@polymorphism-tech/morph-spec 4.10.6 → 4.10.8

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 (149) hide show
  1. package/CLAUDE.md +3 -0
  2. package/LICENSE +71 -71
  3. package/README.md +379 -379
  4. package/bin/morph-spec.js +89 -0
  5. package/bin/task-manager.js +59 -6
  6. package/claude-plugin.json +14 -14
  7. package/docs/CHEATSHEET.md +1 -1
  8. package/docs/QUICKSTART.md +206 -206
  9. package/framework/agents/README.md +14 -14
  10. package/framework/agents/architecture/standards-architect.md +159 -159
  11. package/framework/agents/frontend/blazor-builder.md +13 -0
  12. package/framework/agents/frontend/css-specialist.md +87 -0
  13. package/framework/agents/frontend/nextjs-expert.md +13 -0
  14. package/framework/agents/frontend/nextjs-ui-specialist.md +218 -0
  15. package/framework/agents/frontend/ui-ux-designer.md +80 -10
  16. package/framework/agents/infrastructure/azure-architect.md +149 -149
  17. package/framework/agents/infrastructure/infra-architect.md +48 -48
  18. package/framework/agents.json +2268 -2567
  19. package/framework/hooks/README.md +204 -204
  20. package/framework/hooks/claude-code/post-tool-use/dispatch.js +10 -5
  21. package/framework/hooks/claude-code/session-start/inject-morph-context.js +10 -24
  22. package/framework/hooks/shared/phase-utils.js +139 -139
  23. package/framework/hooks/shared/worktree-helpers.js +30 -8
  24. package/framework/rules/csharp-standards.md +13 -13
  25. package/framework/rules/frontend-standards.md +13 -13
  26. package/framework/rules/infrastructure-standards.md +16 -16
  27. package/framework/rules/testing-standards.md +14 -14
  28. package/framework/skills/README.md +0 -1
  29. package/framework/skills/level-0-meta/morph-brainstorming/SKILL.md +12 -0
  30. package/framework/skills/level-0-meta/morph-code-review-nextjs/references/review-example-nextjs.md +254 -254
  31. package/framework/skills/level-0-meta/morph-init/SKILL.md +88 -3
  32. package/framework/skills/level-1-workflows/morph-phase-clarify/SKILL.md +247 -247
  33. package/framework/skills/level-1-workflows/morph-phase-codebase-analysis/SKILL.md +270 -270
  34. package/framework/skills/level-1-workflows/morph-phase-design/SKILL.md +515 -499
  35. package/framework/skills/level-1-workflows/morph-phase-implement/SKILL.md +508 -471
  36. package/framework/skills/level-1-workflows/morph-phase-plan/SKILL.md +12 -1
  37. package/framework/skills/level-1-workflows/morph-phase-setup/SKILL.md +272 -258
  38. package/framework/skills/level-1-workflows/morph-phase-tasks/SKILL.md +317 -311
  39. package/framework/skills/level-1-workflows/morph-phase-uiux/SKILL.md +424 -323
  40. package/framework/skills/level-1-workflows/morph-scope-escalation/SKILL.md +1 -1
  41. package/framework/standards/STANDARDS.json +2040 -2040
  42. package/framework/standards/frontend/nextjs/motion-patterns.md +321 -0
  43. package/framework/standards/frontend/nextjs/nextjs-patterns.md +17 -17
  44. package/framework/templates/README.md +814 -814
  45. package/framework/templates/code/dotnet/contracts/Commands.cs +74 -74
  46. package/framework/templates/code/dotnet/contracts/Entities.cs +25 -25
  47. package/framework/templates/code/dotnet/contracts/Queries.cs +74 -74
  48. package/framework/templates/code/dotnet/contracts/README.md +74 -74
  49. package/framework/templates/code/dotnet/contracts/api-contracts.cs +173 -173
  50. package/framework/templates/code/dotnet/frontend/component.razor +239 -239
  51. package/framework/templates/code/dotnet/jobs/agent.cs +163 -163
  52. package/framework/templates/code/dotnet/jobs/job.cs +171 -171
  53. package/framework/templates/code/dotnet/test.cs +239 -239
  54. package/framework/templates/code/sql/rls-policy.sql +57 -57
  55. package/framework/templates/code/sql/supabase-migration.sql +100 -100
  56. package/framework/templates/code/sql/supabase-migration.template.sql +113 -113
  57. package/framework/templates/code/typescript/contracts.ts +168 -168
  58. package/framework/templates/context/CONTEXT.md +181 -181
  59. package/framework/templates/context/design-system.md +211 -0
  60. package/framework/templates/docs/proposal.md +182 -182
  61. package/framework/templates/docs/user-stories.md +34 -34
  62. package/framework/templates/examples/design-system-examples.md +357 -357
  63. package/framework/templates/examples/spec-examples.md +90 -90
  64. package/framework/templates/feature/decisions.md +187 -187
  65. package/framework/templates/feature/recap.md +146 -146
  66. package/framework/templates/feature/tasks.md +199 -199
  67. package/framework/templates/infrastructure/azure/README.md +286 -286
  68. package/framework/templates/infrastructure/azure/deploy-checklist.md +426 -426
  69. package/framework/templates/infrastructure/azure/parameters.dev.json +29 -29
  70. package/framework/templates/infrastructure/azure/parameters.prod.json +29 -29
  71. package/framework/templates/infrastructure/azure/parameters.staging.json +29 -29
  72. package/framework/templates/infrastructure/docker/docker-compose.template.yml +67 -67
  73. package/framework/templates/infrastructure/docker/dockerfile-api.dockerfile +38 -38
  74. package/framework/templates/infrastructure/docker/dockerfile-web.dockerfile +48 -48
  75. package/framework/templates/infrastructure/docker/easypanel.template.json +54 -54
  76. package/package.json +82 -82
  77. package/src/commands/agents/agent-metrics.js +174 -0
  78. package/src/commands/agents/audit-dispatch.js +82 -0
  79. package/src/commands/agents/detect-agents.js +275 -0
  80. package/src/commands/agents/dispatch-agents.js +41 -135
  81. package/src/commands/agents/index.js +13 -4
  82. package/src/commands/agents/manage-agents.js +352 -0
  83. package/src/commands/project/doctor.js +59 -0
  84. package/src/commands/project/install-plugin-cmd.js +28 -28
  85. package/src/commands/project/setup-infra-cmd.js +12 -12
  86. package/src/commands/project/update.js +1 -17
  87. package/src/commands/project/worktree.js +58 -2
  88. package/src/commands/state/advance-phase.js +11 -3
  89. package/src/commands/tasks/index.js +4 -4
  90. package/src/commands/templates/index.js +5 -5
  91. package/src/commands/utils/index.js +3 -3
  92. package/src/commands/validation/index.js +4 -4
  93. package/src/core/state/phase-state-machine.js +217 -217
  94. package/src/core/state/state-manager.js +81 -0
  95. package/src/lib/agents/agents-manager.js +349 -0
  96. package/src/lib/agents/metrics-calculator.js +125 -0
  97. package/src/lib/agents/output-collector.js +75 -0
  98. package/src/lib/generators/context-generator.js +8 -7
  99. package/src/lib/generators/design-system-generator.js +298 -298
  100. package/src/lib/generators/index.js +10 -10
  101. package/src/lib/generators/metadata-extractor.js +387 -387
  102. package/src/lib/stack-filter.js +65 -65
  103. package/src/lib/standards/index.js +7 -7
  104. package/src/lib/standards/standards-context-injector.js +302 -302
  105. package/src/lib/tasks/task-parser.js +94 -3
  106. package/src/lib/validators/architecture/architecture-validator.js +387 -387
  107. package/src/lib/validators/architecture/index.js +7 -7
  108. package/src/lib/validators/blazor/blazor-concurrency-analyzer.js +316 -316
  109. package/src/lib/validators/blazor/blazor-state-validator.js +279 -279
  110. package/src/lib/validators/blazor/blazor-validator.js +369 -369
  111. package/src/lib/validators/blazor/index.js +9 -9
  112. package/src/lib/validators/checkpoint-persistence.js +39 -0
  113. package/src/lib/validators/content/content-validator.js +287 -279
  114. package/src/lib/validators/content/index.js +7 -7
  115. package/src/lib/validators/contracts/index.js +7 -7
  116. package/src/lib/validators/css/css-validator.js +352 -352
  117. package/src/lib/validators/css/index.js +7 -7
  118. package/src/lib/validators/design-system/design-system-validator.js +231 -231
  119. package/src/lib/validators/design-system/index.js +7 -7
  120. package/src/lib/validators/nextjs/index.js +6 -6
  121. package/src/lib/validators/nextjs/next-component-validator.js +183 -183
  122. package/src/lib/validators/packages/index.js +7 -7
  123. package/src/lib/validators/packages/package-validator.js +360 -360
  124. package/src/lib/validators/shared/index.js +12 -12
  125. package/src/lib/validators/shared/issue-counter.js +18 -18
  126. package/src/lib/validators/shared/result-formatter.js +124 -124
  127. package/src/lib/validators/spec-validator.js +2 -2
  128. package/src/lib/validators/ui/index.js +7 -7
  129. package/src/lib/validators/ui/ui-contrast-validator.js +422 -422
  130. package/src/lib/validators/validation-runner.js +20 -0
  131. package/src/scripts/global-install.js +58 -58
  132. package/src/scripts/install-plugin.js +126 -126
  133. package/src/scripts/setup-infra.js +1 -17
  134. package/src/utils/agent-id-mapper.js +11 -0
  135. package/src/utils/agents-installer.js +40 -8
  136. package/src/utils/claude-md-injector.js +90 -90
  137. package/src/utils/claude-settings-manager.js +1 -1
  138. package/src/utils/file-copier.js +200 -196
  139. package/src/utils/hooks-installer.js +556 -739
  140. package/src/utils/logger.js +32 -32
  141. package/src/utils/skills-installer.js +178 -178
  142. package/src/utils/tier-helpers.js +24 -0
  143. package/src/utils/version-checker.js +175 -175
  144. package/framework/agents/architecture/po-pm-advisor.md +0 -203
  145. package/framework/hooks/claude-code/user-prompt/set-terminal-title.js +0 -68
  146. package/framework/skills/level-1-workflows/morph-phase-implement/.morph/logs/activity.json +0 -38
  147. package/framework/skills/level-1-workflows/morph-phase-tasks/.morph/logs/activity.json +0 -14
  148. package/framework/templates/.idea/morph-templates.xml +0 -92
  149. package/framework/templates/.vscode/morph-templates.code-snippets +0 -186
