@iowarp/clio-coder 0.3.4 → 0.3.7

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 (376) hide show
  1. package/CHANGELOG.md +65 -2
  2. package/CONTRIBUTING.md +6 -6
  3. package/README.md +16 -5
  4. package/dist/{acp-S5R4RR5B.js → acp-SK4MD6MM.js} +11 -11
  5. package/dist/{agents-P6DMMVZY.js → agents-2FN2K6ME.js} +33 -26
  6. package/dist/assets/codewiki.json +1 -1
  7. package/dist/{auth-2XCZLPKS.js → auth-QIYZWM5I.js} +15 -15
  8. package/dist/{chunk-EKMEHE4H.js → chunk-33YXPOE3.js} +2 -3
  9. package/dist/{chunk-VAWWTKDP.js → chunk-3HAPLH5M.js} +11 -11
  10. package/dist/{chunk-YCWGATWI.js → chunk-465YSENW.js} +3 -3
  11. package/dist/{chunk-4OC57DA6.js → chunk-4DGYLA73.js} +53 -2
  12. package/dist/{chunk-UZHIZC5S.js → chunk-4DWFMQDR.js} +61 -76
  13. package/dist/{chunk-ZWMF7253.js → chunk-5C3AQNDW.js} +328 -9
  14. package/dist/{chunk-22NAGB7X.js → chunk-5C77SEEY.js} +5 -94
  15. package/dist/{chunk-WPQLXFOZ.js → chunk-5FR74PWO.js} +3 -2
  16. package/dist/{chunk-35MKKU5R.js → chunk-5UJ6ECTS.js} +18 -10
  17. package/dist/{chunk-BRXQQJFP.js → chunk-6M7VS3J3.js} +571 -50
  18. package/dist/{chunk-QQK64KLB.js → chunk-6TUKSZVF.js} +141 -23
  19. package/dist/{chunk-N4CZJQRK.js → chunk-AB4XIIVB.js} +8 -6
  20. package/dist/{chunk-KRPY7NTG.js → chunk-BMWK7ZIZ.js} +14 -20
  21. package/dist/{chunk-4BPJXDWC.js → chunk-C4JBQ5SR.js} +30 -14
  22. package/dist/{chunk-ZYKPLLNQ.js → chunk-CEYBNUGC.js} +821 -83
  23. package/dist/{chunk-VEZEGCGW.js → chunk-D4MDIG46.js} +20 -18
  24. package/dist/chunk-DJNLUABN.js +843 -0
  25. package/dist/{chunk-BP4OYD6A.js → chunk-DMD2AGVS.js} +21 -2
  26. package/dist/{chunk-KOHPCX4K.js → chunk-DOOEX22V.js} +2 -2
  27. package/dist/chunk-DQA7QLMD.js +123 -0
  28. package/dist/chunk-DR52UMZW.js +21 -0
  29. package/dist/{chunk-3HZ5RWN2.js → chunk-EBEFWSGL.js} +9 -7
  30. package/dist/{chunk-EDRHSCIE.js → chunk-EELBMBT6.js} +128 -13
  31. package/dist/{chunk-HV5X7OR2.js → chunk-EOOQZZDE.js} +16 -14
  32. package/dist/{chunk-WR67VIZY.js → chunk-FOT2FX5J.js} +63 -5
  33. package/dist/{chunk-BPGS2WCQ.js → chunk-GEYXPTRF.js} +2 -1
  34. package/dist/{chunk-FYYLNIL5.js → chunk-GH5622CP.js} +2 -2
  35. package/dist/{chunk-BEY543CS.js → chunk-GOXNB3AO.js} +5 -2
  36. package/dist/chunk-GWS3VEIW.js +195 -0
  37. package/dist/{chunk-G4BMMOKF.js → chunk-HVDIIIQW.js} +2 -2
  38. package/dist/chunk-HWUFFB6L.js +83 -0
  39. package/dist/{chunk-X6COSD2O.js → chunk-J7PIKKWC.js} +8 -436
  40. package/dist/{chunk-NILBFAPG.js → chunk-JNXPYBB4.js} +2 -2
  41. package/dist/{chunk-4VP4KH3K.js → chunk-JRIO5UD2.js} +4 -4
  42. package/dist/{chunk-K6WL7QZT.js → chunk-JTSEDYVQ.js} +7 -7
  43. package/dist/{chunk-QKMUKYO7.js → chunk-KCMKRQX4.js} +236 -84
  44. package/dist/chunk-KZ2H5X4G.js +1026 -0
  45. package/dist/{chunk-A2GZF7DC.js → chunk-LADCF22A.js} +13 -13
  46. package/dist/chunk-LCGCVYZ4.js +57 -0
  47. package/dist/chunk-M4AKACEO.js +382 -0
  48. package/dist/{chunk-POHLU5DW.js → chunk-M6L6IDJG.js} +3 -3
  49. package/dist/{chunk-4JUF2NNX.js → chunk-MXI6J5JF.js} +7 -7
  50. package/dist/{chunk-X4RCMKVQ.js → chunk-NDINPTJ4.js} +2 -2
  51. package/dist/{chunk-TTNYS3EA.js → chunk-OB5HIGJY.js} +1 -1
  52. package/dist/{chunk-7RXG6QRZ.js → chunk-OBMAI2DP.js} +61 -840
  53. package/dist/{chunk-5M54SPOL.js → chunk-ODFEOB4F.js} +161 -5
  54. package/dist/chunk-PD3MESLB.js +242 -0
  55. package/dist/{chunk-ED4KHGC3.js → chunk-PPAMZ32Z.js} +9 -2
  56. package/dist/{chunk-VMNQ6OZA.js → chunk-QCTRSGHQ.js} +963 -786
  57. package/dist/chunk-RVG5JXAL.js +41 -0
  58. package/dist/{chunk-RD5U66HV.js → chunk-SROCI7ZU.js} +7 -7
  59. package/dist/{chunk-MFFY33HR.js → chunk-THKY7CD7.js} +466 -205
  60. package/dist/{chunk-34475P3I.js → chunk-TSHXZTOQ.js} +5 -4
  61. package/dist/{chunk-PCZJO5TI.js → chunk-UFQ3F4FW.js} +13 -178
  62. package/dist/{chunk-AD2SYQYC.js → chunk-UHXRNZ2J.js} +121 -3
  63. package/dist/chunk-UND3GU2L.js +103 -0
  64. package/dist/{chunk-QQL5RT5M.js → chunk-UUANF5CR.js} +2323 -2114
  65. package/dist/{chunk-VJWL6YS5.js → chunk-UUVG37B4.js} +2 -2
  66. package/dist/chunk-UVDSQ6LW.js +472 -0
  67. package/dist/{chunk-QWU7ZBO7.js → chunk-VQNODYQ4.js} +215 -56
  68. package/dist/chunk-VREKEFLL.js +37 -0
  69. package/dist/{chunk-2TZWSW76.js → chunk-WHGPSPT5.js} +2 -2
  70. package/dist/{chunk-TW3WDMVS.js → chunk-WHJYKASB.js} +2 -2
  71. package/dist/{chunk-MEQ45TQ4.js → chunk-WJHBC77E.js} +21 -7
  72. package/dist/{chunk-HXG4IURW.js → chunk-X2KV5FXT.js} +2 -2
  73. package/dist/{chunk-YHZX5GEU.js → chunk-XAKHZX5N.js} +2 -2
  74. package/dist/{chunk-2LZI5CAG.js → chunk-XEGB6BCN.js} +228 -36
  75. package/dist/{chunk-E25LMLRW.js → chunk-YD734TPH.js} +2 -2
  76. package/dist/{verifiers-4UUM6TEE.js → chunk-YTYFXUI3.js} +121 -372
  77. package/dist/{chunk-3JLKSKD7.js → chunk-ZGH7FGS5.js} +17 -7
  78. package/dist/{chunk-VSNATDE6.js → chunk-ZZMN5OM4.js} +2 -2
  79. package/dist/cli/index.js +34 -32
  80. package/dist/{clio-J5JIOIDS.js → clio-WBVQEBKO.js} +7 -7
  81. package/dist/{code-nav-AXCXSBHX.js → code-nav-FGGFIE7L.js} +7 -7
  82. package/dist/codewiki/build-worker.js +4 -4
  83. package/dist/{components-KELWS457.js → components-F7OEATSO.js} +5 -5
  84. package/dist/{config-OEBMIN2U.js → config-TRBL3RCF.js} +48 -41
  85. package/dist/{configure-PUQOSIXQ.js → configure-OLCVPHNM.js} +17 -17
  86. package/dist/{context-URSXPBCK.js → context-MJIJ6GOX.js} +12 -12
  87. package/dist/{context-EKDCKUUZ.js → context-WFPKQSM6.js} +26 -9
  88. package/dist/{context-MGSE4Z2T.js → context-XEWE3MOJ.js} +44 -37
  89. package/dist/{context-clear-KDAJRNUK.js → context-clear-KNOS2JPB.js} +44 -37
  90. package/dist/{context-index-BZ4UYMTC.js → context-index-SSR5ECNE.js} +3 -3
  91. package/dist/{context-working-set-SBKMPPI2.js → context-working-set-EUXAZI6N.js} +14 -13
  92. package/dist/{dispatch-runner-MSWN72NK.js → dispatch-runner-B7MTOVKL.js} +321 -60
  93. package/dist/{docs-2C2LTVT2.js → docs-FLJTIDSE.js} +5 -5
  94. package/dist/{doctor-7BSE27PJ.js → doctor-RN4YKO2X.js} +15 -15
  95. package/dist/{eval-IZGDOO4H.js → eval-RUBJVSNQ.js} +52 -236
  96. package/dist/{evidence-SR7WXB5B.js → evidence-JZNBUOQZ.js} +39 -33
  97. package/dist/{evolve-K7VE2CBX.js → evolve-FJVC4KKI.js} +39 -33
  98. package/dist/{extensions-QVDOHDGJ.js → extensions-IQL36S7K.js} +5 -5
  99. package/dist/{fleet-7XMJNQNF.js → fleet-BDKYJFCP.js} +243 -370
  100. package/dist/fleet-commands-ZFIWZSB3.js +70 -0
  101. package/dist/fleet-graph-Y6HPXIVF.js +125 -0
  102. package/dist/fleet-new-RDVJLHHH.js +48 -0
  103. package/dist/{fleet-preflight-AQNAH644.js → fleet-preflight-BHSNPBMH.js} +2 -2
  104. package/dist/fleet-validate-BIYREGIK.js +79 -0
  105. package/dist/{init-JGNPAYXT.js → init-LQUB5COQ.js} +57 -48
  106. package/dist/library-NJAHIGG4.js +217 -0
  107. package/dist/memory-OG6HOYKM.js +472 -0
  108. package/dist/{models-ZMMLFJNN.js → models-5ZG5XY7J.js} +23 -22
  109. package/dist/{monitor-2F3T5KHP.js → monitor-TJ7AMTGB.js} +69 -35
  110. package/dist/{orchestrator-ORHT43JB.js → orchestrator-WZYB54DM.js} +4868 -1189
  111. package/dist/{paths-UXLN5YYZ.js → paths-XUC7GS6E.js} +5 -5
  112. package/dist/{reset-NXGTYNUO.js → reset-PXQT45IY.js} +8 -8
  113. package/dist/{run-RF4WJGMT.js → run-FQ74YF62.js} +82 -62
  114. package/dist/{share-UT3W6E4M.js → share-FW7SVCL3.js} +34 -10
  115. package/dist/{skills-PSACKC5Q.js → skills-7E7IRB3R.js} +25 -9
  116. package/dist/{skills-eval-WJSI55RZ.js → skills-eval-LI75W6OK.js} +43 -35
  117. package/dist/{targets-PIIRAOYS.js → targets-4CIFKCTW.js} +27 -24
  118. package/dist/{terminal-lease-ULWXWNVY.js → terminal-lease-WUZY7ZV5.js} +5 -4
  119. package/dist/{uninstall-FZCQCDKC.js → uninstall-7FV7IP4E.js} +5 -5
  120. package/dist/{upgrade-346TZ6AV.js → upgrade-K2HVIVMQ.js} +21 -20
  121. package/dist/{usage-6KKXR32N.js → usage-GTZELZQX.js} +159 -59
  122. package/dist/verifiers-RLAHT27O.js +336 -0
  123. package/dist/{verify-X5HDROLA.js → verify-BX3BRKH5.js} +7 -6
  124. package/dist/{wiki-generate-7STOCIFZ.js → wiki-generate-ASIFASCN.js} +58 -48
  125. package/dist/worker/entry.js +98 -84
  126. package/dist/{workspace-G4ZWUIPR.js → workspace-ZJ6BFM3Q.js} +4 -4
  127. package/docs/README.md +4 -3
  128. package/docs/acp.md +1 -1
  129. package/docs/alcf-provider.md +1 -1
  130. package/docs/architecture.md +2 -2
  131. package/docs/artifact-placement.md +1 -2
  132. package/docs/artifact-versions.md +10 -6
  133. package/docs/built-in-agents.md +26 -2
  134. package/docs/capacity-and-scheduling.md +1 -1
  135. package/docs/commands-and-modes.md +90 -8
  136. package/docs/configuration-and-targets.md +90 -2
  137. package/docs/context-engine.md +4 -2
  138. package/docs/context-working-set.md +4 -4
  139. package/docs/development-pipeline.md +1 -1
  140. package/docs/dispatch-architecture-rationale.md +1 -1
  141. package/docs/documentation-coverage.md +4 -4
  142. package/docs/documentation-guide.md +4 -4
  143. package/docs/eval-runner.md +1 -1
  144. package/docs/evals-internal.md +4 -45
  145. package/docs/evidence-and-memory.md +70 -10
  146. package/docs/evolution.md +1 -1
  147. package/docs/exit-codes-and-output.md +4 -1
  148. package/docs/extensions-and-sharing.md +6 -2
  149. package/docs/fleet-demo-runbook.md +2 -2
  150. package/docs/fleet-dispatch.md +224 -11
  151. package/docs/git-commit-provenance.md +2 -2
  152. package/docs/glossary.md +1 -1
  153. package/docs/installation-and-lifecycle.md +2 -2
  154. package/docs/middleware-and-components.md +20 -2
  155. package/docs/model-catalog.md +1 -1
  156. package/docs/observability.md +55 -8
  157. package/docs/proactive-memory.md +26 -16
  158. package/docs/prompt-envelope-and-tools.md +4 -2
  159. package/docs/provider-adapter-cookbook.md +1 -1
  160. package/docs/release-cut-checklist.md +83 -65
  161. package/docs/resource-library.md +59 -0
  162. package/docs/safety-model.md +29 -7
  163. package/docs/scientific-validation.md +3 -3
  164. package/docs/session-lifecycle.md +37 -1
  165. package/docs/skills-marketplace.md +16 -3
  166. package/docs/tool-usage.md +14 -7
  167. package/docs/trace-store.md +1 -1
  168. package/docs/troubleshooting.md +1 -1
  169. package/docs/tui-design.md +38 -4
  170. package/docs/worker-dispatch-mechanics.md +3 -3
  171. package/package.json +7 -4
  172. package/src/cli/agents.ts +2 -3
  173. package/src/cli/argv.ts +14 -1
  174. package/src/cli/fleet-commands.ts +37 -0
  175. package/src/cli/fleet-graph.ts +102 -0
  176. package/src/cli/fleet-new.ts +36 -0
  177. package/src/cli/fleet-preflight.ts +121 -0
  178. package/src/cli/fleet-validate.ts +30 -0
  179. package/src/cli/fleet.ts +188 -335
  180. package/src/cli/index.ts +4 -2
  181. package/src/cli/library.ts +190 -0
  182. package/src/cli/memory.ts +272 -10
  183. package/src/cli/modes/json-stream.ts +2 -2
  184. package/src/cli/modes/print.ts +12 -1
  185. package/src/cli/run.ts +22 -2
  186. package/src/cli/share.ts +13 -1
  187. package/src/cli/targets.ts +12 -3
  188. package/src/cli/usage.ts +160 -20
  189. package/src/core/bus-events.ts +7 -0
  190. package/src/core/commit-attribution.ts +4 -4
  191. package/src/core/config.ts +130 -0
  192. package/src/core/defaults.ts +81 -0
  193. package/src/core/response-model-id.ts +134 -0
  194. package/src/core/toml.ts +62 -0
  195. package/src/core/workspace-files.ts +0 -1
  196. package/src/domains/agents/builtins/architect.md +2 -1
  197. package/src/domains/agents/builtins/oracle.md +33 -0
  198. package/src/domains/agents/catalog.ts +18 -5
  199. package/src/domains/agents/fleet-contract.ts +278 -16
  200. package/src/domains/agents/index.ts +14 -0
  201. package/src/domains/agents/recipe.ts +54 -14
  202. package/src/domains/agents/result-contract.ts +242 -5
  203. package/src/domains/config/classify.ts +4 -0
  204. package/src/domains/context/bootstrap.ts +36 -27
  205. package/src/domains/context/project-metadata.ts +19 -63
  206. package/src/domains/context/prompt-context.ts +8 -0
  207. package/src/domains/context/working-set/policies/index.ts +3 -4
  208. package/src/domains/dispatch/active-route-planner.ts +14 -0
  209. package/src/domains/dispatch/backoff.ts +2 -1
  210. package/src/domains/dispatch/budget-envelope.ts +396 -0
  211. package/src/domains/dispatch/capability-match.ts +1 -0
  212. package/src/domains/dispatch/checkout-writer-lease.ts +175 -0
  213. package/src/domains/dispatch/contract.ts +36 -0
  214. package/src/domains/dispatch/delegation-plan.ts +167 -0
  215. package/src/domains/dispatch/execution-plan.ts +76 -5
  216. package/src/domains/dispatch/execution-role.ts +3 -1
  217. package/src/domains/dispatch/execution-scheduler.ts +183 -67
  218. package/src/domains/dispatch/extension.ts +339 -36
  219. package/src/domains/dispatch/fleet-gate.ts +14 -0
  220. package/src/domains/dispatch/fleet-plan.ts +63 -3
  221. package/src/domains/dispatch/fleet-run.ts +737 -0
  222. package/src/domains/dispatch/gate-role-prompts.ts +9 -0
  223. package/src/domains/dispatch/host-verification.ts +178 -0
  224. package/src/domains/dispatch/index.ts +38 -0
  225. package/src/domains/dispatch/intent.ts +159 -0
  226. package/src/domains/dispatch/orphan-recovery.ts +1 -0
  227. package/src/domains/dispatch/receipt-integrity.ts +12 -4
  228. package/src/domains/dispatch/state.ts +37 -3
  229. package/src/domains/dispatch/types.ts +61 -9
  230. package/src/domains/dispatch/validation.ts +80 -6
  231. package/src/domains/dispatch/worker-spawn.ts +14 -3
  232. package/src/domains/eval/metrics/evidence.ts +0 -116
  233. package/src/domains/eval/metrics/invariants.ts +1 -1
  234. package/src/domains/eval/runners/clio-run.ts +1 -10
  235. package/src/domains/eval/runners/external-command.ts +2 -29
  236. package/src/domains/eval/schema/suite.ts +0 -7
  237. package/src/domains/eval/suites/run.ts +1 -7
  238. package/src/domains/evidence/trust-status.ts +10 -1
  239. package/src/domains/memory/index.ts +22 -0
  240. package/src/domains/memory/operations.ts +58 -1
  241. package/src/domains/memory/promotion.ts +281 -0
  242. package/src/domains/memory/prompt-section.ts +25 -5
  243. package/src/domains/memory/proposal.ts +51 -7
  244. package/src/domains/memory/task-bank.ts +3 -2
  245. package/src/domains/memory/task-memory-handoff.ts +181 -24
  246. package/src/domains/memory/task-memory-policy.ts +3 -1
  247. package/src/domains/memory/types.ts +37 -0
  248. package/src/domains/memory/validate.ts +178 -0
  249. package/src/domains/middleware/index.ts +15 -0
  250. package/src/domains/middleware/memory-intervention.ts +35 -25
  251. package/src/domains/middleware/runtime.ts +6 -0
  252. package/src/domains/middleware/skills-reminder.ts +19 -4
  253. package/src/domains/middleware/stalled-turn.ts +43 -1
  254. package/src/domains/middleware/types.ts +10 -0
  255. package/src/domains/middleware/watchdog.ts +281 -0
  256. package/src/domains/observability/contract.ts +9 -2
  257. package/src/domains/observability/cost.ts +31 -4
  258. package/src/domains/observability/extension.ts +2 -2
  259. package/src/domains/observability/index.ts +10 -0
  260. package/src/domains/observability/out-of-turn-usage.ts +223 -0
  261. package/src/domains/providers/index.ts +3 -0
  262. package/src/domains/providers/model-discovery.ts +9 -0
  263. package/src/domains/providers/runtime-resolution.ts +38 -1
  264. package/src/domains/providers/runtimes/common/probe-helpers.ts +97 -16
  265. package/src/domains/providers/types/context-window-slots.ts +18 -0
  266. package/src/domains/providers/types/runtime-descriptor.ts +3 -1
  267. package/src/domains/resources/index.ts +20 -0
  268. package/src/domains/resources/library.ts +326 -0
  269. package/src/domains/resources/skills/marketplace.ts +37 -12
  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/redaction.ts +73 -0
  273. package/src/domains/session/context-ledger.ts +10 -1
  274. package/src/domains/session/decision-board.ts +4 -0
  275. package/src/domains/session/entries.ts +3 -0
  276. package/src/domains/session/handoff.ts +629 -0
  277. package/src/domains/session/history.ts +68 -19
  278. package/src/domains/session/usage.ts +24 -7
  279. package/src/domains/share/archive.ts +67 -2
  280. package/src/engine/acp/event-mapper.ts +7 -0
  281. package/src/engine/acp/server.ts +29 -2
  282. package/src/engine/apis/lmstudio.ts +25 -4
  283. package/src/engine/apis/openai-completions.ts +147 -22
  284. package/src/engine/claude/sdk-runtime.ts +8 -2
  285. package/src/engine/claude/tool-safety.ts +13 -0
  286. package/src/engine/loop-guard.ts +27 -3
  287. package/src/engine/worker-events.ts +4 -3
  288. package/src/engine/worker-runtime.ts +59 -54
  289. package/src/entry/orchestrator.ts +55 -1
  290. package/src/interactive/bus-notices.ts +26 -0
  291. package/src/interactive/chat-loop-messages.ts +22 -0
  292. package/src/interactive/chat-loop.ts +248 -1
  293. package/src/interactive/chat-renderer.ts +41 -3
  294. package/src/interactive/clio-editor.ts +44 -7
  295. package/src/interactive/context-overlay.ts +43 -5
  296. package/src/interactive/cost-overlay.ts +70 -11
  297. package/src/interactive/council-dispatch.ts +30 -0
  298. package/src/interactive/council-grid.ts +213 -0
  299. package/src/interactive/council.ts +99 -0
  300. package/src/interactive/dispatch-board.ts +471 -50
  301. package/src/interactive/fleet-run-preview.ts +307 -0
  302. package/src/interactive/footer/notifications.ts +219 -0
  303. package/src/interactive/footer/widgets.ts +13 -0
  304. package/src/interactive/handoff-round.ts +56 -0
  305. package/src/interactive/interactive-application.ts +49 -2
  306. package/src/interactive/interactive-event-projection.ts +9 -1
  307. package/src/interactive/interactive-input-runtime.ts +11 -1
  308. package/src/interactive/interactive-presentation.ts +11 -1
  309. package/src/interactive/interactive-slash-runtime.ts +52 -2
  310. package/src/interactive/interactive-subscriptions.ts +14 -2
  311. package/src/interactive/memory-overlay.ts +89 -4
  312. package/src/interactive/oracle.ts +179 -0
  313. package/src/interactive/overlay-ask-user-lifecycle.ts +7 -1
  314. package/src/interactive/overlay-frame.ts +5 -2
  315. package/src/interactive/overlay-general-openers.ts +230 -2
  316. package/src/interactive/overlay-key-routing.ts +58 -2
  317. package/src/interactive/overlay-lifecycle.ts +52 -5
  318. package/src/interactive/overlay-permission-lifecycle.ts +33 -8
  319. package/src/interactive/overlay-resource-openers.ts +11 -3
  320. package/src/interactive/overlay-session-lifecycle.ts +234 -2
  321. package/src/interactive/overlay-transitions.ts +11 -0
  322. package/src/interactive/overlays/ask-user.ts +74 -30
  323. package/src/interactive/overlays/decisions.ts +3 -1
  324. package/src/interactive/overlays/fleet-run-approval.ts +208 -0
  325. package/src/interactive/overlays/handoff-review.ts +185 -0
  326. package/src/interactive/overlays/library-install-confirm.ts +151 -0
  327. package/src/interactive/overlays/list-overlay.ts +168 -2
  328. package/src/interactive/overlays/settings.ts +101 -4
  329. package/src/interactive/overlays/side-question.ts +139 -0
  330. package/src/interactive/overlays/skills-hub.ts +401 -15
  331. package/src/interactive/permission-hint.ts +35 -0
  332. package/src/interactive/permission-overlay.ts +95 -45
  333. package/src/interactive/renderers/tool-execution.ts +19 -49
  334. package/src/interactive/session-last-turn.ts +8 -1
  335. package/src/interactive/session-usage-reseed.ts +36 -10
  336. package/src/interactive/side-question.ts +171 -0
  337. package/src/interactive/slash-commands.ts +434 -7
  338. package/src/interactive/slash-spec.ts +19 -6
  339. package/src/interactive/status/summary.ts +5 -0
  340. package/src/interactive/status/types.ts +5 -0
  341. package/src/interactive/terminal-lease.ts +1 -0
  342. package/src/interactive/theme/tokens.ts +30 -0
  343. package/src/interactive/turn-context.ts +96 -23
  344. package/src/interactive/turn-middleware.ts +16 -1
  345. package/src/interactive/turn-runtime.ts +37 -8
  346. package/src/interactive/turn-state.ts +3 -0
  347. package/src/interactive/watchdog-run.ts +75 -0
  348. package/src/interactive/worker-progress.ts +440 -0
  349. package/src/interactive/worker-share.ts +56 -1
  350. package/src/interactive/worker-stream.ts +58 -110
  351. package/src/tools/agent-tools.ts +28 -3
  352. package/src/tools/ask-user.ts +21 -1
  353. package/src/tools/bootstrap.ts +3 -0
  354. package/src/tools/compete-worktrees.ts +13 -79
  355. package/src/tools/context/index.ts +2 -2
  356. package/src/tools/dispatch-admission.ts +242 -8
  357. package/src/tools/dispatch-arguments.ts +65 -1
  358. package/src/tools/dispatch-event-text.ts +19 -0
  359. package/src/tools/dispatch-plan.ts +136 -6
  360. package/src/tools/dispatch-runner.ts +319 -13
  361. package/src/tools/dispatch-types.ts +20 -1
  362. package/src/tools/dispatch.ts +96 -3
  363. package/src/tools/monitor.ts +31 -0
  364. package/src/tools/profiles.ts +18 -4
  365. package/src/tools/registry.ts +15 -5
  366. package/src/tools/result-disposition.ts +156 -0
  367. package/src/tools/result-shaping.ts +59 -1
  368. package/src/tools/task-worktree.ts +238 -0
  369. package/src/tools/verify/authoring.ts +116 -55
  370. package/src/tools/verify/scripts.ts +62 -0
  371. package/src/tools/worker-evidence.ts +21 -1
  372. package/src/worker/spec-contract.ts +44 -3
  373. package/dist/chunk-EFADSJET.js +0 -18
  374. package/dist/chunk-HC4CLZ2Y.js +0 -68
  375. package/dist/memory-4ALKDJ4Q.js +0 -246
  376. package/src/domains/eval/metrics/chaos-stream.ts +0 -93
