@vegastack/skills 0.6.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -0
- package/package.json +1 -1
- package/skill/dev-implement/SKILL.md +62 -0
- package/skill/dev-implement/agents/openai.yaml +4 -0
- package/skill/dev-implement/refresh/REFRESH.md +3 -0
- package/skill/dev-implement/refresh/sources.json +6 -0
- package/skill/dev-intake/SKILL.md +62 -0
- package/skill/dev-intake/agents/openai.yaml +4 -0
- package/skill/dev-intake/references/brief-template.md +56 -0
- package/skill/dev-intake/refresh/REFRESH.md +3 -0
- package/skill/dev-intake/refresh/sources.json +6 -0
- package/skill/dev-setup/SKILL.md +65 -0
- package/skill/dev-setup/agents/openai.yaml +4 -0
- package/skill/dev-setup/assets/agents-section.md.template +9 -0
- package/skill/dev-setup/assets/dev-profile.md.template +24 -0
- package/skill/dev-setup/references/harness-facts.md +22 -0
- package/skill/dev-setup/refresh/REFRESH.md +13 -0
- package/skill/dev-setup/refresh/sources.json +152 -0
- package/skill/dev-ship/SKILL.md +33 -0
- package/skill/dev-ship/agents/openai.yaml +4 -0
- package/skill/dev-ship/refresh/REFRESH.md +3 -0
- package/skill/dev-ship/refresh/sources.json +6 -0
- package/skill/skill-maintainer/SKILL.md +9 -10
- package/skill/skill-maintainer/references/release-ops.md +1 -1
- package/skill/skill-maintainer/refresh/REFRESH.md +1 -1
- package/skill/skillify/SKILL.md +38 -48
- package/skill/skillify/assets/templates/REFRESH.md.template +5 -10
- package/skill/skillify/assets/templates/SKILL.md.template +1 -0
- package/skill/skillify/assets/templates/skill.test.ts.template +11 -24
- package/skill/skillify/assets/templates/sources.json.template +1 -1
- package/skill/skillify/assets/templates/trigger-queries.json.template +1 -0
- package/skill/skillify/references/authoring.md +20 -14
- package/skill/skillify/refresh/REFRESH.md +1 -1
- package/skill/skillify/scripts/scaffold-skill.mjs +75 -17
- package/skill-integrity.json +48 -11
|
@@ -9,7 +9,7 @@ Maintenance skill for this repository. Every change under `skills/` must satisfy
|
|
|
9
9
|
|
|
10
10
|
## Operating rules
|
|
11
11
|
|
|
12
|
-
1. Skill content lives only in `skills/<name>/`. Wiring lives outside it: the packaging allowlist in `packages/cli/
|
|
12
|
+
1. Skill content lives only in `skills/<name>/`. Wiring lives outside it: the per-skill packaging allowlist in `packages/cli/packaging.json`, the root `README.md` skills table, and `CHANGELOG.md` (via changesets). The skillify scaffolder writes all three when creating a skill.
|
|
13
13
|
2. Frontmatter is exactly two keys: `name` and `description`. The open spec also allows `license`, `compatibility`, and `metadata`, but this repo defaults to the minimal two; adding any other key is a policy exception needing maintainer sign-off.
|
|
14
14
|
3. `name` must equal the directory name. Grammar: starts with a lowercase letter, then only lowercase letters, digits, and hyphens; no leading/trailing hyphen, no consecutive hyphens; at most 64 chars.
|
|
15
15
|
4. `description`: at most 1024 chars, third person, states WHAT the skill does and WHEN to load it, trigger words front-loaded, no angle brackets. Never summarize the workflow in it — agents follow the summary and skip the body. Err slightly pushy: agents under-trigger.
|
|
@@ -23,29 +23,28 @@ Maintenance skill for this repository. Every change under `skills/` must satisfy
|
|
|
23
23
|
| Need | Read |
|
|
24
24
|
|---|---|
|
|
25
25
|
| tri-harness standards: discovery paths, frontmatter rules, context budgets, install surfaces, portability rules, unverified items | [standards](references/standards.md) |
|
|
26
|
+
| new skill: should-it-exist gate, scaffolding, the 8-item contract audit, behavioral evals | the `skillify` skill |
|
|
26
27
|
| release, rename, deprecate, rollback mechanics | [release ops](references/release-ops.md) |
|
|
27
28
|
| this skill's own freshness contract | [REFRESH](refresh/REFRESH.md), [sources](refresh/sources.json) |
|
|
28
29
|
| authoritative repo policy | `CONTRIBUTING.md`, `docs/policies/content-versioning.md`, `docs/policies/release-and-rollback.md` at the repo root |
|
|
29
30
|
|
|
30
31
|
## Workflow: scaffold a new skill
|
|
31
32
|
|
|
32
|
-
1.
|
|
33
|
-
2. Write frontmatter and body per operating rules 2–6; the body routes to references, it does not inline them.
|
|
34
|
-
3.
|
|
35
|
-
4.
|
|
36
|
-
5. Seed refresh baselines with the deterministic runner, never by hand — invocation in [REFRESH](refresh/REFRESH.md).
|
|
37
|
-
6. Run the checks in operating rule 8.
|
|
33
|
+
1. Run skillify's `scripts/scaffold-skill.mjs` — it creates the contract tree (`SKILL.md`, `README.md`, `refresh/`, `agents/openai.yaml`, tests and the trigger fixture) and performs the repo wiring itself: the `packages/cli/packaging.json` entry, the root README row, and the changeset (a new skill is MINOR). Fill in the README row description and changeset text it leaves as TODOs; files added after scaffolding go into the skill's `packaging.json` entry by hand (the build fails loudly on unlisted files).
|
|
34
|
+
2. Write frontmatter and body per operating rules 2–6; the body routes to references, it does not inline them. `skillify` owns the full authoring and eval discipline.
|
|
35
|
+
3. Seed refresh baselines with the deterministic runner, never by hand — invocation in [REFRESH](refresh/REFRESH.md).
|
|
36
|
+
4. Run the checks in operating rule 8.
|
|
38
37
|
|
|
39
38
|
## Workflow: update or maintain
|
|
40
39
|
|
|
41
|
-
- **
|
|
40
|
+
- **Content versioning.** New rules/references and new recorded decisions are MINOR; weakening a normative rule, removing or renaming a skill, or breaking a per-project profile format is MAJOR; factual refreshes (pins, URLs, checksums) are PATCH (`docs/policies/content-versioning.md`).
|
|
42
41
|
- **Tag volatile claims.** Any sentence carrying a vendor version, mechanism name, or numeric budget gets a source marker comment mapping to an ID in that skill's `refresh/sources.json`, and the registry entry's `affected` list must name the reference it lives in. Untagged volatile facts rot silently.
|
|
43
42
|
- **Description budgets.** Stay within 1024 chars and keep triggers in the first sentence: Codex truncates its skill list at 2% of the context window / 8,000 chars, Claude Code truncates a skill's always-loaded listing at 1,536 chars — the tail of a long description is the first thing lost.
|
|
44
|
-
- **Packaged-file changes.** Any add/remove/rename of a packaged file must update
|
|
43
|
+
- **Packaged-file changes.** Any add/remove/rename of a packaged file must update that skill's `packages/cli/packaging.json` entry in the same PR.
|
|
45
44
|
|
|
46
45
|
## Workflow: rename, deprecate, or remove
|
|
47
46
|
|
|
48
|
-
Full playbook in [release ops](references/release-ops.md). Short form: a rename changes the directory and the frontmatter `name` in the same commit (they must stay equal), updates
|
|
47
|
+
Full playbook in [release ops](references/release-ops.md). Short form: a rename changes the directory and the frontmatter `name` in the same commit (they must stay equal), updates the packaging.json entry + root README table + CHANGELOG, and is MAJOR. Deprecation is announced in README/CHANGELOG before removal. Removal deletes the tree, unwires it, and is MAJOR.
|
|
49
48
|
|
|
50
49
|
## Workflow: release
|
|
51
50
|
|
|
@@ -43,7 +43,7 @@ Contributors do not bump versions in PRs; releases are maintainer-driven.
|
|
|
43
43
|
Skill names are consumer-facing identifiers — treat a rename as a stable-ID break:
|
|
44
44
|
|
|
45
45
|
1. Rename the directory and the frontmatter `name` in the same commit — they must always stay equal.
|
|
46
|
-
2. Update every wiring point in the same PR: the
|
|
46
|
+
2. Update every wiring point in the same PR: the skill's entry in `packages/cli/packaging.json`, the root README skills table row, and any cross-skill or docs links.
|
|
47
47
|
3. Changeset: MAJOR. Note the migration in `CHANGELOG.md`: copies installed under the old name are orphaned, and installer operations addressed to the old name stop resolving once the shipped manifest no longer knows it.
|
|
48
48
|
4. Registry source IDs inside `refresh/sources.json` are skill-internal and unaffected, but every `affected` ref must still resolve to a real reference in the renamed tree.
|
|
49
49
|
5. Re-run `node packages/cli/scripts/validate-skill.mjs skills/<new-name>` and the skill's tests — name/directory equality is validated.
|
|
@@ -5,7 +5,7 @@ Instructions for the scheduled refresh agent (and any human running a manual ref
|
|
|
5
5
|
## What this skill claims
|
|
6
6
|
|
|
7
7
|
- **Durable content** (`SKILL.md` workflows and operating rules, `references/release-ops.md`): repo process, derived from `docs/policies/*` — the refresh agent NEVER edits these. If a policy doc changes, that is a normal human PR, not a refresh.
|
|
8
|
-
- **
|
|
8
|
+
- **Volatile standards claims**: sentences marked `<!-- source: SOURCE-ID -->` inside `references/standards.md`. These carry the tri-harness standards — discovery paths, frontmatter rules, numeric context budgets, install surfaces. They are the compliance basis of every skill in this repo, so **all standards changes are semantic drift requiring a human-reviewed PR**: the agent may propose edits to marked sentences only, in the same PR as the registry update that evidences the change, and a maintainer must review before merge. The hard-limits table in `SKILL.md` mirrors several marked sentences; update it in the same PR (this is the one sanctioned SKILL.md touch, and only when a mirrored number changed).
|
|
9
9
|
- **Volatile layer** (the only file the agent edits freely): `refresh/sources.json` — the source registry and staleness snapshot (checksums, retrieval times).
|
|
10
10
|
|
|
11
11
|
## How to refresh
|
package/skill/skillify/SKILL.md
CHANGED
|
@@ -5,27 +5,22 @@ description: Repo-local skill factory and auditor for the vegastack-skills monor
|
|
|
5
5
|
|
|
6
6
|
# Skillify
|
|
7
7
|
|
|
8
|
-
Turn a raw workflow into a properly-skilled unit of this monorepo, or audit an existing `skills/<name>/` tree against the
|
|
8
|
+
Turn a raw workflow into a properly-skilled unit of this monorepo, or audit an existing `skills/<name>/` tree against the repo contract (CONTRIBUTING.md, "Adding a new skill"). Skillify is repo-only: it creates and scores skills in this repository, not anywhere else. Deep wiring/release mechanics belong to `skill-maintainer`; cross-reference it rather than restating it.
|
|
9
9
|
|
|
10
|
-
## The
|
|
10
|
+
## The contract checklist
|
|
11
11
|
|
|
12
|
-
Score every item pass / fail / N/A. N/A requires a one-line rationale; N/A without one is a fail.
|
|
12
|
+
Score every item pass / fail / N/A. N/A requires a one-line rationale; N/A without one is a fail. Numbering is stable and additive — future items append, existing items never renumber — so other skills can cite "skillify item 6".
|
|
13
13
|
|
|
14
|
-
1. **SKILL.md spec-compliant** — frontmatter is exactly `name` + `description`; name matches the directory and the grammar (starts with a lowercase letter, `[a-z0-9-]`, no consecutive hyphens, max 64); description max 1024 chars with no angle brackets; body
|
|
15
|
-
2. **Description triggers well** — states triggering conditions only (never the workflow), third person, trigger words front-loaded, per [authoring](references/authoring.md); a
|
|
16
|
-
3. **
|
|
17
|
-
4. **References routed** — `references/`
|
|
18
|
-
5. **Scripts deterministic** — dependency-free Node under `scripts/`, `--json` for machine output, documented exit codes, atomic writes and symlink refusal for anything mutating;
|
|
19
|
-
6. **
|
|
20
|
-
7. **
|
|
21
|
-
8. **
|
|
22
|
-
9. **Behavioral eval evidence** — with-skill vs baseline subagent runs on 2–3 realistic prompts per the [eval playbook](references/eval-playbook.md); summary in the PR body; unresolved gaps in a KNOWN_GAPS section of the skill's README.
|
|
23
|
-
10. **Refresh contract** — `refresh/sources.json` + `refresh/REFRESH.md` tracking every volatile claim; or an explicit evergreen waiver in REFRESH.md stating why nothing in the skill decays.
|
|
24
|
-
11. **Codex metadata** — `agents/openai.yaml`.
|
|
25
|
-
12. **Repo wiring** — sync-skill allowlist entry, root README table row, CHANGELOG entry (`skill-maintainer` owns the detail).
|
|
26
|
-
13. **Green check** — `bun run check` passes.
|
|
14
|
+
1. **SKILL.md spec-compliant** — frontmatter is exactly `name` + `description`; name matches the directory and the grammar (starts with a lowercase letter, `[a-z0-9-]`, no consecutive hyphens, max 64); description max 1024 chars with no angle brackets; body targets 50–150 lines with 300 as the ceiling; no harness-specific body syntax. `bun run validate:skill` agrees — it also verifies every relative link in the skill's prose resolves.
|
|
15
|
+
2. **Description triggers well** — states triggering conditions only (never the workflow), third person, trigger words front-loaded, per [authoring](references/authoring.md); a query set of realistic positives and near-miss negatives exists at `tests/fixtures/trigger-queries.json`, with `ambiguous_with` naming the nearest competing skill where one exists.
|
|
16
|
+
3. **Sharp boundary** — the SKILL.md body names its nearest-neighbor skill and the one-sentence axis of difference (or states it has no neighbor). Two skills answering the same trigger get merged, not shipped.
|
|
17
|
+
4. **References routed** — `references/` holds detail only some invocations need, behind a routing table; SKILL.md keeps the workflow, one excellent example, and the routes. N/A for a self-contained skill.
|
|
18
|
+
5. **Scripts deterministic and tested** — dependency-free Node under `scripts/`, `--json` for machine output, documented exit codes, atomic writes and symlink refusal for anything mutating, dry-run default; unit tests cover every deterministic branch. N/A when the skill ships no scripts — a prose-only skill needs no test theater; its quality bar is item 6.
|
|
19
|
+
6. **Behavioral eval passed** — with-skill vs baseline subagent runs on 2–3 realistic prompts per the [eval playbook](references/eval-playbook.md), at most 3 improve cycles; pass, or ship with a KNOWN_GAPS section in the skill's README.
|
|
20
|
+
7. **Freshness honest** — volatile facts (version pins, model names, numeric limits, dated claims) live in refresh-tracked files, never in SKILL.md; a skill with none states a one-line evergreen waiver in `refresh/REFRESH.md`.
|
|
21
|
+
8. **Wired and green** — README walkthrough and `agents/openai.yaml` exist; packaging entry, root README row, and changeset are in place (the scaffolder performs these); `bun run check` passes.
|
|
27
22
|
|
|
28
|
-
**Verdict:** all pass → `properly skilled`. At most
|
|
23
|
+
**Verdict:** all pass → `properly skilled`. At most two misses, neither item 1 nor item 6 → `close — create: <missing items>`. Otherwise → `needs skillify — run skillify on <target>`. Always report the score as `<passed>/8` plus the verdict.
|
|
29
24
|
|
|
30
25
|
## Phase 0 — Should this be a skill?
|
|
31
26
|
|
|
@@ -37,6 +32,8 @@ Before anything else, check:
|
|
|
37
32
|
|
|
38
33
|
If any answer is no: it is a script or a doc, not a skill. Stop — do not scaffold, do not write a SKILL.md. Say why and move on.
|
|
39
34
|
|
|
35
|
+
Then search the existing skills. If one nearly covers the intent, **prefer merging into it** over creating a near-duplicate — a new neighbor that splits an existing trigger family makes both skills trigger worse.
|
|
36
|
+
|
|
40
37
|
Scope upper bound: **one skill = one capability = one coherent trigger family.** If the target spans distinct intents users would invoke separately ("run the build" / "roll back the deploy" / "notify the team" are three intents), do not build one skill covering them all. Propose the split and ask which target to skillify first.
|
|
41
38
|
|
|
42
39
|
## Phase 1 — Audit
|
|
@@ -45,30 +42,22 @@ For an existing skill, score the checklist against the actual tree and stop with
|
|
|
45
42
|
|
|
46
43
|
```
|
|
47
44
|
Skill: <name> Path: skills/<name>/
|
|
48
|
-
Score: <passed>/
|
|
45
|
+
Score: <passed>/8 Verdict: <verdict>
|
|
49
46
|
Missing: <item>: <one-line evidence> ...
|
|
50
47
|
```
|
|
51
48
|
|
|
52
|
-
For a new skill the audit is trivially 0/
|
|
49
|
+
For a new skill the audit is trivially 0/8 — proceed. When the request was only "audit" / "is this complete", deliver the verdict and the shortest path to `properly skilled`; do not start editing unasked.
|
|
53
50
|
|
|
54
51
|
## Phase 2 — Elicit requirements
|
|
55
52
|
|
|
56
53
|
Interview before writing (skip questions the conversation already answers):
|
|
57
54
|
|
|
58
|
-
- **Triggers:** what exact phrases should invoke this? What near-miss requests should NOT? (These become the query set.)
|
|
55
|
+
- **Triggers:** what exact phrases should invoke this? What near-miss requests should NOT? Which existing skill is the nearest neighbor? (These become the query set and the boundary line.)
|
|
59
56
|
- **Output:** what does done look like — files, report shape, side effects?
|
|
60
57
|
- **Edge cases:** empty input, missing config, offline, partial state?
|
|
61
58
|
- **Existing behavior:** is there code/prose to absorb? What did its author correct over time?
|
|
62
59
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
| Class | Meaning | Where it lives |
|
|
66
|
-
|---|---|---|
|
|
67
|
-
| Durable | versionless principle | references prose; refresh never edits |
|
|
68
|
-
| Mechanism-coupled | durable intent through a vendor-named mechanism | marked `<!-- source: SOURCE-ID -->`; edited only with registry evidence |
|
|
69
|
-
| Volatile | version pins, limits, model names, URLs | `refresh/sources.json` entries or refresh-tracked files only |
|
|
70
|
-
|
|
71
|
-
Every mechanism-coupled or volatile claim needs a registry source — or the skill declares an evergreen waiver. No unclassified claims ship.
|
|
60
|
+
While eliciting, mark every volatile fact the skill will state — version pins, model names, numeric limits, dated claims. Those go to refresh-tracked files (item 7); everything else is plain prose. A skill with no volatile facts takes the one-line evergreen waiver.
|
|
72
61
|
|
|
73
62
|
## Phase 3 — Scaffold and write
|
|
74
63
|
|
|
@@ -79,13 +68,12 @@ node <skill-dir>/scripts/scaffold-skill.mjs <name> --dir <repo-root>
|
|
|
79
68
|
node <skill-dir>/scripts/scaffold-skill.mjs <name> --dir <repo-root> --write
|
|
80
69
|
```
|
|
81
70
|
|
|
82
|
-
The scaffolder validates the name grammar, refuses existing directories and symlinks, stages in a temp sibling then renames, and
|
|
71
|
+
The scaffolder validates the name grammar, refuses existing directories and symlinks, stages in a temp sibling then renames, and performs the repo wiring itself (packaging entry, root README row, changeset) — fill in the README row's TODO description. Then write, in this order:
|
|
83
72
|
|
|
84
|
-
1. *Description + trigger query set* — engineer the description per [authoring](references/authoring.md); write
|
|
85
|
-
2. *SKILL.md body* — workflow, one excellent example, routing table. Respect the token budgets in [authoring](references/authoring.md).
|
|
73
|
+
1. *Description + trigger query set* — engineer the description per [authoring](references/authoring.md); write the query set with near-miss negatives into `tests/fixtures/trigger-queries.json`.
|
|
74
|
+
2. *SKILL.md body* — workflow, one excellent example, nearest-neighbor boundary line, routing table. Respect the writing-style rules and token budgets in [authoring](references/authoring.md).
|
|
86
75
|
3. *References* — detail that only some invocations need.
|
|
87
76
|
4. *Scripts* — only for work that is deterministic and repeated (criteria in [authoring](references/authoring.md)).
|
|
88
|
-
5. *Draft tests* — but do not treat them as the quality bar yet; that is Phase 4's job.
|
|
89
77
|
|
|
90
78
|
## Phase 4 — Behavioral eval — the quality gate
|
|
91
79
|
|
|
@@ -99,10 +87,9 @@ Iterate at most 3 cycles: eval → apply the top improvements to the skill → r
|
|
|
99
87
|
|
|
100
88
|
Now that quality is proven:
|
|
101
89
|
|
|
102
|
-
1.
|
|
103
|
-
2. Write `refresh/sources.json` + `refresh/REFRESH.md`
|
|
104
|
-
3. Finish `README.md` and `agents/openai.yaml
|
|
105
|
-
4. Wire the repo: sync-skill allowlist, root README row, CHANGELOG entry — as printed by the scaffolder; `skill-maintainer` documents each step in depth.
|
|
90
|
+
1. Write unit tests for the deterministic branches of any bundled scripts, plus fixtures. A prose-only skill keeps just its trigger-query fixture.
|
|
91
|
+
2. Write `refresh/sources.json` + `refresh/REFRESH.md` for the volatile facts marked in Phase 2 — or the one-line evergreen waiver.
|
|
92
|
+
3. Finish `README.md` and `agents/openai.yaml`; fill in the wiring TODOs the scaffolder left (README row description, changeset text).
|
|
106
93
|
|
|
107
94
|
## Phase 6 — Verify
|
|
108
95
|
|
|
@@ -112,23 +99,24 @@ bun test skills/<name>
|
|
|
112
99
|
bun run check
|
|
113
100
|
```
|
|
114
101
|
|
|
115
|
-
Re-score the checklist and report `<passed>/
|
|
102
|
+
Re-score the checklist and report `<passed>/8` with the verdict. Anything below `properly skilled` ships only with named gaps.
|
|
116
103
|
|
|
117
104
|
## Worked example: skillifying a "release-notes" workflow
|
|
118
105
|
|
|
119
106
|
```
|
|
120
|
-
Phase 0: yes — run at every release, ~80 lines of conventions, trigger "draft the release notes"
|
|
121
|
-
|
|
107
|
+
Phase 0: yes — run at every release, ~80 lines of conventions, trigger "draft the release notes";
|
|
108
|
+
nearest neighbor is skill-maintainer (release wiring) — different axis, proceed
|
|
109
|
+
Phase 1: 0/8 (new)
|
|
122
110
|
Phase 2: triggers "draft/write the release notes", NOT "write a changelog entry for this PR";
|
|
123
|
-
output = CHANGELOG section + npm summary;
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
111
|
+
output = CHANGELOG section + npm summary; volatile: none owned → evergreen waiver
|
|
112
|
+
Phase 3: scaffold-skill.mjs release-notes --dir . --write (wiring done by the scaffolder);
|
|
113
|
+
description + 10 trigger queries incl. ambiguous_with skill-maintainer; body + references/format.md;
|
|
114
|
+
no scripts (judgment-heavy, item 5 N/A)
|
|
127
115
|
Phase 4: eval cycle 1 — baseline subagent invents section headings, with-skill misses breaking-change
|
|
128
116
|
callouts → add callout contract to SKILL.md; cycle 2 — with-skill clearly better, baseline still
|
|
129
117
|
wrong shape → pass
|
|
130
|
-
Phase 5:
|
|
131
|
-
Phase 6: bun run check green;
|
|
118
|
+
Phase 5: trigger fixture locked; evergreen waiver written; README row description filled in
|
|
119
|
+
Phase 6: bun run check green; 8/8 → properly skilled
|
|
132
120
|
```
|
|
133
121
|
|
|
134
122
|
## Anti-patterns
|
|
@@ -141,14 +129,16 @@ Phase 6: bun run check green; 13/13 → properly skilled
|
|
|
141
129
|
- Version pins or model names in SKILL.md — volatile facts live in refresh-tracked locations.
|
|
142
130
|
- Multi-intent skills spanning unrelated triggers — split them.
|
|
143
131
|
- Two skills answering the same trigger — merge or kill one.
|
|
144
|
-
-
|
|
132
|
+
- Steering by prohibition — a wall of NEVERs drags the forbidden behavior into context and grows forever; state the positive rule once and explain why it matters.
|
|
133
|
+
- Patching every observed agent failure with a new clause — that is sediment; rewrite the existing rule in place instead of appending case law.
|
|
134
|
+
- Unit tests for prose — a test asserting a markdown file contains a phrase proves nothing the eval didn't.
|
|
145
135
|
- Building eval tooling — evals are instructions you run with subagents, not code you write.
|
|
146
136
|
|
|
147
137
|
## Routing
|
|
148
138
|
|
|
149
139
|
| Need | Read |
|
|
150
140
|
|---|---|
|
|
151
|
-
| description engineering, numeric limits, token budgets, script-vs-instructions,
|
|
141
|
+
| description engineering, writing style, numeric limits, token budgets, script-vs-instructions, volatile facts | [authoring](references/authoring.md) |
|
|
152
142
|
| eval method, pass criteria, trigger-query doctrine, cycle protocol, KNOWN_GAPS, model guidance | [eval playbook](references/eval-playbook.md) |
|
|
153
143
|
| the scaffolded starting points | `assets/templates/` |
|
|
154
144
|
| skillify's own freshness stance | [refresh/REFRESH.md](refresh/REFRESH.md) |
|
|
@@ -4,18 +4,13 @@ Instructions for the scheduled refresh agent (and any human running a manual ref
|
|
|
4
4
|
|
|
5
5
|
## What this skill claims
|
|
6
6
|
|
|
7
|
-
TODO:
|
|
7
|
+
TODO: apply the volatile-facts rule (skillify references/authoring.md) before shipping:
|
|
8
8
|
|
|
9
9
|
- **Durable rules**: versionless principles in this skill's prose. The refresh agent NEVER edits these; if a source change invalidates one, open an issue quoting the evidence.
|
|
10
|
-
- **
|
|
11
|
-
- **Volatile layer**: `refresh/sources.json` itself (checksums, versions, retrieval times) — the only file the agent edits freely.
|
|
10
|
+
- **Volatile facts**: version pins, model names, numeric vendor limits, URLs, dated claims. Each lives in a refresh-tracked file named here, evidenced by a `sources.json` entry. A sentence leaning on one vendor mechanism may be marked `<!-- source: SOURCE-ID -->`.
|
|
12
11
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
TODO: if this skill has NO mechanism-coupled or volatile claims, replace the sources TODO in `sources.json` with this waiver, filled in: "This skill's content is evergreen: it asserts no version pins, vendor mechanism names, numeric vendor limits, or dated facts. Rationale: ... Revisit if a future edit introduces any." Then delete the refresh steps below. Otherwise delete this section.
|
|
12
|
+
TODO: name the refresh-tracked files and the sections the refresh agent may edit.
|
|
16
13
|
|
|
17
|
-
##
|
|
14
|
+
## Evergreen waiver
|
|
18
15
|
|
|
19
|
-
|
|
20
|
-
2. TODO: what may be auto-accepted vs what needs human review.
|
|
21
|
-
3. One PR per refresh, evidence-linked; refresh branches touch only `refresh/` metadata.
|
|
16
|
+
TODO: if this skill states no volatile facts, replace everything above with one line — "Evergreen: this skill asserts no version pins, vendor mechanism names, numeric vendor limits, or dated facts. Revisit if a future edit introduces any." — and keep `sources: []`.
|
|
@@ -11,6 +11,7 @@ TODO: one-paragraph overview - what this skill guarantees and the single trigger
|
|
|
11
11
|
|
|
12
12
|
- TODO: concrete situations and user phrasings
|
|
13
13
|
- TODO: when NOT to use - the nearest adjacent intent and where it goes instead
|
|
14
|
+
- Nearest neighbor: TODO - name the closest existing skill and the one-sentence axis of difference (or state that none exists)
|
|
14
15
|
|
|
15
16
|
## Workflow
|
|
16
17
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { describe, expect, test } from 'bun:test'
|
|
2
|
-
import {
|
|
2
|
+
import { readFileSync } from 'node:fs'
|
|
3
3
|
import { join, resolve } from 'node:path'
|
|
4
4
|
import { validateSkill } from '../../../packages/cli/scripts/validate-skill.mjs'
|
|
5
5
|
|
|
@@ -12,29 +12,16 @@ describe('{{name}} contract', () => {
|
|
|
12
12
|
expect(result.ok).toBe(true)
|
|
13
13
|
})
|
|
14
14
|
|
|
15
|
-
test('
|
|
16
|
-
const
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
.map(line => line.split(':')[0])
|
|
23
|
-
expect(keys.sort()).toEqual(['description', 'name'])
|
|
15
|
+
test('trigger query fixture is a small hard set with near-miss negatives', () => {
|
|
16
|
+
const queries = JSON.parse(readFileSync(join(skillRoot, 'tests/fixtures/trigger-queries.json'), 'utf8'))
|
|
17
|
+
const positives = queries.filter((entry: { should_trigger: boolean }) => entry.should_trigger)
|
|
18
|
+
const negatives = queries.filter((entry: { should_trigger: boolean }) => !entry.should_trigger)
|
|
19
|
+
expect(positives.length).toBeGreaterThanOrEqual(5)
|
|
20
|
+
expect(negatives.length).toBeGreaterThanOrEqual(4)
|
|
21
|
+
for (const entry of queries) expect(typeof entry.query).toBe('string')
|
|
24
22
|
})
|
|
25
23
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
for (const match of body.matchAll(/\]\(([^)#\s]+)\)/g)) {
|
|
30
|
-
const target = match[1]
|
|
31
|
-
if (/^[a-z][a-z0-9+.-]*:/.test(target)) continue
|
|
32
|
-
expect(`${file} -> ${target}: ${existsSync(join(skillRoot, target))}`).toBe(`${file} -> ${target}: true`)
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
})
|
|
36
|
-
|
|
37
|
-
// TODO: add unit tests for every deterministic branch of scripts/, plus the
|
|
38
|
-
// consistency test (prose, scripts, templates, and registry agree). Lock in
|
|
39
|
-
// eval-proven behavior only AFTER the behavioral eval passes (skillify Phase 4).
|
|
24
|
+
// TODO: if this skill ships scripts/, add unit tests for every deterministic
|
|
25
|
+
// branch. A prose-only skill needs nothing more here - its quality bar is the
|
|
26
|
+
// behavioral eval of skillify Phase 4, which runs BEFORE tests lock anything in.
|
|
40
27
|
})
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
3
|
"retrievalBaseline": "{{date}}",
|
|
4
|
-
"note": "TODO: add one entry per volatile
|
|
4
|
+
"note": "TODO: add one entry per volatile external fact this skill states (see skillify references/authoring.md, volatile facts), or record the one-line evergreen waiver in REFRESH.md and keep sources empty.",
|
|
5
5
|
"sources": []
|
|
6
6
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
[]
|
|
@@ -12,11 +12,22 @@ The description is the primary triggering mechanism: it is always in context, an
|
|
|
12
12
|
- **Cover the ways users actually ask.** Exact phrases in quotes, symptoms, file types, adjacent phrasings, casual variants. Include the situations where the skill competes with a neighbor and should win.
|
|
13
13
|
- **Name the boundary.** One clause on what the skill is NOT for prevents over-triggering ("Only for skills inside this repository...").
|
|
14
14
|
- **No angle brackets** — the repo validator rejects them.
|
|
15
|
+
- **No `#` after a space.** The description is an unquoted YAML scalar, and real harness parsers treat ` #` as a comment start — everything after it silently vanishes from the skill listing. Write "issue 12", never "issue #12"; the repo validator rejects it.
|
|
15
16
|
|
|
16
17
|
Bad: `Helps with skills.` (no triggers, no boundary)
|
|
17
|
-
Bad: `Audits a skill by scoring
|
|
18
|
+
Bad: `Audits a skill by scoring checklist items, then scaffolds, evals, and wires it.` (workflow summary — the body will be skipped)
|
|
18
19
|
Good: `Use when asked to "skillify this", "make this a skill", audit a skill's completeness, or decide whether a workflow should become a skill. Only for skills inside this repository.`
|
|
19
20
|
|
|
21
|
+
## Writing style
|
|
22
|
+
|
|
23
|
+
Rules for the prose itself — they exist because agents pay attention (and tokens) for every sentence, and because rule corpora rot in predictable ways:
|
|
24
|
+
|
|
25
|
+
- **Prompt the positive.** Steering by prohibition drags the forbidden behavior into context and invites a wall of NEVERs that only ever grows. State the rule you want followed, once, with the reason it matters. Reserve negation for genuinely dangerous acts.
|
|
26
|
+
- **Explain why, not ALL-CAPS what.** Modern models have good theory of mind; a rule with its reason generalizes, a bare MUST gets pattern-matched and misapplied. Reaching for caps or bold on every rule is a sign the rule needs a reason, not emphasis.
|
|
27
|
+
- **Hunt no-ops and sediment.** A no-op is an instruction the model already obeys by default — it pays load to say nothing. Sediment is case law: a clause added for one past failure that never gets removed. When a failure exposes a gap, rewrite the existing rule in place; do not append an exception. Prune by deleting whole sentences, not trimming words.
|
|
28
|
+
- **Budget the body.** Target 50–150 lines for a SKILL.md; treat 300 as the ceiling (the spec's 500 is a far bound, not a budget). One great example beats five mediocre ones. Anything only some invocations need goes behind a routed reference.
|
|
29
|
+
- **Name the nearest neighbor.** One sentence in the body stating which existing skill is closest and the axis of difference. It keeps trigger families sharp better than any linter, and forces the merge conversation before a near-duplicate ships.
|
|
30
|
+
|
|
20
31
|
## Numeric limits
|
|
21
32
|
|
|
22
33
|
<!-- mirrored: these numbers are volatile and mirrored from the standards sources tracked by the skill-maintainer registry; on drift, fix them there first, then here. -->
|
|
@@ -32,10 +43,11 @@ Good: `Use when asked to "skillify this", "make this a skill", audit a skill's c
|
|
|
32
43
|
|
|
33
44
|
## Trigger query sets
|
|
34
45
|
|
|
35
|
-
Every skill ships `tests/fixtures/trigger-queries.json`: an array of `{"query": "...", "should_trigger": true|false}
|
|
46
|
+
Every skill ships `tests/fixtures/trigger-queries.json`: an array of `{"query": "...", "should_trigger": true|false}`, with an optional `"ambiguous_with": ["skill-name"]` on entries where a neighboring skill competes for the query.
|
|
36
47
|
|
|
37
|
-
-
|
|
38
|
-
-
|
|
48
|
+
- About 10 queries total: 5–6 should-trigger, 4–5 should-NOT-trigger. A small set of hard queries beats a long set of easy ones.
|
|
49
|
+
- Should-trigger: different phrasings of the same intent — formal, casual, typo-ridden; cases that never name the skill but clearly need it; at least one `ambiguous_with` case this skill should win against its nearest neighbor.
|
|
50
|
+
- Should-NOT-trigger: **near-misses only.** Queries sharing keywords or domain with the skill but needing something else — adjacent intents, ambiguous phrasing a naive keyword match would catch. "Write a fibonacci function" as a negative for a PDF skill tests nothing.
|
|
39
51
|
- Queries must be realistic: concrete detail, file paths, a little backstory — what a user would actually type, not abstract category labels.
|
|
40
52
|
|
|
41
53
|
The set is both a design artifact (it forces the description to draw a real boundary) and eval input (see the [eval playbook](eval-playbook.md)).
|
|
@@ -48,7 +60,7 @@ Three loading levels; spend accordingly:
|
|
|
48
60
|
2. **SKILL.md body** — loaded on every trigger. Keep the workflow, one excellent example, and a routing table; push everything else down a level. One great example beats five mediocre ones.
|
|
49
61
|
3. **references/ / scripts/ / assets/** — loaded or executed on demand; effectively unlimited, but give each reference a clear routing condition so agents read only what the task needs.
|
|
50
62
|
|
|
51
|
-
Cross-reference other skills by name (`skill-maintainer`) instead of restating their content. Don't document a script's flags in prose beyond what routing needs — the script's own `--help`/usage error is the source of truth
|
|
63
|
+
Cross-reference other skills by name (`skill-maintainer`) instead of restating their content. Don't document a script's flags in prose beyond what routing needs — the script's own `--help`/usage error is the source of truth.
|
|
52
64
|
|
|
53
65
|
## Scripts vs instructions
|
|
54
66
|
|
|
@@ -59,14 +71,8 @@ Cross-reference other skills by name (`skill-maintainer`) instead of restating t
|
|
|
59
71
|
- Repo conventions for bundled scripts: dependency-free Node (`.mjs`), runnable from the skill dir with plain relative paths, `--json` for machine-readable output, documented exit codes (0 ok / 1 finding-or-refusal / 2 usage), atomic writes (stage then rename), symlink refusal, and an explicit `--write` gate for anything mutating — dry-run is the default.
|
|
60
72
|
- Do NOT script judgment: descriptions, verdicts, review prose. A script that fakes judgment produces confident garbage.
|
|
61
73
|
|
|
62
|
-
##
|
|
63
|
-
|
|
64
|
-
Classify every factual claim while writing, not after:
|
|
74
|
+
## Volatile facts and refresh
|
|
65
75
|
|
|
66
|
-
|
|
67
|
-
|---|---|---|
|
|
68
|
-
| **Durable** | still true if every vendor renames everything | plain prose; refresh automation never touches it |
|
|
69
|
-
| **Mechanism-coupled** | durable intent expressed through a vendor-named mechanism (an option name, an API shape) | mark the sentence `<!-- source: SOURCE-ID -->`; editable only alongside registry evidence for that source |
|
|
70
|
-
| **Volatile** | version pins, numeric limits, model names, URLs, anything with a date | lives in `refresh/sources.json` entries or other refresh-tracked files — never inline in SKILL.md |
|
|
76
|
+
One rule: **version pins, model names, numeric limits, URLs, and anything with a date live in refresh-tracked files — never inline in SKILL.md.** Everything else is plain prose that refresh automation never touches.
|
|
71
77
|
|
|
72
|
-
|
|
78
|
+
A volatile fact gets a `refresh/sources.json` entry (URL, checksum, threshold) and lives in a section the REFRESH.md names as editable; marking an individual sentence `<!-- source: SOURCE-ID -->` remains available when a durable rule leans on one vendor-named mechanism. A skill with no volatile facts of its own declares an **evergreen waiver** in REFRESH.md — one line stating why nothing decays — and keeps `sources: []`. Facts whose source of truth already lives in another skill's registry are mirrored with a `<!-- mirrored -->` marker, not duplicated as a second registry entry.
|
|
@@ -4,7 +4,7 @@ Instructions for the scheduled refresh agent (and any human running a manual ref
|
|
|
4
4
|
|
|
5
5
|
## What this skill claims
|
|
6
6
|
|
|
7
|
-
- **Durable rules** (SKILL.md, most of `references/`): the phase model, checklist structure, eval-before-tests ordering, description doctrine,
|
|
7
|
+
- **Durable rules** (SKILL.md, most of `references/`): the phase model, checklist structure, eval-before-tests ordering, description doctrine, the volatile-facts rule. Versionless; the refresh agent NEVER edits these. If external evidence invalidates one, open an issue quoting the evidence — do not edit.
|
|
8
8
|
- **Mirrored volatile claims**: skillify does not track its own external sources. Its two volatile spots are marked in place:
|
|
9
9
|
- the numeric limits and harness listing budgets table in `references/authoring.md` (marked `<!-- mirrored -->`);
|
|
10
10
|
- the model guidance section in `references/eval-playbook.md` (marked `<!-- volatile -->`).
|
|
@@ -4,10 +4,11 @@
|
|
|
4
4
|
// node scripts/scaffold-skill.mjs <skill-name> --dir <repo-root> [--write] [--json]
|
|
5
5
|
//
|
|
6
6
|
// Dry-run by default: prints the plan (files that would be created plus the
|
|
7
|
-
//
|
|
8
|
-
// in a temporary sibling inside skills/ and renames it into place,
|
|
9
|
-
// existing directories and symlinks
|
|
10
|
-
//
|
|
7
|
+
// wiring actions that would be performed) and creates nothing. --write stages
|
|
8
|
+
// the tree in a temporary sibling inside skills/ and renames it into place,
|
|
9
|
+
// refusing existing directories and symlinks, then performs the repo wiring
|
|
10
|
+
// itself: packaging.json entry, root README row, changeset. Exit codes: 0 ok,
|
|
11
|
+
// 1 refusal or failure, 2 usage error.
|
|
11
12
|
import { lstat, mkdir, mkdtemp, readFile, rename, rm, writeFile } from 'node:fs/promises'
|
|
12
13
|
import { dirname, join, resolve } from 'node:path'
|
|
13
14
|
import { fileURLToPath } from 'node:url'
|
|
@@ -22,9 +23,14 @@ export const templateFiles = [
|
|
|
22
23
|
['sources.json.template', 'refresh/sources.json'],
|
|
23
24
|
['REFRESH.md.template', 'refresh/REFRESH.md'],
|
|
24
25
|
['openai.yaml.template', 'agents/openai.yaml'],
|
|
26
|
+
// Scaffolded empty so the shape test stays red until real queries are written.
|
|
27
|
+
['trigger-queries.json.template', 'tests/fixtures/trigger-queries.json'],
|
|
25
28
|
['skill.test.ts.template', null],
|
|
26
29
|
]
|
|
27
30
|
|
|
31
|
+
// The scaffolded files that ship to installers (README and tests never package).
|
|
32
|
+
const defaultPackagedFiles = ['SKILL.md', 'agents/openai.yaml', 'refresh/REFRESH.md', 'refresh/sources.json']
|
|
33
|
+
|
|
28
34
|
// Full grammar shared by the repo validator and every target harness: starts
|
|
29
35
|
// with a lowercase letter, then lowercase letters/digits/hyphens, no
|
|
30
36
|
// consecutive hyphens, no trailing hyphen, at most 64 characters.
|
|
@@ -38,14 +44,6 @@ export function validateName(name) {
|
|
|
38
44
|
return null
|
|
39
45
|
}
|
|
40
46
|
|
|
41
|
-
export function wiringSteps(name) {
|
|
42
|
-
return [
|
|
43
|
-
`Add skills/${name}/ packaged files to the allowlist in packages/cli/scripts/sync-skill.mjs (the build fails loudly on unlisted files)`,
|
|
44
|
-
`Add a ${name} row to the Skills table in the root README.md`,
|
|
45
|
-
`Add a CHANGELOG entry (changeset) introducing ${name}`,
|
|
46
|
-
]
|
|
47
|
-
}
|
|
48
|
-
|
|
49
47
|
async function entryAt(path) {
|
|
50
48
|
try {
|
|
51
49
|
return await lstat(path)
|
|
@@ -54,6 +52,66 @@ async function entryAt(path) {
|
|
|
54
52
|
}
|
|
55
53
|
}
|
|
56
54
|
|
|
55
|
+
async function writeAtomic(path, body) {
|
|
56
|
+
const staging = `${path}.scaffold-tmp`
|
|
57
|
+
await writeFile(staging, body)
|
|
58
|
+
await rename(staging, path)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Adds the new skill's entry to packages/cli/packaging.json with the default
|
|
62
|
+
// scaffolded runtime files. Extra authored files added later must be appended
|
|
63
|
+
// there by hand — sync-skill.mjs still fails loudly on anything unlisted.
|
|
64
|
+
async function wirePackaging(repoRoot, name, write) {
|
|
65
|
+
const path = join(repoRoot, 'packages/cli/packaging.json')
|
|
66
|
+
if (!(await entryAt(path))?.isFile()) return { step: 'packaging.json entry', status: 'skipped: packages/cli/packaging.json not found' }
|
|
67
|
+
const packaged = JSON.parse(await readFile(path, 'utf8'))
|
|
68
|
+
if (name in packaged) return { step: 'packaging.json entry', status: 'skipped: entry already exists' }
|
|
69
|
+
if (!write) return { step: 'packaging.json entry', status: 'planned' }
|
|
70
|
+
packaged[name] = defaultPackagedFiles
|
|
71
|
+
const sorted = Object.fromEntries(Object.keys(packaged).sort().map(key => [key, packaged[key]]))
|
|
72
|
+
await writeAtomic(path, `${JSON.stringify(sorted, null, 2)}\n`)
|
|
73
|
+
return { step: 'packaging.json entry', status: 'done' }
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Inserts a row for the new skill at the end of the root README's Skills table.
|
|
77
|
+
async function wireReadme(repoRoot, name, write) {
|
|
78
|
+
const path = join(repoRoot, 'README.md')
|
|
79
|
+
if (!(await entryAt(path))?.isFile()) return { step: 'root README row', status: 'skipped: README.md not found' }
|
|
80
|
+
const body = await readFile(path, 'utf8')
|
|
81
|
+
if (body.includes(`](skills/${name}/)`)) return { step: 'root README row', status: 'skipped: row already exists' }
|
|
82
|
+
const lines = body.split('\n')
|
|
83
|
+
const header = lines.findIndex(line => /^\| *Skill *\|/.test(line))
|
|
84
|
+
if (header < 0 || !/^\|[ -]*---/.test(lines[header + 1] ?? '')) {
|
|
85
|
+
return { step: 'root README row', status: 'skipped: Skills table not found' }
|
|
86
|
+
}
|
|
87
|
+
let last = header + 1
|
|
88
|
+
while (lines[last + 1]?.startsWith('|')) last += 1
|
|
89
|
+
if (!write) return { step: 'root README row', status: 'planned' }
|
|
90
|
+
const row = `| [${name}](skills/${name}/) | TODO: one-line description | [Walkthrough](skills/${name}/README.md) · [SKILL.md](skills/${name}/SKILL.md) |`
|
|
91
|
+
lines.splice(last + 1, 0, row)
|
|
92
|
+
await writeAtomic(path, lines.join('\n'))
|
|
93
|
+
return { step: 'root README row', status: 'done' }
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Writes the changeset introducing the skill (content versioning: new skill = minor).
|
|
97
|
+
async function wireChangeset(repoRoot, name, write) {
|
|
98
|
+
const directory = join(repoRoot, '.changeset')
|
|
99
|
+
if (!(await entryAt(directory))?.isDirectory()) return { step: 'changeset', status: 'skipped: .changeset/ not found' }
|
|
100
|
+
const path = join(directory, `add-${name}.md`)
|
|
101
|
+
if (await entryAt(path)) return { step: 'changeset', status: 'skipped: changeset already exists' }
|
|
102
|
+
if (!write) return { step: 'changeset', status: 'planned' }
|
|
103
|
+
await writeAtomic(path, `---\n"@vegastack/skills": minor\n---\n\nAdd the ${name} skill.\n`)
|
|
104
|
+
return { step: 'changeset', status: 'done' }
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export async function wireSkill({ name, repoRoot, write = false }) {
|
|
108
|
+
return [
|
|
109
|
+
await wirePackaging(repoRoot, name, write),
|
|
110
|
+
await wireReadme(repoRoot, name, write),
|
|
111
|
+
await wireChangeset(repoRoot, name, write),
|
|
112
|
+
]
|
|
113
|
+
}
|
|
114
|
+
|
|
57
115
|
export async function scaffoldSkill({ name, dir, write = false, now = new Date() }) {
|
|
58
116
|
const nameError = validateName(name)
|
|
59
117
|
if (nameError) throw new Error(`Invalid skill name ${JSON.stringify(name ?? null)}: ${nameError}`)
|
|
@@ -69,8 +127,8 @@ export async function scaffoldSkill({ name, dir, write = false, now = new Date()
|
|
|
69
127
|
if (await entryAt(target)) throw new Error(`Refusing to scaffold: ${target} already exists`)
|
|
70
128
|
|
|
71
129
|
const outputs = templateFiles.map(([source, output]) => [source, output ?? `tests/${name}.test.ts`])
|
|
72
|
-
const plan = { name, target, files: outputs.map(([, output]) => output),
|
|
73
|
-
if (!write) return plan
|
|
130
|
+
const plan = { name, target, files: outputs.map(([, output]) => output), wrote: false }
|
|
131
|
+
if (!write) return { ...plan, wiring: await wireSkill({ name, repoRoot }) }
|
|
74
132
|
|
|
75
133
|
const date = now.toISOString().slice(0, 10)
|
|
76
134
|
const staging = await mkdtemp(join(skillsRoot, `.${name}.scaffold-`))
|
|
@@ -88,7 +146,7 @@ export async function scaffoldSkill({ name, dir, write = false, now = new Date()
|
|
|
88
146
|
await rm(staging, { recursive: true, force: true })
|
|
89
147
|
throw error
|
|
90
148
|
}
|
|
91
|
-
return { ...plan, wrote: true }
|
|
149
|
+
return { ...plan, wrote: true, wiring: await wireSkill({ name, repoRoot, write: true }) }
|
|
92
150
|
}
|
|
93
151
|
|
|
94
152
|
function parseArguments(argv) {
|
|
@@ -128,8 +186,8 @@ if (invokedDirectly) {
|
|
|
128
186
|
} else {
|
|
129
187
|
console.log(result.wrote ? `Created ${result.target}` : `Dry run - pass --write to create ${result.target}`)
|
|
130
188
|
for (const file of result.files) console.log(` ${file}`)
|
|
131
|
-
console.log('
|
|
132
|
-
for (const step of result.wiring) console.log(` - ${step}`)
|
|
189
|
+
console.log('Wiring:')
|
|
190
|
+
for (const { step, status } of result.wiring) console.log(` - ${step}: ${status}`)
|
|
133
191
|
}
|
|
134
192
|
} catch (error) {
|
|
135
193
|
console.error(String(error.message ?? error))
|