@iowarp/clio-coder 0.3.1 → 0.3.3

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 (601) hide show
  1. package/CHANGELOG.md +233 -373
  2. package/CONTRIBUTING.md +23 -23
  3. package/README.md +284 -613
  4. package/dist/{acp-FPR54DGL.js → acp-P2AQILE2.js} +43 -53
  5. package/dist/{agents-OGPIHPJH.js → agents-72W3BI7I.js} +43 -26
  6. package/dist/assets/codewiki.json +1 -1
  7. package/dist/{auth-IC3K6NIZ.js → auth-5TWEIYDN.js} +20 -12
  8. package/dist/chunk-2DJ2KNFG.js +2095 -0
  9. package/dist/{chunk-IS3ONKU3.js → chunk-2IR2NMPA.js} +6 -4
  10. package/dist/chunk-2SFS6XQE.js +122 -0
  11. package/dist/{chunk-PV4JUBVJ.js → chunk-2TLUCQVG.js} +40 -21
  12. package/dist/chunk-2VTFPG5O.js +48 -0
  13. package/dist/chunk-4BJ5BYCE.js +61 -0
  14. package/dist/{chunk-474KN5II.js → chunk-4BPJXDWC.js} +111 -181
  15. package/dist/chunk-4VP4KH3K.js +962 -0
  16. package/dist/chunk-4XUGQOHA.js +797 -0
  17. package/dist/chunk-4ZG3XFUR.js +77 -0
  18. package/dist/chunk-5B2AEOW5.js +5407 -0
  19. package/dist/{chunk-K2ITRMHZ.js → chunk-5TSRNF4G.js} +6 -138
  20. package/dist/{chunk-4QKXUHSR.js → chunk-5UFT4SUX.js} +70 -20
  21. package/dist/{chunk-OLBBMFRD.js → chunk-5UUP6MWO.js} +24 -62
  22. package/dist/chunk-65DEGPJ6.js +52 -0
  23. package/dist/chunk-6EJMN2Y3.js +17 -0
  24. package/dist/chunk-6N5PTWMY.js +136 -0
  25. package/dist/chunk-6SGHMWE3.js +277 -0
  26. package/dist/chunk-6XLNIQDB.js +27 -0
  27. package/dist/chunk-7CR24IG7.js +242 -0
  28. package/dist/chunk-7MNJORFF.js +22 -0
  29. package/dist/{chunk-KY56HMHH.js → chunk-A3CYT5EX.js} +125 -31
  30. package/dist/chunk-AGYYIBLL.js +1069 -0
  31. package/dist/{chunk-GB6QRBXN.js → chunk-APJ265NV.js} +54 -1187
  32. package/dist/{chunk-673JJUWJ.js → chunk-BMEMKKIT.js} +2 -2
  33. package/dist/chunk-CBCAPZAA.js +229 -0
  34. package/dist/chunk-CMZWFGD2.js +352 -0
  35. package/dist/chunk-COU2UHX6.js +400 -0
  36. package/dist/chunk-DSELYM6W.js +1077 -0
  37. package/dist/chunk-DUYJ5IO6.js +644 -0
  38. package/dist/chunk-ECH6PKUQ.js +39 -0
  39. package/dist/chunk-ED4KHGC3.js +143 -0
  40. package/dist/chunk-EKMEHE4H.js +340 -0
  41. package/dist/chunk-FCSXB6T2.js +338 -0
  42. package/dist/chunk-FJ3H4MN5.js +48 -0
  43. package/dist/{chunk-RPTR2H26.js → chunk-FNTMWMX5.js} +21 -15
  44. package/dist/chunk-FQ4SKYE4.js +29 -0
  45. package/dist/chunk-G4BMMOKF.js +182 -0
  46. package/dist/{chunk-ZPY3JZ5E.js → chunk-GGXXDWE4.js} +183 -1233
  47. package/dist/chunk-HC4CLZ2Y.js +68 -0
  48. package/dist/{chunk-LU4TK2PR.js → chunk-HFSBBKSQ.js} +5 -56
  49. package/dist/{chunk-PIUMUEMV.js → chunk-HKIYEGME.js} +10 -6
  50. package/dist/chunk-I4HZDVNP.js +73 -0
  51. package/dist/chunk-IKCO5N3L.js +162 -0
  52. package/dist/chunk-IR4CFBFN.js +56 -0
  53. package/dist/{chunk-R5KLMSBV.js → chunk-J5Q24KAG.js} +2 -2
  54. package/dist/chunk-J7CWMCQD.js +255 -0
  55. package/dist/{chunk-K5XEMXTI.js → chunk-JVCV3ICN.js} +1 -1
  56. package/dist/chunk-KZWTDYJF.js +217 -0
  57. package/dist/chunk-LBMZMYH2.js +285 -0
  58. package/dist/{chunk-G34LV2PF.js → chunk-LM5TQCJZ.js} +84 -170
  59. package/dist/chunk-LW6DSM3M.js +5135 -0
  60. package/dist/chunk-LWLEKMDQ.js +3482 -0
  61. package/dist/{chunk-H6F6BYOH.js → chunk-LZSJBIVT.js} +7003 -7434
  62. package/dist/{chunk-HQQID6OA.js → chunk-M6SHUN7Q.js} +5 -5
  63. package/dist/{chunk-FST4FYJB.js → chunk-MFFY33HR.js} +99 -140
  64. package/dist/{chunk-BSU2YIWB.js → chunk-MVVUPGPW.js} +131 -136
  65. package/dist/chunk-OAO4GE4M.js +619 -0
  66. package/dist/{chunk-Q3RUPKEJ.js → chunk-OC7FIQPC.js} +58 -189
  67. package/dist/chunk-OKGUZO2U.js +34 -0
  68. package/dist/{chunk-GAEBEQVI.js → chunk-OOJYHWRB.js} +32 -346
  69. package/dist/{chunk-Q5WJOSJ7.js → chunk-OQ33BKR3.js} +2 -1
  70. package/dist/chunk-OQE5J4C6.js +73 -0
  71. package/dist/{chunk-KKNLWXI6.js → chunk-ORBHGJC5.js} +8 -8
  72. package/dist/{chunk-MAR7Y6HW.js → chunk-PAJK6MAQ.js} +23 -16
  73. package/dist/{chunk-M5T5VO65.js → chunk-PIWWS5BL.js} +837 -635
  74. package/dist/chunk-POHLU5DW.js +1186 -0
  75. package/dist/chunk-QKMUKYO7.js +4961 -0
  76. package/dist/chunk-SRDMMSEP.js +16405 -0
  77. package/dist/chunk-SST6Z5JA.js +80 -0
  78. package/dist/chunk-STBPMHSX.js +2456 -0
  79. package/dist/chunk-T6YILFSB.js +80 -0
  80. package/dist/chunk-TZK7PACC.js +174 -0
  81. package/dist/chunk-TZTZS7QK.js +227 -0
  82. package/dist/{chunk-ASND7OZK.js → chunk-UFIIWP2H.js} +13 -13
  83. package/dist/chunk-UOV2BYIW.js +107 -0
  84. package/dist/{chunk-PFEFKVGL.js → chunk-V6RTAOC2.js} +13 -11
  85. package/dist/chunk-VAKQQHWR.js +434 -0
  86. package/dist/chunk-VG7TBQIY.js +128 -0
  87. package/dist/chunk-VJWL6YS5.js +244 -0
  88. package/dist/{chunk-EYOKLTMF.js → chunk-VPAYEGVX.js} +17 -3
  89. package/dist/chunk-WEH5XRJQ.js +32 -0
  90. package/dist/chunk-X4RCMKVQ.js +641 -0
  91. package/dist/{chunk-TEKV33Q5.js → chunk-X6IAEBZR.js} +65 -33
  92. package/dist/chunk-XBXAASKX.js +18 -0
  93. package/dist/chunk-XN3L4EYL.js +46 -0
  94. package/dist/{chunk-RDLVBZEO.js → chunk-YCWGATWI.js} +6 -4
  95. package/dist/chunk-YHZX5GEU.js +193 -0
  96. package/dist/chunk-YXLYO42X.js +91 -0
  97. package/dist/{chunk-NMOX6HFD.js → chunk-ZDOOVTXZ.js} +29 -77
  98. package/dist/chunk-ZI647VB5.js +37 -0
  99. package/dist/{chunk-C4PTHK7P.js → chunk-ZWLZP4ZT.js} +5 -5
  100. package/dist/chunk-ZWMF7253.js +1882 -0
  101. package/dist/cli/index.js +62 -54
  102. package/dist/clio-JOU4FXVA.js +25 -0
  103. package/dist/code-nav-7AX6FYE6.js +600 -0
  104. package/dist/codewiki/build-worker.js +66 -0
  105. package/dist/compile-cache-CVJMMODC.js +18 -0
  106. package/dist/{components-DMAOEKFB.js → components-KELWS457.js} +11 -6
  107. package/dist/{config-IRUQ7SE4.js → config-XCDVKR23.js} +92 -55
  108. package/dist/configure-4GAP54ZW.js +42 -0
  109. package/dist/{context-5RADCKTR.js → context-4UOGGLQ5.js} +71 -35
  110. package/dist/context-5VKGUVJJ.js +866 -0
  111. package/dist/{context-3KWFLHJG.js → context-77FM5DV5.js} +15 -13
  112. package/dist/{context-clear-7TSNPAAI.js → context-clear-XXJRLCJJ.js} +54 -28
  113. package/dist/{context-index-W4RLWOQH.js → context-index-BZ4UYMTC.js} +30 -24
  114. package/dist/dispatch-runner-QPRDDBDX.js +1997 -0
  115. package/dist/{docs-5AWSPS37.js → docs-2C2LTVT2.js} +23 -10
  116. package/dist/{doctor-UC5NAJYQ.js → doctor-HR46URBJ.js} +27 -17
  117. package/dist/{eval-U6TJHRLX.js → eval-XSSNATB4.js} +29 -16
  118. package/dist/{evidence-YEGUW4L3.js → evidence-6HG2PY2B.js} +46 -26
  119. package/dist/{evolve-TXARCTPG.js → evolve-K7YU3NCY.js} +45 -25
  120. package/dist/{extensions-OZFJ3A3G.js → extensions-QVDOHDGJ.js} +16 -7
  121. package/dist/{fleet-6G3DHNYE.js → fleet-VY3HHKN6.js} +163 -54
  122. package/dist/{fleet-preflight-DSNT37JK.js → fleet-preflight-DDN536IT.js} +7 -4
  123. package/dist/{init-KZ5QTF6M.js → init-JYGXI3FK.js} +69 -32
  124. package/dist/{memory-73ESV5YC.js → memory-WFZMGYHX.js} +48 -27
  125. package/dist/{models-A4PVNWJK.js → models-I5QWSEOM.js} +39 -25
  126. package/dist/monitor-GE4ID3IA.js +661 -0
  127. package/dist/{chunk-FCIH3BIZ.js → orchestrator-EM5MC3HM.js} +15979 -12407
  128. package/dist/{paths-C4H6IV77.js → paths-UXLN5YYZ.js} +10 -5
  129. package/dist/{preload-6WVMHX3A.js → preload-P6DGH2PZ.js} +2 -2
  130. package/dist/{reset-BGW6OGMV.js → reset-L2FQEE3E.js} +16 -10
  131. package/dist/{run-YTPEYQOH.js → run-ZU3QMZPZ.js} +101 -61
  132. package/dist/{share-YIFFV4NQ.js → share-S5BZQC5I.js} +15 -8
  133. package/dist/{skills-2V6RA3OQ.js → skills-X5VXCRNQ.js} +34 -14
  134. package/dist/{skills-eval-S2TVJO4F.js → skills-eval-WKIHWTHR.js} +70 -34
  135. package/dist/steer-GGWFUJUD.js +77 -0
  136. package/dist/{targets-TYXLPB23.js → targets-SNCPI2NR.js} +43 -27
  137. package/dist/terminal-lease-BNAHVHBS.js +395 -0
  138. package/dist/{trace-GGOJ6Q6Z.js → trace-PNCASAXC.js} +41 -16
  139. package/dist/{chunk-N6F52NLF.js → tree-sitter-HGKH6LG4.js} +28 -2306
  140. package/dist/{uninstall-LLLT4F4W.js → uninstall-FZCQCDKC.js} +10 -5
  141. package/dist/{upgrade-33G2LMM5.js → upgrade-JQHHPQ4K.js} +45 -25
  142. package/dist/{usage-ZAFSXKKG.js → usage-OR4O5SMZ.js} +62 -31
  143. package/dist/verify-375KUB3Y.js +716 -0
  144. package/dist/web-fetch-2YHJ3KTG.js +638 -0
  145. package/dist/{wiki-generate-NUQCVOQ3.js → wiki-generate-UEXP2ARI.js} +74 -34
  146. package/dist/worker/entry.js +221 -36
  147. package/dist/workspace-G4ZWUIPR.js +22 -0
  148. package/docs/README.md +22 -17
  149. package/docs/acp.md +168 -16
  150. package/docs/alcf-provider.md +1 -1
  151. package/docs/architecture.md +136 -7
  152. package/docs/artifact-versions.md +1 -1
  153. package/docs/built-in-agents.md +1 -1
  154. package/docs/capacity-and-scheduling.md +1 -1
  155. package/docs/commands-and-modes.md +114 -71
  156. package/docs/config-knobs-audit.md +1 -3
  157. package/docs/configuration-and-targets.md +174 -46
  158. package/docs/context-engine.md +29 -6
  159. package/docs/development-pipeline.md +26 -1
  160. package/docs/dispatch-architecture-rationale.md +1 -1
  161. package/docs/documentation-coverage.md +2 -2
  162. package/docs/documentation-guide.md +1 -1
  163. package/docs/environment-variables.md +13 -5
  164. package/docs/eval-runner.md +1 -1
  165. package/docs/evals-internal.md +1 -1
  166. package/docs/evidence-and-memory.md +6 -2
  167. package/docs/evolution.md +2 -2
  168. package/docs/exit-codes-and-output.md +15 -9
  169. package/docs/extensions-and-sharing.md +9 -9
  170. package/docs/fleet-dispatch.md +7 -5
  171. package/docs/git-commit-provenance.md +120 -0
  172. package/docs/glossary.md +1 -1
  173. package/docs/installation-and-lifecycle.md +34 -27
  174. package/docs/middleware-and-components.md +1 -1
  175. package/docs/model-catalog.md +45 -14
  176. package/docs/observability.md +8 -5
  177. package/docs/performance-methodology.md +491 -0
  178. package/docs/pi-boundary.md +72 -0
  179. package/docs/proactive-memory.md +3 -3
  180. package/docs/prompt-envelope-and-tools.md +24 -3
  181. package/docs/provider-adapter-cookbook.md +57 -4
  182. package/docs/release-cut-checklist.md +129 -115
  183. package/docs/safety-model.md +9 -5
  184. package/docs/scientific-validation.md +3 -3
  185. package/docs/session-lifecycle.md +55 -12
  186. package/docs/skills-marketplace.md +12 -8
  187. package/docs/time-conventions.md +1 -1
  188. package/docs/tool-usage.md +3 -3
  189. package/docs/trace-store.md +1 -1
  190. package/docs/troubleshooting.md +10 -7
  191. package/docs/tui-design.md +47 -10
  192. package/docs/worker-dispatch-mechanics.md +1 -1
  193. package/package.json +19 -22
  194. package/skills/coding/ast-grep/SKILL.md +136 -0
  195. package/skills/coding/ast-grep/evals.md +56 -0
  196. package/skills/coding/ast-grep/references/rule_reference.md +297 -0
  197. package/skills/coding/coding-standards/SKILL.md +113 -0
  198. package/skills/coding/coding-standards/evals.md +34 -0
  199. package/skills/coding/prototype/SKILL.md +86 -0
  200. package/skills/coding/prototype/evals.md +42 -0
  201. package/skills/coding/prototype/references/LOGIC.md +67 -0
  202. package/skills/coding/prototype/references/UI.md +112 -0
  203. package/skills/coding/tdd/SKILL.md +101 -0
  204. package/skills/coding/tdd/evals.md +41 -0
  205. package/skills/coding/tdd/references/mocking.md +59 -0
  206. package/skills/coding/tdd/references/tests.md +77 -0
  207. package/skills/context/context-handoff/SKILL.md +126 -0
  208. package/skills/context/context-handoff/evals.md +57 -0
  209. package/skills/context/context-handoff/scripts/new-handoff.sh +26 -0
  210. package/skills/context/context-prime/SKILL.md +95 -0
  211. package/skills/context/context-prime/evals.md +54 -0
  212. package/skills/meta/clio-dev/SKILL.md +91 -0
  213. package/skills/meta/clio-dev/evals.md +45 -0
  214. package/skills/meta/clio-test/SKILL.md +130 -0
  215. package/skills/meta/clio-test/evals.md +43 -0
  216. package/skills/meta/clio-test/references/harness.md +97 -0
  217. package/skills/meta/clio-test/references/test-map.md +59 -0
  218. package/skills/meta/credentials/SKILL.md +125 -0
  219. package/skills/meta/credentials/evals.md +104 -0
  220. package/skills/meta/find-skills/SKILL.md +72 -0
  221. package/skills/meta/find-skills/evals.md +47 -0
  222. package/skills/meta/herdr/SKILL.md +127 -0
  223. package/skills/meta/herdr/evals.md +38 -0
  224. package/skills/meta/skill-craft/SKILL.md +102 -0
  225. package/skills/meta/skill-craft/evals.md +41 -0
  226. package/skills/planning/architecture/SKILL.md +129 -0
  227. package/skills/planning/architecture/evals.md +36 -0
  228. package/skills/planning/backlog/SKILL.md +90 -0
  229. package/skills/planning/backlog/evals.md +43 -0
  230. package/skills/planning/prd/SKILL.md +82 -0
  231. package/skills/planning/prd/evals.md +49 -0
  232. package/skills/planning/product-intent/SKILL.md +112 -0
  233. package/skills/planning/product-intent/evals.md +36 -0
  234. package/skills/planning/tech-spec/SKILL.md +115 -0
  235. package/skills/planning/tech-spec/evals.md +47 -0
  236. package/skills/registry.yaml +136 -0
  237. package/skills/research/arxiv-literature/SKILL.md +104 -0
  238. package/skills/research/arxiv-literature/evals.md +58 -0
  239. package/skills/research/experiment-protocol/SKILL.md +122 -0
  240. package/skills/research/experiment-protocol/evals.md +91 -0
  241. package/skills/research/scientific-debugging/SKILL.md +119 -0
  242. package/skills/research/scientific-debugging/evals.md +138 -0
  243. package/skills/research/scientific-modernization/SKILL.md +138 -0
  244. package/skills/research/scientific-modernization/evals.md +84 -0
  245. package/skills/workflow/design-council/SKILL.md +139 -0
  246. package/skills/workflow/design-council/evals.md +97 -0
  247. package/skills/workflow/grill-me/SKILL.md +186 -0
  248. package/skills/workflow/grill-me/evals.md +78 -0
  249. package/skills/workflow/workflow-distiller/SKILL.md +136 -0
  250. package/skills/workflow/workflow-distiller/evals.md +107 -0
  251. package/src/cli/acp.ts +31 -4
  252. package/src/cli/clio.ts +68 -6
  253. package/src/cli/config-inspect.ts +28 -22
  254. package/src/cli/configure.ts +47 -9
  255. package/src/cli/context-clear.ts +2 -2
  256. package/src/cli/context-index.ts +21 -23
  257. package/src/cli/context.ts +13 -8
  258. package/src/cli/default-target.ts +9 -17
  259. package/src/cli/docs.ts +11 -5
  260. package/src/cli/evidence.ts +4 -1
  261. package/src/cli/extensions.ts +10 -1
  262. package/src/cli/fleet.ts +47 -6
  263. package/src/cli/index.ts +55 -26
  264. package/src/cli/memory.ts +3 -1
  265. package/src/cli/models.ts +1 -1
  266. package/src/cli/modes/json-stream.ts +37 -1
  267. package/src/cli/modes/print.ts +24 -9
  268. package/src/cli/run.ts +2 -2
  269. package/src/cli/skills-eval.ts +23 -8
  270. package/src/cli/skills.ts +19 -4
  271. package/src/cli/targets.ts +4 -0
  272. package/src/cli/text-layout.ts +15 -5
  273. package/src/cli/trace.ts +62 -14
  274. package/src/cli/upgrade.ts +18 -2
  275. package/src/cli/usage.ts +10 -3
  276. package/src/cli/wiki-generate.ts +2 -1
  277. package/src/core/agent-environment.ts +7 -0
  278. package/src/core/bash-exec.ts +72 -1
  279. package/src/core/boot-trace.ts +9 -4
  280. package/src/core/bus-events.ts +20 -4
  281. package/src/core/commit-attribution.ts +157 -0
  282. package/src/core/compile-cache.ts +159 -0
  283. package/src/core/config.ts +131 -2
  284. package/src/core/defaults.ts +39 -5
  285. package/src/core/domain-loader.ts +12 -5
  286. package/src/core/git-commit-attribution.ts +387 -0
  287. package/src/core/incomplete-installation.ts +45 -0
  288. package/src/core/response-schema.ts +1 -1
  289. package/src/core/safe-exec.ts +13 -1
  290. package/src/core/settings-layers.ts +155 -21
  291. package/src/core/skill-activation.ts +1 -1
  292. package/src/core/startup-timer.ts +3 -3
  293. package/src/core/state-file-lock.ts +13 -1
  294. package/src/core/termination.ts +78 -5
  295. package/src/domains/config/classify.ts +15 -3
  296. package/src/domains/config/extension.ts +19 -13
  297. package/src/domains/config/index.ts +10 -0
  298. package/src/domains/config/keybindings.ts +45 -9
  299. package/src/domains/context/bootstrap-prompt.ts +1 -1
  300. package/src/domains/context/bootstrap.ts +111 -18
  301. package/src/domains/context/clear.ts +16 -11
  302. package/src/domains/context/clio-md.ts +111 -9
  303. package/src/domains/context/codewiki/artifact.ts +400 -0
  304. package/src/domains/context/codewiki/build-worker-protocol.ts +24 -0
  305. package/src/domains/context/codewiki/build-worker.ts +54 -0
  306. package/src/domains/context/codewiki/coordinator.ts +182 -0
  307. package/src/domains/context/codewiki/indexer.ts +59 -144
  308. package/src/domains/context/codewiki/paths.ts +67 -0
  309. package/src/domains/context/codewiki/schema.ts +80 -0
  310. package/src/domains/context/codewiki/tree-sitter.ts +1 -1
  311. package/src/domains/context/contract.ts +11 -5
  312. package/src/domains/context/extension.ts +94 -143
  313. package/src/domains/context/fingerprint.ts +3 -1
  314. package/src/domains/context/index.ts +12 -22
  315. package/src/domains/context/project-metadata.ts +19 -0
  316. package/src/domains/context/prompt-context.ts +9 -10
  317. package/src/domains/context/refresh.ts +29 -21
  318. package/src/domains/context/runtime.ts +17 -0
  319. package/src/domains/context/wiki/generate.ts +39 -34
  320. package/src/domains/context/wiki/plan.ts +1 -1
  321. package/src/domains/context/wiki/prompts.ts +21 -8
  322. package/src/domains/dispatch/code-step.ts +20 -1
  323. package/src/domains/dispatch/extension.ts +158 -21
  324. package/src/domains/dispatch/failure-classification.ts +6 -0
  325. package/src/domains/dispatch/fleet-commit-attribution.ts +56 -0
  326. package/src/domains/dispatch/orphan-recovery.ts +50 -8
  327. package/src/domains/dispatch/receipt-integrity.ts +5 -0
  328. package/src/domains/dispatch/state.ts +31 -6
  329. package/src/domains/dispatch/transport.ts +2 -1
  330. package/src/domains/dispatch/types.ts +14 -0
  331. package/src/domains/dispatch/worker-spawn.ts +21 -2
  332. package/src/domains/eval/metrics/context.ts +1 -1
  333. package/src/domains/eval/types.ts +0 -1
  334. package/src/domains/evidence/build.ts +41 -1
  335. package/src/domains/lifecycle/migrations/2026-08-18-lmstudio-runtime-id.ts +52 -0
  336. package/src/domains/lifecycle/migrations/index.ts +24 -4
  337. package/src/domains/middleware/hooks-io.ts +12 -0
  338. package/src/domains/middleware/skills-reminder.ts +30 -15
  339. package/src/domains/prompts/compiler.ts +142 -84
  340. package/src/domains/prompts/contract.ts +18 -2
  341. package/src/domains/prompts/extension.ts +39 -7
  342. package/src/domains/prompts/fragment-loader.ts +0 -1
  343. package/src/domains/prompts/fragments/identity/clio.md +2 -4
  344. package/src/domains/prompts/fragments/identity/docs-routing.md +10 -0
  345. package/src/domains/prompts/fragments/identity/self-awareness.md +1 -45
  346. package/src/domains/prompts/fragments/operating/contract.md +4 -50
  347. package/src/domains/prompts/fragments/operating/delegation.md +42 -0
  348. package/src/domains/prompts/fragments/operating/skills.md +26 -0
  349. package/src/domains/prompts/fragments/operating/worker.md +16 -0
  350. package/src/domains/prompts/fragments/safety/auto-edit.md +5 -5
  351. package/src/domains/prompts/fragments/safety/full-auto.md +3 -3
  352. package/src/domains/prompts/fragments/safety/read-only.md +4 -4
  353. package/src/domains/prompts/fragments/safety/suggest.md +2 -2
  354. package/src/domains/prompts/fragments/wiki/page.md +10 -0
  355. package/src/domains/prompts/fragments/wiki/plan.md +10 -0
  356. package/src/domains/prompts/preload.ts +3 -3
  357. package/src/domains/providers/auth/api-key.ts +1 -1
  358. package/src/domains/providers/auth/backend-file.ts +20 -10
  359. package/src/domains/providers/auth/backend-memory.ts +59 -4
  360. package/src/domains/providers/auth/boot-status.ts +65 -0
  361. package/src/domains/providers/auth/oauth.ts +2 -1
  362. package/src/domains/providers/auth/storage.ts +97 -38
  363. package/src/domains/providers/capabilities.ts +12 -4
  364. package/src/domains/providers/contract.ts +15 -4
  365. package/src/domains/providers/extension.ts +18 -6
  366. package/src/domains/providers/model-runtime-capabilities.ts +15 -4
  367. package/src/domains/providers/models/local-models/clio-local-coding-targets.yaml +118 -35
  368. package/src/domains/providers/plugins.ts +5 -3
  369. package/src/domains/providers/probe/fingerprint.ts +25 -5
  370. package/src/domains/providers/registry.ts +31 -10
  371. package/src/domains/providers/runtimes/boot-manifest.ts +55 -0
  372. package/src/domains/providers/runtimes/builtins.ts +2 -2
  373. package/src/domains/providers/runtimes/common/lmstudio-http.ts +423 -0
  374. package/src/domains/providers/runtimes/common/local-synth.ts +6 -7
  375. package/src/domains/providers/runtimes/local-native/lmstudio.ts +241 -0
  376. package/src/domains/providers/support.ts +6 -3
  377. package/src/domains/providers/types/local-model-quirks.ts +7 -9
  378. package/src/domains/providers/types/runtime-descriptor.ts +12 -1
  379. package/src/domains/providers/types/target-descriptor.ts +22 -0
  380. package/src/domains/resources/contract.ts +0 -1
  381. package/src/domains/resources/extension.ts +1 -3
  382. package/src/domains/resources/loader.ts +3 -4
  383. package/src/domains/resources/prompts/loader.ts +16 -2
  384. package/src/domains/resources/prompts/substitute.ts +1 -65
  385. package/src/domains/resources/skills/content-hash.ts +2 -0
  386. package/src/domains/resources/skills/install.ts +17 -0
  387. package/src/domains/resources/skills/loader.ts +17 -10
  388. package/src/domains/resources/skills/marketplace.ts +55 -9
  389. package/src/domains/safety/action-classifier.ts +4 -2
  390. package/src/domains/safety/audit.ts +8 -2
  391. package/src/domains/safety/extension.ts +1 -1
  392. package/src/domains/session/compaction/branch-summary.ts +3 -2
  393. package/src/domains/session/compaction/cut-point.ts +2 -1
  394. package/src/domains/session/compaction/tokens.ts +2 -1
  395. package/src/domains/session/context-ledger.ts +14 -0
  396. package/src/domains/session/contract.ts +15 -0
  397. package/src/domains/session/decision-board.ts +190 -0
  398. package/src/domains/session/entries.ts +66 -3
  399. package/src/domains/session/extension.ts +93 -12
  400. package/src/domains/session/retry.ts +10 -18
  401. package/src/domains/session/session-artifacts.ts +107 -0
  402. package/src/domains/session/task-board.ts +207 -13
  403. package/src/domains/session/tree/active-path.ts +44 -5
  404. package/src/domains/session/tree/fork.ts +26 -27
  405. package/src/domains/session/tree/preview.ts +2 -2
  406. package/src/domains/session/workspace/git-probe.ts +17 -11
  407. package/src/domains/user-tasks/store.ts +297 -0
  408. package/src/engine/acp/errors.ts +96 -0
  409. package/src/engine/acp/server.ts +1728 -146
  410. package/src/engine/acp/transport.ts +135 -14
  411. package/src/engine/acp/types.ts +26 -0
  412. package/src/engine/agent.ts +3 -3
  413. package/src/engine/ai.ts +32 -27
  414. package/src/engine/alcf-oauth.ts +26 -19
  415. package/src/engine/api-registry.ts +223 -0
  416. package/src/engine/apis/index.ts +3 -7
  417. package/src/engine/apis/llamacpp-residency.ts +49 -9
  418. package/src/engine/apis/lmstudio-residency.ts +5 -21
  419. package/src/engine/apis/lmstudio.ts +243 -0
  420. package/src/engine/apis/ollama-native.ts +24 -3
  421. package/src/engine/apis/openai-completions.ts +170 -91
  422. package/src/engine/apis/residency.ts +139 -3
  423. package/src/engine/apis/types.ts +16 -0
  424. package/src/engine/env-api-keys.ts +98 -0
  425. package/src/engine/gemma-channel-filter.ts +223 -0
  426. package/src/engine/instrumented-tui.ts +192 -0
  427. package/src/engine/messages.ts +14 -0
  428. package/src/engine/models.ts +42 -0
  429. package/src/engine/oauth.ts +16 -12
  430. package/src/engine/prompt-templates.ts +1 -0
  431. package/src/engine/provider-payload.ts +16 -59
  432. package/src/engine/strip-tokenizer-sentinels.ts +1 -1
  433. package/src/engine/truncate.ts +9 -0
  434. package/src/engine/tui.ts +17 -9
  435. package/src/engine/types.ts +3 -6
  436. package/src/engine/worker-runtime-capabilities.ts +5 -0
  437. package/src/engine/worker-runtime.ts +1 -1
  438. package/src/engine/worker-tools.ts +9 -4
  439. package/src/entry/boot-options.ts +50 -0
  440. package/src/entry/orchestrator.ts +288 -150
  441. package/src/interactive/application-controller.ts +89 -2
  442. package/src/interactive/chat-loop.ts +266 -41
  443. package/src/interactive/chat-panel.ts +715 -278
  444. package/src/interactive/chat-renderer.ts +306 -85
  445. package/src/interactive/clio-editor.ts +3 -8
  446. package/src/interactive/command-fallbacks.ts +2 -2
  447. package/src/interactive/context-overlay.ts +27 -1
  448. package/src/interactive/editor-submit.ts +253 -24
  449. package/src/interactive/export-html/ansi-to-html.ts +161 -0
  450. package/src/interactive/export-html/index.ts +51 -0
  451. package/src/interactive/export-html/template.ts +45 -0
  452. package/src/interactive/export-html/tool-renderer.ts +54 -0
  453. package/src/interactive/footer/dashboard.ts +4 -0
  454. package/src/interactive/footer/notifications.ts +1 -1
  455. package/src/interactive/footer/widgets.ts +42 -22
  456. package/src/interactive/footer-panel.ts +8 -3
  457. package/src/interactive/format-time.ts +14 -2
  458. package/src/interactive/interactive-application.ts +203 -17
  459. package/src/interactive/interactive-event-projection.ts +18 -1
  460. package/src/interactive/interactive-input-runtime.ts +50 -4
  461. package/src/interactive/interactive-presentation.ts +151 -19
  462. package/src/interactive/interactive-shell.ts +268 -14
  463. package/src/interactive/interactive-slash-runtime.ts +184 -117
  464. package/src/interactive/interactive-tickers.ts +38 -7
  465. package/src/interactive/keybinding-manager.ts +1 -1
  466. package/src/interactive/layout.ts +40 -3
  467. package/src/interactive/overlay-frame.ts +1 -1
  468. package/src/interactive/overlay-general-openers.ts +58 -1
  469. package/src/interactive/overlay-key-routing.ts +3 -0
  470. package/src/interactive/overlay-lifecycle.ts +13 -0
  471. package/src/interactive/overlay-permission-lifecycle.ts +2 -1
  472. package/src/interactive/overlay-session-lifecycle.ts +69 -12
  473. package/src/interactive/overlays/ask-user.ts +146 -24
  474. package/src/interactive/overlays/decisions.ts +300 -0
  475. package/src/interactive/overlays/help-reference.ts +15 -10
  476. package/src/interactive/overlays/model-selector.ts +34 -16
  477. package/src/interactive/overlays/session-selector.ts +18 -0
  478. package/src/interactive/overlays/settings.ts +105 -17
  479. package/src/interactive/overlays/skills-hub.ts +4 -4
  480. package/src/interactive/overlays/tree-selector.ts +41 -6
  481. package/src/interactive/render-trace.ts +499 -90
  482. package/src/interactive/renderers/compaction-summary.ts +2 -2
  483. package/src/interactive/renderers/diff.ts +115 -104
  484. package/src/interactive/renderers/mermaid.ts +53 -0
  485. package/src/interactive/renderers/tool-execution.ts +516 -168
  486. package/src/interactive/renderers/worker-entry.ts +20 -4
  487. package/src/interactive/session-switch-settlement.ts +10 -0
  488. package/src/interactive/slash-autocomplete.ts +6 -114
  489. package/src/interactive/slash-commands.ts +135 -47
  490. package/src/interactive/slash-spec.ts +9 -38
  491. package/src/interactive/status/controller.ts +5 -1
  492. package/src/interactive/status/index.ts +12 -1
  493. package/src/interactive/status/reasoning.ts +87 -0
  494. package/src/interactive/status/summary.ts +13 -2
  495. package/src/interactive/stdout-backpressure.ts +99 -0
  496. package/src/interactive/stream-pacer.ts +530 -0
  497. package/src/interactive/stream-pacing-policy.ts +66 -0
  498. package/src/interactive/tasks-overlay.ts +368 -14
  499. package/src/interactive/terminal-lease.ts +485 -0
  500. package/src/interactive/theme/tokens.ts +1 -1
  501. package/src/interactive/transcript-detail.ts +120 -0
  502. package/src/interactive/turn-context.ts +4 -3
  503. package/src/interactive/turn-persistence.ts +30 -13
  504. package/src/interactive/turn-queues.ts +12 -0
  505. package/src/interactive/turn-recovery.ts +25 -8
  506. package/src/interactive/turn-runtime.ts +79 -12
  507. package/src/interactive/turn-state.ts +10 -0
  508. package/src/interactive/view/artifacts.ts +114 -4
  509. package/src/interactive/view/view-overlay.ts +3 -0
  510. package/src/interactive/welcome-dashboard.ts +17 -16
  511. package/src/interactive/worker-receipts.ts +52 -3
  512. package/src/interactive/worker-stream.ts +5 -1
  513. package/src/tools/agent-tools.ts +23 -3
  514. package/src/tools/artifact.ts +2 -2
  515. package/src/tools/ask-user.ts +23 -13
  516. package/src/tools/bash.ts +30 -2
  517. package/src/tools/bootstrap.ts +34 -431
  518. package/src/tools/builtin-tool-catalog.ts +271 -0
  519. package/src/tools/codewiki/code-nav-surface.ts +29 -0
  520. package/src/tools/codewiki/code-nav.ts +8 -22
  521. package/src/tools/codewiki/shared.ts +41 -38
  522. package/src/tools/context/docs-engine.ts +14 -3
  523. package/src/tools/context/index.ts +107 -28
  524. package/src/tools/context/surface.ts +19 -0
  525. package/src/tools/core-bootstrap.ts +168 -0
  526. package/src/tools/credential-present.ts +5 -5
  527. package/src/tools/dispatch-admission.ts +533 -0
  528. package/src/tools/dispatch-background.ts +54 -0
  529. package/src/tools/dispatch-event-text.ts +6 -0
  530. package/src/tools/dispatch-plan.ts +9 -4
  531. package/src/tools/dispatch-run-events.ts +238 -0
  532. package/src/tools/dispatch-runner.ts +2370 -0
  533. package/src/tools/dispatch-scout-admission.ts +295 -0
  534. package/src/tools/dispatch-types.ts +77 -0
  535. package/src/tools/dispatch.ts +67 -3161
  536. package/src/tools/find.ts +4 -2
  537. package/src/tools/grep.ts +2 -2
  538. package/src/tools/lazy-tool.ts +60 -0
  539. package/src/tools/ledger.ts +3 -3
  540. package/src/tools/monitor-surface.ts +36 -0
  541. package/src/tools/monitor.ts +2 -32
  542. package/src/tools/observers.ts +2 -2
  543. package/src/tools/presentation.ts +107 -0
  544. package/src/tools/registry.ts +45 -27
  545. package/src/tools/safe-exec.ts +2 -2
  546. package/src/tools/steer-surface.ts +17 -0
  547. package/src/tools/steer.ts +2 -13
  548. package/src/tools/tasks.ts +108 -11
  549. package/src/tools/truncate.ts +25 -184
  550. package/src/tools/verify/frontend.ts +3 -1
  551. package/src/tools/verify/index.ts +3 -38
  552. package/src/tools/verify/surface.ts +46 -0
  553. package/src/tools/web-fetch-surface.ts +23 -0
  554. package/src/tools/web-fetch.ts +2 -20
  555. package/src/tools/write.ts +7 -2
  556. package/src/worker/entry.ts +39 -2
  557. package/src/worker/spec-contract.ts +26 -5
  558. package/dist/chunk-7SS2CTV2.js +0 -61361
  559. package/dist/chunk-DKGKUHFA.js +0 -924
  560. package/dist/chunk-GEP36Y4X.js +0 -12796
  561. package/dist/chunk-XYWBQRDM.js +0 -137
  562. package/dist/clio-BZVGEUFJ.js +0 -58
  563. package/dist/configure-S7S6F6CL.js +0 -32
  564. package/docs/html/agents_blueprint.html +0 -936
  565. package/docs/html/alcf_blueprint.html +0 -324
  566. package/docs/html/architecture_blueprint.html +0 -850
  567. package/docs/html/commands_blueprint.html +0 -939
  568. package/docs/html/config_knobs_audit_blueprint.html +0 -178
  569. package/docs/html/configuration_blueprint.html +0 -1080
  570. package/docs/html/context_blueprint.html +0 -603
  571. package/docs/html/documentation_blueprint.html +0 -832
  572. package/docs/html/environment_blueprint.html +0 -404
  573. package/docs/html/eval_blueprint.html +0 -743
  574. package/docs/html/evals_internal_blueprint.html +0 -190
  575. package/docs/html/evolution_blueprint.html +0 -674
  576. package/docs/html/extensions_blueprint.html +0 -2065
  577. package/docs/html/fleet_dispatch_blueprint.html +0 -286
  578. package/docs/html/index.html +0 -919
  579. package/docs/html/lifecycle_blueprint.html +0 -723
  580. package/docs/html/memory_blueprint.html +0 -699
  581. package/docs/html/middleware_blueprint.html +0 -664
  582. package/docs/html/models_blueprint.html +0 -2366
  583. package/docs/html/observability_blueprint.html +0 -683
  584. package/docs/html/provider_adapter_blueprint.html +0 -245
  585. package/docs/html/safety_blueprint.html +0 -1386
  586. package/docs/html/shared.css +0 -571
  587. package/docs/html/shared.js +0 -143
  588. package/docs/html/skills_blueprint.html +0 -671
  589. package/docs/html/soak_blueprint.html +0 -182
  590. package/docs/html/tool_usage_blueprint.html +0 -350
  591. package/docs/html/tools_blueprint.html +0 -2249
  592. package/docs/html/trace_blueprint.html +0 -235
  593. package/docs/html/tui_design_blueprint.html +0 -374
  594. package/docs/html/validation_blueprint.html +0 -961
  595. package/docs/html/worker_dispatch_blueprint.html +0 -231
  596. package/src/core/release.ts +0 -2
  597. package/src/domains/providers/runtimes/common/lmstudio-logger.ts +0 -32
  598. package/src/domains/providers/runtimes/local-native/lmstudio-native.ts +0 -491
  599. package/src/engine/apis/lmstudio-native.ts +0 -1438
  600. package/src/engine/apis/thinking-replay.ts +0 -11
  601. package/src/tools/string-enum.ts +0 -15
