@iowarp/clio-coder 0.3.3 → 0.3.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (370) hide show
  1. package/CHANGELOG.md +74 -0
  2. package/CONTRIBUTING.md +7 -7
  3. package/README.md +3 -3
  4. package/dist/{acp-P2AQILE2.js → acp-2BEHC4DL.js} +9 -8
  5. package/dist/{agents-72W3BI7I.js → agents-LNNFTM53.js} +29 -24
  6. package/dist/assets/codewiki.json +1 -1
  7. package/dist/{auth-5TWEIYDN.js → auth-KXXFI2VS.js} +14 -10
  8. package/dist/{chunk-GGXXDWE4.js → chunk-22NAGB7X.js} +2 -2
  9. package/dist/{chunk-YCWGATWI.js → chunk-24I7BN55.js} +2 -2
  10. package/dist/{chunk-EKMEHE4H.js → chunk-33YXPOE3.js} +2 -3
  11. package/dist/chunk-3BPUFZDL.js +37 -0
  12. package/dist/chunk-43AOLP7E.js +375 -0
  13. package/dist/{chunk-ZDOOVTXZ.js → chunk-4OC57DA6.js} +27 -4
  14. package/dist/{chunk-6SGHMWE3.js → chunk-5JGRAMKL.js} +5 -5
  15. package/dist/{chunk-V6RTAOC2.js → chunk-6US73PDB.js} +572 -51
  16. package/dist/{chunk-5UFT4SUX.js → chunk-6XXKFVSN.js} +3 -3
  17. package/dist/{chunk-A3CYT5EX.js → chunk-AD2SYQYC.js} +55 -2
  18. package/dist/chunk-AOCYTWAV.js +449 -0
  19. package/dist/chunk-CFGTUFWB.js +67 -0
  20. package/dist/chunk-CJUB2JJ2.js +1478 -0
  21. package/dist/{chunk-FNTMWMX5.js → chunk-CKXWIANG.js} +14 -12
  22. package/dist/{chunk-PIWWS5BL.js → chunk-CYQKWTG3.js} +63 -78
  23. package/dist/{chunk-LZSJBIVT.js → chunk-DJVECN66.js} +271 -762
  24. package/dist/{chunk-CBCAPZAA.js → chunk-E25LMLRW.js} +2 -2
  25. package/dist/{chunk-ZWMF7253.js → chunk-E2ER4LJF.js} +304 -9
  26. package/dist/{chunk-STBPMHSX.js → chunk-EKY57CSP.js} +51 -84
  27. package/dist/{chunk-DUYJ5IO6.js → chunk-EYPA3EGJ.js} +12 -4
  28. package/dist/{chunk-M6SHUN7Q.js → chunk-FO5ZOVUY.js} +2 -2
  29. package/dist/chunk-FYYLNIL5.js +313 -0
  30. package/dist/{chunk-OQ33BKR3.js → chunk-G7MUEIGA.js} +3 -60
  31. package/dist/chunk-GEYXPTRF.js +613 -0
  32. package/dist/chunk-GOXNB3AO.js +261 -0
  33. package/dist/{chunk-G4BMMOKF.js → chunk-HVDIIIQW.js} +2 -2
  34. package/dist/chunk-HWUFFB6L.js +83 -0
  35. package/dist/{chunk-4XUGQOHA.js → chunk-K7T3E2SR.js} +15 -8
  36. package/dist/chunk-K7VKOLQQ.js +15 -0
  37. package/dist/{chunk-UFIIWP2H.js → chunk-KHSFENX2.js} +8 -8
  38. package/dist/{chunk-BMEMKKIT.js → chunk-KOHPCX4K.js} +2 -2
  39. package/dist/chunk-LCGCVYZ4.js +57 -0
  40. package/dist/chunk-LL4KHSZI.js +22 -0
  41. package/dist/{chunk-PAJK6MAQ.js → chunk-LYF7OHWH.js} +42 -15
  42. package/dist/{chunk-POHLU5DW.js → chunk-M6L6IDJG.js} +3 -3
  43. package/dist/{chunk-5UUP6MWO.js → chunk-MV3K5QF2.js} +5 -436
  44. package/dist/{chunk-X4RCMKVQ.js → chunk-NDINPTJ4.js} +2 -2
  45. package/dist/{chunk-TZK7PACC.js → chunk-NILBFAPG.js} +14 -8
  46. package/dist/chunk-ODFEOB4F.js +1082 -0
  47. package/dist/{chunk-AGYYIBLL.js → chunk-OH3TOQTB.js} +6 -2
  48. package/dist/chunk-OZNBF4L3.js +23 -0
  49. package/dist/{chunk-DSELYM6W.js → chunk-PBTHKCPN.js} +30 -10
  50. package/dist/{verify-375KUB3Y.js → chunk-PCZJO5TI.js} +127 -42
  51. package/dist/{chunk-ED4KHGC3.js → chunk-PPAMZ32Z.js} +9 -2
  52. package/dist/{chunk-SRDMMSEP.js → chunk-QM3F2GKX.js} +1063 -1645
  53. package/dist/{chunk-X6IAEBZR.js → chunk-QNQHSOLF.js} +7 -7
  54. package/dist/{chunk-OC7FIQPC.js → chunk-R46L2BIR.js} +10 -7
  55. package/dist/{chunk-2TLUCQVG.js → chunk-RD5U66HV.js} +3 -3
  56. package/dist/{chunk-6N5PTWMY.js → chunk-RY3LY4J5.js} +50 -13
  57. package/dist/{chunk-OKGUZO2U.js → chunk-SPULKLCF.js} +4 -3
  58. package/dist/{chunk-OOJYHWRB.js → chunk-TSHXZTOQ.js} +6 -5
  59. package/dist/chunk-TZSKNMZG.js +434 -0
  60. package/dist/{chunk-7MNJORFF.js → chunk-UL3WSD3F.js} +6 -1
  61. package/dist/{chunk-VJWL6YS5.js → chunk-UUVG37B4.js} +2 -2
  62. package/dist/{chunk-COU2UHX6.js → chunk-VEZEGCGW.js} +170 -2
  63. package/dist/chunk-W6GROXXM.js +69 -0
  64. package/dist/{chunk-OAO4GE4M.js → chunk-WHGPSPT5.js} +2 -2
  65. package/dist/chunk-WHJYKASB.js +677 -0
  66. package/dist/{chunk-ORBHGJC5.js → chunk-WR67VIZY.js} +3 -3
  67. package/dist/{chunk-YHZX5GEU.js → chunk-XAKHZX5N.js} +2 -2
  68. package/dist/{chunk-TZTZS7QK.js → chunk-XE2VEJHX.js} +5 -3
  69. package/dist/{chunk-LM5TQCJZ.js → chunk-XF5N4U5A.js} +8 -7
  70. package/dist/{chunk-LWLEKMDQ.js → chunk-XXQNGV4M.js} +1073 -552
  71. package/dist/{chunk-KZWTDYJF.js → chunk-XYDYPRZI.js} +7 -7
  72. package/dist/chunk-ZGVHUX3M.js +66 -0
  73. package/dist/{chunk-LW6DSM3M.js → chunk-ZRGEBJ4T.js} +1192 -1119
  74. package/dist/{chunk-2DJ2KNFG.js → chunk-ZXF4XRKW.js} +202 -40
  75. package/dist/chunk-ZZMN5OM4.js +122 -0
  76. package/dist/cli/index.js +34 -30
  77. package/dist/{clio-JOU4FXVA.js → clio-M2KGYUFZ.js} +7 -6
  78. package/dist/{code-nav-7AX6FYE6.js → code-nav-GQNL7XA6.js} +8 -6
  79. package/dist/codewiki/build-worker.js +4 -4
  80. package/dist/{components-KELWS457.js → components-5TTYYX6G.js} +3 -3
  81. package/dist/{config-XCDVKR23.js → config-XUUYQIWO.js} +47 -35
  82. package/dist/{configure-4GAP54ZW.js → configure-IHJ7YOMV.js} +18 -15
  83. package/dist/{context-77FM5DV5.js → context-74JLXAWD.js} +18 -10
  84. package/dist/{context-4UOGGLQ5.js → context-75MIWW3U.js} +41 -29
  85. package/dist/{context-5VKGUVJJ.js → context-ZQ7SIFJV.js} +85 -9
  86. package/dist/{context-clear-XXJRLCJJ.js → context-clear-GYKWNUML.js} +41 -29
  87. package/dist/{context-index-BZ4UYMTC.js → context-index-SSR5ECNE.js} +3 -3
  88. package/dist/context-working-set-UX5KEP4J.js +1553 -0
  89. package/dist/{dispatch-runner-QPRDDBDX.js → dispatch-runner-GIJBHNFL.js} +47 -32
  90. package/dist/{docs-2C2LTVT2.js → docs-6FZSCG5B.js} +3 -3
  91. package/dist/{doctor-HR46URBJ.js → doctor-SVJ5BZCW.js} +12 -12
  92. package/dist/{eval-XSSNATB4.js → eval-CG6LLBLD.js} +54 -238
  93. package/dist/{evidence-6HG2PY2B.js → evidence-ZYFIEN42.js} +57 -28
  94. package/dist/{evolve-K7YU3NCY.js → evolve-QGEXEMDW.js} +36 -25
  95. package/dist/{extensions-QVDOHDGJ.js → extensions-ADGNCJJD.js} +3 -3
  96. package/dist/{fleet-VY3HHKN6.js → fleet-S5R4ZOQY.js} +73 -44
  97. package/dist/{fleet-preflight-DDN536IT.js → fleet-preflight-BHSNPBMH.js} +3 -3
  98. package/dist/{init-JYGXI3FK.js → init-5DRU55YR.js} +49 -37
  99. package/dist/memory-7YKKR6UC.js +467 -0
  100. package/dist/{models-I5QWSEOM.js → models-ZPOLRU2C.js} +24 -21
  101. package/dist/{monitor-GE4ID3IA.js → monitor-US5F5YGZ.js} +73 -46
  102. package/dist/{orchestrator-EM5MC3HM.js → orchestrator-E2AL4T5N.js} +1624 -1007
  103. package/dist/{paths-UXLN5YYZ.js → paths-E7KYAQWE.js} +3 -3
  104. package/dist/{reset-L2FQEE3E.js → reset-KZ652EK6.js} +6 -5
  105. package/dist/{run-ZU3QMZPZ.js → run-SRNBKDWD.js} +76 -54
  106. package/dist/{share-S5BZQC5I.js → share-CGZE33UP.js} +7 -6
  107. package/dist/{skills-X5VXCRNQ.js → skills-S2X4DLY5.js} +4 -4
  108. package/dist/{skills-eval-WKIHWTHR.js → skills-eval-W2GGIC4R.js} +40 -29
  109. package/dist/{targets-SNCPI2NR.js → targets-54SWINWB.js} +28 -23
  110. package/dist/{terminal-lease-BNAHVHBS.js → terminal-lease-SAIF2OGY.js} +6 -4
  111. package/dist/{uninstall-FZCQCDKC.js → uninstall-BVLWXKBT.js} +3 -3
  112. package/dist/{upgrade-JQHHPQ4K.js → upgrade-JKAR27XC.js} +20 -19
  113. package/dist/{usage-OR4O5SMZ.js → usage-MSAWCLX4.js} +79 -36
  114. package/dist/verifiers-NCBTHHN2.js +1220 -0
  115. package/dist/verify-X5HDROLA.js +25 -0
  116. package/dist/{wiki-generate-UEXP2ARI.js → wiki-generate-GUSOQ6ZP.js} +50 -37
  117. package/dist/worker/entry.js +90 -70
  118. package/dist/{workspace-G4ZWUIPR.js → workspace-ZJ6BFM3Q.js} +4 -4
  119. package/docs/README.md +8 -7
  120. package/docs/acp.md +1 -1
  121. package/docs/alcf-provider.md +1 -1
  122. package/docs/architecture.md +2 -2
  123. package/docs/artifact-placement.md +1 -2
  124. package/docs/artifact-versions.md +1 -1
  125. package/docs/built-in-agents.md +1 -1
  126. package/docs/capacity-and-scheduling.md +1 -1
  127. package/docs/commands-and-modes.md +60 -26
  128. package/docs/config-knobs-audit.md +1 -2
  129. package/docs/configuration-and-targets.md +26 -1
  130. package/docs/context-engine.md +67 -13
  131. package/docs/context-working-set.md +194 -0
  132. package/docs/development-pipeline.md +1 -1
  133. package/docs/documentation-coverage.md +6 -6
  134. package/docs/documentation-guide.md +7 -6
  135. package/docs/environment-variables.md +2 -1
  136. package/docs/eval-runner.md +1 -1
  137. package/docs/evals-internal.md +4 -32
  138. package/docs/evidence-and-memory.md +139 -7
  139. package/docs/evolution.md +1 -1
  140. package/docs/exit-codes-and-output.md +1 -1
  141. package/docs/extensions-and-sharing.md +2 -2
  142. package/docs/fleet-dispatch.md +49 -8
  143. package/docs/glossary.md +21 -1
  144. package/docs/installation-and-lifecycle.md +2 -2
  145. package/docs/middleware-and-components.md +19 -2
  146. package/docs/model-catalog.md +7 -9
  147. package/docs/observability.md +4 -4
  148. package/docs/proactive-memory.md +26 -16
  149. package/docs/prompt-envelope-and-tools.md +7 -5
  150. package/docs/provider-adapter-cookbook.md +1 -1
  151. package/docs/release-cut-checklist.md +43 -40
  152. package/docs/safety-model.md +49 -8
  153. package/docs/scientific-validation.md +21 -3
  154. package/docs/session-lifecycle.md +3 -3
  155. package/docs/skills-marketplace.md +1 -1
  156. package/docs/tool-usage.md +79 -12
  157. package/docs/trace-store.md +1 -1
  158. package/docs/troubleshooting.md +1 -1
  159. package/docs/tui-design.md +38 -4
  160. package/docs/worker-dispatch-mechanics.md +11 -1
  161. package/package.json +13 -13
  162. package/skills/meta/clio-test/SKILL.md +20 -17
  163. package/skills/meta/clio-test/evals.md +3 -3
  164. package/skills/meta/clio-test/references/harness.md +35 -6
  165. package/skills/meta/clio-test/references/test-map.md +20 -10
  166. package/skills/registry.yaml +2 -2
  167. package/skills/skill-marketplace.json +1 -1
  168. package/src/cli/agents.ts +2 -3
  169. package/src/cli/argv.ts +14 -1
  170. package/src/cli/context-working-set.ts +513 -0
  171. package/src/cli/context.ts +8 -0
  172. package/src/cli/evidence.ts +20 -2
  173. package/src/cli/fleet.ts +15 -0
  174. package/src/cli/index.ts +5 -1
  175. package/src/cli/memory.ts +272 -10
  176. package/src/cli/modes/json-stream.ts +2 -2
  177. package/src/cli/modes/print.ts +12 -1
  178. package/src/cli/run.ts +22 -2
  179. package/src/cli/targets.ts +12 -3
  180. package/src/cli/usage.ts +55 -7
  181. package/src/cli/verifiers.ts +325 -0
  182. package/src/core/bash-exec.ts +39 -14
  183. package/src/core/bus-events.ts +22 -4
  184. package/src/core/config.ts +54 -0
  185. package/src/core/defaults.ts +50 -3
  186. package/src/core/response-model-id.ts +134 -0
  187. package/src/core/toml.ts +62 -0
  188. package/src/core/verification-scripts.ts +6 -0
  189. package/src/core/workspace-files.ts +0 -1
  190. package/src/domains/agents/builtins/architect.md +1 -1
  191. package/src/domains/agents/builtins/verifier.md +3 -0
  192. package/src/domains/agents/catalog.ts +5 -4
  193. package/src/domains/agents/recipe.ts +54 -14
  194. package/src/domains/agents/result-contract.ts +7 -4
  195. package/src/domains/config/classify.ts +1 -0
  196. package/src/domains/context/bootstrap.ts +36 -27
  197. package/src/domains/context/project-metadata.ts +19 -63
  198. package/src/domains/context/prompt-context.ts +8 -0
  199. package/src/domains/context/working-set/contract.ts +161 -0
  200. package/src/domains/context/working-set/defaults.ts +28 -0
  201. package/src/domains/context/working-set/engine.ts +203 -0
  202. package/src/domains/context/working-set/fold.ts +62 -0
  203. package/src/domains/context/working-set/horizon.ts +38 -0
  204. package/src/domains/context/working-set/marker.ts +103 -0
  205. package/src/domains/context/working-set/path-index.ts +436 -0
  206. package/src/domains/context/working-set/payload.ts +152 -0
  207. package/src/domains/context/working-set/policies/age-horizon.ts +55 -0
  208. package/src/domains/context/working-set/policies/index.ts +20 -0
  209. package/src/domains/context/working-set/policies/structural.ts +160 -0
  210. package/src/domains/context/working-set/project.ts +132 -0
  211. package/src/domains/context/working-set/protect.ts +109 -0
  212. package/src/domains/context/working-set/recall.ts +177 -0
  213. package/src/domains/context/working-set/replay/controls.ts +112 -0
  214. package/src/domains/context/working-set/replay/load-clio.ts +199 -0
  215. package/src/domains/context/working-set/replay/metrics.ts +185 -0
  216. package/src/domains/context/working-set/replay/reference-graph.ts +79 -0
  217. package/src/domains/context/working-set/replay/report.ts +139 -0
  218. package/src/domains/context/working-set/replay/runner.ts +325 -0
  219. package/src/domains/context/working-set/replay/synthetic.ts +422 -0
  220. package/src/domains/context/working-set/replay/trace.ts +21 -0
  221. package/src/domains/context/working-set/visible.ts +54 -0
  222. package/src/domains/dispatch/budget-envelope.ts +396 -0
  223. package/src/domains/dispatch/contract.ts +2 -0
  224. package/src/domains/dispatch/extension.ts +81 -27
  225. package/src/domains/dispatch/orphan-recovery.ts +1 -0
  226. package/src/domains/dispatch/receipt-integrity.ts +4 -0
  227. package/src/domains/dispatch/state.ts +1 -0
  228. package/src/domains/dispatch/types.ts +10 -3
  229. package/src/domains/dispatch/validation.ts +14 -0
  230. package/src/domains/dispatch/worker-spawn.ts +14 -3
  231. package/src/domains/eval/metrics/evidence.ts +0 -116
  232. package/src/domains/eval/metrics/invariants.ts +1 -1
  233. package/src/domains/eval/runners/clio-run.ts +1 -10
  234. package/src/domains/eval/runners/external-command.ts +2 -29
  235. package/src/domains/eval/schema/suite.ts +0 -7
  236. package/src/domains/eval/suites/run.ts +1 -7
  237. package/src/domains/evidence/build.ts +112 -45
  238. package/src/domains/evidence/eval.ts +24 -7
  239. package/src/domains/evidence/index.ts +53 -0
  240. package/src/domains/evidence/ordering.ts +12 -0
  241. package/src/domains/evidence/run-trust.ts +221 -0
  242. package/src/domains/evidence/store.ts +46 -6
  243. package/src/domains/evidence/trust-status.ts +854 -0
  244. package/src/domains/evidence/types.ts +26 -0
  245. package/src/domains/memory/index.ts +22 -0
  246. package/src/domains/memory/operations.ts +58 -1
  247. package/src/domains/memory/promotion.ts +281 -0
  248. package/src/domains/memory/prompt-section.ts +25 -5
  249. package/src/domains/memory/proposal.ts +51 -7
  250. package/src/domains/memory/task-bank.ts +3 -2
  251. package/src/domains/memory/task-memory-handoff.ts +181 -24
  252. package/src/domains/memory/task-memory-policy.ts +3 -1
  253. package/src/domains/memory/types.ts +37 -0
  254. package/src/domains/memory/validate.ts +178 -0
  255. package/src/domains/middleware/memory-intervention.ts +38 -25
  256. package/src/domains/middleware/runtime.ts +6 -0
  257. package/src/domains/middleware/skills-reminder.ts +19 -4
  258. package/src/domains/middleware/stalled-turn.ts +208 -5
  259. package/src/domains/middleware/types.ts +10 -0
  260. package/src/domains/observability/contract.ts +6 -1
  261. package/src/domains/observability/cost.ts +20 -4
  262. package/src/domains/observability/extension.ts +2 -2
  263. package/src/domains/providers/index.ts +3 -0
  264. package/src/domains/providers/model-discovery.ts +9 -0
  265. package/src/domains/providers/runtime-resolution.ts +38 -1
  266. package/src/domains/providers/runtimes/common/probe-helpers.ts +97 -16
  267. package/src/domains/providers/types/context-window-slots.ts +18 -0
  268. package/src/domains/providers/types/runtime-descriptor.ts +3 -1
  269. package/src/domains/safety/autonomy.ts +1 -1
  270. package/src/domains/safety/call-target.ts +211 -14
  271. package/src/domains/safety/decision-presentation.ts +268 -0
  272. package/src/domains/safety/default-path-policy.ts +8 -0
  273. package/src/domains/safety/finish-contract.ts +4 -3
  274. package/src/domains/safety/policy-engine.ts +48 -6
  275. package/src/domains/safety/redaction.ts +73 -0
  276. package/src/domains/session/compaction/compact.ts +23 -1
  277. package/src/domains/session/compaction/cut-point.ts +2 -0
  278. package/src/domains/session/compaction/tokens.ts +16 -1
  279. package/src/domains/session/context-ledger.ts +12 -1
  280. package/src/domains/session/decision-board.ts +4 -0
  281. package/src/domains/session/entries.ts +110 -1
  282. package/src/domains/session/history.ts +68 -19
  283. package/src/domains/session/manager.ts +9 -2
  284. package/src/domains/session/migrations/index.ts +22 -3
  285. package/src/domains/session/usage.ts +24 -7
  286. package/src/engine/acp/event-mapper.ts +7 -0
  287. package/src/engine/acp/server.ts +32 -2
  288. package/src/engine/agent.ts +18 -1
  289. package/src/engine/apis/lmstudio.ts +25 -4
  290. package/src/engine/apis/openai-completions.ts +147 -22
  291. package/src/engine/claude/sdk-runtime.ts +8 -2
  292. package/src/engine/claude/tool-safety.ts +13 -0
  293. package/src/engine/loop-guard.ts +27 -3
  294. package/src/engine/session.ts +9 -3
  295. package/src/engine/worker-events.ts +4 -3
  296. package/src/engine/worker-runtime.ts +59 -54
  297. package/src/entry/orchestrator.ts +34 -5
  298. package/src/interactive/chat-loop-messages.ts +40 -6
  299. package/src/interactive/chat-loop.ts +13 -0
  300. package/src/interactive/chat-panel.ts +17 -1
  301. package/src/interactive/chat-renderer.ts +49 -24
  302. package/src/interactive/clio-editor.ts +44 -7
  303. package/src/interactive/context-meter.ts +10 -0
  304. package/src/interactive/context-overlay.ts +120 -7
  305. package/src/interactive/context-recall-command.ts +110 -0
  306. package/src/interactive/cost-overlay.ts +39 -8
  307. package/src/interactive/dispatch-board.ts +212 -35
  308. package/src/interactive/footer/widgets.ts +13 -0
  309. package/src/interactive/interactive-application.ts +6 -1
  310. package/src/interactive/interactive-input-runtime.ts +11 -1
  311. package/src/interactive/interactive-presentation.ts +11 -1
  312. package/src/interactive/interactive-slash-runtime.ts +37 -1
  313. package/src/interactive/memory-overlay.ts +89 -4
  314. package/src/interactive/model-session-replay.ts +21 -0
  315. package/src/interactive/overlay-ask-user-lifecycle.ts +1 -1
  316. package/src/interactive/overlay-frame.ts +5 -2
  317. package/src/interactive/overlay-general-openers.ts +46 -1
  318. package/src/interactive/overlay-key-routing.ts +41 -1
  319. package/src/interactive/overlay-lifecycle.ts +11 -4
  320. package/src/interactive/overlay-permission-lifecycle.ts +23 -8
  321. package/src/interactive/overlay-session-lifecycle.ts +8 -4
  322. package/src/interactive/overlay-transitions.ts +11 -0
  323. package/src/interactive/overlays/ask-user.ts +74 -30
  324. package/src/interactive/overlays/decisions.ts +3 -1
  325. package/src/interactive/permission-hint.ts +35 -0
  326. package/src/interactive/permission-overlay.ts +95 -45
  327. package/src/interactive/renderers/tool-execution.ts +37 -51
  328. package/src/interactive/session-last-turn.ts +8 -1
  329. package/src/interactive/session-transcript.ts +2 -2
  330. package/src/interactive/session-usage-reseed.ts +36 -10
  331. package/src/interactive/slash-commands.ts +31 -4
  332. package/src/interactive/status/summary.ts +5 -0
  333. package/src/interactive/status/types.ts +5 -0
  334. package/src/interactive/terminal-lease.ts +1 -0
  335. package/src/interactive/turn-context.ts +333 -110
  336. package/src/interactive/turn-middleware.ts +7 -6
  337. package/src/interactive/turn-runtime.ts +37 -8
  338. package/src/interactive/turn-state.ts +3 -0
  339. package/src/interactive/worker-progress.ts +440 -0
  340. package/src/interactive/worker-stream.ts +51 -110
  341. package/src/tools/agent-tools.ts +39 -7
  342. package/src/tools/ask-user.ts +21 -1
  343. package/src/tools/bash.ts +144 -82
  344. package/src/tools/builtin-tool-catalog.ts +11 -5
  345. package/src/tools/context/index.ts +107 -5
  346. package/src/tools/context/surface.ts +3 -2
  347. package/src/tools/core-bootstrap.ts +21 -0
  348. package/src/tools/dispatch-arguments.ts +8 -0
  349. package/src/tools/dispatch-event-text.ts +19 -0
  350. package/src/tools/dispatch-runner.ts +9 -7
  351. package/src/tools/dispatch.ts +24 -1
  352. package/src/tools/monitor.ts +43 -20
  353. package/src/tools/registry.ts +72 -10
  354. package/src/tools/result-disposition.ts +706 -0
  355. package/src/tools/result-shaping.ts +321 -20
  356. package/src/tools/safe-exec.ts +2 -0
  357. package/src/tools/verify/authoring.ts +1120 -0
  358. package/src/tools/verify/catalog.ts +346 -0
  359. package/src/tools/verify/index.ts +13 -3
  360. package/src/tools/verify/scripts.ts +135 -37
  361. package/src/tools/verify/surface.ts +9 -5
  362. package/src/tools/worker-evidence.ts +54 -12
  363. package/src/worker/spec-contract.ts +43 -3
  364. package/dist/chunk-J7CWMCQD.js +0 -255
  365. package/dist/chunk-T6YILFSB.js +0 -80
  366. package/dist/chunk-VAKQQHWR.js +0 -434
  367. package/dist/chunk-VPAYEGVX.js +0 -184
  368. package/dist/chunk-XBXAASKX.js +0 -18
  369. package/dist/memory-WFZMGYHX.js +0 -236
  370. package/src/domains/eval/metrics/chaos-stream.ts +0 -93
