@iowarp/clio-coder 0.3.3 → 0.3.6

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 (370) hide show
  1. package/CHANGELOG.md +74 -0
  2. package/CONTRIBUTING.md +7 -7
  3. package/README.md +3 -3
  4. package/dist/{acp-P2AQILE2.js → acp-2BEHC4DL.js} +9 -8
  5. package/dist/{agents-72W3BI7I.js → agents-LNNFTM53.js} +29 -24
  6. package/dist/assets/codewiki.json +1 -1
  7. package/dist/{auth-5TWEIYDN.js → auth-KXXFI2VS.js} +14 -10
  8. package/dist/{chunk-GGXXDWE4.js → chunk-22NAGB7X.js} +2 -2
  9. package/dist/{chunk-YCWGATWI.js → chunk-24I7BN55.js} +2 -2
  10. package/dist/{chunk-EKMEHE4H.js → chunk-33YXPOE3.js} +2 -3
  11. package/dist/chunk-3BPUFZDL.js +37 -0
  12. package/dist/chunk-43AOLP7E.js +375 -0
  13. package/dist/{chunk-ZDOOVTXZ.js → chunk-4OC57DA6.js} +27 -4
  14. package/dist/{chunk-6SGHMWE3.js → chunk-5JGRAMKL.js} +5 -5
  15. package/dist/{chunk-V6RTAOC2.js → chunk-6US73PDB.js} +572 -51
  16. package/dist/{chunk-5UFT4SUX.js → chunk-6XXKFVSN.js} +3 -3
  17. package/dist/{chunk-A3CYT5EX.js → chunk-AD2SYQYC.js} +55 -2
  18. package/dist/chunk-AOCYTWAV.js +449 -0
  19. package/dist/chunk-CFGTUFWB.js +67 -0
  20. package/dist/chunk-CJUB2JJ2.js +1478 -0
  21. package/dist/{chunk-FNTMWMX5.js → chunk-CKXWIANG.js} +14 -12
  22. package/dist/{chunk-PIWWS5BL.js → chunk-CYQKWTG3.js} +63 -78
  23. package/dist/{chunk-LZSJBIVT.js → chunk-DJVECN66.js} +271 -762
  24. package/dist/{chunk-CBCAPZAA.js → chunk-E25LMLRW.js} +2 -2
  25. package/dist/{chunk-ZWMF7253.js → chunk-E2ER4LJF.js} +304 -9
  26. package/dist/{chunk-STBPMHSX.js → chunk-EKY57CSP.js} +51 -84
  27. package/dist/{chunk-DUYJ5IO6.js → chunk-EYPA3EGJ.js} +12 -4
  28. package/dist/{chunk-M6SHUN7Q.js → chunk-FO5ZOVUY.js} +2 -2
  29. package/dist/chunk-FYYLNIL5.js +313 -0
  30. package/dist/{chunk-OQ33BKR3.js → chunk-G7MUEIGA.js} +3 -60
  31. package/dist/chunk-GEYXPTRF.js +613 -0
  32. package/dist/chunk-GOXNB3AO.js +261 -0
  33. package/dist/{chunk-G4BMMOKF.js → chunk-HVDIIIQW.js} +2 -2
  34. package/dist/chunk-HWUFFB6L.js +83 -0
  35. package/dist/{chunk-4XUGQOHA.js → chunk-K7T3E2SR.js} +15 -8
  36. package/dist/chunk-K7VKOLQQ.js +15 -0
  37. package/dist/{chunk-UFIIWP2H.js → chunk-KHSFENX2.js} +8 -8
  38. package/dist/{chunk-BMEMKKIT.js → chunk-KOHPCX4K.js} +2 -2
  39. package/dist/chunk-LCGCVYZ4.js +57 -0
  40. package/dist/chunk-LL4KHSZI.js +22 -0
  41. package/dist/{chunk-PAJK6MAQ.js → chunk-LYF7OHWH.js} +42 -15
  42. package/dist/{chunk-POHLU5DW.js → chunk-M6L6IDJG.js} +3 -3
  43. package/dist/{chunk-5UUP6MWO.js → chunk-MV3K5QF2.js} +5 -436
  44. package/dist/{chunk-X4RCMKVQ.js → chunk-NDINPTJ4.js} +2 -2
  45. package/dist/{chunk-TZK7PACC.js → chunk-NILBFAPG.js} +14 -8
  46. package/dist/chunk-ODFEOB4F.js +1082 -0
  47. package/dist/{chunk-AGYYIBLL.js → chunk-OH3TOQTB.js} +6 -2
  48. package/dist/chunk-OZNBF4L3.js +23 -0
  49. package/dist/{chunk-DSELYM6W.js → chunk-PBTHKCPN.js} +30 -10
  50. package/dist/{verify-375KUB3Y.js → chunk-PCZJO5TI.js} +127 -42
  51. package/dist/{chunk-ED4KHGC3.js → chunk-PPAMZ32Z.js} +9 -2
  52. package/dist/{chunk-SRDMMSEP.js → chunk-QM3F2GKX.js} +1063 -1645
  53. package/dist/{chunk-X6IAEBZR.js → chunk-QNQHSOLF.js} +7 -7
  54. package/dist/{chunk-OC7FIQPC.js → chunk-R46L2BIR.js} +10 -7
  55. package/dist/{chunk-2TLUCQVG.js → chunk-RD5U66HV.js} +3 -3
  56. package/dist/{chunk-6N5PTWMY.js → chunk-RY3LY4J5.js} +50 -13
  57. package/dist/{chunk-OKGUZO2U.js → chunk-SPULKLCF.js} +4 -3
  58. package/dist/{chunk-OOJYHWRB.js → chunk-TSHXZTOQ.js} +6 -5
  59. package/dist/chunk-TZSKNMZG.js +434 -0
  60. package/dist/{chunk-7MNJORFF.js → chunk-UL3WSD3F.js} +6 -1
  61. package/dist/{chunk-VJWL6YS5.js → chunk-UUVG37B4.js} +2 -2
  62. package/dist/{chunk-COU2UHX6.js → chunk-VEZEGCGW.js} +170 -2
  63. package/dist/chunk-W6GROXXM.js +69 -0
  64. package/dist/{chunk-OAO4GE4M.js → chunk-WHGPSPT5.js} +2 -2
  65. package/dist/chunk-WHJYKASB.js +677 -0
  66. package/dist/{chunk-ORBHGJC5.js → chunk-WR67VIZY.js} +3 -3
  67. package/dist/{chunk-YHZX5GEU.js → chunk-XAKHZX5N.js} +2 -2
  68. package/dist/{chunk-TZTZS7QK.js → chunk-XE2VEJHX.js} +5 -3
  69. package/dist/{chunk-LM5TQCJZ.js → chunk-XF5N4U5A.js} +8 -7
  70. package/dist/{chunk-LWLEKMDQ.js → chunk-XXQNGV4M.js} +1073 -552
  71. package/dist/{chunk-KZWTDYJF.js → chunk-XYDYPRZI.js} +7 -7
  72. package/dist/chunk-ZGVHUX3M.js +66 -0
  73. package/dist/{chunk-LW6DSM3M.js → chunk-ZRGEBJ4T.js} +1192 -1119
  74. package/dist/{chunk-2DJ2KNFG.js → chunk-ZXF4XRKW.js} +202 -40
  75. package/dist/chunk-ZZMN5OM4.js +122 -0
  76. package/dist/cli/index.js +34 -30
  77. package/dist/{clio-JOU4FXVA.js → clio-M2KGYUFZ.js} +7 -6
  78. package/dist/{code-nav-7AX6FYE6.js → code-nav-GQNL7XA6.js} +8 -6
  79. package/dist/codewiki/build-worker.js +4 -4
  80. package/dist/{components-KELWS457.js → components-5TTYYX6G.js} +3 -3
  81. package/dist/{config-XCDVKR23.js → config-XUUYQIWO.js} +47 -35
  82. package/dist/{configure-4GAP54ZW.js → configure-IHJ7YOMV.js} +18 -15
  83. package/dist/{context-77FM5DV5.js → context-74JLXAWD.js} +18 -10
  84. package/dist/{context-4UOGGLQ5.js → context-75MIWW3U.js} +41 -29
  85. package/dist/{context-5VKGUVJJ.js → context-ZQ7SIFJV.js} +85 -9
  86. package/dist/{context-clear-XXJRLCJJ.js → context-clear-GYKWNUML.js} +41 -29
  87. package/dist/{context-index-BZ4UYMTC.js → context-index-SSR5ECNE.js} +3 -3
  88. package/dist/context-working-set-UX5KEP4J.js +1553 -0
  89. package/dist/{dispatch-runner-QPRDDBDX.js → dispatch-runner-GIJBHNFL.js} +47 -32
  90. package/dist/{docs-2C2LTVT2.js → docs-6FZSCG5B.js} +3 -3
  91. package/dist/{doctor-HR46URBJ.js → doctor-SVJ5BZCW.js} +12 -12
  92. package/dist/{eval-XSSNATB4.js → eval-CG6LLBLD.js} +54 -238
  93. package/dist/{evidence-6HG2PY2B.js → evidence-ZYFIEN42.js} +57 -28
  94. package/dist/{evolve-K7YU3NCY.js → evolve-QGEXEMDW.js} +36 -25
  95. package/dist/{extensions-QVDOHDGJ.js → extensions-ADGNCJJD.js} +3 -3
  96. package/dist/{fleet-VY3HHKN6.js → fleet-S5R4ZOQY.js} +73 -44
  97. package/dist/{fleet-preflight-DDN536IT.js → fleet-preflight-BHSNPBMH.js} +3 -3
  98. package/dist/{init-JYGXI3FK.js → init-5DRU55YR.js} +49 -37
  99. package/dist/memory-7YKKR6UC.js +467 -0
  100. package/dist/{models-I5QWSEOM.js → models-ZPOLRU2C.js} +24 -21
  101. package/dist/{monitor-GE4ID3IA.js → monitor-US5F5YGZ.js} +73 -46
  102. package/dist/{orchestrator-EM5MC3HM.js → orchestrator-E2AL4T5N.js} +1624 -1007
  103. package/dist/{paths-UXLN5YYZ.js → paths-E7KYAQWE.js} +3 -3
  104. package/dist/{reset-L2FQEE3E.js → reset-KZ652EK6.js} +6 -5
  105. package/dist/{run-ZU3QMZPZ.js → run-SRNBKDWD.js} +76 -54
  106. package/dist/{share-S5BZQC5I.js → share-CGZE33UP.js} +7 -6
  107. package/dist/{skills-X5VXCRNQ.js → skills-S2X4DLY5.js} +4 -4
  108. package/dist/{skills-eval-WKIHWTHR.js → skills-eval-W2GGIC4R.js} +40 -29
  109. package/dist/{targets-SNCPI2NR.js → targets-54SWINWB.js} +28 -23
  110. package/dist/{terminal-lease-BNAHVHBS.js → terminal-lease-SAIF2OGY.js} +6 -4
  111. package/dist/{uninstall-FZCQCDKC.js → uninstall-BVLWXKBT.js} +3 -3
  112. package/dist/{upgrade-JQHHPQ4K.js → upgrade-JKAR27XC.js} +20 -19
  113. package/dist/{usage-OR4O5SMZ.js → usage-MSAWCLX4.js} +79 -36
  114. package/dist/verifiers-NCBTHHN2.js +1220 -0
  115. package/dist/verify-X5HDROLA.js +25 -0
  116. package/dist/{wiki-generate-UEXP2ARI.js → wiki-generate-GUSOQ6ZP.js} +50 -37
  117. package/dist/worker/entry.js +90 -70
  118. package/dist/{workspace-G4ZWUIPR.js → workspace-ZJ6BFM3Q.js} +4 -4
  119. package/docs/README.md +8 -7
  120. package/docs/acp.md +1 -1
  121. package/docs/alcf-provider.md +1 -1
  122. package/docs/architecture.md +2 -2
  123. package/docs/artifact-placement.md +1 -2
  124. package/docs/artifact-versions.md +1 -1
  125. package/docs/built-in-agents.md +1 -1
  126. package/docs/capacity-and-scheduling.md +1 -1
  127. package/docs/commands-and-modes.md +60 -26
  128. package/docs/config-knobs-audit.md +1 -2
  129. package/docs/configuration-and-targets.md +26 -1
  130. package/docs/context-engine.md +67 -13
  131. package/docs/context-working-set.md +194 -0
  132. package/docs/development-pipeline.md +1 -1
  133. package/docs/documentation-coverage.md +6 -6
  134. package/docs/documentation-guide.md +7 -6
  135. package/docs/environment-variables.md +2 -1
  136. package/docs/eval-runner.md +1 -1
  137. package/docs/evals-internal.md +4 -32
  138. package/docs/evidence-and-memory.md +139 -7
  139. package/docs/evolution.md +1 -1
  140. package/docs/exit-codes-and-output.md +1 -1
  141. package/docs/extensions-and-sharing.md +2 -2
  142. package/docs/fleet-dispatch.md +49 -8
  143. package/docs/glossary.md +21 -1
  144. package/docs/installation-and-lifecycle.md +2 -2
  145. package/docs/middleware-and-components.md +19 -2
  146. package/docs/model-catalog.md +7 -9
  147. package/docs/observability.md +4 -4
  148. package/docs/proactive-memory.md +26 -16
  149. package/docs/prompt-envelope-and-tools.md +7 -5
  150. package/docs/provider-adapter-cookbook.md +1 -1
  151. package/docs/release-cut-checklist.md +43 -40
  152. package/docs/safety-model.md +49 -8
  153. package/docs/scientific-validation.md +21 -3
  154. package/docs/session-lifecycle.md +3 -3
  155. package/docs/skills-marketplace.md +1 -1
  156. package/docs/tool-usage.md +79 -12
  157. package/docs/trace-store.md +1 -1
  158. package/docs/troubleshooting.md +1 -1
  159. package/docs/tui-design.md +38 -4
  160. package/docs/worker-dispatch-mechanics.md +11 -1
  161. package/package.json +13 -13
  162. package/skills/meta/clio-test/SKILL.md +20 -17
  163. package/skills/meta/clio-test/evals.md +3 -3
  164. package/skills/meta/clio-test/references/harness.md +35 -6
  165. package/skills/meta/clio-test/references/test-map.md +20 -10
  166. package/skills/registry.yaml +2 -2
  167. package/skills/skill-marketplace.json +1 -1
  168. package/src/cli/agents.ts +2 -3
  169. package/src/cli/argv.ts +14 -1
  170. package/src/cli/context-working-set.ts +513 -0
  171. package/src/cli/context.ts +8 -0
  172. package/src/cli/evidence.ts +20 -2
  173. package/src/cli/fleet.ts +15 -0
  174. package/src/cli/index.ts +5 -1
  175. package/src/cli/memory.ts +272 -10
  176. package/src/cli/modes/json-stream.ts +2 -2
  177. package/src/cli/modes/print.ts +12 -1
  178. package/src/cli/run.ts +22 -2
  179. package/src/cli/targets.ts +12 -3
  180. package/src/cli/usage.ts +55 -7
  181. package/src/cli/verifiers.ts +325 -0
  182. package/src/core/bash-exec.ts +39 -14
  183. package/src/core/bus-events.ts +22 -4
  184. package/src/core/config.ts +54 -0
  185. package/src/core/defaults.ts +50 -3
  186. package/src/core/response-model-id.ts +134 -0
  187. package/src/core/toml.ts +62 -0
  188. package/src/core/verification-scripts.ts +6 -0
  189. package/src/core/workspace-files.ts +0 -1
  190. package/src/domains/agents/builtins/architect.md +1 -1
  191. package/src/domains/agents/builtins/verifier.md +3 -0
  192. package/src/domains/agents/catalog.ts +5 -4
  193. package/src/domains/agents/recipe.ts +54 -14
  194. package/src/domains/agents/result-contract.ts +7 -4
  195. package/src/domains/config/classify.ts +1 -0
  196. package/src/domains/context/bootstrap.ts +36 -27
  197. package/src/domains/context/project-metadata.ts +19 -63
  198. package/src/domains/context/prompt-context.ts +8 -0
  199. package/src/domains/context/working-set/contract.ts +161 -0
  200. package/src/domains/context/working-set/defaults.ts +28 -0
  201. package/src/domains/context/working-set/engine.ts +203 -0
  202. package/src/domains/context/working-set/fold.ts +62 -0
  203. package/src/domains/context/working-set/horizon.ts +38 -0
  204. package/src/domains/context/working-set/marker.ts +103 -0
  205. package/src/domains/context/working-set/path-index.ts +436 -0
  206. package/src/domains/context/working-set/payload.ts +152 -0
  207. package/src/domains/context/working-set/policies/age-horizon.ts +55 -0
  208. package/src/domains/context/working-set/policies/index.ts +20 -0
  209. package/src/domains/context/working-set/policies/structural.ts +160 -0
  210. package/src/domains/context/working-set/project.ts +132 -0
  211. package/src/domains/context/working-set/protect.ts +109 -0
  212. package/src/domains/context/working-set/recall.ts +177 -0
  213. package/src/domains/context/working-set/replay/controls.ts +112 -0
  214. package/src/domains/context/working-set/replay/load-clio.ts +199 -0
  215. package/src/domains/context/working-set/replay/metrics.ts +185 -0
  216. package/src/domains/context/working-set/replay/reference-graph.ts +79 -0
  217. package/src/domains/context/working-set/replay/report.ts +139 -0
  218. package/src/domains/context/working-set/replay/runner.ts +325 -0
  219. package/src/domains/context/working-set/replay/synthetic.ts +422 -0
  220. package/src/domains/context/working-set/replay/trace.ts +21 -0
  221. package/src/domains/context/working-set/visible.ts +54 -0
  222. package/src/domains/dispatch/budget-envelope.ts +396 -0
  223. package/src/domains/dispatch/contract.ts +2 -0
  224. package/src/domains/dispatch/extension.ts +81 -27
  225. package/src/domains/dispatch/orphan-recovery.ts +1 -0
  226. package/src/domains/dispatch/receipt-integrity.ts +4 -0
  227. package/src/domains/dispatch/state.ts +1 -0
  228. package/src/domains/dispatch/types.ts +10 -3
  229. package/src/domains/dispatch/validation.ts +14 -0
  230. package/src/domains/dispatch/worker-spawn.ts +14 -3
  231. package/src/domains/eval/metrics/evidence.ts +0 -116
  232. package/src/domains/eval/metrics/invariants.ts +1 -1
  233. package/src/domains/eval/runners/clio-run.ts +1 -10
  234. package/src/domains/eval/runners/external-command.ts +2 -29
  235. package/src/domains/eval/schema/suite.ts +0 -7
  236. package/src/domains/eval/suites/run.ts +1 -7
  237. package/src/domains/evidence/build.ts +112 -45
  238. package/src/domains/evidence/eval.ts +24 -7
  239. package/src/domains/evidence/index.ts +53 -0
  240. package/src/domains/evidence/ordering.ts +12 -0
  241. package/src/domains/evidence/run-trust.ts +221 -0
  242. package/src/domains/evidence/store.ts +46 -6
  243. package/src/domains/evidence/trust-status.ts +854 -0
  244. package/src/domains/evidence/types.ts +26 -0
  245. package/src/domains/memory/index.ts +22 -0
  246. package/src/domains/memory/operations.ts +58 -1
  247. package/src/domains/memory/promotion.ts +281 -0
  248. package/src/domains/memory/prompt-section.ts +25 -5
  249. package/src/domains/memory/proposal.ts +51 -7
  250. package/src/domains/memory/task-bank.ts +3 -2
  251. package/src/domains/memory/task-memory-handoff.ts +181 -24
  252. package/src/domains/memory/task-memory-policy.ts +3 -1
  253. package/src/domains/memory/types.ts +37 -0
  254. package/src/domains/memory/validate.ts +178 -0
  255. package/src/domains/middleware/memory-intervention.ts +38 -25
  256. package/src/domains/middleware/runtime.ts +6 -0
  257. package/src/domains/middleware/skills-reminder.ts +19 -4
  258. package/src/domains/middleware/stalled-turn.ts +208 -5
  259. package/src/domains/middleware/types.ts +10 -0
  260. package/src/domains/observability/contract.ts +6 -1
  261. package/src/domains/observability/cost.ts +20 -4
  262. package/src/domains/observability/extension.ts +2 -2
  263. package/src/domains/providers/index.ts +3 -0
  264. package/src/domains/providers/model-discovery.ts +9 -0
  265. package/src/domains/providers/runtime-resolution.ts +38 -1
  266. package/src/domains/providers/runtimes/common/probe-helpers.ts +97 -16
  267. package/src/domains/providers/types/context-window-slots.ts +18 -0
  268. package/src/domains/providers/types/runtime-descriptor.ts +3 -1
  269. package/src/domains/safety/autonomy.ts +1 -1
  270. package/src/domains/safety/call-target.ts +211 -14
  271. package/src/domains/safety/decision-presentation.ts +268 -0
  272. package/src/domains/safety/default-path-policy.ts +8 -0
  273. package/src/domains/safety/finish-contract.ts +4 -3
  274. package/src/domains/safety/policy-engine.ts +48 -6
  275. package/src/domains/safety/redaction.ts +73 -0
  276. package/src/domains/session/compaction/compact.ts +23 -1
  277. package/src/domains/session/compaction/cut-point.ts +2 -0
  278. package/src/domains/session/compaction/tokens.ts +16 -1
  279. package/src/domains/session/context-ledger.ts +12 -1
  280. package/src/domains/session/decision-board.ts +4 -0
  281. package/src/domains/session/entries.ts +110 -1
  282. package/src/domains/session/history.ts +68 -19
  283. package/src/domains/session/manager.ts +9 -2
  284. package/src/domains/session/migrations/index.ts +22 -3
  285. package/src/domains/session/usage.ts +24 -7
  286. package/src/engine/acp/event-mapper.ts +7 -0
  287. package/src/engine/acp/server.ts +32 -2
  288. package/src/engine/agent.ts +18 -1
  289. package/src/engine/apis/lmstudio.ts +25 -4
  290. package/src/engine/apis/openai-completions.ts +147 -22
  291. package/src/engine/claude/sdk-runtime.ts +8 -2
  292. package/src/engine/claude/tool-safety.ts +13 -0
  293. package/src/engine/loop-guard.ts +27 -3
  294. package/src/engine/session.ts +9 -3
  295. package/src/engine/worker-events.ts +4 -3
  296. package/src/engine/worker-runtime.ts +59 -54
  297. package/src/entry/orchestrator.ts +34 -5
  298. package/src/interactive/chat-loop-messages.ts +40 -6
  299. package/src/interactive/chat-loop.ts +13 -0
  300. package/src/interactive/chat-panel.ts +17 -1
  301. package/src/interactive/chat-renderer.ts +49 -24
  302. package/src/interactive/clio-editor.ts +44 -7
  303. package/src/interactive/context-meter.ts +10 -0
  304. package/src/interactive/context-overlay.ts +120 -7
  305. package/src/interactive/context-recall-command.ts +110 -0
  306. package/src/interactive/cost-overlay.ts +39 -8
  307. package/src/interactive/dispatch-board.ts +212 -35
  308. package/src/interactive/footer/widgets.ts +13 -0
  309. package/src/interactive/interactive-application.ts +6 -1
  310. package/src/interactive/interactive-input-runtime.ts +11 -1
  311. package/src/interactive/interactive-presentation.ts +11 -1
  312. package/src/interactive/interactive-slash-runtime.ts +37 -1
  313. package/src/interactive/memory-overlay.ts +89 -4
  314. package/src/interactive/model-session-replay.ts +21 -0
  315. package/src/interactive/overlay-ask-user-lifecycle.ts +1 -1
  316. package/src/interactive/overlay-frame.ts +5 -2
  317. package/src/interactive/overlay-general-openers.ts +46 -1
  318. package/src/interactive/overlay-key-routing.ts +41 -1
  319. package/src/interactive/overlay-lifecycle.ts +11 -4
  320. package/src/interactive/overlay-permission-lifecycle.ts +23 -8
  321. package/src/interactive/overlay-session-lifecycle.ts +8 -4
  322. package/src/interactive/overlay-transitions.ts +11 -0
  323. package/src/interactive/overlays/ask-user.ts +74 -30
  324. package/src/interactive/overlays/decisions.ts +3 -1
  325. package/src/interactive/permission-hint.ts +35 -0
  326. package/src/interactive/permission-overlay.ts +95 -45
  327. package/src/interactive/renderers/tool-execution.ts +37 -51
  328. package/src/interactive/session-last-turn.ts +8 -1
  329. package/src/interactive/session-transcript.ts +2 -2
  330. package/src/interactive/session-usage-reseed.ts +36 -10
  331. package/src/interactive/slash-commands.ts +31 -4
  332. package/src/interactive/status/summary.ts +5 -0
  333. package/src/interactive/status/types.ts +5 -0
  334. package/src/interactive/terminal-lease.ts +1 -0
  335. package/src/interactive/turn-context.ts +333 -110
  336. package/src/interactive/turn-middleware.ts +7 -6
  337. package/src/interactive/turn-runtime.ts +37 -8
  338. package/src/interactive/turn-state.ts +3 -0
  339. package/src/interactive/worker-progress.ts +440 -0
  340. package/src/interactive/worker-stream.ts +51 -110
  341. package/src/tools/agent-tools.ts +39 -7
  342. package/src/tools/ask-user.ts +21 -1
  343. package/src/tools/bash.ts +144 -82
  344. package/src/tools/builtin-tool-catalog.ts +11 -5
  345. package/src/tools/context/index.ts +107 -5
  346. package/src/tools/context/surface.ts +3 -2
  347. package/src/tools/core-bootstrap.ts +21 -0
  348. package/src/tools/dispatch-arguments.ts +8 -0
  349. package/src/tools/dispatch-event-text.ts +19 -0
  350. package/src/tools/dispatch-runner.ts +9 -7
  351. package/src/tools/dispatch.ts +24 -1
  352. package/src/tools/monitor.ts +43 -20
  353. package/src/tools/registry.ts +72 -10
  354. package/src/tools/result-disposition.ts +706 -0
  355. package/src/tools/result-shaping.ts +321 -20
  356. package/src/tools/safe-exec.ts +2 -0
  357. package/src/tools/verify/authoring.ts +1120 -0
  358. package/src/tools/verify/catalog.ts +346 -0
  359. package/src/tools/verify/index.ts +13 -3
  360. package/src/tools/verify/scripts.ts +135 -37
  361. package/src/tools/verify/surface.ts +9 -5
  362. package/src/tools/worker-evidence.ts +54 -12
  363. package/src/worker/spec-contract.ts +43 -3
  364. package/dist/chunk-J7CWMCQD.js +0 -255
  365. package/dist/chunk-T6YILFSB.js +0 -80
  366. package/dist/chunk-VAKQQHWR.js +0 -434
  367. package/dist/chunk-VPAYEGVX.js +0 -184
  368. package/dist/chunk-XBXAASKX.js +0 -18
  369. package/dist/memory-WFZMGYHX.js +0 -236
  370. package/src/domains/eval/metrics/chaos-stream.ts +0 -93
