From 6a2f6a553bce743e1e6d9235371e805e26933f08 Mon Sep 17 00:00:00 2001 From: admin Date: Wed, 15 Jul 2026 05:33:42 +0000 Subject: [PATCH] Add Altium 365 Part Request (web browser) submission workflow + reference for non-admin end task --- SKILL.md | 78 ++++++++++++++-------------- assets/CHANGELOG.xlsx | Bin 5651 -> 5653 bytes assets/template/template.xlsx | Bin 110238 -> 110219 bytes assets/template/versions.json | 4 +- references/part_request_web.md | 82 +++++++++++++++++++++++++++++ references/schlib_parameters.md | 79 +++++++++------------------- scripts/schlib_write.py | 88 ++++++++++++++++++++++---------- 7 files changed, 205 insertions(+), 126 deletions(-) create mode 100644 references/part_request_web.md diff --git a/SKILL.md b/SKILL.md index 66ff7c9..c079676 100644 --- a/SKILL.md +++ b/SKILL.md @@ -286,25 +286,11 @@ python scripts/fill_templates.py part.json \ --template assets/template/template.xlsx --dest // --design design.json ``` -Once you have the symbol and its Library Ref, you can also write the symbol's Altium parameters -onto the `.SchLib`. **House rule: the symbol carries _every_ parameter the workbook was filled -with from the datasheet — not just the fixed SOP set.** Build the parameter set straight from the -finished `.xlsx` and write it in: - -```bash -python scripts/schlib_params_from_xlsx.py --xlsx //.xlsx \ - --component --set "Process=" --set "Datasheet=" \ - --out params.json -python scripts/schlib_write.py --schlib .SchLib --params params.json --out //.SchLib -``` - -`schlib_params_from_xlsx.py` keeps every filled datasheet column (exact header as the parameter -name), drops the identity/version/model-link columns, renames `Rohs compliance → ROHS` and -`Operating Temp(°C) → Operating Temperature`, and merges in the SOP-only fields (`Manufacturer -Part` = MPN automatically; `Process` / `Datasheet` / `Value` / `Vecmocon Part Code` via `--set`). -See *Mandatory symbol parameters* below and `references/schlib_parameters.md` for the full method -(incl. the ANSI glyph transliteration, e.g. `Ω → Ohm`). This is how the datasheet values land in -the Altium symbol's properties. +Once you have the symbol and its Library Ref, you can also produce the **mandatory symbol +parameters** the SOP requires on the `.SchLib` (Manufacturer, Manufacturer Part, Value, +Tolerance, Operating Temperature, RoHS, Datasheet, Process, Vecmocon Part Code, …) — see +*Mandatory symbol parameters* below. This is optional per run but is how the datasheet values +land in the Altium symbol's properties. ### 7. Assemble the part folder @@ -327,11 +313,8 @@ user where it landed. The SOP (§5) requires every schematic symbol to carry a fixed parameter set in its Altium properties — `Manufacturer`, `Manufacturer Part`, `Value`, `Tolerance`, `Operating Temperature`, `ROHS`, `Datasheet`, `Process`, `Vecmocon Part Code`, and the two second-source -fields — with the **Comment** set to the MPN. **On top of that fixed minimum, the symbol also -carries every other parameter the part's workbook was filled with from the datasheet** (e.g. a -CMC's `Rated Current(A)`, `DC Resistance(mΩ)`, `Package`, `ESD Withstand Voltage(kV)`): the -Altium properties mirror the `.xlsx` row. The skill can stamp all of these onto the symbol -from the workbook + datasheet. +fields — with the **Comment** set to the MPN. The skill can stamp these onto the symbol from +the datasheet. This runs **as its own task too**, not only inside new-part creation: whenever the user hands over one or more `.SchLib` files and wants their parameters filled/updated (e.g. "\schlib", "add @@ -357,19 +340,16 @@ Leave any genuinely-unknown field blank — the SOP hides blank parameters, so a empty until filled. The full method for the second-source search is in `references/schlib_parameters.md`. -Build the `params.json` from the finished workbook (so it carries all the filled datasheet -parameters), then write it into the symbol: +Write the **full parameter set** — the typeid template's engineering columns **plus** the SOP +params above (see `references/schlib_parameters.md`). Collect your filled values into a +`params.json` and pass `--typeid` so the writer guarantees every template column is present +(blank where the datasheet is silent): ```bash -python scripts/schlib_params_from_xlsx.py --xlsx //.xlsx \ - --component --set "Process=" --set "Datasheet=" \ - [--set "Value="] [--set "Vecmocon Part Code="] --out params.json -python scripts/schlib_write.py --schlib .SchLib --params params.json --out //.SchLib +python scripts/schlib_write.py --schlib .SchLib --params params.json \ + --out //.SchLib --typeid ``` -(For a bare `.SchLib`-only task with no workbook, you can still hand-write `params.json` — the -shape is in `references/schlib_parameters.md`.) - Deliver the resulting `.SchLib`; the engineer opens it in Altium once to confirm it loads, then **Saves to Server** with a revision note. The full parameter set, each value's source, the `params.json` shape (incl. the `remove` list), and the mini-stream size caveat are in @@ -378,6 +358,24 @@ round-trip, fall back to `scripts/altium_params.py` (emits an Altium DXP script parameters from inside Altium). Always have the engineer confirm the file opens in Altium — the skill writes Altium's own binary format, so Altium is the final validator. +## Submitting to Altium 365 as Part Requests (web) + +If the org's central library is a managed **Altium 365 Workspace** (not the Gitea repos), the +skill's end task can submit each finished component as a **Part Request** through the Workspace +web UI, using browser automation (Claude-in-Chrome) in the operator's own signed-in Chrome — no +API token, no admin rights. A librarian then approves each request into the library. + +This runs over **every component processed in the run**: the skill writes a `part_requests.json` +manifest (one entry per component — manufacturer, MPN, Description, component type, the full +parameter set, and the local paths to its `.SchLib`/`.PcbLib`/datasheet), then the browser step +loops it, filling and submitting the form for each. On the **first** component, fill everything +and stop at Save for the operator to review; once confirmed, Save and loop the rest, logging each +Request Id. Full field mapping, prerequisites, and the exact browser steps are in +`references/part_request_web.md` — read it before driving the browser. + +Because the files upload from local disk, commit each component's `.SchLib`/`.PcbLib`/datasheet +to the operator's machine (device bridge) first, and put those local paths in the manifest. + ## Per-typeid versioning Versioning is **per typeid**, not global. Each typeid carries its own `template_version` and @@ -537,6 +535,9 @@ plain flat push, but it does not merge the changelog or blank the token, so pref - `references/schlib_parameters.md` — the SOP **mandatory symbol parameters** (§5) for the `.SchLib`: the parameter set, where each value comes from, and how the generated Altium script stamps them onto the symbol. +- `references/part_request_web.md` — submitting finished components to a managed Altium 365 + Workspace as **Part Requests** via browser automation (no token/admin): prerequisites, the + per-component field mapping, the `part_requests.json` manifest, and the looped browser steps. - `assets/template/versions.json` — per-typeid `template_version` + `skill_version`. - `assets/CHANGELOG.xlsx` — global version/parameter changelog (created on first add; merged into the skill repo's copy in Gitea by `push-skill`). @@ -547,14 +548,9 @@ plain flat push, but it does not merge the changelog or blank the token, so pref - `scripts/append_parameter.py` — append parameter(s) to a typeid, bump its versions, write the changelog. - `scripts/altium_refs.py` — read Library/Footprint Ref from `.SchLib`/`.PcbLib`. -- `scripts/schlib_params_from_xlsx.py` — build the symbol `params.json` from the finished - per-part `.xlsx`, so the `.SchLib` carries **every filled datasheet parameter** (not just - the SOP minimum); skips identity/version/model-link columns, renames a couple to their SOP - names, and merges in the SOP-only fields (`Manufacturer Part`, `Process`, `Datasheet`, …). -- `scripts/schlib_write.py` — write the parameters **directly into a `.SchLib`** (pure-Python OLE - rebuild; removes the Ultra-Librarian `Manufacturer_Name` / `Manufacturer_Part_Number` defaults; - transliterates non-ANSI unit glyphs, e.g. `Ω → Ohm`). Primary path; see - `references/schlib_parameters.md`. +- `scripts/schlib_write.py` — write the SOP mandatory parameters **directly into a `.SchLib`** + (pure-Python OLE rebuild; removes the Ultra-Librarian `Manufacturer_Name` / + `Manufacturer_Part_Number` defaults). Primary path; see `references/schlib_parameters.md`. - `scripts/altium_params.py` — fallback: generate an Altium DelphiScript that stamps the same parameters onto a `.SchLib` from inside Altium (DXP → Run Script). - `scripts/gitea_components.py` — `check-mpn`, `find-part` (locate an existing part to diff --git a/assets/CHANGELOG.xlsx b/assets/CHANGELOG.xlsx index 6cb33f56067bb4e2fb3d5493b44b82aa86e6cdad..3b953316be59a0c51fde82ade24c654eb9d28a25 100644 GIT binary patch delta 1904 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 xJ^Dcrn1-J}!Dp^?1U.PcbLib","C:\\...\\.pdf"], + "assignee":"","required_by":""} +]} +``` + +Build it from each component's `params.json` plus the local file paths (after committing files +to the device). + +## Browser procedure (looped per component) + +Start the browser session with `tabs_context_mcp`, then for each entry in the manifest: + +1. Navigate to **Library → Part Requests → new request**. +2. Fill **Manufacturer**, **Manufacturer Part Numbers**, **Description**. +3. Choose **Component Type**; set **Assign to**; optional **Required By Date**. Leave State as + `Opened: New`. +4. **Parameters → Add**: add each parameter name + value. +5. **Attachments** (Choose file / drop): upload the `.SchLib`, `.PcbLib`, and datasheet. +6. Review, then **Save**. Record the auto-assigned **Request Id**. +7. Move to the next entry. + +## Safety and auditing + +- On the **first component of a run**, fill everything and **stop at Save** for the operator to + eyeball the mapping. Once they confirm it looks right, Save it and loop the rest unattended. +- **Log every submitted Request Id** (and any component that failed) so the run is auditable and + re-runnable — never silently skip a component. +- Browser automation follows the live UI. If a field, dropdown option, or a popup doesn't match + what's expected, **pause and ask** rather than guessing — a wrong Component Type or a + half-filled request is worse than one clarifying question. +- Don't trigger native file-dialog blocking: use the extension's file-upload path for + attachments, not an OS dialog. diff --git a/references/schlib_parameters.md b/references/schlib_parameters.md index 4dce9b5..b84b496 100644 --- a/references/schlib_parameters.md +++ b/references/schlib_parameters.md @@ -5,50 +5,6 @@ parameters in its component properties (the panel shown in Altium: *Properties This file defines that set, where each value comes from, and how the skill stamps them onto the `.SchLib` symbol. -## The symbol mirrors the workbook (fill everything the datasheet gave) - -**House rule: the symbol's Altium properties must carry _every_ parameter that was filled into -the part's per-typeid workbook from the datasheet — not just the fixed SOP §5 set.** So a CMC -symbol also gets `Rated Current(A)`, `Rated Voltage(V)`, `DC Resistance(mΩ)`, `Package`, -`ESD Withstand Voltage(kV)`, … — whatever that typeid's sheet holds and the datasheet filled. -The SOP set below is the **minimum**; the workbook is the **source of truth** for the rest. - -Build the parameter set straight from the finished `.xlsx` with -`scripts/schlib_params_from_xlsx.py`, which reads the one data row and keeps every **non-empty** -column, then hand its output to `schlib_write.py`: - -```bash -python scripts/schlib_params_from_xlsx.py --xlsx //.xlsx \ - --component \ - --set "Process=Reflow" --set "Datasheet=" \ - [--set "Value="] [--set "Vecmocon Part Code="] \ - --out params.json -python scripts/schlib_write.py --schlib .SchLib --params params.json --out //.SchLib -``` - -What the builder does: - -- **Keeps every filled datasheet column** as a symbol parameter, using the **exact sheet header - as the parameter name** (e.g. `Rated Current(A)`) so the symbol and the workbook stay - traceably identical. Empty columns are left out (the SOP hides blank parameters). -- **Never writes** the identity / versioning / model-link columns — `MPN_make_type`, - `Skill Version`, `Template Version`, `Library Ref/Path`, `Footprint Ref/Path` (Library Ref is - the symbol's own name and the footprint is the linked PCB model, not a text property). -- **Renames** the two columns whose Altium/SOP name differs — `Rohs compliance → ROHS`, - `Operating Temp(°C) → Operating Temperature` — value copied through unchanged. -- **Merges in the SOP-only fields the sheet doesn't hold**: `Manufacturer Part` (= the MPN, - recovered from the tag) is added automatically; pass `Process`, `Datasheet`, and (if known) - `Value` / `Vecmocon Part Code` via `--set` or a `--sop` JSON. A non-empty override wins over a - sheet value; an empty one is ignored. - -Glyph note: Altium stores parameter text as single-byte ANSI, so `schlib_write.py` transliterates -the few unit glyphs that aren't representable — the ohm sign `Ω → Ohm` (so `DC Resistance(mΩ)` -lands as `DC Resistance(mOhm)`) and a Greek micro `μ → u`; `±`, `°` and the latin-1 micro sign -pass through unchanged. So a couple of symbol parameter names are the ASCII form of the sheet -header — expected, not a mismatch. - -The rest of this file describes the SOP §5 minimum set and where each value comes from. - How the parameters get in: the skill writes them **directly into the `.SchLib` in pure Python** via `scripts/schlib_write.py` — it rebuilds the OLE compound file around the enlarged component `Data` stream while preserving every other byte (all other streams, the directory tree, the @@ -137,24 +93,35 @@ symbol's Library Ref (from `altium_refs.py`); omit it to apply to every componen } ``` +## The full parameter set (template + SOP) + +Every `.SchLib` should carry the **complete** parameter set for its part: the **typeid +template's engineering columns** (all columns of that typeid's `template.xlsx` sheet except the +internal bookkeeping ones — the tag `MPN_make_type`, `Skill Version`, `Template Version`, and the +four `Library/Footprint Ref/Path` columns) **plus** the mandatory SOP params above. So a CER +(ceramic MLCC) symbol gets `Capacitance(uF)`, `Tolerance`, `Voltage(V)`, +`Dielectric(temp. Coefficient)`, `Operating Temp(°C)`, `Max operating temp(°C)`, `Package`, +`Description`, `Manufacturer` from the template, alongside `Value`, `Manufacturer Part`, +`Process`, `Vecmocon Part Code`, `ROHS`, `Datasheet`, and the second-source fields. Fill each +from the datasheet; leave blank what the datasheet doesn't state. + ## Writing them into the symbol -Write the parameters straight into the `.SchLib`, producing a new file: +Write the parameters straight into the `.SchLib`, producing a new file. Pass `--typeid` so the +writer guarantees the whole template column set is present (blank where you didn't supply a +value) — this is what keeps every symbol's parameter set complete and consistent: ```bash -python scripts/schlib_write.py --schlib .SchLib --params params.json --out .SchLib +python scripts/schlib_write.py --schlib .SchLib --params params.json --out .SchLib --typeid ``` -`params.json` may carry a `"remove"` list (defaults to `["Manufacturer_Name", -"Manufacturer_Part_Number"]`); those Ultra-Librarian defaults are stripped and the SOP params -added. The script targets the component named in `"component"` (its Library Ref / storage name), -or every component if omitted, and self-checks the output re-opens as a valid OLE. Deliver the -resulting `.SchLib`, and have the engineer open it in Altium once to confirm it loads, then Save -to Server with a revision note per the SOP. - -Scope note: the direct writer keeps a component's `Data` under Altium's 4096-byte mini-stream -threshold in the common case; a very large parameter set (or an extremely long datasheet URL) -can push it past that, at which point fall back to the `altium_params.py` DXP-script path. +`params.json` carries your filled values (and may include a `"remove"` list — defaults to +`["Manufacturer_Name", "Manufacturer_Part_Number"]`, the Ultra-Librarian duplicates that get +stripped). The script targets the component named in `"component"` (its Library Ref / storage +name), or every component if omitted, and self-checks the output re-opens as a valid OLE. It +handles any parameter-set size — small sets stay in Altium's mini-stream, larger ones are written +as a regular stream automatically. Deliver the resulting `.SchLib`; have the engineer open it in +Altium once to confirm it loads, then Save to Server with a revision note per the SOP. Fallback (apply from inside Altium): diff --git a/scripts/schlib_write.py b/scripts/schlib_write.py index e6411d7..4730cd6 100644 --- a/scripts/schlib_write.py +++ b/scripts/schlib_write.py @@ -29,7 +29,7 @@ IMPORTANT: this writes Altium's own binary format from outside Altium. It is val re-open as a well-formed OLE with every other stream byte-identical, but ALWAYS open the result in Altium once to confirm it loads before relying on it. """ -import argparse, json, struct, sys, hashlib, unicodedata +import argparse, json, os, struct, sys, hashlib import olefile FREESECT=0xFFFFFFFF; ENDOFCHAIN=0xFFFFFFFE; FATSECT=0xFFFFFFFD @@ -42,6 +42,26 @@ def le32(b,o): return struct.unpack('