@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
@@ -6,12 +6,7 @@ import FlowGraph from '../components/FlowGraph.jsx';
6
6
  import DetailPanel from '../components/DetailPanel.jsx';
7
7
  import EntityLink, { useSelection } from '../components/EntityLink.jsx';
8
8
 
9
- /**
10
- * Every event the scanner can report. `when` and `power` are what the panel
11
- * explains; `canBlock` is the badge on the graph (the tool-call veto).
12
- * Colors are the dashboard palette as hex, because the MiniMap cannot read
13
- * CSS variables.
14
- */
9
+ /** Colors are hex because the MiniMap cannot read CSS variables. */
15
10
  const EVENTS = {
16
11
  'session-start': {
17
12
  label: 'Início da sessão', color: '#73daca',
@@ -69,12 +64,7 @@ function eventMeta(key) {
69
64
  return EVENTS[key] || { label: key, color: '#8d97a5', when: 'Evento sem descrição no dashboard.', power: '' };
70
65
  }
71
66
 
72
- /**
73
- * The URL key of one registration. A hook file can register more than once
74
- * under the same event with different matchers, so the name alone is not
75
- * unique: `?sel=` holds `event:name:matcher`. A bare hook name also works and
76
- * opens that hook's first registration.
77
- */
67
+ /** A hook can register more than once under one event, so `?sel=` holds `event:name:matcher`. */
78
68
  export function hookKey(hook) {
79
69
  return `${hook.event}:${hook.name}:${hook.matcher || ''}`;
80
70
  }
@@ -89,8 +79,6 @@ function matcherText(hook) {
89
79
  return eventMeta(hook.event).toolEvent ? 'todas as ferramentas' : null;
90
80
  }
91
81
 
92
- // ─── Nodes ────────────────────────────────────────────────────────────────────
93
-
94
82
  const NODE_W = 280;
95
83
  const ROW_H = 26;
96
84
  const HEAD_H = 58;
@@ -161,11 +149,6 @@ function ToolNode() {
161
149
 
162
150
  const nodeTypes = { eventGroupNode: EventGroupNode, toolNode: ToolNode };
163
151
 
164
- // ─── Layout ───────────────────────────────────────────────────────────────────
165
- // Main row: session-start → user-prompt → pre-tool-use → tool → post-tool-use → stop / pre-compact
166
- // Second row: events outside the tool-call flow (worktree pair, teammate-idle,
167
- // unregistered hooks and any event this page does not know).
168
-
169
152
  const COL_GAP = NODE_W + 90;
170
153
  const MAIN_ROW = ['session-start', 'user-prompt', 'pre-tool-use', '__tool__', 'post-tool-use'];
171
154
  const SIDE_ROW = ['worktree-create', 'worktree-remove', 'teammate-idle', 'unregistered'];
@@ -231,8 +214,6 @@ function buildNodesAndEdges(hooksByEvent, onSelectHook, selectedKey) {
231
214
  return { nodes, edges };
232
215
  }
233
216
 
234
- // ─── Panels ───────────────────────────────────────────────────────────────────
235
-
236
217
  function Section({ title, children }) {
237
218
  return (
238
219
  <section>
@@ -369,8 +350,6 @@ function ToolDetail() {
369
350
  );
370
351
  }
371
352
 
372
- // ─── Main Page ────────────────────────────────────────────────────────────────
373
-
374
353
  export default function HookInspector() {
375
354
  const { hooks } = morphData;
376
355
  const [sel, setSel] = useSelection();
@@ -9,12 +9,10 @@ import { phaseMeta, GATE_LABEL } from '../lib/phases.js';
9
9
 
10
10
  const phaseColor = (id) => `var(--color-phase-${id})`;
11
11
 
12
- /** What each approval gate checks, in the words a reader of the pipeline needs. */
13
12
  const GATE_CHECKS = {
14
- proposal: 'Confere o escopo da proposta: o problema, o que entra e o que fica de fora, antes de gastar esforço em design ou plano.',
15
- uiux: 'Confere o design das telas (mockups e checklist de tela). É opcional: só existe quando a feature passa pela fase de UI/UX.',
16
- plan: 'Confere a spec, as tasks e o plano de implementação. Depois dele a spec congela e a implementação começa.',
17
- review: 'Confere a avaliação independente: um avaliador em contexto novo dá o veredito (SHIP ou FIX) e só bloqueia com evidência, com o verify verde.',
13
+ plan: 'Confere o plano: o problema, o que fica de fora, os cenários com a prova de cada um e as fatias. Depois dele o plan.md congela (só a errata cresce).',
14
+ uiux: 'Confere o design das telas (mockups e checklist de tela). É opcional: só existe quando a feature passa pela fase de UI/UX, depois do plano.',
15
+ review: 'Confere a avaliação independente em contexto novo: verificador e revisor (e segurança, quando o diff toca auth, segredo ou dado pessoal), cada um com veredito SHIP ou FIX sobre o mesmo commit. Só bloqueia com evidência, com o verify verde e todo cenário provado.',
18
16
  };
19
17
 
20
18
  const GATE_PREFIX = 'gate-';
@@ -66,7 +64,6 @@ const GATE_W = 150;
66
64
  const GATE_H = 32;
67
65
  const GAP = 48;
68
66
 
69
- /** Left to right: each phase, then its gate (when it has one), then the next phase. */
70
67
  function buildPipelineGraph(phases, sel) {
71
68
  const nodes = [];
72
69
  const edges = [];
@@ -132,7 +129,6 @@ function Chip({ children }) {
132
129
  // Exported for the render smoke test: no page state, only the phase and the personas.
133
130
  export function PhaseDetail({ phase, agents }) {
134
131
  const color = phaseColor(phase.id);
135
- // Personas this phase's skill dispatches (derived by the agents scanner).
136
132
  const activeAgents = agents.filter((a) => a.activePhases?.includes(phase.id));
137
133
 
138
134
  return (
@@ -22,7 +22,6 @@ async function send(method, url, body) {
22
22
  function ProjectBlock({ p, now, onRemove }) {
23
23
  const s = p.summary;
24
24
  const working = s ? s.activeFeatures.filter((f) => isWorking(f, now)).length : 0;
25
- // What waits on you is already listed at the top of the page; here, the rest, latest first.
26
25
  const rest = s ? s.activeFeatures.filter((f) => !f.awaiting) : [];
27
26
  const shown = [...rest].sort((a, b) => (b.lastActivity?.ts || '').localeCompare(a.lastActivity?.ts || '')).slice(0, ACTIVE_SHOWN);
28
27
  return (
@@ -12,13 +12,7 @@ const RULE_COLOR = 'var(--color-phase-plan)';
12
12
  const STD_COLOR = 'var(--color-phase-proposal)';
13
13
  const NODE_W = 260;
14
14
 
15
- // ─── Standard resolution ──────────────────────────────────────────────────────
16
-
17
- /**
18
- * A rule's route → the standard it names in the registry. `id` is what the
19
- * Standards page selects by; with no registry match the path itself is passed,
20
- * so the link still says which file the rule meant.
21
- */
15
+ /** With no registry match the path itself is passed, so the link still names the file. */
22
16
  function resolveStandard(ref, byPath) {
23
17
  const path = standardKey(ref);
24
18
  const std = byPath.get(path);
@@ -30,8 +24,6 @@ function resolveStandard(ref, byPath) {
30
24
  };
31
25
  }
32
26
 
33
- // ─── Node Components ──────────────────────────────────────────────────────────
34
-
35
27
  function RuleNode({ data }) {
36
28
  return (
37
29
  <div
@@ -78,8 +70,6 @@ function StandardRefNode({ data }) {
78
70
 
79
71
  const nodeTypes = { ruleNode: RuleNode, standardRefNode: StandardRefNode };
80
72
 
81
- // ─── Graph Builder ────────────────────────────────────────────────────────────
82
-
83
73
  function matchesFilter(rule, search, stackFilter) {
84
74
  const q = search.toLowerCase();
85
75
  const matchSearch = !q || rule.name.toLowerCase().includes(q) || rule.stacks.some((s) => s.toLowerCase().includes(q));
@@ -153,8 +143,6 @@ function buildGraph(rules, byPath, search, stackFilter, selected) {
153
143
  return { nodes, edges };
154
144
  }
155
145
 
156
- // ─── Detail Content ───────────────────────────────────────────────────────────
157
-
158
146
  function Section({ title, children }) {
159
147
  return (
160
148
  <section>
@@ -221,9 +209,6 @@ function RuleDetail({ rule, byPath }) {
221
209
  );
222
210
  }
223
211
 
224
- // ─── Main Page ────────────────────────────────────────────────────────────────
225
-
226
- /** `?sel=` holds the rule `name` (the file name without `.md`). */
227
212
  export default function RulesMap() {
228
213
  const { rules } = morphData;
229
214
  const [search, setSearch] = useState('');
@@ -22,8 +22,6 @@ const INVOKE_NO = 'só interna';
22
22
 
23
23
  const tint = (color, pct = 14) => `color-mix(in srgb, ${color} ${pct}%, var(--color-core))`;
24
24
 
25
- // ─── Nodes ────────────────────────────────────────────────────────────────────
26
-
27
25
  const HANDLE = { width: 7, height: 7, border: 0 };
28
26
 
29
27
  function PhaseNode({ data }) {
@@ -99,15 +97,11 @@ function GroupNode({ data }) {
99
97
 
100
98
  const nodeTypes = { phaseNode: PhaseNode, skillNode: SkillNode, personaNode: PersonaNode, groupNode: GroupNode };
101
99
 
102
- // ─── Graph model ──────────────────────────────────────────────────────────────
103
-
104
- /** The phase a skill belongs to: its own `phase`, or the phase whose `skill` it is. */
105
100
  function skillPhaseOf(skill, phases) {
106
101
  if (skill.phase) return skill.phase;
107
102
  return phases.find((p) => p.skill === skill.id)?.id || null;
108
103
  }
109
104
 
110
- /** The persona targets of a skill's dispatches: generic ones go to the one "implementadores" node. */
111
105
  function dispatchTargets(skill) {
112
106
  const out = new Set();
113
107
  for (const d of skill.dispatches || []) {
@@ -127,7 +121,7 @@ const SUPPORT_PER_ROW = 5;
127
121
  function buildGraph({ skills, phases, agents, isMatch, hasFilter }) {
128
122
  const nodes = [];
129
123
  const edges = [];
130
- const phaseSkills = new Map(); // phaseId → skill[]
124
+ const phaseSkills = new Map();
131
125
  const support = [];
132
126
  for (const s of skills) {
133
127
  const ph = skillPhaseOf(s, phases);
@@ -137,7 +131,6 @@ function buildGraph({ skills, phases, agents, isMatch, hasFilter }) {
137
131
  } else support.push(s);
138
132
  }
139
133
 
140
- // Row 0 + 1: one column per phase, its skill(s) below it.
141
134
  phases.forEach((p, i) => {
142
135
  const meta = phaseMeta(p.id);
143
136
  const x = i * COL;
@@ -154,7 +147,6 @@ function buildGraph({ skills, phases, agents, isMatch, hasFilter }) {
154
147
  });
155
148
  });
156
149
 
157
- // Row 3+: the support skills, in a labelled group under the personas.
158
150
  const supportCols = Math.min(SUPPORT_PER_ROW, Math.max(1, support.length));
159
151
  const supportRows = Math.ceil(support.length / supportCols);
160
152
  const supportWidth = supportCols * COL;
@@ -173,7 +165,6 @@ function buildGraph({ skills, phases, agents, isMatch, hasFilter }) {
173
165
  nodes.push(skillNode(s, x, y, SUPPORT_COLOR, SUPPORT_LABEL));
174
166
  });
175
167
 
176
- // Row 2: the personas the skills dispatch prompts to.
177
168
  const personaIds = new Set();
178
169
  for (const s of skills) for (const t of dispatchTargets(s)) personaIds.add(t);
179
170
  const agentOrder = agents.map((a) => a.id);
@@ -197,7 +188,6 @@ function buildGraph({ skills, phases, agents, isMatch, hasFilter }) {
197
188
  });
198
189
  });
199
190
 
200
- // skill → persona, from the dispatch prompts.
201
191
  const supportIds = new Set(support.map((s) => s.id));
202
192
  for (const s of skills) {
203
193
  const fromSupport = supportIds.has(s.id);
@@ -226,8 +216,6 @@ function buildGraph({ skills, phases, agents, isMatch, hasFilter }) {
226
216
  }
227
217
  }
228
218
 
229
- // ─── Detail ───────────────────────────────────────────────────────────────────
230
-
231
219
  function Section({ title, children }) {
232
220
  return (
233
221
  <section className="space-y-2">
@@ -252,7 +240,6 @@ function PromptBlock({ text, label = 'Prompt enviado ao sub-agent' }) {
252
240
  );
253
241
  }
254
242
 
255
- /** Plain text of a hast node (the `node` react-markdown hands to overrides). */
256
243
  function hastText(node) {
257
244
  if (!node) return '';
258
245
  if (node.type === 'text') return node.value || '';
@@ -372,8 +359,6 @@ export function SkillDetail({ skill, phases = morphData.phases?.list || [] }) {
372
359
  );
373
360
  }
374
361
 
375
- // ─── Page ─────────────────────────────────────────────────────────────────────
376
-
377
362
  export default function SkillsLibrary() {
378
363
  const skills = morphData.skills || [];
379
364
  const phases = morphData.phases?.list || [];
@@ -8,9 +8,6 @@ import SearchFilter from '../components/SearchFilter.jsx';
8
8
  import Markdown from '../components/Markdown.jsx';
9
9
  import EntityLink, { useSelection, standardKey } from '../components/EntityLink.jsx';
10
10
 
11
- // ─── Colors ───────────────────────────────────────────────────────────────────
12
-
13
- /** Token palette the categories draw from, in order; the categories come from the data. */
14
11
  const PALETTE = [
15
12
  'var(--color-phase-implement)',
16
13
  'var(--color-phase-uiux)',
@@ -24,20 +21,17 @@ const PALETTE = [
24
21
 
25
22
  const tint = (color, pct = 14) => `color-mix(in srgb, ${color} ${pct}%, var(--color-core))`;
26
23
 
27
- /** category → color, stable by category name so a color never jumps between renders. */
24
+ /** Stable by category name, so a color never jumps between renders. */
28
25
  function categoryColors(standards) {
29
26
  const cats = [...new Set(standards.map((s) => s.category || 'outros'))].sort();
30
27
  return Object.fromEntries(cats.map((c, i) => [c, PALETTE[i % PALETTE.length]]));
31
28
  }
32
29
 
33
- /** Resolve `?sel=` to a standard: by id first, then by the path a task cites. */
34
30
  export function findStandard(list, sel) {
35
31
  if (!sel) return null;
36
32
  return list.find((s) => s.id === sel) || list.find((s) => s.path === standardKey(sel)) || null;
37
33
  }
38
34
 
39
- // ─── Nodes ────────────────────────────────────────────────────────────────────
40
-
41
35
  const HANDLE = { width: 7, height: 7, border: 0 };
42
36
  const NODE_W = 230;
43
37
  const NODE_H = 52;
@@ -97,8 +91,6 @@ function CategoryNode({ data }) {
97
91
 
98
92
  const nodeTypes = { standardNode: StandardNode, agentNode: AgentNode, categoryNode: CategoryNode };
99
93
 
100
- // ─── Layout ───────────────────────────────────────────────────────────────────
101
-
102
94
  const CELL_W = NODE_W + 14;
103
95
  const CELL_H = NODE_H + 12;
104
96
  const PAD = 16;
@@ -106,7 +98,6 @@ const HEADER = 40;
106
98
  const BLOCK_GAP = 36;
107
99
  const MAX_ROW_W = 1700;
108
100
 
109
- /** How many columns a category block gets: tall categories spread sideways. */
110
101
  function colsFor(n) {
111
102
  if (n > 12) return 3;
112
103
  if (n > 5) return 2;
@@ -127,7 +118,6 @@ function buildGraph({ standards, agents, colors, isMatch, hasFilter, persona, se
127
118
  .map(([cat, list]) => [cat, [...list].sort((a, b) => (a.subcategory || '').localeCompare(b.subcategory || '') || a.name.localeCompare(b.name))])
128
119
  .sort((a, b) => b[1].length - a[1].length || a[0].localeCompare(b[0]));
129
120
 
130
- // Pack the category blocks into rows no wider than MAX_ROW_W.
131
121
  const blocks = cats.map(([cat, list]) => {
132
122
  const cols = colsFor(list.length);
133
123
  const rows = Math.ceil(list.length / cols);
@@ -141,7 +131,7 @@ function buildGraph({ standards, agents, colors, isMatch, hasFilter, persona, se
141
131
  }
142
132
  const totalW = Math.max(...rows.map((r) => r.w), 0);
143
133
 
144
- const std = new Set(); // node ids present
134
+ const std = new Set();
145
135
  let y = 180;
146
136
  for (const row of rows) {
147
137
  let x = (totalW - row.w) / 2;
@@ -170,7 +160,6 @@ function buildGraph({ standards, agents, colors, isMatch, hasFilter, persona, se
170
160
  y += row.h + BLOCK_GAP;
171
161
  }
172
162
 
173
- // The personas on top, each with an edge to every standard it consults.
174
163
  const withStandards = agents.filter((a) => (a.standards || []).some((id) => std.has(id)));
175
164
  const agentX0 = (totalW - withStandards.length * (NODE_W + 24)) / 2;
176
165
  const byId = new Map(standards.map((s) => [s.id, s]));
@@ -194,8 +183,6 @@ function buildGraph({ standards, agents, colors, isMatch, hasFilter, persona, se
194
183
  return { nodes, edges, categories: cats.map(([c, l]) => [c, l.length]) };
195
184
  }
196
185
 
197
- // ─── Detail ───────────────────────────────────────────────────────────────────
198
-
199
186
  function Section({ title, children }) {
200
187
  return (
201
188
  <section className="space-y-2">
@@ -307,8 +294,6 @@ export function StandardDetail({ std, color = 'var(--color-dim)' }) {
307
294
  );
308
295
  }
309
296
 
310
- // ─── Page ─────────────────────────────────────────────────────────────────────
311
-
312
297
  export default function Standards() {
313
298
  const standards = morphData.standards?.list || [];
314
299
  const version = morphData.standards?.version;
@@ -1,12 +1,6 @@
1
1
  /**
2
- * The harness event stream (`.morph/logs/events.jsonl`, schema v2 of
3
- * framework/hooks/shared/telemetry-logger.js) told as a feed a person can read.
4
- *
5
- * Reading and summing are NOT done here: `loadTelemetryAllTrees` gathers every
6
- * tree's log plus the finish backups, and `aggregateCost` is the one place
7
- * tokens are added up (only `delta` can be summed; a v1 stream yields `null`,
8
- * which the UI shows as unknown — never 0). This module only decides what each
9
- * event means in words, and which ones are worth a line.
2
+ * `loadTelemetryAllTrees` reads and `aggregateCost` is the one place tokens are
3
+ * summed: a v1 stream yields `null`, shown as unknown, never 0.
10
4
  */
11
5
 
12
6
  import { statSync, openSync, readSync, closeSync } from 'fs';
@@ -14,8 +8,7 @@ import { join, resolve } from 'path';
14
8
  import { loadTelemetryAllTrees, aggregateCost, dedupeEvents } from '../../lib/telemetry/telemetry-reader.js';
15
9
  import { isFailedToolCall } from '../../../framework/hooks/shared/telemetry-logger.js';
16
10
 
17
- /** Kinds a person follows by default; the rest are one click away. */
18
- export const DEFAULT_KINDS = ['prompt', 'question', 'skill', 'dispatch', 'handback', 'task', 'verify', 'gate', 'failure'];
11
+ export const DEFAULT_KINDS = ['prompt', 'question', 'skill', 'dispatch', 'handback', 'verify', 'gate', 'failure'];
19
12
  export const ALL_KINDS = [...DEFAULT_KINDS, 'write', 'read', 'command', 'tool'];
20
13
 
21
14
  const GATE_COMMAND = /\bmorph-spec\s+(approve|gate-check|gate-decision|advance|finish)\b/;
@@ -44,20 +37,10 @@ function nodesSummary(nodes) {
44
37
  return Object.entries(nodes).map(([name, n]) => ({ name, status: typeof n === 'string' ? n : n?.status ?? null }));
45
38
  }
46
39
 
47
- /**
48
- * One event → one feed line, or null when the event is bookkeeping.
49
- *
50
- * @returns {null | {
51
- * id: string, ts: string, feature: string|null, phase: string|null,
52
- * kind: string, title: string, detail: string|null, status: 'ok'|'fail'|null,
53
- * refs: { persona?: string, skill?: string, task?: string, path?: string },
54
- * nodes?: Array<{name: string, status: string|null}>
55
- * }}
56
- */
57
40
  export function describeEvent(e) {
58
41
  if (!e || typeof e !== 'object' || SILENT_EVENTS.has(e.event)) return null;
59
42
  const base = {
60
- id: e.eventId || `${e.ts}:${e.event}:${e.tool || ''}:${e.task || ''}`,
43
+ id: e.eventId || `${e.ts}:${e.event}:${e.tool || ''}`,
61
44
  ts: e.ts || null,
62
45
  feature: e.feature || null,
63
46
  phase: e.phase || null,
@@ -69,27 +52,18 @@ export function describeEvent(e) {
69
52
  const line = (kind, title, extra = {}) => ({ ...base, kind, title, ...extra, refs: { ...base.refs, ...(extra.refs || {}) } });
70
53
 
71
54
  if (e.event === 'UserPromptSubmit') {
72
- // Hand-backs, task notifications and reminders arrive through the same door
73
- // as a person's prompt, wrapped in a tag. A slash command is the one tagged
74
- // prompt a person typed.
55
+ // Hand-backs, notifications and reminders arrive as a prompt wrapped in a tag;
56
+ // a slash command is the one tagged prompt a person typed.
75
57
  const text = typeof e.prompt === 'string' ? e.prompt.trim() : '';
76
58
  const command = /^<command-name>\/?([^<]+)<\/command-name>/.exec(text);
77
59
  if (command) return line('prompt', `Você rodou /${command[1].trim()}`);
78
60
  if (text.startsWith('<')) return null;
79
61
  return line('prompt', 'Você escreveu', { detail: clip(text) });
80
62
  }
81
- if (e.event === 'TaskStart') return line('task', `${e.task} começou`, { refs: { task: e.task } });
82
- if (e.event === 'TaskEnd') {
83
- const done = e.status === 'done';
84
- return line('task', done ? `${e.task} concluída` : `${e.task} terminou (${e.status ?? 'sem status'})`, {
85
- status: done ? 'ok' : null, refs: { task: e.task },
86
- });
87
- }
88
63
  if (e.event === 'Verify') {
89
64
  const ok = e.status === 'pass';
90
- const scope = e.task ? e.task : 'feature inteira';
91
- return line('verify', `verify ${scope} ${ok ? 'passou' : 'falhou'}`, {
92
- status: ok ? 'ok' : 'fail', nodes: nodesSummary(e.nodes), refs: e.task ? { task: e.task } : {},
65
+ return line('verify', `verify ${ok ? 'passou' : 'falhou'}`, {
66
+ status: ok ? 'ok' : 'fail', nodes: nodesSummary(e.nodes),
93
67
  detail: e.persisted === false && e.reason ? `não carimbou: ${e.reason}` : null,
94
68
  });
95
69
  }
@@ -127,8 +101,7 @@ export function describeEvent(e) {
127
101
  return line('tool', tool || e.event);
128
102
  }
129
103
 
130
- // The same event array is fed again on every request until the log changes:
131
- // describing ~100k events once, not per page, is the difference that matters.
104
+ // Memoized per events array: describing ~100k events once, not per page.
132
105
  const described = new WeakMap();
133
106
 
134
107
  function describeAll(events) {
@@ -145,12 +118,6 @@ function describeAll(events) {
145
118
  return described.get(events);
146
119
  }
147
120
 
148
- /**
149
- * The feed, newest first, filtered and paginated by a `before` timestamp cursor.
150
- *
151
- * @param {Object[]} events - raw events, any order
152
- * @param {{ feature?: string, kinds?: string[], before?: string, limit?: number }} [opts]
153
- */
154
121
  export function buildFeed(events, { feature, kinds = DEFAULT_KINDS, before, limit = 100 } = {}) {
155
122
  const wanted = new Set(kinds);
156
123
  const lines = describeAll(events).filter((l) => wanted.has(l.kind) && (!feature || l.feature === feature));
@@ -160,15 +127,6 @@ export function buildFeed(events, { feature, kinds = DEFAULT_KINDS, before, limi
160
127
  return { items: page, next: page.length === limit && last ? last.ts : null, total: lines.length };
161
128
  }
162
129
 
163
- /**
164
- * What the feature list shows as "the last thing that happened" in each
165
- * feature: the newest line a person follows by default (a dispatch, a verify, a
166
- * task — not a Read or a shell command), plus `ts`, the newest event of ANY kind,
167
- * which is what says an agent is working right now.
168
- *
169
- * @param {Object[]} events
170
- * @returns {Record<string, {ts: string, title: string|null, kind: string|null, status: string|null, titleTs: string|null}>}
171
- */
172
130
  const lastByLines = new WeakMap();
173
131
 
174
132
  export function lastActivityByFeature(events) {
@@ -187,7 +145,6 @@ export function lastActivityByFeature(events) {
187
145
  return out;
188
146
  }
189
147
 
190
- /** Every event of the project across its trees and finish backups. */
191
148
  export function loadProjectEvents(projectDir) {
192
149
  return dedupeEvents(loadTelemetryAllTrees(projectDir).flatMap((t) => t.events));
193
150
  }
@@ -203,27 +160,14 @@ function fileSize(path) {
203
160
  }
204
161
 
205
162
  /**
206
- * The project's events kept in memory and followed as they are appended.
207
- *
208
- * A running agent appends one line to its tree's `events.jsonl` per tool call.
209
- * Re-reading every log (≈100k events, seconds) on each append would block the
210
- * dev server for the whole run, so the store remembers how far it read each
211
- * live log and parses only the bytes after that. Anything it cannot follow
212
- * that way — a log that shrank (SessionStart rotated it), a log it has never
213
- * seen (a new worktree), an archive or backup — falls back to a full reload
214
- * through `loadTelemetryAllTrees`, the same reader as always. Copies of one
215
- * event are still dropped by `eventId`.
216
- *
217
- * Every update yields a NEW events array, so everything memoized per array
218
- * (described lines, per-feature cost) follows the change.
219
- *
220
- * @param {string} projectDir
221
- * @param {{ loadTrees?: Function }} [deps] - test seam, defaults to loadTelemetryAllTrees
163
+ * Tails each live log from the last byte read; a shrunk (rotated) or unseen log,
164
+ * an archive or a backup falls back to a full reload. Every update yields a NEW
165
+ * events array, so everything memoized per array follows the change.
222
166
  */
223
167
  export function createEventStore(projectDir, { loadTrees = loadTelemetryAllTrees } = {}) {
224
168
  let events = null;
225
169
  let seen = new Set();
226
- let offsets = new Map(); // live log path -> bytes consumed (up to the last newline)
170
+ let offsets = new Map();
227
171
  let pending = new Set();
228
172
  let fullReload = true;
229
173
  const costs = new Map();
@@ -246,7 +190,6 @@ export function createEventStore(projectDir, { loadTrees = loadTelemetryAllTrees
246
190
  costs.clear();
247
191
  }
248
192
 
249
- /** Parse the bytes appended to `path` since the last read; false when it cannot follow. */
250
193
  function tail(path) {
251
194
  const from = offsets.get(path);
252
195
  const size = fileSize(path);
@@ -281,7 +224,6 @@ export function createEventStore(projectDir, { loadTrees = loadTelemetryAllTrees
281
224
  const prevLines = described.get(events);
282
225
  const merged = events.concat(fresh);
283
226
  events = fresh.every((e) => (e.ts || '') >= last) ? merged : dedupeEvents(merged);
284
- // Carry the described lines over instead of describing 100k events again.
285
227
  if (prevLines) {
286
228
  const byTsDesc = (a, b) => (b.ts || '').localeCompare(a.ts || '');
287
229
  const added = fresh.map(describeEvent).filter(Boolean).sort(byTsDesc);
@@ -310,19 +252,13 @@ export function createEventStore(projectDir, { loadTrees = loadTelemetryAllTrees
310
252
 
311
253
  return {
312
254
  events: current,
313
- /**
314
- * Something under `.morph/logs` changed. A known live log is tailed on the
315
- * next read; anything else (rotation archive, new tree, backup) reloads.
316
- */
317
255
  changed(path) {
318
256
  const known = path && [...offsets.keys()].find((p) => resolve(p) === resolve(path));
319
257
  if (known) pending.add(known);
320
258
  else fullReload = true;
321
259
  },
322
260
  reset() { fullReload = true; },
323
- /** Loaded and not waiting for a full reload: reading it now is cheap. */
324
261
  ready() { return events !== null && !fullReload; },
325
- /** `featureCost`, memoized until the events change. */
326
262
  cost(feature) {
327
263
  const all = current();
328
264
  if (!costs.has(feature)) costs.set(feature, featureCost(all, feature));
@@ -331,10 +267,7 @@ export function createEventStore(projectDir, { loadTrees = loadTelemetryAllTrees
331
267
  };
332
268
  }
333
269
 
334
- /**
335
- * What the feature cost, straight from `aggregateCost`. `sessionUsage` and
336
- * `agentUsage` stay `null` when the stream has no summable sample.
337
- */
270
+ /** `sessionUsage` and `agentUsage` stay `null` when the stream has no summable sample. */
338
271
  export function featureCost(events, feature) {
339
272
  const c = aggregateCost(events, { feature });
340
273
  return {
@@ -344,8 +277,6 @@ export function featureCost(events, feature) {
344
277
  dispatches: c.dispatches,
345
278
  bytesTotal: c.bytesTotal,
346
279
  bytesByKind: c.bytesByKind,
347
- taskDurationSeconds: c.taskDurationSeconds,
348
- tasks: c.tasks,
349
280
  events: c.total,
350
281
  };
351
282
  }
@@ -2,27 +2,13 @@ import { readFileSync, existsSync } from 'fs';
2
2
  import { join } from 'path';
3
3
  import { personaStandardIds, isImplementer, renderAgentMd, loadKnownMcpIds } from '../../utils/agents-installer.js';
4
4
 
5
- /** A line of a phase skill that dispatches a sub-agent. */
6
5
  const DISPATCH_LINE = /despach|dispatch|subagent_type/i;
7
6
 
8
- /** The generic dispatch token: "the implementer of the task's domain". */
9
7
  const GENERIC_DISPATCH = 'morph-{id}';
10
8
 
11
9
  /**
12
- * Which phases each persona works in, read from the phase skills themselves.
13
- *
14
- * v5 has no phase list on the persona: a phase dispatches a persona when its
15
- * skill (`phases.json → skill`) names `morph-{personaId}` on a dispatch line
16
- * (morph-uiux → ui-designer, morph-plan → scout, morph-review → evaluator).
17
- * A skill that dispatches the generic `morph-{id}` runs every implementer —
18
- * the same `isImplementer` the validator and the installer use.
19
- *
20
10
  * Only dispatch lines count: morph-plan cites `morph-dotnet-senior` as a
21
11
  * spelling example of the `agent` field, which dispatches nobody.
22
- *
23
- * @param {string} frameworkDir
24
- * @param {Record<string, object>} agents - agents.json `agents` map
25
- * @returns {Map<string, string[]>} personaId → phase ids, in phase order
26
12
  */
27
13
  export function personaPhases(frameworkDir, agents) {
28
14
  const result = new Map(Object.keys(agents).map((id) => [id, []]));
@@ -46,10 +32,6 @@ export function personaPhases(frameworkDir, agents) {
46
32
  return result;
47
33
  }
48
34
 
49
- /**
50
- * Scan agents.json (v5) — flat domain personas, no tiers.
51
- * Returns the list shaped for the dashboard inspector.
52
- */
53
35
  export function scanAgents(frameworkDir) {
54
36
  const agentsJsonPath = join(frameworkDir, 'agents.json');
55
37
  if (!existsSync(agentsJsonPath)) {
@@ -58,9 +40,7 @@ export function scanAgents(frameworkDir) {
58
40
  const agentsJson = JSON.parse(readFileSync(agentsJsonPath, 'utf8'));
59
41
  const phasesOf = personaPhases(frameworkDir, agentsJson.agents);
60
42
  const knownMcpIds = loadKnownMcpIds(frameworkDir);
61
- // The exact `.claude/agents/morph-{id}.md` the installer writes: the system
62
- // prompt the sub-agent actually runs with. A persona whose data the renderer
63
- // refuses shows the refusal instead of hiding the persona.
43
+ // A persona whose data the renderer refuses shows the refusal instead of hiding the persona.
64
44
  const promptOf = (id, agent) => {
65
45
  try { return renderAgentMd({ id, ...agent }, knownMcpIds); } catch (err) { return `<!-- não renderizou: ${err.message} -->`; }
66
46
  };
@@ -71,8 +51,6 @@ export function scanAgents(frameworkDir) {
71
51
  color: agent.color || null,
72
52
  domains: agent.domains || [],
73
53
  keywords: agent.keywords || [],
74
- // Every standard the persona can cite, surfaces included — the same
75
- // reading the installer and the validator use.
76
54
  standards: personaStandardIds(agent),
77
55
  surfaces: agent.surfaces || null,
78
56
  stack: agent.stack || ['*'],
@@ -1,8 +1,3 @@
1
- /**
2
- * The reading material of the framework — the charter, the runtime
3
- * instructions, the CLI reference and the Gate 3 evaluator checklist — for the
4
- * dashboard's Guide page.
5
- */
6
1
  import { readFileSync } from 'fs';
7
2
  import { join } from 'path';
8
3
 
@@ -10,7 +5,6 @@ function read(path) {
10
5
  try { return readFileSync(path, 'utf8'); } catch { return null; }
11
6
  }
12
7
 
13
- /** `## Heading` lines, the table of contents a long document is read by. */
14
8
  export function headingsOf(content) {
15
9
  const out = [];
16
10
  let inFence = false;
@@ -27,7 +21,7 @@ const GUIDE = [
27
21
  { id: 'morph', path: 'MORPH.md', title: 'Carta do harness (MORPH.md)', summary: 'Como o Claude trabalha: papéis, fases, gates, sub-agents. É a fonte única do comportamento.' },
28
22
  { id: 'runtime', path: 'CLAUDE.md', title: 'Instruções de runtime (CLAUDE.md)', summary: 'O que é injetado no CLAUDE.md do projeto: como começar cada sessão, regras críticas, comandos.' },
29
23
  { id: 'cli', path: 'docs/CLI.md', title: 'Referência do CLI', summary: 'Todos os comandos morph-spec: gates, verify, worktrees, grafo, telemetria.' },
30
- { id: 'review-checklist', path: 'evals/review-checklist.md', title: 'Checklist do avaliador (Gate 3)', summary: 'O que o avaliador independente procura antes do ship: veredito SHIP/FIX e bloqueador com evidência.' },
24
+ { id: 'review-checklist', path: 'evals/review-checklist.md', title: 'Checklist do Gate 3', summary: 'O que verificador, revisor e segurança procuram antes do ship: veredito SHIP/FIX e bloqueador com evidência.' },
31
25
  ];
32
26
 
33
27
  export function scanDocs(frameworkDir) {
@@ -1,9 +1,6 @@
1
1
  /**
2
- * When a feature counts as finished — the one rule the portfolio (server) and
3
- * the feature list (client) share. Pure, no node imports: the client bundles it.
4
- *
5
- * A feature in `.morph/archive/` is closed whatever its status says: legacy
6
- * archives keep `draft` or `in_progress` from before `finish` set the status.
2
+ * Pure, no node imports: the client bundles it. An archived feature is closed
3
+ * whatever its legacy status says.
7
4
  */
8
5
  export function isFinished(f) {
9
6
  return f?.status === 'completed' || f?.status === 'abandoned' || f?.location === 'archive';