@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,7 +1,7 @@
1
1
  import { readFileSync, readdirSync, existsSync } from 'fs';
2
2
  import { join } from 'path';
3
3
 
4
- /** One-line `key: value` frontmatter. CRLF-safe: a checkout with autocrlf is still read. */
4
+ /** CRLF-safe: a checkout with autocrlf is still read. */
5
5
  export function parseFrontmatter(content) {
6
6
  const match = /^---\r?\n([\s\S]*?)\r?\n---/.exec(content);
7
7
  if (!match) return {};
@@ -21,19 +21,9 @@ export function parseFrontmatter(content) {
21
21
  const FENCE = /^(\s*)```/;
22
22
  const DISPATCH_HINT = /dispatch|despach|subagent_type|Template do prompt/i;
23
23
  const PERSONA_REF = /morph-(\{id\}|\{task\.agent\}|[a-z][a-z-]*[a-z])/g;
24
- /** Words after `morph-` that are skills or CLI verbs, never personas. */
25
- /** Claude Code's own sub-agents: dispatched by skills, but not personas of agents.json. */
26
24
  const BUILTIN_AGENT = /`(Explore|general-purpose|Plan)`/g;
27
25
  const NOT_PERSONA = /^(spec|proposal|brainstorming|stack-scan|uiux|plan|implement|apply|review|eval|hotfix|standards|media|task)$/;
28
26
 
29
- /**
30
- * The prompts a skill tells the orchestrator to send to a sub-agent: fenced
31
- * blocks that are either written as a dispatch (`dispatch Agent (…)`) or sit
32
- * right under a line about dispatching. Each carries the personas it names —
33
- * `generic` when the template is `morph-{id}` (any implementer).
34
- *
35
- * @returns {Array<{ index: number, personas: string[], generic: boolean, builtin: string[], context: string, text: string }>}
36
- */
37
27
  export function extractDispatchPrompts(content) {
38
28
  const lines = content.split(/\r?\n/);
39
29
  const out = [];
@@ -45,7 +35,7 @@ export function extractDispatchPrompts(content) {
45
35
  const body = lines.slice(i + 1, j);
46
36
  const text = body.map((l) => l.slice(Math.min(open[1].length, l.length - l.trimStart().length))).join('\n');
47
37
  // Only the sentence that introduces the block counts: a paragraph further up
48
- // that mentions a dispatch (morph-apply's DAG example) is not this block's.
38
+ // that mentions a dispatch is not this block's.
49
39
  let k = i - 1;
50
40
  while (k >= 0 && lines[k].trim() === '') k--;
51
41
  const before = k >= 0 && i - k <= 2 ? lines[k] : '';
@@ -1,20 +1,17 @@
1
1
  import { readFileSync, existsSync } from 'fs';
2
2
  import { join } from 'path';
3
3
  import { personaStandardIds } from '../../utils/agents-installer.js';
4
+ import { loadStandardsRegistry } from '../../lib/standards/registry.js';
4
5
 
5
6
  export function scanStandards(frameworkDir, agents) {
6
7
  const standardsJsonPath = join(frameworkDir, 'standards', 'STANDARDS.json');
7
8
  if (!existsSync(standardsJsonPath)) return { version: 'unknown', list: [] };
8
- const sJson = JSON.parse(readFileSync(standardsJsonPath, 'utf8'));
9
+ const sJson = loadStandardsRegistry(standardsJsonPath);
9
10
  const refMap = {};
10
11
  for (const agent of agents) {
11
12
  for (const std of personaStandardIds(agent)) {
12
- // agents.json stores standards as plain id STRINGS. Reading `std.id` off
13
- // a string yields undefined, so every reference piled into refMap
14
- // [undefined] and the lookup below missed all 60 — the Standards graph
15
- // drew standards with no agent edge at all. The object form is the v4
16
- // shape (`{ id, scope, priority }`); still accepted so a mixed or
17
- // restored agents.json does not silently lose edges again.
13
+ // agents.json stores standards as id strings; the `{ id }` object form is
14
+ // still accepted so a mixed agents.json does not lose edges.
18
15
  const id = typeof std === 'string' ? std : std?.id;
19
16
  if (!id) continue;
20
17
  if (!refMap[id]) refMap[id] = [];
@@ -21,14 +21,6 @@ function readBody(req) {
21
21
  });
22
22
  }
23
23
 
24
- /**
25
- * Two data paths:
26
- * - `virtual:morph-data` — the framework's knowledge (agents, phases, skills,
27
- * standards, rules, hooks, docs). Static for the life of the server.
28
- * - `/api/morph/*` — the portfolio (`/projects`) and each project's features
29
- * and activity (`/p/:id/…`), read on demand and pushed as `morph:changed`
30
- * over the HMR socket when a project's `.morph/` changes.
31
- */
32
24
  export default function morphDataPlugin(frameworkDir, projectDir) {
33
25
  return {
34
26
  name: 'vite-plugin-morph-data',
@@ -43,11 +35,8 @@ export default function morphDataPlugin(frameworkDir, projectDir) {
43
35
  const portfolio = createPortfolio({ launchDir: projectDir });
44
36
  const push = (data) => server.ws.send({ type: 'custom', event: 'morph:changed', data });
45
37
 
46
- // Vite reloads the whole page for any changed .html it watches, even when
47
- // handleHotUpdate returns [] (vite 6: no module matched + .html = full
48
- // reload). A project's .morph/ carries .html design sources, and an agent
49
- // writing one reloaded the dashboard under the person reading it. The
50
- // dashboard's own code never lives under .morph/.
38
+ // Vite 6 full-reloads any changed .html it watches even when handleHotUpdate
39
+ // returns [], and a project's .morph/ carries .html design sources.
51
40
  const clientHot = server.environments?.client?.hot;
52
41
  if (clientHot?.send) {
53
42
  const send = clientHot.send.bind(clientHot);
@@ -64,10 +53,8 @@ export default function morphDataPlugin(frameworkDir, projectDir) {
64
53
  if (fresh.length) server.watcher.add(fresh);
65
54
  }
66
55
 
67
- // Read the projects in the background, one at a time, so neither the first
68
- // page nor the portfolio waits for a large project. Reading one blocks the
69
- // event loop for seconds, so each step waits WARM_GAP_MS first: the reads
70
- // a push (or an add) just caused are served before the next block.
56
+ // One project at a time, WARM_GAP_MS apart: a read blocks the event loop for
57
+ // seconds, and the reads a push just caused are served first.
71
58
  let warming = false;
72
59
  function warmSoon() {
73
60
  if (warming) return;
@@ -88,7 +75,6 @@ export default function morphDataPlugin(frameworkDir, projectDir) {
88
75
  res.setHeader('Content-Type', 'application/json; charset=utf-8');
89
76
  res.setHeader('Cache-Control', 'no-store');
90
77
  res.end(JSON.stringify(out));
91
- // The portfolio's list changed: watch and read any project just added.
92
78
  if (req.method !== 'GET' && status === 200) { watchNew(); push({ scope: 'projects' }); warmSoon(); }
93
79
  });
94
80
 
@@ -98,7 +84,7 @@ export default function morphDataPlugin(frameworkDir, projectDir) {
98
84
  rescan.unref?.();
99
85
 
100
86
  const timers = new Map();
101
- const changed = new Map(); // `${project}:${scope}` -> path -> watcher event, in the debounce window
87
+ const changed = new Map();
102
88
  const onFsEvent = (event, path) => {
103
89
  const scope = classifyChange(path);
104
90
  if (!scope) return;
@@ -1,26 +1,5 @@
1
- /**
2
- * ai-checks.js — o coletor das cinco checagens de `morph-spec doctor --ai`.
3
- *
4
- * Contrato de uma checagem:
5
- *
6
- * { id, name, status: 'ok'|'warn'|'error'|'skip', reason?, findings: [], unverified?: [] }
7
- *
8
- * Duas regras que este módulo existe para tornar mecânicas:
9
- *
10
- * 1. **`status: 'skip'` sai com `reason` obrigatória.** "Não verificado" sem
11
- * motivo é ruído — quem lê não consegue decidir se falta insumo ou se falta
12
- * checagem. Um `skip` sem razão é bug deste arquivo, e há canário.
13
- * 2. **`null` de uma função de checagem é DESCONHECIDO, nunca "não achei
14
- * nada".** `[]` é "perguntei e não achei" e vira `ok`. É a doutrina de
15
- * `pr-index.js`, já viva no `doctor`.
16
- *
17
- * E uma proibição: **nada alcançável daqui escreve.** Os candidatos óbvios ao
18
- * erro — `scripts/generate-ai-pin-props.js` e
19
- * `scripts/generate-standards-registry.js` — escrevem por padrão e NÃO entram
20
- * no grafo de imports deste módulo. É a lição do T10 da #90, onde a auditoria
21
- * ia ALOCAR um bloco de porta ao auditar, inventando o estado que reportava.
22
- * O canário assere a lista de chamadas feitas, não só o retorno.
23
- */
1
+ // `skip` sai com `reason` obrigatória, e `null` de uma checagem é DESCONHECIDO, nunca "não achei".
2
+ // Nada alcançável daqui escreve: os geradores de `scripts/` ficam fora do grafo de imports.
24
3
 
25
4
  import { scanAiPackageRefs } from './ai-project-scan.js';
26
5
  import { resolveAiPin, auditPinDrift } from './pin-drift.js';
@@ -30,7 +9,6 @@ import { auditRenamedApi, auditPromptSource, renamedApiGate } from './code-audit
30
9
  /** Os cinco ids, na ordem em que o relatório os imprime. */
31
10
  export const AI_CHECK_IDS = ['pin-drift', 'removed-api', 'pricing-missing', 'api-per-alias', 'prompt-source'];
32
11
 
33
- /** Nome legível de cada checagem. */
34
12
  export const AI_CHECK_NAMES = {
35
13
  'pin-drift': 'pin × projeto (versões de pacote de IA)',
36
14
  'removed-api': 'API renomeada antes do 1.0 GA',
@@ -42,7 +20,6 @@ export const AI_CHECK_NAMES = {
42
20
  /** O pacote cuja versão gateia a checagem de API renomeada. */
43
21
  export const MAF_PACKAGE = 'Microsoft.Agents.AI';
44
22
 
45
- /** As dependências reais. Substituíveis inteiras ou em parte, por canário. */
46
23
  export function defaultAiDeps() {
47
24
  return {
48
25
  scanAiPackageRefs,
@@ -75,19 +52,8 @@ function skipAll(reason) {
75
52
  return AI_CHECK_IDS.map((id) => skip(id, reason));
76
53
  }
77
54
 
78
- /**
79
- * Roda as cinco checagens sobre um projeto.
80
- *
81
- * As três condições de silêncio total acontecem ANTES de qualquer leitura do
82
- * pin — e é essa ordem, não o retorno, que o canário assere: sem `.csproj`
83
- * alcançável, `resolveAiPin` não é sequer chamada.
84
- *
85
- * @param {string} targetPath - raiz do projeto
86
- * @param {object} [options]
87
- * @param {object|null} [options.config] - `.morph/config/config.json` já lido
88
- * @param {object} [options.deps] - substituição parcial de `defaultAiDeps()`
89
- * @returns {Array<{id: string, name: string, status: string, reason?: string, findings: Array}>}
90
- */
55
+ // As condições de silêncio total acontecem ANTES de ler o pin: sem `.csproj` alcançável,
56
+ // `resolveAiPin` nem é chamada.
91
57
  export function collectAiChecks(targetPath, { config = null, deps = {} } = {}) {
92
58
  const d = { ...defaultAiDeps(), ...deps };
93
59
 
@@ -114,8 +80,7 @@ export function collectAiChecks(targetPath, { config = null, deps = {} } = {}) {
114
80
  const unverified = scan.unreadable.slice();
115
81
  const checks = [];
116
82
 
117
- // ── pin-drift ────────────────────────────────────────────────────────────
118
- // Condição 2: sem pin resolvível, a checagem que depende dele sai skip.
83
+ // Sem pin resolvível, a checagem que depende dele sai skip.
119
84
  const pin = d.resolveAiPin(targetPath);
120
85
  if (!pin) {
121
86
  checks.push(skip('pin-drift', 'nenhum `ai-pin.json` resolvível (nem em `.morph/framework/`, nem '
@@ -127,7 +92,6 @@ export function collectAiChecks(targetPath, { config = null, deps = {} } = {}) {
127
92
  : resolved('pin-drift', findings, { unverified }));
128
93
  }
129
94
 
130
- // ── removed-api ──────────────────────────────────────────────────────────
131
95
  const maf = scan.packages.find((p) => p.name === MAF_PACKAGE) ?? null;
132
96
  const gate = d.renamedApiGate(maf);
133
97
  if (gate !== null) {
@@ -139,7 +103,6 @@ export function collectAiChecks(targetPath, { config = null, deps = {} } = {}) {
139
103
  : resolved('removed-api', findings));
140
104
  }
141
105
 
142
- // ── pricing-missing e api-per-alias ──────────────────────────────────────
143
106
  const registry = d.locateAiRegistry(targetPath, config);
144
107
  const noRegistry = 'nenhum registry de modelos encontrado — nem `project.ai.modelRegistry` no '
145
108
  + 'config, nem um `.json` com `defaultAlias` + mapa de aliases, nem uma seção `Pricing` num '
@@ -155,7 +118,6 @@ export function collectAiChecks(targetPath, { config = null, deps = {} } = {}) {
155
118
  : noRegistry)
156
119
  : resolved('api-per-alias', perAlias));
157
120
 
158
- // ── prompt-source ────────────────────────────────────────────────────────
159
121
  const prompts = d.auditPromptSource(targetPath);
160
122
  checks.push(prompts === null
161
123
  ? skip('prompt-source', 'nenhum `.cs` alcançável a partir desta raiz')
@@ -164,19 +126,12 @@ export function collectAiChecks(targetPath, { config = null, deps = {} } = {}) {
164
126
  return checks;
165
127
  }
166
128
 
167
- /**
168
- * Código de saída do `doctor --ai`: 1 quando há ao menos um `error`, 0 caso
169
- * contrário. `warn` e `skip` NUNCA mudam o código de saída — só `pin-drift`
170
- * produz `error`, e só na faixa flutuante, a única classe com prejuízo medido.
171
- *
172
- * @param {Array<{status: string}>} checks
173
- * @returns {0|1}
174
- */
129
+ /** `warn` e `skip` nunca mudam o código de saída: só `pin-drift` produz `error`, na faixa flutuante. */
175
130
  export function aiExitCode(checks) {
176
131
  return checks.some((c) => c.status === 'error') ? 1 : 0;
177
132
  }
178
133
 
179
- /** true quando NENHUMA checagem teve insumo — o relatório sai em uma linha. */
134
+ /** true quando nenhuma checagem teve insumo: o relatório sai em uma linha. */
180
135
  export function allSkipped(checks) {
181
136
  return checks.length > 0 && checks.every((c) => c.status === 'skip');
182
137
  }
@@ -1,28 +1,10 @@
1
- /**
2
- * ai-project-scan.js — varredura READ-ONLY dos `.csproj` / `Directory.Packages.props`
3
- * de um projeto .NET, para responder "o que este projeto declara sobre pacotes de IA?".
4
- *
5
- * Três invariantes deste módulo, todas cobradas por canário:
6
- *
7
- * 1. **Nada aqui escreve.** Nenhum import de `fs` que mute, nenhum `spawn`.
8
- * A auditoria não pode inventar o estado que reporta — é a lição do T10 da
9
- * #90, onde a auditoria de portas ia ALOCAR um bloco ao auditar.
10
- * 2. **`null` é DESCONHECIDO, `[]` é "perguntei e não achei".** Colapsar os
11
- * dois é a doutrina que `src/lib/git/pr-index.js` já pinou neste repositório.
12
- * Aqui: `scanAiPackageRefs` devolve `null` quando havia arquivos candidatos
13
- * e NENHUM foi legível; devolve um resultado com `projectFiles: []` quando
14
- * varreu e não achou `.csproj` nenhum.
15
- * 3. **Worktree é o checkout de OUTRA feature.** `worktrees/` e `.worktrees/`
16
- * ficam fora da varredura pela mesma razão pinada em `test-runner.js`:
17
- * varrê-los reporta sobre código fora da árvore avaliada. Os nomes vêm de
18
- * `src/lib/worktree/dirs.js`, nunca duplicados aqui.
19
- */
1
+ // Nada aqui escreve: a auditoria não pode inventar o estado que reporta. `null` é DESCONHECIDO,
2
+ // `[]` é "perguntei e não achei". Worktrees ficam fora: são o checkout de outra feature.
20
3
 
21
4
  import { readdirSync, readFileSync, statSync, existsSync } from 'node:fs';
22
5
  import { join, basename } from 'node:path';
23
6
  import { WORKTREE_DIR_NAMES } from '../worktree/dirs.js';
24
7
 
25
- /** Diretórios que a varredura nunca desce. */
26
8
  export const SCAN_IGNORED_DIRS = new Set([
27
9
  'node_modules',
28
10
  'bin',
@@ -31,14 +13,8 @@ export const SCAN_IGNORED_DIRS = new Set([
31
13
  ...WORKTREE_DIR_NAMES,
32
14
  ]);
33
15
 
34
- /**
35
- * Prefixos de pacote NuGet que caracterizam "pacote de IA".
36
- *
37
- * Deliberadamente curto: a lista existe para decidir se há assunto (condição 3
38
- * do silêncio do `doctor --ai`), não para catalogar o ecossistema. Um pacote de
39
- * IA fora desta lista aparece na varredura como pacote comum e, se estiver no
40
- * pin, `pin-drift` o pega mesmo assim — o pin é a outra metade do predicado.
41
- */
16
+ // Deliberadamente curto: decide se há assunto, não cataloga o ecossistema; um pacote de IA fora daqui
17
+ // que esteja no pin ainda é pego por `pin-drift`.
42
18
  export const AI_PACKAGE_PREFIXES = [
43
19
  'Microsoft.Agents.AI',
44
20
  'Microsoft.Extensions.AI',
@@ -50,10 +26,6 @@ export const AI_PACKAGE_PREFIXES = [
50
26
  'Anthropic.',
51
27
  ];
52
28
 
53
- /**
54
- * @param {string} name - nome do pacote NuGet
55
- * @returns {boolean} true quando o nome casa com um dos prefixos de IA
56
- */
57
29
  export function isAiPackage(name) {
58
30
  if (typeof name !== 'string' || name.length === 0) return false;
59
31
  return AI_PACKAGE_PREFIXES.some(
@@ -61,22 +33,11 @@ export function isAiPackage(name) {
61
33
  );
62
34
  }
63
35
 
64
- /** Remove o BOM UTF-8 do início do texto (mesmo cuidado de `doctor.js` e `env.js`). */
65
36
  function stripBom(text) {
66
37
  return text.charCodeAt(0) === 0xfeff ? text.slice(1) : text;
67
38
  }
68
39
 
69
- /**
70
- * Checagem de boa-formação de XML suficiente para MSBuild, sem dependência nova.
71
- *
72
- * Não valida schema: valida que as tags fecham na ordem certa e que todo `<`
73
- * tem o seu `>`. É o predicado que separa "li o arquivo" de "não pude
74
- * perguntar" — e é ele que faz um `.csproj` truncado virar `unreadable` em vez
75
- * de virar "sem drift".
76
- *
77
- * @param {string} xml
78
- * @returns {boolean}
79
- */
40
+ /** Tags fecham na ordem e todo `<` tem `>`: um `.csproj` truncado vira `unreadable`, não "sem drift". */
80
41
  export function isWellFormedXml(xml) {
81
42
  const stack = [];
82
43
  let i = 0;
@@ -121,7 +82,6 @@ export function isWellFormedXml(xml) {
121
82
  return stack.length === 0;
122
83
  }
123
84
 
124
- /** Todas as tags de um nome, com os atributos crus. */
125
85
  function* elements(xml, tagName) {
126
86
  const re = new RegExp(`<${tagName}\\b([^>]*?)(/?)>`, 'g');
127
87
  let m;
@@ -130,17 +90,13 @@ function* elements(xml, tagName) {
130
90
  }
131
91
  }
132
92
 
133
- /** Valor de um atributo dentro do texto cru de atributos de uma tag. */
134
93
  function attr(attrs, name) {
135
94
  const m = new RegExp(`\\b${name}\\s*=\\s*"([^"]*)"`, 'i').exec(attrs)
136
95
  || new RegExp(`\\b${name}\\s*=\\s*'([^']*)'`, 'i').exec(attrs);
137
96
  return m ? m[1].trim() : null;
138
97
  }
139
98
 
140
- /**
141
- * Elemento filho `<Version>x</Version>` de um `<PackageReference>` não
142
- * auto-fechado. Recebe o XML e o índice logo após a tag de abertura.
143
- */
99
+ // Recebe o índice logo após a tag de abertura de um `<PackageReference>` não auto-fechado.
144
100
  function childVersion(xml, startIndex, tagName) {
145
101
  const close = xml.indexOf(`</${tagName}>`, startIndex);
146
102
  if (close === -1) return null;
@@ -149,18 +105,7 @@ function childVersion(xml, startIndex, tagName) {
149
105
  return m ? m[1].trim() : null;
150
106
  }
151
107
 
152
- /**
153
- * Classifica a string de versão declarada no projeto.
154
- *
155
- * - `fixed` — `1.20.0` ou a forma de igualdade exata `[1.20.0]`
156
- * - `floating` — contém `*`, ou é intervalo (`[1.0,)`, `[1.0,2.0)`, `(,2.0]`)
157
- * - `unresolved` — referência a propriedade MSBuild (`$(MafVersion)`): a
158
- * varredura NÃO resolve propriedades, e chutar seria inventar o dado
159
- * - `absent` — sem versão declarada e sem entrada de CPM
160
- *
161
- * @param {string|null} raw
162
- * @returns {{ kind: 'fixed'|'floating'|'unresolved'|'absent', value: string|null }}
163
- */
108
+ /** `unresolved` é referência a propriedade MSBuild (`$(X)`): a varredura não resolve, e chutar inventaria o dado. */
164
109
  export function classifyVersion(raw) {
165
110
  if (raw === null || raw === undefined || String(raw).trim() === '') {
166
111
  return { kind: 'absent', value: null };
@@ -175,18 +120,7 @@ export function classifyVersion(raw) {
175
120
  return { kind: 'fixed', value };
176
121
  }
177
122
 
178
- /**
179
- * Coleta recursiva de arquivos que casam com um predicado, respeitando as
180
- * exclusões de `SCAN_IGNORED_DIRS`.
181
- *
182
- * Exportada porque `registry-audit.js` e `code-audit.js` precisam da MESMA
183
- * travessia com as MESMAS exclusões. Uma segunda cópia da lista de diretórios
184
- * ignorados é como um dos três volta a varrer `worktrees/` sozinho.
185
- *
186
- * @param {string} root
187
- * @param {(name: string, fullPath: string) => boolean} matches
188
- * @returns {string[]}
189
- */
123
+ /** Exportada para que registry-audit e code-audit usem a mesma travessia com as mesmas exclusões. */
190
124
  export function collectProjectFiles(root, matches) {
191
125
  const out = [];
192
126
  if (!root || !existsSync(root)) return out;
@@ -194,7 +128,6 @@ export function collectProjectFiles(root, matches) {
194
128
  return out;
195
129
  }
196
130
 
197
- /** Coleta recursiva de arquivos que casam com um predicado, respeitando as exclusões. */
198
131
  function collectFiles(root, matches, out, depth = 0) {
199
132
  if (depth > 24) return;
200
133
  let entries;
@@ -208,8 +141,7 @@ function collectFiles(root, matches, out, depth = 0) {
208
141
  const full = join(root, name);
209
142
  let isDir = entry.isDirectory();
210
143
  if (entry.isSymbolicLink()) {
211
- // Junction/symlink: pode apontar para fora da árvore (é assim que um
212
- // worktree do Windows enxerga `.claude/`). Não descemos.
144
+ // Junction/symlink pode apontar para fora da árvore (assim um worktree do Windows enxerga `.claude/`).
213
145
  continue;
214
146
  }
215
147
  if (isDir) {
@@ -221,23 +153,8 @@ function collectFiles(root, matches, out, depth = 0) {
221
153
  }
222
154
  }
223
155
 
224
- /**
225
- * Varre `root` e devolve o que os projetos .NET declaram sobre pacotes.
226
- *
227
- * Sem limite de 10 arquivos (o de `scanStackDependencies`, que é do relatório
228
- * de arquitetura e tem outro consumidor): uma solução .NET real tem dezenas de
229
- * `.csproj`, e cortar em 10 é reportar sobre uma amostra chamando-a de todo.
230
- *
231
- * @param {string} root - raiz da varredura (o projeto)
232
- * @returns {null | {
233
- * projectFiles: string[],
234
- * cpmFiles: string[],
235
- * unreadable: string[],
236
- * packages: Array<{ name: string, file: string, ai: boolean,
237
- * version: string|null, versionKind: string,
238
- * declared: string|null, fromCpm: boolean }>
239
- * }} `null` = não pude perguntar (havia candidatos e nenhum era legível).
240
- */
156
+ // Sem limite de arquivos: cortar uma solução real é reportar sobre uma amostra chamando-a de todo.
157
+ // `null` = havia candidatos e nenhum era legível.
241
158
  export function scanAiPackageRefs(root) {
242
159
  if (!root || !existsSync(root)) return null;
243
160
  try {
@@ -280,7 +197,7 @@ export function scanAiPackageRefs(root) {
280
197
  }
281
198
 
282
199
  // Central Package Management primeiro: um PackageReference sem Version num
283
- // projeto com CPM não é achado de versão ausente (UC-24 A1).
200
+ // projeto com CPM não é achado de versão ausente.
284
201
  const cpm = new Map();
285
202
  for (const file of cpmFiles) {
286
203
  const xml = readable.get(file);
@@ -319,28 +236,17 @@ export function scanAiPackageRefs(root) {
319
236
  }
320
237
  }
321
238
 
322
- // Um Directory.Packages.props com PackageVersion de pacote de IA e nenhum
323
- // .csproj que o referencie ainda declara a intenção — mas não é uso, e este
324
- // módulo reporta declaração de uso. Fica de fora, de propósito.
239
+ // PackageVersion de IA sem .csproj que o referencie declara intenção, não uso: fica de fora.
325
240
 
326
241
  return { projectFiles, cpmFiles, unreadable, packages };
327
242
  }
328
243
 
329
- /**
330
- * Versão declarada de um pacote específico, ou `null` quando o projeto não a
331
- * declara de forma resolvível. Usado pelo gate do `removed-api` (só roda com
332
- * `Microsoft.Agents.AI` >= 1.0) e pelo relatório.
333
- *
334
- * @param {ReturnType<typeof scanAiPackageRefs>} scan
335
- * @param {string} name
336
- * @returns {{ name: string, version: string|null, versionKind: string, declared: string|null, file: string } | null}
337
- */
244
+ /** `null` quando o projeto não declara o pacote de forma resolvível. */
338
245
  export function findPackage(scan, name) {
339
246
  if (!scan || !Array.isArray(scan.packages)) return null;
340
247
  return scan.packages.find((p) => p.name === name) ?? null;
341
248
  }
342
249
 
343
- /** Nomes de arquivo (sem diretório) dos projetos varridos — para mensagens. */
344
250
  export function projectFileNames(scan) {
345
251
  if (!scan) return [];
346
252
  return scan.projectFiles.map((f) => basename(f));
@@ -1,26 +1,6 @@
1
- /**
2
- * code-audit.js — duas varreduras sobre os `.cs` do projeto.
3
- *
4
- * (a) `removed-api` — nomes renomeados ANTES do 1.0 GA do `Microsoft.Agents.AI`
5
- * (b) `prompt-source` — `Instructions` recebendo literal de string no ponto de
6
- * construção do agente
7
- *
8
- * Nenhuma das duas é grep cego, e as duas são `warn`:
9
- *
10
- * - A #93 apurou, e o standard `ai-agents/agent-session.md` registra, que
11
- * `AgentThread` → `AgentSession` e `GetNewThread()` → `CreateSessionAsync()`
12
- * aconteceram no ciclo PRÉ-GA. Dentro do `Microsoft.Agents.AI` >= 1.0 os
13
- * nomes antigos são nomes mortos — mas o MESMO identificador pertence a
14
- * outros SDKs de agente na mesma solução, e é por isso que o achado é aviso
15
- * e a mensagem manda CONFERIR a qual cliente a chamada pertence, em vez de
16
- * afirmar defeito. Sem o pacote declarado em >= 1.0 a checagem nem roda.
17
- *
18
- * - O `prompt-source` é deliberadamente conservador: acusa só o literal no
19
- * ponto de construção. Leitura de arquivo, banco, configuração ou constante
20
- * nomeada não é acusada. Falso negativo é aceitável; falso positivo não —
21
- * uma checagem que grita em código correto é desligada pelo usuário na
22
- * primeira semana.
23
- */
1
+ // As duas checagens são `warn`: o nome renomeado no ciclo pré-GA é o mesmo identificador de outros SDKs
2
+ // de agente, então a mensagem manda conferir. `prompt-source` acusa só o literal no ponto de construção:
3
+ // falso negativo é aceitável, falso positivo faz o usuário desligar a checagem.
24
4
 
25
5
  import { readFileSync } from 'node:fs';
26
6
  import { relative } from 'node:path';
@@ -40,22 +20,11 @@ function lineOf(text, index) {
40
20
  return line;
41
21
  }
42
22
 
43
- /** Todos os `.cs` do projeto, com as mesmas exclusões da varredura de `.csproj`. */
44
23
  export function collectCsharpFiles(root) {
45
24
  return collectProjectFiles(root, (name) => name.toLowerCase().endsWith('.cs'));
46
25
  }
47
26
 
48
- /**
49
- * Menor major que a versão declarada pode assumir, ou `null` quando a
50
- * declaração não permite decidir.
51
- *
52
- * `1.0.*` e `[1.0,)` têm limite inferior 1 — sobem, nunca descem. `$(Prop)` e
53
- * versão ausente NÃO permitem decidir, e decidir mesmo assim seria inventar o
54
- * dado que a checagem reporta.
55
- *
56
- * @param {{ declared: string|null, versionKind: string }|null} pkg
57
- * @returns {number|null}
58
- */
27
+ /** `null` quando a declaração não permite decidir (`$(Prop)`, ausente): decidir inventaria o dado. */
59
28
  export function lowerBoundMajor(pkg) {
60
29
  if (!pkg) return null;
61
30
  if (pkg.versionKind === 'unresolved' || pkg.versionKind === 'absent') return null;
@@ -66,12 +35,7 @@ export function lowerBoundMajor(pkg) {
66
35
  return m ? Number(m[1]) : null;
67
36
  }
68
37
 
69
- /**
70
- * Por que o `removed-api` NÃO roda, quando não roda.
71
- *
72
- * @param {{ declared: string|null, versionKind: string }|null} mafPackage
73
- * @returns {string|null} razão do "não verificado", ou `null` quando pode rodar
74
- */
38
+ /** A razão do "não verificado", ou `null` quando pode rodar. */
75
39
  export function renamedApiGate(mafPackage) {
76
40
  if (!mafPackage) {
77
41
  return 'o projeto não declara `Microsoft.Agents.AI` — os nomes antigos não pertencem a este código';
@@ -88,14 +52,7 @@ export function renamedApiGate(mafPackage) {
88
52
  return null;
89
53
  }
90
54
 
91
- /**
92
- * (a) Uso de API renomeada antes do 1.0 GA.
93
- *
94
- * @param {string} root
95
- * @param {{ mafPackage?: object|null }} [options]
96
- * @returns {null | Array<{ id: string, severity: 'warn', symbol: string, file: string, line: number, message: string }>}
97
- * `null` = não pude perguntar (gate fechado ou raiz ilegível).
98
- */
55
+ /** `null` = não pude perguntar (gate fechado ou raiz ilegível). */
99
56
  export function auditRenamedApi(root, { mafPackage = null } = {}) {
100
57
  if (renamedApiGate(mafPackage) !== null) return null;
101
58
 
@@ -131,22 +88,9 @@ export function auditRenamedApi(root, { mafPackage = null } = {}) {
131
88
  return findings;
132
89
  }
133
90
 
134
- /**
135
- * `Instructions` recebendo literal de string no ponto de construção.
136
- *
137
- * Casa `Instructions = "…"`, `Instructions = @"…"`, `Instructions = $"…"`,
138
- * `Instructions = """…"""` e o argumento nomeado `instructions: "…"`.
139
- * NÃO casa atribuição de variável, chamada, `await`, constante nomeada nem
140
- * literal dentro de comentário.
141
- */
91
+ // NÃO casa atribuição de variável, chamada, `await`, constante nomeada nem literal dentro de comentário.
142
92
  const INSTRUCTIONS_LITERAL_RE = /(?<![\w."])(?:Instructions\s*=(?!=)|instructions\s*:)\s*(?:[$@]){0,2}"/g;
143
93
 
144
- /**
145
- * (b) Prompt sem fonte declarada.
146
- *
147
- * @param {string} root
148
- * @returns {null | Array<{ id: string, severity: 'warn', file: string, line: number, message: string }>}
149
- */
150
94
  export function auditPromptSource(root) {
151
95
  const files = collectCsharpFiles(root);
152
96
  if (files.length === 0) return null;
@@ -1,70 +1,27 @@
1
- /**
2
- * pin-drift.js — o pin de pacotes de IA (`framework/ai-pin.json`) contra o que
3
- * o `.csproj` do projeto declara.
4
- *
5
- * É a ÚNICA das cinco checagens do `doctor --ai` que produz `error`, e só na
6
- * faixa flutuante. O motivo é prejuízo medido, não estética: uma faixa `2.*`
7
- * sobe sozinha para uma versão com assinatura mudada e o `MissingMethodException`
8
- * chega DEPOIS de a chamada ao modelo ter sido paga. As outras quatro checagens
9
- * informam — uma checagem que grita em código correto é desligada pelo usuário
10
- * na primeira semana.
11
- *
12
- * O pin é lido por `readAiPin` (#92), nunca por um segundo leitor: duas cópias
13
- * do mesmo fato divergem, e é para isso que a Dependency Matrix existe.
14
- */
1
+ // Única checagem que produz `error`, e só na faixa flutuante: `2.*` sobe sozinha para uma assinatura mudada
2
+ // e o `MissingMethodException` chega depois de a chamada ao modelo ter sido paga.
15
3
 
16
4
  import { join } from 'node:path';
17
5
  import { readAiPin } from '../standards/verified-against.js';
18
6
 
19
- /**
20
- * Resolve o pin para um projeto, sem NUNCA lançar.
21
- *
22
- * Ordem: (1) `<target>/.morph/framework/ai-pin.json` — a régua com que aquele
23
- * projeto foi instalado; (2) o pin do pacote da CLI. Nenhum dos dois resolve →
24
- * `null`, que o relatório traduz em "não verificado". Falta de régua é ausência
25
- * de dado, nunca defeito do projeto: é literalmente o estado de todo projeto
26
- * cujo framework é anterior ao pin.
27
- *
28
- * @param {string} targetPath - raiz do projeto
29
- * @returns {{ pinnedAt: string, packages: Record<string, {version: string}> } | null}
30
- */
7
+ // O pin instalado no projeto, senão o do pacote da CLI; nenhum resolve → `null` ("não verificado"):
8
+ // falta de régua é ausência de dado, nunca defeito do projeto.
31
9
  export function resolveAiPin(targetPath) {
32
10
  const roots = [];
33
11
  if (targetPath) roots.push(join(targetPath, '.morph'));
34
- roots.push(undefined); // root default de readAiPin = pacote da CLI
12
+ roots.push(undefined);
35
13
 
36
14
  for (const root of roots) {
37
15
  try {
38
16
  const pin = root === undefined ? readAiPin() : readAiPin(root);
39
17
  if (pin && pin.packages && Object.keys(pin.packages).length > 0) return pin;
40
- } catch {
41
- // Ausente ou inválido nesta raiz — tenta a próxima.
42
- }
18
+ } catch {}
43
19
  }
44
20
  return null;
45
21
  }
46
22
 
47
- /**
48
- * Compara a varredura do projeto com o pin.
49
- *
50
- * Três classes de achado, e a diferença entre elas é de quem é o defeito:
51
- *
52
- * | classe | severidade | de quem é |
53
- * |---|---|---|
54
- * | pacote do pin declarado com faixa flutuante | `error` | do projeto |
55
- * | pacote do pin declarado com versão fixa ≠ pin | `warn` | do projeto |
56
- * | pacote de IA presente no projeto e ausente do pin | `warn` | **do pin** (lacuna) |
57
- *
58
- * A terceira classe é descrita como lacuna do PIN de propósito: medido,
59
- * `Microsoft.Agents.AI.OpenAI` aparece em três repositórios do acervo e não
60
- * está no pin. Acusar o projeto ali seria acusar o certo pelo errado.
61
- *
62
- * @param {object} params
63
- * @param {ReturnType<import('./ai-project-scan.js').scanAiPackageRefs>} params.scan
64
- * @param {ReturnType<typeof resolveAiPin>} params.pin
65
- * @returns {null | Array<{ id: string, severity: 'error'|'warn', package: string, message: string }>}
66
- * `null` = não pude perguntar (sem varredura ou sem pin).
67
- */
23
+ // Pacote de IA presente no projeto e ausente do pin é lacuna do PIN, não do projeto.
24
+ // `null` = não pude perguntar (sem varredura ou sem pin).
68
25
  export function auditPinDrift({ scan, pin } = {}) {
69
26
  if (!scan || !pin || !pin.packages) return null;
70
27