@hegemonart/get-design-done 1.57.1 → 1.57.2
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 +26 -41
- package/.claude-plugin/plugin.json +23 -48
- package/CHANGELOG.md +91 -0
- package/README.md +166 -511
- package/SKILL.md +2 -0
- package/agents/README.md +33 -36
- package/agents/a11y-mapper.md +3 -3
- package/agents/component-benchmark-harvester.md +6 -6
- package/agents/component-benchmark-synthesizer.md +3 -3
- package/agents/compose-executor.md +3 -3
- package/agents/cost-forecaster.md +2 -2
- package/agents/design-auditor.md +7 -7
- package/agents/design-authority-watcher.md +15 -15
- package/agents/design-context-builder.md +4 -4
- package/agents/design-context-checker-gate.md +1 -1
- package/agents/design-discussant.md +2 -2
- package/agents/design-doc-writer.md +1 -1
- package/agents/design-executor.md +2 -2
- package/agents/design-figma-writer.md +2 -2
- package/agents/design-fixer.md +7 -7
- package/agents/design-integration-checker-gate.md +1 -1
- package/agents/design-integration-checker.md +1 -1
- package/agents/design-paper-writer.md +3 -3
- package/agents/design-pencil-writer.md +1 -1
- package/agents/design-planner.md +21 -0
- package/agents/design-reflector.md +39 -39
- package/agents/design-research-synthesizer.md +1 -0
- package/agents/design-start-writer.md +1 -1
- package/agents/design-update-checker.md +5 -5
- package/agents/design-verifier-gate.md +1 -1
- package/agents/design-verifier.md +52 -48
- package/agents/ds-generator.md +2 -2
- package/agents/ds-migration-planner.md +4 -4
- package/agents/email-executor.md +9 -9
- package/agents/experiment-result-ingester.md +3 -3
- package/agents/flutter-executor.md +5 -5
- package/agents/gdd-graph-refresh.md +3 -3
- package/agents/gdd-intel-updater.md +2 -2
- package/agents/motion-mapper.md +2 -2
- package/agents/motion-verifier.md +4 -4
- package/agents/pdf-executor.md +8 -8
- package/agents/perf-analyzer.md +17 -17
- package/agents/pr-commenter.md +9 -9
- package/agents/prototype-gate.md +2 -2
- package/agents/quality-gate-runner.md +1 -1
- package/agents/rollout-coordinator.md +3 -3
- package/agents/swift-executor.md +4 -4
- package/agents/ticket-sync-agent.md +6 -6
- package/agents/user-research-synthesizer.md +2 -2
- package/connections/connections.md +44 -45
- package/connections/cursor.md +73 -0
- package/connections/preview.md +3 -3
- package/dist/claude-code/.claude/skills/cache-manager/SKILL.md +3 -3
- package/dist/claude-code/.claude/skills/cache-manager/cache-policy.md +1 -1
- package/dist/claude-code/.claude/skills/design/SKILL.md +19 -0
- package/dist/claude-code/.claude/skills/explore/SKILL.md +11 -0
- package/dist/claude-code/.claude/skills/figma-write/SKILL.md +13 -2
- package/dist/claude-code/.claude/skills/paper-write/SKILL.md +54 -0
- package/dist/claude-code/.claude/skills/pencil-write/SKILL.md +54 -0
- package/dist/claude-code/.claude/skills/report-issue/SKILL.md +2 -2
- package/dist/claude-code/.claude/skills/router/SKILL.md +2 -2
- package/dist/claude-code/.claude/skills/verify/verify-procedure.md +10 -11
- package/dist/claude-code/.claude/skills/warm-cache/SKILL.md +1 -1
- package/hooks/first-run-nudge.cjs +171 -0
- package/hooks/gdd-intel-trigger.js +243 -0
- package/hooks/gdd-mcp-circuit-breaker.js +62 -7
- package/hooks/gdd-precompact-snapshot.js +50 -29
- package/hooks/gdd-protected-paths.js +150 -18
- package/hooks/gdd-risk-gate.js +93 -1
- package/hooks/gdd-sessionstart-recap.js +59 -24
- package/hooks/hooks.json +13 -4
- package/hooks/inject-using-gdd.cjs +188 -0
- package/hooks/update-check.cjs +511 -0
- package/package.json +9 -2
- package/reference/STATE-TEMPLATE.md +10 -13
- package/reference/audit-scoring.md +1 -1
- package/reference/cache-tier-doctrine.md +46 -0
- package/reference/config-schema.md +9 -9
- package/reference/i18n.md +1 -1
- package/reference/intel-schema.md +37 -2
- package/reference/meta-rules.md +4 -4
- package/reference/model-tiers.md +2 -2
- package/reference/registry.json +101 -94
- package/reference/runtime-models.md +11 -1
- package/reference/shared-preamble.md +13 -14
- package/reference/skill-graph.md +24 -1
- package/scripts/bootstrap.cjs +373 -0
- package/scripts/injection-patterns.cjs +58 -0
- package/scripts/lib/apply-reflections/incubator-proposals.cjs +57 -26
- package/scripts/lib/install/converters/codex-plugin.cjs +5 -2
- package/scripts/lib/install/converters/cursor.cjs +20 -0
- package/scripts/lib/issue-reporter/report-flow.cjs +1 -1
- package/scripts/lib/manifest/skills.json +80 -13
- package/scripts/lib/state/query-surface.cjs +67 -9
- package/scripts/lib/state/state-store.cjs +68 -26
- package/sdk/cli/commands/stage.ts +17 -0
- package/sdk/cli/index.js +14 -0
- package/skills/cache-manager/SKILL.md +3 -3
- package/skills/cache-manager/cache-policy.md +1 -1
- package/skills/design/SKILL.md +19 -0
- package/skills/explore/SKILL.md +11 -0
- package/skills/figma-write/SKILL.md +13 -2
- package/skills/paper-write/SKILL.md +54 -0
- package/skills/pencil-write/SKILL.md +54 -0
- package/skills/report-issue/SKILL.md +2 -2
- package/skills/router/SKILL.md +2 -2
- package/skills/verify/verify-procedure.md +10 -11
- package/skills/warm-cache/SKILL.md +1 -1
- package/hooks/first-run-nudge.sh +0 -82
- package/hooks/inject-using-gdd.sh +0 -72
- package/hooks/update-check.sh +0 -251
- package/scripts/lib/audit-aggregator/index.cjs +0 -219
- package/scripts/lib/hedge-ensemble.cjs +0 -217
|
@@ -1,24 +1,23 @@
|
|
|
1
|
-
// scripts/lib/apply-reflections/incubator-proposals.cjs
|
|
1
|
+
// scripts/lib/apply-reflections/incubator-proposals.cjs
|
|
2
2
|
//
|
|
3
3
|
// Incubator-draft proposal class for /gdd:apply-reflections. Consumes drafts
|
|
4
|
-
// authored by scripts/lib/incubator-author.cjs
|
|
4
|
+
// authored by scripts/lib/incubator-author.cjs at
|
|
5
5
|
// `.design/reflections/incubator/<slug>/` and exposes the 7 actions surfaced
|
|
6
6
|
// in skills/apply-reflections/SKILL.md.
|
|
7
7
|
//
|
|
8
8
|
// Exports: discoverIncubatorDrafts, renderProposal, applyAccept, applyReject,
|
|
9
9
|
// applyEdit, checkStage1Gate, recordOptIn.
|
|
10
10
|
//
|
|
11
|
-
//
|
|
12
|
-
// *
|
|
13
|
-
//
|
|
14
|
-
// *
|
|
15
|
-
//
|
|
16
|
-
// *
|
|
17
|
-
//
|
|
18
|
-
//
|
|
19
|
-
//
|
|
20
|
-
//
|
|
21
|
-
// frontmatter survives the promotion.
|
|
11
|
+
// Invariants:
|
|
12
|
+
// * checkStage1Gate is read-only; recordOptIn is the sole state writer and
|
|
13
|
+
// only fires on explicit user confirmation. No auto-flip ever.
|
|
14
|
+
// * applyAccept performs the full draft → final-artifact write + registry
|
|
15
|
+
// append in one call. No intermediate state.
|
|
16
|
+
// * applyAccept calls validateScope from
|
|
17
|
+
// scripts/validate-incubator-scope.cjs BEFORE any filesystem mutation.
|
|
18
|
+
// Failure throws; registry and incubator subdir untouched. Non-bypassable.
|
|
19
|
+
// * DRAFT.md is copied verbatim, so the drafter's `delegate_to: null`
|
|
20
|
+
// frontmatter survives the promotion.
|
|
22
21
|
//
|
|
23
22
|
// Style: CommonJS, zero external deps (node:fs / node:path / node:child_process /
|
|
24
23
|
// node:os only).
|
|
@@ -31,13 +30,14 @@ const child_process = require('node:child_process');
|
|
|
31
30
|
const os = require('node:os');
|
|
32
31
|
|
|
33
32
|
const { validateScope } = require('../../validate-incubator-scope.cjs');
|
|
33
|
+
const touchesPatternMiner = require('../touches-pattern-miner.cjs');
|
|
34
34
|
|
|
35
35
|
// --- Constants ---
|
|
36
36
|
|
|
37
37
|
const DEFAULT_INCUBATOR_DIR = '.design/reflections/incubator';
|
|
38
38
|
const DEFAULT_REGISTRY_PATH = 'reference/registry.json';
|
|
39
39
|
const DEFAULT_GATE_SPEC_PATH = 'reference/capability-gap-stage-gate.md';
|
|
40
|
-
const DEFAULT_STATE_PATH = '.
|
|
40
|
+
const DEFAULT_STATE_PATH = '.design/STATE.md';
|
|
41
41
|
const OPT_IN_HEADING = '## Capability-gap Stage-1 opt-in';
|
|
42
42
|
const OPT_IN_TOKEN_RE = /Stage-1 opt-in|capability.gap.*opt.in|confirmed_by/i;
|
|
43
43
|
|
|
@@ -94,7 +94,7 @@ function discoverIncubatorDrafts(options) {
|
|
|
94
94
|
const drafts = [];
|
|
95
95
|
for (const ent of entries) {
|
|
96
96
|
if (!ent.isDirectory()) continue;
|
|
97
|
-
if (ent.name === 'archive') continue; //
|
|
97
|
+
if (ent.name === 'archive') continue; // archived drafts not surfaced
|
|
98
98
|
|
|
99
99
|
const slugDir = path.join(incubatorDir, ent.name);
|
|
100
100
|
const manifestPath = path.join(slugDir, 'manifest.json');
|
|
@@ -199,15 +199,15 @@ function renderUnifiedDiff(oldText, newText) {
|
|
|
199
199
|
return out.join('\n');
|
|
200
200
|
}
|
|
201
201
|
|
|
202
|
-
// --- applyAccept
|
|
202
|
+
// --- applyAccept ---
|
|
203
203
|
|
|
204
204
|
/**
|
|
205
|
-
* Promote draft → final artifact + registry entry in one call
|
|
205
|
+
* Promote draft → final artifact + registry entry in one call.
|
|
206
206
|
*
|
|
207
|
-
* Order: validateScope (
|
|
207
|
+
* Order: validateScope (throws → no writes) → read DRAFT.md →
|
|
208
208
|
* [dryRun: return intent] → mkdirp parent → atomic-write target →
|
|
209
209
|
* append-and-atomic-write registry → fs.rm incubator subdir last
|
|
210
|
-
* (so partial failure leaves draft retryable
|
|
210
|
+
* (so partial failure leaves draft retryable).
|
|
211
211
|
*/
|
|
212
212
|
function applyAccept(draft, options) {
|
|
213
213
|
const o = options || {};
|
|
@@ -217,7 +217,7 @@ function applyAccept(draft, options) {
|
|
|
217
217
|
: path.join(repoRoot, o.registryPath || DEFAULT_REGISTRY_PATH);
|
|
218
218
|
const dryRun = !!o.dryRun;
|
|
219
219
|
|
|
220
|
-
// Step 1 —
|
|
220
|
+
// Step 1 — scope guard. THROWS on failure; registry untouched.
|
|
221
221
|
validateScope(draft.target_path, { repoRoot });
|
|
222
222
|
|
|
223
223
|
const draftBody = fs.readFileSync(draft.draft_path, 'utf8');
|
|
@@ -275,7 +275,7 @@ function appendRegistryEntry(registryPath, kind, entry) {
|
|
|
275
275
|
throw new Error(`[incubator-proposals] registry root must be an object: ${registryPath}`);
|
|
276
276
|
}
|
|
277
277
|
|
|
278
|
-
//
|
|
278
|
+
// Self-authoring registry shape: { agents: [...], skills: [...] }.
|
|
279
279
|
// Initialize missing arrays additively so we never clobber another schema's data.
|
|
280
280
|
if (kind === 'agent') {
|
|
281
281
|
if (!Array.isArray(registry.agents)) registry.agents = [];
|
|
@@ -356,10 +356,10 @@ function applyEdit(draft, options) {
|
|
|
356
356
|
}
|
|
357
357
|
}
|
|
358
358
|
|
|
359
|
-
// --- checkStage1Gate (
|
|
359
|
+
// --- checkStage1Gate (read-only) ---
|
|
360
360
|
|
|
361
361
|
/**
|
|
362
|
-
* Read-only Stage-1 gate inspection
|
|
362
|
+
* Read-only Stage-1 gate inspection.
|
|
363
363
|
* thresholdMet = count(registry entries with origin === 'incubator') ≥ K
|
|
364
364
|
* optInRecorded = state file contains an opt-in token
|
|
365
365
|
* summary = human-readable one-liner
|
|
@@ -404,7 +404,7 @@ function checkStage1Gate(options) {
|
|
|
404
404
|
/**
|
|
405
405
|
* Pull `K` out of capability-gap-stage-gate.md. The doc encodes K as a row
|
|
406
406
|
* in a markdown table: `| K | 3 | Minimum number of stable clusters... |`.
|
|
407
|
-
* If absent or unparseable, fall back to 3 (
|
|
407
|
+
* If absent or unparseable, fall back to 3 (the documented default).
|
|
408
408
|
*/
|
|
409
409
|
function readK(gateSpecPath) {
|
|
410
410
|
const src = safeReadFileSync(gateSpecPath);
|
|
@@ -415,12 +415,12 @@ function readK(gateSpecPath) {
|
|
|
415
415
|
return Number.isFinite(v) && v > 0 ? v : 3;
|
|
416
416
|
}
|
|
417
417
|
|
|
418
|
-
// --- recordOptIn (
|
|
418
|
+
// --- recordOptIn (explicit-only) ---
|
|
419
419
|
|
|
420
420
|
/**
|
|
421
421
|
* Persist the user's explicit Stage-1 opt-in to STATE.md. Idempotent.
|
|
422
422
|
* IMPORTANT: this is the SOLE state writer in this module. Only invoke after
|
|
423
|
-
* explicit user confirmation in the apply-reflections UX
|
|
423
|
+
* explicit user confirmation in the apply-reflections UX.
|
|
424
424
|
*/
|
|
425
425
|
function recordOptIn(options) {
|
|
426
426
|
const o = options || {};
|
|
@@ -442,10 +442,41 @@ function recordOptIn(options) {
|
|
|
442
442
|
return { optInRecorded: true, at, confirmedBy };
|
|
443
443
|
}
|
|
444
444
|
|
|
445
|
+
// --- Touches-pattern proposals (Batch D D8 wire) ---
|
|
446
|
+
//
|
|
447
|
+
// Surfaces recurring `Touches:` signatures across archived task files as
|
|
448
|
+
// auto-crystallization proposals alongside the incubator drafts. The miner
|
|
449
|
+
// is opt-in via `proposalsRoot` arg (defaults to the touches-pattern-miner
|
|
450
|
+
// default location); when no archive exists yet, returns an empty list.
|
|
451
|
+
|
|
452
|
+
function discoverTouchesPatternProposals(opts = {}) {
|
|
453
|
+
const cwd = opts.cwd || process.cwd();
|
|
454
|
+
const cycleDir = path.join(cwd, opts.cycleDir || touchesPatternMiner.DEFAULT_CYCLE_DIR);
|
|
455
|
+
if (!fs.existsSync(cycleDir)) return [];
|
|
456
|
+
try {
|
|
457
|
+
const mined = touchesPatternMiner.mine({
|
|
458
|
+
cycleDir,
|
|
459
|
+
minTasks: opts.minTasks,
|
|
460
|
+
minCycles: opts.minCycles,
|
|
461
|
+
});
|
|
462
|
+
if (!Array.isArray(mined) || mined.length === 0) return [];
|
|
463
|
+
return mined.map((pattern, i) => ({
|
|
464
|
+
type: 'touches-pattern',
|
|
465
|
+
id: `touches-pattern-${i + 1}`,
|
|
466
|
+
pattern,
|
|
467
|
+
summary: pattern.signature || pattern.canonical || `Pattern #${i + 1}`,
|
|
468
|
+
}));
|
|
469
|
+
} catch (_err) {
|
|
470
|
+
// Miner is best-effort — never block apply-reflections on its failure.
|
|
471
|
+
return [];
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
|
|
445
475
|
// --- Exports ---
|
|
446
476
|
|
|
447
477
|
module.exports = {
|
|
448
478
|
discoverIncubatorDrafts,
|
|
479
|
+
discoverTouchesPatternProposals,
|
|
449
480
|
renderProposal,
|
|
450
481
|
applyAccept,
|
|
451
482
|
applyReject,
|
|
@@ -306,9 +306,12 @@ function buildManifest(sources) {
|
|
|
306
306
|
category,
|
|
307
307
|
capabilities: ['Read', 'Write'],
|
|
308
308
|
websiteURL: homepage || '',
|
|
309
|
+
// Codex uses /gdd- prefix uniformly (not /gdd: like Claude Code).
|
|
310
|
+
// Both lines use the same prefix to avoid the documented inconsistency
|
|
311
|
+
// (audit P1 #4 — committed manifest had mixed /gdd: and $gdd-).
|
|
309
312
|
defaultPrompt: [
|
|
310
|
-
'Run /gdd
|
|
311
|
-
'
|
|
313
|
+
'Run /gdd-brief to start a design cycle.',
|
|
314
|
+
'Run /gdd-explore to audit a screen.',
|
|
312
315
|
],
|
|
313
316
|
brandColor: '#10A37F',
|
|
314
317
|
};
|
|
@@ -24,6 +24,26 @@
|
|
|
24
24
|
*
|
|
25
25
|
* Pure / side-effect-free: no fs, no env, no path. `convert` is a
|
|
26
26
|
* deterministic string → string transform.
|
|
27
|
+
*
|
|
28
|
+
* KNOWN LIMITATION — sibling .md files (audit batch H6, 2026-06-04):
|
|
29
|
+
* The Cursor install drops ONLY `skills/<name>/SKILL.md`. Sibling
|
|
30
|
+
* `.md` files living next to SKILL.md (e.g. `discover-procedure.md`,
|
|
31
|
+
* `explore-procedure.md`, `cache-policy.md`) are NOT enumerated by
|
|
32
|
+
* `runtime-artifact-layout.cjs#skillsKind` and therefore NOT installed.
|
|
33
|
+
* Source SKILL.md files reference siblings via relative paths
|
|
34
|
+
* (e.g. `./discover-procedure.md`); on Cursor those links resolve to
|
|
35
|
+
* nothing.
|
|
36
|
+
*
|
|
37
|
+
* This is a systemic limitation of the current `multi-artifact`
|
|
38
|
+
* pipeline, not a Cursor-specific bug — it affects every runtime that
|
|
39
|
+
* uses `skillsKind` (claude global, cursor, codex, copilot, antigravity,
|
|
40
|
+
* windsurf, augment, trae, qwen, codebuddy). Fix requires extending the
|
|
41
|
+
* StagedArtifact contract to emit multiple files per skill (one
|
|
42
|
+
* SKILL.md + N siblings), updating `computeDestPath`, the foreign-file
|
|
43
|
+
* detection in `detectMultiArtifactInstalled`, and the uninstall
|
|
44
|
+
* enumeration in `uninstallMultiArtifact`. Tracked as a follow-up
|
|
45
|
+
* beyond batch H6 scope. See `connections/cursor.md` for user-facing
|
|
46
|
+
* guidance.
|
|
27
47
|
*/
|
|
28
48
|
|
|
29
49
|
const shared = require('./shared.cjs');
|
|
@@ -120,7 +120,7 @@ async function runReportFlow(args) {
|
|
|
120
120
|
submitted: false,
|
|
121
121
|
reason: 'disabled',
|
|
122
122
|
surface: reason, // 'env' | 'config'
|
|
123
|
-
message: `/gdd:report-issue is disabled by ${reasonMsg}. Run
|
|
123
|
+
message: `/gdd:report-issue is disabled by ${reasonMsg}. Run \`/gdd:health\` to see the active disable surface.`,
|
|
124
124
|
};
|
|
125
125
|
}
|
|
126
126
|
|
|
@@ -18,7 +18,10 @@
|
|
|
18
18
|
"name": "apply-reflections",
|
|
19
19
|
"description": "Review and selectively apply proposals from .design/reflections/<cycle-slug>.md. Diffs each proposal, prompts user to accept/skip/edit, then writes changes.",
|
|
20
20
|
"argument_hint": "[--cycle <slug>] [--filter <FRONTMATTER|REFERENCE|BUDGET|QUESTION|GLOBAL-SKILL>] [--dry-run]",
|
|
21
|
-
"tools": "Read, Write, Edit, Bash, Glob"
|
|
21
|
+
"tools": "Read, Write, Edit, Bash, Glob",
|
|
22
|
+
"composes_with": [
|
|
23
|
+
"audit"
|
|
24
|
+
]
|
|
22
25
|
},
|
|
23
26
|
{
|
|
24
27
|
"name": "audit",
|
|
@@ -50,6 +53,9 @@
|
|
|
50
53
|
"description": "Stage 1 of 5 design intake that captures problem statement, audience, constraints, success metrics, and scope into .design/BRIEF.md, and bootstraps .design/STATE.md if missing. Use when starting a new design cycle and before {{command_prefix}}explore. Activates for requests involving capturing a problem statement, defining audience and constraints, or starting a new design brief.",
|
|
51
54
|
"argument_hint": "[--re-brief to redo intake on existing project]",
|
|
52
55
|
"tools": "Read, Write, AskUserQuestion, mcp__gdd_state__frontmatter_update, mcp__gdd_state__set_status, mcp__gdd_state__update_progress, mcp__gdd_state__get",
|
|
56
|
+
"composes_with": [
|
|
57
|
+
"explore"
|
|
58
|
+
],
|
|
53
59
|
"next_skills": [
|
|
54
60
|
"explore"
|
|
55
61
|
]
|
|
@@ -63,7 +69,7 @@
|
|
|
63
69
|
},
|
|
64
70
|
{
|
|
65
71
|
"name": "cache-manager",
|
|
66
|
-
"description": "Maintains .design/cache-manifest.json for Layer B explicit cache per D-08. Computes deterministic SHA-256 input-hash from (agent-path + sorted-input-file-paths + input-content-hashes). On spawn: lookup key → return cached blob if within TTL, else miss. On completion: write result + TTL. Consulted by hooks/budget-enforcer.
|
|
72
|
+
"description": "Maintains .design/cache-manifest.json for Layer B explicit cache per D-08. Computes deterministic SHA-256 input-hash from (agent-path + sorted-input-file-paths + input-content-hashes). On spawn: lookup key → return cached blob if within TTL, else miss. On completion: write result + TTL. Consulted by hooks/budget-enforcer.ts before every Agent spawn.",
|
|
67
73
|
"user_invocable": false,
|
|
68
74
|
"tools": "Read, Bash, Write",
|
|
69
75
|
"disable_model_invocation": true
|
|
@@ -78,13 +84,19 @@
|
|
|
78
84
|
"name": "compare",
|
|
79
85
|
"description": "Compute the delta between the `DESIGN.md` baseline (from scan) and the `DESIGN-VERIFICATION.md` result (from verify), reporting per-category score delta, anti-pattern delta (resolved vs new), must-have pass/fail change, and design drift (regressions without covering tasks in `DESIGN-PLAN.md`). Use after `verify` to measure whether a design pipeline cycle actually improved the design. Writes `.design/COMPARE-REPORT.md`. Activates for requests involving diffing a design baseline against verification output, or a before-after design delta.",
|
|
80
86
|
"argument_hint": "",
|
|
81
|
-
"user_invocable": true
|
|
87
|
+
"user_invocable": true,
|
|
88
|
+
"composes_with": [
|
|
89
|
+
"verify"
|
|
90
|
+
]
|
|
82
91
|
},
|
|
83
92
|
{
|
|
84
93
|
"name": "complete-cycle",
|
|
85
94
|
"description": "Cycle closeout command that marks CYCLES.md entry complete, archives pipeline artifacts to .design/archive/cycle-N/, generates EXPERIENCE.md, rebuilds the search index, and resets STATE.md. Use when a design cycle has shipped and you're ready to start the next one.",
|
|
86
95
|
"argument_hint": "[<retrospective note>]",
|
|
87
|
-
"tools": "Read, Write, Bash, AskUserQuestion"
|
|
96
|
+
"tools": "Read, Write, Bash, AskUserQuestion",
|
|
97
|
+
"composes_with": [
|
|
98
|
+
"audit"
|
|
99
|
+
]
|
|
88
100
|
},
|
|
89
101
|
{
|
|
90
102
|
"name": "connections",
|
|
@@ -112,7 +124,10 @@
|
|
|
112
124
|
"name": "darkmode",
|
|
113
125
|
"description": "Audit a project's dark mode implementation - detects architecture (CSS custom props, Tailwind `dark:` prefix, or JS class toggle), runs architecture-specific contrast / token-override / anti-pattern / meta-property checks, and writes a prioritized fix list to `.design/DARKMODE-AUDIT.md`. Use when the user wants to verify dark mode quality without re-running the full design pipeline. Read-only - no score writeback to `DESIGN.md`. Activates for requests involving auditing dark mode, checking dark-theme contrast, or dark-mode anti-patterns.",
|
|
114
126
|
"argument_hint": "",
|
|
115
|
-
"user_invocable": true
|
|
127
|
+
"user_invocable": true,
|
|
128
|
+
"composes_with": [
|
|
129
|
+
"audit"
|
|
130
|
+
]
|
|
116
131
|
},
|
|
117
132
|
{
|
|
118
133
|
"name": "debug",
|
|
@@ -127,6 +142,11 @@
|
|
|
127
142
|
"argument_hint": "[--auto] [--parallel] [--variants N]",
|
|
128
143
|
"user_invocable": true,
|
|
129
144
|
"tools": "Read, Write, Bash, Grep, Glob, Task, AskUserQuestion, mcp__gdd_state__get, mcp__gdd_state__transition_stage, mcp__gdd_state__update_progress, mcp__gdd_state__set_status, mcp__gdd_state__add_blocker, mcp__gdd_state__resolve_blocker, mcp__gdd_state__checkpoint",
|
|
145
|
+
"composes_with": [
|
|
146
|
+
"figma-write",
|
|
147
|
+
"paper-write",
|
|
148
|
+
"pencil-write"
|
|
149
|
+
],
|
|
130
150
|
"next_skills": [
|
|
131
151
|
"verify"
|
|
132
152
|
]
|
|
@@ -136,13 +156,19 @@
|
|
|
136
156
|
"frontmatter_name": "discover",
|
|
137
157
|
"description": "Stage 1.5 of 4 orchestrator that probes Figma / Refero / Pinterest connections, spawns design-context-builder (auto-detect + interview) and (via lazy gate) design-context-checker (6-dimension validator), producing .design/DESIGN-CONTEXT.md. Use after {{command_prefix}}scan when a fast-path context build is wanted instead of the full {{command_prefix}}explore. Activates for requests involving detecting an existing design system, inventorying tokens and components, or onboarding a brownfield repo.",
|
|
138
158
|
"argument_hint": "[--auto] [--incremental] [--full]",
|
|
139
|
-
"user_invocable": true
|
|
159
|
+
"user_invocable": true,
|
|
160
|
+
"composes_with": [
|
|
161
|
+
"explore"
|
|
162
|
+
]
|
|
140
163
|
},
|
|
141
164
|
{
|
|
142
165
|
"name": "discuss",
|
|
143
166
|
"description": "Adaptive design interview command that spawns design-discussant in normal / --all / --spec mode to gather decisions via one-question-at-a-time AskUserQuestion, writing D-XX entries to STATE.md <decisions>. Use when locking design decisions outside the main pipeline or backfilling missing context.",
|
|
144
167
|
"argument_hint": "[topic] [--all] [--spec] [--cycle <name>]",
|
|
145
|
-
"tools": "Read, Write, Task"
|
|
168
|
+
"tools": "Read, Write, Task",
|
|
169
|
+
"composes_with": [
|
|
170
|
+
"list-assumptions"
|
|
171
|
+
]
|
|
146
172
|
},
|
|
147
173
|
{
|
|
148
174
|
"name": "do",
|
|
@@ -155,6 +181,11 @@
|
|
|
155
181
|
"description": "Stage 2 of 5 - unified exploration merging inventory grep + design interview. Probes 6 connections, scans the codebase, conducts the AskUserQuestion interview, and writes .design/DESIGN.md + DESIGN-DEBT.md + DESIGN-CONTEXT.md. Use after {{command_prefix}}brief to map the existing system and lock decisions before planning. Activates for requests involving researching design direction, gathering references, or exploring visual options.",
|
|
156
182
|
"argument_hint": "[--skip-interview] [--skip-scan] [--incremental] [--full]",
|
|
157
183
|
"tools": "Read, Write, Bash, Grep, Glob, Task, AskUserQuestion, mcp__gdd_state__get, mcp__gdd_state__transition_stage, mcp__gdd_state__probe_connections, mcp__gdd_state__update_progress, mcp__gdd_state__set_status, mcp__gdd_state__add_blocker, mcp__gdd_state__checkpoint, mcp__gdd_state__add_decision",
|
|
184
|
+
"composes_with": [
|
|
185
|
+
"discuss",
|
|
186
|
+
"list-assumptions",
|
|
187
|
+
"sketch"
|
|
188
|
+
],
|
|
158
189
|
"next_skills": [
|
|
159
190
|
"plan"
|
|
160
191
|
]
|
|
@@ -272,13 +303,19 @@
|
|
|
272
303
|
"name": "new-cycle",
|
|
273
304
|
"description": "Start a new design cycle. Creates cycle scope in STATE.md, initializes .design/CYCLES.md entry. Each cycle has its own goal and tracks its own decisions/tasks/pipeline runs.",
|
|
274
305
|
"argument_hint": "[<goal>]",
|
|
275
|
-
"tools": "Read, Write, AskUserQuestion"
|
|
306
|
+
"tools": "Read, Write, AskUserQuestion",
|
|
307
|
+
"composes_with": [
|
|
308
|
+
"brief"
|
|
309
|
+
]
|
|
276
310
|
},
|
|
277
311
|
{
|
|
278
312
|
"name": "new-project",
|
|
279
313
|
"description": "Initialize a new get-design-done project. Gathers project context, creates PROJECT.md and STATE.md, initializes first cycle. Run once per project before any pipeline stage.",
|
|
280
314
|
"argument_hint": "[--name <project-name>]",
|
|
281
315
|
"tools": "Read, Write, AskUserQuestion, Bash, Glob",
|
|
316
|
+
"composes_with": [
|
|
317
|
+
"brief"
|
|
318
|
+
],
|
|
282
319
|
"next_skills": [
|
|
283
320
|
"brief"
|
|
284
321
|
]
|
|
@@ -327,6 +364,20 @@
|
|
|
327
364
|
"tools": "Read, Write, Bash, Grep, Glob",
|
|
328
365
|
"registered_in_phase": "56"
|
|
329
366
|
},
|
|
367
|
+
{
|
|
368
|
+
"name": "paper-write",
|
|
369
|
+
"description": "Push design decisions from `.design/DESIGN-CONTEXT.md` into the active paper.design canvas by dispatching the `design-paper-writer` agent in one of three modes (annotate / tokenize / roundtrip). Use when the user has completed a design pipeline cycle and wants the decisions reflected in their paper.design canvas. Operates proposal->confirm with `--dry-run`.",
|
|
370
|
+
"argument_hint": "<annotate|tokenize|roundtrip> [--dry-run]",
|
|
371
|
+
"user_invocable": true,
|
|
372
|
+
"tools": "Read, Write, Bash, Grep, Glob"
|
|
373
|
+
},
|
|
374
|
+
{
|
|
375
|
+
"name": "pencil-write",
|
|
376
|
+
"description": "Update local `.pen` source files with design decisions from `.design/DESIGN-CONTEXT.md` by dispatching the `design-pencil-writer` agent in one of two modes (annotate / roundtrip). Use when the user has completed a design pipeline cycle and wants the decisions reflected in their `.pen` files. Operates proposal->confirm with `--dry-run`.",
|
|
377
|
+
"argument_hint": "<annotate|roundtrip> [--dry-run]",
|
|
378
|
+
"user_invocable": true,
|
|
379
|
+
"tools": "Read, Write, Bash, Grep, Glob"
|
|
380
|
+
},
|
|
330
381
|
{
|
|
331
382
|
"name": "pause",
|
|
332
383
|
"description": "Write a numbered checkpoint so work can resume in a new session without re-running completed stages.",
|
|
@@ -480,7 +531,7 @@
|
|
|
480
531
|
},
|
|
481
532
|
{
|
|
482
533
|
"name": "router",
|
|
483
|
-
"description": "Routes a /gdd command to fast|quick|full path + S|M|L|XL complexity_class and returns {path, complexity_class, model_tier_overrides, resolved_models, estimated_cost_usd, cache_hits}. Deterministic - no model call. Invoked once at command entry before any Agent spawn. Read by hooks/budget-enforcer.
|
|
534
|
+
"description": "Routes a /gdd command to fast|quick|full path + S|M|L|XL complexity_class and returns {path, complexity_class, model_tier_overrides, resolved_models, estimated_cost_usd, cache_hits}. Deterministic - no model call. Invoked once at command entry before any Agent spawn. Read by hooks/budget-enforcer.ts.",
|
|
484
535
|
"argument_hint": "<intent-string> [<target-artifacts-csv>]",
|
|
485
536
|
"tools": "Read, Bash, Grep"
|
|
486
537
|
},
|
|
@@ -489,7 +540,10 @@
|
|
|
489
540
|
"frontmatter_name": "scan",
|
|
490
541
|
"description": "Pre-pipeline initializer that maps an existing repo's design system (colors, typography, spacing, components, tokens), runs the anti-pattern audit, scores the 7 weighted categories, and writes DESIGN.md + .design/DESIGN-DEBT.md. Use when starting work in any new or existing repo before {{command_prefix}}discover. Activates for requests involving a fast read-only anti-pattern sweep, a quick design lint, or spotting slop without a full audit.",
|
|
491
542
|
"argument_hint": "[--quick] [--full]",
|
|
492
|
-
"user_invocable": true
|
|
543
|
+
"user_invocable": true,
|
|
544
|
+
"composes_with": [
|
|
545
|
+
"explore"
|
|
546
|
+
]
|
|
493
547
|
},
|
|
494
548
|
{
|
|
495
549
|
"name": "settings",
|
|
@@ -503,13 +557,19 @@
|
|
|
503
557
|
"description": "Post-verify PR flow - creates a clean PR branch, invokes code review check, and prepares the PR for merge. Activates for requests involving finishing a cycle, packaging design output, or moving work to a pull request.",
|
|
504
558
|
"argument_hint": "[--title <PR title>] [--draft]",
|
|
505
559
|
"tools": "Read, Write, Bash, AskUserQuestion, Task",
|
|
506
|
-
"disable_model_invocation": true
|
|
560
|
+
"disable_model_invocation": true,
|
|
561
|
+
"composes_with": [
|
|
562
|
+
"pr-branch"
|
|
563
|
+
]
|
|
507
564
|
},
|
|
508
565
|
{
|
|
509
566
|
"name": "sketch",
|
|
510
567
|
"description": "Multi-variant HTML design exploration that creates .design/sketches/<slug>/ with N standalone variants (default 3), browser-openable directly via file:// without a build step. Use when answering 'what could this look like?' before committing to a direction.",
|
|
511
568
|
"argument_hint": "[topic] [--variants N] [--quick]",
|
|
512
|
-
"tools": "Read, Write, AskUserQuestion, Bash"
|
|
569
|
+
"tools": "Read, Write, AskUserQuestion, Bash",
|
|
570
|
+
"composes_with": [
|
|
571
|
+
"sketch-wrap-up"
|
|
572
|
+
]
|
|
513
573
|
},
|
|
514
574
|
{
|
|
515
575
|
"name": "sketch-wrap-up",
|
|
@@ -526,7 +586,10 @@
|
|
|
526
586
|
"name": "spike",
|
|
527
587
|
"description": "Timeboxed feasibility experiment that creates .design/spikes/<slug>/ with HYPOTHESIS.md, success/failure criteria, scratch/ subdirectory, and a default 60-minute timebox. Use when answering 'can this work?' before betting design or implementation effort on a risky approach.",
|
|
528
588
|
"argument_hint": "[hypothesis] [--timebox <minutes>]",
|
|
529
|
-
"tools": "Read, Write, Bash, AskUserQuestion"
|
|
589
|
+
"tools": "Read, Write, Bash, AskUserQuestion",
|
|
590
|
+
"composes_with": [
|
|
591
|
+
"spike-wrap-up"
|
|
592
|
+
]
|
|
530
593
|
},
|
|
531
594
|
{
|
|
532
595
|
"name": "spike-wrap-up",
|
|
@@ -631,6 +694,10 @@
|
|
|
631
694
|
"argument_hint": "[--auto] [--post-handoff]",
|
|
632
695
|
"user_invocable": true,
|
|
633
696
|
"tools": "mcp__gdd_state__get, mcp__gdd_state__transition_stage, mcp__gdd_state__add_must_have, mcp__gdd_state__add_blocker, mcp__gdd_state__resolve_blocker, mcp__gdd_state__update_progress, mcp__gdd_state__set_status, mcp__gdd_state__checkpoint, mcp__gdd_state__probe_connections",
|
|
697
|
+
"composes_with": [
|
|
698
|
+
"audit",
|
|
699
|
+
"debug"
|
|
700
|
+
],
|
|
634
701
|
"next_skills": [
|
|
635
702
|
"ship"
|
|
636
703
|
]
|
|
@@ -46,7 +46,8 @@ function _findPackageRoot(startDir) {
|
|
|
46
46
|
const PKG_ROOT = _findPackageRoot(__dirname);
|
|
47
47
|
|
|
48
48
|
// ---------------------------------------------------------------------------
|
|
49
|
-
// Lazy-require state-backend.cjs (
|
|
49
|
+
// Lazy-require state-backend.cjs (loaded on first call so optional better-sqlite3
|
|
50
|
+
// binding does not crash module load).
|
|
50
51
|
// ---------------------------------------------------------------------------
|
|
51
52
|
let _backend = null;
|
|
52
53
|
function _requireBackend() {
|
|
@@ -65,7 +66,7 @@ function _requireBackend() {
|
|
|
65
66
|
}
|
|
66
67
|
|
|
67
68
|
// ---------------------------------------------------------------------------
|
|
68
|
-
// Lazy-require migrate-to-sqlite.cjs
|
|
69
|
+
// Lazy-require migrate-to-sqlite.cjs - used by recover().
|
|
69
70
|
// ---------------------------------------------------------------------------
|
|
70
71
|
let _migrate = null;
|
|
71
72
|
function _requireMigrate() {
|
|
@@ -202,6 +203,42 @@ function query(sql, opts = {}) {
|
|
|
202
203
|
}
|
|
203
204
|
}
|
|
204
205
|
|
|
206
|
+
// ---------------------------------------------------------------------------
|
|
207
|
+
// _safeBackup(srcPath, bakPath) - H5 backup-guard.
|
|
208
|
+
//
|
|
209
|
+
// Copy srcPath to bakPath, then verify the backup exists AND is non-empty
|
|
210
|
+
// AFTER the copy. Returns true only when the backup is a faithful non-empty
|
|
211
|
+
// copy of the source. Callers MUST check the return value before unlinking
|
|
212
|
+
// the source - the dangerous pattern is `copy → unconditional unlink`, where
|
|
213
|
+
// a silent copy failure (or zero-byte destination) means the unlink deletes
|
|
214
|
+
// the only remaining data.
|
|
215
|
+
//
|
|
216
|
+
// Defensive: never throws. Returns false on any error or empty backup.
|
|
217
|
+
//
|
|
218
|
+
// @param {string} srcPath path to source file (must exist)
|
|
219
|
+
// @param {string} bakPath path for the backup (created/overwritten)
|
|
220
|
+
// @returns {boolean} true iff bakPath exists and is non-empty after copy
|
|
221
|
+
// ---------------------------------------------------------------------------
|
|
222
|
+
|
|
223
|
+
function _safeBackup(srcPath, bakPath) {
|
|
224
|
+
try {
|
|
225
|
+
fs.copyFileSync(srcPath, bakPath);
|
|
226
|
+
} catch {
|
|
227
|
+
return false;
|
|
228
|
+
}
|
|
229
|
+
// Post-copy verification: the backup must EXIST and be NON-EMPTY.
|
|
230
|
+
// copyFileSync can silently produce a 0-byte file in some failure modes
|
|
231
|
+
// (interrupted IO, full disk after open). An empty backup is not a backup;
|
|
232
|
+
// unlinking the source after one would destroy the data.
|
|
233
|
+
try {
|
|
234
|
+
const st = fs.statSync(bakPath);
|
|
235
|
+
if (!st.isFile() || st.size === 0) return false;
|
|
236
|
+
return true;
|
|
237
|
+
} catch {
|
|
238
|
+
return false;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
205
242
|
// ---------------------------------------------------------------------------
|
|
206
243
|
// rotateBak(dbPath) - shift .bak.0..9, cap at 10.
|
|
207
244
|
// ---------------------------------------------------------------------------
|
|
@@ -247,12 +284,10 @@ function backupCycle(opts = {}) {
|
|
|
247
284
|
}
|
|
248
285
|
rotateBak(dbPath);
|
|
249
286
|
const bak0 = `${dbPath}.bak.0`;
|
|
250
|
-
|
|
251
|
-
fs.copyFileSync(dbPath, bak0);
|
|
287
|
+
if (_safeBackup(dbPath, bak0)) {
|
|
252
288
|
return { backed_up: true, path: bak0 };
|
|
253
|
-
} catch (err) {
|
|
254
|
-
return { backed_up: false, message: `backupCycle: copy failed: ${err.message}` };
|
|
255
289
|
}
|
|
290
|
+
return { backed_up: false, message: `backupCycle: copy failed or backup is empty at ${bak0}` };
|
|
256
291
|
}
|
|
257
292
|
|
|
258
293
|
// ---------------------------------------------------------------------------
|
|
@@ -282,9 +317,18 @@ function demigrate(opts = {}) {
|
|
|
282
317
|
};
|
|
283
318
|
}
|
|
284
319
|
// Take a backup before removing.
|
|
320
|
+
// H5 backup-guard: only unlink when the backup is a faithful non-empty copy.
|
|
321
|
+
// If the copy failed (or produced a 0-byte file), refuse to unlink the source -
|
|
322
|
+
// we'd be deleting the only remaining data.
|
|
285
323
|
rotateBak(dbPath);
|
|
286
324
|
const bak0 = `${dbPath}.bak.0`;
|
|
287
|
-
|
|
325
|
+
if (!_safeBackup(dbPath, bak0)) {
|
|
326
|
+
return {
|
|
327
|
+
demigrated: false,
|
|
328
|
+
message: `demigrate: refusing to remove ${dbPath} - backup at ${bak0} ` +
|
|
329
|
+
`is missing or empty after copyFileSync (would lose data).`,
|
|
330
|
+
};
|
|
331
|
+
}
|
|
288
332
|
try {
|
|
289
333
|
fs.unlinkSync(dbPath);
|
|
290
334
|
} catch (err) {
|
|
@@ -330,10 +374,23 @@ async function recover(opts = {}) {
|
|
|
330
374
|
const dbPath = opts.dbPath || backend.sqlitePath(opts.projectRoot || process.cwd());
|
|
331
375
|
|
|
332
376
|
// Step 1: Rotate existing (possibly corrupt) file to .bak.0.
|
|
377
|
+
// H5 backup-guard: only unlink the source after a verified non-empty backup.
|
|
378
|
+
// For recover() the source MAY already be corrupt - so an empty/failed backup
|
|
379
|
+
// is still significant signal. We refuse to unlink when the backup is missing
|
|
380
|
+
// OR zero bytes, so the operator retains a copy of the corrupt file for
|
|
381
|
+
// diagnostics. The caller can manually delete and retry once the backup
|
|
382
|
+
// location is writable.
|
|
333
383
|
if (fs.existsSync(dbPath)) {
|
|
334
384
|
rotateBak(dbPath);
|
|
335
385
|
const bak0 = `${dbPath}.bak.0`;
|
|
336
|
-
|
|
386
|
+
if (!_safeBackup(dbPath, bak0)) {
|
|
387
|
+
return {
|
|
388
|
+
recovered: false,
|
|
389
|
+
message: `recover: refusing to remove ${dbPath} - backup at ${bak0} ` +
|
|
390
|
+
`is missing or empty after copyFileSync (would lose corrupt file ` +
|
|
391
|
+
`before rebuild). Resolve disk/permission issues and retry.`,
|
|
392
|
+
};
|
|
393
|
+
}
|
|
337
394
|
try { fs.unlinkSync(dbPath); } catch (err) {
|
|
338
395
|
return { recovered: false, message: `recover: could not remove corrupt ${dbPath}: ${err.message}` };
|
|
339
396
|
}
|
|
@@ -344,7 +401,7 @@ async function recover(opts = {}) {
|
|
|
344
401
|
if (!migrate) {
|
|
345
402
|
return {
|
|
346
403
|
recovered: false,
|
|
347
|
-
message: 'recover: migrate-to-sqlite.cjs not
|
|
404
|
+
message: 'recover: migrate-to-sqlite.cjs could not be loaded (require failed). ' +
|
|
348
405
|
'Cannot rebuild SQLite from markdown.',
|
|
349
406
|
};
|
|
350
407
|
}
|
|
@@ -399,5 +456,6 @@ module.exports = {
|
|
|
399
456
|
// Expose internals for testing.
|
|
400
457
|
_assertReadonly,
|
|
401
458
|
_firstToken,
|
|
459
|
+
_safeBackup,
|
|
402
460
|
DENIED_TOKENS,
|
|
403
461
|
};
|