package/bin/morph-spec.js CHANGED
@@ -26,6 +26,16 @@ import { phaseResetCommand } from '../src/commands/phase/phase-reset.js';
26
26
 
27
27
  // Agent commands
28
28
  import { dispatchAgentsCommand } from '../src/commands/agents/dispatch-agents.js';
29
+ import { auditDispatchCommand } from '../src/commands/agents/audit-dispatch.js';
30
+ import { detectAgentsCommand } from '../src/commands/agents/detect-agents.js';
31
+ import { agentMetricsCommand } from '../src/commands/agents/agent-metrics.js';
32
+ import {
33
+ agentListCommand,
34
+ agentShowCommand,
35
+ agentAddCommand,
36
+ agentEditCommand,
37
+ agentRemoveCommand,
38
+ } from '../src/commands/agents/manage-agents.js';
29
39
 
30
40
  // Task commands
31
41
  import { taskDoneCommand, taskStartCommand, taskNextCommand } from '../src/commands/tasks/task.js';
@@ -300,9 +310,33 @@ program
300
310
  .description('Build dispatch config for parallel agent orchestration (design | tasks | implement)')
301
311
  .option('--table', 'Human-readable table output instead of JSON')
302
312
  .option('--mode <mode>', 'Dispatch mode: validate (includes Tier-4 validators as read-only)')
