@specsafe/cli 0.4.0 → 0.6.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 (39) hide show
  1. package/dist/commands/apply.d.ts +3 -0
  2. package/dist/commands/apply.d.ts.map +1 -0
  3. package/dist/commands/apply.js +182 -0
  4. package/dist/commands/apply.js.map +1 -0
  5. package/dist/commands/constitution.d.ts +3 -0
  6. package/dist/commands/constitution.d.ts.map +1 -0
  7. package/dist/commands/constitution.js +192 -0
  8. package/dist/commands/constitution.js.map +1 -0
  9. package/dist/commands/delta.d.ts +3 -0
  10. package/dist/commands/delta.d.ts.map +1 -0
  11. package/dist/commands/delta.js +82 -0
  12. package/dist/commands/delta.js.map +1 -0
  13. package/dist/commands/diff.d.ts +3 -0
  14. package/dist/commands/diff.d.ts.map +1 -0
  15. package/dist/commands/diff.js +102 -0
  16. package/dist/commands/diff.js.map +1 -0
  17. package/dist/commands/extend.d.ts +6 -0
  18. package/dist/commands/extend.d.ts.map +1 -0
  19. package/dist/commands/extend.js +167 -0
  20. package/dist/commands/extend.js.map +1 -0
  21. package/dist/commands/init-old.d.ts +3 -0
  22. package/dist/commands/init-old.d.ts.map +1 -0
  23. package/dist/commands/init-old.js +146 -0
  24. package/dist/commands/init-old.js.map +1 -0
  25. package/dist/commands/init.d.ts.map +1 -1
  26. package/dist/commands/init.js +195 -43
  27. package/dist/commands/init.js.map +1 -1
  28. package/dist/commands/new.d.ts.map +1 -1
  29. package/dist/commands/new.js +26 -8
  30. package/dist/commands/new.js.map +1 -1
  31. package/dist/commands/qa.d.ts.map +1 -1
  32. package/dist/commands/qa.js +37 -1
  33. package/dist/commands/qa.js.map +1 -1
  34. package/dist/commands/rules.d.ts.map +1 -1
  35. package/dist/commands/rules.js +182 -97
  36. package/dist/commands/rules.js.map +1 -1
  37. package/dist/index.js +15 -0
  38. package/dist/index.js.map +1 -1
  39. package/package.json +3 -3
