@hegemonart/get-design-done 1.0.7

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.
Files changed (144) hide show
  1. package/.claude-plugin/marketplace.json +63 -0
  2. package/.claude-plugin/plugin.json +54 -0
  3. package/CHANGELOG.md +221 -0
  4. package/LICENSE +21 -0
  5. package/README.md +724 -0
  6. package/SKILL.md +232 -0
  7. package/agents/README.md +226 -0
  8. package/agents/a11y-mapper.md +118 -0
  9. package/agents/component-taxonomy-mapper.md +88 -0
  10. package/agents/design-advisor.md +139 -0
  11. package/agents/design-assumptions-analyzer.md +171 -0
  12. package/agents/design-auditor.md +383 -0
  13. package/agents/design-context-builder.md +544 -0
  14. package/agents/design-context-checker-gate.md +90 -0
  15. package/agents/design-context-checker.md +260 -0
  16. package/agents/design-discussant.md +98 -0
  17. package/agents/design-doc-writer.md +229 -0
  18. package/agents/design-executor.md +452 -0
  19. package/agents/design-figma-writer.md +302 -0
  20. package/agents/design-fixer.md +180 -0
  21. package/agents/design-integration-checker-gate.md +93 -0
  22. package/agents/design-integration-checker.md +326 -0
  23. package/agents/design-pattern-mapper.md +206 -0
  24. package/agents/design-phase-researcher.md +229 -0
  25. package/agents/design-plan-checker.md +164 -0
  26. package/agents/design-planner.md +352 -0
  27. package/agents/design-reflector.md +175 -0
  28. package/agents/design-research-synthesizer.md +127 -0
  29. package/agents/design-verifier-gate.md +97 -0
  30. package/agents/design-verifier.md +605 -0
  31. package/agents/gdd-graphify-sync.md +100 -0
  32. package/agents/gdd-intel-updater.md +88 -0
  33. package/agents/gdd-learnings-extractor.md +85 -0
  34. package/agents/motion-mapper.md +103 -0
  35. package/agents/token-mapper.md +103 -0
  36. package/agents/visual-hierarchy-mapper.md +95 -0
  37. package/connections/chromatic.md +247 -0
  38. package/connections/claude-design.md +190 -0
  39. package/connections/connections.md +218 -0
  40. package/connections/figma-writer.md +139 -0
  41. package/connections/figma.md +146 -0
  42. package/connections/graphify.md +197 -0
  43. package/connections/pinterest.md +153 -0
  44. package/connections/preview.md +173 -0
  45. package/connections/refero.md +189 -0
  46. package/connections/storybook.md +280 -0
  47. package/hooks/budget-enforcer.js +318 -0
  48. package/hooks/context-exhaustion.js +127 -0
  49. package/hooks/gdd-read-injection-scanner.js +44 -0
  50. package/hooks/hooks.json +44 -0
  51. package/package.json +60 -0
  52. package/reference/BRANCH-PROTECTION.md +65 -0
  53. package/reference/DEPRECATIONS.md +41 -0
  54. package/reference/STATE-TEMPLATE.md +200 -0
  55. package/reference/accessibility.md +190 -0
  56. package/reference/anti-patterns.md +336 -0
  57. package/reference/audit-scoring.md +205 -0
  58. package/reference/checklists.md +137 -0
  59. package/reference/config-schema.md +319 -0
  60. package/reference/debugger-philosophy.md +32 -0
  61. package/reference/heuristics.md +201 -0
  62. package/reference/intel-schema.md +266 -0
  63. package/reference/model-prices.md +37 -0
  64. package/reference/model-tiers.md +118 -0
  65. package/reference/motion.md +285 -0
  66. package/reference/parallelism-rules.md +108 -0
  67. package/reference/priority-matrix.md +31 -0
  68. package/reference/project-skills-guide.md +42 -0
  69. package/reference/review-format.md +107 -0
  70. package/reference/schemas/config.schema.json +41 -0
  71. package/reference/schemas/hooks.schema.json +55 -0
  72. package/reference/schemas/intel.schema.json +191 -0
  73. package/reference/schemas/marketplace.schema.json +72 -0
  74. package/reference/schemas/plugin.schema.json +59 -0
  75. package/reference/shared-preamble.md +82 -0
  76. package/reference/typography.md +229 -0
  77. package/scripts/aggregate-agent-metrics.js +144 -0
  78. package/scripts/apply-branch-protection.sh +75 -0
  79. package/scripts/bootstrap-manifest.txt +3 -0
  80. package/scripts/bootstrap.sh +80 -0
  81. package/scripts/build-intel.cjs +458 -0
  82. package/scripts/detect-stale-refs.cjs +101 -0
  83. package/scripts/extract-changelog-section.cjs +57 -0
  84. package/scripts/release-smoke-test.cjs +169 -0
  85. package/scripts/rollback-release.sh +42 -0
  86. package/scripts/run-injection-scanner-ci.cjs +92 -0
  87. package/scripts/validate-frontmatter.cjs +68 -0
  88. package/scripts/validate-schemas.cjs +225 -0
  89. package/scripts/verify-version-sync.cjs +30 -0
  90. package/skills/add-backlog/SKILL.md +47 -0
  91. package/skills/analyze-dependencies/SKILL.md +184 -0
  92. package/skills/apply-reflections/SKILL.md +112 -0
  93. package/skills/audit/SKILL.md +54 -0
  94. package/skills/brief/SKILL.md +75 -0
  95. package/skills/cache-manager/SKILL.md +120 -0
  96. package/skills/compare/SKILL.md +322 -0
  97. package/skills/complete-cycle/SKILL.md +33 -0
  98. package/skills/darkmode/SKILL.md +331 -0
  99. package/skills/debug/SKILL.md +38 -0
  100. package/skills/design/SKILL.md +281 -0
  101. package/skills/discover/SKILL.md +172 -0
  102. package/skills/discuss/SKILL.md +67 -0
  103. package/skills/do/SKILL.md +45 -0
  104. package/skills/explore/SKILL.md +109 -0
  105. package/skills/extract-learnings/SKILL.md +98 -0
  106. package/skills/fast/SKILL.md +44 -0
  107. package/skills/figma-write/SKILL.md +40 -0
  108. package/skills/graphify/SKILL.md +48 -0
  109. package/skills/health/SKILL.md +48 -0
  110. package/skills/help/SKILL.md +76 -0
  111. package/skills/list-assumptions/SKILL.md +60 -0
  112. package/skills/map/SKILL.md +112 -0
  113. package/skills/new-cycle/SKILL.md +35 -0
  114. package/skills/new-project/SKILL.md +53 -0
  115. package/skills/next/SKILL.md +42 -0
  116. package/skills/note/SKILL.md +47 -0
  117. package/skills/optimize/SKILL.md +120 -0
  118. package/skills/pause/SKILL.md +41 -0
  119. package/skills/plan/SKILL.md +251 -0
  120. package/skills/plant-seed/SKILL.md +47 -0
  121. package/skills/pr-branch/SKILL.md +31 -0
  122. package/skills/progress/SKILL.md +60 -0
  123. package/skills/quick/SKILL.md +43 -0
  124. package/skills/reapply-patches/SKILL.md +31 -0
  125. package/skills/reflect/SKILL.md +73 -0
  126. package/skills/resume/SKILL.md +37 -0
  127. package/skills/review-backlog/SKILL.md +45 -0
  128. package/skills/router/SKILL.md +67 -0
  129. package/skills/scan/SKILL.md +721 -0
  130. package/skills/settings/SKILL.md +78 -0
  131. package/skills/ship/SKILL.md +31 -0
  132. package/skills/sketch/SKILL.md +78 -0
  133. package/skills/sketch-wrap-up/SKILL.md +88 -0
  134. package/skills/skill-manifest/SKILL.md +79 -0
  135. package/skills/spike/SKILL.md +67 -0
  136. package/skills/spike-wrap-up/SKILL.md +81 -0
  137. package/skills/stats/SKILL.md +50 -0
  138. package/skills/style/SKILL.md +193 -0
  139. package/skills/synthesize/SKILL.md +93 -0
  140. package/skills/todo/SKILL.md +54 -0
  141. package/skills/undo/SKILL.md +30 -0
  142. package/skills/update/SKILL.md +36 -0
  143. package/skills/verify/SKILL.md +452 -0
  144. package/skills/warm-cache/SKILL.md +113 -0
