@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
@@ -0,0 +1,229 @@
1
+ import { costAggregateForAmount, formatCostAggregate } from "../domains/observability/index.js";
2
+ import {
3
+ foldDuplicateAccounts,
4
+ formatPct,
5
+ primaryWindow,
6
+ type QuotaSeverity,
7
+ severityForPct,
8
+ windowSeverity,
9
+ } from "../domains/quota/presentation.js";
10
+ import type { UsageSnapshot } from "../domains/quota/types.js";
11
+ import { sanitizeCallTargetText } from "../domains/safety/call-target.js";
12
+ import { redactSecretString } from "../domains/safety/redaction.js";
13
+ import { truncateToWidth, visibleWidth, wrapTextWithAnsi } from "../engine/tui.js";
14
+ import type { DispatchBoardRow } from "./dispatch-board.js";
15
+ import { formatFooterTokens } from "./footer-panel.js";
16
+ import { type ClioToken, clioTheme, formatCompactMs } from "./theme/index.js";
17
+
18
+ const clean = (text: string) => sanitizeCallTargetText(redactSecretString(text));
19
+ const tone = (severity: QuotaSeverity): ClioToken =>
20
+ severity === "critical" ? "error" : severity === "normal" ? "accent" : "warning";
21
+
22
+ /** Filled cells always mean consumed usage, on every surface. */
23
+ export function quotaMeter(usedPct: number, cells: number, severity: QuotaSeverity = severityForPct(usedPct)): string {
24
+ const count = Math.max(1, Math.floor(cells));
25
+ const used = Math.max(0, Math.min(100, Number.isFinite(usedPct) ? usedPct : 0));
26
+ const filled = Math.round((used / 100) * count);
27
+ const theme = clioTheme();
28
+ return theme.fg(tone(severity), "━".repeat(filled)) + theme.fg("frame", "─".repeat(count - filled));
29
+ }
30
+
31
+ export function quotaResetLabel(
32
+ reset: string | null,
33
+ now = Date.now(),
34
+ timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone,
35
+ ): string {
36
+ const timestamp = reset === null ? NaN : Date.parse(reset);
37
+ if (!Number.isFinite(timestamp)) return "Reset time not reported";
38
+ const absolute = new Intl.DateTimeFormat("en-US", {
39
+ month: "short",
40
+ day: "numeric",
41
+ hour: "numeric",
42
+ minute: "2-digit",
43
+ timeZone,
44
+ }).format(timestamp);
45
+ const minutes = Math.max(0, Math.ceil((timestamp - now) / 60_000));
46
+ const duration =
47
+ minutes >= 1440
48
+ ? `${Math.floor(minutes / 1440)}d ${Math.floor((minutes % 1440) / 60)}h`
49
+ : minutes >= 60
50
+ ? `${Math.floor(minutes / 60)}h ${minutes % 60}m`
51
+ : `${minutes}m`;
52
+ return minutes === 0
53
+ ? `Reset time passed · awaiting provider update (${absolute} · ${timeZone})`
54
+ : `Resets in ${duration} · ${absolute} (${timeZone})`;
55
+ }
56
+
57
+ /** Account-wide facts only: never infer a worker's share from changing percentages. */
58
+ export function renderQuotaAccounts(
59
+ snapshots: ReadonlyArray<UsageSnapshot>,
60
+ width: number,
61
+ options: { compact?: boolean; now?: number; timeZone?: string } = {},
62
+ ): string[] {
63
+ const theme = clioTheme();
64
+ const now = options.now ?? Date.now();
65
+ const accounts = foldDuplicateAccounts(snapshots).filter((account) => account.status !== "no_credentials");
66
+ if (!accounts.length) return [theme.fg("dim", "Subscriptions · loading")];
67
+ const out: string[] = [];
68
+ for (const account of accounts) {
69
+ const title = clean(`${account.displayName}${account.plan ? ` (${account.plan})` : ""}`);
70
+ const age =
71
+ account.fetchedAt === null ? null : Math.max(0, Math.floor((now - Date.parse(account.fetchedAt)) / 60_000));
72
+ const freshness = account.stale
73
+ ? "STALE · last good reading"
74
+ : age === null || !Number.isFinite(age)
75
+ ? ""
76
+ : age === 0
77
+ ? "updated just now"
78
+ : `updated ${age}m ago`;
79
+ if (options.compact) {
80
+ const window = primaryWindow(account);
81
+ const ordered =
82
+ window && ["warning", "critical"].includes(windowSeverity(window))
83
+ ? [window, ...account.windows.filter((item) => item !== window)]
84
+ : account.windows;
85
+ const windows = ordered
86
+ .map(
87
+ (item) =>
88
+ `${item.scope && item.scope !== item.label ? `${item.scope} ` : ""}${item.label} ${formatPct(item.usedPct)} used`,
89
+ )
90
+ .join(" · ");
91
+ const detail =
92
+ account.status !== "ok"
93
+ ? (account.message ?? account.status)
94
+ : account.providerId === "local"
95
+ ? "$0.00 · no subscription window consumed"
96
+ : windows || account.credits?.display || "no windows reported";
97
+ const meter = window && width >= 65 ? `${quotaMeter(window.usedPct, 8, windowSeverity(window))} ` : "";
98
+ out.push(
99
+ truncateToWidth(
100
+ `${meter}${theme.fg(account.status !== "ok" || account.stale ? "warning" : "muted", `${account.stale ? "STALE · " : ""}${title}`)} ${clean(detail)}`,
101
+ width,
102
+ "…",
103
+ true,
104
+ ),
105
+ );
106
+ continue;
107
+ }
108
+ if (out.length) out.push("");
109
+ out.push(theme.style("accent", title, { bold: true }));
110
+ if (freshness) out.push(theme.fg(account.stale ? "warning" : "dim", freshness));
111
+ if (account.status !== "ok")
112
+ out.push(theme.fg("warning", clean(`${account.status} · ${account.message ?? "usage unavailable"}`)));
113
+ let scope: string | undefined;
114
+ for (const window of account.windows) {
115
+ if (window.scope && scope !== window.scope) {
116
+ scope = window.scope;
117
+ out.push(theme.style("muted", clean(scope), { bold: true }));
118
+ }
119
+ const label = `${window.key.startsWith("weekly_scoped.") ? "Weekly" : window.label} · ${formatPct(window.usedPct)} used · ${formatPct(Math.max(0, 100 - window.usedPct))} remaining${window.active ? " · active limit" : ""}`;
120
+ out.push(clean(label));
121
+ out.push(quotaMeter(window.usedPct, Math.max(1, Math.min(48, width)), windowSeverity(window)));
122
+ out.push(theme.fg("dim", quotaResetLabel(window.resetsAt, now, options.timeZone)));
123
+ }
124
+ if (account.credits) {
125
+ out.push(
126
+ clean(
127
+ `${account.providerId === "local" ? "Local inference" : "Usage credits"} · ${account.credits.display}${account.credits.usedPct === null ? "" : ` · ${formatPct(account.credits.usedPct)} used`}`,
128
+ ),
129
+ );
130
+ if (account.credits.usedPct !== null) out.push(quotaMeter(account.credits.usedPct, Math.min(48, width)));
131
+ }
132
+ if (account.status === "ok" && account.message)
133
+ out.push(theme.fg(account.stale ? "warning" : "dim", clean(account.message)));
134
+ if (account.status === "ok" && !account.windows.length && !account.credits && !account.message)
135
+ out.push(theme.fg("dim", "Connected · no usage windows reported"));
136
+ if (account.retryAfterSeconds != null) out.push(theme.fg("warning", `Retry after ${account.retryAfterSeconds}s`));
137
+ }
138
+ return out.flatMap((line) => (visibleWidth(line) > width ? wrapTextWithAnsi(line, Math.max(1, width)) : [line]));
139
+ }
140
+
141
+ /** The route must share the credential owner read by the quota adapter. */
142
+ function routeAccount(
143
+ route: Pick<DispatchBoardRow, "runtimeId" | "node">,
144
+ snapshots: ReadonlyArray<UsageSnapshot>,
145
+ ): UsageSnapshot | undefined {
146
+ if (route.node && route.node !== "local") return undefined;
147
+ const provider = (
148
+ {
149
+ "claude-code": "claude-code",
150
+ "claude-sdk": "claude-code",
151
+ "anthropic-max": "anthropic-max",
152
+ "antigravity-code": "antigravity",
153
+ } as Record<string, string>
154
+ )[route.runtimeId];
155
+ // Clio's openai-codex OAuth storage is independent of Codex CLI auth.json.
156
+ return snapshots.find((item) => item.providerId === provider);
157
+ }
158
+
159
+ /** A weekly badge only when both the account and model group are known. */
160
+ export function routeWeeklyQuota(
161
+ route: Pick<DispatchBoardRow, "runtimeId" | "wireModelId" | "node">,
162
+ snapshots: ReadonlyArray<UsageSnapshot>,
163
+ ): { label: string; account: string; severity: QuotaSeverity } | null {
164
+ const account = routeAccount(route, snapshots);
165
+ if (account?.status !== "ok") return null;
166
+ const weekly = account.windows.filter((window) => window.key === "weekly" || window.key.endsWith(".weekly"));
167
+ const model = route.wireModelId.toLowerCase();
168
+ const matches =
169
+ account.providerId === "antigravity"
170
+ ? weekly.filter((window) => {
171
+ const scope = window.scope?.toLowerCase() ?? "";
172
+ if (model.includes("gemini")) return scope.includes("gemini");
173
+ if (/claude|opus|sonnet|haiku/.test(model)) return scope.includes("claude");
174
+ if (model.includes("gpt")) return scope.includes("gpt");
175
+ return false;
176
+ })
177
+ : weekly.filter((window) => !window.scope);
178
+ if (matches.length !== 1) return null;
179
+ const window = matches[0];
180
+ if (!window) return null;
181
+ return {
182
+ label: `${account.stale ? "STALE · " : ""}weekly ${formatPct(Math.max(0, Math.min(100, 100 - window.usedPct)))} left`,
183
+ account: account.displayName,
184
+ severity: windowSeverity(window),
185
+ };
186
+ }
187
+
188
+ export function workerQuotaLabel(
189
+ row: Pick<DispatchBoardRow, "runtimeId" | "node">,
190
+ snapshots: ReadonlyArray<UsageSnapshot>,
191
+ ): string {
192
+ // Remote workers and generic transports may use different credentials. Only
193
+ // known local credential owners can be associated with this process's reads.
194
+ if (row.node && row.node !== "local") return "Account quota unavailable for remote credentials";
195
+ const account = routeAccount(row, snapshots);
196
+ if (!account) return "Account quota not linked to this runtime";
197
+ if (account.status !== "ok") return `${account.displayName} · ${account.message ?? account.status}`;
198
+ return `Shared ${account.displayName}${account.stale ? " · STALE" : ""} · ${account.windows.map((window) => `${window.scope && window.scope !== window.label ? `${window.scope} ` : ""}${window.label} ${formatPct(Math.max(0, 100 - window.usedPct))} left`).join(" · ") || "no windows reported"}`;
199
+ }
200
+
201
+ export function renderWorkerUsage(
202
+ rows: ReadonlyArray<DispatchBoardRow>,
203
+ snapshots: ReadonlyArray<UsageSnapshot>,
204
+ width: number,
205
+ ): string[] {
206
+ const theme = clioTheme();
207
+ const out = [theme.fg("dim", "Active and recent workers · recorded tokens and cost · account limits are shared.")];
208
+ if (!rows.length) out.push("", "No worker invocations recorded.");
209
+ for (const row of rows) {
210
+ const cost = formatCostAggregate(costAggregateForAmount(row.costUsd, row.costProvenance)) ?? "cost not reported";
211
+ out.push(
212
+ "",
213
+ theme.style("agent", clean(`${row.agentId} · ${row.status} · ${formatCompactMs(row.elapsedMs)}`), { bold: true }),
214
+ );
215
+ out.push(clean(`${row.targetId} / ${row.wireModelId}${row.node ? ` · ${row.node}` : ""}`));
216
+ out.push(
217
+ row.tokenCount > 0 || row.inputTokens > 0 || row.outputTokens > 0 || row.progress?.inputTokens !== undefined
218
+ ? `${formatFooterTokens(row.tokenCount)} recorded tokens · input ${formatFooterTokens(row.inputTokens)} · output ${formatFooterTokens(row.outputTokens)} · ${cost}`
219
+ : `Token usage not reported · ${cost}`,
220
+ );
221
+ if (row.lastContextTokens !== undefined)
222
+ out.push(
223
+ `Context ${formatFooterTokens(row.lastContextTokens)}${row.contextWindow ? ` / ${formatFooterTokens(row.contextWindow)}` : ""}`,
224
+ );
225
+ out.push(theme.fg("muted", clean(workerQuotaLabel(row, snapshots))));
226
+ out.push(theme.fg("dim", clean(`/view dispatch:${row.runId}`)));
227
+ }
228
+ return out.flatMap((line) => wrapTextWithAnsi(line, Math.max(1, width)));
229
+ }
@@ -4,7 +4,7 @@
4
4
  * The line is a live accumulator: it describes whatever turn this process last