313
+ .option('--preflight', 'Exit with code 1 if any agent files are missing')
303
314
  .option('-v, --verbose', 'Show stack trace on error')
304
315
  .action((feature, phase, options) => dispatchAgentsCommand(feature, phase, options));
305
316
 
317
+ program
318
+ .command('audit-dispatch <feature>')
319
+ .description('Display dispatch audit log for a feature')
320
+ .option('--json', 'Output as JSON instead of table')
321
+ .action((feature, options) => auditDispatchCommand(feature, options));
322
+
323
+ program
324
+ .command('agent-metrics [feature]')
325
+ .description('Display agent performance metrics for a feature')
326
+ .option('--json', 'Output as JSON instead of table')
327
+ .option('--all', 'Aggregate metrics across all features')
328
+ .action((feature, options) => agentMetricsCommand(feature, options));
329
+
330
+ program
331
+ .command('detect-agents <feature>')
332
+ .description('Detect relevant agents for a feature based on proposal keywords')
333
+ .option('--proposal <path>', 'Path to proposal file (default: .morph/features/{feature}/0-proposal/proposal.md)')
334
+ .option('--json', 'Output as JSON (default)')
335
+ .option('--table', 'Human-readable table output')
336
+ .option('--exclude <ids>', 'Comma-separated agent IDs to exclude')
337
+ .option('--refresh', 'Refresh detection using all phase outputs (additive, mutates state)')
338
+ .action((feature, options) => detectAgentsCommand(feature, options));
339
+
306
340
  // Scope escalation commands
