@iowarp/clio-coder 0.3.7 → 0.3.9

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 (400) hide show
  1. package/CHANGELOG.md +80 -0
  2. package/README.md +13 -4
  3. package/dist/{acp-SK4MD6MM.js → acp-7LOELQFP.js} +13 -13
  4. package/dist/{agents-2FN2K6ME.js → agents-FIBG2SHA.js} +41 -37
  5. package/dist/assets/codewiki.json +1 -1
  6. package/dist/{auth-QIYZWM5I.js → auth-OI4LIH2I.js} +31 -24
  7. package/dist/builtins-AD25UL3C.js +17 -0
  8. package/dist/{chunk-5FR74PWO.js → chunk-2JDWVJND.js} +2 -2
  9. package/dist/chunk-3DPEIQKN.js +113 -0
  10. package/dist/{chunk-EOOQZZDE.js → chunk-3DUR4WUA.js} +19 -19
  11. package/dist/{chunk-WHJYKASB.js → chunk-3MRC2YSQ.js} +2 -2
  12. package/dist/{chunk-EBEFWSGL.js → chunk-3UUY7R3Z.js} +14 -10
  13. package/dist/{chunk-LADCF22A.js → chunk-3V5AYSEQ.js} +113 -54
  14. package/dist/{chunk-BMWK7ZIZ.js → chunk-465CC7FK.js} +16 -13
  15. package/dist/{chunk-5WIGXA4T.js → chunk-47CMYGET.js} +111 -4
  16. package/dist/{chunk-CEYBNUGC.js → chunk-4H6ULJ3H.js} +378 -36
  17. package/dist/{chunk-YTYFXUI3.js → chunk-4LJX2PUC.js} +9 -9
  18. package/dist/{chunk-DOOEX22V.js → chunk-56KB5IJP.js} +5 -5
  19. package/dist/{chunk-SPULKLCF.js → chunk-5DQRIYDZ.js} +2 -2
  20. package/dist/{chunk-TSHXZTOQ.js → chunk-5HFBWUMU.js} +23 -11
  21. package/dist/{chunk-5UJ6ECTS.js → chunk-5PVQ4SRS.js} +80 -8
  22. package/dist/{chunk-ZWLZP4ZT.js → chunk-5QKCQQ3E.js} +359 -17
  23. package/dist/{chunk-6M7VS3J3.js → chunk-5T7RBWN2.js} +111 -5
  24. package/dist/chunk-774ILSRL.js +172 -0
  25. package/dist/chunk-7C6RYZGQ.js +391 -0
  26. package/dist/{chunk-GH5622CP.js → chunk-A2NJGIB3.js} +2 -2
  27. package/dist/{chunk-C4JBQ5SR.js → chunk-AD7Y7STJ.js} +6 -6
  28. package/dist/{chunk-GEYXPTRF.js → chunk-AEYBF3TB.js} +33 -12
  29. package/dist/{chunk-2SFS6XQE.js → chunk-AMKHQW3C.js} +3 -2
  30. package/dist/{chunk-D4MDIG46.js → chunk-B5CSFE7B.js} +7 -7
  31. package/dist/{chunk-MXI6J5JF.js → chunk-B5XRQOLB.js} +10 -10
  32. package/dist/{chunk-X2KV5FXT.js → chunk-BVDVID7E.js} +2 -2
  33. package/dist/{chunk-JNXPYBB4.js → chunk-CA42X6KT.js} +3 -3
  34. package/dist/{chunk-VREKEFLL.js → chunk-D73KXYPF.js} +3 -3
  35. package/dist/{chunk-JTSEDYVQ.js → chunk-DG4M6ZUE.js} +7 -7
  36. package/dist/{chunk-DQA7QLMD.js → chunk-EBOC7MT3.js} +10 -25
  37. package/dist/{chunk-KZ2H5X4G.js → chunk-ECUO3KDP.js} +129 -14
  38. package/dist/{chunk-JRIO5UD2.js → chunk-EQ63NRB7.js} +5 -5
  39. package/dist/{chunk-YD734TPH.js → chunk-FALJGAWU.js} +2 -2
  40. package/dist/{chunk-GWS3VEIW.js → chunk-FWDFM5ZU.js} +24 -3
  41. package/dist/{chunk-XEGB6BCN.js → chunk-GAYUJ7LE.js} +68 -14
  42. package/dist/{chunk-UND3GU2L.js → chunk-H7IXIC72.js} +2 -2
  43. package/dist/{chunk-IR4CFBFN.js → chunk-HAY4ZE2P.js} +12 -12
  44. package/dist/{chunk-UVDSQ6LW.js → chunk-HCBCAYZU.js} +74 -147
  45. package/dist/{chunk-4DWFMQDR.js → chunk-HJB5IUKP.js} +89 -145
  46. package/dist/{chunk-M4AKACEO.js → chunk-HKO36JWF.js} +33 -5
  47. package/dist/{chunk-KCMKRQX4.js → chunk-HPCTNZM2.js} +45 -82
  48. package/dist/{chunk-465YSENW.js → chunk-IFBNV6H6.js} +3 -3
  49. package/dist/{chunk-FJ3H4MN5.js → chunk-IHKBWSXF.js} +2 -2
  50. package/dist/chunk-JEQQR47K.js +3025 -0
  51. package/dist/{chunk-FO5ZOVUY.js → chunk-KV2AOLDF.js} +27 -7
  52. package/dist/chunk-LU7P4LHA.js +33 -0
  53. package/dist/{chunk-6TUKSZVF.js → chunk-LXPJXFM5.js} +11 -11
  54. package/dist/{chunk-VQNODYQ4.js → chunk-MIX5N5AC.js} +488 -3668
  55. package/dist/chunk-MLOK6ZOS.js +2888 -0
  56. package/dist/{chunk-ZZMN5OM4.js → chunk-MV2VUEJC.js} +2 -2
  57. package/dist/{chunk-MVVUPGPW.js → chunk-MXHC5QYU.js} +6 -6
  58. package/dist/{chunk-OBMAI2DP.js → chunk-N3PBVRTZ.js} +12 -388
  59. package/dist/{chunk-WJHBC77E.js → chunk-N5XKWMDW.js} +17 -7
  60. package/dist/{chunk-5C3AQNDW.js → chunk-NNNWO6F2.js} +124 -36
  61. package/dist/{chunk-UFQ3F4FW.js → chunk-NQ6UCCOD.js} +4 -4
  62. package/dist/chunk-NUGM5KR6.js +165 -0
  63. package/dist/{chunk-DMD2AGVS.js → chunk-NZU6YDNV.js} +20 -18
  64. package/dist/{chunk-WHGPSPT5.js → chunk-O6I4CIEU.js} +151 -13
  65. package/dist/{chunk-XN3L4EYL.js → chunk-OEDBCISO.js} +2 -2
  66. package/dist/{chunk-PD3MESLB.js → chunk-P3JGPQFL.js} +4 -4
  67. package/dist/{chunk-UHXRNZ2J.js → chunk-PNY46YEY.js} +23 -6
  68. package/dist/{chunk-THKY7CD7.js → chunk-PZ4I4JE2.js} +134 -29
  69. package/dist/{chunk-SROCI7ZU.js → chunk-QQ7EKM72.js} +5 -5
  70. package/dist/{chunk-QCTRSGHQ.js → chunk-R7LNVMCS.js} +91 -53
  71. package/dist/{chunk-GOXNB3AO.js → chunk-RAPCMZL4.js} +75 -4
  72. package/dist/chunk-RKKLTLYB.js +45 -0
  73. package/dist/{chunk-OB5HIGJY.js → chunk-RKRLDWD3.js} +4 -1
  74. package/dist/{chunk-DJNLUABN.js → chunk-S4COXYBG.js} +588 -32
  75. package/dist/{chunk-3HAPLH5M.js → chunk-T3Z6VAAF.js} +172 -11
  76. package/dist/{chunk-FOT2FX5J.js → chunk-TD7UE2L5.js} +12 -10
  77. package/dist/{chunk-UUANF5CR.js → chunk-TEO2TLVN.js} +856 -967
  78. package/dist/{chunk-FCSXB6T2.js → chunk-UOSL25KY.js} +14 -2
  79. package/dist/{chunk-EELBMBT6.js → chunk-VKBMFOYV.js} +74 -15
  80. package/dist/chunk-VO2LKSTM.js +165 -0
  81. package/dist/{chunk-5C77SEEY.js → chunk-VPTUJU4P.js} +3 -3
  82. package/dist/{chunk-WEH5XRJQ.js → chunk-WIE7ZOSW.js} +2 -2
  83. package/dist/{chunk-J7PIKKWC.js → chunk-WXCJ7VME.js} +8 -8
  84. package/dist/{chunk-4DGYLA73.js → chunk-XDOQXGFO.js} +22 -7
  85. package/dist/{chunk-PPAMZ32Z.js → chunk-XK56QHLX.js} +6 -1
  86. package/dist/{chunk-AB4XIIVB.js → chunk-YKOFT37S.js} +6 -6
  87. package/dist/chunk-YSEHGPCT.js +127 -0
  88. package/dist/{chunk-HFSBBKSQ.js → chunk-YW7UVM5V.js} +138 -3
  89. package/dist/cli/index.js +32 -32
  90. package/dist/{clio-WBVQEBKO.js → clio-LT5V7SSZ.js} +9 -9
  91. package/dist/{code-nav-FGGFIE7L.js → code-nav-LMW275PA.js} +5 -5
  92. package/dist/codewiki/build-worker.js +4 -4
  93. package/dist/{components-F7OEATSO.js → components-ZFA3SAER.js} +8 -8
  94. package/dist/{config-TRBL3RCF.js → config-RXS5T3JT.js} +98 -65
  95. package/dist/{configure-OLCVPHNM.js → configure-2WYWSCSD.js} +26 -22
  96. package/dist/{context-MJIJ6GOX.js → context-I3BTOTCS.js} +12 -12
  97. package/dist/{context-XEWE3MOJ.js → context-MVOORGMF.js} +54 -47
  98. package/dist/{context-WFPKQSM6.js → context-PALKKQYL.js} +28 -28
  99. package/dist/{context-clear-KNOS2JPB.js → context-clear-N2WOYZ2K.js} +53 -46
  100. package/dist/{context-index-SSR5ECNE.js → context-index-HNG3MOME.js} +6 -6
  101. package/dist/{context-working-set-EUXAZI6N.js → context-working-set-MIEVECVZ.js} +17 -18
  102. package/dist/{dispatch-runner-B7MTOVKL.js → dispatch-runner-VVA4SRRH.js} +90 -61
  103. package/dist/{docs-FLJTIDSE.js → docs-7LQ23DLM.js} +8 -8
  104. package/dist/doctor-TWBWFK5V.js +165 -0
  105. package/dist/eval-IJ5VEZDJ.js +4483 -0
  106. package/dist/{evidence-JZNBUOQZ.js → evidence-L5APPXNV.js} +68 -61
  107. package/dist/{evolve-FJVC4KKI.js → evolve-RGNKFJ52.js} +47 -40
  108. package/dist/{extensions-IQL36S7K.js → extensions-7WYWUX5A.js} +13 -7
  109. package/dist/{fleet-BDKYJFCP.js → fleet-6CNVBZZP.js} +113 -76
  110. package/dist/{fleet-commands-ZFIWZSB3.js → fleet-commands-L2SXSYEI.js} +10 -10
  111. package/dist/{fleet-graph-Y6HPXIVF.js → fleet-graph-2J3OOIPO.js} +17 -15
  112. package/dist/{fleet-preflight-BHSNPBMH.js → fleet-preflight-CZRJ4JP5.js} +5 -6
  113. package/dist/{fleet-validate-BIYREGIK.js → fleet-validate-C5RI6DP7.js} +20 -19
  114. package/dist/{init-LQUB5COQ.js → init-VBN2ACVA.js} +70 -63
  115. package/dist/{library-NJAHIGG4.js → library-JHGUMLY2.js} +22 -20
  116. package/dist/{memory-OG6HOYKM.js → memory-K4OQIYWG.js} +49 -42
  117. package/dist/{models-5ZG5XY7J.js → models-2NCZUWDD.js} +35 -29
  118. package/dist/{monitor-TJ7AMTGB.js → monitor-MMVTJABD.js} +64 -45
  119. package/dist/{orchestrator-WZYB54DM.js → orchestrator-ZKBPCHW6.js} +1971 -520
  120. package/dist/{paths-XUC7GS6E.js → paths-DBXMZMDU.js} +5 -5
  121. package/dist/registry-LG64LTF4.js +11 -0
  122. package/dist/{reset-PXQT45IY.js → reset-DD5JGOY3.js} +11 -11
  123. package/dist/{run-FQ74YF62.js → run-QEGNX7FL.js} +89 -83
  124. package/dist/{share-FW7SVCL3.js → share-JKD3BQMW.js} +20 -18
  125. package/dist/{skills-7E7IRB3R.js → skills-LMQIKDOZ.js} +23 -21
  126. package/dist/{skills-eval-LI75W6OK.js → skills-eval-I7X2774U.js} +59 -52
  127. package/dist/{steer-GGWFUJUD.js → steer-CF5TDANS.js} +3 -3
  128. package/dist/support-I7LOJLIF.js +38 -0
  129. package/dist/{targets-4CIFKCTW.js → targets-RUSR6B5Z.js} +77 -42
  130. package/dist/{terminal-lease-WUZY7ZV5.js → terminal-lease-QYVORFR4.js} +6 -4
  131. package/dist/{trace-PNCASAXC.js → trace-ODOQIVIW.js} +61 -6
  132. package/dist/{uninstall-7FV7IP4E.js → uninstall-ZJF5H5ZN.js} +8 -8
  133. package/dist/{upgrade-K2HVIVMQ.js → upgrade-XANW3FXB.js} +29 -26
  134. package/dist/{usage-GTZELZQX.js → usage-4H7ZRXQT.js} +110 -61
  135. package/dist/{verifiers-RLAHT27O.js → verifiers-UZXNBZEB.js} +13 -13
  136. package/dist/{verify-BX3BRKH5.js → verify-BVKWTNDL.js} +9 -9
  137. package/dist/{wiki-generate-ASIFASCN.js → wiki-generate-MY7WV2QI.js} +76 -69
  138. package/dist/worker/entry.js +69 -66
  139. package/docs/alcf-provider.md +1 -1
  140. package/docs/architecture.md +1 -1
  141. package/docs/artifact-versions.md +11 -5
  142. package/docs/built-in-agents.md +1 -1
  143. package/docs/capacity-and-scheduling.md +23 -2
  144. package/docs/commands-and-modes.md +2 -2
  145. package/docs/configuration-and-targets.md +37 -5
  146. package/docs/context-engine.md +63 -4
  147. package/docs/documentation-coverage.md +3 -3
  148. package/docs/documentation-guide.md +1 -1
  149. package/docs/environment-variables.md +2 -0
  150. package/docs/eval-runner.md +262 -11
  151. package/docs/evals-internal.md +72 -2
  152. package/docs/evidence-and-memory.md +77 -12
  153. package/docs/evolution.md +1 -1
  154. package/docs/extensions-and-sharing.md +3 -1
  155. package/docs/fleet-dispatch.md +34 -9
  156. package/docs/glossary.md +21 -1
  157. package/docs/installation-and-lifecycle.md +1 -1
  158. package/docs/middleware-and-components.md +1 -1
  159. package/docs/model-catalog.md +1 -1
  160. package/docs/observability.md +54 -3
  161. package/docs/proactive-memory.md +127 -14
  162. package/docs/prompt-envelope-and-tools.md +22 -2
  163. package/docs/provider-adapter-cookbook.md +1 -1
  164. package/docs/release-cut-checklist.md +60 -41
  165. package/docs/safety-model.md +1 -1
  166. package/docs/scientific-validation.md +1 -1
  167. package/docs/skills-marketplace.md +1 -1
  168. package/docs/tool-usage.md +1 -1
  169. package/docs/trace-store.md +1 -1
  170. package/docs/troubleshooting.md +87 -0
  171. package/docs/tui-design.md +1 -1
  172. package/docs/worker-dispatch-mechanics.md +1 -1
  173. package/package.json +2 -2
  174. package/src/cli/agents.ts +1 -1
  175. package/src/cli/argv.ts +5 -0
  176. package/src/cli/config-inspect.ts +33 -6
  177. package/src/cli/config.ts +1 -1
  178. package/src/cli/configure.ts +107 -23
  179. package/src/cli/doctor-state-size.ts +82 -0
  180. package/src/cli/doctor.ts +7 -1
  181. package/src/cli/eval.ts +80 -16
  182. package/src/cli/evidence.ts +30 -25
  183. package/src/cli/extensions.ts +5 -1
  184. package/src/cli/fleet-preflight.ts +2 -12
  185. package/src/cli/fleet.ts +32 -3
  186. package/src/cli/shared.ts +1 -0
  187. package/src/cli/targets.ts +45 -11
  188. package/src/cli/trace.ts +63 -4
  189. package/src/cli/usage.ts +63 -14
  190. package/src/cli/validate-model.ts +60 -5
  191. package/src/core/bus-events.ts +54 -1
  192. package/src/core/cache-telemetry.ts +42 -0
  193. package/src/core/commit-attribution.ts +4 -4
  194. package/src/core/config.ts +18 -0
  195. package/src/core/defaults.ts +36 -6
  196. package/src/core/endpoint-key.ts +27 -0
  197. package/src/core/path-boundary.ts +100 -0
  198. package/src/core/residency-target-key.ts +25 -0
  199. package/src/core/response-schema.ts +36 -2
  200. package/src/domains/agents/extension.ts +2 -11
  201. package/src/domains/agents/fleet-contract.ts +30 -12
  202. package/src/domains/agents/recipe.ts +7 -1
  203. package/src/domains/agents/registry.ts +73 -5
  204. package/src/domains/agents/result-contract.ts +128 -17
  205. package/src/domains/agents/write-boundary.ts +15 -50
  206. package/src/domains/config/classify.ts +3 -0
  207. package/src/domains/context/codewiki/coordinator.ts +12 -4
  208. package/src/domains/context/project-rules.ts +51 -1
  209. package/src/domains/dispatch/admission.ts +40 -3
  210. package/src/domains/dispatch/assignment-reconcile.ts +22 -5
  211. package/src/domains/dispatch/assignment-store.ts +151 -14
  212. package/src/domains/dispatch/capacity-lease.ts +98 -9
  213. package/src/domains/dispatch/contract.ts +26 -1
  214. package/src/domains/dispatch/delegation-plan.ts +2 -5
  215. package/src/domains/dispatch/execution-plan.ts +44 -4
  216. package/src/domains/dispatch/execution-role.ts +9 -1
  217. package/src/domains/dispatch/extension.ts +309 -96
  218. package/src/domains/dispatch/fleet-run.ts +78 -4
  219. package/src/domains/dispatch/gate-role-prompts.ts +38 -0
  220. package/src/domains/dispatch/heartbeat.ts +32 -8
  221. package/src/domains/dispatch/index.ts +6 -1
  222. package/src/domains/dispatch/intent-requirements.ts +40 -0
  223. package/src/domains/dispatch/intent.ts +84 -8
  224. package/src/domains/dispatch/orphan-recovery.ts +5 -0
  225. package/src/domains/dispatch/path-scope.ts +370 -0
  226. package/src/domains/dispatch/receipt-integrity.ts +2 -1
  227. package/src/domains/dispatch/reservation-store.ts +116 -8
  228. package/src/domains/dispatch/state.ts +4 -0
  229. package/src/domains/dispatch/types.ts +14 -7
  230. package/src/domains/dispatch/validation.ts +6 -3
  231. package/src/domains/dispatch/worker-spawn.ts +25 -11
  232. package/src/domains/dispatch/write-boundary-enforcer.ts +62 -0
  233. package/src/domains/dispatch/write-boundary.ts +262 -22
  234. package/src/domains/eval/artifacts/store.ts +62 -0
  235. package/src/domains/eval/compare/behavioral.ts +224 -0
  236. package/src/domains/eval/compare/compare.ts +355 -2
  237. package/src/domains/eval/compare/envelope.ts +128 -0
  238. package/src/domains/eval/compare/gates.ts +24 -6
  239. package/src/domains/eval/compare/thresholds.ts +30 -3
  240. package/src/domains/eval/execution-provenance.ts +240 -0
  241. package/src/domains/eval/metrics/aggregate.ts +136 -0
  242. package/src/domains/eval/metrics/call-ledger-stream.ts +112 -0
  243. package/src/domains/eval/metrics/evidence.ts +79 -2
  244. package/src/domains/eval/metrics/tracked.ts +413 -0
  245. package/src/domains/eval/provenance.ts +117 -0
  246. package/src/domains/eval/reports/comparison.ts +128 -0
  247. package/src/domains/eval/reports/junit.ts +17 -3
  248. package/src/domains/eval/reports/markdown.ts +3 -3
  249. package/src/domains/eval/reports/text.ts +14 -0
  250. package/src/domains/eval/run-compare.ts +20 -0
  251. package/src/domains/eval/runners/clio-run.ts +139 -2
  252. package/src/domains/eval/runners/external-command.ts +28 -3
  253. package/src/domains/eval/schema/adapter.ts +111 -0
  254. package/src/domains/eval/schema/artifact.ts +20 -0
  255. package/src/domains/eval/schema/behavioral-metrics.ts +204 -0
  256. package/src/domains/eval/schema/behavioral.ts +520 -0
  257. package/src/domains/eval/schema/execution-envelope.ts +194 -0
  258. package/src/domains/eval/schema/serving.ts +74 -0
  259. package/src/domains/eval/schema/suite.ts +38 -8
  260. package/src/domains/eval/schema/validate.ts +58 -3
  261. package/src/domains/eval/schema/verdict.ts +237 -0
  262. package/src/domains/eval/suites/resolve.ts +2 -0
  263. package/src/domains/eval/suites/run.ts +264 -33
  264. package/src/domains/eval/verifiers/command.ts +2 -1
  265. package/src/domains/eval/workspaces/temp-copy.ts +145 -13
  266. package/src/domains/evidence/build.ts +68 -21
  267. package/src/domains/evidence/eval.ts +2 -12
  268. package/src/domains/evidence/findings-markdown.ts +33 -0
  269. package/src/domains/evidence/index.ts +21 -0
  270. package/src/domains/evidence/provenance.ts +46 -11
  271. package/src/domains/evidence/run-trust.ts +7 -113
  272. package/src/domains/evidence/trust-projection.ts +274 -0
  273. package/src/domains/evidence/trust-status.ts +145 -17
  274. package/src/domains/evidence/types.ts +4 -0
  275. package/src/domains/extensions/compatibility.ts +285 -0
  276. package/src/domains/extensions/discovery.ts +126 -4
  277. package/src/domains/extensions/resources.ts +21 -9
  278. package/src/domains/extensions/state.ts +18 -5
  279. package/src/domains/extensions/types.ts +6 -1
  280. package/src/domains/lifecycle/doctor.ts +209 -2
  281. package/src/domains/memory/index.ts +14 -0
  282. package/src/domains/memory/task-bank-promotion.ts +64 -0
  283. package/src/domains/memory/task-memory-policy.ts +77 -8
  284. package/src/domains/memory/task-memory-spend.ts +131 -0
  285. package/src/domains/memory/task-memory-status.ts +7 -0
  286. package/src/domains/memory/task-memory-telemetry.ts +2 -0
  287. package/src/domains/middleware/index.ts +1 -0
  288. package/src/domains/middleware/memory-intervention.ts +69 -5
  289. package/src/domains/middleware/memory-step-endpoint.ts +71 -0
  290. package/src/domains/observability/background-memory-usage.ts +140 -0
  291. package/src/domains/observability/cost.ts +1 -1
  292. package/src/domains/observability/index.ts +7 -0
  293. package/src/domains/observability/out-of-turn-usage.ts +51 -2
  294. package/src/domains/observability/trace-store.ts +192 -2
  295. package/src/domains/prompts/compiler.ts +100 -13
  296. package/src/domains/prompts/contract.ts +3 -5
  297. package/src/domains/providers/endpoint-capacity.ts +96 -0
  298. package/src/domains/providers/extension.ts +30 -2
  299. package/src/domains/providers/index.ts +10 -0
  300. package/src/domains/providers/models/local-models/clio-local-coding-targets.yaml +243 -1
  301. package/src/domains/providers/runtime-resolution.ts +8 -1
  302. package/src/domains/providers/runtimes/common/probe-helpers.ts +31 -9
  303. package/src/domains/providers/runtimes/local-native/llamacpp-anthropic.ts +1 -1
  304. package/src/domains/providers/runtimes/local-native/llamacpp-completion.ts +1 -1
  305. package/src/domains/providers/runtimes/local-native/llamacpp-embed.ts +1 -1
  306. package/src/domains/providers/runtimes/local-native/llamacpp-rerank.ts +1 -1
  307. package/src/domains/providers/runtimes/local-native/llamacpp.ts +4 -1
  308. package/src/domains/providers/runtimes/local-native/lmstudio.ts +4 -1
  309. package/src/domains/providers/runtimes/local-native/ollama-native.ts +6 -1
  310. package/src/domains/providers/types/capability-flags.ts +2 -0
  311. package/src/domains/providers/types/target-descriptor.ts +2 -0
  312. package/src/domains/resources/common-loader.ts +3 -0
  313. package/src/domains/resources/prompts/loader.ts +184 -17
  314. package/src/domains/safety/call-target.ts +52 -0
  315. package/src/domains/safety/policy-engine.ts +5 -5
  316. package/src/domains/safety/run-effects.ts +96 -2
  317. package/src/domains/safety/scope.ts +7 -12
  318. package/src/domains/session/context-accounting.ts +52 -1
  319. package/src/domains/session/context-ledger.ts +37 -13
  320. package/src/domains/session/index.ts +6 -0
  321. package/src/domains/session/prompt-cache.ts +140 -0
  322. package/src/domains/session/prompt-manifest.ts +42 -0
  323. package/src/engine/acp/adapter.ts +18 -3
  324. package/src/engine/acp/server.ts +4 -1
  325. package/src/engine/ai.ts +35 -0
  326. package/src/engine/apis/llamacpp-residency.ts +55 -3
  327. package/src/engine/apis/lmstudio.ts +25 -5
  328. package/src/engine/apis/ollama-native.ts +2 -1
  329. package/src/engine/apis/openai-completions.ts +80 -17
  330. package/src/engine/apis/residency-lock.ts +3 -1
  331. package/src/engine/apis/residency.ts +34 -1
  332. package/src/engine/prompt-templates.ts +18 -1
  333. package/src/engine/provider-payload.ts +29 -1
  334. package/src/engine/worker-runtime.ts +6 -3
  335. package/src/entry/orchestrator.ts +176 -30
  336. package/src/interactive/chat-loop-messages.ts +26 -7
  337. package/src/interactive/chat-loop.ts +318 -41
  338. package/src/interactive/chat-panel.ts +62 -8
  339. package/src/interactive/clio-editor.ts +45 -8
  340. package/src/interactive/context-activity.ts +5 -1
  341. package/src/interactive/context-meter.ts +1 -1
  342. package/src/interactive/context-overlay.ts +40 -10
  343. package/src/interactive/cost-overlay.ts +64 -6
  344. package/src/interactive/dispatch-board.ts +127 -5
  345. package/src/interactive/fleet-run-preview.ts +41 -15
  346. package/src/interactive/handoff-round.ts +41 -2
  347. package/src/interactive/interactive-application.ts +24 -1
  348. package/src/interactive/interactive-event-projection.ts +14 -0
  349. package/src/interactive/interactive-input-runtime.ts +8 -0
  350. package/src/interactive/interactive-presentation.ts +4 -0
  351. package/src/interactive/interactive-shell.ts +20 -17
  352. package/src/interactive/interactive-slash-runtime.ts +27 -4
  353. package/src/interactive/memory-overlay.ts +8 -0
  354. package/src/interactive/mutation-preview.ts +295 -0
  355. package/src/interactive/overlay-general-openers.ts +16 -0
  356. package/src/interactive/overlay-key-routing.ts +38 -0
  357. package/src/interactive/overlay-lifecycle.ts +38 -5
  358. package/src/interactive/overlay-permission-lifecycle.ts +22 -2
  359. package/src/interactive/overlay-session-lifecycle.ts +73 -9
  360. package/src/interactive/overlays/ask-user.ts +91 -19
  361. package/src/interactive/overlays/help-reference.ts +4 -0
  362. package/src/interactive/overlays/prompts.ts +11 -1
  363. package/src/interactive/overlays/settings.ts +176 -48
  364. package/src/interactive/permission-hint.ts +34 -2
  365. package/src/interactive/permission-overlay.ts +159 -9
  366. package/src/interactive/prewarm.ts +197 -0
  367. package/src/interactive/render-trace.ts +162 -15
  368. package/src/interactive/renderers/tool-execution.ts +4 -0
  369. package/src/interactive/side-question.ts +58 -1
  370. package/src/interactive/slash-commands.ts +7 -2
  371. package/src/interactive/status/controller.ts +11 -0
  372. package/src/interactive/status/state-machine.ts +54 -2
  373. package/src/interactive/status/types.ts +7 -0
  374. package/src/interactive/terminal-lease.ts +2 -0
  375. package/src/interactive/turn-context.ts +299 -31
  376. package/src/interactive/turn-persistence.ts +14 -4
  377. package/src/interactive/turn-prewarm.ts +364 -0
  378. package/src/interactive/turn-queues.ts +7 -4
  379. package/src/interactive/turn-runtime.ts +8 -1
  380. package/src/interactive/turn-state.ts +23 -0
  381. package/src/interactive/view/artifacts.ts +42 -9
  382. package/src/interactive/view/view-overlay.ts +43 -6
  383. package/src/interactive/worker-receipts.ts +14 -2
  384. package/src/interactive/worker-stream.ts +8 -0
  385. package/src/tools/ask-user.ts +43 -2
  386. package/src/tools/dispatch-admission.ts +12 -13
  387. package/src/tools/dispatch-arguments.ts +27 -0
  388. package/src/tools/dispatch-plan.ts +46 -9
  389. package/src/tools/dispatch-runner.ts +48 -13
  390. package/src/tools/dispatch-scout.ts +1 -1
  391. package/src/tools/monitor.ts +13 -0
  392. package/src/tools/registry.ts +16 -0
  393. package/src/tools/worker-evidence.ts +19 -13
  394. package/src/worker/spec-contract.ts +2 -1
  395. package/dist/chunk-AOCYTWAV.js +0 -449
  396. package/dist/chunk-HWUFFB6L.js +0 -83
  397. package/dist/chunk-R346GLFC.js +0 -31
  398. package/dist/chunk-ZGH7FGS5.js +0 -1079
  399. package/dist/doctor-RN4YKO2X.js +0 -87
  400. package/dist/eval-RUBJVSNQ.js +0 -2557
