@event4u/agent-config 16.5.0 → 17.0.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 (1026) hide show
  1. package/.augment-plugin/marketplace.json +3 -3
  2. package/.augment-plugin/plugin.json +1 -1
  3. package/.claude-plugin/marketplace.json +2 -2
  4. package/.claude-plugin/skills/install-agent-config/SKILL.md +4 -4
  5. package/CHANGELOG.md +463 -498
  6. package/CONTRIBUTING.md +47 -0
  7. package/README.md +25 -25
  8. package/dist/agent-src/commands/{design.md → agent-design.md} +10 -6
  9. package/dist/agent-src/commands/agents/init.md +66 -3
  10. package/dist/agent-src/commands/agents/user/init.md +3 -0
  11. package/dist/agent-src/commands/{optimize/deep.md → analyze/and-optimize.md} +72 -33
  12. package/dist/agent-src/commands/analyze/inbox.md +168 -37
  13. package/dist/agent-src/commands/analyze/pr.md +144 -0
  14. package/dist/agent-src/commands/analyze/{repo.md → reference.md} +85 -14
  15. package/dist/agent-src/commands/analyze/roadmap-repos.md +19 -10
  16. package/dist/agent-src/commands/analyze.md +28 -12
  17. package/dist/agent-src/commands/audit.md +115 -0
  18. package/dist/agent-src/commands/brand/review.md +13 -2
  19. package/dist/agent-src/commands/brand/tokens.md +3 -3
  20. package/dist/agent-src/commands/brand/voice.md +8 -5
  21. package/dist/agent-src/commands/brand.md +2 -2
  22. package/dist/agent-src/commands/challenge-me/closure.md +25 -0
  23. package/dist/agent-src/commands/design-system/import.md +8 -3
  24. package/dist/agent-src/commands/design-system/sync.md +98 -0
  25. package/dist/agent-src/commands/design-system.md +6 -1
  26. package/dist/agent-src/commands/evals/analyze.json +44 -0
  27. package/dist/agent-src/commands/evals/audit.json +12 -0
  28. package/dist/agent-src/commands/evals/retro.json +12 -0
  29. package/dist/agent-src/commands/fix/ci.md +10 -8
  30. package/dist/agent-src/commands/ghostwriter/write.md +22 -0
  31. package/dist/agent-src/commands/memory/learn-low-impact.md +70 -83
  32. package/dist/agent-src/commands/memory/propose.md +12 -0
  33. package/dist/agent-src/commands/memory.md +1 -1
  34. package/dist/agent-src/commands/optimize.md +4 -3
  35. package/dist/agent-src/commands/post-as/me.md +18 -0
  36. package/dist/agent-src/commands/pr/create.md +17 -342
  37. package/dist/agent-src/commands/pr/merge.md +129 -368
  38. package/dist/agent-src/commands/retro.md +121 -0
  39. package/dist/agent-src/commands/review/routing.md +1 -1
  40. package/dist/agent-src/commands/roadmap/next.md +4 -1
  41. package/dist/agent-src/commands/roadmap/process-full.md +46 -333
  42. package/dist/agent-src/commands/roadmap/triage-parked.md +6 -2
  43. package/dist/agent-src/commands/team-knowledge/consolidate.md +2 -2
  44. package/dist/agent-src/commands/team-knowledge.md +1 -1
  45. package/dist/agent-src/commands/threat-model.md +1 -1
  46. package/dist/agent-src/commands/upstream-contribute.md +91 -101
  47. package/dist/agent-src/commands/worktree/cleanup.md +18 -11
  48. package/dist/agent-src/contexts/contracts/consumer-agents-md-guide.md +54 -0
  49. package/dist/agent-src/contexts/execution/analysis-loop.md +137 -0
  50. package/dist/agent-src/contexts/execution/auto-dispatch-classification.md +3 -3
  51. package/dist/agent-src/contexts/execution/decision-closure-execution.md +1 -1
  52. package/dist/agent-src/contexts/execution/host-capability-manifest.md +6 -0
  53. package/dist/agent-src/contexts/execution/orchestration-telemetry.md +11 -4
  54. package/dist/agent-src/contexts/execution/pr-create-branches-content.md +250 -0
  55. package/dist/agent-src/contexts/execution/pr-create-branches-freshness.md +150 -0
  56. package/dist/agent-src/contexts/execution/pr-merge-queue.md +287 -0
  57. package/dist/agent-src/contexts/execution/pr-merge-sync.md +276 -0
  58. package/dist/agent-src/contexts/execution/pr-merge-trust-boundary.md +69 -0
  59. package/dist/agent-src/contexts/execution/process-full-all.md +233 -0
  60. package/dist/agent-src/contexts/execution/process-full-delivery.md +231 -0
  61. package/dist/agent-src/contexts/execution/roadmap-execution-contract-branches.md +42 -0
  62. package/dist/agent-src/contexts/execution/roadmap-execution-contract.md +1 -35
  63. package/dist/agent-src/contexts/execution/roadmap-process-loop-close.md +235 -0
  64. package/dist/agent-src/contexts/execution/roadmap-process-loop-prescan.md +216 -0
  65. package/dist/agent-src/contexts/execution/roadmap-process-loop-run.md +253 -0
  66. package/dist/agent-src/contexts/execution/roadmap-process-loop-set.md +212 -0
  67. package/dist/agent-src/contexts/execution/roadmap-process-loop.md +25 -864
  68. package/dist/agent-src/contexts/execution/subagent-spawn-contract.md +14 -2
  69. package/dist/agent-src/contexts/execution/subagent-steering.md +65 -8
  70. package/dist/agent-src/contexts/model-recommendations.md +5 -5
  71. package/dist/agent-src/contexts/subagent-configuration.md +1 -1
  72. package/dist/agent-src/guidelines/agent-infra/api-cost-levers.md +4 -3
  73. package/dist/agent-src/guidelines/agent-infra/model-recommendation.md +11 -5
  74. package/dist/agent-src/guidelines/agent-infra/rule-body-migration-inventory.md +1 -1
  75. package/dist/agent-src/guidelines/agent-infra/self-improvement-pipeline.md +47 -24
  76. package/dist/agent-src/guidelines/design-antipatterns.md +5 -0
  77. package/dist/agent-src/guidelines/design-asset-discipline.md +17 -0
  78. package/dist/agent-src/guidelines/design-fidelity-routing.md +1 -0
  79. package/dist/agent-src/guidelines/php/api-design.md +10 -1
  80. package/dist/agent-src/rules/brand-source-of-truth.md +7 -6
  81. package/dist/agent-src/rules/code-provenance.md +1 -1
  82. package/dist/agent-src/rules/context-hygiene.md +0 -1
  83. package/dist/agent-src/rules/design-fidelity.md +12 -13
  84. package/dist/agent-src/rules/external-reference-deep-dive.md +2 -2
  85. package/dist/agent-src/rules/fix-what-you-see.md +1 -1
  86. package/dist/agent-src/rules/low-impact-corpus-privacy-floor.md +14 -15
  87. package/dist/agent-src/rules/missing-skill-recovery.md +12 -11
  88. package/dist/agent-src/rules/neighbour-precedence.md +1 -1
  89. package/dist/agent-src/rules/recurring-criticism.md +1 -1
  90. package/dist/agent-src/rules/roadmap-ci-steps-policy.md +0 -2
  91. package/dist/agent-src/rules/self-repair-loop.md +2 -2
  92. package/dist/agent-src/rules/token-budget-discipline.md +1 -1
  93. package/dist/agent-src/scripts/dashboard_mode.ts +4 -1
  94. package/dist/agent-src/scripts/roadmap_age.ts +175 -0
  95. package/dist/agent-src/scripts/update_roadmap_progress.ts +10 -2
  96. package/dist/agent-src/skills/accessibility-auditor/SKILL.md +3 -3
  97. package/dist/agent-src/skills/agent-security-review/SKILL.md +2 -2
  98. package/dist/agent-src/skills/agents-md-thin-root/SKILL.md +12 -4
  99. package/dist/agent-src/skills/ai-code-blindspots/SKILL.md +7 -0
  100. package/dist/agent-src/skills/ai-council/references/advanced-modes.md +11 -1
  101. package/dist/agent-src/skills/ai-council/references/cost-and-redaction.md +7 -0
  102. package/dist/agent-src/skills/ai-council/references/execution-modes.md +7 -0
  103. package/dist/agent-src/skills/ai-council/references/output-and-synthesis.md +19 -0
  104. package/dist/agent-src/skills/ai-council/references/procedure.md +7 -0
  105. package/dist/agent-src/skills/api-design/SKILL.md +2 -2
  106. package/dist/agent-src/skills/api-endpoint/SKILL.md +2 -2
  107. package/dist/agent-src/skills/authz-review/SKILL.md +5 -3
  108. package/dist/agent-src/skills/blade-ui/SKILL.md +2 -2
  109. package/dist/agent-src/skills/brand/SKILL.md +7 -3
  110. package/dist/agent-src/skills/brand-asset-generation/SKILL.md +13 -6
  111. package/dist/agent-src/skills/brand-audit/SKILL.md +2 -1
  112. package/dist/agent-src/skills/brand-identity/SKILL.md +5 -4
  113. package/dist/agent-src/skills/brand-strategy/SKILL.md +5 -4
  114. package/dist/agent-src/skills/brand-to-tokens/SKILL.md +18 -39
  115. package/dist/agent-src/skills/brand-to-tokens/templates/marp-brand-deck.md.example +2 -2
  116. package/dist/agent-src/skills/brand-to-tokens/templates/reveal-brand-deck.yaml +2 -2
  117. package/dist/agent-src/skills/canvas-design/SKILL.md +12 -2
  118. package/dist/agent-src/skills/competitive-positioning/SKILL.md +2 -2
  119. package/dist/agent-src/skills/composer-packages/SKILL.md +18 -0
  120. package/dist/agent-src/skills/condense-memory/SKILL.md +1 -1
  121. package/dist/agent-src/skills/content-funnel-design/SKILL.md +8 -1
  122. package/dist/agent-src/skills/context-authoring/SKILL.md +1 -1
  123. package/dist/agent-src/skills/context-document/SKILL.md +2 -2
  124. package/dist/agent-src/skills/corpus-grounding/SKILL.md +6 -6
  125. package/dist/agent-src/skills/corpus-grounding/scripts/decision_engine.ts +13 -11
  126. package/dist/agent-src/skills/corpus-grounding/scripts/ground.mjs +1706 -0
  127. package/dist/agent-src/skills/corpus-grounding/scripts/schema_validator.ts +7 -1
  128. package/dist/agent-src/skills/dashboard-design/SKILL.md +1 -1
  129. package/dist/agent-src/skills/data-flow-mapper/SKILL.md +5 -2
  130. package/dist/agent-src/skills/database/SKILL.md +5 -4
  131. package/dist/agent-src/skills/decision-record/references/weighted-matrix.md +12 -0
  132. package/dist/agent-src/skills/deep-reading-analyst/SKILL.md +1 -1
  133. package/dist/agent-src/skills/dependency-upgrade/SKILL.md +61 -11
  134. package/dist/agent-src/skills/description-assist/SKILL.md +1 -1
  135. package/dist/agent-src/skills/design-intelligence/SKILL.md +1 -1
  136. package/dist/agent-src/skills/design-intelligence/data/landing.csv +1 -1
  137. package/dist/agent-src/skills/design-intelligence/references/context-and-registers.md +10 -2
  138. package/dist/agent-src/skills/design-intelligence/references/design-languages.md +1 -1
  139. package/dist/agent-src/skills/design-intelligence/references/design-rules-checklist.md +4 -3
  140. package/dist/agent-src/skills/design-intelligence/references/integration-mapping.md +14 -14
  141. package/dist/agent-src/skills/{wireframe → design-review}/references/story-beat-ledger.schema.json +1 -1
  142. package/dist/agent-src/skills/design-review/references/verification-automation.md +11 -3
  143. package/dist/agent-src/skills/design-system-capture/SKILL.md +15 -10
  144. package/dist/agent-src/skills/design-system-capture/references/design-system-json.md +20 -5
  145. package/dist/agent-src/skills/design-system-capture/references/import-procedure.md +2 -2
  146. package/dist/agent-src/skills/design-tokens/SKILL.md +23 -23
  147. package/dist/agent-src/skills/design-tokens/scripts/tokens.mjs +1037 -0
  148. package/dist/agent-src/skills/design-tokens/scripts/tokens.ts +336 -13
  149. package/dist/agent-src/skills/design-tokens/templates/design-tokens-starter.json +52 -53
  150. package/dist/agent-src/skills/docker/SKILL.md +1 -1
  151. package/dist/agent-src/skills/estimate-ticket/SKILL.md +1 -1
  152. package/dist/agent-src/skills/existing-ui-audit/SKILL.md +14 -276
  153. package/dist/agent-src/skills/existing-ui-audit/procedure.yaml +44 -0
  154. package/dist/agent-src/skills/existing-ui-audit/references/anti-slop-cross-reference.md +1 -1
  155. package/dist/agent-src/skills/existing-ui-audit/references/steps/00-inspect-stack-and-input.md +4 -0
  156. package/dist/agent-src/skills/existing-ui-audit/references/steps/01-enumerate-components.md +26 -0
  157. package/dist/agent-src/skills/existing-ui-audit/references/steps/01b-detect-component-taxonomy.md +7 -0
  158. package/dist/agent-src/skills/existing-ui-audit/references/steps/02-identify-design-system.md +12 -0
  159. package/dist/agent-src/skills/existing-ui-audit/references/steps/03-detect-design-tokens.md +35 -0
  160. package/dist/agent-src/skills/existing-ui-audit/references/steps/04-detect-shadcn-inventory.md +13 -0
  161. package/dist/agent-src/skills/existing-ui-audit/references/steps/04b-live-storybook-read.md +26 -0
  162. package/dist/agent-src/skills/existing-ui-audit/references/steps/05-list-reusable-patterns.md +14 -0
  163. package/dist/agent-src/skills/existing-ui-audit/references/steps/06-match-candidates.md +52 -0
  164. package/dist/agent-src/skills/existing-ui-audit/references/steps/07-greenfield-branch.md +29 -0
  165. package/dist/agent-src/skills/existing-ui-audit/references/steps/08-a11y-baseline.md +40 -0
  166. package/dist/agent-src/skills/existing-ui-audit/references/steps/09-validate-and-write.md +5 -0
  167. package/dist/agent-src/skills/experiment-loop/SKILL.md +1 -1
  168. package/dist/agent-src/skills/fe-design/references/design-patterns.md +16 -2
  169. package/dist/agent-src/skills/fe-design/references/design-read-and-memory.md +1 -1
  170. package/dist/agent-src/skills/fe-design/references/source-led-port.md +1 -1
  171. package/dist/agent-src/skills/finishing-a-development-branch/SKILL.md +6 -6
  172. package/dist/agent-src/skills/flux/SKILL.md +1 -1
  173. package/dist/agent-src/skills/form-handler/SKILL.md +15 -2
  174. package/dist/agent-src/skills/git-workflow/SKILL.md +2 -2
  175. package/dist/agent-src/skills/git-workflow/references/branch-update.md +7 -0
  176. package/dist/agent-src/skills/git-workflow/references/commit-subject.md +12 -0
  177. package/dist/agent-src/skills/git-workflow/references/push-closes-its-loop.md +10 -0
  178. package/dist/agent-src/skills/gtm-launch/SKILL.md +8 -1
  179. package/dist/agent-src/skills/html-deck/SKILL.md +7 -2
  180. package/dist/agent-src/skills/humanizer/SKILL.md +16 -3
  181. package/dist/agent-src/skills/humanizer/references/anti-aiisms.md +13 -1
  182. package/dist/agent-src/skills/humanizer/references/fixtures.md +8 -0
  183. package/dist/agent-src/skills/js-library-packaging/SKILL.md +5 -4
  184. package/dist/agent-src/skills/js-library-packaging/scripts/check_package_surface.mjs +197 -0
  185. package/dist/agent-src/skills/judge-artifact-completeness/SKILL.md +1 -1
  186. package/dist/agent-src/skills/judge-security-auditor/SKILL.md +2 -2
  187. package/dist/agent-src/skills/launch-readiness/SKILL.md +18 -22
  188. package/dist/agent-src/skills/learning-to-rule-or-skill/SKILL.md +5 -5
  189. package/dist/agent-src/skills/livewire/SKILL.md +1 -1
  190. package/dist/agent-src/skills/llm-provider-knowledge/SKILL.md +18 -0
  191. package/dist/agent-src/skills/logo-generation/SKILL.md +9 -3
  192. package/dist/agent-src/skills/market-entry-analysis/SKILL.md +6 -1
  193. package/dist/agent-src/skills/markitdown/SKILL.md +1 -1
  194. package/dist/agent-src/skills/memory-consolidation/SKILL.md +2 -2
  195. package/dist/agent-src/skills/messaging-architecture/SKILL.md +8 -1
  196. package/dist/agent-src/skills/motion-choreographer/SKILL.md +2 -2
  197. package/dist/agent-src/skills/playwright-testing/SKILL.md +2 -0
  198. package/dist/agent-src/skills/positioning-strategy/SKILL.md +10 -2
  199. package/dist/agent-src/skills/prediction-pool-optimizer/references/ev-fixtures.md +13 -0
  200. package/dist/agent-src/skills/prediction-pool-optimizer/references/odds-and-bonus.md +7 -0
  201. package/dist/agent-src/skills/project-analysis-core/SKILL.md +1 -1
  202. package/dist/agent-src/skills/project-analysis-hypothesis-driven/SKILL.md +1 -1
  203. package/dist/agent-src/skills/project-analyzer/SKILL.md +14 -75
  204. package/dist/agent-src/skills/project-analyzer/procedure.yaml +39 -0
  205. package/dist/agent-src/skills/project-analyzer/references/steps/01-project-overview.md +9 -0
  206. package/dist/agent-src/skills/project-analyzer/references/steps/02-architecture.md +7 -0
  207. package/dist/agent-src/skills/project-analyzer/references/steps/03-data-layer.md +6 -0
  208. package/dist/agent-src/skills/project-analyzer/references/steps/04-business-domains.md +7 -0
  209. package/dist/agent-src/skills/project-analyzer/references/steps/05-api-surface.md +6 -0
  210. package/dist/agent-src/skills/project-analyzer/references/steps/06-service-map.md +6 -0
  211. package/dist/agent-src/skills/project-analyzer/references/steps/07-module-inventory.md +6 -0
  212. package/dist/agent-src/skills/project-analyzer/references/steps/08-infrastructure-and-testing.md +5 -0
  213. package/dist/agent-src/skills/project-analyzer/references/steps/09-agent-docs-audit.md +6 -0
  214. package/dist/agent-src/skills/project-analyzer/references/steps/10-gap-analysis.md +6 -0
  215. package/dist/agent-src/skills/quality-tools/references/js-ts-tools.md +10 -0
  216. package/dist/agent-src/skills/quality-tools/references/php-tools.md +13 -0
  217. package/dist/agent-src/skills/quality-tools/references/python-tools.md +11 -0
  218. package/dist/agent-src/skills/react-native-setup/SKILL.md +7 -2
  219. package/dist/agent-src/skills/react-shadcn-ui/SKILL.md +5 -1
  220. package/dist/agent-src/skills/react-shadcn-ui/references/registry.md +13 -0
  221. package/dist/agent-src/skills/react-shadcn-ui/scripts/shadcn_add.mjs +315 -0
  222. package/dist/agent-src/skills/react-shadcn-ui/scripts/shadcn_add.ts +6 -6
  223. package/dist/agent-src/skills/receiving-code-review/SKILL.md +1 -1
  224. package/dist/agent-src/skills/refine-ticket/SKILL.md +2 -2
  225. package/dist/agent-src/skills/release-comms/SKILL.md +2 -1
  226. package/dist/agent-src/skills/repomix-packer/SKILL.md +2 -2
  227. package/dist/agent-src/skills/requesting-code-review/SKILL.md +3 -3
  228. package/dist/agent-src/skills/roadmap-management/references/archival.md +3 -3
  229. package/dist/agent-src/skills/roadmap-management/references/authoring.md +9 -2
  230. package/dist/agent-src/skills/roadmap-management/references/dashboard.md +3 -3
  231. package/dist/agent-src/skills/roadmap-management/references/lifecycle.md +3 -3
  232. package/dist/agent-src/skills/roadmap-writing/SKILL.md +4 -4
  233. package/dist/agent-src/skills/rtk-output-filtering/SKILL.md +1 -1
  234. package/dist/agent-src/skills/rule-writing/SKILL.md +1 -2
  235. package/dist/agent-src/skills/security/SKILL.md +41 -5
  236. package/dist/agent-src/skills/skill-improvement-pipeline/SKILL.md +5 -3
  237. package/dist/agent-src/skills/skill-reviewer/SKILL.md +1 -1
  238. package/dist/agent-src/skills/skill-writing/SKILL.md +23 -8
  239. package/dist/agent-src/skills/skill-writing/references/section-patterns.md +19 -1
  240. package/dist/agent-src/skills/source-discovery/SKILL.md +3 -3
  241. package/dist/agent-src/skills/sql-writing/SKILL.md +2 -2
  242. package/dist/agent-src/skills/standards-from-config/SKILL.md +2 -2
  243. package/dist/agent-src/skills/storybook-workshop/SKILL.md +5 -0
  244. package/dist/agent-src/skills/storybook-workshop/scripts/story_contrast_floor.mjs +99 -0
  245. package/dist/agent-src/skills/subagent-orchestration/SKILL.md +13 -13
  246. package/dist/agent-src/skills/subagent-orchestration/prompts/README.md +4 -3
  247. package/dist/agent-src/skills/svg-authoring/SKILL.md +7 -1
  248. package/dist/agent-src/skills/systematic-debugging/SKILL.md +2 -2
  249. package/dist/agent-src/skills/tailwind-engineer/SKILL.md +8 -3
  250. package/dist/agent-src/skills/tailwind-engineer/scripts/tailwind_config_gen.mjs +482 -0
  251. package/dist/agent-src/skills/test-case-discovery/SKILL.md +1 -1
  252. package/dist/agent-src/skills/threat-modeling/SKILL.md +8 -1
  253. package/dist/agent-src/skills/threat-modeling/data/manifest.json +5 -2
  254. package/dist/agent-src/skills/threat-modeling/data/reasoning.csv +10 -10
  255. package/dist/agent-src/skills/threat-modeling/data/surfaces.csv +11 -10
  256. package/dist/agent-src/skills/threat-modeling/data/threats.csv +34 -20
  257. package/dist/agent-src/skills/type-design/SKILL.md +196 -0
  258. package/dist/agent-src/skills/type-design/references/font-spec.md +90 -0
  259. package/dist/agent-src/skills/type-design/references/gates.md +113 -0
  260. package/dist/agent-src/skills/type-design/references/toolchain.md +66 -0
  261. package/dist/agent-src/skills/typography-system/SKILL.md +21 -11
  262. package/dist/agent-src/skills/typography-system/references/worked-scales.md +85 -0
  263. package/dist/agent-src/skills/ui-apply-generic/SKILL.md +1 -1
  264. package/dist/agent-src/skills/universal-project-analysis/SKILL.md +1 -1
  265. package/dist/agent-src/skills/upstream-contribute/SKILL.md +120 -125
  266. package/dist/agent-src/skills/using-git-worktrees/SKILL.md +1 -0
  267. package/dist/agent-src/skills/verify-repair-loop/SKILL.md +1 -1
  268. package/dist/agent-src/skills/voice-and-tone-design/SKILL.md +71 -2
  269. package/dist/agent-src/skills/worktree-lifecycle/SKILL.md +16 -14
  270. package/dist/agent-src/templates/AGENTS.md +1 -1
  271. package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
  272. package/dist/agent-src/templates/agents/proposal.example.md +1 -1
  273. package/dist/agent-src/templates/github-workflows/advisories-daily.yml +85 -0
  274. package/dist/agent-src/templates/roadmaps.md +39 -1
  275. package/dist/agent-src/templates/scripts/check_memory.ts +2 -2
  276. package/dist/agent-src/templates/scripts/historical-bug-patterns.example.yml +13 -1
  277. package/dist/agent-src/templates/scripts/work_engine/cli.ts +17 -0
  278. package/dist/agent-src/templates/scripts/work_engine/cli_args.ts +10 -0
  279. package/dist/agent-src/templates/scripts/work_engine/directives/ui/scaffold.ts +22 -13
  280. package/dist/agent-src/templates/scripts/work_engine/dispatcher.ts +18 -4
  281. package/dist/agent-src/templates/scripts/work_engine/procedure/checks.ts +283 -0
  282. package/dist/agent-src/templates/scripts/work_engine/procedure/run.ts +432 -0
  283. package/dist/agent-src/templates/scripts/work_engine/procedure/sidecar.ts +185 -0
  284. package/dist/agent-src/templates/scripts/work_engine/state.ts +3 -0
  285. package/dist/cli/commands/uiRender.js +72 -17
  286. package/dist/cli/commands/uiRenderAsset.js +10 -2
  287. package/dist/cli/commands/uiRenderAssetFonts.js +158 -0
  288. package/dist/cli/commands/uiRenderAssetTypes.js +8 -20
  289. package/dist/cli/initRouting.js +1 -1
  290. package/dist/cli/mcp/dispatch.js +31 -9
  291. package/dist/cli/python/knowledge_ingest.js +7 -39
  292. package/dist/cli/python/workspace_secrets.js +4 -177
  293. package/dist/cli/registry.js +4 -1
  294. package/dist/cli-delegate/archive_completed_roadmaps.js +3 -2
  295. package/dist/cli-delegate/check_update_banner.js +635 -266
  296. package/dist/cli-delegate/{chunk-TMWYUOK4.js → chunk-2CX7NWRB.js} +224 -437
  297. package/dist/cli-delegate/{chunk-F3QDG2GT.js → chunk-2SFOOFJJ.js} +259 -159
  298. package/dist/cli-delegate/chunk-2Y5AMLMY.js +136 -0
  299. package/dist/cli-delegate/{chunk-OKJUIAPS.js → chunk-4E2W63DA.js} +1 -62
  300. package/dist/cli-delegate/{chunk-6SRJTYJS.js → chunk-4SHNERBL.js} +37 -16
  301. package/dist/cli-delegate/chunk-5VO3RTMV.js +208 -0
  302. package/dist/cli-delegate/chunk-6E2LDY4F.js +27 -0
  303. package/dist/cli-delegate/{chunk-XQTPXKFA.js → chunk-6ZD2QZMN.js} +8 -17
  304. package/dist/cli-delegate/{chunk-6V5FMA3P.js → chunk-7CEI2YPS.js} +1 -1
  305. package/dist/cli-delegate/{chunk-DMSZHXZS.js → chunk-7DRWULEQ.js} +80 -7
  306. package/dist/cli-delegate/chunk-7NXCZSDL.js +54 -0
  307. package/dist/cli-delegate/chunk-AX3U3UWJ.js +328 -0
  308. package/dist/cli-delegate/{chunk-WOKWX5PL.js → chunk-BKALSTBZ.js} +18 -3
  309. package/dist/cli-delegate/chunk-BMGUGSY6.js +103 -0
  310. package/dist/cli-delegate/chunk-BYV46VRM.js +3309 -0
  311. package/dist/cli-delegate/{chunk-5GPULQBE.js → chunk-CAL76ADI.js} +4215 -682
  312. package/dist/cli-delegate/chunk-DSY6LLCQ.js +127 -0
  313. package/dist/cli-delegate/chunk-E6XNBVE4.js +581 -0
  314. package/dist/cli-delegate/{chunk-ZUZKZYCN.js → chunk-ESUNQ5XR.js} +46 -10
  315. package/dist/cli-delegate/{chunk-G5VVIZRC.js → chunk-F7HLSW6P.js} +1 -1
  316. package/dist/cli-delegate/chunk-FIEEOH5C.js +133 -0
  317. package/dist/cli-delegate/chunk-FKYZOWVD.js +719 -0
  318. package/dist/cli-delegate/chunk-GOMILC3O.js +918 -0
  319. package/dist/cli-delegate/chunk-I4KJYVPB.js +69 -0
  320. package/dist/cli-delegate/{chunk-JQOM7TTM.js → chunk-IDAOTDPE.js} +1 -100
  321. package/dist/cli-delegate/chunk-IROAQ77A.js +137 -0
  322. package/dist/cli-delegate/chunk-J2SJZICO.js +698 -0
  323. package/dist/cli-delegate/{chunk-6YQC2HLF.js → chunk-JHMMWNJ2.js} +54 -40
  324. package/dist/cli-delegate/{chunk-WQWXGIWB.js → chunk-M6CRG5O6.js} +165 -15
  325. package/dist/cli-delegate/{chunk-PHD7OOLE.js → chunk-MQ2UDEGV.js} +14 -3
  326. package/dist/cli-delegate/chunk-NTM7G2V4.js +220 -0
  327. package/dist/cli-delegate/chunk-PV7S5DPJ.js +175 -0
  328. package/dist/cli-delegate/{chunk-F7DQWYR5.js → chunk-RAXQOETZ.js} +6 -2
  329. package/dist/cli-delegate/{chunk-T7XSJSUQ.js → chunk-SIOMDAKL.js} +980 -784
  330. package/dist/cli-delegate/{chunk-KR6EM23A.js → chunk-TULVDQ4L.js} +3 -48
  331. package/dist/cli-delegate/chunk-UUYEKXKR.js +20 -0
  332. package/dist/cli-delegate/{chunk-7XGD2OEU.js → chunk-UXWHY6CQ.js} +2 -1
  333. package/dist/cli-delegate/{chunk-PWX7CKMD.js → chunk-VC3ECUEK.js} +1 -1
  334. package/dist/cli-delegate/{chunk-KXXWJTDO.js → chunk-WMNYVIYX.js} +1 -1
  335. package/dist/cli-delegate/chunk-XCY5KKUC.js +181 -0
  336. package/dist/cli-delegate/{chunk-H76PHZBI.js → chunk-XLY5G3CM.js} +14 -19
  337. package/dist/cli-delegate/cmd_adr_effective.js +41 -2
  338. package/dist/cli-delegate/cmd_analyze_session.js +7 -7
  339. package/dist/cli-delegate/cmd_brand_status.js +1287 -10
  340. package/dist/cli-delegate/cmd_ci_settle.js +330 -0
  341. package/dist/cli-delegate/cmd_conformance.js +483 -817
  342. package/dist/cli-delegate/cmd_doctor.js +26 -16
  343. package/dist/cli-delegate/cmd_doctor_neighbours.js +10 -7
  344. package/dist/cli-delegate/cmd_explain.js +9 -24
  345. package/dist/cli-delegate/cmd_export.js +14 -11
  346. package/dist/cli-delegate/cmd_fleet.js +5 -3
  347. package/dist/cli-delegate/cmd_git_convention.js +8 -4
  348. package/dist/cli-delegate/cmd_handoff.js +79 -242
  349. package/dist/cli-delegate/cmd_mcp_available.js +1 -1
  350. package/dist/cli-delegate/cmd_memory_get.js +4 -2
  351. package/dist/cli-delegate/cmd_migrate.js +2 -2
  352. package/dist/cli-delegate/cmd_packs_active.js +2 -2
  353. package/dist/cli-delegate/cmd_preflight.js +7 -5
  354. package/dist/cli-delegate/cmd_prune.js +16 -13
  355. package/dist/cli-delegate/cmd_route_audit.js +11 -8
  356. package/dist/cli-delegate/cmd_route_explain.js +649 -16
  357. package/dist/cli-delegate/cmd_session_recycle.js +15 -6
  358. package/dist/cli-delegate/cmd_settings_check.js +2 -2
  359. package/dist/cli-delegate/cmd_settings_get.js +1 -1
  360. package/dist/cli-delegate/cmd_settings_migrate.js +14 -11
  361. package/dist/cli-delegate/cmd_settings_set.js +1 -1
  362. package/dist/cli-delegate/cmd_sync.js +16 -13
  363. package/dist/cli-delegate/cmd_uninstall.js +185 -31
  364. package/dist/cli-delegate/cmd_update.js +67 -3
  365. package/dist/cli-delegate/cmd_upgrade.js +38 -7
  366. package/dist/cli-delegate/cmd_validate.js +16 -13
  367. package/dist/cli-delegate/cmd_versions.js +1 -1
  368. package/dist/cli-delegate/dashboard_mode.js +1 -1
  369. package/dist/cli-delegate/gate_execute.js +4 -3
  370. package/dist/cli-delegate/roadmap_age.js +22 -0
  371. package/dist/cli-delegate/roadmap_gates.js +4 -3
  372. package/dist/cli-delegate/update_roadmap_progress.js +3 -2
  373. package/dist/cli-delegate/upgrade_unattended-VVL6JLSX.js +541 -0
  374. package/dist/discovery/deprecation-report.md +1 -1
  375. package/dist/discovery/discovery-manifest.json +373 -190
  376. package/dist/discovery/discovery-manifest.json.sha256 +1 -1
  377. package/dist/discovery/discovery-manifest.summary.md +5 -5
  378. package/dist/discovery/dormancy-report.md +1 -1
  379. package/dist/discovery/orphan-report.md +1 -1
  380. package/dist/discovery/packs.json +21 -16
  381. package/dist/discovery/trust-report.md +3 -3
  382. package/dist/discovery/workspaces.json +16 -11
  383. package/dist/hooks/chat_history.chunk.cjs +6852 -0
  384. package/dist/hooks/chat_history.chunk.cjs.sha256 +1 -0
  385. package/dist/hooks/dispatch.js +17506 -18692
  386. package/dist/hooks/dispatch.sha256 +1 -1
  387. package/dist/hooks/egress_engine.chunk.cjs +915 -0
  388. package/dist/hooks/egress_engine.chunk.cjs.sha256 +1 -0
  389. package/dist/hooks/svg_rules.chunk.cjs +281 -49
  390. package/dist/hooks/svg_rules.chunk.cjs.sha256 +1 -1
  391. package/dist/install/conflict.js +36 -6
  392. package/dist/install/conflictTracker.js +81 -7
  393. package/dist/install/detect.js +3 -3
  394. package/dist/install/hostPermissionsAdapter.js +106 -0
  395. package/dist/install/install.mjs +3117 -1949
  396. package/dist/install/installThinLayer.js +1 -1
  397. package/dist/install/manifestFiles.js +21 -0
  398. package/dist/install/noGoDenyRows.js +300 -0
  399. package/dist/install/noGoRules.js +368 -0
  400. package/dist/install/ownershipLedger.js +133 -0
  401. package/dist/install/plan.js +1 -1
  402. package/dist/install/preflight.js +39 -8
  403. package/dist/install/preserve.js +74 -12
  404. package/dist/install/recordedOwnership.js +88 -5
  405. package/dist/install/rule_scope.js +20 -3
  406. package/dist/install/stagedRuntime.js +455 -0
  407. package/dist/install/toolsArg.js +19 -0
  408. package/dist/install/userPin.js +47 -0
  409. package/dist/install/wizard-plan.js +26 -4
  410. package/dist/mcp/awesome-mcp-servers.row.md +1 -1
  411. package/dist/mcp/mcp-cloudflare-catalogue.json +3 -2
  412. package/dist/mcp/registry-manifest.json +6 -5
  413. package/dist/mcp/server.json +3 -3
  414. package/dist/mcp/server.mjs +9831 -5546
  415. package/dist/router.json +1 -1
  416. package/dist/scripts/_lib/agent_settings.js +7 -12
  417. package/dist/scripts/_lib/asset_render_record.js +219 -0
  418. package/dist/scripts/_lib/claude_builtin_names.js +9 -4
  419. package/dist/scripts/_lib/claude_settings_hooks.js +102 -34
  420. package/dist/scripts/_lib/egress_rules.js +766 -0
  421. package/dist/scripts/_lib/environment_detector.js +24 -33
  422. package/dist/scripts/_lib/global_deploy_inventory.js +146 -9
  423. package/dist/scripts/_lib/guidelines_lane.js +10 -1
  424. package/dist/scripts/_lib/identifier_redaction.js +24 -0
  425. package/dist/scripts/_lib/installed_layer.js +17 -0
  426. package/dist/scripts/_lib/installed_layer_normalise.js +72 -0
  427. package/dist/scripts/_lib/lean_projection_mode.js +34 -152
  428. package/dist/scripts/_lib/project_tree_form.js +118 -0
  429. package/dist/scripts/_lib/scoped_projection.js +133 -3
  430. package/dist/scripts/_lib/settings_removed_keys.js +29 -0
  431. package/dist/scripts/_lib/settings_renamed_keys.js +17 -5
  432. package/dist/scripts/_lib/subagent_native_fields.js +35 -0
  433. package/dist/scripts/_lib/svg_filled_counter.js +285 -0
  434. package/dist/scripts/_lib/svg_rules.js +2 -0
  435. package/dist/scripts/_lib/ui_surface.js +19 -0
  436. package/dist/scripts/_lib/verification_command.js +364 -0
  437. package/dist/scripts/_lib/workspace_secrets.js +229 -0
  438. package/dist/scripts/ai_council/seat_policy.js +27 -0
  439. package/dist/scripts/ai_council/transport_resolver.js +9 -10
  440. package/dist/scripts/condense.js +25 -29
  441. package/dist/server/io/substituteTemplate.js +2 -2
  442. package/dist/server/io/yamlIO.js +2 -2
  443. package/dist/server/routes/install.js +5 -1
  444. package/dist/server/routes/settings.js +2 -2
  445. package/dist/server/routes/wizard.js +1 -1
  446. package/dist/server/schemas/settings.js +22 -16
  447. package/dist/server/serverInfo.js +1 -1
  448. package/dist/shared/brandTokenDocument.js +47 -0
  449. package/dist/shared/brandTokenPaths.js +43 -0
  450. package/dist/shared/settingsCarveOut.js +0 -7
  451. package/dist/shared/skillRanking.js +103 -5
  452. package/dist/shared/userMd/formAdapter.js +16 -0
  453. package/dist/shared/userMd/schema.js +17 -0
  454. package/dist/ui/assets/index-w70Ado09.js +23 -0
  455. package/dist/ui/index.html +1 -1
  456. package/docs/MIGRATION.md +89 -2
  457. package/docs/THIRD-PARTY-NOTICES.md +27 -0
  458. package/docs/contracts/settings-classes.md +27 -9
  459. package/docs/guidelines/agent-infra/api-cost-levers.md +4 -3
  460. package/docs/guidelines/agent-infra/model-recommendation.md +11 -5
  461. package/docs/guidelines/agent-infra/rule-body-migration-inventory.md +1 -1
  462. package/docs/guidelines/agent-infra/self-improvement-pipeline.md +47 -24
  463. package/docs/guidelines/design-antipatterns.md +5 -0
  464. package/docs/guidelines/design-asset-discipline.md +17 -0
  465. package/docs/guidelines/design-fidelity-routing.md +1 -0
  466. package/docs/guidelines/php/api-design.md +10 -1
  467. package/llms.txt +12 -10
  468. package/package.json +13 -4
  469. package/src/agent-src/scripts/dashboard_mode.ts +4 -1
  470. package/src/agent-src/scripts/roadmap_age.ts +175 -0
  471. package/src/agent-src/scripts/update_roadmap_progress.ts +10 -2
  472. package/src/agent-src/templates/AGENTS.md +1 -1
  473. package/src/agent-src/templates/scripts/check_memory.ts +2 -2
  474. package/src/agent-src/templates/scripts/historical-bug-patterns.example.yml +13 -1
  475. package/src/agent-src/templates/scripts/work_engine/cli.ts +17 -0
  476. package/src/agent-src/templates/scripts/work_engine/cli_args.ts +10 -0
  477. package/src/agent-src/templates/scripts/work_engine/directives/ui/scaffold.ts +22 -13
  478. package/src/agent-src/templates/scripts/work_engine/dispatcher.ts +18 -4
  479. package/src/agent-src/templates/scripts/work_engine/procedure/checks.ts +283 -0
  480. package/src/agent-src/templates/scripts/work_engine/procedure/run.ts +432 -0
  481. package/src/agent-src/templates/scripts/work_engine/procedure/sidecar.ts +185 -0
  482. package/src/agent-src/templates/scripts/work_engine/state.ts +3 -0
  483. package/src/config/agent-settings.template.yml +120 -57
  484. package/src/config/agents-paths.yml +13 -7
  485. package/src/config/ci-local-parity.yml +44 -0
  486. package/src/config/continuity-surface.json +51 -2
  487. package/src/config/depth-audit-samples.json +5 -0
  488. package/src/config/discovery/command-verbs.yml +1 -0
  489. package/src/config/dispatch-economy-metrics.json +1 -0
  490. package/src/config/egress-mutations/class-precedence-swapped.json +7 -0
  491. package/src/config/egress-mutations/credential-token-restores.json +7 -0
  492. package/src/config/egress-mutations/iban-checksum-disabled.json +7 -0
  493. package/src/config/egress-mutations/raw-value-in-the-count-record.json +7 -0
  494. package/src/config/evaluator-budgets.json +4 -4
  495. package/src/config/gate-coverage.yml +149 -3
  496. package/src/config/gate-reachability-exemptions.json +3 -5
  497. package/src/config/gate-violation-baselines.json +26 -22
  498. package/src/config/gitignore-block.txt +6 -3
  499. package/src/config/hook-bundle-budget.json +34 -3
  500. package/src/config/hook-carrier-probes.json +30 -0
  501. package/src/config/hook-latency-budget.json +4 -2
  502. package/src/config/host-injection-effect.json +8 -1
  503. package/src/config/host-skill-frontmatter-keys.json +56 -0
  504. package/src/config/layer-form-brakes.json +4 -0
  505. package/src/config/layer-form-comparison-corpus.json +42 -0
  506. package/src/config/loop-surfaces.yaml +28 -47
  507. package/src/config/memory-twin-verdicts.yml +9 -1
  508. package/src/config/metric-registry.yml +40 -3
  509. package/src/config/pack-size-budget.json +15 -0
  510. package/src/config/procedure-core-budget.json +21 -0
  511. package/src/config/profiles/minimal.ini +1 -1
  512. package/src/config/project-tree-form.json +24 -0
  513. package/src/config/reach-channels.yml +3 -3
  514. package/src/config/reach-prescriptions-intake.yml +1 -1
  515. package/src/config/roadmap-step-size-baseline.json +118 -0
  516. package/src/config/routing-coverage-seed.json +93 -2
  517. package/src/config/skill-body-budget.json +686 -0
  518. package/src/config/skill-fork-pilot.json +17 -0
  519. package/src/config/skill-lifecycle-probes-codex.json +57 -0
  520. package/src/config/skill-lifecycle-probes.json +57 -0
  521. package/src/config/skill-output-shape.json +316 -0
  522. package/src/config/step-depth-table.json +58 -0
  523. package/src/config/turnaround-budget.json +90 -0
  524. package/src/install/conflict.ts +38 -6
  525. package/src/install/conflictTracker.ts +126 -8
  526. package/src/install/detect.ts +3 -3
  527. package/src/install/hostPermissionsAdapter.ts +136 -0
  528. package/src/install/installThinLayer.ts +6 -1
  529. package/src/install/manifestFiles.ts +24 -0
  530. package/src/install/noGoDenyRows.ts +368 -0
  531. package/src/install/noGoRules.ts +438 -0
  532. package/src/install/ownershipLedger.ts +180 -0
  533. package/src/install/plan.ts +1 -1
  534. package/src/install/preflight.ts +42 -10
  535. package/src/install/preserve.ts +94 -12
  536. package/src/install/recordedOwnership.ts +121 -3
  537. package/src/install/rule_scope.ts +20 -3
  538. package/src/install/stagedRuntime.ts +528 -0
  539. package/src/install/toolsArg.ts +16 -0
  540. package/src/install/types.ts +23 -2
  541. package/src/install/userPin.ts +54 -0
  542. package/src/install/wizard-plan.ts +25 -4
  543. package/src/scripts/_cli/_doctor_emit.ts +24 -0
  544. package/src/scripts/_cli/cmd_brand_status.ts +223 -12
  545. package/src/scripts/_cli/cmd_ci_settle.ts +32 -0
  546. package/src/scripts/_cli/cmd_doctor.ts +23 -44
  547. package/src/scripts/_cli/cmd_route_explain.ts +176 -2
  548. package/src/scripts/_cli/cmd_uninstall.ts +270 -26
  549. package/src/scripts/_cli/cmd_update.ts +34 -1
  550. package/src/scripts/_cli/cmd_upgrade.ts +38 -2
  551. package/src/scripts/_cli/detection_report.ts +7 -0
  552. package/src/scripts/_cli/doctor_execution.ts +1 -2
  553. package/src/scripts/_cli/doctor_install_mode.ts +39 -0
  554. package/src/scripts/_cli/doctor_network_posture.ts +3 -3
  555. package/src/scripts/_cli/doctor_ownership_ledger.ts +126 -0
  556. package/src/scripts/_cli/doctor_update_verdict.ts +104 -0
  557. package/src/scripts/_cli/explain_last/scrubber.ts +9 -21
  558. package/src/scripts/_cli/upgrade_unattended.ts +548 -0
  559. package/src/scripts/_dispatch.bash +42 -9
  560. package/src/scripts/_lib/activation_ladder.ts +1 -1
  561. package/src/scripts/_lib/advisory_inventory.ts +405 -0
  562. package/src/scripts/_lib/advisory_notice.ts +270 -0
  563. package/src/scripts/_lib/advisory_sources.ts +752 -0
  564. package/src/scripts/_lib/advisory_verdicts.ts +363 -0
  565. package/src/scripts/_lib/agent_artifact_location.ts +177 -0
  566. package/src/scripts/_lib/agent_settings.ts +7 -12
  567. package/src/scripts/_lib/arrival_record.ts +217 -0
  568. package/src/scripts/_lib/asset_render_record.ts +247 -0
  569. package/src/scripts/_lib/billing_grant.ts +4 -2
  570. package/src/scripts/_lib/brand_voice_slot.ts +258 -0
  571. package/src/scripts/_lib/canary_status.ts +24 -0
  572. package/src/scripts/_lib/cc_transcript.ts +276 -0
  573. package/src/scripts/_lib/changelog_eras.ts +83 -0
  574. package/src/scripts/_lib/claim_phrases.ts +71 -0
  575. package/src/scripts/_lib/classify_update.ts +171 -0
  576. package/src/scripts/_lib/claude_builtin_names.ts +9 -4
  577. package/src/scripts/_lib/claude_hook_scope.ts +195 -0
  578. package/src/scripts/_lib/claude_settings_hooks.ts +118 -34
  579. package/src/scripts/_lib/codex_resident_set.ts +460 -0
  580. package/src/scripts/_lib/codex_skill_finder.ts +225 -0
  581. package/src/scripts/_lib/confusables.ts +19 -0
  582. package/src/scripts/_lib/consumer_impact.ts +199 -0
  583. package/src/scripts/_lib/content_class.ts +127 -0
  584. package/src/scripts/_lib/counted_probe.ts +68 -1
  585. package/src/scripts/_lib/credential_deny_rows.ts +151 -0
  586. package/src/scripts/_lib/credential_files.ts +367 -0
  587. package/src/scripts/_lib/delivery_arm_experiment.ts +2 -2
  588. package/src/scripts/_lib/depth_flip.ts +141 -0
  589. package/src/scripts/_lib/design_lock.ts +117 -0
  590. package/src/scripts/_lib/design_sync_ledger.ts +142 -0
  591. package/src/scripts/_lib/design_sync_plan.ts +177 -0
  592. package/src/scripts/_lib/design_sync_reconcile.ts +159 -0
  593. package/src/scripts/_lib/design_sync_verify.ts +99 -0
  594. package/src/scripts/_lib/design_system_claude_design.ts +323 -0
  595. package/src/scripts/_lib/design_system_import.ts +84 -6
  596. package/src/scripts/_lib/dispatch_import_closure.ts +42 -11
  597. package/src/scripts/_lib/egress_credential_env.ts +35 -0
  598. package/src/scripts/_lib/egress_engine.ts +22 -0
  599. package/src/scripts/_lib/egress_known_values.ts +223 -0
  600. package/src/scripts/_lib/egress_normalize.ts +67 -0
  601. package/src/scripts/_lib/egress_prefixes.ts +42 -0
  602. package/src/scripts/_lib/egress_rules.ts +896 -0
  603. package/src/scripts/_lib/egress_rules_linearity.ts +56 -0
  604. package/src/scripts/_lib/egress_sender_scan.ts +290 -0
  605. package/src/scripts/_lib/egress_session_table.ts +510 -0
  606. package/src/scripts/_lib/egress_text.ts +63 -0
  607. package/src/scripts/_lib/egress_token.ts +252 -0
  608. package/src/scripts/_lib/empty_cycles.ts +1 -1
  609. package/src/scripts/_lib/environment_detector.ts +45 -30
  610. package/src/scripts/_lib/exemption_shape.ts +75 -1
  611. package/src/scripts/_lib/floor_posture.ts +185 -0
  612. package/src/scripts/_lib/forge_protection.ts +140 -2
  613. package/src/scripts/_lib/global_deploy_inventory.ts +159 -6
  614. package/src/scripts/_lib/guidelines_lane.ts +12 -1
  615. package/src/scripts/_lib/hand_kinds.ts +65 -0
  616. package/src/scripts/_lib/headless_invocation.ts +3 -3
  617. package/src/scripts/_lib/host_capability.ts +34 -2
  618. package/src/scripts/_lib/host_env_write.ts +39 -18
  619. package/src/scripts/_lib/host_listing_model.ts +14 -7
  620. package/src/scripts/_lib/identifier_redaction.ts +26 -0
  621. package/src/scripts/_lib/impact_bump.ts +70 -0
  622. package/src/scripts/_lib/install_reach_checks.ts +53 -1
  623. package/src/scripts/_lib/installed_layer.ts +31 -0
  624. package/src/scripts/_lib/installed_layer_normalise.ts +75 -0
  625. package/src/scripts/_lib/instructions_loaded_classify.ts +75 -0
  626. package/src/scripts/_lib/instructions_loaded_event.ts +53 -0
  627. package/src/scripts/_lib/knowledge_global_redaction.ts +2 -2
  628. package/src/scripts/_lib/layer_form_corpus.ts +165 -0
  629. package/src/scripts/_lib/layer_form_decision.ts +248 -0
  630. package/src/scripts/_lib/layer_form_evidence.ts +112 -0
  631. package/src/scripts/_lib/lean_projection_mode.ts +32 -161
  632. package/src/scripts/_lib/llm_proposer_transport.ts +1 -0
  633. package/src/scripts/_lib/loop_guards.ts +8 -120
  634. package/src/scripts/_lib/major_surface.ts +207 -0
  635. package/src/scripts/_lib/mcp_bridge.ts +30 -69
  636. package/src/scripts/_lib/merge_clearance_record.ts +384 -0
  637. package/src/scripts/_lib/neighbour_census.ts +18 -1
  638. package/src/scripts/_lib/orchestration_record.ts +61 -0
  639. package/src/scripts/_lib/outcome_vocabularies.ts +15 -23
  640. package/src/scripts/_lib/pin_advice.ts +49 -0
  641. package/src/scripts/_lib/platform_anchor.ts +222 -0
  642. package/src/scripts/_lib/procedure_checks.ts +5 -0
  643. package/src/scripts/_lib/project_tree_form.ts +134 -0
  644. package/src/scripts/_lib/projection_key_migration.ts +122 -0
  645. package/src/scripts/_lib/prompt_shape.ts +13 -2
  646. package/src/scripts/_lib/provenance_verify.ts +272 -0
  647. package/src/scripts/_lib/quota_parked.ts +27 -1
  648. package/src/scripts/_lib/ratification_artifact.ts +64 -1
  649. package/src/scripts/_lib/ratification_subject.ts +508 -46
  650. package/src/scripts/_lib/release_findings_ingest.ts +52 -5
  651. package/src/scripts/_lib/release_highlights.ts +72 -2
  652. package/src/scripts/_lib/release_settings_surface.ts +392 -0
  653. package/src/scripts/_lib/review_round.ts +134 -0
  654. package/src/scripts/_lib/roadmap_checkboxes.ts +1 -1
  655. package/src/scripts/_lib/roadmap_slug_lock.ts +254 -0
  656. package/src/scripts/_lib/roadmap_step_size.ts +75 -0
  657. package/src/scripts/_lib/run_checkpoint.ts +60 -3
  658. package/src/scripts/_lib/runtime_wiring_checks.ts +15 -1
  659. package/src/scripts/_lib/scope_guard.sh +64 -5
  660. package/src/scripts/_lib/scoped_projection.ts +136 -3
  661. package/src/scripts/_lib/secret_detector.ts +24 -103
  662. package/src/scripts/_lib/security_fix.ts +429 -0
  663. package/src/scripts/_lib/security_fix_context.ts +133 -0
  664. package/src/scripts/_lib/self_repair.ts +69 -39
  665. package/src/scripts/_lib/self_repair_outgoing.ts +209 -0
  666. package/src/scripts/_lib/self_repair_payload.ts +86 -0
  667. package/src/scripts/_lib/session_eol.ts +3 -0
  668. package/src/scripts/_lib/session_pr_watch.ts +207 -0
  669. package/src/scripts/_lib/session_register.ts +51 -1
  670. package/src/scripts/_lib/session_tag.ts +51 -0
  671. package/src/scripts/_lib/settings_removed_keys.ts +30 -0
  672. package/src/scripts/_lib/settings_renamed_keys.ts +19 -5
  673. package/src/scripts/_lib/skill_catalogue.ts +66 -25
  674. package/src/scripts/_lib/skill_fork_pilot.ts +121 -0
  675. package/src/scripts/_lib/skill_leases.ts +203 -0
  676. package/src/scripts/_lib/skill_listing_overrides.ts +294 -0
  677. package/src/scripts/_lib/skill_materialisation.ts +388 -0
  678. package/src/scripts/_lib/skill_materialisation_gate.ts +210 -0
  679. package/src/scripts/_lib/skill_materialisation_lock.ts +149 -0
  680. package/src/scripts/_lib/skill_materialisation_triggers.ts +96 -0
  681. package/src/scripts/_lib/skill_origin.ts +21 -1
  682. package/src/scripts/_lib/skill_reach.ts +342 -0
  683. package/src/scripts/_lib/source_shape.ts +7 -2
  684. package/src/scripts/_lib/sqlite_guard.ts +1 -1
  685. package/src/scripts/_lib/step_anatomy.ts +330 -0
  686. package/src/scripts/_lib/subagent_capsule.ts +8 -2
  687. package/src/scripts/_lib/subagent_native_fields.ts +30 -0
  688. package/src/scripts/_lib/subagent_spawn.ts +36 -0
  689. package/src/scripts/_lib/subagent_steering.ts +367 -0
  690. package/src/scripts/_lib/svg_filled_counter.ts +287 -0
  691. package/src/scripts/_lib/svg_rules.ts +2 -0
  692. package/src/scripts/_lib/test_delta.ts +89 -6
  693. package/src/scripts/_lib/tier_downshift_verdict.ts +222 -0
  694. package/src/scripts/_lib/tool_result_census.ts +62 -0
  695. package/src/scripts/_lib/trigger_routers.ts +1 -0
  696. package/src/scripts/_lib/turnaround_throughput.ts +378 -0
  697. package/src/scripts/_lib/ui_surface.ts +22 -0
  698. package/src/scripts/_lib/unattended_gates.ts +100 -0
  699. package/src/scripts/_lib/undeployed_fixes.ts +34 -0
  700. package/src/scripts/_lib/update_check.ts +143 -12
  701. package/src/scripts/_lib/update_invite.ts +116 -0
  702. package/src/scripts/_lib/update_notice.ts +259 -0
  703. package/src/scripts/_lib/verify_clause.ts +4 -2
  704. package/src/scripts/_lib/version_order.ts +146 -0
  705. package/src/scripts/_lib/worker_reuse.ts +191 -0
  706. package/src/scripts/_lib/workspace_secrets.ts +273 -0
  707. package/src/scripts/_lib/worktree_git.ts +67 -0
  708. package/src/scripts/_lib/worktree_ignored.ts +116 -0
  709. package/src/scripts/adoption_status.ts +330 -3
  710. package/src/scripts/adr_cite_check.ts +93 -0
  711. package/src/scripts/advisories.ts +803 -0
  712. package/src/scripts/ai-image/adapters/flux.sh +1 -0
  713. package/src/scripts/ai-image/adapters/gemini-image.sh +1 -0
  714. package/src/scripts/ai-image/adapters/ideogram.sh +1 -0
  715. package/src/scripts/ai-image/adapters/recraft.sh +1 -0
  716. package/src/scripts/ai-video/adapters/comfyui.sh +1 -0
  717. package/src/scripts/ai-video/adapters/fal.sh +1 -0
  718. package/src/scripts/ai-video/adapters/gemini-veo.sh +1 -0
  719. package/src/scripts/ai-video/adapters/higgsfield.sh +1 -0
  720. package/src/scripts/ai-video/adapters/kling.sh +1 -0
  721. package/src/scripts/ai-video/adapters/musetalk.sh +1 -0
  722. package/src/scripts/ai-video/adapters/openai-images.sh +1 -0
  723. package/src/scripts/ai-video/adapters/replicate.sh +1 -0
  724. package/src/scripts/ai-video/adapters/sora.sh +1 -0
  725. package/src/scripts/ai-video/adapters/syncso.sh +1 -0
  726. package/src/scripts/ai-video/stitch.sh +115 -2
  727. package/src/scripts/ai_council/airgap.ts +1 -0
  728. package/src/scripts/ai_council/api_transport.ts +27 -4
  729. package/src/scripts/ai_council/budget_guard.ts +300 -11
  730. package/src/scripts/ai_council/bundler.ts +20 -29
  731. package/src/scripts/ai_council/chairman.ts +17 -2
  732. package/src/scripts/ai_council/cli_agency_bounds.ts +158 -0
  733. package/src/scripts/ai_council/cli_launch_env.ts +54 -0
  734. package/src/scripts/ai_council/cli_least_agency_canary.ts +18 -2
  735. package/src/scripts/ai_council/clients.ts +55 -73
  736. package/src/scripts/ai_council/config.ts +16 -22
  737. package/src/scripts/ai_council/council_egress.ts +167 -0
  738. package/src/scripts/ai_council/exposure_ledger.ts +117 -0
  739. package/src/scripts/ai_council/free_hand_shadow.ts +276 -0
  740. package/src/scripts/ai_council/free_route.ts +216 -0
  741. package/src/scripts/ai_council/free_route_catalog.ts +173 -0
  742. package/src/scripts/ai_council/free_route_client.ts +95 -0
  743. package/src/scripts/ai_council/free_rung.ts +61 -0
  744. package/src/scripts/ai_council/hand_payload.ts +230 -0
  745. package/src/scripts/ai_council/hand_schemas.ts +123 -0
  746. package/src/scripts/ai_council/jury_aggregate.ts +155 -1
  747. package/src/scripts/ai_council/kind_flip.ts +221 -0
  748. package/src/scripts/ai_council/kind_flip_state.ts +19 -0
  749. package/src/scripts/ai_council/learn_low_impact_preview.ts +50 -22
  750. package/src/scripts/ai_council/modification_review.ts +98 -5
  751. package/src/scripts/ai_council/necessity.ts +7 -0
  752. package/src/scripts/ai_council/orchestrator.ts +16 -16
  753. package/src/scripts/ai_council/pricing.ts +10 -0
  754. package/src/scripts/ai_council/redact_low_impact_entry.ts +5 -2
  755. package/src/scripts/ai_council/response_render.ts +27 -4
  756. package/src/scripts/ai_council/round_reservations.ts +119 -0
  757. package/src/scripts/ai_council/route_chooser.ts +161 -0
  758. package/src/scripts/ai_council/route_liveness.ts +152 -0
  759. package/src/scripts/ai_council/route_member.ts +52 -0
  760. package/src/scripts/ai_council/seat_policy.ts +40 -0
  761. package/src/scripts/ai_council/seat_resume.ts +40 -0
  762. package/src/scripts/ai_council/shadow_dispatch.ts +13 -3
  763. package/src/scripts/ai_council/spend_gate.ts +18 -2
  764. package/src/scripts/ai_council/status_surface.ts +37 -0
  765. package/src/scripts/ai_council/transport_resolver.ts +15 -18
  766. package/src/scripts/analysis_analysts.ts +226 -0
  767. package/src/scripts/analysis_anchors.ts +140 -0
  768. package/src/scripts/analysis_and_optimize.ts +44 -0
  769. package/src/scripts/analysis_emit.ts +150 -0
  770. package/src/scripts/analysis_exchange.ts +186 -0
  771. package/src/scripts/analysis_gate.ts +158 -0
  772. package/src/scripts/analysis_inbox_final.ts +173 -0
  773. package/src/scripts/analysis_ledger.ts +119 -0
  774. package/src/scripts/analysis_pr_optimize.ts +219 -0
  775. package/src/scripts/analysis_pr_review.ts +240 -0
  776. package/src/scripts/analysis_pr_target.ts +121 -0
  777. package/src/scripts/analysis_prompts.ts +130 -0
  778. package/src/scripts/analysis_publish.ts +358 -0
  779. package/src/scripts/analysis_questions.ts +78 -0
  780. package/src/scripts/analysis_run.ts +248 -0
  781. package/src/scripts/analysis_run_record.ts +210 -0
  782. package/src/scripts/analysis_target.ts +343 -0
  783. package/src/scripts/analysis_validate.ts +161 -0
  784. package/src/scripts/anchor_eval_falsify.ts +1 -1
  785. package/src/scripts/arrival_report.ts +115 -0
  786. package/src/scripts/ask_transport.ts +284 -35
  787. package/src/scripts/backfill_model_tier.ts +4 -5
  788. package/src/scripts/before_complete_hook.ts +48 -2
  789. package/src/scripts/bench_hook_latency.ts +3 -3
  790. package/src/scripts/bench_procedure_cursor.ts +440 -0
  791. package/src/scripts/bootstrap.sh +3 -3
  792. package/src/scripts/build_exit_code_register.ts +440 -0
  793. package/src/scripts/build_proof.ts +23 -1
  794. package/src/scripts/cache_realization_report.ts +155 -14
  795. package/src/scripts/canary_liveness.ts +117 -0
  796. package/src/scripts/chat_history.ts +12 -15
  797. package/src/scripts/check_account_surface.ts +318 -0
  798. package/src/scripts/check_agent_artifact_location.ts +17 -160
  799. package/src/scripts/check_bundle_path_leakage.ts +6 -0
  800. package/src/scripts/check_ci_local_parity.ts +21 -13
  801. package/src/scripts/check_claims.ts +77 -2
  802. package/src/scripts/check_completion_review.ts +34 -1
  803. package/src/scripts/check_concern_admissions.ts +41 -5
  804. package/src/scripts/check_consumer_scope_flip.ts +1 -1
  805. package/src/scripts/check_context_paths.ts +2 -0
  806. package/src/scripts/check_council_layout.ts +9 -0
  807. package/src/scripts/check_credential_spelling.ts +267 -0
  808. package/src/scripts/check_egress_mutations.ts +239 -0
  809. package/src/scripts/check_enforcement_coverage.ts +16 -3
  810. package/src/scripts/check_estate_count.ts +16 -1
  811. package/src/scripts/check_finding_dispositions.ts +147 -0
  812. package/src/scripts/check_gate_coverage.ts +123 -21
  813. package/src/scripts/check_gate_reachability.ts +16 -2
  814. package/src/scripts/check_generator_sync.ts +46 -0
  815. package/src/scripts/check_hook_bundle_composition.ts +139 -1
  816. package/src/scripts/check_host_docs_digest.ts +142 -5
  817. package/src/scripts/check_kernel_edit_ratified.ts +301 -76
  818. package/src/scripts/check_kernel_rule_bundle.ts +14 -10
  819. package/src/scripts/check_knowledge_cards.ts +83 -3
  820. package/src/scripts/check_memory.ts +13 -3
  821. package/src/scripts/check_pack_size.ts +1 -1
  822. package/src/scripts/check_permission_deny_syntax.ts +247 -0
  823. package/src/scripts/check_platform_anchor.ts +243 -0
  824. package/src/scripts/check_proposal.ts +183 -1
  825. package/src/scripts/check_reach_channels.ts +5 -3
  826. package/src/scripts/check_references.ts +5 -2
  827. package/src/scripts/check_release_manifest_content.ts +33 -0
  828. package/src/scripts/check_release_pr_shape.ts +5 -0
  829. package/src/scripts/check_rule_invariants.ts +9 -1
  830. package/src/scripts/check_skill_body_budget.ts +343 -0
  831. package/src/scripts/check_skill_requires.ts +137 -1
  832. package/src/scripts/check_step_receipts.ts +246 -0
  833. package/src/scripts/check_structural_breaking.ts +7 -1
  834. package/src/scripts/check_suppression_hygiene.ts +8 -0
  835. package/src/scripts/check_test_weakening.ts +14 -0
  836. package/src/scripts/check_token_quality_golden.ts +5 -1
  837. package/src/scripts/check_update_banner.ts +50 -3
  838. package/src/scripts/check_verify_expectation_delta.ts +2 -1
  839. package/src/scripts/check_voice_lexicon.ts +531 -0
  840. package/src/scripts/ci_os_attribution.ts +327 -0
  841. package/src/scripts/ci_platform_scope.ts +69 -0
  842. package/src/scripts/ci_settle.ts +4 -1
  843. package/src/scripts/ci_status.ts +0 -1
  844. package/src/scripts/ci_time_to_green.ts +748 -0
  845. package/src/scripts/classify_merge_risk.ts +407 -19
  846. package/src/scripts/code_graph/sqlite_store.ts +1 -1
  847. package/src/scripts/compile_trigger_evals.ts +353 -0
  848. package/src/scripts/condense.ts +25 -31
  849. package/src/scripts/consumer_matrix.ts +61 -3
  850. package/src/scripts/council_availability_hook.ts +12 -4
  851. package/src/scripts/council_cli.ts +48 -38
  852. package/src/scripts/cross_repo_retrieve.ts +9 -72
  853. package/src/scripts/design_lock.ts +106 -0
  854. package/src/scripts/design_slop_rules.ts +30 -0
  855. package/src/scripts/design_sync.ts +264 -0
  856. package/src/scripts/design_system_import.ts +30 -13
  857. package/src/scripts/dispatch_economy_report.ts +46 -1
  858. package/src/scripts/dispatch_r2_reviewer.ts +41 -5
  859. package/src/scripts/egress_canary.ts +166 -0
  860. package/src/scripts/egress_sender_census.ts +101 -0
  861. package/src/scripts/external_sources_denylist.json +94 -12
  862. package/src/scripts/generate_catalog.ts +6 -2
  863. package/src/scripts/generate_owned_digest.ts +163 -0
  864. package/src/scripts/generate_reference_toc.ts +143 -0
  865. package/src/scripts/generate_subagent_floor.ts +11 -1
  866. package/src/scripts/handoff_context_hook.ts +34 -0
  867. package/src/scripts/hook_carrier_census.ts +263 -0
  868. package/src/scripts/hook_chunks.d.mts +12 -0
  869. package/src/scripts/hook_chunks.mjs +114 -0
  870. package/src/scripts/hook_manifest.json +1 -1
  871. package/src/scripts/hook_manifest.yaml +65 -42
  872. package/src/scripts/hooks/block_config_weakening.ts +127 -3
  873. package/src/scripts/hooks/block_credential_reads.ts +165 -0
  874. package/src/scripts/hooks/block_no_verify.ts +47 -23
  875. package/src/scripts/hooks/block_speaking_inbox_dir.ts +38 -7
  876. package/src/scripts/hooks/category_a.ts +202 -25
  877. package/src/scripts/hooks/concern_failure_policy.ts +6 -6
  878. package/src/scripts/hooks/concern_registry.ts +31 -6
  879. package/src/scripts/hooks/concern_registry_types.ts +11 -0
  880. package/src/scripts/hooks/delegation_nudge_hook.ts +105 -15
  881. package/src/scripts/hooks/design_pass_hook.ts +42 -10
  882. package/src/scripts/hooks/dispatch_hook.ts +13 -12
  883. package/src/scripts/hooks/egress_engine_loader.ts +125 -0
  884. package/src/scripts/hooks/egress_stage.ts +440 -0
  885. package/src/scripts/hooks/hook_stdin.ts +29 -4
  886. package/src/scripts/hooks/host_docs_pages.ts +194 -0
  887. package/src/scripts/hooks/host_docs_pages.yaml +75 -0
  888. package/src/scripts/hooks/host_lowering.json +1 -1
  889. package/src/scripts/hooks/host_lowering.yaml +22 -21
  890. package/src/scripts/hooks/host_rate_marker_hook.ts +73 -0
  891. package/src/scripts/hooks/instructions_observer_hook.ts +170 -0
  892. package/src/scripts/hooks/interruption_ledger_hook.ts +1 -1
  893. package/src/scripts/hooks/lazy_concern.ts +148 -0
  894. package/src/scripts/hooks/orchestration_record_hook.ts +80 -2
  895. package/src/scripts/hooks/payload_stub.ts +16 -6
  896. package/src/scripts/hooks/permission_gate.ts +7 -7
  897. package/src/scripts/hooks/push_settle_hook.ts +32 -3
  898. package/src/scripts/hooks/replay_hook.ts +43 -0
  899. package/src/scripts/hooks/reread_guard_hook.ts +87 -10
  900. package/src/scripts/hooks/rtk_wrap_hook.ts +4 -3
  901. package/src/scripts/hooks/rule_inject_hook.ts +8 -1
  902. package/src/scripts/hooks/session_eol_hook.ts +48 -1
  903. package/src/scripts/hooks/source_first_gate_hook.ts +6 -8
  904. package/src/scripts/hooks/spawn_guard_shadow_hook.ts +203 -10
  905. package/src/scripts/hooks/state_io.ts +2 -2
  906. package/src/scripts/hooks/svg_obligation.ts +75 -19
  907. package/src/scripts/hooks/tool_result_bytes_hook.ts +14 -5
  908. package/src/scripts/hooks/turn_end_gate_hook.ts +1 -1
  909. package/src/scripts/hooks/ui_route_nudge_hook.ts +2 -12
  910. package/src/scripts/hooks_doctor.ts +31 -0
  911. package/src/scripts/hooks_status.ts +58 -3
  912. package/src/scripts/inbox_source_census.ts +74 -13
  913. package/src/scripts/install +25 -3
  914. package/src/scripts/install.ts +60 -91
  915. package/src/scripts/interruption_report.ts +11 -1
  916. package/src/scripts/layer_baseline_report.ts +267 -0
  917. package/src/scripts/learning_sidecar.ts +1 -1
  918. package/src/scripts/lint_agents_layout.ts +3 -0
  919. package/src/scripts/lint_blocker_citations.ts +104 -0
  920. package/src/scripts/lint_breaking_changes_index.ts +40 -7
  921. package/src/scripts/lint_consolidation_lineage.ts +144 -16
  922. package/src/scripts/lint_consumer_internal_refs.ts +90 -42
  923. package/src/scripts/lint_context_spine_usage.ts +21 -0
  924. package/src/scripts/lint_design_antipattern_parity.ts +39 -7
  925. package/src/scripts/lint_evidence_artifacts.ts +31 -0
  926. package/src/scripts/lint_example_fences.ts +11 -2
  927. package/src/scripts/lint_ghostwriter_source.ts +42 -10
  928. package/src/scripts/lint_hook_manifest.ts +94 -0
  929. package/src/scripts/lint_marketplace_install_completeness.ts +4 -0
  930. package/src/scripts/lint_mcp_config_security.ts +9 -11
  931. package/src/scripts/lint_plan_risk_register.ts +28 -1
  932. package/src/scripts/lint_positioning.ts +4 -4
  933. package/src/scripts/lint_provenance.ts +1 -0
  934. package/src/scripts/lint_roadmap_blockers.ts +65 -4
  935. package/src/scripts/lint_roadmap_complexity.ts +98 -0
  936. package/src/scripts/lint_skill_link_reach.ts +251 -9
  937. package/src/scripts/lint_skill_procedures.ts +252 -0
  938. package/src/scripts/lint_skill_scripts_readonly.ts +12 -1
  939. package/src/scripts/lint_subagent_determinism.ts +14 -1
  940. package/src/scripts/lint_ticked_unmet_criteria.ts +300 -21
  941. package/src/scripts/mcp_registry_submit.sh +2 -2
  942. package/src/scripts/mcp_server/consumer_tool_catalog.json +4 -4
  943. package/src/scripts/mcp_server/suggest_skill.ts +89 -4
  944. package/src/scripts/mcp_server/tools.ts +2 -33
  945. package/src/scripts/measure_skill_ranker_baseline.ts +203 -5
  946. package/src/scripts/measure_turn_end_gate.ts +61 -1
  947. package/src/scripts/merge_clearance.ts +225 -0
  948. package/src/scripts/migrate_command_suggestions.ts +1 -1
  949. package/src/scripts/network_sources.ts +236 -0
  950. package/src/scripts/no_go_deny_rows.ts +225 -0
  951. package/src/scripts/orchestration_record.ts +15 -2
  952. package/src/scripts/plan_test_shards.ts +103 -0
  953. package/src/scripts/pr_url_reminder_hook.ts +10 -0
  954. package/src/scripts/print_required_checks.ts +5 -5
  955. package/src/scripts/probe_depth_shadow.ts +406 -0
  956. package/src/scripts/probe_turnaround.ts +342 -10
  957. package/src/scripts/ratification_subject.ts +176 -0
  958. package/src/scripts/rdp_gate_classify.ts +1 -0
  959. package/src/scripts/rdp_quality_eval.ts +1 -0
  960. package/src/scripts/release.ts +26 -55
  961. package/src/scripts/release_drill.ts +52 -23
  962. package/src/scripts/release_env.ts +37 -0
  963. package/src/scripts/release_publication.ts +11 -1
  964. package/src/scripts/report_consumer_gate_reach.ts +233 -0
  965. package/src/scripts/report_merge_gate_load.ts +295 -0
  966. package/src/scripts/report_project_contract.ts +123 -0
  967. package/src/scripts/report_reducible_classes.ts +342 -0
  968. package/src/scripts/report_required_checks_drift.ts +5 -3
  969. package/src/scripts/report_skill_host_census.ts +199 -0
  970. package/src/scripts/report_standing_payload_by_host.ts +7 -7
  971. package/src/scripts/retro.ts +758 -0
  972. package/src/scripts/retro_facts.ts +575 -0
  973. package/src/scripts/retro_queue.ts +739 -0
  974. package/src/scripts/retro_session_facts.ts +218 -0
  975. package/src/scripts/retro_sweep.ts +493 -0
  976. package/src/scripts/retro_triage.ts +126 -0
  977. package/src/scripts/roadmap_context.ts +2 -2
  978. package/src/scripts/roadmap_drain_queue.ts +601 -0
  979. package/src/scripts/run_supervise.ts +24 -2
  980. package/src/scripts/schemas/agent-settings.schema.json +0 -16
  981. package/src/scripts/schemas/command.schema.json +3 -3
  982. package/src/scripts/schemas/review-findings.schema.json +8 -0
  983. package/src/scripts/schemas/skill.schema.json +7 -6
  984. package/src/scripts/schemas/subagent.schema.json +33 -2
  985. package/src/scripts/score_skill_selection.ts +5 -2
  986. package/src/scripts/second_brain_retrieval.ts +1 -0
  987. package/src/scripts/second_brain_run.ts +1 -0
  988. package/src/scripts/self_repair_cli.ts +563 -87
  989. package/src/scripts/self_review_gate.ts +59 -4
  990. package/src/scripts/session_register_hook.ts +91 -4
  991. package/src/scripts/sessions_cli.ts +100 -5
  992. package/src/scripts/skill_collision_clusters.ts +1 -1
  993. package/src/scripts/skill_tools/score_skill_relevance.ts +31 -2
  994. package/src/scripts/skill_trigger_eval.ts +4 -2
  995. package/src/scripts/source_adapters.ts +183 -0
  996. package/src/scripts/step_receipt.ts +100 -0
  997. package/src/scripts/sync_pr_branch.ts +4 -0
  998. package/src/scripts/test_council_qualification.ts +1 -1
  999. package/src/scripts/trigger_eval_grandfather.json +3 -49
  1000. package/src/scripts/trigger_eval_rotation.ts +31 -3
  1001. package/src/scripts/ui_conformance_probe.ts +405 -1
  1002. package/src/scripts/update_counts.ts +230 -11
  1003. package/src/scripts/update_invite_hook.ts +245 -0
  1004. package/src/scripts/update_notice_hook.ts +298 -0
  1005. package/src/scripts/validate_frontmatter.ts +85 -0
  1006. package/src/scripts/worker_reuse_shadow_report.ts +121 -0
  1007. package/src/scripts/worktree_cleanup_check.ts +915 -121
  1008. package/src/server/io/yamlIO.ts +2 -2
  1009. package/src/server/schemas/settings.ts +37 -23
  1010. package/src/shared/brandTokenDocument.ts +46 -0
  1011. package/src/shared/brandTokenPaths.ts +43 -0
  1012. package/src/shared/settingsCarveOut.ts +0 -8
  1013. package/src/shared/skillRanking.ts +106 -5
  1014. package/src/shared/userMd/formAdapter.ts +15 -1
  1015. package/src/shared/userMd/schema.ts +22 -0
  1016. package/src/templates/agent-user.md +4 -0
  1017. package/src/templates/agent-user.yml +4 -0
  1018. package/dist/cli-delegate/chunk-4DBG5K7M.js +0 -1123
  1019. package/dist/cli-delegate/chunk-523HCFYO.js +0 -90
  1020. package/dist/cli-delegate/chunk-AL3RZ22D.js +0 -74
  1021. package/dist/cli-delegate/chunk-KB5FZ655.js +0 -208
  1022. package/dist/cli-delegate/chunk-MDPPKQCQ.js +0 -875
  1023. package/dist/cli-delegate/chunk-OAFSJBHH.js +0 -272
  1024. package/dist/ui/assets/index-C3djEJah.js +0 -23
  1025. package/src/scripts/_lib/continuation_ladder.ts +0 -335
  1026. package/src/scripts/hooks/run_continuation_hook.ts +0 -1524
