@polymorphism-tech/morph-spec 3.1.0 → 3.2.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 (51) hide show
  1. package/CLAUDE.md +534 -0
  2. package/README.md +78 -4
  3. package/bin/morph-spec.js +50 -1
  4. package/bin/render-template.js +56 -10
  5. package/bin/task-manager.cjs +101 -7
  6. package/docs/cli-auto-detection.md +219 -0
  7. package/docs/llm-interaction-config.md +735 -0
  8. package/docs/troubleshooting.md +269 -0
  9. package/package.json +5 -1
  10. package/src/commands/advance-phase.js +93 -2
  11. package/src/commands/approve.js +221 -0
  12. package/src/commands/capture-pattern.js +121 -0
  13. package/src/commands/generate.js +128 -1
  14. package/src/commands/init.js +37 -0
  15. package/src/commands/migrate-state.js +158 -0
  16. package/src/commands/search-patterns.js +126 -0
  17. package/src/commands/spawn-team.js +172 -0
  18. package/src/commands/task.js +2 -2
  19. package/src/commands/update.js +36 -0
  20. package/src/commands/upgrade.js +346 -0
  21. package/src/generator/.gitkeep +0 -0
  22. package/src/generator/config-generator.js +206 -0
  23. package/src/generator/templates/config.json.template +40 -0
  24. package/src/generator/templates/project.md.template +67 -0
  25. package/src/lib/checkpoint-hooks.js +258 -0
  26. package/src/lib/metadata-extractor.js +380 -0
  27. package/src/lib/phase-state-machine.js +214 -0
  28. package/src/lib/state-manager.js +120 -0
  29. package/src/lib/template-data-sources.js +325 -0
  30. package/src/lib/validators/content-validator.js +351 -0
  31. package/src/llm/.gitkeep +0 -0
  32. package/src/llm/analyzer.js +215 -0
  33. package/src/llm/environment-detector.js +43 -0
  34. package/src/llm/few-shot-examples.js +216 -0
  35. package/src/llm/project-config-schema.json +188 -0
  36. package/src/llm/prompt-builder.js +96 -0
  37. package/src/llm/schema-validator.js +121 -0
  38. package/src/orchestrator.js +206 -0
  39. package/src/sanitizer/.gitkeep +0 -0
  40. package/src/sanitizer/context-sanitizer.js +221 -0
  41. package/src/sanitizer/patterns.js +163 -0
  42. package/src/scanner/.gitkeep +0 -0
  43. package/src/scanner/project-scanner.js +242 -0
  44. package/src/types/index.js +477 -0
  45. package/src/ui/.gitkeep +0 -0
  46. package/src/ui/diff-display.js +91 -0
  47. package/src/ui/interactive-wizard.js +96 -0
  48. package/src/ui/user-review.js +211 -0
  49. package/src/ui/wizard-questions.js +190 -0
  50. package/src/writer/.gitkeep +0 -0
  51. package/src/writer/file-writer.js +86 -0
