@polymorphism-tech/morph-spec 8.47.0 → 9.1.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 (377) hide show
  1. package/CLAUDE.md +51 -43
  2. package/README.md +39 -38
  3. package/bin/morph-spec.js +41 -113
  4. package/bin/validate.js +1 -147
  5. package/claude-plugin.json +1 -1
  6. package/docs/CHEATSHEET.md +1 -1
  7. package/docs/QUICKSTART.md +1 -1
  8. package/framework/CLAUDE.md +41 -101
  9. package/framework/MORPH.md +95 -252
  10. package/framework/agents.json +86 -21
  11. package/framework/commands/morph-apply.md +5 -28
  12. package/framework/commands/morph-archive.md +1 -1
  13. package/framework/commands/morph-hotfix.md +8 -8
  14. package/framework/commands/morph-infra.md +1 -1
  15. package/framework/commands/morph-preflight.md +2 -3
  16. package/framework/commands/morph-status.md +4 -4
  17. package/framework/docs/CLI.md +574 -286
  18. package/framework/evals/review-checklist.md +82 -41
  19. package/framework/hooks/README.md +10 -11
  20. package/framework/hooks/claude-code/core/block-destructive-worktree-removal.js +6 -49
  21. package/framework/hooks/claude-code/core/block-raw-worktree-add.js +2 -35
  22. package/framework/hooks/claude-code/core/chain.js +4 -65
  23. package/framework/hooks/claude-code/core/comment-guard.js +3 -17
  24. package/framework/hooks/claude-code/core/denylist.json +33 -3
  25. package/framework/hooks/claude-code/core/enforce-phase-writes.js +15 -63
  26. package/framework/hooks/claude-code/core/gate-guard.js +9 -78
  27. package/framework/hooks/claude-code/core/graph-refresh-kick.js +3 -24
  28. package/framework/hooks/claude-code/core/heavy-gate.js +3 -21
  29. package/framework/hooks/claude-code/core/heavy-release.js +2 -13
  30. package/framework/hooks/claude-code/core/loop-detect.js +2 -31
  31. package/framework/hooks/claude-code/core/pre-bash-denylist.js +36 -2
  32. package/framework/hooks/claude-code/core/protect-spec-files.js +25 -297
  33. package/framework/hooks/claude-code/core/state-sync.js +15 -85
  34. package/framework/hooks/claude-code/core/telemetry-log.js +15 -96
  35. package/framework/hooks/claude-code/core/validate-completion.js +37 -147
  36. package/framework/hooks/claude-code/core/warn-bash-source-write.js +23 -0
  37. package/framework/hooks/claude-code/core/worktree-context.js +15 -114
  38. package/framework/hooks/claude-code/core/worktree-create.js +6 -70
  39. package/framework/hooks/claude-code/core/worktree-env-inject.js +5 -56
  40. package/framework/hooks/claude-code/core/worktree-remove.js +5 -31
  41. package/framework/hooks/claude-code/statusline.py +55 -41
  42. package/framework/hooks/package.json +3 -0
  43. package/framework/hooks/shared/activity-logger.js +9 -89
  44. package/framework/hooks/shared/agent-reap.js +2 -17
  45. package/framework/hooks/shared/build-check.js +11 -76
  46. package/framework/hooks/shared/claim-registry.js +9 -119
  47. package/framework/hooks/shared/command-tokens.js +168 -44
  48. package/framework/hooks/shared/comment-rules.js +5 -20
  49. package/framework/hooks/shared/comment-scanner.js +11 -43
  50. package/framework/hooks/shared/comment-stripper.js +11 -85
  51. package/framework/hooks/shared/e2e-check.js +0 -0
  52. package/framework/hooks/shared/errata.js +59 -0
  53. package/framework/hooks/shared/feature-locator.js +11 -95
  54. package/framework/hooks/shared/frontend-locations.js +4 -0
  55. package/framework/hooks/shared/gate-question.js +12 -0
  56. package/framework/hooks/shared/git-exclude.js +3 -20
  57. package/framework/hooks/shared/git-paths.js +8 -104
  58. package/framework/hooks/shared/graph-freshness.js +22 -166
  59. package/framework/hooks/shared/graph-refresh.js +21 -149
  60. package/framework/hooks/shared/heavy-command.js +4 -12
  61. package/framework/hooks/shared/hook-response.js +8 -83
  62. package/framework/hooks/shared/morph-cli.js +8 -52
  63. package/framework/hooks/shared/payload-utils.js +10 -132
  64. package/framework/hooks/shared/phase-utils.js +14 -72
  65. package/framework/hooks/shared/redact-secrets.js +4 -15
  66. package/framework/hooks/shared/reparse-scan.js +6 -66
  67. package/framework/hooks/shared/slice-progress.js +99 -0
  68. package/framework/hooks/shared/source-files.js +4 -17
  69. package/framework/hooks/shared/spawn-command.js +23 -0
  70. package/framework/hooks/shared/state-reader.js +51 -247
  71. package/framework/hooks/shared/state-writer.js +9 -54
  72. package/framework/hooks/shared/stdin-reader.js +1 -11
  73. package/framework/hooks/shared/telemetry-logger.js +7 -67
  74. package/framework/hooks/shared/transcript-usage.js +7 -29
  75. package/framework/hooks/shared/worktree-root.js +7 -29
  76. package/framework/mcp/registry.json +3 -4
  77. package/framework/phases.json +23 -39
  78. package/framework/rules/csharp-standards.md +1 -1
  79. package/framework/rules/frontend-standards.md +1 -0
  80. package/framework/rules/hangfire-standards.md +1 -1
  81. package/framework/rules/neon-standards.md +1 -1
  82. package/framework/schemas/config.schema.json +14 -9
  83. package/framework/schemas/feature.schema.json +15 -50
  84. package/framework/skills/README.md +3 -4
  85. package/framework/skills/core/create-umbraco-lp/SKILL.md +1 -1
  86. package/framework/skills/core/migrate-lp-to-umbraco/SKILL.md +1 -1
  87. package/framework/skills/core/morph-apply/SKILL.md +149 -222
  88. package/framework/skills/core/morph-hotfix/SKILL.md +33 -42
  89. package/framework/skills/core/morph-machine/SKILL.md +2 -2
  90. package/framework/skills/core/morph-media/SKILL.md +1 -1
  91. package/framework/skills/core/morph-plan/SKILL.md +137 -299
  92. package/framework/skills/core/morph-review/SKILL.md +111 -136
  93. package/framework/skills/core/morph-standards/SKILL.md +27 -39
  94. package/framework/skills/core/morph-uiux/SKILL.md +94 -152
  95. package/framework/standards/STANDARDS.json +109 -1219
  96. package/framework/standards/STANDARDS.meta.json +1319 -0
  97. package/framework/standards/ai-agents/agent-archetypes.md +2 -2
  98. package/framework/standards/ai-agents/agent-session.md +1 -1
  99. package/framework/standards/ai-agents/conversational-agent-with-phases.md +4 -4
  100. package/framework/standards/ai-agents/durable-workflows-hitl.md +3 -3
  101. package/framework/standards/ai-agents/evals-with-cache.md +1 -2
  102. package/framework/standards/ai-agents/guardrails.md +1 -1
  103. package/framework/standards/ai-agents/multi-agent-patterns.md +2 -2
  104. package/framework/standards/ai-agents/observability-patterns.md +1 -1
  105. package/framework/standards/ai-agents/production.md +1 -1
  106. package/framework/standards/ai-agents/prompt-sources.md +2 -2
  107. package/framework/standards/ai-agents/providers/model-registry.md +1 -1
  108. package/framework/standards/ai-agents/rag-custom-pgvector.md +2 -2
  109. package/framework/standards/ai-agents/setup.md +3 -3
  110. package/framework/standards/ai-agents/sweet-spot.md +2 -2
  111. package/framework/standards/ai-agents/tool-adapters.md +0 -2
  112. package/framework/standards/ai-agents/vector-data-extensions.md +4 -4
  113. package/framework/standards/ai-agents/workflows.md +1 -1
  114. package/framework/standards/architecture/code-comments.md +7 -7
  115. package/framework/standards/architecture/vertical-slice/vertical-slice.md +1 -1
  116. package/framework/standards/backend/api/validation.md +1 -1
  117. package/framework/standards/backend/dotnet/vsa-handler-patterns.md +5 -5
  118. package/framework/standards/backend/integrations/hangfire/hangfire-jobs.md +1 -1
  119. package/framework/standards/backend/integrations/neon-auth/neon-auth.md +2 -2
  120. package/framework/standards/data/nosql/cache/redis.md +1 -1
  121. package/framework/standards/data/nosql/cosmos-db.md +3 -3
  122. package/framework/standards/frontend/admin-app/forms.md +1 -1
  123. package/framework/standards/frontend/design-system/art-direction.md +88 -0
  124. package/framework/standards/frontend/design-system/premium-finish.md +77 -2
  125. package/framework/standards/infrastructure/neon/neon-pgvector.md +5 -5
  126. package/framework/standards/integration/mcp/mcp-tools.md +7 -7
  127. package/framework/templates/CLAUDE.md.core.template +3 -3
  128. package/framework/templates/README.md +2 -3
  129. package/framework/templates/REGISTRY.json +15 -179
  130. package/framework/templates/docs/plan.md +72 -0
  131. package/framework/templates/docs/ui-mockups.md +4 -0
  132. package/framework/templates/dotnet/ai-kit/README.md +1 -9
  133. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Morph.AiKit.Tests.csproj +0 -10
  134. package/framework/templates/meta-prompts/squad-leaders/backend-squad.md +1 -1
  135. package/framework/templates/meta-prompts/squad-leaders/frontend-squad.md +1 -1
  136. package/framework/templates/meta-prompts/squad-leaders/squad-leader.md +1 -1
  137. package/framework/templates/meta-prompts/validators/pre-commit-validator.md +3 -4
  138. package/package.json +1 -1
  139. package/src/commands/context/context-refresh.js +0 -16
  140. package/src/commands/dashboard/dashboard.js +2 -8
  141. package/src/commands/e2e/e2e.js +18 -105
  142. package/src/commands/graph/affected.js +0 -14
  143. package/src/commands/graph/build.js +11 -50
  144. package/src/commands/graph/explain.js +0 -16
  145. package/src/commands/graph/status.js +1 -12
  146. package/src/commands/mcp/mcp-setup.js +4 -62
  147. package/src/commands/observability/cost.js +17 -111
  148. package/src/commands/observability/telemetry.js +1 -14
  149. package/src/commands/project/branch.js +4 -45
  150. package/src/commands/project/claim.js +4 -48
  151. package/src/commands/project/doctor-procs.js +1 -1
  152. package/src/commands/project/doctor.js +53 -307
  153. package/src/commands/project/env.js +1 -27
  154. package/src/commands/project/fleet.js +6 -35
  155. package/src/commands/project/heavy.js +3 -3
  156. package/src/commands/project/init.js +8 -68
  157. package/src/commands/project/install-plugin-cmd.js +0 -1
  158. package/src/commands/project/setup-infra-cmd.js +2 -1
  159. package/src/commands/project/stack-scan.js +58 -0
  160. package/src/commands/project/standards.js +65 -72
  161. package/src/commands/project/status.js +28 -121
  162. package/src/commands/project/update.js +31 -223
  163. package/src/commands/project/worktree.js +109 -883
  164. package/src/commands/scaffold/scaffold.js +0 -25
  165. package/src/commands/state/advance.js +65 -120
  166. package/src/commands/state/approve.js +87 -229
  167. package/src/commands/state/archive.js +23 -139
  168. package/src/commands/state/auto-approval.js +65 -0
  169. package/src/commands/state/create.js +49 -109
  170. package/src/commands/state/delete.js +11 -63
  171. package/src/commands/state/finish.js +105 -494
  172. package/src/commands/state/gate-check.js +74 -183
  173. package/src/commands/state/gate-decision.js +8 -42
  174. package/src/commands/state/handoff.js +4 -31
  175. package/src/commands/state/list.js +21 -91
  176. package/src/commands/state/report-check.js +134 -338
  177. package/src/commands/state/retype.js +12 -28
  178. package/src/commands/validation/index.js +0 -3
  179. package/src/commands/validation/mutate.js +79 -19
  180. package/src/commands/validation/plan-check.js +81 -0
  181. package/src/commands/validation/validate-feature.js +52 -216
  182. package/src/commands/validation/verify.js +45 -160
  183. package/src/core/paths/output-schema.js +9 -155
  184. package/src/core/state/feature-identity.js +1 -25
  185. package/src/core/state/gate-order.js +2 -30
  186. package/src/core/state/lifecycle-audit.js +8 -100
  187. package/src/core/state/state-manager.js +32 -395
  188. package/src/core/templates/template-registry.js +2 -97
  189. package/src/core/templates/template-renderer.js +13 -93
  190. package/src/core/templates/template-seed.js +21 -0
  191. package/src/core/work-types.js +10 -45
  192. package/src/dashboard/app/App.jsx +1 -8
  193. package/src/dashboard/app/components/ActivityFeed.jsx +2 -8
  194. package/src/dashboard/app/components/CommandPalette.jsx +4 -11
  195. package/src/dashboard/app/components/DetailPanel.jsx +1 -5
  196. package/src/dashboard/app/components/EntityLink.jsx +0 -12
  197. package/src/dashboard/app/components/ErrorBoundary.jsx +1 -8
  198. package/src/dashboard/app/components/KnowledgeMarkdown.jsx +0 -11
  199. package/src/dashboard/app/components/Markdown.jsx +0 -9
  200. package/src/dashboard/app/components/PhaseRail.jsx +0 -11
  201. package/src/dashboard/app/components/SearchFilter.jsx +0 -4
  202. package/src/dashboard/app/components/Sidebar.jsx +0 -5
  203. package/src/dashboard/app/hooks/useMorphQuery.js +1 -11
  204. package/src/dashboard/app/hooks/usePref.js +1 -5
  205. package/src/dashboard/app/lib/format.js +0 -2
  206. package/src/dashboard/app/lib/phases.js +3 -9
  207. package/src/dashboard/app/lib/project.js +0 -12
  208. package/src/dashboard/app/pages/Activity.jsx +1 -1
  209. package/src/dashboard/app/pages/AgentMap.jsx +1 -8
  210. package/src/dashboard/app/pages/FeatureDetail.jsx +139 -133
  211. package/src/dashboard/app/pages/Features.jsx +9 -16
  212. package/src/dashboard/app/pages/Guide.jsx +2 -3
  213. package/src/dashboard/app/pages/HookInspector.jsx +2 -23
  214. package/src/dashboard/app/pages/PhasePipeline.jsx +3 -7
  215. package/src/dashboard/app/pages/Portfolio.jsx +0 -1
  216. package/src/dashboard/app/pages/RulesMap.jsx +1 -16
  217. package/src/dashboard/app/pages/SkillsLibrary.jsx +1 -16
  218. package/src/dashboard/app/pages/Standards.jsx +2 -17
  219. package/src/dashboard/scanner/activity-scanner.js +14 -83
  220. package/src/dashboard/scanner/agents-scanner.js +1 -23
  221. package/src/dashboard/scanner/docs-scanner.js +1 -7
  222. package/src/dashboard/scanner/feature-status.js +2 -5
  223. package/src/dashboard/scanner/features-scanner.js +92 -113
  224. package/src/dashboard/scanner/hooks-scanner.js +5 -28
  225. package/src/dashboard/scanner/index.js +0 -4
  226. package/src/dashboard/scanner/portfolio.js +5 -29
  227. package/src/dashboard/scanner/project-api.js +8 -54
  228. package/src/dashboard/scanner/rules-scanner.js +1 -2
  229. package/src/dashboard/scanner/skills-scanner.js +2 -12
  230. package/src/dashboard/scanner/standards-scanner.js +4 -7
  231. package/src/dashboard/vite-plugin-morph-data.js +5 -19
  232. package/src/lib/ai/ai-checks.js +7 -52
  233. package/src/lib/ai/ai-project-scan.js +14 -108
  234. package/src/lib/ai/code-audit.js +7 -63
  235. package/src/lib/ai/pin-drift.js +8 -51
  236. package/src/lib/ai/registry-audit.js +11 -90
  237. package/src/lib/ci/ci-verify.js +14 -13
  238. package/src/lib/ci/github-ci.js +9 -37
  239. package/src/lib/ci/workflow-scaffold.js +2 -10
  240. package/src/lib/detectors/claude-config-detector.js +13 -74
  241. package/src/lib/detectors/index.js +8 -59
  242. package/src/lib/e2e/compose-env.js +5 -66
  243. package/src/lib/e2e/stack-teardown.js +6 -40
  244. package/src/lib/generators/architecture-scanner.js +18 -156
  245. package/src/lib/generators/handoff-generator.js +37 -112
  246. package/src/lib/generators/scaffold-generator.js +5 -101
  247. package/src/lib/generators/settings-generator.js +11 -122
  248. package/src/lib/git/branch-classifier.js +11 -84
  249. package/src/lib/git/default-branch.js +14 -169
  250. package/src/lib/git/evidence-staleness.js +2 -1
  251. package/src/lib/git/gh.js +2 -17
  252. package/src/lib/git/pending-prs.js +6 -37
  253. package/src/lib/git/pr-files.js +3 -28
  254. package/src/lib/git/pr-index.js +3 -34
  255. package/src/lib/git/tree-fingerprint.js +17 -17
  256. package/src/lib/git/tree-state.js +6 -33
  257. package/src/lib/graph/god-nodes.js +2 -22
  258. package/src/lib/graph/graph-health.js +3 -24
  259. package/src/lib/graph/graph-loader.js +5 -56
  260. package/src/lib/graph/graphify-runtime.js +7 -37
  261. package/src/lib/graph/graphifyignore.js +8 -74
  262. package/src/lib/graph/sanitize.js +16 -136
  263. package/src/lib/heavy/cleanup.js +2 -6
  264. package/src/lib/installers/effects.js +8 -93
  265. package/src/lib/installers/mcp-installer.js +9 -169
  266. package/src/lib/installers/memory-installer.js +8 -33
  267. package/src/lib/installers/templates-reconcile.js +5 -60
  268. package/src/lib/mutation/commands.js +3 -2
  269. package/src/lib/mutation/dotnet-introspection.js +281 -0
  270. package/src/lib/mutation/plan.js +14 -6
  271. package/src/lib/mutation/runner.js +1 -1
  272. package/src/lib/mutation/subset.js +47 -13
  273. package/src/lib/plan/artifact-vocabulary.js +40 -0
  274. package/src/lib/plan/checks.js +208 -0
  275. package/src/lib/plan/plan-parser.js +204 -0
  276. package/src/lib/plan/plan-template.js +18 -0
  277. package/src/lib/projects/registry.js +7 -44
  278. package/src/lib/review-reports.js +204 -0
  279. package/src/lib/risk-detector.js +131 -274
  280. package/src/lib/specs/adr-index.js +38 -85
  281. package/src/lib/specs/design-seed.js +18 -0
  282. package/src/lib/specs/frontmatter.js +31 -0
  283. package/src/lib/specs/gfm-table.js +11 -0
  284. package/src/lib/specs/revocations.js +31 -102
  285. package/src/lib/specs/screen-checklist.js +56 -132
  286. package/src/lib/stack/dotnet-build-ignores.js +43 -0
  287. package/src/lib/stack/stack-profile.js +1 -28
  288. package/src/lib/stack/stack-scan.js +260 -0
  289. package/src/lib/stack-filter.js +4 -27
  290. package/src/lib/standards/registry.js +37 -0
  291. package/src/lib/standards/sections.js +47 -0
  292. package/src/lib/standards/verified-against.js +19 -191
  293. package/src/lib/tasks/eval-node.js +23 -179
  294. package/src/lib/tasks/linux-runner.js +18 -142
  295. package/src/lib/tasks/test-nodes.js +43 -313
  296. package/src/lib/tasks/test-runner.js +107 -447
  297. package/src/lib/telemetry/metrics.js +13 -103
  298. package/src/lib/telemetry/telemetry-reader.js +13 -238
  299. package/src/lib/telemetry/verify-event.js +4 -34
  300. package/src/lib/validators/code-budget/code-budget-validator.js +4 -44
  301. package/src/lib/validators/code-budget/index.js +0 -7
  302. package/src/lib/validators/contracts/contract-compliance-validator.js +4 -26
  303. package/src/lib/validators/contracts/index.js +0 -6
  304. package/src/lib/validators/nextjs/index.js +0 -5
  305. package/src/lib/validators/nextjs/next-component-validator.js +4 -81
  306. package/src/lib/validators/packages/index.js +0 -6
  307. package/src/lib/validators/packages/package-validator.js +6 -56
  308. package/src/lib/validators/reuse/index.js +0 -8
  309. package/src/lib/validators/reuse/reuse-validator.js +24 -137
  310. package/src/lib/validators/reuse/symbol-scanner.js +6 -62
  311. package/src/lib/validators/traceability-check.js +54 -156
  312. package/src/lib/validators/validation-runner.js +20 -125
  313. package/src/lib/validators/verify-runner.js +152 -575
  314. package/src/lib/work-type-detector.js +5 -67
  315. package/src/lib/worktree/docker-audit.js +17 -137
  316. package/src/lib/worktree/env-allocator.js +10 -98
  317. package/src/lib/worktree/feature-truth.js +12 -115
  318. package/src/lib/worktree/finish-backup.js +32 -242
  319. package/src/lib/worktree/fleet-scanner.js +31 -126
  320. package/src/lib/worktree/ignored-triage.js +15 -91
  321. package/src/lib/worktree/vscode-settings.js +2 -3
  322. package/src/lib/worktree/worktree-audit.js +21 -213
  323. package/src/lib/worktree/worktree-include.js +3 -5
  324. package/src/scripts/global-install.js +3 -9
  325. package/src/scripts/install-plugin.js +1 -13
  326. package/src/scripts/setup-infra.js +17 -138
  327. package/src/utils/agents-installer.js +92 -272
  328. package/src/utils/banner.js +4 -25
  329. package/src/utils/claude-md-injector.js +1 -37
  330. package/src/utils/claude-settings-manager.js +1 -87
  331. package/src/utils/file-copier.js +32 -90
  332. package/src/utils/hooks-installer.js +26 -296
  333. package/src/utils/skills-installer.js +4 -102
  334. package/src/utils/version-checker.js +4 -83
  335. package/framework/commands/morph-proposal.md +0 -57
  336. package/framework/evals/trace-schema.md +0 -67
  337. package/framework/hooks/claude-code/core/tasks-json-guard.js +0 -83
  338. package/framework/hooks/claude-code/core/trace-autogen.js +0 -277
  339. package/framework/hooks/git/pre-commit/specs.sh +0 -50
  340. package/framework/hooks/shared/tasks-validator.js +0 -111
  341. package/framework/rules/morph-task-tracking.md +0 -54
  342. package/framework/rules/morph-workflow.md +0 -244
  343. package/framework/schemas/tasks.schema.json +0 -79
  344. package/framework/skills/core/morph-brainstorming/SKILL.md +0 -161
  345. package/framework/skills/core/morph-implement/SKILL.md +0 -194
  346. package/framework/skills/core/morph-proposal/SKILL.md +0 -152
  347. package/framework/skills/core/morph-stack-scan/SKILL.md +0 -145
  348. package/framework/templates/docs/proposal.md +0 -192
  349. package/framework/templates/docs/spec.md +0 -57
  350. package/framework/templates/docs/ui-components.md +0 -52
  351. package/framework/templates/docs/ui-design-system.md +0 -76
  352. package/framework/templates/docs/ui-flows.md +0 -167
  353. package/framework/templates/examples/spec-examples.md +0 -91
  354. package/framework/templates/feature/decisions.md +0 -124
  355. package/framework/templates/feature/recap.md +0 -145
  356. package/framework/templates/tasks.template.json +0 -17
  357. package/src/commands/state/usecase.js +0 -143
  358. package/src/commands/tasks/dag.js +0 -181
  359. package/src/commands/utils/index.js +0 -3
  360. package/src/lib/agents/output-collector.js +0 -76
  361. package/src/lib/detectors/design-system-detector.js +0 -188
  362. package/src/lib/evaluator-report.js +0 -104
  363. package/src/lib/generators/design-system-generator.js +0 -508
  364. package/src/lib/specs/acervo-format.js +0 -70
  365. package/src/lib/specs/acervo-lifecycle.js +0 -264
  366. package/src/lib/specs/done-criteria-check.js +0 -200
  367. package/src/lib/specs/usecase-check.js +0 -301
  368. package/src/lib/specs/usecase-promoter.js +0 -301
  369. package/src/lib/specs/usecase-registry.js +0 -237
  370. package/src/lib/tasks/dispatch-planner.js +0 -319
  371. package/src/lib/tasks/dotnet-test-introspection.js +0 -632
  372. package/src/lib/tasks/mermaid-renderer.js +0 -132
  373. package/src/lib/tasks/task-classifier.js +0 -30
  374. package/src/lib/tasks/task-parser.js +0 -209
  375. package/src/lib/tasks/tasks-json-parser.js +0 -296
  376. package/src/lib/tasks/test-scope.js +0 -597
  377. package/src/utils/agent-id-mapper.js +0 -11
