@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
@@ -1,13 +1,5 @@
1
1
  import { spawn } from "node:child_process";
2
2
  import { performance } from "node:perf_hooks";
3
- import {
4
- addChaosObservations,
5
- chaosMetricEntries,
6
- createChaosFold,
7
- EMPTY_CHAOS_OBSERVATION,
8
- type EvalChaosObservation,
9
- parseChaosMarker,
10
- } from "../metrics/chaos-stream.js";
11
3
  import {
12
4
  addFleetLoopObservations,
13
5
  createFleetLoopFold,
@@ -53,8 +45,6 @@ export interface ShellCommandResult {
53
45
  usage: EvalTokenStreamUsage;
54
46
  /** Wire-stream structural invariants folded live, for the same reason. */
55
47
  streamInvariants: EvalStreamInvariants;
56
- /** Strict SIGINT harness marker folded live from stdout. */
57
- chaos: EvalChaosObservation;
58
48
  fleetLoops: EvalFleetLoopObservation;
59
49
  stderr: string;
60
50
  wallTimeMs: number;
@@ -84,7 +74,6 @@ export async function runExternalCommandRunner(
84
74
  // is reported as unmeasured, never as zero cost.
85
75
  let usage = UNMEASURED_TOKEN_USAGE;
86
76
  let streamInvariants = EMPTY_STREAM_INVARIANTS;
87
- let chaos = EMPTY_CHAOS_OBSERVATION;
88
77
  let fleetLoops = EMPTY_FLEET_LOOP_OBSERVATION;
89
78
  for (const command of commands) {
90
79
  const result = await runShellCommand(command, cwd, runner.timeoutMs ?? timeoutMs, env);
@@ -93,7 +82,6 @@ export async function runExternalCommandRunner(
93
82
  wallTimeMs += result.wallTimeMs;
94
83
  usage = addTokenStreamUsage(usage, result.usage);
95
84
  streamInvariants = addStreamInvariants(streamInvariants, result.streamInvariants);
96
- chaos = addChaosObservations(chaos, result.chaos);
97
85
  fleetLoops = addFleetLoopObservations(fleetLoops, result.fleetLoops);
98
86
  if (result.exitCode !== 0) {
99
87
  return {
@@ -107,11 +95,10 @@ export async function runExternalCommandRunner(
107
95
  "latency.wallMs": wallTimeMs,
108
96
  ...tokenMetricEntries(usage),
109
97
  ...streamInvariantMetrics(streamInvariants),
110
- ...chaosMetricEntries(chaos),
111
98
  ...fleetLoopMetricEntries(fleetLoops),
112
99
  "verifier.exitCode": result.exitCode,
113
100
  },
114
- artifacts: chaosArtifacts(chaos),
101
+ artifacts: {},
115
102
  };
116
103
  }
117
104
  }
@@ -126,11 +113,10 @@ export async function runExternalCommandRunner(
126
113
  "latency.wallMs": wallTimeMs,
127
114
  ...tokenMetricEntries(usage),
128
115
  ...streamInvariantMetrics(streamInvariants),
129
- ...chaosMetricEntries(chaos),
130
116
  ...fleetLoopMetricEntries(fleetLoops),
131
117
  "verifier.exitCode": 0,
132
118
  },
133
- artifacts: chaosArtifacts(chaos),
119
+ artifacts: {},
134
120
  };
135
121
  }
136
122
 
@@ -150,7 +136,6 @@ export function runShellCommand(
150
136
  const metricCapture = createJsonlMetricCapture();
151
137
  const usageFold = createTokenUsageFold();
152
138
  const streamFold = createStreamInvariantFold();
153
- const chaosFold = createChaosFold();
154
139
  const fleetLoopFold = createFleetLoopFold();
155
140
  let timedOut = false;
156
141
  let settled = false;
@@ -169,7 +154,6 @@ export function runShellCommand(
169
154
  metricCapture.push(chunk);
170
155
  usageFold.push(chunk);
171
156
  streamFold.push(chunk);
172
- chaosFold.push(chunk);
173
157
  fleetLoopFold.push(chunk);
174
158
  });
175
159
  child.stderr.on("data", (chunk: string) => {
@@ -191,7 +175,6 @@ export function runShellCommand(
191
175
  metricJsonl: metricCapture.finish(),
192
176
  usage: usageFold.usage(),
193
177
  streamInvariants: streamFold.invariants(),
194
- chaos: chaosFold.observation(),
195
178
  fleetLoops: fleetLoopFold.observation(),
196
179
  stderr,
197
180
  wallTimeMs: Math.round(performance.now() - started),
@@ -290,10 +273,6 @@ export function createJsonlMetricCapture(): JsonlMetricCapture {
290
273
 
291
274
  function compactMetricEvent(event: Record<string, unknown>): Record<string, unknown> | null {
292
275
  const type = event.type;
293
- if (type === "clio_soak_chaos") {
294
- const marker = parseChaosMarker(event);
295
- return marker === null ? null : { type, ...marker };
296
- }
297
276
  if (type === "tool_execution_start") {
298
277
  const toolName = stringField(event, "toolName");
299
278
  if (toolName !== "dispatch" && toolName !== "code_nav" && toolName !== "read" && toolName !== "grep") {
@@ -334,12 +313,6 @@ function compactMetricEvent(event: Record<string, unknown>): Record<string, unkn
334
313
  };
335
314
  }
336
315
 
337
- function chaosArtifacts(observation: EvalChaosObservation): Record<string, string> {
338
- return observation.markerCount === 1 && observation.marker !== null
339
- ? { chaosSeed: String(observation.marker.seed) }
340
- : {};
341
- }
342
-
343
316
  function isRecord(value: unknown): value is Record<string, unknown> {
344
317
  return typeof value === "object" && value !== null && !Array.isArray(value);
345
318
  }
@@ -43,13 +43,6 @@ export const CANONICAL_METRICS = [
43
43
  "evidence.verification",
44
44
  "evidence.firstPassSuccess",
45
45
  "cost.usd",
46
- // Behavioral checkpoints for the bounded reconnaissance live suite.
47
- "dispatch.count",
48
- "wiki.staleAcknowledged",
49
- // SIGINT chaos-harness facts folded live from its one strict stdout marker.
50
- "chaos.seed",
51
- "chaos.faultInjected",
52
- "chaos.exitCode",
53
46
  // Invariant checks: what Clio promised about its own machinery, read from
54
47
  // the journal the item's run left behind. These are true or false about
55
48
  // Clio and say nothing about whether the model solved the task. A check
@@ -126,7 +126,7 @@ async function runMatrixItem(
126
126
  CLIO_CODER_ENTRY: clioEntry,
127
127
  });
128
128
  const patch = collectPatchMetrics(workspace.dir);
129
- const receiptExitCode = receiptProcessExitCode(runner);
129
+ const receiptExitCode = runner.exitCode;
130
130
  // Read after the runner returned and before the journal is removed: what
131
131
  // Clio sealed for this item, judged against its own ledger, and whether
132
132
  // the workers it attested are still running.
@@ -193,12 +193,6 @@ async function runMatrixItem(
193
193
  }
194
194
  }
195
195
 
196
- /** A SIGINT harness exits cleanly after checking the nested Clio process; reconcile its receipt to that nested exit. */
197
- export function receiptProcessExitCode(runner: Pick<EvalRunnerOutput, "exitCode" | "metrics">): number {
198
- const chaosExitCode = runner.metrics["chaos.exitCode"];
199
- return typeof chaosExitCode === "number" && Number.isInteger(chaosExitCode) ? chaosExitCode : runner.exitCode;
200
- }
201
-
202
196
  /** Journal-derived invariants for one finished item, read from its isolated state directory. */
203
197
  function invariantMetrics(stateDir: string, runnerExitCode: number): Record<string, number | boolean> {
204
198
  const journal = readRunJournal(stateDir);
@@ -418,6 +418,7 @@ export type PersistedRunReceiptTrustFacts = Pick<RunReceipt, "runId"> &
418
418
  RunReceipt,
419
419
  | "integrity"
420
420
  | "verification"
421
+ | "hostVerification"
421
422
  | "quality"
422
423
  | "validationGrounding"
423
424
  | "briefing"
@@ -536,6 +537,12 @@ export function adaptRunReceiptValidationStatus(
536
537
  ): ValidationGroundingStatus {
537
538
  if (receipt === null || receipt === undefined) return absentTrustStatus("artifact_missing");
538
539
  const artifacts = validationArtifacts(receipt);
540
+ if (receipt.hostVerification?.status === "rejected") {
541
+ return attributed("failed", receiptSource(receipt), { kind: "validator", id: "host-verification" }, artifacts);
542
+ }
543
+ if (receipt.hostVerification?.status === "verified") {
544
+ return attributed("validated", receiptSource(receipt), { kind: "validator", id: "host-verification" }, artifacts);
545
+ }
539
546
  if (qualityHasFailure(receipt.quality)) {
540
547
  return attributed("failed", receiptSource(receipt), { kind: "validator", id: "receipt-quality" }, artifacts);
541
548
  }
@@ -549,7 +556,9 @@ export function adaptRunReceiptValidationStatus(
549
556
  if (qualityHasValidation(receipt.quality)) {
550
557
  return attributed("validated", receiptSource(receipt), { kind: "validator", id: "receipt-quality" }, artifacts);
551
558
  }
552
- if (receipt.verification !== undefined) return verificationStatus(receipt.verification, receipt, artifacts);
559
+ if (receipt.verification !== undefined) {
560
+ return verificationStatus(receipt.verification, receipt, artifacts);
561
+ }
553
562
  return attributed("unknown", compatibilitySource(receipt, "verification"), COMPATIBILITY_AUTHORITY, artifacts);
554
563
  }
555
564
 
@@ -6,6 +6,20 @@ export {
6
6
  rejectMemoryRecord,
7
7
  selectApprovedMemory,
8
8
  } from "./operations.js";
9
+ export {
10
+ applyScopeIdentity,
11
+ MEMORY_PROMOTION_SCOPES,
12
+ type MemoryPromotionScope,
13
+ type MemoryPromotionSource,
14
+ type MemoryPromotionSourceRedaction,
15
+ type MemoryScopeSelection,
16
+ memoryAgentIdentity,
17
+ memoryRecordFromPromotion,
18
+ memoryRuntimeIdentity,
19
+ memoryScopeIdentityKey,
20
+ proposeMemoryPromotion,
21
+ validateMemoryScopeSelection,
22
+ } from "./promotion.js";
9
23
  export {
10
24
  buildMemoryPromptSection,
11
25
  MEMORY_PROMPT_DEFAULT_MAX_ITEMS,
@@ -46,7 +60,9 @@ export {
46
60
  type TaskMemorySnapshot,
47
61
  } from "./task-bank.js";
48
62
  export {
63
+ type LegacyTaskMemoryHandoffSnapshot,
49
64
  parseTaskMemoryHandoffSnapshot,
65
+ type ReviewedTaskMemoryHandoffSnapshot,
50
66
  readNewestTaskMemoryHandoff,
51
67
  renderTaskMemoryHandoffSnapshot,
52
68
  renderTaskMemoryHandoffSource,
@@ -57,9 +73,11 @@ export {
57
73
  type TaskMemoryHandoffArtifact,
58
74
  type TaskMemoryHandoffEntry,
59
75
  type TaskMemoryHandoffOffer,
76
+ type TaskMemoryHandoffRedaction,
60
77
  type TaskMemoryHandoffSeedOutcome,
61
78
  type TaskMemoryHandoffSeedResult,
62
79
  type TaskMemoryHandoffSnapshot,
80
+ type TaskMemoryHandoffSourceProvenance,
63
81
  taskMemoryHandoffSeedOffer,
64
82
  taskMemoryHandoffSnapshot,
65
83
  } from "./task-memory-handoff.js";
@@ -112,12 +130,16 @@ export {
112
130
  taskMemoryTracePath,
113
131
  } from "./task-memory-trace.js";
114
132
  export type {
133
+ MemoryAgentIdentity,
134
+ MemoryPromotionRedaction,
115
135
  MemoryProposalResult,
116
136
  MemoryPruneResult,
117
137
  MemoryRecord,
138
+ MemoryRecordProvenance,
118
139
  MemoryRecordValidationResult,
119
140
  MemoryRepositoryIdentity,
120
141
  MemoryRetrievalOptions,
142
+ MemoryRuntimeIdentity,
121
143
  MemoryScope,
122
144
  MemoryStatus,
123
145
  MemoryStoreFile,
@@ -2,7 +2,13 @@ import { isAbsolute } from "node:path";
2
2
  import { canonicalizeExistingPath } from "../../core/path-canonical.js";
3
3
  import { ceilChars } from "../session/context-accounting.js";
4
4
  import { pruneStaleMemoryRecords, sortMemoryRecords, updateMemoryRecord } from "./store.js";
5
- import type { MemoryRecord, MemoryRepositoryIdentity, MemoryRetrievalOptions } from "./types.js";
5
+ import type {
6
+ MemoryAgentIdentity,
7
+ MemoryRecord,
8
+ MemoryRepositoryIdentity,
9
+ MemoryRetrievalOptions,
10
+ MemoryRuntimeIdentity,
11
+ } from "./types.js";
6
12
 
7
13
  export async function approveMemoryRecord(
8
14
  dataDir: string,
@@ -31,12 +37,16 @@ export function selectApprovedMemory(
31
37
  if (options.tokenBudget <= 0) return [];
32
38
  const allowedScopes = options.scopes === undefined ? null : new Set(options.scopes);
33
39
  const activeRepository = canonicalActiveRepository(options.activeRepository);
40
+ const activeRuntime = validActiveNamedIdentity(options.activeRuntime, "runtime");
41
+ const activeAgent = validActiveNamedIdentity(options.activeAgent, "agent");
34
42
  const candidates = sortMemoryRecords(records)
35
43
  .filter((record) => record.approved)
36
44
  .filter((record) => record.evidenceRefs.length > 0)
37
45
  .filter((record) => record.regressions === undefined || record.regressions.length === 0)
38
46
  .filter((record) => allowedScopes === null || allowedScopes.has(record.scope))
39
47
  .filter((record) => repositoryApplies(record, activeRepository))
48
+ .filter((record) => runtimeApplies(record, activeRuntime))
49
+ .filter((record) => agentApplies(record, activeAgent))
40
50
  .sort(compareRetrievalPriority);
41
51
  const selected: MemoryRecord[] = [];
42
52
  let spent = 0;
@@ -55,6 +65,8 @@ export function estimateMemoryTokens(record: MemoryRecord): number {
55
65
  record.key,
56
66
  record.lesson,
57
67
  ...(record.repository === undefined ? [] : [record.repository.kind, record.repository.key]),
68
+ ...(record.runtime === undefined ? [] : [record.runtime.kind, record.runtime.key]),
69
+ ...(record.agent === undefined ? [] : [record.agent.kind, record.agent.key]),
58
70
  ...record.evidenceRefs,
59
71
  ...record.appliesWhen,
60
72
  ...record.avoidWhen,
@@ -80,6 +92,21 @@ function cloneRecord(record: MemoryRecord): MemoryRecord {
80
92
  if (record.regressions !== undefined) next.regressions = [...record.regressions];
81
93
  if (record.rejectedAt !== undefined) next.rejectedAt = record.rejectedAt;
82
94
  if (record.repository !== undefined) next.repository = { ...record.repository };
95
+ if (record.runtime !== undefined) next.runtime = { ...record.runtime };
96
+ if (record.agent !== undefined) next.agent = { ...record.agent };
97
+ if (record.provenance !== undefined) {
98
+ next.provenance = {
99
+ ...record.provenance,
100
+ ...(record.provenance.redaction === undefined
101
+ ? {}
102
+ : {
103
+ redaction: {
104
+ ...record.provenance.redaction,
105
+ sourceFields: [...record.provenance.redaction.sourceFields],
106
+ },
107
+ }),
108
+ };
109
+ }
83
110
  return next;
84
111
  }
85
112
 
@@ -115,6 +142,36 @@ function repositoryApplies(record: MemoryRecord, activeRepository: MemoryReposit
115
142
  return record.repository.kind === activeRepository.kind && record.repository.key === activeRepository.key;
116
143
  }
117
144
 
145
+ function runtimeApplies(record: MemoryRecord, activeRuntime: MemoryRuntimeIdentity | null): boolean {
146
+ if (record.scope !== "runtime") return true;
147
+ if (activeRuntime === null || record.runtime === undefined) return false;
148
+ return record.runtime.kind === activeRuntime.kind && record.runtime.key === activeRuntime.key;
149
+ }
150
+
151
+ function agentApplies(record: MemoryRecord, activeAgent: MemoryAgentIdentity | null): boolean {
152
+ if (record.scope !== "agent") return true;
153
+ if (activeAgent === null || record.agent === undefined) return false;
154
+ return record.agent.kind === activeAgent.kind && record.agent.key === activeAgent.key;
155
+ }
156
+
157
+ function validActiveNamedIdentity<T extends "runtime" | "agent">(
158
+ identity: { kind: T; key: string } | null | undefined,
159
+ kind: T,
160
+ ): { kind: T; key: string } | null {
161
+ if (
162
+ identity === null ||
163
+ identity === undefined ||
164
+ identity.kind !== kind ||
165
+ identity.key.length === 0 ||
166
+ identity.key.length > 256 ||
167
+ identity.key.trim() !== identity.key ||
168
+ /[\0\r\n\t ]/u.test(identity.key)
169
+ ) {
170
+ return null;
171
+ }
172
+ return { kind, key: identity.key };
173
+ }
174
+
118
175
  function isUsableAbsoluteRepositoryPath(value: string): boolean {
119
176
  return value.length > 0 && !/[\0\r\n]/u.test(value) && isAbsolute(value);
120
177
  }
@@ -0,0 +1,281 @@
1
+ import { createHash } from "node:crypto";
2
+ import { createRedactionTally, redactSecretsText } from "../evidence/redact.js";
3
+ import { canonicalMemoryRepositoryIdentity } from "./operations.js";
4
+ import { loadMemoryRecords, upsertMemoryRecord } from "./store.js";
5
+ import type { TaskMemoryEntry, TaskMemoryRenderableClass } from "./task-bank.js";
6
+ import type {
7
+ MemoryAgentIdentity,
8
+ MemoryProposalResult,
9
+ MemoryRecord,
10
+ MemoryRepositoryIdentity,
11
+ MemoryRuntimeIdentity,
12
+ } from "./types.js";
13
+ import { validateMemoryRecord } from "./validate.js";
14
+
15
+ export const MEMORY_PROMOTION_SCOPES = ["repo", "global", "runtime", "agent"] as const;
16
+ export type MemoryPromotionScope = (typeof MEMORY_PROMOTION_SCOPES)[number];
17
+
18
+ export type MemoryScopeSelection =
19
+ | { scope: "repo"; repository: MemoryRepositoryIdentity }
20
+ | { scope: "global"; acknowledgeGlobal: true }
21
+ | { scope: "runtime"; runtime: MemoryRuntimeIdentity }
22
+ | { scope: "agent"; agent: MemoryAgentIdentity };
23
+
24
+ export interface MemoryPromotionSourceRedaction {
25
+ replacementCount: number;
26
+ sourceFields: ReadonlyArray<string>;
27
+ }
28
+
29
+ export interface MemoryPromotionSource {
30
+ kind: "task-bank-entry" | "handoff-snapshot";
31
+ sessionId: string;
32
+ evidenceRefs: ReadonlyArray<string>;
33
+ entry: TaskMemoryEntry;
34
+ runtimeIds?: ReadonlyArray<string>;
35
+ agentIds?: ReadonlyArray<string>;
36
+ redaction?: MemoryPromotionSourceRedaction;
37
+ }
38
+
39
+ interface ScopeSourceIdentities {
40
+ runtimeIds?: ReadonlyArray<string>;
41
+ agentIds?: ReadonlyArray<string>;
42
+ }
43
+
44
+ /**
45
+ * Validate an operator-selected scope without inferring or widening it.
46
+ * Runtime and agent scopes must name identities carried by the source.
47
+ */
48
+ export function validateMemoryScopeSelection(
49
+ selection: MemoryScopeSelection,
50
+ source: ScopeSourceIdentities,
51
+ ): MemoryScopeSelection {
52
+ switch (selection.scope) {
53
+ case "repo": {
54
+ const repository = canonicalMemoryRepositoryIdentity(selection.repository.key);
55
+ if (
56
+ selection.repository.kind !== "canonical-path" ||
57
+ repository === null ||
58
+ repository.key !== selection.repository.key
59
+ ) {
60
+ throw new Error("repo scope requires an existing canonical absolute repository identity");
61
+ }
62
+ return { scope: "repo", repository };
63
+ }
64
+ case "global":
65
+ if (selection.acknowledgeGlobal !== true) {
66
+ throw new Error("global scope requires a separate operator acknowledgement");
67
+ }
68
+ return selection;
69
+ case "runtime": {
70
+ const runtime = normalizeNamedIdentity(selection.runtime, "runtime");
71
+ if (!(source.runtimeIds ?? []).includes(runtime.key)) {
72
+ throw new Error(`runtime identity '${runtime.key}' does not match the promotion source`);
73
+ }
74
+ return { scope: "runtime", runtime };
75
+ }
76
+ case "agent": {
77
+ const agent = normalizeNamedIdentity(selection.agent, "agent");
78
+ if (!(source.agentIds ?? []).includes(agent.key)) {
79
+ throw new Error(`agent identity '${agent.key}' does not match the promotion source`);
80
+ }
81
+ return { scope: "agent", agent };
82
+ }
83
+ }
84
+ }
85
+
86
+ export function memoryRuntimeIdentity(key: string): MemoryRuntimeIdentity {
87
+ return normalizeNamedIdentity({ kind: "runtime", key }, "runtime");
88
+ }
89
+
90
+ export function memoryAgentIdentity(key: string): MemoryAgentIdentity {
91
+ return normalizeNamedIdentity({ kind: "agent", key }, "agent");
92
+ }
93
+
94
+ /** Create one reviewable proposal from a selected non-private task-bank entry. */
95
+ export async function proposeMemoryPromotion(
96
+ dataDir: string,
97
+ source: MemoryPromotionSource,
98
+ selection: MemoryScopeSelection,
99
+ now: Date = new Date(),
100
+ ): Promise<MemoryProposalResult> {
101
+ validatePromotionSource(source);
102
+ const validatedScope = validateMemoryScopeSelection(selection, {
103
+ runtimeIds: source.runtimeIds ?? [],
104
+ agentIds: source.agentIds ?? [],
105
+ });
106
+ const record = memoryRecordFromPromotion(source, validatedScope, now);
107
+ const existing = (await loadMemoryRecords(dataDir)).find((candidate) => candidate.id === record.id);
108
+ if (existing !== undefined) return { record: existing, created: false };
109
+ await upsertMemoryRecord(dataDir, record);
110
+ return { record, created: true };
111
+ }
112
+
113
+ export function memoryRecordFromPromotion(
114
+ source: MemoryPromotionSource,
115
+ selection: MemoryScopeSelection,
116
+ now: Date = new Date(),
117
+ ): MemoryRecord {
118
+ validatePromotionSource(source);
119
+ const entryKind = source.entry.kind;
120
+ if (entryKind === "status") throw new Error("private task-memory status cannot be promoted");
121
+ const validatedScope = validateMemoryScopeSelection(selection, {
122
+ runtimeIds: source.runtimeIds ?? [],
123
+ agentIds: source.agentIds ?? [],
124
+ });
125
+ const tally = createRedactionTally();
126
+ const lesson = redactPromotionText(source.entry.content, tally).replace(/\s+/gu, " ").trim();
127
+ const sourceFields = new Set(source.redaction?.sourceFields ?? []);
128
+ if (lesson !== source.entry.content) sourceFields.add("content");
129
+ const replacementCount = (source.redaction?.replacementCount ?? 0) + tally.count;
130
+ const scopeKey = memoryScopeIdentityKey(validatedScope);
131
+ const record: MemoryRecord = {
132
+ id: promotedMemoryId({
133
+ sourceKind: source.kind,
134
+ sessionId: source.sessionId,
135
+ entryId: source.entry.id,
136
+ entryKind,
137
+ evidenceRefs: uniqueStrings(source.evidenceRefs),
138
+ lesson,
139
+ scopeKey,
140
+ }),
141
+ scope: validatedScope.scope,
142
+ key: `promotion:${source.kind}:${source.sessionId}:${source.entry.id}`,
143
+ lesson,
144
+ evidenceRefs: uniqueStrings(source.evidenceRefs),
145
+ appliesWhen: scopeApplicability(validatedScope),
146
+ avoidWhen: [],
147
+ confidence: 0.6,
148
+ createdAt: now.toISOString(),
149
+ approved: false,
150
+ provenance: {
151
+ sourceKind: source.kind,
152
+ sourceSessionId: source.sessionId,
153
+ sourceEntryId: source.entry.id,
154
+ sourceEntryKind: entryKind,
155
+ sourceEntryCreatedAt: source.entry.createdAt,
156
+ sourceEntryLastTouchedAt: source.entry.lastTouchedAt,
157
+ redaction: {
158
+ appliedBeforePersistence: true,
159
+ replacementCount,
160
+ sourceFields: [...sourceFields].sort(compareStrings),
161
+ },
162
+ },
163
+ };
164
+ applyScopeIdentity(record, validatedScope);
165
+ const validated = validateMemoryRecord(record);
166
+ if (!validated.valid) {
167
+ throw new Error(
168
+ `promoted memory record invalid: ${validated.issues.map((issue) => `${issue.path}: ${issue.message}`).join("; ")}`,
169
+ );
170
+ }
171
+ return validated.record;
172
+ }
173
+
174
+ export function applyScopeIdentity(record: MemoryRecord, selection: MemoryScopeSelection): void {
175
+ if (selection.scope === "repo") record.repository = { ...selection.repository };
176
+ if (selection.scope === "runtime") record.runtime = { ...selection.runtime };
177
+ if (selection.scope === "agent") record.agent = { ...selection.agent };
178
+ }
179
+
180
+ export function memoryScopeIdentityKey(selection: MemoryScopeSelection): string {
181
+ switch (selection.scope) {
182
+ case "repo":
183
+ return `repo:${selection.repository.kind}:${selection.repository.key}`;
184
+ case "global":
185
+ return "global:acknowledged";
186
+ case "runtime":
187
+ return `runtime:${selection.runtime.key}`;
188
+ case "agent":
189
+ return `agent:${selection.agent.key}`;
190
+ }
191
+ }
192
+
193
+ function validatePromotionSource(source: MemoryPromotionSource): void {
194
+ if (!validSourceValue(source.sessionId)) throw new Error("promotion requires a valid source session id");
195
+ if (source.evidenceRefs.length === 0 || source.evidenceRefs.some((value) => !validSourceValue(value))) {
196
+ throw new Error("promotion requires at least one valid source evidence ref");
197
+ }
198
+ if (source.entry.kind === "status") throw new Error("private task-memory status cannot be promoted");
199
+ if (source.entry.kind !== "knowledge" && source.entry.kind !== "procedural") {
200
+ throw new Error("promotion requires a knowledge or procedural task-memory entry");
201
+ }
202
+ if (!validSourceValue(source.entry.id) || source.entry.content.trim().length === 0) {
203
+ throw new Error("promotion requires a valid task-memory entry");
204
+ }
205
+ for (const runtimeId of source.runtimeIds ?? []) memoryRuntimeIdentity(runtimeId);
206
+ for (const agentId of source.agentIds ?? []) memoryAgentIdentity(agentId);
207
+ if (source.redaction !== undefined) {
208
+ if (!Number.isInteger(source.redaction.replacementCount) || source.redaction.replacementCount < 0) {
209
+ throw new Error("promotion source redaction count must be a non-negative integer");
210
+ }
211
+ if (source.redaction.sourceFields.some((field) => !validSourceValue(field))) {
212
+ throw new Error("promotion source redaction fields must be valid non-empty strings");
213
+ }
214
+ }
215
+ }
216
+
217
+ function normalizeNamedIdentity<T extends "runtime" | "agent">(
218
+ identity: { kind: T; key: string },
219
+ kind: T,
220
+ ): { kind: T; key: string } {
221
+ if (identity.kind !== kind || !validNamedIdentityKey(identity.key)) {
222
+ throw new Error(`${kind} scope requires a valid ${kind} identity`);
223
+ }
224
+ return { kind, key: identity.key };
225
+ }
226
+
227
+ function validNamedIdentityKey(value: string): boolean {
228
+ return value.length > 0 && value.length <= 256 && value.trim() === value && !/[\0\r\n\t ]/u.test(value);
229
+ }
230
+
231
+ function validSourceValue(value: string): boolean {
232
+ return value.length > 0 && value.length <= 1_024 && value.trim() === value && !/[\0\r\n]/u.test(value);
233
+ }
234
+
235
+ function scopeApplicability(selection: MemoryScopeSelection): string[] {
236
+ switch (selection.scope) {
237
+ case "repo":
238
+ return [`repository:${selection.repository.kind}:${selection.repository.key}`];
239
+ case "global":
240
+ return [];
241
+ case "runtime":
242
+ return [`runtime:${selection.runtime.key}`];
243
+ case "agent":
244
+ return [`agent:${selection.agent.key}`];
245
+ }
246
+ }
247
+
248
+ function promotedMemoryId(value: {
249
+ sourceKind: MemoryPromotionSource["kind"];
250
+ sessionId: string;
251
+ entryId: string;
252
+ entryKind: TaskMemoryRenderableClass;
253
+ evidenceRefs: string[];
254
+ lesson: string;
255
+ scopeKey: string;
256
+ }): string {
257
+ const digest = createHash("sha256").update(JSON.stringify(value), "utf8").digest("hex").slice(0, 16);
258
+ return `mem-${digest}`;
259
+ }
260
+
261
+ function uniqueStrings(values: ReadonlyArray<string>): string[] {
262
+ return [...new Set(values)].sort(compareStrings);
263
+ }
264
+
265
+ function redactPromotionText(text: string, tally: ReturnType<typeof createRedactionTally>): string {
266
+ const markers: string[] = [];
267
+ const masked = text.replace(/\[redacted:[a-z-]+\]/gu, (marker) => {
268
+ const token = `\uE000${String.fromCharCode(0xe100 + markers.length)}`;
269
+ markers.push(marker);
270
+ return token;
271
+ });
272
+ let redacted = redactSecretsText(masked, tally);
273
+ for (let index = 0; index < markers.length; index += 1) {
274
+ redacted = redacted.replaceAll(`\uE000${String.fromCharCode(0xe100 + index)}`, markers[index] ?? "");
275
+ }
276
+ return redacted;
277
+ }
278
+
279
+ function compareStrings(left: string, right: string): number {
280
+ return left < right ? -1 : left > right ? 1 : 0;
281
+ }
@@ -1,5 +1,11 @@
1
1
  import { estimateMemoryTokens, selectApprovedMemory } from "./operations.js";
2
- import type { MemoryRecord, MemoryRepositoryIdentity, MemoryScope } from "./types.js";
2
+ import type {
3
+ MemoryAgentIdentity,
4
+ MemoryRecord,
5
+ MemoryRepositoryIdentity,
6
+ MemoryRuntimeIdentity,
7
+ MemoryScope,
8
+ } from "./types.js";
3
9
 
4
10
  export const MEMORY_PROMPT_DEFAULT_TOKEN_BUDGET = 400;
5
11
  export const MEMORY_PROMPT_DEFAULT_MAX_ITEMS = 5;
@@ -20,6 +26,10 @@ export interface MemoryPromptOptions {
20
26
  maxItems?: number;
21
27
  /** Missing or unknown identity leaves global memory eligible but excludes repo memory. */
22
28
  activeRepository?: MemoryRepositoryIdentity | null;
29
+ /** Missing or unknown identity excludes runtime-scoped memory. */
30
+ activeRuntime?: MemoryRuntimeIdentity | null;
31
+ /** Missing or unknown identity excludes agent-scoped memory. */
32
+ activeAgent?: MemoryAgentIdentity | null;
23
33
  }
24
34
 
25
35
  /**
@@ -40,6 +50,8 @@ export function selectMemoryForPrompt(
40
50
  scopes,
41
51
  tokenBudget,
42
52
  activeRepository: options.activeRepository ?? null,
53
+ activeRuntime: options.activeRuntime ?? null,
54
+ activeAgent: options.activeAgent ?? null,
43
55
  });
44
56
  return selected.slice(0, maxItems);
45
57
  }
@@ -67,11 +79,19 @@ export function renderMemoryPromptSection(records: ReadonlyArray<MemoryRecord>):
67
79
  }
68
80
 
69
81
  function renderApplicability(record: MemoryRecord): string {
70
- if (record.scope !== "repo") return `scope=${record.scope}`;
71
- if (record.repository !== undefined) {
72
- return `scope=repo, repository=${JSON.stringify(`${record.repository.kind}:${record.repository.key}`)}`;
82
+ if (record.scope === "repo") {
83
+ if (record.repository !== undefined) {
84
+ return `scope=repo, repository=${JSON.stringify(`${record.repository.kind}:${record.repository.key}`)}`;
85
+ }
86
+ return "scope=repo, repository=unknown";
73
87
  }
74
- return "scope=repo, repository=unknown";
88
+ if (record.scope === "runtime") {
89
+ return `scope=runtime, runtime=${JSON.stringify(record.runtime?.key ?? "unknown")}`;
90
+ }
91
+ if (record.scope === "agent") {
92
+ return `scope=agent, agent=${JSON.stringify(record.agent?.key ?? "unknown")}`;
93
+ }
94
+ return `scope=${record.scope}`;
75
95
  }
76
96
 
77
97
  /** Convenience for callers that want a single end-to-end build step. */