@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,26 +1,6 @@
1
- /**
2
- * Saneamento determinístico do grafo, sem LLM (ADR-003 + errata D2/D3).
3
- *
4
- * O graphify 0.9.50 não implementa escopo hierárquico de namespace em C#
5
- * (graphify/extractors/csharp.py:322-335): um filho que usa um tipo do
6
- * namespace pai sem `using` explícito vira um STUB por arquivo, e o blast
7
- * radius do nó real devolve zero consumidores onde existem dois. É falso
8
- * negativo silencioso — o pior modo de falha possível antes de um hotfix.
9
- *
10
- * Três categorias de stub, medidas no MORPH_GHLBrain em 2026-08-27:
11
- *
12
- * label com 1 nó real (60 labels, 226 arestas) => coalesce no real
13
- * label com 0 nós reais (126 labels, 2.479 arestas) => externo (BCL/NuGet)
14
- * label com 2+ nós reais (22 labels, 93 arestas) => AMBÍGUO
15
- *
16
- * O terceiro grupo são símbolos REAIS do projeto (CatalogSchema, CatalogItem,
17
- * Result, Error, KillSwitch — declarados em CatalogContracts.cs e vizinhos),
18
- * não BCL. Filtrar "o que sobrou depois de coalescer" os descartaria em
19
- * silêncio, reintroduzindo o falso negativo que este módulo existe para matar.
20
- * Por isso o critério de externo é `real.length === 0`, nunca "remanescente".
21
- *
22
- * @module graph-sanitize
23
- */
1
+ // O graphify não resolve escopo hierárquico de namespace em C#: tipo do namespace pai vira stub por arquivo.
2
+ // Label com 1 nó real coalesce; 0 reais é externo; 2+ reais é ambíguo e são símbolos do projeto, por isso
3
+ // externo é `real.length === 0`, nunca "o que sobrou".
24
4
 
25
5
  /** Arestas que contam como dependência para blast radius. */