@@ -0,0 +1,458 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * build-intel.cjs — Full initial index builder for .design/intel/ store
4
+ *
5
+ * Usage: node scripts/build-intel.cjs [--force]
6
+ *
7
+ * Scans all skill, agent, reference, connection, script, hook files in the
8
+ * project and writes ten JSON slices to .design/intel/.
9
+ *
10
+ * On subsequent runs, only re-extracts slices for files whose mtime or git
11
+ * hash has changed (incremental). Pass --force to rebuild all slices.
12
+ *
13
+ * .design/intel/ is gitignored — this script ships tracked, data does not.
14
+ */
15
+
16
+ 'use strict';
17
+
18
+ const fs = require('fs');
19
+ const path = require('path');
20
+ const { execSync } = require('child_process');
21
+
22
+ const ROOT = process.cwd();
23
+ const INTEL_DIR = path.join(ROOT, '.design', 'intel');
24
+ const FORCE = process.argv.includes('--force');
25
+
26
+ // ── Helpers ─────────────────────────────────────────────────────────────────
27
+
28
+ function ensureDir(dir) {
29
+ if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
30
+ }
31
+
32
+ function now() {
33
+ return new Date().toISOString();
34
+ }
35
+
36
+ function readJson(filePath) {
37
+ try { return JSON.parse(fs.readFileSync(filePath, 'utf8')); }
38
+ catch { return null; }
39
+ }
40
+
41
+ function writeSlice(name, data) {
42
+ const dest = path.join(INTEL_DIR, name);
43
+ fs.writeFileSync(dest, JSON.stringify(data, null, 2), 'utf8');
44
+ console.log(` wrote ${name}`);
45
+ }
46
+
47
+ function gitHash(filePath) {
48
+ try {
49
+ return execSync(`git log -1 --format=%h -- "${filePath}"`, { stdio: ['pipe', 'pipe', 'ignore'] })
50
+ .toString().trim() || 'untracked';
51
+ } catch { return 'untracked'; }
52
+ }
53
+
54
+ function headHash() {
55
+ try {
56
+ return execSync('git rev-parse --short HEAD', { stdio: ['pipe', 'pipe', 'ignore'] })
57
+ .toString().trim();
58
+ } catch { return 'unknown'; }
59
+ }
60
+
61
+ function getMtime(filePath) {
62
+ try { return fs.statSync(filePath).mtime.toISOString(); }
63
+ catch { return null; }
64
+ }
65
+
66
+ function getSize(filePath) {
67
+ try { return fs.statSync(filePath).size; }
68
+ catch { return 0; }
69
+ }
70
+
71
+ // ── File discovery ───────────────────────────────────────────────────────────
72
+
73
+ function classifyFile(rel) {
74
+ if (rel.startsWith('skills/')) return 'skill';
75
+ if (rel.startsWith('agents/')) return 'agent';
76
+ if (rel.startsWith('reference/')) return 'reference';
77
+ if (rel.startsWith('connections/')) return 'connection';
78
+ if (rel.startsWith('scripts/')) return 'script';
79
+ if (rel.startsWith('hooks/')) return 'hook';
80
+ if (rel.startsWith('tests/')) return 'test';
81
+ if (rel.endsWith('.json') || rel.endsWith('.yaml') || rel.endsWith('.yml')) return 'config';
82
+ return 'other';
83
+ }
84
+
85
+ function discoverFiles() {
86
+ const DIRS = ['skills', 'agents', 'reference', 'connections', 'scripts', 'hooks', 'tests'];
87
+ const EXTS = new Set(['.md', '.cjs', '.js', '.json', '.yaml', '.yml']);
88
+ const results = [];
89
+
90
+ for (const dir of DIRS) {
91
+ const abs = path.join(ROOT, dir);
92
+ if (!fs.existsSync(abs)) continue;
93
+ walkDir(abs, ROOT, EXTS, results);
94
+ }
95
+
96
+ // Also include top-level config files
97
+ for (const f of ['CLAUDE.md', 'README.md']) {
98
+ const abs = path.join(ROOT, f);
99
+ if (fs.existsSync(abs)) results.push(path.relative(ROOT, abs).replace(/\\/g, '/'));
100
+ }
101
+
102
+ return results;
103
+ }
104
+
105
+ function walkDir(dir, root, exts, out) {
106
+ for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
107
+ const full = path.join(dir, entry.name);
108
+ if (entry.isDirectory()) {
109
+ walkDir(full, root, exts, out);
110
+ } else if (exts.has(path.extname(entry.name))) {
111
+ out.push(path.relative(root, full).replace(/\\/g, '/'));
112
+ }
113
+ }
114
+ }
115
+
116
+ // ── Changed-file detection ───────────────────────────────────────────────────
117
+
118
+ function changedFiles(allFiles, existingFilesSlice) {
119
+ if (FORCE || !existingFilesSlice) return allFiles;
120
+
121
+ const index = {};
122
+ for (const f of (existingFilesSlice.files || [])) {
123
+ index[f.path] = { mtime: f.mtime, git_hash: f.git_hash };
124
+ }
125
+
126
+ return allFiles.filter(rel => {
127
+ const abs = path.join(ROOT, rel);
128
+ const prev = index[rel];
129
+ if (!prev) return true;
130
+ const curMtime = getMtime(abs);
131
+ const curHash = gitHash(rel);
132
+ return curMtime !== prev.mtime || curHash !== prev.git_hash;
133
+ });
134
+ }
135
+
136
+ // ── Frontmatter parser ───────────────────────────────────────────────────────
137
+
138
+ function parseFrontmatter(content) {
139
+ const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
140
+ if (!match) return {};
141
+ const fm = {};
142
+ for (const line of match[1].split('\n')) {
143
+ const kv = line.match(/^(\w[\w-]*):\s*(.+)$/);
144
+ if (kv) fm[kv[1]] = kv[2].trim().replace(/^["']|["']$/g, '');
145
+ }
146
+ return fm;
147
+ }
148
+
149
+ // ── Slice builders ───────────────────────────────────────────────────────────
150
+
151
+ function buildFilesSlice(allFiles) {
152
+ return {
153
+ generated: now(),
154
+ git_hash: headHash(),
155
+ files: allFiles.map(rel => {
156
+ const abs = path.join(ROOT, rel);
157
+ return {
158
+ path: rel,
159
+ type: classifyFile(rel),
160
+ mtime: getMtime(abs),
161
+ size_bytes: getSize(abs),
162
+ git_hash: gitHash(rel),
163
+ };
164
+ }),
165
+ };
166
+ }
167
+
168
+ function buildExportsSlice(allFiles) {
169
+ const exports = [];
170
+ for (const rel of allFiles) {
171
+ if (!rel.endsWith('.md')) continue;
172
+ const abs = path.join(ROOT, rel);
173
+ let content;
174
+ try { content = fs.readFileSync(abs, 'utf8'); } catch { continue; }
175
+ const fm = parseFrontmatter(content);
176
+ if (!fm.name) continue;
177
+
178
+ const kind = classifyFile(rel);
179
+ const entry = { file: rel, kind, name: fm.name };
180
+ // Skills have a command derived from name (gdd-foo → /gdd:foo)
181
+ if (kind === 'skill' && fm.name.startsWith('gdd-')) {
182
+ entry.command = '/gdd:' + fm.name.replace(/^gdd-/, '');
183
+ }
184
+ exports.push(entry);
185
+ }
186
+ return { generated: now(), exports };
187
+ }
188
+
189
+ function buildSymbolsSlice(allFiles) {
190
+ const symbols = [];
191
+ const HEADING_RE = /^(#{1,4})\s+(.+)$/gm;
192
+ for (const rel of allFiles) {
193
+ if (!rel.endsWith('.md')) continue;
194
+ const abs = path.join(ROOT, rel);
195
+ let content;
196
+ try { content = fs.readFileSync(abs, 'utf8'); } catch { continue; }
197
+ const lines = content.split('\n');
198
+ lines.forEach((line, i) => {
199
+ const m = line.match(/^(#{1,4})\s+(.+)$/);
200
+ if (!m) return;
201
+ const heading = m[0];
202
+ const level = m[1].length;
203
+ const text = m[2].trim();
204
+ const anchor = text.toLowerCase().replace(/[^\w\s-]/g, '').replace(/\s+/g, '-');
205
+ symbols.push({ file: rel, heading, level, anchor, line: i + 1 });
206
+ });
207
+ }
208
+ return { generated: now(), symbols };
209
+ }
210
+
211
+ function buildTokensSlice(allFiles) {
212
+ const tokens = [];
213
+ const TOKEN_RE = /--[\w-]+(color|space|spacing|font|radius|shadow|motion|size|weight|line)[^\s,;)']*/gi;
214
+ const CAT_MAP = {
215
+ color: 'color', space: 'spacing', spacing: 'spacing',
216
+ font: 'typography', radius: 'radius', shadow: 'shadow', motion: 'motion',
217
+ };
218
+ for (const rel of allFiles) {
219
+ if (!rel.endsWith('.md') && !rel.endsWith('.cjs') && !rel.endsWith('.js')) continue;
220
+ const abs = path.join(ROOT, rel);
221
+ let content;
222
+ try { content = fs.readFileSync(abs, 'utf8'); } catch { continue; }
223
+ const lines = content.split('\n');
224
+ lines.forEach((line, i) => {
225
+ let m;
226
+ const re = /--[\w-]+/g;
227
+ while ((m = re.exec(line)) !== null) {
228
+ const token = m[0];
229
+ // Categorise by suffix keywords
230
+ let category = 'other';
231
+ for (const [key, cat] of Object.entries(CAT_MAP)) {
232
+ if (token.includes(key)) { category = cat; break; }
233
+ }
234
+ if (category === 'other' && !token.includes('-')) continue;
235
+ tokens.push({ file: rel, token, category, line: i + 1, context: line.trim().slice(0, 80) });
236
+ }
237
+ });
238
+ }
239
+ return { generated: now(), tokens };
240
+ }
241
+
242
+ function buildComponentsSlice(allFiles) {
243
+ const components = [];
244
+ // PascalCase component names in markdown
245
+ const COMP_RE = /\b([A-Z][a-zA-Z0-9]{2,})\b/g;
246
+ const SKIP = new Set(['WCAG', 'CSS', 'JSON', 'HTML', 'URL', 'API', 'MCP', 'GDD', 'UI', 'UX', 'ISO']);
247
+ for (const rel of allFiles) {
248
+ if (!rel.endsWith('.md')) continue;
249
+ const abs = path.join(ROOT, rel);
250
+ let content;
251
+ try { content = fs.readFileSync(abs, 'utf8'); } catch { continue; }
252
+ const lines = content.split('\n');
253
+ lines.forEach((line, i) => {
254
+ // Skip code blocks
255
+ if (line.trim().startsWith('```') || line.trim().startsWith('`')) return;
256
+ let m;
257
+ while ((m = COMP_RE.exec(line)) !== null) {
258
+ const name = m[1];
259
+ if (SKIP.has(name)) continue;
260
+ const role = line.includes('define') || line.includes('export') ? 'definition' : 'reference';
261
+ components.push({ file: rel, component: name, role, line: i + 1 });
262
+ }
263
+ });
264
+ }
265
+ // Deduplicate by file+component+line
266
+ const seen = new Set();
267
+ return {
268
+ generated: now(),
269
+ components: components.filter(c => {
270
+ const key = `${c.file}:${c.component}:${c.line}`;
271
+ if (seen.has(key)) return false;
272
+ seen.add(key);
273
+ return true;
274
+ }),
275
+ };
276
+ }
277
+
278
+ function buildPatternsSlice(allFiles) {
279
+ const patterns = [];
280
+ const PATTERN_CATS = ['color-system', 'spacing-system', 'typography-system', 'component-styling', 'layout', 'interaction'];
281
+ for (const rel of allFiles) {
282
+ if (!rel.endsWith('.md')) continue;
283
+ const abs = path.join(ROOT, rel);
284
+ let content;
285
+ try { content = fs.readFileSync(abs, 'utf8'); } catch { continue; }
286
+ for (const cat of PATTERN_CATS) {
287
+ if (content.includes(cat)) {
288
+ // Find the line
289
+ const lines = content.split('\n');
290
+ lines.forEach((line, i) => {
291
+ if (line.includes(cat)) {
292
+ const name = cat;
293
+ patterns.push({
294
+ name,
295
+ category: cat,
296
+ source_file: rel,
297
+ description: line.trim().slice(0, 100),
298
+ });
299
+ }
300
+ });
301
+ }
302
+ }
303
+ }
304
+ // Deduplicate
305
+ const seen = new Set();
306
+ return {
307
+ generated: now(),
308
+ patterns: patterns.filter(p => {
309
+ const key = `${p.source_file}:${p.category}:${p.description}`;
310
+ if (seen.has(key)) return false;
311
+ seen.add(key);
312
+ return true;
313
+ }),
314
+ };
315
+ }
316
+
317
+ function buildDependenciesSlice(allFiles) {
318
+ const dependencies = [];
319
+ // @-references in markdown
320
+ const AT_REF_RE = /@([\w./\-]+\.md)/g;
321
+ // reads-from in agent frontmatter (reads: field)
322
+ for (const rel of allFiles) {
323
+ if (!rel.endsWith('.md')) continue;
324
+ const abs = path.join(ROOT, rel);
325
+ let content;
326
+ try { content = fs.readFileSync(abs, 'utf8'); } catch { continue; }
327
+ const lines = content.split('\n');
328
+ lines.forEach((line, i) => {
329
+ let m;
330
+ while ((m = AT_REF_RE.exec(line)) !== null) {
331
+ const target = m[1];
332
+ dependencies.push({ from: rel, to: target, kind: 'at-reference', line: i + 1 });
333
+ }
334
+ });
335
+ // Check frontmatter reads field
336
+ const fm = parseFrontmatter(content);
337
+ if (fm.reads) {
338
+ // reads: comma or space separated list
339
+ const targets = fm.reads.split(/[\s,]+/).filter(Boolean);
340
+ for (const t of targets) {
341
+ if (t.endsWith('.md') || t.endsWith('.json')) {
342
+ dependencies.push({ from: rel, to: t, kind: 'reads-from', line: 1 });
343
+ }
344
+ }
345
+ }
346
+ }
347
+ return { generated: now(), dependencies };
348
+ }
349
+
350
+ function buildDecisionsSlice() {
351
+ // Decisions come from .design/DESIGN-CONTEXT.md (runtime, may not exist at build time)
352
+ const decisions = [];
353
+ const CONTEXT_FILE = path.join(ROOT, '.design', 'DESIGN-CONTEXT.md');
354
+ if (!fs.existsSync(CONTEXT_FILE)) {
355
+ return { generated: now(), decisions };
356
+ }
357
+ const content = fs.readFileSync(CONTEXT_FILE, 'utf8');
358
+ const lines = content.split('\n');
359
+ const DECISION_RE = /\b(D-\d+)[:\s]+(.+)/;
360
+ lines.forEach((line, i) => {
361
+ const m = line.match(DECISION_RE);
362
+ if (m) {
363
+ decisions.push({
364
+ id: m[1],
365
+ summary: m[2].trim().slice(0, 120),
366
+ source_file: '.design/DESIGN-CONTEXT.md',
367
+ line: i + 1,
368
+ date: now().slice(0, 10),
369
+ });
370
+ }
371
+ });
372
+ return { generated: now(), decisions };
373
+ }
374
+
375
+ function buildDebtSlice() {
376
+ const debt = [];
377
+ const DEBT_FILE = path.join(ROOT, '.design', 'DESIGN-DEBT.md');
378
+ if (!fs.existsSync(DEBT_FILE)) {
379
+ return { generated: now(), debt };
380
+ }
381
+ const content = fs.readFileSync(DEBT_FILE, 'utf8');
382
+ const lines = content.split('\n');
383
+ const ITEM_RE = /[-*]\s+(?:\*\*(DEBT-\d+|high|medium|low)\*\*[:\s]+)?(.+)/i;
384
+ const SEV_RE = /high|medium|low/i;
385
+ let debtId = 0;
386
+ lines.forEach((line, i) => {
387
+ const m = line.match(ITEM_RE);
388
+ if (!m) return;
389
+ const sevMatch = line.match(SEV_RE);
390
+ const severity = sevMatch ? sevMatch[0].toLowerCase() : 'medium';
391
+ debtId++;
392
+ const id = line.match(/DEBT-\d+/) ? line.match(/DEBT-\d+/)[0] : `DEBT-${String(debtId).padStart(2, '0')}`;
393
+ debt.push({
394
+ id,
395
+ summary: m[2].trim().slice(0, 120),
396
+ severity,
397
+ source_file: '.design/DESIGN-DEBT.md',
398
+ line: i + 1,
399
+ });
400
+ });
401
+ return { generated: now(), debt };
402
+ }
403
+
404
+ function buildGraphSlice(filesSlice, depsSlice) {
405
+ const nodes = (filesSlice.files || []).map(f => ({
406
+ id: f.path,
407
+ type: f.type,
408
+ name: path.basename(f.path, path.extname(f.path)),
409
+ }));
410
+ const edges = (depsSlice.dependencies || []).map(d => ({
411
+ from: d.from,
412
+ to: d.to,
413
+ kind: d.kind,
414
+ }));
415
+ return { generated: now(), nodes, edges };
416
+ }
417
+
418
+ // ── Main ─────────────────────────────────────────────────────────────────────
419
+
420
+ async function main() {
421
+ console.log('build-intel: starting' + (FORCE ? ' (--force)' : ''));
422
+ ensureDir(INTEL_DIR);
423
+
424
+ const existingFiles = readJson(path.join(INTEL_DIR, 'files.json'));
425
+ const allFiles = discoverFiles();
426
+ const changed = changedFiles(allFiles, existingFiles);
427
+
428
+ console.log(` discovered ${allFiles.length} files, ${changed.length} changed`);
429
+
430
+ // Always rebuild files slice when any file changed
431
+ const filesSlice = buildFilesSlice(allFiles);
432
+ writeSlice('files.json', filesSlice);
433
+
434
+ // Rebuild content slices only for changed files (or all if force)
435
+ const targetFiles = FORCE ? allFiles : changed;
436
+
437
+ // For simplicity, rebuild all content slices when any file changed.
438
+ // A production version would merge existing slices with updated entries.
439
+ if (targetFiles.length > 0 || FORCE) {
440
+ writeSlice('exports.json', buildExportsSlice(allFiles));
441
+ writeSlice('symbols.json', buildSymbolsSlice(allFiles));
442
+ writeSlice('tokens.json', buildTokensSlice(allFiles));
443
+ writeSlice('components.json', buildComponentsSlice(allFiles));
444
+ writeSlice('patterns.json', buildPatternsSlice(allFiles));
445
+ const depsSlice = buildDependenciesSlice(allFiles);
446
+ writeSlice('dependencies.json', depsSlice);
447
+ writeSlice('decisions.json', buildDecisionsSlice());
448
+ writeSlice('debt.json', buildDebtSlice());
449
+ writeSlice('graph.json', buildGraphSlice(filesSlice, depsSlice));
450
+ } else {
451
+ console.log(' no changes detected — skipping content slices');
452
+ }
453
+
454
+ console.log('build-intel: done');
455
+ console.log(` output: ${INTEL_DIR}`);
456
+ }
457
+
458
+ main().catch(err => { console.error(err); process.exit(1); });
@@ -0,0 +1,101 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+ // Detect deprecated namespace and stage/agent references in shipped markdown.
4
+ // Reads reference/DEPRECATIONS.md as the authoritative list of stale tokens.
5
+ // Exits 0 if clean, 1 on any match.
6
+
7
+ const fs = require('fs');
8
+ const path = require('path');
9
+
10
+ const REPO_ROOT = path.resolve(__dirname, '..');
11
+ const DEPRECATIONS_PATH = path.join(REPO_ROOT, 'reference/DEPRECATIONS.md');
12
+
13
+ // Patterns checked against every .md file body (not against DEPRECATIONS.md itself).
14
+ // Scope: only truly unambiguous deprecations — names that must not appear anywhere
15
+ // outside DEPRECATIONS.md. Current-but-historically-renamed agents/skills
16
+ // (design-context-builder, design-pattern-mapper, scan/, discover/) are NOT
17
+ // flagged here because they still exist as live files in the tree; the
18
+ // rename/split documented in DEPRECATIONS.md was partial, so static detection
19
+ // would over-fire. Cover those cases via targeted review rather than grep.
20
+ const PATTERNS = [
21
+ { name: '/design: namespace (replaced by /gdd:)', regex: /\/design:[a-z-]+/g },
22
+ ];
23
+
24
+ const EXCLUDE_DIRS = new Set([
25
+ 'node_modules',
26
+ '.planning',
27
+ '.claude',
28
+ '.design',
29
+ 'test-fixture',
30
+ '.git',
31
+ ]);
32
+
33
+ const EXCLUDE_FILES = new Set([
34
+ // Normalize to forward-slashes so Windows matches this set correctly.
35
+ path.relative(REPO_ROOT, DEPRECATIONS_PATH).split(path.sep).join('/'),
36
+ ]);
37
+
38
+ function ensureDeprecationsExists() {
39
+ if (fs.existsSync(DEPRECATIONS_PATH)) return;
40
+ const stub = [
41
+ '# Deprecated Namespaces and Names',
42
+ '',
43
+ 'Auto-generated stub — edit this file to declare deprecations authoritatively.',
44
+ '',
45
+ '## Stale command namespaces',
46
+ '- `/design:*` — replaced by `/gdd:*`',
47
+ '',
48
+ '## Stale agent names',
49
+ '- `design-context-builder` — replaced',
50
+ '- `design-pattern-mapper` (as single blob) — replaced',
51
+ '',
52
+ '## Stale stage names',
53
+ '- `scan` — folded into `/gdd:explore`',
54
+ '- `discover` — folded into `/gdd:explore`',
55
+ '',
56
+ ].join('\n');
57
+ fs.mkdirSync(path.dirname(DEPRECATIONS_PATH), { recursive: true });
58
+ fs.writeFileSync(DEPRECATIONS_PATH, stub, 'utf8');
59
+ }
60
+
61
+ function walk(dir, out) {
62
+ for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
63
+ if (entry.isDirectory()) {
64
+ if (EXCLUDE_DIRS.has(entry.name)) continue;
65
+ walk(path.join(dir, entry.name), out);
66
+ } else if (entry.isFile() && entry.name.endsWith('.md')) {
67
+ const full = path.join(dir, entry.name);
68
+ const rel = path.relative(REPO_ROOT, full).split(path.sep).join('/');
69
+ if (EXCLUDE_FILES.has(rel)) continue;
70
+ out.push(full);
71
+ }
72
+ }
73
+ }
74
+
75
+ function main() {
76
+ ensureDeprecationsExists();
77
+ const files = [];
78
+ walk(REPO_ROOT, files);
79
+
80
+ let findings = 0;
81
+ for (const file of files) {
82
+ const body = fs.readFileSync(file, 'utf8');
83
+ const lines = body.split('\n');
84
+ for (let i = 0; i < lines.length; i++) {
85
+ for (const { name, regex } of PATTERNS) {
86
+ regex.lastIndex = 0;
87
+ let m;
88
+ while ((m = regex.exec(lines[i])) !== null) {
89
+ const rel = path.relative(REPO_ROOT, file);
90
+ console.log(`${rel}:${i + 1}: ${name} → ${m[0]}`);
91
+ findings++;
92
+ }
93
+ }
94
+ }
95
+ }
96
+
97
+ console.log(`summary: ${files.length} files scanned, ${findings} stale refs found`);
98
+ process.exit(findings === 0 ? 0 : 1);
99
+ }
100
+
101
+ main();
@@ -0,0 +1,57 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+ // Extract the `## [<version>]` section of CHANGELOG.md and print to stdout.
4
+ // Used by .github/workflows/release.yml to build the GitHub Release body.
5
+ //
6
+ // Usage: node scripts/extract-changelog-section.cjs <version>
7
+ // Example: node scripts/extract-changelog-section.cjs 1.0.7
8
+ //
9
+ // Exit codes:
10
+ // 0 — section found, body printed
11
+ // 1 — no matching section
12
+ // 2 — missing or empty version argument
13
+
14
+ const fs = require('fs');
15
+ const path = require('path');
16
+
17
+ const version = (process.argv[2] || '').trim();
18
+ if (!version) {
19
+ console.error('Usage: node scripts/extract-changelog-section.cjs <version>');
20
+ process.exit(2);
21
+ }
22
+
23
+ const changelogPath = path.join(__dirname, '..', 'CHANGELOG.md');
24
+ if (!fs.existsSync(changelogPath)) {
25
+ console.error(`ERROR: CHANGELOG.md not found at ${changelogPath}`);
26
+ process.exit(1);
27
+ }
28
+
29
+ const body = fs.readFileSync(changelogPath, 'utf8').replace(/\r\n/g, '\n');
30
+ const lines = body.split('\n');
31
+ const headingRe = new RegExp(`^##\\s*\\[${version.replace(/\./g, '\\.')}\\]`);
32
+ const nextHeadingRe = /^##\s*\[/;
33
+
34
+ let capture = false;
35
+ const out = [];
36
+ for (let i = 0; i < lines.length; i++) {
37
+ const line = lines[i];
38
+ if (!capture) {
39
+ if (headingRe.test(line)) capture = true;
40
+ continue;
41
+ }
42
+ // Stop at next version heading or a standalone horizontal rule
43
+ if (nextHeadingRe.test(line)) break;
44
+ if (line.trim() === '---') break;
45
+ out.push(line);
46
+ }
47
+
48
+ if (!capture) {
49
+ console.error(`ERROR: no section for version ${version}`);
50
+ process.exit(1);
51
+ }
52
+
53
+ // Trim leading + trailing blank lines
54
+ while (out.length && out[0].trim() === '') out.shift();
55
+ while (out.length && out[out.length - 1].trim() === '') out.pop();
56
+
57
+ process.stdout.write(out.join('\n') + '\n');