ISO: add Power(W), Rθ(J-A), Max Output Current(A) (template v2, skill v2)

main
library-manager 2026-07-10 14:08:16 +00:00
parent 8781deb852
commit 6610e8789e
No known key found for this signature in database
10 changed files with 194 additions and 40 deletions

View File

@ -81,6 +81,50 @@ Connection + repo names live in `config/gitea.env` (`SKILL_REPO`, `LIBRARY_REPO`
need no per-session token. If the host is unreachable, the git steps fail clearly and write need no per-session token. If the host is unreachable, the git steps fail clearly and write
nothing. nothing.
## Who's running this (operator identity)
The whole org shares one Claude account and one Gitea token, so the skill can't tell who's
running it on its own. Instead it records the **operator's name** on everything it pushes, and
asks **only once per person**. Establish the identity at the very start of a run:
1. Read `~/.library-manager-id` on the operator's machine (via the desktop bridge):
`cat ~/.library-manager-id`.
2. **If it exists** (JSON like `{"name":"Priya Sharma","email":"priya@vecmocon.com"}`) → use it,
**don't ask**.
3. **If it does NOT exist → this person isn't onboarded yet, so ask once** (do this even though
the config carries a default, so a teammate is never silently logged as "admin"):
> "First time using the library skill on this machine — what name should your library
> changes be recorded under? (If you're the admin, just enter `admin`.) And your email,
> if you have one."
Then save it so it's remembered forever:
`echo '{"name":"<Name>","email":"<email>"}' > ~/.library-manager-id`. Every later run finds
it in step 1 and never asks again — the admin answers `admin` once, each teammate answers
their own name once, and from then on everyone is attributed correctly with no prompt.
4. **Only if you genuinely can't ask** (an unattended / scheduled run, or the machine isn't
reachable) fall back to the config `OPERATOR` default so the run isn't blocked — and say in
your summary that attribution used the default rather than a confirmed person.
Then carry that identity through the run:
- pass `--author "<Name> <<email>>"` to every `push-part` / `push-skill` / `commit-push`, and
- pass `--by "<Name>"` to `append_parameter`.
(Equivalent alternatives the scripts also read: `export LM_AUTHOR_NAME=... LM_AUTHOR_EMAIL=...`
for the session, or drop the same `~/.library-manager-id` file in the container home.)
**Identity precedence** (first one that's set wins): `--author` flag → `LM_AUTHOR_*` env →
per-person `~/.library-manager-id` → the per-install **`OPERATOR`** default in
`config/gitea.env`. So this admin install has `OPERATOR=admin`, meaning **every run/push here
is recorded as "admin" automatically**, with no file or prompt needed. A member's own
`~/.library-manager-id` (or an explicit `--author`) overrides that default with their real name.
This stamps the operator onto three things: the **commit author** (shown in `git log`, the
Gitea commit page, and `git blame`), the **commit message** (it ends with `(by <Name>)`, so the
name shows right in Gitea's activity feed), and a **By** column in the changelog. Honest limit:
the top-line "*X* pushed to main" in Gitea's activity still shows the **shared token owner**
only giving each person their own Gitea token changes that bottom layer.
## Workflow ## Workflow
Run these in order. Each `python`/`bash` command is a helper in `scripts/`. Run these in order. Each `python`/`bash` command is a helper in `scripts/`.
@ -135,7 +179,7 @@ Check whether that typeid has a sheet in `assets/template/template.xlsx`.
```bash ```bash
python scripts/append_parameter.py --typeid <typeid> \ python scripts/append_parameter.py --typeid <typeid> \
--param "New Parameter(unit)" [--param "Another(unit)"] \ --param "New Parameter(unit)" [--param "Another(unit)"] \
--desc "why these were added" --desc "why these were added" --by "<operator name>"
``` ```
This appends the column(s) at the end of that typeid's sheet, **bumps that typeid's This appends the column(s) at the end of that typeid's sheet, **bumps that typeid's
@ -229,7 +273,8 @@ datasheet (name it `<MPN>_data.<ext>`), the symbol, and the footprint.
### 8. Push to the library repo, under the part's Class ### 8. Push to the library repo, under the part's Class
```bash ```bash
python scripts/gitea_components.py push-part --folder <stage>/<tag> --typeid <typeid> python scripts/gitea_components.py push-part --folder <stage>/<tag> --typeid <typeid> \
--author "<operator name> <<operator email>>"
``` ```
This places the folder at `components/<Class>/<tag>/` — creating the Class folder if it This places the folder at `components/<Class>/<tag>/` — creating the Class folder if it
@ -296,7 +341,8 @@ push the skill's own files to the skill repo with `push-skill` **automatically**
confirmation): confirmation):
```bash ```bash
python scripts/gitea_components.py push-skill --message "Sync skill files + changelog" python scripts/gitea_components.py push-skill --author "<operator name> <<operator email>>" \
--message "Sync skill files + changelog"
``` ```
`push-skill` clones the skill repo, copies the skill files in with the **`GIT_TOKEN` blanked `push-skill` clones the skill repo, copies the skill files in with the **`GIT_TOKEN` blanked