@@ -0,0 +1,3 @@
1
+ import { Command } from 'commander';
2
+ export declare const applyCommand: Command;
3
+ //# sourceMappingURL=apply.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apply.d.ts","sourceRoot":"","sources":["../../src/commands/apply.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAQpC,eAAO,MAAM,YAAY,SAqMrB,CAAC"}
@@ -0,0 +1,182 @@
1
+ import { Command } from 'commander';
2
+ import chalk from 'chalk';
3
+ import ora from 'ora';
4
+ import { readFile, writeFile, readdir, copyFile, mkdir, unlink } from 'fs/promises';
5
+ import { join } from 'path';
6
+ import { DeltaParser, SemanticMerger } from '@specsafe/core';
7
+ import { confirm } from '@inquirer/prompts';
8
+ export const applyCommand = new Command('apply')
9
+ .description('Apply pending delta specs to a base spec')
10
+ .argument('<spec-id>', 'Base spec ID (e.g., SPEC-20260101-001)')
11
+ .option('--no-backup', 'Skip creating backup before applying')
12
+ .option('-f, --force', 'Apply even if conflicts exist')
13
+ .action(async (specId, options) => {
14
+ const spinner = ora('Loading delta specs...').start();
15
+ try {
16
+ // Validate specId to prevent path traversal
17
+ if (!/^[A-Za-z0-9_-]+$/.test(specId)) {
18
+ spinner.fail(chalk.red('Invalid spec ID. Use only alphanumeric characters, hyphens, and underscores.'));
19
+ process.exit(1);
20
+ }
21
+ // Load base spec
22
+ const baseSpecPath = join('specs/active', `${specId}.md`);
23
+ let baseContent;
24
+ try {
25
+ baseContent = await readFile(baseSpecPath, 'utf-8');
26
+ }
27
+ catch {
28
+ spinner.fail(chalk.red(`Base spec not found: ${specId}`));
29
+ console.log(chalk.gray('šŸ’” Tip: Check that the spec exists in specs/active/'));
30
+ process.exit(1);
31
+ }
32
+ // Find all delta specs for this base spec
33
+ const deltasDir = 'specs/deltas';
34
+ let deltaFiles = [];
35
+ try {
36
+ const files = await readdir(deltasDir);
37
+ deltaFiles = files.filter(f => f.startsWith(`DELTA-${specId}-`) && f.endsWith('.md'));
38
+ }
39
+ catch {
40
+ spinner.fail(chalk.red('No deltas directory found'));
41
+ console.log(chalk.gray('šŸ’” Tip: Create a delta spec first with: specsafe delta <spec-id>'));
42
+ process.exit(1);
43
+ }
44
+ if (deltaFiles.length === 0) {
45
+ spinner.fail(chalk.red(`No delta specs found for ${specId}`));
46
+ console.log(chalk.gray('šŸ’” Tip: Create a delta spec first with: specsafe delta <spec-id>'));
47
+ process.exit(1);
48
+ }
49
+ spinner.text = `Found ${deltaFiles.length} delta spec(s)`;
50
+ // Parse all delta specs
51
+ const parser = new DeltaParser();
52
+ const deltaSpecs = [];
53
+ for (const file of deltaFiles) {
54
+ const deltaPath = join(deltasDir, file);
55
+ const deltaContent = await readFile(deltaPath, 'utf-8');
56
+ const deltaId = file.replace('.md', '');
57
+ try {
58
+ const deltaSpec = parser.parse(deltaContent, deltaId, specId);
59
+ const validation = parser.validate(deltaSpec);
60
+ if (!validation.valid) {
61
+ spinner.warn(chalk.yellow(`Validation errors in ${deltaId}:`));
62
+ for (const error of validation.errors) {
63
+ console.log(chalk.yellow(` - ${error}`));
64
+ }
65
+ if (!options.force) {
66
+ const proceed = await confirm({
67
+ message: 'Continue with other deltas?',
68
+ default: false
69
+ });
70
+ if (!proceed) {
71
+ process.exit(1);
72
+ }
73
+ spinner.start('Continuing with other deltas...');
74
+ continue;
75
+ }
76
+ spinner.start('Continuing...');
77
+ }
78
+ deltaSpecs.push(deltaSpec);
79
+ }
80
+ catch (err) {
81
+ spinner.warn(chalk.yellow(`Failed to parse ${deltaId}: ${err.message}`));
82
+ spinner.start('Continuing...');
83
+ continue;
84
+ }
85
+ }
86
+ if (deltaSpecs.length === 0) {
87
+ spinner.fail(chalk.red('No valid delta specs to apply'));
88
+ process.exit(1);
89
+ }
90
+ spinner.text = `Applying ${deltaSpecs.length} delta spec(s)...`;
91
+ // Apply all deltas in sequence
92
+ const merger = new SemanticMerger();
93
+ let currentContent = baseContent;
94
+ let totalStats = {
95
+ added: 0,
96
+ modified: 0,
97
+ removed: 0,
98
+ conflicts: 0
99
+ };
100
+ for (const deltaSpec of deltaSpecs) {
101
+ const result = merger.merge(currentContent, deltaSpec);
102
+ // Accumulate stats
103
+ totalStats.added += result.stats.added;
104
+ totalStats.modified += result.stats.modified;
105
+ totalStats.removed += result.stats.removed;
106
+ totalStats.conflicts += result.stats.conflicts;
107
+ if (result.conflicts.length > 0) {
108
+ spinner.warn(chalk.yellow(`Conflicts in ${deltaSpec.id}:`));
109
+ for (const conflict of result.conflicts) {
110
+ console.log(chalk.yellow(` - ${conflict.message}`));
111
+ }
112
+ if (!options.force) {
113
+ const proceed = await confirm({
114
+ message: 'Apply anyway (may result in incomplete merge)?',
115
+ default: false
116
+ });
117
+ if (!proceed) {
118
+ spinner.fail(chalk.red('Apply cancelled due to conflicts'));
119
+ process.exit(1);
120
+ }
121
+ spinner.start();
122
+ }
123
+ }
124
+ currentContent = result.content;
125
+ }
126
+ spinner.stop();
127
+ // Show preview of changes
128
+ console.log(chalk.blue('\nšŸ“Š Merge Summary:'));
129
+ console.log(chalk.green(` āœ“ Added: ${totalStats.added} requirements`));
130
+ console.log(chalk.yellow(` ~ Modified: ${totalStats.modified} requirements`));
131
+ console.log(chalk.red(` - Removed: ${totalStats.removed} requirements`));
132
+ if (totalStats.conflicts > 0) {
133
+ console.log(chalk.red(` ⚠ Conflicts: ${totalStats.conflicts}`));
134
+ }
135
+ // Confirm before writing
136
+ const proceed = await confirm({
137
+ message: 'Apply these changes to the base spec?',
138
+ default: true
139
+ });
140
+ if (!proceed) {
141
+ console.log(chalk.yellow('\nApply cancelled.'));
142
+ process.exit(0);
143
+ }
144
+ spinner.start('Applying changes...');
145
+ // Create backup if requested
146
+ if (options.backup) {
147
+ const backupDir = join('specs', 'backups');
148
+ await mkdir(backupDir, { recursive: true });
149
+ const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
150
+ const backupPath = join(backupDir, `${specId}-${timestamp}.md`);
151
+ await copyFile(baseSpecPath, backupPath);
152
+ spinner.text = `Created backup: ${backupPath}`;
153
+ }
154
+ // Write merged content
155
+ await writeFile(baseSpecPath, currentContent);
156
+ // Archive applied deltas (only those that were successfully applied)
157
+ const archiveDir = join('specs', 'deltas', 'applied');
158
+ await mkdir(archiveDir, { recursive: true });
159
+ for (const deltaSpec of deltaSpecs) {
160
+ const deltaFile = `${deltaSpec.id}.md`;
161
+ const deltaPath = join(deltasDir, deltaFile);
162
+ const archivePath = join(archiveDir, deltaFile);
163
+ await copyFile(deltaPath, archivePath);
164
+ await unlink(deltaPath); // Remove original after archiving
165
+ }
166
+ spinner.succeed(chalk.green(`Successfully applied ${deltaSpecs.length} delta spec(s) to ${specId}`));
167
+ console.log(chalk.blue(` Updated: ${baseSpecPath}`));
168
+ if (options.backup) {
169
+ console.log(chalk.blue(` Backup: specs/backups/`));
170
+ }
171
+ console.log(chalk.blue(` Archived deltas: specs/deltas/applied/`));
172
+ console.log(chalk.gray('\n Next steps:'));
173
+ console.log(chalk.gray(` 1. Review changes: git diff ${baseSpecPath}`));
174
+ console.log(chalk.gray(` 2. Update tests if needed`));
175
+ console.log(chalk.gray(` 3. Run: specsafe verify ${specId}`));
176
+ }
177
+ catch (error) {
178
+ spinner.fail(chalk.red(`Failed to apply deltas: ${error.message}`));
179
+ process.exit(1);
180
+ }
181
+ });
182
+ //# sourceMappingURL=apply.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apply.js","sourceRoot":"","sources":["../../src/commands/apply.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { Command } from 'commander';
2
+ export declare const constitutionCommand: Command;
3
+ //# sourceMappingURL=constitution.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constitution.d.ts","sourceRoot":"","sources":["../../src/commands/constitution.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAwBpC,eAAO,MAAM,mBAAmB,SAgM7B,CAAC"}
@@ -0,0 +1,192 @@
1
+ import { Command } from 'commander';
2
+ import chalk from 'chalk';
3
+ import ora from 'ora';
4
+ import { writeFile, mkdir, readFile } from 'fs/promises';
5
+ import { existsSync } from 'fs';
6
+ import { join } from 'path';
7
+ import { ConstitutionManager, generateConstitution, generateMinimalConstitution, generateStrictConstitution, BUILTIN_PRINCIPLES } from '@specsafe/core';
8
+ async function loadSpec(specId, cwd = process.cwd()) {
9
+ const specsDir = join(cwd, 'specs');
10
+ const specPath = join(specsDir, `${specId}.json`);
11
+ if (!existsSync(specPath))
12
+ throw new Error(`Spec file not found: ${specPath}`);
13
+ const content = await readFile(specPath, 'utf-8');
14
+ const spec = JSON.parse(content);
15
+ spec.createdAt = new Date(spec.createdAt);
16
+ spec.updatedAt = new Date(spec.updatedAt);
17
+ if (spec.completedAt)
18
+ spec.completedAt = new Date(spec.completedAt);
19
+ return spec;
20
+ }
21
+ export const constitutionCommand = new Command('constitution')
22
+ .description('Manage constitutional governance')
23
+ .addCommand(new Command('init')
24
+ .description('Initialize constitution')
25
+ .option('--minimal', 'Minimal constitution')
26
+ .option('--strict', 'Strict constitution')
27
+ .option('--force', 'Overwrite existing')
28
+ .action(async (options) => {
29
+ const spinner = ora('Initializing...').start();
30
+ try {
31
+ const cwd = process.cwd();
32
+ const specsafeDir = join(cwd, '.specsafe');
33
+ const constitutionPath = join(specsafeDir, 'constitution.md');
34
+ if (existsSync(constitutionPath) && !options.force) {
35
+ spinner.fail(chalk.red('Constitution exists. Use --force'));
36
+ process.exit(1);
37
+ }
38
+ await mkdir(specsafeDir, { recursive: true });
39
+ let projectName = 'My Project';
40
+ try {
41
+ const pkgPath = join(cwd, 'package.json');
42
+ if (existsSync(pkgPath)) {
43
+ const pkg = JSON.parse(await readFile(pkgPath, 'utf-8'));
44
+ projectName = pkg.name || projectName;
45
+ }
46
+ }
47
+ catch { }
48
+ let content;
49
+ if (options.minimal)
50
+ content = generateMinimalConstitution(projectName);
51
+ else if (options.strict)
52
+ content = generateStrictConstitution(projectName);
53
+ else
54
+ content = generateConstitution({ projectName });
55
+ await writeFile(constitutionPath, content);
56
+ spinner.succeed(chalk.green('Constitution initialized'));
57
+ console.log(chalk.gray(`\n${constitutionPath}`));
58
+ }
59
+ catch (error) {
60
+ spinner.fail(chalk.red(error.message));
61
+ process.exit(1);
62
+ }
63
+ }))
64
+ .addCommand(new Command('list')
65
+ .description('List principles')
66
+ .option('--builtin-only', 'Show built-ins only')
67
+ .action(async (options) => {
68
+ const spinner = ora('Loading...').start();
69
+ try {
70
+ if (options.builtinOnly) {
71
+ spinner.stop();
72
+ console.log(chalk.bold('\nšŸ“‹ Built-in Principles:\n'));
73
+ for (const p of BUILTIN_PRINCIPLES) {
74
+ const lock = p.immutable ? 'šŸ”’' : 'šŸ”“';
75
+ const sev = p.severity === 'error' ? '🚫' : 'āš ļø';
76
+ console.log(`${lock} ${sev} ${chalk.cyan(p.id.padEnd(30))} ${p.name}`);
77
+ }
78
+ return;
79
+ }
80
+ const mgr = new ConstitutionManager();
81
+ await mgr.load({ includeBuiltins: true });
82
+ const principles = mgr.listPrinciples();
83
+ spinner.stop();
84
+ console.log(chalk.bold('\nšŸ“‹ Principles:\n'));
85
+ const errors = principles.filter(p => p.severity === 'error');
86
+ const warnings = principles.filter(p => p.severity === 'warning');
87
+ if (errors.length > 0) {
88
+ console.log(chalk.bold('🚫 Errors:'));
89
+ for (const p of errors) {
90
+ const lock = p.immutable ? 'šŸ”’' : 'šŸ”“';
91
+ console.log(` ${lock} ${chalk.red(p.id.padEnd(30))} ${p.name}`);
92
+ }
93
+ console.log();
94
+ }
95
+ if (warnings.length > 0) {
96
+ console.log(chalk.bold('āš ļø Warnings:'));
97
+ for (const p of warnings) {
98
+ const lock = p.immutable ? 'šŸ”’' : 'šŸ”“';
99
+ console.log(` ${lock} ${chalk.yellow(p.id.padEnd(30))} ${p.name}`);
100
+ }
101
+ console.log();
102
+ }
103
+ console.log(chalk.gray(`Total: ${principles.length}`));
104
+ }
105
+ catch (error) {
106
+ spinner.fail(chalk.red(error.message));
107
+ process.exit(1);
108
+ }
109
+ }))
110
+ .addCommand(new Command('check')
111
+ .description('Check spec governance')
112
+ .argument('<spec-id>', 'Spec ID')
113
+ .action(async (specId) => {
114
+ const spinner = ora('Checking...').start();
115
+ try {
116
+ const spec = await loadSpec(specId);
117
+ const mgr = new ConstitutionManager();
118
+ await mgr.load({ includeBuiltins: true });
119
+ const results = await mgr.validate(spec);
120
+ spinner.stop();
121
+ console.log(chalk.bold(`\nšŸ” ${spec.name}\n`));
122
+ let totalErrors = 0;
123
+ let totalWarnings = 0;
124
+ for (const result of results) {
125
+ const icon = result.passed ? 'āœ…' : 'āŒ';
126
+ const color = result.passed ? chalk.green : chalk.red;
127
+ console.log(`${icon} ${color(result.gate.name)}`);
128
+ if (result.violations.length > 0) {
129
+ for (const v of result.violations) {
130
+ const vIcon = v.severity === 'error' ? '🚫' : 'āš ļø';
131
+ const vColor = v.severity === 'error' ? chalk.red : chalk.yellow;
132
+ console.log(` ${vIcon} ${vColor(v.principle.name)}`);
133
+ console.log(` ${chalk.gray(v.message)}`);
134
+ }
135
+ }
136
+ totalErrors += result.violations.filter(v => v.severity === 'error').length;
137
+ totalWarnings += result.violations.filter(v => v.severity === 'warning').length;
138
+ }
139
+ console.log(chalk.bold('\nSummary:'));
140
+ console.log(chalk.gray(`Gates: ${results.length}`));
141
+ if (totalErrors > 0)
142
+ console.log(chalk.red(`Errors: ${totalErrors}`));
143
+ if (totalWarnings > 0)
144
+ console.log(chalk.yellow(`Warnings: ${totalWarnings}`));
145
+ if (totalErrors === 0) {
146
+ console.log(chalk.green('\n✨ Passed!'));
147
+ }
148
+ else {
149
+ console.log(chalk.red('\nāŒ Failed'));
150
+ process.exit(1);
151
+ }
152
+ }
153
+ catch (error) {
154
+ spinner.fail(chalk.red(error.message));
155
+ process.exit(1);
156
+ }
157
+ }))
158
+ .addCommand(new Command('add')
159
+ .description('Add custom principle')
160
+ .argument('<id>', 'Principle ID')
161
+ .requiredOption('--name <name>', 'Name')
162
+ .requiredOption('--description <desc>', 'Description')
163
+ .option('--severity <level>', 'error or warning', 'warning')
164
+ .option('--immutable', 'Immutable', false)
165
+ .action(async (id, options) => {
166
+ const spinner = ora('Adding...').start();
167
+ try {
168
+ if (options.severity !== 'error' && options.severity !== 'warning') {
169
+ throw new Error('Severity must be error or warning');
170
+ }
171
+ const mgr = new ConstitutionManager();
172
+ await mgr.load({ includeBuiltins: false });
173
+ const principle = {
174
+ id,
175
+ name: options.name,
176
+ description: options.description,
177
+ severity: options.severity,
178
+ immutable: options.immutable,
179
+ metadata: { createdAt: new Date() },
180
+ };
181
+ mgr.addPrinciple(principle);
182
+ spinner.text = 'Saving...';
183
+ await mgr.save();
184
+ spinner.succeed(chalk.green('Added and saved'));
185
+ console.log(chalk.gray(`\n${principle.id}: ${principle.name}`));
186
+ }
187
+ catch (error) {
188
+ spinner.fail(chalk.red(error.message));
189
+ process.exit(1);
190
+ }
191
+ }));
192
+ //# sourceMappingURL=constitution.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constitution.js","sourceRoot":"","sources":["../../src/commands/constitution.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { Command } from 'commander';
2
+ export declare const deltaCommand: Command;
3
+ //# sourceMappingURL=delta.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"delta.d.ts","sourceRoot":"","sources":["../../src/commands/delta.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AASpC,eAAO,MAAM,YAAY,SA6ErB,CAAC"}
@@ -0,0 +1,82 @@
1
+ import { Command } from 'commander';
2
+ import chalk from 'chalk';
3
+ import ora from 'ora';
4
+ import { writeFile, mkdir, readFile } from 'fs/promises';
5
+ import { join } from 'path';
6
+ import { generateDeltaTemplate } from '@specsafe/core';
7
+ import { confirm } from '@inquirer/prompts';
8
+ import { execFileSync } from 'child_process';
9
+ export const deltaCommand = new Command('delta')
10
+ .description('Create a new delta spec for an existing spec (brownfield changes)')
11
+ .argument('<spec-id>', 'Base spec ID (e.g., SPEC-20260101-001)')
12
+ .option('-a, --author <author>', 'Author name', 'developer')
13
+ .option('--no-edit', 'Create without opening in editor')
14
+ .action(async (specId, options) => {
15
+ const spinner = ora('Creating delta spec...').start();
16
+ try {
17
+ // Validate specId to prevent path traversal
18
+ if (!/^[A-Za-z0-9_-]+$/.test(specId)) {
19
+ spinner.fail(chalk.red('Invalid spec ID. Use only alphanumeric characters, hyphens, and underscores.'));
20
+ process.exit(1);
21
+ }
22
+ // Validate base spec exists
23
+ const baseSpecPath = join('specs/active', `${specId}.md`);
24
+ try {
25
+ await readFile(baseSpecPath, 'utf-8');
26
+ }
27
+ catch {
28
+ spinner.fail(chalk.red(`Base spec not found: ${specId}`));
29
+ console.log(chalk.gray('šŸ’” Tip: Check that the spec exists in specs/active/'));
30
+ process.exit(1);
31
+ }
32
+ // Generate delta spec ID
33
+ const date = new Date().toISOString().split('T')[0].replace(/-/g, '');
34
+ const deltaId = `DELTA-${specId}-${date}`;
35
+ // Create deltas directory if needed
36
+ await mkdir('specs/deltas', { recursive: true });
37
+ const deltaPath = join('specs/deltas', `${deltaId}.md`);
38
+ // Check if delta already exists
39
+ try {
40
+ await readFile(deltaPath, 'utf-8');
41
+ spinner.stop();
42
+ const overwrite = await confirm({
43
+ message: `Delta spec ${deltaId} already exists. Overwrite?`,
44
+ default: false
45
+ });
46
+ if (!overwrite) {
47
+ spinner.stop();
48
+ console.log(chalk.yellow('Delta creation cancelled.'));
49
+ process.exit(0);
50
+ }
51
+ }
52
+ catch {
53
+ // File doesn't exist, proceed
54
+ }
55
+ // Generate template
56
+ const template = generateDeltaTemplate(deltaId, specId, options.author);
57
+ await writeFile(deltaPath, template);
58
+ spinner.succeed(chalk.green(`Created delta spec: ${deltaId}`));
59
+ console.log(chalk.blue(` Location: ${deltaPath}`));
60
+ console.log(chalk.gray('\n Next steps:'));
61
+ console.log(chalk.gray(` 1. Edit ${deltaPath} to describe changes`));
62
+ console.log(chalk.gray(` 2. Run: specsafe diff ${specId}`));
63
+ console.log(chalk.gray(` 3. Run: specsafe apply ${specId}`));
64
+ // Open in editor if requested
65
+ if (options.edit) {
66
+ spinner.start('Opening in editor...');
67
+ try {
68
+ const editor = process.env.EDITOR || 'nano';
69
+ execFileSync(editor, [deltaPath], { stdio: 'inherit' });
70
+ spinner.stop();
71
+ }
72
+ catch (err) {
73
+ spinner.warn(chalk.yellow('Could not open editor. Edit the file manually.'));
74
+ }
75
+ }
76
+ }
77
+ catch (error) {
78
+ spinner.fail(chalk.red(`Failed to create delta spec: ${error.message}`));
79
+ process.exit(1);
80
+ }
81
+ });
82
+ //# sourceMappingURL=delta.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"delta.js","sourceRoot":"","sources":["../../src/commands/delta.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { Command } from 'commander';
2
+ export declare const diffCommand: Command;
3
+ //# sourceMappingURL=diff.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff.d.ts","sourceRoot":"","sources":["../../src/commands/diff.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAOpC,eAAO,MAAM,WAAW,SA2GpB,CAAC"}
@@ -0,0 +1,102 @@
1
+ import { Command } from 'commander';
2
+ import chalk from 'chalk';
3
+ import ora from 'ora';
4
+ import { readFile, readdir } from 'fs/promises';
5
+ import { join } from 'path';
6
+ import { DeltaParser, SemanticMerger } from '@specsafe/core';
7
+ export const diffCommand = new Command('diff')
8
+ .description('Show what would change when applying delta specs')
9
+ .argument('<spec-id>', 'Base spec ID (e.g., SPEC-20260101-001)')
10
+ .option('-v, --verbose', 'Show detailed diff')
11
+ .action(async (specId, options) => {
12
+ const spinner = ora('Loading delta specs...').start();
13
+ try {
14
+ // Validate specId to prevent path traversal
15
+ if (!/^[A-Za-z0-9_-]+$/.test(specId)) {
16
+ spinner.fail(chalk.red('Invalid spec ID. Use only alphanumeric characters, hyphens, and underscores.'));
17
+ process.exit(1);
18
+ }
19
+ // Load base spec
20
+ const baseSpecPath = join('specs/active', `${specId}.md`);
21
+ let baseContent;
22
+ try {
23
+ baseContent = await readFile(baseSpecPath, 'utf-8');
24
+ }
25
+ catch {
26
+ spinner.fail(chalk.red(`Base spec not found: ${specId}`));
27
+ console.log(chalk.gray('šŸ’” Tip: Check that the spec exists in specs/active/'));
28
+ process.exit(1);
29
+ }
30
+ // Find all delta specs for this base spec
31
+ const deltasDir = 'specs/deltas';
32
+ let deltaFiles = [];
33
+ try {
34
+ const files = await readdir(deltasDir);
35
+ deltaFiles = files.filter(f => f.startsWith(`DELTA-${specId}-`) && f.endsWith('.md'));
36
+ }
37
+ catch {
38
+ spinner.fail(chalk.red('No deltas directory found'));
39
+ console.log(chalk.gray('šŸ’” Tip: Create a delta spec first with: specsafe delta <spec-id>'));
40
+ process.exit(1);
41
+ }
42
+ if (deltaFiles.length === 0) {
43
+ spinner.fail(chalk.red(`No delta specs found for ${specId}`));
44
+ console.log(chalk.gray('šŸ’” Tip: Create a delta spec first with: specsafe delta <spec-id>'));
45
+ process.exit(1);
46
+ }
47
+ spinner.succeed(chalk.green(`Found ${deltaFiles.length} delta spec(s)`));
48
+ // Parse and display each delta
49
+ const parser = new DeltaParser();
50
+ const merger = new SemanticMerger();
51
+ for (const file of deltaFiles) {
52
+ const deltaPath = join(deltasDir, file);
53
+ const deltaContent = await readFile(deltaPath, 'utf-8');
54
+ const deltaId = file.replace(/\.md$/, '');
55
+ console.log(chalk.blue(`\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━`));
56
+ console.log(chalk.blue.bold(`šŸ“„ ${deltaId}`));
57
+ console.log(chalk.blue(`━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n`));
58
+ try {
59
+ const deltaSpec = parser.parse(deltaContent, deltaId, specId);
60
+ // Validate
61
+ const validation = parser.validate(deltaSpec);
62
+ if (!validation.valid) {
63
+ console.log(chalk.red('āš ļø Validation Errors:'));
64
+ for (const error of validation.errors) {
65
+ console.log(chalk.red(` • ${error}`));
66
+ }
67
+ console.log();
68
+ }
69
+ // Show diff preview
70
+ const diffPreview = merger.diff(baseContent, deltaSpec);
71
+ console.log(diffPreview);
72
+ // Show detailed changes if verbose
73
+ if (options.verbose) {
74
+ const mergeResult = merger.merge(baseContent, deltaSpec);
75
+ console.log(chalk.blue('\nšŸ“Š Merge Statistics:'));
76
+ console.log(chalk.green(` āœ“ Added: ${mergeResult.stats.added}`));
77
+ console.log(chalk.yellow(` ~ Modified: ${mergeResult.stats.modified}`));
78
+ console.log(chalk.red(` - Removed: ${mergeResult.stats.removed}`));
79
+ if (mergeResult.conflicts.length > 0) {
80
+ console.log(chalk.red(`\nāš ļø Conflicts (${mergeResult.conflicts.length}):`));
81
+ for (const conflict of mergeResult.conflicts) {
82
+ console.log(chalk.red(` • [${conflict.type}] ${conflict.message}`));
83
+ }
84
+ }
85
+ }
86
+ }
87
+ catch (err) {
88
+ console.log(chalk.red(`āŒ Failed to parse: ${err.message}`));
89
+ }
90
+ }
91
+ console.log(chalk.blue(`\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n`));
92
+ console.log(chalk.gray(' Next steps:'));
93
+ console.log(chalk.gray(` • Review changes above`));
94
+ console.log(chalk.gray(` • Edit delta specs if needed`));
95
+ console.log(chalk.gray(` • Run: specsafe apply ${specId}`));
96
+ }
97
+ catch (error) {
98
+ spinner.fail(chalk.red(`Failed to generate diff: ${error.message}`));
99
+ process.exit(1);
100
+ }
101
+ });
102
+ //# sourceMappingURL=diff.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff.js","sourceRoot":"","sources":["../../src/commands/diff.ts"],"names":[],"mappings":"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"}