superspec 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +328 -0
  3. package/dist/cli/commands/archive.d.ts +7 -0
  4. package/dist/cli/commands/archive.d.ts.map +1 -0
  5. package/dist/cli/commands/archive.js +322 -0
  6. package/dist/cli/commands/archive.js.map +1 -0
  7. package/dist/cli/commands/init.d.ts +6 -0
  8. package/dist/cli/commands/init.d.ts.map +1 -0
  9. package/dist/cli/commands/init.js +306 -0
  10. package/dist/cli/commands/init.js.map +1 -0
  11. package/dist/cli/commands/list.d.ts +9 -0
  12. package/dist/cli/commands/list.d.ts.map +1 -0
  13. package/dist/cli/commands/list.js +268 -0
  14. package/dist/cli/commands/list.js.map +1 -0
  15. package/dist/cli/commands/show.d.ts +6 -0
  16. package/dist/cli/commands/show.d.ts.map +1 -0
  17. package/dist/cli/commands/show.js +273 -0
  18. package/dist/cli/commands/show.js.map +1 -0
  19. package/dist/cli/commands/validate.d.ts +8 -0
  20. package/dist/cli/commands/validate.d.ts.map +1 -0
  21. package/dist/cli/commands/validate.js +209 -0
  22. package/dist/cli/commands/validate.js.map +1 -0
  23. package/dist/cli/commands/verify.d.ts +7 -0
  24. package/dist/cli/commands/verify.d.ts.map +1 -0
  25. package/dist/cli/commands/verify.js +328 -0
  26. package/dist/cli/commands/verify.js.map +1 -0
  27. package/dist/cli/commands/view.d.ts +6 -0
  28. package/dist/cli/commands/view.d.ts.map +1 -0
  29. package/dist/cli/commands/view.js +290 -0
  30. package/dist/cli/commands/view.js.map +1 -0
  31. package/dist/cli/index.d.ts +3 -0
  32. package/dist/cli/index.d.ts.map +1 -0
  33. package/dist/cli/index.js +87 -0
  34. package/dist/cli/index.js.map +1 -0
  35. package/dist/cli/ui/display.d.ts +189 -0
  36. package/dist/cli/ui/display.d.ts.map +1 -0
  37. package/dist/cli/ui/display.js +449 -0
  38. package/dist/cli/ui/display.js.map +1 -0
  39. package/dist/cli/ui/index.d.ts +12 -0
  40. package/dist/cli/ui/index.d.ts.map +1 -0
  41. package/dist/cli/ui/index.js +71 -0
  42. package/dist/cli/ui/index.js.map +1 -0
  43. package/dist/cli/ui/interactive.d.ts +21 -0
  44. package/dist/cli/ui/interactive.d.ts.map +1 -0
  45. package/dist/cli/ui/interactive.js +60 -0
  46. package/dist/cli/ui/interactive.js.map +1 -0
  47. package/dist/cli/ui/palette.d.ts +301 -0
  48. package/dist/cli/ui/palette.d.ts.map +1 -0
  49. package/dist/cli/ui/palette.js +673 -0
  50. package/dist/cli/ui/palette.js.map +1 -0
  51. package/dist/cli/ui/prompts.d.ts +62 -0
  52. package/dist/cli/ui/prompts.d.ts.map +1 -0
  53. package/dist/cli/ui/prompts.js +119 -0
  54. package/dist/cli/ui/prompts.js.map +1 -0
  55. package/dist/cli/ui/spinner.d.ts +38 -0
  56. package/dist/cli/ui/spinner.d.ts.map +1 -0
  57. package/dist/cli/ui/spinner.js +72 -0
  58. package/dist/cli/ui/spinner.js.map +1 -0
  59. package/dist/core/config/project-config.d.ts +100 -0
  60. package/dist/core/config/project-config.d.ts.map +1 -0
  61. package/dist/core/config/project-config.js +87 -0
  62. package/dist/core/config/project-config.js.map +1 -0
  63. package/dist/core/parsers/spec-parser.d.ts +48 -0
  64. package/dist/core/parsers/spec-parser.d.ts.map +1 -0
  65. package/dist/core/parsers/spec-parser.js +322 -0
  66. package/dist/core/parsers/spec-parser.js.map +1 -0
  67. package/dist/core/validation/spec-validator.d.ts +32 -0
  68. package/dist/core/validation/spec-validator.d.ts.map +1 -0
  69. package/dist/core/validation/spec-validator.js +242 -0
  70. package/dist/core/validation/spec-validator.js.map +1 -0
  71. package/dist/index.d.ts +35 -0
  72. package/dist/index.d.ts.map +1 -0
  73. package/dist/index.js +44 -0
  74. package/dist/index.js.map +1 -0
  75. package/package.json +66 -0
  76. package/schemas/superspec-workflow/schema.yaml +166 -0
  77. package/templates/design.md +71 -0
  78. package/templates/plan.md +78 -0
  79. package/templates/proposal.md +36 -0
  80. package/templates/spec.md +57 -0
  81. package/templates/tasks.md +29 -0
