@polymorphism-tech/morph-spec 4.8.14 → 4.8.15

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 (71) hide show
  1. package/README.md +2 -2
  2. package/bin/morph-spec.js +23 -2
  3. package/bin/task-manager.js +202 -14
  4. package/claude-plugin.json +1 -1
  5. package/docs/CHEATSHEET.md +1 -1
  6. package/docs/QUICKSTART.md +1 -1
  7. package/framework/agents.json +113 -116
  8. package/framework/hooks/claude-code/post-tool-use/dispatch.js +48 -2
  9. package/framework/hooks/claude-code/post-tool-use/validator-feedback.js +151 -0
  10. package/framework/hooks/claude-code/pre-tool-use/enforce-phase-writes.js +6 -0
  11. package/framework/hooks/claude-code/pre-tool-use/protect-spec-files.js +6 -0
  12. package/framework/hooks/claude-code/session-start/inject-morph-context.js +27 -0
  13. package/framework/hooks/claude-code/stop/validate-completion.js +17 -2
  14. package/framework/hooks/claude-code/teammate-idle/teammate-idle.js +87 -0
  15. package/framework/hooks/claude-code/user-prompt/set-terminal-title.js +58 -0
  16. package/framework/hooks/shared/phase-utils.js +1 -1
  17. package/framework/hooks/shared/state-reader.js +1 -0
  18. package/framework/skills/README.md +1 -0
  19. package/framework/skills/level-0-meta/brainstorming/SKILL.md +2 -0
  20. package/framework/skills/level-0-meta/code-review/SKILL.md +16 -0
  21. package/framework/skills/level-0-meta/code-review/references/review-guidelines.md +100 -0
  22. package/framework/skills/level-0-meta/code-review/scripts/scan-csharp.mjs +36 -6
  23. package/framework/skills/level-0-meta/code-review-nextjs/SKILL.md +16 -0
  24. package/framework/skills/level-0-meta/code-review-nextjs/scripts/scan-nextjs.mjs +189 -0
  25. package/framework/skills/level-0-meta/frontend-review/SKILL.md +359 -0
  26. package/framework/skills/level-0-meta/frontend-review/scripts/scan-accessibility.mjs +376 -0
  27. package/framework/skills/level-0-meta/morph-checklist/SKILL.md +1 -1
  28. package/framework/skills/level-0-meta/morph-replicate/SKILL.md +10 -8
  29. package/framework/skills/level-0-meta/morph-replicate/references/blazor-html-mapping.md +70 -0
  30. package/framework/skills/level-0-meta/post-implementation/SKILL.md +315 -0
  31. package/framework/skills/level-0-meta/post-implementation/scripts/detect-dev-server.mjs +153 -0
  32. package/framework/skills/level-0-meta/post-implementation/scripts/detect-stack.mjs +234 -0
  33. package/framework/skills/level-0-meta/terminal-title/SKILL.md +61 -0
  34. package/framework/skills/level-0-meta/terminal-title/scripts/set_title.sh +65 -0
  35. package/framework/skills/level-0-meta/tool-usage-guide/SKILL.md +13 -206
  36. package/framework/skills/level-0-meta/tool-usage-guide/references/tools-per-phase.md +213 -0
  37. package/framework/skills/level-0-meta/verification-before-completion/SKILL.md +2 -0
  38. package/framework/skills/level-1-workflows/phase-clarify/SKILL.md +4 -7
  39. package/framework/skills/level-1-workflows/phase-codebase-analysis/SKILL.md +1 -1
  40. package/framework/skills/level-1-workflows/phase-design/SKILL.md +16 -110
  41. package/framework/skills/level-1-workflows/phase-design/references/architecture-analysis-guide.md +89 -0
  42. package/framework/skills/level-1-workflows/phase-design/references/spec-authoring-guide.md +55 -0
  43. package/framework/skills/level-1-workflows/phase-implement/SKILL.md +153 -118
  44. package/framework/skills/level-1-workflows/phase-implement/references/vsa-implementation-guide.md +92 -0
  45. package/framework/skills/level-1-workflows/phase-setup/SKILL.md +1 -2
  46. package/framework/skills/level-1-workflows/phase-tasks/SKILL.md +11 -158
  47. package/framework/skills/level-1-workflows/phase-tasks/references/task-planning-patterns.md +172 -0
  48. package/framework/skills/level-1-workflows/phase-uiux/SKILL.md +42 -3
  49. package/framework/squad-templates/backend-only.json +14 -1
  50. package/framework/squad-templates/frontend-only.json +14 -1
  51. package/framework/squad-templates/full-stack.json +25 -8
  52. package/framework/standards/STANDARDS.json +631 -86
  53. package/framework/standards/frontend/design-system/aesthetic-direction.md +213 -0
  54. package/framework/templates/project/validate.js +122 -0
  55. package/framework/workflows/configs/zero-touch.json +7 -0
  56. package/package.json +1 -1
  57. package/src/commands/agents/dispatch-agents.js +53 -10
  58. package/src/commands/state/advance-phase.js +56 -0
  59. package/src/commands/state/index.js +2 -1
  60. package/src/commands/state/phase-runner.js +215 -0
  61. package/src/commands/tasks/task.js +23 -2
  62. package/src/core/paths/output-schema.js +1 -1
  63. package/src/lib/generators/recap-generator.js +16 -0
  64. package/src/lib/orchestration/team-orchestrator.js +171 -89
  65. package/src/lib/phase-chain/eligibility-checker.js +243 -0
  66. package/src/lib/standards/digest-builder.js +231 -0
  67. package/src/lib/validators/blazor/blazor-concurrency-analyzer.js +39 -0
  68. package/src/lib/validators/nextjs/next-component-validator.js +2 -0
  69. package/src/lib/validators/validation-runner.js +2 -2
  70. package/src/utils/file-copier.js +1 -0
  71. package/src/utils/hooks-installer.js +31 -7