@@ -3,6 +3,7 @@ import type { RunPersonaOverride, RunPipelineProvenance, RunReceiptAutonomyEnfor
3
3
  import type { EvalCommandPhase, EvalFailureClass, EvalRunRecord } from "../eval/index.js";
4
4
  import type { ProtectedArtifact } from "../safety/protected-artifacts.js";
5
5
  import type { RunEscalationCounts } from "./provenance.js";
6
+ import type { CanonicalTrustStatus } from "./trust-status.js";
6
7
 
7
8
  export const EVIDENCE_VERSION = 1;
8
9
 
@@ -131,13 +132,38 @@ export interface EvidenceBuildResult {
131
132
  directory: string;
132
133
  overview: EvidenceOverview;
133
134
  findings: EvidenceFinding[];
135
+ trustStatus: EvidenceTrustStatusFile;
134
136
  }
135
137
 
136
138
  export interface EvidenceInspectable {
137
139
  overview: EvidenceOverview;
138
140
  findings: EvidenceFinding[];
141
+ trustStatus: EvidenceTrustStatusView;
139
142
  }
140
143
 
144
+ export interface EvidenceRunTrustStatus {
145
+ runId: string;
146
+ status: CanonicalTrustStatus;
147
+ }
148
+
149
+ /** Canonical per-run projection persisted by current evidence builders. */
150
+ export interface EvidenceTrustStatusFile {
151
+ version: 1;
152
+ evidenceId: string;
153
+ projection: "canonical";
154
+ runs: EvidenceRunTrustStatus[];
155
+ }
156
+
157
+ /** Explicit compatibility result for a bundle built before the projection existed. */
158
+ export interface HistoricalEvidenceTrustStatus {
159
+ version: 1;
160
+ evidenceId: string;
161
+ projection: "historical_format";
162
+ runs: [];
163
+ }
164
+
165
+ export type EvidenceTrustStatusView = EvidenceTrustStatusFile | HistoricalEvidenceTrustStatus;
166
+
141
167
  export interface EvidenceRunSource {
142
168
  envelope: RunEnvelope;
143
169
  receipt: RunReceipt | null;
@@ -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. */
@@ -2,8 +2,15 @@ import { createHash } from "node:crypto";
2
2
  import type { EvidenceFinding, EvidenceOverview, EvidenceTag } from "../evidence/index.js";
3
3
  import { inspectEvidence } from "../evidence/index.js";
4
4
  import { canonicalMemoryRepositoryIdentity } from "./operations.js";
5
+ import {
6
+ applyScopeIdentity,
7
+ type MemoryScopeSelection,
8
+ memoryScopeIdentityKey,
9
+ validateMemoryScopeSelection,
10
+ } from "./promotion.js";
5
11
  import { loadMemoryRecords, upsertMemoryRecord } from "./store.js";
6
12
  import type { MemoryProposalResult, MemoryRecord, MemoryRepositoryIdentity, MemoryScope } from "./types.js";
13
+ import { validateMemoryRecord } from "./validate.js";
7
14
 
8
15
  const LESSON_MAX_CHARS = 240;
9
16
  const APPLY_MAX_CHARS = 160;
@@ -23,12 +30,16 @@ const TAG_PRIORITY = [
23
30
  "unknown",
24
31
  ] as const satisfies ReadonlyArray<EvidenceTag>;
25
32
 
26
- export async function proposeMemoryFromEvidence(dataDir: string, evidenceId: string): Promise<MemoryProposalResult> {
33
+ export async function proposeMemoryFromEvidence(
34
+ dataDir: string,
35
+ evidenceId: string,
36
+ selection?: MemoryScopeSelection,
37
+ ): Promise<MemoryProposalResult> {
27
38
  const evidence = await inspectEvidence(dataDir, evidenceId);
28
- const existing = (await loadMemoryRecords(dataDir)).find((record) => record.id === memoryIdFromEvidence(evidenceId));
39
+ const record = memoryRecordFromEvidence(evidence.overview, evidence.findings, selection);
40
+ const existing = (await loadMemoryRecords(dataDir)).find((candidate) => candidate.id === record.id);
29
41
  if (existing !== undefined) return { record: existing, created: false };
30
42
 
31
- const record = memoryRecordFromEvidence(evidence.overview, evidence.findings);
32
43
  await upsertMemoryRecord(dataDir, record);
33
44
  return { record, created: true };
34
45
  }
@@ -41,13 +52,24 @@ export function memoryIdFromEvidence(evidenceId: string): string {
41
52
  export function memoryRecordFromEvidence(
42
53
  overview: EvidenceOverview,
43
54
  findings: ReadonlyArray<EvidenceFinding>,
55
+ selection?: MemoryScopeSelection,
44
56
  ): MemoryRecord {
45
57
  const tags = overview.tags;
46
58
  const primaryTag = primaryEvidenceTag(tags);
47
59
  const repository = inferRepository(overview);
48
- const scope = inferScope(overview, repository);
60
+ const validatedSelection =
61
+ selection === undefined
62
+ ? undefined
63
+ : validateMemoryScopeSelection(selection, {
64
+ runtimeIds: overview.runtimeIds,
65
+ agentIds: overview.agentIds,
66
+ });
67
+ const scope = validatedSelection?.scope ?? inferScope(overview, repository);
49
68
  const record: MemoryRecord = {
50
- id: memoryIdFromEvidence(overview.evidenceId),
69
+ id:
70
+ validatedSelection === undefined
71
+ ? memoryIdFromEvidence(overview.evidenceId)
72
+ : memoryIdFromEvidenceScope(overview.evidenceId, memoryScopeIdentityKey(validatedSelection)),
51
73
  scope,
52
74
  key: `evidence:${overview.evidenceId}`,
53
75
  lesson: truncateText(buildLesson(overview, findings, primaryTag), LESSON_MAX_CHARS),
@@ -57,9 +79,31 @@ export function memoryRecordFromEvidence(
57
79
  confidence: confidenceForEvidence(overview, findings),
58
80
  createdAt: overview.generatedAt,
59
81
  approved: false,
82
+ provenance: {
83
+ sourceKind: "evidence",
84
+ evidenceId: overview.evidenceId,
85
+ ...(overview.sessionId === null ? {} : { sourceSessionId: overview.sessionId }),
86
+ },
60
87
  };
61
- if (scope === "repo" && repository !== null) record.repository = repository;
62
- return record;
88
+ if (validatedSelection !== undefined) applyScopeIdentity(record, validatedSelection);
89
+ else if (scope === "repo" && repository !== null) record.repository = repository;
90
+ else if (scope === "runtime" && overview.runtimeIds[0] !== undefined) {
91
+ record.runtime = { kind: "runtime", key: overview.runtimeIds[0] };
92
+ } else if (scope === "agent" && overview.agentIds[0] !== undefined) {
93
+ record.agent = { kind: "agent", key: overview.agentIds[0] };
94
+ }
95
+ const validated = validateMemoryRecord(record);
96
+ if (!validated.valid) {
97
+ throw new Error(
98
+ `evidence memory record invalid: ${validated.issues.map((issue) => `${issue.path}: ${issue.message}`).join("; ")}`,
99
+ );
100
+ }
101
+ return validated.record;
102
+ }
103
+
104
+ function memoryIdFromEvidenceScope(evidenceId: string, scopeKey: string): string {
105
+ const digest = createHash("sha256").update(`${evidenceId}\n${scopeKey}`, "utf8").digest("hex").slice(0, 16);
106
+ return `mem-${digest}`;
63
107
  }
64
108
 
65
109
  /**
@@ -37,8 +37,9 @@ export interface SaveTaskMemoryOptions {
37
37
  }
38
38
 
39
39
  /**
40
- * Per-session execution memory. This deliberately has no durable store or
41
- * approval flow: it is authoritative working state for one active task.
40
+ * Per-session execution memory. The bank stays transient and authoritative
41
+ * for one active task. Selected non-private entries can enter the separate
42
+ * durable store only through the reviewed promotion service.
42
43
  */
43
44
  export class TaskMemoryBank {
44
45
  readonly #knowledgeCap: number;