@iowarp/clio-coder 0.3.8 → 0.4.0

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 (552) hide show
  1. package/CHANGELOG.md +102 -0
  2. package/NOTICE +33 -0
  3. package/README.md +12 -3
  4. package/dist/{acp-U67UHUK2.js → acp-G5WJBNCT.js} +13 -12
  5. package/dist/{agents-YU6SGALZ.js → agents-FMV2Q5G4.js} +41 -36
  6. package/dist/assets/codewiki.json +1 -1
  7. package/dist/{auth-5ZPJOIVG.js → auth-3IDSJEIK.js} +18 -18
  8. package/dist/{builtins-C6JMZVV6.js → builtins-XCZWXSC7.js} +5 -5
  9. package/dist/{chunk-IFBNV6H6.js → chunk-2ANTL7MR.js} +3 -3
  10. package/dist/{chunk-5FR74PWO.js → chunk-2JDWVJND.js} +2 -2
  11. package/dist/{chunk-XWSF374K.js → chunk-2OQE55CK.js} +3 -3
  12. package/dist/{chunk-5H3GB5BO.js → chunk-32KWKNSF.js} +8 -384
  13. package/dist/{chunk-KTYTFRMB.js → chunk-36EJLSQQ.js} +34 -36
  14. package/dist/{chunk-FHJEP5SW.js → chunk-3BT2XMV4.js} +19 -13
  15. package/dist/chunk-3DPEIQKN.js +113 -0
  16. package/dist/{chunk-GU2UIAFZ.js → chunk-3URVFKWK.js} +7 -7
  17. package/dist/{chunk-WEH5XRJQ.js → chunk-3XML7CDN.js} +3 -3
  18. package/dist/chunk-42FMPA75.js +101 -0
  19. package/dist/{chunk-A2NJGIB3.js → chunk-5LXZXPKX.js} +2 -2
  20. package/dist/{chunk-VCBR6CU7.js → chunk-5PSMVOLM.js} +2 -2
  21. package/dist/{chunk-NMPKI6XL.js → chunk-6DB53AJS.js} +203 -25
  22. package/dist/{chunk-3BINW3FP.js → chunk-76ONBSIA.js} +2 -2
  23. package/dist/{chunk-26LEYJZH.js → chunk-7MCTRUCE.js} +2 -2
  24. package/dist/{chunk-TYPGUK6W.js → chunk-AB44T6BB.js} +111 -5
  25. package/dist/{chunk-K4XHGFR5.js → chunk-B7OBL7PK.js} +317 -721
  26. package/dist/{chunk-B5CSFE7B.js → chunk-BBVJUZHB.js} +2 -2
  27. package/dist/{chunk-EQ63NRB7.js → chunk-BBVYXMFO.js} +2 -2
  28. package/dist/{chunk-ZVJ5BLO2.js → chunk-BKFJHQCA.js} +154 -16
  29. package/dist/chunk-BKFM6EJV.js +462 -0
  30. package/dist/chunk-BMS5RKQY.js +27 -0
  31. package/dist/{chunk-ZNLWCMVZ.js → chunk-BPKCPIL7.js} +2 -2
  32. package/dist/{chunk-TLQJPP24.js → chunk-BUMFYQFY.js} +1394 -1349
  33. package/dist/{chunk-BNAZZHFG.js → chunk-BYP5D4HI.js} +1 -1
  34. package/dist/chunk-C2LTL2W6.js +2447 -0
  35. package/dist/{chunk-ME6CCNFO.js → chunk-CODPRO7Q.js} +8 -8
  36. package/dist/{chunk-E77JEWSD.js → chunk-CTJ4RNAA.js} +7 -37
  37. package/dist/{chunk-ODFEOB4F.js → chunk-CY6FY24N.js} +26 -8
  38. package/dist/{chunk-7RFXX52T.js → chunk-DQITNCXG.js} +642 -172
  39. package/dist/{chunk-TTHACPOM.js → chunk-DYJP44XW.js} +578 -117
  40. package/dist/{chunk-2HFZQUHL.js → chunk-F4CKPOEQ.js} +18 -8
  41. package/dist/{chunk-DGSYXYMX.js → chunk-FEFIFZTL.js} +3 -3
  42. package/dist/{chunk-GWS3VEIW.js → chunk-FWDFM5ZU.js} +24 -3
  43. package/dist/{chunk-MV3K5QF2.js → chunk-GCSMB2KY.js} +2 -2
  44. package/dist/chunk-GKF55TAZ.js +391 -0
  45. package/dist/{chunk-VWZOAB7K.js → chunk-GR5G2PVF.js} +9 -8
  46. package/dist/{chunk-4DGYLA73.js → chunk-GXNLGKAB.js} +80 -9
  47. package/dist/chunk-HHV2GANA.js +88 -0
  48. package/dist/{chunk-IIZWH4XA.js → chunk-HI63TFOG.js} +5 -4
  49. package/dist/{chunk-WLFILSD5.js → chunk-HJJTYUHX.js} +113 -83
  50. package/dist/{chunk-TT36MB5S.js → chunk-HLW2MRKE.js} +3 -1
  51. package/dist/{chunk-PMDBGQSJ.js → chunk-HWHKMHUA.js} +7 -7
  52. package/dist/chunk-HZHHCK24.js +1631 -0
  53. package/dist/{chunk-WSB3FPX7.js → chunk-I5VEOC6I.js} +39 -143
  54. package/dist/chunk-IBEBSCYA.js +564 -0
  55. package/dist/chunk-IQ7KR472.js +362 -0
  56. package/dist/{chunk-A3WNZD3P.js → chunk-J4W7KFM7.js} +949 -972
  57. package/dist/{chunk-TB5666IT.js → chunk-JDG2WCRO.js} +5 -5
  58. package/dist/{chunk-N22QMJKY.js → chunk-K5C3NCBD.js} +4 -4
  59. package/dist/{chunk-CGKSTWHD.js → chunk-K6BSR66V.js} +2 -1
  60. package/dist/{chunk-5C3AQNDW.js → chunk-KFZI4NIL.js} +216 -38
  61. package/dist/chunk-KMVISBZR.js +132 -0
  62. package/dist/{chunk-WXY7KU3G.js → chunk-LDQ2ZF2M.js} +2 -2
  63. package/dist/{chunk-XN3L4EYL.js → chunk-LQ3DZAMX.js} +3 -3
  64. package/dist/{chunk-U6MBIEMB.js → chunk-LY4S7GJC.js} +173 -144
  65. package/dist/{chunk-4SPRNWDE.js → chunk-MLKNTWH2.js} +19 -19
  66. package/dist/{chunk-MVVUPGPW.js → chunk-MXHC5QYU.js} +6 -6
  67. package/dist/chunk-NEKRRTYW.js +56 -0
  68. package/dist/{chunk-SPULKLCF.js → chunk-NHCZP4K7.js} +3 -3
  69. package/dist/chunk-NHLBIGRH.js +1506 -0
  70. package/dist/chunk-NQQH3YT7.js +302 -0
  71. package/dist/chunk-NYS75XW5.js +15 -0
  72. package/dist/{chunk-GN57SG4G.js → chunk-O4XIVISU.js} +10 -8
  73. package/dist/{chunk-EMYUUSFG.js → chunk-O6TL7WWY.js} +6 -6
  74. package/dist/chunk-OQBA45DZ.js +97 -0
  75. package/dist/{chunk-LU7P4LHA.js → chunk-P3FOHJT4.js} +2 -2
  76. package/dist/chunk-PMZCIOCJ.js +25 -0
  77. package/dist/{chunk-I4HZDVNP.js → chunk-PQEFIJ36.js} +2 -2
  78. package/dist/{chunk-J3YUBZWY.js → chunk-QBJA7R7N.js} +62 -6
  79. package/dist/chunk-QDC3K2U3.js +262 -0
  80. package/dist/{chunk-2HEJ2F35.js → chunk-QLFS5GO2.js} +22 -10
  81. package/dist/{chunk-7RGZWPB6.js → chunk-QLL7ILRG.js} +95 -32
  82. package/dist/{chunk-YS5VLNH5.js → chunk-QREDIESB.js} +6 -6
  83. package/dist/chunk-QSNYB6ZV.js +195 -0
  84. package/dist/{chunk-GOXNB3AO.js → chunk-RAPCMZL4.js} +75 -4
  85. package/dist/chunk-RKKLTLYB.js +45 -0
  86. package/dist/{chunk-P43ETTHK.js → chunk-SJ5ZKQ4S.js} +2 -2
  87. package/dist/{chunk-GPIEI3LY.js → chunk-SP2RXXYO.js} +6 -54
  88. package/dist/chunk-SUCTJL45.js +45 -0
  89. package/dist/{chunk-DYIM5TJT.js → chunk-SUW5DORT.js} +263 -7
  90. package/dist/chunk-T56WDKA5.js +183 -0
  91. package/dist/chunk-TVHHYFHE.js +255 -0
  92. package/dist/{chunk-FJ3H4MN5.js → chunk-TZ3SGWZZ.js} +3 -3
  93. package/dist/{chunk-MXKJU4JB.js → chunk-U77AMWDL.js} +91 -10
  94. package/dist/{chunk-5DHKRSMQ.js → chunk-ULC6OTWO.js} +11 -7
  95. package/dist/{chunk-RWSI4YD7.js → chunk-UM7N4G5A.js} +33 -12
  96. package/dist/{chunk-FCSXB6T2.js → chunk-UOSL25KY.js} +14 -2
  97. package/dist/{chunk-IGWKHNIQ.js → chunk-UXMFQ54G.js} +44 -37
  98. package/dist/{chunk-HFSBBKSQ.js → chunk-V5DHCITQ.js} +171 -3
  99. package/dist/{chunk-5WIGXA4T.js → chunk-VAZSBTKF.js} +111 -4
  100. package/dist/{chunk-VHN4MY6O.js → chunk-VEO4AP2K.js} +2 -2
  101. package/dist/{chunk-IJ7RPIYJ.js → chunk-VFA6GDY5.js} +65 -4
  102. package/dist/{chunk-PT7HYKEM.js → chunk-VO2LKSTM.js} +2 -2
  103. package/dist/chunk-VO67MWHC.js +75 -0
  104. package/dist/{chunk-XK56QHLX.js → chunk-VPKWYKEY.js} +19 -5
  105. package/dist/{chunk-TANS5ZJS.js → chunk-VYMXRQI6.js} +36 -22
  106. package/dist/{chunk-WWCZ5F23.js → chunk-W5VSYASO.js} +77 -16
  107. package/dist/{chunk-WNIJTQQK.js → chunk-WZR7K7ZX.js} +72 -116
  108. package/dist/{chunk-5Q2VVUKB.js → chunk-X3YGUTOB.js} +4 -4
  109. package/dist/chunk-X75E3D2N.js +686 -0
  110. package/dist/{chunk-VAWNZU7Z.js → chunk-YDFRH54B.js} +4 -4
  111. package/dist/chunk-YJX4SHTD.js +40 -0
  112. package/dist/{chunk-ZI647VB5.js → chunk-YPI3QQCF.js} +2 -2
  113. package/dist/chunk-Z2RR6MAK.js +127 -0
  114. package/dist/{chunk-FBVTI2TJ.js → chunk-Z4TXYIEG.js} +12 -131
  115. package/dist/cli/index.js +47 -36
  116. package/dist/{clio-QVTYJ57A.js → clio-2JXHBBY5.js} +7 -7
  117. package/dist/{code-nav-FGGFIE7L.js → code-nav-3YYRMYNF.js} +8 -8
  118. package/dist/{compile-cache-CVJMMODC.js → compile-cache-7FPE6PS3.js} +3 -3
  119. package/dist/{components-ZFA3SAER.js → components-RYZV4JGP.js} +5 -5
  120. package/dist/{config-LW5IJFQN.js → config-QZPCMYSO.js} +99 -63
  121. package/dist/{configure-7XIZCOU4.js → configure-TEGEBYCA.js} +23 -22
  122. package/dist/{context-Y6Y7QPR6.js → context-AV7OEZ4D.js} +12 -12
  123. package/dist/{context-L3WL3X7K.js → context-E6H5RNMC.js} +56 -47
  124. package/dist/{context-N52ZA626.js → context-GSXUE4CT.js} +29 -27
  125. package/dist/{context-clear-MBQRLSDQ.js → context-clear-SHIBYK6T.js} +55 -46
  126. package/dist/{context-index-HVMFQHK3.js → context-index-HNG3MOME.js} +2 -2
  127. package/dist/{context-working-set-GS6DSO7F.js → context-working-set-5ZGKPGZQ.js} +13 -13
  128. package/dist/{dispatch-runner-22ZCNOM3.js → dispatch-runner-EFMJT4LD.js} +93 -64
  129. package/dist/{docs-7LQ23DLM.js → docs-23KQS3XK.js} +5 -5
  130. package/dist/doctor-QOA5FNY5.js +313 -0
  131. package/dist/{eval-BEC2WHDA.js → eval-TFBYQH4H.js} +2032 -156
  132. package/dist/eval-inventory-SXH7PDKX.js +316 -0
  133. package/dist/{evidence-REJUMSKM.js → evidence-ERGESKGN.js} +203 -48
  134. package/dist/{evolve-PY5ZBA5K.js → evolve-VDXTSYCJ.js} +52 -43
  135. package/dist/{extensions-HVKU65YU.js → extensions-7BGBHN57.js} +13 -7
  136. package/dist/{fleet-7WZEWRFA.js → fleet-2RRVDF2V.js} +228 -108
  137. package/dist/{fleet-commands-UVHWM76J.js → fleet-commands-VJ726XIA.js} +11 -11
  138. package/dist/fleet-decisions-EPAPM3XJ.js +157 -0
  139. package/dist/{fleet-graph-6ULH7PES.js → fleet-graph-JF5QOATM.js} +18 -15
  140. package/dist/fleet-inspect-VLY4S7QM.js +442 -0
  141. package/dist/{fleet-preflight-J53T6CCE.js → fleet-preflight-AIZUEJOY.js} +5 -5
  142. package/dist/{fleet-validate-72PC4SLA.js → fleet-validate-AJRPDMDV.js} +22 -19
  143. package/dist/fleet-verify-JFEL2L3H.js +175 -0
  144. package/dist/fleet-view-ZCON35AG.js +102 -0
  145. package/dist/{init-OG3TPGQG.js → init-DN2WWLFE.js} +72 -62
  146. package/dist/install-XGLBQY5E.js +13 -0
  147. package/dist/interop-OZBKXAYL.js +114 -0
  148. package/dist/{library-CNTMPLRF.js → library-YWZG7IMW.js} +21 -18
  149. package/dist/{memory-6IS7F275.js → memory-I4C4HMLW.js} +54 -45
  150. package/dist/{models-ENRJDA5W.js → models-CEYXJBO6.js} +33 -30
  151. package/dist/{monitor-XLDVO7TN.js → monitor-NZ6GCI3P.js} +59 -52
  152. package/dist/{orchestrator-6KSPYRHA.js → orchestrator-GCGQ4N5I.js} +7827 -7328
  153. package/dist/panes-HMABYVO4.js +58 -0
  154. package/dist/panes-KY6W3V2E.js +103 -0
  155. package/dist/{paths-DBXMZMDU.js → paths-II4K7DNR.js} +5 -5
  156. package/dist/{reset-RZ4ER727.js → reset-DQ6FGCSH.js} +13 -11
  157. package/dist/resources-BB3MVJMD.js +111 -0
  158. package/dist/{run-Y2CNK5RU.js → run-H2GQDUER.js} +119 -87
  159. package/dist/{share-A55GYP6Z.js → share-GTJN6A5O.js} +20 -17
  160. package/dist/{skills-ALC5J6AT.js → skills-L55TEW6R.js} +33 -24
  161. package/dist/{skills-eval-JPBEBYQU.js → skills-eval-XVXPH2JI.js} +67 -56
  162. package/dist/skills-inventory-S4MXPJFV.js +126 -0
  163. package/dist/slash-commands-ZSGASKJC.js +77 -0
  164. package/dist/{steer-GGWFUJUD.js → steer-RZGSCY4R.js} +4 -4
  165. package/dist/{support-MIETYA5E.js → support-PKEUNNQL.js} +6 -6
  166. package/dist/{targets-VGNXIR3S.js → targets-NCPZ644J.js} +68 -40
  167. package/dist/{terminal-lease-WOBR64YA.js → terminal-lease-44SV3YCN.js} +6 -4
  168. package/dist/tools-DAF3DI3C.js +27 -0
  169. package/dist/{trace-PNCASAXC.js → trace-FYVW2MQA.js} +207 -10
  170. package/dist/tui-primitives-2AKXQNZK.js +13 -0
  171. package/dist/{uninstall-ZJF5H5ZN.js → uninstall-DW2PNOIC.js} +5 -5
  172. package/dist/{upgrade-FUSUAGHR.js → upgrade-3XPP6OQL.js} +27 -24
  173. package/dist/{usage-N4MKVHKD.js → usage-3NLHGTU2.js} +114 -62
  174. package/dist/{verifiers-YAWOJ3H2.js → verifiers-SSQONKRT.js} +172 -13
  175. package/dist/{verify-LTDHYBGY.js → verify-3U6J7FZI.js} +10 -10
  176. package/dist/{web-fetch-2YHJ3KTG.js → web-fetch-S7RR6GZ7.js} +3 -3
  177. package/dist/{wiki-generate-6M7GHTBJ.js → wiki-generate-CEHYGPGQ.js} +75 -65
  178. package/dist/with-panes-MKB46MPQ.js +782 -0
  179. package/dist/worker/entry.js +106 -75
  180. package/docs/README.md +3 -2
  181. package/docs/acp.md +24 -3
  182. package/docs/alcf-provider.md +1 -1
  183. package/docs/architecture.md +2 -2
  184. package/docs/artifact-versions.md +9 -1
  185. package/docs/built-in-agents.md +1 -1
  186. package/docs/capacity-and-scheduling.md +62 -3
  187. package/docs/commands-and-modes.md +31 -2
  188. package/docs/configuration-and-targets.md +69 -12
  189. package/docs/context-engine.md +63 -4
  190. package/docs/development-pipeline.md +19 -0
  191. package/docs/dispatch-typed-intent.md +385 -0
  192. package/docs/documentation-coverage.md +5 -5
  193. package/docs/documentation-guide.md +1 -1
  194. package/docs/environment-variables.md +3 -0
  195. package/docs/eval-runner.md +262 -11
  196. package/docs/evals-internal.md +72 -2
  197. package/docs/evidence-and-memory.md +12 -11
  198. package/docs/evolution.md +1 -1
  199. package/docs/exit-codes-and-output.md +1 -1
  200. package/docs/extensions-and-sharing.md +27 -1
  201. package/docs/fleet-dispatch.md +25 -4
  202. package/docs/installation-and-lifecycle.md +15 -2
  203. package/docs/middleware-and-components.md +1 -1
  204. package/docs/model-catalog.md +10 -1
  205. package/docs/observability.md +55 -4
  206. package/docs/proactive-memory.md +127 -14
  207. package/docs/prompt-envelope-and-tools.md +19 -1
  208. package/docs/provider-adapter-cookbook.md +1 -1
  209. package/docs/release-cut-checklist.md +19 -3
  210. package/docs/safety-model.md +2 -2
  211. package/docs/scientific-validation.md +3 -3
  212. package/docs/session-lifecycle.md +1 -1
  213. package/docs/skills-marketplace.md +1 -1
  214. package/docs/tool-usage.md +18 -8
  215. package/docs/trace-store.md +1 -1
  216. package/docs/troubleshooting.md +88 -1
  217. package/docs/tui-design.md +1 -1
  218. package/docs/worker-dispatch-mechanics.md +1 -1
  219. package/package.json +5 -2
  220. package/src/cli/acp.ts +6 -2
  221. package/src/cli/agents.ts +1 -1
  222. package/src/cli/argv.ts +25 -0
  223. package/src/cli/config-inspect.ts +33 -6
  224. package/src/cli/config.ts +1 -1
  225. package/src/cli/configure.ts +23 -21
  226. package/src/cli/doctor-panes.ts +124 -0
  227. package/src/cli/doctor-state-size.ts +82 -0
  228. package/src/cli/doctor-toolchain.ts +57 -0
  229. package/src/cli/doctor.ts +22 -1
  230. package/src/cli/eval-inventory.ts +436 -0
  231. package/src/cli/eval.ts +93 -16
  232. package/src/cli/evidence-detail.ts +88 -0
  233. package/src/cli/evidence-inventory.ts +183 -0
  234. package/src/cli/evidence.ts +30 -5
  235. package/src/cli/extensions.ts +5 -1
  236. package/src/cli/fleet-decisions.ts +69 -0
  237. package/src/cli/fleet-inspect.ts +334 -0
  238. package/src/cli/fleet-verify.ts +133 -0
  239. package/src/cli/fleet-view.ts +810 -0
  240. package/src/cli/fleet.ts +179 -39
  241. package/src/cli/index.ts +14 -2
  242. package/src/cli/interop-inspect.ts +128 -0
  243. package/src/cli/interop.ts +34 -0
  244. package/src/cli/panes.ts +35 -0
  245. package/src/cli/reset.ts +5 -2
  246. package/src/cli/run.ts +58 -0
  247. package/src/cli/skills-inventory.ts +185 -0
  248. package/src/cli/skills.ts +16 -13
  249. package/src/cli/targets.ts +44 -13
  250. package/src/cli/tools.ts +321 -0
  251. package/src/cli/trace-inspect.ts +252 -0
  252. package/src/cli/trace.ts +85 -5
  253. package/src/cli/usage.ts +63 -14
  254. package/src/cli/verifiers-inspect.ts +347 -0
  255. package/src/cli/verifiers.ts +9 -0
  256. package/src/core/bus-events.ts +33 -1
  257. package/src/core/cache-telemetry.ts +42 -0
  258. package/src/core/config.ts +67 -0
  259. package/src/core/defaults.ts +124 -8
  260. package/src/core/endpoint-key.ts +27 -0
  261. package/src/core/residency-target-key.ts +25 -0
  262. package/src/core/response-schema.ts +80 -6
  263. package/src/core/theme-token-hex.ts +43 -0
  264. package/src/core/tool-names.ts +2 -1
  265. package/src/core/xdg.ts +1 -1
  266. package/src/domains/agents/fleets/build-review.md +0 -3
  267. package/src/domains/agents/fleets/build-test.md +0 -3
  268. package/src/domains/agents/result-contract-filesystem.ts +32 -0
  269. package/src/domains/agents/result-contract.ts +164 -35
  270. package/src/domains/config/classify.ts +6 -0
  271. package/src/domains/context/codewiki/coordinator.ts +12 -4
  272. package/src/domains/dispatch/admission-error.ts +9 -0
  273. package/src/domains/dispatch/admission.ts +52 -14
  274. package/src/domains/dispatch/capacity-lease.ts +118 -9
  275. package/src/domains/dispatch/contract.ts +11 -0
  276. package/src/domains/dispatch/council-topology.ts +398 -0
  277. package/src/domains/dispatch/execution-plan.ts +44 -4
  278. package/src/domains/dispatch/extension.ts +378 -82
  279. package/src/domains/dispatch/fleet-node-prompt.ts +62 -0
  280. package/src/domains/dispatch/fleet-plan.ts +7 -2
  281. package/src/domains/dispatch/fleet-run.ts +87 -4
  282. package/src/domains/dispatch/gate-decisions.ts +11 -1
  283. package/src/domains/dispatch/gate-role-prompts.ts +9 -0
  284. package/src/domains/dispatch/gate-topology.ts +289 -0
  285. package/src/domains/dispatch/heartbeat.ts +32 -8
  286. package/src/domains/dispatch/index.ts +22 -0
  287. package/src/domains/dispatch/intent-compatibility.ts +330 -0
  288. package/src/domains/dispatch/intent.ts +85 -1
  289. package/src/domains/dispatch/orphan-recovery.ts +5 -0
  290. package/src/domains/dispatch/reservation-store.ts +139 -11
  291. package/src/domains/dispatch/run-event-journal-bridge.ts +149 -0
  292. package/src/domains/dispatch/run-event-journal.ts +598 -0
  293. package/src/domains/dispatch/state.ts +49 -1
  294. package/src/domains/dispatch/types.ts +13 -0
  295. package/src/domains/dispatch/validation.ts +33 -8
  296. package/src/domains/dispatch/worker-spawn.ts +25 -11
  297. package/src/domains/dispatch/write-boundary-enforcer.ts +20 -3
  298. package/src/domains/dispatch/write-boundary.ts +62 -1
  299. package/src/domains/eval/artifacts/store.ts +62 -0
  300. package/src/domains/eval/compare/behavioral.ts +224 -0
  301. package/src/domains/eval/compare/compare.ts +342 -2
  302. package/src/domains/eval/compare/envelope.ts +128 -0
  303. package/src/domains/eval/compare/gates.ts +24 -6
  304. package/src/domains/eval/compare/thresholds.ts +30 -3
  305. package/src/domains/eval/execution-provenance.ts +240 -0
  306. package/src/domains/eval/inventory.ts +113 -0
  307. package/src/domains/eval/metrics/aggregate.ts +136 -0
  308. package/src/domains/eval/metrics/call-ledger-stream.ts +112 -0
  309. package/src/domains/eval/metrics/tracked.ts +413 -0
  310. package/src/domains/eval/provenance.ts +117 -0
  311. package/src/domains/eval/reports/comparison.ts +128 -0
  312. package/src/domains/eval/reports/junit.ts +17 -3
  313. package/src/domains/eval/reports/markdown.ts +3 -3
  314. package/src/domains/eval/reports/text.ts +14 -0
  315. package/src/domains/eval/run-compare.ts +20 -0
  316. package/src/domains/eval/runners/clio-run.ts +127 -0
  317. package/src/domains/eval/runners/external-command.ts +28 -3
  318. package/src/domains/eval/schema/adapter.ts +111 -0
  319. package/src/domains/eval/schema/artifact.ts +20 -0
  320. package/src/domains/eval/schema/behavioral-metrics.ts +204 -0
  321. package/src/domains/eval/schema/behavioral.ts +520 -0
  322. package/src/domains/eval/schema/execution-envelope.ts +194 -0
  323. package/src/domains/eval/schema/serving.ts +105 -0
  324. package/src/domains/eval/schema/suite.ts +38 -8
  325. package/src/domains/eval/schema/validate.ts +58 -3
  326. package/src/domains/eval/schema/verdict.ts +237 -0
  327. package/src/domains/eval/suites/resolve.ts +2 -0
  328. package/src/domains/eval/suites/run.ts +264 -33
  329. package/src/domains/eval/verifiers/command.ts +2 -1
  330. package/src/domains/eval/workspaces/temp-copy.ts +145 -13
  331. package/src/domains/evidence/build.ts +2 -13
  332. package/src/domains/evidence/eval.ts +2 -12
  333. package/src/domains/evidence/findings-markdown.ts +33 -0
  334. package/src/domains/evidence/run-trust.ts +7 -113
  335. package/src/domains/evidence/store.ts +6 -0
  336. package/src/domains/evidence/trust-projection.ts +2 -2
  337. package/src/domains/extensions/compatibility.ts +285 -0
  338. package/src/domains/extensions/discovery.ts +38 -3
  339. package/src/domains/extensions/resources.ts +1 -1
  340. package/src/domains/extensions/state.ts +12 -3
  341. package/src/domains/extensions/types.ts +2 -0
  342. package/src/domains/lifecycle/doctor.ts +69 -1
  343. package/src/domains/memory/index.ts +14 -1
  344. package/src/domains/memory/task-bank-promotion.ts +64 -0
  345. package/src/domains/memory/task-memory-policy.ts +82 -17
  346. package/src/domains/memory/task-memory-spend.ts +131 -0
  347. package/src/domains/memory/task-memory-status.ts +7 -0
  348. package/src/domains/memory/task-memory-telemetry.ts +3 -0
  349. package/src/domains/middleware/index.ts +1 -0
  350. package/src/domains/middleware/memory-intervention.ts +97 -21
  351. package/src/domains/middleware/memory-step-endpoint.ts +71 -0
  352. package/src/domains/mux/contract.ts +434 -0
  353. package/src/domains/mux/detect.ts +158 -0
  354. package/src/domains/mux/extension.ts +47 -0
  355. package/src/domains/mux/index.ts +96 -0
  356. package/src/domains/mux/manifest.ts +6 -0
  357. package/src/domains/mux/operations.ts +164 -0
  358. package/src/domains/mux/pane-registry.ts +90 -0
  359. package/src/domains/mux/protocol.ts +49 -0
  360. package/src/domains/mux/socket-client.ts +816 -0
  361. package/src/domains/mux/types.ts +222 -0
  362. package/src/domains/mux/viewer-command.ts +59 -0
  363. package/src/domains/mux/yazi/assets/init.lua +2 -0
  364. package/src/domains/mux/yazi/assets/plugins/git.yazi/LICENSE +21 -0
  365. package/src/domains/mux/yazi/assets/plugins/git.yazi/README.md +78 -0
  366. package/src/domains/mux/yazi/assets/plugins/git.yazi/main.lua +255 -0
  367. package/src/domains/mux/yazi/assets/plugins/git.yazi/types.lua +12 -0
  368. package/src/domains/mux/yazi/assets/yazi.toml +17 -0
  369. package/src/domains/mux/yazi/event-stream.ts +180 -0
  370. package/src/domains/mux/yazi/profile.ts +299 -0
  371. package/src/domains/mux/yazi/session.ts +228 -0
  372. package/src/domains/mux/yazi/theme.ts +30 -0
  373. package/src/domains/observability/background-memory-usage.ts +140 -0
  374. package/src/domains/observability/cost.ts +22 -1
  375. package/src/domains/observability/index.ts +9 -0
  376. package/src/domains/observability/out-of-turn-usage.ts +51 -2
  377. package/src/domains/observability/trace-store.ts +234 -2
  378. package/src/domains/prompts/compiler.ts +100 -13
  379. package/src/domains/providers/endpoint-capacity.ts +228 -0
  380. package/src/domains/providers/endpoint-slots-store.ts +189 -0
  381. package/src/domains/providers/extension.ts +20 -3
  382. package/src/domains/providers/index.ts +32 -0
  383. package/src/domains/providers/model-runtime-capabilities.ts +32 -0
  384. package/src/domains/providers/models/local-models/clio-local-coding-targets.yaml +243 -1
  385. package/src/domains/providers/runtime-resolution.ts +8 -1
  386. package/src/domains/providers/runtimes/boot-manifest.ts +1 -0
  387. package/src/domains/providers/runtimes/builtins.ts +2 -0
  388. package/src/domains/providers/runtimes/common/probe-helpers.ts +31 -9
  389. package/src/domains/providers/runtimes/local-native/llamacpp-anthropic.ts +1 -1
  390. package/src/domains/providers/runtimes/local-native/llamacpp-completion.ts +1 -1
  391. package/src/domains/providers/runtimes/local-native/llamacpp-embed.ts +1 -1
  392. package/src/domains/providers/runtimes/local-native/llamacpp-rerank.ts +1 -1
  393. package/src/domains/providers/runtimes/local-native/llamacpp.ts +4 -1
  394. package/src/domains/providers/runtimes/local-native/lmstudio.ts +4 -1
  395. package/src/domains/providers/runtimes/local-native/ollama-native.ts +6 -1
  396. package/src/domains/providers/runtimes/protocol/litellm.ts +375 -0
  397. package/src/domains/providers/support.ts +1 -0
  398. package/src/domains/providers/target-model-cache.ts +124 -0
  399. package/src/domains/providers/types/capability-flags.ts +2 -0
  400. package/src/domains/providers/types/target-descriptor.ts +2 -0
  401. package/src/domains/resources/index.ts +3 -0
  402. package/src/domains/resources/prompts/loader.ts +95 -33
  403. package/src/domains/resources/skills/loader.ts +33 -0
  404. package/src/domains/safety/action-classifier.ts +6 -0
  405. package/src/domains/safety/call-target.ts +52 -0
  406. package/src/domains/safety/run-effects.ts +35 -4
  407. package/src/domains/session/context-accounting.ts +52 -1
  408. package/src/domains/session/context-ledger.ts +37 -13
  409. package/src/domains/session/index.ts +6 -0
  410. package/src/domains/session/prompt-cache.ts +140 -0
  411. package/src/domains/session/prompt-manifest.ts +42 -0
  412. package/src/domains/toolchain/archive.ts +175 -0
  413. package/src/domains/toolchain/contract.ts +28 -0
  414. package/src/domains/toolchain/extension.ts +47 -0
  415. package/src/domains/toolchain/index.ts +39 -0
  416. package/src/domains/toolchain/install.ts +327 -0
  417. package/src/domains/toolchain/manifest.ts +8 -0
  418. package/src/domains/toolchain/paths.ts +34 -0
  419. package/src/domains/toolchain/registry.ts +265 -0
  420. package/src/domains/toolchain/remove.ts +218 -0
  421. package/src/domains/toolchain/resolve.ts +182 -0
  422. package/src/domains/toolchain/types.ts +113 -0
  423. package/src/domains/toolchain/version.ts +88 -0
  424. package/src/engine/acp/adapter.ts +18 -3
  425. package/src/engine/acp/server.ts +413 -70
  426. package/src/engine/acp/types.ts +19 -1
  427. package/src/engine/ai.ts +35 -0
  428. package/src/engine/apis/llamacpp-residency.ts +55 -3
  429. package/src/engine/apis/lmstudio.ts +25 -5
  430. package/src/engine/apis/ollama-native.ts +2 -1
  431. package/src/engine/apis/openai-completions.ts +80 -17
  432. package/src/engine/apis/residency-lock.ts +3 -1
  433. package/src/engine/apis/residency.ts +34 -1
  434. package/src/engine/claude/sdk-module.ts +98 -0
  435. package/src/engine/claude/sdk-runtime.ts +19 -11
  436. package/src/engine/provider-payload.ts +29 -1
  437. package/src/engine/tui-primitives.ts +21 -0
  438. package/src/engine/tui.ts +1 -0
  439. package/src/engine/worker-runtime.ts +2 -13
  440. package/src/entry/boot-options.ts +2 -0
  441. package/src/entry/orchestrator.ts +279 -35
  442. package/src/entry/panes-activation.ts +31 -0
  443. package/src/entry/with-panes.ts +20 -0
  444. package/src/interactive/chat-loop-messages.ts +26 -7
  445. package/src/interactive/chat-loop.ts +318 -41
  446. package/src/interactive/chat-panel.ts +62 -8
  447. package/src/interactive/clio-editor.ts +45 -8
  448. package/src/interactive/context-activity.ts +5 -1
  449. package/src/interactive/context-meter.ts +1 -1
  450. package/src/interactive/context-overlay.ts +41 -10
  451. package/src/interactive/cost-overlay.ts +66 -6
  452. package/src/interactive/council-grid.ts +1 -3
  453. package/src/interactive/council.ts +11 -0
  454. package/src/interactive/dispatch-board.ts +102 -20
  455. package/src/interactive/fleet-run-preview.ts +41 -15
  456. package/src/interactive/handoff-round.ts +41 -2
  457. package/src/interactive/interactive-application.ts +177 -7
  458. package/src/interactive/interactive-input-runtime.ts +15 -0
  459. package/src/interactive/interactive-presentation.ts +4 -0
  460. package/src/interactive/interactive-shell.ts +20 -17
  461. package/src/interactive/interactive-slash-runtime.ts +63 -10
  462. package/src/interactive/memory-overlay.ts +9 -0
  463. package/src/interactive/modal-marker.ts +170 -0
  464. package/src/interactive/mutation-preview.ts +295 -0
  465. package/src/interactive/mux-bridge.ts +214 -0
  466. package/src/interactive/overlay-frame.ts +58 -2
  467. package/src/interactive/overlay-general-openers.ts +17 -0
  468. package/src/interactive/overlay-key-routing.ts +52 -3
  469. package/src/interactive/overlay-lifecycle.ts +56 -7
  470. package/src/interactive/overlay-model-selectors.ts +40 -3
  471. package/src/interactive/overlay-permission-lifecycle.ts +112 -24
  472. package/src/interactive/overlay-session-lifecycle.ts +73 -9
  473. package/src/interactive/overlay-transitions.ts +18 -4
  474. package/src/interactive/overlays/agents.ts +1 -0
  475. package/src/interactive/overlays/ask-user.ts +227 -49
  476. package/src/interactive/overlays/auth-dialog.ts +1 -0
  477. package/src/interactive/overlays/context-reset.ts +1 -0
  478. package/src/interactive/overlays/cwd-fallback.ts +1 -0
  479. package/src/interactive/overlays/decisions.ts +11 -11
  480. package/src/interactive/overlays/extensions.ts +1 -0
  481. package/src/interactive/overlays/fleet-run-approval.ts +1 -0
  482. package/src/interactive/overlays/handoff-review.ts +1 -0
  483. package/src/interactive/overlays/help-reference.ts +6 -0
  484. package/src/interactive/overlays/interop.ts +1 -0
  485. package/src/interactive/overlays/library-install-confirm.ts +1 -0
  486. package/src/interactive/overlays/library-tabs.ts +28 -0
  487. package/src/interactive/overlays/list-overlay.ts +10 -1
  488. package/src/interactive/overlays/message-picker.ts +1 -0
  489. package/src/interactive/overlays/model-scope.ts +86 -0
  490. package/src/interactive/overlays/model-selector.ts +1 -0
  491. package/src/interactive/overlays/prompts.ts +12 -1
  492. package/src/interactive/overlays/session-selector.ts +1 -0
  493. package/src/interactive/overlays/settings-sections.ts +30 -0
  494. package/src/interactive/overlays/settings.ts +614 -45
  495. package/src/interactive/overlays/side-question.ts +1 -0
  496. package/src/interactive/overlays/skills-hub.ts +3 -11
  497. package/src/interactive/overlays/tree-selector.ts +1 -0
  498. package/src/interactive/pane-policy.ts +46 -0
  499. package/src/interactive/panes-runtime.ts +292 -0
  500. package/src/interactive/permission-hint.ts +34 -2
  501. package/src/interactive/permission-overlay.ts +159 -9
  502. package/src/interactive/prewarm.ts +197 -0
  503. package/src/interactive/render-trace.ts +162 -15
  504. package/src/interactive/renderers/compaction-summary.ts +29 -0
  505. package/src/interactive/renderers/tool-execution.ts +4 -0
  506. package/src/interactive/renderers/worker-entry.ts +122 -14
  507. package/src/interactive/side-question.ts +58 -1
  508. package/src/interactive/slash-commands.ts +251 -15
  509. package/src/interactive/status/controller.ts +11 -0
  510. package/src/interactive/status/state-machine.ts +54 -2
  511. package/src/interactive/status/types.ts +7 -0
  512. package/src/interactive/tasks-overlay.ts +1 -0
  513. package/src/interactive/terminal-lease.ts +2 -0
  514. package/src/interactive/theme/tokens.ts +3 -14
  515. package/src/interactive/turn-context.ts +346 -33
  516. package/src/interactive/turn-persistence.ts +14 -4
  517. package/src/interactive/turn-prewarm.ts +364 -0
  518. package/src/interactive/turn-queues.ts +7 -4
  519. package/src/interactive/turn-runtime.ts +8 -1
  520. package/src/interactive/turn-state.ts +23 -0
  521. package/src/interactive/view/artifacts.ts +109 -1
  522. package/src/interactive/view/view-overlay.ts +29 -3
  523. package/src/interactive/watch-pane.ts +152 -0
  524. package/src/interactive/worker-progress.ts +7 -1
  525. package/src/interactive/worker-receipts.ts +19 -1
  526. package/src/interactive/worker-stream.ts +5 -0
  527. package/src/interactive/yazi-bridge.ts +444 -0
  528. package/src/tools/ask-user.ts +43 -2
  529. package/src/tools/bootstrap.ts +26 -2
  530. package/src/tools/builtin-tool-catalog.ts +15 -0
  531. package/src/tools/compete-worktrees.ts +83 -2
  532. package/src/tools/core-bootstrap.ts +2 -1
  533. package/src/tools/dispatch-admission.ts +14 -3
  534. package/src/tools/dispatch-arguments.ts +20 -20
  535. package/src/tools/dispatch-plan.ts +17 -9
  536. package/src/tools/dispatch-run-events.ts +134 -19
  537. package/src/tools/dispatch-runner.ts +29 -7
  538. package/src/tools/dispatch-scout.ts +1 -1
  539. package/src/tools/dispatch-types.ts +15 -3
  540. package/src/tools/dispatch.ts +1 -1
  541. package/src/tools/executables.ts +17 -14
  542. package/src/tools/observation.ts +54 -4
  543. package/src/tools/panes-surface.ts +38 -0
  544. package/src/tools/panes.ts +112 -0
  545. package/src/tools/policy.ts +10 -1
  546. package/src/tools/presentation.ts +1 -0
  547. package/src/tools/registry.ts +16 -0
  548. package/dist/chunk-AOCYTWAV.js +0 -449
  549. package/dist/chunk-HLE42MG7.js +0 -37
  550. package/dist/chunk-HWUFFB6L.js +0 -83
  551. package/dist/chunk-JOZYP4GM.js +0 -279
  552. package/dist/doctor-M7YEDGAE.js +0 -91