@@ -61,8 +61,8 @@ skills:
61
61
  sha256: 386ebfdac9379ebf5630fa7a9af259bb45f473f7d3d679b0a7ef4164f5fc4dea
62
62
  - name: clio-test
63
63
  path: meta/clio-test
64
- version: 0.1.3
65
- sha256: 99683ea7d7bf5bf57788e58ee6c66e01a4e30ec8d3d7d0a1f8b2b85caff4ae5a
64
+ version: 0.1.4
65
+ sha256: 90ca1fe7660cd8c3d835801883ebd55d2d17cb652b8585b28ddb82aec642336e
66
66
  - name: credentials
67
67
  path: meta/credentials
68
68
  version: 0.1.2
@@ -109,7 +109,7 @@
109
109
  "name": "clio-test",
110
110
  "description": "Use when writing or modifying Clio Coder's own source under src/, or verifying a change end-to-end against the real test harness. Covers the three real layers (contracts / smoke / boundaries), choosing which to run for a given change, the mock-provider and ACP-over-stdio harness, and the hot-reload dev loop for picking up latest code. Activate on any src/ edit, before declaring a change verified, or when asked whether Clio still works.",
111
111
  "sourceUrl": "https://github.com/iowarp/clio-coder/tree/main/skills/meta/clio-test",