5
5
  * ran. current.jsonl is append-only, so after a `/tree` switch that turn can sit
6
6
  * on a branch the reader just left, and the line kept describing it while the Σ
7
- * total and `/cost` beside it had already been rescoped by the usage reseed. One
7
+ * total and `/usage` beside it had already been rescoped by the usage reseed. One
8
8
  * footer, two branches, no way to tell which line belonged to which.
9
9
  *
10
10
  * The fold reads the same lineage the reseed does, through
@@ -3,7 +3,7 @@ import { collectSessionEntries } from "../domains/session/compaction/session-ent
3
3
  import type { SessionContract, SessionEntry } from "../domains/session/index.js";
4
4
  import { openSession, sessionPaths } from "../engine/session.js";
5
5
  import type { ChatLoop } from "./chat-loop.js";
6
- import { buildModelReplayAgentMessagesFromTurns } from "./model-session-replay.js";
6
+ import { buildModelReplayAgentMessagesFromTurns, continuityContextFromSession } from "./model-session-replay.js";
7
7
 
8
8
  type SessionOwner = Pick<SessionContract, "create" | "current">;
9
9
  type SessionChat = Pick<ChatLoop, "resetForSession">;
@@ -89,6 +89,7 @@ export function createSessionTranscript(deps: SessionTranscriptDeps): SessionTra
89
89
  leafTurnId,