307
341
  const scopeCommand = program
308
342
  .command('scope')
@@ -317,4 +351,59 @@ scopeCommand
317
351
  .option('--dry-run', 'Show recommendation without executing')
318
352
  .action((feature, options) => scopeEscalateCommand(feature, options));
319
353
 
354
+ // Agent management commands (CRUD)
355
+ const agentCommand = program
356
+ .command('agent')
357
+ .description('Manage agents in agents.json (list, show, add, edit, remove)');
358
+
359
+ agentCommand
360
+ .command('list')
361
+ .description('List all agents with optional filters')
362
+ .option('--group <name>', 'Filter by group')
363
+ .option('--tier <n>', 'Filter by tier (1-4)')
364
+ .option('--json', 'Output as JSON')
365
+ .action((options) => agentListCommand(options));
366
+
367
+ agentCommand
368
+ .command('show <id>')
369
+ .description('Show detailed info for an agent')
370
+ .option('--json', 'Output as JSON')
371
+ .option('--full', 'Show full spawn_prompt (no truncation)')
372
+ .action((id, options) => agentShowCommand(id, options));
373
+
374
+ agentCommand
375
+ .command('add <id>')
376
+ .description('Add a new agent via interactive wizard')
377
+ .option('--non-interactive', 'Use flags instead of prompts')
378
+ .option('--tier <n>', 'Tier (1-4)')
379
+ .option('--title <title>', 'Agent title')
380
+ .option('--group <group>', 'Agent group')
381
+ .option('--active-phases <phases>', 'Comma-separated phases or *')
382
+ .option('--reports-to <id>', 'Parent agent ID or "user"')
383
+ .option('--domains <domains>', 'Comma-separated domains')
384
+ .option('--keywords <keywords>', 'Comma-separated keywords')
385
+ .option('--spawn-prompt <prompt>', 'Teammate spawn prompt')
386
+ .option('--role <role>', 'Teammate role')
387
+ .option('--icon <emoji>', 'Teammate icon')
388
+ .action((id, options) => agentAddCommand(id, options));
389
+
390
+ agentCommand
391
+ .command('edit <id>')
392
+ .description('Edit agent fields via flags')
393
+ .option('--tier <n>', 'New tier')
394
+ .option('--title <title>', 'New title')
395
+ .option('--group <group>', 'New group')
396
+ .option('--active-phases <phases>', 'New phases (comma-sep)')
397
+ .option('--reports-to <id>', 'New reports_to')
398
+ .option('--keywords <keywords>', 'New keywords (comma-sep)')
399
+ .option('--domains <domains>', 'New domains (comma-sep)')
400
+ .option('--spawn-prompt <prompt>', 'New spawn prompt')
401
+ .action((id, options) => agentEditCommand(id, options));
402
+
403
+ agentCommand
404
+ .command('remove <id>')
405
+ .description('Remove an agent from agents.json')
406
+ .option('--force', 'Skip confirmation prompt')
407
+ .action((id, options) => agentRemoveCommand(id, options));
408
+
320
409
  program.parse();