@@ -0,0 +1,269 @@
1
+ # Troubleshooting - CLI Auto Context Detection
2
+
3
+ Common issues and solutions for MORPH-SPEC auto-detection.
4
+
5
+ ## Claude Code Issues
6
+
7
+ ### Issue: "Claude Code environment not detected"
8
+
9
+ **Cause**: Auto-detection requires Claude Code CLI to be installed and active.
10
+
11
+ **Solutions**:
12
+
13
+ 1. **Use wizard mode** (recommended for first-time setup):
14
+ ```bash
15
+ morph-spec init --wizard
16
+ ```
17
+
18
+ 2. **Install Claude Code** and retry:
19
+ - Download from https://claude.ai/claude-code
20
+ - Ensure `claude` command is in PATH
21
+ - Retry `morph-spec init`
22
+
23
+ 3. **Skip auto-detection** and configure manually later:
24
+ ```bash
25
+ morph-spec init --skip-detection
26
+ # Later: morph-spec update --wizard
27
+ ```
28
+
29
+ ### Issue: "LLM analysis timeout"
30
+
31
+ **Cause**: Analysis taking longer than 60 seconds (default timeout for interactive mode).
32
+
33
+ **Solutions**:
34
+
35
+ 1. **Clean project before analysis**:
36
+ ```bash
37
+ rm -rf node_modules dist build .next
38
+ morph-spec init
39
+ ```
40
+
41
+ 2. **Use wizard mode** (instant):
42
+ ```bash
43
+ morph-spec init --wizard
44
+ ```
45
+
46
+ 3. **Check Claude Code performance**:
47
+ - Restart Claude Code
48
+ - Check system resources (CPU, memory)
49
+
50
+ ## LLM Analysis Errors
51
+
52
+ ### Issue: "Schema validation failed"
53
+
54
+ **Cause**: LLM returned JSON that doesn't match the expected schema.
55
+
56
+ **Diagnosis**:
57
+ ```bash
58
+ # Enable debug mode to see LLM response
59
+ DEBUG=1 morph-spec init
60
+ ```
61
+
62
+ **Solutions**:
63
+
64
+ 1. **Use wizard mode** to provide manual input:
65
+ ```bash
66
+ morph-spec init --wizard
67
+ ```
68
+
69
+ 2. **Report issue** if recurring:
70
+ - Include project type in issue report
71
+ - Share anonymized `package.json` or `.csproj` structure
72
+
73
+ ### Issue: "LLM response is not valid JSON"
74
+
75
+ **Cause**: LLM returned malformed JSON (rare).
76
+
77
+ **Solutions**:
78
+
79
+ 1. **Retry** - may be a one-time error:
80
+ ```bash
81
+ morph-spec init
82
+ ```
83
+
84
+ 2. **Use wizard mode**:
85
+ ```bash
86
+ morph-spec init --wizard
87
+ ```
88
+
89
+ ## File System Issues
90
+
91
+ ### Issue: "Permission denied" when creating .morph/
92
+
93
+ **Cause**: Insufficient permissions in project directory.
94
+
95
+ **Solutions**:
96
+
97
+ 1. **Run with correct permissions**:
98
+ ```bash
99
+ sudo morph-spec init # Unix/Mac
100
+ # Or run as administrator on Windows
101
+ ```
102
+
103
+ 2. **Check directory ownership**:
104
+ ```bash
105
+ ls -la . # Should show your user as owner
106
+ ```
107
+
108
+ ### Issue: Config files getting overwritten
109
+
110
+ **Cause**: Running `morph-spec update` without reviewing changes.
111
+
112
+ **Protection**: Auto-detection creates backups:
113
+ - `.morph/project.md.YYYY-MM-DDTHH-MM-SS.backup`
114
+ - `.morph/config/config.json.YYYY-MM-DDTHH-MM-SS.backup`
115
+
116
+ **Solutions**:
117
+
118
+ 1. **Review diff before approving**:
119
+ - Auto-detection shows diff when updating
120
+ - Choose "Edit" to modify before saving
121
+
122
+ 2. **Restore from backup** if needed:
123
+ ```bash
124
+ cp .morph/project.md.2026-02-14T10-30-00.backup .morph/project.md
125
+ ```
126
+
127
+ 3. **Skip auto-detection** during update:
128
+ ```bash
129
+ morph-spec update --skip-detection
130
+ ```
131
+
132
+ ## Detection Accuracy Issues
133
+
134
+ ### Issue: Wrong project type detected
135
+
136
+ **Example**: Monorepo detected as `nextjs` instead of `monorepo`.
137
+
138
+ **Solutions**:
139
+
140
+ 1. **Use wizard mode** for accurate manual input:
141
+ ```bash
142
+ morph-spec init --wizard
143
+ ```
144
+
145
+ 2. **Edit config after generation**:
146
+ - Choose "Edit" during review
147
+ - Manually correct `type` field in config.json
148
+
149
+ 3. **Report detection issue**:
150
+ - Helps improve LLM prompt and examples
151
+
152
+ ### Issue: Missing dependencies detected
153
+
154
+ **Cause**: Auto-detection only reads whitelisted files (package.json, .csproj).
155
+
156
+ **Solution**:
157
+
158
+ - This is by design (privacy/security)
159
+ - If critical dependency is missed, manually edit `.morph/project.md`
160
+
161
+ ### Issue: Low confidence score (<70%)
162
+
163
+ **Cause**: Project structure is unclear or non-standard.
164
+
165
+ **Solutions**:
166
+
167
+ 1. **Add README.md or CLAUDE.md** with project description
168
+ 2. **Use wizard mode** for manual configuration
169
+ 3. **Accept low confidence** - configs can be edited later
170
+
171
+ ## Edge Case Handling
172
+
173
+ ### Empty Project (no package.json or .csproj)
174
+
175
+ **Behavior**: Auto-fallback to wizard mode.
176
+
177
+ **Solution**: Answer 7 wizard questions to configure manually.
178
+
179
+ ### Monorepo with Multiple Stacks
180
+
181
+ **Behavior**: Detects all stacks, sets `type: "monorepo"`.
182
+
183
+ **Example Output**:
184
+ ```json
185
+ {
186
+ "type": "monorepo",
187
+ "stack": {
188
+ "frontend": { "tech": "Next.js", "version": "15" },
189
+ "backend": { "tech": ".NET", "version": "10" }
190
+ }
191
+ }
192
+ ```
193
+
194
+ ### Project with No Database
195
+
196
+ **Behavior**: `stack.database` set to `null`.
197
+
198
+ **Warning**: May show "Database technology not detected" in warnings.
199
+
200
+ ### Git Repo Without Remote
201
+
202
+ **Behavior**: `gitRemote` set to `null`.
203
+
204
+ **Not an error** - local repos are valid.
205
+
206
+ ## Privacy & Security Concerns
207
+
208
+ ### Question: What data is sent to LLM?
209
+
210
+ **Answer**: Only sanitized, whitelisted data:
211
+ - package.json (dependencies only, secrets removed)
212
+ - .csproj filenames (not contents)
213
+ - First 500 chars of README.md and CLAUDE.md
214
+ - Directory structure (folder names only)
215
+ - Infrastructure file counts (not contents)
216
+
217
+ **Never sent**:
218
+ - `.env` files
219
+ - Secrets/passwords/API keys
220
+ - File contents (except whitelisted files)
221
+ - node_modules/
222
+ - Source code
223
+
224
+ ### Question: Is data sent to Anthropic servers?
225
+
226
+ **Answer**: No. LLM analysis runs locally in Claude Code. No external API calls.
227
+
228
+ ### Question: What if sensitive data is detected?
229
+
230
+ **Behavior**: Secret redaction removes:
231
+ - API keys (10+ patterns detected)
232
+ - Passwords in connection strings
233
+ - Bearer tokens
234
+ - Private keys (PEM format)
235
+ - GitHub/NPM tokens
236
+
237
+ **Verification**: Review sanitized context in debug mode:
238
+ ```bash
239
+ DEBUG=1 morph-spec init
240
+ ```
241
+
242
+ ## Getting Help
243
+
244
+ ### Enable Debug Mode
245
+
246
+ ```bash
247
+ DEBUG=1 morph-spec init
248
+ ```
249
+
250
+ Shows:
251
+ - Full LLM prompts
252
+ - Raw LLM responses
253
+ - Schema validation errors
254
+ - File read operations
255
+
256
+ ### Report Issues
257
+
258
+ GitHub: https://github.com/polymorphism-tech/morph-spec-framework/issues
259
+
260
+ Include:
261
+ - MORPH-SPEC version (`morph-spec --version`)
262
+ - Claude Code version
263
+ - Project type (Next.js, Blazor, etc.)
264
+ - Error message (with DEBUG=1 output if possible)
265
+ - Anonymized `package.json` or `.csproj` structure
266
+
267
+ ---
268
+
269
+ **Need more help?** Check the [CLI Auto Detection Guide](./cli-auto-detection.md).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@polymorphism-tech/morph-spec",
3
- "version": "3.1.0",
3
+ "version": "3.2.0",
4
4
  "description": "MORPH-SPEC v3: AI-First development framework with validation pipeline, .NET 10, Microsoft Agent Framework, and Fluent UI Blazor",
