@iowarp/clio-coder 0.5.0 → 0.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (312) hide show
  1. package/.claude-plugin/marketplace.json +4 -4
  2. package/CHANGELOG.md +35 -0
  3. package/CONTRIBUTING.md +9 -0
  4. package/README.md +12 -9
  5. package/ROADMAP.md +30 -5
  6. package/dist/{acp-KS7ARGV6.js → acp-F6PGOFZ4.js} +2 -2
  7. package/dist/{agents-YOGJ2YEJ.js → agents-ZHP4R6EX.js} +22 -21
  8. package/dist/assets/codewiki.json +1 -1
  9. package/dist/{auth-CEDCO6O6.js → auth-N75U2H3Z.js} +4 -4
  10. package/dist/{chunk-D3KWFOUT.js → chunk-23UIXH6Z.js} +3 -3
  11. package/dist/{chunk-ZR5YA6ZF.js → chunk-36XVK5P5.js} +5 -5
  12. package/dist/{chunk-AVSR2HKI.js → chunk-3DZ4LPLS.js} +6 -6
  13. package/dist/{chunk-LYJJ6546.js → chunk-3GSPCWFX.js} +12 -12
  14. package/dist/{chunk-CRHPCPZP.js → chunk-4KC4CHKJ.js} +2 -2
  15. package/dist/{chunk-4VDHLCF5.js → chunk-4WJBWKMI.js} +2 -2
  16. package/dist/{chunk-KBUTSJSR.js → chunk-4XBYHXGK.js} +2 -2
  17. package/dist/{chunk-6W75D37F.js → chunk-53P775GE.js} +6 -3
  18. package/dist/{chunk-XZWSP67B.js → chunk-5APYAXCB.js} +2 -2
  19. package/dist/{chunk-D65E25JG.js → chunk-67HPYNTJ.js} +2 -2
  20. package/dist/{chunk-5JQR5B4D.js → chunk-6KV4KCQZ.js} +4 -4
  21. package/dist/{chunk-V4XJWDHR.js → chunk-6UKFRTXI.js} +2 -1
  22. package/dist/{chunk-NDPF2N2L.js → chunk-7DW7CJW2.js} +2 -2
  23. package/dist/{chunk-5KQEUIWM.js → chunk-7LUEQODV.js} +4 -4
  24. package/dist/{chunk-LNOXCGN2.js → chunk-7UFDIOBT.js} +3 -3
  25. package/dist/{chunk-DXSETN72.js → chunk-7WUGNN43.js} +2 -2
  26. package/dist/{chunk-V35KZDUZ.js → chunk-AA3GRZWS.js} +2 -2
  27. package/dist/{chunk-X4CEFOSG.js → chunk-ADO3OQIC.js} +4 -4
  28. package/dist/{chunk-UX2L5CUD.js → chunk-AI36V3ON.js} +3 -3
  29. package/dist/{chunk-B7GY6QER.js → chunk-B26OUMJW.js} +2 -2
  30. package/dist/{chunk-LAR7DX5E.js → chunk-B5TASTCK.js} +153 -62
  31. package/dist/{chunk-TGWZXJ7L.js → chunk-BEMQK5Q7.js} +92 -84
  32. package/dist/{chunk-RNDCROSG.js → chunk-CNXU7TR2.js} +3 -3
  33. package/dist/{chunk-3JLTRPN7.js → chunk-CVMUXT64.js} +35 -66
  34. package/dist/{chunk-733ZBT5P.js → chunk-E74MJF6G.js} +4 -4
  35. package/dist/{chunk-T2MDZES3.js → chunk-EBMTBE76.js} +3 -3
  36. package/dist/{chunk-OZ76TLGU.js → chunk-EEITU7S6.js} +2 -2
  37. package/dist/{chunk-GRHOXDKB.js → chunk-ELDJWJKM.js} +97 -14
  38. package/dist/{chunk-GCQFN7YI.js → chunk-EMYEQLWO.js} +2 -2
  39. package/dist/{chunk-LTWH2ACR.js → chunk-EQPFEDFV.js} +222 -127
  40. package/dist/{chunk-TDGYTWM6.js → chunk-F4I3H56H.js} +2 -2
  41. package/dist/chunk-F6KCJO3U.js +523 -0
  42. package/dist/{chunk-FGSQHUCK.js → chunk-F6VKWTTY.js} +5 -5
  43. package/dist/{chunk-UJD5MPP6.js → chunk-FLNXQQ5B.js} +2 -2
  44. package/dist/{chunk-EX57VVWW.js → chunk-FOSRJ2VZ.js} +4 -4
  45. package/dist/{chunk-ZARZ4POR.js → chunk-G5ZDQQE3.js} +3 -3
  46. package/dist/{chunk-HQVN7G4F.js → chunk-G62JBPXN.js} +7 -7
  47. package/dist/{chunk-ZJPORZTC.js → chunk-GIAI7A2K.js} +2 -2
  48. package/dist/chunk-GPTR6OTU.js +2551 -0
  49. package/dist/{chunk-EZD2BXGP.js → chunk-GUFQPTQK.js} +2 -2
  50. package/dist/{chunk-OPD7GL6F.js → chunk-H6FQVNZC.js} +8 -7
  51. package/dist/chunk-H7REJ7L5.js +80 -0
  52. package/dist/{chunk-EYTLV3W3.js → chunk-HTWTORF7.js} +2 -2
  53. package/dist/{chunk-DF6PI6GN.js → chunk-I6UKQPGS.js} +3 -3
  54. package/dist/{chunk-ISHUS7HC.js → chunk-JRW236JT.js} +3 -3
  55. package/dist/{chunk-DE2LU267.js → chunk-KKAJGT3B.js} +3 -2
  56. package/dist/{chunk-OV62D6KO.js → chunk-KQMYL5GR.js} +3 -3
  57. package/dist/{chunk-QDUUOZ3S.js → chunk-KWMFC7FN.js} +3 -3
  58. package/dist/{chunk-R7FGRZNF.js → chunk-LXYHCCIZ.js} +9 -9
  59. package/dist/{chunk-NFSK2VNU.js → chunk-LZMTVVN4.js} +2 -2
  60. package/dist/{chunk-62UK7AGW.js → chunk-M5PMRZSR.js} +397 -44
  61. package/dist/chunk-MMZMM6SW.js +131 -0
  62. package/dist/{chunk-FFYTC2KQ.js → chunk-MNABNEBX.js} +2 -2
  63. package/dist/{chunk-XMDBTYCH.js → chunk-N3CWOGVF.js} +3 -3
  64. package/dist/{chunk-VYRQHORQ.js → chunk-NMQSO6Z6.js} +4 -3
  65. package/dist/{chunk-R2UUNSNQ.js → chunk-O3ZAF7UY.js} +18 -5
  66. package/dist/{chunk-4SYHGVDE.js → chunk-OQNCLZI4.js} +4 -4
  67. package/dist/{chunk-EG4ARXPC.js → chunk-OX6QTA4N.js} +3 -3
  68. package/dist/{chunk-P4GNZPXO.js → chunk-OYUS3UZP.js} +2 -2
  69. package/dist/{chunk-OQ2EOAHA.js → chunk-PF36KOGI.js} +291 -112
  70. package/dist/{chunk-55RMDDFM.js → chunk-PGQG7ZMW.js} +2 -2
  71. package/dist/{chunk-CBAQPTDU.js → chunk-PIU6BXXW.js} +2 -2
  72. package/dist/{chunk-EKV4UBCM.js → chunk-PZBQUJ2F.js} +2 -2
  73. package/dist/{chunk-7RET77VB.js → chunk-Q2HKY32Y.js} +2 -2
  74. package/dist/{chunk-U6YTUVOX.js → chunk-Q4RMNWMZ.js} +4 -4
  75. package/dist/chunk-Q6FRR3AQ.js +48 -0
  76. package/dist/{chunk-6RJMYYIE.js → chunk-QJSIAJBY.js} +3 -3
  77. package/dist/{chunk-DOUISWEE.js → chunk-QOJ4ERMU.js} +5 -5
  78. package/dist/{chunk-IFPDAD7R.js → chunk-RWSRKXLT.js} +3 -3
  79. package/dist/{chunk-T33IYTZM.js → chunk-SAASVMIY.js} +3 -3
  80. package/dist/{chunk-2DTIWSAW.js → chunk-SEQDH6JC.js} +3 -3
  81. package/dist/{chunk-BRCOSE7O.js → chunk-SZUO5BSE.js} +2 -2
  82. package/dist/{chunk-HOEDA42N.js → chunk-T7HZ7KJF.js} +2 -2
  83. package/dist/{chunk-OJXOA6YU.js → chunk-TL6LNERH.js} +2 -2
  84. package/dist/{chunk-UCINIRHW.js → chunk-TPCZXWLT.js} +3 -3
  85. package/dist/{chunk-ZUKUCZYZ.js → chunk-TQ2KTH4A.js} +2 -2
  86. package/dist/{chunk-4WOOTKFD.js → chunk-U3FETNQB.js} +341 -20
  87. package/dist/{chunk-5B3RTYAK.js → chunk-UGDSB4AN.js} +2 -2
  88. package/dist/{chunk-VKHLUZNO.js → chunk-UZ7YBL43.js} +3 -3
  89. package/dist/{chunk-QNUQ7K7D.js → chunk-VKMSEO7Y.js} +4 -4
  90. package/dist/{chunk-IN7DGBVS.js → chunk-VLX5VZ35.js} +5 -5
  91. package/dist/{chunk-SJGS3GDI.js → chunk-WAGBMMNX.js} +5 -5
  92. package/dist/{chunk-BFOSV5EZ.js → chunk-WX2YCH7F.js} +2 -2
  93. package/dist/{chunk-3LT34CAM.js → chunk-XBIGUILU.js} +32 -17
  94. package/dist/{chunk-XDHUDE5K.js → chunk-XKYBFRWR.js} +5 -5
  95. package/dist/{chunk-U5QU5ZOD.js → chunk-XYPWFSU5.js} +3 -3
  96. package/dist/{chunk-YBUECLAF.js → chunk-YEJQDODA.js} +2 -2
  97. package/dist/{chunk-YQ6XEFVK.js → chunk-Z74OGONW.js} +39 -7
  98. package/dist/{chunk-I4ELN5BX.js → chunk-ZTNOEJRI.js} +2 -2
  99. package/dist/cli/index.js +26 -26
  100. package/dist/{clio-K2PBVCEM.js → clio-4IKFE25F.js} +2 -2
  101. package/dist/{clio-context-tools-GR4OHFSO.js → clio-context-tools-OHJXYX4R.js} +25 -23
  102. package/dist/{code-nav-4X3OI6DK.js → code-nav-XPM3MY5I.js} +7 -7
  103. package/dist/{config-Q5J7UBAB.js → config-343YS25T.js} +43 -41
  104. package/dist/{config-graph-P3555574.js → config-graph-WI263KDX.js} +43 -41
  105. package/dist/{configure-KIJ32ZO6.js → configure-GZDG4HER.js} +21 -21
  106. package/dist/{context-LFBQOSXT.js → context-4OFO7N7Y.js} +12 -12
  107. package/dist/{context-WBH3KSVR.js → context-JLK2RLOG.js} +42 -40
  108. package/dist/{context-NNLBES2Y.js → context-O6DIWCF6.js} +23 -21
  109. package/dist/{context-clear-YOHMQ6SQ.js → context-clear-MR7KOGQI.js} +42 -40
  110. package/dist/{context-working-set-MRAEVDNV.js → context-working-set-YZAD3KWO.js} +14 -13
  111. package/dist/{data-tool-JJPBGMQJ.js → data-tool-EKD7DFHG.js} +7 -7
  112. package/dist/{detail-RHJOTGN4.js → detail-YZPHFEVJ.js} +43 -41
  113. package/dist/{dispatch-runner-NC7PYNIO.js → dispatch-runner-VKVXVTWJ.js} +44 -42
  114. package/dist/{doctor-S5KZ2GTN.js → doctor-53AVQXAO.js} +17 -16
  115. package/dist/{doctor-deep-2EJQSHIZ.js → doctor-deep-BLRB2NCG.js} +5 -5
  116. package/dist/{eval-3D6M36N7.js → eval-P3BQSLQE.js} +21 -20
  117. package/dist/{evidence-XNVPPLVK.js → evidence-6LLI6SZH.js} +44 -42
  118. package/dist/{evidence-6IYN52ET.js → evidence-HTN3JLUO.js} +42 -40
  119. package/dist/{evidence-JVECPI3F.js → evidence-NJRE3R5H.js} +42 -40
  120. package/dist/{evolve-TLPUDJDM.js → evolve-WWZHJVJP.js} +42 -40
  121. package/dist/{fleet-WKVBF5SZ.js → fleet-GGZ4BVJE.js} +64 -62
  122. package/dist/{fleet-6RJWIOEO.js → fleet-QG3IIWWM.js} +44 -42
  123. package/dist/{fleet-commands-L6WFT7KZ.js → fleet-commands-J2ZIKISQ.js} +7 -7
  124. package/dist/{fleet-decisions-BTQMWU5A.js → fleet-decisions-Y2Q7375Q.js} +8 -8
  125. package/dist/{fleet-graph-553DZ67Q.js → fleet-graph-TCBCCCBP.js} +11 -11
  126. package/dist/{fleet-inspect-236FZPRB.js → fleet-inspect-KOLKBC56.js} +44 -42
  127. package/dist/{fleet-preflight-NZQHABWO.js → fleet-preflight-44UNCC4Y.js} +27 -25
  128. package/dist/{fleet-validate-7NLAE26R.js → fleet-validate-K2FXRZVA.js} +13 -13
  129. package/dist/{fleet-verify-E3RO6A5W.js → fleet-verify-AS444WDW.js} +42 -40
  130. package/dist/{fleet-view-KMZQY7YJ.js → fleet-view-X4JU4J6O.js} +43 -41
  131. package/dist/gui/ops-worker.js +9 -9
  132. package/dist/gui/reads-worker.js +9 -8
  133. package/dist/{init-DV5B6HQG.js → init-VSOWFHVL.js} +54 -52
  134. package/dist/{interactive-OXGYZYAS.js → interactive-JRCBENLZ.js} +1733 -577
  135. package/dist/{interop-J7UOBOSF.js → interop-JR6BCY7R.js} +10 -10
  136. package/dist/{inventory-OEGIL6PY.js → inventory-3JUGLVJI.js} +43 -41
  137. package/dist/{library-ROZAMUIL.js → library-7BOH3Y7N.js} +15 -15
  138. package/dist/{library-B3UPGY4V.js → library-7PFONXUI.js} +9 -9
  139. package/dist/{library-MXQA5DLT.js → library-TUYZMFIA.js} +7 -7
  140. package/dist/{library-import-2LTWOVBD.js → library-import-TJVXKLDK.js} +10 -10
  141. package/dist/{library-inventory-LJ3XHLWO.js → library-inventory-MD3AYTP4.js} +9 -9
  142. package/dist/{library-validation-DARHHUNW.js → library-validation-ZDLITEA3.js} +7 -7
  143. package/dist/{mcp-2GSPYQ54.js → mcp-EFCWUPUR.js} +3 -3
  144. package/dist/{memory-J3STUUIK.js → memory-Q2YVOKK5.js} +42 -40
  145. package/dist/{models-Y3GMFJ2V.js → models-M7BOCW7F.js} +17 -16
  146. package/dist/{monitor-LHNH577J.js → monitor-2HD3MC67.js} +47 -45
  147. package/dist/{orchestrator-DTAPXULA.js → orchestrator-OUW3ZN6Y.js} +1894 -226
  148. package/dist/{panes-A743ONZ5.js → panes-TTPPSYCL.js} +3 -3
  149. package/dist/{preload-OJBMAIXF.js → preload-A47C2NUF.js} +42 -40
  150. package/dist/{providers-CMETPZNS.js → providers-T43W7EL4.js} +4 -4
  151. package/dist/{resources-FY6XYFN2.js → resources-TP6X2V6W.js} +20 -11
  152. package/dist/{run-H64MEVTA.js → run-LDSBPMCS.js} +61 -59
  153. package/dist/{share-CAFMMQLM.js → share-URHKKMHR.js} +9 -9
  154. package/dist/{skills-ERKQUC7L.js → skills-E477MOOO.js} +13 -11
  155. package/dist/{skills-eval-CQ23MYQK.js → skills-eval-AIBR2L7H.js} +583 -93
  156. package/dist/{skills-inventory-TVUYJDVN.js → skills-inventory-HLMKY3R5.js} +13 -11
  157. package/dist/{slash-commands-ROG3KIFJ.js → slash-commands-LIIZKA5Y.js} +28 -26
  158. package/dist/{startup-background-KDWCQMWT.js → startup-background-JR2KDK6R.js} +43 -41
  159. package/dist/{steer-KKYXJSH4.js → steer-D7RTAPCM.js} +3 -3
  160. package/dist/{system-ZDW44ZGX.js → system-X2P5N4IY.js} +14 -13
  161. package/dist/{targets-AJWA6E7Z.js → targets-VFFAKUFM.js} +25 -24
  162. package/dist/{tasks-6L2JJRC5.js → tasks-ERAWZA22.js} +6 -6
  163. package/dist/{terminal-lease-YFUSDPAD.js → terminal-lease-V2N2BIKQ.js} +2 -2
  164. package/dist/{trace-LA5MVR4Y.js → trace-MA5BT7XY.js} +3 -3
  165. package/dist/{usage-XSILDHKF.js → usage-WYFY2L6M.js} +50 -48
  166. package/dist/{verifiers-ECA5GIHL.js → verifiers-TYIW2XKF.js} +7 -7
  167. package/dist/{verify-R6QQCCEB.js → verify-242UFYTP.js} +6 -6
  168. package/dist/{web-fetch-PVZNMBOB.js → web-fetch-LRAGYU6Y.js} +3 -3
  169. package/dist/{wiki-generate-RP22WP5K.js → wiki-generate-OFKOX2T6.js} +53 -51
  170. package/dist/worker/entry.js +31 -29
  171. package/docs/architecture/architecture.md +1 -0
  172. package/docs/architecture/context-engine.md +4 -2
  173. package/docs/architecture/observability.md +6 -4
  174. package/docs/architecture/prompt-envelope-and-tools.md +1 -1
  175. package/docs/architecture/session-lifecycle.md +1 -1
  176. package/docs/architecture/tui-design.md +12 -9
  177. package/docs/gui/parity/02-slash-and-surfaces.md +1 -1
  178. package/docs/guide/commands-and-modes.md +91 -5
  179. package/docs/guide/configuration-and-targets.md +2 -2
  180. package/docs/guide/context-continuity.md +49 -0
  181. package/docs/guide/proactive-memory.md +6 -3
  182. package/library/registry.yaml +292 -32
  183. package/library/skills/README.md +27 -2
  184. package/library/skills/context/context-handoff/SKILL.md +10 -4
  185. package/library/skills/meta/clio-coder-dev/SKILL.md +92 -88
  186. package/library/skills/meta/clio-coder-dev/evals.md +51 -46
  187. package/library/skills/meta/clio-coder-dev/plugin.json +2 -2
  188. package/library/skills/meta/clio-coder-dev/references/change-map.md +49 -0
  189. package/library/skills/meta/clio-coder-test/SKILL.md +89 -142
  190. package/library/skills/meta/clio-coder-test/evals.md +58 -62
  191. package/library/skills/meta/clio-coder-test/plugin.json +2 -2
  192. package/library/skills/meta/clio-coder-test/references/harness.md +3 -3
  193. package/library/skills/meta/clio-coder-test/references/lifecycle-validation.md +30 -0
  194. package/library/skills/meta/clio-coder-test/references/test-map.md +60 -89
  195. package/library/skills/registry.yaml +5 -5
  196. package/library/skills/skill-marketplace.json +12 -14
  197. package/package.json +1 -1
  198. package/src/cli/skills-eval.ts +1064 -54
  199. package/src/cli/usage.ts +2 -2
  200. package/src/core/clio-repo.ts +3 -0
  201. package/src/core/tool-names.ts +1 -0
  202. package/src/domains/context/budget/inspection.ts +9 -0
  203. package/src/domains/context/budget/live-view.ts +418 -0
  204. package/src/domains/context/budget/pressure.ts +393 -0
  205. package/src/domains/context/budget/request-fit.ts +15 -0
  206. package/src/domains/evidence/build.ts +24 -0
  207. package/src/domains/gateway/mcp/client.ts +1 -1
  208. package/src/domains/memory/commit-state.ts +160 -0
  209. package/src/domains/memory/operations.ts +18 -10
  210. package/src/domains/memory/prompt-cache.ts +95 -0
  211. package/src/domains/memory/prompt-section.ts +50 -7
  212. package/src/domains/memory/relevance.ts +93 -0
  213. package/src/domains/memory/restoration.ts +78 -0
  214. package/src/domains/memory/store.ts +39 -1
  215. package/src/domains/middleware/memory-intervention.ts +116 -24
  216. package/src/domains/observability/background-memory-usage.ts +1 -1
  217. package/src/domains/observability/cost.ts +3 -3
  218. package/src/domains/observability/extension.ts +1 -1
  219. package/src/domains/observability/metrics.ts +1 -1
  220. package/src/domains/prompts/compiler.ts +1 -1
  221. package/src/domains/prompts/extension.ts +38 -1
  222. package/src/domains/quota/anthropic-max-provider.ts +134 -0
  223. package/src/domains/quota/anthropic-usage.ts +220 -0
  224. package/src/domains/quota/antigravity-provider.ts +339 -0
  225. package/src/domains/quota/cache.ts +87 -0
  226. package/src/domains/quota/claude-code-provider.ts +169 -0
  227. package/src/domains/quota/codex-provider.ts +237 -0
  228. package/src/domains/quota/presentation.ts +240 -0
  229. package/src/domains/quota/registry.ts +23 -0
  230. package/src/domains/quota/service.ts +93 -0
  231. package/src/domains/quota/summary-feed.ts +86 -0
  232. package/src/domains/quota/types.ts +84 -0
  233. package/src/domains/resources/index.ts +11 -0
  234. package/src/domains/resources/skills/catalog-view.ts +571 -0
  235. package/src/domains/resources/skills/lexical-match.ts +136 -0
  236. package/src/domains/resources/skills/loader.ts +38 -0
  237. package/src/domains/resources/skills/promotion.ts +1 -55
  238. package/src/domains/resources/skills/provenance-pin.ts +50 -20
  239. package/src/domains/safety/action-classifier.ts +1 -0
  240. package/src/domains/session/compaction/branch-summary.ts +4 -1
  241. package/src/domains/session/compaction/compact.ts +18 -2
  242. package/src/domains/session/compaction/cut-point.ts +20 -1
  243. package/src/domains/session/compaction/tokens.ts +48 -3
  244. package/src/domains/session/context-accounting.ts +8 -1
  245. package/src/domains/session/continuity/carry.ts +59 -0
  246. package/src/domains/session/continuity/contract.ts +592 -0
  247. package/src/domains/session/continuity/evidence.ts +290 -0
  248. package/src/domains/session/continuity/fold.ts +1075 -0
  249. package/src/domains/session/continuity/note.ts +79 -0
  250. package/src/domains/session/continuity/operator-request.ts +104 -0
  251. package/src/domains/session/continuity/persistence.ts +408 -0
  252. package/src/domains/session/continuity/ports.ts +231 -0
  253. package/src/domains/session/continuity/projection.ts +538 -0
  254. package/src/domains/session/continuity/validate.ts +352 -0
  255. package/src/domains/session/entries.ts +50 -3
  256. package/src/domains/session/index.ts +48 -0
  257. package/src/domains/session/migrations/index.ts +7 -3
  258. package/src/domains/session/tree/fork.ts +15 -1
  259. package/src/domains/session/usage.ts +2 -2
  260. package/src/engine/acp/commands.ts +1 -1
  261. package/src/engine/agent.ts +133 -9
  262. package/src/engine/session.ts +13 -6
  263. package/src/entry/orchestrator.ts +116 -33
  264. package/src/interactive/chat-loop-messages.ts +2 -2
  265. package/src/interactive/chat-loop.ts +219 -63
  266. package/src/interactive/chat-renderer.ts +99 -8
  267. package/src/interactive/context-overlay.ts +24 -3
  268. package/src/interactive/continuity-controller.ts +526 -0
  269. package/src/interactive/dispatch-board.ts +21 -3
  270. package/src/interactive/footer/dashboard.ts +25 -1
  271. package/src/interactive/footer/key-hints.ts +2 -2
  272. package/src/interactive/footer/pages.ts +70 -27
  273. package/src/interactive/footer/widgets.ts +32 -7
  274. package/src/interactive/footer-panel.ts +1 -1
  275. package/src/interactive/interactive-application.ts +7 -2
  276. package/src/interactive/interactive-input-runtime.ts +2 -2
  277. package/src/interactive/interactive-presentation.ts +15 -0
  278. package/src/interactive/interactive-slash-runtime.ts +45 -8
  279. package/src/interactive/interactive-tickers.ts +7 -1
  280. package/src/interactive/model-session-replay.ts +130 -3
  281. package/src/interactive/output-reserve.ts +35 -0
  282. package/src/interactive/overlay-general-openers.ts +12 -8
  283. package/src/interactive/overlay-key-routing.ts +6 -9
  284. package/src/interactive/overlay-lifecycle.ts +10 -6
  285. package/src/interactive/overlay-session-lifecycle.ts +21 -14
  286. package/src/interactive/quota-view.ts +229 -0
  287. package/src/interactive/session-last-turn.ts +1 -1
  288. package/src/interactive/session-transcript.ts +2 -1
  289. package/src/interactive/session-usage-reseed.ts +2 -2
  290. package/src/interactive/side-question.ts +2 -2
  291. package/src/interactive/slash-commands.ts +28 -9
  292. package/src/interactive/turn-context.ts +686 -63
  293. package/src/interactive/turn-middleware.ts +39 -6
  294. package/src/interactive/turn-persistence.ts +15 -2
  295. package/src/interactive/turn-prewarm.ts +1 -1
  296. package/src/interactive/turn-runtime.ts +48 -5
  297. package/src/interactive/{cost-overlay.ts → usage-overlay.ts} +121 -33
  298. package/src/interactive/welcome-dashboard.ts +26 -3
  299. package/src/tools/agent-tools.ts +3 -1
  300. package/src/tools/bootstrap.ts +6 -0
  301. package/src/tools/builtin-tool-catalog.ts +9 -0
  302. package/src/tools/context/index.ts +148 -113
  303. package/src/tools/context/surface.ts +11 -7
  304. package/src/tools/core-bootstrap.ts +4 -0
  305. package/src/tools/observation.ts +8 -2
  306. package/src/tools/policy.ts +3 -0
  307. package/src/tools/self-compact.ts +31 -0
  308. package/src/tools/surface.ts +1 -0
  309. package/src/tools/tasks.ts +1 -1
  310. package/dist/chunk-CTFPFW3H.js +0 -44
  311. package/dist/chunk-EOJPDNUP.js +0 -1325
  312. package/dist/chunk-I4Y4WKZR.js +0 -386
