LDO: add Output Accuracy(%) param (template v2, skill v2)
parent
acbd9973f1
commit
b69a638875
61
SKILL.md
61
SKILL.md
|
|
@ -9,7 +9,7 @@ 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 components repo under its Class. Use WHENEVER the user uploads a component
|
||||
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.
|
||||
|
|
@ -28,10 +28,16 @@ This is a deliberately **interactive** skill. At every decision point, **ask the
|
|||
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**; whether to **apply a new parameter to existing
|
||||
parts** (backfill); and **before every push to Gitea** (the part, the skill files, the
|
||||
changelog). 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.
|
||||
**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
|
||||
|
||||
|
|
@ -54,14 +60,14 @@ use the same tag:
|
|||
`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 components repo into top-level folders.
|
||||
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)
|
||||
|
||||
components repo/
|
||||
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
|
||||
|
|
@ -71,7 +77,7 @@ components repo/
|
|||
```
|
||||
|
||||
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`, `COMPONENTS_REPO`), so runs
|
||||
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.
|
||||
|
||||
|
|
@ -95,7 +101,7 @@ here.** `ABSENT` (exit 0) → continue.
|
|||
|
||||
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 components-repo folder) comes from the same taxonomy row —
|
||||
(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)
|
||||
|
|
@ -118,10 +124,10 @@ Check whether that typeid has a sheet in `assets/template/template.xlsx`.
|
|||
|
||||
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/template/CHANGELOG.xlsx`. Then **ask
|
||||
the user before pushing**, and sync the updated skill files + changelog to the skill repo
|
||||
with `push-skill` (see *Pushing the skill repo*) — that merges the new changelog row onto
|
||||
the one already in Gitea rather than overwriting it.
|
||||
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).
|
||||
|
|
@ -145,9 +151,19 @@ python scripts/fill_templates.py part.json \
|
|||
--template assets/template/template.xlsx --dest <stage>/<tag>/
|
||||
```
|
||||
|
||||
This writes `<tag>.xlsx` — just that typeid's sheet, one row — 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.
|
||||
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
|
||||
|
||||
|
|
@ -194,7 +210,7 @@ python scripts/fill_templates.py part.json \
|
|||
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 components repo, under the part's Class
|
||||
### 8. Push to the library repo, under the part's Class
|
||||
|
||||
```bash
|
||||
python scripts/gitea_components.py push-part --folder <stage>/<tag> --typeid <typeid>
|
||||
|
|
@ -218,7 +234,7 @@ reading and writing these numbers.
|
|||
## The changelog
|
||||
|
||||
`append_parameter.py` maintains one **global** changelog as an Excel workbook at
|
||||
`assets/template/CHANGELOG.xlsx` (sheet `Changelog`, styled green header). Every time a
|
||||
`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).
|
||||
|
|
@ -257,7 +273,8 @@ python scripts/gitea_components.py commit-push --root work/ --message "backfill
|
|||
## Pushing the skill repo
|
||||
|
||||
When skill files change (a new typeid template, a parameter add, a version/changelog bump),
|
||||
**ask the user first**, then push the skill's own files to the skill repo with `push-skill`:
|
||||
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"
|
||||
|
|
@ -278,7 +295,7 @@ plain flat push, but it does not merge the changelog or blank the token, so pref
|
|||
`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/template/CHANGELOG.xlsx` — global version/parameter changelog (created on first add;
|
||||
- `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`).
|
||||
|
|
@ -288,9 +305,9 @@ plain flat push, but it does not merge the changelog or blank the token, so pref
|
|||
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` (components repo), and `push-skill` (skill repo: token-blanked
|
||||
`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` / `COMPONENTS_REPO` names
|
||||
- `config/gitea.env` — host, user, token, and the `SKILL_REPO` / `LIBRARY_REPO` names
|
||||
(**secret** — do not push the token).
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
|
|
@ -156,8 +156,8 @@
|
|||
"template_version": 1
|
||||
},
|
||||
"FBD": {
|
||||
"skill_version": 2,
|
||||
"template_version": 2
|
||||
"skill_version": 1,
|
||||
"template_version": 1
|
||||
},
|
||||
"FFC": {
|
||||
"skill_version": 1,
|
||||
|
|
@ -232,8 +232,8 @@
|
|||
"template_version": 1
|
||||
},
|
||||
"LDO": {
|
||||
"skill_version": 1,
|
||||
"template_version": 1
|
||||
"skill_version": 2,
|
||||
"template_version": 2
|
||||
},
|
||||
"LED": {
|
||||
"skill_version": 1,
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@ GIT_USER=nitishKumar
|
|||
GIT_TOKEN=451bff1dc32202cbc0a371f8e5645079466d2120
|
||||
# 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, ...).
|
||||
# COMPONENTS_REPO : holds components, one folder per Class (Diode, IC, ...); inside each,
|
||||
# LIBRARY_REPO : holds components, one folder per Class (Diode, IC, ...); inside each,
|
||||
# one MPN_make_typeid/ folder per part with { xlsx, datasheet, symbol,
|
||||
# footprint }. (Replaces the old DFS + Parameters repos.)
|
||||
SKILL_REPO=nitishKumar/skill
|
||||
COMPONENTS_REPO=nitishKumar/Components
|
||||
LIBRARY_REPO=nitishKumar/library
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
Use the **Type ID** as the `typeid` in `MPN_make_typeid`. Match each part to the closest
|
||||
subclass. In the current template **each Type ID is its own sheet** (125 sheets), so the
|
||||
template sheet name **is the Type ID** (e.g. `SCH`, `MOS`, `LDO`). The **Class** is used only
|
||||
to organise the components repo into top-level folders (e.g. `SCH` lives under `Diode/`);
|
||||
to organise the library repo into top-level folders (e.g. `SCH` lives under `Diode/`);
|
||||
`scripts/common.py:class_folder()` maps a typeid to its folder name. Full source:
|
||||
`assets/template/Type_ID.xlsx`.
|
||||
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -15,7 +15,7 @@ headers. Then versions.json is bumped and one entry is written to CHANGELOG.xlsx
|
|||
--desc "Added Trr and Cd for SMPS rectifier derating"
|
||||
|
||||
After running, push the updated template.xlsx + versions.json + CHANGELOG.xlsx to the SKILL
|
||||
repo (and, per the workflow, the same change flows to the components repo copies).
|
||||
repo (and, per the workflow, the same change flows to the library repo copies).
|
||||
"""
|
||||
import argparse, datetime, os
|
||||
import openpyxl
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
One place for the three things every script needs to agree on:
|
||||
|
||||
- the taxonomy (typeid -> Class -> components-repo folder name), read from
|
||||
- the taxonomy (typeid -> Class -> library-repo folder name), read from
|
||||
``assets/template/Type_ID.xlsx`` so there is a single source of truth;
|
||||
- the **per-typeid version store** (``assets/template/versions.json``) that holds each
|
||||
typeid's own ``template_version`` and ``skill_version`` - both start at 1 and both bump
|
||||
|
|
@ -29,7 +29,7 @@ COL_SKILL_VER = "Skill Version" # column B (per-typeid skill version, st
|
|||
COL_TEMPLATE_VER = "Template Version" # column C (per-typeid template version, stamped by us)
|
||||
DESIGN_COLS = ("Library Ref", "Library Path", "Footprint Ref", "Footprint Path")
|
||||
|
||||
# Raw taxonomy Class name -> clean, filesystem-safe folder name for the components repo.
|
||||
# Raw taxonomy Class name -> clean, filesystem-safe folder name for the library repo.
|
||||
# These match Vecmocon's established sheet-name convention (the old 18-class template).
|
||||
CLASS_FOLDER = {
|
||||
"Resistor": "Resistor",
|
||||
|
|
@ -80,7 +80,7 @@ def load_taxonomy(type_id_xlsx=TYPE_ID_XLSX):
|
|||
|
||||
|
||||
def class_folder(typeid, taxonomy=None):
|
||||
"""The components-repo top-level folder name for a typeid (e.g. SCH -> 'Diode')."""
|
||||
"""The library-repo top-level folder name for a typeid (e.g. SCH -> 'Diode')."""
|
||||
tax = taxonomy or load_taxonomy()
|
||||
info = tax.get(typeid)
|
||||
return info["folder"] if info else None
|
||||
|
|
@ -153,6 +153,33 @@ def init_versions(force=False):
|
|||
return data
|
||||
|
||||
|
||||
# ---------------------------------------------------------------- changelog (read)
|
||||
|
||||
CHANGELOG_HEADERS = ["Date", "Typeid", "Skill Version", "Template Version", "Description"]
|
||||
|
||||
|
||||
def read_changelog():
|
||||
"""All changelog rows as dicts (empty list if the changelog doesn't exist yet)."""
|
||||
if not os.path.exists(CHANGELOG_XLSX):
|
||||
return []
|
||||
wb = openpyxl.load_workbook(CHANGELOG_XLSX)
|
||||
ws = wb["Changelog"] if "Changelog" in wb.sheetnames else wb.active
|
||||
out = []
|
||||
for r in ws.iter_rows(min_row=2, values_only=True):
|
||||
if not r or all(c is None for c in r):
|
||||
continue
|
||||
r = list(r) + [None] * (5 - len(r))
|
||||
out.append({"date": r[0], "typeid": r[1], "skill": r[2],
|
||||
"template": r[3], "description": r[4]})
|
||||
return out
|
||||
|
||||
|
||||
def changelog_for_typeid(typeid):
|
||||
"""Every recorded version change for one typeid, oldest first — the cumulative history
|
||||
(v1->v2, v2->v3, ...) that each part sheet of that typeid embeds as its Version History."""
|
||||
return [r for r in read_changelog() if str(r["typeid"]) == str(typeid)]
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import sys
|
||||
if len(sys.argv) > 1 and sys.argv[1] == "init":
|
||||
|
|
|
|||
|
|
@ -24,11 +24,54 @@ comes from the extracted ``values``.
|
|||
``part.json`` is either a single part object or {"parts": [ ... ]} (each part built to its
|
||||
own file). A part = {"mpn","manufacturer" (or "make"),"typeid","values":{header:value,...}}.
|
||||
"""
|
||||
import argparse, json, os
|
||||
import argparse, json, os, re
|
||||
import openpyxl
|
||||
from common import (norm, part_tag, version_labels,
|
||||
from openpyxl.styles import Font, PatternFill, Border, Side, Alignment
|
||||
from common import (norm, part_tag, version_labels, changelog_for_typeid,
|
||||
COL_TAG, COL_SKILL_VER, COL_TEMPLATE_VER, DESIGN_COLS)
|
||||
|
||||
GREEN = "B6D7A8"; GRAY = "BFBFBF"
|
||||
VERSION_SHEET = "Version History"
|
||||
|
||||
|
||||
def _vtrans(v):
|
||||
"""'v2' -> 'v1 -> v2' (each changelog row records the new version; the previous is n-1)."""
|
||||
m = re.match(r"v?(\d+)", str(v).strip()) if v is not None else None
|
||||
if not m:
|
||||
return "" if v is None else str(v)
|
||||
n = int(m.group(1))
|
||||
return f"v{n-1} → v{n}" if n > 1 else f"v{n}"
|
||||
|
||||
|
||||
def add_version_history(wb, typeid):
|
||||
"""Sheet 2 of a part workbook: the cumulative version history for this typeid — every
|
||||
template/skill change (v1->v2, v2->v3, ...) with its date and description. Added only when
|
||||
there has actually been a template/skill update; still-v1 typeids get no second sheet."""
|
||||
rows = changelog_for_typeid(typeid)
|
||||
if not rows:
|
||||
return False
|
||||
ws = wb.create_sheet(VERSION_SHEET)
|
||||
s = Side(style="thin", color=GRAY)
|
||||
border = Border(left=s, right=s, top=s, bottom=s)
|
||||
headers = ["Date", "Skill Version", "Template Version", "Description"]
|
||||
for c, h in enumerate(headers, start=1):
|
||||
cell = ws.cell(1, c, h)
|
||||
cell.font = Font(name="Calibri", bold=True)
|
||||
cell.fill = PatternFill("solid", fgColor=GREEN)
|
||||
cell.border = border
|
||||
cell.alignment = Alignment(horizontal="center", vertical="center")
|
||||
for row in rows:
|
||||
r = ws.max_row + 1
|
||||
vals = [row["date"], _vtrans(row["skill"]), _vtrans(row["template"]), row["description"]]
|
||||
for c, v in enumerate(vals, start=1):
|
||||
cell = ws.cell(r, c, v)
|
||||
cell.border = border
|
||||
cell.alignment = Alignment(vertical="center", wrap_text=(c == 4), horizontal="left")
|
||||
for col, w in zip("ABCD", (18, 16, 18, 60)):
|
||||
ws.column_dimensions[col].width = w
|
||||
ws.freeze_panes = "A2"
|
||||
return True
|
||||
|
||||
|
||||
def template_headers(template_path, typeid):
|
||||
"""Canonical headers for a typeid sheet, or None if the template has no such sheet."""
|
||||
|
|
@ -76,6 +119,7 @@ def build_part_sheet(part, template_path, dest_dir, design=None):
|
|||
ws.cell(r, c).value = None
|
||||
for c, h in enumerate(headers, start=1):
|
||||
ws.cell(2, c, row.get(h, ""))
|
||||
add_version_history(wb, typeid) # Sheet 2: cumulative version history (if any)
|
||||
os.makedirs(dest_dir, exist_ok=True)
|
||||
out = os.path.join(dest_dir, f"{tag}.xlsx")
|
||||
wb.save(out)
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
Repos (from config/gitea.env):
|
||||
SKILL_REPO - this skill's own files (pushed with push_to_gitea.sh, not here).
|
||||
COMPONENTS_REPO - one folder per Class (Diode, IC, Transistor, ...); inside each Class,
|
||||
LIBRARY_REPO - one folder per Class (Diode, IC, Transistor, ...); inside each Class,
|
||||
one MPN_make_typeid/ folder per part holding { xlsx, datasheet, symbol,
|
||||
footprint }.
|
||||
|
||||
|
|
@ -11,12 +11,12 @@ Subcommands (all accept --local <dir> to run against a local folder instead of c
|
|||
testing or offline work):
|
||||
|
||||
check-mpn --mpn BAT46WJ --make Nexperia
|
||||
Is any part with this MPN+make already in the components repo? (typeid-agnostic - the
|
||||
Is any part with this MPN+make already in the library repo? (typeid-agnostic - the
|
||||
early duplicate gate, run BEFORE classifying.) Prints EXISTS/<tag> or ABSENT; exit 0
|
||||
if absent, 3 if it already exists (so a shell can hard-stop).
|
||||
|
||||
checkout --dest work/
|
||||
Clone the components repo to a working dir you can browse and edit in place.
|
||||
Clone the library repo to a working dir you can browse and edit in place.
|
||||
|
||||
list-type --typeid SCH [--root work/] [--json]
|
||||
List every existing part of a typeid and the files in its folder (for backfill: the
|
||||
|
|
@ -59,7 +59,7 @@ def load_env(cfg):
|
|||
continue
|
||||
k, v = line.split("=", 1)
|
||||
env[k.strip()] = v.strip()
|
||||
for k in ("GIT_HOST", "GIT_USER", "GIT_TOKEN", "SKILL_REPO", "COMPONENTS_REPO"):
|
||||
for k in ("GIT_HOST", "GIT_USER", "GIT_TOKEN", "SKILL_REPO", "LIBRARY_REPO"):
|
||||
if os.environ.get(k):
|
||||
env[k] = os.environ[k]
|
||||
return env
|
||||
|
|
@ -72,7 +72,7 @@ def repo_url(env, repo):
|
|||
|
||||
|
||||
def clone(env, dest, repo=None):
|
||||
repo = repo or env["COMPONENTS_REPO"]
|
||||
repo = repo or env["LIBRARY_REPO"]
|
||||
url = repo_url(env, repo)
|
||||
r = subprocess.run(["git", "clone", url, dest], capture_output=True, text=True)
|
||||
if r.returncode != 0:
|
||||
|
|
@ -140,7 +140,7 @@ def cmd_check_mpn(env, args):
|
|||
|
||||
def cmd_checkout(env, args):
|
||||
dest = clone(env, args.dest)
|
||||
print(f"components repo checked out at {dest}")
|
||||
print(f"library repo checked out at {dest}")
|
||||
|
||||
|
||||
def cmd_list_type(env, args):
|
||||
|
|
@ -315,7 +315,7 @@ def main():
|
|||
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)):
|
||||
needs.add("COMPONENTS_REPO")
|
||||
needs.add("LIBRARY_REPO")
|
||||
for k in sorted(needs):
|
||||
if not env.get(k):
|
||||
sys.exit(f"missing {k} in env/config")
|
||||
|
|
|
|||
Loading…
Reference in New Issue