5
5
  "keywords": [
6
6
  "claude-code",
@@ -52,8 +52,12 @@
52
52
  "ajv-formats": "^3.0.1",
53
53
  "chalk": "^5.3.0",
54
54
  "commander": "^12.0.0",
55
+ "diff": "^5.2.0",
55
56
  "fs-extra": "^11.2.0",
56
57
  "glob": "^10.3.0",
58
+ "handlebars": "^4.7.8",
59
+ "inquirer": "^9.2.0",
60
+ "minimatch": "^9.0.5",
57
61
  "ora": "^8.0.0",
58
62
  "yaml": "^2.3.4"
59
63
  },
@@ -10,10 +10,12 @@
10
10
  */
11
11
 
12
12
  import chalk from 'chalk';
13
- import { loadState, saveState, getFeature } from '../lib/state-manager.js';
13
+ import { loadState, saveState, getFeature, getApprovalGate } from '../lib/state-manager.js';
14
14
  import { PHASES, validatePhase } from './validate-phase.js';
15
15
  import { detectDesignSystem, hasUIAgentsActive } from '../lib/design-system-detector.js';
16
16
  import { validateSpec } from '../lib/spec-validator.js';
17
+ import { validateTransition, getPhaseDisplayName } from '../lib/phase-state-machine.js';
18
+ import { validateSpecContent, validateTasksContent, validateFeatureOutputs } from '../lib/validators/content-validator.js';
17
19
 
