333 lines
16 KiB
Markdown
333 lines
16 KiB
Markdown
---
|
|
name: library-manager
|
|
description: >-
|
|
Manage Vecmocon's component library: extract parameters from a component datasheet PDF into
|
|
the per-typeid Excel template (125 type-IDs across 18 classes - resistors, capacitors,
|
|
diodes, transistors, ICs, connectors, sensors, etc.). The user gives a datasheet named
|
|
as its MPN plus the make. The skill checks Gitea for a duplicate MPN_make and hard-stops if
|
|
present, classifies the part to a typeid, confirms or updates that typeid's template
|
|
(per-typeid version, changelog, backfill), fills a per-part workbook, loops on human
|
|
verification, then takes the Altium symbol (.SchLib) and footprint (.PcbLib), fills the
|
|
Library/Footprint columns, assembles a part folder (xlsx, datasheet, symbol, footprint) and
|
|
pushes it to the library repo under its Class. Use WHENEVER the user uploads a component
|
|
datasheet, builds a library entry, adds a parameter to a type template, or pushes a part to
|
|
Gitea. ALWAYS trigger on "\datasheet", "\library", or "\library-manager", or any
|
|
component-library / datasheet-extraction task.
|
|
---
|
|
|
|
# Library Manager
|
|
|
|
Turn one component datasheet into a verified, versioned library entry in Gitea. The guiding
|
|
idea is honesty and traceability: every value lands in the right column and unit, anything
|
|
the datasheet doesn't state stays blank, and nothing reaches Gitea until a human has
|
|
confirmed it.
|
|
|
|
## Ask, don't assume
|
|
|
|
This is a deliberately **interactive** skill. At every decision point, **ask the user and
|
|
wait for an answer — do not assume a default and proceed.** In particular, always confirm:
|
|
the **make**; the **typeid/classification** you inferred; whether any **new parameters**
|
|
should be added to the template; the extracted **values** (the verification loop); that the
|
|
**symbol/footprint actually match this part**; and whether to **apply a new parameter to
|
|
existing parts** (backfill). When something is ambiguous, ask a specific question rather than
|
|
guessing. It is always better to ask one more question than to write the wrong thing into the
|
|
library.
|
|
|
|
**Pushing is the exception — push automatically.** Once a part is verified and assembled (or a
|
|
template/version change has been made), push to Gitea **on your own, without asking for
|
|
confirmation**. Never add a "shall I push?" step — just push, then tell the user where it
|
|
landed. (You still flag a genuine symbol/footprint mismatch, because that's a correctness
|
|
issue, not a push confirmation.)
|
|
|
|
## Inputs
|
|
|
|
- **A datasheet PDF whose filename is the MPN** (e.g. `BAT46WJ.pdf`). If it's a series
|
|
datasheet, search that exact MPN inside to read the correct variant.
|
|
- **The make** (manufacturer), given by the user. The `make` tag is the first word of the
|
|
manufacturer, alphanumerics only (Texas Instruments → `Texas`, Nexperia → `Nexperia`).
|
|
- **Later in the flow**, after verification: an Altium **symbol** (`.SchLib`) and
|
|
**footprint** (`.PcbLib`) file, provided by the user.
|
|
|
|
## The identifier: `MPN_make_typeid`
|
|
|
|
Every part folder, every per-part workbook, and column A of every sheet (`MPN_make_type`)
|
|
use the same tag:
|
|
|
|
```
|
|
<MPN>_<make>_<typeid> e.g. BAT46WJ_Nexperia_SCH
|
|
```
|
|
|
|
`typeid` is the part's type-ID code from the taxonomy (`references/taxonomy.md`, full source
|
|
`assets/template/Type_ID.xlsx`) — Schottky → `SCH`, MOSFET → `MOS`, LDO → `LDO`. In the new
|
|
template **each typeid is its own sheet** (125 of them). The broader **Class** (Diode,
|
|
Transistor, IC …) is used only to organise the library repo into top-level folders.
|
|
|
|
## Gitea layout (two repos)
|
|
|
|
```
|
|
skill repo/ this skill's own files (updated versions land here too)
|
|
|
|
library repo/
|
|
<Class>/ e.g. Diode, IC, Transistor, Resistor, ...
|
|
<MPN>_<make>_<typeid>/ e.g. BAT46WJ_Nexperia_SCH
|
|
<MPN>_<make>_<typeid>.xlsx this part's own one-row parameter sheet
|
|
<MPN>_data.pdf the datasheet
|
|
<symbol>.SchLib user-provided
|
|
<footprint>.PcbLib user-provided
|
|
```
|
|
|
|
There is **no single master workbook** — each part carries its own sheet inside its folder.
|
|
Connection + repo names live in `config/gitea.env` (`SKILL_REPO`, `LIBRARY_REPO`), so runs
|
|
need no per-session token. If the host is unreachable, the git steps fail clearly and write
|
|
nothing.
|
|
|
|
## Workflow
|
|
|
|
Run these in order. Each `python`/`bash` command is a helper in `scripts/`.
|
|
|
|
### 0. Sync the skill state from Gitea first — always
|
|
|
|
The skill's state (the template, the per-typeid versions, and the changelog) lives in the
|
|
**skill repo**, and it grows over time. A fresh install/session starts from the packaged v1
|
|
state, so if you don't sync first, a second template change wouldn't build on the first — the
|
|
versions would restart at v1 and the changelog would look like it only holds the latest change.
|
|
**So begin every run by pulling the current state:**
|
|
|
|
```bash
|
|
python scripts/gitea_components.py pull-skill
|
|
```
|
|
|
|
This copies `template.xlsx`, `versions.json`, and `CHANGELOG.xlsx` from the skill repo into the
|
|
local skill, so version bumps continue correctly (v2 → v3 → …) and the changelog stays
|
|
**cumulative from the very first change**.
|
|
|
|
### 1. Duplicate check first — before any real work
|
|
|
|
The part's presence is keyed on **MPN + make** (typeid not known yet). If it already exists,
|
|
stop; re-doing an existing part would only risk overwriting good data.
|
|
|
|
```bash
|
|
python scripts/gitea_components.py check-mpn --mpn <MPN> --make <make>
|
|
```
|
|
|
|
`EXISTS …` (exit 3) → **stop and tell the user the part is already present in Gitea. End
|
|
here.** `ABSENT` (exit 0) → continue.
|
|
|
|
### 2. Classify → typeid (and its Class)
|
|
|
|
Read the datasheet, identify the part, and match it to the closest subclass in
|
|
`references/taxonomy.md`; record its **typeid** (= the template sheet name). The **Class**
|
|
(for the library-repo folder) comes from the same taxonomy row —
|
|
`scripts/common.py:class_folder(typeid)` returns it (e.g. `SCH` → `Diode`).
|
|
|
|
### 3. Confirm the typeid's template (and add parameters if asked)
|
|
|
|
Check whether that typeid has a sheet in `assets/template/template.xlsx`.
|
|
|
|
- **No sheet for this typeid** → ask the user to upload the template sheet for it. Add it to
|
|
`assets/template/template.xlsx`, then push the updated skill files to the skill repo (see
|
|
*Pushing the skill repo*). Then continue.
|
|
- **Sheet exists** → print **all** of that sheet's parameters (its column headers) in the
|
|
chat and ask the user whether any new parameters should be added.
|
|
- **No** → go to step 4.
|
|
- **Yes** → collect the new parameter name(s), then:
|
|
|
|
```bash
|
|
python scripts/append_parameter.py --typeid <typeid> \
|
|
--param "New Parameter(unit)" [--param "Another(unit)"] \
|
|
--desc "why these were added"
|
|
```
|
|
|
|
This appends the column(s) at the end of that typeid's sheet, **bumps that typeid's
|
|
Template Version and Skill Version together** (v1→v2 — see *Per-typeid versioning*),
|
|
and writes one row to the global changelog `assets/CHANGELOG.xlsx`. Then sync the updated
|
|
skill files + changelog to the skill repo with `push-skill` **automatically** (see
|
|
*Pushing the skill repo*) — that merges the new changelog row onto the one already in Gitea
|
|
rather than overwriting it.
|
|
|
|
Then ask: **should this change apply to the parts of this typeid already in Gitea?**
|
|
- **No** → go to step 4 (only the current part gets the new column).
|
|
- **Yes → backfill** (see *Backfilling existing parts*), then tell the user the previous
|
|
sheets were updated, and go to step 4.
|
|
|
|
### 4. Extract and fill the per-part workbook
|
|
|
|
Read every parameter the datasheet actually states into that typeid's columns, converting to
|
|
each header's unit. **Leave blanks where the datasheet is silent — an honest blank beats a
|
|
guess.** Collect them into a small `part.json`:
|
|
|
|
```json
|
|
{"mpn":"BAT46WJ","manufacturer":"Nexperia","typeid":"SCH",
|
|
"values":{"Description":"100 V 250 mA Schottky, SOD323F","Forward Voltage(V)":"0.71",
|
|
"Reverse Voltage(V)":"100","Forward Current(A)":"0.25","Package":"SOD323F"}}
|
|
```
|
|
|
|
```bash
|
|
python scripts/fill_templates.py part.json \
|
|
--template assets/template/template.xlsx --dest <stage>/<tag>/
|
|
```
|
|
|
|
This writes `<tag>.xlsx` with column A = the tag, **Skill Version (col B)** and **Template
|
|
Version (col C)** stamped from this typeid's current versions, and the four design columns
|
|
left blank for now.
|
|
|
|
The part workbook has up to **two sheets**:
|
|
|
|
- **Sheet 1** — the typeid's parameter sheet (the one filled row).
|
|
- **Sheet 2 — `Version History`** — added **only when this typeid has had a template/skill
|
|
update**. It lists the **cumulative** change history for that typeid (Date, Skill Version,
|
|
Template Version as `v1 → v2`, Description) — every change up to the version this file was
|
|
built at. So a part built at v3 shows both `v1 → v2` and `v2 → v3`; a still-at-v1 typeid has
|
|
no second sheet. The history is read from `assets/CHANGELOG.xlsx`, so make sure the local
|
|
changelog is current (it's kept in sync by `push-skill`) before building parts.
|
|
|
|
### 5. Human verification loop
|
|
|
|
Deliver the filled workbook to the user and ask them to verify it. If they report an error
|
|
or say it isn't right, **go back to step 4, re-read the datasheet more carefully, re-fill,
|
|
and hand it back.** Repeat until the user confirms it's verified. Nothing is pushed until
|
|
this passes — the engineer is the ground truth for the numbers.
|
|
|
|
### 6. Symbol + footprint → the design columns
|
|
|
|
Once verified, ask the user to upload the **symbol (`.SchLib`)** and **footprint
|
|
(`.PcbLib`)** files. Copy them into the staging part folder **under their proper names** (so
|
|
the Path columns match the files that actually get stored — strip any upload-staging prefix
|
|
the environment may have added), then read all four design values in one shot:
|
|
|
|
```bash
|
|
cp <uploaded_symbol> <stage>/<tag>/<symbol_name>.SchLib
|
|
cp <uploaded_footprint> <stage>/<tag>/<footprint_name>.PcbLib
|
|
python scripts/altium_refs.py design \
|
|
--symbol <stage>/<tag>/<symbol_name>.SchLib \
|
|
--footprint <stage>/<tag>/<footprint_name>.PcbLib > design.json
|
|
```
|
|
|
|
This produces (verified against real Ultra-Librarian exports):
|
|
|
|
- **Library Ref** = the component name **inside** the `.SchLib` (e.g. `CGA3E3X7R1H474K080AE`)
|
|
- **Library Path** = the `.SchLib` file name
|
|
- **Footprint Ref** = the **base** pattern inside the `.PcbLib`; Altium ships IPC density
|
|
variants (`-L` / `-M` / `-N`) alongside the base, and the base is the one used (e.g.
|
|
`CAP_CGA3_TDK`, not `CAP_CGA3_TDK-L`)
|
|
- **Footprint Path** = the `.PcbLib` file name
|
|
|
|
These Ref names come from *inside* the files and can differ from the MPN or filename. If a Ref
|
|
comes back `null` (or a footprint shows several unrelated candidates), ask the user to confirm
|
|
the name from Altium's properties and edit `design.json`. Then re-fill so the columns land:
|
|
|
|
```bash
|
|
python scripts/fill_templates.py part.json \
|
|
--template assets/template/template.xlsx --dest <stage>/<tag>/ --design design.json
|
|
```
|
|
|
|
### 7. Assemble the part folder
|
|
|
|
The staging folder `<tag>/` should now hold the four files: the per-part `<tag>.xlsx`, the
|
|
datasheet (name it `<MPN>_data.<ext>`), the symbol, and the footprint.
|
|
|
|
### 8. Push to the library repo, under the part's Class
|
|
|
|
```bash
|
|
python scripts/gitea_components.py push-part --folder <stage>/<tag> --typeid <typeid>
|
|
```
|
|
|
|
This places the folder at `components/<Class>/<tag>/` — creating the Class folder if it
|
|
doesn't exist yet, or pushing into it if it does — and commits and pushes. Confirm to the
|
|
user where it landed.
|
|
|
|
## Per-typeid versioning
|
|
|
|
Versioning is **per typeid**, not global. Each typeid carries its own `template_version` and
|
|
`skill_version` in `assets/template/versions.json` (both start at 1). When a parameter is
|
|
added to a typeid, that typeid gets a new template, so its `template_version` bumps — and on
|
|
the back of that its `skill_version` bumps too (v1→v2). **Only that typeid moves**; every
|
|
other typeid keeps its versions. Those two numbers are exactly what `fill_templates` stamps
|
|
into that typeid's rows (cols B and C), so a row always records the template/skill version it
|
|
was built against. `append_parameter.py` does the bump; `common.py` is the single source for
|
|
reading and writing these numbers.
|
|
|
|
## The changelog
|
|
|
|
`append_parameter.py` maintains one **global** changelog as an Excel workbook at
|
|
`assets/CHANGELOG.xlsx` (sheet `Changelog`, styled green header). Every time a
|
|
typeid's template/version changes, one row is appended with columns
|
|
**Date | Typeid | Skill Version | Template Version | Description** — the version columns hold
|
|
the new versions, and Description is your note (or the parameter(s) added if you gave none).
|
|
|
|
The changelog lives in the **skill repo in Gitea** as well, and it is **cumulative from the
|
|
first change onward**. Two things keep it that way: at the start of a run `pull-skill` (step 0)
|
|
brings the current changelog down so a new change appends to the full history, and on push
|
|
`push-skill` **merges** the new local rows onto the changelog already in Gitea — appended,
|
|
never overwritten. So the Gitea copy is the growing, authoritative history across machines and
|
|
sessions; the merged file is copied back locally so the two stay in sync. If you ever see the
|
|
Gitea changelog with only the latest change, it means step 0 (`pull-skill`) was skipped.
|
|
|
|
## Backfilling existing parts
|
|
|
|
When the user wants a newly-added parameter applied to parts of that typeid already in Gitea:
|
|
|
|
```bash
|
|
python scripts/gitea_components.py checkout --dest work/
|
|
python scripts/gitea_components.py list-type --typeid <typeid> --root work/ --json
|
|
```
|
|
|
|
`list-type` lists every existing part of that typeid with the files in its folder — including
|
|
its datasheet, which is co-located. For each one: read that datasheet, re-extract the values
|
|
(including the new parameter), and rebuild its per-part sheet in place:
|
|
|
|
```bash
|
|
python scripts/fill_templates.py <that_part>.json \
|
|
--template assets/template/template.xlsx --dest work/<Class>/<that_tag>/
|
|
```
|
|
|
|
Because `fill_templates` uses the current template and current versions, each rebuilt sheet
|
|
picks up the new column and the bumped version automatically. When all are done, push once
|
|
and tell the user the previous sheets were updated:
|
|
|
|
```bash
|
|
python scripts/gitea_components.py commit-push --root work/ --message "backfill <param> into <typeid>"
|
|
```
|
|
|
|
## Pushing the skill repo
|
|
|
|
When skill files change (a new typeid template, a parameter add, a version/changelog bump),
|
|
push the skill's own files to the skill repo with `push-skill` **automatically** (no
|
|
confirmation):
|
|
|
|
```bash
|
|
python scripts/gitea_components.py push-skill --message "Sync skill files + changelog"
|
|
```
|
|
|
|
`push-skill` clones the skill repo, copies the skill files in with the **`GIT_TOKEN` blanked
|
|
out** (the real token never leaves the machine), and **merges** `CHANGELOG.xlsx` — appending
|
|
this run's new rows onto the changelog already in Gitea so earlier entries are preserved — then
|
|
writes the merged changelog back locally. (The older `push_to_gitea.sh` still exists for a
|
|
plain flat push, but it does not merge the changelog or blank the token, so prefer
|
|
`push-skill` for the skill repo.)
|
|
|
|
## Resources
|
|
|
|
- `assets/template/template.xlsx` — the master template: one sheet per **typeid** (125),
|
|
source of every sheet's headers, styling and order. Columns A/B/C are always
|
|
`MPN_make_type` / `Skill Version` / `Template Version`; `Library Ref/Path`,
|
|
`Footprint Ref/Path` and `Manufacturer` sit near the end.
|
|
- `assets/template/Type_ID.xlsx` + `references/taxonomy.md` — Class → Subclass → Type ID.
|
|
- `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`).
|
|
- `scripts/common.py` — taxonomy loader (`load_taxonomy`, `class_folder`), version store
|
|
(`get_versions`, `version_labels`, `bump_versions`), and the tag helper (`part_tag`).
|
|
- `scripts/fill_templates.py` — build one per-part `<tag>.xlsx` (version-stamped); reused for
|
|
backfill.
|
|
- `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/gitea_components.py` — `check-mpn`, `checkout`, `list-type`, `place-part`,
|
|
`commit-push`, `push-part` (library repo), and `push-skill` (skill repo: token-blanked
|
|
push + append-only changelog merge).
|
|
- `scripts/push_to_gitea.sh` — push a folder's contents to a Gitea repo (used for the skill
|
|
repo).
|
|
- `config/gitea.env` — host, user, token, and the `SKILL_REPO` / `LIBRARY_REPO` names
|
|
(**secret** — do not push the token).
|