@@ -2,7 +2,7 @@ import { performance } from "node:perf_hooks";
2
2
  import type { OutputVerbosity } from "../core/defaults.js";
3
3
  import { SKILL_SUGGESTION_PREFIX } from "../core/skill-activation.js";
4
4
  import { rawDurationMs } from "../core/timers.js";
5
- import { type Component, Markdown, truncateToWidth, wrapTextWithAnsi } from "../engine/tui.js";
5
+ import { type Component, Markdown, truncateToWidth, visibleWidth, wrapTextWithAnsi } from "../engine/tui.js";
6
6
  import type { AgentMessage } from "../engine/types.js";
7
7
  import { toolPresentationPolicy } from "../tools/presentation.js";
8
8
  import { toolResultPresentationPolicy } from "../tools/result-disposition.js";
@@ -252,7 +252,7 @@ type ReplayBlockRenderer = (width: number, detail: TranscriptDetailPolicy) => st
252
252
  type AssistantStatusLine = { phase: StatusPhase; verb: string; toneHint: VerbRender["toneHint"] };
253
253
 
254
254
  type TranscriptEntry =
255
- | { role: "user"; text: string }
255
+ | { role: "user"; text: string; status?: () => UserTurnStatus }
256
256
  | { role: "retryStatus"; status: RetryStatusPayload }