@@ -16,14 +16,9 @@ import { dirname, join } from "node:path";
16
16
  import type { ContextActivityPayload } from "../../../core/bus-events.js";
17
17
  import { detectProjectType } from "../../session/workspace/project-type.js";
18
18
  import type { BootstrapProgressSink } from "../bootstrap.js";
19
- import {
20
- buildCodewiki,
21
- type Codewiki,
22
- codewikiNeedsBackfill,
23
- readCodewiki,
24
- writeCodewiki,
25
- } from "../codewiki/indexer.js";
26
- import { computeFingerprint, isStale } from "../fingerprint.js";
19
+ import { coordinateCodewikiWrite } from "../codewiki/coordinator.js";
20
+ import type { Codewiki } from "../codewiki/schema.js";
21
+ import type { Fingerprint } from "../fingerprint.js";
27
22
  import { readClioState, writeClioState } from "../state.js";
28
23
  import { assembleWikiTree, normalizeRepoPath, pageSourceIndex } from "./assemble.js";
29
24
  import { isGeneratedWikiFile, listWikiPagesInDir, WIKI_PLAN_FILE, wikiDir, wikiMarkdownFilesInDir } from "./layout.js";
@@ -108,32 +103,42 @@ function indexedSourceFileCount(codewiki: Codewiki): number {
108
103
  return codewiki.files.filter((file) => file.lang !== "config").length;
109
104
  }
