@hegemonart/get-design-done 1.59.3 → 1.59.4
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/.claude-plugin/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +1 -1
- package/CHANGELOG.md +31 -0
- package/SKILL.md +2 -0
- package/figma-plugin/README.md +61 -0
- package/figma-plugin/code.ts +36 -0
- package/figma-plugin/manifest.json +12 -0
- package/figma-plugin/package-lock.json +35 -0
- package/figma-plugin/package.json +12 -0
- package/figma-plugin/src/export-variables.ts +144 -0
- package/figma-plugin/src/payload-schema.ts +250 -0
- package/figma-plugin/tsconfig.json +16 -0
- package/figma-plugin/ui.html +44 -0
- package/hooks/gdd-intel-trigger.js +3 -3
- package/package.json +6 -1
- package/reference/DEPRECATIONS.md +3 -3
- package/reference/live-mode-integration.md +1 -1
- package/reference/registry.json +1 -1
- package/reference/skill-metadata.md +4 -4
- package/reference/skill-placeholders.md +2 -2
- package/scripts/build-skills.cjs +146 -0
- package/scripts/generate-skill-frontmatter.cjs +243 -0
- package/scripts/lib/manifest/scaffolder.cjs +1 -1
- package/scripts/lib/manifest/schemas/skills.schema.json +1 -1
- package/scripts/lib/manifest/skills.json +1 -1
- package/scripts/lib/new-addendum.cjs +1 -1
- package/scripts/skill-templates/README.md +90 -0
- package/scripts/skill-templates/add-backlog/SKILL.md +48 -0
- package/scripts/skill-templates/analyze-dependencies/SKILL.md +95 -0
- package/scripts/skill-templates/apply-reflections/SKILL.md +109 -0
- package/scripts/skill-templates/apply-reflections/apply-reflections-procedure.md +170 -0
- package/scripts/skill-templates/audit/SKILL.md +79 -0
- package/scripts/skill-templates/bandit-reset/SKILL.md +91 -0
- package/scripts/skill-templates/bandit-status/SKILL.md +94 -0
- package/scripts/skill-templates/benchmark/SKILL.md +65 -0
- package/scripts/skill-templates/bootstrap-ds/SKILL.md +43 -0
- package/scripts/skill-templates/brief/SKILL.md +145 -0
- package/scripts/skill-templates/budget/SKILL.md +45 -0
- package/scripts/skill-templates/cache-manager/SKILL.md +66 -0
- package/scripts/skill-templates/cache-manager/cache-policy.md +126 -0
- package/scripts/skill-templates/check-update/SKILL.md +98 -0
- package/scripts/skill-templates/compare/SKILL.md +82 -0
- package/scripts/skill-templates/compare/compare-rubric.md +171 -0
- package/scripts/skill-templates/complete-cycle/SKILL.md +81 -0
- package/scripts/skill-templates/connections/SKILL.md +71 -0
- package/scripts/skill-templates/connections/connections-onboarding.md +608 -0
- package/scripts/skill-templates/context/SKILL.md +137 -0
- package/scripts/skill-templates/continue/SKILL.md +24 -0
- package/scripts/skill-templates/darkmode/SKILL.md +76 -0
- package/scripts/skill-templates/darkmode/darkmode-audit-procedure.md +258 -0
- package/scripts/skill-templates/debug/SKILL.md +41 -0
- package/scripts/skill-templates/debug/debug-feedback-loops.md +119 -0
- package/scripts/skill-templates/design/SKILL.md +118 -0
- package/scripts/skill-templates/design/design-procedure.md +304 -0
- package/scripts/skill-templates/discuss/SKILL.md +96 -0
- package/scripts/skill-templates/do/SKILL.md +45 -0
- package/scripts/skill-templates/explore/SKILL.md +118 -0
- package/scripts/skill-templates/explore/explore-procedure.md +267 -0
- package/scripts/skill-templates/export/SKILL.md +30 -0
- package/scripts/skill-templates/extract-learnings/SKILL.md +114 -0
- package/scripts/skill-templates/fast/SKILL.md +91 -0
- package/scripts/skill-templates/figma-extract/SKILL.md +64 -0
- package/scripts/skill-templates/figma-write/SKILL.md +50 -0
- package/scripts/skill-templates/graphify/SKILL.md +49 -0
- package/scripts/skill-templates/health/SKILL.md +99 -0
- package/scripts/skill-templates/health/health-mcp-detection.md +44 -0
- package/scripts/skill-templates/health/health-skill-length-report.md +69 -0
- package/scripts/skill-templates/help/SKILL.md +60 -0
- package/scripts/skill-templates/instinct/SKILL.md +111 -0
- package/scripts/skill-templates/list-assumptions/SKILL.md +61 -0
- package/scripts/skill-templates/list-pins/SKILL.md +27 -0
- package/scripts/skill-templates/live/SKILL.md +98 -0
- package/scripts/skill-templates/locale/SKILL.md +51 -0
- package/scripts/skill-templates/map/SKILL.md +89 -0
- package/scripts/skill-templates/migrate/SKILL.md +70 -0
- package/scripts/skill-templates/migrate-context/SKILL.md +123 -0
- package/scripts/skill-templates/new-addendum/SKILL.md +81 -0
- package/scripts/skill-templates/new-cycle/SKILL.md +37 -0
- package/scripts/skill-templates/new-project/SKILL.md +53 -0
- package/scripts/skill-templates/new-skill/SKILL.md +90 -0
- package/scripts/skill-templates/next/SKILL.md +68 -0
- package/scripts/skill-templates/note/SKILL.md +48 -0
- package/scripts/skill-templates/openrouter-status/SKILL.md +86 -0
- package/scripts/skill-templates/optimize/SKILL.md +97 -0
- package/scripts/skill-templates/override/SKILL.md +86 -0
- package/scripts/skill-templates/paper-write/SKILL.md +54 -0
- package/scripts/skill-templates/pause/SKILL.md +77 -0
- package/scripts/skill-templates/peer-cli-add/SKILL.md +88 -0
- package/scripts/skill-templates/peer-cli-add/peer-cli-protocol.md +161 -0
- package/scripts/skill-templates/peer-cli-customize/SKILL.md +89 -0
- package/scripts/skill-templates/peers/SKILL.md +96 -0
- package/scripts/skill-templates/pencil-write/SKILL.md +54 -0
- package/scripts/skill-templates/pin/SKILL.md +37 -0
- package/scripts/skill-templates/plan/SKILL.md +105 -0
- package/scripts/skill-templates/plan/plan-procedure.md +278 -0
- package/scripts/skill-templates/plant-seed/SKILL.md +48 -0
- package/scripts/skill-templates/pr-branch/SKILL.md +32 -0
- package/scripts/skill-templates/progress/SKILL.md +107 -0
- package/scripts/skill-templates/quality-gate/SKILL.md +90 -0
- package/scripts/skill-templates/quality-gate/threat-modeling.md +101 -0
- package/scripts/skill-templates/quick/SKILL.md +44 -0
- package/scripts/skill-templates/reapply-patches/SKILL.md +32 -0
- package/scripts/skill-templates/recall/SKILL.md +75 -0
- package/scripts/skill-templates/reflect/SKILL.md +85 -0
- package/scripts/skill-templates/reflect/procedures/capability-gap-scan.md +119 -0
- package/scripts/skill-templates/report-issue/SKILL.md +53 -0
- package/scripts/skill-templates/report-issue/report-issue-procedure.md +119 -0
- package/scripts/skill-templates/resume/SKILL.md +93 -0
- package/scripts/skill-templates/review-backlog/SKILL.md +46 -0
- package/scripts/skill-templates/review-decisions/SKILL.md +42 -0
- package/scripts/skill-templates/roi/SKILL.md +54 -0
- package/scripts/skill-templates/rollout-status/SKILL.md +35 -0
- package/scripts/skill-templates/router/SKILL.md +89 -0
- package/scripts/skill-templates/router/capability-gap-emitter.md +65 -0
- package/scripts/skill-templates/router/router-pick-emitter.md +78 -0
- package/scripts/skill-templates/router/router-rules.md +84 -0
- package/scripts/skill-templates/settings/SKILL.md +87 -0
- package/scripts/skill-templates/ship/SKILL.md +48 -0
- package/scripts/skill-templates/sketch/SKILL.md +78 -0
- package/scripts/skill-templates/sketch-wrap-up/SKILL.md +92 -0
- package/scripts/skill-templates/skill-manifest/SKILL.md +79 -0
- package/scripts/skill-templates/spike/SKILL.md +67 -0
- package/scripts/skill-templates/spike-wrap-up/SKILL.md +86 -0
- package/scripts/skill-templates/start/SKILL.md +67 -0
- package/scripts/skill-templates/start/start-procedure.md +115 -0
- package/scripts/skill-templates/state/SKILL.md +106 -0
- package/scripts/skill-templates/stats/SKILL.md +51 -0
- package/scripts/skill-templates/style/SKILL.md +71 -0
- package/scripts/skill-templates/style/style-doc-procedure.md +150 -0
- package/scripts/skill-templates/synthesize/SKILL.md +94 -0
- package/scripts/skill-templates/timeline/SKILL.md +66 -0
- package/scripts/skill-templates/todo/SKILL.md +64 -0
- package/scripts/skill-templates/turn-closeout/SKILL.md +95 -0
- package/scripts/skill-templates/undo/SKILL.md +31 -0
- package/scripts/skill-templates/unlock-decision/SKILL.md +54 -0
- package/scripts/skill-templates/unpin/SKILL.md +31 -0
- package/scripts/skill-templates/update/SKILL.md +56 -0
- package/scripts/skill-templates/using-gdd/SKILL.md +78 -0
- package/scripts/skill-templates/verify/SKILL.md +113 -0
- package/scripts/skill-templates/verify/verify-procedure.md +511 -0
- package/scripts/skill-templates/warm-cache/SKILL.md +81 -0
- package/scripts/skill-templates/watch-authorities/SKILL.md +82 -0
- package/scripts/skill-templates/zoom-out/SKILL.md +26 -0
- package/sdk/cli/commands/build.ts +2 -2
- package/sdk/cli/index.js +2 -2
- package/sdk/cli/index.ts +1 -1
- package/skills/README.md +22 -14
- package/skills/help/SKILL.md +28 -55
- package/skills/new-skill/SKILL.md +5 -5
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8" />
|
|
5
|
+
<style>
|
|
6
|
+
body {
|
|
7
|
+
font-family: Inter, system-ui, sans-serif;
|
|
8
|
+
margin: 0;
|
|
9
|
+
padding: 16px;
|
|
10
|
+
font-size: 12px;
|
|
11
|
+
color: #1a1a1a;
|
|
12
|
+
}
|
|
13
|
+
button {
|
|
14
|
+
width: 100%;
|
|
15
|
+
padding: 10px;
|
|
16
|
+
font-size: 13px;
|
|
17
|
+
font-weight: 600;
|
|
18
|
+
color: #fff;
|
|
19
|
+
background: #18a0fb;
|
|
20
|
+
border: none;
|
|
21
|
+
border-radius: 6px;
|
|
22
|
+
cursor: pointer;
|
|
23
|
+
}
|
|
24
|
+
button:hover {
|
|
25
|
+
background: #0d8de0;
|
|
26
|
+
}
|
|
27
|
+
#status {
|
|
28
|
+
margin-top: 12px;
|
|
29
|
+
min-height: 16px;
|
|
30
|
+
color: #555;
|
|
31
|
+
}
|
|
32
|
+
</style>
|
|
33
|
+
</head>
|
|
34
|
+
<body>
|
|
35
|
+
<button id="export">Export to GDD</button>
|
|
36
|
+
<p id="status">Reads local Figma variables and POSTs them to the GDD receiver on localhost:5179.</p>
|
|
37
|
+
<script>
|
|
38
|
+
document.getElementById('export').onclick = function () {
|
|
39
|
+
document.getElementById('status').textContent = 'Exporting…';
|
|
40
|
+
parent.postMessage({ pluginMessage: { type: 'export' } }, '*');
|
|
41
|
+
};
|
|
42
|
+
</script>
|
|
43
|
+
</body>
|
|
44
|
+
</html>
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* hooks/gdd-intel-trigger.js — D5 (PostToolUse on Edit|Write)
|
|
5
5
|
*
|
|
6
6
|
* On every Edit/Write that touches a design-authoritative surface
|
|
7
|
-
* (skills/**, agents/**, reference/**, skill-templates/**), spawn a
|
|
7
|
+
* (skills/**, agents/**, reference/**, scripts/skill-templates/**), spawn a
|
|
8
8
|
* background, detached refresh of the .design/intel/ store so downstream
|
|
9
9
|
* consumers (router, planner, audits) see the latest extracts without the
|
|
10
10
|
* user paying for a full rebuild on the next /gdd run.
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* camelCase field names (tool_name/toolName, tool_input/toolInput,
|
|
15
15
|
* file_path/filePath/path).
|
|
16
16
|
* 2. If the edited path matches
|
|
17
|
-
* ^(skills|agents|reference|skill-templates)/.*\.(md|json)$
|
|
17
|
+
* ^(skills|agents|reference|scripts/skill-templates)/.*\.(md|json)$
|
|
18
18
|
* (path-separator-agnostic), schedule a background refresh.
|
|
19
19
|
* 3. Otherwise no-op — write {continue:true} and exit 0.
|
|
20
20
|
* 4. Always exit 0. Never block. Never surface errors. Errors only ever
|
|
@@ -55,7 +55,7 @@ const path = require('node:path');
|
|
|
55
55
|
const { spawn } = require('node:child_process');
|
|
56
56
|
|
|
57
57
|
const LOCK_TTL_MS = 5 * 60 * 1000; // 5 minutes
|
|
58
|
-
const TARGET_RE = /^(?:skills|agents|reference|
|
|
58
|
+
const TARGET_RE = /^(?:skills|agents|reference|scripts\/skill-templates)\/.*\.(?:md|json)$/;
|
|
59
59
|
|
|
60
60
|
/**
|
|
61
61
|
* Extract the edited file path + tool name from a PostToolUse payload.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hegemonart/get-design-done",
|
|
3
|
-
"version": "1.59.
|
|
3
|
+
"version": "1.59.4",
|
|
4
4
|
"description": "A design-quality pipeline for AI coding agents: brief, explore, plan, design, and verify UI work against your design system.",
|
|
5
5
|
"author": "Hegemon",
|
|
6
6
|
"homepage": "https://github.com/hegemonart/get-design-done",
|
|
@@ -25,9 +25,13 @@
|
|
|
25
25
|
"docs/i18n/",
|
|
26
26
|
"scripts/lib/",
|
|
27
27
|
"scripts/cli/",
|
|
28
|
+
"scripts/skill-templates/",
|
|
28
29
|
"scripts/install.cjs",
|
|
29
30
|
"scripts/injection-patterns.cjs",
|
|
30
31
|
"scripts/bootstrap.cjs",
|
|
32
|
+
"scripts/build-skills.cjs",
|
|
33
|
+
"scripts/generate-skill-frontmatter.cjs",
|
|
34
|
+
"figma-plugin/",
|
|
31
35
|
"SKILL.md",
|
|
32
36
|
"README.md",
|
|
33
37
|
"CHANGELOG.md",
|
|
@@ -62,6 +66,7 @@
|
|
|
62
66
|
"test:behavior": "node scripts/run-behavior-tests.cjs",
|
|
63
67
|
"typecheck": "tsc --noEmit",
|
|
64
68
|
"codegen:schemas": "node --experimental-strip-types scripts/codegen-schema-types.ts",
|
|
69
|
+
"codegen:schemas:check": "node --experimental-strip-types scripts/codegen-schema-types.ts --check",
|
|
65
70
|
"lint:md": "npx --yes markdownlint-cli2 \"**/*.md\" \"#**/node_modules\" \"#.planning\" \"#.claude\" \"#test/fixtures/baselines\"",
|
|
66
71
|
"lint:links": "npx --yes lychee --no-progress --accept 200,206,403,429 \"**/*.md\" || true",
|
|
67
72
|
"lint:agentskills": "node scripts/lint-agentskills-spec.cjs",
|
|
@@ -31,7 +31,7 @@ the scanner pattern list in lockstep.
|
|
|
31
31
|
## Authoring surfaces
|
|
32
32
|
|
|
33
33
|
- **`skills/` as the authoring source** → **`source/skills/`** (Phase 42, deprecated)
|
|
34
|
-
→ **`skill-templates/`** (v1.58.0, current).
|
|
34
|
+
→ **`skill-templates/`** (v1.58.0) → **`scripts/skill-templates/`** (v1.59, current). Migration:
|
|
35
35
|
|
|
36
36
|
- **Phase 42** introduced multi-harness compilation. Skills moved to `source/skills/` with
|
|
37
37
|
placeholders (`{{command_prefix}}` et al.; see `reference/skill-placeholders.md`) and the
|
|
@@ -43,10 +43,10 @@ the scanner pattern list in lockstep.
|
|
|
43
43
|
tarball via `prepack`. Net: 232 tracked files dropped to 116, with no change to end-user
|
|
44
44
|
install experience (the tarball still ships `skills/` pre-built).
|
|
45
45
|
|
|
46
|
-
Migration for contributors: **edit `skill-templates/`, never `skills/` directly**. After edits,
|
|
46
|
+
Migration for contributors: **edit `scripts/skill-templates/`, never `skills/` directly**. After edits,
|
|
47
47
|
`npm run build:skills` regenerates `skills/` locally (or `npm install` does it automatically).
|
|
48
48
|
`.claude-plugin/plugin.json`'s `"skills": ["./skills/"]` is unchanged - the plugin still loads
|
|
49
|
-
`skills/`, now produced from `skill-templates/`. The `detect-stale-refs.cjs` list is extended to
|
|
49
|
+
`skills/`, now produced from `scripts/skill-templates/`. The `detect-stale-refs.cjs` list is extended to
|
|
50
50
|
emit warnings on lingering `source/skills/` path references.
|
|
51
51
|
|
|
52
52
|
## Scanner scope
|
|
@@ -9,7 +9,7 @@ last_updated: 2026-06-03
|
|
|
9
9
|
|
|
10
10
|
# Live Mode Integration
|
|
11
11
|
|
|
12
|
-
This file is the meta-rules companion to the `gdd-live` skill (`skill-templates/live/SKILL.md`). It describes how `/gdd:live` turns a running dev server into a live design surface: the user picks a DOM element, the agent generates N variants in one batch, the variants hot-swap in place, the user accepts or discards, and the whole session persists. For the SKILL.md structural contract (line cap, description budget, frontmatter), see `./skill-authoring-contract.md`. The variants themselves are grounded in the Phase 45 domain indexes (`./spatial.md`, `./interaction.md`, `./color.md`, `./typography.md`, `./motion.md`).
|
|
12
|
+
This file is the meta-rules companion to the `gdd-live` skill (`scripts/skill-templates/live/SKILL.md`). It describes how `/gdd:live` turns a running dev server into a live design surface: the user picks a DOM element, the agent generates N variants in one batch, the variants hot-swap in place, the user accepts or discards, and the whole session persists. For the SKILL.md structural contract (line cap, description budget, frontmatter), see `./skill-authoring-contract.md`. The variants themselves are grounded in the Phase 45 domain indexes (`./spatial.md`, `./interaction.md`, `./color.md`, `./typography.md`, `./motion.md`).
|
|
13
13
|
|
|
14
14
|
There is NO bundled browser automation. The skill drives the Claude Preview MCP at runtime; the modules under `scripts/lib/live/` are pure and dependency-free.
|
|
15
15
|
|
package/reference/registry.json
CHANGED
|
@@ -1071,7 +1071,7 @@
|
|
|
1071
1071
|
"path": "reference/skill-placeholders.md",
|
|
1072
1072
|
"type": "meta-rules",
|
|
1073
1073
|
"phase": 42,
|
|
1074
|
-
"description": "Multi-harness skill-placeholder catalogue: the four placeholders ({{command_prefix}}/{{model}}/{{config_file}}/{{ask_instruction}}) + per-harness substitution table + the \\{{...}} escape + the <!-- harness-only: a,b --> block rule. Skills authored once in skill-templates/, compiled per-harness by scripts/build-skills.cjs via scripts/lib/build/factory.cjs reading scripts/lib/manifest/harnesses.json."
|
|
1074
|
+
"description": "Multi-harness skill-placeholder catalogue: the four placeholders ({{command_prefix}}/{{model}}/{{config_file}}/{{ask_instruction}}) + per-harness substitution table + the \\{{...}} escape + the <!-- harness-only: a,b --> block rule. Skills authored once in scripts/skill-templates/, compiled per-harness by scripts/build-skills.cjs via scripts/lib/build/factory.cjs reading scripts/lib/manifest/harnesses.json."
|
|
1075
1075
|
},
|
|
1076
1076
|
{
|
|
1077
1077
|
"name": "color",
|
|
@@ -10,7 +10,7 @@ last_updated: 2026-06-02
|
|
|
10
10
|
# Skill Metadata Single Source of Truth
|
|
11
11
|
|
|
12
12
|
`scripts/lib/manifest/skills.json` is the one place skill frontmatter is authored. A
|
|
13
|
-
generator projects it onto every `skill-templates/<id>/SKILL.md`, the build step compiles
|
|
13
|
+
generator projects it onto every `scripts/skill-templates/<id>/SKILL.md`, the build step compiles
|
|
14
14
|
those into the shipped trees, and CI gates keep the three copies identical. This doc
|
|
15
15
|
explains the file, the generator, and the description budget. For the structural rules a
|
|
16
16
|
SKILL.md body must follow (line cap, progressive disclosure, frontmatter required fields),
|
|
@@ -20,7 +20,7 @@ see `./skill-authoring-contract.md`.
|
|
|
20
20
|
|
|
21
21
|
The file is a JSON object: a `schema_version` integer and a `skills` array. Each array
|
|
22
22
|
element is one skill record. Only `name` is required (it must equal the
|
|
23
|
-
`skill-templates/<id>/` directory name); every other field is optional and omitted when it
|
|
23
|
+
`scripts/skill-templates/<id>/` directory name); every other field is optional and omitted when it
|
|
24
24
|
has no value.
|
|
25
25
|
|
|
26
26
|
```json
|
|
@@ -50,7 +50,7 @@ Metadata flows in one direction, and a `*:check` gate guards each hop:
|
|
|
50
50
|
```text
|
|
51
51
|
skills.json
|
|
52
52
|
-> generate-skill-frontmatter (npm run generate:skill-frontmatter)
|
|
53
|
-
-> skill-templates/<id>/SKILL.md
|
|
53
|
+
-> scripts/skill-templates/<id>/SKILL.md
|
|
54
54
|
-> build:skills (npm run build:skills)
|
|
55
55
|
-> skills/ + dist/claude-code/
|
|
56
56
|
```
|
|
@@ -64,7 +64,7 @@ skills.json
|
|
|
64
64
|
- `--check`: the CI drift gate. It writes nothing and exits non-zero when any committed
|
|
65
65
|
frontmatter differs from what the manifest would generate.
|
|
66
66
|
|
|
67
|
-
`scripts/build-skills.cjs` then propagates `skill-templates/` into the committed `skills/`
|
|
67
|
+
`scripts/build-skills.cjs` then propagates `scripts/skill-templates/` into the committed `skills/`
|
|
68
68
|
tree and `dist/claude-code/`; its own check mode asserts that the built output equals the
|
|
69
69
|
committed output. So the contract is: edit `skills.json`, regenerate, build. Never
|
|
70
70
|
hand-edit a managed frontmatter line in `SKILL.md`, because the drift gate will fail.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Skill Placeholders - Multi-Harness Source Compilation
|
|
2
2
|
|
|
3
|
-
> Phase 42. Skills are authored once in `skill-templates/` with placeholders and compiled per-harness into
|
|
3
|
+
> Phase 42. Skills are authored once in `scripts/skill-templates/` with placeholders and compiled per-harness into
|
|
4
4
|
> `dist/<bundle>/<config-dir>/skills/...` by `scripts/build-skills.cjs` (the pure transform lives in
|
|
5
5
|
> `scripts/lib/build/factory.cjs`; the per-harness values in `scripts/lib/build/harness-configs.cjs`,
|
|
6
6
|
> which reads the Phase 41.5 manifest root `scripts/lib/manifest/harnesses.json`). The Claude-Code
|
|
@@ -68,4 +68,4 @@ scope (a maintenance trap) - see the Phase 42 CONTEXT.
|
|
|
68
68
|
## Validation
|
|
69
69
|
|
|
70
70
|
`test/suite/phase-42-placeholders.test.cjs` asserts that every placeholder actually used across
|
|
71
|
-
`skill-templates/` is documented in this file, and that `skill-templates/` mirrors the `skills/` skill count.
|
|
71
|
+
`scripts/skill-templates/` is documented in this file, and that `scripts/skill-templates/` mirrors the `skills/` skill count.
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
// Phase 42 — multi-harness skill build orchestrator.
|
|
3
|
+
// v1.58.0 renamed source/skills/ → skill-templates/ (the source/ wrapper held only skills/
|
|
4
|
+
// and added nothing). v1.58.0 ALSO gitignored skills/ as a pure build artifact — that broke
|
|
5
|
+
// the Claude Code marketplace install path (Claude Code git-clones the plugin without running
|
|
6
|
+
// `npm install`, so `./skills/` was absent post-clone). v1.58.1 reverts the gitignore:
|
|
7
|
+
// skills/ is committed again so git-clone-based installs work; scripts/skill-templates/ remains the
|
|
8
|
+
// canonical editable source; `prepare` still regenerates skills/ on contributor checkouts.
|
|
9
|
+
//
|
|
10
|
+
// node scripts/build-skills.cjs [--harness <id>] [--check] [--zip]
|
|
11
|
+
//
|
|
12
|
+
// Reads scripts/skill-templates/**/*.md, applies the pure factory per harness config, and writes:
|
|
13
|
+
// - skills/** (the committed Claude-Code surface, regenerated in place)
|
|
14
|
+
// - dist/<bundleSlug>/<configDir>/skills/** (per-harness bundles; build-only artifacts, gitignored)
|
|
15
|
+
//
|
|
16
|
+
// --check : no writes; verify the committed skills/ equals compile(scripts/skill-templates/),
|
|
17
|
+
// exit 1 on any byte drift. This is the CI drift gate.
|
|
18
|
+
// --harness <id> : restrict to one harness (skips the skills/ in-place regen unless id === claude).
|
|
19
|
+
// --zip : after building, tar -czf dist/<bundleSlug>.tgz each bundle (graceful skip if tar absent).
|
|
20
|
+
//
|
|
21
|
+
// Idempotent + byte-stable: file walk is sorted; bytes are written verbatim (line endings preserved).
|
|
22
|
+
|
|
23
|
+
const fs = require('fs');
|
|
24
|
+
const path = require('path');
|
|
25
|
+
const { spawnSync } = require('child_process');
|
|
26
|
+
const { compile } = require('./lib/build/factory.cjs');
|
|
27
|
+
const { CONFIGS, byId, claude } = require('./lib/build/harness-configs.cjs');
|
|
28
|
+
|
|
29
|
+
const ROOT = path.resolve(__dirname, '..');
|
|
30
|
+
const SRC = path.join(ROOT, 'scripts', 'skill-templates');
|
|
31
|
+
const SKILLS = path.join(ROOT, 'skills');
|
|
32
|
+
const DIST = path.join(ROOT, 'dist');
|
|
33
|
+
|
|
34
|
+
function parseArgs(argv) {
|
|
35
|
+
const out = { check: false, zip: false, harness: null };
|
|
36
|
+
for (let i = 0; i < argv.length; i++) {
|
|
37
|
+
const a = argv[i];
|
|
38
|
+
if (a === '--check') out.check = true;
|
|
39
|
+
else if (a === '--zip') out.zip = true;
|
|
40
|
+
else if (a === '--harness') out.harness = argv[++i];
|
|
41
|
+
else if (a.startsWith('--harness=')) out.harness = a.slice('--harness='.length);
|
|
42
|
+
}
|
|
43
|
+
return out;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function walkMd(dir) {
|
|
47
|
+
const out = [];
|
|
48
|
+
for (const e of fs.readdirSync(dir, { withFileTypes: true }).sort((x, y) => x.name.localeCompare(y.name))) {
|
|
49
|
+
const p = path.join(dir, e.name);
|
|
50
|
+
if (e.isDirectory()) out.push(...walkMd(p));
|
|
51
|
+
else if (e.isFile() && e.name.endsWith('.md')) out.push(p);
|
|
52
|
+
}
|
|
53
|
+
return out;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** Compile every source file for one config -> Map<relPath, string>. */
|
|
57
|
+
function compileAll(config) {
|
|
58
|
+
const result = new Map();
|
|
59
|
+
for (const abs of walkMd(SRC)) {
|
|
60
|
+
const rel = path.relative(SRC, abs).split(path.sep).join('/');
|
|
61
|
+
result.set(rel, compile(fs.readFileSync(abs, 'utf8'), config));
|
|
62
|
+
}
|
|
63
|
+
return result;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function writeMap(map, destRoot) {
|
|
67
|
+
let written = 0;
|
|
68
|
+
for (const [rel, text] of map) {
|
|
69
|
+
const dst = path.join(destRoot, rel.split('/').join(path.sep));
|
|
70
|
+
fs.mkdirSync(path.dirname(dst), { recursive: true });
|
|
71
|
+
fs.writeFileSync(dst, text);
|
|
72
|
+
written++;
|
|
73
|
+
}
|
|
74
|
+
return written;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function bundleDir(config) {
|
|
78
|
+
return path.join(DIST, config.bundleSlug, config.configDir, 'skills');
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** Compare a compiled map against on-disk files under destRoot. Returns array of drifting rel paths. */
|
|
82
|
+
function diffMap(map, destRoot) {
|
|
83
|
+
const drift = [];
|
|
84
|
+
for (const [rel, text] of map) {
|
|
85
|
+
const dst = path.join(destRoot, rel.split('/').join(path.sep));
|
|
86
|
+
let cur = null;
|
|
87
|
+
try { cur = fs.readFileSync(dst, 'utf8'); } catch { /* missing */ }
|
|
88
|
+
if (cur !== text) drift.push(rel);
|
|
89
|
+
}
|
|
90
|
+
return drift;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function runCheck() {
|
|
94
|
+
// v1.58.1: skills/ is committed (reverts v1.58.0 gitignore — Claude Code marketplace
|
|
95
|
+
// git-clones the plugin without running npm install, so `./skills/` MUST exist post-clone).
|
|
96
|
+
// --check is back to its original Phase 42 semantics: gate that committed skills/ matches
|
|
97
|
+
// compile(scripts/skill-templates/). If contributors edit scripts/skill-templates/ without re-running
|
|
98
|
+
// `npm run build:skills`, this catches the drift.
|
|
99
|
+
const cfg = claude();
|
|
100
|
+
const map = compileAll(cfg);
|
|
101
|
+
const driftSkills = diffMap(map, SKILLS);
|
|
102
|
+
if (driftSkills.length) {
|
|
103
|
+
process.stderr.write('build-skills --check: DRIFT detected (run `npm run build:skills` and commit).\n');
|
|
104
|
+
for (const r of driftSkills.slice(0, 10)) process.stderr.write(` skills/${r}\n`);
|
|
105
|
+
if (driftSkills.length > 10) process.stderr.write(' ...\n');
|
|
106
|
+
return 1;
|
|
107
|
+
}
|
|
108
|
+
process.stderr.write(`build-skills --check: OK - skills/ matches scripts/skill-templates/ (${map.size} files).\n`);
|
|
109
|
+
return 0;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function tarBundle(config) {
|
|
113
|
+
const tgz = path.join(DIST, `${config.bundleSlug}.tgz`);
|
|
114
|
+
const r = spawnSync('tar', ['-czf', tgz, '-C', DIST, config.bundleSlug], { stdio: 'ignore' });
|
|
115
|
+
if (r.error || r.status !== 0) {
|
|
116
|
+
process.stderr.write(` (zip skipped for ${config.bundleSlug}: tar unavailable)\n`);
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
return true;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function runBuild(opts) {
|
|
123
|
+
const targets = opts.harness ? [byId(opts.harness)].filter(Boolean) : CONFIGS;
|
|
124
|
+
if (opts.harness && targets.length === 0) {
|
|
125
|
+
process.stderr.write(`build-skills: unknown harness '${opts.harness}'\n`);
|
|
126
|
+
return 1;
|
|
127
|
+
}
|
|
128
|
+
let total = 0;
|
|
129
|
+
for (const cfg of targets) {
|
|
130
|
+
const map = compileAll(cfg);
|
|
131
|
+
total += writeMap(map, bundleDir(cfg));
|
|
132
|
+
if (cfg.id === 'claude') writeMap(map, SKILLS); // regenerate the committed Claude surface in place
|
|
133
|
+
if (opts.zip) tarBundle(cfg);
|
|
134
|
+
process.stderr.write(` built ${cfg.bundleSlug} (${map.size} files)${cfg.id === 'claude' ? ' + skills/' : ''}\n`);
|
|
135
|
+
}
|
|
136
|
+
process.stderr.write(`build-skills: wrote ${total} files across ${targets.length} harness bundle(s).\n`);
|
|
137
|
+
return 0;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function main(argv) {
|
|
141
|
+
const opts = parseArgs(argv);
|
|
142
|
+
return opts.check ? runCheck() : runBuild(opts);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
if (require.main === module) process.exit(main(process.argv.slice(2)));
|
|
146
|
+
module.exports = { main, parseArgs, compileAll, bundleDir };
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
/**
|
|
4
|
+
* generate-skill-frontmatter.cjs — Phase 46 (Skill UX Polish).
|
|
5
|
+
*
|
|
6
|
+
* scripts/lib/manifest/skills.json is the single source of truth for the
|
|
7
|
+
* universal skill frontmatter fields (description, argument-hint, tools,
|
|
8
|
+
* user-invocable, disable-model-invocation). This script regenerates the
|
|
9
|
+
* frontmatter block of every scripts/skill-templates/<name>/SKILL.md from that manifest,
|
|
10
|
+
* preserving the markdown body and any non-managed frontmatter lines verbatim.
|
|
11
|
+
*
|
|
12
|
+
* Direction is forward (manifest -> source frontmatter); build-skills.cjs then
|
|
13
|
+
* propagates scripts/skill-templates -> skills/ + dist/claude-code/. A CI drift gate
|
|
14
|
+
* (--check) keeps committed frontmatter == generated.
|
|
15
|
+
*
|
|
16
|
+
* Modes:
|
|
17
|
+
* (no flag) regenerate scripts/skill-templates/<name>/SKILL.md frontmatter from skills.json
|
|
18
|
+
* --check exit 1 if any committed frontmatter differs from generated (no writes)
|
|
19
|
+
* --extract reverse: read current source frontmatter -> rewrite skills.json
|
|
20
|
+
* (seed/refresh the SoT from ground truth; idempotent with forward)
|
|
21
|
+
*
|
|
22
|
+
* Managed keys (emitted in this canonical order, only when present):
|
|
23
|
+
* name, description, argument-hint, tools, user-invocable, disable-model-invocation
|
|
24
|
+
* Everything else (color, model, writes:, ...) is carried verbatim in the record's
|
|
25
|
+
* `extra_frontmatter` array and re-emitted after the managed block.
|
|
26
|
+
*
|
|
27
|
+
* Exit: 0 ok / 1 drift (--check) / 2 error.
|
|
28
|
+
*/
|
|
29
|
+
const fs = require('fs');
|
|
30
|
+
const path = require('path');
|
|
31
|
+
|
|
32
|
+
const ROOT = path.resolve(__dirname, '..');
|
|
33
|
+
const SRC = path.join(ROOT, 'scripts', 'skill-templates');
|
|
34
|
+
const SKILLS_JSON = path.join(ROOT, 'scripts', 'lib', 'manifest', 'skills.json');
|
|
35
|
+
|
|
36
|
+
// Managed frontmatter keys <-> manifest record keys, in canonical emit order.
|
|
37
|
+
const MANAGED = [
|
|
38
|
+
{ fm: 'name', rec: 'name', kind: 'name' },
|
|
39
|
+
{ fm: 'description', rec: 'description', kind: 'qstr' },
|
|
40
|
+
{ fm: 'argument-hint', rec: 'argument_hint', kind: 'qstr' },
|
|
41
|
+
{ fm: 'tools', rec: 'tools', kind: 'bare' },
|
|
42
|
+
{ fm: 'user-invocable', rec: 'user_invocable', kind: 'bool' },
|
|
43
|
+
{ fm: 'disable-model-invocation', rec: 'disable_model_invocation', kind: 'bool' },
|
|
44
|
+
];
|
|
45
|
+
const MANAGED_FM = new Set(MANAGED.map((m) => m.fm));
|
|
46
|
+
|
|
47
|
+
function fail(msg) {
|
|
48
|
+
process.stderr.write(`generate-skill-frontmatter: ${msg}\n`);
|
|
49
|
+
process.exit(2);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function listSkillDirs() {
|
|
53
|
+
if (!fs.existsSync(SRC)) fail(`source dir not found: ${SRC}`);
|
|
54
|
+
return fs
|
|
55
|
+
.readdirSync(SRC, { withFileTypes: true })
|
|
56
|
+
.filter((e) => e.isDirectory() && fs.existsSync(path.join(SRC, e.name, 'SKILL.md')))
|
|
57
|
+
.map((e) => e.name)
|
|
58
|
+
.sort((a, b) => a.localeCompare(b));
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** Split a SKILL.md into { fmLines, body }. fmLines excludes the --- fences. */
|
|
62
|
+
function splitFrontmatter(text, id) {
|
|
63
|
+
const norm = text.replace(/\r\n/g, '\n');
|
|
64
|
+
if (!norm.startsWith('---\n')) fail(`${id}: SKILL.md does not start with a --- frontmatter fence`);
|
|
65
|
+
const end = norm.indexOf('\n---\n', 4);
|
|
66
|
+
if (end === -1) fail(`${id}: unterminated frontmatter`);
|
|
67
|
+
const fmBlock = norm.slice(4, end + 1); // include trailing \n of last fm line
|
|
68
|
+
const body = norm.slice(end + 5); // after "\n---\n"
|
|
69
|
+
const fmLines = fmBlock.replace(/\n$/, '').split('\n');
|
|
70
|
+
return { fmLines, body };
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function unquote(v) {
|
|
74
|
+
const t = v.trim();
|
|
75
|
+
if (t.length >= 2 && t.startsWith('"') && t.endsWith('"')) {
|
|
76
|
+
return t.slice(1, -1).replace(/\\"/g, '"').replace(/\\\\/g, '\\');
|
|
77
|
+
}
|
|
78
|
+
return t;
|
|
79
|
+
}
|
|
80
|
+
function quote(s) {
|
|
81
|
+
return '"' + String(s).replace(/\\/g, '\\\\').replace(/"/g, '\\"') + '"';
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/** Parse one skill's frontmatter lines into an enriched record. */
|
|
85
|
+
function recordFromFrontmatter(id, fmLines) {
|
|
86
|
+
const rec = { name: id };
|
|
87
|
+
const extra = [];
|
|
88
|
+
let i = 0;
|
|
89
|
+
while (i < fmLines.length) {
|
|
90
|
+
const line = fmLines[i];
|
|
91
|
+
const m = /^([A-Za-z][\w-]*):(.*)$/.exec(line);
|
|
92
|
+
if (!m) {
|
|
93
|
+
// stray non-key line at top level — preserve verbatim
|
|
94
|
+
extra.push(line);
|
|
95
|
+
i += 1;
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
const key = m[1];
|
|
99
|
+
const rawVal = m[2];
|
|
100
|
+
// gather continuation lines (indented or list items or blank-within-block)
|
|
101
|
+
const block = [line];
|
|
102
|
+
let j = i + 1;
|
|
103
|
+
while (j < fmLines.length && /^(\s+\S|\s*-\s|\s*$)/.test(fmLines[j]) && !/^[A-Za-z][\w-]*:/.test(fmLines[j])) {
|
|
104
|
+
block.push(fmLines[j]);
|
|
105
|
+
j += 1;
|
|
106
|
+
}
|
|
107
|
+
const managed = MANAGED.find((mm) => mm.fm === key);
|
|
108
|
+
if (managed && block.length === 1) {
|
|
109
|
+
const v = rawVal.trim();
|
|
110
|
+
if (managed.kind === 'name') {
|
|
111
|
+
if (v !== `gdd-${id}`) rec.frontmatter_name = v;
|
|
112
|
+
} else if (managed.kind === 'bool') {
|
|
113
|
+
rec[managed.rec] = v === 'true';
|
|
114
|
+
} else if (managed.kind === 'qstr') {
|
|
115
|
+
rec[managed.rec] = unquote(v);
|
|
116
|
+
} else {
|
|
117
|
+
rec[managed.rec] = v; // bare (tools)
|
|
118
|
+
}
|
|
119
|
+
} else {
|
|
120
|
+
extra.push(...block);
|
|
121
|
+
}
|
|
122
|
+
i = j;
|
|
123
|
+
}
|
|
124
|
+
if (extra.length) rec.extra_frontmatter = extra;
|
|
125
|
+
return rec;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Emit the frontmatter block (without --- fences) for a record.
|
|
130
|
+
*
|
|
131
|
+
* Order-preserving: `name` always leads, then the managed keys are emitted in
|
|
132
|
+
* the record's own insertion order (which --extract captures from the original
|
|
133
|
+
* file order), then any non-managed lines verbatim. This keeps forward
|
|
134
|
+
* generation a byte-for-byte fixed point on the committed tree, so existing
|
|
135
|
+
* frontmatter-snapshot baselines never churn. New skills authored directly in
|
|
136
|
+
* skills.json get whatever key order their record uses.
|
|
137
|
+
*/
|
|
138
|
+
function frontmatterFromRecord(rec) {
|
|
139
|
+
const out = [`name: ${rec.frontmatter_name || `gdd-${rec.name}`}`];
|
|
140
|
+
const byRec = new Map(MANAGED.filter((m) => m.kind !== 'name').map((m) => [m.rec, m]));
|
|
141
|
+
for (const key of Object.keys(rec)) {
|
|
142
|
+
const m = byRec.get(key);
|
|
143
|
+
if (!m) continue; // name / frontmatter_name / extra_frontmatter / registered_in_phase / aliases / ...
|
|
144
|
+
const v = rec[key];
|
|
145
|
+
if (v === undefined || v === null) continue;
|
|
146
|
+
if (m.kind === 'bool') out.push(`${m.fm}: ${v ? 'true' : 'false'}`);
|
|
147
|
+
else if (m.kind === 'qstr') out.push(`${m.fm}: ${quote(v)}`);
|
|
148
|
+
else out.push(`${m.fm}: ${v}`);
|
|
149
|
+
}
|
|
150
|
+
if (Array.isArray(rec.extra_frontmatter)) out.push(...rec.extra_frontmatter);
|
|
151
|
+
return out.join('\n');
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function readSkillsJson() {
|
|
155
|
+
return JSON.parse(fs.readFileSync(SKILLS_JSON, 'utf8'));
|
|
156
|
+
}
|
|
157
|
+
function recordMap(json) {
|
|
158
|
+
const map = new Map();
|
|
159
|
+
for (const r of json.skills || []) map.set(r.name, r);
|
|
160
|
+
return map;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/** Build the regenerated SKILL.md text for one skill from its record. */
|
|
164
|
+
function renderSkill(id, rec) {
|
|
165
|
+
const abs = path.join(SRC, id, 'SKILL.md');
|
|
166
|
+
const { body } = splitFrontmatter(fs.readFileSync(abs, 'utf8'), id);
|
|
167
|
+
return `---\n${frontmatterFromRecord(rec)}\n---\n${body}`;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
function modeForward(check) {
|
|
171
|
+
const json = readSkillsJson();
|
|
172
|
+
const map = recordMap(json);
|
|
173
|
+
const dirs = listSkillDirs();
|
|
174
|
+
const drift = [];
|
|
175
|
+
let written = 0;
|
|
176
|
+
for (const id of dirs) {
|
|
177
|
+
const rec = map.get(id);
|
|
178
|
+
if (!rec) {
|
|
179
|
+
if (check) { drift.push(`${id} (missing from skills.json)`); continue; }
|
|
180
|
+
fail(`${id}: present in scripts/skill-templates but missing from skills.json — add a record (run --extract)`);
|
|
181
|
+
}
|
|
182
|
+
const abs = path.join(SRC, id, 'SKILL.md');
|
|
183
|
+
const cur = fs.readFileSync(abs, 'utf8').replace(/\r\n/g, '\n');
|
|
184
|
+
const next = renderSkill(id, rec);
|
|
185
|
+
if (cur === next) continue;
|
|
186
|
+
if (check) drift.push(id);
|
|
187
|
+
else { fs.writeFileSync(abs, next); written += 1; }
|
|
188
|
+
}
|
|
189
|
+
// records in skills.json with no source dir (e.g. not yet authored) are tolerated
|
|
190
|
+
if (check) {
|
|
191
|
+
if (drift.length) {
|
|
192
|
+
process.stderr.write(
|
|
193
|
+
`generate-skill-frontmatter --check: ${drift.length} skill(s) drift from skills.json:\n ${drift.slice(0, 20).join('\n ')}\n` +
|
|
194
|
+
`Run \`npm run generate:skill-frontmatter\` then \`npm run build:skills\`.\n`,
|
|
195
|
+
);
|
|
196
|
+
process.exit(1);
|
|
197
|
+
}
|
|
198
|
+
process.stdout.write(`generate-skill-frontmatter --check: OK — ${dirs.length} skills match skills.json.\n`);
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
process.stdout.write(`generate-skill-frontmatter: regenerated ${written}/${dirs.length} skill frontmatter block(s).\n`);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
function modeExtract() {
|
|
205
|
+
const existing = fs.existsSync(SKILLS_JSON) ? readSkillsJson() : { schema_version: 1, skills: [] };
|
|
206
|
+
const prevMap = recordMap(existing);
|
|
207
|
+
const dirs = listSkillDirs();
|
|
208
|
+
const skills = [];
|
|
209
|
+
for (const id of dirs) {
|
|
210
|
+
const { fmLines } = splitFrontmatter(fs.readFileSync(path.join(SRC, id, 'SKILL.md'), 'utf8'), id);
|
|
211
|
+
const rec = recordFromFrontmatter(id, fmLines);
|
|
212
|
+
// preserve curated fields that live only in the manifest (not frontmatter)
|
|
213
|
+
const prev = prevMap.get(id);
|
|
214
|
+
if (prev && prev.registered_in_phase != null) rec.registered_in_phase = prev.registered_in_phase;
|
|
215
|
+
if (prev && prev.aliases != null) rec.aliases = prev.aliases;
|
|
216
|
+
skills.push(rec);
|
|
217
|
+
}
|
|
218
|
+
const out = { schema_version: existing.schema_version || 1 };
|
|
219
|
+
if (existing.note) out.note = existing.note;
|
|
220
|
+
out.skills = skills;
|
|
221
|
+
fs.writeFileSync(SKILLS_JSON, JSON.stringify(out, null, 2) + '\n');
|
|
222
|
+
process.stdout.write(`generate-skill-frontmatter --extract: wrote ${skills.length} enriched records to skills.json.\n`);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
function main(argv) {
|
|
226
|
+
const args = argv.slice(2);
|
|
227
|
+
if (args.includes('--extract')) return modeExtract();
|
|
228
|
+
return modeForward(args.includes('--check'));
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
if (require.main === module) main(process.argv);
|
|
232
|
+
|
|
233
|
+
module.exports = {
|
|
234
|
+
splitFrontmatter,
|
|
235
|
+
recordFromFrontmatter,
|
|
236
|
+
frontmatterFromRecord,
|
|
237
|
+
renderSkill,
|
|
238
|
+
unquote,
|
|
239
|
+
quote,
|
|
240
|
+
MANAGED,
|
|
241
|
+
MANAGED_FM,
|
|
242
|
+
main,
|
|
243
|
+
};
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* scripts/lib/manifest/scaffolder.cjs — Phase 50 (Authoring Contract v3).
|
|
4
4
|
*
|
|
5
5
|
* Pure, dependency-free generator behind the `/gdd:new-skill` scaffolder skill.
|
|
6
|
-
* The SKILL.md (skill-templates/new-skill/SKILL.md) drives the interactive
|
|
6
|
+
* The SKILL.md (scripts/skill-templates/new-skill/SKILL.md) drives the interactive
|
|
7
7
|
* prompts; this module is the deterministic core it (and the test suite) call.
|
|
8
8
|
*
|
|
9
9
|
* Exports:
|
|
@@ -319,7 +319,7 @@
|
|
|
319
319
|
},
|
|
320
320
|
{
|
|
321
321
|
"name": "new-skill",
|
|
322
|
-
"description": "Scaffolds a new Phase-28.5 + Phase-50-compliant skill: gathers a name, a multi-paragraph v3 description, a lifecycle stage, an allowed-tools list, and optional composes_with neighbours, then writes skill-templates/<name>/SKILL.md from the pure generator. Use when adding a brand-new gdd skill and you want the frontmatter, length cap, and v3 description form correct from the first commit. Activates for requests involving authoring a skill, scaffolding a command, creating a new SKILL.md, or adding a slash command.",
|
|
322
|
+
"description": "Scaffolds a new Phase-28.5 + Phase-50-compliant skill: gathers a name, a multi-paragraph v3 description, a lifecycle stage, an allowed-tools list, and optional composes_with neighbours, then writes scripts/skill-templates/<name>/SKILL.md from the pure generator. Use when adding a brand-new gdd skill and you want the frontmatter, length cap, and v3 description form correct from the first commit. Activates for requests involving authoring a skill, scaffolding a command, creating a new SKILL.md, or adding a slash command.",
|
|
323
323
|
"argument_hint": "<skill-name>",
|
|
324
324
|
"tools": "Read, Write, Bash, AskUserQuestion",
|
|
325
325
|
"user_invocable": true,
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* scripts/lib/new-addendum.cjs — Phase 54 (Composable Reference Addendums), REG-01.
|
|
4
4
|
*
|
|
5
5
|
* Pure, dependency-free generator behind the `/gdd:new-addendum <kind> <name>`
|
|
6
|
-
* scaffolder skill (skill-templates/new-addendum/SKILL.md). The SKILL.md drives
|
|
6
|
+
* scaffolder skill (scripts/skill-templates/new-addendum/SKILL.md). The SKILL.md drives
|
|
7
7
|
* the prompts; this module is the deterministic core it (and the test suite)
|
|
8
8
|
* call. Mirrors scripts/lib/manifest/scaffolder.cjs (the Phase 50 skill
|
|
9
9
|
* scaffolder): same ReDoS-safe NAME_RE, same throw-on-invalid contract, same
|