@iowarp/clio-coder 0.3.0 → 0.3.1

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 (988) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/README.md +50 -53
  3. package/dist/acp-FPR54DGL.js +138 -0
  4. package/dist/{agents-Q4MYPMUW.js → agents-OGPIHPJH.js} +33 -25
  5. package/dist/assets/codewiki.json +1 -0
  6. package/dist/assets/grammars/notices/@vscode__tree-sitter-wasm/LICENSE +21 -0
  7. package/dist/assets/grammars/notices/@vscode__tree-sitter-wasm/cgmanifest.json +16 -0
  8. package/dist/assets/grammars/notices/tree-sitter-wasms/LICENSE +24 -0
  9. package/dist/assets/grammars/tree-sitter-c-sharp.wasm +0 -0
  10. package/dist/assets/grammars/tree-sitter-c.wasm +0 -0
  11. package/dist/assets/grammars/tree-sitter-cpp.wasm +0 -0
  12. package/dist/assets/grammars/tree-sitter-go.wasm +0 -0
  13. package/dist/assets/grammars/tree-sitter-java.wasm +0 -0
  14. package/dist/assets/grammars/tree-sitter-javascript.wasm +0 -0
  15. package/dist/assets/grammars/tree-sitter-python.wasm +0 -0
  16. package/dist/assets/grammars/tree-sitter-ruby.wasm +0 -0
  17. package/dist/assets/grammars/tree-sitter-rust.wasm +0 -0
  18. package/dist/assets/grammars/tree-sitter-tsx.wasm +0 -0
  19. package/dist/assets/grammars/tree-sitter-typescript.wasm +0 -0
  20. package/dist/assets/grammars/tree-sitter.wasm +0 -0
  21. package/dist/{auth-O6HYIJ6J.js → auth-IC3K6NIZ.js} +22 -15
  22. package/dist/{chunk-KKKPTZLM.js → chunk-2STGEDFV.js} +8 -1
  23. package/dist/chunk-3I7MS7N2.js +40 -0
  24. package/dist/chunk-3R73A4XB.js +69 -0
  25. package/dist/{chunk-26BZQOAD.js → chunk-474KN5II.js} +86 -115
  26. package/dist/{chunk-NI4DEJMC.js → chunk-4QKXUHSR.js} +26 -3
  27. package/dist/{chunk-X3BR7HWV.js → chunk-5WIGXA4T.js} +7 -1
  28. package/dist/{chunk-TFSSEXL6.js → chunk-673JJUWJ.js} +14 -4
  29. package/dist/{chunk-GNGDQYDU.js → chunk-7SS2CTV2.js} +27922 -1249
  30. package/dist/{chunk-7RBKDI66.js → chunk-ASND7OZK.js} +104 -12
  31. package/dist/{chunk-X3NE4WVW.js → chunk-BNAZZHFG.js} +7 -1
  32. package/dist/{chunk-RQDWMVRB.js → chunk-BSU2YIWB.js} +9 -3
  33. package/dist/{chunk-CLJ5HLUD.js → chunk-C4PTHK7P.js} +24 -5
  34. package/dist/{chunk-QV47YRF4.js → chunk-CGKSTWHD.js} +7 -1
  35. package/dist/{chunk-BYEU76JP.js → chunk-DKGKUHFA.js} +34 -9
  36. package/dist/chunk-EYOKLTMF.js +170 -0
  37. package/dist/{chunk-PS4PFJQP.js → chunk-FCIH3BIZ.js} +15258 -14130
  38. package/dist/{chunk-2J63S4SF.js → chunk-FST4FYJB.js} +82 -14
  39. package/dist/{chunk-3DANZDGR.js → chunk-G34LV2PF.js} +34 -9
  40. package/dist/{chunk-BBUH4VAA.js → chunk-GAEBEQVI.js} +34 -21
  41. package/dist/chunk-GB6QRBXN.js +8543 -0
  42. package/dist/chunk-GEP36Y4X.js +12796 -0
  43. package/dist/{chunk-TKHQ4DGZ.js → chunk-H6F6BYOH.js} +496 -121
  44. package/dist/{chunk-UGYAX5YI.js → chunk-HQQID6OA.js} +10 -5
  45. package/dist/chunk-IHXBNWMM.js +137 -0
  46. package/dist/{chunk-ME6DNWIU.js → chunk-IS3ONKU3.js} +7 -1
  47. package/dist/{chunk-DXQNI4PC.js → chunk-IWHMRKLL.js} +8 -1
  48. package/dist/chunk-K2ITRMHZ.js +642 -0
  49. package/dist/{chunk-KBR4MZZR.js → chunk-K5XEMXTI.js} +7 -1
  50. package/dist/{chunk-AMFR5YA3.js → chunk-KKNLWXI6.js} +24 -10
  51. package/dist/{chunk-JWHCJDCI.js → chunk-KY56HMHH.js} +145 -61
  52. package/dist/{chunk-E3NYWENM.js → chunk-LU4TK2PR.js} +52 -7
  53. package/dist/{chunk-UWIJNAOB.js → chunk-M5T5VO65.js} +109 -42
  54. package/dist/{chunk-JPOWPFCU.js → chunk-MAR7Y6HW.js} +38 -16
  55. package/dist/chunk-N6F52NLF.js +6951 -0
  56. package/dist/{chunk-UHTSULZS.js → chunk-NMOX6HFD.js} +20 -7
  57. package/dist/{chunk-WD6AJM35.js → chunk-OLBBMFRD.js} +30 -13
  58. package/dist/{chunk-VOO7NYPP.js → chunk-PFEFKVGL.js} +22 -6
  59. package/dist/{chunk-6CWDTGUC.js → chunk-PIUMUEMV.js} +7 -1
  60. package/dist/chunk-PV4JUBVJ.js +462 -0
  61. package/dist/{chunk-527KG6XR.js → chunk-Q3RUPKEJ.js} +22 -4
  62. package/dist/{chunk-D5YD55AR.js → chunk-Q5WJOSJ7.js} +11 -1
  63. package/dist/{chunk-5N2FG33Q.js → chunk-R346GLFC.js} +7 -1
  64. package/dist/{chunk-4UQA7NCT.js → chunk-R5KLMSBV.js} +7 -2
  65. package/dist/{chunk-PIDUD6M2.js → chunk-RDLVBZEO.js} +11 -6
  66. package/dist/{chunk-O4EJEDHO.js → chunk-RPTR2H26.js} +40 -31
  67. package/dist/{chunk-HBU5MTAM.js → chunk-SVNXH4L2.js} +7 -1
  68. package/dist/{chunk-XNISANGE.js → chunk-TEKV33Q5.js} +122 -57
  69. package/dist/chunk-TXOTCRLG.js +15 -0
  70. package/dist/{chunk-VPAWTYLY.js → chunk-WEPFGWHJ.js} +7 -1
  71. package/dist/{chunk-HMYNFFY4.js → chunk-XPLRXC72.js} +7 -2
  72. package/dist/{chunk-UU3R62TT.js → chunk-XYWBQRDM.js} +13 -4
  73. package/dist/{chunk-7BHLZB3A.js → chunk-ZPY3JZ5E.js} +32 -10
  74. package/dist/cli/index.js +39 -33
  75. package/dist/clio-BZVGEUFJ.js +58 -0
  76. package/dist/{components-JVHMUBEB.js → components-DMAOEKFB.js} +26 -9
  77. package/dist/{config-ZFCDBMDC.js → config-IRUQ7SE4.js} +42 -31
  78. package/dist/configure-S7S6F6CL.js +32 -0
  79. package/dist/{context-CDXTP2MP.js → context-3KWFLHJG.js} +17 -11
  80. package/dist/{context-E3KIFVXI.js → context-5RADCKTR.js} +33 -28
  81. package/dist/{context-clear-3F4PLXOS.js → context-clear-7TSNPAAI.js} +36 -28
  82. package/dist/{context-index-Q7YSYTR3.js → context-index-W4RLWOQH.js} +10 -4
  83. package/dist/{docs-YIETIWZI.js → docs-5AWSPS37.js} +16 -10
  84. package/dist/doctor-UC5NAJYQ.js +77 -0
  85. package/dist/{eval-B3KZZESM.js → eval-U6TJHRLX.js} +77 -24
  86. package/dist/{evidence-V67CHM35.js → evidence-YEGUW4L3.js} +34 -26
  87. package/dist/{evolve-YDZSUQYA.js → evolve-TXARCTPG.js} +39 -26
  88. package/dist/{extensions-SRG7XCAH.js → extensions-OZFJ3A3G.js} +13 -7
  89. package/dist/{fleet-CA2CRTVG.js → fleet-6G3DHNYE.js} +45 -37
  90. package/dist/fleet-preflight-DSNT37JK.js +23 -0
  91. package/dist/{init-2OZDJE2D.js → init-KZ5QTF6M.js} +42 -34
  92. package/dist/{memory-3PIQQAKX.js → memory-73ESV5YC.js} +35 -27
  93. package/dist/{models-DY35XI7Y.js → models-A4PVNWJK.js} +34 -23
  94. package/dist/{paths-5OMXW7Z4.js → paths-C4H6IV77.js} +12 -6
  95. package/dist/preload-6WVMHX3A.js +13 -0
  96. package/dist/{reset-PIFYNOS3.js → reset-BGW6OGMV.js} +17 -11
  97. package/dist/{run-3VSPP24F.js → run-YTPEYQOH.js} +60 -48
  98. package/dist/{share-D36RQCXM.js → share-YIFFV4NQ.js} +16 -10
  99. package/dist/{skills-F2MRLELY.js → skills-2V6RA3OQ.js} +18 -11
  100. package/dist/{skills-eval-E2ZTW4PL.js → skills-eval-S2TVJO4F.js} +45 -36
  101. package/dist/{targets-DZMEZAH4.js → targets-TYXLPB23.js} +61 -59
  102. package/dist/{trace-7NYCUI2J.js → trace-GGOJ6Q6Z.js} +9 -3
  103. package/dist/{uninstall-AD3JWHBB.js → uninstall-LLLT4F4W.js} +14 -8
  104. package/dist/{upgrade-WYYBKGDY.js → upgrade-33G2LMM5.js} +45 -23
  105. package/dist/{usage-ULIDAGFF.js → usage-ZAFSXKKG.js} +35 -27
  106. package/dist/version-KGEG7EPO.js +21 -0
  107. package/dist/{wiki-generate-PKFIX6OB.js → wiki-generate-NUQCVOQ3.js} +55 -45
  108. package/dist/worker/entry.js +101 -43
  109. package/docs/README.md +12 -9
  110. package/docs/acp.md +28 -5
  111. package/docs/alcf-provider.md +1 -1
  112. package/docs/architecture.md +23 -2
  113. package/docs/artifact-placement.md +101 -0
  114. package/docs/artifact-versions.md +1 -1
  115. package/docs/built-in-agents.md +4 -2
  116. package/docs/capacity-and-scheduling.md +1 -1
  117. package/docs/commands-and-modes.md +125 -41
  118. package/docs/configuration-and-targets.md +88 -18
  119. package/docs/context-engine.md +6 -2
  120. package/docs/development-pipeline.md +77 -0
  121. package/docs/documentation-coverage.md +4 -4
  122. package/docs/documentation-guide.md +3 -3
  123. package/docs/environment-variables.md +2 -1
  124. package/docs/eval-runner.md +3 -3
  125. package/docs/evals-internal.md +2 -2
  126. package/docs/evidence-and-memory.md +6 -2
  127. package/docs/evolution.md +1 -1
  128. package/docs/exit-codes-and-output.md +1 -1
  129. package/docs/extensions-and-sharing.md +18 -11
  130. package/docs/fleet-demo-runbook.md +22 -23
  131. package/docs/fleet-dispatch.md +111 -12
  132. package/docs/glossary.md +107 -15
  133. package/docs/html/agents_blueprint.html +3 -3
  134. package/docs/html/alcf_blueprint.html +3 -3
  135. package/docs/html/architecture_blueprint.html +3 -3
  136. package/docs/html/commands_blueprint.html +187 -42
  137. package/docs/html/configuration_blueprint.html +7 -7
  138. package/docs/html/context_blueprint.html +3 -3
  139. package/docs/html/documentation_blueprint.html +1 -1
  140. package/docs/html/environment_blueprint.html +3 -3
  141. package/docs/html/eval_blueprint.html +4 -4
  142. package/docs/html/evals_internal_blueprint.html +3 -3
  143. package/docs/html/evolution_blueprint.html +3 -3
  144. package/docs/html/extensions_blueprint.html +3 -3
  145. package/docs/html/fleet_dispatch_blueprint.html +8 -8
  146. package/docs/html/index.html +5 -5
  147. package/docs/html/lifecycle_blueprint.html +4 -4
  148. package/docs/html/memory_blueprint.html +3 -3
  149. package/docs/html/middleware_blueprint.html +3 -3
  150. package/docs/html/models_blueprint.html +2 -2
  151. package/docs/html/observability_blueprint.html +2 -2
  152. package/docs/html/provider_adapter_blueprint.html +3 -3
  153. package/docs/html/safety_blueprint.html +3 -3
  154. package/docs/html/skills_blueprint.html +2 -2
  155. package/docs/html/soak_blueprint.html +3 -3
  156. package/docs/html/tool_usage_blueprint.html +4 -4
  157. package/docs/html/tools_blueprint.html +2 -2
  158. package/docs/html/trace_blueprint.html +3 -3
  159. package/docs/html/tui_design_blueprint.html +100 -40
  160. package/docs/html/validation_blueprint.html +1 -1
  161. package/docs/html/worker_dispatch_blueprint.html +3 -3
  162. package/docs/installation-and-lifecycle.md +62 -11
  163. package/docs/middleware-and-components.md +1 -1
  164. package/docs/model-catalog.md +2 -2
  165. package/docs/observability.md +3 -3
  166. package/docs/proactive-memory.md +12 -12
  167. package/docs/prompt-envelope-and-tools.md +2 -2
  168. package/docs/provider-adapter-cookbook.md +1 -1
  169. package/docs/release-cut-checklist.md +4 -0
  170. package/docs/safety-model.md +21 -5
  171. package/docs/scientific-validation.md +3 -3
  172. package/docs/session-lifecycle.md +2 -2
  173. package/docs/skills-marketplace.md +1 -1
  174. package/docs/time-conventions.md +101 -0
  175. package/docs/tool-usage.md +5 -4
  176. package/docs/trace-store.md +1 -1
  177. package/docs/troubleshooting.md +1 -1
  178. package/docs/tui-design.md +83 -27
  179. package/docs/worker-dispatch-mechanics.md +3 -3
  180. package/package.json +16 -16
  181. package/skills/README.md +5 -6
  182. package/skills/git/file-ticket/SKILL.md +107 -0
  183. package/skills/git/file-ticket/evals.md +54 -0
  184. package/skills/git/fix-issue/SKILL.md +106 -0
  185. package/skills/git/fix-issue/evals.md +71 -0
  186. package/skills/git/ship/SKILL.md +92 -0
  187. package/skills/git/ship/evals.md +72 -0
  188. package/skills/skill-marketplace.json +12 -20
  189. package/src/cli/acp.ts +88 -0
  190. package/src/cli/agents.ts +60 -0
  191. package/src/cli/args.ts +280 -0
  192. package/src/cli/argv.ts +170 -0
  193. package/src/cli/ask.ts +34 -0
  194. package/src/cli/auth.ts +468 -0
  195. package/src/cli/bootstrap-generate.ts +498 -0
  196. package/src/cli/clio.ts +34 -0
  197. package/src/cli/components.ts +195 -0
  198. package/src/cli/config-inspect.ts +330 -0
  199. package/src/cli/config.ts +72 -0
  200. package/src/cli/configure-interop.ts +67 -0
  201. package/src/cli/configure-layout.ts +172 -0
  202. package/src/cli/configure.ts +1487 -0
  203. package/src/cli/context-clear.ts +76 -0
  204. package/src/cli/context-index.ts +102 -0
  205. package/src/cli/context.ts +316 -0
  206. package/src/cli/default-target.ts +63 -0
  207. package/src/cli/docs.ts +340 -0
  208. package/src/cli/doctor.ts +54 -0
  209. package/src/cli/eval.ts +315 -0
  210. package/src/cli/evidence.ts +222 -0
  211. package/src/cli/evolve.ts +219 -0
  212. package/src/cli/extensions.ts +205 -0
  213. package/src/cli/fleet.ts +827 -0
  214. package/src/cli/index.ts +309 -0
  215. package/src/cli/init.ts +219 -0
  216. package/src/cli/initial-message.ts +47 -0
  217. package/src/cli/internal-dispatch.ts +55 -0
  218. package/src/cli/memory.ts +180 -0
  219. package/src/cli/models.ts +257 -0
  220. package/src/cli/modes/json-stream.ts +85 -0
  221. package/src/cli/modes/jsonl.ts +9 -0
  222. package/src/cli/modes/print.ts +589 -0
  223. package/src/cli/oauth-manual-input.ts +72 -0
  224. package/src/cli/oauth-select.ts +36 -0
  225. package/src/cli/output-guard.ts +48 -0
  226. package/src/cli/paths.ts +44 -0
  227. package/src/cli/provider-target.ts +113 -0
  228. package/src/cli/removal.ts +72 -0
  229. package/src/cli/reset.ts +253 -0
  230. package/src/cli/run.ts +497 -0
  231. package/src/cli/share.ts +243 -0
  232. package/src/cli/shared.ts +60 -0
  233. package/src/cli/skills-eval.ts +1225 -0
  234. package/src/cli/skills.ts +470 -0
  235. package/src/cli/steer-channel.ts +86 -0
  236. package/src/cli/targets.ts +1150 -0
  237. package/src/cli/text-layout.ts +102 -0
  238. package/src/cli/trace.ts +274 -0
  239. package/src/cli/uninstall.ts +405 -0
  240. package/src/cli/upgrade.ts +270 -0
  241. package/src/cli/usage.ts +869 -0
  242. package/src/cli/validate-model.ts +28 -0
  243. package/src/cli/version.ts +7 -0
  244. package/src/cli/wiki-generate.ts +509 -0
  245. package/src/core/artifact-paths.ts +43 -0
  246. package/src/core/bash-exec.ts +242 -0
  247. package/src/core/boot-trace.ts +37 -0
  248. package/src/core/bus-events.ts +728 -0
  249. package/src/core/bus-trace.ts +53 -0
  250. package/src/core/c-header-language.ts +265 -0
  251. package/src/core/clio-repo.ts +78 -0
  252. package/src/core/config.ts +1593 -0
  253. package/src/core/context-floor.ts +33 -0
  254. package/src/core/defaults.ts +625 -0
  255. package/src/core/domain-loader.ts +170 -0
  256. package/src/core/event-bus.ts +94 -0
  257. package/src/core/file-references.ts +282 -0
  258. package/src/core/guardrails.ts +185 -0
  259. package/src/core/headless-permission.ts +21 -0
  260. package/src/core/init.ts +223 -0
  261. package/src/core/json-payload.ts +58 -0
  262. package/src/core/package-root.ts +54 -0
  263. package/src/core/path-canonical.ts +37 -0
  264. package/src/core/process-identity.ts +41 -0
  265. package/src/core/recent-models.ts +91 -0
  266. package/src/core/release.ts +2 -0
  267. package/src/core/residency-protection.ts +56 -0
  268. package/src/core/resolve-config-value.ts +88 -0
  269. package/src/core/response-schema.ts +279 -0
  270. package/src/core/run-overrides.ts +77 -0
  271. package/src/core/safe-exec.ts +193 -0
  272. package/src/core/safe-id.ts +37 -0
  273. package/src/core/safe-resource-write.ts +162 -0
  274. package/src/core/session-routing.ts +339 -0
  275. package/src/core/settings-layers.ts +220 -0
  276. package/src/core/shared-bus.ts +8 -0
  277. package/src/core/shell-quote.ts +26 -0
  278. package/src/core/skill-activation.ts +190 -0
  279. package/src/core/startup-timer.ts +37 -0
  280. package/src/core/state-file-lock.ts +207 -0
  281. package/src/core/termination.ts +202 -0
  282. package/src/core/timers.ts +38 -0
  283. package/src/core/tool-names.ts +65 -0
  284. package/src/core/verification-scripts.ts +13 -0
  285. package/src/core/workspace-files.ts +492 -0
  286. package/src/core/xdg.ts +177 -0
  287. package/src/domains/agents/builtins/architect.md +4 -4
  288. package/src/domains/agents/builtins/coder.md +3 -2
  289. package/src/domains/agents/builtins/debugger.md +1 -1
  290. package/src/domains/agents/builtins/documenter.md +1 -1
  291. package/src/domains/agents/builtins/git-master.md +3 -3
  292. package/src/domains/agents/builtins/provenance.md +1 -1
  293. package/src/domains/agents/builtins/researcher.md +1 -1
  294. package/src/domains/agents/builtins/scout.md +1 -1
  295. package/src/domains/agents/builtins/tester.md +1 -1
  296. package/src/domains/agents/builtins/verifier.md +1 -1
  297. package/src/domains/agents/builtins/wiki-writer.md +1 -1
  298. package/src/domains/agents/catalog.ts +172 -0
  299. package/src/domains/agents/contract.ts +16 -0
  300. package/src/domains/agents/extension.ts +110 -0
  301. package/src/domains/agents/fleet-commands.ts +154 -0
  302. package/src/domains/agents/fleet-contract.ts +797 -0
  303. package/src/domains/agents/frontmatter.ts +40 -0
  304. package/src/domains/agents/index.ts +102 -0
  305. package/src/domains/agents/manifest.ts +6 -0
  306. package/src/domains/agents/recipe-schema.ts +202 -0
  307. package/src/domains/agents/recipe.ts +125 -0
  308. package/src/domains/agents/registry.ts +111 -0
  309. package/src/domains/agents/result-contract.ts +1265 -0
  310. package/src/domains/agents/spec.ts +371 -0
  311. package/src/domains/agents/write-boundary.ts +109 -0
  312. package/src/domains/components/diff.ts +99 -0
  313. package/src/domains/components/hash.ts +21 -0
  314. package/src/domains/components/index.ts +3 -0
  315. package/src/domains/components/scan.ts +304 -0
  316. package/src/domains/components/snapshot.ts +108 -0
  317. package/src/domains/components/types.ts +82 -0
  318. package/src/domains/config/agent-namespace.ts +13 -0
  319. package/src/domains/config/classify.ts +94 -0
  320. package/src/domains/config/contract.ts +22 -0
  321. package/src/domains/config/extension.ts +136 -0
  322. package/src/domains/config/index.ts +13 -0
  323. package/src/domains/config/keybindings.ts +164 -0
  324. package/src/domains/config/manifest.ts +6 -0
  325. package/src/domains/config/watcher.ts +41 -0
  326. package/src/domains/context/adoption.ts +880 -0
  327. package/src/domains/context/bootstrap-prompt.ts +273 -0
  328. package/src/domains/context/bootstrap.ts +1409 -0
  329. package/src/domains/context/clear.ts +86 -0
  330. package/src/domains/context/clio-md.ts +327 -0
  331. package/src/domains/context/codewiki/cmake.ts +356 -0
  332. package/src/domains/context/codewiki/cooperative.ts +46 -0
  333. package/src/domains/context/codewiki/digest.ts +135 -0
  334. package/src/domains/context/codewiki/grammar-assets.ts +33 -0
  335. package/src/domains/context/codewiki/indexer.ts +1614 -0
  336. package/src/domains/context/codewiki/tree-sitter.ts +771 -0
  337. package/src/domains/context/contract.ts +62 -0
  338. package/src/domains/context/excluded-dirs.ts +1 -0
  339. package/src/domains/context/extension.ts +407 -0
  340. package/src/domains/context/fingerprint.ts +196 -0
  341. package/src/domains/context/index.ts +164 -0
  342. package/src/domains/context/init-options.ts +69 -0
  343. package/src/domains/context/manifest.ts +6 -0
  344. package/src/domains/context/operator-profile.ts +157 -0
  345. package/src/domains/context/project-metadata.ts +510 -0
  346. package/src/domains/context/project-rules.ts +227 -0
  347. package/src/domains/context/prompt-context.ts +62 -0
  348. package/src/domains/context/refresh.ts +170 -0
  349. package/src/domains/context/sibling-files.ts +10 -0
  350. package/src/domains/context/state.ts +237 -0
  351. package/src/domains/context/wiki/assemble.ts +303 -0
  352. package/src/domains/context/wiki/frontmatter.ts +210 -0
  353. package/src/domains/context/wiki/generate.ts +590 -0
  354. package/src/domains/context/wiki/layout.ts +111 -0
  355. package/src/domains/context/wiki/meta.ts +221 -0
  356. package/src/domains/context/wiki/plan-store.ts +217 -0
  357. package/src/domains/context/wiki/plan.ts +250 -0
  358. package/src/domains/context/wiki/prompts.ts +270 -0
  359. package/src/domains/context/wiki/staleness.ts +198 -0
  360. package/src/domains/dispatch/active-route-planner.ts +168 -0
  361. package/src/domains/dispatch/admission-queue.ts +150 -0
  362. package/src/domains/dispatch/admission.ts +334 -0
  363. package/src/domains/dispatch/agent-candidates.ts +307 -0
  364. package/src/domains/dispatch/agent-ledger-hub.ts +71 -0
  365. package/src/domains/dispatch/agent-ledger-store.ts +257 -0
  366. package/src/domains/dispatch/agent-ledger.ts +212 -0
  367. package/src/domains/dispatch/agent-plan-adapter.ts +85 -0
  368. package/src/domains/dispatch/assignment-events.ts +132 -0
  369. package/src/domains/dispatch/assignment-reconcile.ts +76 -0
  370. package/src/domains/dispatch/assignment-store.ts +162 -0
  371. package/src/domains/dispatch/assignment.ts +278 -0
  372. package/src/domains/dispatch/backoff.ts +59 -0
  373. package/src/domains/dispatch/batch-store.ts +134 -0
  374. package/src/domains/dispatch/batch-tracker.ts +66 -0
  375. package/src/domains/dispatch/capability-match.ts +155 -0
  376. package/src/domains/dispatch/capacity-lease.ts +413 -0
  377. package/src/domains/dispatch/code-step-store.ts +52 -0
  378. package/src/domains/dispatch/code-step.ts +368 -0
  379. package/src/domains/dispatch/contract.ts +278 -0
  380. package/src/domains/dispatch/dedup.ts +133 -0
  381. package/src/domains/dispatch/event-pump.ts +251 -0
  382. package/src/domains/dispatch/execution-handoff.ts +29 -0
  383. package/src/domains/dispatch/execution-plan.ts +328 -0
  384. package/src/domains/dispatch/execution-role.ts +277 -0
  385. package/src/domains/dispatch/execution-scheduler.ts +583 -0
  386. package/src/domains/dispatch/extension.ts +5869 -0
  387. package/src/domains/dispatch/failure-classification.ts +141 -0
  388. package/src/domains/dispatch/fleet-plan.ts +225 -0
  389. package/src/domains/dispatch/fleet-preflight.ts +394 -0
  390. package/src/domains/dispatch/gate-decisions.ts +1040 -0
  391. package/src/domains/dispatch/gate-role-prompts.ts +58 -0
  392. package/src/domains/dispatch/heartbeat.ts +27 -0
  393. package/src/domains/dispatch/index.ts +137 -0
  394. package/src/domains/dispatch/joint-route-adapter.ts +114 -0
  395. package/src/domains/dispatch/joint-route-resolver.ts +283 -0
  396. package/src/domains/dispatch/manifest.ts +6 -0
  397. package/src/domains/dispatch/orphan-recovery.ts +224 -0
  398. package/src/domains/dispatch/outcome.ts +109 -0
  399. package/src/domains/dispatch/phase-timing.ts +47 -0
  400. package/src/domains/dispatch/placement.ts +202 -0
  401. package/src/domains/dispatch/receipt-findings.ts +255 -0
  402. package/src/domains/dispatch/receipt-integrity.ts +378 -0
  403. package/src/domains/dispatch/recovery-candidates.ts +74 -0
  404. package/src/domains/dispatch/reproducibility.ts +48 -0
  405. package/src/domains/dispatch/reservation-store.ts +501 -0
  406. package/src/domains/dispatch/route-approval.ts +177 -0
  407. package/src/domains/dispatch/route-candidates.ts +57 -0
  408. package/src/domains/dispatch/route-decision.ts +1079 -0
  409. package/src/domains/dispatch/route-facts.ts +187 -0
  410. package/src/domains/dispatch/route-history.ts +238 -0
  411. package/src/domains/dispatch/route-observer.ts +488 -0
  412. package/src/domains/dispatch/route-policy.ts +327 -0
  413. package/src/domains/dispatch/route-quality.ts +256 -0
  414. package/src/domains/dispatch/route-readiness.ts +120 -0
  415. package/src/domains/dispatch/routing-intent.ts +287 -0
  416. package/src/domains/dispatch/run-identity.ts +56 -0
  417. package/src/domains/dispatch/scout-transition.ts +130 -0
  418. package/src/domains/dispatch/state.ts +277 -0
  419. package/src/domains/dispatch/tool-stats.ts +132 -0
  420. package/src/domains/dispatch/transport.ts +209 -0
  421. package/src/domains/dispatch/types.ts +785 -0
  422. package/src/domains/dispatch/validation-grounding.ts +154 -0
  423. package/src/domains/dispatch/validation.ts +721 -0
  424. package/src/domains/dispatch/worker-protocol.ts +275 -0
  425. package/src/domains/dispatch/worker-spawn.ts +566 -0
  426. package/src/domains/dispatch/write-boundary-enforcer.ts +97 -0
  427. package/src/domains/dispatch/write-boundary.ts +426 -0
  428. package/src/domains/eval/artifacts/redact.ts +42 -0
  429. package/src/domains/eval/artifacts/store.ts +173 -0
  430. package/src/domains/eval/compare/compare.ts +33 -0
  431. package/src/domains/eval/compare/gates.ts +66 -0
  432. package/src/domains/eval/compare/thresholds.ts +92 -0
  433. package/src/domains/eval/harness-metrics.ts +62 -0
  434. package/src/domains/eval/index.ts +66 -0
  435. package/src/domains/eval/metrics/chaos-stream.ts +93 -0
  436. package/src/domains/eval/metrics/context.ts +34 -0
  437. package/src/domains/eval/metrics/coverage.ts +21 -0
  438. package/src/domains/eval/metrics/evidence.ts +182 -0
  439. package/src/domains/eval/metrics/fleet-loop-stream.ts +196 -0
  440. package/src/domains/eval/metrics/invariants.ts +736 -0
  441. package/src/domains/eval/metrics/latency.ts +4 -0
  442. package/src/domains/eval/metrics/token-stream.ts +139 -0
  443. package/src/domains/eval/metrics/tokens.ts +51 -0
  444. package/src/domains/eval/metrics/tool-calls.ts +7 -0
  445. package/src/domains/eval/proactive-memory.ts +279 -0
  446. package/src/domains/eval/provenance.ts +35 -0
  447. package/src/domains/eval/report.ts +234 -0
  448. package/src/domains/eval/reports/json.ts +5 -0
  449. package/src/domains/eval/reports/junit.ts +23 -0
  450. package/src/domains/eval/reports/markdown.ts +20 -0
  451. package/src/domains/eval/reports/swe-jsonl.ts +16 -0
  452. package/src/domains/eval/reports/text.ts +25 -0
  453. package/src/domains/eval/run-compare.ts +274 -0
  454. package/src/domains/eval/runner.ts +244 -0
  455. package/src/domains/eval/runners/clio-run.ts +148 -0
  456. package/src/domains/eval/runners/context-index.ts +56 -0
  457. package/src/domains/eval/runners/context-init.ts +203 -0
  458. package/src/domains/eval/runners/external-command.ts +350 -0
  459. package/src/domains/eval/runtime-paths.ts +171 -0
  460. package/src/domains/eval/schema/artifact.ts +75 -0
  461. package/src/domains/eval/schema/suite.ts +235 -0
  462. package/src/domains/eval/schema/validate.ts +339 -0
  463. package/src/domains/eval/store.ts +392 -0
  464. package/src/domains/eval/suites/load.ts +74 -0
  465. package/src/domains/eval/suites/matrix.ts +19 -0
  466. package/src/domains/eval/suites/resolve.ts +44 -0
  467. package/src/domains/eval/suites/run.ts +325 -0
  468. package/src/domains/eval/task-file.ts +186 -0
  469. package/src/domains/eval/types.ts +141 -0
  470. package/src/domains/eval/verifiers/command.ts +27 -0
  471. package/src/domains/eval/verifiers/file-exists.ts +6 -0
  472. package/src/domains/eval/verifiers/patch.ts +22 -0
  473. package/src/domains/eval/workspaces/git.ts +41 -0
  474. package/src/domains/eval/workspaces/local.ts +17 -0
  475. package/src/domains/eval/workspaces/temp-copy.ts +29 -0
  476. package/src/domains/evidence/build.ts +1714 -0
  477. package/src/domains/evidence/eval.ts +605 -0
  478. package/src/domains/evidence/failure-attribution.ts +54 -0
  479. package/src/domains/evidence/finish-contract-map.ts +42 -0
  480. package/src/domains/evidence/index.ts +55 -0
  481. package/src/domains/evidence/provenance.ts +200 -0
  482. package/src/domains/evidence/redact.ts +81 -0
  483. package/src/domains/evidence/store.ts +291 -0
  484. package/src/domains/evidence/types.ts +325 -0
  485. package/src/domains/evolution/SELF_EDIT_GATE.md +91 -0
  486. package/src/domains/evolution/index.ts +26 -0
  487. package/src/domains/evolution/manifest.ts +154 -0
  488. package/src/domains/evolution/validate.ts +304 -0
  489. package/src/domains/extensions/contract.ts +22 -0
  490. package/src/domains/extensions/discovery.ts +193 -0
  491. package/src/domains/extensions/extension.ts +46 -0
  492. package/src/domains/extensions/index.ts +34 -0
  493. package/src/domains/extensions/manager.ts +30 -0
  494. package/src/domains/extensions/manifest.ts +6 -0
  495. package/src/domains/extensions/resources.ts +38 -0
  496. package/src/domains/extensions/state.ts +224 -0
  497. package/src/domains/extensions/types.ts +83 -0
  498. package/src/domains/interop/consent.ts +185 -0
  499. package/src/domains/interop/contract.ts +29 -0
  500. package/src/domains/interop/detect.ts +173 -0
  501. package/src/domains/interop/extension.ts +59 -0
  502. package/src/domains/interop/index.ts +34 -0
  503. package/src/domains/interop/manifest.ts +6 -0
  504. package/src/domains/interop/registry.ts +139 -0
  505. package/src/domains/interop/state.ts +92 -0
  506. package/src/domains/interop/types.ts +109 -0
  507. package/src/domains/lifecycle/contract.ts +11 -0
  508. package/src/domains/lifecycle/doctor.ts +536 -0
  509. package/src/domains/lifecycle/extension.ts +23 -0
  510. package/src/domains/lifecycle/index.ts +21 -0
  511. package/src/domains/lifecycle/install-method.ts +51 -0
  512. package/src/domains/lifecycle/manifest.ts +6 -0
  513. package/src/domains/lifecycle/migrations/index.ts +94 -0
  514. package/src/domains/lifecycle/state.ts +93 -0
  515. package/src/domains/lifecycle/upgrade-notice.ts +35 -0
  516. package/src/domains/lifecycle/version.ts +35 -0
  517. package/src/domains/memory/index.ts +128 -0
  518. package/src/domains/memory/operations.ts +143 -0
  519. package/src/domains/memory/prompt-section.ts +86 -0
  520. package/src/domains/memory/proposal.ts +180 -0
  521. package/src/domains/memory/store.ts +163 -0
  522. package/src/domains/memory/task-bank.ts +229 -0
  523. package/src/domains/memory/task-memory-handoff.ts +222 -0
  524. package/src/domains/memory/task-memory-policy.ts +602 -0
  525. package/src/domains/memory/task-memory-status.ts +58 -0
  526. package/src/domains/memory/task-memory-telemetry.ts +346 -0
  527. package/src/domains/memory/task-memory-trace.ts +89 -0
  528. package/src/domains/memory/types.ts +74 -0
  529. package/src/domains/memory/validate.ts +297 -0
  530. package/src/domains/middleware/budget.ts +216 -0
  531. package/src/domains/middleware/contract.ts +35 -0
  532. package/src/domains/middleware/dispatch-nudge.ts +469 -0
  533. package/src/domains/middleware/extension.ts +129 -0
  534. package/src/domains/middleware/hook-receipts.ts +70 -0
  535. package/src/domains/middleware/hooks-io.ts +174 -0
  536. package/src/domains/middleware/hooks.ts +432 -0
  537. package/src/domains/middleware/index.ts +154 -0
  538. package/src/domains/middleware/manifest.ts +6 -0
  539. package/src/domains/middleware/memory-intervention.ts +701 -0
  540. package/src/domains/middleware/rules.ts +42 -0
  541. package/src/domains/middleware/runtime.ts +333 -0
  542. package/src/domains/middleware/skills-reminder.ts +187 -0
  543. package/src/domains/middleware/snapshot.ts +71 -0
  544. package/src/domains/middleware/stalled-turn.ts +71 -0
  545. package/src/domains/middleware/task-board-reminder.ts +87 -0
  546. package/src/domains/middleware/task-nudge.ts +77 -0
  547. package/src/domains/middleware/tool-choice-control.ts +42 -0
  548. package/src/domains/middleware/types.ts +131 -0
  549. package/src/domains/middleware/validate.ts +329 -0
  550. package/src/domains/observability/accountability.ts +67 -0
  551. package/src/domains/observability/contract.ts +168 -0
  552. package/src/domains/observability/cost.ts +206 -0
  553. package/src/domains/observability/evidence-index.ts +123 -0
  554. package/src/domains/observability/extension.ts +281 -0
  555. package/src/domains/observability/index.ts +78 -0
  556. package/src/domains/observability/manifest.ts +10 -0
  557. package/src/domains/observability/metrics.ts +37 -0
  558. package/src/domains/observability/projection.ts +477 -0
  559. package/src/domains/observability/telemetry.ts +89 -0
  560. package/src/domains/observability/trace-store.ts +1454 -0
  561. package/src/domains/prompts/compiler.ts +556 -0
  562. package/src/domains/prompts/contract.ts +30 -0
  563. package/src/domains/prompts/extension.ts +304 -0
  564. package/src/domains/prompts/fragment-loader.ts +139 -0
  565. package/src/domains/prompts/fragments/identity/clio.md +3 -2
  566. package/src/domains/prompts/fragments/identity/self-awareness.md +63 -0
  567. package/src/domains/prompts/fragments/operating/contract.md +10 -1
  568. package/src/domains/prompts/hash.ts +73 -0
  569. package/src/domains/prompts/index.ts +32 -0
  570. package/src/domains/prompts/manifest.ts +8 -0
  571. package/src/domains/prompts/memory-intervention.ts +57 -0
  572. package/src/domains/prompts/preload.ts +82 -0
  573. package/src/domains/providers/auth/api-key.ts +47 -0
  574. package/src/domains/providers/auth/backend-file.ts +69 -0
  575. package/src/domains/providers/auth/backend-memory.ts +17 -0
  576. package/src/domains/providers/auth/index.ts +37 -0
  577. package/src/domains/providers/auth/oauth.ts +36 -0
  578. package/src/domains/providers/auth/storage.ts +667 -0
  579. package/src/domains/providers/capabilities.ts +50 -0
  580. package/src/domains/providers/catalog.ts +162 -0
  581. package/src/domains/providers/contract.ts +151 -0
  582. package/src/domains/providers/credentials.ts +20 -0
  583. package/src/domains/providers/eligibility.ts +24 -0
  584. package/src/domains/providers/errors.ts +64 -0
  585. package/src/domains/providers/extension.ts +536 -0
  586. package/src/domains/providers/index.ts +142 -0
  587. package/src/domains/providers/knowledge-base-path.ts +102 -0
  588. package/src/domains/providers/manifest.ts +6 -0
  589. package/src/domains/providers/model-capabilities.ts +136 -0
  590. package/src/domains/providers/model-discovery.ts +144 -0
  591. package/src/domains/providers/model-family.ts +32 -0
  592. package/src/domains/providers/model-runtime-capabilities.ts +712 -0
  593. package/src/domains/providers/models/local-models/clio-local-coding-targets.yaml +2 -2
  594. package/src/domains/providers/plugins.ts +59 -0
  595. package/src/domains/providers/probe/fingerprint.ts +44 -0
  596. package/src/domains/providers/probe/http.ts +114 -0
  597. package/src/domains/providers/probe/reasoning.ts +111 -0
  598. package/src/domains/providers/registry.ts +166 -0
  599. package/src/domains/providers/resolver.ts +156 -0
  600. package/src/domains/providers/runtime-resolution.ts +720 -0
  601. package/src/domains/providers/runtimes/antigravity/antigravity-code.ts +90 -0
  602. package/src/domains/providers/runtimes/builtins.ts +78 -0
  603. package/src/domains/providers/runtimes/claude/claude-code.ts +38 -0
  604. package/src/domains/providers/runtimes/claude/claude-sdk.ts +38 -0
  605. package/src/domains/providers/runtimes/claude/common.ts +55 -0
  606. package/src/domains/providers/runtimes/cloud/alcf.ts +171 -0
  607. package/src/domains/providers/runtimes/cloud/anthropic-max.ts +71 -0
  608. package/src/domains/providers/runtimes/cloud/anthropic.ts +43 -0
  609. package/src/domains/providers/runtimes/cloud/bedrock.ts +35 -0
  610. package/src/domains/providers/runtimes/cloud/deepseek.ts +50 -0
  611. package/src/domains/providers/runtimes/cloud/google.ts +41 -0
  612. package/src/domains/providers/runtimes/cloud/groq.ts +46 -0
  613. package/src/domains/providers/runtimes/cloud/mistral.ts +46 -0
  614. package/src/domains/providers/runtimes/cloud/openai-codex.ts +49 -0
  615. package/src/domains/providers/runtimes/cloud/openai.ts +46 -0
  616. package/src/domains/providers/runtimes/cloud/openrouter.ts +111 -0
  617. package/src/domains/providers/runtimes/common/lmstudio-logger.ts +32 -0
  618. package/src/domains/providers/runtimes/common/local-synth.ts +165 -0
  619. package/src/domains/providers/runtimes/common/probe-helpers.ts +474 -0
  620. package/src/domains/providers/runtimes/local-native/lemonade-anthropic.ts +27 -0
  621. package/src/domains/providers/runtimes/local-native/lemonade-openai.ts +26 -0
  622. package/src/domains/providers/runtimes/local-native/llamacpp-anthropic.ts +88 -0
  623. package/src/domains/providers/runtimes/local-native/llamacpp-completion.ts +207 -0
  624. package/src/domains/providers/runtimes/local-native/llamacpp-embed.ts +180 -0
  625. package/src/domains/providers/runtimes/local-native/llamacpp-rerank.ts +126 -0
  626. package/src/domains/providers/runtimes/local-native/llamacpp.ts +98 -0
  627. package/src/domains/providers/runtimes/local-native/lmstudio-native.ts +491 -0
  628. package/src/domains/providers/runtimes/local-native/ollama-native.ts +117 -0
  629. package/src/domains/providers/runtimes/local-native/sglang.ts +26 -0
  630. package/src/domains/providers/runtimes/local-native/vllm.ts +27 -0
  631. package/src/domains/providers/runtimes/protocol/anthropic-compat.ts +104 -0
  632. package/src/domains/providers/runtimes/protocol/anthropic-messages.ts +28 -0
  633. package/src/domains/providers/runtimes/protocol/bedrock.ts +26 -0
  634. package/src/domains/providers/runtimes/protocol/google.ts +27 -0
  635. package/src/domains/providers/runtimes/protocol/openai-compat.ts +145 -0
  636. package/src/domains/providers/support.ts +238 -0
  637. package/src/domains/providers/thinking-control-policy.ts +85 -0
  638. package/src/domains/providers/types/capability-flags.ts +114 -0
  639. package/src/domains/providers/types/cost-provenance.ts +7 -0
  640. package/src/domains/providers/types/inference.ts +41 -0
  641. package/src/domains/providers/types/knowledge-base.ts +156 -0
  642. package/src/domains/providers/types/local-model-quirks.ts +218 -0
  643. package/src/domains/providers/types/runtime-descriptor.ts +170 -0
  644. package/src/domains/providers/types/target-descriptor.ts +38 -0
  645. package/src/domains/resources/collision.ts +92 -0
  646. package/src/domains/resources/common-loader.ts +140 -0
  647. package/src/domains/resources/contract.ts +25 -0
  648. package/src/domains/resources/extension.ts +61 -0
  649. package/src/domains/resources/index.ts +74 -0
  650. package/src/domains/resources/loader.ts +86 -0
  651. package/src/domains/resources/manifest.ts +6 -0
  652. package/src/domains/resources/prompts/loader.ts +232 -0
  653. package/src/domains/resources/prompts/substitute.ts +65 -0
  654. package/src/domains/resources/skills/content-hash.ts +105 -0
  655. package/src/domains/resources/skills/evals.ts +175 -0
  656. package/src/domains/resources/skills/install.ts +410 -0
  657. package/src/domains/resources/skills/loader.ts +978 -0
  658. package/src/domains/resources/skills/marketplace.ts +255 -0
  659. package/src/domains/resources/skills/provenance-pin.ts +115 -0
  660. package/src/domains/safety/action-classifier.ts +268 -0
  661. package/src/domains/safety/approval-axis.ts +23 -0
  662. package/src/domains/safety/audit.ts +487 -0
  663. package/src/domains/safety/autonomy.ts +174 -0
  664. package/src/domains/safety/call-target.ts +59 -0
  665. package/src/domains/safety/contract.ts +65 -0
  666. package/src/domains/safety/damage-control.ts +44 -0
  667. package/src/domains/safety/default-path-policy.ts +117 -0
  668. package/src/domains/safety/extension.ts +383 -0
  669. package/src/domains/safety/finish-contract-registration.ts +128 -0
  670. package/src/domains/safety/finish-contract.ts +554 -0
  671. package/src/domains/safety/index.ts +44 -0
  672. package/src/domains/safety/loop-detector.ts +143 -0
  673. package/src/domains/safety/manifest.ts +6 -0
  674. package/src/domains/safety/path-policy.ts +164 -0
  675. package/src/domains/safety/policy-engine.ts +994 -0
  676. package/src/domains/safety/project-policy.ts +391 -0
  677. package/src/domains/safety/protected-artifacts-registration.ts +189 -0
  678. package/src/domains/safety/protected-artifacts.ts +993 -0
  679. package/src/domains/safety/rejection-feedback.ts +102 -0
  680. package/src/domains/safety/rigor.ts +72 -0
  681. package/src/domains/safety/rule-compiler.ts +48 -0
  682. package/src/domains/safety/rule-pack-loader.ts +92 -0
  683. package/src/domains/safety/run-effects.ts +197 -0
  684. package/src/domains/safety/scope.ts +61 -0
  685. package/src/domains/scheduling/budget.ts +35 -0
  686. package/src/domains/scheduling/cluster.ts +175 -0
  687. package/src/domains/scheduling/contract.ts +30 -0
  688. package/src/domains/scheduling/extension.ts +91 -0
  689. package/src/domains/scheduling/index.ts +12 -0
  690. package/src/domains/scheduling/manifest.ts +6 -0
  691. package/src/domains/session/archive-readers.ts +208 -0
  692. package/src/domains/session/checkpoint.ts +38 -0
  693. package/src/domains/session/compaction/auto.ts +89 -0
  694. package/src/domains/session/compaction/branch-summary.ts +186 -0
  695. package/src/domains/session/compaction/compact.ts +493 -0
  696. package/src/domains/session/compaction/cut-point.ts +171 -0
  697. package/src/domains/session/compaction/defaults.ts +34 -0
  698. package/src/domains/session/compaction/mask-observations.ts +265 -0
  699. package/src/domains/session/compaction/session-entries.ts +18 -0
  700. package/src/domains/session/compaction/tokens.ts +147 -0
  701. package/src/domains/session/context-accounting.ts +583 -0
  702. package/src/domains/session/context-ledger.ts +348 -0
  703. package/src/domains/session/contract.ts +144 -0
  704. package/src/domains/session/cwd-fallback.ts +65 -0
  705. package/src/domains/session/entries.ts +509 -0
  706. package/src/domains/session/extension.ts +322 -0
  707. package/src/domains/session/history.ts +172 -0
  708. package/src/domains/session/index.ts +84 -0
  709. package/src/domains/session/manager.ts +128 -0
  710. package/src/domains/session/manifest.ts +6 -0
  711. package/src/domains/session/migrations/index.ts +27 -0
  712. package/src/domains/session/prompt-manifest.ts +173 -0
  713. package/src/domains/session/protected-artifact-journal.ts +241 -0
  714. package/src/domains/session/protected-artifacts.ts +90 -0
  715. package/src/domains/session/retry.ts +238 -0
  716. package/src/domains/session/task-board.ts +375 -0
  717. package/src/domains/session/tree/active-path.ts +98 -0
  718. package/src/domains/session/tree/fork.ts +160 -0
  719. package/src/domains/session/tree/manager.ts +128 -0
  720. package/src/domains/session/tree/navigator.ts +177 -0
  721. package/src/domains/session/tree/preview.ts +259 -0
  722. package/src/domains/session/usage.ts +148 -0
  723. package/src/domains/session/workspace/git-probe.ts +161 -0
  724. package/src/domains/session/workspace/index.ts +4 -0
  725. package/src/domains/session/workspace/project-type.ts +217 -0
  726. package/src/domains/session/workspace/snapshot.ts +74 -0
  727. package/src/domains/share/archive.ts +684 -0
  728. package/src/domains/share/contract.ts +9 -0
  729. package/src/domains/share/extension.ts +26 -0
  730. package/src/domains/share/index.ts +28 -0
  731. package/src/domains/share/manifest.ts +6 -0
  732. package/src/engine/acp/adapter.ts +397 -0
  733. package/src/engine/acp/errors.ts +32 -0
  734. package/src/engine/acp/event-mapper.ts +154 -0
  735. package/src/engine/acp/server.ts +656 -0
  736. package/src/engine/acp/tool-mediator.ts +686 -0
  737. package/src/engine/acp/transport.ts +654 -0
  738. package/src/engine/acp/types.ts +170 -0
  739. package/src/engine/agent.ts +29 -0
  740. package/src/engine/ai.ts +202 -0
  741. package/src/engine/alcf-oauth.ts +198 -0
  742. package/src/engine/antigravity/subprocess-runtime.ts +205 -0
  743. package/src/engine/apis/degraded-inference.ts +95 -0
  744. package/src/engine/apis/index.ts +20 -0
  745. package/src/engine/apis/llamacpp-residency.ts +252 -0
  746. package/src/engine/apis/lmstudio-native.ts +1438 -0
  747. package/src/engine/apis/lmstudio-residency.ts +92 -0
  748. package/src/engine/apis/ollama-native.ts +507 -0
  749. package/src/engine/apis/openai-completions.ts +716 -0
  750. package/src/engine/apis/output-budget.ts +99 -0
  751. package/src/engine/apis/residency-lock.ts +29 -0
  752. package/src/engine/apis/residency.ts +640 -0
  753. package/src/engine/apis/resident-models.ts +42 -0
  754. package/src/engine/apis/sampling-overrides.ts +38 -0
  755. package/src/engine/apis/thinking-replay.ts +11 -0
  756. package/src/engine/claude/sdk-runtime.ts +685 -0
  757. package/src/engine/claude/session-id.ts +5 -0
  758. package/src/engine/claude/subprocess-runtime.ts +316 -0
  759. package/src/engine/claude/tool-safety.ts +400 -0
  760. package/src/engine/external-subprocess.ts +23 -0
  761. package/src/engine/harmony-response.ts +165 -0
  762. package/src/engine/loop-guard.ts +1127 -0
  763. package/src/engine/oauth.ts +192 -0
  764. package/src/engine/pi-mono-names.ts +13 -0
  765. package/src/engine/provider-payload.ts +315 -0
  766. package/src/engine/select-list.ts +53 -0
  767. package/src/engine/session.ts +834 -0
  768. package/src/engine/strip-tokenizer-sentinels.ts +125 -0
  769. package/src/engine/tui.ts +103 -0
  770. package/src/engine/types.ts +66 -0
  771. package/src/engine/worker-events.ts +100 -0
  772. package/src/engine/worker-runtime.ts +1022 -0
  773. package/src/engine/worker-tools.ts +203 -0
  774. package/src/entry/orchestrator.ts +1873 -0
  775. package/src/interactive/application-controller.ts +346 -0
  776. package/src/interactive/bus-notices.ts +265 -0
  777. package/src/interactive/chat-loop-messages.ts +626 -0
  778. package/src/interactive/chat-loop-policy.ts +18 -0
  779. package/src/interactive/chat-loop.ts +865 -0
  780. package/src/interactive/chat-panel.ts +1694 -0
  781. package/src/interactive/chat-renderer.ts +1038 -0
  782. package/src/interactive/clio-editor.ts +166 -0
  783. package/src/interactive/command-fallbacks.ts +23 -0
  784. package/src/interactive/command-output.ts +85 -0
  785. package/src/interactive/context-activity.ts +203 -0
  786. package/src/interactive/context-meter.ts +223 -0
  787. package/src/interactive/context-overlay.ts +220 -0
  788. package/src/interactive/cost-overlay.ts +279 -0
  789. package/src/interactive/dispatch-board.ts +1319 -0
  790. package/src/interactive/dispatch-steering.ts +86 -0
  791. package/src/interactive/editor-bash.ts +46 -0
  792. package/src/interactive/editor-steer.ts +51 -0
  793. package/src/interactive/editor-submit.ts +303 -0
  794. package/src/interactive/external-editor.ts +67 -0
  795. package/src/interactive/follow-up-queue-panel.ts +75 -0
  796. package/src/interactive/footer/dashboard.ts +534 -0
  797. package/src/interactive/footer/notifications.ts +275 -0
  798. package/src/interactive/footer/widgets.ts +1246 -0
  799. package/src/interactive/footer-panel.ts +187 -0
  800. package/src/interactive/format-time.ts +85 -0
  801. package/src/interactive/index.ts +11 -0
  802. package/src/interactive/interactive-application.ts +755 -0
  803. package/src/interactive/interactive-event-projection.ts +380 -0
  804. package/src/interactive/interactive-input-runtime.ts +261 -0
  805. package/src/interactive/interactive-presentation.ts +452 -0
  806. package/src/interactive/interactive-shell.ts +134 -0
  807. package/src/interactive/interactive-slash-runtime.ts +492 -0
  808. package/src/interactive/interactive-subscriptions.ts +111 -0
  809. package/src/interactive/interactive-tickers.ts +152 -0
  810. package/src/interactive/keybinding-manager.ts +496 -0
  811. package/src/interactive/layout.ts +20 -0
  812. package/src/interactive/leader-key.ts +143 -0
  813. package/src/interactive/loop-guard-interrupt.ts +101 -0
  814. package/src/interactive/memory-overlay.ts +280 -0
  815. package/src/interactive/overlay-ask-user-lifecycle.ts +110 -0
  816. package/src/interactive/overlay-auth-lifecycle.ts +308 -0
  817. package/src/interactive/overlay-frame.ts +502 -0
  818. package/src/interactive/overlay-general-openers.ts +217 -0
  819. package/src/interactive/overlay-key-routing.ts +213 -0
  820. package/src/interactive/overlay-lifecycle.ts +413 -0
  821. package/src/interactive/overlay-model-selectors.ts +127 -0
  822. package/src/interactive/overlay-permission-lifecycle.ts +344 -0
  823. package/src/interactive/overlay-resource-openers.ts +112 -0
  824. package/src/interactive/overlay-session-lifecycle.ts +270 -0
  825. package/src/interactive/overlay-transitions.ts +57 -0
  826. package/src/interactive/overlays/agents.ts +69 -0
  827. package/src/interactive/overlays/ask-user.ts +921 -0
  828. package/src/interactive/overlays/auth-dialog.ts +221 -0
  829. package/src/interactive/overlays/context-reset.ts +108 -0
  830. package/src/interactive/overlays/cwd-fallback.ts +141 -0
  831. package/src/interactive/overlays/extensions.ts +54 -0
  832. package/src/interactive/overlays/help-reference.ts +140 -0
  833. package/src/interactive/overlays/interop.ts +139 -0
  834. package/src/interactive/overlays/keybinding-detail.ts +90 -0
  835. package/src/interactive/overlays/list-overlay.ts +606 -0
  836. package/src/interactive/overlays/message-picker.ts +155 -0
  837. package/src/interactive/overlays/model-selector.ts +1091 -0
  838. package/src/interactive/overlays/prompts.ts +72 -0
  839. package/src/interactive/overlays/session-selector-search.ts +31 -0
  840. package/src/interactive/overlays/session-selector.ts +266 -0
  841. package/src/interactive/overlays/settings.ts +3363 -0
  842. package/src/interactive/overlays/skills-hub.ts +237 -0
  843. package/src/interactive/overlays/tree-selector.ts +387 -0
  844. package/src/interactive/permission-overlay.ts +170 -0
  845. package/src/interactive/render-trace.ts +125 -0
  846. package/src/interactive/renderers/branch-summary.ts +86 -0
  847. package/src/interactive/renderers/code-ink.ts +420 -0
  848. package/src/interactive/renderers/compaction-summary.ts +112 -0
  849. package/src/interactive/renderers/diff.ts +126 -0
  850. package/src/interactive/renderers/notice.ts +28 -0
  851. package/src/interactive/renderers/retry-status.ts +31 -0
  852. package/src/interactive/renderers/structured.ts +89 -0
  853. package/src/interactive/renderers/tool-execution.ts +1104 -0
  854. package/src/interactive/renderers/worker-entry.ts +264 -0
  855. package/src/interactive/session-last-turn.ts +186 -0
  856. package/src/interactive/session-transcript.ts +105 -0
  857. package/src/interactive/session-usage-reseed.ts +74 -0
  858. package/src/interactive/slash-autocomplete.ts +364 -0
  859. package/src/interactive/slash-commands.ts +1319 -0
  860. package/src/interactive/slash-spec.ts +453 -0
  861. package/src/interactive/status/controller.ts +256 -0
  862. package/src/interactive/status/index.ts +23 -0
  863. package/src/interactive/status/state-machine.ts +530 -0
  864. package/src/interactive/status/summary.ts +170 -0
  865. package/src/interactive/status/types.ts +121 -0
  866. package/src/interactive/status/verbs.ts +163 -0
  867. package/src/interactive/status/watchdog.ts +24 -0
  868. package/src/interactive/tasks-overlay.ts +186 -0
  869. package/src/interactive/theme/components.ts +55 -0
  870. package/src/interactive/theme/glyphs.ts +70 -0
  871. package/src/interactive/theme/index.ts +15 -0
  872. package/src/interactive/theme/labels.ts +88 -0
  873. package/src/interactive/theme/rules.ts +138 -0
  874. package/src/interactive/theme/segments.ts +88 -0
  875. package/src/interactive/theme/tokens.ts +121 -0
  876. package/src/interactive/thinking-level-policy.ts +6 -0
  877. package/src/interactive/tool-prose-loop.ts +122 -0
  878. package/src/interactive/tool-prose-registration.ts +48 -0
  879. package/src/interactive/turn-context.ts +854 -0
  880. package/src/interactive/turn-middleware.ts +283 -0
  881. package/src/interactive/turn-persistence.ts +441 -0
  882. package/src/interactive/turn-queues.ts +169 -0
  883. package/src/interactive/turn-recovery.ts +306 -0
  884. package/src/interactive/turn-runtime.ts +802 -0
  885. package/src/interactive/turn-state.ts +123 -0
  886. package/src/interactive/view/artifacts.ts +1342 -0
  887. package/src/interactive/view/view-overlay.ts +732 -0
  888. package/src/interactive/welcome-dashboard.ts +536 -0
  889. package/src/interactive/worker-receipts.ts +94 -0
  890. package/src/interactive/worker-replay.ts +111 -0
  891. package/src/interactive/worker-share.ts +100 -0
  892. package/src/interactive/worker-stream.ts +442 -0
  893. package/src/interactive/workspace-facts.ts +141 -0
  894. package/src/tools/agent-tools.ts +382 -0
  895. package/src/tools/artifact.ts +103 -0
  896. package/src/tools/ask-user.ts +656 -0
  897. package/src/tools/bash.ts +176 -0
  898. package/src/tools/bootstrap.ts +474 -0
  899. package/src/tools/codewiki/code-nav.ts +563 -0
  900. package/src/tools/codewiki/shared.ts +115 -0
  901. package/src/tools/compete-worktrees.ts +898 -0
  902. package/src/tools/context/docs-engine.ts +619 -0
  903. package/src/tools/context/index.ts +435 -0
  904. package/src/tools/credential-present.ts +151 -0
  905. package/src/tools/dispatch-arguments.ts +228 -0
  906. package/src/tools/dispatch-plan.ts +741 -0
  907. package/src/tools/dispatch-scout.ts +461 -0
  908. package/src/tools/dispatch.ts +3338 -0
  909. package/src/tools/edit-diff.ts +534 -0
  910. package/src/tools/edit.ts +128 -0
  911. package/src/tools/executables.ts +22 -0
  912. package/src/tools/file-mutation-queue.ts +35 -0
  913. package/src/tools/find.ts +292 -0
  914. package/src/tools/grep.ts +495 -0
  915. package/src/tools/ignore-policy.ts +169 -0
  916. package/src/tools/ledger.ts +206 -0
  917. package/src/tools/ls.ts +110 -0
  918. package/src/tools/monitor.ts +797 -0
  919. package/src/tools/network-policy.ts +29 -0
  920. package/src/tools/observation.ts +421 -0
  921. package/src/tools/observers.ts +99 -0
  922. package/src/tools/path-utils.ts +79 -0
  923. package/src/tools/policy.ts +154 -0
  924. package/src/tools/profiles.ts +108 -0
  925. package/src/tools/read.ts +173 -0
  926. package/src/tools/registry.ts +1157 -0
  927. package/src/tools/result-shaping.ts +204 -0
  928. package/src/tools/safe-exec.ts +128 -0
  929. package/src/tools/spawn-hygiene.ts +182 -0
  930. package/src/tools/steer.ts +88 -0
  931. package/src/tools/string-enum.ts +15 -0
  932. package/src/tools/tasks.ts +168 -0
  933. package/src/tools/truncate-utf8.ts +17 -0
  934. package/src/tools/truncate.ts +202 -0
  935. package/src/tools/verify/frontend.ts +685 -0
  936. package/src/tools/verify/index.ts +66 -0
  937. package/src/tools/verify/scripts.ts +108 -0
  938. package/src/tools/web-fetch.ts +777 -0
  939. package/src/tools/worker-evidence.ts +215 -0
  940. package/src/tools/write.ts +52 -0
  941. package/src/utils/exif-orientation.ts +192 -0
  942. package/src/utils/git.ts +24 -0
  943. package/src/utils/image-resize.ts +148 -0
  944. package/src/utils/photon.ts +103 -0
  945. package/src/worker/control-lane.ts +22 -0
  946. package/src/worker/entry.ts +257 -0
  947. package/src/worker/event-projection.ts +56 -0
  948. package/src/worker/heartbeat.ts +24 -0
  949. package/src/worker/ledger-mirror.ts +95 -0
  950. package/src/worker/ndjson.ts +40 -0
  951. package/src/worker/protocol.ts +529 -0
  952. package/src/worker/resource-facts.ts +79 -0
  953. package/src/worker/runtime-registry.ts +12 -0
  954. package/src/worker/spec-contract.ts +654 -0
  955. package/src/worker/stdin-demux.ts +316 -0
  956. package/dist/acp-UMLFVA3F.js +0 -92
  957. package/dist/chunk-262G75JS.js +0 -35
  958. package/dist/chunk-5LDRNKX2.js +0 -1063
  959. package/dist/chunk-67MTHP2E.js +0 -135
  960. package/dist/chunk-GOTUR54M.js +0 -9
  961. package/dist/chunk-TPOCL34A.js +0 -2876
  962. package/dist/chunk-XV4ZJ6ZM.js +0 -3177
  963. package/dist/clio-KIQ5SNDS.js +0 -53
  964. package/dist/configure-G4E3A2PG.js +0 -27
  965. package/dist/doctor-M5HJJZOL.js +0 -61
  966. package/dist/domains/agents/builtins/architect.md +0 -33
  967. package/dist/domains/agents/builtins/coder.md +0 -31
  968. package/dist/domains/agents/builtins/context-bootstrap.md +0 -38
  969. package/dist/domains/agents/builtins/debugger.md +0 -30
  970. package/dist/domains/agents/builtins/documenter.md +0 -31
  971. package/dist/domains/agents/builtins/git-master.md +0 -30
  972. package/dist/domains/agents/builtins/provenance.md +0 -30
  973. package/dist/domains/agents/builtins/researcher.md +0 -71
  974. package/dist/domains/agents/builtins/scout.md +0 -42
  975. package/dist/domains/agents/builtins/tester.md +0 -31
  976. package/dist/domains/agents/builtins/verifier.md +0 -30
  977. package/dist/domains/agents/builtins/wiki-writer.md +0 -41
  978. package/dist/fleet-preflight-CLIAX7YR.js +0 -21
  979. package/dist/preload-KZVHET2B.js +0 -11
  980. package/dist/version-ROZ6CZKH.js +0 -16
  981. package/skills/git/commit-crafting/SKILL.md +0 -79
  982. package/skills/git/commit-crafting/evals.md +0 -92
  983. package/skills/git/create-pr/SKILL.md +0 -116
  984. package/skills/git/create-pr/evals.md +0 -114
  985. package/skills/git/investigate-issue/SKILL.md +0 -139
  986. package/skills/git/investigate-issue/evals.md +0 -94
  987. package/skills/git/review-changes/SKILL.md +0 -103
  988. package/skills/git/review-changes/evals.md +0 -85