package/src/cli/index.ts CHANGED
@@ -57,14 +57,15 @@ Usage:
57
57
  clio-coder uninstall remove all Clio Coder state; --remove-binary also unlinks the launcher
58
58
  clio-coder upgrade upgrade Clio Coder and run pending migrations
59
59
  clio-coder agents list discovered agent recipes
60
- clio-coder fleet list|run|status|drain|resume fleet contracts, status, and admission control
60
+ clio-coder fleet new|validate|graph|commands|run|status|drain|resume fleet authoring, execution, status, and admission control
61
61
  clio-coder evidence build, list, or inspect evidence artifacts
62
62
  clio-coder eval run, report, or compare local eval task files
63
- clio-coder memory list, propose, approve, reject, or prune memory
63
+ clio-coder memory list, propose, promote, approve, reject, or prune memory
64
64
  clio-coder usage report cross-session usage facts and opportunities (experimental)
65
65
  clio-coder trace query or view the durable dispatch trace mirror
66
66
  clio-coder extensions install, list, enable, disable, or remove extension packages
67
67
  clio-coder skills list, inspect, validate, or install skills
68
+ clio-coder library list, search, add, or sync agents, prompts, fleets, and skills from catalogs
68
69
  clio-coder verifiers discover, author, validate, edit, or dry-run project checks
