@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,124 +0,0 @@
1
- # Architecture Decision Records - {{titleCase FEATURE_NAME}}
2
-
3
- ## ADR-001: {Decision Title}
4
-
5
- **Date:** {{DATE}}
6
- **Status:** Proposed | Accepted | Deprecated | Superseded
7
- **Deciders:** MORPH Agents, Developer
8
- **Alcance:** feature
9
-
10
- ### Context
11
-
12
- {Describe the context and problem that led to this decision}
13
-
14
- ### Decision
15
-
16
- {Describe the decision made}
17
-
18
- ### Consequences
19
-
20
- **Pros:**
21
- - {Positive consequence 1}
22
- - {Positive consequence 2}
23
-
24
- **Cons:**
25
- - {Negative consequence 1}
26
-
27
- **Risks:**
28
- - {Identified risk}
29
-
30
- ### Alternatives Considered
31
-
32
- #### Option A: {Name}
33
- - Pros: {advantages}
34
- - Cons: {disadvantages}
35
- - **Rejected because:** {reason}
36
-
37
- #### Option B: {Name}
38
- - Pros: {advantages}
39
- - Cons: {disadvantages}
40
- - **Rejected because:** {reason}
41
-
42
- ---
43
-
44
- {{#if (eq STACK "nextjs-neon")}}
45
- ## ADR-002: Database Access Strategy
46
-
47
- **Date:** {{DATE}}
48
- **Status:** Accepted
49
-
50
- ### Context
51
-
52
- Need to decide how the .NET API accesses Neon PostgreSQL.
53
-
54
- ### Decision
55
-
56
- Use Dapper with Npgsql for direct SQL queries. No EF Core.
57
-
58
- ### Consequences
59
-
60
- **Pros:**
61
- - Full control over SQL queries
62
- - Better performance (no ORM overhead)
63
- - Direct access to PostgreSQL features (jsonb, pgvector, functions)
64
- - RLS policies apply naturally through connection
65
-
66
- **Cons:**
67
- - No automatic migrations (use Neon CLI / dotnet ef instead)
68
- - Manual SQL query writing
69
- - No change tracking
70
-
71
- ---
72
-
73
- ## ADR-003: Auth Strategy
74
-
75
- **Date:** {{DATE}}
76
- **Status:** Accepted
77
-
78
- ### Context
79
-
80
- Need authentication for both Next.js frontend and .NET API.
81
-
82
- ### Decision
83
-
84
- Use Neon Auth (Better Auth) for authentication. Auth data lives in the Neon database. JWT validated by .NET API middleware.
85
-
86
- ### Consequences
87
-
88
- **Pros:**
89
- - Auth data in same database — no external provider, no sync delays
90
- - RLS policies work with Neon Auth JWT via auth.user_id() / pg_session_jwt
91
- - Built-in social login, email/password via @neondatabase/auth SDK
92
- - Branch isolation — each Neon branch gets isolated auth data
93
- - No webhooks needed — query neon_auth schema directly
94
-
95
- **Cons:**
96
- - Neon Auth is currently in Beta
97
- - JWT must be forwarded to .NET API for backend auth
98
- {{/if}}
99
-
100
- ---
101
-
102
- ## Template for New ADRs
103
-
104
- ```markdown
105
- ## ADR-XXX: {Title}
106
-
107
- **Date:**
108
- **Status:** Proposed | Accepted | Deprecated | Superseded
109
- **Alcance:** feature | projeto — `projeto` when the rule holds beyond this feature: `morph-spec finish` copies it to `.morph/specs/adrs/`, the folder brainstorming and plan read instead of archived decisions.md
110
-
111
- ### Context
112
- {Why is this decision needed?}
113
-
114
- ### Decision
115
- {What was decided?}
116
-
117
- ### Consequences
118
- **Pros:** {list}
119
- **Cons:** {list}
120
- ```
121
-
122
- ---
123
-
124
- *Generated by MORPH Framework*
@@ -1,145 +0,0 @@
1
- # Feature Recap: {{titleCase FEATURE_NAME}}
2
-
3
- ## Summary
4
-
5
- | Field | Value |
6
- |-------|-------|
7
- | **Feature ID** | {{FEATURE_NAME}} |
8
- | **Completed** | {{DATE}} |
9
- | **Total Tasks** | {X} |
10
- | **Time Spent** | {X}h |
11
- | **Agents Used** | {list} |
12
- {{#if STACK}}| **Stack** | {{STACK}} |{{/if}}
13
-
14
- ---
15
-
16
- ## Tasks Completed
17
-
18
- | ID | Title | Category | Duration |
19
- |----|-------|----------|----------|
20
- | T001 | {title} | {{#if (eq STACK "nextjs-neon")}}Database{{else}}{category}{{/if}} | {X}min |
21
- | T002 | {title} | {{#if (eq STACK "nextjs-neon")}}Backend{{else}}{category}{{/if}} | {X}min |
22
- | T003 | {title} | {{#if (eq STACK "nextjs-neon")}}Frontend{{else}}{category}{{/if}} | {X}min |
23
-
24
- ---
25
-
26
- {{#if (eq STACK "nextjs-neon")}}
27
- ## Validation Results
28
-
29
- | Validator | Status | Details |
30
- |-----------|--------|---------|
31
- | contract-compliance | Pass/Fail | {details} |
32
- | architecture | Pass/Fail | {details} |
33
- | design-system | Pass/Fail | {details} |
34
- | coding-standards | Pass/Fail | {details} |
35
-
36
- ---
37
-
38
- {{/if}}
39
- ## What Was Delivered
40
-
41
- ### Functionality
42
- - {Functionality 1 delivered}
43
- - {Functionality 2 delivered}
44
- - {Functionality 3 delivered}
45
-
46
- {{#if (eq STACK "nextjs-neon")}}
47
- ### Database (Neon PostgreSQL)
48
- - Tables: {list}
49
- - RLS Policies: {count} policies
50
- - Migrations: {count} files
51
-
52
- ### Backend API (.NET)
53
- - Endpoints: {count} endpoints
54
- - Services: {list}
55
-
56
- ### Frontend (Next.js)
57
- - Pages: {list}
58
- - Components: {list}
59
- {{/if}}
60
-
61
- ---
62
-
63
- ## Files Created
64
-
65
- ```
66
- {{#if (eq STACK "nextjs-neon")}}
67
- migrations/{files}
68
- backend/src/{files}
69
- frontend/src/{files}
70
- {{else}}
71
- {list of created files}
72
- {{/if}}
73
- ```
74
-
75
- ## Files Modified
76
-
77
- ```
78
- {list of modified files}
79
- ```
80
-
81
- ---
82
-
83
- ## Architecture Decisions
84
-
85
- | Decision | Rationale |
86
- |----------|-----------|
87
- | {Decision 1} | {Reason} |
88
- | {Decision 2} | {Reason} |
89
-
90
- See full ADRs in `decisions.md`
91
-
92
- ---
93
-
94
- ## Test Coverage
95
-
96
- | Type | Files | Coverage |
97
- |------|-------|----------|
98
- | {{#if (eq STACK "nextjs-neon")}}Backend Unit{{else}}Unit Tests{{/if}} | {X} | {X}% |
99
- | {{#if (eq STACK "nextjs-neon")}}Frontend Component{{else}}Integration Tests{{/if}} | {X} | {X}% |
100
-
101
- ---
102
-
103
- ## Lessons Learned
104
-
105
- ### What Went Well
106
- - {Positive point 1}
107
- - {Positive point 2}
108
-
109
- ### What Could Be Improved
110
- - {Improvement point 1}
111
- - {Improvement point 2}
112
-
113
- ### Recommendations for Future
114
- - {Recommendation 1}
115
- - {Recommendation 2}
116
-
117
- ---
118
-
119
- ## Metrics
120
-
121
- | Metric | Value |
122
- |--------|-------|
123
- | Tasks Completed | {X}/{X} |
124
- | Checkpoints Passed | {X} |
125
- {{#if (eq STACK "nextjs-neon")}}| Validation Passes | {X}/{X} |
126
- {{else}}| Code Reviews | {X} |
127
- {{/if}}| Bugs Found | {X} |
128
- | Bugs Fixed | {X} |
129
-
130
- ---
131
-
132
- ## Related Resources
133
-
134
- - **Proposal:** `proposal.md`
135
- - **Spec:** `spec.md`
136
- {{#if (eq STACK "nextjs-neon")}}- **Contracts (.NET):** `contracts.cs`
137
- - **Contracts (TS):** `contracts.ts`
138
- {{else}}- **Contracts:** `contracts.cs`
139
- {{/if}}- **Tasks:** `tasks.json`
140
- - **Decisions:** `decisions.md`
141
- - **PR:** {link}
142
-
143
- ---
144
-
145
- *Generated by MORPH Framework on {{DATE}}*
@@ -1,17 +0,0 @@
1
- {
2
- "version": "1.0",
3
- "feature": "{{featureName}}",
4
- "tasks": [
5
- {
6
- "id": "T1",
7
- "title": "Example task title",
8
- "description": "What this task accomplishes and why",
9
- "dependencies": [],
10
- "effort": "M",
11
- "doneCriteria": "Verifiable acceptance condition stated in one sentence",
12
- "status": "pending",
13
- "outputs": [],
14
- "group": "backend"
15
- }
16
- ]
17
- }
@@ -1,143 +0,0 @@
1
- /**
2
- * `morph-spec usecase reserve [--count <n>] [--feature <name>] [--json]` —
3
- * atomically mint the next N `UC-{nn}` numbers, shared across every worktree
4
- * of this repo. See `usecase-registry.js` for why this exists (worktrees only
5
- * ever see their own tree, so an independent max+1 scan collides).
6
- *
7
- * `--feature` is more than an audit label: `usecase-promoter.js`'s collision
8
- * guard uses the reservation record to tell a legitimate cross-feature
9
- * correction (never reserved — reusing a published number by design) from an
10
- * accidental collision (both features reserved the same id). Passing it is
11
- * how `morph-plan` gets that protection; omitting it degrades to "reserved,
12
- * no owner recorded" — still collision-free, just unable to name the
13
- * conflicting feature if one ever surfaces.
14
- *
15
- * `morph-spec usecase check <feature>` — see `usecaseCheckCommand` below.
16
- */
17
-
18
- import chalk from 'chalk';
19
- import { existsSync, readdirSync } from 'fs';
20
- import { join } from 'path';
21
- import { resolveGitCommonDir } from '../../../framework/hooks/shared/git-paths.js';
22
- import { reserveUseCases } from '../../lib/specs/usecase-registry.js';
23
- import { checkUseCases } from '../../lib/specs/usecase-check.js';
24
- import { checkLifecycle } from '../../lib/specs/acervo-lifecycle.js';
25
- import { parseTasksJsonLenient } from '../../lib/tasks/tasks-json-parser.js';
26
- import { isValidFeatureName } from '../project/worktree.js';
27
- import { printLifecycleWarnings } from '../tasks/dag.js';
28
-
29
- /**
30
- * Best-effort feature-name inference when `--feature` is omitted: only when
31
- * exactly one active feature exists is the guess unambiguous. Anything else
32
- * (zero, or more than one) is left null rather than guessed wrong — a wrong
33
- * guess would poison the collision guard's provenance record.
34
- */
35
- function inferActiveFeature(cwd) {
36
- const featuresDir = join(cwd, '.morph', 'features');
37
- try {
38
- if (!existsSync(featuresDir)) return null;
39
- const entries = readdirSync(featuresDir, { withFileTypes: true }).filter((e) => e.isDirectory());
40
- return entries.length === 1 ? entries[0].name : null;
41
- } catch {
42
- return null;
43
- }
44
- }
45
-
46
- /**
47
- * @param {{ count?: string, feature?: string, json?: boolean, cwd?: string }} [options]
48
- */
49
- export function usecaseReserveCommand(options = {}) {
50
- const cwd = options.cwd || process.cwd();
51
- const count = Number.parseInt(options.count, 10);
52
- const n = Number.isInteger(count) && count > 0 ? count : 1;
53
- const feature = options.feature || inferActiveFeature(cwd) || null;
54
-
55
- let gitCommonDir = null;
56
- try { gitCommonDir = resolveGitCommonDir(cwd); } catch { gitCommonDir = null; }
57
-
58
- let result;
59
- try {
60
- result = reserveUseCases(cwd, { feature, count: n, gitCommonDir });
61
- } catch (error) {
62
- if (options.json) {
63
- console.log(JSON.stringify({ reserved: false, error: error.message }));
64
- process.exit(1);
65
- }
66
- console.error(chalk.red(`\n❌ ${error.message}\n`));
67
- process.exit(1);
68
- }
69
-
70
- const warning = gitCommonDir
71
- ? null
72
- : 'projeto fora de um repositório git — numeração protegida só localmente; paralelismo entre worktrees NÃO está garantido.';
73
-
74
- if (options.json) {
75
- console.log(JSON.stringify({ reserved: true, ...result, feature, warning }));
76
- process.exit(0);
77
- }
78
-
79
- console.log(chalk.green(`\n✅ Reservado: ${result.numbers.join(' ')}`));
80
- if (feature) console.log(chalk.gray(` feature: ${feature}`));
81
- if (warning) console.log(chalk.yellow(`⚠️ ${warning}\n`));
82
- else console.log('');
83
- process.exit(0);
84
- }
85
-
86
- /**
87
- * `morph-spec usecase check <feature> [--json]` — the use-case half of `dag`,
88
- * runnable before `tasks.json` exists: the feature's use cases and the
89
- * revocations its `spec.md` declares, against the acervo's lifecycle. With a
90
- * `tasks.json`, also the task → use case plumbing `dag` checks.
91
- *
92
- * Exit 1 only for what `dag` also refuses (a task pointing at a use case that
93
- * does not exist, a tasks.json that does not validate); lifecycle findings are
94
- * warnings.
95
- *
96
- * @param {string} feature
97
- * @param {{ json?: boolean, cwd?: string }} [options]
98
- */
99
- export async function usecaseCheckCommand(feature, options = {}) {
100
- const cwd = options.cwd || process.cwd();
101
- const fail = (error) => {
102
- if (options.json) console.log(JSON.stringify({ feature, error }));
103
- else console.error(chalk.red(`\n❌ ${error}\n`));
104
- process.exit(1);
105
- };
106
-
107
- if (!isValidFeatureName(feature)) fail(`nome de feature inválido: "${feature}"`);
108
- const featureDir = join(cwd, '.morph', 'features', feature);
109
- if (!existsSync(featureDir)) fail(`feature não encontrada: .morph/features/${feature}`);
110
-
111
- const tasksPath = join(featureDir, '2-plan', 'tasks.json');
112
- let tasksData = null;
113
- if (existsSync(tasksPath)) {
114
- try {
115
- ({ data: tasksData } = await parseTasksJsonLenient(tasksPath));
116
- } catch (error) {
117
- fail(`tasks.json inválido: ${error.message}`);
118
- }
119
- }
120
-
121
- const useCases = tasksData ? checkUseCases(tasksData, join(featureDir, '2-plan', 'usecases')) : null;
122
- const lifecycle = checkLifecycle({ cwd, featureDir, tasksData });
123
- const broken = useCases?.errors.length > 0;
124
-
125
- if (options.json) {
126
- console.log(JSON.stringify({ feature, useCases, lifecycle }, null, 2));
127
- process.exit(broken ? 1 : 0);
128
- }
129
-
130
- if (broken) {
131
- console.error(chalk.red(`\n❌ Use cases — ${useCases.errors.length} erro(s)\n`));
132
- for (const e of useCases.errors) console.error(chalk.red(` ${e}`));
133
- }
134
- if (useCases?.warnings.length) {
135
- console.error(chalk.yellow(`\n⚠ Use cases — ${useCases.warnings.length} aviso(s)`));
136
- for (const w of useCases.warnings) console.error(chalk.yellow(` ${w}`));
137
- }
138
- printLifecycleWarnings(lifecycle);
139
- if (!broken && !useCases?.warnings.length && !lifecycle.warnings.length) {
140
- console.log(chalk.green(`\n✅ ${feature}: use cases e acervo sem achados\n`));
141
- }
142
- process.exit(broken ? 1 : 0);
143
- }
@@ -1,181 +0,0 @@
1
- import chalk from 'chalk';
2
- import { existsSync, readFileSync } from 'fs';
3
- import { join } from 'path';
4
- import { parseTasksJsonLenient, oversizedTasks, MAX_TASK_OUTPUTS } from '../../lib/tasks/tasks-json-parser.js';
5
- import { planDispatch } from '../../lib/tasks/dispatch-planner.js';
6
- import { renderMermaidFlowchart } from '../../lib/tasks/mermaid-renderer.js';
7
- import { checkUseCases } from '../../lib/specs/usecase-check.js';
8
- import { checkArtifactCriteria } from '../../lib/specs/done-criteria-check.js';
9
- import { checkLifecycle } from '../../lib/specs/acervo-lifecycle.js';
10
-
11
- /** Shared by `dag` and `usecase check` — the two surfaces of the same finding. */
12
- export function printLifecycleWarnings(lifecycle) {
13
- if (!lifecycle?.warnings?.length) return;
14
- const n = lifecycle.warnings.length;
15
- console.error(chalk.yellow(`\n⚠ Ciclo de vida do acervo — ${n} ${n === 1 ? 'aviso' : 'avisos'}`));
16
- for (const w of lifecycle.warnings) console.error(chalk.yellow(` ${w}`));
17
- }
18
-
19
- function planGateApproved(featureDir) {
20
- try {
21
- const feature = JSON.parse(readFileSync(join(featureDir, 'feature.json'), 'utf8'));
22
- return feature?.approvalGates?.plan?.approved === true;
23
- } catch {
24
- return false;
25
- }
26
- }
27
-
28
- /**
29
- * `morph-spec dag <feature>` — analyze the tasks.json DAG and print the
30
- * sequential vs parallel dispatch decision, weighted by effort.
31
- *
32
- * This is the command morph-apply §2 runs instead of re-deriving the rules
33
- * (and instead of the old inline JS snippets the LLM could not execute).
34
- *
35
- * `--mermaid` emits the DAG as a Mermaid `flowchart TD` instead (for
36
- * visualizing the plan at Gate 2), bypassing the dispatch analysis entirely.
37
- */
38
- export async function dagCommand(featureName, options = {}) {
39
- try {
40
- const featureDir = join(process.cwd(), '.morph', 'features', featureName);
41
- const planDir = join(featureDir, '2-plan');
42
- const tasksPath = join(planDir, 'tasks.json');
43
- if (!existsSync(tasksPath)) {
44
- console.error(chalk.red(`\n❌ tasks.json not found for feature "${featureName}"`));
45
- console.error(chalk.gray(`Expected at: .morph/features/${featureName}/2-plan/tasks.json\n`));
46
- process.exit(1);
47
- }
48
-
49
- // parseTasksJsonLenient validates the schema and throws with the error
50
- // list, but defaults a missing `version` (legacy plans predating the
51
- // field) instead of failing — the DAG analysis doesn't depend on it.
52
- const { data, versionDefaulted } = await parseTasksJsonLenient(tasksPath);
53
- if (versionDefaulted) {
54
- console.error(chalk.yellow(
55
- `⚠ tasks.json has no 'version' field — defaulting to "1.0" for this analysis.\n` +
56
- ` Consider adding it back explicitly (safe: protect-spec-files allows backfilling it).`
57
- ));
58
- }
59
-
60
- // --mermaid short-circuits before the dispatch analysis: visualizing the
61
- // plan's DAG doesn't need a sequential-vs-parallel decision.
62
- if (options.mermaid) {
63
- console.log(renderMermaidFlowchart(data));
64
- return;
65
- }
66
-
67
- // Use-case cross-check. Runs AFTER the --mermaid short-circuit on purpose:
68
- // rendering the DAG is pure visualization and must never be blocked by the
69
- // state of the spec. A broken `usecase` reference IS fatal here — the file
70
- // either exists or it does not, so there is no false positive to weigh
71
- // against a plan that points at a use case nobody can read.
72
- const ucCheck = checkUseCases(data, join(planDir, 'usecases'));
73
-
74
- // Artifact-postcondition warning (issue #87). Lexical, not wiring — it
75
- // runs over ALL tasks even when the feature has no use cases at all
76
- // (checkUseCases short-circuits above in that case), because a task's
77
- // own doneCriteria can describe an artifact with no use case in sight.
78
- const artifactCriteria = checkArtifactCriteria(data, join(planDir, 'usecases'));
79
-
80
- // Acervo lifecycle: a task citing a superseded use case, and the spec.md
81
- // revocation rows the finish would fail to apply. Warnings only.
82
- const lifecycle = checkLifecycle({ cwd: process.cwd(), featureDir, tasksData: data });
83
-
84
- // Task acima do teto não cabe num dispatch. Antes do Gate 2 é erro (o plano
85
- // ainda fatia); depois é aviso, para não travar feature em voo.
86
- const oversized = oversizedTasks(data);
87
- const sizeBlocks = oversized.length > 0 && !planGateApproved(featureDir);
88
- const taskSize = { max: MAX_TASK_OUTPUTS, oversized, blocking: sizeBlocks };
89
-
90
- const plan = planDispatch(data);
91
-
92
- if (options.json) {
93
- console.log(JSON.stringify({ ...plan, useCases: ucCheck, artifactCriteria, lifecycle, taskSize }, null, 2));
94
- if (ucCheck.errors.length || sizeBlocks) process.exit(1);
95
- return;
96
- }
97
-
98
- const plural = (n, one, many) => `${n} ${n === 1 ? one : many}`;
99
-
100
- if (ucCheck.errors.length) {
101
- console.error(chalk.red(`\n❌ Use cases — ${plural(ucCheck.errors.length, 'erro', 'erros')}\n`));
102
- for (const e of ucCheck.errors) console.error(chalk.red(` ${e}`));
103
- console.error(chalk.gray('\n Corrija a referência no tasks.json ou restaure o use case.\n'));
104
- process.exit(1);
105
- }
106
- if (oversized.length) {
107
- const tone = sizeBlocks ? chalk.red : chalk.yellow;
108
- const head = sizeBlocks ? '❌' : '⚠';
109
- console.error(tone(`\n${head} Tamanho de task — ${plural(oversized.length, 'task', 'tasks')} acima de ${MAX_TASK_OUTPUTS} outputs`));
110
- for (const t of oversized) console.error(tone(` ${t.id}: ${t.outputs} outputs`));
111
- console.error(chalk.gray(' Fatie por pós-condição: uma task cabe num dispatch (morph-plan, "Tamanho da task").\n'));
112
- if (sizeBlocks) process.exit(1);
113
- }
114
- if (ucCheck.warnings.length) {
115
- console.error(chalk.yellow(`\n⚠ Use cases — ${plural(ucCheck.warnings.length, 'aviso', 'avisos')}`));
116
- for (const w of ucCheck.warnings) console.error(chalk.yellow(` ${w}`));
117
- }
118
- if (artifactCriteria.warnings.length) {
119
- console.error(chalk.yellow(`\n⚠ Critérios de artefato — ${plural(artifactCriteria.warnings.length, 'aviso', 'avisos')}`));
120
- for (const w of artifactCriteria.warnings) console.error(chalk.yellow(` ${w}`));
121
- console.error(chalk.gray(' Teste que lê texto de arquivo não prova comportamento (morph-plan §2, "Por que artefato").'));
122
- }
123
- printLifecycleWarnings(lifecycle);
124
-
125
- console.log(chalk.bold(`\n📊 DAG — ${featureName}`));
126
- console.log('━'.repeat(60));
127
-
128
- const { stats } = plan;
129
- console.log(`\nTasks: ${stats.total} total, ${stats.pending} pendente(s)`);
130
- const groupLine = Object.keys(stats.groups)
131
- .map(g => `${g}:${stats.groups[g]} (peso ${stats.weights[g]})`)
132
- .join(' | ');
133
- if (groupLine) console.log(chalk.gray(`Grupos pendentes: ${groupLine}`));
134
-
135
- const modeLabel = {
136
- 'sequential': 'SEQUENCIAL (auto-advance)',
137
- 'parallel-flows': 'PARALELO por fluxo de domínio',
138
- 'parallel-roots': 'PARALELO por raízes independentes',
139
- }[plan.mode];
140
- console.log(chalk.cyan(`\nDecisão: ${modeLabel}`));
141
- console.log(` → ${plan.reason}`);
142
-
143
- for (const flow of plan.flows) {
144
- console.log(` ${chalk.green('▶')} Fluxo ${chalk.bold(flow.group)} (peso ${flow.weight}): ${flow.taskIds.join(', ')}`);
145
- }
146
- if (plan.batch.length > 0) {
147
- console.log(` ${chalk.green('▶')} Batch paralelo: ${plan.batch.join(', ')}`);
148
- }
149
- if (plan.inline.length > 0) {
150
- console.log(` ${chalk.yellow('○')} Inline (sem dispatch próprio): ${plan.inline.join(', ')}`);
151
- }
152
- if (plan.sequentialRemainder.length > 0) {
153
- console.log(` ${chalk.gray('→')} Sequencial: ${plan.sequentialRemainder.join(', ')}`);
154
- }
155
-
156
- // Isolamento — only meaningful when there IS a parallel batch. In a shared
157
- // working tree two agents writing the same path corrupt each other; the
158
- // dag recommends `isolation: "worktree"` so each runs in its own worktree
159
- // (morph-apply §3b-w).
160
- const iso = plan.isolation;
161
- if (iso && (iso.recommended === 'worktree' || iso.unknownFootprint.length > 0)) {
162
- console.log(chalk.bold('\nIsolamento:'));
163
- if (iso.recommended === 'worktree') {
164
- console.log(` ${chalk.yellow('⚠')} recomendado: ${chalk.bold('worktree')} — ${iso.reason}`);
165
- for (const c of iso.collisions) {
166
- console.log(chalk.gray(` colisão em "${c.path}": ${c.units.join(' ‖ ')} (${c.tasks.join(', ')})`));
167
- }
168
- } else {
169
- console.log(` ${chalk.gray('○')} ${iso.reason}`);
170
- }
171
- if (iso.unknownFootprint.length > 0) {
172
- console.log(chalk.gray(` footprint desconhecido (sem outputs): ${iso.unknownFootprint.join(', ')}`));
173
- }
174
- }
175
-
176
- console.log('\n' + '━'.repeat(60) + '\n');
177
- } catch (error) {
178
- console.error(chalk.red(`\n❌ Error analyzing DAG: ${error.message}\n`));
179
- process.exit(1);
180
- }
181
- }
@@ -1,3 +0,0 @@
1
- /**
2
- * Utility Commands — no active commands after CLI simplification
3
- */
@@ -1,76 +0,0 @@
1
- /**
2
- * output-collector — Collect phase output files for multi-source agent detection
3
- *
4
- * Reads all existing phase outputs for a feature and returns them as
5
- * weighted TextSource[] for use in detectAgents().
6
- */
7
-
8
- import { readFileSync, existsSync } from 'fs';
9
- import { OUTPUT_SCHEMA, getAbsoluteOutputPath } from '../../core/paths/output-schema.js';
10
-
11
- /**
12
- * Default source weights per output type.
13
- * Keys match OUTPUT_SCHEMA keys (camelCase).
14
- */
15
- export const SOURCE_WEIGHTS = {
16
- proposal: 1.0,
17
- stackScan: 0.8,
18
- spec: 1.5,
19
- tasks: 1.3,
20
- decisions: 1.0,
21
- uiDesignSystem: 1.0,
22
- uiMockups: 1.0,
23
- uiComponents: 1.0,
24
- uiFlows: 1.0,
25
- recap: 1.0,
26
- reviewReport: 1.0,
27
- };
28
-
29
- /** Phase order for sorting collected outputs (v5 NLH model) */
30
- const PHASE_ORDER = ['proposal', 'uiux', 'plan', 'implement', 'review'];
31
-
32
- /**
33
- * Collect all existing phase output files for a feature.
34
- *
35
- * @param {string} projectRoot - Absolute path to project root
36
- * @param {string} featureName - Feature name
37
- * @returns {Array<{source: string, content: string, weight: number}>}
38
- */
39
- export function collectPhaseOutputs(projectRoot, featureName) {
40
- const results = [];
41
-
42
- for (const [key, entry] of Object.entries(OUTPUT_SCHEMA)) {
43
- // Multi-file types resolve to a DIRECTORY — there is no single document to
44
- // weigh as one source. Skipped explicitly rather than left to fail as an
45
- // EISDIR swallowed by the catch below.
46
- if (entry.multi) continue;
47
-
48
- const absPath = getAbsoluteOutputPath(projectRoot, featureName, key);
49
- if (!existsSync(absPath)) continue;
50
-
51
- try {
52
- const content = readFileSync(absPath, 'utf8');
53
- if (!content.trim()) continue; // Skip empty files
54
-
55
- results.push({
56
- source: entry.filename,
57
- content,
58
- weight: SOURCE_WEIGHTS[key] ?? 1.0,
59
- _phase: entry.phase,
60
- });
61
- } catch {
62
- // Skip unreadable files — fail-open
63
- continue;
64
- }
65
- }
66
-
67
- // Sort by phase order
68
- results.sort((a, b) => {
69
- const orderA = PHASE_ORDER.indexOf(a._phase);
70
- const orderB = PHASE_ORDER.indexOf(b._phase);
71
- return (orderA === -1 ? 99 : orderA) - (orderB === -1 ? 99 : orderB);
72
- });
73
-
74
- // Remove internal _phase field
75
- return results.map(({ source, content, weight }) => ({ source, content, weight }));
76
- }