@@ -1,11 +1,3 @@
1
- /**
2
- * Scaffold Command - Generate feature files from templates.
3
- *
4
- * Sub-commands:
5
- * - scaffold dotnet <feature> <slice-name> — VSA feature slice (.NET)
6
- * - scaffold nextjs <feature> — Feature page + components (Next.js)
7
- */
8
-
9
1
  import chalk from 'chalk';
10
2
  import { relative } from 'path';
11
3
  import { logger } from '../../utils/logger.js';
@@ -17,11 +9,6 @@ import {
17
9
 
18
10
  const KEBAB_REGEX = /^[a-z][a-z0-9]*(-[a-z0-9]+)*$/;
19
11
 
20
- /**
21
- * Validate that a name is valid kebab-case.
22
- * @param {string} name
23
- * @param {string} label
24
- */
25
12
  function validateKebabCase(name, label) {
26
13
  if (!KEBAB_REGEX.test(name)) {
27
14
  logger.error(`Invalid ${label}: "${name}"`);
@@ -30,11 +17,6 @@ function validateKebabCase(name, label) {
30
17
  }
31
18
  }
32
19
 
33
- /**
34
- * Log the result of a scaffold operation.
35
- * @param {Array<{path: string, skipped: boolean}>} files
36
- * @param {string} outputDir
37
- */
38
20
  function logResult(files, outputDir) {
39
21
  let created = 0;
40
22
  let skipped = 0;
@@ -56,16 +38,12 @@ function logResult(files, outputDir) {
56
38
  logger.info(parts.join(', '));
57
39
  }
58
40
 
59
- /**
60
- * Scaffold .NET VSA feature slice.
61
- */
62
41
  export async function scaffoldDotnetCommand(feature, sliceName, options) {
63
42
  validateKebabCase(feature, 'feature name');
64
43
  validateKebabCase(sliceName, 'slice name');
65
44
 
66
45
  const outputDir = options.outputDir || process.cwd();
67
46
 
68
- // Detect or use provided namespace
69
47
  const namespace = options.namespace || detectNamespace(outputDir);
70
48
  if (!namespace) {
71
49
  logger.error('Could not detect namespace');
@@ -100,9 +78,6 @@ export async function scaffoldDotnetCommand(feature, sliceName, options) {
100
78
  }
101
79
  }
102
80
 
103
- /**
104
- * Scaffold Next.js feature page with components and hooks.
105
- */
106
81
  export async function scaffoldNextjsCommand(feature, options) {
107
82
  validateKebabCase(feature, 'feature name');
108
83
 
@@ -1,54 +1,30 @@
1
1
  import chalk from 'chalk';
2
2
  import { existsSync, mkdirSync, readFileSync } from 'fs';
3
- import { join } from 'path';
3
+ import { join, relative } from 'path';
4
4
  import { fileURLToPath } from 'url';
5
5
  import { getFeature, setApprovalGate, derivePhase } from '../../core/state/state-manager.js';
6
6
  import { unmetPrereqs } from '../../core/state/gate-order.js';
7
7
  import { OUTPUT_SCHEMA } from '../../core/paths/output-schema.js';
8
8
  import { assertOwnerTree, ownerTreeRefusalLines } from '../../lib/worktree/feature-truth.js';
9
9
  import { uiuxAutoApprovalBlock } from '../../lib/specs/screen-checklist.js';
10
+ import { seedDesignArtifacts } from '../../lib/specs/design-seed.js';
11
+ import { sliceProgress } from '../../../framework/hooks/shared/slice-progress.js';
12
+ import { autoApprovalRefusal, printRefusal } from './auto-approval.js';
13
+ import { seedDotnetBuildIgnores } from '../../lib/stack/dotnet-build-ignores.js';
10
14
 
11
15
  const FRAMEWORK_DIR = fileURLToPath(new URL('../../../framework/', import.meta.url));
12
16
 
13
- /**
14
- * `morph-spec advance <feature>` — approve the current phase's gate AND scaffold
15
- * the next phase's folder in one step. This is the sanctioned, one-command way
16
- * to move a feature forward: it removes the need to hand-edit state.json (gate)
17
- * AND the need to `mkdir` the next phase folder by hand. Once the gate is
18
- * approved, the enforce-phase-writes hook permits writing the next phase's first
19
- * canonical artifact (which then advances the derived phase).
20
- */
17
+ // `implement` has no gate: advancing from it only scaffolds the review folder.
18
+ const PHASE_GATE = { plan: 'plan', uiux: 'uiux', review: 'review' };
21
19
 
22
- // The gate approved when *completing* a given phase. `implement` has no gate
23
- // (it ends when all tasks are done), so advancing from implement just scaffolds
24
- // the review folder.
25
- const PHASE_GATE = { proposal: 'proposal', uiux: 'uiux', plan: 'plan', review: 'review' };
26
-
27
- // The next phase folder to scaffold when advancing FROM a given phase. The
28
- // default forward path skips the optional design phase (proposal → plan); pass
29
- // --design to take the uiux branch (proposal → 1-design).
30
20
  const NEXT_PHASE_DIR = {
31
- proposal: '2-plan',
32
- uiux: '2-plan',
33
21
  plan: '3-implement',
22
+ uiux: '3-implement',
34
23
  implement: '4-review',
35
24
  };
36
25
 
37
- /**
38
- * The canonical artifacts the phase being CLOSED owes, per
39
- * `framework/phases.json → phases[phase].requiredOutputs`, resolved to real
40
- * filenames through OUTPUT_SCHEMA.
41
- *
42
- * Data-driven on purpose: adding an artifact to a phase must not need a code
43
- * change here, and the list must never drift from the phase definition.
44
- * Fail-open — an unreadable phases.json/OUTPUT_SCHEMA yields an empty list, so
45
- * a broken install degrades to today's behaviour instead of blocking every
46
- * advance.
47
- *
48
- * @param {string} phase
49
- * @param {string} featurePath
50
- * @returns {string[]} relative paths of the MISSING required artifacts
51
- */
26
+ // Data-driven from phases.json so the list never drifts from the phase definition. Fail-open:
27
+ // an unreadable phases.json yields an empty list instead of blocking every advance.
52
28
  function missingPhaseArtifacts(phase, featurePath) {
53
29
  try {
54
30
  const phasesPath = join(FRAMEWORK_DIR, 'phases.json');
@@ -56,33 +32,27 @@ function missingPhaseArtifacts(phase, featurePath) {
56
32
  const required = phases[phase]?.requiredOutputs || [];
57
33
  const missing = [];
58
34
  for (const outputType of required) {
59
- // requiredOutputs already carries OUTPUT_SCHEMA's camelCase keys — an
60
- // unknown key is skipped rather than guessed at.
35
+ // An unknown key is skipped rather than guessed at.
61
36
  const entry = OUTPUT_SCHEMA[outputType];
62
37
  if (!entry?.filename || !entry?.phaseDir) continue;
63
38
  const rel = `${entry.phaseDir}/${entry.filename}`;
64
39
  if (!existsSync(join(featurePath, entry.phaseDir, entry.filename))) missing.push(rel);
65
40
  }
41
+ if (phase === 'implement') missing.push(...unfinishedSliceReports(featurePath));
66
42
  return missing;
67
43
  } catch {
68
44
  return [];
69
45
  }
70
46
  }
71
47
 
72
- /**
73
- * When a required artifact is absent HERE, check whether it exists in the
74
- * worktree that owns this feature. `feature.json` travels committed on
75
- * `morph/{feature}`, so a feature developed in a worktree has its artifacts
76
- * there and only a scaffold in the primary root — running `advance` from the
77
- * root then demanded a file that already exists, one directory over.
78
- *
79
- * Message-only: this never reads state for a decision and never writes across
80
- * trees. It replaces a misleading error with an accurate one.
81
- *
82
- * Fail-open — no git, no worktree, or any error yields null (today's message).
83
- *
84
- * @returns {Promise<{path: string, branch: string|null, present: string[]}|null>}
85
- */
48
+ function unfinishedSliceReports(featurePath) {
49
+ const progress = sliceProgress(featurePath);
50
+ if (!progress) return ['2-plan/checks.json'];
51
+ return progress.slices.filter((s) => s.status !== 'feito').map((s) => `3-implement/reports/${s.id}.md`);
52
+ }
53
+
54
+ // Message-only and fail-open: names the worktree that holds the artifacts instead of demanding
55
+ // a file that exists one directory over. Never writes across trees.
86
56
  async function artifactsLiveInWorktree(featureName, missing) {
87
57
  try {
88
58
  const { findWorktreeForFeature } = await import('../project/worktree.js');
@@ -97,7 +67,6 @@ async function artifactsLiveInWorktree(featureName, missing) {
97
67
  }
98
68
  }
99
69
 
100
- /** Resolve who approved, honestly (mirrors approve.js — no fake human signatures). */
101
70
  function resolveApprovedBy(options) {
102
71
  if (options.approver) return options.approver;
103
72
  if (options.mode === 'auto') return 'auto';
@@ -105,6 +74,16 @@ function resolveApprovedBy(options) {
105
74
  return 'auto';
106
75
  }
107
76
 
77
+ export function reportDotnetIgnores(added) {
78
+ if (added.length) console.log(chalk.gray(` .gitignore: ${added.join(' ')} adicionados (projeto .NET) — commite antes do primeiro build.`));
79
+ }
80
+
81
+ function reportDesignSeed({ mockups, designSystem }) {
82
+ const rel = (p) => relative(process.cwd(), p).replace(/\\/g, '/');
83
+ if (mockups.written) console.log(chalk.gray(` Escrito ${rel(mockups.path)} a partir do template (checklist de tela por \`## Tela:\`).`));
84
+ if (designSystem.written) console.log(chalk.gray(` Escrito ${rel(designSystem.path)} a partir do template (o projeto não tinha design system).`));
85
+ }
86
+
108
87
  export async function advanceCommand(featureName, options = {}) {
109
88
  try {
110
89
  const feature = getFeature(featureName);
@@ -113,9 +92,7 @@ export async function advanceCommand(featureName, options = {}) {
113
92
  process.exit(1);
114
93
  }
115
94
 
116
- // Owner-tree guard: a live worktree elsewhere owns this feature's state —
117
- // never stamp a gate onto the root's birth-instant skeleton (branch-drift
118
- // created by this command, not merely left behind by one).
95
+ // A live worktree elsewhere owns the state: never stamp a gate onto the root skeleton.
119
96
  const owner = assertOwnerTree(featureName, process.cwd());
120
97
  if (owner.blocked) {
121
98
  for (const { tone, text } of ownerTreeRefusalLines(featureName, owner.tree, owner.branch, `morph-spec advance ${featureName}`)) {
@@ -127,6 +104,21 @@ export async function advanceCommand(featureName, options = {}) {
127
104
  const featurePath = join(process.cwd(), '.morph', 'features', featureName);
128
105
  const phase = derivePhase(featurePath);
129
106
 
107
+ // The plan gate is often closed by the human's answer to the gate question
108
+ // (state-sync), which already moves the derived phase to implement: taking
109
+ // the design branch then is opening 1-design/, not closing a phase.
110
+ if (options.design && phase === 'implement' && feature.approvalGates?.plan?.approved === true) {
111
+ mkdirSync(join(featurePath, '1-design'), { recursive: true });
112
+ reportDesignSeed(seedDesignArtifacts(featureName, process.cwd()));
113
+ reportDotnetIgnores(seedDotnetBuildIgnores(process.cwd(), { featureName }));
114
+ try {
115
+ const { writeHandoff } = await import('../../lib/generators/handoff-generator.js');
116
+ writeHandoff(featureName, process.cwd());
117
+ } catch { /* fail-open */ }
118
+ console.log(chalk.green(`\n✅ "${featureName}": gate plan já aprovado — ramo de design aberto (1-design/).\n`));
119
+ return;
120
+ }
121
+
130
122
  if (phase === 'review') {
131
123
  console.log(chalk.yellow(`\n⚠️ Feature "${featureName}" is already at the final phase (review).`));
132
124
  console.log(chalk.gray(`Approve Gate 3 with: morph-spec approve ${featureName} review`));
@@ -134,19 +126,10 @@ export async function advanceCommand(featureName, options = {}) {
134
126
  return;
135
127
  }
136
128
 
137
- // Phase-exit artifact check (D3): a phase transition must not step over the
138
- // artifact the phase it is CLOSING owes. Observed: a feature reached review
139
- // with NO 3-implement/recap.md — the file was written later, by hand, so
140
- // the Gate 3 review had nothing to review. `implement` has no gate, which
141
- // is precisely why nothing stopped it.
142
- //
143
- // `--force` bypasses (same deliberate-recovery role it already plays for
144
- // gate order) but still names what was skipped — a silent bypass would be
145
- // the defect again.
129
+ // `implement` has no gate, so this is what keeps unfinished slice reports out of review.
130
+ // `--force` bypasses it but still names what was skipped.
146
131
  const missingArtifacts = missingPhaseArtifacts(phase, featurePath);
147
132
  if (missingArtifacts.length && !options.force) {
148
- // Divergence, not absence: name the tree that actually holds the work
149
- // instead of asking for a file that exists in it.
150
133
  const elsewhere = await artifactsLiveInWorktree(featureName, missingArtifacts);
151
134
  if (elsewhere) {
152
135
  console.error(chalk.red(`\n❌ A fase "${phase}" de "${featureName}" não pode ser encerrada A PARTIR DESTA ÁRVORE.`));
@@ -160,36 +143,16 @@ export async function advanceCommand(featureName, options = {}) {
160
143
  process.exit(1);
161
144
  }
162
145
 
163
- console.error(chalk.red(`\n❌ A fase "${phase}" não pode ser encerrada — artefato(s) obrigatório(s) ausente(s):`));
146
+ console.error(chalk.red(`\n❌ A fase "${phase}" não pode ser encerrada — artefato(s) obrigatório(s) ausente(s) ou PARCIAL:`));
164
147
  for (const rel of missingArtifacts) console.error(chalk.gray(` • ${rel}`));
165
148
  console.error(chalk.gray('\n Produza o artefato e rode de novo, ou passe --force para avançar assim mesmo.\n'));
166
149
  process.exit(1);
167
150
  }
168
151
 
169
- // 1) Approve the gate that completes the current phase.
170
152
  const gate = PHASE_GATE[phase];
171
153
  const approvedBy = resolveApprovedBy(options);
172
154
 
173
- // The screen checklist is part of what the uiux phase owes. The predicate
174
- // is approve.js's too: an "auto" signature never closes a gate the
175
- // gate-check would pause, and a recorded decision or a human signature
176
- // (--approver) is the answer to that pause; --force is not, as in approve.
177
- const checklistBlock = phase === 'uiux' ? uiuxAutoApprovalBlock(process.cwd(), featureName, feature) : null;
178
- if (checklistBlock && approvedBy === 'auto') {
179
- console.error(chalk.red(`\n❌ A fase "uiux" não pode ser encerrada com assinatura automática — ${checklistBlock}.`));
180
- console.error(chalk.gray('\n Complete o checklist (ver a skill morph-uiux) e rode de novo. Quem decidiu aprovar assim'));
181
- console.error(chalk.gray(` mesmo grava a decisão (morph-spec gate-decision ${featureName} uiux --pause false --reason "...")`));
182
- console.error(chalk.gray(' ou assina com --approver <nome>. O --force não dispensa o checklist.\n'));
183
- process.exit(1);
184
- }
185
-
186
- // Gate monotonicity (mirrors approve.js): advance is a gate write-path too,
187
- // so it must not stamp gate N while a predecessor is pending. In the
188
- // sanctioned flow advance is always in-order (it approves G1 before the plan
189
- // artifact that flips the phase to plan exists), but an anomalous filesystem
190
- // state — e.g. 2-plan/spec.md present without Gate 1, the lead-termometro
191
- // shape — would otherwise let advance deepen the violation by stamping G2.
192
- // Escape via --force for deliberate recovery.
155
+ // Gate monotonicity: never stamp gate N while a predecessor is pending (`--force` to recover).
193
156
  if (gate) {
194
157
  const unmet = unmetPrereqs(gate, feature.approvalGates);
195
158
  if (unmet.length && !options.force) {
@@ -199,35 +162,19 @@ export async function advanceCommand(featureName, options = {}) {
199
162
  }
200
163
  }
201
164
 
202
- // Hotfix backstop (defensive, mirrors approve.js): the phase==='review'
203
- // early-return above already stops advance from ever reaching a
204
- // gate==='review' approval, but guard the approval itself too so this
205
- // stays true even if the early-return's shape changes later. Gate on the
206
- // RESOLVED approvedBy — headless contexts have no TTY and resolve to
207
- // "auto" regardless of --mode, so checking the raw --mode string alone
208
- // would let them slip through (same bug the approve.js backstop had).
209
- if (gate === 'review' && feature.workType === 'hotfix' && approvedBy === 'auto') {
210
- console.error(chalk.red('\n❌ Hotfix exige aprovação humana no Gate 3 — trust:auto não se aplica.'));
211
- console.error(chalk.gray(' Aprove com --approver <nome>, num terminal interativo, ou pela resposta humana "aprovado" (state-sync) ao review-report via AskUserQuestion.\n'));
212
- process.exit(1);
213
- }
214
-
215
- // Gate idempotency (F15): `setApprovalGate` REPLACES the gate object whole
216
- // (state-manager.js), so re-writing an already-approved gate does not
217
- // refresh it — it destroys `approvedBy`, `timestamp`, `notes` and
218
- // `selfAssessed` in one assignment. And `resolveApprovedBy` above answers
219
- // "auto" in every headless context, so `approve f proposal --approver
220
- // lucas` followed by `advance f` used to rewrite a human's signature as
221
- // "auto" — the one stamp the charter forbids on a human-approved gate.
222
- // The state-sync hook already carries exactly this guard; `advance`, the
223
- // other gate write-path, simply never got it.
224
- //
225
- // It skips ONLY the write. The scaffold and the handoff below still run,
226
- // so re-running `advance` after a failed scaffold keeps working — the
227
- // reason this is a guard and not an abort.
165
+ // `setApprovalGate` replaces the gate whole: rewriting an approved gate would turn a human
166
+ // signature into "auto". Skips ONLY the write, so the scaffold and handoff below still run.
228
167
  const priorGate = gate ? feature.approvalGates?.[gate] : null;
229
168
  const alreadyApproved = priorGate?.approved === true;
230
169
 
170
+ const refusal = alreadyApproved ? null
171
+ : autoApprovalRefusal({ cwd: process.cwd(), featureName, feature, gate, approvedBy });
172
+ if (refusal) {
173
+ printRefusal(chalk, refusal);
174
+ process.exit(1);
175
+ }
176
+ const checklistBlock = phase === 'uiux' && !alreadyApproved ? uiuxAutoApprovalBlock(process.cwd(), featureName, feature) : null;
177
+
231
178
  if (gate && !alreadyApproved) {
232
179
  await setApprovalGate(featureName, gate, true, {
233
180
  approvedBy,
@@ -236,17 +183,16 @@ export async function advanceCommand(featureName, options = {}) {
236
183
  });
237
184
  }
238
185
 
239
- // 2) Scaffold the next phase folder so the agent can write its first artifact.
240
186
  let nextDir = NEXT_PHASE_DIR[phase];
241
- if (phase === 'proposal' && options.design) nextDir = '1-design';
187
+ if (phase === 'plan' && options.design) nextDir = '1-design';
242
188
  if (nextDir) {
243
189
  const nextPath = join(featurePath, nextDir);
244
190
  if (!existsSync(nextPath)) mkdirSync(nextPath, { recursive: true });
245
191
  }
192
+ if (nextDir === '1-design') reportDesignSeed(seedDesignArtifacts(featureName, process.cwd()));
193
+ if (phase === 'plan') reportDotnetIgnores(seedDotnetBuildIgnores(process.cwd(), { featureName }));
246
194
 
247
- // Fleet handoff: a phase transition is exactly when a session hands the
248
- // feature over (to a new instance, or to itself after /compact) — refresh
249
- // the derived handoff.md so the next reader starts from the new phase.
195
+ // A phase transition is when a session hands the feature over: refresh handoff.md.
250
196
  try {
251
197
  const { writeHandoff } = await import('../../lib/generators/handoff-generator.js');
252
198
  writeHandoff(featureName, process.cwd());
@@ -260,8 +206,7 @@ export async function advanceCommand(featureName, options = {}) {
260
206
  const by = options.force ? '--force' : `aprovado por ${approvedBy}`;
261
207
  console.log(chalk.yellow(` ⚠️ ${by}: avançou com o ${checklistBlock}.`));
262
208
  }
263
- // Report what actually happened: claiming "approved (auto)" when nothing
264
- // was written is how the destroyed signature stayed invisible.
209
+ // Never claim "approved (auto)" when nothing was written.
265
210
  if (gate && alreadyApproved) {
266
211
  console.log(chalk.gray(` Gate "${gate}" was already approved (${priorGate.approvedBy || 'unknown'}) — approval preserved, nothing re-written.`));
267
212
  } else if (gate) {