69
70
  clio-coder docs [topic] serve the HTML docs of a source checkout on 127.0.0.1 (--no-open to skip browser)
70
71
  clio-coder dev <command> harness instruments; run 'clio-coder dev' for the list
@@ -246,6 +247,7 @@ const COMMAND_HANDLERS = new Map<string, CommandHandler>([
246
247
  ["ext", extensionsCommand],
247
248
  ["fleet", async (subArgs) => (await import("./fleet.js")).runFleetCommand(subArgs)],
248
249
  ["skills", async (subArgs) => (await import("./skills.js")).runSkillsCommand(subArgs)],
250
+ ["library", async (subArgs) => (await import("./library.js")).runLibraryCommand(subArgs)],
249
251
  ["verifiers", async (subArgs) => (await import("./verifiers.js")).runVerifiersCommand(subArgs)],
250
252
  ["docs", async (subArgs) => (await import("./docs.js")).runDocsCommand(subArgs)],
251
253
  ["share", async (subArgs) => (await import("./share.js")).runShareCommand(subArgs)],
@@ -0,0 +1,190 @@
1
+ import {
2
+ classifyLibraryRequirements,
3
+ confirmLibraryRemote,
4
+ discoverLibrary,
5
+ installLibraryPlan,
6
+ type LibraryEntry,
7
+ type LibraryEntryKind,
8
+ libraryEntryRef,
9
+ libraryInstallPath,
10
+ planLibraryInstall,
11
+ syncLibrary,
12
+ } from "../domains/resources/index.js";
13
+ import { printError, printOk } from "./shared.js";
14
+
15
+ const KINDS = new Set<LibraryEntryKind>(["skill", "agent", "prompt", "fleet"]);
16
+ const HELP = `clio-coder library <command>
17
+
18
+ Commands:
19
+ clio-coder library list [--kind <kind>] [--json]
20
+ clio-coder library search <query> [--kind <kind>] [--json]
21
+ clio-coder library add <ref> [--from <catalog|path>] [--with-requirements] [--yes] [--json]
22
+ clio-coder library use <kind> <name>
23
+ clio-coder library sync
24
+ clio-coder library push
25
+ clio-coder library remote confirm <url>
26
+ `;
27
+
28
+ interface Parsed {
29
+ command?: string;
30
+ positional: string[];
31
+ kind?: LibraryEntryKind;
32
+ from?: string;
33
+ json: boolean;
34
+ yes: boolean;
35
+ withRequirements: boolean;
36
+ help: boolean;
37
+ }
38
+
39
+ function parse(argv: ReadonlyArray<string>): Parsed {
40
+ const out: Parsed = { positional: [], json: false, yes: false, withRequirements: false, help: false };
41
+ for (let i = 0; i < argv.length; i += 1) {
42
+ const arg = argv[i];
43
+ if (!arg) continue;
44
+ if (!out.command && !arg.startsWith("-")) {
45
+ out.command = arg;
46
+ continue;
47
+ }
48
+ if (arg === "--json") out.json = true;
49
+ else if (arg === "--yes") out.yes = true;
50
+ else if (arg === "--with-requirements") out.withRequirements = true;
51
+ else if (arg === "--help" || arg === "-h") out.help = true;
52
+ else if (arg === "--kind") {
53
+ const value = argv[++i];
54
+ if (!value || !KINDS.has(value as LibraryEntryKind))
55
+ throw new Error("--kind requires skill, agent, prompt, or fleet");
56
+ out.kind = value as LibraryEntryKind;
57
+ } else if (arg === "--from") {
58
+ const value = argv[++i];
59
+ if (!value) throw new Error("--from requires a value");
60
+ out.from = value;
61
+ } else if (arg.startsWith("-")) throw new Error(`unknown flag: ${arg}`);
62
+ else out.positional.push(arg);
63
+ }
64
+ return out;
65
+ }
66
+
67
+ function selectEntry(entries: ReadonlyArray<LibraryEntry>, ref: string): LibraryEntry {
68
+ const matches = ref.includes(":")
69
+ ? entries.filter((entry) => libraryEntryRef(entry) === ref)
70
+ : entries.filter((entry) => entry.name === ref);
71
+ if (matches.length === 0) throw new Error(`library entry not found: ${ref}`);
72
+ if (matches.length > 1)
73
+ throw new Error(`library entry is ambiguous; use a typed reference: ${matches.map(libraryEntryRef).join(", ")}`);
74
+ return matches[0] as LibraryEntry;
75
+ }
76
+
77
+ function filtered(entries: ReadonlyArray<LibraryEntry>, kind?: LibraryEntryKind): LibraryEntry[] {
78
+ return entries.filter((entry) => kind === undefined || entry.kind === kind);
79
+ }
80
+
81
+ export async function runLibraryCommand(argv: ReadonlyArray<string>): Promise<number> {
82
+ let parsed: Parsed;
83
+ try {
84
+ parsed = parse(argv);
85
+ } catch (error) {
86
+ printError(error instanceof Error ? error.message : String(error));
87
+ return 2;
88
+ }
89
+ if (!parsed.command || parsed.help) {
90
+ process.stdout.write(HELP);
91
+ return parsed.help ? 0 : 2;
92
+ }
93
+ try {
94
+ if (parsed.command === "list" || parsed.command === "search") {
95
+ const discovery = discoverLibrary();
96
+ const query = parsed.command === "search" ? parsed.positional.join(" ").trim().toLowerCase() : "";
97
+ if (parsed.command === "search" && !query) throw new Error("library search requires a query");
98
+ const entries = filtered(discovery.entries, parsed.kind).filter(
99
+ (entry) => !query || entry.name.toLowerCase().includes(query) || entry.description.toLowerCase().includes(query),
100
+ );
101
+ if (parsed.json)
102
+ process.stdout.write(`${JSON.stringify({ entries, diagnostics: discovery.diagnostics }, null, 2)}\n`);
103
+ else
104
+ for (const entry of entries) process.stdout.write(`${libraryEntryRef(entry).padEnd(28)} ${entry.description}\n`);
105
+ return 0;
106
+ }
107
+ if (parsed.command === "add") {
108
+ const ref = parsed.positional[0];
109
+ if (!ref || parsed.positional.length !== 1) throw new Error("library add requires one reference");
110
+ const catalog = parsed.from && parsed.from !== "catalog" ? parsed.from : undefined;
111
+ const discovery = discoverLibrary(catalog ? { catalog } : {});
112
+ let entry: LibraryEntry;
113
+ try {
114
+ entry = selectEntry(discovery.entries, ref);
115
+ } catch (error) {
116
+ const refusal = ref.includes(":")
117
+ ? discovery.refusals[ref]
118
+ : Object.entries(discovery.refusals).find(([key]) => key.endsWith(`:${ref}`))?.[1];
119
+ if (refusal) throw new Error(refusal);
120
+ throw error;
121
+ }
122
+ const requirements = classifyLibraryRequirements(entry, discovery.entries);
123
+ if (requirements.unsatisfied.length > 0 && !parsed.withRequirements) {
124
+ const refs = requirements.unsatisfied.map(libraryEntryRef);
125
+ if (parsed.json)
126
+ process.stdout.write(
127
+ `${JSON.stringify({ ok: false, entry: libraryEntryRef(entry), satisfiedRequirements: requirements.satisfied.map(libraryEntryRef), unresolvedRequirements: refs }, null, 2)}\n`,
128
+ );
129
+ else
130
+ process.stderr.write(
131
+ `satisfied requirements: ${requirements.satisfied.length > 0 ? requirements.satisfied.map(libraryEntryRef).join(", ") : "none"}\nunresolved requirements: ${refs.join(", ")}\npass --with-requirements to install them in dependency order\n`,
132
+ );
133
+ return 1;
134
+ }
135
+ const plans = [...(parsed.withRequirements ? requirements.unsatisfied : []), entry].map(planLibraryInstall);
136
+ if (parsed.json)
137
+ process.stdout.write(
138
+ `${JSON.stringify({ ok: true, confirmed: parsed.yes, satisfiedRequirements: requirements.satisfied.map(libraryEntryRef), writes: plans.map((plan) => ({ ref: libraryEntryRef(plan.entry), path: plan.path, sha256: plan.sha256 })) }, null, 2)}\n`,
139
+ );
140
+ else {
141
+ process.stdout.write("library add plan:\n");
142
+ process.stdout.write(
143
+ ` satisfied requirements: ${requirements.satisfied.length > 0 ? requirements.satisfied.map(libraryEntryRef).join(", ") : "none"}\n`,
144
+ );
145
+ for (const plan of plans)
146
+ process.stdout.write(` ${libraryEntryRef(plan.entry)} -> ${plan.path} sha256 ${plan.sha256}\n`);
147
+ }
148
+ if (!parsed.yes) return 0;
149
+ for (const plan of plans) installLibraryPlan(plan);
150
+ if (!parsed.json) printOk(`installed ${plans.length} library entry or entries`);
151
+ return 0;
152
+ }
153
+ if (parsed.command === "use") {
154
+ const kind = parsed.positional[0] as LibraryEntryKind | undefined;
155
+ const name = parsed.positional[1];
156
+ if (!kind || !KINDS.has(kind) || !name || parsed.positional.length !== 2)
157
+ throw new Error("library use requires a kind and name");
158
+ // A skill is loaded by the operator from the Skills Hub, never by a CLI
159
+ // verb, so the honest answer names where it lives and how to load it.
160
+ const output =
161
+ kind === "fleet"
162
+ ? `clio-coder fleet run ${name}`
163
+ : kind === "agent"
164
+ ? `/run ${name}`
165
+ : kind === "skill"
166
+ ? `${libraryInstallPath({ kind, name })}\nload it from /skill in the TUI, or ask the model to call context(scope="skills")`
167
+ : name;
168
+ process.stdout.write(`${output}\n`);
169
+ return 0;
170
+ }
171
+ if (parsed.command === "remote") {
172
+ if (parsed.positional[0] !== "confirm" || !parsed.positional[1] || parsed.positional.length !== 2)
173
+ throw new Error("library remote confirm requires a URL");
174
+ confirmLibraryRemote(parsed.positional[1]);
175
+ printOk("confirmed library remote");
176
+ return 0;
177
+ }
178
+ if (parsed.command === "sync" || parsed.command === "push") {
179
+ await syncLibrary(parsed.command);
180
+ printOk(`library ${parsed.command} complete`);
181
+ return 0;
182
+ }
183
+ throw new Error(`unknown library command: ${parsed.command}`);
184
+ } catch (error) {
185
+ const message = error instanceof Error ? error.message : String(error);
186
+ printError(message);
187
+ if (parsed.json) process.stdout.write(`${JSON.stringify({ ok: false, error: message }, null, 2)}\n`);
188
+ return 1;
189
+ }
190
+ }
package/src/cli/memory.ts CHANGED
@@ -1,36 +1,62 @@
1
+ import { readFile, stat } from "node:fs/promises";
1
2
  import { clioDataDir } from "../core/xdg.js";
2
3
  import {
3
4
  approveMemoryRecord,
5
+ canonicalMemoryRepositoryIdentity,
4
6
  loadMemoryRecords,
5
7
  type MemoryRecord,
8
+ type MemoryScopeSelection,
9
+ memoryAgentIdentity,
10
+ memoryRuntimeIdentity,
6
11
  memoryStatus,
12
+ parseTaskMemoryHandoffSnapshot,
7
13
  proposeMemoryFromEvidence,
14
+ proposeMemoryPromotion,
8
15
  pruneStaleMemory,
16
+ type ReviewedTaskMemoryHandoffSnapshot,
9
17
  rejectMemoryRecord,
18
+ type TaskMemoryHandoffEntry,
10
19
  } from "../domains/memory/index.js";
11
20
  import { printError, printOk } from "./shared.js";
12
21
 
13
22
  const HELP = `clio-coder memory list
14
- clio-coder memory propose --from-evidence <evidenceId>
23
+ clio-coder memory propose --from-evidence <evidenceId> [scope options]
24
+ clio-coder memory promote --from-handoff <path> [--entry <id>...] --scope <scope> [scope options]
15
25
  clio-coder memory approve <memoryId>
16
26
  clio-coder memory reject <memoryId>
17
27
  clio-coder memory prune --stale
18
28
 
19
29
  Manage scoped, approved, evidence-linked local memory records.
30
+
31
+ Scope options:
32
+ --scope repo --repository <canonical-absolute-path>
33
+ --scope global --acknowledge-global
34
+ --scope runtime --runtime <source-runtime-id>
35
+ --scope agent --agent <source-agent-id>
36
+
37
+ Omit scope options from propose to preserve evidence-inferred scope. Promotion
38
+ always requires an explicit scope and creates unapproved records for review.
20
39
  `;
21
40
 
22
- type MemoryCommand = "list" | "propose" | "approve" | "reject" | "prune";
41
+ type MemoryCommand = "list" | "propose" | "promote" | "approve" | "reject" | "prune";
23
42
 
24
43
  interface ParsedMemoryArgs {
25
44
  command?: MemoryCommand;
26
45
  evidenceId?: string;
46
+ handoffPath?: string;
47
+ entryIds: string[];
27
48
  memoryId?: string;
49
+ scope?: "repo" | "global" | "runtime" | "agent";
50
+ repositoryPath?: string;
51
+ acknowledgeGlobal: boolean;
52
+ runtimeId?: string;
53
+ agentId?: string;
28
54
  stale: boolean;
29
55
  help: boolean;
30
56
  }
31
57
 
32
58
  function parseMemoryArgs(args: ReadonlyArray<string>): ParsedMemoryArgs {
33
- const parsed: ParsedMemoryArgs = { stale: false, help: false };
59
+ const parsed: ParsedMemoryArgs = { entryIds: [], acknowledgeGlobal: false, stale: false, help: false };
34
60
  for (let index = 0; index < args.length; index += 1) {
35
61
  const arg = args[index];
36
62
  if (arg === undefined) continue;
@@ -39,21 +65,70 @@ function parseMemoryArgs(args: ReadonlyArray<string>): ParsedMemoryArgs {
39
65
  continue;
40
66
  }
41
67
  if (parsed.command === undefined) {
42
- if (arg === "list" || arg === "propose" || arg === "approve" || arg === "reject" || arg === "prune") {
68
+ if (
69
+ arg === "list" ||
70
+ arg === "propose" ||
71
+ arg === "promote" ||
72
+ arg === "approve" ||
73
+ arg === "reject" ||
74
+ arg === "prune"
75
+ ) {
43
76
  parsed.command = arg;
44
77
  continue;
45
78
  }
46
79
  throw new Error(`unknown memory command: ${arg}`);
47
80
  }
48
- if (parsed.command === "propose") {
81
+ if (parsed.command === "propose" || parsed.command === "promote") {
49
82
  if (arg === "--from-evidence") {
83
+ if (parsed.command !== "propose") throw new Error("--from-evidence is valid only for memory propose");
50
84
  const value = args[index + 1];
51
85
  if (value === undefined || value.startsWith("-")) throw new Error("--from-evidence requires an evidence id");
52
86
  parsed.evidenceId = value;
53
87
  index += 1;
54
88
  continue;
55
89
  }
56
- throw new Error(`unknown memory propose argument: ${arg}`);
90
+ if (arg === "--from-handoff") {
91
+ if (parsed.command !== "promote") throw new Error("--from-handoff is valid only for memory promote");
92
+ const value = requireOptionValue(args, index, "--from-handoff", "a path");
93
+ parsed.handoffPath = value;
94
+ index += 1;
95
+ continue;
96
+ }
97
+ if (arg === "--entry") {
98
+ if (parsed.command !== "promote") throw new Error("--entry is valid only for memory promote");
99
+ parsed.entryIds.push(requireOptionValue(args, index, "--entry", "an entry id"));
100
+ index += 1;
101
+ continue;
102
+ }
103
+ if (arg === "--scope") {
104
+ const value = requireOptionValue(args, index, "--scope", "repo, global, runtime, or agent");
105
+ if (value !== "repo" && value !== "global" && value !== "runtime" && value !== "agent") {
106
+ throw new Error("--scope requires repo, global, runtime, or agent");
107
+ }
108
+ parsed.scope = value;
109
+ index += 1;
110
+ continue;
111
+ }
112
+ if (arg === "--repository") {
113
+ parsed.repositoryPath = requireOptionValue(args, index, "--repository", "a canonical absolute path");
114
+ index += 1;
115
+ continue;
116
+ }
117
+ if (arg === "--acknowledge-global") {
118
+ parsed.acknowledgeGlobal = true;
119
+ continue;
120
+ }
121
+ if (arg === "--runtime") {
122
+ parsed.runtimeId = requireOptionValue(args, index, "--runtime", "a runtime id");
123
+ index += 1;
124
+ continue;
125
+ }
126
+ if (arg === "--agent") {
127
+ parsed.agentId = requireOptionValue(args, index, "--agent", "an agent id");
128
+ index += 1;
129
+ continue;
130
+ }
131
+ throw new Error(`unknown memory ${parsed.command} argument: ${arg}`);
57
132
  }
58
133
  if (parsed.command === "approve" || parsed.command === "reject") {
59
134
  if (parsed.memoryId === undefined && !arg.startsWith("-")) {
@@ -72,20 +147,79 @@ function parseMemoryArgs(args: ReadonlyArray<string>): ParsedMemoryArgs {
72
147
  throw new Error(`unexpected memory argument: ${arg}`);
73
148
  }
74
149
  if (parsed.help) return parsed;
75
- if (parsed.command === undefined) throw new Error("memory requires list, propose, approve, reject, or prune");
150
+ if (parsed.command === undefined) throw new Error("memory requires list, propose, promote, approve, reject, or prune");
76
151
  if (parsed.command === "propose" && parsed.evidenceId === undefined) {
77
152
  throw new Error("propose requires --from-evidence <evidenceId>");
78
153
  }
154
+ if (parsed.command === "promote" && parsed.handoffPath === undefined) {
155
+ throw new Error("promote requires --from-handoff <path>");
156
+ }
79
157
  if ((parsed.command === "approve" || parsed.command === "reject") && parsed.memoryId === undefined) {
80
158
  throw new Error(`${parsed.command} requires a memory id`);
81
159
  }
82
160
  if (parsed.command === "prune" && !parsed.stale) throw new Error("prune requires --stale");
83
- if (parsed.command === "list" && (parsed.evidenceId !== undefined || parsed.memoryId !== undefined || parsed.stale)) {
161
+ if (parsed.command === "promote" && parsed.scope === undefined) {
162
+ throw new Error("promote requires --scope <repo|global|runtime|agent>");
163
+ }
164
+ validateScopeArguments(parsed);
165
+ if (
166
+ parsed.command === "list" &&
167
+ (parsed.evidenceId !== undefined ||
168
+ parsed.handoffPath !== undefined ||
169
+ parsed.entryIds.length > 0 ||
170
+ parsed.memoryId !== undefined ||
171
+ parsed.stale ||
172
+ parsed.scope !== undefined)
173
+ ) {
84
174
  throw new Error("list does not accept extra arguments");
85
175
  }
86
176
  return parsed;
87
177
  }
88
178
 
179
+ function requireOptionValue(args: ReadonlyArray<string>, index: number, option: string, expected: string): string {
180
+ const value = args[index + 1];
181
+ if (value === undefined || value.startsWith("-")) throw new Error(`${option} requires ${expected}`);
182
+ return value;
183
+ }
184
+
185
+ function validateScopeArguments(parsed: ParsedMemoryArgs): void {
186
+ const hasIdentityOption =
187
+ parsed.repositoryPath !== undefined ||
188
+ parsed.acknowledgeGlobal ||
189
+ parsed.runtimeId !== undefined ||
190
+ parsed.agentId !== undefined;
191
+ if (parsed.scope === undefined) {
192
+ if (hasIdentityOption) throw new Error("scope identity options require --scope");
193
+ return;
194
+ }
195
+ if (parsed.scope === "repo") {
196
+ if (parsed.repositoryPath === undefined)
197
+ throw new Error("repo scope requires --repository <canonical-absolute-path>");
198
+ if (parsed.acknowledgeGlobal || parsed.runtimeId !== undefined || parsed.agentId !== undefined) {
199
+ throw new Error("repo scope accepts only --repository");
200
+ }
201
+ return;
202
+ }
203
+ if (parsed.scope === "global") {
204
+ if (!parsed.acknowledgeGlobal) throw new Error("global scope requires --acknowledge-global");
205
+ if (parsed.repositoryPath !== undefined || parsed.runtimeId !== undefined || parsed.agentId !== undefined) {
206
+ throw new Error("global scope accepts only --acknowledge-global");
207
+ }
208
+ return;
209
+ }
210
+ if (parsed.scope === "runtime") {
211
+ if (parsed.runtimeId === undefined) throw new Error("runtime scope requires --runtime <source-runtime-id>");
212
+ if (parsed.repositoryPath !== undefined || parsed.acknowledgeGlobal || parsed.agentId !== undefined) {
213
+ throw new Error("runtime scope accepts only --runtime");
214
+ }
215
+ return;
216
+ }
217
+ if (parsed.agentId === undefined) throw new Error("agent scope requires --agent <source-agent-id>");
218
+ if (parsed.repositoryPath !== undefined || parsed.acknowledgeGlobal || parsed.runtimeId !== undefined) {
219
+ throw new Error("agent scope accepts only --agent");
220
+ }
221
+ }
222
+
89
223
  export async function runMemoryCommand(args: ReadonlyArray<string>): Promise<number> {
90
224
  let parsed: ParsedMemoryArgs;
91
225
  try {
@@ -114,10 +248,40 @@ export async function runMemoryCommand(args: ReadonlyArray<string>): Promise<num
114
248
  printError("propose requires --from-evidence <evidenceId>");
115
249
  return 2;
116
250
  }
117
- const result = await proposeMemoryFromEvidence(dataDir, evidenceId);
251
+ const result = await proposeMemoryFromEvidence(dataDir, evidenceId, scopeSelection(parsed));
118
252
  renderProposal(result.record, result.created);
119
253
  return 0;
120
254
  }
255
+ if (parsed.command === "promote") {
256
+ const handoffPath = parsed.handoffPath;
257
+ const selection = scopeSelection(parsed);
258
+ if (handoffPath === undefined || selection === undefined) {
259
+ printError("promote requires a handoff and explicit scope");
260
+ return 2;
261
+ }
262
+ const snapshot = await readReviewedHandoff(handoffPath);
263
+ const entries = selectHandoffEntries(snapshot, parsed.entryIds);
264
+ for (const entry of entries) {
265
+ const result = await proposeMemoryPromotion(
266
+ dataDir,
267
+ {
268
+ kind: "handoff-snapshot",
269
+ sessionId: snapshot.source.sessionId,
270
+ evidenceRefs: snapshot.source.evidenceRefs,
271
+ runtimeIds: snapshot.source.runtimeIds,
272
+ agentIds: snapshot.source.agentIds,
273
+ entry: handoffTaskEntry(entry),
274
+ redaction: {
275
+ replacementCount: snapshot.redaction.replacementCount,
276
+ sourceFields: snapshot.redaction.sourceFields,
277
+ },
278
+ },
279
+ selection,
280
+ );
281
+ renderProposal(result.record, result.created);
282
+ }
283
+ return 0;
284
+ }
121
285
  if (parsed.command === "approve") {
122
286
  const memoryId = parsed.memoryId;
123
287
  if (memoryId === undefined) {
@@ -143,7 +307,7 @@ export async function runMemoryCommand(args: ReadonlyArray<string>): Promise<num
143
307
  printOk(`pruned ${pruned.length} stale memory record${pruned.length === 1 ? "" : "s"}`);
144
308
  return 0;
145
309
  }
146
- printError("memory requires list, propose, approve, reject, or prune");
310
+ printError("memory requires list, propose, promote, approve, reject, or prune");
147
311
  return 2;
148
312
  } catch (error) {
149
313
  printError(error instanceof Error ? error.message : String(error));
@@ -151,14 +315,112 @@ export async function runMemoryCommand(args: ReadonlyArray<string>): Promise<num
151
315
  }
152
316
  }
153
317
 
318
+ function scopeSelection(parsed: ParsedMemoryArgs): MemoryScopeSelection | undefined {
319
+ if (parsed.scope === undefined) return undefined;
320
+ if (parsed.scope === "repo") {
321
+ const repositoryPath = parsed.repositoryPath;
322
+ if (repositoryPath === undefined) throw new Error("repo scope requires --repository");
323
+ const repository = canonicalMemoryRepositoryIdentity(repositoryPath);
324
+ if (repository === null || repository.key !== repositoryPath) {
325
+ throw new Error("--repository must be an existing canonical absolute repository path");
326
+ }
327
+ return { scope: "repo", repository };
328
+ }
329
+ if (parsed.scope === "global") {
330
+ if (!parsed.acknowledgeGlobal) throw new Error("global scope requires --acknowledge-global");
331
+ return { scope: "global", acknowledgeGlobal: true };
332
+ }
333
+ if (parsed.scope === "runtime") {
334
+ if (parsed.runtimeId === undefined) throw new Error("runtime scope requires --runtime");
335
+ return { scope: "runtime", runtime: memoryRuntimeIdentity(parsed.runtimeId) };
336
+ }
337
+ if (parsed.agentId === undefined) throw new Error("agent scope requires --agent");
338
+ return { scope: "agent", agent: memoryAgentIdentity(parsed.agentId) };
339
+ }
340
+
341
+ async function readReviewedHandoff(path: string): Promise<ReviewedTaskMemoryHandoffSnapshot> {
342
+ const info = await stat(path);
343
+ if (!info.isFile()) throw new Error(`task-memory handoff is not a file: ${path}`);
344
+ if (info.size > 1_000_000) throw new Error(`task-memory handoff exceeds 1000000 bytes: ${path}`);
345
+ const snapshot = parseTaskMemoryHandoffSnapshot(await readFile(path, "utf8"));
346
+ if (snapshot === null) throw new Error(`task-memory handoff is invalid: ${path}`);
347
+ if (snapshot.version !== 2) {
348
+ throw new Error("task-memory handoff lacks source session and evidence provenance; create a new redacted handoff");
349
+ }
350
+ return snapshot;
351
+ }
352
+
353
+ interface SelectedHandoffEntry {
354
+ kind: "knowledge" | "procedural";
355
+ entry: TaskMemoryHandoffEntry;
356
+ }
357
+
358
+ function selectHandoffEntries(
359
+ snapshot: ReviewedTaskMemoryHandoffSnapshot,
360
+ entryIds: ReadonlyArray<string>,
361
+ ): SelectedHandoffEntry[] {
362
+ const entries: SelectedHandoffEntry[] = [
363
+ ...snapshot.knowledge.map((entry) => ({ kind: "knowledge" as const, entry })),
364
+ ...snapshot.procedural.map((entry) => ({ kind: "procedural" as const, entry })),
365
+ ];
366
+ if (entries.length === 0) throw new Error("task-memory handoff contains no promotable entries");
367
+ if (entryIds.length === 0) return entries;
368
+ const requested = new Set(entryIds);
369
+ const selected = entries.filter(({ entry }) => requested.has(entry.id));
370
+ const missing = [...requested].filter((id) => !selected.some(({ entry }) => entry.id === id));
371
+ if (missing.length > 0) throw new Error(`task-memory handoff entry not found: ${missing.join(", ")}`);
372
+ return selected;
373
+ }
374
+
375
+ function handoffTaskEntry(selected: SelectedHandoffEntry): {
376
+ id: string;
377
+ kind: "knowledge" | "procedural";
378
+ content: string;
379
+ createdAt: string;
380
+ lastTouchedAt: string;
381
+ injectionCount: number;
382
+ } {
383
+ const createdAt = selected.entry.createdAt;
384
+ const lastTouchedAt = selected.entry.lastTouchedAt;
385
+ if (createdAt === undefined || lastTouchedAt === undefined) {
386
+ throw new Error(`task-memory handoff entry lacks timestamps: ${selected.entry.id}`);
387
+ }
388
+ return {
389
+ id: selected.entry.id,
390
+ kind: selected.kind,
391
+ content: selected.entry.content,
392
+ createdAt,
393
+ lastTouchedAt,
394
+ injectionCount: selected.entry.injectionCount,
395
+ };
396
+ }
397
+
154
398
  function renderProposal(record: MemoryRecord, created: boolean): void {
155
399
  process.stdout.write(`memory: ${record.id}\n`);
156
400
  process.stdout.write(`status: ${created ? "proposed" : memoryStatus(record)}\n`);
157
401
  process.stdout.write(`scope: ${record.scope}\n`);
402
+ if (record.repository !== undefined) process.stdout.write(`repository: ${record.repository.key}\n`);
403
+ if (record.runtime !== undefined) process.stdout.write(`runtime: ${record.runtime.key}\n`);
404
+ if (record.agent !== undefined) process.stdout.write(`agent: ${record.agent.key}\n`);
158
405
  process.stdout.write(`key: ${record.key}\n`);
159
406
  process.stdout.write(`evidence: ${record.evidenceRefs.join(", ")}\n`);
160
407
  process.stdout.write(`confidence: ${record.confidence.toFixed(2)}\n`);
161
408
  process.stdout.write(`lesson: ${record.lesson}\n`);
409
+ if (record.provenance !== undefined) {
410
+ process.stdout.write(`source: ${record.provenance.sourceKind}\n`);
411
+ if (record.provenance.sourceSessionId !== undefined) {
412
+ process.stdout.write(`source-session: ${record.provenance.sourceSessionId}\n`);
413
+ }
414
+ if (record.provenance.sourceEntryId !== undefined) {
415
+ process.stdout.write(`source-entry: ${record.provenance.sourceEntryId}\n`);
416
+ }
417
+ if (record.provenance.redaction !== undefined) {
418
+ process.stdout.write(
419
+ `redaction: ${record.provenance.redaction.replacementCount} replacement${record.provenance.redaction.replacementCount === 1 ? "" : "s"}; fields=${record.provenance.redaction.sourceFields.join(",") || "none"}\n`,
420
+ );
421
+ }
422
+ }
423
+ process.stdout.write(`review: clio-coder memory approve ${record.id}\n`);
162
424
  }
163
425
 
164
426
  function renderMemoryList(records: ReadonlyArray<MemoryRecord>): void {
@@ -4,8 +4,8 @@
4
4
  * The stream is append-oriented: it carries each piece of content exactly
5
5
  * once, as an increment while it streams and as one completed message when it
6
6
  * lands. It never repeats the growing snapshot of an in-progress message,
7
- * because that is quadratic in a long turn. One tool-heavy SciCode sub-step
8
- * wrote 802 MB of stdout, 99.3% of it `message_update` snapshots of a message
7
+ * because that is quadratic in a long turn. One tool-heavy headless turn wrote
8
+ * 802 MB of stdout, 99.3% of it `message_update` snapshots of a message
9
9
  * whose final form is 44 KB.
10
10
  *
11
11
  * The rules, in one place:
@@ -1,4 +1,8 @@
1
1
  import { readClioVersion, readPiMonoVersion } from "../../core/package-root.js";
2
+ import {
3
+ addResponseModelIdObservationCounts,
4
+ emptyResponseModelIdObservationCounts,
5
+ } from "../../core/response-model-id.js";
2
6
  import { withRunOverrides } from "../../core/run-overrides.js";
3
7
  import {
4
8
  type PendingSkillRequest,
@@ -187,6 +191,10 @@ function recordToolEnd(stats: HeadlessMainAgentReceiptStats, event: ChatLoopEven
187
191
  }
188
192
 
189
193
  function addRunUsage(left: RunUsageSummary, right: RunUsageSummary): RunUsageSummary {
194
+ const responseModelIdObservationCounts = emptyResponseModelIdObservationCounts();
195
+ addResponseModelIdObservationCounts(responseModelIdObservationCounts, left.responseModelIdObservationCounts);
196
+ addResponseModelIdObservationCounts(responseModelIdObservationCounts, right.responseModelIdObservationCounts);
197
+ const last = right.hadUsage ? right : left;
190
198
  return {
191
199
  tokens: left.tokens + right.tokens,
192
200
  costUsd: left.costUsd + right.costUsd,
@@ -197,7 +205,10 @@ function addRunUsage(left: RunUsageSummary, right: RunUsageSummary): RunUsageSum
197
205
  reasoning: left.reasoning + right.reasoning,
198
206
  apiCalls: left.apiCalls + right.apiCalls,
199
207
  hadReasoning: left.hadReasoning || right.hadReasoning,
200
- hadUsage: true,
208
+ hadUsage: left.hadUsage || right.hadUsage,
209
+ responseModelIdObservationCounts,
210
+ lastResponseModelIdObservation: last.lastResponseModelIdObservation,
211
+ lastDifferingResponseModelId: last.lastDifferingResponseModelId,
201
212
  };
202
213
  }
203
214