112
- "version": "0.1.3",
112
+ "version": "0.1.4",
113
113
  "audit": "pass",
114
114
  "category": "meta"
115
115
  },
package/src/cli/agents.ts CHANGED
@@ -53,8 +53,7 @@ export async function runAgentsCommand(args: ReadonlyArray<string>): Promise<num
53
53
  function renderLine(spec: AgentSpec): void {
54
54
  const shape = `${spec.audience}/${spec.category}/${spec.capabilityClass}/${spec.latencyClass}`;
55
55
  const skills = spec.skills.length > 0 ? ` skills=${spec.skills.join(",")}` : "";
56
- const budget = spec.budget
57
- ? `${spec.budget.toolCalls}/${spec.budget.readReserve}/${spec.budget.synthesis ? "synthesize" : "stop"}`
58
- : "operator-default";
56
+ const maximum = spec.budget.maximum ? `..${spec.budget.maximum.toolCalls}/${spec.budget.maximum.readReserve}` : "";
57
+ const budget = `${spec.budget.toolCalls}/${spec.budget.readReserve}${maximum}/${spec.budget.synthesis ? "synthesize" : "stop"}`;
59
58
  process.stdout.write(`${spec.id.padEnd(20)} ${shape.padEnd(48)} ${spec.description}${skills} budget=${budget}\n`);
60
59
  }
