@iowarp/clio-coder 0.4.1 → 0.4.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (604) hide show
  1. package/CHANGELOG.md +127 -0
  2. package/CONTRIBUTING.md +142 -52
  3. package/README.md +434 -473
  4. package/SECURITY.md +2 -1
  5. package/dist/{acp-ZILU3AUO.js → acp-H2NGRPWO.js} +12 -12
  6. package/dist/{agents-HYWGBGQR.js → agents-TL5LLUQP.js} +56 -55
  7. package/dist/assets/codewiki.json +1 -1
  8. package/dist/{auth-N3QT7CBO.js → auth-E5SW4HMS.js} +23 -21
  9. package/dist/builtins-IA7V7FUC.js +22 -0
  10. package/dist/{chunk-7RY5VZPH.js → chunk-2APPQIER.js} +8 -8
  11. package/dist/{chunk-72GZI5EV.js → chunk-2JH2WHGE.js} +2 -2
  12. package/dist/{chunk-JA5QWE4Z.js → chunk-2UG5F4C5.js} +1973 -1664
  13. package/dist/{chunk-5YHDIDBP.js → chunk-2UH2KFUP.js} +2 -2
  14. package/dist/{chunk-CTJ4RNAA.js → chunk-2VIKGWFZ.js} +2 -2
  15. package/dist/{chunk-I66EAJFY.js → chunk-2WZ546HR.js} +267 -232
  16. package/dist/{chunk-GIZNH63R.js → chunk-35MSIRKH.js} +9 -4
  17. package/dist/chunk-3EBYEESD.js +314 -0
  18. package/dist/{chunk-J5LZHVIT.js → chunk-3M6DQK6S.js} +113 -35
  19. package/dist/{chunk-RKSR6VSF.js → chunk-4IUZQIJ3.js} +29 -1
  20. package/dist/{chunk-6FN3E6KX.js → chunk-4O6MANBS.js} +2 -2
  21. package/dist/chunk-4UVU7BJ5.js +39 -0
  22. package/dist/{chunk-VKRH2TCS.js → chunk-4WR7VSYB.js} +2 -2
  23. package/dist/{chunk-BBTJOK6Y.js → chunk-54CBCGIR.js} +5 -5
  24. package/dist/{chunk-AP73CFDC.js → chunk-5ICU3EUH.js} +2 -2
  25. package/dist/chunk-5MEZN6CB.js +1334 -0
  26. package/dist/{chunk-O42A54GG.js → chunk-5OIVVPHF.js} +2 -2
  27. package/dist/{chunk-ABLSQ6JX.js → chunk-64I3JVYM.js} +8 -2
  28. package/dist/{chunk-AFKWHWXF.js → chunk-6PTFB5VS.js} +39 -22
  29. package/dist/{chunk-VN3SHNBN.js → chunk-7DICMOS6.js} +2 -2
  30. package/dist/chunk-7DRAWPTZ.js +360 -0
  31. package/dist/chunk-7E7I3WLS.js +3762 -0
  32. package/dist/{chunk-BJGUKIG4.js → chunk-7ZYNNDKC.js} +7 -7
  33. package/dist/{chunk-XKA2ICR3.js → chunk-AF4YM7Z4.js} +652 -252
  34. package/dist/{chunk-GVQJ5CCZ.js → chunk-AX2THNSA.js} +12 -12
  35. package/dist/{chunk-IG7BCQBA.js → chunk-B4OAX3SI.js} +65 -3
  36. package/dist/{chunk-TD3PGPQA.js → chunk-B4VEBZKF.js} +3 -3
  37. package/dist/{chunk-74YWRRU5.js → chunk-BEPZRGGU.js} +10 -10
  38. package/dist/{chunk-FEFIFZTL.js → chunk-CE5AX47J.js} +2 -2
  39. package/dist/{chunk-UAPGZHYC.js → chunk-DWUOQKRU.js} +25 -11
  40. package/dist/{chunk-THYWACCR.js → chunk-E3TPLWFX.js} +3 -3
  41. package/dist/{chunk-7EPLI7VL.js → chunk-EKCHAPYA.js} +2 -2
  42. package/dist/{chunk-HLW2MRKE.js → chunk-F4EKGO4N.js} +3 -1
  43. package/dist/{chunk-PJJ6MY27.js → chunk-F5JHEYZM.js} +7 -7
  44. package/dist/{chunk-6CCS4G3W.js → chunk-FTMGRKEF.js} +3 -3
  45. package/dist/{chunk-SINK3QR6.js → chunk-G76U63X4.js} +17 -17
  46. package/dist/{chunk-EIMVLWB3.js → chunk-GHS5EBTQ.js} +64 -9
  47. package/dist/{chunk-QMXC4JB7.js → chunk-GI7YYQ3F.js} +187 -1419
  48. package/dist/{chunk-TZSKNMZG.js → chunk-GTUD2WMY.js} +2 -1
  49. package/dist/{chunk-6HMJX2VU.js → chunk-GWZNEVM2.js} +44 -12
  50. package/dist/chunk-GYV6VZOC.js +26 -0
  51. package/dist/{chunk-MQXIVJ35.js → chunk-HAXOFFRH.js} +5 -5
  52. package/dist/{chunk-UXN6JT4W.js → chunk-HEQY7ZFI.js} +3 -3
  53. package/dist/{chunk-7PWAODYW.js → chunk-I7XBWTYH.js} +2 -2
  54. package/dist/{chunk-GCSMB2KY.js → chunk-I7ZPNEJM.js} +145 -102
  55. package/dist/{chunk-WNP7O5WZ.js → chunk-ID64D7PE.js} +4 -4
  56. package/dist/{chunk-QTFGO774.js → chunk-IGLP3ODT.js} +29 -16
  57. package/dist/chunk-IJNZMHLA.js +101 -0
  58. package/dist/{chunk-BDPT6GTK.js → chunk-INY6HTFL.js} +7 -7
  59. package/dist/{chunk-PBP4B7XR.js → chunk-IUE3Y34X.js} +2 -2
  60. package/dist/{chunk-6NJQITNH.js → chunk-IWT4SF4R.js} +6 -3
  61. package/dist/{chunk-R23Z6K6I.js → chunk-JDAY6FIL.js} +19 -19
  62. package/dist/chunk-JEQ3XTHC.js +42 -0
  63. package/dist/{chunk-FSP7CMNU.js → chunk-JGRC33J2.js} +50 -4
  64. package/dist/{chunk-TVH4ONAM.js → chunk-JKKCYP3C.js} +10 -10
  65. package/dist/{chunk-HJWWJ6IL.js → chunk-JSC3U7TI.js} +16 -4
  66. package/dist/{chunk-C537JADH.js → chunk-KK4JZPBQ.js} +19 -141
  67. package/dist/{chunk-K6BF4U2H.js → chunk-KKOJXO6R.js} +62 -14
  68. package/dist/{chunk-IHXBNWMM.js → chunk-KXDSS5WJ.js} +7 -3
  69. package/dist/{chunk-6DWBAZ5U.js → chunk-L47TF46W.js} +5 -7
  70. package/dist/{chunk-HUAS7ITX.js → chunk-LDJG7DW3.js} +91 -42
  71. package/dist/{chunk-CDNVLKUX.js → chunk-LLDJM5XK.js} +13 -7
  72. package/dist/{chunk-YPI3QQCF.js → chunk-MCEPRMZW.js} +2 -4
  73. package/dist/{chunk-Y4CAGMM6.js → chunk-MNJGS2IN.js} +5 -6
  74. package/dist/{chunk-VKFQTNDV.js → chunk-MUW2BDDH.js} +4 -4
  75. package/dist/{chunk-E67WX76H.js → chunk-MWUZBSAQ.js} +104 -152
  76. package/dist/{chunk-OJTRZGR3.js → chunk-N2Z7HLVY.js} +21 -21
  77. package/dist/{chunk-TVHHYFHE.js → chunk-NEDJ26B5.js} +2 -2
  78. package/dist/{chunk-FYUN5KZ3.js → chunk-NIQJ66N4.js} +21 -21
  79. package/dist/{chunk-U2WB7TZS.js → chunk-NMJXSHBJ.js} +97 -85
  80. package/dist/{chunk-CWVRRIEI.js → chunk-NZMNUPZZ.js} +2 -2
  81. package/dist/{chunk-VEGN6WIQ.js → chunk-O5CVSAG5.js} +3 -3
  82. package/dist/{chunk-MOPSG2X7.js → chunk-OML5D5V5.js} +8 -8
  83. package/dist/{chunk-2VG7KLYV.js → chunk-PAJQJ7BS.js} +5816 -3255
  84. package/dist/{chunk-ZW55JB7N.js → chunk-PUVDKJ2Y.js} +2 -2
  85. package/dist/{chunk-BTGG6BG2.js → chunk-QWGDJJYJ.js} +158 -19
  86. package/dist/chunk-R6Q67RJH.js +134 -0
  87. package/dist/{chunk-ZJLUDYFY.js → chunk-RRNP2ANY.js} +6 -6
  88. package/dist/{chunk-PVAMAVBB.js → chunk-RSJ25QSL.js} +102 -2
  89. package/dist/{chunk-NLFAQR7Z.js → chunk-S66XZJOF.js} +3 -23
  90. package/dist/chunk-SKHCAU7K.js +385 -0
  91. package/dist/chunk-SZAA6XDG.js +30 -0
  92. package/dist/{chunk-J4HBWF6Y.js → chunk-TM6LQDI3.js} +131 -28
  93. package/dist/chunk-UOIZ7DA4.js +41 -0
  94. package/dist/{chunk-MA3H6DM5.js → chunk-UPZU6GE4.js} +25 -3
  95. package/dist/{chunk-BWW4HLO4.js → chunk-UXCU4E3T.js} +8 -6
  96. package/dist/{chunk-N5UK64DP.js → chunk-V2ANDPVT.js} +4 -4
  97. package/dist/{chunk-AK5XEFVZ.js → chunk-VA5FNYMT.js} +26 -13
  98. package/dist/{chunk-6VC4OV3Z.js → chunk-VIA6RFQZ.js} +3 -11
  99. package/dist/{chunk-ZAZB4JMW.js → chunk-VKPAQYEB.js} +27 -8
  100. package/dist/{chunk-QKIFBZKT.js → chunk-VW6DOEDG.js} +497 -81
  101. package/dist/{chunk-SCYB3HA4.js → chunk-W6RRQCPQ.js} +63 -19
  102. package/dist/{chunk-2NM363SV.js → chunk-WBKFA554.js} +10 -10
  103. package/dist/{chunk-R32CLGZ6.js → chunk-WCXUNS7U.js} +82 -21
  104. package/dist/{chunk-GPPB3JBE.js → chunk-WRBAGUNF.js} +3 -3
  105. package/dist/{chunk-IXJT6DCX.js → chunk-XIVNBFZS.js} +85 -30
  106. package/dist/{chunk-UEDMSP56.js → chunk-XPWWI35G.js} +417 -201
  107. package/dist/chunk-XRZT5WY5.js +47 -0
  108. package/dist/{chunk-3QSOM6PA.js → chunk-Y3CBHOR6.js} +2 -2
  109. package/dist/{chunk-VXMFAE2W.js → chunk-YPC6ZR5L.js} +19 -6
  110. package/dist/{chunk-AKB4GYDL.js → chunk-YQWYVTMC.js} +5 -5
  111. package/dist/{chunk-6I5ILFOF.js → chunk-ZA4VCIGV.js} +3 -3
  112. package/dist/{chunk-7OBGU7UB.js → chunk-ZDN3Y73Y.js} +12 -18
  113. package/dist/{chunk-3I5NY75V.js → chunk-ZWPRK62N.js} +8 -5
  114. package/dist/cli/index.js +41 -39
  115. package/dist/{clio-IT3G3VQH.js → clio-CMMK4KRR.js} +9 -9
  116. package/dist/{code-nav-RK6S7F6E.js → code-nav-MDZNQS33.js} +89 -21
  117. package/dist/{components-UBWCQSRW.js → components-UCUQ4QXW.js} +4 -4
  118. package/dist/{config-3QZRWZJF.js → config-SVM5P5YI.js} +131 -84
  119. package/dist/{configure-FL7Y3KJF.js → configure-LE3IK2TJ.js} +28 -26
  120. package/dist/{context-5HE7ODYK.js → context-2OHRKS42.js} +69 -64
  121. package/dist/{context-KYQFRVDC.js → context-E3VC7RX5.js} +15 -11
  122. package/dist/{context-XNHL75JV.js → context-VNCR7KAG.js} +93 -65
  123. package/dist/{context-clear-N545L53A.js → context-clear-BW4O37TG.js} +64 -60
  124. package/dist/context-map-COB37XXN.js +505 -0
  125. package/dist/{context-working-set-QHKXSV2F.js → context-working-set-VDS25HXZ.js} +19 -18
  126. package/dist/{dispatch-runner-RGIE5PCT.js → dispatch-runner-5AHT53RF.js} +93 -82
  127. package/dist/{docs-5NAF6AU7.js → docs-PD3EXDKU.js} +21 -20
  128. package/dist/{doctor-ZGPEGHIP.js → doctor-WNNVO6FY.js} +48 -47
  129. package/dist/{eval-GXLL44RD.js → eval-7G7SGAYO.js} +287 -115
  130. package/dist/{eval-inventory-HBWSWQOK.js → eval-inventory-Y6QRFOH5.js} +4 -4
  131. package/dist/{evidence-HWLBRH3Q.js → evidence-VD6736FQ.js} +67 -64
  132. package/dist/{evolve-FTZBMNVW.js → evolve-AL3NGVRL.js} +65 -62
  133. package/dist/{extensions-VHRBEID7.js → extensions-MOVJ32NM.js} +9 -7
  134. package/dist/{fleet-CKZHJWZJ.js → fleet-QZHUMAGI.js} +114 -111
  135. package/dist/{fleet-commands-EXDXBMV6.js → fleet-commands-BAYT5FJZ.js} +10 -10
  136. package/dist/{fleet-decisions-OTHB6KRL.js → fleet-decisions-IREVMRU4.js} +7 -6
  137. package/dist/{fleet-graph-YTEZUCUT.js → fleet-graph-YCTT3HTI.js} +22 -19
  138. package/dist/{fleet-inspect-SS6YMDCK.js → fleet-inspect-QVJTDAVB.js} +58 -55
  139. package/dist/{fleet-preflight-PBY4VYOM.js → fleet-preflight-25QAFPK4.js} +4 -4
  140. package/dist/{fleet-validate-KMEM5L3S.js → fleet-validate-5O57AAJ7.js} +26 -23
  141. package/dist/{fleet-verify-QD5M7E7Q.js → fleet-verify-CPH2W2T6.js} +59 -56
  142. package/dist/{fleet-view-WAMJYNDT.js → fleet-view-SWBR3VGQ.js} +58 -55
  143. package/dist/{init-5XQRBOFV.js → init-J477LKZH.js} +82 -79
  144. package/dist/{interop-34TVO25M.js → interop-3FCM6XLG.js} +11 -11
  145. package/dist/{library-3QY6KF57.js → library-QUQEIUG6.js} +30 -27
  146. package/dist/{memory-L4UTIIIW.js → memory-SGGSEP65.js} +67 -64
  147. package/dist/{models-ZVX3QOWE.js → models-HEKUAXXK.js} +53 -46
  148. package/dist/{monitor-CEKVSYTS.js → monitor-HKU57TYQ.js} +63 -60
  149. package/dist/{orchestrator-77BAP6BC.js → orchestrator-VDFAEFAI.js} +1831 -1057
  150. package/dist/{panes-7STHOAUJ.js → panes-DN2SSFOH.js} +5 -5
  151. package/dist/{panes-SHAUIRXY.js → panes-TALGNPZT.js} +29 -14
  152. package/dist/{paths-L7LGY6RN.js → paths-NBMFAIEZ.js} +5 -5
  153. package/dist/reset-EAJFFJVB.js +344 -0
  154. package/dist/{resources-74GKTLSF.js → resources-OVKSEFVE.js} +29 -20
  155. package/dist/{run-HBAUJNNZ.js → run-7DP7ZF2J.js} +120 -115
  156. package/dist/{share-G3APVLVP.js → share-WML67FT3.js} +32 -27
  157. package/dist/{skills-35HHUKCR.js → skills-SG662R2K.js} +41 -31
  158. package/dist/{skills-eval-QN4HSHDC.js → skills-eval-VVZEUU46.js} +78 -77
  159. package/dist/{skills-inventory-J357J34F.js → skills-inventory-I2E23GET.js} +23 -20
  160. package/dist/{slash-commands-JZZCQA32.js → slash-commands-S7MBJDQK.js} +40 -36
  161. package/dist/{steer-XAVHJM22.js → steer-2LQOMCPB.js} +3 -3
  162. package/dist/{support-U7QOWY26.js → support-CC2UJBJ6.js} +6 -6
  163. package/dist/{targets-DSM6CY3M.js → targets-4QC3HIEW.js} +54 -54
  164. package/dist/{terminal-lease-JOPFUVEM.js → terminal-lease-TUHIJ6Y2.js} +5 -5
  165. package/dist/{tools-MKNWVPBH.js → tools-TFGJICCU.js} +10 -10
  166. package/dist/{trace-ECQ7TIYZ.js → trace-FXMXUZUF.js} +55 -7
  167. package/dist/uninstall-5PEVOE5B.js +408 -0
  168. package/dist/upgrade-M4WXY6KN.js +303 -0
  169. package/dist/{usage-X52N3IDJ.js → usage-N7ZNVLEM.js} +151 -104
  170. package/dist/{verifiers-EJTVVSMA.js → verifiers-DJTP4XX6.js} +15 -15
  171. package/dist/{verify-YJL6XET2.js → verify-RWE4PPEK.js} +9 -9
  172. package/dist/{web-fetch-MPIFL3LL.js → web-fetch-MPARV2K7.js} +2 -2
  173. package/dist/{wiki-generate-4NDZTQ4B.js → wiki-generate-C7IQOXSP.js} +89 -86
  174. package/dist/{with-panes-OBOBFIIR.js → with-panes-4GCGSL7J.js} +53 -257
  175. package/dist/worker/entry.js +90 -74
  176. package/docs/README.md +176 -81
  177. package/docs/{acp.md → architecture/acp.md} +36 -20
  178. package/docs/{alcf-provider.md → architecture/alcf-provider.md} +8 -5
  179. package/docs/{architecture.md → architecture/architecture.md} +43 -22
  180. package/docs/{artifact-placement.md → architecture/artifact-placement.md} +27 -23
  181. package/docs/architecture/artifact-versions.md +90 -0
  182. package/docs/{capacity-and-scheduling.md → architecture/capacity-and-scheduling.md} +26 -13
  183. package/docs/{context-engine.md → architecture/context-engine.md} +29 -25
  184. package/docs/{context-working-set.md → architecture/context-working-set.md} +13 -10
  185. package/docs/{dispatch-architecture-rationale.md → architecture/dispatch-architecture-rationale.md} +12 -9
  186. package/docs/{dispatch-typed-intent.md → architecture/dispatch-typed-intent.md} +68 -46
  187. package/docs/{evidence-and-memory.md → architecture/evidence-and-memory.md} +23 -16
  188. package/docs/{middleware-and-components.md → architecture/middleware-and-components.md} +11 -5
  189. package/docs/{model-catalog.md → architecture/model-catalog.md} +61 -27
  190. package/docs/{observability.md → architecture/observability.md} +38 -14
  191. package/docs/{pi-boundary.md → architecture/pi-boundary.md} +24 -11
  192. package/docs/{prompt-envelope-and-tools.md → architecture/prompt-envelope-and-tools.md} +57 -20
  193. package/docs/{provider-adapter-cookbook.md → architecture/provider-adapter-cookbook.md} +99 -25
  194. package/docs/{safety-model.md → architecture/safety-model.md} +35 -20
  195. package/docs/{session-lifecycle.md → architecture/session-lifecycle.md} +8 -5
  196. package/docs/architecture/time-conventions.md +125 -0
  197. package/docs/{trace-store.md → architecture/trace-store.md} +13 -5
  198. package/docs/{tui-design.md → architecture/tui-design.md} +13 -13
  199. package/docs/{worker-dispatch-mechanics.md → architecture/worker-dispatch-mechanics.md} +27 -30
  200. package/docs/{built-in-agents.md → guide/built-in-agents.md} +65 -35
  201. package/docs/{commands-and-modes.md → guide/commands-and-modes.md} +66 -61
  202. package/docs/{configuration-and-targets.md → guide/configuration-and-targets.md} +323 -297
  203. package/docs/guide/configuration-reference.md +1163 -0
  204. package/docs/{environment-variables.md → guide/environment-variables.md} +33 -28
  205. package/docs/{exit-codes-and-output.md → guide/exit-codes-and-output.md} +6 -3
  206. package/docs/{extensions-and-sharing.md → guide/extensions-and-sharing.md} +41 -14
  207. package/docs/{fleet-dispatch.md → guide/fleet-dispatch.md} +39 -43
  208. package/docs/{glossary.md → guide/glossary.md} +14 -11
  209. package/docs/{installation-and-lifecycle.md → guide/installation-and-lifecycle.md} +81 -17
  210. package/docs/guide/panes-and-files.md +290 -0
  211. package/docs/{proactive-memory.md → guide/proactive-memory.md} +131 -107
  212. package/docs/{resource-library.md → guide/resource-library.md} +13 -4
  213. package/docs/{skills-marketplace.md → guide/skills-marketplace.md} +25 -3
  214. package/docs/{tool-usage.md → guide/tool-usage.md} +87 -23
  215. package/docs/{troubleshooting.md → guide/troubleshooting.md} +9 -4
  216. package/docs/{config-knobs-audit.md → history/config-knobs-audit.md} +11 -11
  217. package/docs/{release-cut-checklist.md → history/release-cut-checklist.md} +29 -2
  218. package/docs/process/development-pipeline.md +152 -0
  219. package/docs/process/documentation-coverage.md +100 -0
  220. package/docs/process/documentation-guide.md +187 -0
  221. package/docs/{eval-runner.md → process/eval-runner.md} +108 -53
  222. package/docs/{evals-internal.md → process/evals-internal.md} +10 -10
  223. package/docs/{evolution.md → process/evolution.md} +2 -2
  224. package/docs/{fleet-demo-runbook.md → process/fleet-demo-runbook.md} +11 -7
  225. package/docs/{git-commit-provenance.md → process/git-commit-provenance.md} +11 -4
  226. package/docs/{performance-methodology.md → process/performance-methodology.md} +87 -69
  227. package/docs/{scientific-validation.md → process/scientific-validation.md} +4 -4
  228. package/evals/README.md +2 -2
  229. package/evals/behavioral-model.yaml +3 -2
  230. package/package.json +10 -8
  231. package/skills/README.md +52 -41
  232. package/skills/coding/ast-grep/SKILL.md +102 -31
  233. package/skills/coding/ast-grep/evals.md +26 -0
  234. package/skills/coding/coding-standards/SKILL.md +41 -6
  235. package/skills/coding/coding-standards/evals.md +23 -0
  236. package/skills/coding/prototype/SKILL.md +88 -29
  237. package/skills/coding/prototype/evals.md +19 -0
  238. package/skills/coding/tdd/SKILL.md +81 -54
  239. package/skills/coding/tdd/evals.md +20 -0
  240. package/skills/context/context-handoff/SKILL.md +44 -3
  241. package/skills/context/context-handoff/evals.md +44 -0
  242. package/skills/context/context-prime/SKILL.md +46 -16
  243. package/skills/context/context-prime/evals.md +45 -0
  244. package/skills/git/branch-closeout/SKILL.md +132 -0
  245. package/skills/git/branch-closeout/evals.md +133 -0
  246. package/skills/git/branch-closeout/references/closeout-checklist.md +81 -0
  247. package/skills/git/file-ticket/SKILL.md +78 -64
  248. package/skills/git/file-ticket/assets/issue-template.md +22 -0
  249. package/skills/git/file-ticket/evals.md +31 -26
  250. package/skills/git/file-ticket/references/issue-discovery.md +49 -0
  251. package/skills/git/fix-issue/SKILL.md +88 -65
  252. package/skills/git/fix-issue/evals.md +35 -31
  253. package/skills/git/fix-issue/references/diagnosis-and-rca.md +46 -0
  254. package/skills/git/resolve-merge-conflicts/SKILL.md +101 -52
  255. package/skills/git/resolve-merge-conflicts/evals.md +52 -25
  256. package/skills/git/resolve-merge-conflicts/references/conflict-matrix.md +126 -0
  257. package/skills/git/ship/SKILL.md +103 -67
  258. package/skills/git/ship/assets/pr-template.md +21 -0
  259. package/skills/git/ship/evals.md +44 -28
  260. package/skills/git/ship/references/remote-and-branch-policy.md +62 -0
  261. package/skills/git/worktree-create/SKILL.md +80 -50
  262. package/skills/git/worktree-create/evals.md +40 -33
  263. package/skills/git/worktree-create/references/worktree-setup.md +62 -66
  264. package/skills/git/worktree-merge/SKILL.md +112 -65
  265. package/skills/git/worktree-merge/evals.md +42 -34
  266. package/skills/git/worktree-merge/references/merge-strategies.md +52 -0
  267. package/skills/meta/clio-coder-dev/SKILL.md +9 -5
  268. package/skills/meta/clio-coder-dev/evals.md +3 -2
  269. package/skills/meta/clio-coder-test/SKILL.md +102 -95
  270. package/skills/meta/clio-coder-test/evals.md +9 -4
  271. package/skills/meta/clio-coder-test/references/harness.md +100 -124
  272. package/skills/meta/clio-coder-test/references/test-map.md +77 -50
  273. package/skills/meta/credentials/SKILL.md +2 -2
  274. package/skills/meta/find-skills/SKILL.md +2 -2
  275. package/skills/meta/herdr/SKILL.md +2 -2
  276. package/skills/meta/skill-craft/SKILL.md +22 -16
  277. package/skills/planning/archify/SKILL.md +196 -0
  278. package/skills/planning/archify/evals.md +65 -0
  279. package/skills/planning/architecture/SKILL.md +62 -13
  280. package/skills/planning/architecture/evals.md +65 -0
  281. package/skills/planning/backlog/SKILL.md +131 -15
  282. package/skills/planning/backlog/evals.md +142 -0
  283. package/skills/planning/prd/SKILL.md +47 -7
  284. package/skills/planning/prd/evals.md +54 -0
  285. package/skills/planning/product-intent/SKILL.md +58 -3
  286. package/skills/planning/product-intent/evals.md +70 -0
  287. package/skills/planning/tech-spec/SKILL.md +54 -3
  288. package/skills/planning/tech-spec/evals.md +73 -0
  289. package/skills/registry.yaml +70 -62
  290. package/skills/remote.yaml +13 -0
  291. package/skills/research/arxiv-literature/SKILL.md +77 -19
  292. package/skills/research/arxiv-literature/evals.md +50 -0
  293. package/skills/research/experiment-protocol/SKILL.md +21 -2
  294. package/skills/research/experiment-protocol/evals.md +23 -0
  295. package/skills/research/scientific-debugging/SKILL.md +24 -2
  296. package/skills/research/scientific-debugging/evals.md +18 -0
  297. package/skills/research/scientific-modernization/SKILL.md +27 -2
  298. package/skills/research/scientific-modernization/evals.md +27 -0
  299. package/skills/skill-marketplace.json +97 -62
  300. package/skills/workflow/cut-it/SKILL.md +66 -6
  301. package/skills/workflow/cut-it/evals.md +101 -0
  302. package/skills/workflow/design-council/SKILL.md +118 -28
  303. package/skills/workflow/design-council/evals.md +161 -0
  304. package/skills/workflow/grill-me/SKILL.md +87 -11
  305. package/skills/workflow/grill-me/evals.md +153 -0
  306. package/skills/workflow/workflow-distiller/SKILL.md +77 -18
  307. package/skills/workflow/workflow-distiller/evals.md +118 -0
  308. package/src/cli/args.ts +2 -2
  309. package/src/cli/bootstrap-generate.ts +1 -1
  310. package/src/cli/config-inspect.ts +65 -12
  311. package/src/cli/configure-interop.ts +105 -13
  312. package/src/cli/configure-oauth.ts +57 -0
  313. package/src/cli/configure-onboarding.ts +980 -0
  314. package/src/cli/configure-target.ts +594 -0
  315. package/src/cli/configure.ts +1082 -532
  316. package/src/cli/context-map.ts +114 -0
  317. package/src/cli/context.ts +4 -0
  318. package/src/cli/docs.ts +22 -14
  319. package/src/cli/doctor-naming.ts +5 -5
  320. package/src/cli/doctor-toolchain.ts +3 -3
  321. package/src/cli/eval.ts +1 -2
  322. package/src/cli/extensions.ts +2 -1
  323. package/src/cli/fleet.ts +1 -1
  324. package/src/cli/index.ts +3 -1
  325. package/src/cli/internal-dispatch.ts +3 -4
  326. package/src/cli/lifecycle-presenter.ts +436 -0
  327. package/src/cli/models.ts +10 -2
  328. package/src/cli/modes/print.ts +5 -1
  329. package/src/cli/panes.ts +19 -5
  330. package/src/cli/reset.ts +228 -106
  331. package/src/cli/run.ts +9 -4
  332. package/src/cli/select.ts +664 -0
  333. package/src/cli/share.ts +5 -1
  334. package/src/cli/skills-eval.ts +3 -3
  335. package/src/cli/skills.ts +9 -2
  336. package/src/cli/targets.ts +5 -6
  337. package/src/cli/trace.ts +55 -4
  338. package/src/cli/uninstall.ts +233 -165
  339. package/src/cli/upgrade.ts +204 -149
  340. package/src/cli/usage.ts +86 -27
  341. package/src/cli/validate-model.ts +3 -3
  342. package/src/cli/wiki-generate.ts +1 -1
  343. package/src/core/artifact-paths.ts +1 -1
  344. package/src/core/bash-exec.ts +131 -86
  345. package/src/core/bus-events.ts +51 -6
  346. package/src/core/config.ts +61 -1
  347. package/src/core/defaults.ts +7 -4
  348. package/src/core/dispatch-outcome.ts +16 -0
  349. package/src/core/external-diagnostic.ts +44 -0
  350. package/src/core/gateway-routing.ts +157 -0
  351. package/src/core/guardrails.ts +10 -49
  352. package/src/core/prompt-hint.ts +9 -0
  353. package/src/core/safe-exec.ts +17 -2
  354. package/src/core/skill-activation.ts +89 -2
  355. package/src/domains/agents/builtins/architect.md +2 -3
  356. package/src/domains/agents/builtins/coder.md +3 -2
  357. package/src/domains/agents/builtins/debugger.md +2 -2
  358. package/src/domains/agents/builtins/documenter.md +2 -2
  359. package/src/domains/agents/builtins/git-master.md +1 -1
  360. package/src/domains/agents/builtins/oracle.md +1 -1
  361. package/src/domains/agents/builtins/provenance.md +1 -1
  362. package/src/domains/agents/builtins/researcher.md +1 -1
  363. package/src/domains/agents/builtins/scout.md +1 -1
  364. package/src/domains/agents/builtins/tester.md +2 -2
  365. package/src/domains/agents/builtins/verifier.md +2 -2
  366. package/src/domains/agents/builtins/wiki-writer.md +1 -1
  367. package/src/domains/agents/builtins/world-knowledge.md +31 -0
  368. package/src/domains/agents/catalog.ts +13 -15
  369. package/src/domains/agents/contract.ts +2 -0
  370. package/src/domains/agents/extension.ts +23 -1
  371. package/src/domains/agents/result-contract.ts +70 -0
  372. package/src/domains/config/keybindings.ts +8 -0
  373. package/src/domains/context/extension.ts +0 -3
  374. package/src/domains/context/wiki/map-seed.ts +589 -0
  375. package/src/domains/context/wiki/plan.ts +2 -2
  376. package/src/domains/context/working-set/path-index.ts +1 -0
  377. package/src/domains/dispatch/admission.ts +29 -0
  378. package/src/domains/dispatch/agent-candidates.ts +10 -0
  379. package/src/domains/dispatch/budget-envelope.ts +86 -1
  380. package/src/domains/dispatch/capability-match.ts +11 -0
  381. package/src/domains/dispatch/capacity-lease.ts +17 -0
  382. package/src/domains/dispatch/contract.ts +11 -1
  383. package/src/domains/dispatch/extension.ts +237 -49
  384. package/src/domains/dispatch/host-verification.ts +435 -39
  385. package/src/domains/dispatch/intent-requirements.ts +10 -0
  386. package/src/domains/dispatch/intent.ts +18 -1
  387. package/src/domains/dispatch/path-scope.ts +235 -24
  388. package/src/domains/dispatch/run-event-journal.ts +4 -15
  389. package/src/domains/dispatch/state.ts +2 -3
  390. package/src/domains/dispatch/transport.ts +45 -21
  391. package/src/domains/dispatch/types.ts +58 -3
  392. package/src/domains/dispatch/worker-model-metadata.ts +38 -0
  393. package/src/domains/eval/artifacts/store.ts +5 -0
  394. package/src/domains/eval/metrics/call-ledger-stream.ts +34 -11
  395. package/src/domains/eval/metrics/token-stream.ts +201 -31
  396. package/src/domains/eval/metrics/tracked.ts +40 -4
  397. package/src/domains/eval/runners/clio-run.ts +5 -2
  398. package/src/domains/eval/schema/suite.ts +28 -0
  399. package/src/domains/eval/schema/verdict.ts +2 -2
  400. package/src/domains/eval/store.ts +8 -1
  401. package/src/domains/eval/suites/resolve.ts +13 -1
  402. package/src/domains/eval/suites/run.ts +24 -3
  403. package/src/domains/evidence/trust-status.ts +10 -1
  404. package/src/domains/extensions/contract.ts +15 -1
  405. package/src/domains/extensions/discovery.ts +238 -41
  406. package/src/domains/extensions/extension.ts +105 -6
  407. package/src/domains/extensions/index.ts +24 -0
  408. package/src/domains/extensions/integrity.ts +189 -0
  409. package/src/domains/extensions/manager.ts +17 -1
  410. package/src/domains/extensions/resource-path.ts +27 -0
  411. package/src/domains/extensions/resources.ts +18 -38
  412. package/src/domains/extensions/snapshot-store.ts +39 -0
  413. package/src/domains/extensions/snapshot.ts +180 -0
  414. package/src/domains/extensions/state.ts +385 -57
  415. package/src/domains/extensions/types.ts +118 -1
  416. package/src/domains/interop/registry.ts +6 -2
  417. package/src/domains/interop/types.ts +4 -0
  418. package/src/domains/lifecycle/migrations/2026-09-01-extension-install-digests.ts +27 -0
  419. package/src/domains/lifecycle/migrations/index.ts +6 -0
  420. package/src/domains/lifecycle/naming-resources.ts +19 -4
  421. package/src/domains/lifecycle/naming-yazi.ts +10 -5
  422. package/src/domains/memory/task-memory-policy.ts +70 -26
  423. package/src/domains/memory/task-memory-telemetry.ts +1 -0
  424. package/src/domains/middleware/contract.ts +26 -0
  425. package/src/domains/middleware/extension.ts +24 -24
  426. package/src/domains/middleware/hook-receipts.ts +27 -4
  427. package/src/domains/middleware/hooks-io.ts +65 -32
  428. package/src/domains/middleware/hooks.ts +64 -0
  429. package/src/domains/middleware/index.ts +28 -5
  430. package/src/domains/middleware/marketplace-offer.ts +3 -35
  431. package/src/domains/middleware/memory-intervention.ts +127 -32
  432. package/src/domains/middleware/memory-step-endpoint.ts +3 -2
  433. package/src/domains/middleware/registrations.ts +326 -0
  434. package/src/domains/middleware/runtime.ts +28 -0
  435. package/src/domains/middleware/skills-reminder.ts +31 -2
  436. package/src/domains/middleware/snapshot.ts +20 -7
  437. package/src/domains/mux/contract.ts +38 -0
  438. package/src/domains/mux/detect.ts +6 -13
  439. package/src/domains/mux/index.ts +1 -1
  440. package/src/domains/mux/operations.ts +44 -5
  441. package/src/domains/mux/yazi/assets/yazi.toml +2 -2
  442. package/src/domains/mux/yazi/session.ts +53 -4
  443. package/src/domains/mux/yazi/theme.ts +117 -17
  444. package/src/domains/observability/compaction-usage.ts +118 -0
  445. package/src/domains/observability/contract.ts +10 -11
  446. package/src/domains/observability/cost.ts +1 -1
  447. package/src/domains/observability/extension.ts +17 -4
  448. package/src/domains/observability/out-of-turn-usage.ts +52 -21
  449. package/src/domains/observability/projection.ts +14 -90
  450. package/src/domains/observability/trace-store.ts +43 -7
  451. package/src/domains/prompts/compiler.ts +73 -53
  452. package/src/domains/prompts/contract.ts +15 -3
  453. package/src/domains/prompts/extension.ts +97 -9
  454. package/src/domains/prompts/fragments/identity/clio-worker.md +1 -3
  455. package/src/domains/prompts/fragments/identity/clio.md +6 -12
  456. package/src/domains/prompts/fragments/identity/docs-routing.md +1 -2
  457. package/src/domains/prompts/fragments/identity/self-awareness.md +3 -11
  458. package/src/domains/prompts/fragments/operating/contract.md +7 -15
  459. package/src/domains/prompts/fragments/operating/delegation.md +32 -34
  460. package/src/domains/prompts/fragments/operating/skills.md +10 -24
  461. package/src/domains/prompts/fragments/operating/worker.md +1 -8
  462. package/src/domains/providers/contract.ts +4 -1
  463. package/src/domains/providers/extension.ts +40 -9
  464. package/src/domains/providers/index.ts +1 -1
  465. package/src/domains/providers/model-capabilities.ts +9 -0
  466. package/src/domains/providers/model-discovery.ts +2 -0
  467. package/src/domains/providers/model-runtime-capabilities.ts +99 -25
  468. package/src/domains/providers/models/local-models/clio-coder-local-coding-targets.yaml +699 -114
  469. package/src/domains/providers/runtime-resolution.ts +31 -0
  470. package/src/domains/providers/runtimes/antigravity/antigravity-code.ts +225 -45
  471. package/src/domains/providers/runtimes/common/lmstudio-http.ts +6 -2
  472. package/src/domains/providers/runtimes/common/local-synth.ts +2 -0
  473. package/src/domains/providers/runtimes/common/probe-helpers.ts +7 -2
  474. package/src/domains/providers/runtimes/local-native/llamacpp.ts +9 -1
  475. package/src/domains/providers/runtimes/protocol/litellm.ts +119 -29
  476. package/src/domains/providers/support.ts +11 -5
  477. package/src/domains/providers/target-model-cache.ts +25 -2
  478. package/src/domains/providers/types/capability-flags.ts +2 -0
  479. package/src/domains/providers/types/cost-provenance.ts +19 -0
  480. package/src/domains/providers/types/local-model-quirks.ts +85 -37
  481. package/src/domains/providers/types/runtime-descriptor.ts +20 -1
  482. package/src/domains/providers/types/target-descriptor.ts +19 -0
  483. package/src/domains/resources/index.ts +3 -0
  484. package/src/domains/resources/skills/install.ts +72 -7
  485. package/src/domains/resources/skills/loader.ts +23 -19
  486. package/src/domains/resources/skills/marketplace.ts +63 -11
  487. package/src/domains/safety/autonomy.ts +15 -0
  488. package/src/domains/safety/call-target.ts +1 -1
  489. package/src/domains/safety/index.ts +1 -0
  490. package/src/domains/safety/loop-detector.ts +7 -4
  491. package/src/domains/safety/path-policy.ts +1 -1
  492. package/src/domains/safety/policy-engine.ts +34 -11
  493. package/src/domains/safety/protected-artifacts.ts +191 -88
  494. package/src/domains/safety/run-effects.ts +2 -22
  495. package/src/domains/safety/skill-authority.ts +55 -0
  496. package/src/domains/session/compaction/compact.ts +72 -22
  497. package/src/domains/session/entries.ts +6 -0
  498. package/src/domains/session/task-board.ts +10 -9
  499. package/src/domains/session/usage.ts +3 -3
  500. package/src/domains/share/archive.ts +164 -7
  501. package/src/engine/acp/server.ts +62 -9
  502. package/src/engine/agent.ts +13 -3
  503. package/src/engine/ai.ts +26 -8
  504. package/src/engine/antigravity/subprocess-runtime.ts +386 -120
  505. package/src/engine/api-registry.ts +3 -0
  506. package/src/engine/apis/llamacpp-residency.ts +3 -4
  507. package/src/engine/apis/lmstudio.ts +3 -3
  508. package/src/engine/apis/ollama-native.ts +6 -6
  509. package/src/engine/apis/openai-completions.ts +145 -39
  510. package/src/engine/apis/output-budget.ts +8 -18
  511. package/src/engine/apis/residency.ts +8 -27
  512. package/src/engine/external-subprocess.ts +114 -6
  513. package/src/engine/gemma-channel-filter.ts +19 -0
  514. package/src/engine/loop-guard.ts +92 -12
  515. package/src/engine/worker-runtime.ts +40 -11
  516. package/src/engine/worker-tools.ts +3 -1
  517. package/src/entry/background-model-metadata.ts +18 -0
  518. package/src/entry/compaction-prompt.ts +57 -0
  519. package/src/entry/extension-hook-sources.ts +28 -0
  520. package/src/entry/extension-reload.ts +309 -0
  521. package/src/entry/orchestrator.ts +464 -251
  522. package/src/entry/task-memory-lifecycle.ts +35 -0
  523. package/src/interactive/application-controller.ts +2 -1
  524. package/src/interactive/bus-notices.ts +8 -1
  525. package/src/interactive/chat-loop-messages.ts +16 -17
  526. package/src/interactive/chat-loop.ts +75 -3
  527. package/src/interactive/chat-panel.ts +36 -13
  528. package/src/interactive/chat-renderer.ts +72 -7
  529. package/src/interactive/cost-overlay.ts +26 -2
  530. package/src/interactive/dispatch-board.ts +6 -11
  531. package/src/interactive/footer/widgets.ts +13 -0
  532. package/src/interactive/interactive-application.ts +39 -4
  533. package/src/interactive/interactive-input-runtime.ts +4 -0
  534. package/src/interactive/interactive-presentation.ts +2 -2
  535. package/src/interactive/interactive-slash-runtime.ts +4 -1
  536. package/src/interactive/overlays/extensions.ts +9 -1
  537. package/src/interactive/overlays/help-reference.ts +13 -0
  538. package/src/interactive/overlays/settings.ts +27 -16
  539. package/src/interactive/panes-runtime.ts +111 -35
  540. package/src/interactive/prompt-cache-identity.ts +88 -0
  541. package/src/interactive/renderers/worker-entry.ts +32 -0
  542. package/src/interactive/slash-commands.ts +153 -20
  543. package/src/interactive/stream-pacing-policy.ts +0 -23
  544. package/src/interactive/theme/labels.ts +19 -13
  545. package/src/interactive/turn-context.ts +39 -20
  546. package/src/interactive/turn-recovery.ts +8 -0
  547. package/src/interactive/turn-runtime.ts +27 -11
  548. package/src/interactive/turn-state.ts +7 -0
  549. package/src/interactive/worker-receipts.ts +1 -0
  550. package/src/interactive/worker-stream.ts +6 -1
  551. package/src/interactive/yazi-bridge.ts +60 -6
  552. package/src/tools/agent-tools.ts +30 -1
  553. package/src/tools/artifact.ts +2 -2
  554. package/src/tools/ask-user.ts +3 -3
  555. package/src/tools/bash.ts +1 -1
  556. package/src/tools/bootstrap.ts +4 -0
  557. package/src/tools/builtin-tool-catalog.ts +52 -22
  558. package/src/tools/codewiki/code-nav-surface.ts +6 -0
  559. package/src/tools/codewiki/code-nav.ts +99 -13
  560. package/src/tools/context/docs-engine.ts +20 -7
  561. package/src/tools/context/index.ts +59 -21
  562. package/src/tools/core-bootstrap.ts +28 -6
  563. package/src/tools/credential-present.ts +1 -2
  564. package/src/tools/dispatch-arguments.ts +6 -1
  565. package/src/tools/dispatch-event-text.ts +10 -0
  566. package/src/tools/dispatch-plan.ts +49 -4
  567. package/src/tools/dispatch-run-events.ts +1 -1
  568. package/src/tools/dispatch-runner.ts +12 -0
  569. package/src/tools/dispatch-schema.ts +338 -0
  570. package/src/tools/dispatch-types.ts +3 -0
  571. package/src/tools/dispatch.ts +9 -254
  572. package/src/tools/ledger.ts +3 -5
  573. package/src/tools/monitor-surface.ts +5 -13
  574. package/src/tools/observation.ts +4 -5
  575. package/src/tools/panes-surface.ts +4 -11
  576. package/src/tools/panes.ts +4 -2
  577. package/src/tools/policy.ts +15 -2
  578. package/src/tools/read.ts +5 -6
  579. package/src/tools/registry.ts +41 -12
  580. package/src/tools/result-shaping.ts +18 -14
  581. package/src/tools/steer-surface.ts +1 -1
  582. package/src/tools/tasks.ts +1 -1
  583. package/src/tools/truncate.ts +6 -5
  584. package/src/tools/verify/surface.ts +6 -12
  585. package/src/tools/web-fetch-surface.ts +1 -3
  586. package/src/tools/worker-evidence.ts +3 -1
  587. package/src/worker/spec-contract.ts +4 -0
  588. package/dist/builtins-UJLMOVOV.js +0 -17
  589. package/dist/chunk-5QIAJV2D.js +0 -48
  590. package/dist/chunk-JZWT5J3Y.js +0 -814
  591. package/dist/chunk-K7VKOLQQ.js +0 -15
  592. package/dist/chunk-PMZCIOCJ.js +0 -25
  593. package/dist/chunk-SUW5DORT.js +0 -819
  594. package/dist/chunk-UOV2BYIW.js +0 -107
  595. package/dist/chunk-WR6U3OVP.js +0 -45
  596. package/dist/chunk-Y45G3AXC.js +0 -1558
  597. package/dist/reset-EOLM7GVE.js +0 -230
  598. package/dist/uninstall-N34PCTGJ.js +0 -331
  599. package/dist/upgrade-H7TOM7YL.js +0 -323
  600. package/docs/artifact-versions.md +0 -67
  601. package/docs/development-pipeline.md +0 -121
  602. package/docs/documentation-coverage.md +0 -46
  603. package/docs/documentation-guide.md +0 -167
  604. package/docs/time-conventions.md +0 -101