90
90
  buildModelReplayAgentMessagesFromTurns(turns, {
91
91
  ...(leafTurnId ? { activeLeafTurnId: leafTurnId } : {}),
92
+ continuity: continuityContextFromSession(deps.session),
92
93
  }),
93
94
  );
94
95
  deps.refreshStatus();
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Rebuild the running usage totals from a session's own ledger.
3
3
  *
4
- * The `/cost` overlay and the footer both render one process-lifetime
4
+ * The `/usage` overlay and the footer both render one process-lifetime
5
5
  * accumulator, and only `startNewSession` ever reset it. Resuming did not, so a
6
6
  * resumed session showed the *previous* session's numbers under the resumed
7
7
  * session's id: one process, two sessions, byte-identical totals relabelled.
@@ -56,7 +56,7 @@ export interface SessionUsageSink {
56
56
  * `activeLeafTurnId` scopes the fold to one branch, through the same
57
57
  * `filterEntriesToActivePath` the transcript replays through. current.jsonl is
58
58
  * append-only, so after a `/tree` switch the abandoned sibling turns are still
59
- * in the file: the transcript stopped showing them and `/cost` and the footer Σ
59
+ * in the file: the transcript stopped showing them and `/usage` and the footer Σ
60
60
  * kept counting them, which put a session total on screen for turns the reader
61
61
  * had just been told were not on this branch. Omitted, the fold follows the
62
62
  * newest message's ancestry, the same fallback an offline read of the transcript
@@ -100,7 +100,7 @@ function positive(value: unknown): number {
100
100
  }
101
101
 
102
102
  /**
103
- * Normalize one provider usage object into the shape `/cost` and the
103
+ * Normalize one provider usage object into the shape `/usage` and the
104
104
  * out-of-turn usage store take. Shared with the session pre-warm, which is
105
105
  * another call billed beside the session rather than inside it.
106
106
  */
@@ -144,7 +144,7 @@ function textFromMessage(message: unknown): string {
144
144
 
145
145
  /**
146
146
  * Run the side-question round. Resolves with the answer, the provider usage
147
- * (which is still real money and is reported to `/cost`), and whether the
147
+ * (which is still real money and is reported to `/usage`), and whether the
148
148
  * operator aborted it. Provider failures reject; the caller renders the reason
149
149
  * in the overlay.
150
150
  */
@@ -144,6 +144,7 @@ type SlashCommandVariant =
144
144
  | { kind: "context-refresh" }
145
145
  /** `ref` is the turnId an `[evicted ...]` marker names. */
146
146
  | { kind: "context-recall"; ref: string }
147
+ | { kind: "context-recover"; handoffId: string; action: "reduce" | "deliver" }
147
148
  | {
148
149
  kind: "resources";
149
150
  family?: "extensions" | "plugins";
@@ -183,7 +184,7 @@ type SlashCommandVariant =
183
184
  | { kind: "fleet-run-usage"; reason?: string }
184
185
  | { kind: "fleet" }
185
186
  | { kind: "agents"; connect?: boolean }
186
- | { kind: "cost" }
187
+ | { kind: "usage" }
187
188
  | { kind: "context-view" }
188
189
  | { kind: "tasks" }
189
190
  | { kind: "decisions" }
@@ -706,7 +707,7 @@ export interface SlashCommandContext {
706
707
  }>;
707
708
  exportShareArchive?: (outPath: string) => { fileCount: number; path: string };
708
709
  importShareArchive?: (path: string, options: { dryRun?: boolean; force?: boolean }) => ShareImportPlan;
709
- openCost: () => void;
710
+ openUsage: () => void;
710
711
  /**
711
712
  * `/doctor [deep]`: the CLI doctor's findings, rendered as one notice.
712
713
  * `deep` adds the live tool probe on the session's targets and the
@@ -823,6 +824,7 @@ export interface SlashCommandContext {
823
824
  * appends a compactionSummary entry. No-op when no session is open, so the
824
825
  * handler prints an actionable stderr line instead.
825
826
  */
827
+ runHandoffRecovery?: (handoffId: string, action: "reduce" | "deliver") => void;
826
828
  runCompact: (instructions: string | undefined) => void;
827
829
  /**
828
830
  * Escape hatch for the `view verify` entry: verify a receipt file on disk
@@ -1686,23 +1688,24 @@ export const BUILTIN_SLASH_COMMANDS: ReadonlyArray<BuiltinSlashCommand> = [
1686
1688
  },
1687
1689
  },
1688
1690
  {
1689
- name: "cost",
1690
- description: "Show session token and cost totals",
1691
+ name: "usage",
1692
+ description: "Show subscription quota, credits, and session token and cost totals",
1691
1693
  group: "Inspect",
1692
- kinds: ["cost"],
1694
+ kinds: ["usage"],
1693
1695
  args: {},
1694
- fromArgs: fromArgsOrUsage("cost", { kind: "cost" }),
1696
+ fromArgs: fromArgsOrUsage("usage", { kind: "usage" }),
1695
1697
  handle(_command, ctx) {
1696
- ctx.openCost();
1698
+ ctx.openUsage();
1697
1699
  },
1698
1700
  },
1699
1701
  {
1700
1702
  name: "context",
1701
1703
  description: "Context hub: window overlay plus compact, recall, init, refresh, and reset",
1702
1704
  group: "Inspect",
1703
- kinds: ["context-view", "compact", "context-recall", "init", "context-clear", "context-refresh"],
1705
+ kinds: ["context-view", "compact", "context-recover", "context-recall", "init", "context-clear", "context-refresh"],
1704
1706
  subcommandDescriptions: {
1705
1707
  compact: "Compact session context",
1708
+ recover: "Recover a paused handoff: ID reduce|deliver",
1706
1709
  recall: "Recall an evicted result",
1707
1710
  init: "Initialize project context",
1708
1711
  refresh: "Refresh project context",
@@ -1711,6 +1714,12 @@ export const BUILTIN_SLASH_COMMANDS: ReadonlyArray<BuiltinSlashCommand> = [
1711
1714
  args: {
1712
1715
  subcommands: {
1713
1716
  compact: { positionals: [...COMPACT_POSITIONALS] },
1717
+ recover: {
1718
+ positionals: [
1719
+ { name: "handoffId", required: true },
1720
+ { name: "action", required: true },
1721
+ ],
1722
+ },
1714
1723
  recall: { positionals: [...RECALL_POSITIONALS] },
1715
1724
  init: {
1716
1725
  flags: CONTEXT_INIT_FLAG_TABLE.flatMap(({ flag, aliases = [] }) => [flag, ...aliases].map((name) => ({ name }))),
@@ -1724,6 +1733,12 @@ export const BUILTIN_SLASH_COMMANDS: ReadonlyArray<BuiltinSlashCommand> = [
1724
1733
  switch (parsed.subcommand) {
1725
1734
  case "compact":
1726
1735
  return { kind: "compact", instructions: parsed.rest };
1736
+ case "recover": {
1737
+ const [handoffId, action] = parsed.positionals;
1738
+ return handoffId && (action === "reduce" || action === "deliver")
1739
+ ? { kind: "context-recover", handoffId, action }
1740
+ : { kind: "usage-error", command: "context", reason: "Use /context recover <handoffId> <reduce|deliver>" };
1741
+ }
1727
1742
  case "recall":
1728
1743
  return { kind: "context-recall", ref: parsed.positionals[0] ?? "" };
1729
1744
  case "init": {
@@ -1752,6 +1767,10 @@ export const BUILTIN_SLASH_COMMANDS: ReadonlyArray<BuiltinSlashCommand> = [
1752
1767
  case "compact":
1753
1768
  ctx.runCompact(command.instructions);
1754
1769
  return;
1770
+ case "context-recover":
1771
+ if (ctx.runHandoffRecovery) ctx.runHandoffRecovery(command.handoffId, command.action);
1772
+ else ctx.notice("error", "native handoff recovery is unavailable");
1773
+ return;
1755
1774
  case "context-recall":
1756
1775
  if (ctx.runContextRecall) {
1757
1776
  ctx.runContextRecall(command.ref);
@@ -2648,7 +2667,7 @@ const COMMAND_ORDER = [
2648
2667
  "memory",
2649
2668
  "view",
2650
2669
  "panes",
2651
- "cost",
2670
+ "usage",
2652
2671
  "doctor",
2653
2672
  "decisions",
2654
2673
  "library",