110
105
 
111
- async function loadOrBuildCodewiki(cwd: string): Promise<Codewiki> {
112
- const existing = readCodewiki(cwd);
113
- const prev = readClioState(cwd);
114
- // Mirror the code_nav demand-load freshness check: a stale index must never
115
- // ground the wiki writer prompt, so drift forces a rebuild here too.
116
- if (existing && !codewikiNeedsBackfill(existing)) {
117
- const fingerprint = computeFingerprint(cwd, existing);
118
- if (prev && !isStale(prev.fingerprint, fingerprint)) return existing;
119
- }
106
+ async function loadOrBuildCodewiki(cwd: string): Promise<{
107
+ codewiki: Codewiki;
108
+ fingerprint: Fingerprint;
109
+ }> {
120
110
  const generatedAt = new Date().toISOString();
121
111
  const projectType = detectProjectType(cwd);
122
- const rebuilt = await buildCodewiki({ cwd, language: projectType, generatedAt });
123
- writeCodewiki(cwd, rebuilt);
124
- writeClioState(cwd, {
125
- version: 1,
126
- projectType: prev?.projectType ?? projectType,
127
- fingerprint: computeFingerprint(cwd, rebuilt),
128
- codewikiVersion: rebuilt.version,
129
- ...(prev?.contextSources ? { contextSources: prev.contextSources } : {}),
130
- ...(prev?.contextSourceHash ? { contextSourceHash: prev.contextSourceHash } : {}),
131
- ...(prev?.lastBootstrap ? { lastBootstrap: prev.lastBootstrap } : {}),
132
- ...(prev?.lastInitAt ? { lastInitAt: prev.lastInitAt } : {}),
133
- lastSessionAt: prev?.lastSessionAt ?? generatedAt,
134
- lastIndexedAt: generatedAt,
135
- });
136
- return rebuilt;
112
+ const coordinated = await coordinateCodewikiWrite(
113
+ cwd,
114
+ (current, workspace) => ({
115
+ kind: "ensure",
116
+ cwd: workspace,
117
+ language: projectType,
118
+ current,
119
+ previous: readClioState(workspace)?.fingerprint ?? null,
120
+ }),
121
+ {
122
+ afterCommit: ({ codewiki, fingerprint, changed }, workspace) => {
123
+ const prev = readClioState(workspace);
124
+ if (!changed && prev) return;
125
+ writeClioState(workspace, {
126
+ version: 1,
127
+ projectType: prev?.projectType ?? projectType,
128
+ fingerprint,
129
+ codewikiVersion: codewiki.version,
130
+ ...(prev?.contextSources ? { contextSources: prev.contextSources } : {}),
131
+ ...(prev?.contextSourceHash ? { contextSourceHash: prev.contextSourceHash } : {}),
132
+ ...(prev?.lastBootstrap ? { lastBootstrap: prev.lastBootstrap } : {}),
133
+ ...(prev?.lastInitAt ? { lastInitAt: prev.lastInitAt } : {}),
134
+ lastSessionAt: prev?.lastSessionAt ?? generatedAt,
135
+ lastIndexedAt: generatedAt,
136
+ });
137
+ },
138
+ },
139
+ );
140
+ if (!coordinated) throw new Error("codewiki wiki transaction did not commit");
141
+ return { codewiki: coordinated.codewiki, fingerprint: coordinated.worker.fingerprint };
137
142
  }
138
143
 
139
144
  function failed(problems: string[], pages: number): RunWikiGenerateResult {
@@ -411,8 +416,8 @@ export async function runWikiGenerate(
411
416
 
412
417
  try {
413
418
  progress(input, { phase: "codewiki", status: "started", message: "loading codewiki for wiki generation" });
414
- const codewiki = await loadOrBuildCodewiki(cwd);
415
- const sourceTreeHash = computeFingerprint(cwd, codewiki).treeHash;
419
+ const { codewiki, fingerprint } = await loadOrBuildCodewiki(cwd);
420
+ const sourceTreeHash = fingerprint.treeHash;
416
421
  const generation = planWikiGeneration(codewiki, input.depth ?? "auto");
417
422
  progress(input, {
418
423
  phase: "codewiki",
@@ -16,7 +16,7 @@
16
16
  * index finds at the requested depth.
17
17
  */
18
18
 
19
- import type { Codewiki, CodewikiFile } from "../codewiki/indexer.js";
19
+ import type { Codewiki, CodewikiFile } from "../codewiki/schema.js";
20
20
 
21
21
  export type WikiDepth = "auto" | "simple" | "medium" | "detailed";
22
22
  export type ResolvedWikiDepth = Exclude<WikiDepth, "auto">;
@@ -11,11 +11,11 @@
11
11
  */
12
12
 
13
13
  import { execFileSync } from "node:child_process";
14
- import { existsSync, readFileSync, realpathSync, statSync } from "node:fs";
14
+ import { existsSync, realpathSync, statSync } from "node:fs";
15
15
  import { isAbsolute, join, relative } from "node:path";
16
- import { resolvePackageRoot } from "../../../core/package-root.js";
16
+ import { loadFragments } from "../../prompts/fragment-loader.js";
17
17
  import { renderCodewikiDigest } from "../codewiki/digest.js";
18
- import type { Codewiki } from "../codewiki/indexer.js";
18
+ import type { Codewiki } from "../codewiki/schema.js";
19
19
  import { WIKI_PLAN_FILE } from "./layout.js";
20
20
  import type { WikiGenerationPlan, WikiPlan, WikiPlanPage } from "./plan.js";
21
21
 
@@ -23,12 +23,25 @@ export type WikiGenerateMode = "init" | "update";
23
23
 
24
24
  type WikiFragment = "plan" | "page";
25
25
 
26
- function fragmentPath(fragment: WikiFragment): string {
27
- return join(resolvePackageRoot(), "src", "domains", "prompts", "fragments", "wiki", `${fragment}.md`);
28
- }
29
-
26
+ /**
27
+ * `wiki.plan` and `wiki.page` load through the same fragment loader every
28
+ * other prompt fragment does (`prompts/fragments/wiki/*.md`), so their
29
+ * content participates in the same id/version/content-hash contract. What
30
+ * this module owns and the loader does not is `{{token}}` substitution: each
31
+ * fragment carries per-dispatch values (a page's path, title, relative path;
32
+ * the plan file's path) the loader has no way to supply, the same division
33
+ * `identity.self-awareness` uses for its own `{TOKEN}` placeholders in
34
+ * `prompts/compiler.ts`. Loaded fresh on every call rather than cached, so a
35
+ * fragment edit or config hot-reload is visible on the next dispatch with no
36
+ * separate subscription to wire.
37
+ */
30
38
  function readWikiFragment(fragment: WikiFragment, substitutions: Record<string, string>): string {
31
- let text = readFileSync(fragmentPath(fragment), "utf8").trim();
39
+ const id = `wiki.${fragment}`;
40
+ const loaded = loadFragments().byId.get(id);
41
+ if (!loaded) {
42
+ throw new Error(`context/wiki: fragment "${id}" not found; check prompts/fragments/wiki/${fragment}.md frontmatter`);
43
+ }
44
+ let text = loaded.body.trim();
32
45
  for (const [token, value] of Object.entries(substitutions)) {
33
46
  text = text.split(`{{${token}}}`).join(value);
34
47
  }
@@ -17,6 +17,13 @@ import { execFileSync, spawn } from "node:child_process";
17
17
  import { createHash } from "node:crypto";
18
18
  import { mkdirSync, writeFileSync } from "node:fs";
19
19
  import { isAbsolute, join, resolve } from "node:path";
20
+ import { AI_AGENT_NAME } from "../../core/agent-environment.js";
21
+ import type { CommitAttributionEvidence } from "../../core/commit-attribution.js";
22
+ import {
23
+ gitCommitAttributionEnabled,
24
+ reportCommitAttributionDiagnostic,
25
+ withManagedGitCommitAttributionEnvironment,
26
+ } from "../../core/git-commit-attribution.js";
20
27
  import { FLEET_COMMAND_BASE_ENV, type FleetCommand } from "../agents/fleet-commands.js";
21
28
  import type { CodeReportResult } from "../agents/result-contract.js";
22
29
 
@@ -59,6 +66,11 @@ export interface CodeStepRunInput {
59
66
  * a failure, not a no-op: it means the step it describes produced nothing.
60
67
  */
61
68
  requireWorkspaceChanges?: boolean;
69
+ /** Trusted attribution facts for a commit command; omitted uses Clio-authored child-process defaults. */
70
+ commitAttribution?: {
71
+ enabled: boolean;
72
+ evidence: Readonly<CommitAttributionEvidence>;
73
+ };
62
74
  signal?: AbortSignal;
63
75
  }
64
76
 
@@ -140,6 +152,7 @@ export function codeStepEnv(command: FleetCommand, source: NodeJS.ProcessEnv): N
140
152
  const value = source[name];
141
153
  if (value !== undefined) env[name] = value;
142
154
  }
155
+ env.AI_AGENT = AI_AGENT_NAME;
143
156
  return env;
144
157
  }
145
158
 
@@ -206,6 +219,12 @@ async function spawnCommand(input: CodeStepRunInput, cwd: string, argv: Readonly
206
219
  const [executable, ...args] = argv;
207
220
  if (executable === undefined) throw new Error(`code step: command '${command.id}' has no executable`);
208
221
  return await new Promise<SpawnOutcome>((resolvePromise) => {
222
+ const attribution = withManagedGitCommitAttributionEnvironment(codeStepEnv(command, input.env ?? process.env), {
223
+ cwd,
224
+ enabled: input.commitAttribution?.enabled ?? gitCommitAttributionEnabled(process.env),
225
+ ...(input.commitAttribution?.evidence === undefined ? {} : { evidence: input.commitAttribution.evidence }),
226
+ });
227
+ reportCommitAttributionDiagnostic(attribution.diagnostic);
209
228
  const chunks: Buffer[] = [];
210
229
  let outputBytes = 0;
211
230
  let captured = 0;
@@ -214,7 +233,7 @@ async function spawnCommand(input: CodeStepRunInput, cwd: string, argv: Readonly
214
233
  let spawnError: string | null = null;
215
234
  const child = spawn(executable, args, {
216
235
  cwd,
217
- env: codeStepEnv(command, input.env ?? process.env),
236
+ env: attribution.env,
218
237
  stdio: ["ignore", "pipe", "pipe"],
219
238
  // The command leads its own process group, so a timeout kills the
220
239
  // whole tree rather than orphaning a test runner's children.
@@ -35,8 +35,8 @@ import {
35
35
  import { antigravitySubprocessConfigForAutonomy } from "../../engine/antigravity/subprocess-runtime.js";
36
36
  import { claudeSubprocessPermissionConfigForAutonomy } from "../../engine/claude/subprocess-runtime.js";
37
37
  import { isClaudeCanonicalTool } from "../../engine/claude/tool-safety.js";
38
- import { WORKER_RUNTIME_MEDIATES_CLIO_DISPATCH } from "../../engine/worker-tools.js";
39
- import { toolPromptHintsForNames } from "../../tools/bootstrap.js";
38
+ import { WORKER_RUNTIME_MEDIATES_CLIO_DISPATCH } from "../../engine/worker-runtime-capabilities.js";
39
+ import { toolPromptHintsForNames } from "../../tools/builtin-tool-catalog.js";
40
40
  import { networkToolsDisabled } from "../../tools/network-policy.js";
41
41
  import { applyToolProfile, assertToolProfileEnforceable, type ToolProfileName } from "../../tools/profiles.js";
42
42
  import { truncateUtf8 } from "../../tools/truncate-utf8.js";
@@ -73,6 +73,7 @@ import {
73
73
  isDispatchEligibleRuntime,
74
74
  type ProvidersContract,
75
75
  type ResolvedRuntimeTarget,
76
+ type RuntimeApiFamily,
76
77
  type RuntimeDescriptor,
77
78
  resolveModelCapabilities,
78
79
  resolveRuntimeTarget,
@@ -372,6 +373,14 @@ const DEFAULT_ACP_STALL_TIMEOUT_MS = 300_000;
372
373
  const ADMISSION_INPUT_TOKEN_ESTIMATE = 4096;
373
374
  const ACP_TOOL_SIGNATURE = "acp:unobservable";
374
375
  const ACP_SPEC_FINGERPRINT = "acp:unobservable";
376
+ /**
377
+ * Where the worker process ran when no fleet placement chose a node. This is the
378
+ * worker's own host, never the host serving the model: a run against a remote
379
+ * target from this machine is still a local node. Emitted on every run so a
380
+ * receipt has one node shape, rather than carrying the block only on the paths
381
+ * that happened to have a placement object.
382
+ */
383
+ const LOCAL_RUN_NODE: RunNodeIdentity = { id: "local", kind: "local" };
375
384
  function sealRouteDecision(draft: RunReceiptDraft, decision: RouteDecisionV1): RunReceiptDraft {
376
385
  return { ...draft, routeDecision: decision };
377
386
  }
@@ -980,8 +989,14 @@ function personaOverrideFor(req: DispatchRequest, staticCompositionHash: string
980
989
 
981
990
  /**
982
991
  * Per-run context for the dynamic worker prompt messages. Everything here
983
- * flows through dynamic messages, never through the stable system prompt, so
984
- * `staticCompositionHash` stays byte-identical run over run.
992
+ * flows through dynamic messages, never through the system prompt. The system
993
+ * prompt itself is stable per recipe and tool surface with one exception: the
994
+ * operator-editable layer (`additionalFragments`) folds in path-scoped project
995
+ * rules selected by `workerWorkingContextPaths`, which are recalled from the
996
+ * task and briefing text, so `staticCompositionHash` can differ between two
997
+ * runs of one recipe when a rule's glob matches one task and not the other.
998
+ * A local model's worker prefix cache misses on that flip; the trade was made
999
+ * deliberately in #96 to keep rules scoped rather than shipped wholesale.
985
1000
  */
986
1001
  export interface WorkerDynamicContext {
987
1002
  /** Used only for the verification-section inclusion rule, never for tier policy. */
@@ -1048,6 +1063,35 @@ function workerProjectContextIncludesVerification(body: string): boolean {
1048
1063
  return body.includes("\nVerification expectations:\n");
1049
1064
  }
1050
1065
 
1066
+ /**
1067
+ * Path-like tokens in free text: a slash-separated segment, or a bare
1068
+ * `name.ext` token. The model-facing dispatch tool has no structured
1069
+ * path/file field, so a worker's task text is the only working-context
1070
+ * signal available at compile time; this is best-effort recall, not a
1071
+ * parser. A false-positive token is harmless because `selectActiveRules`
1072
+ * only activates a rule when the token matches that rule's own glob.
1073
+ */
1074
+ const PATH_TOKEN_RE = /(?:[\w.-]+\/)+[\w.-]+|\b[\w-]+\.[A-Za-z0-9]{1,8}\b/g;
1075
+
1076
+ /**
1077
+ * Best-effort working-context paths for a dispatched worker: `writeRoots`
1078
+ * when the caller set them (the precise signal, for internal/programmatic
1079
+ * callers), plus path-like tokens recalled from the task and briefing text.
1080
+ * Feeds the same `selectActiveRules` a session uses, so a worker whose task
1081
+ * touches a ruled path reads that rule instead of never hearing about it.
1082
+ */
1083
+ function workerWorkingContextPaths(req: DispatchRequest): string[] {
1084
+ const out = new Set<string>();
1085
+ for (const root of req.writeRoots ?? []) out.add(root);
1086
+ const text = `${req.task}\n${req.briefing ?? ""}`;
1087
+ for (const match of text.matchAll(PATH_TOKEN_RE)) {
1088
+ const token = match[0];
1089
+ if (token.startsWith("http://") || token.startsWith("https://")) continue;
1090
+ out.add(token);
1091
+ }
1092
+ return [...out];
1093
+ }
1094
+
1051
1095
  export function buildDynamicPromptMessages(
1052
1096
  req: DispatchRequest,
1053
1097
  dynamicContext: WorkerDynamicContext = {},
@@ -1122,6 +1166,15 @@ interface ResolvedTarget {
1122
1166
  thinkingLevel: ThinkingLevel;
1123
1167
  capabilities: CapabilityFlags | null;
1124
1168
  modelCapabilities: CapabilityFlags | null;
1169
+ /**
1170
+ * What actually answered the tool-support question for this wire model: the
1171
+ * operator's own target override, else the knowledge-base entry, else null
1172
+ * when nothing named it. The merged `modelCapabilities` cannot express this,
1173
+ * because a runtime default of `tools: false` is indistinguishable there
1174
+ * from a measurement, and a knowledge-base miss on a local model id is
1175
+ * routine rather than an answer. See {@link targetToolCapability}.
1176
+ */
1177
+ toolsCapabilityExplicit: boolean | null;
1125
1178
  runtimeResolution: ResolvedRuntimeTarget;
1126
1179
  effectivePricing: EffectivePricing;
1127
1180
  /** Why the route this run got is not the route it asked for. Belongs in the outcome. */
@@ -1226,6 +1279,10 @@ interface DispatchLifecycleStage {
1226
1279
  briefing: RunBriefingProvenance | null;
1227
1280
  personaOverride: RunPersonaOverride | null;
1228
1281
  projectContext: RunProjectContextProvenance;
1282
+ /** Rule ids the worker prompt compiler selected into this run's system prompt; [] when none matched. */
1283
+ rulesApplied: string[];
1284
+ /** Whether the operator profile rendered non-empty content into this run's system prompt. */
1285
+ operatorProfileApplied: boolean;
1229
1286
  /** Read-only recipe admitted against a mutating task; null when the pairing was sound. */
1230
1287
  capabilityMismatch: CapabilityMismatch | null;
1231
1288
  effectiveAutonomy: AutonomyLevel;
@@ -1252,6 +1309,10 @@ interface AcpDelegationLifecycleStage {
1252
1309
  briefing: RunBriefingProvenance | null;
1253
1310
  personaOverride: RunPersonaOverride | null;
1254
1311
  projectContext: RunProjectContextProvenance;
1312
+ /** ACP delegation bypasses the worker prompt compiler entirely, so this is always []. */
1313
+ rulesApplied: string[];
1314
+ /** ACP delegation bypasses the worker prompt compiler entirely, so this is always false. */
1315
+ operatorProfileApplied: boolean;
1255
1316
  sessionAutonomy: AutonomyLevel;
1256
1317
  autonomy: AutonomyLevel;
1257
1318
  }
@@ -1307,16 +1368,6 @@ function runtimeLimitations(runtimeKind: RunKind, runtimeId: string): string[] {
1307
1368
  "Claude CLI subprocess executes Claude Code tools; Clio constrains permission mode and forbids dangerous bypass unless explicitly gated",
1308
1369
  ];
1309
1370
  }
1310
- if (runtimeId === "lmstudio-native") {
1311
- // The SDK owns model management only. Predictions go over the same
1312
- // server's OpenAI-compatible port, which is the surface that carries a
1313
- // thinking control, so the resolved level does reach the wire. What the
1314
- // SDK still cannot do is unload a model another client loaded outside
1315
- // Clio's residency plan, which is the one dispatch-visible limit left.
1316
- return [
1317
- "LM Studio residency is reconciled through the native SDK; models loaded outside Clio are observed rather than evicted",
1318
- ];
1319
- }
1320
1371
  // HTTP/native runtimes run through pi-agent-core, which Clio observes and
1321
1372
  // controls directly, so there are no runtime-imposed dispatch limitations.
1322
1373
  return [];
@@ -1364,8 +1415,65 @@ function assertWorkerBudgetEnforceable(runtime: RuntimeDescriptor, hasDeclaredBu
1364
1415
  );
1365
1416
  }
1366
1417
 
1418
+ /**
1419
+ * API families whose wire protocol carries tool calls. Membership is a property
1420
+ * of the protocol, not of any one model: every server speaking one of these can
1421
+ * express a tool call, so a model served over it is presumed able to take one
1422
+ * until something says otherwise. The excluded families (`embeddings-http`,
1423
+ * `rerank-http`) have no tool surface to offer at all.
1424
+ */
1425
+ const TOOL_CARRYING_API_FAMILIES: ReadonlySet<RuntimeApiFamily> = new Set([
1426
+ "openai-completions",
1427
+ "openai-responses",
1428
+ "openai-codex-responses",
1429
+ "azure-openai-responses",
1430
+ "anthropic-messages",
1431
+ "bedrock-converse-stream",
1432
+ "google-generative-ai",
1433
+ "google-vertex",
1434
+ "mistral-conversations",
1435
+ "ollama-native",
1436
+ "claude-agent-sdk",
1437
+ "claude-code-subprocess",
1438
+ ]);
1439
+
1440
+ /**
1441
+ * Whether this run may be offered tools at all.
1442
+ *
1443
+ * A runtime default of `tools: false` on a protocol runtime is a placeholder,
1444
+ * not a measurement: the generic `openai-compat` descriptor cannot know what an
1445
+ * arbitrary local server has loaded, so it declares the conservative value and
1446
+ * leaves the answer to the knowledge base. A knowledge-base miss on a local
1447
+ * model id is routine (a new quant, a renamed GGUF, a model newer than the
1448
+ * catalog), so reading that miss as "no tools" denied every dispatch against
1449
+ * every unlisted local model while the same target answered tool calls fine on
1450
+ * the chat path. Only an explicit `false`, from the operator's target override
1451
+ * or from a knowledge-base entry that names the model, denies now; an unanswered
1452
+ * question lets a tool-carrying protocol try and surface a real provider error
1453
+ * if the server genuinely cannot.
1454
+ */
1367
1455
  function targetToolCapability(target: ResolvedTarget): boolean {
1368
- return target.modelCapabilities?.tools ?? target.runtime.defaultCapabilities.tools === true;
1456
+ if (target.modelCapabilities?.tools === true) return true;
1457
+ if (target.runtime.defaultCapabilities.tools === true) return true;
1458
+ if (target.toolsCapabilityExplicit === false) return false;
1459
+ return TOOL_CARRYING_API_FAMILIES.has(target.runtime.apiFamily);
1460
+ }
1461
+
1462
+ /**
1463
+ * The only two sources that can actually answer "does this model take tools":
1464
+ * the operator's own target override, which wins, and the knowledge-base entry
1465
+ * for the wire model. Null means nothing named it, which is the common case for
1466
+ * a local model id the catalog has never seen.
1467
+ */
1468
+ function explicitToolCapability(
1469
+ providers: ProvidersContract,
1470
+ target: TargetDescriptor,
1471
+ wireModelId: string,
1472
+ ): boolean | null {
1473
+ if (typeof target.capabilities?.tools === "boolean") return target.capabilities.tools;
1474
+ const hit = providers.knowledgeBase?.lookup(wireModelId) ?? null;
1475
+ const fromKnowledgeBase = hit?.entry.capabilities?.tools;
1476
+ return typeof fromKnowledgeBase === "boolean" ? fromKnowledgeBase : null;
1369
1477
  }
1370
1478
 
1371
1479
  function writeConfinedRequest(req: DispatchRequest): boolean {
@@ -1674,7 +1782,10 @@ function buildDispatchWorkerSpec(input: DispatchWorkerSpecInput, config?: Config
1674
1782
  ...(input.dynamicHash !== null ? { dynamicHash: input.dynamicHash } : {}),
1675
1783
  agentId: input.req.agentId,
1676
1784
  task: input.req.task,
1677
- target: input.target.target,
1785
+ // The configured target may name its runtime by a legacy alias. The attested
1786
+ // document records the resolved runtime instead, so what the worker reads
1787
+ // and what the orchestrator routed on are the same id.
1788
+ target: { ...input.target.target, runtime: input.target.runtime.id },
1678
1789
  runtime: serializeWorkerRuntimeDescriptor(input.target.runtime),
1679
1790
  runtimeId: input.target.runtime.id,
1680
1791
  wireModelId: input.target.wireModelId,
@@ -1705,7 +1816,18 @@ function buildDispatchWorkerSpec(input: DispatchWorkerSpecInput, config?: Config
1705
1816
  }
1706
1817
  const product = input.req.product ?? input.recipe?.product;
1707
1818
  if (product) spec.product = product;
1708
- spec.runtimeResolution = runtimeTargetSnapshot(input.target.runtimeResolution);
1819
+ // The orchestrator's tool decision is the one the run was admitted under and
1820
+ // the one the approved tool signature was computed from, so it travels on the
1821
+ // snapshot rather than being re-derived worker-side. The worker's
1822
+ // workerProviderSupportsTools reads this field first; letting it recompute
1823
+ // from the merged capability decision made an unanswered tool question
1824
+ // resolve differently in the two processes, and the announcement was then
1825
+ // refused for tool surface drift.
1826
+ const resolutionSnapshot = runtimeTargetSnapshot(input.target.runtimeResolution);
1827
+ spec.runtimeResolution = {
1828
+ ...resolutionSnapshot,
1829
+ capabilities: { ...resolutionSnapshot.capabilities, tools: targetToolCapability(input.target) },
1830
+ };
1709
1831
  if (input.target.modelCapabilities) spec.modelCapabilities = input.target.modelCapabilities;
1710
1832
  // Configured model ids with the role each serves, so the worker's empty
1711
1833
  // residency registry evicts nothing and names what it must touch.
@@ -1730,6 +1852,7 @@ function buildDispatchWorkerSpec(input: DispatchWorkerSpecInput, config?: Config
1730
1852
  } else if (settings) {
1731
1853
  spec.trustProjectCompatRoots = settings.skills.trustProjectCompatRoots === true;
1732
1854
  }
1855
+ spec.gitCommitAttribution = settings?.attribution.gitCommits ?? true;
1733
1856
  // Non-stall posture (Symphony §10.5): a dispatched worker has no operator
1734
1857
  // to answer a permission prompt by default, so the resolution policy ships
1735
1858
  // with the spec and the worker enforces it within bounded time. Under the
@@ -2023,6 +2146,7 @@ function resolveSelectedDispatchTarget(
2023
2146
  thinkingLevel: resolved.target.effectiveThinkingLevel,
2024
2147
  capabilities: capabilityInfoForTarget(providers, target.id),
2025
2148
  modelCapabilities,
2149
+ toolsCapabilityExplicit: explicitToolCapability(providers, target, wireModelId),
2026
2150
  runtimeResolution: resolved.target,
2027
2151
  effectivePricing: resolveEffectivePricing(target, runtime.id, wireModelId),
2028
2152
  };
@@ -3103,6 +3227,8 @@ export function createDispatchBundle(
3103
3227
  contentHash: sha256(personaBody),
3104
3228
  dynamic: false,
3105
3229
  },
3230
+ cwd,
3231
+ workingContextPaths: workerWorkingContextPaths(req),
3106
3232
  });
3107
3233
  const systemPrompt = compiledWorkerPrompt.systemPrompt;
3108
3234
  const budget = resolveEffectiveWorkerBudget({ declared: spec.budget, allowedTools: effectiveTools, settings });
@@ -3161,6 +3287,8 @@ export function createDispatchBundle(
3161
3287
  briefing: briefingProvenanceFor(req),
3162
3288
  personaOverride,
3163
3289
  projectContext: projectContextProvenance,
3290
+ rulesApplied: compiledWorkerPrompt.rulesApplied ?? [],
3291
+ operatorProfileApplied: compiledWorkerPrompt.operatorProfileApplied ?? false,
3164
3292
  capabilityMismatch,
3165
3293
  effectiveAutonomy,
3166
3294
  budget,
@@ -3250,6 +3378,8 @@ export function createDispatchBundle(
3250
3378
  briefing: briefingProvenanceFor(req),
3251
3379
  personaOverride,
3252
3380
  projectContext: projectContextProvenance,
3381
+ rulesApplied: [],
3382
+ operatorProfileApplied: false,
3253
3383
  sessionAutonomy,
3254
3384
  autonomy,
3255
3385
  };
@@ -3485,6 +3615,7 @@ export function createDispatchBundle(
3485
3615
  heartbeatAt: heartbeatIso(acp.heartbeatAt.current),
3486
3616
  lineage,
3487
3617
  identity,
3618
+ node: LOCAL_RUN_NODE,
3488
3619
  ...(lifecycle.pipeline ? { pipeline: lifecycle.pipeline } : {}),
3489
3620
  ...(lifecycle.briefing ? { briefing: lifecycle.briefing } : {}),
3490
3621
  ...(req.gate !== undefined ? { gate: req.gate } : {}),
@@ -3639,12 +3770,16 @@ export function createDispatchBundle(
3639
3770
  outcomeDetail,
3640
3771
  lineage,
3641
3772
  identity,
3773
+ // An ACP peer is spawned by this process, so the run's node is this host.
3774
+ node: LOCAL_RUN_NODE,
3642
3775
  ...(lifecycle.pipeline ? { pipeline: lifecycle.pipeline } : {}),
3643
3776
  ...(lifecycle.briefing ? { briefing: lifecycle.briefing } : {}),
3644
3777
  ...(req.gate !== undefined ? { gate: req.gate } : {}),
3645
3778
  ...(req.plan !== undefined ? { plan: req.plan } : {}),
3646
3779
  ...(lifecycle.personaOverride ? { personaOverride: lifecycle.personaOverride } : {}),
3647
3780
  projectContext: lifecycle.projectContext,
3781
+ rulesApplied: lifecycle.rulesApplied,
3782
+ operatorProfileApplied: lifecycle.operatorProfileApplied,
3648
3783
  startedAt,
3649
3784
  endedAt,
3650
3785
  exitCode:
@@ -4479,7 +4614,7 @@ export function createDispatchBundle(
4479
4614
  pid,
4480
4615
  lineage,
4481
4616
  identity,
4482
- ...(placement ? { node: placement.node } : {}),
4617
+ node: placement?.node ?? LOCAL_RUN_NODE,
4483
4618
  ...(placement?.reroutes !== undefined && placement.reroutes.length > 0
4484
4619
  ? { reroutes: [...placement.reroutes] }
4485
4620
  : {}),
@@ -4690,7 +4825,7 @@ export function createDispatchBundle(
4690
4825
  outcomeCode,
4691
4826
  lineage,
4692
4827
  identity,
4693
- ...(placement ? { node: placement.node } : {}),
4828
+ node: placement?.node ?? LOCAL_RUN_NODE,
4694
4829
  ...receiptAttestationFields(worker.attestation?.() ?? null),
4695
4830
  ...(placement?.reroutes !== undefined && placement.reroutes.length > 0
4696
4831
  ? { reroutes: [...placement.reroutes] }
@@ -4702,6 +4837,8 @@ export function createDispatchBundle(
4702
4837
  ...(req.plan !== undefined ? { plan: req.plan } : {}),
4703
4838
  ...(lifecycle.personaOverride ? { personaOverride: lifecycle.personaOverride } : {}),
4704
4839
  projectContext: lifecycle.projectContext,
4840
+ rulesApplied: lifecycle.rulesApplied,
4841
+ operatorProfileApplied: lifecycle.operatorProfileApplied,
4705
4842
  ...(validationGrounding !== null ? { validationGrounding } : {}),
4706
4843
  ...(ledgerContribution !== null ? { ledgerContribution } : {}),
4707
4844
  ...(lifecycle.capabilityMismatch !== null
@@ -5534,11 +5671,11 @@ export function createDispatchBundle(
5534
5671
  // recordReceipt() and persist(); quarantine tampered ones.
5535
5672
  try {
5536
5673
  const recovery = recoverOrphanReceipts(ledger);
5537
- if (recovery.recovered > 0 || recovery.corrupt > 0 || recovery.abandoned > 0) {
5674
+ if (recovery.recovered > 0 || recovery.corrupt > 0 || recovery.abandoned > 0 || recovery.sealed > 0) {
5538
5675
  await ledger.persist();
5539
5676
  if (process.env.CLIO_CODER_INTERACTIVE !== "1") {
5540
5677
  process.stderr.write(
5541
- `[dispatch] ledger recovery: recovered=${recovery.recovered} corrupt=${recovery.corrupt} abandoned=${recovery.abandoned} skipped=${recovery.skipped}\n`,
5678
+ `[dispatch] ledger recovery: recovered=${recovery.recovered} sealed=${recovery.sealed} corrupt=${recovery.corrupt} abandoned=${recovery.abandoned} skipped=${recovery.skipped}\n`,
5542
5679
  );
5543
5680
  }
5544
5681
  }
@@ -61,6 +61,12 @@ export function classifyFailure(
61
61
  // healthy endpoint for every other run in the window. Deterministic ends the
62
62
  // attempt here and leaves the caller free to redispatch without the schema.
63
63
  if (isResponseSchemaRejection(diagnostic)) return "deterministic-task";
64
+ // The worker rejected the specification the orchestrator wrote. A retry sends
65
+ // a document built the same way from the same settings and earns the same
66
+ // rejection, so three attempts only tripled the cost of one configuration
67
+ // error. Ending it here surfaces the contract message the operator has to act
68
+ // on instead of burying it under two more identical failures.
69
+ if (/\[worker\] fatal: workerspec/.test(diagnostic)) return "deterministic-task";
64
70
  if (/\b(?:401|403)\b|unauthorized|forbidden|invalid api key|authentication/.test(diagnostic)) return "target-auth";
65
71
  if (/\b429\b|rate[ -]?limit|too many requests/.test(diagnostic)) return "target-rate-limit";
66
72
  if (/\bvram\b|\bgpu\b|\bcuda\b|\boom\b|out of memory/.test(diagnostic)) return "node-resource";
@@ -0,0 +1,56 @@
1
+ import type { CommitAttributionEvidence } from "../../core/commit-attribution.js";
2
+ import type { ExecutionPlan, ExecutionPlanCodeStep } from "./execution-plan.js";
3
+ import { RUN_RECEIPT_INTEGRITY_ALGORITHM, RUN_RECEIPT_INTEGRITY_VERSION } from "./receipt-integrity.js";
4
+
5
+ export interface FleetCommitPriorResult {
6
+ succeeded: boolean;
7
+ integrityValid: boolean;
8
+ receiptDigest: string;
9
+ }
10
+
11
+ /**
12
+ * Derive one fleet commit's semantic attribution from scheduler-owned facts.
13
+ * Agent output text is deliberately absent from this input: prose cannot turn
14
+ * into testing or review evidence.
15
+ */
16
+ export function deriveFleetCommitAttribution(input: {
17
+ plan: ExecutionPlan;
18
+ step: ExecutionPlanCodeStep;
19
+ priorResults: ReadonlyMap<string, FleetCommitPriorResult>;
20
+ validationFresh: boolean;
21
+ independentReviewFresh: boolean;
22
+ }): CommitAttributionEvidence {
23
+ const byId = new Map(input.plan.steps.map((step) => [step.id, step] as const));
24
+ let materiallyAuthored = false;
25
+ let receipt: CommitAttributionEvidence["receipt"];
26
+ for (const candidate of input.step.commitFrom ?? []) {
27
+ const source = byId.get(candidate);
28
+ const result = input.priorResults.get(candidate);
29
+ if (
30
+ source?.kind !== "agent" ||
31
+ source.scope !== "workspace" ||
32
+ result?.succeeded !== true ||
33
+ result.integrityValid !== true
34
+ ) {
35
+ continue;
36
+ }
37
+ materiallyAuthored = true;
38
+ if (/^[0-9a-f]{64}$/u.test(result.receiptDigest)) {
39
+ receipt = {
40
+ version: RUN_RECEIPT_INTEGRITY_VERSION,
41
+ algorithm: RUN_RECEIPT_INTEGRITY_ALGORITHM,
42
+ digest: result.receiptDigest,
43
+ integrityValid: true,
44
+ directlyRelevant: true,
45
+ };
46
+ }
47
+ break;
48
+ }
49
+ return {
50
+ materiallyAssisted: materiallyAuthored,
51
+ materiallyAuthored,
52
+ validationSucceeded: input.validationFresh,
53
+ independentReviewPassed: input.independentReviewFresh,
54
+ ...(receipt === undefined ? {} : { receipt }),
55
+ };
56
+ }