@iowarp/clio-coder 0.3.0 → 0.3.2

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 (1187) hide show
  1. package/CHANGELOG.md +123 -2
  2. package/CONTRIBUTING.md +23 -23
  3. package/README.md +295 -627
  4. package/dist/acp-BIYHVZIM.js +128 -0
  5. package/dist/{agents-Q4MYPMUW.js → agents-YT6SSRIT.js} +52 -27
  6. package/dist/assets/codewiki.json +1 -0
  7. package/dist/assets/grammars/notices/@vscode__tree-sitter-wasm/LICENSE +21 -0
  8. package/dist/assets/grammars/notices/@vscode__tree-sitter-wasm/cgmanifest.json +16 -0
  9. package/dist/assets/grammars/notices/tree-sitter-wasms/LICENSE +24 -0
  10. package/dist/assets/grammars/tree-sitter-c-sharp.wasm +0 -0
  11. package/dist/assets/grammars/tree-sitter-c.wasm +0 -0
  12. package/dist/assets/grammars/tree-sitter-cpp.wasm +0 -0
  13. package/dist/assets/grammars/tree-sitter-go.wasm +0 -0
  14. package/dist/assets/grammars/tree-sitter-java.wasm +0 -0
  15. package/dist/assets/grammars/tree-sitter-javascript.wasm +0 -0
  16. package/dist/assets/grammars/tree-sitter-python.wasm +0 -0
  17. package/dist/assets/grammars/tree-sitter-ruby.wasm +0 -0
  18. package/dist/assets/grammars/tree-sitter-rust.wasm +0 -0
  19. package/dist/assets/grammars/tree-sitter-tsx.wasm +0 -0
  20. package/dist/assets/grammars/tree-sitter-typescript.wasm +0 -0
  21. package/dist/assets/grammars/tree-sitter.wasm +0 -0
  22. package/dist/{auth-O6HYIJ6J.js → auth-5TWEIYDN.js} +30 -15
  23. package/dist/chunk-2EHAIA3X.js +481 -0
  24. package/dist/{chunk-ME6DNWIU.js → chunk-2IR2NMPA.js} +12 -4
  25. package/dist/chunk-2SFS6XQE.js +122 -0
  26. package/dist/{chunk-KKKPTZLM.js → chunk-2STGEDFV.js} +8 -1
  27. package/dist/chunk-2VTFPG5O.js +48 -0
  28. package/dist/chunk-3I7MS7N2.js +40 -0
  29. package/dist/chunk-3R73A4XB.js +69 -0
  30. package/dist/{chunk-JPOWPFCU.js → chunk-3ZXDFGR5.js} +52 -23
  31. package/dist/chunk-4BJ5BYCE.js +61 -0
  32. package/dist/{chunk-26BZQOAD.js → chunk-4BPJXDWC.js} +161 -260
  33. package/dist/chunk-4KLWL3UC.js +18 -0
  34. package/dist/{chunk-5LDRNKX2.js → chunk-4VP4KH3K.js} +161 -262
  35. package/dist/chunk-4ZG3XFUR.js +77 -0
  36. package/dist/chunk-5B2AEOW5.js +5407 -0
  37. package/dist/chunk-5TSRNF4G.js +510 -0
  38. package/dist/{chunk-WD6AJM35.js → chunk-5UUP6MWO.js} +48 -69
  39. package/dist/{chunk-X3BR7HWV.js → chunk-5WIGXA4T.js} +7 -1
  40. package/dist/chunk-65DEGPJ6.js +52 -0
  41. package/dist/chunk-6EJMN2Y3.js +17 -0
  42. package/dist/chunk-6EJV5X2W.js +16405 -0
  43. package/dist/chunk-6N5PTWMY.js +136 -0
  44. package/dist/chunk-6XLNIQDB.js +27 -0
  45. package/dist/{chunk-XNISANGE.js → chunk-77VKQEHF.js} +171 -74
  46. package/dist/chunk-7CR24IG7.js +242 -0
  47. package/dist/{chunk-UWIJNAOB.js → chunk-7EYHLWU7.js} +907 -638
  48. package/dist/chunk-7MNJORFF.js +22 -0
  49. package/dist/{chunk-JWHCJDCI.js → chunk-A3CYT5EX.js} +257 -79
  50. package/dist/chunk-AGYYIBLL.js +1069 -0
  51. package/dist/chunk-AO4RKG4M.js +277 -0
  52. package/dist/chunk-APJ265NV.js +7410 -0
  53. package/dist/chunk-ARBGF5F7.js +174 -0
  54. package/dist/{chunk-TFSSEXL6.js → chunk-BMEMKKIT.js} +14 -4
  55. package/dist/{chunk-X3NE4WVW.js → chunk-BNAZZHFG.js} +7 -1
  56. package/dist/chunk-CBCAPZAA.js +229 -0
  57. package/dist/{chunk-QV47YRF4.js → chunk-CGKSTWHD.js} +7 -1
  58. package/dist/chunk-CMZWFGD2.js +352 -0
  59. package/dist/chunk-ECH6PKUQ.js +39 -0
  60. package/dist/{chunk-67MTHP2E.js → chunk-ED4KHGC3.js} +13 -5
  61. package/dist/chunk-EKMEHE4H.js +340 -0
  62. package/dist/{chunk-O4EJEDHO.js → chunk-EPVUXGXG.js} +50 -35
  63. package/dist/chunk-FCSXB6T2.js +338 -0
  64. package/dist/chunk-FJ3H4MN5.js +48 -0
  65. package/dist/chunk-FQ4SKYE4.js +29 -0
  66. package/dist/chunk-G2DE3C7R.js +644 -0
  67. package/dist/chunk-G4BMMOKF.js +182 -0
  68. package/dist/{chunk-7BHLZB3A.js → chunk-GGXXDWE4.js} +190 -1218
  69. package/dist/chunk-HC4CLZ2Y.js +68 -0
  70. package/dist/{chunk-E3NYWENM.js → chunk-HFSBBKSQ.js} +55 -61
  71. package/dist/chunk-HKIYEGME.js +30 -0
  72. package/dist/chunk-I4HZDVNP.js +73 -0
  73. package/dist/chunk-IGLFWIYI.js +161 -0
  74. package/dist/chunk-IHXBNWMM.js +137 -0
  75. package/dist/chunk-IKCO5N3L.js +162 -0
  76. package/dist/chunk-IR4CFBFN.js +56 -0
  77. package/dist/{chunk-DXQNI4PC.js → chunk-IWHMRKLL.js} +8 -1
  78. package/dist/{chunk-VOO7NYPP.js → chunk-J5HN4RYU.js} +27 -9
  79. package/dist/{chunk-4UQA7NCT.js → chunk-J5Q24KAG.js} +7 -2
  80. package/dist/{chunk-KBR4MZZR.js → chunk-JVCV3ICN.js} +7 -1
  81. package/dist/chunk-KJ5LWLOE.js +1077 -0
  82. package/dist/chunk-LBMZMYH2.js +285 -0
  83. package/dist/{chunk-3DANZDGR.js → chunk-LBNRH5WM.js} +100 -161
  84. package/dist/{chunk-TKHQ4DGZ.js → chunk-LZSJBIVT.js} +7358 -7414
  85. package/dist/{chunk-UGYAX5YI.js → chunk-M6SHUN7Q.js} +13 -8
  86. package/dist/chunk-MAW544W2.js +1882 -0
  87. package/dist/chunk-MBS4V7ZP.js +217 -0
  88. package/dist/{chunk-2J63S4SF.js → chunk-MFFY33HR.js} +167 -140
  89. package/dist/chunk-MNA4JGU4.js +255 -0
  90. package/dist/chunk-MQSRRFWA.js +3428 -0
  91. package/dist/{chunk-RQDWMVRB.js → chunk-MVVUPGPW.js} +138 -137
  92. package/dist/chunk-OAO4GE4M.js +619 -0
  93. package/dist/chunk-OHHN2SO4.js +5135 -0
  94. package/dist/chunk-OKGUZO2U.js +34 -0
  95. package/dist/{chunk-BBUH4VAA.js → chunk-OOJYHWRB.js} +60 -361
  96. package/dist/{chunk-D5YD55AR.js → chunk-OQ33BKR3.js} +12 -1
  97. package/dist/chunk-OQE5J4C6.js +73 -0
  98. package/dist/{chunk-AMFR5YA3.js → chunk-ORBHGJC5.js} +26 -12
  99. package/dist/chunk-POHLU5DW.js +1186 -0
  100. package/dist/chunk-QKMUKYO7.js +4961 -0
  101. package/dist/{chunk-7RBKDI66.js → chunk-QTYWRVRA.js} +104 -12
  102. package/dist/{chunk-5N2FG33Q.js → chunk-R346GLFC.js} +7 -1
  103. package/dist/chunk-SRF2PJNW.js +184 -0
  104. package/dist/chunk-SST6Z5JA.js +80 -0
  105. package/dist/{chunk-XV4ZJ6ZM.js → chunk-STBPMHSX.js} +473 -1194
  106. package/dist/{chunk-HBU5MTAM.js → chunk-SVNXH4L2.js} +7 -1
  107. package/dist/chunk-T6YILFSB.js +80 -0
  108. package/dist/chunk-TXOTCRLG.js +15 -0
  109. package/dist/chunk-TZTZS7QK.js +227 -0
  110. package/dist/chunk-UOV2BYIW.js +107 -0
  111. package/dist/{chunk-527KG6XR.js → chunk-V4RXGQ5Q.js} +72 -185
  112. package/dist/chunk-VAKQQHWR.js +434 -0
  113. package/dist/chunk-VG7TBQIY.js +128 -0
  114. package/dist/chunk-VJWL6YS5.js +244 -0
  115. package/dist/chunk-WEH5XRJQ.js +32 -0
  116. package/dist/{chunk-VPAWTYLY.js → chunk-WEPFGWHJ.js} +7 -1
  117. package/dist/chunk-WMSVI4G2.js +2095 -0
  118. package/dist/chunk-WVO7V2QY.js +797 -0
  119. package/dist/chunk-X4RCMKVQ.js +641 -0
  120. package/dist/chunk-X75S7HFS.js +374 -0
  121. package/dist/chunk-XN3L4EYL.js +46 -0
  122. package/dist/{chunk-HMYNFFY4.js → chunk-XPLRXC72.js} +7 -2
  123. package/dist/{chunk-PIDUD6M2.js → chunk-YCWGATWI.js} +12 -5
  124. package/dist/chunk-YHZX5GEU.js +193 -0
  125. package/dist/chunk-YXLYO42X.js +91 -0
  126. package/dist/{chunk-UHTSULZS.js → chunk-ZDOOVTXZ.js} +38 -73
  127. package/dist/chunk-ZI647VB5.js +37 -0
  128. package/dist/{chunk-CLJ5HLUD.js → chunk-ZWLZP4ZT.js} +25 -6
  129. package/dist/cli/index.js +70 -56
  130. package/dist/clio-4LY5K2AC.js +25 -0
  131. package/dist/code-nav-7AX6FYE6.js +600 -0
  132. package/dist/codewiki/build-worker.js +66 -0
  133. package/dist/compile-cache-CVJMMODC.js +18 -0
  134. package/dist/{components-JVHMUBEB.js → components-KELWS457.js} +31 -9
  135. package/dist/{config-ZFCDBMDC.js → config-GTLUW2PR.js} +104 -56
  136. package/dist/configure-R6A64DHX.js +42 -0
  137. package/dist/context-5VKGUVJJ.js +866 -0
  138. package/dist/{context-CDXTP2MP.js → context-JFZEJ7W5.js} +21 -13
  139. package/dist/{context-E3KIFVXI.js → context-RW5HC47S.js} +77 -36
  140. package/dist/{context-clear-3F4PLXOS.js → context-clear-6ZHBAZZT.js} +64 -30
  141. package/dist/{context-index-Q7YSYTR3.js → context-index-BZ4UYMTC.js} +36 -24
  142. package/dist/dispatch-runner-VKBRCWQC.js +1997 -0
  143. package/dist/{docs-YIETIWZI.js → docs-2C2LTVT2.js} +32 -13
  144. package/dist/doctor-KI767GSN.js +87 -0
  145. package/dist/{eval-B3KZZESM.js → eval-XSSNATB4.js} +93 -27
  146. package/dist/{evidence-V67CHM35.js → evidence-UA6AWDQQ.js} +55 -27
  147. package/dist/{evolve-YDZSUQYA.js → evolve-QNTFGV6Z.js} +59 -26
  148. package/dist/{extensions-SRG7XCAH.js → extensions-QVDOHDGJ.js} +23 -8
  149. package/dist/{fleet-CA2CRTVG.js → fleet-Q7UOMUSG.js} +173 -56
  150. package/dist/fleet-preflight-DDN536IT.js +26 -0
  151. package/dist/{init-2OZDJE2D.js → init-WBB65ZHQ.js} +79 -34
  152. package/dist/{memory-3PIQQAKX.js → memory-MD3O64RI.js} +57 -28
  153. package/dist/{models-DY35XI7Y.js → models-BZU34YWD.js} +49 -24
  154. package/dist/monitor-MEQA5C3I.js +661 -0
  155. package/dist/{chunk-PS4PFJQP.js → orchestrator-CGFKEP27.js} +22837 -18564
  156. package/dist/{paths-5OMXW7Z4.js → paths-UXLN5YYZ.js} +17 -6
  157. package/dist/preload-P6DGH2PZ.js +13 -0
  158. package/dist/{reset-PIFYNOS3.js → reset-L2FQEE3E.js} +25 -13
  159. package/dist/{run-3VSPP24F.js → run-IV4Q6RLN.js} +115 -63
  160. package/dist/{share-D36RQCXM.js → share-S5BZQC5I.js} +23 -10
  161. package/dist/{skills-F2MRLELY.js → skills-LQEKRDTN.js} +42 -15
  162. package/dist/{skills-eval-E2ZTW4PL.js → skills-eval-3DC4HEWS.js} +90 -45
  163. package/dist/steer-GGWFUJUD.js +77 -0
  164. package/dist/{targets-DZMEZAH4.js → targets-C4SSGQOB.js} +78 -60
  165. package/dist/terminal-lease-IT5JW2NR.js +395 -0
  166. package/dist/{trace-7NYCUI2J.js → trace-PNCASAXC.js} +48 -17
  167. package/dist/tree-sitter-HGKH6LG4.js +4673 -0
  168. package/dist/{uninstall-AD3JWHBB.js → uninstall-FZCQCDKC.js} +19 -8
  169. package/dist/{upgrade-WYYBKGDY.js → upgrade-7TT7SQ3G.js} +66 -24
  170. package/dist/{usage-ULIDAGFF.js → usage-GV4PKT3M.js} +71 -32
  171. package/dist/verify-G6V4D2G7.js +716 -0
  172. package/dist/version-KGEG7EPO.js +21 -0
  173. package/dist/web-fetch-2YHJ3KTG.js +638 -0
  174. package/dist/{wiki-generate-PKFIX6OB.js → wiki-generate-DQF6Z66B.js} +98 -48
  175. package/dist/worker/entry.js +297 -54
  176. package/dist/workspace-G4ZWUIPR.js +22 -0
  177. package/docs/README.md +29 -21
  178. package/docs/acp.md +191 -16
  179. package/docs/alcf-provider.md +1 -1
  180. package/docs/architecture.md +157 -7
  181. package/docs/artifact-placement.md +101 -0
  182. package/docs/artifact-versions.md +1 -1
  183. package/docs/built-in-agents.md +4 -2
  184. package/docs/capacity-and-scheduling.md +1 -1
  185. package/docs/commands-and-modes.md +224 -97
  186. package/docs/config-knobs-audit.md +1 -3
  187. package/docs/configuration-and-targets.md +236 -38
  188. package/docs/context-engine.md +34 -7
  189. package/docs/development-pipeline.md +102 -0
  190. package/docs/dispatch-architecture-rationale.md +1 -1
  191. package/docs/documentation-coverage.md +4 -4
  192. package/docs/documentation-guide.md +3 -3
  193. package/docs/environment-variables.md +15 -6
  194. package/docs/eval-runner.md +3 -3
  195. package/docs/evals-internal.md +2 -2
  196. package/docs/evidence-and-memory.md +10 -2
  197. package/docs/evolution.md +2 -2
  198. package/docs/exit-codes-and-output.md +15 -9
  199. package/docs/extensions-and-sharing.md +25 -18
  200. package/docs/fleet-demo-runbook.md +22 -23
  201. package/docs/fleet-dispatch.md +117 -16
  202. package/docs/git-commit-provenance.md +120 -0
  203. package/docs/glossary.md +107 -15
  204. package/docs/installation-and-lifecycle.md +75 -17
  205. package/docs/middleware-and-components.md +1 -1
  206. package/docs/model-catalog.md +46 -15
  207. package/docs/observability.md +8 -5
  208. package/docs/performance-methodology.md +491 -0
  209. package/docs/pi-boundary.md +72 -0
  210. package/docs/proactive-memory.md +14 -14
  211. package/docs/prompt-envelope-and-tools.md +25 -4
  212. package/docs/provider-adapter-cookbook.md +57 -4
  213. package/docs/release-cut-checklist.md +129 -111
  214. package/docs/safety-model.md +28 -8
  215. package/docs/scientific-validation.md +3 -3
  216. package/docs/session-lifecycle.md +55 -12
  217. package/docs/skills-marketplace.md +12 -8
  218. package/docs/time-conventions.md +101 -0
  219. package/docs/tool-usage.md +6 -5
  220. package/docs/trace-store.md +1 -1
  221. package/docs/troubleshooting.md +10 -7
  222. package/docs/tui-design.md +121 -28
  223. package/docs/worker-dispatch-mechanics.md +3 -3
  224. package/package.json +33 -36
  225. package/skills/README.md +5 -6
  226. package/skills/coding/ast-grep/SKILL.md +136 -0
  227. package/skills/coding/ast-grep/evals.md +56 -0
  228. package/skills/coding/ast-grep/references/rule_reference.md +297 -0
  229. package/skills/coding/coding-standards/SKILL.md +113 -0
  230. package/skills/coding/coding-standards/evals.md +34 -0
  231. package/skills/coding/prototype/SKILL.md +86 -0
  232. package/skills/coding/prototype/evals.md +42 -0
  233. package/skills/coding/prototype/references/LOGIC.md +67 -0
  234. package/skills/coding/prototype/references/UI.md +112 -0
  235. package/skills/coding/tdd/SKILL.md +101 -0
  236. package/skills/coding/tdd/evals.md +41 -0
  237. package/skills/coding/tdd/references/mocking.md +59 -0
  238. package/skills/coding/tdd/references/tests.md +77 -0
  239. package/skills/context/context-handoff/SKILL.md +126 -0
  240. package/skills/context/context-handoff/evals.md +57 -0
  241. package/skills/context/context-handoff/scripts/new-handoff.sh +26 -0
  242. package/skills/context/context-prime/SKILL.md +95 -0
  243. package/skills/context/context-prime/evals.md +54 -0
  244. package/skills/git/file-ticket/SKILL.md +107 -0
  245. package/skills/git/file-ticket/evals.md +54 -0
  246. package/skills/git/fix-issue/SKILL.md +106 -0
  247. package/skills/git/fix-issue/evals.md +71 -0
  248. package/skills/git/ship/SKILL.md +92 -0
  249. package/skills/git/ship/evals.md +72 -0
  250. package/skills/meta/clio-dev/SKILL.md +91 -0
  251. package/skills/meta/clio-dev/evals.md +45 -0
  252. package/skills/meta/clio-test/SKILL.md +130 -0
  253. package/skills/meta/clio-test/evals.md +43 -0
  254. package/skills/meta/clio-test/references/harness.md +97 -0
  255. package/skills/meta/clio-test/references/test-map.md +59 -0
  256. package/skills/meta/credentials/SKILL.md +125 -0
  257. package/skills/meta/credentials/evals.md +104 -0
  258. package/skills/meta/find-skills/SKILL.md +72 -0
  259. package/skills/meta/find-skills/evals.md +47 -0
  260. package/skills/meta/herdr/SKILL.md +127 -0
  261. package/skills/meta/herdr/evals.md +38 -0
  262. package/skills/meta/skill-craft/SKILL.md +102 -0
  263. package/skills/meta/skill-craft/evals.md +41 -0
  264. package/skills/planning/architecture/SKILL.md +129 -0
  265. package/skills/planning/architecture/evals.md +36 -0
  266. package/skills/planning/backlog/SKILL.md +90 -0
  267. package/skills/planning/backlog/evals.md +43 -0
  268. package/skills/planning/prd/SKILL.md +82 -0
  269. package/skills/planning/prd/evals.md +49 -0
  270. package/skills/planning/product-intent/SKILL.md +112 -0
  271. package/skills/planning/product-intent/evals.md +36 -0
  272. package/skills/planning/tech-spec/SKILL.md +115 -0
  273. package/skills/planning/tech-spec/evals.md +47 -0
  274. package/skills/registry.yaml +136 -0
  275. package/skills/research/arxiv-literature/SKILL.md +104 -0
  276. package/skills/research/arxiv-literature/evals.md +58 -0
  277. package/skills/research/experiment-protocol/SKILL.md +122 -0
  278. package/skills/research/experiment-protocol/evals.md +91 -0
  279. package/skills/research/scientific-debugging/SKILL.md +119 -0
  280. package/skills/research/scientific-debugging/evals.md +138 -0
  281. package/skills/research/scientific-modernization/SKILL.md +138 -0
  282. package/skills/research/scientific-modernization/evals.md +84 -0
  283. package/skills/skill-marketplace.json +12 -20
  284. package/skills/workflow/design-council/SKILL.md +139 -0
  285. package/skills/workflow/design-council/evals.md +97 -0
  286. package/skills/workflow/grill-me/SKILL.md +186 -0
  287. package/skills/workflow/grill-me/evals.md +78 -0
  288. package/skills/workflow/workflow-distiller/SKILL.md +136 -0
  289. package/skills/workflow/workflow-distiller/evals.md +107 -0
  290. package/src/cli/acp.ts +115 -0
  291. package/src/cli/agents.ts +60 -0
  292. package/src/cli/args.ts +280 -0
  293. package/src/cli/argv.ts +170 -0
  294. package/src/cli/ask.ts +34 -0
  295. package/src/cli/auth.ts +468 -0
  296. package/src/cli/bootstrap-generate.ts +498 -0
  297. package/src/cli/clio.ts +96 -0
  298. package/src/cli/components.ts +195 -0
  299. package/src/cli/config-inspect.ts +336 -0
  300. package/src/cli/config.ts +72 -0
  301. package/src/cli/configure-interop.ts +67 -0
  302. package/src/cli/configure-layout.ts +172 -0
  303. package/src/cli/configure.ts +1525 -0
  304. package/src/cli/context-clear.ts +76 -0
  305. package/src/cli/context-index.ts +100 -0
  306. package/src/cli/context.ts +321 -0
  307. package/src/cli/default-target.ts +55 -0
  308. package/src/cli/docs.ts +346 -0
  309. package/src/cli/doctor.ts +54 -0
  310. package/src/cli/eval.ts +315 -0
  311. package/src/cli/evidence.ts +225 -0
  312. package/src/cli/evolve.ts +219 -0
  313. package/src/cli/extensions.ts +214 -0
  314. package/src/cli/fleet.ts +868 -0
  315. package/src/cli/index.ts +338 -0
  316. package/src/cli/init.ts +219 -0
  317. package/src/cli/initial-message.ts +47 -0
  318. package/src/cli/internal-dispatch.ts +55 -0
  319. package/src/cli/memory.ts +182 -0
  320. package/src/cli/models.ts +257 -0
  321. package/src/cli/modes/json-stream.ts +121 -0
  322. package/src/cli/modes/jsonl.ts +9 -0
  323. package/src/cli/modes/print.ts +604 -0
  324. package/src/cli/oauth-manual-input.ts +72 -0
  325. package/src/cli/oauth-select.ts +36 -0
  326. package/src/cli/output-guard.ts +48 -0
  327. package/src/cli/paths.ts +44 -0
  328. package/src/cli/provider-target.ts +113 -0
  329. package/src/cli/removal.ts +72 -0
  330. package/src/cli/reset.ts +253 -0
  331. package/src/cli/run.ts +497 -0
  332. package/src/cli/share.ts +243 -0
  333. package/src/cli/shared.ts +60 -0
  334. package/src/cli/skills-eval.ts +1240 -0
  335. package/src/cli/skills.ts +485 -0
  336. package/src/cli/steer-channel.ts +86 -0
  337. package/src/cli/targets.ts +1154 -0
  338. package/src/cli/text-layout.ts +112 -0
  339. package/src/cli/trace.ts +322 -0
  340. package/src/cli/uninstall.ts +405 -0
  341. package/src/cli/upgrade.ts +286 -0
  342. package/src/cli/usage.ts +876 -0
  343. package/src/cli/validate-model.ts +28 -0
  344. package/src/cli/version.ts +7 -0
  345. package/src/cli/wiki-generate.ts +510 -0
  346. package/src/core/agent-environment.ts +7 -0
  347. package/src/core/artifact-paths.ts +43 -0
  348. package/src/core/bash-exec.ts +313 -0
  349. package/src/core/boot-trace.ts +42 -0
  350. package/src/core/bus-events.ts +744 -0
  351. package/src/core/bus-trace.ts +53 -0
  352. package/src/core/c-header-language.ts +265 -0
  353. package/src/core/clio-repo.ts +78 -0
  354. package/src/core/commit-attribution.ts +157 -0
  355. package/src/core/compile-cache.ts +159 -0
  356. package/src/core/config.ts +1722 -0
  357. package/src/core/context-floor.ts +33 -0
  358. package/src/core/defaults.ts +659 -0
  359. package/src/core/domain-loader.ts +177 -0
  360. package/src/core/event-bus.ts +94 -0
  361. package/src/core/file-references.ts +282 -0
  362. package/src/core/git-commit-attribution.ts +362 -0
  363. package/src/core/guardrails.ts +185 -0
  364. package/src/core/headless-permission.ts +21 -0
  365. package/src/core/incomplete-installation.ts +45 -0
  366. package/src/core/init.ts +223 -0
  367. package/src/core/json-payload.ts +58 -0
  368. package/src/core/package-root.ts +54 -0
  369. package/src/core/path-canonical.ts +37 -0
  370. package/src/core/process-identity.ts +41 -0
  371. package/src/core/recent-models.ts +91 -0
  372. package/src/core/residency-protection.ts +56 -0
  373. package/src/core/resolve-config-value.ts +88 -0
  374. package/src/core/response-schema.ts +279 -0
  375. package/src/core/run-overrides.ts +77 -0
  376. package/src/core/safe-exec.ts +205 -0
  377. package/src/core/safe-id.ts +37 -0
  378. package/src/core/safe-resource-write.ts +162 -0
  379. package/src/core/session-routing.ts +339 -0
  380. package/src/core/settings-layers.ts +354 -0
  381. package/src/core/shared-bus.ts +8 -0
  382. package/src/core/shell-quote.ts +26 -0
  383. package/src/core/skill-activation.ts +190 -0
  384. package/src/core/startup-timer.ts +37 -0
  385. package/src/core/state-file-lock.ts +219 -0
  386. package/src/core/termination.ts +275 -0
  387. package/src/core/timers.ts +38 -0
  388. package/src/core/tool-names.ts +65 -0
  389. package/src/core/verification-scripts.ts +13 -0
  390. package/src/core/workspace-files.ts +492 -0
  391. package/src/core/xdg.ts +177 -0
  392. package/src/domains/agents/builtins/architect.md +4 -4
  393. package/src/domains/agents/builtins/coder.md +3 -2
  394. package/src/domains/agents/builtins/debugger.md +1 -1
  395. package/src/domains/agents/builtins/documenter.md +1 -1
  396. package/src/domains/agents/builtins/git-master.md +3 -3
  397. package/src/domains/agents/builtins/provenance.md +1 -1
  398. package/src/domains/agents/builtins/researcher.md +1 -1
  399. package/src/domains/agents/builtins/scout.md +1 -1
  400. package/src/domains/agents/builtins/tester.md +1 -1
  401. package/src/domains/agents/builtins/verifier.md +1 -1
  402. package/src/domains/agents/builtins/wiki-writer.md +1 -1
  403. package/src/domains/agents/catalog.ts +172 -0
  404. package/src/domains/agents/contract.ts +16 -0
  405. package/src/domains/agents/extension.ts +110 -0
  406. package/src/domains/agents/fleet-commands.ts +154 -0
  407. package/src/domains/agents/fleet-contract.ts +797 -0
  408. package/src/domains/agents/frontmatter.ts +40 -0
  409. package/src/domains/agents/index.ts +102 -0
  410. package/src/domains/agents/manifest.ts +6 -0
  411. package/src/domains/agents/recipe-schema.ts +202 -0
  412. package/src/domains/agents/recipe.ts +125 -0
  413. package/src/domains/agents/registry.ts +111 -0
  414. package/src/domains/agents/result-contract.ts +1265 -0
  415. package/src/domains/agents/spec.ts +371 -0
  416. package/src/domains/agents/write-boundary.ts +109 -0
  417. package/src/domains/components/diff.ts +99 -0
  418. package/src/domains/components/hash.ts +21 -0
  419. package/src/domains/components/index.ts +3 -0
  420. package/src/domains/components/scan.ts +304 -0
  421. package/src/domains/components/snapshot.ts +108 -0
  422. package/src/domains/components/types.ts +82 -0
  423. package/src/domains/config/agent-namespace.ts +13 -0
  424. package/src/domains/config/classify.ts +106 -0
  425. package/src/domains/config/contract.ts +22 -0
  426. package/src/domains/config/extension.ts +142 -0
  427. package/src/domains/config/index.ts +23 -0
  428. package/src/domains/config/keybindings.ts +200 -0
  429. package/src/domains/config/manifest.ts +6 -0
  430. package/src/domains/config/watcher.ts +41 -0
  431. package/src/domains/context/adoption.ts +880 -0
  432. package/src/domains/context/bootstrap-prompt.ts +273 -0
  433. package/src/domains/context/bootstrap.ts +1502 -0
  434. package/src/domains/context/clear.ts +91 -0
  435. package/src/domains/context/clio-md.ts +429 -0
  436. package/src/domains/context/codewiki/artifact.ts +400 -0
  437. package/src/domains/context/codewiki/build-worker-protocol.ts +24 -0
  438. package/src/domains/context/codewiki/build-worker.ts +54 -0
  439. package/src/domains/context/codewiki/cmake.ts +356 -0
  440. package/src/domains/context/codewiki/cooperative.ts +46 -0
  441. package/src/domains/context/codewiki/coordinator.ts +182 -0
  442. package/src/domains/context/codewiki/digest.ts +135 -0
  443. package/src/domains/context/codewiki/grammar-assets.ts +33 -0
  444. package/src/domains/context/codewiki/indexer.ts +1529 -0
  445. package/src/domains/context/codewiki/paths.ts +67 -0
  446. package/src/domains/context/codewiki/schema.ts +80 -0
  447. package/src/domains/context/codewiki/tree-sitter.ts +771 -0
  448. package/src/domains/context/contract.ts +68 -0
  449. package/src/domains/context/excluded-dirs.ts +1 -0
  450. package/src/domains/context/extension.ts +358 -0
  451. package/src/domains/context/fingerprint.ts +198 -0
  452. package/src/domains/context/index.ts +154 -0
  453. package/src/domains/context/init-options.ts +69 -0
  454. package/src/domains/context/manifest.ts +6 -0
  455. package/src/domains/context/operator-profile.ts +157 -0
  456. package/src/domains/context/project-metadata.ts +529 -0
  457. package/src/domains/context/project-rules.ts +227 -0
  458. package/src/domains/context/prompt-context.ts +61 -0
  459. package/src/domains/context/refresh.ts +178 -0
  460. package/src/domains/context/runtime.ts +17 -0
  461. package/src/domains/context/sibling-files.ts +10 -0
  462. package/src/domains/context/state.ts +237 -0
  463. package/src/domains/context/wiki/assemble.ts +303 -0
  464. package/src/domains/context/wiki/frontmatter.ts +210 -0
  465. package/src/domains/context/wiki/generate.ts +595 -0
  466. package/src/domains/context/wiki/layout.ts +111 -0
  467. package/src/domains/context/wiki/meta.ts +221 -0
  468. package/src/domains/context/wiki/plan-store.ts +217 -0
  469. package/src/domains/context/wiki/plan.ts +250 -0
  470. package/src/domains/context/wiki/prompts.ts +283 -0
  471. package/src/domains/context/wiki/staleness.ts +198 -0
  472. package/src/domains/dispatch/active-route-planner.ts +168 -0
  473. package/src/domains/dispatch/admission-queue.ts +150 -0
  474. package/src/domains/dispatch/admission.ts +334 -0
  475. package/src/domains/dispatch/agent-candidates.ts +307 -0
  476. package/src/domains/dispatch/agent-ledger-hub.ts +71 -0
  477. package/src/domains/dispatch/agent-ledger-store.ts +257 -0
  478. package/src/domains/dispatch/agent-ledger.ts +212 -0
  479. package/src/domains/dispatch/agent-plan-adapter.ts +85 -0
  480. package/src/domains/dispatch/assignment-events.ts +132 -0
  481. package/src/domains/dispatch/assignment-reconcile.ts +76 -0
  482. package/src/domains/dispatch/assignment-store.ts +162 -0
  483. package/src/domains/dispatch/assignment.ts +278 -0
  484. package/src/domains/dispatch/backoff.ts +59 -0
  485. package/src/domains/dispatch/batch-store.ts +134 -0
  486. package/src/domains/dispatch/batch-tracker.ts +66 -0
  487. package/src/domains/dispatch/capability-match.ts +155 -0
  488. package/src/domains/dispatch/capacity-lease.ts +413 -0
  489. package/src/domains/dispatch/code-step-store.ts +52 -0
  490. package/src/domains/dispatch/code-step.ts +387 -0
  491. package/src/domains/dispatch/contract.ts +278 -0
  492. package/src/domains/dispatch/dedup.ts +133 -0
  493. package/src/domains/dispatch/event-pump.ts +251 -0
  494. package/src/domains/dispatch/execution-handoff.ts +29 -0
  495. package/src/domains/dispatch/execution-plan.ts +328 -0
  496. package/src/domains/dispatch/execution-role.ts +277 -0
  497. package/src/domains/dispatch/execution-scheduler.ts +583 -0
  498. package/src/domains/dispatch/extension.ts +6006 -0
  499. package/src/domains/dispatch/failure-classification.ts +147 -0
  500. package/src/domains/dispatch/fleet-commit-attribution.ts +56 -0
  501. package/src/domains/dispatch/fleet-plan.ts +225 -0
  502. package/src/domains/dispatch/fleet-preflight.ts +394 -0
  503. package/src/domains/dispatch/gate-decisions.ts +1040 -0
  504. package/src/domains/dispatch/gate-role-prompts.ts +58 -0
  505. package/src/domains/dispatch/heartbeat.ts +27 -0
  506. package/src/domains/dispatch/index.ts +137 -0
  507. package/src/domains/dispatch/joint-route-adapter.ts +114 -0
  508. package/src/domains/dispatch/joint-route-resolver.ts +283 -0
  509. package/src/domains/dispatch/manifest.ts +6 -0
  510. package/src/domains/dispatch/orphan-recovery.ts +266 -0
  511. package/src/domains/dispatch/outcome.ts +109 -0
  512. package/src/domains/dispatch/phase-timing.ts +47 -0
  513. package/src/domains/dispatch/placement.ts +202 -0
  514. package/src/domains/dispatch/receipt-findings.ts +255 -0
  515. package/src/domains/dispatch/receipt-integrity.ts +383 -0
  516. package/src/domains/dispatch/recovery-candidates.ts +74 -0
  517. package/src/domains/dispatch/reproducibility.ts +48 -0
  518. package/src/domains/dispatch/reservation-store.ts +501 -0
  519. package/src/domains/dispatch/route-approval.ts +177 -0
  520. package/src/domains/dispatch/route-candidates.ts +57 -0
  521. package/src/domains/dispatch/route-decision.ts +1079 -0
  522. package/src/domains/dispatch/route-facts.ts +187 -0
  523. package/src/domains/dispatch/route-history.ts +238 -0
  524. package/src/domains/dispatch/route-observer.ts +488 -0
  525. package/src/domains/dispatch/route-policy.ts +327 -0
  526. package/src/domains/dispatch/route-quality.ts +256 -0
  527. package/src/domains/dispatch/route-readiness.ts +120 -0
  528. package/src/domains/dispatch/routing-intent.ts +287 -0
  529. package/src/domains/dispatch/run-identity.ts +56 -0
  530. package/src/domains/dispatch/scout-transition.ts +130 -0
  531. package/src/domains/dispatch/state.ts +302 -0
  532. package/src/domains/dispatch/tool-stats.ts +132 -0
  533. package/src/domains/dispatch/transport.ts +210 -0
  534. package/src/domains/dispatch/types.ts +799 -0
  535. package/src/domains/dispatch/validation-grounding.ts +154 -0
  536. package/src/domains/dispatch/validation.ts +721 -0
  537. package/src/domains/dispatch/worker-protocol.ts +275 -0
  538. package/src/domains/dispatch/worker-spawn.ts +585 -0
  539. package/src/domains/dispatch/write-boundary-enforcer.ts +97 -0
  540. package/src/domains/dispatch/write-boundary.ts +426 -0
  541. package/src/domains/eval/artifacts/redact.ts +42 -0
  542. package/src/domains/eval/artifacts/store.ts +173 -0
  543. package/src/domains/eval/compare/compare.ts +33 -0
  544. package/src/domains/eval/compare/gates.ts +66 -0
  545. package/src/domains/eval/compare/thresholds.ts +92 -0
  546. package/src/domains/eval/harness-metrics.ts +62 -0
  547. package/src/domains/eval/index.ts +66 -0
  548. package/src/domains/eval/metrics/chaos-stream.ts +93 -0
  549. package/src/domains/eval/metrics/context.ts +34 -0
  550. package/src/domains/eval/metrics/coverage.ts +21 -0
  551. package/src/domains/eval/metrics/evidence.ts +182 -0
  552. package/src/domains/eval/metrics/fleet-loop-stream.ts +196 -0
  553. package/src/domains/eval/metrics/invariants.ts +736 -0
  554. package/src/domains/eval/metrics/latency.ts +4 -0
  555. package/src/domains/eval/metrics/token-stream.ts +139 -0
  556. package/src/domains/eval/metrics/tokens.ts +51 -0
  557. package/src/domains/eval/metrics/tool-calls.ts +7 -0
  558. package/src/domains/eval/proactive-memory.ts +279 -0
  559. package/src/domains/eval/provenance.ts +35 -0
  560. package/src/domains/eval/report.ts +234 -0
  561. package/src/domains/eval/reports/json.ts +5 -0
  562. package/src/domains/eval/reports/junit.ts +23 -0
  563. package/src/domains/eval/reports/markdown.ts +20 -0
  564. package/src/domains/eval/reports/swe-jsonl.ts +16 -0
  565. package/src/domains/eval/reports/text.ts +25 -0
  566. package/src/domains/eval/run-compare.ts +274 -0
  567. package/src/domains/eval/runner.ts +244 -0
  568. package/src/domains/eval/runners/clio-run.ts +148 -0
  569. package/src/domains/eval/runners/context-index.ts +56 -0
  570. package/src/domains/eval/runners/context-init.ts +203 -0
  571. package/src/domains/eval/runners/external-command.ts +350 -0
  572. package/src/domains/eval/runtime-paths.ts +171 -0
  573. package/src/domains/eval/schema/artifact.ts +75 -0
  574. package/src/domains/eval/schema/suite.ts +235 -0
  575. package/src/domains/eval/schema/validate.ts +339 -0
  576. package/src/domains/eval/store.ts +392 -0
  577. package/src/domains/eval/suites/load.ts +74 -0
  578. package/src/domains/eval/suites/matrix.ts +19 -0
  579. package/src/domains/eval/suites/resolve.ts +44 -0
  580. package/src/domains/eval/suites/run.ts +325 -0
  581. package/src/domains/eval/task-file.ts +186 -0
  582. package/src/domains/eval/types.ts +140 -0
  583. package/src/domains/eval/verifiers/command.ts +27 -0
  584. package/src/domains/eval/verifiers/file-exists.ts +6 -0
  585. package/src/domains/eval/verifiers/patch.ts +22 -0
  586. package/src/domains/eval/workspaces/git.ts +41 -0
  587. package/src/domains/eval/workspaces/local.ts +17 -0
  588. package/src/domains/eval/workspaces/temp-copy.ts +29 -0
  589. package/src/domains/evidence/build.ts +1754 -0
  590. package/src/domains/evidence/eval.ts +605 -0
  591. package/src/domains/evidence/failure-attribution.ts +54 -0
  592. package/src/domains/evidence/finish-contract-map.ts +42 -0
  593. package/src/domains/evidence/index.ts +55 -0
  594. package/src/domains/evidence/provenance.ts +200 -0
  595. package/src/domains/evidence/redact.ts +81 -0
  596. package/src/domains/evidence/store.ts +291 -0
  597. package/src/domains/evidence/types.ts +325 -0
  598. package/src/domains/evolution/SELF_EDIT_GATE.md +91 -0
  599. package/src/domains/evolution/index.ts +26 -0
  600. package/src/domains/evolution/manifest.ts +154 -0
  601. package/src/domains/evolution/validate.ts +304 -0
  602. package/src/domains/extensions/contract.ts +22 -0
  603. package/src/domains/extensions/discovery.ts +193 -0
  604. package/src/domains/extensions/extension.ts +46 -0
  605. package/src/domains/extensions/index.ts +34 -0
  606. package/src/domains/extensions/manager.ts +30 -0
  607. package/src/domains/extensions/manifest.ts +6 -0
  608. package/src/domains/extensions/resources.ts +38 -0
  609. package/src/domains/extensions/state.ts +224 -0
  610. package/src/domains/extensions/types.ts +83 -0
  611. package/src/domains/interop/consent.ts +185 -0
  612. package/src/domains/interop/contract.ts +29 -0
  613. package/src/domains/interop/detect.ts +173 -0
  614. package/src/domains/interop/extension.ts +59 -0
  615. package/src/domains/interop/index.ts +34 -0
  616. package/src/domains/interop/manifest.ts +6 -0
  617. package/src/domains/interop/registry.ts +139 -0
  618. package/src/domains/interop/state.ts +92 -0
  619. package/src/domains/interop/types.ts +109 -0
  620. package/src/domains/lifecycle/contract.ts +11 -0
  621. package/src/domains/lifecycle/doctor.ts +536 -0
  622. package/src/domains/lifecycle/extension.ts +23 -0
  623. package/src/domains/lifecycle/index.ts +21 -0
  624. package/src/domains/lifecycle/install-method.ts +51 -0
  625. package/src/domains/lifecycle/manifest.ts +6 -0
  626. package/src/domains/lifecycle/migrations/2026-08-18-lmstudio-runtime-id.ts +52 -0
  627. package/src/domains/lifecycle/migrations/index.ts +114 -0
  628. package/src/domains/lifecycle/state.ts +93 -0
  629. package/src/domains/lifecycle/upgrade-notice.ts +35 -0
  630. package/src/domains/lifecycle/version.ts +35 -0
  631. package/src/domains/memory/index.ts +128 -0
  632. package/src/domains/memory/operations.ts +143 -0
  633. package/src/domains/memory/prompt-section.ts +86 -0
  634. package/src/domains/memory/proposal.ts +180 -0
  635. package/src/domains/memory/store.ts +163 -0
  636. package/src/domains/memory/task-bank.ts +229 -0
  637. package/src/domains/memory/task-memory-handoff.ts +222 -0
  638. package/src/domains/memory/task-memory-policy.ts +602 -0
  639. package/src/domains/memory/task-memory-status.ts +58 -0
  640. package/src/domains/memory/task-memory-telemetry.ts +346 -0
  641. package/src/domains/memory/task-memory-trace.ts +89 -0
  642. package/src/domains/memory/types.ts +74 -0
  643. package/src/domains/memory/validate.ts +297 -0
  644. package/src/domains/middleware/budget.ts +216 -0
  645. package/src/domains/middleware/contract.ts +35 -0
  646. package/src/domains/middleware/dispatch-nudge.ts +469 -0
  647. package/src/domains/middleware/extension.ts +129 -0
  648. package/src/domains/middleware/hook-receipts.ts +70 -0
  649. package/src/domains/middleware/hooks-io.ts +186 -0
  650. package/src/domains/middleware/hooks.ts +432 -0
  651. package/src/domains/middleware/index.ts +154 -0
  652. package/src/domains/middleware/manifest.ts +6 -0
  653. package/src/domains/middleware/memory-intervention.ts +701 -0
  654. package/src/domains/middleware/rules.ts +42 -0
  655. package/src/domains/middleware/runtime.ts +333 -0
  656. package/src/domains/middleware/skills-reminder.ts +202 -0
  657. package/src/domains/middleware/snapshot.ts +71 -0
  658. package/src/domains/middleware/stalled-turn.ts +71 -0
  659. package/src/domains/middleware/task-board-reminder.ts +87 -0
  660. package/src/domains/middleware/task-nudge.ts +77 -0
  661. package/src/domains/middleware/tool-choice-control.ts +42 -0
  662. package/src/domains/middleware/types.ts +131 -0
  663. package/src/domains/middleware/validate.ts +329 -0
  664. package/src/domains/observability/accountability.ts +67 -0
  665. package/src/domains/observability/contract.ts +168 -0
  666. package/src/domains/observability/cost.ts +206 -0
  667. package/src/domains/observability/evidence-index.ts +123 -0
  668. package/src/domains/observability/extension.ts +281 -0
  669. package/src/domains/observability/index.ts +78 -0
  670. package/src/domains/observability/manifest.ts +10 -0
  671. package/src/domains/observability/metrics.ts +37 -0
  672. package/src/domains/observability/projection.ts +477 -0
  673. package/src/domains/observability/telemetry.ts +89 -0
  674. package/src/domains/observability/trace-store.ts +1454 -0
  675. package/src/domains/prompts/compiler.ts +614 -0
  676. package/src/domains/prompts/contract.ts +46 -0
  677. package/src/domains/prompts/extension.ts +336 -0
  678. package/src/domains/prompts/fragment-loader.ts +138 -0
  679. package/src/domains/prompts/fragments/identity/clio.md +5 -6
  680. package/src/domains/prompts/fragments/identity/docs-routing.md +10 -0
  681. package/src/domains/prompts/fragments/identity/self-awareness.md +19 -0
  682. package/src/domains/prompts/fragments/operating/contract.md +4 -41
  683. package/src/domains/prompts/fragments/operating/delegation.md +42 -0
  684. package/src/domains/prompts/fragments/operating/skills.md +26 -0
  685. package/src/domains/prompts/fragments/operating/worker.md +16 -0
  686. package/src/domains/prompts/fragments/safety/auto-edit.md +5 -5
  687. package/src/domains/prompts/fragments/safety/full-auto.md +3 -3
  688. package/src/domains/prompts/fragments/safety/read-only.md +4 -4
  689. package/src/domains/prompts/fragments/safety/suggest.md +2 -2
  690. package/src/domains/prompts/fragments/wiki/page.md +10 -0
  691. package/src/domains/prompts/fragments/wiki/plan.md +10 -0
  692. package/src/domains/prompts/hash.ts +73 -0
  693. package/src/domains/prompts/index.ts +32 -0
  694. package/src/domains/prompts/manifest.ts +8 -0
  695. package/src/domains/prompts/memory-intervention.ts +57 -0
  696. package/src/domains/prompts/preload.ts +82 -0
  697. package/src/domains/providers/auth/api-key.ts +47 -0
  698. package/src/domains/providers/auth/backend-file.ts +79 -0
  699. package/src/domains/providers/auth/backend-memory.ts +72 -0
  700. package/src/domains/providers/auth/boot-status.ts +65 -0
  701. package/src/domains/providers/auth/index.ts +37 -0
  702. package/src/domains/providers/auth/oauth.ts +37 -0
  703. package/src/domains/providers/auth/storage.ts +726 -0
  704. package/src/domains/providers/capabilities.ts +58 -0
  705. package/src/domains/providers/catalog.ts +162 -0
  706. package/src/domains/providers/contract.ts +162 -0
  707. package/src/domains/providers/credentials.ts +20 -0
  708. package/src/domains/providers/eligibility.ts +24 -0
  709. package/src/domains/providers/errors.ts +64 -0
  710. package/src/domains/providers/extension.ts +548 -0
  711. package/src/domains/providers/index.ts +142 -0
  712. package/src/domains/providers/knowledge-base-path.ts +102 -0
  713. package/src/domains/providers/manifest.ts +6 -0
  714. package/src/domains/providers/model-capabilities.ts +136 -0
  715. package/src/domains/providers/model-discovery.ts +144 -0
  716. package/src/domains/providers/model-family.ts +32 -0
  717. package/src/domains/providers/model-runtime-capabilities.ts +723 -0
  718. package/src/domains/providers/models/local-models/clio-local-coding-targets.yaml +120 -37
  719. package/src/domains/providers/plugins.ts +61 -0
  720. package/src/domains/providers/probe/fingerprint.ts +64 -0
  721. package/src/domains/providers/probe/http.ts +114 -0
  722. package/src/domains/providers/probe/reasoning.ts +111 -0
  723. package/src/domains/providers/registry.ts +187 -0
  724. package/src/domains/providers/resolver.ts +156 -0
  725. package/src/domains/providers/runtime-resolution.ts +720 -0
  726. package/src/domains/providers/runtimes/antigravity/antigravity-code.ts +90 -0
  727. package/src/domains/providers/runtimes/boot-manifest.ts +55 -0
  728. package/src/domains/providers/runtimes/builtins.ts +78 -0
  729. package/src/domains/providers/runtimes/claude/claude-code.ts +38 -0
  730. package/src/domains/providers/runtimes/claude/claude-sdk.ts +38 -0
  731. package/src/domains/providers/runtimes/claude/common.ts +55 -0
  732. package/src/domains/providers/runtimes/cloud/alcf.ts +171 -0
  733. package/src/domains/providers/runtimes/cloud/anthropic-max.ts +71 -0
  734. package/src/domains/providers/runtimes/cloud/anthropic.ts +43 -0
  735. package/src/domains/providers/runtimes/cloud/bedrock.ts +35 -0
  736. package/src/domains/providers/runtimes/cloud/deepseek.ts +50 -0
  737. package/src/domains/providers/runtimes/cloud/google.ts +41 -0
  738. package/src/domains/providers/runtimes/cloud/groq.ts +46 -0
  739. package/src/domains/providers/runtimes/cloud/mistral.ts +46 -0
  740. package/src/domains/providers/runtimes/cloud/openai-codex.ts +49 -0
  741. package/src/domains/providers/runtimes/cloud/openai.ts +46 -0
  742. package/src/domains/providers/runtimes/cloud/openrouter.ts +111 -0
  743. package/src/domains/providers/runtimes/common/lmstudio-http.ts +423 -0
  744. package/src/domains/providers/runtimes/common/local-synth.ts +164 -0
  745. package/src/domains/providers/runtimes/common/probe-helpers.ts +474 -0
  746. package/src/domains/providers/runtimes/local-native/lemonade-anthropic.ts +27 -0
  747. package/src/domains/providers/runtimes/local-native/lemonade-openai.ts +26 -0
  748. package/src/domains/providers/runtimes/local-native/llamacpp-anthropic.ts +88 -0
  749. package/src/domains/providers/runtimes/local-native/llamacpp-completion.ts +207 -0
  750. package/src/domains/providers/runtimes/local-native/llamacpp-embed.ts +180 -0
  751. package/src/domains/providers/runtimes/local-native/llamacpp-rerank.ts +126 -0
  752. package/src/domains/providers/runtimes/local-native/llamacpp.ts +98 -0
  753. package/src/domains/providers/runtimes/local-native/lmstudio.ts +241 -0
  754. package/src/domains/providers/runtimes/local-native/ollama-native.ts +117 -0
  755. package/src/domains/providers/runtimes/local-native/sglang.ts +26 -0
  756. package/src/domains/providers/runtimes/local-native/vllm.ts +27 -0
  757. package/src/domains/providers/runtimes/protocol/anthropic-compat.ts +104 -0
  758. package/src/domains/providers/runtimes/protocol/anthropic-messages.ts +28 -0
  759. package/src/domains/providers/runtimes/protocol/bedrock.ts +26 -0
  760. package/src/domains/providers/runtimes/protocol/google.ts +27 -0
  761. package/src/domains/providers/runtimes/protocol/openai-compat.ts +145 -0
  762. package/src/domains/providers/support.ts +241 -0
  763. package/src/domains/providers/thinking-control-policy.ts +85 -0
  764. package/src/domains/providers/types/capability-flags.ts +114 -0
  765. package/src/domains/providers/types/cost-provenance.ts +7 -0
  766. package/src/domains/providers/types/inference.ts +41 -0
  767. package/src/domains/providers/types/knowledge-base.ts +156 -0
  768. package/src/domains/providers/types/local-model-quirks.ts +216 -0
  769. package/src/domains/providers/types/runtime-descriptor.ts +181 -0
  770. package/src/domains/providers/types/target-descriptor.ts +60 -0
  771. package/src/domains/resources/collision.ts +92 -0
  772. package/src/domains/resources/common-loader.ts +140 -0
  773. package/src/domains/resources/contract.ts +24 -0
  774. package/src/domains/resources/extension.ts +59 -0
  775. package/src/domains/resources/index.ts +74 -0
  776. package/src/domains/resources/loader.ts +85 -0
  777. package/src/domains/resources/manifest.ts +6 -0
  778. package/src/domains/resources/prompts/loader.ts +246 -0
  779. package/src/domains/resources/prompts/substitute.ts +1 -0
  780. package/src/domains/resources/skills/content-hash.ts +107 -0
  781. package/src/domains/resources/skills/evals.ts +175 -0
  782. package/src/domains/resources/skills/install.ts +427 -0
  783. package/src/domains/resources/skills/loader.ts +985 -0
  784. package/src/domains/resources/skills/marketplace.ts +301 -0
  785. package/src/domains/resources/skills/provenance-pin.ts +115 -0
  786. package/src/domains/safety/action-classifier.ts +270 -0
  787. package/src/domains/safety/approval-axis.ts +23 -0
  788. package/src/domains/safety/audit.ts +493 -0
  789. package/src/domains/safety/autonomy.ts +174 -0
  790. package/src/domains/safety/call-target.ts +59 -0
  791. package/src/domains/safety/contract.ts +65 -0
  792. package/src/domains/safety/damage-control.ts +44 -0
  793. package/src/domains/safety/default-path-policy.ts +117 -0
  794. package/src/domains/safety/extension.ts +383 -0
  795. package/src/domains/safety/finish-contract-registration.ts +128 -0
  796. package/src/domains/safety/finish-contract.ts +554 -0
  797. package/src/domains/safety/index.ts +44 -0
  798. package/src/domains/safety/loop-detector.ts +143 -0
  799. package/src/domains/safety/manifest.ts +6 -0
  800. package/src/domains/safety/path-policy.ts +164 -0
  801. package/src/domains/safety/policy-engine.ts +994 -0
  802. package/src/domains/safety/project-policy.ts +391 -0
  803. package/src/domains/safety/protected-artifacts-registration.ts +189 -0
  804. package/src/domains/safety/protected-artifacts.ts +993 -0
  805. package/src/domains/safety/rejection-feedback.ts +102 -0
  806. package/src/domains/safety/rigor.ts +72 -0
  807. package/src/domains/safety/rule-compiler.ts +48 -0
  808. package/src/domains/safety/rule-pack-loader.ts +92 -0
  809. package/src/domains/safety/run-effects.ts +197 -0
  810. package/src/domains/safety/scope.ts +61 -0
  811. package/src/domains/scheduling/budget.ts +35 -0
  812. package/src/domains/scheduling/cluster.ts +175 -0
  813. package/src/domains/scheduling/contract.ts +30 -0
  814. package/src/domains/scheduling/extension.ts +91 -0
  815. package/src/domains/scheduling/index.ts +12 -0
  816. package/src/domains/scheduling/manifest.ts +6 -0
  817. package/src/domains/session/archive-readers.ts +208 -0
  818. package/src/domains/session/checkpoint.ts +38 -0
  819. package/src/domains/session/compaction/auto.ts +89 -0
  820. package/src/domains/session/compaction/branch-summary.ts +187 -0
  821. package/src/domains/session/compaction/compact.ts +493 -0
  822. package/src/domains/session/compaction/cut-point.ts +172 -0
  823. package/src/domains/session/compaction/defaults.ts +34 -0
  824. package/src/domains/session/compaction/mask-observations.ts +265 -0
  825. package/src/domains/session/compaction/session-entries.ts +18 -0
  826. package/src/domains/session/compaction/tokens.ts +148 -0
  827. package/src/domains/session/context-accounting.ts +583 -0
  828. package/src/domains/session/context-ledger.ts +362 -0
  829. package/src/domains/session/contract.ts +159 -0
  830. package/src/domains/session/cwd-fallback.ts +65 -0
  831. package/src/domains/session/decision-board.ts +190 -0
  832. package/src/domains/session/entries.ts +572 -0
  833. package/src/domains/session/extension.ts +403 -0
  834. package/src/domains/session/history.ts +172 -0
  835. package/src/domains/session/index.ts +84 -0
  836. package/src/domains/session/manager.ts +128 -0
  837. package/src/domains/session/manifest.ts +6 -0
  838. package/src/domains/session/migrations/index.ts +27 -0
  839. package/src/domains/session/prompt-manifest.ts +173 -0
  840. package/src/domains/session/protected-artifact-journal.ts +241 -0
  841. package/src/domains/session/protected-artifacts.ts +90 -0
  842. package/src/domains/session/retry.ts +230 -0
  843. package/src/domains/session/session-artifacts.ts +107 -0
  844. package/src/domains/session/task-board.ts +569 -0
  845. package/src/domains/session/tree/active-path.ts +137 -0
  846. package/src/domains/session/tree/fork.ts +159 -0
  847. package/src/domains/session/tree/manager.ts +128 -0
  848. package/src/domains/session/tree/navigator.ts +177 -0
  849. package/src/domains/session/tree/preview.ts +259 -0
  850. package/src/domains/session/usage.ts +148 -0
  851. package/src/domains/session/workspace/git-probe.ts +167 -0
  852. package/src/domains/session/workspace/index.ts +4 -0
  853. package/src/domains/session/workspace/project-type.ts +217 -0
  854. package/src/domains/session/workspace/snapshot.ts +74 -0
  855. package/src/domains/share/archive.ts +684 -0
  856. package/src/domains/share/contract.ts +9 -0
  857. package/src/domains/share/extension.ts +26 -0
  858. package/src/domains/share/index.ts +28 -0
  859. package/src/domains/share/manifest.ts +6 -0
  860. package/src/domains/user-tasks/store.ts +297 -0
  861. package/src/engine/acp/adapter.ts +397 -0
  862. package/src/engine/acp/errors.ts +128 -0
  863. package/src/engine/acp/event-mapper.ts +154 -0
  864. package/src/engine/acp/server.ts +2238 -0
  865. package/src/engine/acp/tool-mediator.ts +686 -0
  866. package/src/engine/acp/transport.ts +775 -0
  867. package/src/engine/acp/types.ts +196 -0
  868. package/src/engine/agent.ts +29 -0
  869. package/src/engine/ai.ts +207 -0
  870. package/src/engine/alcf-oauth.ts +205 -0
  871. package/src/engine/antigravity/subprocess-runtime.ts +205 -0
  872. package/src/engine/api-registry.ts +223 -0
  873. package/src/engine/apis/degraded-inference.ts +95 -0
  874. package/src/engine/apis/index.ts +16 -0
  875. package/src/engine/apis/llamacpp-residency.ts +292 -0
  876. package/src/engine/apis/lmstudio-residency.ts +76 -0
  877. package/src/engine/apis/lmstudio.ts +243 -0
  878. package/src/engine/apis/ollama-native.ts +528 -0
  879. package/src/engine/apis/openai-completions.ts +795 -0
  880. package/src/engine/apis/output-budget.ts +99 -0
  881. package/src/engine/apis/residency-lock.ts +29 -0
  882. package/src/engine/apis/residency.ts +776 -0
  883. package/src/engine/apis/resident-models.ts +42 -0
  884. package/src/engine/apis/sampling-overrides.ts +38 -0
  885. package/src/engine/apis/types.ts +16 -0
  886. package/src/engine/claude/sdk-runtime.ts +685 -0
  887. package/src/engine/claude/session-id.ts +5 -0
  888. package/src/engine/claude/subprocess-runtime.ts +316 -0
  889. package/src/engine/claude/tool-safety.ts +400 -0
  890. package/src/engine/env-api-keys.ts +98 -0
  891. package/src/engine/external-subprocess.ts +23 -0
  892. package/src/engine/gemma-channel-filter.ts +223 -0
  893. package/src/engine/harmony-response.ts +165 -0
  894. package/src/engine/instrumented-tui.ts +192 -0
  895. package/src/engine/loop-guard.ts +1127 -0
  896. package/src/engine/messages.ts +14 -0
  897. package/src/engine/models.ts +42 -0
  898. package/src/engine/oauth.ts +196 -0
  899. package/src/engine/pi-mono-names.ts +13 -0
  900. package/src/engine/prompt-templates.ts +1 -0
  901. package/src/engine/provider-payload.ts +272 -0
  902. package/src/engine/select-list.ts +53 -0
  903. package/src/engine/session.ts +834 -0
  904. package/src/engine/strip-tokenizer-sentinels.ts +125 -0
  905. package/src/engine/truncate.ts +9 -0
  906. package/src/engine/tui.ts +111 -0
  907. package/src/engine/types.ts +63 -0
  908. package/src/engine/worker-events.ts +100 -0
  909. package/src/engine/worker-runtime-capabilities.ts +5 -0
  910. package/src/engine/worker-runtime.ts +1022 -0
  911. package/src/engine/worker-tools.ts +208 -0
  912. package/src/entry/boot-options.ts +50 -0
  913. package/src/entry/orchestrator.ts +2011 -0
  914. package/src/interactive/application-controller.ts +433 -0
  915. package/src/interactive/bus-notices.ts +265 -0
  916. package/src/interactive/chat-loop-messages.ts +626 -0
  917. package/src/interactive/chat-loop-policy.ts +18 -0
  918. package/src/interactive/chat-loop.ts +1090 -0
  919. package/src/interactive/chat-panel.ts +1820 -0
  920. package/src/interactive/chat-renderer.ts +1228 -0
  921. package/src/interactive/clio-editor.ts +161 -0
  922. package/src/interactive/command-fallbacks.ts +23 -0
  923. package/src/interactive/command-output.ts +85 -0
  924. package/src/interactive/context-activity.ts +203 -0
  925. package/src/interactive/context-meter.ts +223 -0
  926. package/src/interactive/context-overlay.ts +246 -0
  927. package/src/interactive/cost-overlay.ts +279 -0
  928. package/src/interactive/dispatch-board.ts +1319 -0
  929. package/src/interactive/dispatch-steering.ts +86 -0
  930. package/src/interactive/editor-bash.ts +46 -0
  931. package/src/interactive/editor-steer.ts +51 -0
  932. package/src/interactive/editor-submit.ts +507 -0
  933. package/src/interactive/export-html/ansi-to-html.ts +161 -0
  934. package/src/interactive/export-html/index.ts +51 -0
  935. package/src/interactive/export-html/template.ts +45 -0
  936. package/src/interactive/export-html/tool-renderer.ts +54 -0
  937. package/src/interactive/external-editor.ts +67 -0
  938. package/src/interactive/follow-up-queue-panel.ts +75 -0
  939. package/src/interactive/footer/dashboard.ts +538 -0
  940. package/src/interactive/footer/notifications.ts +275 -0
  941. package/src/interactive/footer/widgets.ts +1264 -0
  942. package/src/interactive/footer-panel.ts +187 -0
  943. package/src/interactive/format-time.ts +97 -0
  944. package/src/interactive/index.ts +11 -0
  945. package/src/interactive/interactive-application.ts +939 -0
  946. package/src/interactive/interactive-event-projection.ts +385 -0
  947. package/src/interactive/interactive-input-runtime.ts +307 -0
  948. package/src/interactive/interactive-presentation.ts +584 -0
  949. package/src/interactive/interactive-shell.ts +388 -0
  950. package/src/interactive/interactive-slash-runtime.ts +554 -0
  951. package/src/interactive/interactive-subscriptions.ts +111 -0
  952. package/src/interactive/interactive-tickers.ts +183 -0
  953. package/src/interactive/keybinding-manager.ts +496 -0
  954. package/src/interactive/layout.ts +57 -0
  955. package/src/interactive/leader-key.ts +143 -0
  956. package/src/interactive/loop-guard-interrupt.ts +101 -0
  957. package/src/interactive/memory-overlay.ts +280 -0
  958. package/src/interactive/overlay-ask-user-lifecycle.ts +110 -0
  959. package/src/interactive/overlay-auth-lifecycle.ts +308 -0
  960. package/src/interactive/overlay-frame.ts +502 -0
  961. package/src/interactive/overlay-general-openers.ts +274 -0
  962. package/src/interactive/overlay-key-routing.ts +216 -0
  963. package/src/interactive/overlay-lifecycle.ts +426 -0
  964. package/src/interactive/overlay-model-selectors.ts +127 -0
  965. package/src/interactive/overlay-permission-lifecycle.ts +345 -0
  966. package/src/interactive/overlay-resource-openers.ts +112 -0
  967. package/src/interactive/overlay-session-lifecycle.ts +327 -0
  968. package/src/interactive/overlay-transitions.ts +57 -0
  969. package/src/interactive/overlays/agents.ts +69 -0
  970. package/src/interactive/overlays/ask-user.ts +921 -0
  971. package/src/interactive/overlays/auth-dialog.ts +221 -0
  972. package/src/interactive/overlays/context-reset.ts +108 -0
  973. package/src/interactive/overlays/cwd-fallback.ts +141 -0
  974. package/src/interactive/overlays/decisions.ts +300 -0
  975. package/src/interactive/overlays/extensions.ts +54 -0
  976. package/src/interactive/overlays/help-reference.ts +145 -0
  977. package/src/interactive/overlays/interop.ts +139 -0
  978. package/src/interactive/overlays/keybinding-detail.ts +90 -0
  979. package/src/interactive/overlays/list-overlay.ts +606 -0
  980. package/src/interactive/overlays/message-picker.ts +155 -0
  981. package/src/interactive/overlays/model-selector.ts +1109 -0
  982. package/src/interactive/overlays/prompts.ts +72 -0
  983. package/src/interactive/overlays/session-selector-search.ts +31 -0
  984. package/src/interactive/overlays/session-selector.ts +284 -0
  985. package/src/interactive/overlays/settings.ts +3451 -0
  986. package/src/interactive/overlays/skills-hub.ts +237 -0
  987. package/src/interactive/overlays/tree-selector.ts +422 -0
  988. package/src/interactive/permission-overlay.ts +170 -0
  989. package/src/interactive/render-trace.ts +534 -0
  990. package/src/interactive/renderers/branch-summary.ts +86 -0
  991. package/src/interactive/renderers/code-ink.ts +420 -0
  992. package/src/interactive/renderers/compaction-summary.ts +112 -0
  993. package/src/interactive/renderers/diff.ts +137 -0
  994. package/src/interactive/renderers/mermaid.ts +53 -0
  995. package/src/interactive/renderers/notice.ts +28 -0
  996. package/src/interactive/renderers/retry-status.ts +31 -0
  997. package/src/interactive/renderers/structured.ts +89 -0
  998. package/src/interactive/renderers/tool-execution.ts +1357 -0
  999. package/src/interactive/renderers/worker-entry.ts +280 -0
  1000. package/src/interactive/session-last-turn.ts +186 -0
  1001. package/src/interactive/session-switch-settlement.ts +10 -0
  1002. package/src/interactive/session-transcript.ts +105 -0
  1003. package/src/interactive/session-usage-reseed.ts +74 -0
  1004. package/src/interactive/slash-autocomplete.ts +256 -0
  1005. package/src/interactive/slash-commands.ts +1407 -0
  1006. package/src/interactive/slash-spec.ts +424 -0
  1007. package/src/interactive/status/controller.ts +260 -0
  1008. package/src/interactive/status/index.ts +23 -0
  1009. package/src/interactive/status/state-machine.ts +530 -0
  1010. package/src/interactive/status/summary.ts +170 -0
  1011. package/src/interactive/status/types.ts +121 -0
  1012. package/src/interactive/status/verbs.ts +163 -0
  1013. package/src/interactive/status/watchdog.ts +24 -0
  1014. package/src/interactive/stdout-backpressure.ts +99 -0
  1015. package/src/interactive/stream-pacer.ts +530 -0
  1016. package/src/interactive/stream-pacing-policy.ts +66 -0
  1017. package/src/interactive/tasks-overlay.ts +540 -0
  1018. package/src/interactive/terminal-lease.ts +485 -0
  1019. package/src/interactive/theme/components.ts +55 -0
  1020. package/src/interactive/theme/glyphs.ts +70 -0
  1021. package/src/interactive/theme/index.ts +15 -0
  1022. package/src/interactive/theme/labels.ts +88 -0
  1023. package/src/interactive/theme/rules.ts +138 -0
  1024. package/src/interactive/theme/segments.ts +88 -0
  1025. package/src/interactive/theme/tokens.ts +121 -0
  1026. package/src/interactive/thinking-level-policy.ts +6 -0
  1027. package/src/interactive/tool-prose-loop.ts +122 -0
  1028. package/src/interactive/tool-prose-registration.ts +48 -0
  1029. package/src/interactive/turn-context.ts +855 -0
  1030. package/src/interactive/turn-middleware.ts +283 -0
  1031. package/src/interactive/turn-persistence.ts +458 -0
  1032. package/src/interactive/turn-queues.ts +181 -0
  1033. package/src/interactive/turn-recovery.ts +323 -0
  1034. package/src/interactive/turn-runtime.ts +869 -0
  1035. package/src/interactive/turn-state.ts +133 -0
  1036. package/src/interactive/view/artifacts.ts +1452 -0
  1037. package/src/interactive/view/view-overlay.ts +735 -0
  1038. package/src/interactive/welcome-dashboard.ts +537 -0
  1039. package/src/interactive/worker-receipts.ts +143 -0
  1040. package/src/interactive/worker-replay.ts +111 -0
  1041. package/src/interactive/worker-share.ts +100 -0
  1042. package/src/interactive/worker-stream.ts +446 -0
  1043. package/src/interactive/workspace-facts.ts +141 -0
  1044. package/src/tools/agent-tools.ts +402 -0
  1045. package/src/tools/artifact.ts +103 -0
  1046. package/src/tools/ask-user.ts +666 -0
  1047. package/src/tools/bash.ts +204 -0
  1048. package/src/tools/bootstrap.ts +77 -0
  1049. package/src/tools/builtin-tool-catalog.ts +265 -0
  1050. package/src/tools/codewiki/code-nav-surface.ts +29 -0
  1051. package/src/tools/codewiki/code-nav.ts +549 -0
  1052. package/src/tools/codewiki/shared.ts +118 -0
  1053. package/src/tools/compete-worktrees.ts +898 -0
  1054. package/src/tools/context/docs-engine.ts +630 -0
  1055. package/src/tools/context/index.ts +514 -0
  1056. package/src/tools/context/surface.ts +19 -0
  1057. package/src/tools/core-bootstrap.ts +168 -0
  1058. package/src/tools/credential-present.ts +151 -0
  1059. package/src/tools/dispatch-admission.ts +533 -0
  1060. package/src/tools/dispatch-arguments.ts +228 -0
  1061. package/src/tools/dispatch-background.ts +54 -0
  1062. package/src/tools/dispatch-event-text.ts +6 -0
  1063. package/src/tools/dispatch-plan.ts +746 -0
  1064. package/src/tools/dispatch-run-events.ts +238 -0
  1065. package/src/tools/dispatch-runner.ts +2370 -0
  1066. package/src/tools/dispatch-scout-admission.ts +295 -0
  1067. package/src/tools/dispatch-scout.ts +461 -0
  1068. package/src/tools/dispatch-types.ts +77 -0
  1069. package/src/tools/dispatch.ts +244 -0
  1070. package/src/tools/edit-diff.ts +534 -0
  1071. package/src/tools/edit.ts +128 -0
  1072. package/src/tools/executables.ts +22 -0
  1073. package/src/tools/file-mutation-queue.ts +35 -0
  1074. package/src/tools/find.ts +294 -0
  1075. package/src/tools/grep.ts +495 -0
  1076. package/src/tools/ignore-policy.ts +169 -0
  1077. package/src/tools/lazy-tool.ts +60 -0
  1078. package/src/tools/ledger.ts +206 -0
  1079. package/src/tools/ls.ts +110 -0
  1080. package/src/tools/monitor-surface.ts +36 -0
  1081. package/src/tools/monitor.ts +767 -0
  1082. package/src/tools/network-policy.ts +29 -0
  1083. package/src/tools/observation.ts +421 -0
  1084. package/src/tools/observers.ts +99 -0
  1085. package/src/tools/path-utils.ts +79 -0
  1086. package/src/tools/policy.ts +154 -0
  1087. package/src/tools/profiles.ts +108 -0
  1088. package/src/tools/read.ts +173 -0
  1089. package/src/tools/registry.ts +1169 -0
  1090. package/src/tools/result-shaping.ts +204 -0
  1091. package/src/tools/safe-exec.ts +128 -0
  1092. package/src/tools/spawn-hygiene.ts +182 -0
  1093. package/src/tools/steer-surface.ts +17 -0
  1094. package/src/tools/steer.ts +77 -0
  1095. package/src/tools/tasks.ts +265 -0
  1096. package/src/tools/truncate-utf8.ts +17 -0
  1097. package/src/tools/truncate.ts +43 -0
  1098. package/src/tools/verify/frontend.ts +687 -0
  1099. package/src/tools/verify/index.ts +31 -0
  1100. package/src/tools/verify/scripts.ts +108 -0
  1101. package/src/tools/verify/surface.ts +46 -0
  1102. package/src/tools/web-fetch-surface.ts +23 -0
  1103. package/src/tools/web-fetch.ts +759 -0
  1104. package/src/tools/worker-evidence.ts +215 -0
  1105. package/src/tools/write.ts +57 -0
  1106. package/src/utils/exif-orientation.ts +192 -0
  1107. package/src/utils/git.ts +24 -0
  1108. package/src/utils/image-resize.ts +148 -0
  1109. package/src/utils/photon.ts +103 -0
  1110. package/src/worker/control-lane.ts +22 -0
  1111. package/src/worker/entry.ts +294 -0
  1112. package/src/worker/event-projection.ts +56 -0
  1113. package/src/worker/heartbeat.ts +24 -0
  1114. package/src/worker/ledger-mirror.ts +95 -0
  1115. package/src/worker/ndjson.ts +40 -0
  1116. package/src/worker/protocol.ts +529 -0
  1117. package/src/worker/resource-facts.ts +79 -0
  1118. package/src/worker/runtime-registry.ts +12 -0
  1119. package/src/worker/spec-contract.ts +675 -0
  1120. package/src/worker/stdin-demux.ts +316 -0
  1121. package/dist/acp-UMLFVA3F.js +0 -92
  1122. package/dist/chunk-262G75JS.js +0 -35
  1123. package/dist/chunk-6CWDTGUC.js +0 -20
  1124. package/dist/chunk-BYEU76JP.js +0 -899
  1125. package/dist/chunk-GNGDQYDU.js +0 -34688
  1126. package/dist/chunk-GOTUR54M.js +0 -9
  1127. package/dist/chunk-NI4DEJMC.js +0 -88
  1128. package/dist/chunk-TPOCL34A.js +0 -2876
  1129. package/dist/chunk-UU3R62TT.js +0 -128
  1130. package/dist/clio-KIQ5SNDS.js +0 -53
  1131. package/dist/configure-G4E3A2PG.js +0 -27
  1132. package/dist/doctor-M5HJJZOL.js +0 -61
  1133. package/dist/domains/agents/builtins/architect.md +0 -33
  1134. package/dist/domains/agents/builtins/coder.md +0 -31
  1135. package/dist/domains/agents/builtins/context-bootstrap.md +0 -38
  1136. package/dist/domains/agents/builtins/debugger.md +0 -30
  1137. package/dist/domains/agents/builtins/documenter.md +0 -31
  1138. package/dist/domains/agents/builtins/git-master.md +0 -30
  1139. package/dist/domains/agents/builtins/provenance.md +0 -30
  1140. package/dist/domains/agents/builtins/researcher.md +0 -71
  1141. package/dist/domains/agents/builtins/scout.md +0 -42
  1142. package/dist/domains/agents/builtins/tester.md +0 -31
  1143. package/dist/domains/agents/builtins/verifier.md +0 -30
  1144. package/dist/domains/agents/builtins/wiki-writer.md +0 -41
  1145. package/dist/fleet-preflight-CLIAX7YR.js +0 -21
  1146. package/dist/preload-KZVHET2B.js +0 -11
  1147. package/dist/version-ROZ6CZKH.js +0 -16
  1148. package/docs/html/agents_blueprint.html +0 -936
  1149. package/docs/html/alcf_blueprint.html +0 -324
  1150. package/docs/html/architecture_blueprint.html +0 -850
  1151. package/docs/html/commands_blueprint.html +0 -794
  1152. package/docs/html/config_knobs_audit_blueprint.html +0 -178
  1153. package/docs/html/configuration_blueprint.html +0 -1080
  1154. package/docs/html/context_blueprint.html +0 -603
  1155. package/docs/html/documentation_blueprint.html +0 -832
  1156. package/docs/html/environment_blueprint.html +0 -404
  1157. package/docs/html/eval_blueprint.html +0 -743
  1158. package/docs/html/evals_internal_blueprint.html +0 -190
  1159. package/docs/html/evolution_blueprint.html +0 -674
  1160. package/docs/html/extensions_blueprint.html +0 -2065
  1161. package/docs/html/fleet_dispatch_blueprint.html +0 -286
  1162. package/docs/html/index.html +0 -919
  1163. package/docs/html/lifecycle_blueprint.html +0 -723
  1164. package/docs/html/memory_blueprint.html +0 -699
  1165. package/docs/html/middleware_blueprint.html +0 -664
  1166. package/docs/html/models_blueprint.html +0 -2366
  1167. package/docs/html/observability_blueprint.html +0 -683
  1168. package/docs/html/provider_adapter_blueprint.html +0 -245
  1169. package/docs/html/safety_blueprint.html +0 -1386
  1170. package/docs/html/shared.css +0 -571
  1171. package/docs/html/shared.js +0 -143
  1172. package/docs/html/skills_blueprint.html +0 -671
  1173. package/docs/html/soak_blueprint.html +0 -182
  1174. package/docs/html/tool_usage_blueprint.html +0 -350
  1175. package/docs/html/tools_blueprint.html +0 -2249
  1176. package/docs/html/trace_blueprint.html +0 -235
  1177. package/docs/html/tui_design_blueprint.html +0 -314
  1178. package/docs/html/validation_blueprint.html +0 -961
  1179. package/docs/html/worker_dispatch_blueprint.html +0 -231
  1180. package/skills/git/commit-crafting/SKILL.md +0 -79
  1181. package/skills/git/commit-crafting/evals.md +0 -92
  1182. package/skills/git/create-pr/SKILL.md +0 -116
  1183. package/skills/git/create-pr/evals.md +0 -114
  1184. package/skills/git/investigate-issue/SKILL.md +0 -139
  1185. package/skills/git/investigate-issue/evals.md +0 -94
  1186. package/skills/git/review-changes/SKILL.md +0 -103
  1187. package/skills/git/review-changes/evals.md +0 -85