@@ -1,7 +1,9 @@
1
- import { mkdtemp, rm } from "node:fs/promises";
1
+ import { mkdtemp, rm, writeFile } from "node:fs/promises";
2
2
  import { tmpdir } from "node:os";
3
3
  import { resolve } from "node:path";
4
4
  import { resolveMetricAssertion } from "../compare/thresholds.js";
5
+ import { buildEvalExecutionEnvelopeV1, type EvalExecutionObservationV1 } from "../execution-provenance.js";
6
+ import { aggregateEvalVerdicts } from "../metrics/aggregate.js";
5
7
  import { collectContextMetrics } from "../metrics/context.js";
6
8
  import { fleetLoopReceiptAgreement } from "../metrics/fleet-loop-stream.js";
7
9
  import {
@@ -15,12 +17,22 @@ import {
15
17
  import { wallTimeMetric } from "../metrics/latency.js";
16
18
  import { tokenAccountingFrom } from "../metrics/tokens.js";
17
19
  import { zeroToolCallMetrics } from "../metrics/tool-calls.js";
18
- import { evalClioProvenance, evalEnvironmentProvenance } from "../provenance.js";
20
+ import { buildEvalTrackedMetrics, emptyEvalTrackedMetrics, readEvalLedgerSnapshot } from "../metrics/tracked.js";
21
+ import {
22
+ type EvalServingObservation,
23
+ evalClioProvenance,
24
+ evalEnvironmentProvenance,
25
+ evalServingConfiguration,
26
+ evalServingObservationFrom,
27
+ } from "../provenance.js";
19
28
  import { runClioRunRunner } from "../runners/clio-run.js";
20
29
  import { runContextIndexRunner } from "../runners/context-index.js";
21
30
  import { runContextInitRunner } from "../runners/context-init.js";
22
31
  import { type EvalRunnerOutput, runExternalCommandRunner } from "../runners/external-command.js";
32
+ import { adaptSuiteV2ResultToBehaviorV1, adaptSuiteV2ResultToVerdictV1 } from "../schema/adapter.js";
23
33
  import type { EvalArtifactResultV4, EvalArtifactV4 } from "../schema/artifact.js";
34
+ import { buildEvalBehaviorMetricsV1 } from "../schema/behavioral-metrics.js";
35
+ import type { EvalServingConfigurationV1 } from "../schema/serving.js";
24
36
  import type { EvalMetricAssertion, EvalSuiteTargetV2, LoadedEvalSuiteV2 } from "../schema/suite.js";
25
37
  import { createEvalId } from "../store.js";
26
38
  import { runCommandVerifiers } from "../verifiers/command.js";
@@ -28,7 +40,7 @@ import { forbiddenPathHits } from "../verifiers/file-exists.js";
28
40
  import { collectPatchMetrics } from "../verifiers/patch.js";
29
41
  import { prepareGitWorkspace } from "../workspaces/git.js";
30
42
  import { type PreparedEvalWorkspace, prepareLocalWorkspace } from "../workspaces/local.js";
31
- import { prepareTempCopyWorkspace } from "../workspaces/temp-copy.js";
43
+ import { type PrepareTempCopyWorkspaceOptions, prepareTempCopyWorkspace } from "../workspaces/temp-copy.js";
32
44
  import { expandEvalMatrix } from "./matrix.js";
33
45
  import { artifactMatrixIdentity } from "./resolve.js";
34
46
 
@@ -42,6 +54,15 @@ class EvalWorkspaceSetupError extends Error {
42
54
  export interface RunEvalSuiteV2Options {
43
55
  clioEntry: string;
44
56
  now?: () => Date;
57
+ /** Convert local workspaces into isolated copies for explicit trial runs. */
58
+ freshWorkspaces?: boolean;
59
+ /** Dependency/root seam for deterministic workspace lifecycle contracts. */
60
+ tempCopy?: PrepareTempCopyWorkspaceOptions;
61
+ }
62
+
63
+ interface CompletedMatrixItem {
64
+ result: EvalArtifactResultV4;
65
+ serving: EvalServingObservation;
45
66
  }
46
67
 
47
68
  export async function runEvalSuiteV2(
@@ -52,6 +73,7 @@ export async function runEvalSuiteV2(
52
73
  const started = now();
53
74
  const evalId = createEvalId(started, loaded.hash);
54
75
  const results: EvalArtifactResultV4[] = [];
76
+ const servingObservations: EvalServingObservation[] = [];
55
77
  const maxCostUsd = loaded.suite.matrix.maxCostUsd;
56
78
  let spentUsd = 0;
57
79
  for (const item of expandEvalMatrix(loaded.suite)) {
@@ -59,14 +81,24 @@ export async function runEvalSuiteV2(
59
81
  // exceeds it, remaining items fail closed instead of running. A live
60
82
  // suite can therefore never keep spending past its declared budget.
61
83
  if (maxCostUsd !== undefined && spentUsd > maxCostUsd) {
62
- results.push(budgetExhaustedResult(item.task.id, item.target, item.repeatIndex, spentUsd, maxCostUsd));
84
+ results.push(budgetExhaustedResult(loaded, item.task, item.target, item.repeatIndex, spentUsd, maxCostUsd));
63
85
  continue;
64
86
  }
65
- const result = await runMatrixItem(loaded, item.task, item.target, item.repeatIndex, options.clioEntry);
66
- spentUsd += resultCostUsd(result);
67
- results.push(result);
87
+ const completed = await runMatrixItem(
88
+ loaded,
89
+ item.task,
90
+ item.target,
91
+ item.repeatIndex,
92
+ options.clioEntry,
93
+ options.freshWorkspaces === true,
94
+ options.tempCopy,
95
+ );
96
+ spentUsd += resultCostUsd(completed.result);
97
+ results.push(completed.result);
98
+ servingObservations.push(completed.serving);
68
99
  }
69
- return buildArtifact(loaded, evalId, results, options.clioEntry);
100
+ const serving = await evalServingConfiguration(loaded.suite.matrix.targets, servingObservations);
101
+ return buildArtifact(loaded, evalId, results, options.clioEntry, serving);
70
102
  }
71
103
 
72
104
  /** Known receipt cost of one finished matrix item; unpriced runs count zero. */
@@ -76,16 +108,17 @@ export function resultCostUsd(result: Pick<EvalArtifactResultV4, "metrics">): nu
76
108
  }
77
109
 
78
110
  function budgetExhaustedResult(
79
- taskId: string,
111
+ loaded: LoadedEvalSuiteV2,
112
+ task: LoadedEvalSuiteV2["suite"]["tasks"][number],
80
113
  target: EvalSuiteTargetV2,
81
114
  repeatIndex: number,
82
115
  spentUsd: number,
83
116
  maxCostUsd: number,
84
117
  ): EvalArtifactResultV4 {
85
- return {
118
+ const result: EvalArtifactResultV4 = {
86
119
  assignmentId: null,
87
120
  terminalReceiptDigest: null,
88
- taskId,
121
+ taskId: task.id,
89
122
  repeatIndex,
90
123
  target: { id: target.id, model: target.model ?? null, thinking: target.thinking ?? null },
91
124
  pass: false,
@@ -100,6 +133,10 @@ function budgetExhaustedResult(
100
133
  error: `matrix cost budget exhausted: spent $${spentUsd.toFixed(4)} of max $${maxCostUsd.toFixed(4)} before this item`,
101
134
  },
102
135
  };
136
+ result.verdict = adaptSuiteV2ResultToVerdictV1(result, emptyEvalTrackedMetrics());
137
+ attachBehavioralResult(result, task);
138
+ attachExecutionEnvelope(result, task, target, loaded.baseDir, null, emptyLedgerSnapshot());
139
+ return result;
103
140
  }
104
141
 
105
142
  async function runMatrixItem(
@@ -108,15 +145,20 @@ async function runMatrixItem(
108
145
  target: EvalSuiteTargetV2,
109
146
  repeatIndex: number,
110
147
  clioEntry: string,
111
- ): Promise<EvalArtifactResultV4> {
148
+ freshWorkspace: boolean,
149
+ tempCopy: PrepareTempCopyWorkspaceOptions | undefined,
150
+ ): Promise<CompletedMatrixItem> {
112
151
  let workspace: PreparedEvalWorkspace | null = null;
152
+ let receipt: EvalRunnerOutput["receipt"] = null;
153
+ let runnerWallTimeMs = 0;
154
+ let executionObservation: EvalExecutionObservationV1 | undefined;
113
155
  // One matrix item, one Clio journal. An item measures Clio, and a shared
114
156
  // state directory would mix sibling processes' runs and yesterday's sessions
115
157
  // into the reading; pinning it here also means an item leaves nothing behind
116
158
  // in the operator's own state.
117
- const stateDir = await mkdtemp(resolve(tmpdir(), "clio-eval-state-"));
159
+ const stateDir = await mkdtemp(resolve(tempCopy?.tempRoot ?? tmpdir(), "clio-eval-state-"));
118
160
  try {
119
- workspace = await prepareWorkspace(loaded.baseDir, task);
161
+ workspace = await prepareWorkspace(loaded.baseDir, task, freshWorkspace, tempCopy);
120
162
  const setup = await runCommandVerifiers(task.workspace.setup ?? [], workspace.dir, task.timeoutMs);
121
163
  // A fixture that never came up measured nothing, so the item fails as a
122
164
  // harness failure rather than reporting an invariant it never observed.
@@ -125,12 +167,20 @@ async function runMatrixItem(
125
167
  CLIO_CODER_STATE_DIR: stateDir,
126
168
  CLIO_CODER_ENTRY: clioEntry,
127
169
  });
170
+ const runnerStdoutFile = resolve(stateDir, "eval-runner-output.jsonl");
171
+ await writeFile(runnerStdoutFile, runner.stdout, "utf8");
172
+ receipt = runner.receipt ?? null;
173
+ runnerWallTimeMs = runner.wallTimeMs;
128
174
  const patch = collectPatchMetrics(workspace.dir);
129
175
  const receiptExitCode = runner.exitCode;
130
176
  // Read after the runner returned and before the journal is removed: what
131
177
  // Clio sealed for this item, judged against its own ledger, and whether
132
178
  // the workers it attested are still running.
133
179
  const journalMetrics = invariantMetrics(stateDir, receiptExitCode);
180
+ const measurement = await measureTaskOutcome(task, workspace.dir, {
181
+ CLIO_EVAL_RUNNER_STDOUT_FILE: runnerStdoutFile,
182
+ });
183
+ executionObservation = measurement.executionObservation;
134
184
  const metrics: Record<string, number | string | boolean | null> = {
135
185
  ...zeroToolCallMetrics(),
136
186
  ...collectContextMetrics(workspace.dir),
@@ -146,15 +196,22 @@ async function runMatrixItem(
146
196
  "patch.testFilesModified": patch.testFilesModified,
147
197
  "result.pass": runner.exitCode === 0,
148
198
  "result.failureClass": runner.exitCode === 0 ? null : "runner_failed",
149
- ...(await measureTaskOutcome(task, workspace.dir)),
199
+ ...measurement.metrics,
150
200
  };
151
201
  const verifier = await runVerifiers(task, workspace.dir, metrics);
152
- const pass = runner.exitCode === 0 && verifier.pass;
153
- const failureClass = pass ? null : runner.exitCode !== 0 ? "runner_failed" : verifier.failureClass;
202
+ const graderFailed = metrics["task.solved"] === false;
203
+ const pass = runner.exitCode === 0 && verifier.pass && !graderFailed;
204
+ const failureClass = pass
205
+ ? null
206
+ : runner.exitCode !== 0
207
+ ? "runner_failed"
208
+ : !verifier.pass
209
+ ? verifier.failureClass
210
+ : "grader_failed";
154
211
  metrics["verifier.exitCode"] = verifier.exitCode;
155
212
  metrics["result.pass"] = pass;
156
213
  metrics["result.failureClass"] = failureClass;
157
- return {
214
+ const result: EvalArtifactResultV4 = {
158
215
  assignmentId: runner.assignmentId,
159
216
  terminalReceiptDigest: runner.terminalReceiptDigest,
160
217
  taskId: task.id,
@@ -165,13 +222,30 @@ async function runMatrixItem(
165
222
  metrics,
166
223
  artifacts: {
167
224
  ...runner.artifacts,
225
+ workspace: workspace.dir,
168
226
  ...(verifier.stdout.length > 0 ? { verifierStdout: verifier.stdout } : {}),
169
227
  ...(verifier.stderr.length > 0 ? { verifierStderr: verifier.stderr } : {}),
170
228
  },
171
229
  };
230
+ const snapshot = await readEvalLedgerSnapshot(stateDir);
231
+ const ledgerEntries = [...snapshot.entries, ...(runner.ledgerEntries ?? [])];
232
+ result.verdict = adaptSuiteV2ResultToVerdictV1(
233
+ result,
234
+ buildEvalTrackedMetrics({
235
+ ledgerEntries,
236
+ receipt: receipt ?? null,
237
+ fallbackWallClockMs: runner.wallTimeMs,
238
+ }),
239
+ );
240
+ attachBehavioralResult(result, task);
241
+ attachExecutionEnvelope(result, task, target, workspace.dir, receipt ?? null, snapshot, executionObservation);
242
+ return {
243
+ result,
244
+ serving: evalServingObservationFrom(target, receipt ?? null, snapshot.compiledPromptHashes),
245
+ };
172
246
  } catch (error) {
173
247
  const failureClass = error instanceof EvalWorkspaceSetupError ? "setup_failed" : "command_error";
174
- return {
248
+ const result: EvalArtifactResultV4 = {
175
249
  assignmentId: null,
176
250
  terminalReceiptDigest: null,
177
251
  taskId: task.id,
@@ -185,14 +259,74 @@ async function runMatrixItem(
185
259
  "verifier.exitCode": 1,
186
260
  "latency.wallMs": 0,
187
261
  },
188
- artifacts: { error: error instanceof Error ? error.message : String(error) },
262
+ artifacts: {
263
+ error: error instanceof Error ? error.message : String(error),
264
+ ...(workspace === null ? {} : { workspace: workspace.dir }),
265
+ },
266
+ };
267
+ const snapshot = await readEvalLedgerSnapshot(stateDir);
268
+ result.verdict = adaptSuiteV2ResultToVerdictV1(
269
+ result,
270
+ buildEvalTrackedMetrics({
271
+ ledgerEntries: snapshot.entries,
272
+ receipt: receipt ?? null,
273
+ fallbackWallClockMs: runnerWallTimeMs,
274
+ }),
275
+ );
276
+ attachBehavioralResult(result, task);
277
+ attachExecutionEnvelope(
278
+ result,
279
+ task,
280
+ target,
281
+ workspace?.dir ?? loaded.baseDir,
282
+ receipt ?? null,
283
+ snapshot,
284
+ executionObservation,
285
+ );
286
+ return {
287
+ result,
288
+ serving: evalServingObservationFrom(target, receipt ?? null, snapshot.compiledPromptHashes),
189
289
  };
190
290
  } finally {
191
- await workspace?.cleanup();
192
- await rm(stateDir, { recursive: true, force: true });
291
+ try {
292
+ await workspace?.cleanup();
293
+ } finally {
294
+ // A workspace cleanup error must not strand the suite-owned journal.
295
+ await rm(stateDir, { recursive: true, force: true });
296
+ }
193
297
  }
194
298
  }
195
299
 
300
+ function attachBehavioralResult(result: EvalArtifactResultV4, task: LoadedEvalSuiteV2["suite"]["tasks"][number]): void {
301
+ if (task.behavioral === undefined || result.verdict === undefined) return;
302
+ result.behavioral = adaptSuiteV2ResultToBehaviorV1(result, result.verdict, task.behavioral);
303
+ result.behavioralMetrics = buildEvalBehaviorMetricsV1(result, task.behavioral.execution.subject.role);
304
+ }
305
+
306
+ function attachExecutionEnvelope(
307
+ result: EvalArtifactResultV4,
308
+ task: LoadedEvalSuiteV2["suite"]["tasks"][number],
309
+ target: EvalSuiteTargetV2,
310
+ cwd: string | null,
311
+ receipt: NonNullable<EvalRunnerOutput["receipt"]> | null,
312
+ ledger: Awaited<ReturnType<typeof readEvalLedgerSnapshot>>,
313
+ observation?: EvalExecutionObservationV1,
314
+ ): void {
315
+ if (task.behavioral === undefined) return;
316
+ result.executionEnvelope = buildEvalExecutionEnvelopeV1({
317
+ task,
318
+ target,
319
+ cwd,
320
+ receipt,
321
+ ledger,
322
+ ...(observation === undefined ? {} : { observation }),
323
+ });
324
+ }
325
+
326
+ function emptyLedgerSnapshot(): Awaited<ReturnType<typeof readEvalLedgerSnapshot>> {
327
+ return { entries: [], compiledPromptHashes: [], promptManifests: [], contextSnapshots: [] };
328
+ }
329
+
196
330
  /** Journal-derived invariants for one finished item, read from its isolated state directory. */
197
331
  function invariantMetrics(stateDir: string, runnerExitCode: number): Record<string, number | boolean> {
198
332
  const journal = readRunJournal(stateDir);
@@ -208,10 +342,15 @@ function invariantMetrics(stateDir: string, runnerExitCode: number): Record<stri
208
342
  async function prepareWorkspace(
209
343
  baseDir: string,
210
344
  task: LoadedEvalSuiteV2["suite"]["tasks"][number],
345
+ freshWorkspace: boolean,
346
+ tempCopy: PrepareTempCopyWorkspaceOptions | undefined,
211
347
  ): Promise<PreparedEvalWorkspace> {
348
+ if (task.workspace.kind === "local" && freshWorkspace) {
349
+ return prepareTempCopyWorkspace(baseDir, { ...task.workspace, kind: "temp-copy" }, tempCopy);
350
+ }
212
351
  if (task.workspace.kind === "local") return prepareLocalWorkspace(baseDir, task.workspace);
213
352
  if (task.workspace.kind === "git") return prepareGitWorkspace(task.workspace);
214
- return prepareTempCopyWorkspace(baseDir, task.workspace);
353
+ return prepareTempCopyWorkspace(baseDir, task.workspace, tempCopy);
215
354
  }
216
355
 
217
356
  async function runTaskRunner(
@@ -225,23 +364,87 @@ async function runTaskRunner(
225
364
  if (task.runner.kind === "context-index") return runContextIndexRunner(cwd, clioEntry, task.timeoutMs, target, env);
226
365
  if (task.runner.kind === "context-init")
227
366
  return runContextInitRunner(task.runner, cwd, clioEntry, task.timeoutMs, target, env);
228
- return runClioRunRunner(task.runner, cwd, clioEntry, task.timeoutMs, target, env);
367
+ return runClioRunRunner(task.runner, cwd, clioEntry, task.timeoutMs, target, env, task.metrics.readObservation);
229
368
  }
230
369
 
231
370
  /**
232
- * Run the task-outcome commands and report what they found. A nonzero exit is
233
- * recorded, never raised: whether the model solved the workload is a
234
- * measurement, and only the machinery's behavior is a gate. A task that
235
- * declares no measure commands reports nothing rather than a passing zero.
371
+ * Run the task-outcome grader and report what it found. A nonzero exit is
372
+ * recorded rather than thrown so the verdict can report a failed outcome with
373
+ * healthy machinery. A task that declares no measure commands reports nothing
374
+ * and leaves its final pass decision to the runner and gating verifiers.
236
375
  */
237
376
  async function measureTaskOutcome(
238
377
  task: LoadedEvalSuiteV2["suite"]["tasks"][number],
239
378
  cwd: string,
240
- ): Promise<Record<string, number | boolean>> {
379
+ env?: NodeJS.ProcessEnv,
380
+ ): Promise<{ metrics: Record<string, number | boolean>; executionObservation?: EvalExecutionObservationV1 }> {
241
381
  const commands = task.verify.measure ?? [];
242
- if (commands.length === 0) return {};
243
- const result = await runCommandVerifiers(commands, cwd, task.timeoutMs);
244
- return { "task.exitCode": result.exitCode, "task.solved": result.exitCode === 0 };
382
+ if (commands.length === 0) return { metrics: {} };
383
+ const result = await runCommandVerifiers(commands, cwd, task.timeoutMs, env);
384
+ const behavioral = graderBehaviorMeasurement(result.stdout);
385
+ return {
386
+ metrics: {
387
+ "task.exitCode": result.exitCode,
388
+ "task.solved": result.exitCode === 0,
389
+ ...behavioral.metrics,
390
+ },
391
+ ...(behavioral.executionObservation === undefined ? {} : { executionObservation: behavioral.executionObservation }),
392
+ };
393
+ }
394
+
395
+ function graderBehaviorMeasurement(stdout: string): {
396
+ metrics: Record<string, number | boolean>;
397
+ executionObservation?: EvalExecutionObservationV1;
398
+ } {
399
+ const metrics: Record<string, number | boolean> = {};
400
+ let executionObservation: EvalExecutionObservationV1 | undefined;
401
+ for (const line of stdout.split(/\r?\n/u)) {
402
+ if (line.trim().length === 0) continue;
403
+ let value: unknown;
404
+ try {
405
+ value = JSON.parse(line) as unknown;
406
+ } catch {
407
+ continue;
408
+ }
409
+ if (!isRecord(value)) continue;
410
+ if (value.schema === "clio.eval.measure.v1" && isRecord(value.metrics)) {
411
+ for (const [key, metric] of Object.entries(value.metrics)) {
412
+ if (key !== "claims.unsupported" && key !== "completion.reported") continue;
413
+ if (typeof metric === "boolean" || (typeof metric === "number" && Number.isFinite(metric))) metrics[key] = metric;
414
+ }
415
+ }
416
+ if (value.schema === "clio.eval.execution-observation.v1") {
417
+ executionObservation = parseExecutionObservation(value);
418
+ }
419
+ }
420
+ return { metrics, ...(executionObservation === undefined ? {} : { executionObservation }) };
421
+ }
422
+
423
+ function parseExecutionObservation(value: Record<string, unknown>): EvalExecutionObservationV1 {
424
+ const policies = isRecord(value.policyHashes) ? value.policyHashes : {};
425
+ const project = isRecord(value.projectContext) ? value.projectContext : null;
426
+ return {
427
+ compositionHash: nullableDigest(value.compositionHash),
428
+ target: nullableString(value.target),
429
+ wireModel: nullableString(value.wireModel),
430
+ runtime: nullableString(value.runtime),
431
+ thinkingLevel: nullableString(value.thinkingLevel),
432
+ toolSignature: nullableDigest(value.toolSignature),
433
+ autonomy: nullableString(value.autonomy),
434
+ policyHashes: { rulePack: nullableDigest(policies.rulePack), project: nullableDigest(policies.project) },
435
+ projectContext:
436
+ project === null
437
+ ? null
438
+ : {
439
+ tier: nullableString(project.tier),
440
+ contentHash: nullableDigest(project.contentHash),
441
+ chars: nullableNonNegativeInteger(project.chars),
442
+ sections: stringArray(project.sections),
443
+ rulesApplied: stringArray(project.rulesApplied),
444
+ operatorProfileApplied:
445
+ typeof project.operatorProfileApplied === "boolean" ? project.operatorProfileApplied : null,
446
+ },
447
+ };
245
448
  }
246
449
 
247
450
  async function runVerifiers(
@@ -293,6 +496,7 @@ function buildArtifact(
293
496
  evalId: string,
294
497
  results: EvalArtifactResultV4[],
295
498
  clioEntry: string,
499
+ servingConfiguration: EvalServingConfigurationV1,
296
500
  ): EvalArtifactV4 {
297
501
  const passed = results.filter((result) => result.pass).length;
298
502
  return {
@@ -301,7 +505,11 @@ function buildArtifact(
301
505
  suite: { id: loaded.suite.suite.id, hash: loaded.hash },
302
506
  clio: evalClioProvenance({ entry: clioEntry }),
303
507
  environment: evalEnvironmentProvenance(),
304
- matrix: artifactMatrixIdentity(loaded.suite.matrix.targets),
508
+ matrix: {
509
+ ...artifactMatrixIdentity(loaded.suite.matrix.targets),
510
+ ...(loaded.suite.matrix.dimensions === undefined ? {} : { dimensions: loaded.suite.matrix.dimensions }),
511
+ },
512
+ servingConfiguration,
305
513
  summary: {
306
514
  runs: results.length,
307
515
  passed,
@@ -310,6 +518,9 @@ function buildArtifact(
310
518
  tokens: tokenAccountingFrom(results),
311
519
  wallTimeMs: results.reduce((sum, result) => sum + wallTimeMetric(result.metrics), 0),
312
520
  },
521
+ aggregates: aggregateEvalVerdicts(
522
+ results.flatMap((result) => (result.verdict === undefined ? [] : [result.verdict])),
523
+ ),
313
524
  results,
314
525
  };
315
526
  }
@@ -317,3 +528,23 @@ function buildArtifact(
317
528
  function assertionMessage(assertion: EvalMetricAssertion, actual: number | string | boolean | null): string {
318
529
  return `assertion failed: ${assertion.metric} ${assertion.op} ${String(assertion.value)} (actual ${JSON.stringify(actual)})`;
319
530
  }
531
+
532
+ function isRecord(value: unknown): value is Record<string, unknown> {
533
+ return typeof value === "object" && value !== null && !Array.isArray(value);
534
+ }
535
+
536
+ function nullableString(value: unknown): string | null {
537
+ return typeof value === "string" && value.length > 0 ? value : null;
538
+ }
539
+
540
+ function nullableDigest(value: unknown): string | null {
541
+ return typeof value === "string" && /^[a-f0-9]{64}$/u.test(value) ? value : null;
542
+ }
543
+
544
+ function nullableNonNegativeInteger(value: unknown): number | null {
545
+ return typeof value === "number" && Number.isInteger(value) && value >= 0 ? value : null;
546
+ }
547
+
548
+ function stringArray(value: unknown): string[] {
549
+ return Array.isArray(value) ? value.filter((entry): entry is string => typeof entry === "string") : [];
550
+ }
@@ -12,12 +12,13 @@ export async function runCommandVerifiers(
12
12
  commands: ReadonlyArray<string>,
13
13
  cwd: string,
14
14
  timeoutMs: number,
15
+ env?: NodeJS.ProcessEnv,
15
16
  ): Promise<CommandVerifierResult> {
16
17
  let stdout = "";
17
18
  let stderr = "";
18
19
  let wallTimeMs = 0;
19
20
  for (const command of commands) {
20
- const result = await runShellCommand(command, cwd, timeoutMs);
21
+ const result = await runShellCommand(command, cwd, timeoutMs, env);
21
22
  stdout += result.stdout;
22
23
  stderr += result.stderr;
23
24
  wallTimeMs += result.wallTimeMs;
@@ -1,29 +1,161 @@
1
- import { cp, mkdtemp, rm } from "node:fs/promises";
1
+ import { execFile } from "node:child_process";
2
+ import { cp, lstat, mkdtemp, rm } from "node:fs/promises";
2
3
  import { tmpdir } from "node:os";
3
4
  import { relative, resolve } from "node:path";
5
+ import { promisify } from "node:util";
4
6
  import type { EvalWorkspaceV2 } from "../schema/suite.js";
5
7
  import type { PreparedEvalWorkspace } from "./local.js";
6
8
 
9
+ const execFileAsync = promisify(execFile);
10
+ const GIT_FILE_LIST_LIMIT_BYTES = 128 * 1024 * 1024;
11
+
12
+ export interface EvalWorkspaceCopyOptions {
13
+ recursive: true;
14
+ filter: (source: string, destination: string) => boolean;
15
+ }
16
+
17
+ export type EvalWorkspaceCopy = (
18
+ source: string,
19
+ destination: string,
20
+ options: EvalWorkspaceCopyOptions,
21
+ ) => Promise<void>;
22
+
23
+ export interface PrepareTempCopyWorkspaceOptions {
24
+ /** Test/integration seam; production uses node:fs/promises.cp. */
25
+ copy?: EvalWorkspaceCopy;
26
+ /** Parent for both workspace and suite-owned state directories. */
27
+ tempRoot?: string;
28
+ }
29
+
7
30
  export async function prepareTempCopyWorkspace(
8
31
  baseDir: string,
9
32
  workspace: EvalWorkspaceV2,
33
+ options: PrepareTempCopyWorkspaceOptions = {},
10
34
  ): Promise<PreparedEvalWorkspace> {
11
35
  const source = resolve(baseDir, workspace.path ?? ".");
12
- const dest = await mkdtemp(resolve(tmpdir(), "clio-eval-workspace-"));
13
- const excludes = workspace.excludes ?? [];
14
- await cp(source, dest, {
15
- recursive: true,
16
- filter: (path) => !isExcluded(relative(source, path), excludes),
17
- });
18
- return {
19
- dir: dest,
20
- cleanup: async () => {
21
- await rm(dest, { recursive: true, force: true });
22
- },
23
- };
36
+ const dest = await mkdtemp(resolve(options.tempRoot ?? tmpdir(), "clio-eval-workspace-"));
37
+ try {
38
+ const selection = await gitCopySelection(source);
39
+ const excludes = workspace.excludes ?? [];
40
+ const copyWorkspace = options.copy ?? defaultCopy;
41
+ await copyWorkspace(source, dest, {
42
+ recursive: true,
43
+ filter: (path) => shouldCopy(relative(source, path), excludes, selection),
44
+ });
45
+ return {
46
+ dir: dest,
47
+ cleanup: async () => {
48
+ await rm(dest, { recursive: true, force: true });
49
+ },
50
+ };
51
+ } catch (error) {
52
+ // `mkdtemp` succeeded before either Git enumeration or the recursive
53
+ // copy could throw. The preparer still owns that incomplete destination.
54
+ await rm(dest, { recursive: true, force: true });
55
+ throw error;
56
+ }
24
57
  }
25
58
 
26
59
  function isExcluded(rel: string, excludes: ReadonlyArray<string>): boolean {
27
60
  const normalized = rel.replaceAll("\\", "/");
28
61
  return excludes.some((entry) => normalized === entry || normalized.startsWith(`${entry.replaceAll("\\", "/")}/`));
29
62
  }
63
+
64
+ async function defaultCopy(source: string, destination: string, options: EvalWorkspaceCopyOptions): Promise<void> {
65
+ await cp(source, destination, options);
66
+ }
67
+
68
+ interface GitCopySelection {
69
+ files: ReadonlySet<string>;
70
+ directories: ReadonlySet<string>;
71
+ }
72
+
73
+ function shouldCopy(
74
+ relativePath: string,
75
+ excludes: ReadonlyArray<string>,
76
+ selection: GitCopySelection | null,
77
+ ): boolean {
78
+ const normalized = relativePath.replaceAll("\\", "/");
79
+ if (normalized.length === 0) return true;
80
+ if (isExcluded(normalized, excludes)) return false;
81
+ if (selection === null) return true;
82
+ return selection.files.has(normalized) || selection.directories.has(normalized);
83
+ }
84
+
85
+ /**
86
+ * A Git checkout supplies the authoritative copy set: tracked files plus
87
+ * untracked files that are not ignored. Outside Git, null preserves the
88
+ * existing recursive-copy behavior.
89
+ */
90
+ async function gitCopySelection(source: string): Promise<GitCopySelection | null> {
91
+ let inside: string;
92
+ try {
93
+ inside = await gitOutput(source, ["rev-parse", "--is-inside-work-tree"]);
94
+ } catch (error) {
95
+ // Outside a checkout, Git's refusal selects the legacy recursive path. A
96
+ // checkout whose Git query broke must fail closed: falling back there can
97
+ // silently copy the ignored data this branch exists to exclude.
98
+ if (await hasGitMarker(source)) throw error;
99
+ return null;
100
+ }
101
+ if (inside.trim() !== "true") return null;
102
+
103
+ const output = await gitOutput(source, [
104
+ "--literal-pathspecs",
105
+ "ls-files",
106
+ "-z",
107
+ "--cached",
108
+ "--others",
109
+ "--exclude-standard",
110
+ "--",
111
+ ".",
112
+ ]);
113
+ const files = new Set<string>();
114
+ const directories = new Set<string>();
115
+ for (const path of output.split("\0")) {
116
+ if (path.length === 0) continue;
117
+ const normalized = normalizeGitPath(path);
118
+ if (normalized === null) throw new Error("git ls-files returned a path outside the eval workspace");
119
+ files.add(normalized);
120
+ let separator = normalized.lastIndexOf("/");
121
+ while (separator >= 0) {
122
+ directories.add(normalized.slice(0, separator));
123
+ separator = normalized.lastIndexOf("/", separator - 1);
124
+ }
125
+ }
126
+ return { files, directories };
127
+ }
128
+
129
+ async function gitOutput(cwd: string, args: ReadonlyArray<string>): Promise<string> {
130
+ const { stdout } = await execFileAsync("git", [...args], {
131
+ cwd,
132
+ encoding: "utf8",
133
+ maxBuffer: GIT_FILE_LIST_LIMIT_BYTES,
134
+ });
135
+ return stdout;
136
+ }
137
+
138
+ function normalizeGitPath(path: string): string | null {
139
+ const normalized = path.replaceAll("\\", "/").replace(/^\.\//u, "");
140
+ if (normalized.length === 0 || normalized.startsWith("/") || /^[A-Za-z]:\//u.test(normalized)) return null;
141
+ const segments = normalized.split("/");
142
+ if (segments.some((segment) => segment.length === 0 || segment === "." || segment === "..")) return null;
143
+ return normalized;
144
+ }
145
+
146
+ async function hasGitMarker(source: string): Promise<boolean> {
147
+ let current = resolve(source);
148
+ while (true) {
149
+ try {
150
+ await lstat(resolve(current, ".git"));
151
+ return true;
152
+ } catch (error) {
153
+ const code =
154
+ typeof error === "object" && error !== null && "code" in error ? (error as { code?: unknown }).code : undefined;
155
+ if (code !== "ENOENT" && code !== "ENOTDIR") throw error;
156
+ }
157
+ const parent = resolve(current, "..");
158
+ if (parent === current) return false;
159
+ current = parent;
160
+ }
161
+ }