diff --git a/SKILL.md b/SKILL.md index b19e6e0..bcd0922 100644 --- a/SKILL.md +++ b/SKILL.md @@ -9,10 +9,13 @@ description: >- (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. + pushes it to the library repo under its Class. Can also UPDATE a part already in the library + (revise its values, symbol, footprint, or datasheet) instead of hard-stopping on a duplicate. + Every Description it writes follows Vecmocon's strict Altium Description Format. Use WHENEVER + the user uploads a component datasheet, builds a library entry, adds a parameter to a type + template, updates/revises/corrects an existing part, or pushes a part to Gitea. ALWAYS trigger + on "\datasheet", "\library", or "\library-manager", or any component-library / + datasheet-extraction / library-update task. --- # Library Manager @@ -33,11 +36,15 @@ existing parts** (backfill). When something is ambiguous, ask a specific questio guessing. It is always better to ask one more question than to write the wrong thing into the library. +One more thing to confirm when a part **already exists**: whether to **update it or stop** +(don't silently overwrite), and if updating, **which fields change** (values, symbol/footprint, +datasheet). An update still goes through the same verification loop before anything is pushed. + **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.) +template/version change has been made, or a verified update is ready), 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 @@ -154,8 +161,13 @@ stop; re-doing an existing part would only risk overwriting good data. python scripts/gitea_components.py check-mpn --mpn --make ``` -`EXISTS …` (exit 3) → **stop and tell the user the part is already present in Gitea. End -here.** `ABSENT` (exit 0) → continue. +`ABSENT` (exit 0) → this is a **new part**; continue to step 2. + +`EXISTS …` (exit 3) → the part is already in Gitea. Don't silently overwrite it, but don't +dead-end either — **ask the user whether they want to update the existing part or stop.** If +they want to revise it (new/corrected values, a swapped symbol/footprint, a newer datasheet), +go to *Updating an existing part*. If not, stop here. (If the user's request already said +"update"/"revise"/"fix" this part, take that as the answer and go straight to the update flow.) ### 2. Classify → typeid (and its Class) @@ -198,14 +210,27 @@ Check whether that typeid has a sheet in `assets/template/template.xlsx`. 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`: +guess.** + +The **`Description`** column is special: it is **not** free prose but a strict `_`-joined +engineering string — a type prefix, the defining parameters in a fixed order, package near the +end, optional AEC-Q last (e.g. `CHIP_RES_36kΩ_62.2mW_±0.1%_0402`, `CHIP_CAP_2.2uF_100v_±10%_1210_x7r`, +`SCH_100V_0.25A_SOD-323F`). `references/description_format.md` defines the format for **every** +type in the library: the four the Altium SOP spells out (Resistor, Capacitor, Zener, TVS) are +**strict**; the rest are the house extension on the same basis. Look up the part's type there, +build the Description to that format, and if a real datasheet doesn't fit the format cleanly, +follow the pattern and **flag the mismatch to the engineer** rather than bending it silently. +Collect the values 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"}} + "values":{"Description":"SCH_100V_0.25A_SOD-323F","Forward Voltage(V)":"0.71", + "Reverse Voltage(V)":"100","Forward Current(A)":"0.25","Package":"SOD-323F"}} ``` +(typeid `SCH` → prefix `SCH`, format `SCH_Vr_Io_Package`, so a 100 V / 250 mA Schottky in +SOD-323F becomes `SCH_100V_0.25A_SOD-323F`.) + ```bash python scripts/fill_templates.py part.json \ --template assets/template/template.xlsx --dest // @@ -334,6 +359,80 @@ and tell the user the previous sheets were updated: python scripts/gitea_components.py commit-push --root work/ --message "backfill into " ``` +## Updating an existing part + +When the duplicate check finds the part (or the user asks to revise one that's already in +Gitea), you're **editing a part in place** rather than assembling a new one. The mechanics are +the same edit-in-a-checkout pattern as backfill — the difference is you're changing one part's +own data, not applying a template change across a whole typeid. The guiding rule doesn't +change: nothing is overwritten until the engineer has verified the new version. + +1. **Locate the part in a checkout you can commit.** Clone the library repo, then find the + part's folder and typeid (recovered from its tag): + + ```bash + python scripts/gitea_components.py checkout --dest work/ + python scripts/gitea_components.py find-part --mpn --make --root work/ --json + ``` + + `find-part` returns the part's Class, tag, typeid, the editable folder path under `work/`, + and the files in it (its current `.xlsx`, datasheet, symbol, footprint). If it prints + `NOT FOUND` (exit 4), the part isn't actually there — treat it as a **new** part and go back + to the normal add flow from step 2. + +2. **Decide with the user what's changing.** A part update can revise any of: the **parameter + values** (re-read the datasheet, or a corrected/newer one), the **symbol/footprint**, or the + **datasheet PDF** itself. Ask which, so you only touch what's meant to change and leave the + rest of the folder intact. + +3. **Apply the change in place, in `work///`.** A key thing to understand first: + `fill_templates` **rewrites the whole data row**, so it fills the four design columns + (`Library Ref/Path`, `Footprint Ref/Path`) from the `--design` map you give it — and leaves + them **blank if you don't**. When you rebuild a sheet, always re-supply the design values, or + you'll silently wipe the symbol/footprint refs that were already there. The symbol and + footprint files live in the part folder, so re-deriving them is cheap: point `altium_refs` + at whatever the folder will hold **after** your change. + + - **Values** (re-read the datasheet, or a corrected/newer one) → read the current + `.xlsx` and the folder's datasheet so you start from what's there, re-extract into a + fresh `part.json` (Description still built to `references/description_format.md`), + re-derive the design columns from the folder's existing symbol/footprint, and rebuild the + sheet in place **with `--design`**: + + ```bash + python scripts/altium_refs.py design \ + --symbol work///.SchLib \ + --footprint work///.PcbLib > design.json + python scripts/fill_templates.py part.json \ + --template assets/template/template.xlsx --dest work/// --design design.json + ``` + + Because `fill_templates` reads the **current** template and versions, the rebuilt sheet + keeps this typeid's version stamp (a part-data fix isn't a template change, so nothing + bumps) and picks up any columns the typeid has gained — while the `--design` map carries + the existing symbol/footprint refs through unchanged. (If a part somehow has no + symbol/footprint yet, there's nothing to preserve — rebuild without `--design`.) + - **Symbol/footprint** → copy the new `.SchLib`/`.PcbLib` into the folder under their proper + names (replacing the old ones), then re-derive against the **new** files and rebuild with + `--design` exactly as above (this is step 6 of the add flow). Still flag a genuine + symbol/footprint-vs-part mismatch — that's a correctness issue. + - **Datasheet** → drop the newer PDF in as `_data.`, replacing the old one. If the + values should reflect it, also redo the values step above. + +4. **Verify, then push.** Hand the rebuilt `.xlsx` back and run the same human + verification loop (step 5) — the engineer is still the ground truth. Once confirmed, commit + the checkout and push (attributed to the operator, with a message that says it's an update): + + ```bash + python scripts/gitea_components.py commit-push --root work/ \ + --message "update : (by )" \ + --author " <>" + ``` + + The authored commit and message are the record of the revision (visible in `git log`, the + Gitea commit view and `git blame`); the changelog stays reserved for template/version + changes, not per-part data fixes. Tell the user what changed and where it landed. + ## Pushing the skill repo When skill files change (a new typeid template, a parameter add, a version/changelog bump), @@ -359,6 +458,10 @@ plain flat push, but it does not merge the changelog or blank the token, so pref `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. +- `references/description_format.md` — Vecmocon's Altium **Description Format** (the `_`-joined + engineering string for each part's Description column). Defines a format for **every** type: + the four SOP-defined ones (RES/CAP/Zener/TVS) are strict, the rest are the house extension on + the same basis. Read it before filling any Description. - `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`). @@ -369,9 +472,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/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/gitea_components.py` — `check-mpn`, `find-part` (locate an existing part to + update), `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 diff --git a/assets/CHANGELOG.xlsx b/assets/CHANGELOG.xlsx index 4f1b9f8..cdd51ab 100644 Binary files a/assets/CHANGELOG.xlsx and b/assets/CHANGELOG.xlsx differ diff --git a/config/gitea.env b/config/gitea.env index e29c3ee..0b943a2 100644 --- a/config/gitea.env +++ b/config/gitea.env @@ -3,7 +3,7 @@ # Use a token scoped to these repos (repository: write) and rotate periodically. GIT_HOST=gitea.vecmocon.com GIT_USER=nitishKumar -GIT_TOKEN=451bff1dc32202cbc0a371f8e5645079466d2120 +GIT_TOKEN= # Target repos — TWO now (set these to the exact repo names on your Gitea): # SKILL_REPO : holds this skill's own files (SKILL.md, scripts, assets, ...). # LIBRARY_REPO : holds components, one folder per Class (Diode, IC, ...); inside each, diff --git a/evals/evals.json b/evals/evals.json new file mode 100644 index 0000000..3f3b064 --- /dev/null +++ b/evals/evals.json @@ -0,0 +1,26 @@ +{ + "skill_name": "library-manager", + "evals": [ + { + "id": 0, + "name": "resistor-description-format", + "prompt": "We're adding the Yageo RC0402FR-0736KL to our component library. From its datasheet: resistance 36 kohm, tolerance 1%, package 0402, rated power 63 mW (1/16 W), thick-film chip resistor, not AEC-Q qualified. Following our library process, what exactly should go in this part's Description field in its library sheet? Give me the final Description string.", + "expected_output": "A strict SOP Description string (e.g. CHIP_RES_36kOhm_63mW_+-1%_0402): type prefix, value, wattage, tolerance, package; no AEC-Q token since not qualified. NOT free prose.", + "files": [] + }, + { + "id": 1, + "name": "capacitor-description-format", + "prompt": "Adding a TDK CGA5L1X7R2A225K MLCC to the library. Datasheet: 2.2 uF, 100 V, tolerance 10%, 1210 case size, X7R dielectric, AEC-Q200 qualified. Per our library workflow, what is the exact Description field value for this part?", + "expected_output": "A strict SOP Description string (e.g. CHIP_CAP_2.2uF_100v_+-10%_1210_x7r_AECQ-200): type, value, voltage, tolerance, package, temp-coefficient, AEC-Q last. NOT free prose.", + "files": [] + }, + { + "id": 2, + "name": "existing-part-update-flow", + "prompt": "The part BAT46WJ from Nexperia is already in our library, but its forward-voltage value was entered wrong. I want to correct it. Walk me through exactly how you'd handle this with our library tooling, including the commands you'd run.", + "expected_output": "Recognizes this is an UPDATE of an existing part (not a hard-stop): offers update-or-stop, uses checkout + find-part to locate it, rebuilds the sheet in place with fill_templates (no version bump), keeps human verification, then commit-push with operator attribution. Does not invent a delete/re-add.", + "files": [] + } + ] +} diff --git a/references/description_format.md b/references/description_format.md new file mode 100644 index 0000000..9150fdb --- /dev/null +++ b/references/description_format.md @@ -0,0 +1,334 @@ +# Description format (Vecmocon Altium Library SOP) + +This is the authoritative rule for the **Description** field the skill writes into a part's +workbook. It has two layers: + +1. The **four formats the SOP defines outright** — Resistor, Capacitor, Zener, TVS — from + *Engineering Data Management — SOP: Component Naming, Mandatory Parameters, and Design Item + ID Format* (§6). Follow these parameter orders **strictly** (with one house tweak: the + Zener/TVS prefix uses the generic diode code `ZEN`/`TVS`, not the SOP's `DIO-Z`/`DIO-T` — see + the note under those two below). +2. A **house extension** that carries the *same basis* to every other type in the library + (all 125 type-IDs / 18 classes), so no component is left without a Description convention. + These are built on the SOP pattern and are the working standard; when a specific part + doesn't fit cleanly, follow the pattern and confirm the token order with the engineer rather + than inventing something off-pattern. + +## The basis (applies to every component) + +The Description is **not** a free-form sentence. It is a single string of `_`-joined tokens in +this shape: + +``` +PREFIX_param1_param2_..._Package_[AECQ-XXX] +``` + +- **PREFIX** — a short token (or two) naming the sub-family / technology, e.g. `CHIP_RES`, + `ELE_CAP`, `SCH`, `NMOS`. The per-type prefix is listed for every type below. +- **params** — the part's defining ratings, in the **fixed order** given for that class. Read + them off the datasheet. If the datasheet is silent on a required token, leave it out and flag + it — an honest gap beats a guessed value. +- **Package** — the IPC/industry package or case code, near the end (`0402`, `SOD-323`, + `SOIC-8`, `LQFP-48`, `SMD,D6.3xL5.8mm`, …). +- **AECQ-XXX** — only when the datasheet states automotive qualification (`AECQ-200`, + `AECQ-101`, `AECQ-100`); it is always the **last** token. Omit entirely if not stated — + never assume qualification. + +Description ≠ Design Item ID ≠ Comment — three different fields that share notation but not +content: **Description** is the strict string here (SOP §6); **Design Item ID** (SOP §2) is a +shorter procurement id (`RES_36kΩ_±0.1%_0402`) — use it only as a guide to token vocabulary, +never put it in the Description column; **Comment** (SOP §4) is always the exact MPN. + +## Notation conventions (from the SOP examples) + +- **Value / unit** with SOP casing: `36kΩ`, `2.2uF`, `600Ω`, `48MHz`, `10uH`. Use `Ω` for ohms; + `uF`/`nF`/`pF`, `uH`/`nH`/`mH`, `Hz`/`kHz`/`MHz`, `F` for farads (supercaps). A **range** uses + `~` (`3.5V~28V`, `5.2V~5.6V`). +- **Power** `62.2mW`, `500mW`, `344W`; **voltage** `100v`, `25V`; **current** `0.25A`, `250mA`. +- **Tolerance** signed percent `±0.1%`, `±10%`. +- **Temperature coefficient** (ceramics) lower-case dielectric class: `x7r`, `c0g`, `x5r`. +- Keep tokens in the same style throughout so descriptions sort and read consistently. + +--- + +# Layer 1 — the four SOP-defined formats (strict) + +**Resistor** + +``` +Type_RES_Value_Wattage_Tolerance_Package_AECQ-XXX(optional) +``` + +Example: `CHIP_RES_36kΩ_62.2mW_±0.1%_0402` + +**Capacitor** + +``` +Type_CAP_Value_Voltage_Tolerance_Package_TemperatureCoefficient_AECQ-XXX(optional) +``` + +Example: `CHIP_CAP_2.2uF_100v_±10%_1210_x7r` + +**Zener diode** + +``` +ZEN_VoltageZener(Vz)_Power_Package_AECQ-XXX(optional) +``` + +**TVS diode** + +``` +TVS_VoltageBreakdown(Vbr)_VoltageClamping(Vc)_Current(Ip)_Package_AECQ-XXX(optional) +``` + +**House prefix note:** the SOP §6 wrote these two as `DIO-Z` / `DIO-T`, but Vecmocon +standardised on the **generic diode type code** (`ZEN`, `TVS`, and likewise `SCH`, `ESD`, …) as +the prefix for *all* diodes. So use `ZEN` / `TVS` here — the parameter order (Vz+Power for +Zener; Vbr+Vc+Ip for TVS) is still exactly the SOP's; only the prefix token differs. + +--- + +# Layer 2 — house extension, every other type (same basis) + +Each class below gives its **parameter order** (the tokens between prefix and package) and the +**per-type prefix**. Package is always the second-to-last token; optional `AECQ-XXX` is last. + +## Resistor (RES family) — `PREFIX_Value_Power_Tolerance_Package_[AECQ]` + +| Type | Prefix | Notes | +|------|--------|-------| +| FIX Thick-film chip | `CHIP_RES` | SOP example; the strict format above | +| TFR Thin-film chip | `TFILM_RES` | precision/low-tempco; may append tempco (ppm) | +| MFR Metal-film | `MFILM_RES` | | +| CFR Carbon-film | `CFILM_RES` | | +| MOR Metal-oxide | `MOX_RES` | high-power leaded | +| WWR Wirewound | `WW_RES` | low-ohm/high-power | +| SHT Current-sense/shunt | `SHUNT_RES` | value in mΩ (e.g. `2mΩ`), power token is the sense power | +| ARR Array/network | `ARR_RES` | add element count/config, e.g. `4x`, before value | +| POT Potentiometer/trimmer | `POT` | `POT_Value_Taper_Power_Package` (taper `LIN`/`LOG`) | +| FSR Fusible/safety | `FUSE_RES` | | +| NTC thermistor | `NTC` | `NTC_R25_Beta_Tolerance_Package` (R25 e.g. `10kΩ`, Beta e.g. `B3950`) | +| PTC thermistor | `PTC` | `PTC_R25_Package` (or trip current/temp if that's the rated spec) | + +Example: `SHUNT_RES_2mΩ_1W_±1%_2512` · `NTC_10kΩ_B3950_±1%_0402` + +## Capacitor (CAP family) — `PREFIX_Value_Voltage_Tolerance_Package_[Dielectric]_[AECQ]` + +| Type | Prefix | Notes | +|------|--------|-------| +| CER Ceramic MLCC | `CHIP_CAP` | SOP; dielectric token (`x7r`/`c0g`…) required | +| ELE Aluminium electrolytic | `ELE_CAP` | tolerance often omitted; case like `SMD,D6.3xL5.8mm` | +| TAN Tantalum | `TANT_CAP` | | +| PLY Aluminium-polymer | `POLY_CAP` | low-ESR; ESR may follow voltage | +| FLM Film (MKT/MKP) | `FILM_CAP` | | +| SFY Safety Class-X/Y | `SAFETY_CAP` | add safety class token (`X2`/`Y1`) after value | +| SUP Supercapacitor/EDLC | `SUPERCAP` | value in farads, e.g. `1F`; add ESR if rated | + +Example: `ELE_CAP_33uF_25V_SMD,D6.3xL5.8mm` · `SUPERCAP_1F_5.5V_RADIAL` + +## Inductor / Magnetics — `PREFIX_Value_Current_[DCR]_Package_[AECQ]` + +| Type | Prefix | Format detail | +|------|--------|---------------| +| PWR Power inductor | `PWR_IND` | `PWR_IND_L_Isat_DCR_Package` (L e.g. `10uH`, Isat `3A`) | +| FBD Ferrite bead | `FB` | `FB_Impedance@freq_Current_Package` (e.g. `FB_600Ω@100MHz_2A_0603`) | +| CMC Common-mode choke | `CMC` | `CMC_Impedance@freq_Current_Package` | +| RFI RFI choke | `RFI_CHK` | `RFI_CHK_L_Current_Package` | +| XFM Transformer | `XFMR` | `XFMR_Ratio_Power_Package` (ratio e.g. `1:1`) | +| CTX Current transformer | `CT` | `CT_Ratio_Package` (e.g. `1000:1`) | +| CPL Coupled inductor | `CPL_IND` | `CPL_IND_L_Current_Package` | + +## Diode — reverse-voltage / current ratings, then package + +The prefix is the **generic diode type code (the typeid itself)** — `REC`, `FRD`, `SCH`, `SIC`, +`ZEN`, `TVS`, `ESD`, `SWI`, `BRG`, `LED` — not a `DIO-x` form. + +| Type | Prefix | Format | +|------|--------|--------| +| REC Rectifier | `REC` | `REC_Vrrm_Io_Package` | +| FRD Fast-recovery | `FRD` | `FRD_Vrrm_Io_trr_Package` | +| SCH Schottky | `SCH` | `SCH_Vr_Io_Package` | +| SIC SiC Schottky | `SIC` | `SIC_Vr_Io_Package` | +| ZEN Zener | `ZEN` | `ZEN_Vz_Power_Package` | +| TVS TVS | `TVS` | `TVS_Vbr_Vc_Ip_Package` | +| ESD ESD protection | `ESD` | `ESD_Vrwm_Vc_Channels_Package` | +| SWI Switching/small-signal | `SWI` | `SWI_Vr_Io_trr_Package` | +| BRG Bridge rectifier | `BRG` | `BRG_Vrrm_Io_Package` | +| LED Indicator LED | `LED` | `LED_Color_Vf_If_Package` (color e.g. `RED`) | + +Example (Schottky BAT46WJ, 100 V / 250 mA): `SCH_100V_0.25A_SOD-323F` + +## Transistor — `PREFIX_Voltage_Current_[Rds(on)]_Package_[AECQ]` + +The polarity/channel is **folded into the prefix** as a single token (matching the SOP's own +Design Item ID form, e.g. `NMOS_20V_SOT-23`), not carried as a separate `_NCH`/`_PCH` token. + +| Type | Prefix | Format | +|------|--------|--------| +| BJT BJT | `BJT_NPN` / `BJT_PNP` | `BJT_NPN_Vceo_Ic_Package` | +| MOS MOSFET (Si) | `NMOS` / `PMOS` | `NMOS_Vds_Id_Rdson_Package` | +| SCM SiC MOSFET | `NSICFET` / `PSICFET` | `NSICFET_Vds_Id_Rdson_Package` | +| GAN GaN FET | `GANFET` | `GANFET_Vds_Id_Rdson_Package` | +| IGBT IGBT | `IGBT` | `IGBT_Vces_Ic_Package` | +| JFET JFET | `NJFET` / `PJFET` | `NJFET_Vds_Idss_Package` | +| DIG Digital/bias-R transistor | `DTR_NPN` / `DTR_PNP` | `DTR_NPN_Vceo_R1/R2_Package` | + +Example: `NMOS_20V_6A_15mΩ_SOT-23` · `BJT_NPN_50V_0.1A_SOT-416FL` + +## Integrated Circuit (IC) — one line per subtype; package always last (before AECQ) + +| Type | Prefix | Format | +|------|--------|--------| +| MCU Microcontroller | `MCU` | `MCU_Core_Flash_Package` (e.g. `MCU_M0+_128Kb_LQFP-48`) | +| LDO LDO regulator | `LDO` | `LDO_Vout_Iout_Package` (`ADJ` if adjustable) | +| DCD DC-DC IC | `DCD` | `DCD_Topology_Vin_Iout_Package` (topology `BUCK`/`BOOST`/`BUCKBOOST`) | +| PMU PMIC | `PMIC` | `PMIC_Rails_Package` | +| BMS BMS AFE | `BMS` | `BMS_Cells_Package` (e.g. `16S`) | +| DRV Gate/motor driver | `DRV` | `DRV_Type_Voltage_Current_Package` (type `GATE`/`MOTOR`/`HB`) | +| AMP Amplifier/op-amp | `AMP` | `AMP_GBW_Channels_Package` | +| CMP Comparator | `CMP` | `CMP_Channels_Package` | +| VRF Voltage reference | `VREF` | `VREF_Voltage_Tolerance_Package` | +| ADC ADC | `ADC` | `ADC_Bits_Rate_Package` | +| DAC DAC | `DAC` | `DAC_Bits_Channels_Package` | +| ISO Isolator/optocoupler | `ISO` | `ISO_Channels_IsolationV_Package` | +| XCV Transceiver | `XCVR` | `XCVR_Bus_Speed_Package` (bus `CAN`/`RS485`; e.g. `XCVR_CAN_5Mbps_SOIC-8`) | +| AFE Analog front end | `AFE` | `AFE_Function_Package` | +| MEM Memory | `MEM` | `MEM_Type_Size_Interface_Package` (e.g. `MEM_FLASH_128Mb_SPI_SOIC-8`) | +| LOG Logic gate | `LOG` | `LOG_Function_Package` (e.g. `AND2`, `BUF`) | +| SEN Sensor IC | `SEN_IC` | `SEN_IC_Type_Package` | +| IFC Interface/expander | `IFC` | `IFC_Function_Package` | +| CLK Clock/RTC | `CLK` | `CLK_Freq_Package` (or `RTC_Package`) | +| SVR Supervisor/reset | `SVR` | `SVR_Threshold_Package` | +| MTR Energy metering | `METER` | `METER_Phases_Package` | + +## Protection Device — `PREFIX_ratings_Package` + +| Type | Prefix | Format | +|------|--------|--------| +| FUS Fuse | `FUSE` | `FUSE_Current_Voltage_Package` (speed `F`/`T` may precede current) | +| RSF Resettable/PPTC | `PPTC` | `PPTC_Ihold_Voltage_Package` | +| VAR Varistor/MOV | `MOV` | `MOV_Vrms_Energy_Package` | +| GDT Gas-discharge tube | `GDT` | `GDT_Vspark_Package` | +| CBK Circuit breaker | `BREAKER` | `BREAKER_Current_Poles_Package` | + +## Power Conversion Module — `PREFIX_Vin_Vout_Power_Package` + +| Type | Prefix | Notes | +|------|--------|-------| +| DCM DC-DC module | `DCM` | non-isolated PoL | +| IDC Isolated DC-DC | `IDCM` | isolated brick | +| INV Inverter (DC-AC) | `INV` | `INV_Power_Voltage_Package` | +| OBC On-board charger | `OBC` | `OBC_Power_Voltage_Package` | +| CHG Charger module | `CHG` | `CHG_Power_Voltage_Package` | +| PSU AC-DC SMPS | `PSU` | `PSU_Power_Vout_Package` | +| RCM Rectifier module | `RECT` | `RECT_Current_Voltage_Package` | + +## Relay / Contactor — `PREFIX_CoilVoltage_ContactRating_Package` + +| Type | Prefix | Notes | +|------|--------|-------| +| RLS Signal relay | `RLY_S` | contact rating e.g. `2A/30V` | +| RLP Power relay | `RLY_P` | | +| SSR Solid-state relay | `SSR` | `SSR_ControlV_LoadRating_Package` | +| RLR Reed relay | `RLY_REED` | | +| CTC Contactor | `CTC` | HV/HC contact rating | + +## Switch / Button — `PREFIX_[Positions]_Rating_Package` + +| Type | Prefix | Notes | +|------|--------|-------| +| SWT Tactile | `SW_TACT` | rating e.g. `50mA/12V` | +| PBT Push button | `SW_PB` | | +| DSW DIP/slide | `SW_DIP` | positions e.g. `4P` | +| RSW Rocker/toggle | `SW_ROCK` | | +| RSY Rotary | `SW_ROT` | positions e.g. `12POS` | + +## Connector — `CON_TYPE_Positions_Pitch_Package` + +| Type | Prefix | Notes | +|------|--------|-------| +| CWB Wire-to-board | `CON_W2B` | e.g. `CON_W2B_2x2_P2.0` | +| CBB Board-to-board | `CON_B2B` | | +| HDR Header/socket | `CON_HDR` | pitch e.g. `2.54mm` | +| FFC FFC/FPC | `CON_FFC` | | +| USB USB/data | `CON_USB` | add USB type (`C`, `MICRO`) | +| PWC Power/high-current | `CON_PWR` | add current rating | +| TBK Terminal block | `CON_TB` | | + +## Antenna / RF — `PREFIX_Band_Package` + +| Type | Prefix | Notes | +|------|--------|-------| +| ANC Chip antenna | `ANT_CHIP` | band e.g. `2.4GHz` | +| ANP PCB/trace antenna | `ANT_PCB` | | +| ANE External/whip | `ANT_EXT` | add connector token | +| SAW SAW filter | `SAW` | `SAW_Freq_Package` | +| RFM RF/wireless module | `RFMOD` | protocol e.g. `BLE`, `WIFI`, `LTE` | + +## Crystal / Oscillator / Timing — `PREFIX_Freq_[Load]_Package` + +| Type | Prefix | Notes | +|------|--------|-------| +| XTL Crystal | `XTAL` | `XTAL_Freq_LoadCap_Package` (e.g. `XTAL_48MHz_18pF_SMD2016-4P`) | +| OSC Crystal oscillator | `OSC` | `OSC_Freq_Package` | +| MMO MEMS oscillator | `MEMS_OSC` | | +| RSN Ceramic resonator | `RESON` | `RESON_Freq_Package` | + +## Battery / Cell — `PREFIX_Capacity_Voltage_Format` + +| Type | Prefix | Notes | +|------|--------|-------| +| CLI Li-ion cell | `CELL_LI` | format e.g. `18650`; capacity `2600mAh` | +| CLF LiFePO4 cell | `CELL_LFP` | | +| CCO Coin/button | `CELL_COIN` | add chemistry (`CR`/`LIR`) + size (`2032`) | +| CNI NiMH | `CELL_NIMH` | | +| BPK Battery pack | `PACK` | `PACK_Voltage_Capacity` (e.g. `48V_20Ah`) | +| CHL Cell holder | `HOLDER` | `HOLDER_CellType_Package` | + +## Audible / Indicator + +| Type | Prefix | Format | +|------|--------|--------| +| BUZ Magnetic buzzer | `BUZ_MAG` | `BUZ_MAG_Voltage_Freq_Package` | +| PBZ Piezo buzzer | `BUZ_PIEZO` | `BUZ_PIEZO_Voltage_Freq_Package` | +| SPK Speaker | `SPK` | `SPK_Power_Impedance_Package` | +| IND Indicator lamp | `IND` | `IND_Color_Voltage_Package` | + +## Display / HMI — `PREFIX_Resolution/Digits_Size_Interface` + +| Type | Prefix | Notes | +|------|--------|-------| +| DSG 7-segment | `DISP_7SEG` | `DISP_7SEG_Digits_Color_Package` | +| OLE OLED | `DISP_OLED` | resolution e.g. `128x64`, size `0.96in` | +| LCD LCD | `DISP_LCD` | char (`16x2`) or graphic resolution | +| TFT TFT | `DISP_TFT` | resolution + size + interface (`SPI`/`RGB`) | + +## Sensor (discrete / module) — `SEN_TYPE_Range_[Interface]_Package` + +| Type | Prefix | Notes | +|------|--------|-------| +| STE Temperature | `SEN_TEMP` | range + interface (`I2C`/`ANALOG`) | +| SCU Current (Hall) | `SEN_CURR` | range e.g. `±50A` | +| SVO Voltage/isolated | `SEN_VOLT` | | +| SHA Hall/position | `SEN_HALL` | type (`LATCH`/`LINEAR`) | +| SIM IMU/accel | `SEN_IMU` | axes (`6AXIS`) + interface | +| SPR Pressure | `SEN_PRES` | range + interface | + +## Thermal / Cooling + +| Type | Prefix | Format | +|------|--------|--------| +| FAN Fan | `FAN` | `FAN_Size_Voltage_Airflow` (size e.g. `40x40mm`) | +| HSK Heatsink | `HSK` | `HSK_Dimensions_ThermalResistance` | +| TPD Thermal pad/TIM | `TIM` | `TIM_Conductivity_Thickness` | + +--- + +## When a part doesn't fit + +The Layer-2 formats are the working house standard, but real datasheets vary. If a part is +missing a token the format asks for, leave it out and flag it. If it has a defining rating the +format doesn't capture, add it in the sensible position and **tell the engineer** what you +added so the convention can be updated deliberately. Never silently bend a format — an +inconsistent Description is worse than one confirmed question. The Layer-1 (SOP) formats are +fixed and are not up for reinterpretation. diff --git a/scripts/gitea_components.py b/scripts/gitea_components.py index 0027631..2d57dee 100644 --- a/scripts/gitea_components.py +++ b/scripts/gitea_components.py @@ -15,6 +15,13 @@ testing or offline work): early duplicate gate, run BEFORE classifying.) Prints EXISTS/ or ABSENT; exit 0 if absent, 3 if it already exists (so a shell can hard-stop). + find-part --mpn BAT46WJ --make Nexperia [--root work/] [--json] + Locate an existing part so it can be REVISED (the update path — the mirror of + check-mpn, which gates *new* parts). Reports the part's Class, tag, typeid and the + files in its folder. Point --root at a `checkout` clone and the folder it returns is + the real, editable one to change in place before `commit-push`. Exit 0 if found, 4 if + not (so a shell can branch: found -> update, not found -> fall through to add). + checkout --dest work/ Clone the library repo to a working dir you can browse and edit in place. @@ -142,6 +149,12 @@ def find_part_dirs(root, prefix="", typeid=None): yield cls, name, pdir +def _typeid_of(tag): + """Recover the typeid from a part tag __. The typeid is the last + underscore-delimited token, so this is robust even if the MPN itself contains underscores.""" + return tag.rsplit("_", 1)[1] if "_" in tag else "" + + def cmd_check_mpn(env, args): root, _ = _root(env, args) prefix = mpn_make_prefix(args.mpn, args.make) @@ -153,6 +166,31 @@ def cmd_check_mpn(env, args): print("ABSENT") +def cmd_find_part(env, args): + """Locate an existing part by MPN+make so it can be REVISED — the mirror image of + check-mpn (which gates *new* parts). Reports the folder, its typeid and its files. + + Point --root at a checkout (from `checkout`) and the folder it returns is the real, + editable, committable one — that's the update path: checkout -> find-part -> edit in + place -> commit-push. Without --root/--local it clones a throwaway copy for a read-only + look. Exit 0 if found, 4 if not (so a shell can branch).""" + root, _ = _root(env, args) + prefix = mpn_make_prefix(args.mpn, args.make) + matches = list(find_part_dirs(root, prefix=prefix)) + if not matches: + print("[]" if args.json else "NOT FOUND") + sys.exit(4) + out = [{"class": cls, "tag": name, "typeid": _typeid_of(name), + "folder": pdir, "files": sorted(os.listdir(pdir))} + for cls, name, pdir in matches] + if args.json: + import json + print(json.dumps(out, indent=2)) + else: + for o in out: + print(f'{o["class"]}/{o["tag"]} (typeid {o["typeid"]}) -> {", ".join(o["files"])}') + + def cmd_checkout(env, args): dest = clone(env, args.dest) print(f"library repo checked out at {dest}") @@ -370,6 +408,10 @@ def main(): p = sub.add_parser("check-mpn"); p.add_argument("--mpn", required=True) p.add_argument("--make", required=True); p.add_argument("--local"); p.add_argument("--root") + p = sub.add_parser("find-part"); p.add_argument("--mpn", required=True) + p.add_argument("--make", required=True); p.add_argument("--local"); p.add_argument("--root") + p.add_argument("--json", action="store_true") + p = sub.add_parser("checkout"); p.add_argument("--dest", required=True) p = sub.add_parser("list-type"); p.add_argument("--typeid", required=True) @@ -401,14 +443,14 @@ def main(): if args.cmd in ("push-skill", "pull-skill"): needs.add("SKILL_REPO") elif args.cmd in ("check-mpn", "checkout", "commit-push", "push-part") or \ - (args.cmd in ("list-type", "place-part") and not getattr(args, "local", None) and not getattr(args, "root", None)): + (args.cmd in ("list-type", "place-part", "find-part") and not getattr(args, "local", None) and not getattr(args, "root", None)): needs.add("LIBRARY_REPO") for k in sorted(needs): if not env.get(k): sys.exit(f"missing {k} in env/config") - {"check-mpn": cmd_check_mpn, "checkout": cmd_checkout, "list-type": cmd_list_type, - "place-part": cmd_place_part, "commit-push": cmd_commit_push, "push-part": cmd_push_part, - "push-skill": cmd_push_skill, "pull-skill": cmd_pull_skill}[args.cmd](env, args) + {"check-mpn": cmd_check_mpn, "find-part": cmd_find_part, "checkout": cmd_checkout, + "list-type": cmd_list_type, "place-part": cmd_place_part, "commit-push": cmd_commit_push, + "push-part": cmd_push_part, "push-skill": cmd_push_skill, "pull-skill": cmd_pull_skill}[args.cmd](env, args) if __name__ == "__main__":