18
20
  // Phase order for advancing (skips optional phases unless active)
19
21
  const PHASE_ORDER = ['proposal', 'setup', 'uiux', 'design', 'clarify', 'tasks', 'implement', 'sync'];
@@ -96,6 +98,42 @@ export async function advancePhaseCommand(feature, options = {}) {
96
98
  const nextPhaseDef = PHASES[nextPhase];
97
99
  console.log(chalk.gray('Next Phase:'), nextPhaseDef.name);
98
100
 
101
+ // === GATE 1: State Machine Validation ===
102
+ // Ensure phase transition is valid (no skipping required phases)
103
+ if (!options.force) {
104
+ try {
105
+ validateTransition(currentPhase, nextPhase);
106
+ } catch (error) {
107
+ console.log(chalk.red('\n✗ Invalid phase transition'));
108
+ console.log(chalk.yellow(error.message));
109
+ console.log(chalk.gray('\nUse --force to override (not recommended)\n'));
110
+ process.exit(1);
111
+ }
112
+ }
113
+
114
+ // === GATE 2: Approval Gate Check ===
115
+ // Check if current phase requires approval before advancing
116
+ const approvalGateMap = {
117
+ 'design': 'design',
118
+ 'tasks': 'tasks',
119
+ 'uiux': 'uiux'
120
+ };
121
+
122
+ const requiredGate = approvalGateMap[currentPhase];
123
+ if (requiredGate && !options.skipApproval) {
124
+ const gateStatus = getApprovalGate(feature, requiredGate);
125
+
126
+ if (!gateStatus || !gateStatus.approved) {
127
+ console.log(chalk.red(`\n✗ Phase "${currentPhase}" requires approval before advancing`));
128
+ console.log(chalk.yellow(`\nRun: morph-spec approve ${feature} ${requiredGate}`));
129
+ console.log(chalk.gray('Or use --skip-approval to bypass (not recommended)\n'));
130
+ process.exit(1);
131
+ }
132
+
133
+ console.log(chalk.green(`✓ Approval gate "${requiredGate}" passed`));
134
+ }
135
+
136
+ // === GATE 3: Output Requirements ===
99
137
  // Validate that current phase requirements are met before advancing
100
138
  const validation = validatePhase(feature, nextPhase);
101
139
 
@@ -112,8 +150,34 @@ export async function advancePhaseCommand(feature, options = {}) {
112
150
  console.log(chalk.yellow(`\n⚠️ ${validation.stateWarning}`));
113
151
  }
114
152
 
115
- // Gate: Validate spec.md and contracts.cs when advancing from design phase
153
+ // === GATE 4: Content Validation ===
154
+ // Validate spec.md and contracts.cs when advancing from design phase
116
155
  if (currentPhase === 'design' && (nextPhase === 'clarify' || nextPhase === 'tasks')) {
156
+ // Check spec.md structure and content
157
+ if (featureData.outputs?.spec?.created) {
158
+ const specContentValidation = validateSpecContent(featureData.outputs.spec.path);
159
+
160
+ if (!specContentValidation.valid) {
161
+ console.log(chalk.red('\n✗ Spec content validation failed:'));
162
+ specContentValidation.missing.forEach(section => {
163
+ console.log(chalk.red(` - Missing section: ${section}`));
164
+ });
165
+ specContentValidation.errors.forEach(error => {
166
+ console.log(chalk.red(` - ${error}`));
167
+ });
168
+ console.log('');
169
+ process.exit(1);
170
+ }
171
+
172
+ if (specContentValidation.warnings?.length > 0 && !options.skipWarnings) {
173
+ console.log(chalk.yellow('\n⚠️ Spec content warnings:'));
174
+ specContentValidation.warnings.forEach(warning => {
175
+ console.log(chalk.yellow(` - ${warning}`));
176
+ });
177
+ }
178
+ }
179
+
180
+ // Run existing spec validator (anti-patterns, IaC checks)
117
181
  const specValidation = await validateSpec('.', feature);
118
182
 
119
183
  if (specValidation.errors > 0) {
@@ -135,6 +199,33 @@ export async function advancePhaseCommand(feature, options = {}) {
135
199
  }
136
200
  }
137
201
 
202
+ // === GATE 5: Tasks Content Validation ===
203
+ // Validate tasks.json structure when advancing to implement
204
+ if (currentPhase === 'tasks' && nextPhase === 'implement') {
205
+ if (featureData.outputs?.tasks?.created) {
206
+ const tasksContentValidation = validateTasksContent(featureData.outputs.tasks.path);
207
+
208
+ if (!tasksContentValidation.valid) {
209
+ console.log(chalk.red('\n✗ Tasks content validation failed:'));
210
+ tasksContentValidation.errors.forEach(error => {
211
+ console.log(chalk.red(` - ${error}`));
212
+ });
213
+ console.log('');
214
+ process.exit(1);
215
+ }
216
+
217
+ if (tasksContentValidation.warnings?.length > 0 && !options.skipWarnings) {
218
+ console.log(chalk.yellow('\n⚠️ Tasks content warnings:'));
219
+ tasksContentValidation.warnings.forEach(warning => {
220
+ console.log(chalk.yellow(` - ${warning}`));
221
+ });
222
+ }
223
+
224
+ // Show tasks stats
225
+ console.log(chalk.green(`\n✓ Tasks validated: ${tasksContentValidation.stats.totalTasks} total (${tasksContentValidation.stats.regularTasks} tasks + ${tasksContentValidation.stats.checkpoints} checkpoints)`));
226
+ }
227
+ }
228
+
138
229
  // Gate: Check design system when advancing to implement with UI agents
139
230
  if (nextPhase === 'implement') {
140
231
  const gateResult = designSystemGate(feature);
@@ -0,0 +1,221 @@
1
+ import { Command } from 'commander';
2
+ import chalk from 'chalk';
3
+ import { getFeature, setApprovalGate, getApprovalGate, getApprovalHistory } from '../lib/state-manager.js';
4
+
5
+ /**
6
+ * Approval Commands - Manage approval gates for MORPH workflow
7
+ *
8
+ * Commands:
9
+ * - approve: Mark a gate as approved
10
+ * - reject: Reject a gate with reason
11
+ * - approval-status: Show approval status for all gates
12
+ */
13
+
14
+ const program = new Command();
15
+
16
+ /**
17
+ * Valid approval gate names
18
+ */
19
+ const VALID_GATES = ['proposal', 'uiux', 'design', 'tasks'];
20
+
21
+ /**
22
+ * Approve action function - Mark a gate as approved
23
+ */
24
+ export async function approveCommand(featureName, gateName, options = {}) {
25
+ try {
26
+ // Validate gate name
27
+ if (!VALID_GATES.includes(gateName)) {
28
+ console.error(chalk.red(`\n❌ Invalid gate: ${gateName}`));
29
+ console.log(chalk.gray(`Valid gates: ${VALID_GATES.join(', ')}\n`));
30
+ process.exit(1);
31
+ }
32
+
33
+ // Get feature state
34
+ const feature = getFeature(featureName);
35
+ if (!feature) {
36
+ console.error(chalk.red(`\n❌ Feature not found: ${featureName}\n`));
37
+ process.exit(1);
38
+ }
39
+
40
+ // Check if already approved
41
+ const currentStatus = getApprovalGate(featureName, gateName);
42
+ if (currentStatus?.approved) {
43
+ console.log(chalk.yellow(`\n⚠️ Gate "${gateName}" is already approved`));
44
+ console.log(chalk.gray(`Approved at: ${currentStatus.timestamp}`));
45
+ console.log(chalk.gray(`Approved by: ${currentStatus.approvedBy || 'Unknown'}\n`));
46
+ return;
47
+ }
48
+
49
+ // Set approval
50
+ setApprovalGate(featureName, gateName, true, {
51
+ approvedBy: options.approver || process.env.USER || process.env.USERNAME || 'user',
52
+ approvedAt: new Date().toISOString(),
53
+ notes: options.notes
54
+ });
55
+
56
+ console.log(chalk.green(`\n✅ Gate "${gateName}" approved for feature: ${featureName}`));
57
+ console.log(chalk.gray(`Workflow can now proceed past ${gateName} phase\n`));
58
+
59
+ } catch (error) {
60
+ console.error(chalk.red(`\n❌ Error approving gate: ${error.message}\n`));
61
+ process.exit(1);
62
+ }
63
+ }
64
+
65
+ /**
66
+ * Approve command - Mark a gate as approved
67
+ */
68
+ program
69
+ .command('approve <feature> <gate>')
70
+ .description('Approve a phase gate to allow workflow progression')
71
+ .action(approveCommand);
72
+
73
+ /**
74
+ * Reject action function - Reject a gate with optional reason
75
+ */
76
+ export async function rejectCommand(featureName, gateName, reason, options = {}) {
77
+ try {
78
+ // Validate gate name
79
+ if (!VALID_GATES.includes(gateName)) {
80
+ console.error(chalk.red(`\n❌ Invalid gate: ${gateName}`));
81
+ console.log(chalk.gray(`Valid gates: ${VALID_GATES.join(', ')}\n`));
82
+ process.exit(1);
83
+ }
84
+
85
+ // Get feature state
86
+ const feature = getFeature(featureName);
87
+ if (!feature) {
88
+ console.error(chalk.red(`\n❌ Feature not found: ${featureName}\n`));
89
+ process.exit(1);
90
+ }
91
+
92
+ // Set rejection
93
+ setApprovalGate(featureName, gateName, false, {
94
+ rejectedBy: process.env.USER || process.env.USERNAME || 'user',
95
+ rejectedAt: new Date().toISOString(),
96
+ reason: reason || 'No reason provided'
97
+ });
98
+
99
+ console.log(chalk.red(`\n❌ Gate "${gateName}" rejected for feature: ${featureName}`));
100
+ if (reason) {
101
+ console.log(chalk.gray(`Reason: ${reason}`));
102
+ }
103
+ console.log(chalk.yellow(`\n⚠️ Address the concerns and request approval again\n`));
104
+
105
+ } catch (error) {
106
+ console.error(chalk.red(`\n❌ Error rejecting gate: ${error.message}\n`));
107
+ process.exit(1);
108
+ }
109
+ }
110
+
111
+ /**
112
+ * Reject command - Reject a gate with optional reason
113
+ */
114
+ program
115
+ .command('reject <feature> <gate> [reason]')
116
+ .description('Reject a phase gate with optional reason')
117
+ .action(rejectCommand);
118
+
119
+ /**
120
+ * Approval status action function - Show all gates and their status
121
+ */
122
+ export async function approvalStatusCommand(featureName, options = {}) {
123
+ try {
124
+ // Get feature state
125
+ const feature = getFeature(featureName);
126
+ if (!feature) {
127
+ console.error(chalk.red(`\n❌ Feature not found: ${featureName}\n`));
128
+ process.exit(1);
129
+ }
130
+
131
+ // JSON output
132
+ if (options.json) {
133
+ const status = {
134
+ feature: featureName,
135
+ phase: feature.phase,
136
+ status: feature.status,
137
+ gates: {}
138
+ };
139
+
140
+ for (const gateName of VALID_GATES) {
141
+ status.gates[gateName] = getApprovalGate(featureName, gateName) || { approved: false };
142
+ }
143
+
144
+ console.log(JSON.stringify(status, null, 2));
145
+ return;
146
+ }
147
+
148
+ console.log(chalk.bold(`\n📋 Approval Status for: ${featureName}`));
149
+ console.log('━'.repeat(60));
150
+
151
+ // Show current phase
152
+ console.log(chalk.cyan(`\nCurrent Phase: ${feature.phase || 'unknown'}`));
153
+ console.log(chalk.gray(`Feature Status: ${feature.status || 'unknown'}\n`));
154
+
155
+ // Show each gate
156
+ console.log(chalk.bold('Approval Gates:'));
157
+
158
+ for (const gateName of VALID_GATES) {
159
+ const gateStatus = getApprovalGate(featureName, gateName);
160
+
161
+ if (!gateStatus) {
162
+ console.log(` ${chalk.gray('○')} ${gateName}: ${chalk.gray('Not yet evaluated')}`);
163
+ continue;
164
+ }
165
+
166
+ if (gateStatus.approved) {
167
+ console.log(` ${chalk.green('✓')} ${gateName}: ${chalk.green('Approved')}`);
168
+ if (gateStatus.timestamp) {
169
+ console.log(chalk.gray(` Approved at: ${gateStatus.timestamp}`));
170
+ }
171
+ if (gateStatus.approvedBy) {
172
+ console.log(chalk.gray(` Approved by: ${gateStatus.approvedBy}`));
173
+ }
174
+ } else {
175
+ console.log(` ${chalk.red('✗')} ${gateName}: ${chalk.red('Rejected / Not Approved')}`);
176
+ if (gateStatus.reason) {
177
+ console.log(chalk.gray(` Reason: ${gateStatus.reason}`));
178
+ }
179
+ if (gateStatus.timestamp) {
180
+ console.log(chalk.gray(` Rejected at: ${gateStatus.timestamp}`));
181
+ }
182
+ }
183
+ }
184
+
185
+ // Show approval history if available
186
+ const history = getApprovalHistory(featureName);
187
+ if (history && history.length > 0) {
188
+ console.log(chalk.bold('\nApproval History:'));
189
+ history.slice(-5).forEach(entry => {
190
+ const status = entry.approved ? chalk.green('✓ Approved') : chalk.red('✗ Rejected');
191
+ console.log(` ${status} ${entry.gate} - ${entry.timestamp}`);
192
+ });
193
+ }
194
+
195
+ console.log('\n' + '━'.repeat(60) + '\n');
196
+
197
+ } catch (error) {
198
+ console.error(chalk.red(`\n❌ Error showing approval status: ${error.message}\n`));
199
+ process.exit(1);
200
+ }
201
+ }
202
+
203
+ /**
204
+ * Approval status command - Show all gates and their status
205
+ */
206
+ program
207
+ .command('approval-status <feature>')
208
+ .alias('status')
209
+ .description('Show approval status for all gates')
210
+ .action(approvalStatusCommand);
211
+
212
+ // Only parse if run directly (not imported as module)
213
+ if (import.meta.url === `file://${process.argv[1]}`) {
214
+ if (process.argv.length > 2) {
215
+ program.parse(process.argv);
216
+ } else {
217
+ program.help();
218
+ }
219
+ }
220
+
221
+ export default program;