@@ -13,7 +13,7 @@ import { access } from 'fs/promises';
13
13
  import { execSync } from 'child_process';
14
14
  import chalk from 'chalk';
15
15
 
16
- import { loadState, saveState } from '../src/core/state/state-manager.js';
16
+ import { loadState, saveState, resolveAgentForTask, updateDispatchAgentTiming } from '../src/core/state/state-manager.js';
17
17
  import { parseTasksMd, ensureTaskList, syncCounters } from '../src/lib/tasks/task-parser.js';
18
18
  import { isTestTask } from '../src/lib/tasks/task-classifier.js';
19
19
  import { runTestSuite } from '../src/lib/tasks/test-runner.js';
@@ -124,6 +124,7 @@ class TaskManager {
124
124
  // Persist initial taskList so counters are visible in `state get` even if
125
125
  // validation fails later and the completion save never runs.
126
126
  syncCounters(feature);
127
+ feature.updatedAt = new Date().toISOString();
127
128
  saveState(state);
128
129
 
129
130
  const results = [];
@@ -160,7 +161,7 @@ class TaskManager {
160
161
 
161
162
  // Run validation BEFORE marking tasks as complete
162
163
  if (tasksToComplete.length > 0 && !options.skipValidation) {
163
- const validationResult = await this.runValidation(featureName);
164
+ const validationResult = await this.runValidation(featureName, { mode: 'light' });
164
165
  if (options.dryRun) {
165
166
  console.log(chalk.cyan('\n ℹ️ Dry-run — tasks NOT marked as complete'));
166
167
  return [];
@@ -240,10 +241,14 @@ class TaskManager {
240
241
  }
241
242
 
242
243
  // Mark tasks as completed (only after validation passes)
244
+ // Mark tasks as completed with agent correlation
243
245
  for (const task of tasksToComplete) {
244
246
  task.status = 'completed';
245
247
  task.completedAt = new Date().toISOString();
246
- task.completedBy = 'claude';
248
+
249
+ // Resolve agent from dispatch (falls back to 'claude')
250
+ const agentId = resolveAgentForTask(featureName, task.id);
251
+ task.completedBy = agentId || 'claude';
247
252
 
248
253
  results.push(task);
249
254
 
@@ -255,6 +260,25 @@ class TaskManager {
255
260
  }
256
261
  }
257
262
 
263
+ // Update dispatch agent timing for completed tasks
264
+ const agentCompletions = new Map();
265
+ for (const task of results) {
266
+ const aid = task.completedBy;
267
+ if (aid && aid !== 'claude') {
268
+ if (!agentCompletions.has(aid)) agentCompletions.set(aid, []);
269
+ agentCompletions.get(aid).push(task.id);
270
+ }
271
+ }
272
+ for (const [aid, taskIds] of agentCompletions) {
273
+ const lastDispatch = feature.dispatchLog?.[feature.dispatchLog.length - 1];
274
+ const dispatchAgent = lastDispatch?.agents?.find(a => a.id === aid);
275
+ const existing = dispatchAgent?.tasksCompleted || [];
276
+ updateDispatchAgentTiming(featureName, aid, {
277
+ completedAt: new Date().toISOString(),
278
+ tasksCompleted: [...new Set([...existing, ...taskIds])]
279
+ });
280
+ }
281
+
258
282
  // Sync v3 counters then compute progress
259
283
  syncCounters(feature);
260
284
  feature.progress = this.calculateProgress(taskList);
@@ -273,6 +297,7 @@ class TaskManager {
273
297
  }
274
298
 
275
299
  // Persist state (atomic write via state-manager)
300
+ feature.updatedAt = new Date().toISOString();
276
301
  saveState(state);
277
302
 
278
303
  // Run TaskCompleted agent-teams hook for each completed task (non-blocking)
@@ -335,12 +360,12 @@ class TaskManager {
335
360
  * @param {string} featureName - Feature name
336
361
  * @returns {{ passed: boolean, validators: Object, passRate: number }}
337
362
  */
338
- async runValidation(featureName) {
363
+ async runValidation(featureName, opts = {}) {
339
364
  try {
340
365
  console.log(chalk.cyan('\n🔍 Running code validation...'));
341
366
 
342
367
  const { runValidation, formatValidationResults } = await import('../src/lib/validators/validation-runner.js');
343
- const result = await runValidation('.', featureName, { verbose: true });
368
+ const result = await runValidation('.', featureName, { verbose: true, ...opts });
344
369
 
345
370
  formatValidationResults(result);
346
371
 
@@ -498,10 +523,24 @@ class TaskManager {
498
523
  console.log(chalk.yellow('⚠️ Checkpoint hooks not available, using legacy validation'));
499
524
  try {
500
525
  const { runValidation } = await import('../src/lib/validators/validation-runner.js');
501
- const result = await runValidation('.', featureName, { verbose: false });
526
+ const result = await runValidation('.', featureName, { verbose: false, mode: 'full' });
502
527
  validationNote = result.passed
503
528
  ? ' | Validation: PASSED'
504
529
  : ` | Validation: ${result.errors} errors, ${result.warnings} warnings`;
530
+
531
+ // Persist checkpoint validation results to disk
532
+ try {
533
+ const { persistCheckpointValidation } = await import('../src/lib/validators/checkpoint-persistence.js');
534
+ persistCheckpointValidation(process.cwd(), featureName, {
535
+ checkpointNum,
536
+ timestamp: new Date().toISOString(),
537
+ passed: result.passed,
538
+ validators: result.results || {},
539
+ summary: result.summary || '',
540
+ });
541
+ } catch {
542
+ // Non-blocking
543
+ }
505
544
  } catch {
506
545
  // No validation available
507
546
  }
@@ -683,7 +722,21 @@ class TaskManager {
683
722
 
684
723
  task.status = 'in_progress';
685
724
  task.startedAt = new Date().toISOString();
725
+
726
+ // Agent correlation: resolve which agent is assigned this task from the latest dispatch
727
+ const agentId = resolveAgentForTask(featureName, taskId);
728
+ if (agentId) {
729
+ task.assignedAgent = agentId;
730
+ // Record agent startedAt only for the first task (don't overwrite)
731
+ const lastDispatch = feature.dispatchLog?.[feature.dispatchLog.length - 1];
732
+ const dispatchAgent = lastDispatch?.agents?.find(a => a.id === agentId);
733
+ if (dispatchAgent && !dispatchAgent.startedAt) {
734
+ updateDispatchAgentTiming(featureName, agentId, { startedAt: task.startedAt });
735
+ }
736
+ }
737
+
686
738
  syncCounters(feature);
739
+ feature.updatedAt = new Date().toISOString();
687
740
 
688
741
  saveState(state);
689
742
 
@@ -1,14 +1,14 @@
1
- {
2
- "name": "morph-spec",
3
- "version": "4.10.6",
4
- "displayName": "MORPH-SPEC Framework",
5
- "description": "Spec-driven development with 38 agents and 8-phase workflow for .NET/Blazor/Next.js/Azure",
6
- "publisher": "polymorphism-tech",
7
- "skills": {
8
- "directory": "framework/skills",
9
- "namespace": "morph-spec"
10
- },
11
- "hooks": {
12
- "directory": "framework/hooks/claude-code"
13
- }
14
- }
1
+ {
2
+ "name": "morph-spec",
3
+ "version": "4.10.8",
4
+ "displayName": "MORPH-SPEC Framework",
5
+ "description": "Spec-driven development with 38 agents and 8-phase workflow for .NET/Blazor/Next.js/Azure",
6
+ "publisher": "polymorphism-tech",
7
+ "skills": {
8
+ "directory": "framework/skills",
9
+ "namespace": "morph-spec"
10
+ },
11
+ "hooks": {
12
+ "directory": "framework/hooks/claude-code"
13
+ }
14
+ }
@@ -198,4 +198,4 @@ These files are never edited directly. Use CLI commands or `morph-spec update` i
198
198
 
199
199
  ---
200
200
 
201
- *morph-spec v4.10.6 by Polymorphism Tech*
201
+ *morph-spec v4.10.8 by Polymorphism Tech*