Binary file not shown.

Binary file not shown.

View File

@ -220,8 +220,8 @@
"template_version": 1 "template_version": 1
}, },
"ISO": { "ISO": {
"skill_version": 1, "skill_version": 2,
"template_version": 1 "template_version": 2
}, },
"JFET": { "JFET": {
"skill_version": 1, "skill_version": 1,

View File

@ -3,7 +3,7 @@
# Use a token scoped to these repos (repository: write) and rotate periodically. # Use a token scoped to these repos (repository: write) and rotate periodically.
GIT_HOST=gitea.vecmocon.com GIT_HOST=gitea.vecmocon.com
GIT_USER=nitishKumar GIT_USER=nitishKumar
GIT_TOKEN= GIT_TOKEN=451bff1dc32202cbc0a371f8e5645079466d2120
# Target repos — TWO now (set these to the exact repo names on your Gitea): # 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, ...). # SKILL_REPO : holds this skill's own files (SKILL.md, scripts, assets, ...).
# LIBRARY_REPO : holds components, one folder per Class (Diode, IC, ...); inside each, # LIBRARY_REPO : holds components, one folder per Class (Diode, IC, ...); inside each,
@ -11,3 +11,7 @@ GIT_TOKEN=
# footprint }. (Replaces the old DFS + Parameters repos.) # footprint }. (Replaces the old DFS + Parameters repos.)
SKILL_REPO=nitishKumar/skill SKILL_REPO=nitishKumar/skill
LIBRARY_REPO=nitishKumar/library LIBRARY_REPO=nitishKumar/library
# Default operator for THIS install — who shows as the author / in the changelog "By" when no
# per-person identity (~/.library-manager-id) is set. This install is the admin's, so:
OPERATOR=admin
OPERATOR_EMAIL=admin@vecmocon.com

View File

@ -21,9 +21,9 @@ import argparse, datetime, os
import openpyxl import openpyxl
from copy import copy from copy import copy
from openpyxl.styles import Font, PatternFill, Border, Side, Alignment from openpyxl.styles import Font, PatternFill, Border, Side, Alignment
from common import (TEMPLATE_XLSX, CHANGELOG_XLSX, bump_versions) from common import (TEMPLATE_XLSX, CHANGELOG_XLSX, CHANGELOG_HEADERS,
bump_versions, resolve_operator)
CHANGELOG_HEADERS = ["Date", "Typeid", "Skill Version", "Template Version", "Description"]
GREEN = "B6D7A8"; GRAY = "BFBFBF" GREEN = "B6D7A8"; GRAY = "BFBFBF"
@ -74,16 +74,17 @@ def _new_changelog_book():
cell.fill = PatternFill("solid", fgColor=GREEN) cell.fill = PatternFill("solid", fgColor=GREEN)
cell.border = _thin() cell.border = _thin()
cell.alignment = Alignment(horizontal="center", vertical="center") cell.alignment = Alignment(horizontal="center", vertical="center")
for col, w in zip("ABCDE", (18, 10, 14, 16, 60)): for col, w in zip("ABCDEF", (18, 10, 14, 16, 50, 22)):
ws.column_dimensions[col].width = w ws.column_dimensions[col].width = w
ws.freeze_panes = "A2" ws.freeze_panes = "A2"
return wb return wb
def write_changelog(typeid, added, old, new, desc, when=None): def write_changelog(typeid, added, old, new, desc, by="", when=None):
"""Append one row to the Excel changelog for a typeid's template/version change. """Append one row to the Excel changelog for a typeid's template/version change.
Columns: Date | Typeid | Skill Version | Template Version | Description. The version Columns: Date | Typeid | Skill Version | Template Version | Description | By. The version
columns show the NEW versions; Description is the user's note (or the added params).""" columns show the NEW versions; Description is the note (or the added params); By is who
made the change (the operator)."""
when = when or datetime.datetime.now() when = when or datetime.datetime.now()
detail = desc or ("Added parameter(s): " + ", ".join(added)) detail = desc or ("Added parameter(s): " + ", ".join(added))
if os.path.exists(CHANGELOG_XLSX): if os.path.exists(CHANGELOG_XLSX):
@ -93,7 +94,7 @@ def write_changelog(typeid, added, old, new, desc, when=None):
wb = _new_changelog_book() wb = _new_changelog_book()
ws = wb.active ws = wb.active
row = [when.strftime("%Y-%m-%d %H:%M"), typeid, row = [when.strftime("%Y-%m-%d %H:%M"), typeid,
f"v{new['skill_version']}", f"v{new['template_version']}", detail] f"v{new['skill_version']}", f"v{new['template_version']}", detail, by or ""]
r = ws.max_row + 1 r = ws.max_row + 1
for c, v in enumerate(row, start=1): for c, v in enumerate(row, start=1):
cell = ws.cell(r, c, v) cell = ws.cell(r, c, v)
@ -110,13 +111,16 @@ def main():
ap.add_argument("--param", required=True, action="append", ap.add_argument("--param", required=True, action="append",
help="new column header; repeat for several") help="new column header; repeat for several")
ap.add_argument("--desc", default="", help="what/why - goes in the changelog") ap.add_argument("--desc", default="", help="what/why - goes in the changelog")
ap.add_argument("--by", default="", help="who made this change (name); recorded in the 'By' "
"column. If omitted, the operator identity is resolved automatically.")
ap.add_argument("--template", default=TEMPLATE_XLSX) ap.add_argument("--template", default=TEMPLATE_XLSX)
a = ap.parse_args() a = ap.parse_args()
by = a.by or (resolve_operator()[0] or "")
added = append_params(a.template, a.typeid, a.param) added = append_params(a.template, a.typeid, a.param)
old, new = bump_versions(a.typeid) old, new = bump_versions(a.typeid)
cl = write_changelog(a.typeid, added, old, new, a.desc) cl = write_changelog(a.typeid, added, old, new, a.desc, by=by)
print(f"Added to {a.typeid}: {', '.join(added)}") print(f"Added to {a.typeid}: {', '.join(added)}" + (f" (by {by})" if by else ""))
print(f"{a.typeid}: template v{old['template_version']}->v{new['template_version']}, " print(f"{a.typeid}: template v{old['template_version']}->v{new['template_version']}, "
f"skill v{old['skill_version']}->v{new['skill_version']}") f"skill v{old['skill_version']}->v{new['skill_version']}")
print(f"Changelog updated: {cl}") print(f"Changelog updated: {cl}")

View File

@ -155,7 +155,8 @@ def init_versions(force=False):
# ---------------------------------------------------------------- changelog (read) # ---------------------------------------------------------------- changelog (read)
CHANGELOG_HEADERS = ["Date", "Typeid", "Skill Version", "Template Version", "Description"] # "By" = who made the change (the operator). See operator identity below.
CHANGELOG_HEADERS = ["Date", "Typeid", "Skill Version", "Template Version", "Description", "By"]
def read_changelog(): def read_changelog():
@ -168,9 +169,9 @@ def read_changelog():
for r in ws.iter_rows(min_row=2, values_only=True): for r in ws.iter_rows(min_row=2, values_only=True):
if not r or all(c is None for c in r): if not r or all(c is None for c in r):
continue continue
r = list(r) + [None] * (5 - len(r)) r = list(r) + [None] * (len(CHANGELOG_HEADERS) - len(r)) # pad old 5-col rows
out.append({"date": r[0], "typeid": r[1], "skill": r[2], out.append({"date": r[0], "typeid": r[1], "skill": r[2],
"template": r[3], "description": r[4]}) "template": r[3], "description": r[4], "by": r[5]})
return out return out
@ -180,6 +181,61 @@ def changelog_for_typeid(typeid):
return [r for r in read_changelog() if str(r["typeid"]) == str(typeid)] return [r for r in read_changelog() if str(r["typeid"]) == str(typeid)]
# ---------------------------------------------------------------- operator identity
# Where each person's "who am I" is stored, on their OWN machine. The skill asks once, writes
# it here, and reads it silently on every later run so nobody has to retype their name. Because
# it lives on each person's computer (not in the shared config), it stays per-person even though
# the Claude account and the Gitea token are shared.
IDENTITY_FILE = os.path.expanduser("~/.library-manager-id")
def parse_author(author):
"""'Name <email>' or 'Name' -> (name, email). Returns (None, None) for empty input."""
if not author:
return None, None
m = re.match(r"^\s*(.*?)\s*<(.*?)>\s*$", str(author))
if m:
return m.group(1).strip() or None, m.group(2).strip()
return str(author).strip() or None, ""
def _config_operator():
"""(name, email) from the OPERATOR / OPERATOR_EMAIL lines of config/gitea.env — the
per-install default identity (e.g. the admin's install sets OPERATOR=admin)."""
cfg = os.path.join(SKILL_ROOT, "config", "gitea.env")
name = email = None
if os.path.exists(cfg):
for line in open(cfg, encoding="utf-8"):
line = line.strip()
if line.startswith("OPERATOR="):
name = line.split("=", 1)[1].strip()
elif line.startswith("OPERATOR_EMAIL="):
email = line.split("=", 1)[1].strip()
return (name or None), (email or "")
def resolve_operator(author_arg=None):
"""Return (name, email) for the person running this, trying in order:
(1) an explicit --author, (2) the LM_AUTHOR_NAME/LM_AUTHOR_EMAIL env vars, (3) the
per-person identity file ~/.library-manager-id, (4) the per-install OPERATOR default in
config/gitea.env. (None, None) if none set callers fall back to the generic bot."""
name, email = parse_author(author_arg)
if name:
return name, email
name = os.environ.get("LM_AUTHOR_NAME")
if name:
return name, os.environ.get("LM_AUTHOR_EMAIL", "")
if os.path.exists(IDENTITY_FILE):
try:
d = json.load(open(IDENTITY_FILE, encoding="utf-8"))
if d.get("name"):
return d.get("name"), d.get("email", "")
except Exception:
pass
return _config_operator()
if __name__ == "__main__": if __name__ == "__main__":
import sys import sys
if len(sys.argv) > 1 and sys.argv[1] == "init": if len(sys.argv) > 1 and sys.argv[1] == "init":

View File

@ -53,7 +53,7 @@ def add_version_history(wb, typeid):
ws = wb.create_sheet(VERSION_SHEET) ws = wb.create_sheet(VERSION_SHEET)
s = Side(style="thin", color=GRAY) s = Side(style="thin", color=GRAY)
border = Border(left=s, right=s, top=s, bottom=s) border = Border(left=s, right=s, top=s, bottom=s)
headers = ["Date", "Skill Version", "Template Version", "Description"] headers = ["Date", "Skill Version", "Template Version", "Description", "By"]
for c, h in enumerate(headers, start=1): for c, h in enumerate(headers, start=1):
cell = ws.cell(1, c, h) cell = ws.cell(1, c, h)
cell.font = Font(name="Calibri", bold=True) cell.font = Font(name="Calibri", bold=True)
@ -62,12 +62,13 @@ def add_version_history(wb, typeid):
cell.alignment = Alignment(horizontal="center", vertical="center") cell.alignment = Alignment(horizontal="center", vertical="center")
for row in rows: for row in rows:
r = ws.max_row + 1 r = ws.max_row + 1
vals = [row["date"], _vtrans(row["skill"]), _vtrans(row["template"]), row["description"]] vals = [row["date"], _vtrans(row["skill"]), _vtrans(row["template"]),
row["description"], row.get("by") or ""]
for c, v in enumerate(vals, start=1): for c, v in enumerate(vals, start=1):
cell = ws.cell(r, c, v) cell = ws.cell(r, c, v)
cell.border = border cell.border = border
cell.alignment = Alignment(vertical="center", wrap_text=(c == 4), horizontal="left") cell.alignment = Alignment(vertical="center", wrap_text=(c == 4), horizontal="left")
for col, w in zip("ABCD", (18, 16, 18, 60)): for col, w in zip("ABCDE", (18, 16, 18, 50, 22)):
ws.column_dimensions[col].width = w ws.column_dimensions[col].width = w
ws.freeze_panes = "A2" ws.freeze_panes = "A2"
return True return True

View File

@ -44,7 +44,8 @@ nothing is written.
import argparse, os, re, shutil, subprocess, sys, tempfile import argparse, os, re, shutil, subprocess, sys, tempfile
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
from common import (class_folder, load_taxonomy, mpn_make_prefix, from common import (class_folder, load_taxonomy, mpn_make_prefix,
SKILL_ROOT, TEMPLATE_XLSX, VERSIONS_JSON, CHANGELOG_XLSX) SKILL_ROOT, TEMPLATE_XLSX, VERSIONS_JSON, CHANGELOG_XLSX,
CHANGELOG_HEADERS, resolve_operator)
CFG_DEFAULT = os.path.join(os.path.dirname(__file__), "..", "config", "gitea.env") CFG_DEFAULT = os.path.join(os.path.dirname(__file__), "..", "config", "gitea.env")
@ -89,9 +90,15 @@ def clone(env, dest, repo=None):
return dest return dest
def commit_push(root, token, msg): def commit_push(root, token, msg, author=None):
for args in (["config", "user.email", "datasheet-bot@local"], """Commit + push. `author` = (name, email) of the operator; when given, the commit is
["config", "user.name", "library-manager"], authored by that real person (visible in git log / Gitea commit view / blame). Without it,
a generic bot identity is used."""
name, email = author or (None, None)
name = name or "library-manager"
email = email or "datasheet-bot@local"
for args in (["config", "user.email", email],
["config", "user.name", name],
["checkout", "-B", "main"], ["add", "-A"]): ["checkout", "-B", "main"], ["add", "-A"]):
subprocess.run(["git", "-C", root] + args, capture_output=True) subprocess.run(["git", "-C", root] + args, capture_output=True)
if subprocess.run(["git", "-C", root, "diff", "--cached", "--quiet"]).returncode == 0: if subprocess.run(["git", "-C", root, "diff", "--cached", "--quiet"]).returncode == 0:
@ -193,30 +200,50 @@ def cmd_place_part(env, args):
print(f"placed {tag} -> {cls}/{tag}") print(f"placed {tag} -> {cls}/{tag}")
def _operator(args):
"""(name, email) of who's running this — from --author, else env, else identity file."""
return resolve_operator(getattr(args, "author", None))
def _by(name):
return f" (by {name})" if name else ""
def cmd_commit_push(env, args): def cmd_commit_push(env, args):
commit_push(args.root, env.get("GIT_TOKEN", ""), args.message or "library-manager: update components") name, email = _operator(args)
commit_push(args.root, env.get("GIT_TOKEN", ""),
args.message or f"library-manager: update components{_by(name)}", author=(name, email))
def cmd_push_part(env, args): def cmd_push_part(env, args):
name, email = _operator(args)
tmp = tempfile.mkdtemp(prefix="components_") tmp = tempfile.mkdtemp(prefix="components_")
clone(env, tmp) clone(env, tmp)
cls, tag, _ = place_part(tmp, args.folder, args.typeid) cls, tag, _ = place_part(tmp, args.folder, args.typeid)
print(f"placed {tag} -> {cls}/{tag}") print(f"placed {tag} -> {cls}/{tag}" + (f" (by {name})" if name else ""))
commit_push(tmp, env.get("GIT_TOKEN", ""), args.message or f"library-manager: add {tag}") commit_push(tmp, env.get("GIT_TOKEN", ""),
args.message or f"library-manager: add {tag}{_by(name)}", author=(name, email))
# ------------------------------------------------------------------ skill repo + changelog # ------------------------------------------------------------------ skill repo + changelog
def _changelog_rows(path): def _changelog_rows(path):
"""(workbook, sheet, [row-tuples]) for a changelog xlsx; ([]) if the file is absent.""" """(workbook, sheet, [row-tuples]) for a changelog xlsx; ([]) if the file is absent. Rows are
padded/truncated to the canonical column count so old 5-column changelogs (no 'By') merge
cleanly with new 6-column ones."""
import openpyxl import openpyxl
if not os.path.exists(path): if not os.path.exists(path):
return None, None, [] return None, None, []
n = len(CHANGELOG_HEADERS)
wb = openpyxl.load_workbook(path) wb = openpyxl.load_workbook(path)
ws = wb["Changelog"] if "Changelog" in wb.sheetnames else wb.active ws = wb["Changelog"] if "Changelog" in wb.sheetnames else wb.active
rows = [tuple("" if c is None else str(c) for c in r) rows = []
for r in ws.iter_rows(min_row=2, values_only=True)] for r in ws.iter_rows(min_row=2, values_only=True):
vals = ["" if c is None else str(c) for c in r]
vals = (vals + [""] * n)[:n]
if any(v for v in vals):
rows.append(tuple(vals))
return wb, ws, rows return wb, ws, rows
@ -234,6 +261,7 @@ def merge_changelog(local_path, repo_path):
shutil.copy(local_path, repo_path) shutil.copy(local_path, repo_path)
_, _, rows = _changelog_rows(repo_path) _, _, rows = _changelog_rows(repo_path)
return len(rows) return len(rows)
from openpyxl.styles import Font, PatternFill
repo_wb, repo_ws, repo_rows = _changelog_rows(repo_path) repo_wb, repo_ws, repo_rows = _changelog_rows(repo_path)
_, _, local_rows = _changelog_rows(local_path) _, _, local_rows = _changelog_rows(local_path)
seen = set(repo_rows) seen = set(repo_rows)
@ -245,16 +273,26 @@ def merge_changelog(local_path, repo_path):
seen.add(row) seen.add(row)
added += 1 added += 1
merged.sort(key=lambda r: r[0]) # chronological by Date (column A) merged.sort(key=lambda r: r[0]) # chronological by Date (column A)
if repo_ws.max_row > 1: # rewrite data rows, keep the header n = len(CHANGELOG_HEADERS)
repo_ws.delete_rows(2, repo_ws.max_row - 1) desc_col = CHANGELOG_HEADERS.index("Description") + 1
s = Side(style="thin", color="BFBFBF") s = Side(style="thin", color="BFBFBF")
border = Border(left=s, right=s, top=s, bottom=s) border = Border(left=s, right=s, top=s, bottom=s)
if repo_ws.max_row > 1: # clear everything, rewrite header + rows
repo_ws.delete_rows(1, repo_ws.max_row)
for c, h in enumerate(CHANGELOG_HEADERS, start=1): # canonical header (migrates 5->6 cols)
cell = repo_ws.cell(1, c, h)
cell.font = Font(name="Calibri", bold=True)
cell.fill = PatternFill("solid", fgColor="B6D7A8")
cell.border = border
cell.alignment = Alignment(horizontal="center", vertical="center")
for row in merged: for row in merged:
repo_ws.append(list(row)) rr = repo_ws.max_row + 1
rr = repo_ws.max_row for c in range(1, n + 1):
for c in range(1, 6): cell = repo_ws.cell(rr, c, row[c - 1] if c - 1 < len(row) else "")
repo_ws.cell(rr, c).border = border cell.border = border
repo_ws.cell(rr, c).alignment = Alignment(vertical="center", wrap_text=(c == 5), horizontal="left") cell.alignment = Alignment(vertical="center", wrap_text=(c == desc_col), horizontal="left")
repo_wb.freeze_panes = None
repo_ws.freeze_panes = "A2"
repo_wb.save(repo_path) repo_wb.save(repo_path)
return added return added
@ -297,7 +335,10 @@ def cmd_push_skill(env, args):
if os.path.exists(repo_cl): # sync merged history back to local if os.path.exists(repo_cl): # sync merged history back to local
shutil.copy(repo_cl, local_cl) shutil.copy(repo_cl, local_cl)
print(f"changelog: merged (+{added} new row(s)) into the skill repo's CHANGELOG.xlsx") print(f"changelog: merged (+{added} new row(s)) into the skill repo's CHANGELOG.xlsx")
commit_push(tmp, env.get("GIT_TOKEN", ""), args.message or "library-manager: sync skill files + changelog") name, email = _operator(args)
commit_push(tmp, env.get("GIT_TOKEN", ""),
args.message or f"library-manager: sync skill files + changelog{_by(name)}",
author=(name, email))
def cmd_pull_skill(env, args): def cmd_pull_skill(env, args):
@ -338,12 +379,14 @@ def main():
p.add_argument("--typeid", required=True); p.add_argument("--root"); p.add_argument("--local") p.add_argument("--typeid", required=True); p.add_argument("--root"); p.add_argument("--local")
p = sub.add_parser("commit-push"); p.add_argument("--root", required=True) p = sub.add_parser("commit-push"); p.add_argument("--root", required=True)
p.add_argument("--message") p.add_argument("--message"); p.add_argument("--author", help="'Name <email>' of the operator")
p = sub.add_parser("push-part"); p.add_argument("--folder", required=True) p = sub.add_parser("push-part"); p.add_argument("--folder", required=True)
p.add_argument("--typeid", required=True); p.add_argument("--message") p.add_argument("--typeid", required=True); p.add_argument("--message")
p.add_argument("--author", help="'Name <email>' of the operator (who added the part)")
p = sub.add_parser("push-skill") p = sub.add_parser("push-skill")
p.add_argument("--author", help="'Name <email>' of the operator (who made the change)")
p.add_argument("--src", default=os.path.join(os.path.dirname(__file__), ".."), p.add_argument("--src", default=os.path.join(os.path.dirname(__file__), ".."),
help="skill directory to push (defaults to this skill)") help="skill directory to push (defaults to this skill)")
p.add_argument("--message") p.add_argument("--message")