package/src/cli/argv.ts CHANGED
@@ -102,6 +102,19 @@ export function globalFlagPositionHint(arg: string, command: string): string | n
102
102
  * for the command boundary, so `--skill path --api-key SECRET paths` treated
103
103
  * SECRET as a subcommand and printed it in an error.
104
104
  */
105
+ /**
106
+ * Sessions are resumed from the interactive picker, not from a flag, and the
107
+ * flag every other agent CLI spells `--resume` or `--continue` fails closed
108
+ * here. The failure names the picker so the habit lands somewhere (#191).
109
+ */
110
+ function unknownGlobalOptionError(arg: string): string {
111
+ const bare = arg.replace(/=.*$/u, "");
112
+ if (bare === "--resume" || bare === "--continue" || bare === "-r" || bare === "-c") {
113
+ return `unknown global option: ${arg}. Sessions are resumed from inside the app: start clio-coder, then type /resume to pick one.`;
114
+ }
115
+ return `unknown global option: ${arg}`;
116
+ }
117
+
105
118
  export function extractGlobalFlags(
106
119
  argv: ReadonlyArray<string>,
107
120
  isSubcommand: (token: string) => boolean = () => false,
@@ -156,7 +169,7 @@ export function extractGlobalFlags(
156
169
  noSkills,
157
170
  skillPaths,
158
171
  rest,
159
- error: `unknown global option: ${arg}`,
172
+ error: unknownGlobalOptionError(arg),
160
173
  ...(apiKey === undefined ? {} : { apiKey }),
161
174
  };
162
175
  }