@@ -1,3 +1,4 @@
1
+ import type { UsageSnapshot } from "../domains/quota/types.js";
1
2
  import { type TaskBoardSnapshot, type TaskBoardStore, taskBoardCounts } from "../domains/session/task-board.js";
2
3
  import { Text, type TUI, visibleWidth, wrapTextWithAnsi } from "../engine/tui.js";
3
4
  import {
@@ -28,6 +29,7 @@ export interface InteractiveTickersDeps {
28
29
  dispatchBoardStore: InteractiveDispatchStore;
29
30
  contextActivityStore: InteractiveContextActivityStore;
30
31
  getOverlayState: () => string;
32
+ getQuotaSnapshots?: () => ReadonlyArray<UsageSnapshot>;
31
33
  isFooterExpanded: () => boolean;
32
34
  /** Bound to TaskBoardStore.cachedSnapshot; repaint must never fold the session ledger. */
33
35
  getTaskBoard?: TaskBoardStore["cachedSnapshot"];
@@ -126,7 +128,11 @@ export function createInteractiveTickers(deps: InteractiveTickersDeps): Interact
126
128
  taskIslandHidden = hidden;
127
129
  if (rows.length > 0)
128
130
  taskIsland.setText(
129
- formatTaskIslandLines(rows, Math.max(1, Math.min(4, Math.floor((taskIslandHeight - 8) / 9)))).join("\n"),
131
+ formatTaskIslandLines(
132
+ rows,
133
+ Math.max(1, Math.min(4, Math.floor((taskIslandHeight - 8) / 10))),
134
+ deps.getQuotaSnapshots?.() ?? [],
135
+ ).join("\n"),
130
136
  );
131
137
  else if (board) taskIsland.setText(formatTaskBoardIslandLines(board).join("\n"));
132
138
  taskIsland.invalidate();
@@ -1,8 +1,123 @@
1
1
  import { foldWorkingSet } from "../domains/context/working-set/fold.js";
2
2
  import { projectWorkingSet } from "../domains/context/working-set/project.js";
3
+ import {
4
+ type ContinuityForkBinding,
5
+ type ContinuityProjection,
6
+ continuityReplayBlocks,
7
+ resolveContinuityProjection,
8
+ } from "../domains/session/continuity/projection.js";
9
+ import type { SessionContract } from "../domains/session/contract.js";
3
10
  import type { SessionEntry } from "../domains/session/entries.js";
4
11
  import type { AgentMessage } from "../engine/types.js";
5
- import { buildReplayAgentMessagesFromTurns, type RehydrateChatPanelOptions } from "./chat-renderer.js";
12
+ import {
13
+ activeEntriesBeforeCompactionCut,
14
+ buildReplayAgentMessagesFromTurns,
15
+ type RehydrateChatPanelOptions,
16
+ } from "./chat-renderer.js";
17
+
18
+ /**
19
+ * The session-ownership facts continuity needs, which a renderer does not have.
20
+ *
21
+ * Supplying this is what separates a fork's own transactions from the ones it
22
+ * inherited. Without it a reader owns nothing: inherited recall still projects,
23
+ * because losing the note is the one outcome that is never safe, but no
24
+ * transaction can reach execution authority.
25
+ */
26
+ export interface ContinuityReplayContext {
27
+ /** The opened session's actual id, from `session.current()`. */
28
+ sessionId?: string;
29
+ /** `meta.parentSessionId` / `meta.parentTurnId`, when this session is a fork. */
30
+ fork?: ContinuityForkBinding;
31
+ /**
32
+ * True only for a genuine historical cut of this session's own transactions.
33
+ * A live `/tree` selection is not one, even though the renderer passes
34
+ * `uptoTurnId` for both.
35
+ */
36
+ historical?: boolean;
37
+ /** Parse failures the reader counted, so a torn record cannot become permission. */
38
+ unreadableRecords?: number;
39
+ nowMs?: number;
40
+ }
41
+
42
+ export interface ModelReplayOptions extends RehydrateChatPanelOptions {
43
+ continuity?: ContinuityReplayContext;
44
+ }
45
+
46
+ /**
47
+ * Derive replay ownership from the open session.
48
+ *
49
+ * `meta.parentSessionId` and `meta.parentTurnId` are what `enrichForkMeta`
50
+ * stamps on a child, and together they are the fork binding. The header's
51
+ * `parentSession` is a path to the parent's ledger, a different fact, and is
52
+ * deliberately not used as a session id. A session with no fork pointers
53
+ * publishes no binding, so a foreign-origin record in a session that never
54
+ * forked stays unprojected instead of being read as inheritance.
55
+ *
56
+ * `historical` is never set here. A replay is historical only when a caller
57
+ * standing at a past turn says so; deriving it from the renderer's `uptoTurnId`
58
+ * would make an ordinary `/tree` selection permanently surrender this session's
59
+ * ownership of its own transactions.
60
+ */
61
+ export function continuityContextFromSession(
62
+ /** Narrowed to the one method this needs, so partial session owners qualify. */
63
+ session: Pick<SessionContract, "current"> | undefined,
64
+ ): ContinuityReplayContext {
65
+ const meta = session?.current();
66
+ if (!meta) return {};
67
+ const parentSessionId = meta.parentSessionId ?? null;
68
+ const parentTurnId = meta.parentTurnId ?? null;
69
+ return {
70
+ sessionId: meta.id,
71
+ ...(parentSessionId !== null && parentTurnId !== null ? { fork: { parentSessionId, parentTurnId } } : {}),
72
+ };
73
+ }
74
+
75
+ /**
76
+ * Resolve the continuity projection for a replay.
77
+ *
78
+ * Folded over the active path **before** the compaction cut and before the
79
+ * working-set projection, because both of those remove records the fold needs:
80
+ * a commit, a pause or an operator control request older than the cut is still
81
+ * the evidence for the state the note describes. `withContinuityReplay` is the
82
+ * exported entry point, so the transcript and the model always render blocks
83
+ * from one resolution rather than two.
84
+ */
85
+ function resolveReplayContinuity(
86
+ entries: ReadonlyArray<SessionEntry>,
87
+ options: ModelReplayOptions = {},
88
+ ): ContinuityProjection {
89
+ const context = options.continuity ?? {};
90
+ return resolveContinuityProjection({
91
+ // The positional cut applies only to a real historical selection. A live
92
+ // /tree switch passes `uptoTurnId` for display and must still see the
93
+ // sidecars anchored after the selected message, because they are part of
94
+ // its own branch's current state.
95
+ entries: activeEntriesBeforeCompactionCut(entries, options, context.historical === true),
96
+ ...(context.sessionId === undefined ? {} : { sessionId: context.sessionId }),
97
+ ...(context.fork === undefined ? {} : { fork: context.fork }),
98
+ ...(context.historical === undefined ? {} : { historical: context.historical }),
99
+ ...(context.unreadableRecords === undefined ? {} : { unreadableRecords: context.unreadableRecords }),
100
+ ...(context.nowMs === undefined ? {} : { nowMs: context.nowMs }),
101
+ });
102
+ }
103
+
104
+ /**
105
+ * Resolve continuity once and hand the same finished blocks to both surfaces.
106
+ *
107
+ * The transcript and the model must show byte-identical note text, so the
108
+ * projection is resolved here and the rendered blocks travel on the options
109
+ * object that `rehydrateChatPanelFromTurns` and
110
+ * `buildModelReplayAgentMessagesFromTurns` both receive. Resolving it twice
111
+ * would be two chances to disagree.
112
+ */
113
+ export function withContinuityReplay(
114
+ turns: ReadonlyArray<SessionEntry>,
115
+ options: RehydrateChatPanelOptions,
116
+ session: Pick<SessionContract, "current"> | undefined,
117
+ ): ModelReplayOptions {
118
+ const merged: ModelReplayOptions = { ...options, continuity: continuityContextFromSession(session) };
119
+ return { ...merged, continuityBlocks: continuityReplayBlocks(resolveReplayContinuity(turns, merged)) };
120
+ }
6
121
 
7
122
  /**
8
123
  * Build provider-facing replay messages from the durable session ledger.
@@ -10,12 +125,24 @@ import { buildReplayAgentMessagesFromTurns, type RehydrateChatPanelOptions } fro
10
125
  * setting gates creation of new evictions, not replay of durable state.
11
126
  * Visible transcript and export callers intentionally keep using the raw
12
127
  * rehydration helpers so eviction remains a model projection, not data loss.
128
+ *
129
+ * Continuity is resolved first, from the complete pre-cut ledger, so the
130
+ * accepted note survives both the working-set projection and the compaction
131
+ * cut. It is carried as labelled data and never becomes a synthetic operator
132
+ * instruction.
13
133
  */
14
134
  export function buildModelReplayAgentMessagesFromTurns(
15
135
  entries: ReadonlyArray<SessionEntry>,
16
- options: RehydrateChatPanelOptions = {},
136
+ options: ModelReplayOptions = {},
17
137
  ): AgentMessage[] {
18
138
  const activeLeafTurnId = options.activeLeafTurnId ?? options.uptoTurnId;
139
+ // A caller that already resolved the projection passes its blocks through,
140
+ // so the transcript beside this replay renders the identical bytes.
141
+ const blocks = options.continuityBlocks ?? continuityReplayBlocks(resolveReplayContinuity(entries, options));
19
142
  const projected = projectWorkingSet(entries, foldWorkingSet(entries, activeLeafTurnId), activeLeafTurnId);
20
- return buildReplayAgentMessagesFromTurns(projected, { ...options, skillContextEntries: entries });
143
+ return buildReplayAgentMessagesFromTurns(projected, {
144
+ ...options,
145
+ skillContextEntries: entries,
146
+ continuityBlocks: blocks,
147
+ });
21
148
  }
@@ -0,0 +1,35 @@
1
+ /**
2
+ * The one preflight output reservation a turn asks for.
3
+ *
4
+ * Extracted from the submit guard in `chat-loop.ts` so the guard and the live
5
+ * budget view quote the same number instead of growing a second formula. It
6
+ * resolves through `resolveReservedOutputTokens`, which applies the configured
7
+ * output budget, the model's advertised cap, and the remaining-context clamp
8
+ * the `openai-completions` and `ollama-native` transports already perform on
9
+ * the wire. The capability-resolved cap is the input, because that is what the
10
+ * runtime resolution decided this target may actually be asked for.
11
+ *
12
+ * This is a preflight reservation, not a guarantee of the final wire ceiling:
13
+ * `remainingContextMaxTokens` re-derives the ceiling at request time against
14
+ * the context the transport is about to send.
15
+ *
16
+ * It is not the compaction-threshold reserve. `ContextSnapshot.categories.reserve`
17
+ * is window headroom held back so auto-compaction fires before a request is
18
+ * refused, and the two figures are unrelated.
19
+ */
20
+
21
+ import { resolveReservedOutputTokens } from "../engine/apis/output-budget.js";
22
+ import type { AgentRuntime } from "./turn-state.js";
23
+
24
+ export function resolveTurnOutputReserve(agentRuntime: AgentRuntime, inputTokens: number): number {
25
+ // A runtime resolution always carries capability decisions in production. The
26
+ // optional read is for a partially built runtime: an absent cap is the
27
+ // resolver's own "no advertised limit" case, which falls back to the
28
+ // configured budget and then the product floor, rather than a crash on a path
29
+ // that now runs during ordinary accounting.
30
+ return resolveReservedOutputTokens(agentRuntime.runtimeResolution.capabilityDecisions?.maxTokens, {
31
+ api: agentRuntime.agent.state.model?.api ?? "",
32
+ contextWindow: agentRuntime.runtimeResolution.contextWindowDetails.effectiveContextWindow,
33
+ inputTokens,
34
+ });
35
+ }
@@ -23,7 +23,6 @@ import { formatUserTaskHandoff } from "../domains/user-tasks/handoff.js";
23
23
  import type { UserTasksStore } from "../domains/user-tasks/store.js";
24
24
  import type { TUI } from "../engine/tui.js";
25
25
  import { type OpenContextOverlayOptions, openContextOverlay } from "./context-overlay.js";
26
- import { openCostOverlay } from "./cost-overlay.js";
27
26
  import {
28
27
  type createDispatchBoardView,
29
28
  isDispatchBoardRowCancellable,
@@ -43,6 +42,7 @@ import { openFleetRunApprovalOverlay } from "./overlays/fleet-run-approval.js";
43
42
  import { openSideQuestionOverlay } from "./overlays/side-question.js";
44
43
  import type { ContextClearCommandOptions } from "./slash-commands.js";
45
44
  import { openTasksOverlay } from "./tasks-overlay.js";
45
+ import { openUsageOverlay } from "./usage-overlay.js";
46
46
  import { type ArtifactProviderDeps, createDefaultArtifactProviders } from "./view/artifacts.js";
47
47
  import { openViewOverlay } from "./view/view-overlay.js";
48
48
 
@@ -51,6 +51,8 @@ export interface OverlayGeneralOpenersDeps {
51
51
  tui: TUI;
52
52
  transitions: OverlayTransitions;
53
53
  observability: ObservabilityContract;
54
+ getQuotaSnapshots?: () => ReadonlyArray<import("../domains/quota/types.js").UsageSnapshot>;
55
+ getDispatchRows?: () => ReadonlyArray<import("./dispatch-board.js").DispatchBoardRow>;
54
56
  getSessionId?: () => string | null;
55
57
  getContextLedger: () => ContextLedger;
56
58
  contextChat: NonNullable<OpenContextOverlayOptions["chat"]>;
@@ -80,7 +82,7 @@ export interface OverlayGeneralOpenersDeps {
80
82
  startDispatchBoardTicker: () => void;
81
83
  closeOverlay: () => void;
82
84
  showOverlayFrame?: typeof showClioOverlayFrame;
83
- openCostOverlay?: typeof openCostOverlay;
85
+ openUsageOverlay?: typeof openUsageOverlay;
84
86
  openContextOverlay?: typeof openContextOverlay;
85
87
  openContextResetOverlay?: typeof openContextResetOverlay;
86
88
  openTasksOverlay?: typeof openTasksOverlay;
@@ -121,7 +123,7 @@ export interface OverlayGeneralOpenersDeps {
121
123
  }
122
124
 
123
125
  export interface OverlayGeneralOpeners {
124
- openCost(): void;
126
+ openUsage(): void;
125
127
  openContextView(): void;
126
128
  openContextReset(): void;
127
129
  toggleFooter(): void;
@@ -136,7 +138,7 @@ export interface OverlayGeneralOpeners {
136
138
  }
137
139
 
138
140
  export function createOverlayGeneralOpeners(deps: OverlayGeneralOpenersDeps): OverlayGeneralOpeners {
139
- const openCostOverlayFactory = deps.openCostOverlay ?? openCostOverlay;
141
+ const openUsageOverlayFactory = deps.openUsageOverlay ?? openUsageOverlay;
140
142
  const openContextOverlayFactory = deps.openContextOverlay ?? openContextOverlay;
141
143
  const openContextResetOverlayFactory = deps.openContextResetOverlay ?? openContextResetOverlay;
142
144
  const openTasksOverlayFactory = deps.openTasksOverlay ?? openTasksOverlay;
@@ -146,11 +148,13 @@ export function createOverlayGeneralOpeners(deps: OverlayGeneralOpenersDeps): Ov
146
148
  const showOverlayFrameFactory = deps.showOverlayFrame ?? showClioOverlayFrame;
147
149
  const openSideQuestionOverlayFactory = deps.openSideQuestionOverlay ?? openSideQuestionOverlay;
148
150
 
149
- const openCost = (): void => {
151
+ const openUsage = (): void => {
150
152
  if (deps.transitions.state !== "closed") return;
151
- deps.transitions.state = "cost";
152
- deps.transitions.handle = openCostOverlayFactory(deps.tui, deps.observability, {
153
+ deps.transitions.state = "usage";
154
+ deps.transitions.handle = openUsageOverlayFactory(deps.tui, deps.observability, {
153
155
  sessionId: deps.getSessionId?.() ?? null,
156
+ ...(deps.getQuotaSnapshots ? { getQuotaSnapshots: deps.getQuotaSnapshots } : {}),
157
+ ...(deps.getDispatchRows ? { getDispatchRows: deps.getDispatchRows } : {}),
154
158
  ...(deps.readSessionEntries
155
159
  ? {
156
160
  getSessionEntries: () => deps.readSessionEntries?.() ?? [],
@@ -525,7 +529,7 @@ export function createOverlayGeneralOpeners(deps: OverlayGeneralOpenersDeps): Ov
525
529
  };
526
530
 
527
531
  return {
528
- openCost,
532
+ openUsage,
529
533
  openContextView,
530
534
  openContextReset,
531
535
  toggleFooter,
@@ -7,7 +7,7 @@ export type OverlayState =
7
7
  | "permission-confirm"
8
8
  | "dispatch-board"
9
9
  | "auth"
10
- | "cost"
10
+ | "usage"
11
11
  | "context-view"
12
12
  | "context-reset"
13
13
  | "tasks"
@@ -213,8 +213,8 @@ function routeAuthOverlayKey(data: string, deps: CloseOverlayKeyDeps): boolean {
213
213
  return false;
214
214
  }
215
215
 
216
- /** Pure overlay key router for the /cost overlay. Esc closes; everything else is swallowed. */
217
- function routeCostOverlayKey(data: string, deps: CloseOverlayKeyDeps): boolean {
216
+ /** Esc closes an inspection overlay; callers decide how to route its remaining keys. */
217
+ function routeReadOnlyOverlayKey(data: string, deps: CloseOverlayKeyDeps): boolean {
218
218
  if (isEscapeKey(data)) {
219
219
  deps.closeOverlay();
220
220
  return true;
@@ -262,19 +262,16 @@ export function routeOverlayKey(
262
262
  return true;
263
263
  }
264
264
  if (overlayState === "auth") return routeAuthOverlayKey(data, deps);
265
- if (overlayState === "cost") {
266
- routeCostOverlayKey(data, deps);
267
- return true;
268
- }
265
+ if (overlayState === "usage") return routeReadOnlyOverlayKey(data, deps);
269
266
  if (overlayState === "context-view") {
270
- routeCostOverlayKey(data, deps);
267
+ routeReadOnlyOverlayKey(data, deps);
271
268
  return true;
272
269
  }
273
270
  // Esc is the only key the side-question overlay answers: it aborts a round
274
271
  // that is still streaming and closes one that has settled. Everything else is
275
272
  // swallowed so a keystroke cannot reach the composer behind it.
276
273
  if (overlayState === "side-question") {
277
- routeCostOverlayKey(data, deps);
274
+ routeReadOnlyOverlayKey(data, deps);
278
275
  return true;
279
276
  }
280
277
  // The handoff review overlay owns Enter, `e`, the arrows, and Esc itself, so
@@ -75,6 +75,8 @@ function interopProposalsFor(
75
75
 
76
76
  export interface OverlayLifecycleRuntimeDeps {
77
77
  app: OverlayLifecycleApplicationDeps;
78
+ getQuotaSnapshots?: () => ReadonlyArray<import("../domains/quota/types.js").UsageSnapshot>;
79
+ getDispatchRows?: () => ReadonlyArray<import("./dispatch-board.js").DispatchBoardRow>;
78
80
  tui: import("../engine/tui.js").TUI;
79
81
  footer: import("./footer/dashboard.js").FooterDashboardPanel;
80
82
  interactiveTickers: import("./interactive-tickers.js").InteractiveTickers;
@@ -117,7 +119,7 @@ export interface OverlayLifecycleRuntimeDeps {
117
119
  openTreeOverlay?: typeof import("./overlays/tree-selector.js").openTreeOverlay;
118
120
  openMessagePickerOverlay?: typeof import("./overlays/message-picker.js").openMessagePickerOverlay;
119
121
  openCwdFallbackOverlay?: typeof import("./overlays/cwd-fallback.js").openCwdFallbackOverlay;
120
- openCostOverlay?: typeof import("./cost-overlay.js").openCostOverlay;
122
+ openUsageOverlay?: typeof import("./usage-overlay.js").openUsageOverlay;
121
123
  openContextOverlay?: typeof import("./context-overlay.js").openContextOverlay;
122
124
  openContextResetOverlay?: typeof import("./overlays/context-reset.js").openContextResetOverlay;
123
125
  openTasksOverlay?: typeof import("./tasks-overlay.js").openTasksOverlay;
@@ -140,7 +142,7 @@ export interface OverlayLifecycleController {
140
142
  isAskUserWaiting(): boolean;
141
143
  resetAskUserCancellation(): void;
142
144
  refreshSettingsOverlay(): void;
143
- openCostOverlayState(): void;
145
+ openUsageOverlayState(): void;
144
146
  openContextViewOverlayState(): void;
145
147
  openContextResetOverlayState(): void;
146
148
  toggleFooterDashboardState(): void;
@@ -207,7 +209,7 @@ export function createOverlayLifecycle(deps: OverlayLifecycleRuntimeDeps): Overl
207
209
  openTreeOverlay: openTreeOverlayFactory,
208
210
  openMessagePickerOverlay: openMessagePickerOverlayFactory,
209
211
  openCwdFallbackOverlay: openCwdFallbackOverlayFactory,
210
- openCostOverlay: openCostOverlayFactory,
212
+ openUsageOverlay: openUsageOverlayFactory,
211
213
  openContextOverlay: openContextOverlayFactory,
212
214
  openContextResetOverlay: openContextResetOverlayFactory,
213
215
  openTasksOverlay: openTasksOverlayFactory,
@@ -417,6 +419,8 @@ export function createOverlayLifecycle(deps: OverlayLifecycleRuntimeDeps): Overl
417
419
  tui,
418
420
  transitions: overlayTransitions,
419
421
  observability: deps.app.observability,
422
+ ...(deps.getQuotaSnapshots ? { getQuotaSnapshots: deps.getQuotaSnapshots } : {}),
423
+ ...(deps.getDispatchRows ? { getDispatchRows: deps.getDispatchRows } : {}),
420
424
  ...(deps.app.getSessionId ? { getSessionId: deps.app.getSessionId } : {}),
421
425
  getContextLedger: () => deps.app.chat.contextLedger(),
422
426
  contextChat: deps.app.chat,
@@ -445,7 +449,7 @@ export function createOverlayLifecycle(deps: OverlayLifecycleRuntimeDeps): Overl
445
449
  startDispatchBoardTicker: () => interactiveTickers.startDispatchBoardTicker(),
446
450
  closeOverlay,
447
451
  showOverlayFrame,
448
- ...(openCostOverlayFactory ? { openCostOverlay: openCostOverlayFactory } : {}),
452
+ ...(openUsageOverlayFactory ? { openUsageOverlay: openUsageOverlayFactory } : {}),
449
453
  ...(openContextOverlayFactory ? { openContextOverlay: openContextOverlayFactory } : {}),
450
454
  ...(openContextResetOverlayFactory ? { openContextResetOverlay: openContextResetOverlayFactory } : {}),
451
455
  ...(openTasksOverlayFactory ? { openTasksOverlay: openTasksOverlayFactory } : {}),
@@ -462,7 +466,7 @@ export function createOverlayLifecycle(deps: OverlayLifecycleRuntimeDeps): Overl
462
466
  const openResumeOverlayState = overlaySessions.openResume;
463
467
  const openTreeOverlayState = overlaySessions.openTree;
464
468
  const openMessagePickerOverlayState = overlaySessions.openMessagePicker;
465
- const openCostOverlayState = overlayGeneralOpeners.openCost;
469
+ const openUsageOverlayState = overlayGeneralOpeners.openUsage;
466
470
  const openContextViewOverlayState = overlayGeneralOpeners.openContextView;
467
471
  const openContextResetOverlayState = overlayGeneralOpeners.openContextReset;
468
472
  const toggleFooterDashboardState = overlayGeneralOpeners.toggleFooter;
@@ -484,7 +488,7 @@ export function createOverlayLifecycle(deps: OverlayLifecycleRuntimeDeps): Overl
484
488
  isAskUserWaiting: overlayAskUser.isWaiting,
485
489
  resetAskUserCancellation: overlayAskUser.resetCancellation,
486
490
  refreshSettingsOverlay: overlayModelSelectors.refreshSettingsOverlay,
487
- openCostOverlayState,
491
+ openUsageOverlayState,
488
492
  openContextViewOverlayState,
489
493
  openContextResetOverlayState,
490
494
  toggleFooterDashboardState,
@@ -20,7 +20,7 @@ import type { ChatPanel } from "./chat-panel.js";
20
20
  import { rehydrateChatPanelFromTurns } from "./chat-renderer.js";
21
21
  import { emitCommandNotice } from "./command-fallbacks.js";
22
22
  import type { InteractiveNoticeLevel } from "./interactive-subscriptions.js";
23
- import { buildModelReplayAgentMessagesFromTurns } from "./model-session-replay.js";
23
+ import { buildModelReplayAgentMessagesFromTurns, withContinuityReplay } from "./model-session-replay.js";
24
24
  import type { OverlayTransitions } from "./overlay-transitions.js";
25
25
  import { openCwdFallbackOverlay } from "./overlays/cwd-fallback.js";
26
26
  import { openHandoffReviewOverlay } from "./overlays/handoff-review.js";
@@ -92,7 +92,7 @@ export interface OverlaySessionLifecycle {
92
92
 
93
93
  /**
94
94
  * The target and model a session started under, so reseeded calls land in the
95
- * same `/cost` bucket the live path writes to. Without it a single target read
95
+ * same `/usage` bucket the live path writes to. Without it a single target read
96
96
  * as two providers, one under the target id and one under the runtime name.
97
97
  */
98
98
  function sessionUsageDefaults(session: SessionContract): { target?: string | null; model?: string | null } {
@@ -120,7 +120,7 @@ function restorePriorSessionOrReopen(
120
120
 
121
121
  export function createOverlaySessionLifecycle(deps: OverlaySessionLifecycleDeps): OverlaySessionLifecycle {
122
122
  /**
123
- * Point every running number the footer and `/cost` show at one branch. The
123
+ * Point every running number the footer and `/usage` show at one branch. The
124
124
  * session total and the last-turn line are read off the same lineage in the
125
125
  * same call, so a switch cannot move one and leave the other behind.
126
126
  */
@@ -188,7 +188,7 @@ export function createOverlaySessionLifecycle(deps: OverlaySessionLifecycleDeps)
188
188
  // after it (a compaction summary covering the leaf, above all)
189
189
  // still belong on screen. uptoTurnId is the historical-truncation
190
190
  // variant `/tree` uses.
191
- const replayOptions = leafTurnId ? { activeLeafTurnId: leafTurnId } : {};
191
+ const replayOptions = withContinuityReplay(turns, leafTurnId ? { activeLeafTurnId: leafTurnId } : {}, session);
192
192
  deps.resetTranscript();
193
193
  rehydrateChatPanelFromTurns(deps.chatPanel, turns, replayOptions);
194
194
  const replayMessages = buildModelReplayAgentMessagesFromTurns(turns, replayOptions);
@@ -240,11 +240,17 @@ export function createOverlaySessionLifecycle(deps: OverlaySessionLifecycleDeps)
240
240
  if (!sessionId) throw new Error("no current session after turn switch");
241
241
  const turns = deps.readStructuredEntries(sessionId);
242
242
  deps.resetTranscript();
243
- rehydrateChatPanelFromTurns(deps.chatPanel, turns, { uptoTurnId: turnId });
244
- const replayMessages = buildModelReplayAgentMessagesFromTurns(turns, { uptoTurnId: turnId });
243
+ // `uptoTurnId` truncates the display at the selected turn. It is
244
+ // deliberately not a continuity `historical` flag: a live /tree
245
+ // selection is still this session's own branch, and treating every
246
+ // display truncation as a historical fork would surrender ownership
247
+ // of its own transactions for good.
248
+ const replayOptions = withContinuityReplay(turns, { uptoTurnId: turnId }, session);
249
+ rehydrateChatPanelFromTurns(deps.chatPanel, turns, replayOptions);
250
+ const replayMessages = buildModelReplayAgentMessagesFromTurns(turns, replayOptions);
245
251
  deps.chat.resetForSession(turnId, replayMessages);
246
252
  // The same branch the transcript above was just scoped to. Without the
247
- // leaf, /cost, the footer Σ, and the last-turn line kept reporting the
253
+ // leaf, /usage, the footer Σ, and the last-turn line kept reporting the
248
254
  // abandoned turns.
249
255
  rescopeToBranch(session, turns, turnId);
250
256
  } catch (error) {
@@ -324,12 +330,12 @@ export function createOverlaySessionLifecycle(deps: OverlaySessionLifecycleDeps)
324
330
  function replayFork(forkedSessionId: string, parentTurnId: string, session: SessionContract): void {
325
331
  try {
326
332
  const turns = deps.readStructuredEntries(forkedSessionId);
327
- rehydrateChatPanelFromTurns(deps.chatPanel, turns);
328
333
  const leafTurnId = session.tree(forkedSessionId).leafId ?? parentTurnId;
329
- const replayMessages = buildModelReplayAgentMessagesFromTurns(
330
- turns,
331
- leafTurnId ? { activeLeafTurnId: leafTurnId } : {},
332
- );
334
+ // The child is already current here, so its own id and fork pointers are
335
+ // what separate the transactions it inherited from any it later mints.
336
+ const replayOptions = withContinuityReplay(turns, leafTurnId ? { activeLeafTurnId: leafTurnId } : {}, session);
337
+ rehydrateChatPanelFromTurns(deps.chatPanel, turns, replayOptions);
338
+ const replayMessages = buildModelReplayAgentMessagesFromTurns(turns, replayOptions);
333
339
  deps.chat.resetForSession(leafTurnId, replayMessages);
334
340
  rescopeToBranch(session, turns, leafTurnId);
335
341
  } catch (error) {
@@ -617,8 +623,9 @@ export function createOverlaySessionLifecycle(deps: OverlaySessionLifecycleDeps)
617
623
  try {
618
624
  const turns = deps.readStructuredEntries(toSessionId);
619
625
  deps.resetTranscript();
620
- rehydrateChatPanelFromTurns(deps.chatPanel, turns);
621
- deps.chat.resetForSession(null, buildModelReplayAgentMessagesFromTurns(turns));
626
+ const replayOptions = withContinuityReplay(turns, {}, session);
627
+ rehydrateChatPanelFromTurns(deps.chatPanel, turns, replayOptions);
628
+ deps.chat.resetForSession(null, buildModelReplayAgentMessagesFromTurns(turns, replayOptions));
622
629
  rescopeToBranch(session, turns, null);
623
630
  } catch (error) {
624
631
  deps.stderr(`[/handoff] seeding replay failed: ${error instanceof Error ? error.message : String(error)}\n`);