257
257
  | {
258
258
  role: "assistant";
@@ -308,8 +308,20 @@ export interface ReplayBlockFoldControl {
308
308
  setFold(fold: FoldOverride): void;
309
309
  }
310
310
 
311
+ /**
312
+ * Whether a painted operator turn exists in the ledger yet. `pending` is the
313
+ * window between the editor being consumed and admission; `refused` is a
314
+ * submit that never reached the durable append.
315
+ */
316
+ export type UserTurnStatus = "pending" | "committed" | "refused";
317
+
311
318
  export interface ChatPanel extends Component {
312
- appendUser(text: string): void;
319
+ /**
320
+ * Paint an operator turn. `status`, when given, is read every frame while it
321
+ * reports anything but `committed`, so the row the transcript shows before
322
+ * admission is visibly not the durable turn it will become.
323
+ */
324
+ appendUser(text: string, status?: () => UserTurnStatus): void;
313
325
  /**
314
326
  * Append a caller-rendered block. Pass `isLive` when the closure reads state
315
327
  * that keeps changing after the append, so the panel keeps re-rendering it
@@ -675,6 +687,20 @@ function renderErrorSegmentLines(seg: ErrorSegment, width: number): string[] {
675
687
  const CLIO_PREFIX = `${TEAL}${AGENT_GLYPH}${RESET} `;
676
688
  const CLIO_PREFIX_ERROR = `${RED_CRIT}${AGENT_GLYPH}${RESET} `;
677
689
  const USER_PREFIX = `${TEAL}${USER_GLYPH}${RESET} `;
690
+ /**
691
+ * A prompt Clio has taken but not yet committed. The glyph is dim rather than
692
+ * teal and the row says so, because the transcript used to paint an
693
+ * uncommitted prompt exactly like a durable user turn while the ledger still
694
+ * had no entry for it (issue #251).
695
+ */
696
+ const USER_PREFIX_PENDING = `${DIM}${USER_GLYPH}${RESET} `;
697
+ /**
698
+ * The uncommitted-row tails, stored as plain text so their width can be spent
699
+ * against the row's budget before the dim codes go on. Both begin with the
700
+ * separating space they carry when they ride on the end of a body line.
701
+ */
702
+ const USER_PENDING_TAIL = " · preparing";
703
+ const USER_REFUSED_TAIL = " · not sent";
678
704
  const PROSE_GUTTER = " ";
679
705
  const PROSE_GUTTER_WIDTH = 2;
680
706
 
@@ -688,6 +714,30 @@ function hangProseLines(lines: string[], firstPrefix?: string): string[] {
688
714
  return lines.map((line, index) => `${index === 0 && firstPrefix !== undefined ? firstPrefix : PROSE_GUTTER}${line}`);
689
715
  }
690
716
 
717
+ /**
718
+ * Put an uncommitted row's status tail on the row without letting it push a
719
+ * line past the terminal. The tail used to be concatenated onto the last
720
+ * rendered line unconditionally, so a body that had already folded near the
721
+ * content width came out up to 12 cells past the terminal, and pi-tui's
722
+ * `doRender` throws on an overlong line and kills the process. A `/share` of
723
+ * a worker answer is the ordinary way to hit that: a `research-report` body is
724
+ * JSON with no space to fold at, so an 80-column pane died on any shared body
725
+ * over 58 columns (#257).
726
+ *
727
+ * The tail rides on the last body line when that line has room for it, and
728
+ * drops to its own hanging row when it does not, so it stays whole either way
729
+ * rather than breaking between `·` and the word.
730
+ */
731
+ function appendUserRowTail(rendered: string[], tail: string, width: number): void {
732
+ const last = rendered.length - 1;
733
+ const lastLine = rendered[last];
734
+ if (lastLine !== undefined && visibleWidth(lastLine) + tail.length <= width) {
735
+ rendered[last] = `${lastLine}${DIM}${tail}${RESET}`;
736
+ return;
737
+ }
738
+ rendered.push(`${PROSE_GUTTER}${dimLine(tail.trimStart(), Math.max(1, width - PROSE_GUTTER_WIDTH))}`);
739
+ }
740
+
691
741
  /**
692
742
  * Static marker used when thinking is folded. This matches pi-coding-agent's
693
743
  * hidden-thinking presentation and avoids previewing reasoning content.
@@ -964,8 +1014,11 @@ function renderEntryLines(
964
1014
  const contentWidth = Math.max(1, width - PROSE_GUTTER_WIDTH);
965
1015
  const lines: string[] = [];
966
1016
  for (const sourceLine of entry.text.split("\n")) lines.push(...wrapTextWithAnsi(sourceLine, contentWidth));
967
- const rendered = hangProseLines(lines, USER_PREFIX);
1017
+ const status = entry.status?.() ?? "committed";
1018
+ const rendered = hangProseLines(lines, status === "committed" ? USER_PREFIX : USER_PREFIX_PENDING);
968
1019
  if (rendered[0] !== undefined) rendered[0] = `${OSC133_PROMPT_START}${rendered[0]}`;
1020
+ if (status !== "committed")
1021
+ appendUserRowTail(rendered, status === "pending" ? USER_PENDING_TAIL : USER_REFUSED_TAIL, width);
969
1022
  return rendered;
970
1023
  }
971
1024
  if (entry.role === "retryStatus") {
@@ -1450,7 +1503,8 @@ export function createChatPanel(options: ChatPanelOptions = {}): ChatPanel {
1450
1503
  // only thinking still needs the time-keyed render key.
1451
1504
  ) ||
1452
1505
  (entry.pending && openThinkingSegment(entry)?.startedAtMs !== undefined))) ||
1453
- (entry.role === "replayBlock" && entry.isLive?.() === true);
1506
+ (entry.role === "replayBlock" && entry.isLive?.() === true) ||
1507
+ (entry.role === "user" && (entry.status?.() ?? "committed") !== "committed");
1454
1508
 
1455
1509
  /**
1456
1510
  * Settled entries whose render is a pure function of the base key. A live
@@ -1460,7 +1514,7 @@ export function createChatPanel(options: ChatPanelOptions = {}): ChatPanel {
1460
1514
  * declares itself live is excluded on the same grounds.
1461
1515
  */
1462
1516
  const entryIsStable = (entry: TranscriptEntry): boolean =>
1463
- entry.role === "user" ||
1517
+ (entry.role === "user" && (entry.status?.() ?? "committed") === "committed") ||
1464
1518
  (entry.role === "replayBlock" && entry.isLive?.() !== true) ||
1465
1519
  (entry.role === "worker" && !entry.state.pending) ||
1466
1520
  (entry.role === "assistant" &&
@@ -1593,8 +1647,8 @@ export function createChatPanel(options: ChatPanelOptions = {}): ChatPanel {
1593
1647
  };
1594
1648
 
1595
1649
  return {
1596
- appendUser(text: string): void {
1597
- transcript.push({ role: "user", text });
1650
+ appendUser(text: string, status?: () => UserTurnStatus): void {
1651
+ transcript.push({ role: "user", text, ...(status ? { status } : {}) });
1598
1652
  markDirty();
1599
1653
  },
1600
1654
  appendReplayBlock(renderBlock: ReplayBlockRenderer, isLive?: () => boolean, fold?: ReplayBlockFoldControl): void {
@@ -1,12 +1,15 @@
1
1
  import { Editor, stripTerminalSequences, type TUI, truncateToWidth, visibleWidth } from "../engine/tui.js";
2
2
  import { fitHintEntries } from "./overlay-frame.js";
3
- import { permissionHintEntries } from "./permission-hint.js";
3
+ import { type PermissionInspectionHint, permissionHintEntries } from "./permission-hint.js";
4
4
  import type { ClioTheme } from "./theme/index.js";
5
5
  import { clioTheme, editorTheme, GLYPH, rule } from "./theme/index.js";
6
+ import type { TurnPreparationPhase } from "./turn-state.js";
6
7
 
7
8
  const REVERSE_VIDEO_BLANK = `${String.fromCharCode(27)}[7m ${String.fromCharCode(27)}[0m`;
8
9
  const EMPTY_PROMPT = "Ask Clio… / for commands";
9
10
  const CONFIRM_PROMPT = "A parked call is waiting for your decision";
11
+ const PREPARING_PROMPT = "Clio has your prompt and is preparing the turn";
12
+ const COMPACTING_PROMPT = "Clio has your prompt and is compacting the context first";
10
13
  const MIN_HINT_WIDTH = 60;
11
14
 
12
15
  function hasScrollIndicator(line: string): boolean {
@@ -28,6 +31,19 @@ export interface EditorChrome {
28
31
  * dialog's keys whenever the prompt owns input (issues #186 and #194).
29
32
  */
30
33
  isAwaitingApproval?: () => boolean;
34
+ /**
35
+ * Whether that prompt is a mutation the operator can read locally, and
36
+ * whether it is open. The rail carries the dialog's keys, so it names the
37
+ * inspect key on exactly the cards that have one (issue #254).
38
+ */
39
+ getPermissionInspection?: () => PermissionInspectionHint;
40
+ /**
41
+ * Where a consumed prompt is between the editor and the stream. The editor
42
+ * is cleared before admission, so without this the composer went straight
43
+ * back to `MESSAGE` and a 77-second pre-submit compaction was
44
+ * indistinguishable from a dropped Enter (issue #251).
45
+ */
46
+ getTurnPreparation?: () => TurnPreparationPhase;
31
47
  /** Whether the current draft will actually steer Clio or live dispatch work on Enter. */
32
48
  willEnterSteer?: (text: string) => boolean;
33
49
  /** Resolved submit binding, formatted for display. */
@@ -36,7 +52,7 @@ export interface EditorChrome {
36
52
  getNewlineKeyLabel?: () => string;
37
53
  }
38
54
 
39
- type ComposerMode = "MESSAGE" | "FOLLOW-UP" | "STEER" | "CONFIRM";
55
+ type ComposerMode = "MESSAGE" | "FOLLOW-UP" | "STEER" | "CONFIRM" | "PREPARING" | "COMPACTING";
40
56
 
41
57
  function normalizeThinkingHint(value: string): string {
42
58
  return value
@@ -72,7 +88,15 @@ function styledRailLabel(theme: ClioTheme, chrome: EditorChrome): string {
72
88
 
73
89
  function composerMode(chrome: EditorChrome, text: string): ComposerMode {
74
90
  if (chrome.isAwaitingApproval?.() ?? false) return "CONFIRM";
75
- if (!(chrome.isStreaming?.() ?? false)) return "MESSAGE";
91
+ if (!(chrome.isStreaming?.() ?? false)) {
92
+ // A prompt Clio is holding is not an idle composer. Streaming outranks it
93
+ // because a steer typed during a live run is what the rail is for, and a
94
+ // steer's own submit passes through this window on its way to the queue.
95
+ const preparation = chrome.getTurnPreparation?.() ?? "idle";
96
+ if (preparation === "compacting") return "COMPACTING";
97
+ if (preparation === "preparing") return "PREPARING";
98
+ return "MESSAGE";
99
+ }
76
100
  const willSteer = chrome.willEnterSteer?.(text) ?? text.trim().length > 0;
77
101
  return willSteer ? "STEER" : "FOLLOW-UP";
78
102
  }
@@ -89,16 +113,29 @@ function lowerRailHint(theme: ClioTheme, chrome: EditorChrome): string {
89
113
  * both surfaces narrow in the same order and never drop allow or stop first.
90
114
  * The rule spends three columns around a right label, hence the subtraction.
91
115
  */
92
- function confirmRailHint(theme: ClioTheme, width: number, hasDraft: boolean): string {
93
- return theme.fg("warning", fitHintEntries(permissionHintEntries(hasDraft), Math.max(1, width - 3)));
116
+ function confirmRailHint(
117
+ theme: ClioTheme,
118
+ width: number,
119
+ hasDraft: boolean,
120
+ inspection: PermissionInspectionHint,
121
+ ): string {
122
+ return theme.fg("warning", fitHintEntries(permissionHintEntries(hasDraft, inspection), Math.max(1, width - 3)));
94
123
  }
95
124
 
96
125
  function modeToken(mode: ComposerMode): "action" | "accentDeep" | "warning" {
97
- if (mode === "STEER") return "action";
126
+ if (mode === "STEER" || mode === "PREPARING" || mode === "COMPACTING") return "action";
98
127
  if (mode === "CONFIRM") return "warning";
99
128
  return "accentDeep";
100
129
  }
101
130
 
131
+ /** The line the empty composer shows for the mode it is in. */
132
+ function emptyPromptFor(mode: ComposerMode): string {
133
+ if (mode === "CONFIRM") return CONFIRM_PROMPT;
134
+ if (mode === "PREPARING") return PREPARING_PROMPT;
135
+ if (mode === "COMPACTING") return COMPACTING_PROMPT;
136
+ return EMPTY_PROMPT;
137
+ }
138
+
102
139
  function renderEmptyPrompt(line: string, width: number, theme: ClioTheme, text = EMPTY_PROMPT): string {
103
140
  const cursorAt = line.indexOf(REVERSE_VIDEO_BLANK);
104
141
  if (cursorAt < 0) return line;
@@ -151,7 +188,7 @@ export class ClioEditor extends Editor {
151
188
  }
152
189
 
153
190
  if (text.length === 0 && lines[1]) {
154
- lines[1] = renderEmptyPrompt(lines[1], safeWidth, theme, mode === "CONFIRM" ? CONFIRM_PROMPT : EMPTY_PROMPT);
191
+ lines[1] = renderEmptyPrompt(lines[1], safeWidth, theme, emptyPromptFor(mode));
155
192
  }
156
193
 
157
194
  const bottomRail = findBottomRail(lines, safeWidth);
@@ -159,7 +196,7 @@ export class ClioEditor extends Editor {
159
196
  // that a narrow composer can drop, the allow and deny keys are not.
160
197
  if (bottomRail >= 0 && mode === "CONFIRM") {
161
198
  lines[bottomRail] = rule(theme, safeWidth, {
162
- right: confirmRailHint(theme, safeWidth, text.length > 0),
199
+ right: confirmRailHint(theme, safeWidth, text.length > 0, this.chrome.getPermissionInspection?.() ?? "none"),
163
200
  fillToken: "frameStrong",
164
201
  rightRaw: true,
165
202
  rightTail: theme.style("frameStrong", "─", { bold: true }),
@@ -32,6 +32,8 @@ const PHASES: ReadonlyArray<ContextActivityPhase> = ["scan", "codewiki", "genera
32
32
  * happen.
33
33
  */
34
34
  const WIKI_PHASES: ReadonlyArray<ContextActivityPhase> = ["codewiki", "generate", "state", "done"];
35
+ /** Compaction is one bounded operation, not the five-stage context-init pipeline. */
36
+ const COMPACTION_PHASES: ReadonlyArray<ContextActivityPhase> = ["compact", "done"];
35
37
  const PHASE_LABELS: Record<ContextActivityPhase, string> = {
36
38
  scan: "scan",
37
39
  // "index" rather than "wiki": this phase is the codewiki index build, and
@@ -40,6 +42,7 @@ const PHASE_LABELS: Record<ContextActivityPhase, string> = {
40
42
  generate: "draft",
41
43
  "clio-md": "CLIO-CODER.md",
42
44
  state: "state",
45
+ compact: "compact",
43
46
  done: "done",
44
47
  };
45
48
  const WIKI_PHASE_LABELS: Partial<Record<ContextActivityPhase, string>> = {
@@ -55,9 +58,10 @@ const KINDS: ReadonlySet<string> = new Set<ContextActivityKind>([
55
58
  "context-wiki",
56
59
  "compaction",
57
60
  ]);
58
- const PHASE_SET: ReadonlySet<string> = new Set<ContextActivityPhase>(PHASES);
61
+ const PHASE_SET: ReadonlySet<string> = new Set<ContextActivityPhase>([...PHASES, ...COMPACTION_PHASES]);
59
62
 
60
63
  function phasesFor(kind: ContextActivityKind): ReadonlyArray<ContextActivityPhase> {
64
+ if (kind === "compaction") return COMPACTION_PHASES;
61
65
  return kind === "context-wiki" ? WIKI_PHASES : PHASES;
62
66
  }
63
67
 
@@ -18,7 +18,7 @@ export const CONTEXT_CATEGORY_TOKEN: Readonly<Record<ContextLedgerCategory, Clio
18
18
  project: "muted",
19
19
  messages: "accent",
20
20
  pending: "accentDeep",
21
- reserve: "dim",
21
+ reserve: "frame",
22
22
  free: "frame",
23
23
  streaming: "accent",
24
24
  };
@@ -77,7 +77,7 @@ function legendRow(group: ContextLedgerGroup, contentWidth: number): string {
77
77
  const tokens = formatTokens(group.tokens);
78
78
  const percent = formatContextPercent(group.percent);
79
79
  const right = `${tokens.padStart(9)} ${percent.padStart(6)}`;
80
- const labelToken: ClioToken = group.category === "free" || group.category === "reserve" ? "dim" : "muted";
80
+ const labelToken: ClioToken = group.category === "reserve" ? "frame" : group.category === "free" ? "dim" : "muted";
81
81
  const leftWidth = Math.max(0, contentWidth - visibleWidth(right) - 2);
82
82
  const labelText = group.label.length > leftWidth ? group.label.slice(0, leftWidth) : group.label.padEnd(leftWidth);
83
83
  return `${swatch} ${theme.fg(labelToken, labelText)} ${theme.fg("muted", right)}`;
@@ -108,6 +108,16 @@ function coldReasonLabel(reason: string): string {
108
108
  return "compaction";
109
109
  case "dispatch":
110
110
  return "dispatch traffic";
111
+ case "residency":
112
+ return "residency change";
113
+ case "thinking_change":
114
+ return "thinking-level change";
115
+ case "tool_surface_change":
116
+ return "tool-surface change";
117
+ case "prompt_recompiled":
118
+ return "prompt recompile";
119
+ case "background_memory":
120
+ return "background memory step";
111
121
  default:
112
122
  return reason;
113
123
  }
@@ -221,8 +231,10 @@ export function renderContextLedgerLines(
221
231
  if (ledger.promptCache) {
222
232
  const cache = ledger.promptCache;
223
233
  const shell = cache.shellReused ? "shell reused" : "shell recompiled";
224
- const backend =
225
- cache.backendVerdict === "hot" || cache.backendVerdict === "partial"
234
+ const backendCacheReadsUnknown = cache.backend?.cachedTokens === null;
235
+ const backend = backendCacheReadsUnknown
236
+ ? "server does not report cache reads"
237
+ : cache.backendVerdict === "hot" || cache.backendVerdict === "partial"
226
238
  ? "backend reused"
227
239
  : cache.backendVerdict === "cold"
228
240
  ? "backend cold"
@@ -232,24 +244,42 @@ export function renderContextLedgerLines(
232
244
  const read = cache.cacheReadTokens !== null ? `cache read ${formatTokens(cache.cacheReadTokens)}` : "cache read n/a";
233
245
  const uncached =
234
246
  cache.uncachedInputTokens !== null ? `uncached input ${formatTokens(cache.uncachedInputTokens)}` : null;
235
- const line = ["prompt cache:", shell, "·", backend, "·", read, ...(uncached ? ["·", uncached] : [])].join(" ");
236
- // Reasons Clio recorded before the run: working-set eviction, summary
237
- // compaction, and dispatch traffic all move the byte prefix a local
238
- // single-slot backend caches, so a cold turn after one of them is the
239
- // expected outcome rather than a provider surprise.
240
- const coldReasons = cache.backendVerdict === "cold" ? (cache.expectedColdReasons ?? []) : [];
247
+ const line = backendCacheReadsUnknown
248
+ ? ["prompt cache:", shell, "·", backend].join(" ")
249
+ : ["prompt cache:", shell, "·", backend, "·", read, ...(uncached ? ["·", uncached] : [])].join(" ");
250
+ // Reasons Clio recorded before the run describe either prefix-byte changes
251
+ // or local-server activity that displaced the cached prefix. A cold turn
252
+ // after one of them is expected rather than a provider surprise.
253
+ const coldReasons =
254
+ cache.backendVerdict === "cold" && !backendCacheReadsUnknown ? (cache.expectedColdReasons ?? []) : [];
241
255
  // A reused shell with a cold backend means Clio kept the bytes stable
242
256
  // but the provider re-prefilled anyway; surface that disagreement
243
257
  // instead of hiding it. An expected reason explains the same numbers, so
244
258
  // it is reported on its own line and not as a warning.
245
- const misleading = cache.shellReused && cache.backendVerdict === "cold" && coldReasons.length === 0;
259
+ const misleading =
260
+ cache.shellReused && cache.backendVerdict === "cold" && !backendCacheReadsUnknown && coldReasons.length === 0;
246
261
  lines.push(theme.fg(misleading ? "warning" : "dim", line));
262
+ if (cache.backend) {
263
+ const prefill =
264
+ cache.backend.cachedTokens !== null && cache.uncachedPrefillTokens !== null
265
+ ? `prefill: ${formatTokens(cache.uncachedPrefillTokens)} uncached · ${formatTokens(cache.backend.cachedTokens)} cached · ${formatTokens(cache.backend.promptMs)} ms`
266
+ : `prefill: ${formatTokens(cache.backend.promptTokens)} prompt · ${formatTokens(cache.backend.promptMs)} ms`;
267
+ lines.push(theme.fg("dim", prefill));
268
+ }
247
269
  if (coldReasons.length > 0) {
248
270
  const reasons = coldReasons.map(coldReasonLabel).join(", ");
249
271
  lines.push(theme.fg("dim", `last cold turn: ${reasons} (expected)`));
250
272
  }
251
273
  }
252
274
 
275
+ if (ledger.prewarm) {
276
+ // What the backend has already prefilled for the turn the operator has not
277
+ // typed yet. It survives until the next settled run answers the question.
278
+ const tokens = ledger.prewarm.tokens !== null ? `${formatTokens(ledger.prewarm.tokens)} tokens` : "prefix";
279
+ const aborted = ledger.prewarm.aborted ? " (aborted on submit; prefix stays in the slot)" : "";
280
+ lines.push(theme.fg("dim", `prewarmed: ${tokens} in ${formatTokens(ledger.prewarm.ms)} ms${aborted}`));
281
+ }
282
+
253
283
  if (ledger.lastCompaction) {
254
284
  const pruneInfo = `last compaction: reclaimed ${formatTokens(ledger.lastCompaction.tokensBefore)} -> ${formatTokens(ledger.lastCompaction.tokensAfter)} tokens (${ledger.lastCompaction.stage})`;
255
285
  lines.push(theme.fg("dim", pruneInfo));
@@ -300,6 +330,7 @@ export function openContextOverlay(
300
330
  const handle = showClioOverlayFrame(tui, text, {
301
331
  anchor: "center",
302
332
  width: CONTEXT_OVERLAY_WIDTH,
333
+ markerId: "context-view",
303
334
  title: "Context Window",
304
335
  footerHint: buildHint([]),
305
336
  });
@@ -11,6 +11,12 @@ import {
11
11
  type ObservabilityContract,
12
12
  type ObservabilitySnapshot,
13
13
  } from "../domains/observability/index.js";
14
+ import {
15
+ foldPromptCacheTelemetry,
16
+ hasPromptCacheTelemetry,
17
+ type PromptCacheTelemetry,
18
+ type SessionEntry,
19
+ } from "../domains/session/index.js";
14
20
  import type { Component, OverlayHandle, TUI } from "../engine/tui.js";
15
21
  import { buildHint, showClioOverlayFrame } from "./overlay-frame.js";
16
22
  import { clioTheme, rule } from "./theme/index.js";
@@ -36,6 +42,10 @@ export interface CostRow {
36
42
  sideQuestions: number;
37
43
  /** Calls in this row that were `/handoff` extraction rounds rather than turns. */
38
44
  handoffs: number;
45
+ /** Calls in this row that were session pre-warms rather than turns. */
46
+ prewarms: number;
47
+ /** Calls in this row that were proactive-memory steps on the background target. */
48
+ backgroundMemory: number;
39
49
  cost: CostAggregate;
40
50
  }
41
51
 
@@ -67,6 +77,8 @@ export function aggregateCostEntries(entries: ReadonlyArray<CostEntry>): CostRow
67
77
  existing.row.apiCalls += entry.apiCalls ?? 1;
68
78
  if (entry.label === "side-question") existing.row.sideQuestions += 1;
69
79
  if (entry.label === "handoff") existing.row.handoffs += 1;
80
+ if (entry.label === "prewarm") existing.row.prewarms += 1;
81
+ if (entry.label === "background-memory") existing.row.backgroundMemory += 1;
70
82
  for (const requestedModelId of entry.requestedModelIds) existing.requestedModelIds.add(requestedModelId);
71
83
  addResponseModelIdObservationCounts(
72
84
  existing.responseModelIdObservationCounts,
@@ -89,6 +101,8 @@ export function aggregateCostEntries(entries: ReadonlyArray<CostEntry>): CostRow
89
101
  apiCalls: entry.apiCalls ?? 1,
90
102
  sideQuestions: entry.label === "side-question" ? 1 : 0,
91
103
  handoffs: entry.label === "handoff" ? 1 : 0,
104
+ prewarms: entry.label === "prewarm" ? 1 : 0,
105
+ backgroundMemory: entry.label === "background-memory" ? 1 : 0,
92
106
  },
93
107
  requestedModelIds: new Set(entry.requestedModelIds),
94
108
  responseModelIdObservationCounts: { ...entry.responseModelIdObservationCounts },
@@ -127,6 +141,8 @@ function sumRows(
127
141
  apiCalls: acc.apiCalls + row.apiCalls,
128
142
  sideQuestions: acc.sideQuestions + row.sideQuestions,
129
143
  handoffs: acc.handoffs + row.handoffs,
144
+ prewarms: acc.prewarms + row.prewarms,
145
+ backgroundMemory: acc.backgroundMemory + row.backgroundMemory,
130
146
  }),
131
147
  {
132
148
  runs: 0,
@@ -139,6 +155,8 @@ function sumRows(
139
155
  apiCalls: 0,
140
156
  sideQuestions: 0,
141
157
  handoffs: 0,
158
+ prewarms: 0,
159
+ backgroundMemory: 0,
142
160
  },
143
161
  );
144
162
  }
@@ -179,7 +197,12 @@ function kvBlock(entries: ReadonlyArray<readonly [string, string, string?]>): st
179
197
  });
180
198
  }
181
199
 
182
- function summaryBlock(totalCost: CostAggregate, totalTokens: number, rows: ReadonlyArray<CostRow>): string[] {
200
+ function summaryBlock(
201
+ totalCost: CostAggregate,
202
+ totalTokens: number,
203
+ rows: ReadonlyArray<CostRow>,
204
+ promptCache: PromptCacheTelemetry | null,
205
+ ): string[] {
183
206
  const totals = sumRows(rows);
184
207
  const resolvedTotal = totalTokens > 0 ? totalTokens : totals.tokens;
185
208
  // No priced call, no cost row: neither the `cost $0.00` the overlay used to
@@ -190,17 +213,36 @@ function summaryBlock(totalCost: CostAggregate, totalTokens: number, rows: Reado
190
213
  // A side question is billed like anything else and is counted here, but it is
191
214
  // deliberately not a turn: it never entered the session, so `turns` above
192
215
  // excludes it and this row says how much of the spend sat beside the session.
216
+ const cacheRows =
217
+ promptCache !== null && hasPromptCacheTelemetry(promptCache)
218
+ ? [
219
+ [
220
+ "uncached prefill",
221
+ promptCache.uncachedPrefillTokens === null ? "not reported" : formatTokens(promptCache.uncachedPrefillTokens),
222
+ ] as const,
223
+ [
224
+ "cache verdicts",
225
+ `hot ${promptCache.verdictCounts.hot} · partial ${promptCache.verdictCounts.partial} · cold ${promptCache.verdictCounts.cold} · small ${promptCache.verdictCounts.small}`,
226
+ ] as const,
227
+ ]
228
+ : [];
193
229
  return kvBlock([
194
- ["turns", formatTokens(totals.runs - totals.sideQuestions - totals.handoffs)],
230
+ [
231
+ "turns",
232
+ formatTokens(totals.runs - totals.sideQuestions - totals.handoffs - totals.prewarms - totals.backgroundMemory),
233
+ ],
195
234
  ["model calls", formatTokens(totals.apiCalls)],
196
235
  ...(totals.sideQuestions > 0 ? [["side questions", formatTokens(totals.sideQuestions)] as const] : []),
197
236
  ...(totals.handoffs > 0 ? [["handoffs", formatTokens(totals.handoffs)] as const] : []),
237
+ ...(totals.prewarms > 0 ? [["pre-warms", formatTokens(totals.prewarms)] as const] : []),
238
+ ...(totals.backgroundMemory > 0 ? [["memory steps", formatTokens(totals.backgroundMemory)] as const] : []),
198
239
  ...(cost === null ? [] : [["cost", cost] as const]),
199
240
  ["input", formatTokens(totals.input)],
200
241
  ["output", formatTokens(totals.output)],
201
242
  ["reasoning", ...reasoningValue(totals.reasoningTokens)],
202
243
  ["cache read", ...cacheReadValue(totals.cacheRead, totals.apiCalls)],
203
244
  ["cache write", formatTokens(totals.cacheWrite)],
245
+ ...cacheRows,
204
246
  ["processed", `${formatTokens(resolvedTotal)} tokens`],
205
247
  ]);
206
248
  }
@@ -213,10 +255,12 @@ function modelBlock(row: CostRow): string[] {
213
255
  return kvBlock([
214
256
  ["requested model ids", row.requestedModelIds.join(", ")],
215
257
  ["response model id observation", responseModelIdObservationCountsLabel(row.responseModelIdObservationCounts)],
216
- ["turns", formatTokens(row.runs - row.sideQuestions - row.handoffs)],
258
+ ["turns", formatTokens(row.runs - row.sideQuestions - row.handoffs - row.prewarms - row.backgroundMemory)],
217
259
  ["model calls", formatTokens(row.apiCalls)],
218
260
  ...(row.sideQuestions > 0 ? [["side questions", formatTokens(row.sideQuestions)] as const] : []),
219
261
  ...(row.handoffs > 0 ? [["handoffs", formatTokens(row.handoffs)] as const] : []),
262
+ ...(row.prewarms > 0 ? [["pre-warms", formatTokens(row.prewarms)] as const] : []),
263
+ ...(row.backgroundMemory > 0 ? [["memory steps", formatTokens(row.backgroundMemory)] as const] : []),
220
264
  ...(cost === null ? [] : [["cost", cost] as const]),
221
265
  ["input", formatTokens(row.input)],
222
266
  ["output", formatTokens(row.output)],
@@ -232,10 +276,11 @@ export function formatCostOverlayBodyLines(
232
276
  totalTokens: number,
233
277
  rows: ReadonlyArray<CostRow>,
234
278
  contentWidth: number,
279
+ promptCache: PromptCacheTelemetry | null = null,
235
280
  ): string[] {
236
281
  const theme = clioTheme();
237
282
  const lines: string[] = [];
238
- for (const line of summaryBlock(totalCost, totalTokens, rows)) {
283
+ for (const line of summaryBlock(totalCost, totalTokens, rows, promptCache)) {
239
284
  lines.push(line);
240
285
  }
241
286
  lines.push(rule(theme, contentWidth));
@@ -258,6 +303,7 @@ export interface CostSnapshot {
258
303
  totalCost: CostAggregate;
259
304
  totalTokens: number;
260
305
  rows: CostRow[];
306
+ promptCache: PromptCacheTelemetry | null;
261
307
  }
262
308
 
263
309
  // Session totals come from the observability projection: when a snapshot is
@@ -268,6 +314,7 @@ function buildCostSnapshot(
268
314
  observability: ObservabilityContract,
269
315
  sessionId: string | null,
270
316
  snapshot?: ObservabilitySnapshot,
317
+ getSessionEntries?: () => ReadonlyArray<SessionEntry>,
271
318
  ): CostSnapshot {
272
319
  const entries = observability.costEntries();
273
320
  const rows = aggregateCostEntries(entries);
@@ -277,11 +324,14 @@ function buildCostSnapshot(
277
324
  totalCost: snapshot?.session.cost ?? observability.sessionCostSummary(),
278
325
  totalTokens,
279
326
  rows,
327
+ promptCache: getSessionEntries ? foldPromptCacheTelemetry(getSessionEntries()) : null,
280
328
  };
281
329
  }
282
330
 
283
331
  export interface OpenCostOverlayOptions {
284
332
  sessionId?: string | null;
333
+ /** Session ledger, read on every render so newly settled and branched calls appear. */
334
+ getSessionEntries?: () => ReadonlyArray<SessionEntry>;
285
335
  }
286
336
 
287
337
  class CostOverlayBody implements Component {
@@ -290,7 +340,13 @@ class CostOverlayBody implements Component {
290
340
  render(width: number): string[] {
291
341
  const contentWidth = Math.max(1, Math.floor(width));
292
342
  const snapshot = this.getSnapshot();
293
- return formatCostOverlayBodyLines(snapshot.totalCost, snapshot.totalTokens, snapshot.rows, contentWidth);
343
+ return formatCostOverlayBodyLines(
344
+ snapshot.totalCost,
345
+ snapshot.totalTokens,
346
+ snapshot.rows,
347
+ contentWidth,
348
+ snapshot.promptCache,
349
+ );
294
350
  }
295
351
 
296
352
  invalidate(): void {}
@@ -312,10 +368,14 @@ export function openCostOverlay(
312
368
  ): OverlayHandle {
313
369
  const sessionId = options?.sessionId ?? null;
314
370
  let latest: ObservabilitySnapshot = observability.snapshot();
315
- const body = new CostOverlayBody(() => buildCostSnapshot(observability, sessionId, latest));
371
+ const body = new CostOverlayBody(() =>
372
+ buildCostSnapshot(observability, sessionId, latest, options?.getSessionEntries),
373
+ );
316
374
  const handle = showClioOverlayFrame(tui, body, {
317
375
  anchor: "center",
318
376
  width: COST_OVERLAY_WIDTH,
377
+ // Not derived from the title: that one carries the session id.
378
+ markerId: "cost",
319
379
  title: sessionId && sessionId.length > 0 ? `Session usage (${sessionId})` : "Session usage",
320
380
  footerHint: buildHint([]),
321
381
  });
@@ -14,6 +14,7 @@
14
14
  */
15
15
 
16
16
  import { truncateToWidth, wrapTextWithAnsi } from "../engine/tui.js";
17
+ import { COUNCIL_SYNTHESIS_LABEL } from "./council.js";
17
18
  import {
18
19
  type ClioTheme,
19
20
  type ClioToken,
@@ -38,9 +39,6 @@ export const COUNCIL_COLUMN_GUTTER = 2;
38
39
  /** Rows of a member's bounded answer tail a column shows before it defers to `/view`. */
39
40
  export const COUNCIL_ANSWER_ROWS = 4;
40
41
 
41
- /** The label the coordinator gives the synthesis run of every council group. */
42
- export const COUNCIL_SYNTHESIS_LABEL = "synthesis";
43
-
44
42
  /** One council run as the board draws it: the roster facts plus the run's presentation. */
45
43
  export interface CouncilMemberView {
46
44
  runId: string;
@@ -26,6 +26,17 @@ export type CouncilSynthesisMode = (typeof COUNCIL_SYNTHESIS_MODES)[number];
26
26
  /** Rounds the dispatch tool admits. The command enforces the same bound where the operator typed it. */
27
27
  export const COUNCIL_MAX_ROUNDS = 3;
28
28
 
29
+ /**
30
+ * The label the coordinator gives the synthesis run of every council group.
31
+ *
32
+ * It lives here rather than beside the board layout that draws it because it is
33
+ * council vocabulary, not presentation: the share path compares against it to
34
+ * decide whether a run seals the whole council or one voice, and that path must
35
+ * stay off the render module graph. See the header of
36
+ * `src/interactive/slash-commands.ts` for the closure budget that depends on it.
37
+ */
38
+ export const COUNCIL_SYNTHESIS_LABEL = "synthesis";
39
+
29
40
  export function isCouncilSynthesisMode(value: string): value is CouncilSynthesisMode {
30
41
  return COUNCIL_SYNTHESIS_MODES.some((mode) => mode === value);
31
42
  }