@@ -0,0 +1,1240 @@
1
+ import { spawn } from "node:child_process";
2
+ import { createHash, randomBytes } from "node:crypto";
3
+ import { existsSync } from "node:fs";
4
+ import { cp, mkdir, mkdtemp, readdir, readFile, rm, stat, writeFile } from "node:fs/promises";
5
+ import { tmpdir } from "node:os";
6
+ import { join, resolve } from "node:path";
7
+ import { performance } from "node:perf_hooks";
8
+ import { combineBashOutput, runBashCommand } from "../core/bash-exec.js";
9
+ import { HEADLESS_PERMISSION_DENIED_MARKER } from "../core/headless-permission.js";
10
+ import { clioDataDir, clioStateDir } from "../core/xdg.js";
11
+ import {
12
+ type EvalHarnessMetrics,
13
+ type EvalRunArtifact,
14
+ type EvalRunRecord,
15
+ evalClioProvenance,
16
+ evalEnvironmentProvenance,
17
+ summarizeEvalResults,
18
+ writeEvalArtifact,
19
+ ZERO_EVAL_HARNESS_METRICS,
20
+ } from "../domains/eval/index.js";
21
+ import { buildEvalEvidence } from "../domains/evidence/index.js";
22
+ import {
23
+ discoverMarketplaceSkills,
24
+ loadSkills,
25
+ parseSkillEvals,
26
+ type SkillEvalScenario,
27
+ } from "../domains/resources/index.js";
28
+ import { NO_NETWORK_TOOLS_ENV } from "../tools/network-policy.js";
29
+ import { formatColumns, printError } from "./shared.js";
30
+
31
+ /**
32
+ * Executable skill evals (experimental). Every catalog skill ships an
33
+ * `evals.md` with RED-GREEN scenarios; this lane executes them instead of
34
+ * trusting the prose: per scenario one baseline headless run (no skills), one
35
+ * treatment run (the skill loaded via the explicit --skill path and invoked
36
+ * with /skill <name>), then one judge run that scores each Expected bullet
37
+ * pass/fail from the two transcripts.
38
+ *
39
+ * Deltas from the task-file eval harness, recorded rather than papered over:
40
+ * the evals domain verifies with setup/verifier commands and has no judge, so
41
+ * bullet verdicts here come from a model run, not command exit codes. The
42
+ * synthesized EvalRunArtifact carries scenario-level records with empty
43
+ * command lists, receipt-backed token/cost totals when headless main-agent
44
+ * receipts are present, and per-bullet detail in a `skill-eval.json` sidecar
45
+ * registered in the bundle's `overview.json` files list.
46
+ */
47
+
48
+ const DEFAULT_RUN_TIMEOUT_MS = 600_000;
49
+ /**
50
+ * The autonomy the acting arms run at.
51
+ *
52
+ * A headless `clio-coder run` has no operator to answer a permission ask, so below
53
+ * full-auto every exec-class call in an arm dies with the harness's own denial
54
+ * and the judge scores a skill that was never allowed to act. Operator decision
55
+ * of 2026-08-13 (docs/findings/HARNESS-NOTES.md item 4): eval arms run
56
+ * full-auto, because their workspaces are per-run copies created under a
57
+ * private temp root and removed when the scenario ends. The judge arm is
58
+ * excluded: it scores text and is instructed to call no tools, so granting it
59
+ * unattended write and exec buys nothing.
60
+ */
61
+ const ARM_AUTONOMY = "full-auto";
62
+ const CHILD_OUTPUT_LIMIT = 4_000_000;
63
+ const PREVIEW_MAX_CHARS = 300;
64
+ const TRANSCRIPT_HEAD_CHARS = 9_000;
65
+ const TRANSCRIPT_TAIL_CHARS = 4_000;
66
+ /** Per-eval detail file written beside the standard bundle and registered in overview.files. */
67
+ const SKILL_EVAL_SIDECAR = "skill-eval.json";
68
+
69
+ export interface SkillsEvalOptions {
70
+ json: boolean;
71
+ /**
72
+ * Fixture commands in evals.md are shell authored by the skill, executed
73
+ * with the operator's environment. They run only on explicit opt-in;
74
+ * without it a fixture-bearing scenario reports an error instead of
75
+ * silently executing third-party shell.
76
+ */
77
+ trustFixtures: boolean;
78
+ /**
79
+ * Let the arm runs keep the network tool plane. Off by default: an eval is
80
+ * a measurement of a skill against a fixed workspace, and a run that can
81
+ * fetch the open web is measuring something else as well.
82
+ */
83
+ allowNetwork: boolean;
84
+ scenario?: string;
85
+ target?: string;
86
+ timeoutSeconds?: number;
87
+ workspace?: string;
88
+ }
89
+
90
+ /**
91
+ * `unmeasured` is not a verdict on the skill. It is the state of a bullet the
92
+ * judge never scored, which is a different fact from a bullet the judge scored
93
+ * negative, and reporting it as `fail` (or as `error`, which the exit code
94
+ * treats as failure) said the skill broke when what broke was the scoring run.
95
+ */
96
+ type BulletVerdict = "pass" | "fail" | "error" | "unmeasured";
97
+
98
+ /** Exported for contracts tests. */
99
+ export interface ScoredBullet {
100
+ index: number;
101
+ text: string;
102
+ verdict: BulletVerdict;
103
+ reason: string;
104
+ }
105
+
106
+ /** Exported for contracts tests. */
107
+ export interface CapturedRun {
108
+ sessionId: string | null;
109
+ transcript: string;
110
+ finalText: string;
111
+ exitCode: number;
112
+ timedOut: boolean;
113
+ wallTimeMs: number;
114
+ stderr: string;
115
+ }
116
+
117
+ interface ScenarioUsage {
118
+ tokens: number;
119
+ costUsd: number;
120
+ harness: EvalHarnessMetrics;
121
+ }
122
+
123
+ interface ScenarioOutcome {
124
+ scenario: SkillEvalScenario;
125
+ bullets: ScoredBullet[];
126
+ baseline: CapturedRun | null;
127
+ treatment: CapturedRun | null;
128
+ judge: CapturedRun | null;
129
+ /** Seed workspace cloned for both arms; removed after the run, kept as a record. */
130
+ workspace: string;
131
+ wallTimeMs: number;
132
+ infraError: string | null;
133
+ usage: ScenarioUsage;
134
+ }
135
+
136
+ export async function runSkillsEvalCommand(nameOrPath: string, options: SkillsEvalOptions): Promise<number> {
137
+ const resolved = resolveSkillBaseDir(nameOrPath, process.cwd());
138
+ if (resolved.baseDir === null) {
139
+ printError(resolved.error ?? `unknown skill: ${nameOrPath}`);
140
+ return 2;
141
+ }
142
+ const list = loadSkills({ disableDiscovery: true, explicitSkillPaths: [resolved.baseDir] });
143
+ const skill = list.items[0];
144
+ if (skill === undefined) {
145
+ printError(`skill did not load from ${resolved.baseDir}: ${list.diagnostics.map((d) => d.message).join("; ")}`);
146
+ return 2;
147
+ }
148
+ // Which copy is under test, before any scenario runs. A result nobody can
149
+ // attribute to a source is not evidence about a skill, and several roots may
150
+ // carry this name.
151
+ process.stderr.write(
152
+ `clio-coder skills eval: ${skill.name} from ${resolved.origin ?? "unknown"} at ${resolved.baseDir} (sha256 ${skill.normalizedHash.slice(0, 12)}…)\n`,
153
+ );
154
+ const evalsPath = join(resolved.baseDir, "evals.md");
155
+ let evalsRaw: string;
156
+ try {
157
+ evalsRaw = await readFile(evalsPath, "utf8");
158
+ } catch {
159
+ printError(`skill ${skill.name} has no evals.md at ${evalsPath}`);
160
+ return 2;
161
+ }
162
+ const parsed = parseSkillEvals(evalsRaw);
163
+ for (const diagnostic of parsed.diagnostics) {
164
+ process.stderr.write(`clio-coder skills eval: ${diagnostic}\n`);
165
+ }
166
+ const matcher = options.scenario === undefined ? null : scenarioMatcher(options.scenario);
167
+ if (options.scenario !== undefined && matcher === null) {
168
+ printError(`invalid --scenario "${options.scenario}": use a scenario id like S1 or a bare number`);
169
+ return 2;
170
+ }
171
+ const scenarios = matcher === null ? parsed.scenarios : parsed.scenarios.filter(matcher);
172
+ if (scenarios.length === 0) {
173
+ printError(
174
+ matcher === null
175
+ ? `no parseable scenarios in ${evalsPath}`
176
+ : `scenario ${options.scenario} not found in ${evalsPath} (have: ${parsed.scenarios.map((s) => s.id).join(", ") || "none"})`,
177
+ );
178
+ return 2;
179
+ }
180
+
181
+ process.stderr.write(`clio-coder skills eval: ${describeArmPolicy(options.allowNetwork)}\n`);
182
+ const childEnv = evalChildEnv(options.allowNetwork);
183
+ const timeoutMs = options.timeoutSeconds !== undefined ? options.timeoutSeconds * 1000 : DEFAULT_RUN_TIMEOUT_MS;
184
+ const workspaceOverride = await resolveWorkspaceOverride(options.workspace);
185
+ if (typeof workspaceOverride !== "string" && workspaceOverride !== null) {
186
+ printError(workspaceOverride.error);
187
+ return 2;
188
+ }
189
+ const startedAt = new Date().toISOString();
190
+ const outcomes: ScenarioOutcome[] = [];
191
+ for (const scenario of scenarios) {
192
+ process.stderr.write(`clio-coder skills eval: ${skill.name} ${scenario.id} baseline/treatment/judge...\n`);
193
+ outcomes.push(
194
+ await runScenario(
195
+ skill.name,
196
+ resolved.baseDir,
197
+ scenario,
198
+ options.target,
199
+ timeoutMs,
200
+ workspaceOverride,
201
+ options.trustFixtures,
202
+ childEnv,
203
+ ),
204
+ );
205
+ }
206
+ const endedAt = new Date().toISOString();
207
+
208
+ const artifact = synthesizeArtifact(skill.name, evalsPath, evalsRaw, startedAt, endedAt, outcomes, options.target);
209
+ let evidenceId: string | null = null;
210
+ let evidenceDirectory: string | null = null;
211
+ const evidenceErrors: string[] = [];
212
+ try {
213
+ await writeEvalArtifact(clioDataDir(), artifact);
214
+ const built = await buildEvalEvidence({
215
+ dataDir: clioDataDir(),
216
+ stateDir: clioStateDir(),
217
+ artifact,
218
+ sidecars: [SKILL_EVAL_SIDECAR],
219
+ });
220
+ evidenceId = built.evidenceId;
221
+ evidenceDirectory = built.directory;
222
+ await writeFile(
223
+ join(built.directory, SKILL_EVAL_SIDECAR),
224
+ `${JSON.stringify(sidecar(skill.name, artifact.evalId, outcomes, options.allowNetwork), null, 2)}\n`,
225
+ "utf8",
226
+ );
227
+ } catch (error) {
228
+ evidenceErrors.push(error instanceof Error ? error.message : String(error));
229
+ }
230
+ for (const message of evidenceErrors) {
231
+ process.stderr.write(`clio-coder skills eval: evidence build failed: ${message}\n`);
232
+ }
233
+
234
+ if (options.json) {
235
+ for (const outcome of outcomes) {
236
+ for (const bullet of outcome.bullets) {
237
+ process.stdout.write(
238
+ `${JSON.stringify({
239
+ schema: "experimental",
240
+ kind: "skill-eval-bullet",
241
+ skill: skill.name,
242
+ scenario: outcome.scenario.id,
243
+ title: outcome.scenario.title,
244
+ bullet: bullet.index,
245
+ expected: bullet.text,
246
+ verdict: bullet.verdict,
247
+ reason: bullet.reason,
248
+ network: networkPolicyLabel(options.allowNetwork),
249
+ autonomy: ARM_AUTONOMY,
250
+ baselineSessionId: outcome.baseline?.sessionId ?? null,
251
+ treatmentSessionId: outcome.treatment?.sessionId ?? null,
252
+ judgeSessionId: outcome.judge?.sessionId ?? null,
253
+ evalId: artifact.evalId,
254
+ evidenceId,
255
+ })}\n`,
256
+ );
257
+ }
258
+ }
259
+ } else {
260
+ printHumanReport(skill.name, outcomes, artifact.evalId, evidenceId, evidenceDirectory, options.allowNetwork);
261
+ }
262
+ const anyFailure = outcomes.some((outcome) =>
263
+ outcome.bullets.some((bullet) => bullet.verdict === "fail" || bullet.verdict === "error"),
264
+ );
265
+ const anyUnmeasured = outcomes.some((outcome) => outcome.bullets.some((bullet) => bullet.verdict === "unmeasured"));
266
+ // 1 means the skill failed its rubric. 3 means no rubric verdict stands to
267
+ // regress against, either because a scenario went unmeasured or because the
268
+ // evidence archive write failed; a caller branching on the code must not
269
+ // read either as a regression, and a run that measured nothing is still not
270
+ // a pass.
271
+ if (anyFailure) return 1;
272
+ return anyUnmeasured || evidenceErrors.length > 0 ? 3 : 0;
273
+ }
274
+
275
+ export type NetworkPolicyLabel = "hermetic" | "allowed";
276
+
277
+ function networkPolicyLabel(allowNetwork: boolean): NetworkPolicyLabel {
278
+ return allowNetwork ? "allowed" : "hermetic";
279
+ }
280
+
281
+ /**
282
+ * One line stating everything the harness imposes on its children, before the
283
+ * first arm starts. Autonomy sits beside the network mode because they are the
284
+ * same kind of fact: a reader who has to guess either one cannot tell what a
285
+ * verdict was measured under.
286
+ */
287
+ function describeArmPolicy(allowNetwork: boolean): string {
288
+ const network = allowNetwork
289
+ ? "network allowed (--allow-network), so arm runs keep the web tools"
290
+ : "network hermetic, so the web tools are stripped from every arm run (pass --allow-network to keep them)";
291
+ return `policy: autonomy ${ARM_AUTONOMY} for the baseline and treatment arms in per-run disposable workspaces; ${network}`;
292
+ }
293
+
294
+ /** The same two facts in the past tense, for the tail of the human report. */
295
+ function describeArmPolicyOutcome(allowNetwork: boolean): string {
296
+ const network = allowNetwork
297
+ ? "network: allowed (--allow-network); arm runs kept the web tools"
298
+ : "network: hermetic; the web tools were stripped from every arm run";
299
+ return `policy: the baseline and treatment arms ran at autonomy ${ARM_AUTONOMY}; ${network}`;
300
+ }
301
+
302
+ type EvalArm = "baseline" | "treatment" | "judge";
303
+
304
+ /**
305
+ * The argv for one arm's child `clio-coder run`. Every arm streams the full JSON
306
+ * event sequence because the evaluator scores assistant messages and tool
307
+ * evidence, while terminal mode is intentionally receipt-only. A turn that ends
308
+ * on a terminating tool carries its content in the full event stream rather
309
+ * than text mode. Discovery stays off so only the treatment arm's explicit
310
+ * skill loads.
311
+ *
312
+ * @internal Exported for contract tests.
313
+ */
314
+ export function armRunArgs(
315
+ arm: EvalArm,
316
+ prompt: string,
317
+ options: { target?: string | undefined; skillBaseDir?: string | undefined } = {},
318
+ ): string[] {
319
+ const args = ["run", "--json", "--json-events", "full", "--no-skills"];
320
+ if (arm !== "judge") args.push("--autonomy", ARM_AUTONOMY);
321
+ if (options.skillBaseDir !== undefined) args.push("--skill", options.skillBaseDir);
322
+ if (options.target !== undefined) args.push("--target", options.target);
323
+ args.push(prompt);
324
+ return args;
325
+ }
326
+
327
+ /**
328
+ * The harness's own permission gate, found in an arm transcript.
329
+ *
330
+ * A headless run denies any call it cannot get an operator's approval for, and
331
+ * the denial reaches the model as a tool error. An arm that collected those is
332
+ * not evidence about the skill in either direction: it never ran the skill's
333
+ * workflow, so its bullets are unmeasured, exactly like a judge that never
334
+ * scored them. Reported as an infra error, never as a verdict.
335
+ *
336
+ * @internal Exported for contract tests.
337
+ */
338
+ export function permissionWallReason(arm: EvalArm, run: CapturedRun): string | null {
339
+ const haystack = `${run.transcript}\n${run.finalText}`;
340
+ let blocked = 0;
341
+ let at = haystack.indexOf(HEADLESS_PERMISSION_DENIED_MARKER);
342
+ while (at >= 0) {
343
+ blocked += 1;
344
+ at = haystack.indexOf(HEADLESS_PERMISSION_DENIED_MARKER, at + HEADLESS_PERMISSION_DENIED_MARKER.length);
345
+ }
346
+ if (blocked === 0) return null;
347
+ return `${arm} arm transcript carries the headless permission wall ${blocked} time(s) ("${HEADLESS_PERMISSION_DENIED_MARKER}"): this run measured the harness's own autonomy gate, not the skill`;
348
+ }
349
+
350
+ function unmeasuredBullets(scenario: SkillEvalScenario, reason: string): ScoredBullet[] {
351
+ return scenario.expected.map((text, index) => ({ index: index + 1, text, verdict: "unmeasured", reason }));
352
+ }
353
+
354
+ /**
355
+ * The environment each arm's child `clio-coder run` inherits. Absent
356
+ * `--allow-network` the hermetic switch is set, which strips the RETRIEVE
357
+ * plane from every registry the child and its descendants build. With the flag
358
+ * the variable is removed rather than left alone, so an ambient setting in the
359
+ * operator's shell cannot make `--allow-network` a claim the run does not keep.
360
+ *
361
+ * @internal Exported for contract tests.
362
+ */
363
+ export function evalChildEnv(allowNetwork: boolean, env: NodeJS.ProcessEnv = process.env): NodeJS.ProcessEnv {
364
+ const childEnv: NodeJS.ProcessEnv = { ...env };
365
+ if (allowNetwork) Reflect.deleteProperty(childEnv, NO_NETWORK_TOOLS_ENV);
366
+ else childEnv[NO_NETWORK_TOOLS_ENV] = "1";
367
+ return childEnv;
368
+ }
369
+
370
+ /**
371
+ * The copy of a named skill this eval will actually execute.
372
+ *
373
+ * Resolution follows activation, not the catalog. A bare name previously
374
+ * resolved straight to the catalog entry, so an operator with the same skill
375
+ * installed in a project or user root evaluated a different artifact from the
376
+ * one their agent would load, and nothing in the run said which. Discovery runs
377
+ * first and its precedence winner is exactly what an activation would select;
378
+ * the catalog answers only for a name no root installed, which is the skill
379
+ * author's case in this repository.
380
+ */
381
+ export function resolveSkillBaseDir(
382
+ nameOrPath: string,
383
+ cwd: string,
384
+ ): { baseDir: string | null; origin?: string; error?: string } {
385
+ const asPath = resolve(nameOrPath);
386
+ if (existsSync(join(asPath, "SKILL.md"))) return { baseDir: asPath, origin: "path" };
387
+ const discovered = loadSkills({ cwd }).items.find((skill) => skill.name === nameOrPath);
388
+ if (discovered !== undefined) {
389
+ return { baseDir: discovered.baseDir, origin: `${discovered.source}/${discovered.scope}` };
390
+ }
391
+ const marketplace = discoverMarketplaceSkills({ cwd });
392
+ const entry = marketplace.skills.find((skill) => skill.name === nameOrPath && skill.origin === "catalog");
393
+ if (entry !== undefined) return { baseDir: entry.sourceUrl, origin: "catalog" };
394
+ return {
395
+ baseDir: null,
396
+ error: `skill not found: ${nameOrPath} (expected an installed skill, a catalog skill name, or a directory containing SKILL.md)`,
397
+ };
398
+ }
399
+
400
+ /**
401
+ * A full id like "D2" selects exactly that scenario; a bare number selects
402
+ * every scenario with that number (evals.md files may mix letter prefixes).
403
+ */
404
+ function scenarioMatcher(value: string): ((scenario: SkillEvalScenario) => boolean) | null {
405
+ const trimmed = value.trim();
406
+ const full = /^([A-Za-z])(\d+)$/.exec(trimmed);
407
+ if (full !== null) {
408
+ const id = `${(full[1] ?? "").toUpperCase()}${Number.parseInt(full[2] ?? "", 10)}`;
409
+ return (scenario) => scenario.id === id;
410
+ }
411
+ const bare = /^(\d+)$/.exec(trimmed);
412
+ if (bare !== null) {
413
+ const wanted = Number.parseInt(bare[1] ?? "", 10);
414
+ return (scenario) => scenario.number === wanted;
415
+ }
416
+ return null;
417
+ }
418
+
419
+ async function resolveWorkspaceOverride(workspace: string | undefined): Promise<string | null | { error: string }> {
420
+ if (workspace === undefined) return null;
421
+ const resolved = resolve(workspace);
422
+ try {
423
+ const info = await stat(resolved);
424
+ if (!info.isDirectory()) return { error: `--workspace is not a directory: ${resolved}` };
425
+ return resolved;
426
+ } catch (error) {
427
+ const detail = error instanceof Error ? error.message : String(error);
428
+ return { error: `--workspace is not readable: ${resolved}: ${detail}` };
429
+ }
430
+ }
431
+
432
+ async function runScenario(
433
+ skillName: string,
434
+ skillBaseDir: string,
435
+ scenario: SkillEvalScenario,
436
+ target: string | undefined,
437
+ timeoutMs: number,
438
+ workspaceOverride: string | null,
439
+ trustFixtures: boolean,
440
+ childEnv: NodeJS.ProcessEnv,
441
+ ): Promise<ScenarioOutcome> {
442
+ // Published per-scenario figure: monotonic so a clock correction during a
443
+ // long sweep cannot land in one row's wall time.
444
+ const scenarioStart = performance.now();
445
+ const workspace = await mkdtemp(join(tmpdir(), "clio-skill-eval-seed-"));
446
+ let runWorkspaces: MaterializedSkillEvalWorkspaces | null = null;
447
+ try {
448
+ if (workspaceOverride !== null) await copyWorkspace(workspaceOverride, workspace);
449
+ const fixtureError = await runFixtureCommands(scenario, workspace, timeoutMs, trustFixtures);
450
+ if (fixtureError !== null) {
451
+ return await completeScenarioOutcome({
452
+ scenario,
453
+ bullets: errorBullets(scenario, fixtureError),
454
+ baseline: null,
455
+ treatment: null,
456
+ judge: null,
457
+ workspace,
458
+ wallTimeMs: Math.round(performance.now() - scenarioStart),
459
+ infraError: fixtureError,
460
+ });
461
+ }
462
+ runWorkspaces = await materializeSkillEvalWorkspaces(workspace);
463
+ const baseline = await captureHeadlessRun(
464
+ armRunArgs("baseline", scenario.setup, { target }),
465
+ runWorkspaces.baseline,
466
+ timeoutMs,
467
+ childEnv,
468
+ );
469
+ const treatment = await captureHeadlessRun(
470
+ armRunArgs("treatment", `/skill ${skillName} ${scenario.setup}`, { target, skillBaseDir }),
471
+ runWorkspaces.treatment,
472
+ timeoutMs,
473
+ childEnv,
474
+ );
475
+ const infra = runInfraError("baseline", baseline) ?? runInfraError("treatment", treatment);
476
+ if (infra !== null) {
477
+ return await completeScenarioOutcome({
478
+ scenario,
479
+ bullets: errorBullets(scenario, infra),
480
+ baseline,
481
+ treatment,
482
+ judge: null,
483
+ workspace,
484
+ wallTimeMs: Math.round(performance.now() - scenarioStart),
485
+ infraError: infra,
486
+ });
487
+ }
488
+ // An arm the harness itself blocked is scored by nobody: spending a judge
489
+ // run on those transcripts would only buy well-reasoned verdicts about
490
+ // the permission wall.
491
+ const wall = permissionWallReason("baseline", baseline) ?? permissionWallReason("treatment", treatment);
492
+ if (wall !== null) {
493
+ return await completeScenarioOutcome({
494
+ scenario,
495
+ bullets: unmeasuredBullets(scenario, wall),
496
+ baseline,
497
+ treatment,
498
+ judge: null,
499
+ workspace,
500
+ wallTimeMs: Math.round(performance.now() - scenarioStart),
501
+ infraError: wall,
502
+ });
503
+ }
504
+ // The judge also runs with --json: a model that ends the turn through a
505
+ // terminating tool (artifact plan/review/report) prints only that tool's
506
+ // result line in text mode, while the event stream carries the artifact
507
+ // content the verdict may live in.
508
+ const judge = await captureHeadlessRun(
509
+ armRunArgs("judge", judgePrompt(scenario, baseline.transcript, treatment.transcript), { target }),
510
+ runWorkspaces.judge,
511
+ timeoutMs,
512
+ childEnv,
513
+ );
514
+ const judgeInfra = runInfraError("judge", judge);
515
+ if (judgeInfra !== null) {
516
+ return await completeScenarioOutcome({
517
+ scenario,
518
+ bullets: errorBullets(scenario, judgeInfra),
519
+ baseline,
520
+ treatment,
521
+ judge,
522
+ workspace,
523
+ wallTimeMs: Math.round(performance.now() - scenarioStart),
524
+ infraError: judgeInfra,
525
+ });
526
+ }
527
+ const bullets = parseJudgeVerdicts(scenario, judge);
528
+ return await completeScenarioOutcome({
529
+ scenario,
530
+ bullets,
531
+ baseline,
532
+ treatment,
533
+ judge,
534
+ workspace,
535
+ wallTimeMs: Math.round(performance.now() - scenarioStart),
536
+ infraError: null,
537
+ });
538
+ } finally {
539
+ try {
540
+ if (runWorkspaces !== null) await runWorkspaces.cleanup();
541
+ } finally {
542
+ await rm(workspace, { recursive: true, force: true });
543
+ }
544
+ }
545
+ }
546
+
547
+ export interface MaterializedSkillEvalWorkspaces {
548
+ baseline: string;
549
+ treatment: string;
550
+ judge: string;
551
+ cleanup(): Promise<void>;
552
+ }
553
+
554
+ /**
555
+ * One private root per arm, with the arm's workspace nested inside it.
556
+ *
557
+ * The arms used to be three `mkdtemp` directories sitting side by side in the
558
+ * system temp dir, named `...-baseline-`, `...-treatment-` and `...-judge-`.
559
+ * A full-auto run in one arm could therefore reach the others in a single
560
+ * relative step, and the names said which was which, so a treatment run could
561
+ * read the baseline it is supposed to be measured against. Nesting each
562
+ * workspace one level down under a neutrally-named private root means `..`
563
+ * from a workspace shows only that arm.
564
+ *
565
+ * This raises the cost of crossing arms; it is not containment. Nothing here
566
+ * confines a run to its workspace, because the write boundary is a per-run
567
+ * tool policy and not something the eval harness can impose on a child
568
+ * process it spawns. An arm that walks the system temp dir can still find the
569
+ * others. Treat eval results from a full-auto run as evidence about a
570
+ * cooperative model, not as an isolation guarantee.
571
+ */
572
+ async function armWorkspace(created: string[]): Promise<string> {
573
+ const root = await mkdtemp(join(tmpdir(), "clio-skill-eval-"));
574
+ created.push(root);
575
+ const workspace = join(root, "workspace");
576
+ await mkdir(workspace, { recursive: true });
577
+ return workspace;
578
+ }
579
+
580
+ /** @internal Exported for contract tests. */
581
+ export async function materializeSkillEvalWorkspaces(seedWorkspace: string): Promise<MaterializedSkillEvalWorkspaces> {
582
+ const created: string[] = [];
583
+ try {
584
+ const baseline = await armWorkspace(created);
585
+ const treatment = await armWorkspace(created);
586
+ const judge = await armWorkspace(created);
587
+ await Promise.all([copyWorkspace(seedWorkspace, baseline), copyWorkspace(seedWorkspace, treatment)]);
588
+ return {
589
+ baseline,
590
+ treatment,
591
+ judge,
592
+ cleanup: async () => {
593
+ await Promise.all(created.map((path) => rm(path, { recursive: true, force: true })));
594
+ },
595
+ };
596
+ } catch (error) {
597
+ await Promise.all(created.map((path) => rm(path, { recursive: true, force: true })));
598
+ throw error;
599
+ }
600
+ }
601
+
602
+ async function copyWorkspace(source: string, destination: string): Promise<void> {
603
+ await cp(source, destination, {
604
+ recursive: true,
605
+ preserveTimestamps: true,
606
+ verbatimSymlinks: true,
607
+ });
608
+ }
609
+
610
+ async function completeScenarioOutcome(outcome: Omit<ScenarioOutcome, "usage">): Promise<ScenarioOutcome> {
611
+ return {
612
+ ...outcome,
613
+ usage: await usageForCapturedRuns([outcome.baseline, outcome.treatment, outcome.judge]),
614
+ };
615
+ }
616
+
617
+ async function runFixtureCommands(
618
+ scenario: SkillEvalScenario,
619
+ workspace: string,
620
+ timeoutMs: number,
621
+ trustFixtures: boolean,
622
+ ): Promise<string | null> {
623
+ const commands = scenario.fixtureCommands?.trim();
624
+ if (commands === undefined || commands.length === 0) return null;
625
+ if (!trustFixtures) {
626
+ return "scenario declares fixture commands, which are real shell from the skill's evals.md; review them and rerun with --trust-fixtures";
627
+ }
628
+ const validationError = validateFixtureCommands(commands);
629
+ if (validationError !== null) return `fixture setup rejected: ${validationError}`;
630
+ const result = await runBashCommand(commands, {
631
+ cwd: workspace,
632
+ timeoutMs: Math.min(timeoutMs, 120_000),
633
+ });
634
+ const output = combineBashOutput(result).trim();
635
+ if (result.timedOut) return `fixture setup timed out${output.length > 0 ? `: ${truncate(output, 300)}` : ""}`;
636
+ if (result.outputCapped) {
637
+ return `fixture setup output exceeded limit${output.length > 0 ? `: ${truncate(output, 300)}` : ""}`;
638
+ }
639
+ if (result.error !== null) {
640
+ return `fixture setup failed${output.length > 0 ? `: ${truncate(output, 300)}` : `: ${result.error.message}`}`;
641
+ }
642
+ return null;
643
+ }
644
+
645
+ /**
646
+ * Best-effort lint over trusted fixture scripts, not a sandbox: fixtures only
647
+ * run behind --trust-fixtures, and these checks exist to catch obvious
648
+ * workspace escapes in otherwise-reviewed scripts (shell is not reliably
649
+ * classifiable by regex).
650
+ */
651
+ function validateFixtureCommands(commands: string): string | null {
652
+ const checks: Array<{ pattern: RegExp; reason: string }> = [
653
+ {
654
+ pattern: /(^|[\s;&|(<>='"`])\/(?!dev\/null(?:\s|$))(?=\S)/,
655
+ reason: "absolute paths are not allowed in fixture commands",
656
+ },
657
+ {
658
+ pattern: /(^|[\s;&|()'"`/=])\.\.(?=$|[/\s;&|()'"`])/,
659
+ reason: "parent-directory path segments are not allowed in fixture commands",
660
+ },
661
+ {
662
+ pattern: /(^|[\s;&|()])~(?=$|[/\s;&|()])/,
663
+ reason: "home-directory expansion is not allowed in fixture commands",
664
+ },
665
+ {
666
+ pattern:
667
+ /\$(?:\{(?:HOME|CLIO_CODER_HOME|CLIO_CODER_CONFIG_DIR|CLIO_CODER_DATA_DIR|CLIO_CODER_STATE_DIR|CLIO_CODER_CACHE_DIR)\}|(?:HOME|CLIO_CODER_HOME|CLIO_CODER_CONFIG_DIR|CLIO_CODER_DATA_DIR|CLIO_CODER_STATE_DIR|CLIO_CODER_CACHE_DIR)\b)/,
668
+ reason: "home and Clio directory environment variables are not allowed in fixture commands",
669
+ },
670
+ {
671
+ pattern: /(^|[\s;&|()])(?:cd|pushd|popd)\b/,
672
+ reason: "directory-changing commands are not allowed in fixture commands",
673
+ },
674
+ {
675
+ pattern: /(^|[\s;&|()])(?:sudo|su|ssh|scp|rsync)\b/,
676
+ reason: "privilege-changing or remote commands are not allowed in fixture commands",
677
+ },
678
+ ];
679
+ for (const check of checks) {
680
+ if (check.pattern.test(commands)) return check.reason;
681
+ }
682
+ return null;
683
+ }
684
+
685
+ async function usageForCapturedRuns(runs: ReadonlyArray<CapturedRun | null>): Promise<ScenarioUsage> {
686
+ const sessionIds = new Set(
687
+ runs.flatMap((run) => (run?.sessionId !== null && run?.sessionId !== undefined ? [run.sessionId] : [])),
688
+ );
689
+ const usage: ScenarioUsage = {
690
+ tokens: 0,
691
+ costUsd: 0,
692
+ harness: { ...ZERO_EVAL_HARNESS_METRICS },
693
+ };
694
+ if (sessionIds.size === 0) return usage;
695
+ const receiptRoot = join(clioStateDir(), "receipts");
696
+ let files: string[];
697
+ try {
698
+ files = (await readdir(receiptRoot)).filter((name) => name.endsWith(".json"));
699
+ } catch {
700
+ return usage;
701
+ }
702
+ for (const file of files) {
703
+ let parsed: unknown;
704
+ try {
705
+ parsed = JSON.parse(await readFile(join(receiptRoot, file), "utf8"));
706
+ } catch {
707
+ continue;
708
+ }
709
+ if (!isRecord(parsed) || typeof parsed.sessionId !== "string" || !sessionIds.has(parsed.sessionId)) continue;
710
+ usage.tokens += readNumber(parsed.tokenCount);
711
+ usage.costUsd += readNumber(parsed.costUsd);
712
+ usage.harness.receiptCount += 1;
713
+ usage.harness.toolCalls += readNumber(parsed.toolCalls);
714
+ if (isRecord(parsed.safety) && isRecord(parsed.safety.decisions)) {
715
+ usage.harness.safetyBlocks += readNumber(parsed.safety.decisions.blocked);
716
+ }
717
+ }
718
+ return usage;
719
+ }
720
+
721
+ function runInfraError(label: string, run: CapturedRun): string | null {
722
+ if (run.timedOut) return `${label} run timed out`;
723
+ if (run.exitCode !== 0) {
724
+ const detail = run.stderr.trim().split("\n").at(-1) ?? "";
725
+ return `${label} run exited ${run.exitCode}${detail.length > 0 ? `: ${detail}` : ""}`;
726
+ }
727
+ if (run.transcript.trim().length === 0 && run.finalText.trim().length === 0) {
728
+ return `${label} run produced no transcript`;
729
+ }
730
+ return null;
731
+ }
732
+
733
+ function errorBullets(scenario: SkillEvalScenario, reason: string): ScoredBullet[] {
734
+ return scenario.expected.map((text, index) => ({ index: index + 1, text, verdict: "error", reason }));
735
+ }
736
+
737
+ function captureHeadlessRun(
738
+ args: ReadonlyArray<string>,
739
+ cwd: string,
740
+ timeoutMs: number,
741
+ env: NodeJS.ProcessEnv,
742
+ ): Promise<CapturedRun> {
743
+ const startedMs = performance.now();
744
+ return new Promise((resolvePromise) => {
745
+ let stdout = "";
746
+ let pendingStdout = "";
747
+ let stderr = "";
748
+ let timedOut = false;
749
+ let settled = false;
750
+ const keepLine = (line: string): void => {
751
+ if (line.length === 0) return;
752
+ if (stdout.length < CHILD_OUTPUT_LIMIT) stdout += `${line}\n`;
753
+ };
754
+ const child = spawn(process.execPath, [process.argv[1] ?? "", ...args], {
755
+ cwd,
756
+ stdio: ["ignore", "pipe", "pipe"],
757
+ env,
758
+ });
759
+ child.stdout.setEncoding("utf8");
760
+ child.stderr.setEncoding("utf8");
761
+ child.stdout.on("data", (chunk: string) => {
762
+ pendingStdout += chunk;
763
+ const lines = pendingStdout.split("\n");
764
+ pendingStdout = lines.pop() ?? "";
765
+ for (const line of lines) keepLine(line);
766
+ });
767
+ child.stderr.on("data", (chunk: string) => {
768
+ if (stderr.length < CHILD_OUTPUT_LIMIT) stderr += chunk;
769
+ });
770
+ let killTimer: NodeJS.Timeout | undefined;
771
+ const timer = setTimeout(() => {
772
+ timedOut = true;
773
+ child.kill("SIGTERM");
774
+ killTimer = setTimeout(() => child.kill("SIGKILL"), 5_000);
775
+ }, timeoutMs);
776
+ const finish = (exitCode: number): void => {
777
+ if (settled) return;
778
+ settled = true;
779
+ clearTimeout(timer);
780
+ if (killTimer !== undefined) clearTimeout(killTimer);
781
+ keepLine(pendingStdout);
782
+ pendingStdout = "";
783
+ const parsedRun = parseRunStdout(stdout);
784
+ resolvePromise({
785
+ ...parsedRun,
786
+ exitCode,
787
+ timedOut,
788
+ wallTimeMs: Math.round(performance.now() - startedMs),
789
+ stderr,
790
+ });
791
+ };
792
+ child.on("error", (error) => {
793
+ stderr += `\n${error.message}`;
794
+ finish(1);
795
+ });
796
+ child.on("close", (code) => finish(typeof code === "number" ? code : timedOut ? 124 : 1));
797
+ });
798
+ }
799
+
800
+ /**
801
+ * Fold a headless run's stdout into a compact transcript. `--json` runs emit
802
+ * one terminal JSONL event per line (session header, message_end,
803
+ * tool_execution_*, turn_start, turn_end);
804
+ * text-mode runs emit the final assistant text, which passes through as-is.
805
+ */
806
+ /**
807
+ * True for the `context` call that delivers a skill's body:
808
+ * `context(scope="skills", name=<skill>)`. Without a name the same scope only
809
+ * lists what is available, which carries no instructions.
810
+ */
811
+ function loadsSkillBody(tool: string, args: unknown): boolean {
812
+ if (tool !== "context" || !isRecord(args)) return false;
813
+ return args.scope === "skills" && typeof args.name === "string" && args.name.trim().length > 0;
814
+ }
815
+
816
+ /** @internal Exported for contract tests. */
817
+ export function parseRunStdout(stdout: string): { sessionId: string | null; transcript: string; finalText: string } {
818
+ let sessionId: string | null = null;
819
+ const lines: string[] = [];
820
+ let finalText = "";
821
+ let sawJson = false;
822
+ const streamedText = new Map<number, string>();
823
+ // Tool calls whose result is the skill's own SKILL.md. Correlated by
824
+ // toolCallId, which both the start and end events carry.
825
+ const skillBodyCallIds = new Set<string>();
826
+ for (const line of stdout.split("\n")) {
827
+ if (line.trim().length === 0) continue;
828
+ let event: unknown;
829
+ try {
830
+ event = JSON.parse(line);
831
+ } catch {
832
+ continue;
833
+ }
834
+ if (!isRecord(event)) continue;
835
+ sawJson = true;
836
+ if (event.type === "session" && typeof event.id === "string") {
837
+ sessionId = event.id;
838
+ continue;
839
+ }
840
+ if (event.type === "text_delta" && typeof event.delta === "string") {
841
+ const contentIndex = typeof event.contentIndex === "number" ? event.contentIndex : 0;
842
+ streamedText.set(contentIndex, `${streamedText.get(contentIndex) ?? ""}${event.delta}`);
843
+ continue;
844
+ }
845
+ if (event.type === "tool_execution_start") {
846
+ const tool = readString(event.toolName) ?? readString(event.tool) ?? "tool";
847
+ const args = event.args ?? event.arguments ?? event.input;
848
+ const callId = readString(event.toolCallId);
849
+ if (callId !== null && loadsSkillBody(tool, args)) skillBodyCallIds.add(callId);
850
+ lines.push(`TOOL ${tool} args=${preview(args)}`);
851
+ // Terminating tools end the turn with no assistant text; their content
852
+ // IS the answer, so keep it whole (the judge verdict may live here).
853
+ if (tool === "artifact" && isRecord(args) && typeof args.content === "string") {
854
+ lines.push(`TERMINAL ${tool} content:\n${args.content}`);
855
+ }
856
+ continue;
857
+ }
858
+ if (event.type === "tool_execution_end") {
859
+ const tool = readString(event.toolName) ?? readString(event.tool) ?? "tool";
860
+ const status = event.isError === true ? "error" : "ok";
861
+ const callId = readString(event.toolCallId);
862
+ // The skill body is the instructions, not the behavior. Left in the
863
+ // transcript it is the easiest thing in the run for a judge to quote,
864
+ // and a 30B judge scored bullets as passing from SKILL.md prose that
865
+ // the model had only read, never acted on. The load still shows, so
866
+ // "did it load the skill" stays checkable.
867
+ if (callId !== null && skillBodyCallIds.has(callId)) {
868
+ lines.push(`RESULT ${tool} ${status}: <skill body withheld from the judge>`);
869
+ continue;
870
+ }
871
+ lines.push(`RESULT ${tool} ${status}: ${preview(event.result)}`);
872
+ continue;
873
+ }
874
+ if (event.type === "message_end" && isRecord(event.message) && event.message.role === "assistant") {
875
+ const content = Array.isArray(event.message.content) ? event.message.content : [];
876
+ const completedText = content
877
+ .filter((item): item is { type: "text"; text: string } => {
878
+ return isRecord(item) && item.type === "text" && typeof item.text === "string";
879
+ })
880
+ .map((item) => item.text)
881
+ .join("")
882
+ .trim();
883
+ const streamed = [...streamedText.entries()]
884
+ .sort(([left], [right]) => left - right)
885
+ .map(([, text]) => text)
886
+ .join("")
887
+ .trim();
888
+ streamedText.clear();
889
+ const text = completedText.length > 0 ? completedText : streamed;
890
+ if (text.length > 0) {
891
+ lines.push(`ASSISTANT: ${text}`);
892
+ finalText = text;
893
+ }
894
+ }
895
+ }
896
+ if (!sawJson) {
897
+ const text = stdout.trim();
898
+ return { sessionId: null, transcript: text, finalText: text };
899
+ }
900
+ return { sessionId, transcript: elide(lines.join("\n")), finalText };
901
+ }
902
+
903
+ function judgePrompt(scenario: SkillEvalScenario, baselineTranscript: string, treatmentTranscript: string): string {
904
+ const bullets = scenario.expected.map((text, index) => `${index + 1}. ${text}`).join("\n");
905
+ return [
906
+ "You are scoring a skill evaluation. Two transcripts follow: BASELINE ran without the skill, TREATMENT ran with the skill loaded.",
907
+ "Score each EXPECTED bullet strictly against the TREATMENT transcript; the baseline exists only for gap context.",
908
+ "A bullet passes only if the treatment transcript observably satisfies it; anything unverifiable from the transcript fails.",
909
+ 'Reply with STRICT JSON only, no prose and no code fences, exactly: {"bullets":[{"index":1,"pass":true,"reason":"<= 25 words"}]}',
910
+ `Include one entry per bullet, indexes 1 through ${scenario.expected.length} in order.`,
911
+ "Do not use any tools. Respond with the JSON verdict directly.",
912
+ "",
913
+ `SCENARIO ${scenario.id} - ${scenario.title}`,
914
+ `SETUP: ${scenario.setup}`,
915
+ "",
916
+ "EXPECTED BULLETS:",
917
+ bullets,
918
+ "",
919
+ "BASELINE TRANSCRIPT:",
920
+ baselineTranscript.length > 0 ? baselineTranscript : "(empty)",
921
+ "",
922
+ "TREATMENT TRANSCRIPT:",
923
+ treatmentTranscript.length > 0 ? treatmentTranscript : "(empty)",
924
+ ].join("\n");
925
+ }
926
+
927
+ /**
928
+ * Why a judge response carried no verdict, named after the thing that failed.
929
+ * A response that opened a bullets object and never closed it is the observed
930
+ * truncation on small local models; a response with no bullets key at all
931
+ * never started one. Neither is evidence about the skill.
932
+ */
933
+ function judgeVerdictAbsenceReason(judge: CapturedRun): string {
934
+ const sawBulletsKey = `${judge.finalText}\n${judge.transcript}`.includes('"bullets"');
935
+ return sawBulletsKey
936
+ ? "judge response truncated mid-verdict (no complete bullets object): bullet not scored"
937
+ : "judge response carried no parseable verdict object: bullet not scored";
938
+ }
939
+
940
+ /** Exported for contracts tests. */
941
+ export function parseJudgeVerdicts(scenario: SkillEvalScenario, judge: CapturedRun): ScoredBullet[] {
942
+ const parsed = extractBulletsObject(judge.finalText) ?? extractBulletsObject(judge.transcript);
943
+ // No verdict object anywhere in the judge run. The scenario was not scored,
944
+ // which is a fact about the judge, so every bullet stays unmeasured rather
945
+ // than collecting a verdict nothing produced.
946
+ if (parsed === null) {
947
+ const reason = judgeVerdictAbsenceReason(judge);
948
+ return scenario.expected.map((text, i) => ({ index: i + 1, text, verdict: "unmeasured" as const, reason }));
949
+ }
950
+ const entries = new Map<number, { pass: boolean; reason: string }>();
951
+ if (Array.isArray(parsed.bullets)) {
952
+ for (const item of parsed.bullets) {
953
+ if (!isRecord(item)) continue;
954
+ const index = typeof item.index === "number" ? item.index : Number.parseInt(String(item.index), 10);
955
+ if (!Number.isInteger(index)) continue;
956
+ entries.set(index, {
957
+ pass: item.pass === true,
958
+ reason: readString(item.reason) ?? "",
959
+ });
960
+ }
961
+ }
962
+ return scenario.expected.map((text, i) => {
963
+ const index = i + 1;
964
+ const entry = entries.get(index);
965
+ if (entry === undefined) {
966
+ // The judge scored other bullets and skipped this one, so this bullet
967
+ // has no verdict either. Same state, narrower cause.
968
+ return {
969
+ index,
970
+ text,
971
+ verdict: "unmeasured" as const,
972
+ reason: "judge output omitted this bullet: bullet not scored",
973
+ };
974
+ }
975
+ return { index, text, verdict: entry.pass ? ("pass" as const) : ("fail" as const), reason: entry.reason };
976
+ });
977
+ }
978
+
979
+ /**
980
+ * Find the JSON object carrying the judge's `bullets` array anywhere in the
981
+ * text: models wrap verdicts in prose, code fences, or terminating tool
982
+ * content, so this walks candidate `{` openers around the first "bullets" key
983
+ * and balance-scans to the matching close brace.
984
+ */
985
+ export function extractBulletsObject(text: string): Record<string, unknown> | null {
986
+ const stripped = text.replace(/```(?:json)?/g, "");
987
+ const bulletsAt = stripped.indexOf('"bullets"');
988
+ if (bulletsAt < 0) return null;
989
+ let start = stripped.lastIndexOf("{", bulletsAt);
990
+ while (start >= 0) {
991
+ const candidate = balancedJsonSlice(stripped, start);
992
+ if (candidate !== null) {
993
+ try {
994
+ const parsed = JSON.parse(candidate) as unknown;
995
+ if (isRecord(parsed) && Array.isArray(parsed.bullets)) return parsed;
996
+ } catch {
997
+ // Try the next opener out.
998
+ }
999
+ }
1000
+ // lastIndexOf clamps a negative fromIndex to 0, so stepping from 0 would
1001
+ // loop forever on a leading brace.
1002
+ if (start === 0) break;
1003
+ start = stripped.lastIndexOf("{", start - 1);
1004
+ }
1005
+ return null;
1006
+ }
1007
+
1008
+ /** Slice a balanced {...} region starting at `start`, string-aware. */
1009
+ function balancedJsonSlice(text: string, start: number): string | null {
1010
+ let depth = 0;
1011
+ let inString = false;
1012
+ let escaped = false;
1013
+ for (let i = start; i < text.length; i += 1) {
1014
+ const ch = text[i];
1015
+ if (escaped) {
1016
+ escaped = false;
1017
+ continue;
1018
+ }
1019
+ if (ch === "\\") {
1020
+ if (inString) escaped = true;
1021
+ continue;
1022
+ }
1023
+ if (ch === '"') {
1024
+ inString = !inString;
1025
+ continue;
1026
+ }
1027
+ if (inString) continue;
1028
+ if (ch === "{") depth += 1;
1029
+ else if (ch === "}") {
1030
+ depth -= 1;
1031
+ if (depth === 0) return text.slice(start, i + 1);
1032
+ }
1033
+ }
1034
+ return null;
1035
+ }
1036
+
1037
+ function synthesizeArtifact(
1038
+ skillName: string,
1039
+ evalsPath: string,
1040
+ evalsRaw: string,
1041
+ startedAt: string,
1042
+ endedAt: string,
1043
+ outcomes: ReadonlyArray<ScenarioOutcome>,
1044
+ target: string | undefined,
1045
+ ): EvalRunArtifact {
1046
+ const contentHash = createHash("sha256").update(evalsRaw, "utf8").digest("hex");
1047
+ const stamp = startedAt.replace(/[-:.]/g, "");
1048
+ // Random suffix for the same reason createEvalId carries one: the stamp plus
1049
+ // content hash collides between two workers on the same file in one millisecond,
1050
+ // and the id is the artifact filename.
1051
+ const evalId = `skill-${skillName}-${stamp}-${contentHash.slice(0, 8)}-${randomBytes(6).toString("hex")}`;
1052
+ const results: EvalRunRecord[] = outcomes.map((outcome) => {
1053
+ const failed = outcome.bullets.some((bullet) => bullet.verdict === "fail" || bullet.verdict === "error");
1054
+ const unmeasured = outcome.bullets.some((bullet) => bullet.verdict === "unmeasured");
1055
+ const pass = outcome.bullets.length > 0 && !failed && !unmeasured;
1056
+ const record: EvalRunRecord = {
1057
+ taskId: outcome.scenario.id,
1058
+ runId: `${evalId}-${outcome.scenario.id}`,
1059
+ repeatIndex: 0,
1060
+ cwd: outcome.workspace,
1061
+ prompt: outcome.scenario.setup,
1062
+ tags: [
1063
+ "skill-eval",
1064
+ `skill:${skillName}`,
1065
+ ...(unmeasured ? ["scenario:unmeasured"] : []),
1066
+ ...outcome.bullets.map((bullet) => `bullet-${bullet.index}:${bullet.verdict}`),
1067
+ ],
1068
+ pass,
1069
+ // 3, not 1, when the scenario carries an unscored bullet and no failed
1070
+ // one: a reader who sees exitCode 1 with failureClass verifier_failed
1071
+ // reads "this skill failed its rubric", and an unscored bullet is the
1072
+ // judge's silence, not the skill's answer.
1073
+ exitCode: pass ? 0 : failed ? 1 : 3,
1074
+ tokens: outcome.usage.tokens,
1075
+ costUsd: outcome.usage.costUsd,
1076
+ wallTimeMs: outcome.wallTimeMs,
1077
+ harness: outcome.usage.harness,
1078
+ commands: [],
1079
+ };
1080
+ if (failed) record.failureClass = "verifier_failed";
1081
+ return record;
1082
+ });
1083
+ return {
1084
+ version: 1,
1085
+ evalId,
1086
+ taskFile: evalsPath,
1087
+ taskFileHash: contentHash,
1088
+ clio: evalClioProvenance(),
1089
+ environment: evalEnvironmentProvenance(),
1090
+ target: target ?? null,
1091
+ model: null,
1092
+ thinking: null,
1093
+ paths: { taskFile: evalsPath, receipts: [], sessionLedgers: [] },
1094
+ repeat: 1,
1095
+ startedAt,
1096
+ endedAt,
1097
+ summary: summarizeEvalResults(results),
1098
+ results,
1099
+ };
1100
+ }
1101
+
1102
+ function sidecar(
1103
+ skillName: string,
1104
+ evalId: string,
1105
+ outcomes: ReadonlyArray<ScenarioOutcome>,
1106
+ allowNetwork: boolean,
1107
+ ): unknown {
1108
+ return {
1109
+ version: 1,
1110
+ schema: "experimental",
1111
+ kind: "skill-eval",
1112
+ skill: skillName,
1113
+ evalId,
1114
+ network: networkPolicyLabel(allowNetwork),
1115
+ autonomy: ARM_AUTONOMY,
1116
+ deltas: [
1117
+ "bullet verdicts are judge-scored from run transcripts, not command exit codes; the evals-domain artifact carries scenario-level records with empty command lists",
1118
+ "a bullet the judge never scored is recorded unmeasured, not failed: its scenario record is pass:false with exitCode 3 and no failureClass",
1119
+ "an arm whose transcript carries the headless permission wall is recorded unmeasured with an infraError: the harness's own gate is not a verdict about the skill",
1120
+ "tokens and cost are rolled up from headless main-agent receipts when those receipts are present",
1121
+ "this sidecar is additive and is registered in overview.json files[]",
1122
+ ],
1123
+ scenarios: outcomes.map((outcome) => ({
1124
+ id: outcome.scenario.id,
1125
+ title: outcome.scenario.title,
1126
+ setup: outcome.scenario.setup,
1127
+ fixtureCommands: outcome.scenario.fixtureCommands ?? null,
1128
+ infraError: outcome.infraError,
1129
+ usage: outcome.usage,
1130
+ bullets: outcome.bullets,
1131
+ baseline: sidecarRun(outcome.baseline),
1132
+ treatment: sidecarRun(outcome.treatment),
1133
+ judge: sidecarRun(outcome.judge),
1134
+ })),
1135
+ };
1136
+ }
1137
+
1138
+ function sidecarRun(run: CapturedRun | null): unknown {
1139
+ if (run === null) return null;
1140
+ return {
1141
+ sessionId: run.sessionId,
1142
+ exitCode: run.exitCode,
1143
+ timedOut: run.timedOut,
1144
+ wallTimeMs: run.wallTimeMs,
1145
+ transcript: run.transcript,
1146
+ stderrTail: run.stderr.slice(-500),
1147
+ };
1148
+ }
1149
+
1150
+ function printHumanReport(
1151
+ skillName: string,
1152
+ outcomes: ReadonlyArray<ScenarioOutcome>,
1153
+ evalId: string,
1154
+ evidenceId: string | null,
1155
+ evidenceDirectory: string | null,
1156
+ allowNetwork: boolean,
1157
+ ): void {
1158
+ const rows: string[][] = [["scenario", "bullet", "verdict", "expected"]];
1159
+ for (const outcome of outcomes) {
1160
+ for (const bullet of outcome.bullets) {
1161
+ rows.push([outcome.scenario.id, String(bullet.index), bullet.verdict, truncate(bullet.text, 76)]);
1162
+ }
1163
+ }
1164
+ process.stdout.write(formatColumns(rows));
1165
+ const total = outcomes.reduce((sum, outcome) => sum + outcome.bullets.length, 0);
1166
+ const passed = outcomes.reduce(
1167
+ (sum, outcome) => sum + outcome.bullets.filter((bullet) => bullet.verdict === "pass").length,
1168
+ 0,
1169
+ );
1170
+ const unmeasured = outcomes.reduce(
1171
+ (sum, outcome) => sum + outcome.bullets.filter((bullet) => bullet.verdict === "unmeasured").length,
1172
+ 0,
1173
+ );
1174
+ // The denominator counts bullets the judge never scored, so it says how many
1175
+ // passed out of how many were asked, not out of how many were answered. The
1176
+ // unscored count is stated beside it rather than folded into the failures.
1177
+ const unmeasuredNote = unmeasured > 0 ? `, ${unmeasured} unmeasured` : "";
1178
+ process.stdout.write(
1179
+ `\n${skillName}: ${passed}/${total} bullets passed${unmeasuredNote} (judge-scored, experimental)\n`,
1180
+ );
1181
+ if (unmeasured > 0) {
1182
+ process.stdout.write(
1183
+ unmeasured === total
1184
+ ? "no bullet was scored, so this run is not evidence about the skill either way\n"
1185
+ : `${unmeasured} of ${total} bullets were never scored; unmeasured is not a failed bullet\n`,
1186
+ );
1187
+ }
1188
+ for (const outcome of outcomes) {
1189
+ if (outcome.infraError !== null) {
1190
+ process.stdout.write(`${outcome.scenario.id}: infra error: ${outcome.infraError}\n`);
1191
+ continue;
1192
+ }
1193
+ for (const bullet of outcome.bullets.filter((item) => item.verdict !== "pass")) {
1194
+ process.stdout.write(
1195
+ `${outcome.scenario.id} bullet ${bullet.index} ${bullet.verdict}${bullet.reason.length > 0 ? `: ${bullet.reason}` : ""}\n`,
1196
+ );
1197
+ }
1198
+ }
1199
+ process.stdout.write(`${describeArmPolicyOutcome(allowNetwork)}\n`);
1200
+ process.stdout.write(`eval artifact: ${evalId}\n`);
1201
+ if (evidenceId !== null && evidenceDirectory !== null) {
1202
+ process.stdout.write(`evidence: ${evidenceId} at ${evidenceDirectory} (per-bullet detail in skill-eval.json)\n`);
1203
+ }
1204
+ }
1205
+
1206
+ function preview(value: unknown): string {
1207
+ if (value === undefined) return "";
1208
+ const text = typeof value === "string" ? value : safeStringify(value);
1209
+ return truncate(text.replace(/\s+/g, " ").trim(), PREVIEW_MAX_CHARS);
1210
+ }
1211
+
1212
+ function safeStringify(value: unknown): string {
1213
+ try {
1214
+ return JSON.stringify(value) ?? "";
1215
+ } catch {
1216
+ return String(value);
1217
+ }
1218
+ }
1219
+
1220
+ function elide(text: string): string {
1221
+ if (text.length <= TRANSCRIPT_HEAD_CHARS + TRANSCRIPT_TAIL_CHARS) return text;
1222
+ return `${text.slice(0, TRANSCRIPT_HEAD_CHARS)}\n[... transcript elided ...]\n${text.slice(-TRANSCRIPT_TAIL_CHARS)}`;
1223
+ }
1224
+
1225
+ function truncate(text: string, maxChars: number): string {
1226
+ if (text.length <= maxChars) return text;
1227
+ return `${text.slice(0, Math.max(0, maxChars - 3))}...`;
1228
+ }
1229
+
1230
+ function readString(value: unknown): string | null {
1231
+ return typeof value === "string" && value.length > 0 ? value : null;
1232
+ }
1233
+
1234
+ function readNumber(value: unknown): number {
1235
+ return typeof value === "number" && Number.isFinite(value) ? value : 0;
1236
+ }
1237
+
1238
+ function isRecord(value: unknown): value is Record<string, unknown> {
1239
+ return typeof value === "object" && value !== null && !Array.isArray(value);
1240
+ }