@polymorphism-tech/morph-spec 4.10.9 → 4.11.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 (145) hide show
  1. package/CLAUDE.md +3 -3
  2. package/LICENSE +71 -71
  3. package/README.md +5 -11
  4. package/bin/morph-spec.js +23 -1
  5. package/bin/task-manager.js +5 -5
  6. package/claude-plugin.json +1 -1
  7. package/docs/CHEATSHEET.md +1 -1
  8. package/docs/QUICKSTART.md +2 -8
  9. package/framework/agents/README.md +14 -14
  10. package/framework/agents/architecture/standards-architect.md +159 -159
  11. package/framework/agents/frontend/css-specialist.md +1 -1
  12. package/framework/agents/infrastructure/azure-architect.md +149 -149
  13. package/framework/agents/infrastructure/azure-deploy-specialist.md +4 -4
  14. package/framework/agents/infrastructure/infra-architect.md +48 -48
  15. package/framework/commands/morph-apply.md +18 -18
  16. package/framework/commands/morph-preflight.md +3 -3
  17. package/framework/commands/morph-proposal.md +15 -15
  18. package/framework/commands/morph-status.md +3 -3
  19. package/framework/commands/morph-troubleshoot.md +1 -1
  20. package/framework/hooks/README.md +204 -204
  21. package/framework/hooks/claude-code/pre-tool-use/task-tracking-guard.js +2 -2
  22. package/framework/hooks/claude-code/session-start/inject-morph-context.js +1 -1
  23. package/framework/hooks/claude-code/teammate-idle/teammate-idle.js +3 -3
  24. package/framework/hooks/claude-code/user-prompt/enrich-prompt.js +2 -2
  25. package/framework/hooks/git/pre-commit/agents.sh +1 -1
  26. package/framework/hooks/shared/phase-utils.js +139 -139
  27. package/framework/rules/csharp-standards.md +13 -13
  28. package/framework/rules/frontend-standards.md +13 -13
  29. package/framework/rules/infrastructure-standards.md +16 -16
  30. package/framework/rules/testing-standards.md +14 -14
  31. package/framework/skills/level-0-meta/morph-brainstorming/SKILL.md +8 -8
  32. package/framework/skills/level-0-meta/morph-checklist/SKILL.md +3 -3
  33. package/framework/skills/level-0-meta/morph-code-review-nextjs/references/review-example-nextjs.md +254 -254
  34. package/framework/skills/level-0-meta/morph-frontend-review/SKILL.md +1 -1
  35. package/framework/skills/level-0-meta/morph-init/SKILL.md +11 -11
  36. package/framework/skills/level-0-meta/morph-post-implementation/SKILL.md +3 -3
  37. package/framework/skills/level-0-meta/morph-replicate/SKILL.md +1 -1
  38. package/framework/skills/level-0-meta/morph-simulation-checklist/SKILL.md +4 -4
  39. package/framework/skills/level-0-meta/morph-tool-usage-guide/references/tools-per-phase.md +25 -25
  40. package/framework/skills/level-0-meta/morph-verification-before-completion/SKILL.md +8 -8
  41. package/framework/skills/level-1-workflows/morph-phase-clarify/SKILL.md +7 -7
  42. package/framework/skills/level-1-workflows/morph-phase-codebase-analysis/SKILL.md +4 -4
  43. package/framework/skills/level-1-workflows/morph-phase-design/SKILL.md +23 -23
  44. package/framework/skills/level-1-workflows/morph-phase-design/references/architecture-analysis-guide.md +1 -1
  45. package/framework/skills/level-1-workflows/morph-phase-implement/.morph/logs/activity.json +38 -0
  46. package/framework/skills/level-1-workflows/morph-phase-implement/SKILL.md +29 -29
  47. package/framework/skills/level-1-workflows/morph-phase-implement/prompts/implementer-prompt.md +4 -4
  48. package/framework/skills/level-1-workflows/morph-phase-plan/SKILL.md +9 -9
  49. package/framework/skills/level-1-workflows/morph-phase-setup/SKILL.md +17 -17
  50. package/framework/skills/level-1-workflows/morph-phase-tasks/.morph/logs/activity.json +14 -0
  51. package/framework/skills/level-1-workflows/morph-phase-tasks/SKILL.md +12 -12
  52. package/framework/skills/level-1-workflows/morph-phase-uiux/SKILL.md +16 -16
  53. package/framework/skills/level-1-workflows/morph-scope-escalation/SKILL.md +5 -5
  54. package/framework/standards/STANDARDS.json +2338 -2041
  55. package/framework/standards/frontend/nextjs/nextjs-patterns.md +17 -17
  56. package/framework/standards/infrastructure/supabase/supabase-custom-jwt.md +206 -0
  57. package/framework/templates/.idea/morph-templates.xml +92 -0
  58. package/framework/templates/.vscode/morph-templates.code-snippets +186 -0
  59. package/framework/templates/README.md +814 -814
  60. package/framework/templates/code/dotnet/contracts/Commands.cs +74 -74
  61. package/framework/templates/code/dotnet/contracts/Entities.cs +25 -25
  62. package/framework/templates/code/dotnet/contracts/Queries.cs +74 -74
  63. package/framework/templates/code/dotnet/contracts/README.md +74 -74
  64. package/framework/templates/code/dotnet/contracts/api-contracts.cs +173 -173
  65. package/framework/templates/code/dotnet/frontend/component.razor +239 -239
  66. package/framework/templates/code/dotnet/jobs/agent.cs +163 -163
  67. package/framework/templates/code/dotnet/jobs/job.cs +171 -171
  68. package/framework/templates/code/dotnet/test.cs +239 -239
  69. package/framework/templates/code/sql/rls-policy.sql +57 -57
  70. package/framework/templates/code/sql/supabase-migration.sql +100 -100
  71. package/framework/templates/code/sql/supabase-migration.template.sql +113 -113
  72. package/framework/templates/code/typescript/contracts.ts +168 -168
  73. package/framework/templates/context/CONTEXT.md +181 -181
  74. package/framework/templates/docs/proposal.md +182 -182
  75. package/framework/templates/docs/user-stories.md +34 -34
  76. package/framework/templates/examples/design-system-examples.md +357 -357
  77. package/framework/templates/examples/spec-examples.md +90 -90
  78. package/framework/templates/feature/decisions.md +187 -187
  79. package/framework/templates/feature/recap.md +146 -146
  80. package/framework/templates/feature/tasks.md +199 -199
  81. package/framework/templates/infrastructure/azure/README.md +286 -286
  82. package/framework/templates/infrastructure/azure/deploy-checklist.md +426 -426
  83. package/framework/templates/infrastructure/azure/parameters.dev.json +29 -29
  84. package/framework/templates/infrastructure/azure/parameters.prod.json +29 -29
  85. package/framework/templates/infrastructure/azure/parameters.staging.json +29 -29
  86. package/framework/templates/infrastructure/docker/docker-compose.template.yml +67 -67
  87. package/framework/templates/infrastructure/docker/dockerfile-api.dockerfile +38 -38
  88. package/framework/templates/infrastructure/docker/dockerfile-web.dockerfile +48 -48
  89. package/framework/templates/infrastructure/docker/easypanel.template.json +54 -54
  90. package/framework/workflows/README.md +18 -18
  91. package/framework/workflows/docs/enforcement-pipeline.md +1 -1
  92. package/framework/workflows/docs/full-morph.md +2 -2
  93. package/package.json +1 -1
  94. package/src/commands/agents/dispatch-agents.js +17 -0
  95. package/src/commands/agents/index.js +13 -13
  96. package/src/commands/agents/project-metrics.js +74 -0
  97. package/src/commands/project/doctor.js +3 -4
  98. package/src/commands/project/install-plugin-cmd.js +28 -28
  99. package/src/commands/project/setup-infra-cmd.js +12 -12
  100. package/src/commands/project/status.js +8 -1
  101. package/src/commands/scope/escalate.js +5 -3
  102. package/src/commands/standards/context-budget.js +89 -0
  103. package/src/commands/tasks/index.js +4 -4
  104. package/src/commands/templates/index.js +5 -5
  105. package/src/commands/utils/index.js +3 -3
  106. package/src/commands/validation/index.js +4 -4
  107. package/src/commands/validation/validate-feature.js +32 -3
  108. package/src/core/state/phase-state-machine.js +217 -217
  109. package/src/lib/agents/metrics-aggregator.js +56 -0
  110. package/src/lib/generators/design-system-generator.js +298 -298
  111. package/src/lib/generators/index.js +10 -10
  112. package/src/lib/generators/metadata-extractor.js +387 -387
  113. package/src/lib/stack-filter.js +65 -65
  114. package/src/lib/standards/digest-builder.js +57 -3
  115. package/src/lib/standards/index.js +7 -7
  116. package/src/lib/standards/standards-context-injector.js +302 -302
  117. package/src/lib/validators/architecture/architecture-validator.js +387 -387
  118. package/src/lib/validators/architecture/index.js +7 -7
  119. package/src/lib/validators/blazor/blazor-concurrency-analyzer.js +316 -316
  120. package/src/lib/validators/blazor/blazor-state-validator.js +279 -279
  121. package/src/lib/validators/blazor/blazor-validator.js +369 -369
  122. package/src/lib/validators/blazor/index.js +9 -9
  123. package/src/lib/validators/content/content-validator.js +287 -287
  124. package/src/lib/validators/content/index.js +7 -7
  125. package/src/lib/validators/contracts/index.js +7 -7
  126. package/src/lib/validators/css/css-validator.js +352 -352
  127. package/src/lib/validators/css/index.js +7 -7
  128. package/src/lib/validators/design-system/design-system-validator.js +231 -231
  129. package/src/lib/validators/design-system/index.js +7 -7
  130. package/src/lib/validators/nextjs/index.js +6 -6
  131. package/src/lib/validators/nextjs/next-component-validator.js +183 -183
  132. package/src/lib/validators/packages/index.js +7 -7
  133. package/src/lib/validators/packages/package-validator.js +360 -360
  134. package/src/lib/validators/shared/index.js +12 -12
  135. package/src/lib/validators/shared/issue-counter.js +18 -18
  136. package/src/lib/validators/shared/result-formatter.js +124 -124
  137. package/src/lib/validators/ui/index.js +7 -7
  138. package/src/lib/validators/ui/ui-contrast-validator.js +422 -422
  139. package/src/scripts/global-install.js +112 -58
  140. package/src/scripts/install-plugin.js +126 -126
  141. package/src/utils/claude-md-injector.js +90 -90
  142. package/src/utils/file-copier.js +200 -200
  143. package/src/utils/logger.js +32 -32
  144. package/src/utils/skills-installer.js +178 -178
  145. package/src/utils/version-checker.js +169 -175