@@ -0,0 +1,513 @@
1
+ import { execFileSync } from "node:child_process";
2
+ import { mkdir, readdir, readFile, stat, writeFile } from "node:fs/promises";
3
+ import { basename, dirname, join, resolve } from "node:path";
4
+ import { assertSafeId } from "../core/safe-id.js";
5
+ import { clioStatePath } from "../core/xdg.js";
6
+ import { DEFAULT_WORKING_SET_SETTINGS } from "../domains/context/working-set/defaults.js";
7
+ import { foldWorkingSet } from "../domains/context/working-set/fold.js";
8
+ import { buildPathIndex } from "../domains/context/working-set/path-index.js";
9
+ import { resolveWorkingSetPolicy } from "../domains/context/working-set/policies/index.js";
10
+ import { makeOraclePolicy, makeRandomPolicy, nonePolicy } from "../domains/context/working-set/replay/controls.js";
11
+ import { loadClioTraces, type ReplayLoadCascade } from "../domains/context/working-set/replay/load-clio.js";
12
+ import { aggregateReplayMetrics, type ReplayMeasurement } from "../domains/context/working-set/replay/metrics.js";
13
+ import { buildReferenceGraph, type ReferenceGraph } from "../domains/context/working-set/replay/reference-graph.js";
14
+ import {
15
+ type ReplayPolicyResult,
16
+ type ReplayReportInput,
17
+ renderReplayJson,
18
+ renderReplayMarkdown,
19
+ } from "../domains/context/working-set/replay/report.js";
20
+ import { replayTrace } from "../domains/context/working-set/replay/runner.js";
21
+ import { generateSyntheticCorpora, SYNTHETIC_CORPORA } from "../domains/context/working-set/replay/synthetic.js";
22
+ import type { Trace } from "../domains/context/working-set/replay/trace.js";
23
+ import { parseSessionEntries } from "../domains/session/archive-readers.js";
24
+ import { DEFAULT_KEEP_RECENT_TOKENS } from "../domains/session/compaction/defaults.js";
25
+ import { filterEntriesToActivePath } from "../domains/session/tree/active-path.js";
26
+
27
+ const REPLAY_HELP = `Usage:
28
+ clio-coder context replay (--sessions <path>... | --synthetic <corpus>...) [options]
29
+
30
+ Options:
31
+ --sessions <path>... Clio session directories, sessions roots, or ledger JSONL files
32
+ --synthetic <ids> comma-separated procedural corpora: ${SYNTHETIC_CORPORA.map((spec) => spec.id).join(",")}
33
+ --policies <ids> comma-separated none,random,age-horizon,structural-v1,oracle
34
+ --budgets <tokens> comma-separated budgets (default: 16000,32000,64000)
35
+ --threshold <ratio> pressure threshold (default: 0.8)
36
+ --target <ratio> post-eviction pressure target (default: 0.6)
37
+ --protect-last-turns <n>
38
+ protected recent turns (default: ${DEFAULT_WORKING_SET_SETTINGS.protectLastTurns})
39
+ --min-evictable-tokens <n>
40
+ minimum tool-result body tokens (default: ${DEFAULT_WORKING_SET_SETTINGS.minEvictableTokens})
41
+ --seed <integer> deterministic random-policy seed (default: 0)
42
+ --no-filter include every readable transcript
43
+ --json <path> write the stable JSON report
44
+ --md <path> write Markdown instead of printing it
45
+ `;
46
+
47
+ const WORKING_SET_HELP = `Usage:
48
+ clio-coder context working-set --session <id|path>
49
+
50
+ Print the durable working-set fold and path-index summary for one Clio session.
51
+ `;
52
+
53
+ /**
54
+ * Conservative stand-in for replay's summary paraphrase. Five recorded local
55
+ * compactions price at 405, 405, 968, 981, and 1,124 tokens; 1,500 sits above
56
+ * that observed range. The replay README records the sample and sensitivity.
57
+ */
58
+ const REPLAY_SUMMARY_TOKENS = 1_500;
59
+
60
+ const POLICY_IDS = ["none", "random", "age-horizon", "structural-v1", "oracle"] as const;
61
+ type ReplayPolicyId = (typeof POLICY_IDS)[number];
62
+
63
+ class CliUsageError extends Error {}
64
+
65
+ interface ReplayArgs {
66
+ sessions: string[];
67
+ policies: ReplayPolicyId[];
68
+ budgets: number[];
69
+ threshold: number;
70
+ target: number;
71
+ protectLastTurns: number;
72
+ minEvictableTokens: number;
73
+ seed: number;
74
+ synthetic: string[];
75
+ noFilter: boolean;
76
+ jsonPath?: string;
77
+ markdownPath?: string;
78
+ }
79
+
80
+ function commaValues(value: string, flag: string): string[] {
81
+ const values = value
82
+ .split(",")
83
+ .map((entry) => entry.trim())
84
+ .filter((entry) => entry.length > 0);
85
+ if (values.length === 0) throw new CliUsageError(`${flag} requires at least one value`);
86
+ return [...new Set(values)];
87
+ }
88
+
89
+ function numberValue(value: string, flag: string): number {
90
+ const parsed = Number(value);
91
+ if (!Number.isFinite(parsed)) throw new CliUsageError(`${flag} requires a finite number`);
92
+ return parsed;
93
+ }
94
+
95
+ function requiredValue(args: ReadonlyArray<string>, index: number, flag: string): string {
96
+ const value = args[index + 1];
97
+ if (value === undefined || value.startsWith("--")) throw new CliUsageError(`${flag} requires a value`);
98
+ return value;
99
+ }
100
+
101
+ function policyResolves(id: ReplayPolicyId): boolean {
102
+ if (id === "none" || id === "random" || id === "oracle") return true;
103
+ try {
104
+ resolveWorkingSetPolicy(id);
105
+ return true;
106
+ } catch {
107
+ return false;
108
+ }
109
+ }
110
+
111
+ function defaultPolicies(): ReplayPolicyId[] {
112
+ return POLICY_IDS.filter(policyResolves);
113
+ }
114
+
115
+ function parseReplayArgs(args: ReadonlyArray<string>): ReplayArgs {
116
+ const parsed: ReplayArgs = {
117
+ sessions: [],
118
+ policies: defaultPolicies(),
119
+ budgets: [16_000, 32_000, 64_000],
120
+ threshold: 0.8,
121
+ target: 0.6,
122
+ protectLastTurns: DEFAULT_WORKING_SET_SETTINGS.protectLastTurns,
123
+ minEvictableTokens: DEFAULT_WORKING_SET_SETTINGS.minEvictableTokens,
124
+ seed: 0,
125
+ synthetic: [],
126
+ noFilter: false,
127
+ };
128
+ let policiesExplicit = false;
129
+ for (let index = 0; index < args.length; index += 1) {
130
+ const arg = args[index];
131
+ if (arg === "--no-filter") {
132
+ parsed.noFilter = true;
133
+ continue;
134
+ }
135
+ if (arg === "--sessions") {
136
+ let consumed = 0;
137
+ while (index + 1 < args.length && !args[index + 1]?.startsWith("--")) {
138
+ parsed.sessions.push(args[index + 1] as string);
139
+ index += 1;
140
+ consumed += 1;
141
+ }
142
+ if (consumed === 0) throw new CliUsageError("--sessions requires at least one path");
143
+ continue;
144
+ }
145
+ if (
146
+ arg === "--policies" ||
147
+ arg === "--budgets" ||
148
+ arg === "--synthetic" ||
149
+ arg === "--threshold" ||
150
+ arg === "--target" ||
151
+ arg === "--protect-last-turns" ||
152
+ arg === "--min-evictable-tokens" ||
153
+ arg === "--seed"
154
+ ) {
155
+ const value = requiredValue(args, index, arg);
156
+ index += 1;
157
+ if (arg === "--policies") {
158
+ const values = commaValues(value, arg);
159
+ const unknown = values.filter((entry) => !(POLICY_IDS as ReadonlyArray<string>).includes(entry));
160
+ if (unknown.length > 0) throw new CliUsageError(`unknown replay policy: ${unknown.join(", ")}`);
161
+ parsed.policies = values as ReplayPolicyId[];
162
+ policiesExplicit = true;
163
+ } else if (arg === "--budgets") {
164
+ parsed.budgets = commaValues(value, arg).map((entry) => {
165
+ const budget = numberValue(entry, arg);
166
+ if (!Number.isInteger(budget) || budget <= 0) {
167
+ throw new CliUsageError("--budgets values must be positive integers");
168
+ }
169
+ return budget;
170
+ });
171
+ } else if (arg === "--synthetic") {
172
+ const values = commaValues(value, arg);
173
+ const known = SYNTHETIC_CORPORA.map((spec) => spec.id);
174
+ const unknown = values.filter((entry) => !known.includes(entry));
175
+ if (unknown.length > 0) throw new CliUsageError(`unknown synthetic corpus: ${unknown.join(", ")}`);
176
+ parsed.synthetic = values;
177
+ } else if (arg === "--threshold") {
178
+ parsed.threshold = numberValue(value, arg);
179
+ if (parsed.threshold <= 0 || parsed.threshold > 1) {
180
+ throw new CliUsageError("--threshold must be greater than 0 and at most 1");
181
+ }
182
+ } else if (arg === "--target") {
183
+ parsed.target = numberValue(value, arg);
184
+ if (parsed.target <= 0 || parsed.target >= 1) {
185
+ throw new CliUsageError("--target must be greater than 0 and less than 1");
186
+ }
187
+ } else if (arg === "--protect-last-turns") {
188
+ parsed.protectLastTurns = numberValue(value, arg);
189
+ if (!Number.isInteger(parsed.protectLastTurns) || parsed.protectLastTurns < 1) {
190
+ throw new CliUsageError("--protect-last-turns must be an integer at least 1");
191
+ }
192
+ } else if (arg === "--min-evictable-tokens") {
193
+ parsed.minEvictableTokens = numberValue(value, arg);
194
+ if (!Number.isInteger(parsed.minEvictableTokens) || parsed.minEvictableTokens < 0) {
195
+ throw new CliUsageError("--min-evictable-tokens must be a non-negative integer");
196
+ }
197
+ } else {
198
+ parsed.seed = numberValue(value, arg);
199
+ if (!Number.isInteger(parsed.seed)) throw new CliUsageError("--seed must be an integer");
200
+ }
201
+ continue;
202
+ }
203
+ if (arg === "--json" || arg === "--md") {
204
+ const value = requiredValue(args, index, arg);
205
+ index += 1;
206
+ if (arg === "--json") parsed.jsonPath = value;
207
+ else parsed.markdownPath = value;
208
+ continue;
209
+ }
210
+ throw new CliUsageError(`unknown flag ${arg}`);
211
+ }
212
+ if (parsed.sessions.length === 0 && parsed.synthetic.length === 0) {
213
+ throw new CliUsageError("--sessions or --synthetic is required");
214
+ }
215
+ if (parsed.target >= parsed.threshold) throw new CliUsageError("--target must be less than --threshold");
216
+ if (policiesExplicit) {
217
+ const unavailable = parsed.policies.filter((id) => !policyResolves(id));
218
+ if (unavailable.length > 0) {
219
+ throw new CliUsageError(`replay policy is not available in this build: ${unavailable.join(", ")}`);
220
+ }
221
+ }
222
+ return parsed;
223
+ }
224
+
225
+ function policyForTrace(id: ReplayPolicyId, graph: ReferenceGraph, seed: number) {
226
+ if (id === "none") return nonePolicy;
227
+ if (id === "random") return makeRandomPolicy(seed);
228
+ if (id === "oracle") return makeOraclePolicy(graph);
229
+ return resolveWorkingSetPolicy(id);
230
+ }
231
+
232
+ function gitSha(): string | null {
233
+ try {
234
+ return execFileSync("git", ["rev-parse", "HEAD"], {
235
+ cwd: process.cwd(),
236
+ encoding: "utf8",
237
+ stdio: ["ignore", "pipe", "ignore"],
238
+ }).trim();
239
+ } catch {
240
+ return null;
241
+ }
242
+ }
243
+
244
+ function exactCommandLine(): string[] {
245
+ return [process.execPath, ...process.execArgv, ...process.argv.slice(1)];
246
+ }
247
+
248
+ async function writeOutput(path: string, contents: string): Promise<string> {
249
+ const output = resolve(path);
250
+ await mkdir(dirname(output), { recursive: true });
251
+ await writeFile(output, contents, "utf8");
252
+ return output;
253
+ }
254
+
255
+ function cascadeLine(cascade: ReplayLoadCascade): string {
256
+ const filtered = Object.entries(cascade.filtered)
257
+ .map(([stage, count]) => `${stage}=${count}`)
258
+ .join(" ");
259
+ return `cascade found=${cascade.found} unreadable=${cascade.unreadable} ${filtered} kept=${cascade.kept}`;
260
+ }
261
+
262
+ export async function runContextReplayCommand(args: string[]): Promise<number> {
263
+ if (args.includes("--help") || args.includes("-h")) {
264
+ process.stdout.write(REPLAY_HELP);
265
+ return 0;
266
+ }
267
+ let parsed: ReplayArgs;
268
+ try {
269
+ parsed = parseReplayArgs(args);
270
+ } catch (error) {
271
+ process.stderr.write(
272
+ `clio-coder context replay: ${error instanceof Error ? error.message : String(error)}\n${REPLAY_HELP}`,
273
+ );
274
+ return 2;
275
+ }
276
+ try {
277
+ const ledgers = await loadClioTraces(parsed.sessions, { filter: parsed.noFilter ? false : {} });
278
+ const synthetic = generateSyntheticCorpora(parsed.synthetic);
279
+ const loaded = {
280
+ traces: [...ledgers.traces, ...synthetic.traces],
281
+ cascade: {
282
+ found: ledgers.cascade.found + synthetic.cascade.found,
283
+ unreadable: ledgers.cascade.unreadable,
284
+ filtered: ledgers.cascade.filtered,
285
+ kept: ledgers.cascade.kept + synthetic.cascade.kept,
286
+ },
287
+ };
288
+ if (loaded.traces.length === 0) {
289
+ process.stderr.write(`clio-coder context replay: no traces to replay (${cascadeLine(loaded.cascade)})\n`);
290
+ return 1;
291
+ }
292
+ const indexed = loaded.traces.map((trace) => {
293
+ const index = buildPathIndex(trace.entries, { cwd: trace.cwd });
294
+ return { trace, index, graph: buildReferenceGraph(trace, index) };
295
+ });
296
+ const settings = {
297
+ ...DEFAULT_WORKING_SET_SETTINGS,
298
+ target: parsed.target,
299
+ protectLastTurns: parsed.protectLastTurns,
300
+ minEvictableTokens: parsed.minEvictableTokens,
301
+ };
302
+ const results: ReplayPolicyResult[] = [];
303
+ for (const budgetTokens of parsed.budgets) {
304
+ for (const policyId of parsed.policies) {
305
+ const measurements: ReplayMeasurement[] = indexed.map(({ trace, index, graph }) => ({
306
+ trace,
307
+ index,
308
+ graph,
309
+ replay: replayTrace(trace, policyForTrace(policyId, graph, parsed.seed), {
310
+ policyId,
311
+ budgetTokens,
312
+ threshold: parsed.threshold,
313
+ target: parsed.target,
314
+ settings,
315
+ seed: parsed.seed,
316
+ summaries: { keepRecentTokens: DEFAULT_KEEP_RECENT_TOKENS, summaryTokens: REPLAY_SUMMARY_TOKENS },
317
+ }),
318
+ }));
319
+ results.push({ budgetTokens, policyId, metrics: aggregateReplayMetrics(measurements) });
320
+ }
321
+ }
322
+ const report: ReplayReportInput = {
323
+ config: {
324
+ policies: parsed.policies,
325
+ budgets: parsed.budgets,
326
+ threshold: parsed.threshold,
327
+ target: parsed.target,
328
+ seed: parsed.seed,
329
+ corpus: [...(parsed.sessions.length > 0 ? ["ledgers"] : []), ...parsed.synthetic],
330
+ filter: parsed.noFilter ? "none" : "default",
331
+ settings,
332
+ },
333
+ cascade: loaded.cascade,
334
+ results,
335
+ gitSha: gitSha(),
336
+ commandLine: exactCommandLine(),
337
+ };
338
+ const markdown = renderReplayMarkdown(report);
339
+ if (parsed.markdownPath === undefined) process.stdout.write(markdown);
340
+ else {
341
+ const path = await writeOutput(parsed.markdownPath, markdown);
342
+ process.stdout.write(`${cascadeLine(loaded.cascade)}\nmarkdown ${path}\n`);
343
+ }
344
+ if (parsed.jsonPath !== undefined) {
345
+ const path = await writeOutput(parsed.jsonPath, renderReplayJson(report));
346
+ process.stdout.write(`json ${path}\n`);
347
+ }
348
+ return 0;
349
+ } catch (error) {
350
+ process.stderr.write(`clio-coder context replay failed: ${error instanceof Error ? error.message : String(error)}\n`);
351
+ return 1;
352
+ }
353
+ }
354
+
355
+ async function sessionPath(value: string): Promise<string> {
356
+ const candidate = resolve(value);
357
+ try {
358
+ const facts = await stat(candidate);
359
+ if (facts.isDirectory()) return join(candidate, "current.jsonl");
360
+ if (facts.isFile()) return candidate;
361
+ } catch {
362
+ // A non-path value is resolved as a validated session id below.
363
+ }
364
+ try {
365
+ assertSafeId(value, "session");
366
+ } catch (error) {
367
+ throw new CliUsageError(error instanceof Error ? error.message : String(error));
368
+ }
369
+ const sessionsRoot = join(clioStatePath(), "sessions");
370
+ let cwdHashes: string[];
371
+ try {
372
+ cwdHashes = await readdir(sessionsRoot);
373
+ } catch {
374
+ throw new Error(`session not found: ${value}`);
375
+ }
376
+ for (const cwdHash of cwdHashes.sort()) {
377
+ const current = join(sessionsRoot, cwdHash, value, "current.jsonl");
378
+ try {
379
+ if ((await stat(current)).isFile()) return current;
380
+ } catch {
381
+ // Continue across repositories until the id is found.
382
+ }
383
+ }
384
+ throw new Error(`session not found: ${value}`);
385
+ }
386
+
387
+ async function pinnedLeafForSession(source: string): Promise<string | undefined> {
388
+ try {
389
+ const raw = await readFile(join(dirname(source), "meta.json"), "utf8");
390
+ const value = JSON.parse(raw) as unknown;
391
+ if (typeof value !== "object" || value === null || Array.isArray(value)) return undefined;
392
+ const pinned = (value as Record<string, unknown>).pinnedLeafTurnId;
393
+ return typeof pinned === "string" && pinned.length > 0 ? pinned : undefined;
394
+ } catch {
395
+ return undefined;
396
+ }
397
+ }
398
+
399
+ async function sessionCwdForSession(source: string): Promise<string | null> {
400
+ try {
401
+ const raw = await readFile(join(dirname(source), "meta.json"), "utf8");
402
+ const value = JSON.parse(raw) as unknown;
403
+ if (typeof value !== "object" || value === null || Array.isArray(value)) return null;
404
+ const cwd = (value as Record<string, unknown>).cwd;
405
+ return typeof cwd === "string" && cwd.length > 0 ? cwd : null;
406
+ } catch {
407
+ return null;
408
+ }
409
+ }
410
+
411
+ function formatWorkingSet(trace: Trace): string {
412
+ const view = foldWorkingSet(trace.entries);
413
+ const index = buildPathIndex(trace.entries, { cwd: trace.cwd });
414
+ const graph = buildReferenceGraph(trace, index);
415
+ const evictedTokens = [...view.evicted.values()].reduce((sum, state) => sum + state.tokensFreed, 0);
416
+ const churn = view.itemsEvicted === 0 ? "n/a" : (view.recalls / view.itemsEvicted).toFixed(3);
417
+ const opCounts = new Map<string, number>();
418
+ for (const observation of index.observations) {
419
+ opCounts.set(observation.op, (opCounts.get(observation.op) ?? 0) + 1);
420
+ }
421
+ const rewrittenPaths = new Set<string>();
422
+ for (const edge of graph.edges) {
423
+ if (edge.kind !== "file_rewrite") continue;
424
+ const path = index.byRef.get(edge.from)?.path;
425
+ if (path) rewrittenPaths.add(path);
426
+ }
427
+ const lines = [
428
+ `session: ${trace.id}`,
429
+ `source: ${trace.source}`,
430
+ "working set:",
431
+ ` policy: ${view.lastPolicyId ?? "none"}`,
432
+ ` eviction events: ${view.evictionEvents}`,
433
+ ` evicted refs: ${view.evicted.size}`,
434
+ ` items evicted: ${view.itemsEvicted}`,
435
+ ` evicted tokens: ${evictedTokens}`,
436
+ ` recalls: ${view.recalls}`,
437
+ ` churn: ${churn}`,
438
+ " refs:",
439
+ ...([...view.evicted.entries()].length === 0
440
+ ? [" none"]
441
+ : [...view.evicted.entries()]
442
+ .sort(([a], [b]) => a.localeCompare(b))
443
+ .map(([ref, state]) => ` ${ref} reason=${state.reason} by=${state.by ?? "-"} tokens=${state.tokensFreed}`)),
444
+ "path index:",
445
+ ` observations: ${index.observations.length}`,
446
+ ` ops: ${
447
+ [...opCounts.entries()]
448
+ .sort(([a], [b]) => a.localeCompare(b))
449
+ .map(([op, count]) => `${op}=${count}`)
450
+ .join(", ") || "none"
451
+ }`,
452
+ ` paths with rewrites: ${rewrittenPaths.size}`,
453
+ ...[...rewrittenPaths].sort().map((path) => ` ${path}`),
454
+ "",
455
+ ];
456
+ return lines.join("\n");
457
+ }
458
+
459
+ export async function runContextWorkingSetCommand(args: string[]): Promise<number> {
460
+ if (args.includes("--help") || args.includes("-h")) {
461
+ process.stdout.write(WORKING_SET_HELP);
462
+ return 0;
463
+ }
464
+ let session: string | undefined;
465
+ for (let index = 0; index < args.length; index += 1) {
466
+ const arg = args[index];
467
+ if (arg === "--session") {
468
+ try {
469
+ session = requiredValue(args, index, arg);
470
+ } catch (error) {
471
+ process.stderr.write(
472
+ `clio-coder context working-set: ${error instanceof Error ? error.message : String(error)}\n${WORKING_SET_HELP}`,
473
+ );
474
+ return 2;
475
+ }
476
+ index += 1;
477
+ continue;
478
+ }
479
+ process.stderr.write(`clio-coder context working-set: unknown flag ${arg}\n${WORKING_SET_HELP}`);
480
+ return 2;
481
+ }
482
+ if (session === undefined) {
483
+ process.stderr.write(`clio-coder context working-set: --session is required\n${WORKING_SET_HELP}`);
484
+ return 2;
485
+ }
486
+ try {
487
+ const source = await sessionPath(session);
488
+ const raw = await readFile(source, "utf8");
489
+ const parsed = parseSessionEntries(raw, source);
490
+ if (parsed.errors.length > 0) throw new Error(parsed.errors.join("; "));
491
+ const entries = filterEntriesToActivePath(parsed.entries, await pinnedLeafForSession(source));
492
+ const cwd = await sessionCwdForSession(source);
493
+ process.stdout.write(
494
+ formatWorkingSet({
495
+ id: basename(dirname(source)),
496
+ source,
497
+ cwd,
498
+ entries,
499
+ turnCount: buildPathIndex(entries, { cwd }).turnCount,
500
+ }),
501
+ );
502
+ return 0;
503
+ } catch (error) {
504
+ if (error instanceof CliUsageError) {
505
+ process.stderr.write(`clio-coder context working-set: ${error.message}\n${WORKING_SET_HELP}`);
506
+ return 2;
507
+ }
508
+ process.stderr.write(
509
+ `clio-coder context working-set failed: ${error instanceof Error ? error.message : String(error)}\n`,
510
+ );
511
+ return 1;
512
+ }
513
+ }
@@ -10,6 +10,8 @@ const HELP = `Usage:
10
10
  [--target <id>] [--model <id>] [--thinking off|low|medium|high]
11
11
  clio-coder context reset [--all] [--yes]
12
12
  clio-coder context index [--json]
13
+ clio-coder context replay --sessions <path>... [options]
14
+ clio-coder context working-set --session <id|path>
13
15
 
14
16
  Project context commands:
15
17
  clio-coder context show project context status (CLIO-CODER.md, preload, codewiki)
@@ -18,6 +20,8 @@ Project context commands:
18
20
  clio-coder context wiki generate or inspect the agent-authored Markdown wiki
19
21
  clio-coder context reset clear accumulated project context artifacts
20
22
  clio-coder context index build the codewiki index without model calls
23
+ clio-coder context replay compare working-set policies over Clio ledgers
24
+ clio-coder context working-set inspect one session's working-set fold and path index
21
25
  `;