@@ -1,1524 +0,0 @@
1
- /**
2
- * run_continuation — road-to-long-horizon-execution Phase 1 (H-1).
3
- *
4
- * The stop slot's first WORK-REMAINING concern. Every other stop concern is a
5
- * quality or state concern; this one compares the session's contracted scope
6
- * against roadmap checkbox state and, when contracted work remains, returns
7
- * the dispatcher's block verdict with a continuation naming the next unchecked
8
- * step and its `verify:` line. The dispatcher translates a stop-slot block to
9
- * host exit 2, and the host feeds this concern's stderr back to the agent —
10
- * that channel IS the re-engagement; no daemon, no second process.
11
- *
12
- * SHAPE PROVENANCE, and the three deliberate differences. The allow/deny-plus-
13
- * continuation shape is claude-flow's `autopilotCheck` (commands/autopilot.ts
14
- * @ fa13ee4, v3.38.12), verified at source in the roadmap's § 1. AC's version
15
- * differs by design, not oversight:
16
- *
17
- * 1. The progress signal is the claimed roadmap's own checkboxes — the same
18
- * artefact `roadmap-progress` already watches — never a parallel task
19
- * file that can drift from the roadmap it mirrors.
20
- * 2. Quality gates take precedence. Concerns run SEQUENTIALLY in chain
21
- * order (dispatch_hook.ts § runner); this concern is registered AFTER
22
- * `turn-end-gate`, and when the gate refused THIS turn (its refusal
23
- * marker carries the turn ordinal) this concern defers. A turn refused
24
- * for unverified claims is never re-engaged past the refusal — the
25
- * upstream's naked "Do not stop until all are complete" is the
26
- * anti-pattern this branch exists against.
27
- * 3. Every re-engagement names the next step and its `verify:` line. A
28
- * continuation that does not say what "continue" means just burns an
29
- * iteration on re-orientation.
30
- *
31
- * CONTRACT GATING — when this concern is a no-op, which is almost always:
32
- * · no roadmap claim for this session (`sessions:claim` never ran), or
33
- * · the claimed roadmap's frontmatter `execution.mode` is anything but
34
- * `autonomous` (absent, `interactive`, `phase-checkpoints` — a
35
- * checkpointed run WANTS its phase-boundary conversation), or
36
- * · replay mode, or the kill switch `AGENT_CONFIG_NO_RUN_CONTINUATION=1`.
37
- * The claim file plus the mode field is the run contract this file consumes;
38
- * it invents no second contract carrier.
39
- *
40
- * TERMINATION LADDER (Phase 1.1) — every rung a named event in
41
- * `agents/runtime/state/run-continuation.jsonl`:
42
- * contract absent → no-op (no event; the common case is silent)
43
- * roadmap unreadable from the
44
- * authoritative tree → allow (event: halt-roadmap-absent, ONCE PER
45
- * ABSENCE EPISODE with a readable state and ONCE PER
46
- * RUN without one — the two guards have different
47
- * carriers: `absent_fires` resets on a successful
48
- * read, the ledger guard cannot forget. So a second
49
- * episode on an unparseable state is SILENT,
50
- * only for a run this concern had already engaged
51
- * on THIS roadmap — the keyed state is the
52
- * discriminator. State absent stays silent,
53
- * because nothing was ever driven. The budget is
54
- * reclaimed only after `ABSENT_CONFIRM_FIRES`
55
- * consecutive absent fires: one fire cannot tell
56
- * an archival from a non-atomic rewrite, two can.
57
- * Deliberately NOT in `HALT_ACTIONS` — it clears
58
- * the budget rather than stamping `halted`, and
59
- * the two are exclusive)
60
- * transcript over the shared
61
- * read cap → allow (event: inert-transcript-over-cap, ONCE
62
- * per run. The concern cannot compute a turn
63
- * ordinal past the cap, so it goes inert — and an
64
- * inert mechanism that says nothing is
65
- * indistinguishable from a healthy idle run,
66
- * which is the failure this file exists over)
67
- * plan premise moved → allow (event: halt-premise-invalidated, ONCE per
68
- * run. Engaged-under fingerprint and newest
69
- * observation both known and differing. Before the
70
- * counter rungs: iterating against a stale plan
71
- * does not make it current, and capping out would
72
- * report `exhausted`, a budget word, for staleness.
73
- * Never fires on traffic the run did not observe)
74
- * quality-gate refusal → defer (event: deferred-quality-gate)
75
- * duplicate stop fire → repeat the BLOCK, no count (event: none —
76
- * an allow here would END the reply the block
77
- * one event earlier exists to continue). A fire
78
- * whose roadmap SOURCE changed is never a
79
- * duplicate, whatever the counts say.
80
- * scope complete (0 open,
81
- * none blocked) → allow (event: complete; state cleared)
82
- * remaining work externally
83
- * impossible (0 open, ≥1
84
- * blocked) → allow (event: blocked, ONCE per run, guarded by
85
- * the LEDGER: the state is cleared like `complete`,
86
- * so no field there outlives the event. A terminal
87
- * outcome — not a sixth halt, never in
88
- * `HALT_ACTIONS`, never stamped into `halted`.
89
- * ADR-237 narrows what may legally wear a
90
- * `blocked-by:` marker; semantics unchanged.)
91
- * iterations ≥ MAX (25) → allow (event: halt-max-iterations)
92
- * wall clock ≥ cap (4 h) → allow (event: halt-wall-clock)
93
- * stall (3 engagements, no
94
- * checkbox delta) → allow (event: halt-stall)
95
- * otherwise → BLOCK + continue (event: engage)
96
- *
97
- * Every event this concern writes carries `workspace_root`, `session_root`,
98
- * `session_cwd`, `git_dir`, `git_common_dir` and `claim_path` — the two-tree
99
- * provenance, per `provenance()` below — plus `roadmap_path`, the file the
100
- * open-step count on that same line was read from (round 4 finding 4). Seven
101
- * fields. The count has been caught wrong in three separate rounds; if you add
102
- * one, this line, `provenance()`s heading and the roadmap enumeration all move. Without them the ledger records that an
103
- * engagement happened but not that it crossed the tree boundary the fix was
104
- * about, and crossing it is the whole claim. This list is the file's canonical
105
- * statement of the contract: R2 round 2 finding 4 caught it enumerating four
106
- * fields while the function emitted five, which would have let a later edit drop
107
- * one without contradicting any documented promise.
108
- *
109
- * Stall counts CONSECUTIVE ENGAGEMENTS whose open-step count did not move.
110
- * The upstream stalls on 5-of-5 completed-count readings; AC's checkbox
111
- * signal is finer-grained (a step in progress usually flips SOMETHING), so
112
- * the default is tighter at 3 — pre-registered for revisit against Phase 4
113
- * data in the roadmap, not tuned here.
114
- *
115
- * `[~]` (deferred) and `[-]` (cancelled) boxes are not open work — the
116
- * vocabulary is `update_roadmap_progress.ts`'s. A step carrying a
117
- * `blocked-by:` marker is open work this RUN cannot do, so it neither counts
118
- * toward the open total nor gets named as the next step: re-engaging an
119
- * agent into a step the roadmap itself declares blocked is a guaranteed
120
- * stall, manufactured by the mechanism whose job is to detect one.
121
- *
122
- * FAIL-OPEN THROUGHOUT. severity: BLOCKING, fail_closed: false. Any read
123
- * error, any malformed state, any surprise → EXIT_ALLOW. A continuation
124
- * mechanism must never be the thing that blocks a stop for a reason nobody
125
- * can see; the only BLOCK this file emits is the one that carries its own
126
- * explanation on stderr.
127
- *
128
- * The severity word matters and this docblock had the wrong one. It read
129
- * `advisory` — which the dispatcher enforces as a CEILING, downgrading any
130
- * EXIT_BLOCK to WARN, so the whole mechanism was inert. That was round 1's
131
- * critical finding; the manifest moved and this line did not, which round 3
132
- * then caught as a doc contradicting the declaration it describes. Blocking
133
- * and fail-open are not in tension: fail-open governs what happens when this
134
- * file cannot decide, blocking governs what happens when it decides to
135
- * continue.
136
- */
137
-
138
- import * as fs from 'node:fs';
139
- import { revokeBillingGrant } from '../_lib/billing_grant.js';
140
- import * as path from 'node:path';
141
- import { fileURLToPath, pathToFileURL } from 'node:url';
142
-
143
- import { unwrap, type JsonObject, type JsonValue } from './envelope.js';
144
- import { readHookStdin } from './hook_stdin.js';
145
- import { is_replay_mode } from './state_io.js';
146
- import { readTranscriptTail } from './turn_end_gate_hook.js';
147
- import { resolve_claim, session_checkout } from '../session_register_hook.js';
148
- import { git_common_dir, git_dir } from '../_lib/git_common_dir.js';
149
- import {
150
- deriveSessionKey,
151
- parseRecord,
152
- sessionRefusalFile,
153
- } from '../_lib/turn_end_refusals.js';
154
- import { phaseLines } from '../_lib/roadmap_checkboxes.js';
155
- import { commandBearing, renderVerifyLine, type VerifyClause } from '../_lib/verify_clause.js';
156
-
157
- /** Dispatcher-internal block code; the dispatcher maps stop-slot 1 → host 2. */
158
-
159
- /**
160
- * The gate's cap, IMPORTED rather than restated — the two must agree by
161
- * construction, not by two numbers that happened to match.
162
- *
163
- * R2 round 2, finding 1, and it was critical. This file carried its own 2 MB
164
- * ("same cap the interruption ledger reads its tail under") while
165
- * `turn_end_gate_hook` uses 8 MB, and `readTranscriptTail` returns
166
- * `turnOrdinal: 0` over its cap WITHOUT throwing. So on any 2-8 MB transcript
167
- * the gate computed ordinal N and wrote `refused_turn: N`, this concern
168
- * computed 0, `refusedThisTurn` compared `N === 0`, the defer was skipped, and
169
- * the concern BLOCKED a stop the quality gate had just refused — silently, and
170
- * in exactly the long-running regime this roadmap targets. That is Risk 1 of
171
- * the register ("quality gates outrank continuation, always") inverted.
172
- *
173
- * Sharing the constant is the fix; a matching literal would re-introduce the
174
- * same defect the next time one side is tuned.
175
- */
176
- import { TRANSCRIPT_READ_MAX_BYTES } from './turn_end_gate_hook.js';
177
- import {
178
- atomicWriteJson,
179
- readUnavailableDependency,
180
- stallSignal,
181
- type StallLevel,
182
- } from '../_lib/loop_guards.js';
183
- import { premiseMoved, readContextObservation } from '../_lib/context_observation.js';
184
- import { RUN_TERMINAL_VOCABULARY_VERSION } from '../_lib/outcome_vocabularies.js';
185
- import {
186
- HALT_ACTIONS,
187
- buildLedgerEvent, parseDeliveryState, type DeliveryState,
188
- ladder,
189
- MAX_ITERATIONS,
190
- parseHaltStamp,
191
- STALL_WINDOW,
192
- terminalStateFor,
193
- WALL_CLOCK_CAP_MS,
194
- type LadderAction,
195
- } from '../_lib/continuation_ladder.js';
196
- import { EXIT_ALLOW, EXIT_BLOCK } from './exit_codes.js';
197
-
198
- /**
199
- * DECLARED in `_lib/continuation_ladder.ts`, re-exported here: one declaration,
200
- * two import paths, no second copy to drift. That module's header says why the
201
- * move happened (`road-to-wired-instruments` Phase 2).
202
- */
203
- export {
204
- HALT_ACTIONS,
205
- ladder,
206
- MAX_ITERATIONS,
207
- parseHaltStamp,
208
- STALL_WINDOW,
209
- terminalStateFor,
210
- WALL_CLOCK_CAP_MS,
211
- type LadderAction,
212
- };
213
-
214
- /** Re-exported so a test can assert the IDENTITY, not two matching literals. */
215
- export { TRANSCRIPT_READ_MAX_BYTES };
216
-
217
- /**
218
- * The blocked-step marker, as § 3c of the process loop documents it. Anchored on
219
- * the comment form with the id REQUIRED: this decides a terminal outcome and
220
- * whether a budget is cleared, so prose merely mentioning the words must not
221
- * remove a step from the open count.
222
- */
223
- const BLOCKED_BY_MARKER = /<!--\s*blocked-by:\s*\S[^>]*-->/;
224
-
225
- /** Tail bound for `eventAlreadyLogged` — the line it seeks is near the end. */
226
- const LEDGER_TAIL_MAX_BYTES = 512 * 1024;
227
-
228
- export const EVENTS_RELPATH = path.join(
229
- 'agents',
230
- 'runtime',
231
- 'state',
232
- 'run-continuation.jsonl',
233
- );
234
- const STATE_DIR_REL = path.join('agents', 'runtime', 'state');
235
-
236
- /**
237
- * How many consecutive absent-roadmap fires confirm the absence.
238
- *
239
- * Two, because that is the smallest number that separates the two causes: a
240
- * non-atomic rewrite is open for well under one turn, an archival lasts across
241
- * them. Round 7 findings 1 and 4 measured the cost of treating one fire as
242
- * confirmation — an unbounded budget reset, repeatable.
243
- */
244
- export const ABSENT_CONFIRM_FIRES = 2;
245
-
246
- export interface RunState {
247
- started_at: string;
248
- iterations: number;
249
- last_turn: number;
250
- /** Open-step count recorded at each engagement, newest last. */
251
- history: number[];
252
- /**
253
- * The derived stall level (Phase 6.6): `progressing` | `flat` | `stalled`.
254
- * Written by the producer so a reader never re-derives it from `history`.
255
- */
256
- stall?: StallLevel;
257
- /**
258
- * Set once the over-cap-transcript rung has reported this run inert.
259
- *
260
- * The rung fires on every stop for the rest of a long run, and one line saying
261
- * so is information while a stream of identical lines is noise.
262
- */
263
- inert_reported?: boolean;
264
- /**
265
- * CONSECUTIVE stop fires on which the roadmap was unreadable — a run of
266
- * absences, not a total, which is why the main path deletes it on a successful
267
- * read. At `ABSENT_CONFIRM_FIRES` the budget is reclaimed; below it the state
268
- * is left alone. The absent branch says why one fire is not enough.
269
- */
270
- absent_fires?: number;
271
- /**
272
- * The roadmap slug this state belongs to.
273
- *
274
- * Round 6 finding 2: the state is keyed on the session id alone, and one
275
- * session may re-claim a different roadmap. A halt stamp is never cleared —
276
- * only `complete` unlinks — so a later legitimate claim of roadmap B inherited
277
- * A's stamp, emitted a halt line naming B without ever engaging, and reported
278
- * A's iteration count under B's slug.
279
- *
280
- * Keying the FILE on the slug would have orphaned every state file in
281
- * existence; recording the slug inside it does the same work and degrades
282
- * cleanly. A mismatch is read as a fresh run, which is what it is.
283
- *
284
- * Optional so a state file written before this field parses unchanged; absent
285
- * means "unknown roadmap" and is trusted, because the alternative is
286
- * discarding a live budget on an upgrade.
287
- */
288
- roadmap?: string;
289
- /**
290
- * The roadmap file the counts in `history` were read from.
291
- *
292
- * Round 4 finding 2: `resolveRoadmap` re-chooses the source tree on every
293
- * fire, and `ladder`'s stall test compares the counts for equality — so a run
294
- * whose source changed mid-flight compared numbers from two different
295
- * documents. Both directions were wrong: a differing earlier count from the
296
- * other tree reset a genuine stall streak, and a coincidentally equal one
297
- * contributed a false match toward `halt-stall`. Recording the source lets a
298
- * change reset the window, which is the only honest reading — the counts
299
- * before the change measured a different file.
300
- *
301
- * Optional so a state file written before this field parses unchanged; absent
302
- * means "unknown source", which resets once and then tracks.
303
- */
304
- history_source?: string;
305
- /** ISO stamp of the most recent engagement — half of the duplicate key. */
306
- last_engaged_at?: string;
307
- /**
308
- * Which halt rung ended this run's budget, if one did. Set instead of
309
- * deleting the state file, and the difference is the whole point: a host
310
- * may fire `stop` several times for one reply, and a deleted state makes
311
- * the next fire read `prev === null`, build `iterations: 0` with a fresh
312
- * `started_at`, and engage again — so the 25-iteration cap bounded a
313
- * 25-block and the 4 h clock restarted on every halt. The R2 review found
314
- * this; the roadmap's Risk 2 ("the agent loops forever on a roadmap it
315
- * cannot finish") named these rungs as its mitigation.
316
- */
317
- halted?: LadderAction;
318
- /**
319
- * The fingerprint this run ENGAGED under — its plan premise, recorded once on
320
- * the first engagement from `_lib/context_observation` and then left alone.
321
- * Refreshing it every fire would make both sides of the premise comparison
322
- * equal by construction and the rung unreachable. Absent means the run never
323
- * observed one, which is never a disagreement (`premiseMoved`).
324
- */
325
- context_fingerprint?: string;
326
- /** DELIVERY position (8.1), written by the run; absent is no hold. */
327
- delivery?: DeliveryState;
328
- }
329
-
330
- /**
331
- * A host may fire `stop` more than once for one reply (the turn-end gate
332
- * documents the same quirk). The duplicate key is ordinal + open-count +
333
- * a short window, because the ordinal ALONE is not a turn identity here:
334
- * a re-engaged reply often lands in the same user turn, so its ordinal is
335
- * unchanged even though real work happened — the open count is what moved.
336
- */
337
- export const DUPLICATE_WINDOW_MS = 60 * 1000;
338
-
339
- export function isDuplicateFire(
340
- state: RunState | null,
341
- turnOrdinal: number,
342
- openCount: number,
343
- nowMs: number,
344
- roadmapSource?: string,
345
- ): boolean {
346
- if (state === null) return false;
347
- if (state.last_turn !== turnOrdinal) return false;
348
- // Round 5 finding 6: this compared the recorded count against the fresh scan
349
- // with no regard for which FILE either came from — the same cross-document
350
- // comparison `history_source` exists to stop, in the one place that returns
351
- // BLOCK without consuming an iteration or writing a line. A source change with
352
- // a coincidentally equal count therefore erased a genuine engagement from the
353
- // ledger the acceptance criteria are counted from. A changed source is never a
354
- // duplicate fire.
355
- // Round 7 finding 6: this read an ABSENT recorded source as a changed one, so
356
- // the first fire after the upgrade that introduced the field failed to
357
- // recognise a genuine duplicate — it consumed an iteration and appended an
358
- // extra `engage` line to the ledger the acceptance criteria count from, which
359
- // is the false count round 5 finding 6 added the guard to prevent. Both sides
360
- // must be known before a difference means anything.
361
- if (
362
- state.history_source !== undefined &&
363
- roadmapSource !== undefined &&
364
- state.history_source !== roadmapSource
365
- ) {
366
- return false;
367
- }
368
- if (state.history.length === 0 || state.history[state.history.length - 1] !== openCount) {
369
- return false;
370
- }
371
- const at = Date.parse(state.last_engaged_at ?? '');
372
- return Number.isFinite(at) && nowMs - at < DUPLICATE_WINDOW_MS;
373
- }
374
-
375
- export interface NextStep {
376
- /** The step's own line, checkbox stripped, truncated for the message. */
377
- text: string;
378
- /** The step's `verify:` clause — command plus optional expectation. */
379
- verify: VerifyClause | null;
380
- }
381
-
382
- export interface ScanResult {
383
- /** Open (`- [ ]`) steps that are not `blocked-by:`-marked. */
384
- open: number;
385
- /** Open steps excluded because their line carries `blocked-by:`. */
386
- blocked: number;
387
- next: NextStep | null;
388
- }
389
-
390
- /**
391
- * Frontmatter `execution.mode`, or null. Line-oriented on purpose: the
392
- * frontmatter this repo writes is two levels deep at most, and a YAML parser
393
- * on the Stop path is a dependency this read does not need.
394
- */
395
- export function parseExecutionMode(text: string): string | null {
396
- if (!text.startsWith('---')) return null;
397
- const end = text.indexOf('\n---', 3);
398
- if (end === -1) return null;
399
- const fm = text.slice(0, end);
400
- if (!/^execution:\s*$/m.test(fm)) return null;
401
- const m = fm.match(/^\s+mode:\s*(\S+)\s*$/m);
402
- return m ? m[1]! : null;
403
- }
404
-
405
- /**
406
- * An OPEN step. The mark set is the dashboard's, narrowed to the one mark that
407
- * means "not done": `[~]` and `[-]` are parked by a human decision, and `[x]`
408
- * is finished. The BULLET set is the dashboard's in full, because a `*` bullet
409
- * is a legitimate authoring shape that used to read as zero open steps.
410
- */
411
- const OPEN_BOX = /^[ \t]*[-*][ \t]+\[ \][ \t]+(.*)$/;
412
-
413
- /**
414
- * Count open steps and pick the next one. `[~]` / `[-]` never match the open
415
- * pattern; a `blocked-by:` marker on the step's own line excludes it from
416
- * both the count and the pick (see the header for why).
417
- */
418
- export function scanOpenSteps(text: string): ScanResult {
419
- let open = 0;
420
- let blocked = 0;
421
- let next: NextStep | null = null;
422
- // Phase spans only. A `- [ ]` under `## Acceptance criteria`,
423
- // `## Blockers` or `## Risk Register` is a criterion, a gate or a risk
424
- // row — never an executable step, and re-engaging on one is a guaranteed
425
- // stall. See `_lib/roadmap_checkboxes.ts`.
426
- const lines = phaseLines(text);
427
- for (let i = 0; i < lines.length; i++) {
428
- const line = lines[i] as string;
429
- const m = OPEN_BOX.exec(line);
430
- if (!m) continue;
431
- // A step spans its own line plus the indented continuation lines under
432
- // it, and the `verify:` command is conventionally written on one of
433
- // those rather than inline. Gathered up to the next checkbox or
434
- // heading, so one step never absorbs the next one's verify line.
435
- const step: string[] = [line];
436
- for (let j = i + 1; j < lines.length; j++) {
437
- const cont = lines[j] as string;
438
- if (cont.trim() === '') break;
439
- if (/^[ \t]*[-*][ \t]+\[/.test(cont)) break;
440
- if (/^#{1,6}[ \t]/.test(cont)) break;
441
- if (!/^[ \t]/.test(cont)) break;
442
- step.push(cont);
443
- }
444
- const full = step.join('\n');
445
- const body = m[1] as string;
446
- if (BLOCKED_BY_MARKER.test(body)) {
447
- blocked += 1;
448
- continue;
449
- }
450
- open += 1;
451
- if (next === null) {
452
- next = {
453
- text: (() => {
454
- const cleaned = body
455
- .replace(/<!--.*?-->/g, '')
456
- .replace(/\s+/g, ' ')
457
- .trim();
458
- return cleaned.length > 240 ? `${cleaned.slice(0, 237)}...` : cleaned;
459
- })(),
460
- verify: extractVerify(full),
461
- };
462
- }
463
- }
464
- return { open, blocked, next };
465
- }
466
-
467
- /**
468
- * The step's `verify:` command, in either form the tree writes.
469
- *
470
- * R2 round 2, finding 10. Only the HTML-comment form was matched, and only on
471
- * the step's OWN line — while 18 roadmaps, including both this branch ships,
472
- * write the backticked form on a continuation line:
473
- *
474
- * - [ ] **1.0** do the thing
475
- * `verify:` `./scripts-run src/scripts/lint_thing`
476
- *
477
- * So the continuation named a next step and omitted the command that proves it
478
- * — and Risk 7 of the roadmap names exactly that command as its mitigation
479
- * against a re-engagement that cannot check its own work.
480
- *
481
- * The comment form wins when both are present: it is the machine-readable one,
482
- * and a step carrying both has a human-facing line and a tooling-facing line
483
- * rather than two commands.
484
- *
485
- * The hook's narrowing only — a prose clause is not a command, and the
486
- * continuation message renders commands. It parses nothing itself: a second
487
- * copy of the arrow grammar is how this hook and `closure_scan` would drift,
488
- * and a drifted grammar stops reading expectations without failing anything.
489
- * `_lib/verify_clause.ts` owns the grammar and the sweep that keeps it single.
490
- */
491
- export function extractVerify(stepText: string): VerifyClause | null {
492
- return commandBearing(stepText);
493
- }
494
-
495
- /**
496
- * Where a run's state lives: keyed on the session AND the roadmap.
497
- *
498
- * ## Round 6 keyed it on the session alone, and round 7 killed that
499
- *
500
- * Round 6 finding 2 observed that one session may re-claim, so a halt stamped on
501
- * roadmap A was inherited by a later claim of roadmap B. It fixed that by
502
- * recording the slug INSIDE the file and reading a mismatch as a fresh run —
503
- * declining to key the path on the slug because that "would have orphaned every
504
- * state file in existence".
505
- *
506
- * Round 7 findings 2 and 3 showed the in-file discriminator trades one defect for
507
- * two. The absent-roadmap branch never applied it, so it reported A's iteration
508
- * count under B's slug and deleted A's live state; and on the main path, nulling
509
- * `prev` on a mismatch means the next write OVERWRITES A's halt stamp — so a
510
- * halted roadmap became re-engageable with a full budget by the detour of
511
- * claiming something else once. "A halt must NOT clear it" was not durable.
512
- *
513
- * One file cannot hold two roadmaps' budgets, which is what both findings say from
514
- * opposite ends. So the path carries the slug, and the orphaning objection is
515
- * answered by MIGRATING rather than by avoiding: `readRunState` falls back to the
516
- * legacy per-session path when the keyed one is absent, and adopts it only when its
517
- * recorded roadmap is absent or equal. A live budget survives the upgrade; a
518
- * foreign one is not inherited.
519
- */
520
- export function stateRelPath(runId: string, slug: string): string {
521
- const safeRun = runId.replace(/[^A-Za-z0-9_-]/g, '_');
522
- const safeSlug = slug.replace(/[^A-Za-z0-9_-]/g, '_');
523
- return path.join(STATE_DIR_REL, `run-continuation-${safeRun}-${safeSlug}.json`);
524
- }
525
-
526
- /** The pre-round-7 path, read for migration and never written. */
527
- export function legacyStateRelPath(runId: string): string {
528
- const safe = runId.replace(/[^A-Za-z0-9_-]/g, '_');
529
- return path.join(STATE_DIR_REL, `run-continuation-${safe}.json`);
530
- }
531
-
532
- /**
533
- * This run's state, from the keyed path or — once, on migration — from the legacy
534
- * per-session one.
535
- *
536
- * Returns the state and the file it came from, because the caller has to know
537
- * whether it is looking at a keyed file (safe to delete) or a legacy one shared
538
- * with other roadmaps (never deleted; the keyed write supersedes it).
539
- */
540
- export function readRunState(
541
- workspaceRoot: string,
542
- runId: string,
543
- slug: string,
544
- ): { state: RunState | null; from: 'keyed' | 'legacy' | 'none'; keyedFile: string } {
545
- const keyedFile = path.join(workspaceRoot, stateRelPath(runId, slug));
546
- const keyed = readState(keyedFile);
547
- if (keyed !== null) return { state: keyed, from: 'keyed', keyedFile };
548
- if (fileExists(keyedFile)) {
549
- // Present but unreadable. NOT a migration case: adopting the legacy file
550
- // here would silently replace a corrupt budget with a foreign one.
551
- return { state: null, from: 'keyed', keyedFile };
552
- }
553
- const legacy = readState(path.join(workspaceRoot, legacyStateRelPath(runId)));
554
- if (legacy === null) return { state: null, from: 'none', keyedFile };
555
- // Adopted only when the legacy file is not another roadmap's.
556
- if (legacy.roadmap !== undefined && legacy.roadmap !== slug) {
557
- return { state: null, from: 'none', keyedFile };
558
- }
559
- return { state: legacy, from: 'legacy', keyedFile };
560
- }
561
-
562
- /**
563
- * The only writer of a run-state file. Never throws — the state is a budget, and
564
- * throwing here would turn an observability concern into a turn-end failure.
565
- *
566
- * RETURNS whether the write landed, and the return is load-bearing exactly once:
567
- * the engage path must not BLOCK on a counter it could not persist, because there
568
- * the ladder cannot bound the loop. Every other caller ignores it (fail-open).
569
- */
570
- function writeState(file: string, state: RunState): boolean {
571
- // ATOMIC (runtime-enforcement Phase 5.2): temp beside the target, then
572
- // rename. This file is the loop's ITERATION BUDGET — a torn direct write
573
- // leaves a record `parseRecord` rejects, the counter restarts at zero, and
574
- // the cap stops bounding anything. A non-atomic budget write fails as an
575
- // UNBOUNDED loop, which is what the budget exists to prevent.
576
- return atomicWriteJson(file, state);
577
- }
578
-
579
- /**
580
- * Clear a run's budget: the keyed file, and the legacy per-session file ONLY when
581
- * this read adopted it. Both halves are load-bearing.
582
- *
583
- * Touching the legacy file at all: `readRunState` adopts it for a migrated run, so
584
- * clearing only the keyed one made every clear a no-op there — `complete` stayed
585
- * resumable and the absent-confirm clear became a repeating cycle.
586
- *
587
- * Gating on `adoptedLegacy` rather than on the adoption predicate: adoption and
588
- * deletion want OPPOSITE defaults. A pre-round-7 file carries no `roadmap` field
589
- * and is therefore adoptable by every slug — right for adopting, catastrophic for
590
- * deleting, where one slug's clear would take another slug's live budget or halt
591
- * stamp with it. Adoption is a fact this read already established; it is passed in
592
- * rather than re-derived from a condition that cannot express it.
593
- */
594
- export function clearRunState(
595
- workspaceRoot: string,
596
- runId: string,
597
- keyedFile: string,
598
- adoptedLegacy: boolean,
599
- ): void {
600
- revokeBillingGrant(workspaceRoot, runId); // the run IS the grant's TTL
601
- try {
602
- fs.rmSync(keyedFile, { force: true });
603
- } catch {
604
- /* fail-open */
605
- }
606
- if (!adoptedLegacy) return;
607
- try {
608
- fs.rmSync(path.join(workspaceRoot, legacyStateRelPath(runId)), { force: true });
609
- } catch {
610
- /* fail-open */
611
- }
612
- }
613
-
614
- function fileExists(p: string): boolean {
615
- try {
616
- return fs.statSync(p).isFile();
617
- } catch {
618
- return false;
619
- }
620
- }
621
-
622
- function readState(file: string): RunState | null {
623
- try {
624
- const parsed: unknown = JSON.parse(fs.readFileSync(file, 'utf8'));
625
- if (parsed === null || typeof parsed !== 'object') return null;
626
- const o = parsed as Record<string, unknown>;
627
- if (typeof o['started_at'] !== 'string') return null;
628
- if (typeof o['iterations'] !== 'number') return null;
629
- if (typeof o['last_turn'] !== 'number') return null;
630
- if (!Array.isArray(o['history'])) return null;
631
- const rec: RunState = {
632
- started_at: o['started_at'],
633
- iterations: o['iterations'],
634
- last_turn: o['last_turn'],
635
- history: (o['history'] as unknown[]).filter(
636
- (n): n is number => typeof n === 'number',
637
- ),
638
- };
639
- if (typeof o['last_engaged_at'] === 'string') {
640
- rec.last_engaged_at = o['last_engaged_at'];
641
- }
642
- // Round-tripped, and it has to be: dropping it here would make the
643
- // source look changed on EVERY fire, reset the window every time, and
644
- // silently disable the stall detector the field was added to protect.
645
- if (typeof o['history_source'] === 'string') {
646
- rec.history_source = o['history_source'];
647
- }
648
- if (typeof o['roadmap'] === 'string') {
649
- rec.roadmap = o['roadmap'];
650
- }
651
- if (typeof o['absent_fires'] === 'number' && Number.isFinite(o['absent_fires'])) {
652
- rec.absent_fires = o['absent_fires'];
653
- }
654
- if (o['inert_reported'] === true) {
655
- rec.inert_reported = true;
656
- }
657
- // Round-tripped for the same reason `history_source` is: without this the
658
- // 8.1 hold is dead code that reads as shipped.
659
- const dlv = parseDeliveryState(o['delivery']);
660
- if (dlv !== undefined) rec.delivery = dlv;
661
- // Round-tripped for the same reason `history_source` is: dropped, the
662
- // premise would be re-recorded every fire from the newest observation, so
663
- // the two sides could never differ and the rung would be dead code.
664
- if (typeof o['context_fingerprint'] === 'string' && o['context_fingerprint'] !== '') {
665
- rec.context_fingerprint = o['context_fingerprint'];
666
- }
667
- // Tolerant, not permissive — see `parseHaltStamp` for what it accepts
668
- // beyond the halt set and why dropping a newer build's stamp was the
669
- // wrong failure direction for a budget.
670
- const halted = parseHaltStamp(o['halted']);
671
- if (halted !== null) rec.halted = halted;
672
- return rec;
673
- } catch {
674
- return null;
675
- }
676
- }
677
-
678
- /**
679
- * The six fields that make an event's two-tree property checkable by a third
680
- * party holding nothing but the ledger line. The caller adds a seventh,
681
- * `roadmap_path`, which it knows and this function does not.
682
- *
683
- * Keep this count in step with the file header and the call-site comment. Round 2
684
- * finding 4 caught the header saying four where the function emitted five; the
685
- * edit that fixed it added `session_cwd` and left THIS heading saying five, which
686
- * round 3 finding 3 then caught. Two rounds, same drift, opposite direction — the
687
- * count is load-bearing because it is what a later edit dropping a field would
688
- * have to contradict.
689
- *
690
- * The defect this concern shipped with was a writer and a reader resolving
691
- * DIFFERENT trees: `sessions:claim` wrote under `process.cwd()` (the operator's
692
- * worktree) while this concern read under `--project-dir` (the parent
693
- * checkout), so the claim was never found and no event was written. An empty
694
- * ledger looked exactly like a healthy idle run, which is how it survived a
695
- * release.
696
- *
697
- * A reader therefore has to see, from the line alone, which trees were in play
698
- * and where the contract was actually read out of. A boolean such as
699
- * `worktree_started: true` would be another assertion by the system under
700
- * observation rather than a check on it; the falsifiable facts are concrete
701
- * (AI council 2026-08-19, 2/2 convergent):
702
- *
703
- * `session_root !== workspace_root` → writer and reader resolved different
704
- * trees. After the fix this is the
705
- * NORMAL healthy two-tree arrangement,
706
- * not a defect: the claim now lives in
707
- * the shared root, so the line existing
708
- * at all with the two roots differing is
709
- * the fix working. Round 2 finding 7
710
- * caught the previous wording calling it
711
- * "the shipped defect condition", which
712
- * made a healthy engagement line read as
713
- * evidence of the bug
714
- * `git_dir !== git_common_dir` → the session's own tree IS a linked
715
- * worktree. Only meaningful when both
716
- * are non-empty — see the degenerate
717
- * reading below
718
- * `claim_path` under `git_common_dir` → the contract crossed into the shared
719
- * root. Also gated on a non-empty
720
- * `git_common_dir`: round 2 finding 2
721
- * measured that on a non-repo line both
722
- * git fields are `''` and every absolute
723
- * path satisfies `startsWith('')`, so a
724
- * reader applying the rule unguarded
725
- * concludes the contract crossed a
726
- * boundary the line says nothing about
727
- * `session_cwd` → the raw directory the session reported
728
- * before any resolution, so a reader can
729
- * tell "same tree" from "could not
730
- * resolve"
731
- *
732
- * ## The degenerate reading, stated so it cannot be mistaken for a negative
733
- *
734
- * Two of the three path relations above are only interpretable on a line whose
735
- * git fields are non-empty. Empty means git could not be read from the session's
736
- * root at all — a plain temp directory, a broken checkout — and that is an
737
- * ABSENCE of evidence rather than evidence of a same-root run. A reader must
738
- * check `git_common_dir !== ''` before applying either relation.
739
- *
740
- * `session_cwd` exists for the same reason, and it is a fact rather than an
741
- * assertion. `session_checkout` degrades to `workspace_root` when its guards
742
- * fail, and the raw `cwd` is what can make a degraded line distinguishable from a
743
- * genuine same-tree one. A boolean `resolved: false` would have been the system
744
- * under observation asserting its own health; the raw path is checkable.
745
- *
746
- * **The relation is SUFFICIENT, never necessary, and this file has now written it
747
- * as necessary three rounds running.** A `session_cwd` outside `session_root`
748
- * proves a fallback happened. The converse does not hold: round 4 finding 3 names
749
- * three reachable inputs where the resolver falls back and the raw cwd still sits
750
- * under `session_root` — a cwd inside a DIFFERENT repository nested under this
751
- * checkout (a vendored clone, a test fixture) failing the identity check, a cwd
752
- * that does not exist, and a relative cwd resolved against the reader's root. On
753
- * those lines the provenance cannot tell a reader that a fallback occurred, and
754
- * saying so is the honest bound rather than a wider claim that keeps being
755
- * refuted.
756
- *
757
- * **The degradation this field was introduced for is gone, and the field stayed.**
758
- * Round 2 added it because a session started from a SUBDIRECTORY of a worktree
759
- * failed the resolver's checkout-root condition and collapsed onto the reader's
760
- * root. Round 3 finding 2 then showed the field was BLIND to exactly that case in
761
- * the layout it mattered in: with the worktree nested under the parent, the
762
- * collapsed root, both git fields AND the raw cwd all read healthy same-tree.
763
- * The fix was upstream — `session_checkout` now walks up to the nearest enclosing
764
- * checkout root — so a subdirectory is no longer a degradation at all.
765
- *
766
- * What remains, and what the field is now for: a cwd inside a DIFFERENT
767
- * repository, a cwd that does not exist, a cwd under no checkout root at all.
768
- * Those still fall back, and on those lines `session_cwd` is still the only
769
- * thing that says so. Two cases pin both directions.
770
- *
771
- * ## Both git fields come from `session_root`, not from `workspace_root`
772
- *
773
- * The first shipped version of this function derived both of them from the
774
- * READER's root, and R2 finding 1 killed it: in the arrangement documented
775
- * three paragraphs up as the live one — the concern running under
776
- * `--project-dir <parent checkout>` — `git_dir(parent)` and
777
- * `git_common_dir(parent)` are the SAME path, so the discriminator above read
778
- * FALSE for every real worktree-started run. The enrichment existed to make
779
- * the two-tree property auditable and could not express it. `claim_path` could
780
- * not rescue it either: the claim lands under `git_common_dir` in a plain
781
- * checkout too, so that containment holds in both arrangements.
782
- *
783
- * `session_root` is the session's OWN checkout, resolved through the register's
784
- * `session_checkout` — the same three-condition guard (existing directory,
785
- * checkout root, same repository) rather than a second, divergent reading of
786
- * `payload.cwd`. It degrades to `workspace_root` when any condition fails,
787
- * which makes `session_root === workspace_root` mean "same tree, or unresolvable"
788
- * and never a false two-tree claim.
789
- *
790
- * `process.cwd()` is deliberately NOT among the fields. The dispatcher chdirs
791
- * into `--project-dir` before the chain runs, so at concern time cwd equals
792
- * `workspace_root` on every shipped path — a field that can never disagree with
793
- * another cannot falsify anything, and shipping it as provenance would be the
794
- * decorative-evidence shape this whole change exists to remove. Measured while
795
- * writing the test that asserted the opposite.
796
- *
797
- * Absolute AND realpath-normalised, deliberately: a relative form is
798
- * interpreted against whichever root the reader happens to hold, and a
799
- * symlinked form defeats the containment test above. R2 finding 3 measured the
800
- * second half — the git fields come back realpath-resolved from
801
- * `_lib/git_common_dir.ts` while the first version passed the envelope string
802
- * verbatim, so on macOS a healthy run wrote `workspace_root: /var/...` against
803
- * `git_common_dir: /private/var/...` and the documented prefix test failed on
804
- * it. Normalising here is the only place a ledger-only reader can inherit it
805
- * from. These are local filesystem paths in gitignored runtime state, never
806
- * published — the same posture the session register already takes.
807
- */
808
- function normalizeDir(p: string): string {
809
- const abs = path.resolve(p);
810
- try {
811
- return fs.realpathSync(abs);
812
- } catch {
813
- return abs;
814
- }
815
- }
816
-
817
- /**
818
- * Realpath a file path without requiring the file to exist: the directory is
819
- * normalised and the basename rejoined. The per-tree claim fallback names a
820
- * path that may not have been written, and a missing file must not downgrade
821
- * the whole line to un-normalised paths.
822
- */
823
- function normalizeFile(p: string): string {
824
- const abs = path.resolve(p);
825
- return path.join(normalizeDir(path.dirname(abs)), path.basename(abs));
826
- }
827
-
828
- export function provenance(
829
- workspaceRoot: string,
830
- claimPath: string,
831
- sessionRoot: string,
832
- sessionCwd: string,
833
- ): JsonObject {
834
- const reader = normalizeDir(workspaceRoot);
835
- const writer = normalizeDir(sessionRoot);
836
- return {
837
- workspace_root: reader,
838
- session_root: writer,
839
- // Empty when the host sent no `cwd` at all, which is a different fact
840
- // from a `cwd` that failed resolution — the first says the host is
841
- // silent, the second says the session sat somewhere `session_checkout`
842
- // would not trust. Both are readable; neither is guessed.
843
- //
844
- // Trimmed with the SAME rule `session_checkout` applies to the same
845
- // string (round 3 finding 6). Without it a whitespace-padded value
846
- // validated fine there and was `path.resolve`d here against the reader's
847
- // cwd, fabricating a path that is neither `session_root` nor under it —
848
- // precisely the shape the docblock above says no healthy resolution
849
- // produces, so a healthy line read as degraded. A whitespace-only value
850
- // now reads as host silence, which is what it is.
851
- session_cwd: sessionCwd.trim() === '' ? '' : normalizeDir(sessionCwd.trim()),
852
- git_dir: git_dir(writer) ?? '',
853
- git_common_dir: git_common_dir(writer) ?? '',
854
- claim_path: normalizeFile(claimPath),
855
- };
856
- }
857
-
858
- /**
859
- * The roadmap file this run is executing, chosen by which tree OWNS the
860
- * roadmaps directory — never by whether one particular file is present.
861
- *
862
- * ## The per-file fallback was wrong, and round 4 finding 1 named the cost
863
- *
864
- * The first version resolved per FILE: session copy if it exists, else the
865
- * reader's. That reads correctly in a fresh worktree and breaks a finished run.
866
- * `roadmap-progress-sync` mandates archival in the SAME change that closes the
867
- * last step, so a completing run `git mv`s the file into
868
- * `agents/roadmaps/archive/`. On the next stop fire the session copy is gone, the
869
- * per-file rule silently fell back to the parent's UN-archived copy, read its
870
- * still-open steps, and blocked with "continue with this step now" against a path
871
- * that no longer exists in the tree the agent is editing — re-engaging to the
872
- * iteration cap instead of ever reaching `complete`.
873
- *
874
- * Per DIRECTORY instead: if the session's tree has `agents/roadmaps/` at all,
875
- * that tree is authoritative and a missing slug file means the roadmap is gone
876
- * from this run — archived, renamed, or never created — which the caller's
877
- * unreadable-roadmap branch already handles correctly by allowing the turn to
878
- * end. The fallback survives for the case it was actually for: a session root
879
- * that is not a checkout of this project layout.
880
- *
881
- * ## Slug containment
882
- *
883
- * The slug comes from a claim file, and `_read_claim_file` accepts any non-empty
884
- * trimmed string. `claim_is_stale` in the same module treats containment as
885
- * necessary before any read; round 4 finding 7 observed that this function did
886
- * not, and that it now builds paths in TWO trees rather than one. A slug that
887
- * escapes `agents/roadmaps/` returns `null` and the caller allows — refusing to
888
- * name a file is the safe direction for a concern whose only power is refusing to
889
- * end a turn.
890
- */
891
- function resolveRoadmap(
892
- sessionRoot: string,
893
- workspaceRoot: string,
894
- slug: string,
895
- ): string | null {
896
- const dirRel = path.join('agents', 'roadmaps');
897
- // The SAME normalisation `claim_is_stale` applies to the same claim string
898
- // (round 5 finding 7). Without it a claim whose slug already carries the
899
- // suffix rendered as live work in the register while this concern resolved
900
- // `<slug>.md.md`, failed the read, and allowed every stop — two functions in
901
- // one flow disagreeing about one string.
902
- const stem = slug.trim().replace(/\.md$/, '');
903
- const rel = path.join(dirRel, `${stem}.md`);
904
- const norm = path.normalize(rel);
905
- // Containment on the STRUCTURE, not on the characters: `path.join` has already
906
- // collapsed traversal, so what matters is whether the result is still inside
907
- // the roadmaps directory and names a file directly in it. Round 5 finding 10:
908
- // a substring test for `..` also rejected a legitimate slug like
909
- // `road-to-a..b`, which then silently allowed every stop.
910
- if (path.dirname(norm) !== dirRel) return null;
911
- if (sessionRoot !== workspaceRoot && isDirectory(path.join(sessionRoot, dirRel))) {
912
- return path.join(sessionRoot, norm);
913
- }
914
- // Canonical, like every emitted path field (round 5 finding 9). The fallback
915
- // branch joined the RAW reader root while `workspace_root` on the same line is
916
- // normalised, so under a symlinked ancestor a reader's containment test failed
917
- // on a perfectly healthy line — the regression round 2 finding 3 fixed for the
918
- // other six fields, reintroduced on the seventh.
919
- return path.join(normalizeDir(workspaceRoot), norm);
920
- }
921
-
922
- function isDirectory(p: string): boolean {
923
- try {
924
- return fs.statSync(p).isDirectory();
925
- } catch {
926
- return false;
927
- }
928
- }
929
-
930
- /**
931
- * True when a line with this event name, run id and roadmap is already in the
932
- * ledger — the durable once-guard for the two rungs that cannot keep one in the
933
- * state file: `halt-roadmap-absent` fires precisely when the state is absent or
934
- * unparseable, and `blocked` CLEARS the state.
935
- */
936
- function eventAlreadyLogged(
937
- workspaceRoot: string,
938
- runId: string,
939
- slug: string,
940
- event: string,
941
- ): boolean {
942
- try {
943
- const file = path.join(workspaceRoot, EVENTS_RELPATH);
944
- const size = fs.statSync(file).size;
945
- const start = Math.max(0, size - LEDGER_TAIL_MAX_BYTES);
946
- const fd = fs.openSync(file, 'r');
947
- let text: string;
948
- try {
949
- const buf = Buffer.alloc(size - start);
950
- // The byte count is honoured: a short read, or a truncation between the
951
- // `statSync` and here, would otherwise decode NUL padding into lines that
952
- // fail `JSON.parse` and become a false negative.
953
- const read = fs.readSync(fd, buf, 0, buf.length, start);
954
- text = buf.subarray(0, read).toString('utf8');
955
- } finally {
956
- fs.closeSync(fd);
957
- }
958
- for (const line of text.split('\n')) {
959
- if (line === '') continue;
960
- let rec: unknown;
961
- try {
962
- rec = JSON.parse(line);
963
- } catch {
964
- // A partial first line from the tail cut, or a torn append.
965
- continue;
966
- }
967
- if (rec === null || typeof rec !== 'object') continue;
968
- const o = rec as Record<string, unknown>;
969
- if (o['event'] === event && o['run_id'] === runId && o['roadmap'] === slug) {
970
- return true;
971
- }
972
- }
973
- return false;
974
- } catch {
975
- // No ledger, or unreadable: nothing proves the line was written, and
976
- // emitting once more is the lesser failure than going silent on a rung this
977
- // whole file exists to make visible.
978
- return false;
979
- }
980
- }
981
-
982
- function appendEvent(workspaceRoot: string, record: JsonObject): void {
983
- try {
984
- const file = path.join(workspaceRoot, EVENTS_RELPATH);
985
- fs.mkdirSync(path.dirname(file), { recursive: true });
986
- fs.appendFileSync(file, `${JSON.stringify(record)}\n`, 'utf8');
987
- } catch {
988
- // The ledger is observability, never a reason to change the verdict.
989
- }
990
- }
991
-
992
- /**
993
- * True when `turn-end-gate` refused exactly this turn — the defer branch.
994
- * Race-free by chain order: concerns run sequentially and this concern is
995
- * registered after the gate, so the gate's marker for this turn is on disk
996
- * before this read happens.
997
- */
998
- export function refusedThisTurn(
999
- workspaceRoot: string,
1000
- sessionId: string,
1001
- turnOrdinal: number,
1002
- ): boolean {
1003
- try {
1004
- const file = sessionRefusalFile(workspaceRoot, deriveSessionKey(sessionId || 'unknown-session'));
1005
- const rec = parseRecord(fs.readFileSync(file, 'utf-8'));
1006
- return rec !== null && rec.refused_turn === turnOrdinal;
1007
- } catch {
1008
- return false;
1009
- }
1010
- }
1011
-
1012
- function str(v: JsonValue | undefined): string {
1013
- return typeof v === 'string' ? v : '';
1014
- }
1015
-
1016
- export function main(): number {
1017
- if (is_replay_mode()) return EXIT_ALLOW;
1018
- if (process.env['AGENT_CONFIG_NO_RUN_CONTINUATION'] === '1') return EXIT_ALLOW;
1019
-
1020
- let envelope: JsonObject;
1021
- let payload: JsonObject;
1022
- try {
1023
- [envelope, payload] = unwrap(readHookStdin(), 'claude');
1024
- } catch {
1025
- return EXIT_ALLOW;
1026
- }
1027
-
1028
- const workspaceRoot = str(envelope['workspace_root'] as JsonValue | undefined) || process.cwd();
1029
- const sessionId =
1030
- str(payload['session_id'] as JsonValue | undefined) ||
1031
- str(envelope['session_id'] as JsonValue | undefined);
1032
-
1033
- // ── contract gate ────────────────────────────────────────────────
1034
- const claim = resolve_claim(workspaceRoot, sessionId || null);
1035
- if (claim === null) return EXIT_ALLOW;
1036
- const slug = claim.slug;
1037
-
1038
- // ── which tree's roadmap is the run ──────────────────────────────
1039
- //
1040
- // The SESSION's own checkout, falling back to the reader's root. In a plain
1041
- // checkout the two are the same path and nothing about this changes; only
1042
- // the two-tree case moves.
1043
- //
1044
- // R2 round 3 finding 1: this read the READER's tree unconditionally, and the
1045
- // count it produces feeds the stall detector. In a worktree session the agent
1046
- // flips checkboxes in the worktree copy while the parent copy does not move
1047
- // until a merge — so the detector watched a file nobody was editing, the
1048
- // count never changed, and after three engagements it emitted `halt-stall`
1049
- // and declared a working run finished. The mechanism whose job is to detect a
1050
- // stall was manufacturing one, which is the failure this file's own header
1051
- // warns about in the abstract.
1052
- //
1053
- // AI council 2026-08-19, 2/2 convergent: resolve against the session
1054
- // checkout, keep the fallback. Both seats also flagged, independently, that
1055
- // `execution.mode` and the open-step count need not share an authority —
1056
- // progress is inherently session-local while a mode could be read as
1057
- // repo-wide policy. That choice is made HERE and stated rather than left
1058
- // implicit: BOTH come from the session's file, because the session is
1059
- // executing the file in its own tree and the parent's copy is simply an older
1060
- // revision of the same document. A genuinely repo-wide mode policy would need
1061
- // its own precedence rule, and inventing one on this evidence would be
1062
- // designing for a case nobody has met.
1063
- const sessionRoot = session_checkout(
1064
- workspaceRoot,
1065
- str(payload['cwd'] as JsonValue | undefined),
1066
- );
1067
- const roadmapPath = resolveRoadmap(sessionRoot, workspaceRoot, slug);
1068
- const runId = deriveSessionKey(sessionId || 'unknown-session');
1069
-
1070
- // Two locals rather than one plus a re-check: `roadmapFile` is only assigned
1071
- // where the read succeeded, so the guard below narrows BOTH and everything
1072
- // downstream holds a plain string. The alternative — re-testing `roadmapPath`
1073
- // after the guard purely for the compiler — would be a branch that cannot be
1074
- // reached and cannot be tested.
1075
- let roadmapFile: string | null = null;
1076
- let roadmapText: string | null = null;
1077
- if (roadmapPath !== null) {
1078
- try {
1079
- roadmapText = fs.readFileSync(roadmapPath, 'utf8');
1080
- roadmapFile = roadmapPath;
1081
- } catch {
1082
- roadmapText = null;
1083
- }
1084
- }
1085
-
1086
- if (roadmapText === null || roadmapFile === null) {
1087
- // ── the roadmap is not readable from the authoritative tree ──────
1088
- //
1089
- // Round 5 findings 2, 5 and 10, which are one shape seen three ways: this
1090
- // returned a bare `EXIT_ALLOW` and left NOTHING behind.
1091
- //
1092
- // Finding 2 is the sharp end. `roadmap-progress-sync` mandates archival in
1093
- // the same change that closes the last step, so a completing run flips the
1094
- // last box and `git mv`s the file in one reply. The next fire found it
1095
- // gone, allowed, and never reached the `complete` rung — so no line said
1096
- // the run finished, AND `fs.rmSync(stateFile)` never ran. The state file
1097
- // survived with `iterations` and `started_at` from the finished run, so a
1098
- // later claim by the same session id began with part of the 25-iteration
1099
- // budget spent and the 4 h clock already running — exactly what the
1100
- // comment on that rung promises will not happen.
1101
- //
1102
- // A prior state file is the discriminator, and it is a fact rather than a
1103
- // guess: the state only exists if THIS concern engaged on this roadmap
1104
- // before, which it only does on an `autonomous` one. So:
1105
- //
1106
- // state present → this run was driven here and its roadmap is gone. Emit
1107
- // the line, clear the budget, allow.
1108
- // state absent → nothing was ever driven. Stay silent, which is the
1109
- // truth rather than a gap: a `phase-checkpoints` claim
1110
- // and a worktree branched before the roadmap landed
1111
- // (finding 5) both land here, and neither is an event.
1112
- //
1113
- // What this does NOT claim is to tell archival from never-created. The
1114
- // filesystem cannot: both are an absent file. The docblock on
1115
- // `resolveRoadmap` used to assert the archival reading, and finding 5 was
1116
- // right that it conflated the two — so the reading is now carried by the
1117
- // state file, which actually knows.
1118
- // Read THIS roadmap's state, keyed (round 7 finding 2). The previous version
1119
- // read the session-keyed file with no roadmap discriminator, so after a
1120
- // re-claim it reported roadmap A's iteration count under roadmap B's slug
1121
- // and deleted A's live state — falsifying its own documented premise that
1122
- // "state only exists if this concern engaged on THIS roadmap before".
1123
- const runState = readRunState(workspaceRoot, runId, slug);
1124
- const driven = runState.state;
1125
- if (driven === null && runState.from === 'none') return EXIT_ALLOW;
1126
-
1127
- // A HALT STAMP IS NEVER ERASED HERE (round 6 finding 1, high).
1128
- //
1129
- // A halted run has already recorded its own end, so there is nothing to
1130
- // announce and nothing to reclaim. Silence and no write is the whole
1131
- // correct action.
1132
- if (driven?.halted !== undefined) return EXIT_ALLOW;
1133
- const absenceRoots = provenance(
1134
- workspaceRoot,
1135
- claim.path,
1136
- sessionRoot,
1137
- str(payload['cwd'] as JsonValue | undefined),
1138
- );
1139
- // `null` where a traversal or malformed slug refused to name a file at
1140
- // all (finding 10): the line still exists, so a refusal is no longer
1141
- // indistinguishable from the concern never firing.
1142
- absenceRoots['roadmap_path'] = roadmapPath;
1143
-
1144
- // ── ONE absence is not a finished run (round 7 findings 1 and 4) ──
1145
- //
1146
- // Round 6 stopped this branch erasing a HALTED run's stamp and left the
1147
- // larger half open: a run with a LIVE budget still had its state deleted on
1148
- // a single unreadable fire. The triggers are ordinary — the agent checks out
1149
- // a ref without the roadmap, a tool rewrites the file unlink-then-write, an
1150
- // EACCES lands on the stop fire — and the consequence is unbounded: iteration
1151
- // 20 becomes iteration 1 with a fresh 4 h clock, repeatable every time.
1152
- //
1153
- // Archival and a momentary read failure are indistinguishable from ONE fire.
1154
- // They are not indistinguishable across two: a rewrite window is
1155
- // sub-second, while an archived roadmap stays archived across turns. So the
1156
- // absence is counted, the ledger line is written ONCE (on the first), and
1157
- // the budget is reclaimed only after the absence has persisted.
1158
- //
1159
- // A state file that exists but cannot be parsed is never deleted here
1160
- // (round 7 finding 4): the counter has nowhere to live, and deleting what we
1161
- // could not read would erase an interrupted halt stamp — the exact leak the
1162
- // presence check was added to close. The next healthy write supersedes it.
1163
- const absentFires = (driven?.absent_fires ?? 0) + 1;
1164
- // A readable state carries the counter; without one it has nowhere to live
1165
- // and would recompute to 1 every fire, so the ledger answers instead.
1166
- const firstAbsence =
1167
- driven === null
1168
- ? !eventAlreadyLogged(workspaceRoot, runId, slug, 'halt-roadmap-absent')
1169
- : absentFires === 1;
1170
- if (firstAbsence) {
1171
- appendEvent(workspaceRoot, {
1172
- event: 'halt-roadmap-absent',
1173
- run_id: runId,
1174
- roadmap: slug,
1175
- // `null` when the state file exists but could not be parsed.
1176
- // Reported as null rather than as 0, which would claim a fact the
1177
- // file no longer carries.
1178
- iterations: driven?.iterations ?? null,
1179
- absent_fires: driven === null ? null : absentFires,
1180
- at: new Date().toISOString(),
1181
- ...absenceRoots,
1182
- });
1183
- }
1184
- if (driven === null) return EXIT_ALLOW;
1185
- if (absentFires < ABSENT_CONFIRM_FIRES) {
1186
- driven.absent_fires = absentFires;
1187
- writeState(runState.keyedFile, driven);
1188
- return EXIT_ALLOW;
1189
- }
1190
- // Confirmed — see `clearRunState` for why the legacy file is in scope and
1191
- // why only an adopted one is.
1192
- clearRunState(workspaceRoot, runId, runState.keyedFile, runState.from === 'legacy');
1193
- return EXIT_ALLOW;
1194
- }
1195
- if (parseExecutionMode(roadmapText) !== 'autonomous') return EXIT_ALLOW;
1196
-
1197
- // ── turn identity ────────────────────────────────────────────────
1198
- const transcriptPath = str(
1199
- (payload['transcript_path'] ?? payload['transcriptPath']) as JsonValue | undefined,
1200
- );
1201
- if (!transcriptPath) return EXIT_ALLOW;
1202
- // Over the shared cap, `readTranscriptTail` returns `turnOrdinal: 0`
1203
- // without throwing — indistinguishable from a genuinely fresh session. The
1204
- // ordinal is the ONLY key the defer-to-the-gate check has, so an untrusted
1205
- // one must not be used to decide a block: allow instead.
1206
- //
1207
- // This is the residual half of R2 round 2's finding 1. Sharing the cap
1208
- // stops the two hooks disagreeing about the SAME transcript; this stops
1209
- // this concern acting on an ordinal neither of them could compute. Erring
1210
- // toward allow is the same fail-open posture the gate takes on every
1211
- // unreadable-transcript case.
1212
- try {
1213
- if (fs.statSync(transcriptPath).size > TRANSCRIPT_READ_MAX_BYTES) {
1214
- // Round 7 finding 5: this returned ALLOW with no event and no state
1215
- // change, so in the long-run regime this concern exists for — a 4 h cap
1216
- // — a session whose transcript crosses the cap went silently inert for
1217
- // the rest of the run while its budget stayed live. An inert mechanism
1218
- // indistinguishable in the ledger from a healthy idle run is the exact
1219
- // failure this whole roadmap is about, and the header claims every rung
1220
- // is a named event.
1221
- //
1222
- // Emitted ONCE per run, keyed on the state, so a long inert tail does
1223
- // not become a long stream of identical lines. No state file means no
1224
- // run to report on — the same silence the contract-absent rung takes.
1225
- const inert = readRunState(workspaceRoot, runId, slug);
1226
- if (inert.state !== null && inert.state.inert_reported !== true) {
1227
- // The header declares the provenance mandatory for EVERY event, and
1228
- // a rung that exists to be distinguishable in the ledger is the last
1229
- // one that should lack the fields a reader distinguishes runs by.
1230
- const inertRoots = provenance(
1231
- workspaceRoot,
1232
- claim.path,
1233
- sessionRoot,
1234
- str(payload['cwd'] as JsonValue | undefined),
1235
- );
1236
- inertRoots['roadmap_path'] = roadmapFile;
1237
- appendEvent(workspaceRoot, {
1238
- event: 'inert-transcript-over-cap',
1239
- run_id: runId,
1240
- roadmap: slug,
1241
- iterations: inert.state.iterations,
1242
- at: new Date().toISOString(),
1243
- ...inertRoots,
1244
- });
1245
- inert.state.inert_reported = true;
1246
- writeState(inert.keyedFile, inert.state);
1247
- }
1248
- return EXIT_ALLOW;
1249
- }
1250
- } catch {
1251
- return EXIT_ALLOW;
1252
- }
1253
- let turnOrdinal = 0;
1254
- try {
1255
- turnOrdinal = readTranscriptTail(transcriptPath, {
1256
- maxBytes: TRANSCRIPT_READ_MAX_BYTES,
1257
- }).turnOrdinal;
1258
- } catch {
1259
- return EXIT_ALLOW;
1260
- }
1261
-
1262
- // The two-tree provenance, carried on every event this run emits. See
1263
- // `provenance()` for the six fields and why none of them is a boolean.
1264
- //
1265
- // Position, and what changed about the cost argument. Rounds 1 and 2 pushed
1266
- // this call downward to stop a `phase-checkpoints` session, and then a
1267
- // session with an over-cap transcript, from paying the git resolution for a
1268
- // value the next line discarded.
1269
- //
1270
- // Round 3 finding 1 made half of that moot: the session root is now needed
1271
- // ABOVE the mode gate, because it decides which tree's roadmap the mode is
1272
- // read from. So the resolution happens early by necessity and this call
1273
- // merely reuses it — the double resolution round 2 finding 5 accepted is
1274
- // gone as a side effect, and nothing here re-derives it.
1275
- //
1276
- // What remains true, and round 3 finding 5 was right to catch the previous
1277
- // comment claiming otherwise: two branches below still return without an
1278
- // `appendEvent` — the duplicate-stop-fire guard and the failed-state-write
1279
- // path — so this is not a position where every path writes a line. It is
1280
- // simply the cheapest honest one now that the value is already in hand.
1281
- //
1282
- // The git resolution here duplicates the one `session_checkout` does to
1283
- // validate the cwd, and that duplication is ACCEPTED rather than removed
1284
- // (round 2 finding 5): collapsing it means widening a register API that
1285
- // other callers use, to save six syscalls on a path that has already read a
1286
- // roadmap file and a transcript tail. The two resolutions also answer
1287
- // different questions — the guard asks whether the cwd belongs to this
1288
- // repository, this asks what the session's own tree is.
1289
- const roots = provenance(
1290
- workspaceRoot,
1291
- claim.path,
1292
- sessionRoot,
1293
- str(payload['cwd'] as JsonValue | undefined),
1294
- );
1295
- // Round 4 finding 4: the line carried six path fields and not the one path
1296
- // the only tree-dependent NUMBER on it came from. On a line with
1297
- // `session_root !== workspace_root` and `open: 2`, a reader could not tell
1298
- // whether the count came from the session copy (the fix working) or from the
1299
- // reader's after a fallback (the defect still live) — the exact ambiguity the
1300
- // other six fields exist to remove.
1301
- roots['roadmap_path'] = roadmapFile;
1302
-
1303
- // ── defer to the quality gate ────────────────────────────────────
1304
- if (refusedThisTurn(workspaceRoot, sessionId, turnOrdinal)) {
1305
- appendEvent(workspaceRoot, {
1306
- event: 'deferred-quality-gate',
1307
- run_id: runId,
1308
- roadmap: slug,
1309
- turn: turnOrdinal,
1310
- at: new Date().toISOString(),
1311
- ...roots,
1312
- });
1313
- return EXIT_ALLOW;
1314
- }
1315
-
1316
- // ── state + duplicate-fire detection ─────────────────────────────
1317
- //
1318
- // A state file recorded against a DIFFERENT roadmap is not this run's state —
1319
- // round 6 finding 2. The file is keyed on the session id alone and one session
1320
- // may re-claim, so a halt stamped on roadmap A (never cleared: only `complete`
1321
- // unlinks) was inherited by a later claim of roadmap B, which then emitted a
1322
- // halt line naming B without ever engaging and reported A's iteration count
1323
- // under B's slug. An absent `roadmap` field is trusted rather than discarded:
1324
- // it means the state predates this field, and dropping a live budget on an
1325
- // upgrade would be the worse error.
1326
- // Keyed on (session, roadmap), with the legacy per-session file migrated once —
1327
- // see `readRunState`. The in-file `roadmap` guard round 6 added is gone as a
1328
- // BRANCH: it is now an identity, so a mismatch cannot reach this code at all,
1329
- // and round 7 finding 3's "a mismatch nulls prev, so the next write overwrites
1330
- // the other roadmap's halt stamp" has no path left.
1331
- const mainState = readRunState(workspaceRoot, runId, slug);
1332
- const stateFile = mainState.keyedFile;
1333
- const prev = mainState.state;
1334
- const state: RunState = prev ?? {
1335
- started_at: new Date().toISOString(),
1336
- iterations: 0,
1337
- last_turn: -1,
1338
- history: [],
1339
- roadmap: slug,
1340
- };
1341
- // Stamped on an inherited state too, so the field fills in on first contact
1342
- // rather than staying absent for the life of the run.
1343
- state.roadmap = slug;
1344
- // The reset the field's docblock promises. Reaching this line means the
1345
- // roadmap read succeeded (the absent branch returns above), and the engage and
1346
- // halt paths write THIS object back — so without the delete the counter is a
1347
- // lifetime total and two separated absences reclaim a live budget.
1348
- delete state.absent_fires;
1349
-
1350
- const scan = scanOpenSteps(roadmapText);
1351
-
1352
- // A duplicate stop fire repeats the SAME verdict without consuming an
1353
- // iteration. It must repeat the BLOCK: this concern just blocked this
1354
- // very stop, and an allow on the re-fire would end the reply the block
1355
- // exists to continue. (An earlier draft allowed here — the smoke run
1356
- // caught it ending the run it had re-engaged one event earlier.)
1357
- if (isDuplicateFire(prev, turnOrdinal, scan.open, Date.now(), roadmapFile)) {
1358
- process.stderr.write(_continuationText(slug, scan, state.iterations));
1359
- return EXIT_BLOCK;
1360
- }
1361
-
1362
- // The source-change reset runs HERE, before the ladder reads the history —
1363
- // round 5 finding 1. It used to sit inside the engage branch, which is after
1364
- // `ladder()` and after the non-engage branch returns, so on the ONE fire where
1365
- // the source document changes the stall test still compared counts from two
1366
- // different files. Three parent-copy readings at `open: 4` followed by a
1367
- // session copy that also reads 4 produced `halt-stall` on the parent's numbers
1368
- // and declared a working run finished — the precise failure the field's own
1369
- // docblock claims to prevent, defeated by where the guard sat.
1370
- if (state.history_source !== roadmapFile) {
1371
- state.history = [];
1372
- state.history_source = roadmapFile;
1373
- }
1374
-
1375
- // Phase 5.4 — a dependency the run cannot obtain. Read from the transcript
1376
- // TAIL only: an authentication failure from an hour ago that was then fixed
1377
- // must not halt the run now. A read failure is `null` (fail-open), because a
1378
- // detector that cannot read must not manufacture a halt.
1379
- const unavailable = readUnavailableDependency(transcriptPath);
1380
-
1381
- // Phase 6.6 — the stall signal, WRITTEN rather than re-derived. A consumer
1382
- // asking "is this run still making progress" had to reconstruct it from the
1383
- // history array and the window constant, so every reader could answer
1384
- // differently. One producer, one definition.
1385
- state.stall = stallSignal(state.history, STALL_WINDOW).level;
1386
-
1387
- // 2.1 — repository drift, from the newest observation `roadmap:context`
1388
- // recorded. No probe here: the fingerprint costs a `gh` call and this is the
1389
- // Stop path. An unknown on either side is never a halt.
1390
- const observed = readContextObservation(workspaceRoot)?.fingerprint ?? null;
1391
- const premiseInvalidated = premiseMoved(state.context_fingerprint, observed);
1392
-
1393
- const delivery = parseDeliveryState(state.delivery) ?? null;
1394
- const action = ladder(
1395
- state, scan.open, Date.now(),
1396
- scan.blocked,
1397
- undefined,
1398
- unavailable,
1399
- premiseInvalidated,
1400
- delivery,
1401
- );
1402
-
1403
- if (action !== 'engage') {
1404
- // A run that is ALREADY stamped emits nothing further — round 6 finding 6.
1405
- // Once `halted` is set the state file is immortal for the session (only
1406
- // `complete` unlinks it), so every later stop fire re-entered this branch
1407
- // and appended another line with the same `run_id` and `iterations`: an
1408
- // unbounded number of duplicate halt records in the ledger the acceptance
1409
- // criteria's counts are derived from. The FIRST halt is the event; the rest
1410
- // are the same fact re-stated.
1411
- const alreadyStamped = prev?.halted !== undefined;
1412
- // `blocked` can use neither `halted` (not in `HALT_ACTIONS`, by ADR-235) nor
1413
- // a state field (the state is cleared below). The ledger survives both.
1414
- const alreadyBlocked =
1415
- action === 'blocked' && eventAlreadyLogged(workspaceRoot, runId, slug, 'blocked');
1416
- if (!alreadyStamped && !alreadyBlocked) {
1417
- const line = buildLedgerEvent(
1418
- { action, runId, slug, turn: turnOrdinal, iterations: state.iterations,
1419
- open: scan.open, blocked: scan.blocked, delivery },
1420
- RUN_TERMINAL_VOCABULARY_VERSION,
1421
- new Date(),
1422
- );
1423
- appendEvent(workspaceRoot, { ...line, ...roots } as JsonObject);
1424
- }
1425
- if (action === 'complete') {
1426
- // Only a COMPLETION clears the state, so a later run on the same
1427
- // roadmap (post-merge follow-up, re-claim) starts a fresh budget.
1428
- // A halt must NOT clear it — see `RunState.halted`.
1429
- clearRunState(workspaceRoot, runId, stateFile, mainState.from === 'legacy');
1430
- return EXIT_ALLOW;
1431
- }
1432
- if (action === 'blocked') {
1433
- // CLEARED, like `complete`, and `runId` is why: it is
1434
- // `deriveSessionKey(sessionId)` — a SESSION hash — so this same session
1435
- // re-claiming this same roadmap reuses this same keyed file. Keeping the
1436
- // state would hand the next run a spent budget, and since the ladder
1437
- // tests `blocked` BEFORE the iteration cap, an unblocked roadmap could go
1438
- // straight to `halt-max-iterations` without ever engaging.
1439
- //
1440
- // Safe only because the once-guard is the LEDGER: the next fire builds a
1441
- // fresh state, reaches `blocked`, finds the line and stays silent.
1442
- clearRunState(workspaceRoot, runId, stateFile, mainState.from === 'legacy');
1443
- return EXIT_ALLOW;
1444
- }
1445
- // A halt is recorded in place. A failed write is fail-open in the safe
1446
- // direction here: the rung already decided to allow this stop, and the
1447
- // worst case of a lost stamp is the pre-fix behaviour, never a block.
1448
- if (!state.halted) {
1449
- state.halted = action;
1450
- writeState(stateFile, state);
1451
- }
1452
- return EXIT_ALLOW;
1453
- }
1454
-
1455
- state.iterations += 1;
1456
- state.last_turn = turnOrdinal;
1457
- // Recorded ONCE — the premise this run engaged under. See the field's docblock.
1458
- if (state.context_fingerprint === undefined && observed !== null) {
1459
- state.context_fingerprint = observed;
1460
- }
1461
- state.history.push(scan.open);
1462
- state.last_engaged_at = new Date().toISOString();
1463
- if (!writeState(stateFile, state)) {
1464
- // If the counter cannot persist, the ladder cannot bound the loop —
1465
- // so the loop must not run. Allowing here is the fail-open posture
1466
- // applied to the ONE branch where a lost write means an unbounded
1467
- // re-engagement rather than a missed one.
1468
- return EXIT_ALLOW;
1469
- }
1470
-
1471
- appendEvent(workspaceRoot, {
1472
- event: 'engage',
1473
- run_id: runId,
1474
- roadmap: slug,
1475
- turn: turnOrdinal,
1476
- iteration: state.iterations,
1477
- open: scan.open,
1478
- blocked: scan.blocked,
1479
- at: new Date().toISOString(),
1480
- ...roots,
1481
- });
1482
-
1483
- process.stderr.write(_continuationText(slug, scan, state.iterations));
1484
- return EXIT_BLOCK;
1485
- }
1486
-
1487
- function _continuationText(slug: string, scan: ScanResult, iteration: number): string {
1488
- const stepLine = scan.next
1489
- ? `Next step: ${scan.next.text}${renderVerifyLine(scan.next.verify)}`
1490
- : 'Next step: (first open checkbox in the roadmap)';
1491
- return (
1492
- `run-continuation: the contracted roadmap \`${slug}\` has ${scan.open} open ` +
1493
- `step${scan.open === 1 ? '' : 's'}` +
1494
- (scan.blocked > 0 ? ` (+${scan.blocked} blocked-by, not yours this run)` : '') +
1495
- ` — iteration ${iteration}/${MAX_ITERATIONS}.\n` +
1496
- `${stepLine}\n` +
1497
- 'Continue with this step now: do the work, run its verify line, flip ' +
1498
- 'the box, then end the turn. Escalate instead of continuing ONLY for a ' +
1499
- 'locked decision class (high_impact / user_required) or a halt your ' +
1500
- 'contract names.\n'
1501
- );
1502
- }
1503
-
1504
- // Bundle-safety: never auto-run when inlined into an esbuild bundle.
1505
- declare const __AGENT_CONFIG_BUNDLE__: boolean | undefined;
1506
- function _isCliEntry(): boolean {
1507
- if (typeof __AGENT_CONFIG_BUNDLE__ !== 'undefined' && __AGENT_CONFIG_BUNDLE__) {
1508
- return false;
1509
- }
1510
- if (process.argv[1] === undefined) return false;
1511
- const argvUrl = pathToFileURL(path.resolve(process.argv[1])).href;
1512
- if (import.meta.url === argvUrl) return true;
1513
- try {
1514
- const here = fs.realpathSync(fileURLToPath(import.meta.url));
1515
- const argv = fs.realpathSync(path.resolve(process.argv[1]));
1516
- return here === argv;
1517
- } catch {
1518
- return false;
1519
- }
1520
- }
1521
-
1522
- if (_isCliEntry()) {
1523
- process.exit(main());
1524
- }