@@ -0,0 +1,328 @@
1
+ import { existsSync, readFileSync, readdirSync } from 'fs';
2
+ import { join } from 'path';
3
+ import { glob } from 'glob';
4
+ import { PALETTE, SYMBOLS, commandHeader, sectionDivider, createProgressBar, startSpinner, spinnerSuccess, isInteractive, selectChange, } from '../ui/index.js';
5
+ export async function verifyCommand(id, options) {
6
+ const superspecPath = join(process.cwd(), 'superspec');
7
+ if (!existsSync(superspecPath)) {
8
+ console.log(PALETTE.error('SuperSpec not initialized. Run: superspec init'));
9
+ process.exit(1);
10
+ }
11
+ // Interactive mode if no ID provided
12
+ if (!id) {
13
+ if (!isInteractive()) {
14
+ console.log(PALETTE.error('Please specify a change ID to verify.'));
15
+ process.exit(1);
16
+ }
17
+ const changesPath = join(superspecPath, 'changes');
18
+ const changes = [];
19
+ if (existsSync(changesPath)) {
20
+ const entries = readdirSync(changesPath, { withFileTypes: true });
21
+ for (const entry of entries) {
22
+ if (entry.isDirectory() && entry.name !== 'archive') {
23
+ changes.push(entry.name);
24
+ }
25
+ }
26
+ }
27
+ if (changes.length === 0) {
28
+ console.log(PALETTE.warning('No active changes found.'));
29
+ return;
30
+ }
31
+ id = await selectChange(changes, 'Select a change to verify:');
32
+ }
33
+ const changePath = join(superspecPath, 'changes', id);
34
+ const specsPath = join(changePath, 'specs');
35
+ if (!existsSync(changePath)) {
36
+ console.log(PALETTE.error(`Change not found: ${id}`));
37
+ process.exit(1);
38
+ }
39
+ if (!existsSync(specsPath)) {
40
+ console.log(PALETTE.error(`No specs found for change: ${id}`));
41
+ process.exit(1);
42
+ }
43
+ console.log(commandHeader(`verify ${id}`, 'Implementation verification'));
44
+ // Parse specs
45
+ const specSpinner = startSpinner('Parsing specifications...');
46
+ const requirements = await parseSpecs(specsPath);
47
+ spinnerSuccess(specSpinner, `Found ${requirements.length} requirements`);
48
+ // Find test files
49
+ const testSpinner = startSpinner('Scanning test files...');
50
+ const testFiles = await findTestFiles();
51
+ spinnerSuccess(testSpinner, `Found ${testFiles.length} test files`);
52
+ // Match scenarios to tests
53
+ const matchSpinner = startSpinner('Matching scenarios to tests...');
54
+ const result = await matchScenariosToTests(requirements, testFiles, options);
55
+ spinnerSuccess(matchSpinner, 'Analysis complete');
56
+ console.log();
57
+ // Print report
58
+ printVerifyReport(result, options);
59
+ if (result.verdict === 'fail') {
60
+ process.exit(1);
61
+ }
62
+ }
63
+ async function parseSpecs(specsPath) {
64
+ const requirements = [];
65
+ const entries = readdirSync(specsPath, { withFileTypes: true });
66
+ for (const entry of entries) {
67
+ if (entry.isDirectory()) {
68
+ const specFile = join(specsPath, entry.name, 'spec.md');
69
+ if (existsSync(specFile)) {
70
+ const content = readFileSync(specFile, 'utf-8');
71
+ requirements.push(...parseSpecContent(content));
72
+ }
73
+ }
74
+ }
75
+ return requirements;
76
+ }
77
+ function parseSpecContent(content) {
78
+ const requirements = [];
79
+ const lines = content.split('\n');
80
+ let currentReq = null;
81
+ let currentScenario = null;
82
+ for (const line of lines) {
83
+ // Match requirement
84
+ const reqMatch = line.match(/^### Requirement: (.+)$/);
85
+ if (reqMatch?.[1]) {
86
+ if (currentReq) {
87
+ if (currentScenario) {
88
+ currentReq.scenarios.push(currentScenario);
89
+ }
90
+ requirements.push(currentReq);
91
+ }
92
+ currentReq = { name: reqMatch[1], scenarios: [] };
93
+ currentScenario = null;
94
+ continue;
95
+ }
96
+ // Match scenario
97
+ const scenarioMatch = line.match(/^#### Scenario: (.+)$/);
98
+ if (scenarioMatch?.[1] && currentReq) {
99
+ if (currentScenario) {
100
+ currentReq.scenarios.push(currentScenario);
101
+ }
102
+ currentScenario = { name: scenarioMatch[1], when: '', then: [] };
103
+ continue;
104
+ }
105
+ // Match WHEN
106
+ const whenMatch = line.match(/^\s*-\s*\*\*WHEN\*\*\s*(.+)$/);
107
+ if (whenMatch?.[1] && currentScenario) {
108
+ currentScenario.when = whenMatch[1];
109
+ continue;
110
+ }
111
+ // Match THEN
112
+ const thenMatch = line.match(/^\s*-\s*\*\*THEN\*\*\s*(.+)$/);
113
+ if (thenMatch?.[1] && currentScenario) {
114
+ currentScenario.then.push(thenMatch[1]);
115
+ continue;
116
+ }
117
+ // Match AND
118
+ const andMatch = line.match(/^\s*-\s*\*\*AND\*\*\s*(.+)$/);
119
+ if (andMatch?.[1] && currentScenario) {
120
+ currentScenario.then.push(andMatch[1]);
121
+ }
122
+ }
123
+ // Don't forget the last ones
124
+ if (currentReq) {
125
+ if (currentScenario) {
126
+ currentReq.scenarios.push(currentScenario);
127
+ }
128
+ requirements.push(currentReq);
129
+ }
130
+ return requirements;
131
+ }
132
+ async function findTestFiles() {
133
+ const patterns = [
134
+ '**/*.test.ts',
135
+ '**/*.test.js',
136
+ '**/*.spec.ts',
137
+ '**/*.spec.js',
138
+ '**/test/**/*.ts',
139
+ '**/test/**/*.js',
140
+ '**/tests/**/*.ts',
141
+ '**/tests/**/*.js',
142
+ ];
143
+ const files = [];
144
+ for (const pattern of patterns) {
145
+ const matches = await glob(pattern, {
146
+ ignore: ['node_modules/**', 'dist/**'],
147
+ });
148
+ files.push(...matches);
149
+ }
150
+ return [...new Set(files)];
151
+ }
152
+ async function matchScenariosToTests(requirements, testFiles, options) {
153
+ const allTests = [];
154
+ // Parse test files to find test names
155
+ for (const file of testFiles) {
156
+ if (existsSync(file)) {
157
+ const content = readFileSync(file, 'utf-8');
158
+ const lines = content.split('\n');
159
+ for (let i = 0; i < lines.length; i++) {
160
+ const line = lines[i];
161
+ // Match test/it/describe patterns
162
+ const testMatch = line?.match(/(?:test|it|describe)\s*\(\s*['"`]([^'"`]+)['"`]/);
163
+ if (testMatch?.[1]) {
164
+ allTests.push({
165
+ file,
166
+ line: i + 1,
167
+ name: testMatch[1],
168
+ confidence: 'high',
169
+ });
170
+ }
171
+ }
172
+ }
173
+ }
174
+ // Match scenarios to tests
175
+ const missingTests = [];
176
+ let matchedScenarios = 0;
177
+ for (const req of requirements) {
178
+ for (const scenario of req.scenarios) {
179
+ const match = findMatchingTest(scenario.name, allTests);
180
+ if (match) {
181
+ scenario.testMatch = match;
182
+ matchedScenarios++;
183
+ }
184
+ else {
185
+ missingTests.push(scenario);
186
+ }
187
+ }
188
+ }
189
+ // Find extra tests (not matching any scenario)
190
+ const matchedTestNames = new Set(requirements
191
+ .flatMap(r => r.scenarios)
192
+ .filter(s => s.testMatch)
193
+ .map(s => s.testMatch.name));
194
+ const extraTests = options.strict
195
+ ? allTests.filter(t => !matchedTestNames.has(t.name))
196
+ : [];
197
+ const totalScenarios = requirements.reduce((sum, r) => sum + r.scenarios.length, 0);
198
+ const reqsWithCoverage = requirements.filter(r => r.scenarios.every(s => s.testMatch)).length;
199
+ return {
200
+ requirements,
201
+ coverage: {
202
+ requirements: reqsWithCoverage,
203
+ requirementsTotal: requirements.length,
204
+ scenarios: matchedScenarios,
205
+ scenariosTotal: totalScenarios,
206
+ },
207
+ issues: {
208
+ missingTests,
209
+ extraTests,
210
+ },
211
+ verdict: missingTests.length === 0 ? 'pass' : 'fail',
212
+ };
213
+ }
214
+ function findMatchingTest(scenarioName, tests) {
215
+ // Normalize names for comparison
216
+ const normalized = scenarioName.toLowerCase().replace(/[^a-z0-9]+/g, ' ').trim();
217
+ const words = normalized.split(' ').filter(w => w.length > 2);
218
+ let bestMatch;
219
+ let bestScore = 0;
220
+ for (const test of tests) {
221
+ const testNormalized = test.name.toLowerCase().replace(/[^a-z0-9]+/g, ' ').trim();
222
+ // Exact match
223
+ if (testNormalized === normalized) {
224
+ return { ...test, confidence: 'high' };
225
+ }
226
+ // Word matching score
227
+ const testWords = testNormalized.split(' ').filter(w => w.length > 2);
228
+ const matchingWords = words.filter(w => testWords.includes(w));
229
+ const score = matchingWords.length / Math.max(words.length, testWords.length);
230
+ if (score > bestScore && score >= 0.5) {
231
+ bestScore = score;
232
+ bestMatch = {
233
+ ...test,
234
+ confidence: score >= 0.8 ? 'high' : score >= 0.6 ? 'medium' : 'low',
235
+ };
236
+ }
237
+ }
238
+ return bestMatch;
239
+ }
240
+ function printVerifyReport(result, options) {
241
+ // Coverage summary
242
+ console.log();
243
+ console.log(sectionDivider());
244
+ console.log();
245
+ console.log(` ${PALETTE.bold(PALETTE.white('📊 Coverage Summary'))}`);
246
+ console.log();
247
+ const reqPercent = result.coverage.requirementsTotal > 0
248
+ ? Math.round((result.coverage.requirements / result.coverage.requirementsTotal) * 100)
249
+ : 0;
250
+ const scenarioPercent = result.coverage.scenariosTotal > 0
251
+ ? Math.round((result.coverage.scenarios / result.coverage.scenariosTotal) * 100)
252
+ : 0;
253
+ console.log(` ${PALETTE.midGray('Requirements:')} ${createProgressBar(result.coverage.requirements, result.coverage.requirementsTotal, { width: 20 })} ${result.coverage.requirements}/${result.coverage.requirementsTotal} ${PALETTE.midGray(`(${reqPercent}%)`)}`);
254
+ console.log(` ${PALETTE.midGray('Scenarios: ')} ${createProgressBar(result.coverage.scenarios, result.coverage.scenariosTotal, { width: 20 })} ${result.coverage.scenarios}/${result.coverage.scenariosTotal} ${PALETTE.midGray(`(${scenarioPercent}%)`)}`);
255
+ // Requirement coverage detail
256
+ if (options.verbose) {
257
+ console.log();
258
+ console.log(sectionDivider());
259
+ console.log();
260
+ console.log(` ${PALETTE.bold(PALETTE.white('📋 Requirement Coverage'))}`);
261
+ console.log();
262
+ for (const req of result.requirements) {
263
+ const allCovered = req.scenarios.every(s => s.testMatch);
264
+ const icon = allCovered
265
+ ? PALETTE.success(SYMBOLS.success)
266
+ : PALETTE.error(SYMBOLS.error);
267
+ console.log(` ${icon} ${PALETTE.primary(req.name)}`);
268
+ for (const scenario of req.scenarios) {
269
+ const sIcon = scenario.testMatch
270
+ ? PALETTE.success(' ' + SYMBOLS.success)
271
+ : PALETTE.error(' ' + SYMBOLS.error);
272
+ if (scenario.testMatch) {
273
+ const confidence = scenario.testMatch.confidence === 'high'
274
+ ? ''
275
+ : PALETTE.warning(` [${scenario.testMatch.confidence}]`);
276
+ console.log(` ${sIcon} ${scenario.name}${confidence}`);
277
+ console.log(` ${PALETTE.darkGray('→')} ${PALETTE.midGray(`${scenario.testMatch.file}:${scenario.testMatch.line}`)}`);
278
+ }
279
+ else {
280
+ console.log(` ${sIcon} ${scenario.name} ${PALETTE.error('(no test found)')}`);
281
+ }
282
+ }
283
+ console.log();
284
+ }
285
+ }
286
+ // Issues
287
+ if (result.issues.missingTests.length > 0) {
288
+ console.log();
289
+ console.log(sectionDivider());
290
+ console.log();
291
+ console.log(` ${PALETTE.bold(PALETTE.white('⚠️ Missing Tests'))}`);
292
+ console.log();
293
+ for (const scenario of result.issues.missingTests) {
294
+ console.log(` ${PALETTE.error(SYMBOLS.error)} ${scenario.name}`);
295
+ }
296
+ }
297
+ if (result.issues.extraTests.length > 0) {
298
+ console.log();
299
+ console.log(sectionDivider());
300
+ console.log();
301
+ console.log(` ${PALETTE.bold(PALETTE.white('📝 Extra Tests (not in Specs)'))}`);
302
+ console.log();
303
+ const displayCount = Math.min(result.issues.extraTests.length, 10);
304
+ for (const test of result.issues.extraTests.slice(0, displayCount)) {
305
+ console.log(` ${PALETTE.warning(SYMBOLS.warning)} ${test.name}`);
306
+ console.log(` ${PALETTE.midGray(`${test.file}:${test.line}`)}`);
307
+ }
308
+ if (result.issues.extraTests.length > 10) {
309
+ console.log(` ${PALETTE.midGray(`... and ${result.issues.extraTests.length - 10} more`)}`);
310
+ }
311
+ }
312
+ // Verdict
313
+ console.log();
314
+ console.log(sectionDivider());
315
+ console.log();
316
+ if (result.verdict === 'pass') {
317
+ console.log(` ${PALETTE.success(SYMBOLS.success)} ${PALETTE.bold(PALETTE.success('READY TO ARCHIVE'))}`);
318
+ console.log();
319
+ console.log(` ${PALETTE.midGray('Next:')} ${PALETTE.white('superspec archive <change-id>')}`);
320
+ }
321
+ else {
322
+ console.log(` ${PALETTE.error(SYMBOLS.error)} ${PALETTE.bold(PALETTE.error('NEEDS WORK'))}`);
323
+ console.log();
324
+ console.log(` ${PALETTE.midGray('Write tests for missing scenarios before archiving.')}`);
325
+ }
326
+ console.log();
327
+ }
328
+ //# sourceMappingURL=verify.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verify.js","sourceRoot":"","sources":["../../../src/cli/commands/verify.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ interface ViewOptions {
2
+ json?: boolean;
3
+ }
4
+ export declare function viewCommand(options: ViewOptions): Promise<void>;
5
+ export {};
6
+ //# sourceMappingURL=view.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"view.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/view.ts"],"names":[],"mappings":"AAiBA,UAAU,WAAW;IACnB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AA8BD,wBAAsB,WAAW,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CA8KrE"}
@@ -0,0 +1,290 @@
1
+ import { existsSync, readFileSync, readdirSync } from 'fs';
2
+ import { join } from 'path';
3
+ import matter from 'gray-matter';
4
+ import { PALETTE, ICONS, BOX, sectionHeader, createProgressBar, startSpinner, spinnerSuccess, isInteractive, selectPrompt, displayCommand, displayStats, } from '../ui/index.js';
5
+ export async function viewCommand(options) {
6
+ const superspecPath = join(process.cwd(), 'superspec');
7
+ if (!existsSync(superspecPath)) {
8
+ console.log(` ${ICONS.error} ${PALETTE.error('SuperSpec not initialized.')}`);
9
+ console.log(` ${PALETTE.dim('Run:')} ${PALETTE.accent('superspec init')}`);
10
+ process.exit(1);
11
+ }
12
+ const spinner = startSpinner('Loading project overview...');
13
+ const overview = gatherProjectOverview(superspecPath);
14
+ spinnerSuccess(spinner, 'Project loaded');
15
+ if (options.json) {
16
+ console.log(JSON.stringify(overview, null, 2));
17
+ return;
18
+ }
19
+ // ═══════════════════════════════════════════════════════════════════════════
20
+ // DASHBOARD HEADER
21
+ // ═══════════════════════════════════════════════════════════════════════════
22
+ console.log();
23
+ console.log(` ${PALETTE.subtle(BOX.heavyTopLeft + BOX.heavyH.repeat(58) + BOX.heavyTopRight)}`);
24
+ console.log(` ${PALETTE.subtle(BOX.heavyV)} ${PALETTE.primary('⬡')} ${PALETTE.bold(PALETTE.white('SuperSpec Dashboard'))}${' '.repeat(36)}${PALETTE.subtle(BOX.heavyV)}`);
25
+ console.log(` ${PALETTE.subtle(BOX.heavyBottomLeft + BOX.heavyH.repeat(58) + BOX.heavyBottomRight)}`);
26
+ // ═══════════════════════════════════════════════════════════════════════════
27
+ // PROJECT STATISTICS
28
+ // ═══════════════════════════════════════════════════════════════════════════
29
+ console.log(sectionHeader('Project Statistics', '📊'));
30
+ console.log();
31
+ displayStats([
32
+ { label: 'Main Specs', value: overview.stats.mainSpecCount },
33
+ { label: 'Active', value: overview.stats.activeChangeCount },
34
+ { label: 'Archived', value: overview.stats.archivedChangeCount },
35
+ ]);
36
+ console.log();
37
+ displayStats([
38
+ { label: 'Requirements', value: overview.stats.totalRequirements, icon: PALETTE.primary('◆') },
39
+ { label: 'Scenarios', value: overview.stats.totalScenarios, icon: PALETTE.accent('◆') },
40
+ ]);
41
+ // ═══════════════════════════════════════════════════════════════════════════
42
+ // ACTIVE CHANGES
43
+ // ═══════════════════════════════════════════════════════════════════════════
44
+ console.log(sectionHeader('Active Changes', '🔄'));
45
+ console.log();
46
+ if (overview.activeChanges.length > 0) {
47
+ for (const change of overview.activeChanges) {
48
+ const phaseIcon = getPhaseIcon(change.phase);
49
+ const title = change.title
50
+ ? PALETTE.dim(` - ${change.title.slice(0, 35)}${change.title.length > 35 ? '…' : ''}`)
51
+ : '';
52
+ console.log(` ${PALETTE.subtle('┌─')} ${phaseIcon} ${PALETTE.bold(PALETTE.white(change.id))}${title}`);
53
+ // Progress bar if in execute phase
54
+ if (change.progress && change.progress.total > 0) {
55
+ const { completed, total } = change.progress;
56
+ const bar = createProgressBar(completed, total, { width: 18, showCount: true });
57
+ console.log(` ${PALETTE.subtle('│')} ${bar}`);
58
+ }
59
+ // Phase indicator
60
+ const phases = ['proposal', 'design', 'spec', 'plan', 'execute', 'verify'];
61
+ const currentPhaseIndex = phases.indexOf(change.phase);
62
+ const phaseBar = phases.map((p, i) => {
63
+ if (i < currentPhaseIndex)
64
+ return PALETTE.success('●');
65
+ if (i === currentPhaseIndex)
66
+ return PALETTE.accent('●');
67
+ return PALETTE.dark('○');
68
+ }).join(' ');
69
+ console.log(` ${PALETTE.subtle('│')} ${PALETTE.dim('Phase:')} ${phaseBar}`);
70
+ console.log(` ${PALETTE.subtle('└─')}`);
71
+ console.log();
72
+ }
73
+ }
74
+ else {
75
+ console.log(` ${PALETTE.dim('No active changes.')}`);
76
+ console.log();
77
+ displayCommand('/superspec:brainstorm', 'Start a new change');
78
+ console.log();
79
+ }
80
+ // ═══════════════════════════════════════════════════════════════════════════
81
+ // MAIN SPECIFICATIONS
82
+ // ═══════════════════════════════════════════════════════════════════════════
83
+ if (overview.mainSpecs.length > 0) {
84
+ console.log(sectionHeader('Main Specifications', '📋'));
85
+ console.log();
86
+ // Table header
87
+ console.log(` ${PALETTE.bold(PALETTE.dim('Name'.padEnd(28)))} ${PALETTE.bold(PALETTE.dim('Reqs'.padStart(8)))} ${PALETTE.bold(PALETTE.dim('Scenarios'.padStart(10)))}`);
88
+ console.log(` ${PALETTE.dark('─'.repeat(28))} ${PALETTE.dark('─'.repeat(8))} ${PALETTE.dark('─'.repeat(10))}`);
89
+ for (const spec of overview.mainSpecs.slice(0, 8)) {
90
+ const name = spec.name.length > 27
91
+ ? spec.name.slice(0, 25) + '…'
92
+ : spec.name;
93
+ console.log(` ${PALETTE.primaryBright(name.padEnd(28))} ${PALETTE.white(String(spec.requirementCount).padStart(8))} ${PALETTE.white(String(spec.scenarioCount).padStart(10))}`);
94
+ }
95
+ if (overview.mainSpecs.length > 8) {
96
+ console.log(` ${PALETTE.dim(`... and ${overview.mainSpecs.length - 8} more`)}`);
97
+ }
98
+ console.log();
99
+ }
100
+ // ═══════════════════════════════════════════════════════════════════════════
101
+ // QUICK ACTIONS
102
+ // ═══════════════════════════════════════════════════════════════════════════
103
+ console.log(sectionHeader('Quick Actions', '🚀'));
104
+ console.log();
105
+ displayCommand('superspec list', 'View all changes');
106
+ displayCommand('superspec list -s', 'View all specs');
107
+ displayCommand('superspec validate', 'Validate specs');
108
+ displayCommand('/superspec:brainstorm', 'Start new change');
109
+ console.log();
110
+ // ═══════════════════════════════════════════════════════════════════════════
111
+ // INTERACTIVE NAVIGATION
112
+ // ═══════════════════════════════════════════════════════════════════════════
113
+ if (isInteractive() && (overview.activeChanges.length > 0 || overview.mainSpecs.length > 0)) {
114
+ console.log(` ${PALETTE.subtle('─'.repeat(55))}`);
115
+ console.log();
116
+ const choices = [
117
+ { name: `${PALETTE.primary('›')} View a change`, value: 'change' },
118
+ { name: `${PALETTE.primary('›')} View a spec`, value: 'spec' },
119
+ { name: `${PALETTE.primary('›')} Run validation`, value: 'validate' },
120
+ { name: PALETTE.dim(' (Exit)'), value: 'exit' },
121
+ ];
122
+ const action = await selectPrompt({
123
+ message: 'What would you like to do?',
124
+ choices,
125
+ });
126
+ if (action === 'change' && overview.activeChanges.length > 0) {
127
+ const { showCommand } = await import('./show.js');
128
+ const changeChoices = overview.activeChanges.map(c => ({
129
+ name: `${c.id}${c.title ? ` - ${c.title}` : ''}`,
130
+ value: c.id,
131
+ }));
132
+ const selectedChange = await selectPrompt({
133
+ message: 'Select a change:',
134
+ choices: [...changeChoices, { name: PALETTE.dim('(Cancel)'), value: '' }],
135
+ });
136
+ if (selectedChange) {
137
+ await showCommand(selectedChange, {});
138
+ }
139
+ }
140
+ else if (action === 'spec' && overview.mainSpecs.length > 0) {
141
+ const { showCommand } = await import('./show.js');
142
+ const specChoices = overview.mainSpecs.map(s => ({
143
+ name: `${s.name} (${s.requirementCount} requirements)`,
144
+ value: s.name,
145
+ }));
146
+ const selectedSpec = await selectPrompt({
147
+ message: 'Select a spec:',
148
+ choices: [...specChoices, { name: PALETTE.dim('(Cancel)'), value: '' }],
149
+ });
150
+ if (selectedSpec) {
151
+ await showCommand(selectedSpec, {});
152
+ }
153
+ }
154
+ else if (action === 'validate') {
155
+ const { validateCommand } = await import('./validate.js');
156
+ await validateCommand(undefined, { all: true });
157
+ }
158
+ }
159
+ }
160
+ function gatherProjectOverview(superspecPath) {
161
+ const overview = {
162
+ initialized: true,
163
+ activeChanges: [],
164
+ archivedChanges: 0,
165
+ mainSpecs: [],
166
+ stats: {
167
+ totalRequirements: 0,
168
+ totalScenarios: 0,
169
+ activeChangeCount: 0,
170
+ archivedChangeCount: 0,
171
+ mainSpecCount: 0,
172
+ },
173
+ };
174
+ // Gather active changes
175
+ const changesPath = join(superspecPath, 'changes');
176
+ if (existsSync(changesPath)) {
177
+ const entries = readdirSync(changesPath, { withFileTypes: true });
178
+ for (const entry of entries) {
179
+ if (entry.isDirectory() && entry.name !== 'archive') {
180
+ const changePath = join(changesPath, entry.name);
181
+ overview.activeChanges.push(getChangeOverview(entry.name, changePath));
182
+ }
183
+ }
184
+ }
185
+ // Count archived changes
186
+ const archivePath = join(changesPath, 'archive');
187
+ if (existsSync(archivePath)) {
188
+ const entries = readdirSync(archivePath, { withFileTypes: true });
189
+ overview.archivedChanges = entries.filter(e => e.isDirectory()).length;
190
+ }
191
+ // Gather main specs
192
+ const specsPath = join(superspecPath, 'specs');
193
+ if (existsSync(specsPath)) {
194
+ const entries = readdirSync(specsPath, { withFileTypes: true });
195
+ for (const entry of entries) {
196
+ if (entry.isDirectory()) {
197
+ const specFile = join(specsPath, entry.name, 'spec.md');
198
+ if (existsSync(specFile)) {
199
+ overview.mainSpecs.push(getSpecOverview(entry.name, specFile));
200
+ }
201
+ }
202
+ }
203
+ }
204
+ // Calculate stats
205
+ overview.stats.activeChangeCount = overview.activeChanges.length;
206
+ overview.stats.archivedChangeCount = overview.archivedChanges;
207
+ overview.stats.mainSpecCount = overview.mainSpecs.length;
208
+ overview.stats.totalRequirements = overview.mainSpecs.reduce((sum, s) => sum + s.requirementCount, 0);
209
+ overview.stats.totalScenarios = overview.mainSpecs.reduce((sum, s) => sum + s.scenarioCount, 0);
210
+ return overview;
211
+ }
212
+ function getChangeOverview(id, path) {
213
+ const overview = {
214
+ id,
215
+ phase: 'proposal',
216
+ specCount: 0,
217
+ };
218
+ // Get title from proposal
219
+ const proposalPath = join(path, 'proposal.md');
220
+ if (existsSync(proposalPath)) {
221
+ try {
222
+ const content = readFileSync(proposalPath, 'utf-8');
223
+ const { data } = matter(content);
224
+ overview.title = data['title'];
225
+ }
226
+ catch { /* ignore */ }
227
+ }
228
+ // Determine phase
229
+ const hasDesign = existsSync(join(path, 'design.md'));
230
+ const hasSpecs = existsSync(join(path, 'specs'));
231
+ const hasPlan = existsSync(join(path, 'plan.md'));
232
+ const hasTasks = existsSync(join(path, 'tasks.md'));
233
+ if (hasTasks) {
234
+ const content = readFileSync(join(path, 'tasks.md'), 'utf-8');
235
+ const total = (content.match(/^- \[[ x]\]/gm) ?? []).length;
236
+ const completed = (content.match(/^- \[x\]/gm) ?? []).length;
237
+ overview.progress = { completed, total };
238
+ if (completed === total && total > 0) {
239
+ overview.phase = 'verify';
240
+ }
241
+ else {
242
+ overview.phase = 'execute';
243
+ }
244
+ }
245
+ else if (hasPlan) {
246
+ overview.phase = 'plan';
247
+ }
248
+ else if (hasSpecs) {
249
+ overview.phase = 'spec';
250
+ }
251
+ else if (hasDesign) {
252
+ overview.phase = 'design';
253
+ }
254
+ else {
255
+ overview.phase = 'proposal';
256
+ }
257
+ // Count specs
258
+ const specsPath = join(path, 'specs');
259
+ if (existsSync(specsPath)) {
260
+ const entries = readdirSync(specsPath, { withFileTypes: true });
261
+ overview.specCount = entries.filter(e => e.isDirectory()).length;
262
+ }
263
+ return overview;
264
+ }
265
+ function getSpecOverview(name, path) {
266
+ const overview = {
267
+ name,
268
+ requirementCount: 0,
269
+ scenarioCount: 0,
270
+ };
271
+ try {
272
+ const content = readFileSync(path, 'utf-8');
273
+ overview.requirementCount = (content.match(/^### Requirement:/gm) ?? []).length;
274
+ overview.scenarioCount = (content.match(/^#### Scenario:/gm) ?? []).length;
275
+ }
276
+ catch { /* ignore */ }
277
+ return overview;
278
+ }
279
+ function getPhaseIcon(phase) {
280
+ const icons = {
281
+ proposal: PALETTE.dark('◐'),
282
+ design: PALETTE.dim('◑'),
283
+ spec: PALETTE.primary('◐'),
284
+ plan: PALETTE.primaryBright('◑'),
285
+ execute: PALETTE.accent('◉'),
286
+ verify: PALETTE.success('●'),
287
+ };
288
+ return icons[phase] ?? PALETTE.dark('○');
289
+ }
290
+ //# sourceMappingURL=view.js.map