@@ -0,0 +1,215 @@
1
+ /**
2
+ * MORPH-SPEC Phase Runner
3
+ *
4
+ * Executes an automated phase chain loop for a feature.
5
+ * Reads eligibility at each step, auto-advances when eligible, and
6
+ * pauses on blockers (blocked_tasks, low_pass_rate, trust_too_low).
7
+ *
8
+ * Usage:
9
+ * morph-spec phase run <feature>
10
+ * morph-spec phase run <feature> --dry-run
11
+ * morph-spec phase run <feature> --max-phases 3
12
+ *
13
+ * Eligibility gates:
14
+ * - Required outputs present on disk
15
+ * - No blocked tasks in validationHistory
16
+ * - Validation pass rate >= minPassRate (from workflow config)
17
+ * - Trust level meets gate requirements (or gates already approved)
18
+ *
19
+ * Level 3 autonomy: when run with zero-touch workflow + trust=maximum,
20
+ * executes proposal → design → tasks → implement without human input,
21
+ * pausing only on escalation triggers.
22
+ */
23
+
24
+ import chalk from 'chalk';
25
+ import { join } from 'path';
26
+ import { checkPhaseEligibility, computePassRate } from '../../lib/phase-chain/eligibility-checker.js';
27
+ import { advancePhaseCommand } from './advance-phase.js';
28
+ import { loadState } from '../../core/state/state-manager.js';
29
+ import { derivePhase } from '../../core/state/state-manager.js';
30
+ import { getWorkflowConfig } from '../../core/workflows/workflow-detector.js';
31
+
32
+ // Phases that trigger a pause regardless of eligibility
33
+ const PAUSE_TRIGGERS = ['blocked_tasks', 'trust_too_low'];
34
+
35
+ // Maximum auto-phases before stopping (safety valve)
36
+ const DEFAULT_MAX_PHASES = 6;
37
+
38
+ /**
39
+ * Render a decision tree for --dry-run mode.
40
+ */
41
+ function renderDecisionTree(featureName, eligibility, workflowConfig, dryRun) {
42
+ const { eligible, blockers, currentPhase, nextPhase, passRate } = eligibility;
43
+
44
+ console.log(chalk.cyan('\n╔════════════════════════════════════════════════╗'));
45
+ console.log(chalk.cyan('║ MORPH-SPEC PHASE CHAIN DECISION TREE ║'));
46
+ if (dryRun) console.log(chalk.yellow('║ *** DRY RUN *** ║'));
47
+ console.log(chalk.cyan('╚════════════════════════════════════════════════╝\n'));
48
+
49
+ console.log(chalk.gray('Feature:'), featureName);
50
+ console.log(chalk.gray('Current Phase:'), chalk.cyan(currentPhase));
51
+ console.log(chalk.gray('Next Phase:'), nextPhase ? chalk.cyan(nextPhase) : chalk.gray('(final)'));
52
+ if (passRate !== null) {
53
+ const rateColor = passRate >= 0.95 ? chalk.green : passRate >= 0.80 ? chalk.yellow : chalk.red;
54
+ console.log(chalk.gray('Pass Rate:'), rateColor(`${(passRate * 100).toFixed(0)}%`));
55
+ }
56
+
57
+ if (workflowConfig?.phaseChain) {
58
+ console.log(chalk.gray('Phase Chain:'), chalk.green('enabled'));
59
+ console.log(chalk.gray('Max Auto Phases:'), workflowConfig.phaseChain.maxAutoPhases ?? DEFAULT_MAX_PHASES);
60
+ }
61
+
62
+ console.log();
63
+
64
+ if (eligible) {
65
+ console.log(chalk.green(`✓ ELIGIBLE — can advance from ${currentPhase} → ${nextPhase}`));
66
+ } else {
67
+ console.log(chalk.red(`✗ BLOCKED — cannot advance from ${currentPhase}`));
68
+ console.log(chalk.yellow('\n Blockers:'));
69
+ for (const blocker of blockers) {
70
+ switch (blocker.type) {
71
+ case 'missing_outputs':
72
+ console.log(chalk.red(` • missing_outputs: ${blocker.items.join(', ')}`));
73
+ break;
74
+ case 'blocked_tasks':
75
+ console.log(chalk.red(` • blocked_tasks: ${blocker.items.join(', ')} (attempt ≥ 3, needs human review)`));
76
+ break;
77
+ case 'low_pass_rate':
78
+ console.log(chalk.red(` • low_pass_rate: ${(blocker.current * 100).toFixed(0)}% (required: ${(blocker.required * 100).toFixed(0)}%)`));
79
+ break;
80
+ case 'trust_too_low':
81
+ console.log(chalk.yellow(` • trust_too_low: ${blocker.items.join(', ')}`));
82
+ break;
83
+ default:
84
+ console.log(chalk.red(` • ${blocker.type}: ${(blocker.items || []).join(', ')}`));
85
+ }
86
+ }
87
+ }
88
+
89
+ console.log();
90
+ }
91
+
92
+ /**
93
+ * Main command handler for `morph-spec phase run <feature>`.
94
+ *
95
+ * @param {string} featureName - Feature to run
96
+ * @param {Object} options
97
+ * @param {boolean} [options.dryRun] - Show decision tree without executing
98
+ * @param {number} [options.maxPhases] - Max phases to auto-advance (default: 6)
99
+ * @param {boolean} [options.skipApproval] - Skip approval gate checks
100
+ */
101
+ export async function phaseRunCommand(featureName, options = {}) {
102
+ if (!featureName) {
103
+ console.error(chalk.red('Usage: morph-spec phase run <feature> [--dry-run] [--max-phases N]'));
104
+ process.exit(1);
105
+ }
106
+
107
+ const maxPhases = options.maxPhases ?? DEFAULT_MAX_PHASES;
108
+ const dryRun = options.dryRun ?? false;
109
+
110
+ // Load workflow config for phaseChain settings
111
+ const state = loadState(false);
112
+ const feature = state?.features?.[featureName];
113
+ let workflowConfig = null;
114
+ if (feature?.workflow && feature.workflow !== 'auto') {
115
+ try {
116
+ workflowConfig = getWorkflowConfig(feature.workflow);
117
+ } catch {
118
+ // Non-blocking
119
+ }
120
+ }
121
+
122
+ // Determine pause conditions from workflow
123
+ const pauseOnTypes = workflowConfig?.phaseChain?.pauseOn ?? PAUSE_TRIGGERS;
124
+ const autoChainMax = workflowConfig?.phaseChain?.maxAutoPhases ?? maxPhases;
125
+
126
+ if (!dryRun) {
127
+ console.log(chalk.cyan('\n╔════════════════════════════════════════════════╗'));
128
+ console.log(chalk.cyan('║ MORPH-SPEC PHASE CHAIN RUNNER ║'));
129
+ console.log(chalk.cyan('╚════════════════════════════════════════════════╝\n'));
130
+ console.log(chalk.gray('Feature:'), featureName);
131
+ console.log(chalk.gray('Max auto-phases:'), autoChainMax);
132
+ console.log();
133
+ }
134
+
135
+ let phasesAdvanced = 0;
136
+
137
+ while (phasesAdvanced < autoChainMax) {
138
+ // ── Check eligibility ──────────────────────────────────────────────────
139
+ const eligibility = checkPhaseEligibility(featureName, { projectPath: process.cwd() });
140
+
141
+ // Dry-run: just show the decision tree and exit
142
+ if (dryRun) {
143
+ renderDecisionTree(featureName, eligibility, workflowConfig, true);
144
+ return;
145
+ }
146
+
147
+ // Display current state
148
+ console.log(chalk.gray(`[${phasesAdvanced + 1}/${autoChainMax}] Checking phase: ${eligibility.currentPhase} → ${eligibility.nextPhase || '(final)'}`));
149
+
150
+ if (!eligibility.nextPhase) {
151
+ console.log(chalk.green('\n✓ Feature has reached the final phase!'));
152
+ console.log(chalk.gray(' Consider running: morph-spec generate recap ' + featureName));
153
+ break;
154
+ }
155
+
156
+ if (!eligibility.eligible) {
157
+ // Check if any blocker type triggers a pause
158
+ const shouldPause = eligibility.blockers.some(b => pauseOnTypes.includes(b.type));
159
+
160
+ console.log(chalk.yellow(`\n⚠ Not eligible to advance (${eligibility.currentPhase} → ${eligibility.nextPhase})`));
161
+ for (const blocker of eligibility.blockers) {
162
+ switch (blocker.type) {
163
+ case 'missing_outputs':
164
+ console.log(chalk.gray(` • Missing outputs: ${blocker.items.join(', ')}`));
165
+ break;
166
+ case 'blocked_tasks':
167
+ console.log(chalk.red(` • Blocked tasks: ${blocker.items.join(', ')} — requires human review`));
168
+ break;
169
+ case 'low_pass_rate':
170
+ console.log(chalk.yellow(` • Low pass rate: ${(blocker.current * 100).toFixed(0)}% < ${(blocker.required * 100).toFixed(0)}% required`));
171
+ break;
172
+ case 'trust_too_low':
173
+ console.log(chalk.yellow(` • Trust too low: ${blocker.items.join(', ')}`));
174
+ break;
175
+ default:
176
+ console.log(chalk.gray(` • ${blocker.type}: ${(blocker.items || []).join(', ')}`));
177
+ }
178
+ }
179
+
180
+ if (shouldPause) {
181
+ console.log(chalk.red('\n⛔ Pausing phase chain — human intervention required'));
182
+ console.log(chalk.gray(' Fix the blockers above, then re-run: morph-spec phase run ' + featureName));
183
+ process.exit(1);
184
+ }
185
+
186
+ // Non-pause blocker (e.g. missing_optional_outputs) — still stop
187
+ console.log(chalk.yellow('\n Stopping chain — resolve blockers before continuing'));
188
+ break;
189
+ }
190
+
191
+ // ── Advance the phase ─────────────────────────────────────────────────
192
+ console.log(chalk.green(`\n✓ Eligible — advancing to ${eligibility.nextPhase}`));
193
+
194
+ try {
195
+ await advancePhaseCommand(featureName, {
196
+ skipOptional: false,
197
+ skipApproval: options.skipApproval,
198
+ });
199
+ phasesAdvanced++;
200
+ } catch (err) {
201
+ console.error(chalk.red(`\n✗ Phase advance failed: ${err.message}`));
202
+ console.log(chalk.gray(' Fix the issue and re-run: morph-spec phase run ' + featureName));
203
+ process.exit(1);
204
+ }
205
+ }
206
+
207
+ if (phasesAdvanced >= autoChainMax) {
208
+ console.log(chalk.yellow(`\n⚠ Reached max auto-phases limit (${autoChainMax})`));
209
+ console.log(chalk.gray(' Use --max-phases N to increase the limit'));
210
+ }
211
+
212
+ if (phasesAdvanced > 0 && !dryRun) {
213
+ console.log(chalk.cyan(`\n ${phasesAdvanced} phase(s) advanced automatically`));
214
+ }
215
+ }
@@ -41,9 +41,30 @@ function executeTaskManager(args) {
41
41
  export async function taskDoneCommand(featureName, taskIds, options) {
42
42
  try {
43
43
  const args = ['done', featureName, ...taskIds];
44
- if (options.skipValidation) {
45
- args.push('--skip-validation');
44
+ if (options.skipValidation) args.push('--skip-validation');
45
+ if (options.dryRun) args.push('--dry-run');
46
+ await executeTaskManager(args);
47
+ } catch (error) {
48
+ console.error(chalk.red(`Error: ${error.message}`));
49
+ process.exit(1);
50
+ }
51
+ }
52
+
53
+ /**
54
+ * Bulk-complete tasks command
55
+ */
56
+ export async function taskBulkDoneCommand(featureName, rangeArg, options) {
57
+ try {
58
+ const args = ['bulk-done', featureName];
59
+ if (options.all) {
60
+ args.push('--all');
61
+ } else if (options.from && options.to) {
62
+ args.push('--from', options.from, '--to', options.to);
63
+ } else if (rangeArg) {
64
+ args.push(rangeArg);
46
65
  }
66
+ if (options.skipValidation) args.push('--skip-validation');
67
+ if (options.dryRun) args.push('--dry-run');
47
68
  await executeTaskManager(args);
48
69
  } catch (error) {
49
70
  console.error(chalk.red(`Error: ${error.message}`));
@@ -26,7 +26,7 @@ export const OUTPUT_SCHEMA = {
26
26
  proposal: { filename: 'proposal.md', phaseDir: '0-proposal', phase: 'proposal', protected: false },
27
27
  schemaAnalysis:{ filename: 'schema-analysis.md', phaseDir: '1-design', phase: 'design', protected: true, approvalGate: 'design' },
28
28
  spec: { filename: 'spec.md', phaseDir: '1-design', phase: 'design', protected: true, approvalGate: 'design' },
29
- clarifications:{ filename: 'clarifications.md', phaseDir: '1-design', phase: 'clarify', protected: false },
29
+ clarifications:{ filename: 'clarifications.md', phaseDir: '2-clarify', phase: 'clarify', protected: false },
30
30
  contracts: { filename: 'contracts.cs', phaseDir: '1-design', phase: 'design', protected: true, approvalGate: 'design' },
31
31
  contractsVsa: { filename: 'contracts-vsa.cs', phaseDir: '1-design', phase: 'design', protected: true, approvalGate: 'design' },
32
32
  tasks: { filename: 'tasks.md', phaseDir: '3-tasks', phase: 'tasks', protected: true, approvalGate: 'tasks' },
@@ -175,6 +175,22 @@ function buildRecapMarkdown(data) {
175
175
  }
176
176
  md += `\n`;
177
177
  }
178
+ md += `> **Note:** Errors above are from morph-spec static validators (may include false positives).\n`;
179
+ md += `> Verify actual build status with the commands in the section below.\n\n`;
180
+ }
181
+
182
+ // Suggested Quality Verification
183
+ const agents = agentsSummary;
184
+ const hasNextjs = agents.some(a => ['nextjs-expert', 'css-specialist', 'ui-designer'].includes(a));
185
+ const hasBlazor = agents.some(a => ['blazor-builder', 'blazor-specialist', 'dotnet-senior'].includes(a));
186
+ if (hasNextjs || hasBlazor) {
187
+ md += `## Suggested Quality Verification\n\n`;
188
+ if (hasNextjs) {
189
+ md += `**Next.js / TypeScript:**\n\`\`\`bash\nnpx tsc --noEmit\nnpx eslint . --max-warnings 0\n\`\`\`\n\n`;
190
+ }
191
+ if (hasBlazor) {
192
+ md += `**Blazor / .NET:**\n\`\`\`bash\ndotnet build\ndotnet test\n\`\`\`\n\n`;
193
+ }
178
194
  }
179
195
 
180
196
  // Contract Coverage