@@ -0,0 +1,1265 @@
1
+ import { createHash } from "node:crypto";
2
+ import path from "node:path";
3
+ import { parseJsonObjectPayload } from "../../core/json-payload.js";
4
+ import { AGENT_AUTOMATION_AUTHORITIES, type AgentAutomationAuthority } from "./spec.js";
5
+
6
+ export type ResultContract =
7
+ | { kind: "architect-plan"; path: string }
8
+ | { kind: "scout-report" }
9
+ | { kind: "verifier-report" }
10
+ | { kind: "debugger-report" }
11
+ | { kind: "research-report" }
12
+ | { kind: "mutation-report" }
13
+ | { kind: "provenance-report" }
14
+ | { kind: "external-delegation" }
15
+ /**
16
+ * The run's postcondition is the artifact it left on disk, so its terminal
17
+ * text carries no claim to validate. Only the caller that named the output
18
+ * location can check the artifact, and it does so by reading the location
19
+ * rather than by believing a report. A writer asked for a typed report
20
+ * instead has to invent one: a small model handed `mutation-report` for a
21
+ * documentation pass routinely seals a fabricated passing `npm test` entry,
22
+ * which is a false correctness signal produced purely to satisfy a shape.
23
+ * Recipes may declare this kind; Scout subtasks may not request it, because
24
+ * a subtask's result is consumed as data by its dependents.
25
+ */
26
+ | { kind: "artifact-report" }
27
+ /**
28
+ * The CLIO-CODER.md handbook payload `clio-coder context init` parses. It exists as its
29
+ * own kind because the alternative was dispatching Scout and telling it in
30
+ * prose to ignore its own recipe: the recipe body and the repair directive
31
+ * both name the findings shape, so a model that obeys the recipe returns
32
+ * reconnaissance and the bootstrap parser rejects every run. A contract is
33
+ * the wrong thing to override with a sentence in a task prompt.
34
+ * Scout subtasks may not request it; it is a command's payload, not a
35
+ * dependency edge.
36
+ */
37
+ | { kind: "context-handbook" }
38
+ /**
39
+ * A deterministic command's structured result. No agent recipe may declare
40
+ * it (`parseResultContract` rejects the kind) and no Scout subtask may
41
+ * request it: it is authored by the code-step runner, never by a model. It
42
+ * lives in this union so a code step's terminal result is validated, sealed,
43
+ * and handed across plan edges through exactly the same door an agent's
44
+ * report uses.
45
+ */
46
+ | { kind: "code-report" };
47
+
48
+ export type ResultContractQuality = "pass" | "fail" | "unmeasured";
49
+
50
+ export interface ResultContractValidation {
51
+ /** Whether the declared postcondition itself was met. */
52
+ conformance: "pass" | "fail";
53
+ /** Only correctness-bearing contracts can produce a routing-quality label. */
54
+ quality: ResultContractQuality;
55
+ sourceId: string;
56
+ validatorDigest: string;
57
+ /** Parsed Scout data for the model-facing dispatch projection. */
58
+ scout?: ScoutResult;
59
+ /** Parsed Verifier data for the dispatch review-gate projection. */
60
+ verifier?: VerifierResult;
61
+ reason?: string;
62
+ }
63
+
64
+ export interface ResultContractFilesystem {
65
+ readFile(path: string): string | null;
66
+ /**
67
+ * Whether anything exists at this location. Optional because most contracts
68
+ * only ever need a file's bytes; a mutation report needs presence, since a
69
+ * run legitimately creates directories and writes through channels no tool
70
+ * event enumerates. Absent means presence is unobservable here, and the
71
+ * mutation grounding below degrades to the quality label rather than
72
+ * calling an unreadable path fabricated.
73
+ */
74
+ pathExists?(path: string): boolean;
75
+ }
76
+
77
+ /**
78
+ * Inclusive `[start, end]` line spans a run actually observed, by absolute
79
+ * path. Grounding is only checkable where this evidence exists, which is the
80
+ * worker that made the reads.
81
+ */
82
+ export type ObservedReadRanges = ReadonlyMap<string, ReadonlyArray<readonly [number, number]>>;
83
+
84
+ /**
85
+ * The write-side counterpart of `ObservedReadRanges`: what this run's own tool
86
+ * calls show it changed and ran. Both are recorded by the layer that watched
87
+ * the tool stream (`domains/safety/run-effects.ts`).
88
+ */
89
+ export interface ObservedRunEffects {
90
+ /** Absolute paths the run's successful tool calls aimed a mutation at. */
91
+ mutatedPaths: ReadonlySet<string>;
92
+ /** Absolute paths whose only mutation attempt came back blocked or errored. */
93
+ failedMutationPaths: ReadonlySet<string>;
94
+ /** Canonical validation commands the run ran to a clean exit. */
95
+ validationCommands: ReadonlySet<string>;
96
+ }
97
+
98
+ export interface ResultContractValidationInput {
99
+ contract: ResultContract;
100
+ output: string | null;
101
+ cwd: string;
102
+ networkAllowed: boolean;
103
+ filesystem: ResultContractFilesystem;
104
+ /**
105
+ * Line spans this run read. When supplied, a cited line must fall inside
106
+ * one, which turns "this line exists in the file" into "this run looked at
107
+ * this line". Absent means grounding is not observable at this layer and
108
+ * only the weaker existence check applies.
109
+ */
110
+ observedReadRanges?: ObservedReadRanges;
111
+ /**
112
+ * What this run did to the workspace. When supplied, a mutation report is
113
+ * measured against it instead of being believed. Absent means the effects
114
+ * are not observable at this layer and the report's own word stands, which
115
+ * is what every caller got before grounding existed.
116
+ */
117
+ observedRunEffects?: ObservedRunEffects;
118
+ }
119
+
120
+ /**
121
+ * Receipt-ready projection of the typed result validator.
122
+ *
123
+ * `not-reached` is the third conformance state and is not a soft failure. A
124
+ * declared postcondition is only an applicable check once the run got far
125
+ * enough to produce a terminal result. A worker that crashed before its first
126
+ * token, a target that could not load the model, an operator abort, and an
127
+ * engine loop-guard abort all leave the contract unevaluated. Recording those
128
+ * as `fail` invents correctness evidence out of infrastructure noise, so they
129
+ * seal `not-reached` and stay out of the routing quality denominator.
130
+ */
131
+ export interface ResultContractFact {
132
+ sourceId: string;
133
+ validatorDigest: string;
134
+ conformance: "pass" | "fail" | "not-reached";
135
+ quality: ResultContractQuality;
136
+ }
137
+
138
+ export interface ValidateRecipeResultInput {
139
+ contract: ResultContract | null;
140
+ output: string | null;
141
+ cwd: string;
142
+ networkAllowed: boolean;
143
+ filesystem: ResultContractFilesystem;
144
+ /**
145
+ * Whether the run reached the point where its terminal result was due. The
146
+ * caller owns this judgement because only it knows how the attempt ended.
147
+ */
148
+ reachedTerminalResult: boolean;
149
+ /** What the run's tool calls show it changed and ran, when observed. */
150
+ observedRunEffects?: ObservedRunEffects;
151
+ }
152
+
153
+ /**
154
+ * A declared contract that never got to run. `applicable: false` carries the
155
+ * contract's identity so offline replay still knows which postcondition was in
156
+ * force, while contributing no correctness label.
157
+ */
158
+ export type RecipeResultOutcome =
159
+ | { applicable: true; validation: ResultContractValidation; fact: ResultContractFact }
160
+ | { applicable: false; fact: ResultContractFact };
161
+
162
+ export interface ScoutCitation {
163
+ path: string;
164
+ line: number;
165
+ }
166
+
167
+ /** One reconnaissance claim and the live-read location that grounds it. */
168
+ export interface ScoutFinding extends ScoutCitation {
169
+ claim: string;
170
+ }
171
+
172
+ export interface ScoutResult {
173
+ findings: ReadonlyArray<ScoutFinding>;
174
+ /** Grounding locations projected from findings, in reported order. */
175
+ citations: ReadonlyArray<ScoutCitation>;
176
+ needsSplit: boolean;
177
+ proposedSubtasks: ReadonlyArray<ScoutSubtask>;
178
+ /**
179
+ * Claims salvaged from a degraded result that carry no citation this run can
180
+ * ground. They are leads, never evidence, and they exist so a small model's
181
+ * observations survive a terminal shape it could not emit. Absent on a
182
+ * strictly conforming result.
183
+ */
184
+ ungroundedClaims?: ReadonlyArray<string>;
185
+ /**
186
+ * The validator's own reason for accepting a degraded shape. Its presence is
187
+ * the flag: any consumer that needs strict Scout data checks for it. Absent
188
+ * on a strictly conforming result.
189
+ */
190
+ degradedReason?: string;
191
+ }
192
+
193
+ /** Strict Scout-authored data. Every execution/control field is coordinator-owned. */
194
+ export interface ScoutSubtask {
195
+ id: string;
196
+ task: string;
197
+ dependencies: ReadonlyArray<string>;
198
+ expectedResultContract: ResultContract["kind"];
199
+ requestedAuthority: AgentAutomationAuthority;
200
+ }
201
+
202
+ export interface VerifierCheck {
203
+ name: string;
204
+ passed: boolean;
205
+ evidence: string;
206
+ }
207
+
208
+ /** Parsed `verifier-report` payload, for callers that need the verdict itself. */
209
+ export interface VerifierResult {
210
+ verdict: "pass" | "fail";
211
+ checks: ReadonlyArray<VerifierCheck>;
212
+ }
213
+
214
+ /**
215
+ * Parsed `code-report` payload. `passed` restates `exitCode === 0` so a
216
+ * downstream reader never has to know a runner's exit conventions, and
217
+ * `outputExcerpt` is the command's own bytes so a builder repairs from what
218
+ * the command printed rather than from someone's summary of it.
219
+ */
220
+ export interface CodeReportResult {
221
+ passed: boolean;
222
+ exitCode: number;
223
+ checks: ReadonlyArray<VerifierCheck>;
224
+ artifactPaths: ReadonlyArray<string>;
225
+ outputExcerpt: string;
226
+ }
227
+
228
+ function canonical(value: unknown): string {
229
+ if (value === null) return "null";
230
+ if (typeof value === "string" || typeof value === "boolean") return JSON.stringify(value);
231
+ if (typeof value === "number") {
232
+ if (!Number.isFinite(value)) throw new Error("result contract cannot digest non-finite numbers");
233
+ return JSON.stringify(value);
234
+ }
235
+ if (Array.isArray(value)) return `[${value.map(canonical).join(",")}]`;
236
+ if (typeof value === "object") {
237
+ const record = value as Record<string, unknown>;
238
+ return `{${Object.keys(record)
239
+ .sort()
240
+ .map((key) => `${JSON.stringify(key)}:${canonical(record[key])}`)
241
+ .join(",")}}`;
242
+ }
243
+ throw new Error(`result contract cannot digest ${typeof value}`);
244
+ }
245
+
246
+ function digest(value: unknown): string {
247
+ return createHash("sha256").update(canonical(value), "utf8").digest("hex");
248
+ }
249
+
250
+ export function resultContractDigest(contract: ResultContract): string {
251
+ return digest(contract);
252
+ }
253
+
254
+ export function resultContractSourceId(contract: ResultContract): string {
255
+ return `agent-result-contract:${contract.kind}:${resultContractDigest(contract)}`;
256
+ }
257
+
258
+ function failure(contract: ResultContract, quality: ResultContractQuality, reason: string): ResultContractValidation {
259
+ return {
260
+ conformance: "fail",
261
+ quality,
262
+ sourceId: resultContractSourceId(contract),
263
+ validatorDigest: digest({ contract, reason }),
264
+ reason,
265
+ };
266
+ }
267
+
268
+ function success(
269
+ contract: ResultContract,
270
+ quality: ResultContractQuality,
271
+ value: unknown,
272
+ extra: Pick<ResultContractValidation, "scout" | "verifier" | "reason"> = {},
273
+ ): ResultContractValidation {
274
+ return {
275
+ conformance: "pass",
276
+ quality,
277
+ sourceId: resultContractSourceId(contract),
278
+ validatorDigest: digest({ contract, value }),
279
+ ...extra,
280
+ };
281
+ }
282
+
283
+ /**
284
+ * Read the JSON object a terminal result carries. Every contract prompt asks
285
+ * for bare JSON and a fence is the deviation local models reach for first, so
286
+ * refusing one burns both repair rounds and fails a run whose payload was
287
+ * correct. Widening the span that is searched does not widen what conforms: a
288
+ * candidate still has to parse and still has to be an object, and the per-kind
289
+ * validators still own every field.
290
+ */
291
+ function parseJson(
292
+ output: string | null,
293
+ ): { ok: true; value: Record<string, unknown> } | { ok: false; reason: string } {
294
+ if (output === null || output.trim().length === 0) return { ok: false, reason: "missing final result" };
295
+ const parsed = parseJsonObjectPayload(output);
296
+ if (parsed.ok) return parsed;
297
+ return {
298
+ ok: false,
299
+ reason: parsed.reason === "not-object" ? "result must be a JSON object" : "result must be valid JSON",
300
+ };
301
+ }
302
+
303
+ function hasOnlyKeys(value: Record<string, unknown>, keys: ReadonlyArray<string>): boolean {
304
+ const allowed = new Set(keys);
305
+ return Object.keys(value).every((key) => allowed.has(key));
306
+ }
307
+
308
+ function string(value: unknown): value is string {
309
+ return typeof value === "string" && value.trim().length > 0;
310
+ }
311
+
312
+ function parseFindings(value: unknown): ScoutFinding[] | null {
313
+ if (!Array.isArray(value)) return null;
314
+ const findings: ScoutFinding[] = [];
315
+ for (const entry of value) {
316
+ if (entry === null || typeof entry !== "object" || Array.isArray(entry)) return null;
317
+ const finding = entry as Record<string, unknown>;
318
+ const line = finding.line;
319
+ if (
320
+ !hasOnlyKeys(finding, ["claim", "path", "line"]) ||
321
+ !string(finding.claim) ||
322
+ !string(finding.path) ||
323
+ typeof line !== "number" ||
324
+ !Number.isSafeInteger(line) ||
325
+ line < 1
326
+ ) {
327
+ return null;
328
+ }
329
+ findings.push({ claim: finding.claim, path: finding.path, line });
330
+ }
331
+ return findings;
332
+ }
333
+
334
+ const RESULT_CONTRACT_KINDS: ReadonlyArray<ResultContract["kind"]> = [
335
+ "architect-plan",
336
+ "scout-report",
337
+ "verifier-report",
338
+ "debugger-report",
339
+ "research-report",
340
+ "mutation-report",
341
+ "provenance-report",
342
+ "external-delegation",
343
+ ];
344
+
345
+ function parseSubtasks(value: unknown): ScoutSubtask[] | null {
346
+ if (!Array.isArray(value) || value.length > 4) return null;
347
+ const subtasks: ScoutSubtask[] = [];
348
+ const ids = new Set<string>();
349
+ for (const entry of value) {
350
+ if (entry === null || typeof entry !== "object" || Array.isArray(entry)) return null;
351
+ const subtask = entry as Record<string, unknown>;
352
+ if (
353
+ !hasOnlyKeys(subtask, ["id", "task", "dependencies", "expectedResultContract", "requestedAuthority"]) ||
354
+ !string(subtask.id) ||
355
+ !/^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/u.test(subtask.id) ||
356
+ ids.has(subtask.id) ||
357
+ !string(subtask.task) ||
358
+ Buffer.byteLength(subtask.task, "utf8") > 4096 ||
359
+ !Array.isArray(subtask.dependencies) ||
360
+ subtask.dependencies.length > 4 ||
361
+ subtask.dependencies.some((dependency) => !string(dependency)) ||
362
+ new Set(subtask.dependencies).size !== subtask.dependencies.length ||
363
+ !RESULT_CONTRACT_KINDS.includes(subtask.expectedResultContract as ResultContract["kind"]) ||
364
+ !AGENT_AUTOMATION_AUTHORITIES.includes(subtask.requestedAuthority as AgentAutomationAuthority)
365
+ ) {
366
+ return null;
367
+ }
368
+ ids.add(subtask.id);
369
+ subtasks.push({
370
+ id: subtask.id,
371
+ task: subtask.task,
372
+ dependencies: [...subtask.dependencies] as string[],
373
+ expectedResultContract: subtask.expectedResultContract as ResultContract["kind"],
374
+ requestedAuthority: subtask.requestedAuthority as AgentAutomationAuthority,
375
+ });
376
+ }
377
+ for (const subtask of subtasks) {
378
+ if (subtask.dependencies.some((dependency) => dependency === subtask.id || !ids.has(dependency))) return null;
379
+ }
380
+ const remaining = new Set(ids);
381
+ const completed = new Set<string>();
382
+ while (remaining.size > 0) {
383
+ const ready = subtasks.filter(
384
+ (subtask) => remaining.has(subtask.id) && subtask.dependencies.every((dependency) => completed.has(dependency)),
385
+ );
386
+ if (ready.length === 0) return null;
387
+ for (const subtask of ready) {
388
+ remaining.delete(subtask.id);
389
+ completed.add(subtask.id);
390
+ }
391
+ }
392
+ return subtasks;
393
+ }
394
+
395
+ function isContextHandbookResult(value: Record<string, unknown>): boolean {
396
+ if (!hasOnlyKeys(value, ["projectName", "identity", "conventions", "invariants", "sections"])) return false;
397
+ if (!string(value.projectName) || !string(value.identity)) return false;
398
+ if (!Array.isArray(value.conventions) || value.conventions.some((entry) => !string(entry))) return false;
399
+ if (!Array.isArray(value.invariants) || value.invariants.some((entry) => !string(entry))) return false;
400
+ if (!Array.isArray(value.sections)) return false;
401
+ return value.sections.every((entry) => {
402
+ if (entry === null || typeof entry !== "object" || Array.isArray(entry)) return false;
403
+ const section = entry as Record<string, unknown>;
404
+ return hasOnlyKeys(section, ["title", "body"]) && string(section.title) && string(section.body);
405
+ });
406
+ }
407
+
408
+ /**
409
+ * The handbook payload conforms or it does not. Quality stays unmeasured: a
410
+ * well-formed handbook is a shape, not evidence that the repository was read
411
+ * correctly, and routing statistics must not treat it as a correctness signal.
412
+ */
413
+ function validateContextHandbook(contract: ResultContract, output: string | null): ResultContractValidation {
414
+ const parsed = parseJson(output);
415
+ if (!parsed.ok) return failure(contract, "fail", parsed.reason);
416
+ if (!isContextHandbookResult(parsed.value)) {
417
+ return failure(
418
+ contract,
419
+ "fail",
420
+ "context handbook result must carry projectName, identity, conventions[], invariants[], and sections[{title, body}] and nothing else",
421
+ );
422
+ }
423
+ return success(contract, "unmeasured", parsed.value);
424
+ }
425
+
426
+ /**
427
+ * Everything a degraded Scout result still carries: the claims themselves,
428
+ * split by whether a `path`/`line` came with them. Deliberately lenient where
429
+ * `parseFindings` is strict, because this runs only after the strict parse has
430
+ * already failed and the alternative to leniency is discarding the run.
431
+ */
432
+ function salvageScoutClaims(value: unknown): { grounded: ScoutFinding[]; ungrounded: string[] } {
433
+ const grounded: ScoutFinding[] = [];
434
+ const ungrounded: string[] = [];
435
+ if (!Array.isArray(value)) return { grounded, ungrounded };
436
+ for (const entry of value) {
437
+ if (entry === null || typeof entry !== "object" || Array.isArray(entry)) continue;
438
+ const finding = entry as Record<string, unknown>;
439
+ if (!string(finding.claim)) continue;
440
+ const line = finding.line;
441
+ if (string(finding.path) && typeof line === "number" && Number.isSafeInteger(line) && line >= 1) {
442
+ grounded.push({ claim: finding.claim, path: finding.path, line });
443
+ continue;
444
+ }
445
+ ungrounded.push(finding.claim);
446
+ }
447
+ return { grounded, ungrounded };
448
+ }
449
+
450
+ /**
451
+ * A degraded acceptance. The strict contract is the goal, not the point: on a
452
+ * small local model the `{claim, path, line}` shape is close to a coin flip,
453
+ * and the E19 drive lost an entire 51k-token reconnaissance run because two
454
+ * bounded repair rounds could not land it. Nothing about the evidence was
455
+ * wrong; only the envelope was, and failing the run threw the evidence away
456
+ * with it.
457
+ *
458
+ * So a result that still carries usable claims conforms, and the claims reach
459
+ * the parent. Quality is `unmeasured`, never `pass`: a shape this validator had
460
+ * to repair is not correctness evidence, and routing statistics must not
461
+ * inherit one. `degradedReason` marks it for every consumer that needs the
462
+ * strict data, and `parseScoutResult` refuses it outright, so a degraded run
463
+ * can never become a `from_scout` continuation source.
464
+ */
465
+ function degradedScout(
466
+ contract: ResultContract,
467
+ value: Record<string, unknown>,
468
+ reason: string,
469
+ ): ResultContractValidation | null {
470
+ const salvaged = salvageScoutClaims(value.findings);
471
+ if (salvaged.grounded.length === 0 && salvaged.ungrounded.length === 0) return null;
472
+ const degradedReason = `${reason} (accepted as a degraded reconnaissance result; findings are leads, not validation evidence)`;
473
+ // needsSplit is forced false and subtasks dropped: a subtask is control-plane
474
+ // data a coordinator acts on, so a malformed one is never repaired here.
475
+ const scout: ScoutResult = {
476
+ findings: salvaged.grounded,
477
+ citations: salvaged.grounded.map(({ path: citedPath, line }) => ({ path: citedPath, line })),
478
+ needsSplit: false,
479
+ proposedSubtasks: [],
480
+ ungroundedClaims: salvaged.ungrounded,
481
+ degradedReason,
482
+ };
483
+ return success(contract, "unmeasured", scout, { scout, reason: degradedReason });
484
+ }
485
+
486
+ function validateScout(contract: ResultContract, output: string | null): ResultContractValidation {
487
+ const parsed = parseJson(output);
488
+ // Nothing to salvage from bytes that are not a JSON object.
489
+ if (!parsed.ok) return failure(contract, "fail", parsed.reason);
490
+ const value = parsed.value;
491
+ // Every strict rejection below falls through to `degrade`, which returns the
492
+ // strict failure unchanged when the result carries no usable claim either.
493
+ const degrade = (reason: string): ResultContractValidation =>
494
+ degradedScout(contract, value, reason) ?? failure(contract, "fail", reason);
495
+ if (!hasOnlyKeys(value, ["findings", "needsSplit", "proposedSubtasks"])) {
496
+ return degrade("Scout result has unknown fields");
497
+ }
498
+ const findings = parseFindings(value.findings);
499
+ const proposedSubtasks = parseSubtasks(value.proposedSubtasks);
500
+ if (findings === null || typeof value.needsSplit !== "boolean" || proposedSubtasks === null) {
501
+ return degrade(
502
+ "Scout result must carry findings as {claim, path, line} objects, needsSplit, and 0..4 typed proposed subtasks",
503
+ );
504
+ }
505
+ if (value.needsSplit !== proposedSubtasks.length > 0) {
506
+ return degrade("Scout needsSplit must agree with proposedSubtasks");
507
+ }
508
+ // A grounded report needs at least one cited claim. A split recommendation
509
+ // is the explicit exception: it reports that the task did not fit, so it
510
+ // carries subtasks instead of findings.
511
+ if (findings.length === 0 && !value.needsSplit) {
512
+ return degrade("Scout result must carry at least one cited finding, or set needsSplit");
513
+ }
514
+ if (value.needsSplit && findings.length > 0) {
515
+ return degrade("Scout split recommendations carry typed subtasks instead of findings");
516
+ }
517
+ const scout: ScoutResult = {
518
+ findings,
519
+ citations: findings.map(({ path: citedPath, line }) => ({ path: citedPath, line })),
520
+ needsSplit: value.needsSplit,
521
+ proposedSubtasks,
522
+ };
523
+ return success(contract, "pass", scout, { scout });
524
+ }
525
+
526
+ function parseChecks(value: unknown): VerifierCheck[] | null {
527
+ if (!Array.isArray(value) || value.length === 0) return null;
528
+ const checks: VerifierCheck[] = [];
529
+ for (const entry of value) {
530
+ if (entry === null || typeof entry !== "object" || Array.isArray(entry)) return null;
531
+ const check = entry as Record<string, unknown>;
532
+ if (
533
+ !hasOnlyKeys(check, ["name", "passed", "evidence"]) ||
534
+ !string(check.name) ||
535
+ typeof check.passed !== "boolean" ||
536
+ !string(check.evidence)
537
+ ) {
538
+ return null;
539
+ }
540
+ checks.push({ name: check.name, passed: check.passed, evidence: check.evidence });
541
+ }
542
+ return checks;
543
+ }
544
+
545
+ type ScoutCitationEvidence = ScoutCitation & { contentDigest: string };
546
+
547
+ /** One citation against the workspace and, where known, against this run's own reads. */
548
+ function validateScoutCitation(
549
+ input: ResultContractValidationInput,
550
+ citation: ScoutCitation,
551
+ ): { ok: true; evidence: ScoutCitationEvidence } | { ok: false; reason: string } {
552
+ const cwd = path.resolve(input.cwd);
553
+ const citedPath = path.resolve(cwd, citation.path);
554
+ const relative = path.relative(cwd, citedPath);
555
+ if (relative === "" || relative.startsWith(`..${path.sep}`) || relative === ".." || path.isAbsolute(relative)) {
556
+ return { ok: false, reason: `Scout citation path escapes the workspace: ${citation.path}` };
557
+ }
558
+ const content = input.filesystem.readFile(citedPath);
559
+ if (content === null) return { ok: false, reason: `Scout citation cannot be read: ${citation.path}` };
560
+ const lineCount = content.split(/\r\n|\r|\n/u).length;
561
+ if (citation.line > lineCount) {
562
+ return { ok: false, reason: `Scout citation is past end of file: ${citation.path}:${citation.line}` };
563
+ }
564
+ // Grounding: a line that exists is not a line anyone looked at. Where the
565
+ // run's own read spans are known, the cited line has to fall inside one,
566
+ // so an approximated or inferred line number cannot pass as observation.
567
+ if (input.observedReadRanges !== undefined) {
568
+ const spans = input.observedReadRanges.get(citedPath) ?? [];
569
+ if (!spans.some(([start, end]) => citation.line >= start && citation.line <= end)) {
570
+ const observed =
571
+ spans.length === 0
572
+ ? "this run never read that file"
573
+ : `this run read only ${spans.map(([start, end]) => `${start}-${end}`).join(", ")}`;
574
+ return {
575
+ ok: false,
576
+ reason: `Scout citation is not grounded in a live read: ${citation.path}:${citation.line} (${observed})`,
577
+ };
578
+ }
579
+ }
580
+ return {
581
+ ok: true,
582
+ evidence: { ...citation, contentDigest: createHash("sha256").update(content, "utf8").digest("hex") },
583
+ };
584
+ }
585
+
586
+ /**
587
+ * Every citation on a strictly conforming result has to ground. One that does
588
+ * not is a fabricated location on a report claiming `pass`, so it fails the
589
+ * whole result; this check is the only thing standing between an invented
590
+ * `path:line` and a quality label the router believes.
591
+ */
592
+ function validateScoutCitations(
593
+ input: ResultContractValidationInput,
594
+ citations: ReadonlyArray<ScoutCitation>,
595
+ ): { ok: true; evidence: ReadonlyArray<ScoutCitationEvidence> } | { ok: false; reason: string } {
596
+ const evidence: ScoutCitationEvidence[] = [];
597
+ for (const citation of citations) {
598
+ const checked = validateScoutCitation(input, citation);
599
+ if (!checked.ok) return checked;
600
+ evidence.push(checked.evidence);
601
+ }
602
+ return { ok: true, evidence };
603
+ }
604
+
605
+ /**
606
+ * Ground a degraded result without ever failing it. On a strict result an
607
+ * ungrounded citation is fabrication and fails the run; here the result already
608
+ * carries no correctness label, so a citation that does not ground is simply
609
+ * dropped and its claim demoted to an ungrounded lead. The parent gets what the
610
+ * run actually observed, correctly labeled, instead of nothing.
611
+ */
612
+ function groundDegradedScout(
613
+ contract: ResultContract,
614
+ input: ResultContractValidationInput,
615
+ scout: ScoutResult,
616
+ degradedReason: string,
617
+ ): ResultContractValidation {
618
+ const grounded: ScoutFinding[] = [];
619
+ const evidence: ScoutCitationEvidence[] = [];
620
+ const demoted: string[] = [];
621
+ for (const finding of scout.findings) {
622
+ const checked = validateScoutCitation(input, { path: finding.path, line: finding.line });
623
+ if (checked.ok) {
624
+ grounded.push(finding);
625
+ evidence.push(checked.evidence);
626
+ continue;
627
+ }
628
+ demoted.push(finding.claim);
629
+ }
630
+ const degraded: ScoutResult = {
631
+ findings: grounded,
632
+ citations: grounded.map(({ path: citedPath, line }) => ({ path: citedPath, line })),
633
+ needsSplit: false,
634
+ proposedSubtasks: [],
635
+ ungroundedClaims: [...(scout.ungroundedClaims ?? []), ...demoted],
636
+ degradedReason,
637
+ };
638
+ return success(contract, "unmeasured", { scout: degraded, evidence }, { scout: degraded, reason: degradedReason });
639
+ }
640
+
641
+ function validateVerifier(contract: ResultContract, output: string | null): ResultContractValidation {
642
+ const parsed = parseJson(output);
643
+ if (!parsed.ok) return failure(contract, "fail", parsed.reason);
644
+ const value = parsed.value;
645
+ if (!hasOnlyKeys(value, ["verdict", "checks"]) || (value.verdict !== "pass" && value.verdict !== "fail")) {
646
+ return failure(contract, "fail", "Verifier result must carry pass or fail verdict and checks");
647
+ }
648
+ const checks = parseChecks(value.checks);
649
+ if (checks === null || (value.verdict === "pass") !== checks.every((check) => check.passed)) {
650
+ return failure(contract, "fail", "Verifier verdict must agree with every typed check");
651
+ }
652
+ const verifier: VerifierResult = { verdict: value.verdict, checks };
653
+ return success(contract, value.verdict, verifier, { verifier });
654
+ }
655
+
656
+ /**
657
+ * Parse a Verifier structured result under the same schema its recipe contract
658
+ * enforces. The review gate needs the verdict itself, not just its conformance
659
+ * label, so this exposes the parsed payload the way `parseScoutResult` does for
660
+ * reconnaissance. It defines no new schema.
661
+ */
662
+ export function parseVerifierResult(output: string | null): VerifierResult | null {
663
+ const validation = validateVerifier({ kind: "verifier-report" }, output);
664
+ return validation.verifier ?? null;
665
+ }
666
+
667
+ /**
668
+ * A code step's result is always `unmeasured` for routing quality. A red suite
669
+ * is evidence about the repository, not about the route that ran the command,
670
+ * and code steps are not routes: they never reach route history or the routing
671
+ * quality reducer. Conformance here judges the shape alone, so a failing
672
+ * command still produces a conformant report that crosses its outgoing edges.
673
+ */
674
+ function validateCodeReport(contract: ResultContract, output: string | null): ResultContractValidation {
675
+ const parsed = parseJson(output);
676
+ if (!parsed.ok) return failure(contract, "unmeasured", parsed.reason);
677
+ const value = parsed.value;
678
+ if (
679
+ !hasOnlyKeys(value, ["passed", "exitCode", "checks", "artifactPaths", "outputExcerpt"]) ||
680
+ typeof value.passed !== "boolean" ||
681
+ typeof value.exitCode !== "number" ||
682
+ !Number.isSafeInteger(value.exitCode) ||
683
+ typeof value.outputExcerpt !== "string" ||
684
+ !Array.isArray(value.artifactPaths) ||
685
+ value.artifactPaths.some((entry) => !string(entry))
686
+ ) {
687
+ return failure(
688
+ contract,
689
+ "unmeasured",
690
+ "Code result must carry passed, integer exitCode, checks, artifactPaths, and outputExcerpt",
691
+ );
692
+ }
693
+ const checks = parseChecks(value.checks);
694
+ if (checks === null) return failure(contract, "unmeasured", "Code result must carry typed checks");
695
+ if (value.passed !== (value.exitCode === 0) || value.passed !== checks.every((check) => check.passed)) {
696
+ return failure(contract, "unmeasured", "Code result passed must agree with its exit code and every check");
697
+ }
698
+ return success(contract, "unmeasured", value);
699
+ }
700
+
701
+ /** Parse a `code-report` payload for callers that need the structured result. */
702
+ export function parseCodeReport(output: string | null): CodeReportResult | null {
703
+ const validation = validateCodeReport({ kind: "code-report" }, output);
704
+ if (validation.conformance !== "pass" || output === null) return null;
705
+ // The same reader the validator used, so a fenced payload that passed
706
+ // validation cannot fail here on a re-parse of the raw text.
707
+ const parsed = parseJsonObjectPayload(output);
708
+ if (!parsed.ok) return null;
709
+ const value = parsed.value as unknown as CodeReportResult;
710
+ return {
711
+ passed: value.passed,
712
+ exitCode: value.exitCode,
713
+ checks: value.checks.map((check) => ({ ...check })),
714
+ artifactPaths: [...value.artifactPaths],
715
+ outputExcerpt: value.outputExcerpt,
716
+ };
717
+ }
718
+
719
+ /**
720
+ * Bytes of authored commit message a terminal result may carry. A commit
721
+ * subject and a short body fit; a pasted diff does not.
722
+ */
723
+ export const RESULT_COMMIT_MESSAGE_MAX_BYTES = 1_000;
724
+
725
+ /** Authored prose a work-product contract may carry beside its evidence. */
726
+ export interface ResultAuthorship {
727
+ /** The agent's proposed commit message for the work it just produced. */
728
+ commitMessage: string | null;
729
+ /** One-line description, used to build a deterministic fallback message. */
730
+ summary: string | null;
731
+ }
732
+
733
+ const AUTHORSHIP_FIELDS: ReadonlyArray<keyof ResultAuthorship> = ["commitMessage", "summary"];
734
+
735
+ function hasControlCharacters(value: string): boolean {
736
+ for (const character of value) {
737
+ const code = character.codePointAt(0) ?? 0;
738
+ if (code === 0x7f) return true;
739
+ if (code < 0x20 && character !== "\n" && character !== "\r" && character !== "\t") return true;
740
+ }
741
+ return false;
742
+ }
743
+
744
+ function normalizeAuthored(value: string): string {
745
+ return value.replace(/\r\n/gu, "\n").replace(/\r/gu, "\n").trim();
746
+ }
747
+
748
+ /**
749
+ * Optional authored fields, checked only for shape. Code owns committing; the
750
+ * agent only supplies the sentence, so the sentence is bounded and free of the
751
+ * control characters that would make a commit log unreadable.
752
+ */
753
+ function validateAuthorship(value: Record<string, unknown>): string | null {
754
+ for (const field of AUTHORSHIP_FIELDS) {
755
+ const raw = value[field];
756
+ // Absent, null, and blank are three spellings of the same thing: nothing
757
+ // was authored. `ResultAuthorship` types the field `string | null` and
758
+ // `resultContractAuthorship` already normalizes a blank to null, so
759
+ // failing here on a spelling this contract's own reader accepts ends a
760
+ // finished run over an optional field the agent correctly left empty.
761
+ if (raw === undefined || raw === null) continue;
762
+ if (typeof raw !== "string") return `${field} must be a string when present`;
763
+ if (raw.trim().length === 0) continue;
764
+ if (Buffer.byteLength(raw, "utf8") > RESULT_COMMIT_MESSAGE_MAX_BYTES) {
765
+ return `${field} must be at most ${RESULT_COMMIT_MESSAGE_MAX_BYTES} bytes`;
766
+ }
767
+ // Tab, newline, and carriage return are the only control bytes a message
768
+ // may carry; anything else would corrupt the log it lands in.
769
+ if (hasControlCharacters(raw)) return `${field} must not contain control characters`;
770
+ }
771
+ return null;
772
+ }
773
+
774
+ /**
775
+ * Read the authored commit message and summary from a terminal result.
776
+ *
777
+ * Only work-product contracts carry them: `mutation-report` validates them
778
+ * strictly as optional fields, and `architect-plan` reads them from a JSON
779
+ * answer if one was given, because that contract's postcondition is the plan
780
+ * artifact and its final text has never been constrained. Anything unreadable
781
+ * is simply absent, which the caller turns into its deterministic fallback
782
+ * rather than into a failed commit.
783
+ */
784
+ export function resultContractAuthorship(contract: ResultContract, output: string | null): ResultAuthorship {
785
+ const empty: ResultAuthorship = { commitMessage: null, summary: null };
786
+ if (contract.kind !== "mutation-report" && contract.kind !== "architect-plan") return empty;
787
+ const parsed = parseJson(output);
788
+ if (!parsed.ok || validateAuthorship(parsed.value) !== null) return empty;
789
+ const read = (field: keyof ResultAuthorship): string | null => {
790
+ const raw = parsed.value[field];
791
+ if (typeof raw !== "string") return null;
792
+ const normalized = normalizeAuthored(raw);
793
+ return normalized.length === 0 ? null : normalized;
794
+ };
795
+ return { commitMessage: read("commitMessage"), summary: read("summary") };
796
+ }
797
+
798
+ function validateDebugger(contract: ResultContract, output: string | null): ResultContractValidation {
799
+ const parsed = parseJson(output);
800
+ if (!parsed.ok) return failure(contract, "unmeasured", parsed.reason);
801
+ const value = parsed.value;
802
+ if (
803
+ !hasOnlyKeys(value, ["diagnosis", "reproduction", "evidence"]) ||
804
+ !string(value.diagnosis) ||
805
+ (value.reproduction !== "reproduced" &&
806
+ value.reproduction !== "not-reproduced" &&
807
+ value.reproduction !== "unknown") ||
808
+ !Array.isArray(value.evidence) ||
809
+ value.evidence.some((entry) => !string(entry))
810
+ ) {
811
+ return failure(
812
+ contract,
813
+ "unmeasured",
814
+ "Debugger result must carry diagnosis, reproduction status, and evidence without a verdict",
815
+ );
816
+ }
817
+ return success(contract, "unmeasured", value);
818
+ }
819
+
820
+ function validateResearch(
821
+ contract: ResultContract,
822
+ output: string | null,
823
+ networkAllowed: boolean,
824
+ ): ResultContractValidation {
825
+ const parsed = parseJson(output);
826
+ if (!parsed.ok) return failure(contract, "unmeasured", parsed.reason);
827
+ const value = parsed.value;
828
+ if (
829
+ !hasOnlyKeys(value, ["source", "findings"]) ||
830
+ (value.source !== "local" && value.source !== "external") ||
831
+ !Array.isArray(value.findings)
832
+ ) {
833
+ return failure(
834
+ contract,
835
+ "unmeasured",
836
+ "Research result must distinguish local or external sources and carry findings",
837
+ );
838
+ }
839
+ if (value.source === "external" && !networkAllowed) {
840
+ return failure(contract, "unmeasured", "external research requires an allowed network posture");
841
+ }
842
+ for (const finding of value.findings) {
843
+ if (finding === null || typeof finding !== "object" || Array.isArray(finding)) {
844
+ return failure(contract, "unmeasured", "Research findings must be objects");
845
+ }
846
+ const record = finding as Record<string, unknown>;
847
+ if (!hasOnlyKeys(record, ["claim", "evidence"]) || !string(record.claim) || !string(record.evidence)) {
848
+ return failure(contract, "unmeasured", "Research findings must carry claim and evidence");
849
+ }
850
+ }
851
+ return success(contract, "unmeasured", value);
852
+ }
853
+
854
+ /** Paths this run wrote, as workspace-relative names, for a validator reason. */
855
+ function describeWriteSet(effects: ObservedRunEffects, cwd: string): string {
856
+ if (effects.mutatedPaths.size === 0) return "this run wrote nothing";
857
+ const written = [...effects.mutatedPaths]
858
+ .map((target) => path.relative(cwd, target) || target)
859
+ .sort()
860
+ .slice(0, MUTATION_WRITE_SET_REASON_LIMIT);
861
+ const more = effects.mutatedPaths.size - written.length;
862
+ return `this run wrote ${written.join(", ")}${more > 0 ? ` (+${more} more)` : ""}`;
863
+ }
864
+
865
+ /** Written paths quoted back in one validator reason before it is truncated. */
866
+ const MUTATION_WRITE_SET_REASON_LIMIT = 8;
867
+
868
+ /**
869
+ * Whether anything is at this location. Without a presence check the validator
870
+ * cannot tell a fabricated path from a directory or an unreadable file, so it
871
+ * answers yes and lets the quality label carry the doubt.
872
+ */
873
+ function pathIsPresent(filesystem: ResultContractFilesystem, target: string): boolean {
874
+ if (filesystem.pathExists === undefined) return true;
875
+ return filesystem.pathExists(target);
876
+ }
877
+
878
+ /** One `validations` entry, quoted by every reason that rejects the array. */
879
+ const MUTATION_VALIDATION_EXAMPLE = '{"name":"npm test","passed":true,"evidence":"exit 0"}';
880
+
881
+ /**
882
+ * Why a `validations` array was refused, in terms the model can act on. Naming
883
+ * the requirement was not enough for a small local model (#74): a run that
884
+ * emitted `"validations":[]` read the reason as satisfied, spent both repair
885
+ * rounds re-emitting the same empty array, and failed `result_contract_exhausted`.
886
+ * The two ways to get this wrong need different corrections, so each reason
887
+ * says which one happened and shows the entry that would have passed.
888
+ */
889
+ function mutationValidationsReason(value: unknown): string {
890
+ const empty = Array.isArray(value) && value.length === 0;
891
+ if (empty) {
892
+ return `Mutation result must carry typed validation results: validations was empty. Emit one entry per check this run actually made, each shaped like ${MUTATION_VALIDATION_EXAMPLE}. A run that only read files still names the read and cites what it saw.`;
893
+ }
894
+ return `Mutation result must carry typed validation results: every validations entry is shaped like ${MUTATION_VALIDATION_EXAMPLE}, with a string name, a boolean passed, a string evidence, and no other keys.`;
895
+ }
896
+
897
+ /**
898
+ * A mutation report states what the run changed and what it validated. Shape
899
+ * alone cannot tell either claim from an invention, and the shape example this
900
+ * module prints ends up echoed verbatim by small models, so a run that touched
901
+ * nothing has sealed `mutatedPaths: ["src/file.ts"]` as conforming fact.
902
+ *
903
+ * Where the run's own effects were observed, each reported path is measured
904
+ * against them:
905
+ * - in the write set -> the run did this, and it is verified
906
+ * - its only attempt came back refused -> the run's own tool result says the
907
+ * write did not land, so the claim is false however the file looks on disk
908
+ * - absent from it but present on disk -> the run may have written it through
909
+ * a channel no tool event enumerates, so this is not a failure, but it is
910
+ * not verified either
911
+ * - absent from both -> nothing this run did could have
912
+ * produced it, which is a failed postcondition, not a quality signal
913
+ *
914
+ * Quality follows the same rule as conformance. A reported validation the run
915
+ * never ran is not correctness evidence, so it seals `unmeasured` (the label
916
+ * this module already uses for "nothing here can be measured") instead of
917
+ * pass. A self-reported failure still seals `fail`: an agent reporting against
918
+ * its own interest is the one claim here that needs no corroboration.
919
+ */
920
+ function validateMutation(contract: ResultContract, input: ResultContractValidationInput): ResultContractValidation {
921
+ const parsed = parseJson(input.output);
922
+ if (!parsed.ok) return failure(contract, "unmeasured", parsed.reason);
923
+ const value = parsed.value;
924
+ if (
925
+ !hasOnlyKeys(value, ["mutatedPaths", "validations", "commitMessage", "summary"]) ||
926
+ !Array.isArray(value.mutatedPaths) ||
927
+ value.mutatedPaths.some((entry) => !string(entry))
928
+ ) {
929
+ return failure(contract, "unmeasured", "Mutation result must carry mutatedPaths and validations");
930
+ }
931
+ const authorship = validateAuthorship(value);
932
+ if (authorship !== null) return failure(contract, "unmeasured", authorship);
933
+ const validations = parseChecks(value.validations);
934
+ if (validations === null) return failure(contract, "unmeasured", mutationValidationsReason(value.validations));
935
+ const reportedFailure = !validations.every((check) => check.passed);
936
+ const effects = input.observedRunEffects;
937
+ if (effects === undefined) return success(contract, reportedFailure ? "fail" : "pass", value);
938
+ const cwd = path.resolve(input.cwd);
939
+ let unverifiedMutation = false;
940
+ for (const reported of value.mutatedPaths as ReadonlyArray<string>) {
941
+ const target = path.resolve(cwd, reported);
942
+ if (effects.mutatedPaths.has(target)) continue;
943
+ if (effects.failedMutationPaths.has(target)) {
944
+ return failure(
945
+ contract,
946
+ "unmeasured",
947
+ `Mutation result names a path whose only write this run attempted was refused: ${reported} (${describeWriteSet(effects, cwd)})`,
948
+ );
949
+ }
950
+ if (pathIsPresent(input.filesystem, target)) {
951
+ unverifiedMutation = true;
952
+ continue;
953
+ }
954
+ return failure(
955
+ contract,
956
+ "unmeasured",
957
+ `Mutation result names a path this run never wrote and that does not exist: ${reported} (${describeWriteSet(effects, cwd)})`,
958
+ );
959
+ }
960
+ if (reportedFailure) return success(contract, "fail", value);
961
+ const measured = !unverifiedMutation && effects.validationCommands.size > 0;
962
+ return success(contract, measured ? "pass" : "unmeasured", value);
963
+ }
964
+
965
+ function validateProvenance(contract: ResultContract, output: string | null): ResultContractValidation {
966
+ const parsed = parseJson(output);
967
+ if (!parsed.ok) return failure(contract, "unmeasured", parsed.reason);
968
+ const value = parsed.value;
969
+ if (
970
+ !hasOnlyKeys(value, ["confirmedFacts", "missingEvidence", "nextInspections"]) ||
971
+ ![value.confirmedFacts, value.missingEvidence, value.nextInspections].every(
972
+ (entry) => Array.isArray(entry) && entry.every((item) => string(item)),
973
+ )
974
+ ) {
975
+ return failure(
976
+ contract,
977
+ "unmeasured",
978
+ "Provenance result must carry confirmedFacts, missingEvidence, and nextInspections",
979
+ );
980
+ }
981
+ return success(contract, "unmeasured", value);
982
+ }
983
+
984
+ function validateArchitect(
985
+ contract: Extract<ResultContract, { kind: "architect-plan" }>,
986
+ input: ResultContractValidationInput,
987
+ ): ResultContractValidation {
988
+ const artifactPath = path.resolve(input.cwd, contract.path);
989
+ const content = input.filesystem.readFile(artifactPath);
990
+ if (content === null || content.trim().length === 0) {
991
+ return failure(contract, "unmeasured", `required plan artifact is missing or empty: ${contract.path}`);
992
+ }
993
+ return success(contract, "unmeasured", {
994
+ path: contract.path,
995
+ artifactDigest: createHash("sha256").update(content, "utf8").digest("hex"),
996
+ });
997
+ }
998
+
999
+ /**
1000
+ * Validate one terminal result under its recipe's typed contract. The caller
1001
+ * supplies filesystem access so this module stays deterministic and testable.
1002
+ */
1003
+ /**
1004
+ * Parse the Scout structured result for model-facing task decomposition.
1005
+ * Strict on purpose: this feeds the `from_scout` continuation, where a subtask
1006
+ * becomes a real dispatch, so a degraded result is rejected here even though it
1007
+ * conforms as a terminal result. Degraded reconnaissance is readable evidence,
1008
+ * never a control-plane input.
1009
+ */
1010
+ export function parseScoutResult(output: string): ScoutResult | null {
1011
+ const validation = validateScout({ kind: "scout-report" }, output);
1012
+ if (validation.conformance !== "pass" || validation.scout === undefined) return null;
1013
+ return validation.scout.degradedReason === undefined ? validation.scout : null;
1014
+ }
1015
+
1016
+ export function validateResultContract(input: ResultContractValidationInput): ResultContractValidation {
1017
+ switch (input.contract.kind) {
1018
+ case "architect-plan":
1019
+ return validateArchitect(input.contract, input);
1020
+ case "scout-report": {
1021
+ const validation = validateScout(input.contract, input.output);
1022
+ if (validation.scout === undefined) return validation;
1023
+ const degradedReason = validation.scout.degradedReason;
1024
+ if (degradedReason !== undefined) {
1025
+ return groundDegradedScout(input.contract, input, validation.scout, degradedReason);
1026
+ }
1027
+ const citations = validateScoutCitations(input, validation.scout.citations);
1028
+ return citations.ok
1029
+ ? success(
1030
+ input.contract,
1031
+ "pass",
1032
+ { scout: validation.scout, evidence: citations.evidence },
1033
+ { scout: validation.scout },
1034
+ )
1035
+ : failure(input.contract, "fail", citations.reason);
1036
+ }
1037
+ case "verifier-report":
1038
+ return validateVerifier(input.contract, input.output);
1039
+ case "debugger-report":
1040
+ return validateDebugger(input.contract, input.output);
1041
+ case "research-report":
1042
+ return validateResearch(input.contract, input.output, input.networkAllowed);
1043
+ case "mutation-report":
1044
+ return validateMutation(input.contract, input);
1045
+ case "provenance-report":
1046
+ return validateProvenance(input.contract, input.output);
1047
+ case "external-delegation":
1048
+ return success(input.contract, "unmeasured", { external: true });
1049
+ case "artifact-report":
1050
+ // Nothing here can be measured: the artifact lives at a location only
1051
+ // the caller knows, so the caller checks it. Any terminal text
1052
+ // conforms, which is what stops a bounded repair round from being
1053
+ // spent teaching a writer a JSON shape that proves nothing.
1054
+ return success(input.contract, "unmeasured", { artifact: true });
1055
+ case "context-handbook":
1056
+ return validateContextHandbook(input.contract, input.output);
1057
+ case "code-report":
1058
+ return validateCodeReport(input.contract, input.output);
1059
+ }
1060
+ }
1061
+
1062
+ /** Validate a recipe's final result and project it into receipt-safe facts. */
1063
+ export function validateRecipeResult(input: ValidateRecipeResultInput): RecipeResultOutcome | null {
1064
+ if (input.contract === null) return null;
1065
+ if (!input.reachedTerminalResult) {
1066
+ return {
1067
+ applicable: false,
1068
+ fact: {
1069
+ sourceId: resultContractSourceId(input.contract),
1070
+ validatorDigest: digest({ contract: input.contract, reached: false }),
1071
+ conformance: "not-reached",
1072
+ quality: "unmeasured",
1073
+ },
1074
+ };
1075
+ }
1076
+ const validation = validateResultContract({
1077
+ contract: input.contract,
1078
+ output: input.output,
1079
+ cwd: input.cwd,
1080
+ networkAllowed: input.networkAllowed,
1081
+ filesystem: input.filesystem,
1082
+ ...(input.observedRunEffects !== undefined ? { observedRunEffects: input.observedRunEffects } : {}),
1083
+ });
1084
+ return {
1085
+ applicable: true,
1086
+ validation,
1087
+ fact: {
1088
+ sourceId: validation.sourceId,
1089
+ validatorDigest: validation.validatorDigest,
1090
+ conformance: validation.conformance,
1091
+ quality: validation.quality,
1092
+ },
1093
+ };
1094
+ }
1095
+
1096
+ /**
1097
+ * Bounded in-worker repair rounds for a terminal result that missed its
1098
+ * contract. A local model with few active parameters routinely gathers correct
1099
+ * evidence and then emits the wrong terminal shape; without feedback that run
1100
+ * is lost. Two rounds is the whole allowance, and the run fails after them.
1101
+ */
1102
+ export const RESULT_CONTRACT_REPAIR_LIMIT = 2;
1103
+
1104
+ /** Live-read anchors quoted back to the model in a repair round. */
1105
+ export const RESULT_CONTRACT_ANCHOR_LIMIT = 12;
1106
+
1107
+ /**
1108
+ * The exact terminal shape each contract accepts, quoted to the model verbatim.
1109
+ * This is the one place a contract's wire example is written; agent recipes and
1110
+ * repair rounds both cite it, so a prompt cannot drift from its validator.
1111
+ */
1112
+ function resultContractShape(contract: ResultContract): string {
1113
+ switch (contract.kind) {
1114
+ case "architect-plan":
1115
+ return `a plan artifact written to ${contract.path}, then optionally {"commitMessage":"...","summary":"..."} describing it`;
1116
+ case "scout-report":
1117
+ // The third alternative is the floor this validator actually accepts.
1118
+ // A repair round that only ever restates the strict shape is what the
1119
+ // run already failed twice, so it is told the cheaper exit as well.
1120
+ return '{"findings":[{"claim":"what you observed","path":"src/file.ts","line":1}],"needsSplit":false,"proposedSubtasks":[]} or {"findings":[],"needsSplit":true,"proposedSubtasks":[{"id":"inspect","task":"Inspect the boundary","dependencies":[],"expectedResultContract":"scout-report","requestedAuthority":"read-only"}]} or, if you cannot produce a citation you are sure of, at least {"findings":[{"claim":"what you observed"}]}, which is accepted as an ungrounded lead rather than losing the run';
1121
+ case "verifier-report":
1122
+ return '{"verdict":"pass","checks":[{"name":"npm run typecheck","passed":true,"evidence":"exit 0"}]}';
1123
+ case "debugger-report":
1124
+ return '{"diagnosis":"...","reproduction":"reproduced","evidence":["..."]}';
1125
+ case "research-report":
1126
+ return '{"source":"local","findings":[{"claim":"...","evidence":"..."}]}';
1127
+ case "mutation-report":
1128
+ return '{"mutatedPaths":["src/file.ts"],"validations":[{"name":"npm test","passed":true,"evidence":"exit 0"}],"commitMessage":"optional: the commit message for this change","summary":"optional: one line"}';
1129
+ case "provenance-report":
1130
+ return '{"confirmedFacts":["..."],"missingEvidence":["..."],"nextInspections":["..."]}';
1131
+ case "external-delegation":
1132
+ return "any final text";
1133
+ case "artifact-report":
1134
+ return "any final text; the artifact you wrote at the location the task named is the result";
1135
+ case "context-handbook":
1136
+ return '{"projectName":"string","identity":"one sentence","conventions":[],"invariants":[],"sections":[{"title":"Architecture","body":"markdown that cites `real/path.ts` tokens"}]}';
1137
+ case "code-report":
1138
+ return '{"passed":false,"exitCode":1,"checks":[{"name":"test","passed":false,"evidence":"exit 1"}],"artifactPaths":["/path/command.log"],"outputExcerpt":"..."}';
1139
+ }
1140
+ }
1141
+
1142
+ export interface ResultContractRepairInput {
1143
+ contract: ResultContract;
1144
+ /** The validator's own reason; never a paraphrase. */
1145
+ reason: string;
1146
+ /** 1-based repair round. */
1147
+ attempt: number;
1148
+ /** `path:line` anchors from reads that succeeded in this run. */
1149
+ anchors: ReadonlyArray<string>;
1150
+ }
1151
+
1152
+ /**
1153
+ * One repair directive. It states the validator's reason, the exact shape, and
1154
+ * that tool use is over, so the model's only remaining move is to emit the
1155
+ * terminal document from evidence it already has.
1156
+ */
1157
+ export function resultContractRepairMessage(input: ResultContractRepairInput): string {
1158
+ const last = input.attempt >= RESULT_CONTRACT_REPAIR_LIMIT;
1159
+ const lines = [
1160
+ last
1161
+ ? "FINAL RESULT REQUIRED IN THIS RESPONSE. Your previous response still did not satisfy this run's result contract."
1162
+ : "Your previous response did not satisfy this run's result contract.",
1163
+ `Validator reason: ${input.reason}`,
1164
+ "Tool use is over. Answer from the evidence you already gathered.",
1165
+ `Emit exactly this shape and nothing else: ${resultContractShape(input.contract)}`,
1166
+ "Do not add prose, code fences, or commentary around it. Do not describe work you intend to do next.",
1167
+ ];
1168
+ if (input.anchors.length > 0) {
1169
+ lines.push(
1170
+ "",
1171
+ "Locations you read successfully in this run (use these exact path:line values):",
1172
+ ...input.anchors.slice(-RESULT_CONTRACT_ANCHOR_LIMIT).map((anchor) => `- ${anchor}`),
1173
+ );
1174
+ }
1175
+ return lines.join("\n");
1176
+ }
1177
+
1178
+ /** Name of the synthetic tool call that carries a repair round. */
1179
+ export const RESULT_CONTRACT_REPAIR_TOOL = "result_contract";
1180
+
1181
+ /**
1182
+ * One repair round as a protocol-legal tool exchange: a synthetic assistant
1183
+ * call to `result_contract` and the tool result that answers it, sharing the
1184
+ * id `clio-result-contract-repair-N`. Strict endpoints (OpenAI, Anthropic)
1185
+ * reject a tool result no assistant call issued; local servers tolerated the
1186
+ * bare result, and this keeps the history-append shape #55 measured while
1187
+ * satisfying both. `stopReason: "toolUse"` and the toolCall block keep the
1188
+ * assistant half out of terminal validation, durable output, and the
1189
+ * synthesis sanitizer.
1190
+ *
1191
+ * The assistant half carries explicit zero usage. pi-ai's context estimator
1192
+ * (`estimateContextTokens`, run while sizing every request) dereferences
1193
+ * `usage` on any assistant message not marked `aborted`/`error`, so a
1194
+ * usage-less `toolUse` message throws `Cannot read properties of undefined
1195
+ * (reading 'totalTokens')` on the very next model round and the worker dies
1196
+ * with the contract `not-reached` (#70). Zero usage keeps the estimator on
1197
+ * the model's last real usage and its byte-for-byte prompt-cache behavior.
1198
+ */
1199
+ export function resultContractRepairMessages(
1200
+ input: ResultContractRepairInput,
1201
+ origin: { provider: string; api: string; model: string },
1202
+ ) {
1203
+ const id = `clio-result-contract-repair-${input.attempt}`;
1204
+ const timestamp = Date.now();
1205
+ return [
1206
+ {
1207
+ role: "assistant",
1208
+ content: [{ type: "toolCall", id, name: RESULT_CONTRACT_REPAIR_TOOL, arguments: {} }],
1209
+ stopReason: "toolUse",
1210
+ usage: {
1211
+ input: 0,
1212
+ output: 0,
1213
+ cacheRead: 0,
1214
+ cacheWrite: 0,
1215
+ totalTokens: 0,
1216
+ cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
1217
+ },
1218
+ ...origin,
1219
+ timestamp,
1220
+ },
1221
+ {
1222
+ role: "toolResult",
1223
+ toolCallId: id,
1224
+ toolName: RESULT_CONTRACT_REPAIR_TOOL,
1225
+ content: [{ type: "text", text: resultContractRepairMessage(input) }],
1226
+ isError: true,
1227
+ timestamp,
1228
+ },
1229
+ ] as const;
1230
+ }
1231
+
1232
+ /** Strict frontmatter parser for the one recipe result-contract schema. */
1233
+ export function parseResultContract(value: unknown, sourcePath: string): ResultContract {
1234
+ if (value === null || typeof value !== "object" || Array.isArray(value)) {
1235
+ throw new Error(`agent recipe: ${sourcePath}: resultContract must be an object`);
1236
+ }
1237
+ const record = value as Record<string, unknown>;
1238
+ if (typeof record.kind !== "string") throw new Error(`agent recipe: ${sourcePath}: resultContract.kind is required`);
1239
+ const keys = Object.keys(record);
1240
+ const only = (...allowed: string[]): boolean => keys.every((key) => allowed.includes(key));
1241
+ if (record.kind === "architect-plan") {
1242
+ if (!only("kind", "path") || !string(record.path)) {
1243
+ throw new Error(`agent recipe: ${sourcePath}: architect-plan requires only non-empty path`);
1244
+ }
1245
+ if (path.isAbsolute(record.path) || record.path.split(/[\\/]/u).includes("..")) {
1246
+ throw new Error(`agent recipe: ${sourcePath}: architect-plan path must be workspace-relative`);
1247
+ }
1248
+ return { kind: "architect-plan", path: record.path };
1249
+ }
1250
+ const kinds = [
1251
+ "scout-report",
1252
+ "verifier-report",
1253
+ "debugger-report",
1254
+ "research-report",
1255
+ "mutation-report",
1256
+ "provenance-report",
1257
+ "external-delegation",
1258
+ "artifact-report",
1259
+ "context-handbook",
1260
+ ] as const;
1261
+ if (!(kinds as ReadonlyArray<string>).includes(record.kind) || !only("kind")) {
1262
+ throw new Error(`agent recipe: ${sourcePath}: resultContract.kind is unsupported or has unknown keys`);
1263
+ }
1264
+ return { kind: record.kind as Exclude<ResultContract["kind"], "architect-plan"> };
1265
+ }