22
26
 
23
27
  function printWikiProgress(event: BootstrapProgressEvent): void {
@@ -313,6 +317,10 @@ export async function runContextCommand(args: string[]): Promise<number> {
313
317
  return (await import("./context-clear.js")).runContextClearCommand(rest);
314
318
  case "index":
315
319
  return (await import("./context-index.js")).runContextIndexCommand(rest);
320
+ case "replay":
321
+ return (await import("./context-working-set.js")).runContextReplayCommand(rest);
322
+ case "working-set":
323
+ return (await import("./context-working-set.js")).runContextWorkingSetCommand(rest);
316
324
  default:
317
325
  process.stderr.write(`clio-coder context: unknown subcommand ${verb}\n`);
318
326
  process.stdout.write(HELP);
@@ -1,6 +1,6 @@
1
1
  import { InvalidIdError } from "../core/safe-id.js";
2
2
  import { clioDataDir, clioStateDir } from "../core/xdg.js";
3
- import type { EvidenceOverview, EvidenceRunProvenance } from "../domains/evidence/index.js";
3
+ import type { CanonicalTrustStatus, EvidenceOverview, EvidenceRunProvenance } from "../domains/evidence/index.js";
4
4
  import {
5
5
  buildEvalEvidence,
6
6
  buildEvidence,
@@ -178,7 +178,7 @@ function renderEvidence(
178
178
  input: Awaited<ReturnType<typeof inspectEvidence>>,
179
179
  provenance: ReadonlyArray<EvidenceRunProvenance> = [],
180
180
  ): void {
181
- const { overview, findings } = input;
181
+ const { overview, findings, trustStatus } = input;
182
182
  process.stdout.write(`evidence: ${overview.evidenceId}\n`);
183
183
  process.stdout.write(`source: ${formatSource(overview)}\n`);
184
184
  process.stdout.write(`generated: ${overview.generatedAt}\n`);
@@ -188,6 +188,13 @@ function renderEvidence(
188
188
  process.stdout.write(`blocked tools: ${overview.totals.blockedToolCalls}\n`);
189
189
  process.stdout.write(`tags: ${formatList(overview.tags)}\n`);
190
190
  process.stdout.write(`findings: ${findings.length}\n`);
191
+ if (trustStatus.projection === "historical_format") {
192
+ process.stdout.write("trust status: unavailable (historical bundle without canonical projection)\n");
193
+ } else {
194
+ for (const run of trustStatus.runs) {
195
+ process.stdout.write(`trust ${run.runId}: ${formatTrustStatus(run.status)}\n`);
196
+ }
197
+ }
191
198
  // Provenance is printed only for runs whose receipts carry it, so a legacy
192
199
  // bundle prints nothing new here.
193
200
  for (const { runId, view } of provenance) {
@@ -197,6 +204,17 @@ function renderEvidence(
197
204
  process.stdout.write(`files: ${formatList(overview.files)}\n`);
198
205
  }
199
206
 
207
+ function formatTrustStatus(status: CanonicalTrustStatus): string {
208
+ return [
209
+ `artifactIntegrity=${status.artifactIntegrity.state}`,
210
+ `validationGrounding=${status.validationGrounding.state}`,
211
+ `independentReview=${status.independentReview.state}`,
212
+ `contextProvenance=${status.contextProvenance.state}`,
213
+ `autonomyEnforcement=${status.autonomyEnforcement.state}`,
214
+ `completionEvidence=${status.completionEvidence.state}`,
215
+ ].join(" ");
216
+ }
217
+
200
218
  function renderEvidenceList(overviews: ReadonlyArray<EvidenceOverview>): void {
201
219
  process.stdout.write(`${overviews.length} evidence artifacts\n`);
202
220
  if (overviews.length === 0) return;
package/src/cli/fleet.ts CHANGED
@@ -37,6 +37,13 @@ import {
37
37
  import type { ConfigContract } from "../domains/config/contract.js";
38
38
  import { ConfigDomainModule } from "../domains/config/index.js";
39
39
  import { ContextDomainModule } from "../domains/context/runtime.js";
40
+ import {
41
+ formatBudgetPolicy,
42
+ formatBudgetReasons,
43
+ formatBudgetRequest,
44
+ formatEffectiveBudget,
45
+ type RunToolBudgetEnvelope,
46
+ } from "../domains/dispatch/budget-envelope.js";
40
47
  import { type CapacityDrain, capacityDrain, setCapacityDraining } from "../domains/dispatch/capacity-lease.js";
41
48
  import { runCodeStep } from "../domains/dispatch/code-step.js";
42
49
  import { codeStepDir, writeCodeStepRecord } from "../domains/dispatch/code-step-store.js";
@@ -740,6 +747,7 @@ export function statusSnapshot(): {
740
747
  return {
741
748
  runId: row.id,
742
749
  agentId: row.agentId,
750
+ budget: row.budget ?? null,
743
751
  runtimeKind: row.runtimeKind,
744
752
  outcomePhase: row.status,
745
753
  heartbeat: rowHeartbeat(row),
@@ -798,6 +806,13 @@ function runStatus(args: ReadonlyArray<string>): number {
798
806
  process.stdout.write(
799
807
  ` ${row.runId} ${row.agentId} node=${row.node} ${row.heartbeat} attempt=${lineage.attempt} depth=${lineage.depth} ${Math.round((row.elapsedMs as number) / 1000)}s $${(row.costUsd as number).toFixed(4)}\n`,
800
808
  );
809
+ const budget = row.budget as RunToolBudgetEnvelope | null;
810
+ if (budget !== null) {
811
+ process.stdout.write(` recipe policy: ${formatBudgetPolicy(budget)}\n`);
812
+ process.stdout.write(` requested envelope: ${formatBudgetRequest(budget)}\n`);
813
+ process.stdout.write(` effective envelope: ${formatEffectiveBudget(budget)}\n`);
814
+ process.stdout.write(` clamp or escalation reason: ${formatBudgetReasons(budget)}\n`);
815
+ }
801
816
  }
802
817
  }
803
818
  if (snapshot.retrying.length === 0) {