@@ -11,6 +11,11 @@ import { parseEvalVerdictEnvelopeV1 } from "../schema/verdict.js";
11
11
  import { evalRoot } from "../store.js";
12
12
  import { redactArtifactForStorage } from "./redact.js";
13
13
 
14
+ // This is the documented location (docs/architecture/artifact-versions.md's
15
+ // Eval Artifact row): <dataDir>/evals/<evalId>.json, flat. The legacy version-1
16
+ // shape skills-eval writes lives at evalRoot()/skills-eval/ instead
17
+ // (store.ts's evalArtifactPath) so the two writers can never resolve to the
18
+ // same file for the same id.
14
19
  function evalArtifactPathV4(dataDir: string, evalId: string): string {
15
20
  assertSafeId(evalId, "eval");
16
21
  return join(evalRoot(dataDir), `${evalId}.json`);
@@ -6,7 +6,11 @@ export interface EvalCallLedgerFold {
6
6
  entries(): SessionEntry[];
7
7
  }
8
8
 
9
- /** Fold structured assistant completions into the eval's per-call ledger. */
9
+ /**
10
+ * Fold stdout assistant completions into a fallback ledger. These spans start
11
+ * at the provider's message_start, which may follow its response-header wait;
12
+ * they are not complete request latency. Native eval prefers session timing.
13
+ */
10
14
  export function createEvalCallLedgerFold(now: () => number = () => performance.now()): EvalCallLedgerFold {
11
15
  const entries: SessionEntry[] = [];
12
16
  let pending = "";
@@ -21,7 +25,7 @@ export function createEvalCallLedgerFold(now: () => number = () => performance.n
21
25
  activeFirstOutputAt = null;
22
26
  return;
23
27
  }
24
- if (event.type === "message_update" && activeStartedAt !== null && activeFirstOutputAt === null) {
28
+ if (isAssistantOutput(event) && activeStartedAt !== null && activeFirstOutputAt === null) {
25
29
  activeFirstOutputAt = now();
26
30
  return;
27
31
  }
@@ -42,19 +46,25 @@ export function createEvalCallLedgerFold(now: () => number = () => performance.n
42
46
  };
43
47
  if (isRecord(message.backendTimings)) promptCache.backend = structuredClone(message.backendTimings);
44
48
  const previous = entries.at(-1);
49
+ const timestamp = messageTimestamp(message.timestamp);
45
50
  entries.push({
46
51
  kind: "message",
47
52
  role: "assistant",
48
53
  turnId: `eval-call-${entries.length + 1}`,
49
54
  parentTurnId: previous?.turnId ?? null,
50
- timestamp: messageTimestamp(message.timestamp),
55
+ timestamp: timestamp ?? new Date(0).toISOString(),
51
56
  payload: {
57
+ // Retain the legacy ISO placeholder without treating it as observed
58
+ // chronology. Per-call monotonic timing remains usable on its own.
59
+ ...(timestamp === null ? { timestampEstimated: true } : {}),
52
60
  promptCache,
53
- timing: {
54
- ttftMs:
55
- activeStartedAt === null ? null : Math.round(Math.max(0, (activeFirstOutputAt ?? endedAt) - activeStartedAt)),
56
- apiMs: activeStartedAt === null ? 0 : Math.round(Math.max(0, endedAt - activeStartedAt)),
57
- },
61
+ timing:
62
+ activeStartedAt === null
63
+ ? null
64
+ : {
65
+ ttftMs: activeFirstOutputAt === null ? null : Math.round(Math.max(0, activeFirstOutputAt - activeStartedAt)),
66
+ apiMs: Math.round(Math.max(0, endedAt - activeStartedAt)),
67
+ },
58
68
  usage: structuredClone(usage),
59
69
  },
60
70
  });
@@ -82,15 +92,28 @@ export function createEvalCallLedgerFold(now: () => number = () => performance.n
82
92
  };
83
93
  }
84
94
 
95
+ function isAssistantOutput(event: Record<string, unknown>): boolean {
96
+ // Headless chat projects updates to text/thinking deltas; worker stdout
97
+ // retains the nested update. Structural events are not token observations.
98
+ const output = event.type === "message_update" ? event.assistantMessageEvent : event;
99
+ if (!isRecord(output)) return false;
100
+ if (output.type === "toolcall_start") return event.type === "message_update";
101
+ return (
102
+ (output.type === "text_delta" || output.type === "thinking_delta" || output.type === "toolcall_delta") &&
103
+ typeof output.delta === "string" &&
104
+ output.delta.length > 0
105
+ );
106
+ }
107
+
85
108
  function isAssistantMessage(value: unknown): value is Record<string, unknown> & { role: "assistant" } {
86
109
  return isRecord(value) && value.role === "assistant";
87
110
  }
88
111
 
89
- function messageTimestamp(value: unknown): string {
112
+ function messageTimestamp(value: unknown): string | null {
90
113
  const milliseconds = nonNegativeNumber(value);
91
- if (milliseconds === null) return new Date(0).toISOString();
114
+ if (milliseconds === null) return null;
92
115
  const date = new Date(milliseconds);
93
- return Number.isFinite(date.getTime()) ? date.toISOString() : new Date(0).toISOString();
116
+ return Number.isFinite(date.getTime()) ? date.toISOString() : null;
94
117
  }
95
118
 
96
119
  function nonNegativeNumber(value: unknown): number | null {
@@ -1,14 +1,17 @@
1
+ import { extractReasoningTokens } from "../../session/context-accounting.js";
1
2
  import type { EvalTokenMetricsV4 } from "../schema/artifact.js";
2
3
 
3
4
  export interface EvalTokenStreamUsage {
4
5
  /**
5
6
  * True when the stream carried at least one completed assistant message
6
- * with provider usage. False means this runner observed no token
7
+ * with observed token facts. False means this runner observed no token
7
8
  * accounting at all, which is not the same as a run that cost nothing.
8
9
  */
9
10
  measured: boolean;
11
+ /** Known token subtotals; missing failed-call coverage is reported separately. */
10
12
  tokens: EvalTokenMetricsV4;
11
13
  costUsd: number;
14
+ provider: EvalProviderObservation;
12
15
  }
13
16
 
14
17
  export interface EvalTokenUsageFold {
@@ -21,6 +24,7 @@ export const UNMEASURED_TOKEN_USAGE: EvalTokenStreamUsage = {
21
24
  measured: false,
22
25
  tokens: { input: 0, output: 0, total: 0, cacheRead: 0, cacheWrite: 0 },
23
26
  costUsd: 0,
27
+ provider: emptyProviderObservation(),
24
28
  };
25
29
 
26
30
  /**
@@ -30,8 +34,12 @@ export const UNMEASURED_TOKEN_USAGE: EvalTokenStreamUsage = {
30
34
  * carrying a completed message's usage exactly once; `turn_end` republishes
31
35
  * the same assistant message and `agent_end` republishes its segment's
32
36
  * summary, so counting those too would multiply a run's reported cost. Every
33
- * message counts, because a headless turn spans several agent segments and the
34
- * run's cost is their sum.
37
+ * reported call counts, including known errored-call spend: a headless turn
38
+ * spans several segments and its cost is their sum. Provider facts and the
39
+ * errored known share are folded here too, from the same events before truncation.
40
+ * Failed all-zero usage is ambiguous (adapters synthesize it), so it cannot
41
+ * establish measured usage. Unknown failed spend is retained as missing coverage,
42
+ * never subtracted from inclusive totals or used to change task pass policy.
35
43
  *
36
44
  * Folding as the stream arrives is what makes the count trustworthy: the
37
45
  * operator-facing stdout artifact keeps only a bounded head and tail, so a
@@ -42,6 +50,7 @@ export function createTokenUsageFold(): EvalTokenUsageFold {
42
50
  let costUsd = 0;
43
51
  let measured = false;
44
52
  let pending = "";
53
+ const provider = emptyProviderObservation();
45
54
 
46
55
  const consume = (line: string): void => {
47
56
  if (line.trim().length === 0) return;
@@ -51,23 +60,16 @@ export function createTokenUsageFold(): EvalTokenUsageFold {
51
60
  } catch {
52
61
  return;
53
62
  }
54
- if (!isRecord(event) || event.type !== "message_end") return;
55
- const message = isRecord(event.message) ? event.message : undefined;
56
- if (message === undefined || message.role !== "assistant") return;
57
- const usage = isRecord(message.usage) ? message.usage : undefined;
58
- if (usage === undefined) return;
59
- measured = true;
60
- const input = numberField(usage, "input");
61
- const output = numberField(usage, "output");
62
- const cacheRead = numberField(usage, "cacheRead");
63
- const cacheWrite = numberField(usage, "cacheWrite");
64
- const totalTokens = numberField(usage, "totalTokens");
65
- tokens.input += input;
66
- tokens.output += output;
67
- tokens.cacheRead += cacheRead;
68
- tokens.cacheWrite += cacheWrite;
69
- tokens.total += totalTokens > 0 ? totalTokens : input + output + cacheRead + cacheWrite;
70
- if (isRecord(usage.cost)) costUsd += numberField(usage.cost, "total");
63
+ if (!isRecord(event)) return;
64
+ observeProviderEvent(provider, event);
65
+ if (event.type !== "message_end" || !isRecord(event.message) || event.message.role !== "assistant") return;
66
+ const usage = readMessageUsage(event.message);
67
+ if (usage === null) return;
68
+ if (Object.keys(usage.tokens).length > 0) {
69
+ measured = true;
70
+ for (const field of TOKEN_FIELDS) tokens[field] += usage.tokens[field] ?? 0;
71
+ }
72
+ costUsd += usage.costUsd ?? 0;
71
73
  };
72
74
 
73
75
  return {
@@ -85,7 +87,7 @@ export function createTokenUsageFold(): EvalTokenUsageFold {
85
87
  consume(pending.replace(/\r$/u, ""));
86
88
  pending = "";
87
89
  }
88
- return { measured, tokens: { ...tokens }, costUsd };
90
+ return { measured, tokens: { ...tokens }, costUsd, provider: structuredClone(provider) };
89
91
  },
90
92
  };
91
93
  }
@@ -101,6 +103,7 @@ export function addTokenStreamUsage(left: EvalTokenStreamUsage, right: EvalToken
101
103
  cacheWrite: left.tokens.cacheWrite + right.tokens.cacheWrite,
102
104
  },
103
105
  costUsd: left.costUsd + right.costUsd,
106
+ provider: addProviderObservations(left.provider, right.provider),
104
107
  };
105
108
  }
106
109
 
@@ -110,21 +113,188 @@ export function addTokenStreamUsage(left: EvalTokenStreamUsage, right: EvalToken
110
113
  * read an absence as a zero-cost run.
111
114
  */
112
115
  export function tokenMetricEntries(usage: EvalTokenStreamUsage): Record<string, number | boolean> {
113
- if (!usage.measured) return { "tokens.measured": false };
114
116
  return {
115
- "tokens.measured": true,
116
- "tokens.input": usage.tokens.input,
117
- "tokens.output": usage.tokens.output,
118
- "tokens.total": usage.tokens.total,
119
- "tokens.cacheRead": usage.tokens.cacheRead,
120
- "tokens.cacheWrite": usage.tokens.cacheWrite,
117
+ ...providerMetricEntries(usage.provider),
118
+ "tokens.measured": usage.measured,
119
+ ...(usage.measured
120
+ ? {
121
+ "tokens.input": usage.tokens.input,
122
+ "tokens.output": usage.tokens.output,
123
+ "tokens.total": usage.tokens.total,
124
+ "tokens.cacheRead": usage.tokens.cacheRead,
125
+ "tokens.cacheWrite": usage.tokens.cacheWrite,
126
+ }
127
+ : {}),
121
128
  ...(usage.costUsd > 0 ? { "cost.usd": usage.costUsd } : {}),
122
129
  };
123
130
  }
124
131
 
125
- function numberField(record: Record<string, unknown>, field: string): number {
126
- const value = record[field];
127
- return typeof value === "number" && Number.isFinite(value) ? value : 0;
132
+ const TOKEN_FIELDS = ["input", "output", "total", "cacheRead", "cacheWrite"] as const;
133
+ const STOP_REASONS = ["stop", "toolUse", "length", "error", "aborted", "other"] as const;
134
+ const RETRY_PHASES = {
135
+ scheduled: "retryScheduled",
136
+ retrying: "retryStarted",
137
+ cancelled: "retryCancelled",
138
+ exhausted: "retryExhausted",
139
+ recovered: "retryRecovered",
140
+ } as const;
141
+ type StopReason = (typeof STOP_REASONS)[number];
142
+ type RetryPhase = keyof typeof RETRY_PHASES;
143
+
144
+ interface EvalProviderObservation {
145
+ measured: boolean;
146
+ stops: Record<StopReason, number>;
147
+ retries: Record<RetryPhase, number>;
148
+ errorUsageObservedCalls: number;
149
+ errorUsageUnobservedCalls: number;
150
+ errorUsageIncompleteCalls: number;
151
+ errorCostUnobservedCalls: number;
152
+ errorReasoningUnobservedCalls: number;
153
+ errorReasoningTokens: number | null;
154
+ errorTokens: Partial<EvalTokenMetricsV4>;
155
+ errorCostUsd: number | null;
156
+ }
157
+
158
+ interface MessageUsageObservation {
159
+ reasoningTokens: number | null;
160
+ tokens: Partial<EvalTokenMetricsV4>;
161
+ costUsd: number | null;
162
+ completeTokens: boolean;
163
+ }
164
+
165
+ function emptyProviderObservation(): EvalProviderObservation {
166
+ return {
167
+ measured: false,
168
+ stops: { stop: 0, toolUse: 0, length: 0, error: 0, aborted: 0, other: 0 },
169
+ retries: { scheduled: 0, retrying: 0, cancelled: 0, exhausted: 0, recovered: 0 },
170
+ errorUsageObservedCalls: 0,
171
+ errorUsageUnobservedCalls: 0,
172
+ errorUsageIncompleteCalls: 0,
173
+ errorCostUnobservedCalls: 0,
174
+ errorReasoningUnobservedCalls: 0,
175
+ errorReasoningTokens: null,
176
+ errorTokens: {},
177
+ errorCostUsd: null,
178
+ };
179
+ }
180
+
181
+ /** Same usage interpretation for inclusive totals and their known errored share. */
182
+ function readMessageUsage(message: Record<string, unknown>): MessageUsageObservation | null {
183
+ if (!isRecord(message.usage)) return null;
184
+ const usage = message.usage;
185
+ const failed = message.stopReason === "error" || message.stopReason === "aborted";
186
+ const raw: Partial<EvalTokenMetricsV4> = {};
187
+ for (const field of TOKEN_FIELDS) {
188
+ const value = nonNegativeNumber(usage[field === "total" ? "totalTokens" : field]);
189
+ // Failed adapter objects can initialize each absent field to zero even
190
+ // when another field is reported. Keep only attributable positive facts.
191
+ if (value !== null && (!failed || value > 0)) raw[field] = value;
192
+ }
193
+ const cost = isRecord(usage.cost) ? nonNegativeNumber(usage.cost.total) : null;
194
+ // Zero prices are also initialized by adapters without pricing evidence.
195
+ const costUsd = cost !== null && cost > 0 ? cost : null;
196
+
197
+ // The compat adapter can synthesize the root reasoningTokens alias from
198
+ // thinking text without marking it estimated. Preserve explicit provider
199
+ // detail through the shared reader, but never promote that ambiguous alias.
200
+ // Normalized zero reasoning can also mean omitted provider detail.
201
+ const reportedReasoning = extractReasoningTokens({ ...usage, reasoningTokens: undefined });
202
+ const reasoningTokens = reportedReasoning !== null && reportedReasoning > 0 ? reportedReasoning : null;
203
+ const tokens = raw;
204
+ if (Object.keys(tokens).length === 0 && costUsd === null && reasoningTokens === null) return null;
205
+ const completeTokens = Object.keys(tokens).length === TOKEN_FIELDS.length;
206
+ if (Object.keys(tokens).length > 0 && !(tokens.total !== undefined && tokens.total > 0)) {
207
+ // This is a known subtotal when fields are missing; coverage stays incomplete.
208
+ tokens.total = (tokens.input ?? 0) + (tokens.output ?? 0) + (tokens.cacheRead ?? 0) + (tokens.cacheWrite ?? 0);
209
+ }
210
+ return { tokens, costUsd, completeTokens, reasoningTokens };
211
+ }
212
+
213
+ function observeProviderEvent(provider: EvalProviderObservation, event: Record<string, unknown>): void {
214
+ if (event.type === "retry_status" && isRecord(event.status)) {
215
+ const phase = event.status.phase;
216
+ if (typeof phase === "string" && Object.hasOwn(RETRY_PHASES, phase)) {
217
+ provider.measured = true;
218
+ provider.retries[phase as RetryPhase] += 1;
219
+ }
220
+ // Waiting frames are countdown ticks, not attempts. Attempt numbers may
221
+ // restart in another chain, so neither frames nor attempts are deduplicated.
222
+ return;
223
+ }
224
+ if (event.type !== "message_end" || !isRecord(event.message) || event.message.role !== "assistant") return;
225
+ const reason = event.message.stopReason;
226
+ if (typeof reason !== "string" || reason.length === 0 || reason === "pending") return;
227
+ provider.measured = true;
228
+ const stop = STOP_REASONS.includes(reason as StopReason) ? (reason as StopReason) : "other";
229
+ provider.stops[stop] += 1;
230
+ if (reason !== "error") return;
231
+ const usage = readMessageUsage(event.message);
232
+ if (usage === null) provider.errorUsageUnobservedCalls += 1;
233
+ else {
234
+ provider.errorUsageObservedCalls += 1;
235
+ for (const field of TOKEN_FIELDS) {
236
+ const value = usage.tokens[field];
237
+ if (value !== undefined) provider.errorTokens[field] = (provider.errorTokens[field] ?? 0) + value;
238
+ }
239
+ }
240
+ if (usage?.completeTokens !== true) provider.errorUsageIncompleteCalls += 1;
241
+ if (usage?.costUsd === undefined || usage.costUsd === null) provider.errorCostUnobservedCalls += 1;
242
+ else provider.errorCostUsd = (provider.errorCostUsd ?? 0) + usage.costUsd;
243
+ if (usage?.reasoningTokens === undefined || usage.reasoningTokens === null)
244
+ provider.errorReasoningUnobservedCalls += 1;
245
+ else provider.errorReasoningTokens = (provider.errorReasoningTokens ?? 0) + usage.reasoningTokens;
246
+ }
247
+
248
+ function addProviderObservations(
249
+ left: EvalProviderObservation,
250
+ right: EvalProviderObservation,
251
+ ): EvalProviderObservation {
252
+ const result = emptyProviderObservation();
253
+ result.measured = left.measured || right.measured;
254
+ for (const reason of STOP_REASONS) result.stops[reason] = left.stops[reason] + right.stops[reason];
255
+ for (const phase of Object.keys(RETRY_PHASES) as RetryPhase[])
256
+ result.retries[phase] = left.retries[phase] + right.retries[phase];
257
+ result.errorUsageObservedCalls = left.errorUsageObservedCalls + right.errorUsageObservedCalls;
258
+ result.errorUsageUnobservedCalls = left.errorUsageUnobservedCalls + right.errorUsageUnobservedCalls;
259
+ result.errorUsageIncompleteCalls = left.errorUsageIncompleteCalls + right.errorUsageIncompleteCalls;
260
+ result.errorCostUnobservedCalls = left.errorCostUnobservedCalls + right.errorCostUnobservedCalls;
261
+ result.errorReasoningUnobservedCalls = left.errorReasoningUnobservedCalls + right.errorReasoningUnobservedCalls;
262
+ if (left.errorReasoningTokens !== null || right.errorReasoningTokens !== null)
263
+ result.errorReasoningTokens = (left.errorReasoningTokens ?? 0) + (right.errorReasoningTokens ?? 0);
264
+ for (const field of TOKEN_FIELDS) {
265
+ if (left.errorTokens[field] !== undefined || right.errorTokens[field] !== undefined) {
266
+ result.errorTokens[field] = (left.errorTokens[field] ?? 0) + (right.errorTokens[field] ?? 0);
267
+ }
268
+ }
269
+ if (left.errorCostUsd !== null || right.errorCostUsd !== null)
270
+ result.errorCostUsd = (left.errorCostUsd ?? 0) + (right.errorCostUsd ?? 0);
271
+ return result;
272
+ }
273
+
274
+ /** Provider observations are independent of task success and receipt billing. */
275
+ function providerMetricEntries(provider: EvalProviderObservation): Record<string, number | boolean> {
276
+ if (!provider.measured) return { "provider.measured": false };
277
+ const metrics: Record<string, number | boolean> = { "provider.measured": true };
278
+ for (const reason of STOP_REASONS) metrics[`provider.stopReason.${reason}`] = provider.stops[reason];
279
+ for (const phase of Object.keys(RETRY_PHASES) as RetryPhase[])
280
+ metrics[`provider.${RETRY_PHASES[phase]}`] = provider.retries[phase];
281
+ if (provider.stops.error === 0) return metrics;
282
+ metrics["provider.errorUsageObservedCalls"] = provider.errorUsageObservedCalls;
283
+ metrics["provider.errorUsageUnobservedCalls"] = provider.errorUsageUnobservedCalls;
284
+ metrics["provider.errorUsageIncompleteCalls"] = provider.errorUsageIncompleteCalls;
285
+ metrics["provider.errorCostUnobservedCalls"] = provider.errorCostUnobservedCalls;
286
+ metrics["provider.errorReasoningUnobservedCalls"] = provider.errorReasoningUnobservedCalls;
287
+ if (provider.errorReasoningTokens !== null) metrics["provider.errorReasoningTokens"] = provider.errorReasoningTokens;
288
+ for (const field of TOKEN_FIELDS) {
289
+ const value = provider.errorTokens[field];
290
+ if (value !== undefined) metrics[`provider.errorTokens.${field}`] = value;
291
+ }
292
+ if (provider.errorCostUsd !== null) metrics["provider.errorCostUsd"] = provider.errorCostUsd;
293
+ return metrics;
294
+ }
295
+
296
+ function nonNegativeNumber(value: unknown): number | null {
297
+ return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : null;
128
298
  }
129
299
 
130
300
  function isRecord(value: unknown): value is Record<string, unknown> {
@@ -47,6 +47,7 @@ export interface BuildEvalTrackedMetricsInput {
47
47
  }
48
48
 
49
49
  interface AssistantCall {
50
+ timestamp: string | null;
50
51
  payload: Record<string, unknown>;
51
52
  promptCache: Record<string, unknown> | null;
52
53
  backend: Record<string, unknown> | null;
@@ -59,6 +60,28 @@ interface NumericReading {
59
60
  source: EvalMetricSource;
60
61
  }
61
62
 
63
+ /**
64
+ * The session ledger and stdout fold observe the same assistant calls on the
65
+ * native runner. Prefer the durable calls (including their richer timing and
66
+ * cache facts), with stdout as a fallback only when no durable calls exist.
67
+ * Keep non-call entries in either case: compaction is billed but not streamed.
68
+ * Counts are observations, NOT identities or evidence of matching coverage;
69
+ * partial/mixed ledgers cannot be unioned without a shared call identity.
70
+ */
71
+ export function selectEvalLedgerEntries(
72
+ durable: ReadonlyArray<SessionEntry>,
73
+ stream: ReadonlyArray<SessionEntry>,
74
+ ): { entries: ReadonlyArray<SessionEntry>; source: "session" | "stream"; sessionCalls: number; streamCalls: number } {
75
+ const sessionCalls = assistantCalls(durable).length;
76
+ const streamCalls = assistantCalls(stream).length;
77
+ return {
78
+ entries: sessionCalls > 0 ? durable : [...durable, ...stream],
79
+ source: sessionCalls > 0 ? "session" : "stream",
80
+ sessionCalls,
81
+ streamCalls,
82
+ };
83
+ }
84
+
62
85
  /** Read every isolated session ledger and its prompt manifest before cleanup. */
63
86
  export async function readEvalLedgerSnapshot(stateDir: string): Promise<EvalLedgerSnapshot> {
64
87
  const refs = await listSessionLedgerRefs(stateDir);
@@ -175,7 +198,7 @@ export function emptyEvalTrackedMetrics(source: EvalMetricSource = "estimated"):
175
198
  reasoningTokens: { value: null, source },
176
199
  toolCalls: zero(),
177
200
  toolErrors: zero(),
178
- ttftMsFirstCall: zero(),
201
+ ttftMsFirstCall: { value: null, source: "estimated" },
179
202
  wallClockMs: zero(),
180
203
  contextTokensAtEnd: zero(),
181
204
  compactions: zero(),
@@ -192,6 +215,7 @@ function assistantCalls(entries: ReadonlyArray<SessionEntry>): AssistantCall[] {
192
215
  if (promptCache === null && timing === null && usage === null) return [];
193
216
  return [
194
217
  {
218
+ timestamp: entry.payload.timestampEstimated === true ? null : entry.timestamp,
195
219
  payload: entry.payload,
196
220
  promptCache,
197
221
  backend: promptCache === null ? null : recordField(promptCache, "backend"),
@@ -260,10 +284,22 @@ function reasoningMetric(
260
284
  return measured ? { value: total, source: "ledger" } : { value: null, source: "estimated" };
261
285
  }
262
286
 
263
- function firstCallTtft(calls: ReadonlyArray<AssistantCall>): EvalSourcedNumber {
264
- const first = calls[0];
287
+ function firstCallTtft(calls: ReadonlyArray<AssistantCall>): EvalSourcedNullableNumber {
288
+ // Session directories are read by name, not by call time. Select without
289
+ // reordering the evidence or borrowing a later call's available timing.
290
+ let first: AssistantCall | undefined;
291
+ let firstAt = Number.POSITIVE_INFINITY;
292
+ for (const call of calls) {
293
+ if (call.timestamp === null) return { value: null, source: "estimated" };
294
+ const at = Date.parse(call.timestamp);
295
+ if (!Number.isFinite(at)) return { value: null, source: "estimated" };
296
+ if (at < firstAt) {
297
+ first = call;
298
+ firstAt = at;
299
+ }
300
+ }
265
301
  const value = first?.timing === null || first?.timing === undefined ? null : nonNegativeNumber(first.timing.ttftMs);
266
- return value === null ? { value: 0, source: "estimated" } : { value, source: "ledger" };
302
+ return value === null ? { value: null, source: "estimated" } : { value, source: "ledger" };
267
303
  }
268
304
 
269
305
  function wallClockMetric(receipt: RunReceipt | null, fallback: number): EvalSourcedNumber {
@@ -149,7 +149,7 @@ interface BehavioralToolTerminal {
149
149
  * bounded counters against the suite's explicit public allowlist and decoy
150
150
  * list; they never become behavioral fact values or evidence excerpts.
151
151
  */
152
- function toolBehaviorMetricEntriesFromJsonl(
152
+ export function toolBehaviorMetricEntriesFromJsonl(
153
153
  stdout: string,
154
154
  cwd: string,
155
155
  readObservation?: { allowedPaths: string[]; decoyPaths: string[] },
@@ -201,16 +201,19 @@ function toolBehaviorMetricEntriesFromJsonl(
201
201
 
202
202
  const terminals = canonicalFinishes.length > 0 ? canonicalFinishes : executionEnds;
203
203
  const calls = new Map<string, number>();
204
+ const succeeded = new Map<string, number>();
204
205
  const blocked = new Map<string, number>();
205
206
  for (const terminal of terminals) {
206
207
  const tool = metricToolName(terminal.tool);
207
208
  calls.set(tool, (calls.get(tool) ?? 0) + 1);
209
+ if (terminal.outcome === "ok") succeeded.set(tool, (succeeded.get(tool) ?? 0) + 1);
208
210
  if (terminal.outcome === "blocked") blocked.set(tool, (blocked.get(tool) ?? 0) + 1);
209
211
  }
210
- const namedTools = new Set(["bash", "dispatch", "read", ...calls.keys(), ...blocked.keys()]);
212
+ const namedTools = new Set(["bash", "dispatch", "read", ...calls.keys(), ...succeeded.keys(), ...blocked.keys()]);
211
213
  const entries: Record<string, number> = { "tools.read.distinctPaths": readPaths.size };
212
214
  for (const tool of [...namedTools].sort()) {
213
215
  entries[`tools.calls.${tool}`] = calls.get(tool) ?? 0;
216
+ entries[`tools.succeeded.${tool}`] = succeeded.get(tool) ?? 0;
214
217
  entries[`tools.blocked.${tool}`] = blocked.get(tool) ?? 0;
215
218
  }
216
219
  if (readObservation !== undefined) {
@@ -13,6 +13,33 @@ export const CANONICAL_METRICS = [
13
13
  // are absent in that case rather than zero, so a gate on cost can require
14
14
  // measurement instead of reading silence as free.
15
15
  "tokens.measured",
16
+ // Observed stdout terminal/retry facts, independent of task success. Opaque
17
+ // runs carry measured:false and no counters. Errored usage stays in inclusive
18
+ // tokens.* totals; errorTokens/errorCostUsd are known subtotals with coverage.
19
+ "provider.measured",
20
+ "provider.stopReason.stop",
21
+ "provider.stopReason.toolUse",
22
+ "provider.stopReason.length",
23
+ "provider.stopReason.error",
24
+ "provider.stopReason.aborted",
25
+ "provider.stopReason.other",
26
+ "provider.retryScheduled",
27
+ "provider.retryStarted",
28
+ "provider.retryCancelled",
29
+ "provider.retryExhausted",
30
+ "provider.retryRecovered",
31
+ "provider.errorUsageObservedCalls",
32
+ "provider.errorUsageUnobservedCalls",
33
+ "provider.errorUsageIncompleteCalls",
34
+ "provider.errorCostUnobservedCalls",
35
+ "provider.errorReasoningUnobservedCalls",
36
+ "provider.errorReasoningTokens",
37
+ "provider.errorTokens.input",
38
+ "provider.errorTokens.output",
39
+ "provider.errorTokens.total",
40
+ "provider.errorTokens.cacheRead",
41
+ "provider.errorTokens.cacheWrite",
42
+ "provider.errorCostUsd",
16
43
  "latency.wallMs",
17
44
  "latency.modelMs",
18
45
  "tools.totalCalls",
@@ -22,6 +49,7 @@ export const CANONICAL_METRICS = [
22
49
  "tools.read.outsideAllowed",
23
50
  "tools.read.decoyHits",
24
51
  "tools.calls.dispatch",
52
+ "tools.succeeded.dispatch",
25
53
  "tools.blocked.bash",
26
54
  "claims.unsupported",
27
55
  "completion.reported",
@@ -39,7 +39,7 @@ export interface EvalTrackedMetricsV1 {
39
39
  reasoningTokens: EvalSourcedNullableNumber;
40
40
  toolCalls: EvalSourcedNumber;
41
41
  toolErrors: EvalSourcedNumber;
42
- ttftMsFirstCall: EvalSourcedNumber;
42
+ ttftMsFirstCall: EvalSourcedNullableNumber;
43
43
  wallClockMs: EvalSourcedNumber;
44
44
  contextTokensAtEnd: EvalSourcedNumber;
45
45
  compactions: EvalSourcedNumber;
@@ -125,7 +125,7 @@ function parseTrackedMetrics(value: unknown, source: string): EvalTrackedMetrics
125
125
  reasoningTokens: readSourcedNullableNumber(record.reasoningTokens, `${source}.reasoningTokens`),
126
126
  toolCalls: readSourcedNumber(record.toolCalls, `${source}.toolCalls`),
127
127
  toolErrors: readSourcedNumber(record.toolErrors, `${source}.toolErrors`),
128
- ttftMsFirstCall: readSourcedNumber(record.ttftMsFirstCall, `${source}.ttftMsFirstCall`),
128
+ ttftMsFirstCall: readSourcedNullableNumber(record.ttftMsFirstCall, `${source}.ttftMsFirstCall`),
129
129
  wallClockMs: readSourcedNumber(record.wallClockMs, `${source}.wallClockMs`),
130
130
  contextTokensAtEnd: readSourcedNumber(record.contextTokensAtEnd, `${source}.contextTokensAtEnd`),
131
131
  compactions: readSourcedNumber(record.compactions, `${source}.compactions`),
@@ -60,9 +60,16 @@ export function evalRoot(dataDir: string): string {
60
60
  return join(dataDir, "evals");
61
61
  }
62
62
 
63
+ /**
64
+ * `skills-eval` is the only writer of this legacy version-1 shape; it nests
65
+ * under its own subdirectory so a legacy id that collides with a `clio-coder
66
+ * eval` run's version-4 id (evalArtifactPathV4, artifacts/store.ts) cannot
67
+ * clobber that artifact, and so `eval inventory`'s top-level readdir of
68
+ * evalRoot() never trips over a shape it does not parse.
69
+ */
63
70
  export function evalArtifactPath(dataDir: string, evalId: string): string {
64
71
  assertSafeId(evalId, "eval");
65
- return join(evalRoot(dataDir), `${evalId}.json`);
72
+ return join(evalRoot(dataDir), "skills-eval", `${evalId}.json`);
66
73
  }
67
74
 
68
75
  /**
@@ -38,7 +38,19 @@ function resolveTargets(targets: ReadonlyArray<EvalSuiteTargetV2>, options: Reso
38
38
  const filtered =
39
39
  options.target === undefined ? [...targets] : targets.filter((target) => target.id === options.target);
40
40
  const selected =
41
- filtered.length > 0 ? filtered : options.target === undefined ? [...targets] : [{ id: options.target }];
41
+ filtered.length > 0
42
+ ? filtered
43
+ : options.target === undefined
44
+ ? [...targets]
45
+ : [
46
+ {
47
+ id: options.target,
48
+ // A one-row suite still owns its thinking dimension when the CLI
49
+ // substitutes the target/model pair. Dropping it silently changes
50
+ // an off baseline into the target's configured default.
51
+ ...(targets.length === 1 && targets[0]?.thinking !== undefined ? { thinking: targets[0].thinking } : {}),
52
+ },
53
+ ];
42
54
  return selected.map((target) => ({
43
55
  ...target,
44
56
  ...(options.model === undefined ? {} : { model: options.model }),
@@ -18,7 +18,12 @@ import {
18
18
  import { wallTimeMetric } from "../metrics/latency.js";
19
19
  import { tokenAccountingFrom } from "../metrics/tokens.js";
20
20
  import { zeroToolCallMetrics } from "../metrics/tool-calls.js";
21
- import { buildEvalTrackedMetrics, emptyEvalTrackedMetrics, readEvalLedgerSnapshot } from "../metrics/tracked.js";
21
+ import {
22
+ buildEvalTrackedMetrics,
23
+ emptyEvalTrackedMetrics,
24
+ readEvalLedgerSnapshot,
25
+ selectEvalLedgerEntries,
26
+ } from "../metrics/tracked.js";
22
27
  import {
23
28
  type EvalServingObservation,
24
29
  evalClioProvenance,
@@ -234,11 +239,27 @@ async function runMatrixItem(
234
239
  },
235
240
  };
236
241
  const snapshot = await readEvalLedgerSnapshot(stateDir);
237
- const ledgerEntries = [...snapshot.entries, ...(runner.ledgerEntries ?? [])];
242
+ const selected = selectEvalLedgerEntries(snapshot.entries, runner.ledgerEntries ?? []);
243
+ result.artifacts.trackedMetricSources = JSON.stringify({
244
+ assistantCalls: selected.source,
245
+ sessionCalls: selected.sessionCalls,
246
+ streamCalls: selected.streamCalls,
247
+ compactions: "session",
248
+ });
249
+ if (selected.sessionCalls > 0 && selected.streamCalls > 0) {
250
+ // Preserve the unmerged evidence for opaque runners too. The native
251
+ // runner already publishes this artifact before stdout truncation.
252
+ result.artifacts.callLedger ??= JSON.stringify(runner.ledgerEntries);
253
+ if (selected.sessionCalls !== selected.streamCalls || task.runner.kind === "external-command") {
254
+ result.artifacts.trackedMetricWarning =
255
+ "Session and stream call coverage may differ; tracked metrics use session calls, not a reconciled union. " +
256
+ "Inspect callLedger before treating these counts as complete: no shared call identity proves overlap.";
257
+ }
258
+ }
238
259
  result.verdict = adaptSuiteV2ResultToVerdictV1(
239
260
  result,
240
261
  buildEvalTrackedMetrics({
241
- ledgerEntries,
262
+ ledgerEntries: selected.entries,
242
263
  receipt: receipt ?? null,
243
264
  fallbackWallClockMs: runner.wallTimeMs,
244
265
  }),