26
6
  export const USE_RELATIONS = new Set([
@@ -28,10 +8,7 @@ export const USE_RELATIONS = new Set([
28
8
  'inherits', 'implements', 'extends', 'dispatches_to', 'indirect_call',
29
9
  ]);
30
10
 
31
- /**
32
- * Herança não é uso. No ProspectPRO, `IHandler` aparece em 193 arquivos no
33
- * grep e tem 2 usos reais: é implementada por 98.
34
- */
11
+ /** Herança não é uso: uma interface muito implementada tem poucos usos reais. */
35
12
  export const INHERITANCE_RELATIONS = new Set(['inherits', 'implements', 'extends']);
36
13
 
37
14
  const LANG_BY_EXT = {
@@ -40,31 +17,15 @@ const LANG_BY_EXT = {
40
17
  sql: 'sql', py: 'python', go: 'go', rs: 'rust', java: 'jvm', kt: 'jvm',
41
18
  };
42
19
 
43
- /**
44
- * Código de teste — o predicado ÚNICO de "isto é teste" do grafo e do
45
- * validador de reuso. Pasta de projeto de teste em qualquer nível, em três
46
- * formas, e só três, porque `[^/]*[Tt]ests?/` genérico também casaria
47
- * `latest/` e `contests/`:
48
- * - o segmento inteiro é `test`/`tests` (qualquer caixa)
49
- * - termina em `.Test`/`.Tests` — a convenção .NET (ProspectPRO.Tests/)
50
- * - termina em `Test`/`Tests` com T maiúsculo — PascalCase (AlvoTests/)
51
- * mais o teste colocado ao lado do código em JS/TS: `__tests__/`,
52
- * `*.test.*` e `*.spec.*`.
53
- */
20
+ // O predicado único de teste do grafo e do validador de reuso. Só três formas de pasta, porque
21
+ // `[^/]*[Tt]ests?/` genérico também casaria `latest/` e `contests/`.
54
22
  const TEST_PATH = /(^|\/)__tests__\/|\.(test|spec)\.[jt]sx?$|(^|\/)(?:[Tt]ests?|[^/]*\.[Tt]ests?|[^/]*[a-z0-9_]Tests?)\//;
55
23
 
56
- /**
57
- * @param {string} sourceFile
58
- * @returns {boolean} o arquivo é código de teste (dublê, fixture ou o teste em si)
59
- */
60
24
  export function isTestPath(sourceFile) {
61
25
  return TEST_PATH.test(String(sourceFile || '').replace(/\\/g, '/'));
62
26
  }
63
27
 
64
- /**
65
- * @param {string} sourceFile
66
- * @returns {string} família de linguagem do arquivo, ou '' quando desconhecida
67
- */
28
+ /** Família de linguagem do arquivo, ou '' quando desconhecida. */
68
29
  export function languageOf(sourceFile) {
69
30
  const m = /\.([a-z0-9]+)$/i.exec(sourceFile || '');
70
31
  if (!m) return '';
@@ -73,29 +34,9 @@ export function languageOf(sourceFile) {
73
34
 
74
35
  const normOf = (node) => node.norm_label ?? String(node.label ?? '').toLowerCase();
75
36
 
76
- /**
77
- * Label sem os parênteses de chamada. O graphify rotula função como `tchau()`
78
- * em JS/TS, mas quem consulta digita `tchau` — e em C# o mesmo símbolo aparece
79
- * sem parênteses. Sem esta normalização, `graph affected tchau` devolve
80
- * not-found num grafo que tem o símbolo.
81
- */
37
+ // O graphify rotula função como `tchau()` em JS/TS, mas quem consulta digita `tchau`, e em C# não há parênteses.
82
38
  const baseOf = (norm) => norm.replace(/\(\s*\)$/, '');
83
39
 
84
- /**
85
- * @typedef {object} GraphIndex
86
- * @property {Map<string, object>} byId
87
- * @property {Map<string, {real: object[], stub: object[]}>} byLabel
88
- * @property {Map<string, object[]>} byBaseLabel label sem `()` -> nós reais
89
- * @property {Map<string, string>} coalesce stubId -> id do nó real
90
- * @property {object[]} recovered `dispatches_to` recuperados (ver recoverDispatch)
91
- */
92
-
93
- /**
94
- * Índice por id e por label + mapa de coalescência. Uma passada pelos nós.
95
- *
96
- * @param {{nodes: object[], links: object[]}} graph
97
- * @returns {GraphIndex}
98
- */
99
40
  export function buildIndex(graph) {
100
41
  const byId = new Map();
101
42
  const byLabel = new Map();
@@ -121,7 +62,7 @@ export function buildIndex(graph) {
121
62
  }
122
63
  if (entry.real.length === 0) continue;
123
64
  const base = baseOf(key);
124
- if (base === key) continue; // já consultável pelo caminho exato
65
+ if (base === key) continue;
125
66
  const bucket = byBaseLabel.get(base);
126
67
  if (bucket) bucket.push(...entry.real);
127
68
  else byBaseLabel.set(base, [...entry.real]);
@@ -137,21 +78,8 @@ const isCsharp = (node) => Boolean(node?.source_file) && /\.cs$/i.test(node.sour
137
78
  /** Nome do método sem o ponto inicial e sem a assinatura, como o graphify casa. */
138
79
  const methodName = (node) => String(node.label ?? '').trim().replace(/^\./, '').split('(')[0];
139
80
 
140
- /**
141
- * `dispatches_to` que o graphify deixou de emitir por causa de um dublê de
142
- * teste. O resolvedor dele (graphify/csharp_dispatch.py) liga o método da
143
- * interface ao da implementação só quando há EXATAMENTE um implementador — e
144
- * um `FakeX : IX` no grafo é o segundo. Este é o mesmo algoritmo, com o guard
145
- * contando só implementadores de produção. Medido no MORPH_GHLBrain: com os
146
- * dublês no grafo o graphify cai de 122 para 5 arestas, e esta função devolve
147
- * as 122 do grafo sem testes, nenhuma a mais.
148
- *
149
- * Aditivo: um par que o graphify já emitiu não é repetido.
150
- *
151
- * @param {GraphIndex} index
152
- * @param {{links?: object[]}} graph
153
- * @returns {object[]} arestas sintéticas, marcadas `_recovered: true`
154
- */
81
+ // O resolvedor do graphify liga interface a implementação só com EXATAMENTE um implementador, e um
82
+ // dublê `FakeX : IX` é o segundo. Mesmo algoritmo contando só produção; aditivo, nunca repete um par.
155
83
  function recoverDispatch(index, graph) {
156
84
  const implementers = new Map();
157
85
  const methodsOf = new Map();
@@ -204,24 +132,12 @@ function recoverDispatch(index, graph) {
204
132
  return recovered;
205
133
  }
206
134
 
207
- /**
208
- * As arestas do grafo mais as recuperadas pelo saneamento — o conjunto que
209
- * todo consumidor deve percorrer.
210
- *
211
- * @param {GraphIndex} index
212
- * @param {{links?: object[]}} graph
213
- * @returns {object[]}
214
- */
135
+ /** As arestas do grafo mais as recuperadas pelo saneamento: o conjunto que todo consumidor percorre. */
215
136
  export function linksOf(index, graph) {
216
137
  const own = graph.links ?? [];
217
138
  return index.recovered?.length ? own.concat(index.recovered) : own;
218
139
  }
219
140
 
220
- /**
221
- * @param {GraphIndex} index
222
- * @param {string} normLabel label já normalizado (minúsculo)
223
- * @returns {'resolved'|'coalescible'|'external'|'ambiguous'|'unknown'}
224
- */
225
141
  export function classifyLabel(index, normLabel) {
226
142
  const entry = index.byLabel.get(normLabel);
227
143
  if (!entry) return 'unknown';
@@ -230,13 +146,6 @@ export function classifyLabel(index, normLabel) {
230
146
  return entry.stub.length > 0 ? 'coalescible' : 'resolved';
231
147
  }
232
148
 
233
- /**
234
- * Para onde uma aresta REALMENTE aponta depois do saneamento.
235
- *
236
- * @param {GraphIndex} index
237
- * @param {object} link
238
- * @returns {{id: string|null, kind: 'direct'|'coalesced'|'language-disambiguated'|'external'|'ambiguous'|'unknown'}}
239
- */
240
149
  export function resolveEdgeTarget(index, link) {
241
150
  const target = index.byId.get(link.target);
242
151
  if (!target) return { id: null, kind: 'unknown' };
@@ -248,10 +157,8 @@ export function resolveEdgeTarget(index, link) {
248
157
  const entry = index.byLabel.get(normOf(target));
249
158
  if (!entry || entry.real.length === 0) return { id: null, kind: 'external' };
250
159
 
251
- // D3: uma aresta nascida num .cs só pode apontar para o candidato .cs.
252
- // Recupera 54% dos casos ambíguos sem LLM e sem heurística de grau — que é
253
- // a alternativa (b) rejeitada na ADR-003 por errar justamente nas interfaces
254
- // muito referenciadas.
160
+ // Uma aresta nascida num .cs só pode apontar para o candidato .cs: desambigua sem heurística de grau,
161
+ // que erra justamente nas interfaces muito referenciadas.
255
162
  const originLang = languageOf(link.source_file);
256
163
  if (originLang) {
257
164
  const matches = entry.real.filter((n) => languageOf(n.source_file) === originLang);
@@ -261,13 +168,7 @@ export function resolveEdgeTarget(index, link) {
261
168
  return { id: null, kind: 'ambiguous' };
262
169
  }
263
170
 
264
- /**
265
- * label -> id. Empate real devolve as opções em vez de escolher (ADR-003).
266
- *
267
- * @param {GraphIndex} index
268
- * @param {string} label
269
- * @returns {{ok: true, id: string, node: object}|{ok: false, reason: 'not-found'|'ambiguous', options: Array<{id: string, source_file: string}>}}
270
- */
171
+ /** Empate real devolve as opções em vez de escolher. */
271
172
  export function resolveLabel(index, label) {
272
173
  const key = String(label).toLowerCase();
273
174
  const exact = index.byLabel.get(key);
@@ -290,19 +191,6 @@ export function resolveLabel(index, label) {
290
191
  };
291
192
  }
292
193
 
293
- /**
294
- * Blast radius saneado: quem depende de `id`.
295
- *
296
- * O valor medido não é recall — contra o grep, o grafo achou ZERO arquivos a
297
- * mais. É precisão: 58% menos ruído em 12 símbolos do ProspectPRO (1.092
298
- * arquivos no grep, 266 usos reais) e a classificação da relação.
299
- *
300
- * @param {GraphIndex} index
301
- * @param {{links: object[]}} graph
302
- * @param {string} id
303
- * @param {{prod?: boolean, excludeInheritance?: boolean}} [opts]
304
- * @returns {Array<{id: string, label: string, source_file: string, source_location: string, relation: string, test: boolean}>}
305
- */
306
194
  export function affected(index, graph, id, opts = {}) {
307
195
  const seen = new Set();
308
196
  const out = [];
@@ -334,15 +222,7 @@ export function affected(index, graph, id, opts = {}) {
334
222
  return out;
335
223
  }
336
224
 
337
- /**
338
- * Vizinhança de um nó, para `graph explain`. Cada aresta carrega a procedência
339
- * (`via`), então dá para ver o que o saneamento recuperou, e `test` diz se a
340
- * outra ponta é código de teste.
341
- *
342
- * @param {GraphIndex} index
343
- * @param {{links: object[]}} graph
344
- * @param {string} id
345
- */
225
+ /** Cada aresta carrega a procedência (`via`); `test` diz se a outra ponta é código de teste. */
346
226
  export function neighborhood(index, graph, id) {
347
227
  const incoming = [];
348
228
  const outgoing = [];
@@ -6,7 +6,6 @@ import { heavyDir, runExclusive } from '../../../framework/hooks/shared/heavy-sl
6
6
 
7
7
  const DOTNET_ACTIVE = /\bdotnet(?:\.exe)?["']?\s+(?:build|test|publish|pack|msbuild|restore|run|watch|vstest)\b/i;
8
8
  const IDLE_WORKER = /\/nodemode:\d|vbcscompiler|razorserver/i;
9
- const SHUTDOWN_SCOPES = new Set(['feature', 'e2e-down', 'prune']);
10
9
  const SHUTDOWN_TIMEOUT_MS = 30_000;
11
10
  const TAIL_CHARS = 400;
12
11
 
@@ -15,7 +14,7 @@ function hasDotnet(projectPath) {
15
14
  const stack = config?.project?.stack;
16
15
  try {
17
16
  if (stack && getBuildSteps(stack, { cwd: projectPath }).some((s) => /\bdotnet\b/.test(s.command))) return true;
18
- } catch { /* stack sem passo de build */ }
17
+ } catch {}
19
18
  try {
20
19
  return readdirSync(projectPath).some((n) => /\.(sln|slnx|csproj)$/i.test(n));
21
20
  } catch {
@@ -33,16 +32,13 @@ export function dotnetBusy(procs) {
33
32
  });
34
33
  }
35
34
 
36
- export function afterHeavyRun({ projectPath, config, scope, env = process.env, deps = {} }) {
35
+ export function afterHeavyRun({ projectPath, config, env = process.env, deps = {} }) {
37
36
  const {
38
37
  exec = defaultProcExec, list = listProcesses, dotnet = hasDotnet, exclusive = runExclusive,
39
38
  } = deps;
40
39
 
41
40
  if (!config.enabled) return { status: 'skipped', reason: 'semáforo desligado: sem ele nada prova que outra sessão não está compilando' };
42
41
  if (!config.shutdownBuildServer) return { status: 'skipped', reason: 'desligado em heavy.shutdownBuildServer' };
43
- if (!SHUTDOWN_SCOPES.has(scope)) {
44
- return { status: 'skipped', reason: 'escopo de task: o servidor de compilação segue quente para a próxima task' };
45
- }
46
42
  if (!dotnet(projectPath)) return { status: 'skipped', reason: 'projeto sem .NET' };
47
43
 
48
44
  const guarded = exclusive({
@@ -1,70 +1,12 @@
1
- /**
2
- * effects.js — o coletor de efeitos ÚNICO do caminho de instalação/atualização.
3
- *
4
- * A propriedade que faz o `--dry-run` ser honesto está numa frase:
5
- *
6
- * > **o caminho real também emite.**
7
- *
8
- * Em modo normal cada verbo EXECUTA e registra; em `dryRun`, só registra. O
9
- * resumo impresso ao fim de uma execução real sai de `list()`, não de
10
- * contadores paralelos. A consequência é o ponto: um ponto de emissão
11
- * esquecido some das DUAS saídas ao mesmo tempo, e o resumo de uma execução
12
- * real fica visivelmente incompleto — o defeito aparece sem sequer usar o
13
- * `--dry-run`.
14
- *
15
- * **Não há segunda travessia.** Nenhum filtro, walker ou lista de payload é
16
- * reimplementado aqui. Os filtros que decidem o que instalar
17
- * (`shouldInstallSkill`, `agentEligible`, `shouldInstall`) já são puros e
18
- * continuam sendo os únicos. O anti-exemplar tem nome e mora neste
19
- * repositório: `checkAgentsDrift` funciona como preditor porque re-deriva o
20
- * conjunto elegível por conta própria e porque os dois lados chamam o mesmo
21
- * renderer puro. Estender essa forma para 9 payloads + hooks + merge de
22
- * settings + gitignore + índice do git é reimplementar o instalador inteiro e
23
- * depender de disciplina humana para mantê-los sincronizados.
24
- *
25
- * **Os verbos são SÍNCRONOS de propósito.** Metade dos instaladores que eles
26
- * atravessam (`installSkills`, `installAgents`, `installRulesForStack`) é
27
- * síncrona; um coletor assíncrono obrigaria a tornar `installRulesForStack`
28
- * async e a mudar a assinatura que `setup-infra`, `init` e os testes já usam.
29
- *
30
- * **O registro é a IDENTIDADE do efeito, nunca o conteúdo.** `writeFile` grava
31
- * `{ verb, target }`, não os bytes: `installClaudeHooks` carimba um
32
- * `generated_at` a cada execução, e comparar conteúdo faria o canário de
33
- * igualdade dry × real reprovar por causa do relógio.
34
- */
1
+ // O caminho real também emite: o resumo de uma execução real sai de `list()`, então um ponto de
2
+ // emissão esquecido some das duas saídas. Registra-se a identidade do efeito, nunca o conteúdo:
3
+ // `installClaudeHooks` carimba `generated_at`, e comparar bytes reprovaria a igualdade dry × real.
35
4
 
36
5
  import fs from 'fs-extra';
37
6
  import { spawnSync } from 'node:child_process';
38
7
  import { dirname } from 'node:path';
39
8
 
40
- /**
41
- * @typedef {Object} Effect
42
- * @property {string} verb - ensureDir | remove | copyDir | copyFile | writeFile | writeJson | mergeJson | spawn | gitIndex
43
- * @property {string} target - o caminho (ou comando) sobre o qual o efeito age
44
- * @property {string} [from] - origem, para os verbos de cópia
45
- * @property {string} [detail] - qualificador estável (argumentos do spawn, operação do git)
46
- */
47
-
48
- /**
49
- * Cria um coletor de efeitos.
50
- *
51
- * @param {{ dryRun?: boolean }} [options]
52
- * @returns {{
53
- * dryRun: boolean,
54
- * ensureDir: (path: string) => void,
55
- * remove: (path: string) => void,
56
- * copyDir: (from: string, to: string) => void,
57
- * copyFile: (from: string, to: string) => void,
58
- * writeFile: (path: string, content: string) => void,
59
- * writeJson: (path: string, data: object) => void,
60
- * mergeJson: (path: string, patch: object) => void,
61
- * spawn: (cmd: string, args: string[], options?: object) => object|null,
62
- * gitIndex: (op: string, path: string, options?: object) => boolean,
63
- * list: () => Effect[],
64
- * }}
65
- */
66
9
  export function createEffects({ dryRun = false } = {}) {
67
- /** @type {Effect[]} */
68
10
  const effects = [];
69
11
 
70
12
  const record = (verb, target, extra = {}) => {
@@ -118,13 +60,7 @@ export function createEffects({ dryRun = false } = {}) {
118
60
  }
119
61
  },
120
62
 
121
- /**
122
- * Leitura + fusão rasa + escrita, como UM efeito.
123
- *
124
- * A leitura acontece nos dois modos (ler não muda nada); só a escrita é
125
- * suprimida em dry. É assim que `~/.claude/settings.json` — um arquivo do
126
- * usuário, FORA do projeto — é atualizado sem que o dry o toque.
127
- */
63
+ // A leitura acontece nos dois modos; só a escrita é suprimida em dry.
128
64
  mergeJson(path, patch) {
129
65
  record('mergeJson', path);
130
66
  if (dryRun) return;
@@ -138,21 +74,9 @@ export function createEffects({ dryRun = false } = {}) {
138
74
  fs.writeJsonSync(path, { ...current, ...patch }, { spaces: 2 });
139
75
  },
140
76
 
141
- /**
142
- * @param {string} cmd
143
- * @param {string[]} args
144
- * @param {{ cwd?: string, dryRunArgs?: string[] }} [options]
145
- * `dryRunArgs` é a variante SÓ-LEITURA do mesmo comando (por exemplo
146
- * `--check`). Em dry ela é executada no lugar; sem ela, nada roda.
147
- * O REGISTRO é o mesmo nos dois modos: o efeito previsto é o comando
148
- * real, não a sua sonda.
149
- */
77
+ // `dryRunArgs`: variante só-leitura do comando, executada no lugar em dry; o registro é o comando real.
150
78
  spawn(cmd, args = [], options = {}) {
151
- // `args` viaja no registro ALÉM do `detail` legível. O `detail` é para
152
- // humano; quebrá-lo por espaço para descobrir onde o spawn escreve é o
153
- // bug que um caminho como `R:\Polymorphism Tech\...` produz em silêncio,
154
- // e que o relatório mostrou pondo um efeito do PACOTE da CLI no grupo
155
- // "no projeto".
79
+ // `args` viaja além do `detail`: quebrar o `detail` por espaço erra caminhos com espaço.
156
80
  record('spawn', cmd, { detail: args.join(' '), args: [...args] });
157
81
  const { cwd, dryRunArgs } = options;
158
82
  if (dryRun) {
@@ -162,11 +86,7 @@ export function createEffects({ dryRun = false } = {}) {
162
86
  return spawnSync(cmd, args, { cwd, encoding: 'utf8' });
163
87
  },
164
88
 
165
- /**
166
- * Mutação do índice do git (`git rm --cached`, etc.). A SONDA que decide
167
- * se há o que fazer fica fora daqui de propósito: sondar é ler, e ler
168
- * acontece nos dois modos.
169
- */
89
+ // A sonda que decide se há o que fazer fica fora daqui: sondar é ler, e ler acontece nos dois modos.
170
90
  gitIndex(op, path, options = {}) {
171
91
  record('gitIndex', path, { detail: op });
172
92
  if (dryRun) return true;
@@ -182,12 +102,7 @@ export function createEffects({ dryRun = false } = {}) {
182
102
  };
183
103
  }
184
104
 
185
- /**
186
- * Coletor no-op-de-registro para chamadores que não passam um: executa
187
- * normalmente e registra numa lista descartada. Existe para que assinaturas
188
- * novas de `installSkills`/`installAgents`/`installRulesForStack` continuem
189
- * funcionando para `setup-infra` e `init` sem mudança de comportamento.
190
- */
105
+ // Executa e registra numa lista descartada, para chamadores que não passam um coletor.
191
106
  export function realEffects() {
192
107
  return createEffects({ dryRun: false });
193
108
  }