@@ -371,7 +371,7 @@ Keywords like: `bicep`, `azure`, `deploy`, `docker`, `kubernetes`, `infrastructu
371
371
 
372
372
  ```bash
373
373
  # When creating a feature
374
- npx morph-spec feature create user-pagination \
374
+ morph-spec feature create user-pagination \
375
375
  --request "add pagination to users table"
376
376
 
377
377
  # System automatically:
@@ -385,7 +385,7 @@ npx morph-spec feature create user-pagination \
385
385
 
386
386
  ```bash
387
387
  # Analyze request without creating feature
388
- npx morph-spec detect-workflow "implement complete authentication system"
388
+ morph-spec detect-workflow "implement complete authentication system"
389
389
 
390
390
  # Output:
391
391
  Detected Workflow: full-morph (92% confidence)
@@ -407,7 +407,7 @@ Alternative Workflows:
407
407
  ### JSON Output (for automation)
408
408
 
409
409
  ```bash
410
- npx morph-spec detect-workflow "add pagination" --json
410
+ morph-spec detect-workflow "add pagination" --json
411
411
 
412
412
  # Output:
413
413
  {
@@ -435,17 +435,17 @@ npx morph-spec detect-workflow "add pagination" --json
435
435
 
436
436
  ```bash
437
437
  # Force specific workflow
438
- npx morph-spec state set user-auth workflow full-morph
438
+ morph-spec state set user-auth workflow full-morph
439
439
 
440
440
  # Re-detect after request changes
441
- npx morph-spec state detect-workflow user-auth \
441
+ morph-spec state detect-workflow user-auth \
442
442
  "implement basic login only (no OAuth)"
443
443
  ```
444
444
 
445
445
  ### View Current Workflow
446
446
 
447
447
  ```bash
448
- npx morph-spec state get user-auth workflow
448
+ morph-spec state get user-auth workflow
449
449
 
450
450
  # Output:
451
451
  Workflow: standard
@@ -594,7 +594,7 @@ Create `framework/workflows/docs/my-workflow.md` explaining the workflow.
594
594
  **3. Test Detection:**
595
595
 
596
596
  ```bash
597
- npx morph-spec detect-workflow "request with custom-keyword"
597
+ morph-spec detect-workflow "request with custom-keyword"
598
598
  ```
599
599
 
600
600
  ### Modifying Existing Workflows
@@ -675,7 +675,7 @@ Phases: Quick Analysis → Implement
675
675
 
676
676
  **User Experience:**
677
677
  ```bash
678
- npx morph-spec feature create login-typo --request "fix typo in login button"
678
+ morph-spec feature create login-typo --request "fix typo in login button"
679
679
 
680
680
  # Output:
681
681
  ✓ Detected workflow: fast-track
@@ -683,7 +683,7 @@ npx morph-spec feature create login-typo --request "fix typo in login button"
683
683
  📝 Write quick analysis (1 paragraph) and implement
684
684
 
685
685
  # User writes quick analysis, then:
686
- npx morph-spec phase advance login-typo
686
+ morph-spec phase advance login-typo
687
687
 
688
688
  # Output:
689
689
  ⏩ Skipping: setup, uiux, design, clarify, tasks, sync
@@ -704,7 +704,7 @@ Phases: PROPOSAL → DESIGN → TASKS → IMPLEMENT
704
704
 
705
705
  **User Experience:**
706
706
  ```bash
707
- npx morph-spec feature create user-pagination \
707
+ morph-spec feature create user-pagination \
708
708
  --request "add pagination to users table"
709
709
 
710
710
  # Output:
@@ -727,7 +727,7 @@ Phases: ALL (9 phases mandatory)
727
727
 
728
728
  **User Experience:**
729
729
  ```bash
730
- npx morph-spec feature create user-auth \
730
+ morph-spec feature create user-auth \
731
731
  --request "implement complete authentication system with OAuth"
732
732
 
733
733
  # Output:
@@ -750,7 +750,7 @@ Phases: PROTOTYPE ANALYSIS → TASKS → IMPLEMENT
750
750
 
751
751
  **User Experience:**
752
752
  ```bash
753
- npx morph-spec feature create dashboard-screens \
753
+ morph-spec feature create dashboard-screens \
754
754
  --request "implement screens from Figma design"
755
755
 
756
756
  # Output:
@@ -774,7 +774,7 @@ Phases: VISUAL ANALYSIS → DESIGN SYSTEM → IMPLEMENT
774
774
 
775
775
  **User Experience:**
776
776
  ```bash
777
- npx morph-spec feature create dashboard-redesign \
777
+ morph-spec feature create dashboard-redesign \
778
778
  --request "redesign dashboard to look more modern"
779
779
 
780
780
  # Output:
@@ -794,13 +794,13 @@ npx morph-spec feature create dashboard-redesign \
794
794
 
795
795
  **Solution 1: Provide more context**
796
796
  ```bash
797
- npx morph-spec feature create simple-fix \
797
+ morph-spec feature create simple-fix \
798
798
  --request "add pagination (simple, already have paginator component)"
799
799
  ```
800
800
 
801
801
  **Solution 2: Manual override**
802
802
  ```bash
803
- npx morph-spec state set my-feature workflow standard
803
+ morph-spec state set my-feature workflow standard
804
804
  ```
805
805
 
806
806
  **Solution 3: Improve keywords**
@@ -849,7 +849,7 @@ If this happens often, add keywords to workflow config:
849
849
  **Alternative:**
850
850
  Use `detect-workflow` first to see both options:
851
851
  ```bash
852
- npx morph-spec detect-workflow "add authentication"
852
+ morph-spec detect-workflow "add authentication"
853
853
 
854
854
  # Review both workflows
855
855
  # Decide based on:
@@ -891,13 +891,13 @@ Create `framework/workflows/configs/blazor-standard.json`:
891
891
  **Solution 1: Force phase**
892
892
  ```bash
893
893
  # Manually go to UIUX phase
894
- npx morph-spec phase set my-feature uiux
894
+ morph-spec phase set my-feature uiux
895
895
  ```
896
896
 
897
897
  **Solution 2: Override workflow**
898
898
  ```bash
899
899
  # Use full-morph (includes all phases)
900
- npx morph-spec state set my-feature workflow full-morph
900
+ morph-spec state set my-feature workflow full-morph
901
901
  ```
902
902
 
903
903
  **Solution 3: Document in decisions.md**
@@ -113,7 +113,7 @@ export function loadStandardsForAgent(agentId, projectPath) {
113
113
 
114
114
  ```bash
115
115
  # Standards auto-injected when running detect-agents with --json
116
- npx morph-spec detect-agents --json "create blazor dashboard"
116
+ morph-spec detect-agents --json "create blazor dashboard"
117
117
 
118
118
  # Output includes standardsSummary for each agent:
119
119
  {
@@ -18,7 +18,7 @@
18
18
  6. Ativar agentes baseado em stack + keywords
19
19
 
20
20
  ### FASE 0: PROPOSAL
21
- 1. `npx morph-spec detect "{user-request}"`
21
+ 1. `morph-spec detect "{user-request}"`
22
22
  2. Analisar solicitação, identificar stack, estimar complexidade
23
23
  3. Gerar proposal.md, registrar agentes no state.json
24
24
  - **⛔ PAUSA:** 3 itens (1 ação + 1 pergunta + 1 sugestão)
@@ -55,7 +55,7 @@
55
55
 
56
56
  ### FASE 5: IMPLEMENT
57
57
  1. Implementar task por task
58
- 2. `npx morph-spec task done {feature} {task-id}` após cada task
58
+ 2. `morph-spec task done {feature} {task-id}` após cada task
59
59
  3. Framework gerencia checkpoints automaticamente (a cada 3 tasks)
60
60
  4. Gerar recap.md ao final
61
61
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@polymorphism-tech/morph-spec",
3
- "version": "4.10.9",
3
+ "version": "4.11.0",
4
4
  "description": "MORPH-SPEC: AI-First development framework with validation pipeline and multi-stack support",
5
5
  "keywords": [
6
6
  "claude-code",
@@ -22,6 +22,7 @@ import { fileURLToPath } from 'url';
22
22
  import { loadState, stateExists } from '../../core/state/state-manager.js';
23
23
  import { buildAgentBriefing, buildValidatorPrompt } from '../../lib/standards/digest-builder.js';
24
24
  import { agentIdToSubagentType } from '../../utils/agent-id-mapper.js';
25
+ import { shouldInstall, getProjectTags } from '../../lib/stack-filter.js';
25
26
  import { parseAndGroupTasks } from '../../lib/tasks/task-parser.js';
26
27
  export { parseAndGroupTasks } from '../../lib/tasks/task-parser.js';
27
28
  import chalk from 'chalk';
@@ -222,6 +223,16 @@ export async function buildDispatchConfig(projectPath, featureName, phase, opts
222
223
  // Non-blocking — fail silent, skills block will be omitted
223
224
  }
224
225
 
226
+ // Load project config for stack filtering
227
+ const configPath = join(projectPath, '.morph', 'config.json');
228
+ let projectTags = [];
229
+ try {
230
+ if (existsSync(configPath)) {
231
+ const config = JSON.parse(readFileSync(configPath, 'utf8'));
232
+ projectTags = getProjectTags(config);
233
+ }
234
+ } catch { /* non-blocking */ }
235
+
225
236
  // Active agents from state (keyword-detected during setup phase)
226
237
  const activeAgentIds = new Set(feature.activeAgents || []);
227
238
 
@@ -259,6 +270,12 @@ export async function buildDispatchConfig(projectPath, featureName, phase, opts
259
270
  // Phase relevance check (tier-4 bypass in validate mode)
260
271
  if (!isRelevantForPhase(agentId, agentData, phase) && !(isValidateMode && isTier4)) continue;
261
272
 
273
+ // Stack filtering (Tier 1/2 exempt — always dispatched)
274
+ if (agentData.tier >= 3 && projectTags.length > 0) {
275
+ const agentStacks = agentData.stacks || [];
276
+ if (!shouldInstall(agentStacks, projectTags)) continue;
277
+ }
278
+
262
279
  const group = getAgentGroup(agentId, agentData);
263
280
 
264
281
  // Build task prompt: validator prompt for tier-4 in validate mode, else spawn_prompt
@@ -1,13 +1,13 @@
1
- /**
2
- * Agent Commands
3
- */
4
- export { dispatchAgentsCommand, buildDispatchConfig } from './dispatch-agents.js';
5
- export { auditDispatchCommand } from './audit-dispatch.js';
6
- export { detectAgentsCommand, detectAgents } from './detect-agents.js';
7
- export {
8
- agentListCommand,
9
- agentShowCommand,
10
- agentAddCommand,
11
- agentEditCommand,
12
- agentRemoveCommand,
13
- } from './manage-agents.js';
1
+ /**
2
+ * Agent Commands
3
+ */
4
+ export { dispatchAgentsCommand, buildDispatchConfig } from './dispatch-agents.js';
5
+ export { auditDispatchCommand } from './audit-dispatch.js';
6
+ export { detectAgentsCommand, detectAgents } from './detect-agents.js';
7
+ export {
8
+ agentListCommand,
9
+ agentShowCommand,
10
+ agentAddCommand,
11
+ agentEditCommand,
12
+ agentRemoveCommand,
13
+ } from './manage-agents.js';
@@ -0,0 +1,74 @@
1
+ /**
2
+ * project-metrics — Project-level metrics aggregation CLI
3
+ *
4
+ * Aggregates feature data from state.json into a project-wide summary.
5
+ *
6
+ * Usage:
7
+ * morph-spec project-metrics [--json] [--save]
8
+ */
9
+
10
+ import { writeFileSync, existsSync, mkdirSync } from 'fs';
11
+ import { join } from 'path';
12
+ import { loadState, stateExists } from '../../core/state/state-manager.js';
13
+ import { aggregateProjectMetrics } from '../../lib/agents/metrics-aggregator.js';
14
+ import chalk from 'chalk';
15
+
16
+ /**
17
+ * CLI command: morph-spec project-metrics [--json] [--save]
18
+ */
19
+ export async function projectMetricsCommand(options = {}) {
20
+ if (!stateExists()) {
21
+ console.error(chalk.red('No state.json found. Run morph-spec state init first.'));
22
+ process.exit(1);
23
+ }
24
+
25
+ try {
26
+ const state = loadState(false);
27
+ if (!state) {
28
+ console.error(chalk.red('Failed to load state.json.'));
29
+ process.exit(1);
30
+ }
31
+
32
+ const metrics = aggregateProjectMetrics(state);
33
+
34
+ if (options.save) {
35
+ const morphDir = join(process.cwd(), '.morph');
36
+ if (!existsSync(morphDir)) {
37
+ mkdirSync(morphDir, { recursive: true });
38
+ }
39
+ const outPath = join(morphDir, 'metrics.json');
40
+ writeFileSync(outPath, JSON.stringify(metrics, null, 2) + '\n', 'utf8');
41
+ console.log(chalk.green(`Metrics saved to ${outPath}`));
42
+ }
43
+
44
+ if (options.json) {
45
+ console.log(JSON.stringify(metrics, null, 2));
46
+ return;
47
+ }
48
+
49
+ // Human-readable table
50
+ const s = metrics.summary;
51
+ console.log(chalk.bold('\n Project Metrics'));
52
+ console.log(' ' + '─'.repeat(50));
53
+ console.log(` Features: ${s.totalFeatures} (${s.completedFeatures} completed)`);
54
+ console.log(` Tasks: ${s.completedTasks}/${s.totalTasks} (${s.completionRate}%)`);
55
+ console.log(` Avg tasks/feat: ${s.avgTasksPerFeature}`);
56
+ console.log(` Dispatches: ${s.totalDispatches}`);
57
+
58
+ if (metrics.features.length > 0) {
59
+ console.log(chalk.bold('\n Features:'));
60
+ console.log(` ${'Name'.padEnd(24)} ${'Phase'.padEnd(14)} ${'Tasks'.padEnd(10)} Dispatches`);
61
+ console.log(' ' + '─'.repeat(60));
62
+ for (const f of metrics.features) {
63
+ const taskStr = `${f.completedTasks}/${f.taskCount}`;
64
+ console.log(
65
+ ` ${f.name.padEnd(24)} ${chalk.cyan(f.phase.padEnd(14))} ${taskStr.padEnd(10)} ${f.dispatchCount}`
66
+ );
67
+ }
68
+ }
69
+ console.log();
70
+ } catch (err) {
71
+ console.error(chalk.red(`Error: ${err.message}`));
72
+ process.exit(1);
73
+ }
74
+ }
@@ -947,13 +947,12 @@ export async function doctorCommand(options = {}) {
947
947
  logger.dim(' PowerShell (as Administrator):');
948
948
  console.log(chalk.gray(` [Environment]::SetEnvironmentVariable("Path", [Environment]::GetEnvironmentVariable("Path", "User") + ";${prefix}", "User")`));
949
949
  logger.blank();
950
- logger.dim(' Or use npx instead:');
951
- logger.dim(' npx @polymorphism-tech/morph-spec init');
950
+ logger.dim(' Then open a new terminal.');
952
951
  logger.blank();
953
952
  } else if (!inPath) {
954
953
  logger.info('morph-spec not in PATH:');
955
- logger.dim(' Use npx instead:');
956
- logger.dim(' npx @polymorphism-tech/morph-spec init');
954
+ logger.dim(' Open a new terminal — the installer adds npm global to $PROFILE automatically.');
955
+ logger.dim(' If it persists, add manually: npm config get prefix → add to PATH');
957
956
  logger.blank();
958
957
  }
959
958
  }
@@ -1,28 +1,28 @@
1
- // src/commands/project/install-plugin-cmd.js
2
- import { installPlugin } from '../../scripts/install-plugin.js';
3
- import { logger } from '../../utils/logger.js';
4
-
5
- export async function installPluginCommand(pluginName, _options) {
6
- if (!pluginName) {
7
- logger.error('Plugin name required. Usage: morph-spec install-plugin <name>');
8
- logger.dim(' Available: superpowers, context7');
9
- process.exit(1);
10
- }
11
- try {
12
- const result = await installPlugin(pluginName);
13
- if (result.alreadyInstalled) {
14
- logger.dim(` ✓ ${pluginName} already installed (${result.version})`);
15
- } else {
16
- logger.success(` ✓ ${pluginName} installed (${result.version})`);
17
- logger.dim(' Restart Claude Code to activate.');
18
- }
19
- } catch (err) {
20
- logger.error(`Failed to install plugin "${pluginName}": ${err.message}`);
21
- logger.blank();
22
- logger.warn('Manual installation:');
23
- logger.dim(' 1. Claude Code → Settings (Cmd/Ctrl+,) → Extensions');
24
- logger.dim(` 2. Browse → search "${pluginName}" → Install`);
25
- logger.dim(' 3. Restart Claude Code');
26
- process.exit(1);
27
- }
28
- }
1
+ // src/commands/project/install-plugin-cmd.js
2
+ import { installPlugin } from '../../scripts/install-plugin.js';
3
+ import { logger } from '../../utils/logger.js';
4
+
5
+ export async function installPluginCommand(pluginName, _options) {
6
+ if (!pluginName) {
7
+ logger.error('Plugin name required. Usage: morph-spec install-plugin <name>');
8
+ logger.dim(' Available: superpowers, context7');
9
+ process.exit(1);
10
+ }
11
+ try {
12
+ const result = await installPlugin(pluginName);
13
+ if (result.alreadyInstalled) {
14
+ logger.dim(` ✓ ${pluginName} already installed (${result.version})`);
15
+ } else {
16
+ logger.success(` ✓ ${pluginName} installed (${result.version})`);
17
+ logger.dim(' Restart Claude Code to activate.');
18
+ }
19
+ } catch (err) {
20
+ logger.error(`Failed to install plugin "${pluginName}": ${err.message}`);
21
+ logger.blank();
22
+ logger.warn('Manual installation:');
23
+ logger.dim(' 1. Claude Code → Settings (Cmd/Ctrl+,) → Extensions');
24
+ logger.dim(` 2. Browse → search "${pluginName}" → Install`);
25
+ logger.dim(' 3. Restart Claude Code');
26
+ process.exit(1);
27
+ }
28
+ }
@@ -1,12 +1,12 @@
1
- import { setupInfra } from '../../scripts/setup-infra.js';
2
- import { logger } from '../../utils/logger.js';
3
-
4
- export async function setupInfraCommand(options) {
5
- const targetPath = options.path || process.cwd();
6
- try {
7
- await setupInfra(targetPath);
8
- } catch (err) {
9
- logger.error(`setup-infra failed: ${err.message}`);
10
- process.exit(1);
11
- }
12
- }
1
+ import { setupInfra } from '../../scripts/setup-infra.js';
2
+ import { logger } from '../../utils/logger.js';
3
+
4
+ export async function setupInfraCommand(options) {
5
+ const targetPath = options.path || process.cwd();
6
+ try {
7
+ await setupInfra(targetPath);
8
+ } catch (err) {
9
+ logger.error(`setup-infra failed: ${err.message}`);
10
+ process.exit(1);
11
+ }
12
+ }
@@ -236,7 +236,14 @@ export async function statusCommand(featureName, options = {}) {
236
236
  process.exit(1);
237
237
  }
238
238
 
239
- const feature = getFeature(featureName);
239
+ let feature;
240
+ try {
241
+ feature = getFeature(featureName);
242
+ } catch (err) {
243
+ console.error(chalk.red(`✗ Error: ${err.message}`));
244
+ console.error(chalk.gray('Run \'morph-spec doctor\' to diagnose or fix your state.json'));
245
+ process.exit(1);
246
+ }
240
247
  if (!feature) {
241
248
  console.error(chalk.red(`✗ Error: Feature '${featureName}' not found`));
242
249
  console.error(chalk.gray(`Run 'morph-spec state get ${featureName}' to check if feature exists`));
@@ -13,7 +13,7 @@
13
13
  import chalk from 'chalk';
14
14
  import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'fs';
15
15
  import { join } from 'path';
16
- import { loadState, saveState } from '../../core/state/state-manager.js';
16
+ import { loadState, saveState, derivePhase } from '../../core/state/state-manager.js';
17
17
  import { analyzeImpact } from '../../lib/scope/impact-analyzer.js';
18
18
 
19
19
  /**
@@ -35,8 +35,10 @@ export async function escalateScope(featureName, options) {
35
35
  return { success: false, error: `Feature "${featureName}" not found in state.json` };
36
36
  }
37
37
 
38
- if (feature.phase !== 'implement') {
39
- return { success: false, error: `Scope escalation only available during implement phase (current: ${feature.phase})` };
38
+ const featurePath = join(process.cwd(), '.morph', 'features', featureName);
39
+ const currentPhase = feature.phase || derivePhase(featurePath);
40
+ if (currentPhase !== 'implement') {
41
+ return { success: false, error: `Scope escalation only available during implement phase (current: ${currentPhase})` };
40
42
  }
41
43
 
42
44
  // Read tasks.md
@@ -0,0 +1,89 @@
1
+ /**
2
+ * context-budget — Token budget tracking for standards context
3
+ *
4
+ * Shows estimated token usage for agent briefings built from STANDARDS.json digests.
5
+ *
6
+ * Usage:
7
+ * morph-spec context-budget [--phase <phase>] [--json]
8
+ */
9
+
10
+ import { readFileSync, existsSync } from 'fs';
11
+ import { join, dirname } from 'path';
12
+ import { fileURLToPath } from 'url';
13
+ import { buildAgentBriefing, estimateTokens, clearCache } from '../../lib/standards/digest-builder.js';
14
+ import chalk from 'chalk';
15
+
16
+ const __dirname = dirname(fileURLToPath(import.meta.url));
17
+ const AGENTS_JSON_PATH = join(__dirname, '../../../framework/agents.json');
18
+
19
+ /**
20
+ * CLI command: morph-spec context-budget [--phase <phase>] [--json]
21
+ */
22
+ export async function contextBudgetCommand(options = {}) {
23
+ const phase = options.phase || 'implement';
24
+
25
+ if (!existsSync(AGENTS_JSON_PATH)) {
26
+ console.error(chalk.red('framework/agents.json not found.'));
27
+ process.exit(1);
28
+ }
29
+
30
+ try {
31
+ clearCache();
32
+ const agentsData = JSON.parse(readFileSync(AGENTS_JSON_PATH, 'utf8'));
33
+ const allAgents = agentsData.agents || {};
34
+
35
+ const results = [];
36
+
37
+ for (const [agentId, agentData] of Object.entries(allAgents)) {
38
+ if (agentId.startsWith('_comment')) continue;
39
+ if (!agentData.standards || agentData.standards.length === 0) continue;
40
+
41
+ const briefing = buildAgentBriefing(agentId, phase);
42
+ if (!briefing) continue;
43
+
44
+ const tokens = estimateTokens(briefing);
45
+ results.push({
46
+ agentId,
47
+ tier: agentData.tier,
48
+ standardsCount: agentData.standards.length,
49
+ tokens,
50
+ overBudget: tokens > 8000,
51
+ });
52
+ }
53
+
54
+ // Sort by tokens descending
55
+ results.sort((a, b) => b.tokens - a.tokens);
56
+
57
+ const totalTokens = results.reduce((sum, r) => sum + r.tokens, 0);
58
+ const overBudget = results.filter(r => r.overBudget);
59
+
60
+ if (options.json) {
61
+ console.log(JSON.stringify({ phase, totalTokens, overBudgetCount: overBudget.length, agents: results }, null, 2));
62
+ return;
63
+ }
64
+
65
+ // Human-readable
66
+ console.log(chalk.bold(`\n Context Budget — phase: ${phase}`));
67
+ console.log(' ' + '─'.repeat(62));
68
+ console.log(` ${'Agent'.padEnd(32)} ${'Tier'.padEnd(6)} ${'Stds'.padEnd(6)} Tokens`);
69
+ console.log(' ' + '─'.repeat(62));
70
+
71
+ for (const r of results) {
72
+ const tokenStr = r.overBudget ? chalk.red(String(r.tokens)) : String(r.tokens);
73
+ const flag = r.overBudget ? ' ⚠' : '';
74
+ console.log(
75
+ ` ${r.agentId.padEnd(32)} ${String(r.tier).padEnd(6)} ${String(r.standardsCount).padEnd(6)} ${tokenStr}${flag}`
76
+ );
77
+ }
78
+
79
+ console.log(' ' + '─'.repeat(62));
80
+ console.log(` Total: ${results.length} agents, ${totalTokens} tokens`);
81
+ if (overBudget.length > 0) {
82
+ console.log(chalk.yellow(` ⚠ ${overBudget.length} agent(s) exceed 8000 token threshold`));
83
+ }
84
+ console.log();
85
+ } catch (err) {
86
+ console.error(chalk.red(`Error: ${err.message}`));
87
+ process.exit(1);
88
+ }
89
+ }
@@ -1,4 +1,4 @@
1
- /**
2
- * Task Management Commands
3
- */
4
- export { taskCommand } from './task.js';
1
+ /**
2
+ * Task Management Commands
3
+ */
4
+ export { taskCommand } from './task.js';
@@ -1,5 +1,5 @@
1
- /**
2
- * Template Commands
3
- */
4
- export { templateRenderCommand } from './template-render.js';
5
- export { generateContractsCommand, parseSchemaAnalysisMd } from './generate-contracts.js';
1
+ /**
2
+ * Template Commands
3
+ */
4
+ export { templateRenderCommand } from './template-render.js';
5
+ export { generateContractsCommand, parseSchemaAnalysisMd } from './generate-contracts.js';
@@ -1,3 +1,3 @@
1
- /**
2
- * Utility Commands — no active commands after CLI simplification
3
- */
1
+ /**
2
+ * Utility Commands — no active commands after CLI simplification
3
+ */
@@ -1,4 +1,4 @@
1
- /**
2
- * Validation Commands
3
- */
4
- export { validateFeatureCommand } from './validate-feature.js';
1
+ /**
2
+ * Validation Commands
3
+ */
4
+ export { validateFeatureCommand } from './validate-feature.js';
@@ -70,6 +70,19 @@ const PHASE_OUTPUTS = {
70
70
  implement: ['spec.md', 'contracts.cs', 'tasks.md']
71
71
  };
72
72
 
73
+ /**
74
+ * Phase-to-folder mapping (filesystem convention)
75
+ */
76
+ const PHASE_FOLDERS = {
77
+ proposal: '0-proposal',
78
+ uiux: '2-ui',
79
+ design: '1-design',
80
+ clarify: '1-design',
81
+ plan: '3-plan',
82
+ tasks: '4-tasks',
83
+ implement: '5-implement',
84
+ };
85
+
73
86
  /**
74
87
  * Validate a single output file
75
88
  */
@@ -254,12 +267,28 @@ export async function validateFeatureCommand(featureName, options = {}) {
254
267
  process.exit(1);
255
268
  }
256
269
  } else {
257
- // Validate all existing outputs
258
- outputFiles = fs.readdirSync(featurePath).filter(f => f.endsWith('.md') || f.endsWith('.cs'));
270
+ // Validate all existing outputs across all phase folders
271
+ outputFiles = [];
272
+ const entries = fs.readdirSync(featurePath, { withFileTypes: true });
273
+ for (const entry of entries) {
274
+ if (entry.isDirectory()) {
275
+ const subDir = path.join(featurePath, entry.name);
276
+ const files = fs.readdirSync(subDir).filter(f => f.endsWith('.md') || f.endsWith('.cs'));
277
+ outputFiles.push(...files.map(f => ({ file: f, dir: subDir })));
278
+ } else if (entry.name.endsWith('.md') || entry.name.endsWith('.cs')) {
279
+ outputFiles.push({ file: entry.name, dir: featurePath });
280
+ }
281
+ }
259
282
  }
260
283
 
284
+ // Resolve phase folder for path lookup
285
+ const phaseFolder = phase ? PHASE_FOLDERS[phase] : null;
286
+ const searchPath = phaseFolder ? path.join(featurePath, phaseFolder) : featurePath;
287
+
261
288
  // Run validation
262
- const results = outputFiles.map(file => validateOutput(featurePath, file));
289
+ const results = phase
290
+ ? outputFiles.map(file => validateOutput(searchPath, file))
291
+ : outputFiles.map(({ file, dir }) => validateOutput(dir, file));
263
292
  const schemaWarnings = crossValidateSchema(featurePath);
264
293
 
265
294
  // Aggregate results