@caupulican/pi-adaptative 0.81.38 → 0.81.40

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 (881) hide show
  1. package/CHANGELOG.md +131 -0
  2. package/README.md +2 -0
  3. package/dist/bundled-resources/extensions/tmux-agent-manager/README.md +18 -1
  4. package/dist/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.d.ts +133 -0
  5. package/dist/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.d.ts.map +1 -0
  6. package/dist/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.js +198 -0
  7. package/dist/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.js.map +1 -0
  8. package/dist/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.ts +311 -0
  9. package/dist/bundled-resources/extensions/tmux-agent-manager/index.d.ts +31 -2
  10. package/dist/bundled-resources/extensions/tmux-agent-manager/index.d.ts.map +1 -1
  11. package/dist/bundled-resources/extensions/tmux-agent-manager/index.js +823 -79
  12. package/dist/bundled-resources/extensions/tmux-agent-manager/index.js.map +1 -1
  13. package/dist/bundled-resources/extensions/tmux-agent-manager/index.ts +1043 -86
  14. package/dist/bundled-resources/runtimes/pi-shell-engine/commands/__init__.py +43 -0
  15. package/dist/bundled-resources/runtimes/pi-shell-engine/commands/fs.py +270 -0
  16. package/dist/bundled-resources/runtimes/pi-shell-engine/commands/search.py +252 -0
  17. package/dist/bundled-resources/runtimes/pi-shell-engine/commands/strings.py +399 -0
  18. package/dist/bundled-resources/runtimes/pi-shell-engine/commands/text.py +575 -0
  19. package/dist/bundled-resources/runtimes/pi-shell-engine/context.py +52 -0
  20. package/dist/bundled-resources/runtimes/pi-shell-engine/errors.py +49 -0
  21. package/dist/bundled-resources/runtimes/pi-shell-engine/exec.py +734 -0
  22. package/dist/bundled-resources/runtimes/pi-shell-engine/expand.py +238 -0
  23. package/dist/bundled-resources/runtimes/pi-shell-engine/main.py +132 -0
  24. package/dist/bundled-resources/runtimes/pi-shell-engine/nodes.py +116 -0
  25. package/dist/bundled-resources/runtimes/pi-shell-engine/parser.py +287 -0
  26. package/dist/bundled-resources/runtimes/pi-shell-engine/proc.py +137 -0
  27. package/dist/bundled-resources/runtimes/pi-shell-engine/state.py +100 -0
  28. package/dist/bundled-resources/runtimes/pi-shell-engine/tokens.py +579 -0
  29. package/dist/bundled-resources/skills/tool-call-repair/SKILL.md +19 -9
  30. package/dist/bundled-resources/skills/tool-call-repair/references/failure-grammar.md +22 -5
  31. package/dist/bundled-resources/skills/tool-call-repair/references/repair-catalogue.md +7 -7
  32. package/dist/bundled-resources/skills/tool-call-repair/references/text-protocol-grammar.md +28 -7
  33. package/dist/cli/args.d.ts +5 -0
  34. package/dist/cli/args.d.ts.map +1 -1
  35. package/dist/cli/args.js +24 -0
  36. package/dist/cli/args.js.map +1 -1
  37. package/dist/core/agent-directory-layout.d.ts +15 -0
  38. package/dist/core/agent-directory-layout.d.ts.map +1 -0
  39. package/dist/core/agent-directory-layout.js +72 -0
  40. package/dist/core/agent-directory-layout.js.map +1 -0
  41. package/dist/core/agent-paths.d.ts +66 -0
  42. package/dist/core/agent-paths.d.ts.map +1 -0
  43. package/dist/core/agent-paths.js +170 -0
  44. package/dist/core/agent-paths.js.map +1 -0
  45. package/dist/core/agent-session-runtime.d.ts +52 -8
  46. package/dist/core/agent-session-runtime.d.ts.map +1 -1
  47. package/dist/core/agent-session-runtime.js +397 -79
  48. package/dist/core/agent-session-runtime.js.map +1 -1
  49. package/dist/core/agent-session-services.d.ts +1 -0
  50. package/dist/core/agent-session-services.d.ts.map +1 -1
  51. package/dist/core/agent-session-services.js +4 -3
  52. package/dist/core/agent-session-services.js.map +1 -1
  53. package/dist/core/agent-session.d.ts +255 -103
  54. package/dist/core/agent-session.d.ts.map +1 -1
  55. package/dist/core/agent-session.js +754 -1173
  56. package/dist/core/agent-session.js.map +1 -1
  57. package/dist/core/autonomy/approval-gate.d.ts +3 -2
  58. package/dist/core/autonomy/approval-gate.d.ts.map +1 -1
  59. package/dist/core/autonomy/approval-gate.js +6 -28
  60. package/dist/core/autonomy/approval-gate.js.map +1 -1
  61. package/dist/core/autonomy/bounded-completion.d.ts +1 -1
  62. package/dist/core/autonomy/bounded-completion.d.ts.map +1 -1
  63. package/dist/core/autonomy/bounded-completion.js +1 -1
  64. package/dist/core/autonomy/bounded-completion.js.map +1 -1
  65. package/dist/core/autonomy/contracts.d.ts +26 -9
  66. package/dist/core/autonomy/contracts.d.ts.map +1 -1
  67. package/dist/core/autonomy/contracts.js.map +1 -1
  68. package/dist/core/autonomy/foreground-envelope.d.ts +8 -2
  69. package/dist/core/autonomy/foreground-envelope.d.ts.map +1 -1
  70. package/dist/core/autonomy/foreground-envelope.js +8 -25
  71. package/dist/core/autonomy/foreground-envelope.js.map +1 -1
  72. package/dist/core/autonomy/gates.d.ts.map +1 -1
  73. package/dist/core/autonomy/gates.js +8 -10
  74. package/dist/core/autonomy/gates.js.map +1 -1
  75. package/dist/core/autonomy/lane-private-paths.d.ts +2 -0
  76. package/dist/core/autonomy/lane-private-paths.d.ts.map +1 -0
  77. package/dist/core/autonomy/lane-private-paths.js +16 -0
  78. package/dist/core/autonomy/lane-private-paths.js.map +1 -0
  79. package/dist/core/autonomy/lane-tool-surface.d.ts +10 -0
  80. package/dist/core/autonomy/lane-tool-surface.d.ts.map +1 -1
  81. package/dist/core/autonomy/lane-tool-surface.js +46 -8
  82. package/dist/core/autonomy/lane-tool-surface.js.map +1 -1
  83. package/dist/core/autonomy/lane-tracker.d.ts +24 -1
  84. package/dist/core/autonomy/lane-tracker.d.ts.map +1 -1
  85. package/dist/core/autonomy/lane-tracker.js +43 -1
  86. package/dist/core/autonomy/lane-tracker.js.map +1 -1
  87. package/dist/core/autonomy/risk-assessment.d.ts +1 -2
  88. package/dist/core/autonomy/risk-assessment.d.ts.map +1 -1
  89. package/dist/core/autonomy/risk-assessment.js +1 -123
  90. package/dist/core/autonomy/risk-assessment.js.map +1 -1
  91. package/dist/core/autonomy/session-lane-record.d.ts +4 -4
  92. package/dist/core/autonomy/session-lane-record.d.ts.map +1 -1
  93. package/dist/core/autonomy/session-lane-record.js +16 -29
  94. package/dist/core/autonomy/session-lane-record.js.map +1 -1
  95. package/dist/core/autonomy/telemetry-events.d.ts +1 -1
  96. package/dist/core/autonomy/telemetry-events.d.ts.map +1 -1
  97. package/dist/core/autonomy/telemetry-events.js +1 -1
  98. package/dist/core/autonomy/telemetry-events.js.map +1 -1
  99. package/dist/core/autonomy-telemetry.d.ts +7 -7
  100. package/dist/core/autonomy-telemetry.d.ts.map +1 -1
  101. package/dist/core/autonomy-telemetry.js +9 -9
  102. package/dist/core/autonomy-telemetry.js.map +1 -1
  103. package/dist/core/background-lane-controller.d.ts +90 -156
  104. package/dist/core/background-lane-controller.d.ts.map +1 -1
  105. package/dist/core/background-lane-controller.js +192 -968
  106. package/dist/core/background-lane-controller.js.map +1 -1
  107. package/dist/core/bash-execution-controller.d.ts +4 -0
  108. package/dist/core/bash-execution-controller.d.ts.map +1 -1
  109. package/dist/core/bash-execution-controller.js +7 -1
  110. package/dist/core/bash-execution-controller.js.map +1 -1
  111. package/dist/core/capability-contract.d.ts +4 -0
  112. package/dist/core/capability-contract.d.ts.map +1 -0
  113. package/dist/core/capability-contract.js +28 -0
  114. package/dist/core/capability-contract.js.map +1 -0
  115. package/dist/core/compaction-controller.d.ts +90 -0
  116. package/dist/core/compaction-controller.d.ts.map +1 -0
  117. package/dist/core/compaction-controller.js +452 -0
  118. package/dist/core/compaction-controller.js.map +1 -0
  119. package/dist/core/compaction-support.d.ts +24 -13
  120. package/dist/core/compaction-support.d.ts.map +1 -1
  121. package/dist/core/compaction-support.js +43 -7
  122. package/dist/core/compaction-support.js.map +1 -1
  123. package/dist/core/context/context-artifacts.d.ts +6 -2
  124. package/dist/core/context/context-artifacts.d.ts.map +1 -1
  125. package/dist/core/context/context-artifacts.js +34 -2
  126. package/dist/core/context/context-artifacts.js.map +1 -1
  127. package/dist/core/context/context-audit.d.ts +33 -1
  128. package/dist/core/context/context-audit.d.ts.map +1 -1
  129. package/dist/core/context/context-audit.js +31 -5
  130. package/dist/core/context/context-audit.js.map +1 -1
  131. package/dist/core/context/context-store-retention.d.ts +8 -2
  132. package/dist/core/context/context-store-retention.d.ts.map +1 -1
  133. package/dist/core/context/context-store-retention.js +158 -35
  134. package/dist/core/context/context-store-retention.js.map +1 -1
  135. package/dist/core/context/okf-memory.d.ts.map +1 -1
  136. package/dist/core/context/okf-memory.js +9 -11
  137. package/dist/core/context/okf-memory.js.map +1 -1
  138. package/dist/core/context/sqlite-runtime-index.d.ts.map +1 -1
  139. package/dist/core/context/sqlite-runtime-index.js +6 -8
  140. package/dist/core/context/sqlite-runtime-index.js.map +1 -1
  141. package/dist/core/context-gc.d.ts +3 -0
  142. package/dist/core/context-gc.d.ts.map +1 -1
  143. package/dist/core/context-gc.js +26 -6
  144. package/dist/core/context-gc.js.map +1 -1
  145. package/dist/core/context-pipeline.d.ts +26 -4
  146. package/dist/core/context-pipeline.d.ts.map +1 -1
  147. package/dist/core/context-pipeline.js +146 -18
  148. package/dist/core/context-pipeline.js.map +1 -1
  149. package/dist/core/cost-guard.d.ts +19 -3
  150. package/dist/core/cost-guard.d.ts.map +1 -1
  151. package/dist/core/cost-guard.js +18 -3
  152. package/dist/core/cost-guard.js.map +1 -1
  153. package/dist/core/default-tool-surface.d.ts.map +1 -1
  154. package/dist/core/default-tool-surface.js +1 -0
  155. package/dist/core/default-tool-surface.js.map +1 -1
  156. package/dist/core/delegation/managed-lane-controller.d.ts +34 -0
  157. package/dist/core/delegation/managed-lane-controller.d.ts.map +1 -0
  158. package/dist/core/delegation/managed-lane-controller.js +217 -0
  159. package/dist/core/delegation/managed-lane-controller.js.map +1 -0
  160. package/dist/core/delegation/session-worker-claim.d.ts +44 -0
  161. package/dist/core/delegation/session-worker-claim.d.ts.map +1 -0
  162. package/dist/core/delegation/session-worker-claim.js +98 -0
  163. package/dist/core/delegation/session-worker-claim.js.map +1 -0
  164. package/dist/core/delegation/worker-actions.d.ts +7 -5
  165. package/dist/core/delegation/worker-actions.d.ts.map +1 -1
  166. package/dist/core/delegation/worker-actions.js +20 -4
  167. package/dist/core/delegation/worker-actions.js.map +1 -1
  168. package/dist/core/delegation/worker-claim.d.ts +56 -0
  169. package/dist/core/delegation/worker-claim.d.ts.map +1 -0
  170. package/dist/core/delegation/worker-claim.js +239 -0
  171. package/dist/core/delegation/worker-claim.js.map +1 -0
  172. package/dist/core/delegation/worker-delegation-controller.d.ts +110 -0
  173. package/dist/core/delegation/worker-delegation-controller.d.ts.map +1 -0
  174. package/dist/core/delegation/worker-delegation-controller.js +861 -0
  175. package/dist/core/delegation/worker-delegation-controller.js.map +1 -0
  176. package/dist/core/delegation/worker-delegation-request.d.ts +11 -0
  177. package/dist/core/delegation/worker-delegation-request.d.ts.map +1 -0
  178. package/dist/core/delegation/worker-delegation-request.js +2 -0
  179. package/dist/core/delegation/worker-delegation-request.js.map +1 -0
  180. package/dist/core/delegation/worker-dispatch-scheduler.d.ts +40 -0
  181. package/dist/core/delegation/worker-dispatch-scheduler.d.ts.map +1 -0
  182. package/dist/core/delegation/worker-dispatch-scheduler.js +93 -0
  183. package/dist/core/delegation/worker-dispatch-scheduler.js.map +1 -0
  184. package/dist/core/delegation/worker-execution-policy.d.ts +62 -0
  185. package/dist/core/delegation/worker-execution-policy.d.ts.map +1 -0
  186. package/dist/core/delegation/worker-execution-policy.js +160 -0
  187. package/dist/core/delegation/worker-execution-policy.js.map +1 -0
  188. package/dist/core/delegation/worker-lane-projection.d.ts +14 -0
  189. package/dist/core/delegation/worker-lane-projection.d.ts.map +1 -0
  190. package/dist/core/delegation/worker-lane-projection.js +100 -0
  191. package/dist/core/delegation/worker-lane-projection.js.map +1 -0
  192. package/dist/core/delegation/worker-lifecycle.d.ts +97 -0
  193. package/dist/core/delegation/worker-lifecycle.d.ts.map +1 -0
  194. package/dist/core/delegation/worker-lifecycle.js +339 -0
  195. package/dist/core/delegation/worker-lifecycle.js.map +1 -0
  196. package/dist/core/delegation/worker-notification-coordinator.d.ts +36 -0
  197. package/dist/core/delegation/worker-notification-coordinator.d.ts.map +1 -0
  198. package/dist/core/delegation/worker-notification-coordinator.js +90 -0
  199. package/dist/core/delegation/worker-notification-coordinator.js.map +1 -0
  200. package/dist/core/delegation/worker-profile-resolver.d.ts +55 -0
  201. package/dist/core/delegation/worker-profile-resolver.d.ts.map +1 -0
  202. package/dist/core/delegation/worker-profile-resolver.js +113 -0
  203. package/dist/core/delegation/worker-profile-resolver.js.map +1 -0
  204. package/dist/core/delegation/worker-runner.d.ts +25 -14
  205. package/dist/core/delegation/worker-runner.d.ts.map +1 -1
  206. package/dist/core/delegation/worker-runner.js +122 -53
  207. package/dist/core/delegation/worker-runner.js.map +1 -1
  208. package/dist/core/delegation/worker-task-label.d.ts +3 -0
  209. package/dist/core/delegation/worker-task-label.d.ts.map +1 -0
  210. package/dist/core/delegation/worker-task-label.js +11 -0
  211. package/dist/core/delegation/worker-task-label.js.map +1 -0
  212. package/dist/core/doctor.d.ts +8 -0
  213. package/dist/core/doctor.d.ts.map +1 -1
  214. package/dist/core/doctor.js +32 -1
  215. package/dist/core/doctor.js.map +1 -1
  216. package/dist/core/extensions/index.d.ts +1 -1
  217. package/dist/core/extensions/index.d.ts.map +1 -1
  218. package/dist/core/extensions/index.js.map +1 -1
  219. package/dist/core/extensions/loader.d.ts +5 -1
  220. package/dist/core/extensions/loader.d.ts.map +1 -1
  221. package/dist/core/extensions/loader.js +68 -13
  222. package/dist/core/extensions/loader.js.map +1 -1
  223. package/dist/core/extensions/runner.d.ts.map +1 -1
  224. package/dist/core/extensions/runner.js +7 -0
  225. package/dist/core/extensions/runner.js.map +1 -1
  226. package/dist/core/extensions/storage.d.ts +8 -0
  227. package/dist/core/extensions/storage.d.ts.map +1 -0
  228. package/dist/core/extensions/storage.js +28 -0
  229. package/dist/core/extensions/storage.js.map +1 -0
  230. package/dist/core/extensions/types.d.ts +101 -1
  231. package/dist/core/extensions/types.d.ts.map +1 -1
  232. package/dist/core/extensions/types.js.map +1 -1
  233. package/dist/core/failure-corpus.d.ts +1 -15
  234. package/dist/core/failure-corpus.d.ts.map +1 -1
  235. package/dist/core/failure-corpus.js +9 -37
  236. package/dist/core/failure-corpus.js.map +1 -1
  237. package/dist/core/foreground-recovery-controller.d.ts +52 -0
  238. package/dist/core/foreground-recovery-controller.d.ts.map +1 -0
  239. package/dist/core/foreground-recovery-controller.js +111 -0
  240. package/dist/core/foreground-recovery-controller.js.map +1 -0
  241. package/dist/core/gateways/channel-provider.d.ts +3 -0
  242. package/dist/core/gateways/channel-provider.d.ts.map +1 -1
  243. package/dist/core/gateways/channel-provider.js +31 -6
  244. package/dist/core/gateways/channel-provider.js.map +1 -1
  245. package/dist/core/goal-loop-controller.d.ts +17 -1
  246. package/dist/core/goal-loop-controller.d.ts.map +1 -1
  247. package/dist/core/goal-loop-controller.js +79 -11
  248. package/dist/core/goal-loop-controller.js.map +1 -1
  249. package/dist/core/goals/goal-acceptance.d.ts +11 -0
  250. package/dist/core/goals/goal-acceptance.d.ts.map +1 -0
  251. package/dist/core/goals/goal-acceptance.js +25 -0
  252. package/dist/core/goals/goal-acceptance.js.map +1 -0
  253. package/dist/core/goals/goal-auto-continue-controller.d.ts +27 -0
  254. package/dist/core/goals/goal-auto-continue-controller.d.ts.map +1 -0
  255. package/dist/core/goals/goal-auto-continue-controller.js +93 -0
  256. package/dist/core/goals/goal-auto-continue-controller.js.map +1 -0
  257. package/dist/core/goals/goal-continuation-controller.d.ts +48 -2
  258. package/dist/core/goals/goal-continuation-controller.d.ts.map +1 -1
  259. package/dist/core/goals/goal-continuation-controller.js +87 -0
  260. package/dist/core/goals/goal-continuation-controller.js.map +1 -1
  261. package/dist/core/goals/goal-continuation-defaults.d.ts +39 -0
  262. package/dist/core/goals/goal-continuation-defaults.d.ts.map +1 -1
  263. package/dist/core/goals/goal-continuation-defaults.js +42 -0
  264. package/dist/core/goals/goal-continuation-defaults.js.map +1 -1
  265. package/dist/core/goals/goal-continuation-prompt.d.ts +5 -1
  266. package/dist/core/goals/goal-continuation-prompt.d.ts.map +1 -1
  267. package/dist/core/goals/goal-continuation-prompt.js +56 -15
  268. package/dist/core/goals/goal-continuation-prompt.js.map +1 -1
  269. package/dist/core/goals/goal-lifecycle.d.ts +20 -0
  270. package/dist/core/goals/goal-lifecycle.d.ts.map +1 -0
  271. package/dist/core/goals/goal-lifecycle.js +17 -0
  272. package/dist/core/goals/goal-lifecycle.js.map +1 -0
  273. package/dist/core/goals/goal-runtime-snapshot.d.ts +105 -4
  274. package/dist/core/goals/goal-runtime-snapshot.d.ts.map +1 -1
  275. package/dist/core/goals/goal-runtime-snapshot.js +91 -6
  276. package/dist/core/goals/goal-runtime-snapshot.js.map +1 -1
  277. package/dist/core/goals/goal-state.d.ts +90 -1
  278. package/dist/core/goals/goal-state.d.ts.map +1 -1
  279. package/dist/core/goals/goal-state.js +78 -15
  280. package/dist/core/goals/goal-state.js.map +1 -1
  281. package/dist/core/goals/goal-tool-core.d.ts +58 -2
  282. package/dist/core/goals/goal-tool-core.d.ts.map +1 -1
  283. package/dist/core/goals/goal-tool-core.js +82 -6
  284. package/dist/core/goals/goal-tool-core.js.map +1 -1
  285. package/dist/core/goals/session-goal-state.d.ts +13 -6
  286. package/dist/core/goals/session-goal-state.d.ts.map +1 -1
  287. package/dist/core/goals/session-goal-state.js +20 -28
  288. package/dist/core/goals/session-goal-state.js.map +1 -1
  289. package/dist/core/human-input.d.ts +100 -0
  290. package/dist/core/human-input.d.ts.map +1 -0
  291. package/dist/core/human-input.js +362 -0
  292. package/dist/core/human-input.js.map +1 -0
  293. package/dist/core/index.d.ts +9 -1
  294. package/dist/core/index.d.ts.map +1 -1
  295. package/dist/core/index.js +9 -1
  296. package/dist/core/index.js.map +1 -1
  297. package/dist/core/{telemetry.d.ts → install-telemetry.d.ts} +1 -1
  298. package/dist/core/install-telemetry.d.ts.map +1 -0
  299. package/dist/core/{telemetry.js → install-telemetry.js} +1 -1
  300. package/dist/core/install-telemetry.js.map +1 -0
  301. package/dist/core/keybindings.d.ts +27 -1
  302. package/dist/core/keybindings.d.ts.map +1 -1
  303. package/dist/core/keybindings.js +34 -8
  304. package/dist/core/keybindings.js.map +1 -1
  305. package/dist/core/learning/learning-audit.d.ts +2 -4
  306. package/dist/core/learning/learning-audit.d.ts.map +1 -1
  307. package/dist/core/learning/learning-audit.js +9 -29
  308. package/dist/core/learning/learning-audit.js.map +1 -1
  309. package/dist/core/learning/learning-gate.d.ts.map +1 -1
  310. package/dist/core/learning/learning-gate.js +1 -6
  311. package/dist/core/learning/learning-gate.js.map +1 -1
  312. package/dist/core/learning/observation-store.d.ts +12 -3
  313. package/dist/core/learning/observation-store.d.ts.map +1 -1
  314. package/dist/core/learning/observation-store.js +30 -15
  315. package/dist/core/learning/observation-store.js.map +1 -1
  316. package/dist/core/learning/session-learning-decision.d.ts +2 -4
  317. package/dist/core/learning/session-learning-decision.d.ts.map +1 -1
  318. package/dist/core/learning/session-learning-decision.js +9 -29
  319. package/dist/core/learning/session-learning-decision.js.map +1 -1
  320. package/dist/core/learning/skill-curator.d.ts +5 -1
  321. package/dist/core/learning/skill-curator.d.ts.map +1 -1
  322. package/dist/core/learning/skill-curator.js +21 -19
  323. package/dist/core/learning/skill-curator.js.map +1 -1
  324. package/dist/core/local-runtime-controller.d.ts +65 -3
  325. package/dist/core/local-runtime-controller.d.ts.map +1 -1
  326. package/dist/core/local-runtime-controller.js +186 -26
  327. package/dist/core/local-runtime-controller.js.map +1 -1
  328. package/dist/core/memory/providers/file-store.d.ts +1 -1
  329. package/dist/core/memory/providers/file-store.d.ts.map +1 -1
  330. package/dist/core/memory/providers/file-store.js +6 -6
  331. package/dist/core/memory/providers/file-store.js.map +1 -1
  332. package/dist/core/memory-controller.d.ts.map +1 -1
  333. package/dist/core/memory-controller.js +4 -4
  334. package/dist/core/memory-controller.js.map +1 -1
  335. package/dist/core/model-capability.d.ts +34 -0
  336. package/dist/core/model-capability.d.ts.map +1 -1
  337. package/dist/core/model-capability.js +43 -1
  338. package/dist/core/model-capability.js.map +1 -1
  339. package/dist/core/model-resolver.d.ts +1 -1
  340. package/dist/core/model-resolver.d.ts.map +1 -1
  341. package/dist/core/model-resolver.js +6 -9
  342. package/dist/core/model-resolver.js.map +1 -1
  343. package/dist/core/model-router/intent-classifier.d.ts +1 -4
  344. package/dist/core/model-router/intent-classifier.d.ts.map +1 -1
  345. package/dist/core/model-router/intent-classifier.js +1 -156
  346. package/dist/core/model-router/intent-classifier.js.map +1 -1
  347. package/dist/core/model-router/tool-escalation.d.ts +15 -0
  348. package/dist/core/model-router/tool-escalation.d.ts.map +1 -1
  349. package/dist/core/model-router/tool-escalation.js +23 -1
  350. package/dist/core/model-router/tool-escalation.js.map +1 -1
  351. package/dist/core/model-router-controller.d.ts +34 -7
  352. package/dist/core/model-router-controller.d.ts.map +1 -1
  353. package/dist/core/model-router-controller.js +95 -16
  354. package/dist/core/model-router-controller.js.map +1 -1
  355. package/dist/core/model-selection-controller.d.ts +4 -4
  356. package/dist/core/model-selection-controller.d.ts.map +1 -1
  357. package/dist/core/model-selection-controller.js.map +1 -1
  358. package/dist/core/model-tool-protocol.d.ts +23 -0
  359. package/dist/core/model-tool-protocol.d.ts.map +1 -0
  360. package/dist/core/model-tool-protocol.js +43 -0
  361. package/dist/core/model-tool-protocol.js.map +1 -0
  362. package/dist/core/models/adaptation-store.d.ts +10 -5
  363. package/dist/core/models/adaptation-store.d.ts.map +1 -1
  364. package/dist/core/models/adaptation-store.js +129 -81
  365. package/dist/core/models/adaptation-store.js.map +1 -1
  366. package/dist/core/models/default-model-suggestions.d.ts.map +1 -1
  367. package/dist/core/models/default-model-suggestions.js +17 -0
  368. package/dist/core/models/default-model-suggestions.js.map +1 -1
  369. package/dist/core/models/fitness-store.d.ts +4 -11
  370. package/dist/core/models/fitness-store.d.ts.map +1 -1
  371. package/dist/core/models/fitness-store.js +87 -51
  372. package/dist/core/models/fitness-store.js.map +1 -1
  373. package/dist/core/models/host-state-store.d.ts +34 -0
  374. package/dist/core/models/host-state-store.d.ts.map +1 -0
  375. package/dist/core/models/host-state-store.js +86 -0
  376. package/dist/core/models/host-state-store.js.map +1 -0
  377. package/dist/core/models/llamacpp-runtime.d.ts +180 -0
  378. package/dist/core/models/llamacpp-runtime.d.ts.map +1 -0
  379. package/dist/core/models/llamacpp-runtime.js +475 -0
  380. package/dist/core/models/llamacpp-runtime.js.map +1 -0
  381. package/dist/core/models/local-registration.d.ts +40 -0
  382. package/dist/core/models/local-registration.d.ts.map +1 -1
  383. package/dist/core/models/local-registration.js +94 -5
  384. package/dist/core/models/local-registration.js.map +1 -1
  385. package/dist/core/models/local-runtime.d.ts.map +1 -1
  386. package/dist/core/models/local-runtime.js +6 -5
  387. package/dist/core/models/local-runtime.js.map +1 -1
  388. package/dist/core/models/model-ref.d.ts +7 -0
  389. package/dist/core/models/model-ref.d.ts.map +1 -1
  390. package/dist/core/models/model-ref.js +26 -0
  391. package/dist/core/models/model-ref.js.map +1 -1
  392. package/dist/core/models/needle-runtime.d.ts +257 -0
  393. package/dist/core/models/needle-runtime.d.ts.map +1 -0
  394. package/dist/core/models/needle-runtime.js +519 -0
  395. package/dist/core/models/needle-runtime.js.map +1 -0
  396. package/dist/core/models/prism-llamacpp-lifecycle.d.ts +89 -0
  397. package/dist/core/models/prism-llamacpp-lifecycle.d.ts.map +1 -0
  398. package/dist/core/models/prism-llamacpp-lifecycle.js +121 -0
  399. package/dist/core/models/prism-llamacpp-lifecycle.js.map +1 -0
  400. package/dist/core/orchestration/agent-resume.d.ts +24 -0
  401. package/dist/core/orchestration/agent-resume.d.ts.map +1 -0
  402. package/dist/core/orchestration/agent-resume.js +90 -0
  403. package/dist/core/orchestration/agent-resume.js.map +1 -0
  404. package/dist/core/orchestration/capability-gateway.d.ts +61 -0
  405. package/dist/core/orchestration/capability-gateway.d.ts.map +1 -0
  406. package/dist/core/orchestration/capability-gateway.js +152 -0
  407. package/dist/core/orchestration/capability-gateway.js.map +1 -0
  408. package/dist/core/orchestration/contracts.d.ts +343 -0
  409. package/dist/core/orchestration/contracts.d.ts.map +1 -0
  410. package/dist/core/orchestration/contracts.js +135 -0
  411. package/dist/core/orchestration/contracts.js.map +1 -0
  412. package/dist/core/orchestration/delegation-ledger.d.ts +56 -0
  413. package/dist/core/orchestration/delegation-ledger.d.ts.map +1 -0
  414. package/dist/core/orchestration/delegation-ledger.js +197 -0
  415. package/dist/core/orchestration/delegation-ledger.js.map +1 -0
  416. package/dist/core/orchestration/event-store.d.ts +83 -0
  417. package/dist/core/orchestration/event-store.d.ts.map +1 -0
  418. package/dist/core/orchestration/event-store.js +560 -0
  419. package/dist/core/orchestration/event-store.js.map +1 -0
  420. package/dist/core/orchestration/lane-tool-manifests.d.ts +9 -0
  421. package/dist/core/orchestration/lane-tool-manifests.d.ts.map +1 -0
  422. package/dist/core/orchestration/lane-tool-manifests.js +37 -0
  423. package/dist/core/orchestration/lane-tool-manifests.js.map +1 -0
  424. package/dist/core/orchestration/model-binding.d.ts +15 -0
  425. package/dist/core/orchestration/model-binding.d.ts.map +1 -0
  426. package/dist/core/orchestration/model-binding.js +29 -0
  427. package/dist/core/orchestration/model-binding.js.map +1 -0
  428. package/dist/core/orchestration/policy-compiler.d.ts +49 -0
  429. package/dist/core/orchestration/policy-compiler.d.ts.map +1 -0
  430. package/dist/core/orchestration/policy-compiler.js +191 -0
  431. package/dist/core/orchestration/policy-compiler.js.map +1 -0
  432. package/dist/core/orchestration/policy-gate.d.ts +18 -0
  433. package/dist/core/orchestration/policy-gate.d.ts.map +1 -0
  434. package/dist/core/orchestration/policy-gate.js +24 -0
  435. package/dist/core/orchestration/policy-gate.js.map +1 -0
  436. package/dist/core/orchestration/profile-registry.d.ts +51 -0
  437. package/dist/core/orchestration/profile-registry.d.ts.map +1 -0
  438. package/dist/core/orchestration/profile-registry.js +393 -0
  439. package/dist/core/orchestration/profile-registry.js.map +1 -0
  440. package/dist/core/orchestration/profile-store.d.ts +31 -0
  441. package/dist/core/orchestration/profile-store.d.ts.map +1 -0
  442. package/dist/core/orchestration/profile-store.js +136 -0
  443. package/dist/core/orchestration/profile-store.js.map +1 -0
  444. package/dist/core/orchestration/risk-budget.d.ts +9 -0
  445. package/dist/core/orchestration/risk-budget.d.ts.map +1 -0
  446. package/dist/core/orchestration/risk-budget.js +48 -0
  447. package/dist/core/orchestration/risk-budget.js.map +1 -0
  448. package/dist/core/orchestration/task-runtime.d.ts +168 -0
  449. package/dist/core/orchestration/task-runtime.d.ts.map +1 -0
  450. package/dist/core/orchestration/task-runtime.js +1600 -0
  451. package/dist/core/orchestration/task-runtime.js.map +1 -0
  452. package/dist/core/orchestration/work-state-projection.d.ts +32 -0
  453. package/dist/core/orchestration/work-state-projection.d.ts.map +1 -0
  454. package/dist/core/orchestration/work-state-projection.js +116 -0
  455. package/dist/core/orchestration/work-state-projection.js.map +1 -0
  456. package/dist/core/orchestration/worker-execution-contract.d.ts +21 -0
  457. package/dist/core/orchestration/worker-execution-contract.d.ts.map +1 -0
  458. package/dist/core/orchestration/worker-execution-contract.js +179 -0
  459. package/dist/core/orchestration/worker-execution-contract.js.map +1 -0
  460. package/dist/core/orchestration/worker-result-adapter.d.ts +21 -0
  461. package/dist/core/orchestration/worker-result-adapter.d.ts.map +1 -0
  462. package/dist/core/orchestration/worker-result-adapter.js +109 -0
  463. package/dist/core/orchestration/worker-result-adapter.js.map +1 -0
  464. package/dist/core/package-manager.d.ts.map +1 -1
  465. package/dist/core/package-manager.js +11 -10
  466. package/dist/core/package-manager.js.map +1 -1
  467. package/dist/core/process-identity.d.ts +11 -0
  468. package/dist/core/process-identity.d.ts.map +1 -0
  469. package/dist/core/process-identity.js +26 -0
  470. package/dist/core/process-identity.js.map +1 -0
  471. package/dist/core/process-matrix/codes.d.ts +83 -0
  472. package/dist/core/process-matrix/codes.d.ts.map +1 -0
  473. package/dist/core/process-matrix/codes.js +15 -0
  474. package/dist/core/process-matrix/codes.js.map +1 -0
  475. package/dist/core/process-matrix/resume-launcher.d.ts +26 -0
  476. package/dist/core/process-matrix/resume-launcher.d.ts.map +1 -0
  477. package/dist/core/process-matrix/resume-launcher.js +62 -0
  478. package/dist/core/process-matrix/resume-launcher.js.map +1 -0
  479. package/dist/core/process-matrix/runtime.d.ts +78 -0
  480. package/dist/core/process-matrix/runtime.d.ts.map +1 -0
  481. package/dist/core/process-matrix/runtime.js +633 -0
  482. package/dist/core/process-matrix/runtime.js.map +1 -0
  483. package/dist/core/process-matrix/store.d.ts +25 -0
  484. package/dist/core/process-matrix/store.d.ts.map +1 -0
  485. package/dist/core/process-matrix/store.js +189 -0
  486. package/dist/core/process-matrix/store.js.map +1 -0
  487. package/dist/core/process-matrix/supervisor.d.ts +75 -0
  488. package/dist/core/process-matrix/supervisor.d.ts.map +1 -0
  489. package/dist/core/process-matrix/supervisor.js +161 -0
  490. package/dist/core/process-matrix/supervisor.js.map +1 -0
  491. package/dist/core/profile-registry.d.ts +7 -0
  492. package/dist/core/profile-registry.d.ts.map +1 -1
  493. package/dist/core/profile-registry.js +25 -7
  494. package/dist/core/profile-registry.js.map +1 -1
  495. package/dist/core/python-runtime.d.ts.map +1 -1
  496. package/dist/core/python-runtime.js +3 -3
  497. package/dist/core/python-runtime.js.map +1 -1
  498. package/dist/core/reflection-controller.d.ts +33 -9
  499. package/dist/core/reflection-controller.d.ts.map +1 -1
  500. package/dist/core/reflection-controller.js +217 -127
  501. package/dist/core/reflection-controller.js.map +1 -1
  502. package/dist/core/reload-blockers.d.ts +36 -0
  503. package/dist/core/reload-blockers.d.ts.map +1 -1
  504. package/dist/core/reload-blockers.js +50 -8
  505. package/dist/core/reload-blockers.js.map +1 -1
  506. package/dist/core/research/evidence-bundle.d.ts.map +1 -1
  507. package/dist/core/research/evidence-bundle.js +1 -6
  508. package/dist/core/research/evidence-bundle.js.map +1 -1
  509. package/dist/core/research/lane-model-resolver.d.ts +33 -0
  510. package/dist/core/research/lane-model-resolver.d.ts.map +1 -0
  511. package/dist/core/research/lane-model-resolver.js +65 -0
  512. package/dist/core/research/lane-model-resolver.js.map +1 -0
  513. package/dist/core/research/model-fitness-controller.d.ts +38 -0
  514. package/dist/core/research/model-fitness-controller.d.ts.map +1 -0
  515. package/dist/core/research/model-fitness-controller.js +106 -0
  516. package/dist/core/research/model-fitness-controller.js.map +1 -0
  517. package/dist/core/research/model-fitness.d.ts +1 -1
  518. package/dist/core/research/model-fitness.d.ts.map +1 -1
  519. package/dist/core/research/model-fitness.js +4 -4
  520. package/dist/core/research/model-fitness.js.map +1 -1
  521. package/dist/core/research/research-gate.d.ts.map +1 -1
  522. package/dist/core/research/research-gate.js +7 -7
  523. package/dist/core/research/research-gate.js.map +1 -1
  524. package/dist/core/research/research-lane-controller.d.ts +62 -0
  525. package/dist/core/research/research-lane-controller.d.ts.map +1 -0
  526. package/dist/core/research/research-lane-controller.js +292 -0
  527. package/dist/core/research/research-lane-controller.js.map +1 -0
  528. package/dist/core/research/session-evidence-bundle.d.ts +2 -4
  529. package/dist/core/research/session-evidence-bundle.d.ts.map +1 -1
  530. package/dist/core/research/session-evidence-bundle.js +10 -46
  531. package/dist/core/research/session-evidence-bundle.js.map +1 -1
  532. package/dist/core/resource-loader.d.ts.map +1 -1
  533. package/dist/core/resource-loader.js +15 -9
  534. package/dist/core/resource-loader.js.map +1 -1
  535. package/dist/core/risk-classifier.d.ts +6 -0
  536. package/dist/core/risk-classifier.d.ts.map +1 -0
  537. package/dist/core/risk-classifier.js +225 -0
  538. package/dist/core/risk-classifier.js.map +1 -0
  539. package/dist/core/runtime-builder.d.ts +76 -17
  540. package/dist/core/runtime-builder.d.ts.map +1 -1
  541. package/dist/core/runtime-builder.js +367 -124
  542. package/dist/core/runtime-builder.js.map +1 -1
  543. package/dist/core/scout-controller.d.ts +6 -0
  544. package/dist/core/scout-controller.d.ts.map +1 -1
  545. package/dist/core/scout-controller.js +66 -52
  546. package/dist/core/scout-controller.js.map +1 -1
  547. package/dist/core/sdk.d.ts +6 -3
  548. package/dist/core/sdk.d.ts.map +1 -1
  549. package/dist/core/sdk.js +64 -27
  550. package/dist/core/sdk.js.map +1 -1
  551. package/dist/core/session-analytics.d.ts.map +1 -1
  552. package/dist/core/session-analytics.js +28 -1
  553. package/dist/core/session-analytics.js.map +1 -1
  554. package/dist/core/session-image-store.d.ts +33 -0
  555. package/dist/core/session-image-store.d.ts.map +1 -0
  556. package/dist/core/session-image-store.js +283 -0
  557. package/dist/core/session-image-store.js.map +1 -0
  558. package/dist/core/session-role.d.ts +33 -0
  559. package/dist/core/session-role.d.ts.map +1 -0
  560. package/dist/core/session-role.js +58 -0
  561. package/dist/core/session-role.js.map +1 -0
  562. package/dist/core/session-snapshot.d.ts +34 -0
  563. package/dist/core/session-snapshot.d.ts.map +1 -0
  564. package/dist/core/session-snapshot.js +68 -0
  565. package/dist/core/session-snapshot.js.map +1 -0
  566. package/dist/core/session-supervision-runtime.d.ts +31 -0
  567. package/dist/core/session-supervision-runtime.d.ts.map +1 -0
  568. package/dist/core/session-supervision-runtime.js +97 -0
  569. package/dist/core/session-supervision-runtime.js.map +1 -0
  570. package/dist/core/settings-manager.d.ts +51 -7
  571. package/dist/core/settings-manager.d.ts.map +1 -1
  572. package/dist/core/settings-manager.js +168 -82
  573. package/dist/core/settings-manager.js.map +1 -1
  574. package/dist/core/system-prompt-builder.d.ts +12 -0
  575. package/dist/core/system-prompt-builder.d.ts.map +1 -1
  576. package/dist/core/system-prompt-builder.js +6 -0
  577. package/dist/core/system-prompt-builder.js.map +1 -1
  578. package/dist/core/system-prompt.d.ts +14 -1
  579. package/dist/core/system-prompt.d.ts.map +1 -1
  580. package/dist/core/system-prompt.js +20 -3
  581. package/dist/core/system-prompt.js.map +1 -1
  582. package/dist/core/tasks/session-task-state.d.ts +13 -6
  583. package/dist/core/tasks/session-task-state.d.ts.map +1 -1
  584. package/dist/core/tasks/session-task-state.js +20 -22
  585. package/dist/core/tasks/session-task-state.js.map +1 -1
  586. package/dist/core/tasks/task-contract-monitor.d.ts +45 -0
  587. package/dist/core/tasks/task-contract-monitor.d.ts.map +1 -0
  588. package/dist/core/tasks/task-contract-monitor.js +56 -0
  589. package/dist/core/tasks/task-contract-monitor.js.map +1 -0
  590. package/dist/core/tasks/task-projection.d.ts +20 -0
  591. package/dist/core/tasks/task-projection.d.ts.map +1 -0
  592. package/dist/core/tasks/task-projection.js +47 -0
  593. package/dist/core/tasks/task-projection.js.map +1 -0
  594. package/dist/core/tasks/task-state.d.ts +12 -0
  595. package/dist/core/tasks/task-state.d.ts.map +1 -1
  596. package/dist/core/tasks/task-state.js +56 -12
  597. package/dist/core/tasks/task-state.js.map +1 -1
  598. package/dist/core/tool-capability-policy.d.ts +13 -0
  599. package/dist/core/tool-capability-policy.d.ts.map +1 -0
  600. package/dist/core/tool-capability-policy.js +85 -0
  601. package/dist/core/tool-capability-policy.js.map +1 -0
  602. package/dist/core/tool-gate-controller.d.ts.map +1 -1
  603. package/dist/core/tool-gate-controller.js +5 -0
  604. package/dist/core/tool-gate-controller.js.map +1 -1
  605. package/dist/core/tool-protocol-controller.d.ts +91 -0
  606. package/dist/core/tool-protocol-controller.d.ts.map +1 -0
  607. package/dist/core/tool-protocol-controller.js +512 -0
  608. package/dist/core/tool-protocol-controller.js.map +1 -0
  609. package/dist/core/tool-recovery-log-records.d.ts +6 -0
  610. package/dist/core/tool-recovery-log-records.d.ts.map +1 -1
  611. package/dist/core/tool-recovery-log-records.js +13 -31
  612. package/dist/core/tool-recovery-log-records.js.map +1 -1
  613. package/dist/core/tool-selection/promotion.d.ts +54 -0
  614. package/dist/core/tool-selection/promotion.d.ts.map +1 -0
  615. package/dist/core/tool-selection/promotion.js +81 -0
  616. package/dist/core/tool-selection/promotion.js.map +1 -0
  617. package/dist/core/tool-selection/tool-performance-store.d.ts +39 -6
  618. package/dist/core/tool-selection/tool-performance-store.d.ts.map +1 -1
  619. package/dist/core/tool-selection/tool-performance-store.js +153 -110
  620. package/dist/core/tool-selection/tool-performance-store.js.map +1 -1
  621. package/dist/core/tool-selection/tool-selection-controller.d.ts +45 -0
  622. package/dist/core/tool-selection/tool-selection-controller.d.ts.map +1 -1
  623. package/dist/core/tool-selection/tool-selection-controller.js +96 -0
  624. package/dist/core/tool-selection/tool-selection-controller.js.map +1 -1
  625. package/dist/core/tools/ask-question.d.ts +124 -0
  626. package/dist/core/tools/ask-question.d.ts.map +1 -0
  627. package/dist/core/tools/ask-question.js +693 -0
  628. package/dist/core/tools/ask-question.js.map +1 -0
  629. package/dist/core/tools/bash.d.ts +18 -0
  630. package/dist/core/tools/bash.d.ts.map +1 -1
  631. package/dist/core/tools/bash.js +95 -16
  632. package/dist/core/tools/bash.js.map +1 -1
  633. package/dist/core/tools/delegate-status.d.ts +44 -2
  634. package/dist/core/tools/delegate-status.d.ts.map +1 -1
  635. package/dist/core/tools/delegate-status.js +214 -19
  636. package/dist/core/tools/delegate-status.js.map +1 -1
  637. package/dist/core/tools/delegate.d.ts +15 -13
  638. package/dist/core/tools/delegate.d.ts.map +1 -1
  639. package/dist/core/tools/delegate.js +124 -22
  640. package/dist/core/tools/delegate.js.map +1 -1
  641. package/dist/core/tools/extensionify.d.ts.map +1 -1
  642. package/dist/core/tools/extensionify.js +1 -0
  643. package/dist/core/tools/extensionify.js.map +1 -1
  644. package/dist/core/tools/goal.d.ts +94 -3
  645. package/dist/core/tools/goal.d.ts.map +1 -1
  646. package/dist/core/tools/goal.js +165 -15
  647. package/dist/core/tools/goal.js.map +1 -1
  648. package/dist/core/tools/model-fitness.d.ts +7 -0
  649. package/dist/core/tools/model-fitness.d.ts.map +1 -1
  650. package/dist/core/tools/model-fitness.js +4 -4
  651. package/dist/core/tools/model-fitness.js.map +1 -1
  652. package/dist/core/tools/orchestration-panel.d.ts +43 -0
  653. package/dist/core/tools/orchestration-panel.d.ts.map +1 -0
  654. package/dist/core/tools/orchestration-panel.js +168 -0
  655. package/dist/core/tools/orchestration-panel.js.map +1 -0
  656. package/dist/core/tools/run-process.d.ts +26 -0
  657. package/dist/core/tools/run-process.d.ts.map +1 -0
  658. package/dist/core/tools/run-process.js +138 -0
  659. package/dist/core/tools/run-process.js.map +1 -0
  660. package/dist/core/tools/shell-contract-router.d.ts +6 -1
  661. package/dist/core/tools/shell-contract-router.d.ts.map +1 -1
  662. package/dist/core/tools/shell-contract-router.js +23 -2
  663. package/dist/core/tools/shell-contract-router.js.map +1 -1
  664. package/dist/core/tools/shell-session.d.ts +89 -0
  665. package/dist/core/tools/shell-session.d.ts.map +1 -0
  666. package/dist/core/tools/shell-session.js +432 -0
  667. package/dist/core/tools/shell-session.js.map +1 -0
  668. package/dist/core/tools/task-steps.d.ts +6 -0
  669. package/dist/core/tools/task-steps.d.ts.map +1 -1
  670. package/dist/core/tools/task-steps.js +165 -8
  671. package/dist/core/tools/task-steps.js.map +1 -1
  672. package/dist/core/tools/tmux-dispatch.d.ts +84 -0
  673. package/dist/core/tools/tmux-dispatch.d.ts.map +1 -0
  674. package/dist/core/tools/tmux-dispatch.js +91 -0
  675. package/dist/core/tools/tmux-dispatch.js.map +1 -0
  676. package/dist/core/tools/windows-shell-engine.d.ts +42 -0
  677. package/dist/core/tools/windows-shell-engine.d.ts.map +1 -0
  678. package/dist/core/tools/windows-shell-engine.js +151 -0
  679. package/dist/core/tools/windows-shell-engine.js.map +1 -0
  680. package/dist/core/tools/windows-shell-state.d.ts +40 -0
  681. package/dist/core/tools/windows-shell-state.d.ts.map +1 -0
  682. package/dist/core/tools/windows-shell-state.js +59 -0
  683. package/dist/core/tools/windows-shell-state.js.map +1 -0
  684. package/dist/core/tools/worktree-sync.d.ts +24 -0
  685. package/dist/core/tools/worktree-sync.d.ts.map +1 -0
  686. package/dist/core/tools/worktree-sync.js +338 -0
  687. package/dist/core/tools/worktree-sync.js.map +1 -0
  688. package/dist/core/trust-manager.d.ts +4 -1
  689. package/dist/core/trust-manager.d.ts.map +1 -1
  690. package/dist/core/trust-manager.js +20 -2
  691. package/dist/core/trust-manager.js.map +1 -1
  692. package/dist/core/util/atomic-file.d.ts +55 -0
  693. package/dist/core/util/atomic-file.d.ts.map +1 -0
  694. package/dist/core/util/atomic-file.js +255 -0
  695. package/dist/core/util/atomic-file.js.map +1 -0
  696. package/dist/core/util/bounded-jsonl.d.ts +10 -0
  697. package/dist/core/util/bounded-jsonl.d.ts.map +1 -0
  698. package/dist/core/util/bounded-jsonl.js +75 -0
  699. package/dist/core/util/bounded-jsonl.js.map +1 -0
  700. package/dist/core/util/minimatch-cache.d.ts +33 -0
  701. package/dist/core/util/minimatch-cache.d.ts.map +1 -0
  702. package/dist/core/util/minimatch-cache.js +0 -0
  703. package/dist/core/util/minimatch-cache.js.map +1 -0
  704. package/dist/core/util/value-guards.d.ts +5 -0
  705. package/dist/core/util/value-guards.d.ts.map +1 -0
  706. package/dist/core/util/value-guards.js +12 -0
  707. package/dist/core/util/value-guards.js.map +1 -0
  708. package/dist/core/worktree-sync/codes.d.ts +227 -0
  709. package/dist/core/worktree-sync/codes.d.ts.map +1 -0
  710. package/dist/core/worktree-sync/codes.js +14 -0
  711. package/dist/core/worktree-sync/codes.js.map +1 -0
  712. package/dist/core/worktree-sync/git-engine.d.ts +156 -0
  713. package/dist/core/worktree-sync/git-engine.d.ts.map +1 -0
  714. package/dist/core/worktree-sync/git-engine.js +1191 -0
  715. package/dist/core/worktree-sync/git-engine.js.map +1 -0
  716. package/dist/core/worktree-sync/lane-gate.d.ts +75 -0
  717. package/dist/core/worktree-sync/lane-gate.d.ts.map +1 -0
  718. package/dist/core/worktree-sync/lane-gate.js +360 -0
  719. package/dist/core/worktree-sync/lane-gate.js.map +1 -0
  720. package/dist/core/worktree-sync/runtime.d.ts +47 -0
  721. package/dist/core/worktree-sync/runtime.d.ts.map +1 -0
  722. package/dist/core/worktree-sync/runtime.js +96 -0
  723. package/dist/core/worktree-sync/runtime.js.map +1 -0
  724. package/dist/core/worktree-sync/store.d.ts +69 -0
  725. package/dist/core/worktree-sync/store.d.ts.map +1 -0
  726. package/dist/core/worktree-sync/store.js +252 -0
  727. package/dist/core/worktree-sync/store.js.map +1 -0
  728. package/dist/core/worktree-sync/watcher.d.ts +29 -0
  729. package/dist/core/worktree-sync/watcher.d.ts.map +1 -0
  730. package/dist/core/worktree-sync/watcher.js +93 -0
  731. package/dist/core/worktree-sync/watcher.js.map +1 -0
  732. package/dist/index.d.ts +13 -3
  733. package/dist/index.d.ts.map +1 -1
  734. package/dist/index.js +12 -2
  735. package/dist/index.js.map +1 -1
  736. package/dist/main.d.ts.map +1 -1
  737. package/dist/main.js +179 -1
  738. package/dist/main.js.map +1 -1
  739. package/dist/migrations.d.ts +7 -0
  740. package/dist/migrations.d.ts.map +1 -1
  741. package/dist/migrations.js +197 -1
  742. package/dist/migrations.js.map +1 -1
  743. package/dist/modes/interactive/auto-learn-controller.d.ts +16 -1
  744. package/dist/modes/interactive/auto-learn-controller.d.ts.map +1 -1
  745. package/dist/modes/interactive/auto-learn-controller.js +50 -8
  746. package/dist/modes/interactive/auto-learn-controller.js.map +1 -1
  747. package/dist/modes/interactive/clipboard-input.d.ts +7 -1
  748. package/dist/modes/interactive/clipboard-input.d.ts.map +1 -1
  749. package/dist/modes/interactive/clipboard-input.js +44 -6
  750. package/dist/modes/interactive/clipboard-input.js.map +1 -1
  751. package/dist/modes/interactive/components/profile-resource-editor.d.ts.map +1 -1
  752. package/dist/modes/interactive/components/profile-resource-editor.js +23 -1
  753. package/dist/modes/interactive/components/profile-resource-editor.js.map +1 -1
  754. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  755. package/dist/modes/interactive/components/settings-selector.js +2 -2
  756. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  757. package/dist/modes/interactive/config-backup.d.ts.map +1 -1
  758. package/dist/modes/interactive/config-backup.js +5 -4
  759. package/dist/modes/interactive/config-backup.js.map +1 -1
  760. package/dist/modes/interactive/extension-ui-host.d.ts +14 -0
  761. package/dist/modes/interactive/extension-ui-host.d.ts.map +1 -1
  762. package/dist/modes/interactive/extension-ui-host.js +76 -15
  763. package/dist/modes/interactive/extension-ui-host.js.map +1 -1
  764. package/dist/modes/interactive/interactive-mode.d.ts +4 -0
  765. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  766. package/dist/modes/interactive/interactive-mode.js +67 -1
  767. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  768. package/dist/modes/interactive/key-handlers.d.ts.map +1 -1
  769. package/dist/modes/interactive/key-handlers.js +1 -1
  770. package/dist/modes/interactive/key-handlers.js.map +1 -1
  771. package/dist/modes/interactive/local-model-commands.d.ts +43 -0
  772. package/dist/modes/interactive/local-model-commands.d.ts.map +1 -1
  773. package/dist/modes/interactive/local-model-commands.js +290 -3
  774. package/dist/modes/interactive/local-model-commands.js.map +1 -1
  775. package/dist/modes/interactive/profile-menu-controller.d.ts.map +1 -1
  776. package/dist/modes/interactive/profile-menu-controller.js +7 -7
  777. package/dist/modes/interactive/profile-menu-controller.js.map +1 -1
  778. package/dist/modes/interactive/report-commands.d.ts.map +1 -1
  779. package/dist/modes/interactive/report-commands.js +21 -0
  780. package/dist/modes/interactive/report-commands.js.map +1 -1
  781. package/dist/modes/interactive/session-flow-commands.d.ts +17 -2
  782. package/dist/modes/interactive/session-flow-commands.d.ts.map +1 -1
  783. package/dist/modes/interactive/session-flow-commands.js +74 -21
  784. package/dist/modes/interactive/session-flow-commands.js.map +1 -1
  785. package/dist/modes/interactive/session-io-commands.d.ts.map +1 -1
  786. package/dist/modes/interactive/session-io-commands.js +16 -6
  787. package/dist/modes/interactive/session-io-commands.js.map +1 -1
  788. package/dist/modes/interactive/session-replacement-errors.d.ts +7 -0
  789. package/dist/modes/interactive/session-replacement-errors.d.ts.map +1 -0
  790. package/dist/modes/interactive/session-replacement-errors.js +15 -0
  791. package/dist/modes/interactive/session-replacement-errors.js.map +1 -0
  792. package/dist/modes/interactive/startup-checks.d.ts.map +1 -1
  793. package/dist/modes/interactive/startup-checks.js +1 -1
  794. package/dist/modes/interactive/startup-checks.js.map +1 -1
  795. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  796. package/dist/modes/rpc/rpc-mode.js +82 -23
  797. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  798. package/dist/modes/rpc/rpc-types.d.ts +15 -0
  799. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  800. package/dist/modes/rpc/rpc-types.js +138 -1
  801. package/dist/modes/rpc/rpc-types.js.map +1 -1
  802. package/dist/utils/clipboard-image.d.ts.map +1 -1
  803. package/dist/utils/clipboard-image.js +2 -13
  804. package/dist/utils/clipboard-image.js.map +1 -1
  805. package/dist/utils/clipboard-native.d.ts +1 -0
  806. package/dist/utils/clipboard-native.d.ts.map +1 -1
  807. package/dist/utils/clipboard-native.js.map +1 -1
  808. package/dist/utils/clipboard.d.ts +1 -0
  809. package/dist/utils/clipboard.d.ts.map +1 -1
  810. package/dist/utils/clipboard.js +52 -1
  811. package/dist/utils/clipboard.js.map +1 -1
  812. package/dist/utils/fs-watch.d.ts +11 -0
  813. package/dist/utils/fs-watch.d.ts.map +1 -1
  814. package/dist/utils/fs-watch.js +20 -2
  815. package/dist/utils/fs-watch.js.map +1 -1
  816. package/dist/utils/highlight-js-languages.d.ts +4 -0
  817. package/dist/utils/highlight-js-languages.d.ts.map +1 -0
  818. package/dist/utils/highlight-js-languages.js +573 -0
  819. package/dist/utils/highlight-js-languages.js.map +1 -0
  820. package/dist/utils/platform.d.ts +3 -0
  821. package/dist/utils/platform.d.ts.map +1 -0
  822. package/dist/utils/platform.js +8 -0
  823. package/dist/utils/platform.js.map +1 -0
  824. package/dist/utils/shell.d.ts +7 -1
  825. package/dist/utils/shell.d.ts.map +1 -1
  826. package/dist/utils/shell.js +21 -6
  827. package/dist/utils/shell.js.map +1 -1
  828. package/dist/utils/syntax-highlight.d.ts.map +1 -1
  829. package/dist/utils/syntax-highlight.js +53 -5
  830. package/dist/utils/syntax-highlight.js.map +1 -1
  831. package/dist/utils/tools-manager.d.ts.map +1 -1
  832. package/dist/utils/tools-manager.js +112 -1
  833. package/dist/utils/tools-manager.js.map +1 -1
  834. package/dist/utils/work-directory.d.ts +11 -0
  835. package/dist/utils/work-directory.d.ts.map +1 -1
  836. package/dist/utils/work-directory.js +30 -9
  837. package/dist/utils/work-directory.js.map +1 -1
  838. package/docs/UI_POLISH_ORCHESTRATION.md +44 -0
  839. package/docs/UI_QUALITY_ORCHESTRATION.md +30 -0
  840. package/docs/docs.json +4 -0
  841. package/docs/extensions.md +62 -2
  842. package/docs/harness-architecture.md +156 -0
  843. package/docs/keybindings.md +11 -1
  844. package/docs/process-matrix.md +153 -0
  845. package/docs/rpc.md +45 -2
  846. package/docs/sessions.md +15 -0
  847. package/docs/settings.md +128 -11
  848. package/docs/task-steps.md +8 -0
  849. package/docs/telemetry.md +19 -0
  850. package/docs/tmux-agent-manager.md +92 -2
  851. package/docs/ui-reference/README.md +9 -0
  852. package/docs/ui-reference/orchestration-after.txt +7 -0
  853. package/docs/ui-reference/orchestration-before.txt +7 -0
  854. package/docs/ui-reference/orchestration-reference.txt +6 -0
  855. package/docs/usage.md +14 -2
  856. package/docs/windows.md +52 -3
  857. package/docs/work-directory.md +42 -2
  858. package/docs/worktree-sync.md +250 -0
  859. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  860. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  861. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  862. package/examples/extensions/question.ts +34 -245
  863. package/examples/extensions/questionnaire.ts +41 -407
  864. package/examples/extensions/sandbox/package-lock.json +2 -2
  865. package/examples/extensions/sandbox/package.json +1 -1
  866. package/examples/extensions/with-deps/package-lock.json +2 -2
  867. package/examples/extensions/with-deps/package.json +1 -1
  868. package/npm-shrinkwrap.json +12 -12
  869. package/package.json +10 -4
  870. package/dist/core/delegation/session-worker-result.d.ts +0 -16
  871. package/dist/core/delegation/session-worker-result.d.ts.map +0 -1
  872. package/dist/core/delegation/session-worker-result.js +0 -53
  873. package/dist/core/delegation/session-worker-result.js.map +0 -1
  874. package/dist/core/delegation/worker-result.d.ts +0 -15
  875. package/dist/core/delegation/worker-result.d.ts.map +0 -1
  876. package/dist/core/delegation/worker-result.js +0 -161
  877. package/dist/core/delegation/worker-result.js.map +0 -1
  878. package/dist/core/telemetry.d.ts.map +0 -1
  879. package/dist/core/telemetry.js.map +0 -1
  880. package/docs/integration-sweep-builder-blueprint-2026-07-09.md +0 -365
  881. package/docs/integration-sweep-resume-2026-07-09.md +0 -407
@@ -1 +1 @@
1
- {"version":3,"file":"file-store.d.ts","sourceRoot":"","sources":["../../../../src/core/memory/providers/file-store.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uCAAuC,CAAC;AAChF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAGhE,OAAO,KAAK,EAAE,sBAAsB,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAEpF;;;;GAIG;AACH,wBAAgB,0BAA0B,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAsB3F;AAiBD,qBAAa,iBAAkB,YAAW,cAAc;IACvD,SAAgB,IAAI,gBAAgB;IACpC,SAAgB,MAAM,WAAW;IAEjC,OAAO,CAAC,GAAG,CAAC,CAAyB;IACrC,OAAO,CAAC,cAAc,CAAM;IAC5B,OAAO,CAAC,YAAY,CAAM;IAE1B,OAAO,CAAC,iBAAiB,CAAM;IAC/B,OAAO,CAAC,eAAe,CAAM;IAG7B,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,aAAa,CAAQ;IAC7C,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,WAAW,CAAQ;IAEpC,WAAW,IAAI,OAAO,CAE5B;IAEM,eAAe;;MAErB;IAEY,UAAU,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC,CAqBtF;IAEM,iBAAiB,CAAC,MAAM,CAAC,EAAE,kBAAkB,GAAG,MAAM,CA4C5D;IAEY,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAGrD;IAEY,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,CAErC;IAEM,iBAAiB,IAAI,MAAM,EAAE,CAEnC;IAEM,kBAAkB,IAAI,cAAc,EAAE,CAoK5C;CACD","sourcesContent":["import { existsSync, promises as fs, mkdirSync, writeFileSync } from \"fs\";\nimport { join } from \"path\";\nimport lockfile from \"proper-lockfile\";\nimport { type Static, Type } from \"typebox\";\nimport type { MemoryPromptBudget } from \"../../context/memory-prompt-budget.ts\";\nimport type { ToolDefinition } from \"../../extensions/types.ts\";\nimport { hasInvisibleUnicode, scanContextFileThreats, stripInvisibleUnicode } from \"../../resource-loader.ts\";\nimport { jaccard, tokenize } from \"../../tools/skill-audit.ts\";\nimport type { MemoryLifecycleContext, MemoryProvider } from \"../memory-provider.ts\";\n\n/**\n * R5 confront-before-write (anti append-rot): if `content` is a near-duplicate of an existing\n * non-empty line (token Jaccard ≥ threshold — i.e. the same fact reworded), supersede that line in\n * place and return the rewritten file; otherwise return null (the caller appends normally).\n */\nexport function supersedeNearDuplicateLine(existing: string, content: string): string | null {\n\tconst NEAR_DUP_THRESHOLD = 0.6;\n\tconst contentTokens = tokenize(content);\n\tif (contentTokens.length === 0) return null;\n\tconst lines = existing.split(\"\\n\");\n\tlet bestIdx = -1;\n\tlet bestScore = NEAR_DUP_THRESHOLD;\n\tfor (let i = 0; i < lines.length; i++) {\n\t\tconst line = lines[i].trim();\n\t\tif (!line) continue;\n\t\t// Never supersede structural Markdown (headings, list markers as headings) — a fact must not\n\t\t// silently overwrite section structure (Bug #15).\n\t\tif (line.startsWith(\"#\")) continue;\n\t\tconst score = jaccard(contentTokens, tokenize(line));\n\t\tif (score >= bestScore) {\n\t\t\tbestScore = score;\n\t\t\tbestIdx = i;\n\t\t}\n\t}\n\tif (bestIdx === -1) return null;\n\tlines[bestIdx] = content;\n\treturn lines.join(\"\\n\");\n}\n\nconst memorySchema = Type.Object({\n\taction: Type.Union([Type.Literal(\"add\"), Type.Literal(\"replace\"), Type.Literal(\"remove\")], {\n\t\tdescription: \"Action to perform: add new content, replace existing content, or remove content\",\n\t}),\n\ttarget: Type.Union([Type.Literal(\"memory\"), Type.Literal(\"user\")], {\n\t\tdescription: \"Target file: 'memory' for MEMORY.md, 'user' for USER.md\",\n\t}),\n\tcontent: Type.Optional(Type.String({ description: \"Content to write (required for 'add' or 'replace')\" })),\n\toldContent: Type.Optional(\n\t\tType.String({ description: \"Exact substring to replace or remove (required for 'replace' or 'remove')\" }),\n\t),\n});\n\ntype MemoryParams = Static<typeof memorySchema>;\n\nexport class FileStoreProvider implements MemoryProvider {\n\tpublic readonly name = \"file-store\";\n\tpublic readonly egress = \"local\";\n\n\tprivate ctx?: MemoryLifecycleContext;\n\tprivate memoryFilePath = \"\";\n\tprivate userFilePath = \"\";\n\n\tprivate lastWrittenMemory = \"\";\n\tprivate lastWrittenUser = \"\";\n\n\t// Character budgets\n\tprivate static readonly BUDGET_MEMORY = 2200;\n\tprivate static readonly BUDGET_USER = 1375;\n\n\tpublic isAvailable(): boolean {\n\t\treturn true;\n\t}\n\n\tpublic getCapabilities() {\n\t\treturn { surfaces: [\"context\" as const] };\n\t}\n\n\tpublic async initialize(_sessionId: string, ctx: MemoryLifecycleContext): Promise<void> {\n\t\tthis.ctx = ctx;\n\t\tthis.memoryFilePath = join(ctx.agentDir, \"MEMORY.md\");\n\t\tthis.userFilePath = join(ctx.agentDir, \"USER.md\");\n\n\t\t// Ensure agentDir exists\n\t\tif (!existsSync(ctx.agentDir)) {\n\t\t\tmkdirSync(ctx.agentDir, { recursive: true });\n\t\t}\n\n\t\t// Initialize files if they do not exist\n\t\tif (!existsSync(this.memoryFilePath)) {\n\t\t\twriteFileSync(this.memoryFilePath, \"\", \"utf-8\");\n\t\t}\n\t\tif (!existsSync(this.userFilePath)) {\n\t\t\twriteFileSync(this.userFilePath, \"\", \"utf-8\");\n\t\t}\n\n\t\t// Load initial contents\n\t\tthis.lastWrittenMemory = await fs.readFile(this.memoryFilePath, \"utf-8\");\n\t\tthis.lastWrittenUser = await fs.readFile(this.userFilePath, \"utf-8\");\n\t}\n\n\tpublic systemPromptBlock(budget?: MemoryPromptBudget): string {\n\t\tconst sanitize = (content: string) => {\n\t\t\t// Strip hidden/bidi-control chars before injecting memory into the prompt (defence in depth: the\n\t\t\t// write path already blocks them, but a file edited out-of-band could carry them). Strip #31.\n\t\t\tconst lines = stripInvisibleUnicode(content).cleaned.split(\"\\n\");\n\t\t\tconst sanitizedLines = lines.map((line) => {\n\t\t\t\tconst threats = scanContextFileThreats(line);\n\t\t\t\tif (threats.length > 0) {\n\t\t\t\t\treturn `[BLOCKED: potential threat detected (${threats.join(\", \")})]`;\n\t\t\t\t}\n\t\t\t\treturn line;\n\t\t\t});\n\t\t\treturn sanitizedLines.join(\"\\n\");\n\t\t};\n\n\t\t// Read-time budget guard (cost): the memory tool already caps writes at BUDGET_*, but a file edited\n\t\t// externally (or by any path that bypasses the tool) could be arbitrarily large and would then\n\t\t// bloat the system prompt on EVERY turn. Cap the injected view to the same budget so the per-turn\n\t\t// cost stays bounded; the file on disk is untouched and the model is told it was truncated.\n\t\tconst cap = (content: string, limit: number) => {\n\t\t\tif (content.length <= limit) return content;\n\t\t\treturn `${content.slice(0, limit)}\\n[…truncated to ${limit} chars for the prompt; full file is on disk]`;\n\t\t};\n\n\t\tconst mem = cap(sanitize(this.lastWrittenMemory), FileStoreProvider.BUDGET_MEMORY);\n\t\tconst usr = cap(sanitize(this.lastWrittenUser), FileStoreProvider.BUDGET_USER);\n\n\t\tconst blocks: string[] = [];\n\t\tif (mem.trim()) {\n\t\t\tblocks.push(`## MEMORY.md:\\n${mem}`);\n\t\t}\n\t\tif (usr.trim()) {\n\t\t\tblocks.push(`## USER.md:\\n${usr}`);\n\t\t}\n\n\t\tif (blocks.length === 0) {\n\t\t\treturn \"\";\n\t\t}\n\n\t\tconst block = `=== Persistent Memory (file-store) ===\\n[System Note: Below is a snapshot of your persistent memory. You can update these using the 'memory' tool.]\\n\\n${blocks.join(\"\\n\\n\")}`;\n\t\tif (budget?.compact && (block.split(\"\\n\").length > budget.maxLines || block.length > budget.maxChars)) {\n\t\t\treturn \"\";\n\t\t}\n\t\treturn block;\n\t}\n\n\tpublic async prefetch(_query: string): Promise<string> {\n\t\t// static system prompt block is sufficient for file-store default; no-op prefetch\n\t\treturn \"\";\n\t}\n\n\tpublic async shutdown(): Promise<void> {\n\t\t// no-op\n\t}\n\n\tpublic getContextMarkers(): string[] {\n\t\treturn [];\n\t}\n\n\tpublic getToolDefinitions(): ToolDefinition[] {\n\t\treturn [\n\t\t\t{\n\t\t\t\tname: \"memory\",\n\t\t\t\tlabel: \"Persistent Memory Manager\",\n\t\t\t\tdescription: \"Add, replace, or remove contents in persistent memory files (MEMORY.md/USER.md).\",\n\t\t\t\tparameters: memorySchema,\n\t\t\t\texecute: async (_toolCallId, params: MemoryParams, _signal, _onUpdate, _execCtx) => {\n\t\t\t\t\tif (this.ctx?.isChildSession) {\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tcontent: [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\t\t\ttext: \"Error: Writes to persistent memory are not allowed in child sessions (subagents).\",\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\tdetails: { success: false, error: \"Child session write-gated\" },\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\n\t\t\t\t\tconst { action, target, content, oldContent } = params;\n\n\t\t\t\t\t// Strict-scope injection guard on the high-privilege WRITE path (agy #31): a poisoned\n\t\t\t\t\t// memory entry persists across sessions and is injected into every future system prompt,\n\t\t\t\t\t// so block outright rather than strip. Hidden/bidi-control chars have no legitimate place\n\t\t\t\t\t// in a memory note, so reject those too.\n\t\t\t\t\tif ((action === \"add\" || action === \"replace\") && content !== undefined) {\n\t\t\t\t\t\tif (hasInvisibleUnicode(content)) {\n\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\tcontent: [\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\t\t\t\ttext: \"Error: memory write rejected — contains hidden/bidirectional control characters.\",\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\tdetails: { success: false, error: \"Invisible unicode in memory write\" },\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconst threats = scanContextFileThreats(content, \"strict\");\n\t\t\t\t\t\tif (threats.length > 0) {\n\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\tcontent: [\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\t\t\t\ttext: `Error: memory write rejected — potential injection/exfiltration detected (${threats.join(\", \")}).`,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\tdetails: { success: false, error: \"Threat in memory write\" },\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tconst filePath = target === \"memory\" ? this.memoryFilePath : this.userFilePath;\n\t\t\t\t\tconst budget = target === \"memory\" ? FileStoreProvider.BUDGET_MEMORY : FileStoreProvider.BUDGET_USER;\n\n\t\t\t\t\tlet release: (() => Promise<void>) | undefined;\n\t\t\t\t\ttry {\n\t\t\t\t\t\t// File lock\n\t\t\t\t\t\trelease = await lockfile.lock(filePath, { realpath: false, retries: 5 });\n\n\t\t\t\t\t\tconst lastWritten = target === \"memory\" ? this.lastWrittenMemory : this.lastWrittenUser;\n\t\t\t\t\t\t// Read current file content on disk for drift detection\n\t\t\t\t\t\tconst currentOnDisk = await fs.readFile(filePath, \"utf-8\");\n\t\t\t\t\t\tif (currentOnDisk !== lastWritten) {\n\t\t\t\t\t\t\t// Drift detected. Backup current file and refuse write.\n\t\t\t\t\t\t\tconst backupPath = `${filePath}.bak.${Date.now()}`;\n\t\t\t\t\t\t\tawait fs.writeFile(backupPath, currentOnDisk, \"utf-8\");\n\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\tcontent: [\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\t\t\t\ttext: `Error: Drift detected. The memory file has been modified out-of-band by an external process. A backup was created at ${backupPath}. Operation aborted.`,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\tdetails: { success: false, error: \"Drift detected\" },\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tlet newContent = currentOnDisk;\n\t\t\t\t\t\tif (action === \"add\") {\n\t\t\t\t\t\t\tif (content === undefined) {\n\t\t\t\t\t\t\t\tthrow new Error(\"Parameter 'content' is required for action 'add'.\");\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t// R5: confront before write. If this fact is a near-duplicate of an existing line,\n\t\t\t\t\t\t\t// supersede it in place instead of appending a redundant copy (prevents append-rot).\n\t\t\t\t\t\t\tconst superseded = supersedeNearDuplicateLine(currentOnDisk, content);\n\t\t\t\t\t\t\tif (superseded !== null) {\n\t\t\t\t\t\t\t\tnewContent = superseded;\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tnewContent =\n\t\t\t\t\t\t\t\t\tnewContent.endsWith(\"\\n\") || newContent === \"\"\n\t\t\t\t\t\t\t\t\t\t? `${newContent}${content}\\n`\n\t\t\t\t\t\t\t\t\t\t: `${newContent}\\n${content}\\n`;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else if (action === \"replace\") {\n\t\t\t\t\t\t\tif (content === undefined || oldContent === undefined) {\n\t\t\t\t\t\t\t\tthrow new Error(\"Parameters 'content' and 'oldContent' are required for action 'replace'.\");\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (!currentOnDisk.includes(oldContent)) {\n\t\t\t\t\t\t\t\tthrow new Error(`The content to replace ('oldContent') was not found in the file.`);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tnewContent = currentOnDisk.replace(oldContent, content);\n\t\t\t\t\t\t} else if (action === \"remove\") {\n\t\t\t\t\t\t\tif (oldContent === undefined) {\n\t\t\t\t\t\t\t\tthrow new Error(\"Parameter 'oldContent' is required for action 'remove'.\");\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (!currentOnDisk.includes(oldContent)) {\n\t\t\t\t\t\t\t\tthrow new Error(`The content to remove ('oldContent') was not found in the file.`);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tnewContent = currentOnDisk.replace(oldContent, \"\");\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Budget check\n\t\t\t\t\t\tif (newContent.length > budget) {\n\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\tcontent: [\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\t\t\t\ttext: `Error: Memory budget exceeded. ${target === \"memory\" ? \"MEMORY.md\" : \"USER.md\"} limit is ${budget} characters. Current operation would result in ${newContent.length} characters.`,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\tdetails: { success: false, error: \"Memory budget exceeded\" },\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Atomic write\n\t\t\t\t\t\tconst tmpPath = `${filePath}.tmp`;\n\t\t\t\t\t\tawait fs.writeFile(tmpPath, newContent, \"utf-8\");\n\t\t\t\t\t\tawait fs.rename(tmpPath, filePath);\n\n\t\t\t\t\t\t// Update in-memory tracker\n\t\t\t\t\t\tif (target === \"memory\") {\n\t\t\t\t\t\t\tthis.lastWrittenMemory = newContent;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tthis.lastWrittenUser = newContent;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tcontent: [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\t\t\ttext: `Successfully updated ${target === \"memory\" ? \"MEMORY.md\" : \"USER.md\"}.`,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\tdetails: { success: true },\n\t\t\t\t\t\t};\n\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tcontent: [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\t\t\ttext: `Error: Failed to perform memory operation: ${String(err)}`,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\tdetails: { success: false, error: String(err) },\n\t\t\t\t\t\t};\n\t\t\t\t\t} finally {\n\t\t\t\t\t\tif (release) {\n\t\t\t\t\t\t\tawait release();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t},\n\t\t];\n\t}\n}\n"]}
1
+ {"version":3,"file":"file-store.d.ts","sourceRoot":"","sources":["../../../../src/core/memory/providers/file-store.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uCAAuC,CAAC;AAChF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAGhE,OAAO,KAAK,EAAE,sBAAsB,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAEpF;;;;GAIG;AACH,wBAAgB,0BAA0B,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAsB3F;AAiBD,qBAAa,iBAAkB,YAAW,cAAc;IACvD,SAAgB,IAAI,gBAAgB;IACpC,SAAgB,MAAM,WAAW;IAEjC,OAAO,CAAC,GAAG,CAAC,CAAyB;IACrC,OAAO,CAAC,cAAc,CAAM;IAC5B,OAAO,CAAC,YAAY,CAAM;IAE1B,OAAO,CAAC,iBAAiB,CAAM;IAC/B,OAAO,CAAC,eAAe,CAAM;IAG7B,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,aAAa,CAAQ;IAC7C,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,WAAW,CAAQ;IAEpC,WAAW,IAAI,OAAO,CAE5B;IAEM,eAAe;;MAErB;IAEY,UAAU,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC,CAqBtF;IAEM,iBAAiB,CAAC,MAAM,CAAC,EAAE,kBAAkB,GAAG,MAAM,CA4C5D;IAEY,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAGrD;IAEY,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,CAErC;IAEM,iBAAiB,IAAI,MAAM,EAAE,CAEnC;IAEM,kBAAkB,IAAI,cAAc,EAAE,CAoK5C;CACD","sourcesContent":["import { existsSync, promises as fs, mkdirSync, writeFileSync } from \"fs\";\nimport lockfile from \"proper-lockfile\";\nimport { type Static, Type } from \"typebox\";\nimport { configFile } from \"../../agent-paths.ts\";\nimport type { MemoryPromptBudget } from \"../../context/memory-prompt-budget.ts\";\nimport type { ToolDefinition } from \"../../extensions/types.ts\";\nimport { hasInvisibleUnicode, scanContextFileThreats, stripInvisibleUnicode } from \"../../resource-loader.ts\";\nimport { jaccard, tokenize } from \"../../tools/skill-audit.ts\";\nimport type { MemoryLifecycleContext, MemoryProvider } from \"../memory-provider.ts\";\n\n/**\n * Confront-before-write (anti append-rot): if `content` is a near-duplicate of an existing\n * non-empty line (token Jaccard ≥ threshold — i.e. the same fact reworded), supersede that line in\n * place and return the rewritten file; otherwise return null (the caller appends normally).\n */\nexport function supersedeNearDuplicateLine(existing: string, content: string): string | null {\n\tconst NEAR_DUP_THRESHOLD = 0.6;\n\tconst contentTokens = tokenize(content);\n\tif (contentTokens.length === 0) return null;\n\tconst lines = existing.split(\"\\n\");\n\tlet bestIdx = -1;\n\tlet bestScore = NEAR_DUP_THRESHOLD;\n\tfor (let i = 0; i < lines.length; i++) {\n\t\tconst line = lines[i].trim();\n\t\tif (!line) continue;\n\t\t// Never supersede structural Markdown (headings, list markers as headings) — a fact must not\n\t\t// silently overwrite section structure.\n\t\tif (line.startsWith(\"#\")) continue;\n\t\tconst score = jaccard(contentTokens, tokenize(line));\n\t\tif (score >= bestScore) {\n\t\t\tbestScore = score;\n\t\t\tbestIdx = i;\n\t\t}\n\t}\n\tif (bestIdx === -1) return null;\n\tlines[bestIdx] = content;\n\treturn lines.join(\"\\n\");\n}\n\nconst memorySchema = Type.Object({\n\taction: Type.Union([Type.Literal(\"add\"), Type.Literal(\"replace\"), Type.Literal(\"remove\")], {\n\t\tdescription: \"Action to perform: add new content, replace existing content, or remove content\",\n\t}),\n\ttarget: Type.Union([Type.Literal(\"memory\"), Type.Literal(\"user\")], {\n\t\tdescription: \"Target file: 'memory' for MEMORY.md, 'user' for USER.md\",\n\t}),\n\tcontent: Type.Optional(Type.String({ description: \"Content to write (required for 'add' or 'replace')\" })),\n\toldContent: Type.Optional(\n\t\tType.String({ description: \"Exact substring to replace or remove (required for 'replace' or 'remove')\" }),\n\t),\n});\n\ntype MemoryParams = Static<typeof memorySchema>;\n\nexport class FileStoreProvider implements MemoryProvider {\n\tpublic readonly name = \"file-store\";\n\tpublic readonly egress = \"local\";\n\n\tprivate ctx?: MemoryLifecycleContext;\n\tprivate memoryFilePath = \"\";\n\tprivate userFilePath = \"\";\n\n\tprivate lastWrittenMemory = \"\";\n\tprivate lastWrittenUser = \"\";\n\n\t// Character budgets\n\tprivate static readonly BUDGET_MEMORY = 2200;\n\tprivate static readonly BUDGET_USER = 1375;\n\n\tpublic isAvailable(): boolean {\n\t\treturn true;\n\t}\n\n\tpublic getCapabilities() {\n\t\treturn { surfaces: [\"context\" as const] };\n\t}\n\n\tpublic async initialize(_sessionId: string, ctx: MemoryLifecycleContext): Promise<void> {\n\t\tthis.ctx = ctx;\n\t\tthis.memoryFilePath = configFile(ctx.agentDir, \"MEMORY.md\");\n\t\tthis.userFilePath = configFile(ctx.agentDir, \"USER.md\");\n\n\t\t// Ensure agentDir exists\n\t\tif (!existsSync(ctx.agentDir)) {\n\t\t\tmkdirSync(ctx.agentDir, { recursive: true });\n\t\t}\n\n\t\t// Initialize files if they do not exist\n\t\tif (!existsSync(this.memoryFilePath)) {\n\t\t\twriteFileSync(this.memoryFilePath, \"\", \"utf-8\");\n\t\t}\n\t\tif (!existsSync(this.userFilePath)) {\n\t\t\twriteFileSync(this.userFilePath, \"\", \"utf-8\");\n\t\t}\n\n\t\t// Load initial contents\n\t\tthis.lastWrittenMemory = await fs.readFile(this.memoryFilePath, \"utf-8\");\n\t\tthis.lastWrittenUser = await fs.readFile(this.userFilePath, \"utf-8\");\n\t}\n\n\tpublic systemPromptBlock(budget?: MemoryPromptBudget): string {\n\t\tconst sanitize = (content: string) => {\n\t\t\t// Strip hidden/bidi-control chars before injecting memory into the prompt (defence in depth: the\n\t\t\t// write path already blocks them, but a file edited out-of-band could carry them). Strip #31.\n\t\t\tconst lines = stripInvisibleUnicode(content).cleaned.split(\"\\n\");\n\t\t\tconst sanitizedLines = lines.map((line) => {\n\t\t\t\tconst threats = scanContextFileThreats(line);\n\t\t\t\tif (threats.length > 0) {\n\t\t\t\t\treturn `[BLOCKED: potential threat detected (${threats.join(\", \")})]`;\n\t\t\t\t}\n\t\t\t\treturn line;\n\t\t\t});\n\t\t\treturn sanitizedLines.join(\"\\n\");\n\t\t};\n\n\t\t// Read-time budget guard (cost): the memory tool already caps writes at BUDGET_*, but a file edited\n\t\t// externally (or by any path that bypasses the tool) could be arbitrarily large and would then\n\t\t// bloat the system prompt on EVERY turn. Cap the injected view to the same budget so the per-turn\n\t\t// cost stays bounded; the file on disk is untouched and the model is told it was truncated.\n\t\tconst cap = (content: string, limit: number) => {\n\t\t\tif (content.length <= limit) return content;\n\t\t\treturn `${content.slice(0, limit)}\\n[…truncated to ${limit} chars for the prompt; full file is on disk]`;\n\t\t};\n\n\t\tconst mem = cap(sanitize(this.lastWrittenMemory), FileStoreProvider.BUDGET_MEMORY);\n\t\tconst usr = cap(sanitize(this.lastWrittenUser), FileStoreProvider.BUDGET_USER);\n\n\t\tconst blocks: string[] = [];\n\t\tif (mem.trim()) {\n\t\t\tblocks.push(`## MEMORY.md:\\n${mem}`);\n\t\t}\n\t\tif (usr.trim()) {\n\t\t\tblocks.push(`## USER.md:\\n${usr}`);\n\t\t}\n\n\t\tif (blocks.length === 0) {\n\t\t\treturn \"\";\n\t\t}\n\n\t\tconst block = `=== Persistent Memory (file-store) ===\\n[System Note: Below is a snapshot of your persistent memory. You can update these using the 'memory' tool.]\\n\\n${blocks.join(\"\\n\\n\")}`;\n\t\tif (budget?.compact && (block.split(\"\\n\").length > budget.maxLines || block.length > budget.maxChars)) {\n\t\t\treturn \"\";\n\t\t}\n\t\treturn block;\n\t}\n\n\tpublic async prefetch(_query: string): Promise<string> {\n\t\t// static system prompt block is sufficient for file-store default; no-op prefetch\n\t\treturn \"\";\n\t}\n\n\tpublic async shutdown(): Promise<void> {\n\t\t// no-op\n\t}\n\n\tpublic getContextMarkers(): string[] {\n\t\treturn [];\n\t}\n\n\tpublic getToolDefinitions(): ToolDefinition[] {\n\t\treturn [\n\t\t\t{\n\t\t\t\tname: \"memory\",\n\t\t\t\tlabel: \"Persistent Memory Manager\",\n\t\t\t\tdescription: \"Add, replace, or remove contents in persistent memory files (MEMORY.md/USER.md).\",\n\t\t\t\tparameters: memorySchema,\n\t\t\t\texecute: async (_toolCallId, params: MemoryParams, _signal, _onUpdate, _execCtx) => {\n\t\t\t\t\tif (this.ctx?.isChildSession) {\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tcontent: [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\t\t\ttext: \"Error: Writes to persistent memory are not allowed in child sessions (subagents).\",\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\tdetails: { success: false, error: \"Child session write-gated\" },\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\n\t\t\t\t\tconst { action, target, content, oldContent } = params;\n\n\t\t\t\t\t// Strict-scope injection guard on the high-privilege WRITE path (agy #31): a poisoned\n\t\t\t\t\t// memory entry persists across sessions and is injected into every future system prompt,\n\t\t\t\t\t// so block outright rather than strip. Hidden/bidi-control chars have no legitimate place\n\t\t\t\t\t// in a memory note, so reject those too.\n\t\t\t\t\tif ((action === \"add\" || action === \"replace\") && content !== undefined) {\n\t\t\t\t\t\tif (hasInvisibleUnicode(content)) {\n\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\tcontent: [\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\t\t\t\ttext: \"Error: memory write rejected — contains hidden/bidirectional control characters.\",\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\tdetails: { success: false, error: \"Invisible unicode in memory write\" },\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconst threats = scanContextFileThreats(content, \"strict\");\n\t\t\t\t\t\tif (threats.length > 0) {\n\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\tcontent: [\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\t\t\t\ttext: `Error: memory write rejected — potential injection/exfiltration detected (${threats.join(\", \")}).`,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\tdetails: { success: false, error: \"Threat in memory write\" },\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tconst filePath = target === \"memory\" ? this.memoryFilePath : this.userFilePath;\n\t\t\t\t\tconst budget = target === \"memory\" ? FileStoreProvider.BUDGET_MEMORY : FileStoreProvider.BUDGET_USER;\n\n\t\t\t\t\tlet release: (() => Promise<void>) | undefined;\n\t\t\t\t\ttry {\n\t\t\t\t\t\t// File lock\n\t\t\t\t\t\trelease = await lockfile.lock(filePath, { realpath: false, retries: 5 });\n\n\t\t\t\t\t\tconst lastWritten = target === \"memory\" ? this.lastWrittenMemory : this.lastWrittenUser;\n\t\t\t\t\t\t// Read current file content on disk for drift detection\n\t\t\t\t\t\tconst currentOnDisk = await fs.readFile(filePath, \"utf-8\");\n\t\t\t\t\t\tif (currentOnDisk !== lastWritten) {\n\t\t\t\t\t\t\t// Drift detected. Backup current file and refuse write.\n\t\t\t\t\t\t\tconst backupPath = `${filePath}.bak.${Date.now()}`;\n\t\t\t\t\t\t\tawait fs.writeFile(backupPath, currentOnDisk, \"utf-8\");\n\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\tcontent: [\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\t\t\t\ttext: `Error: Drift detected. The memory file has been modified out-of-band by an external process. A backup was created at ${backupPath}. Operation aborted.`,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\tdetails: { success: false, error: \"Drift detected\" },\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tlet newContent = currentOnDisk;\n\t\t\t\t\t\tif (action === \"add\") {\n\t\t\t\t\t\t\tif (content === undefined) {\n\t\t\t\t\t\t\t\tthrow new Error(\"Parameter 'content' is required for action 'add'.\");\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t// Confront before write. If this fact is a near-duplicate of an existing line,\n\t\t\t\t\t\t\t// supersede it in place instead of appending a redundant copy (prevents append-rot).\n\t\t\t\t\t\t\tconst superseded = supersedeNearDuplicateLine(currentOnDisk, content);\n\t\t\t\t\t\t\tif (superseded !== null) {\n\t\t\t\t\t\t\t\tnewContent = superseded;\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tnewContent =\n\t\t\t\t\t\t\t\t\tnewContent.endsWith(\"\\n\") || newContent === \"\"\n\t\t\t\t\t\t\t\t\t\t? `${newContent}${content}\\n`\n\t\t\t\t\t\t\t\t\t\t: `${newContent}\\n${content}\\n`;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else if (action === \"replace\") {\n\t\t\t\t\t\t\tif (content === undefined || oldContent === undefined) {\n\t\t\t\t\t\t\t\tthrow new Error(\"Parameters 'content' and 'oldContent' are required for action 'replace'.\");\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (!currentOnDisk.includes(oldContent)) {\n\t\t\t\t\t\t\t\tthrow new Error(`The content to replace ('oldContent') was not found in the file.`);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tnewContent = currentOnDisk.replace(oldContent, content);\n\t\t\t\t\t\t} else if (action === \"remove\") {\n\t\t\t\t\t\t\tif (oldContent === undefined) {\n\t\t\t\t\t\t\t\tthrow new Error(\"Parameter 'oldContent' is required for action 'remove'.\");\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (!currentOnDisk.includes(oldContent)) {\n\t\t\t\t\t\t\t\tthrow new Error(`The content to remove ('oldContent') was not found in the file.`);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tnewContent = currentOnDisk.replace(oldContent, \"\");\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Budget check\n\t\t\t\t\t\tif (newContent.length > budget) {\n\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\tcontent: [\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\t\t\t\ttext: `Error: Memory budget exceeded. ${target === \"memory\" ? \"MEMORY.md\" : \"USER.md\"} limit is ${budget} characters. Current operation would result in ${newContent.length} characters.`,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\tdetails: { success: false, error: \"Memory budget exceeded\" },\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Atomic write\n\t\t\t\t\t\tconst tmpPath = `${filePath}.tmp`;\n\t\t\t\t\t\tawait fs.writeFile(tmpPath, newContent, \"utf-8\");\n\t\t\t\t\t\tawait fs.rename(tmpPath, filePath);\n\n\t\t\t\t\t\t// Update in-memory tracker\n\t\t\t\t\t\tif (target === \"memory\") {\n\t\t\t\t\t\t\tthis.lastWrittenMemory = newContent;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tthis.lastWrittenUser = newContent;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tcontent: [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\t\t\ttext: `Successfully updated ${target === \"memory\" ? \"MEMORY.md\" : \"USER.md\"}.`,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\tdetails: { success: true },\n\t\t\t\t\t\t};\n\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tcontent: [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\t\t\ttext: `Error: Failed to perform memory operation: ${String(err)}`,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\tdetails: { success: false, error: String(err) },\n\t\t\t\t\t\t};\n\t\t\t\t\t} finally {\n\t\t\t\t\t\tif (release) {\n\t\t\t\t\t\t\tawait release();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t},\n\t\t];\n\t}\n}\n"]}
@@ -1,11 +1,11 @@
1
1
  import { existsSync, promises as fs, mkdirSync, writeFileSync } from "fs";
2
- import { join } from "path";
3
2
  import lockfile from "proper-lockfile";
4
3
  import { Type } from "typebox";
4
+ import { configFile } from "../../agent-paths.js";
5
5
  import { hasInvisibleUnicode, scanContextFileThreats, stripInvisibleUnicode } from "../../resource-loader.js";
6
6
  import { jaccard, tokenize } from "../../tools/skill-audit.js";
7
7
  /**
8
- * R5 confront-before-write (anti append-rot): if `content` is a near-duplicate of an existing
8
+ * Confront-before-write (anti append-rot): if `content` is a near-duplicate of an existing
9
9
  * non-empty line (token Jaccard ≥ threshold — i.e. the same fact reworded), supersede that line in
10
10
  * place and return the rewritten file; otherwise return null (the caller appends normally).
11
11
  */
@@ -22,7 +22,7 @@ export function supersedeNearDuplicateLine(existing, content) {
22
22
  if (!line)
23
23
  continue;
24
24
  // Never supersede structural Markdown (headings, list markers as headings) — a fact must not
25
- // silently overwrite section structure (Bug #15).
25
+ // silently overwrite section structure.
26
26
  if (line.startsWith("#"))
27
27
  continue;
28
28
  const score = jaccard(contentTokens, tokenize(line));
@@ -65,8 +65,8 @@ export class FileStoreProvider {
65
65
  }
66
66
  async initialize(_sessionId, ctx) {
67
67
  this.ctx = ctx;
68
- this.memoryFilePath = join(ctx.agentDir, "MEMORY.md");
69
- this.userFilePath = join(ctx.agentDir, "USER.md");
68
+ this.memoryFilePath = configFile(ctx.agentDir, "MEMORY.md");
69
+ this.userFilePath = configFile(ctx.agentDir, "USER.md");
70
70
  // Ensure agentDir exists
71
71
  if (!existsSync(ctx.agentDir)) {
72
72
  mkdirSync(ctx.agentDir, { recursive: true });
@@ -210,7 +210,7 @@ export class FileStoreProvider {
210
210
  if (content === undefined) {
211
211
  throw new Error("Parameter 'content' is required for action 'add'.");
212
212
  }
213
- // R5: confront before write. If this fact is a near-duplicate of an existing line,
213
+ // Confront before write. If this fact is a near-duplicate of an existing line,
214
214
  // supersede it in place instead of appending a redundant copy (prevents append-rot).
215
215
  const superseded = supersedeNearDuplicateLine(currentOnDisk, content);
216
216
  if (superseded !== null) {
@@ -1 +1 @@
1
- {"version":3,"file":"file-store.js","sourceRoot":"","sources":["../../../../src/core/memory/providers/file-store.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync, promises as fs, mkdirSync, writeFileSync } from \"fs\";\nimport { join } from \"path\";\nimport lockfile from \"proper-lockfile\";\nimport { type Static, Type } from \"typebox\";\nimport type { MemoryPromptBudget } from \"../../context/memory-prompt-budget.ts\";\nimport type { ToolDefinition } from \"../../extensions/types.ts\";\nimport { hasInvisibleUnicode, scanContextFileThreats, stripInvisibleUnicode } from \"../../resource-loader.ts\";\nimport { jaccard, tokenize } from \"../../tools/skill-audit.ts\";\nimport type { MemoryLifecycleContext, MemoryProvider } from \"../memory-provider.ts\";\n\n/**\n * R5 confront-before-write (anti append-rot): if `content` is a near-duplicate of an existing\n * non-empty line (token Jaccard ≥ threshold — i.e. the same fact reworded), supersede that line in\n * place and return the rewritten file; otherwise return null (the caller appends normally).\n */\nexport function supersedeNearDuplicateLine(existing: string, content: string): string | null {\n\tconst NEAR_DUP_THRESHOLD = 0.6;\n\tconst contentTokens = tokenize(content);\n\tif (contentTokens.length === 0) return null;\n\tconst lines = existing.split(\"\\n\");\n\tlet bestIdx = -1;\n\tlet bestScore = NEAR_DUP_THRESHOLD;\n\tfor (let i = 0; i < lines.length; i++) {\n\t\tconst line = lines[i].trim();\n\t\tif (!line) continue;\n\t\t// Never supersede structural Markdown (headings, list markers as headings) — a fact must not\n\t\t// silently overwrite section structure (Bug #15).\n\t\tif (line.startsWith(\"#\")) continue;\n\t\tconst score = jaccard(contentTokens, tokenize(line));\n\t\tif (score >= bestScore) {\n\t\t\tbestScore = score;\n\t\t\tbestIdx = i;\n\t\t}\n\t}\n\tif (bestIdx === -1) return null;\n\tlines[bestIdx] = content;\n\treturn lines.join(\"\\n\");\n}\n\nconst memorySchema = Type.Object({\n\taction: Type.Union([Type.Literal(\"add\"), Type.Literal(\"replace\"), Type.Literal(\"remove\")], {\n\t\tdescription: \"Action to perform: add new content, replace existing content, or remove content\",\n\t}),\n\ttarget: Type.Union([Type.Literal(\"memory\"), Type.Literal(\"user\")], {\n\t\tdescription: \"Target file: 'memory' for MEMORY.md, 'user' for USER.md\",\n\t}),\n\tcontent: Type.Optional(Type.String({ description: \"Content to write (required for 'add' or 'replace')\" })),\n\toldContent: Type.Optional(\n\t\tType.String({ description: \"Exact substring to replace or remove (required for 'replace' or 'remove')\" }),\n\t),\n});\n\ntype MemoryParams = Static<typeof memorySchema>;\n\nexport class FileStoreProvider implements MemoryProvider {\n\tpublic readonly name = \"file-store\";\n\tpublic readonly egress = \"local\";\n\n\tprivate ctx?: MemoryLifecycleContext;\n\tprivate memoryFilePath = \"\";\n\tprivate userFilePath = \"\";\n\n\tprivate lastWrittenMemory = \"\";\n\tprivate lastWrittenUser = \"\";\n\n\t// Character budgets\n\tprivate static readonly BUDGET_MEMORY = 2200;\n\tprivate static readonly BUDGET_USER = 1375;\n\n\tpublic isAvailable(): boolean {\n\t\treturn true;\n\t}\n\n\tpublic getCapabilities() {\n\t\treturn { surfaces: [\"context\" as const] };\n\t}\n\n\tpublic async initialize(_sessionId: string, ctx: MemoryLifecycleContext): Promise<void> {\n\t\tthis.ctx = ctx;\n\t\tthis.memoryFilePath = join(ctx.agentDir, \"MEMORY.md\");\n\t\tthis.userFilePath = join(ctx.agentDir, \"USER.md\");\n\n\t\t// Ensure agentDir exists\n\t\tif (!existsSync(ctx.agentDir)) {\n\t\t\tmkdirSync(ctx.agentDir, { recursive: true });\n\t\t}\n\n\t\t// Initialize files if they do not exist\n\t\tif (!existsSync(this.memoryFilePath)) {\n\t\t\twriteFileSync(this.memoryFilePath, \"\", \"utf-8\");\n\t\t}\n\t\tif (!existsSync(this.userFilePath)) {\n\t\t\twriteFileSync(this.userFilePath, \"\", \"utf-8\");\n\t\t}\n\n\t\t// Load initial contents\n\t\tthis.lastWrittenMemory = await fs.readFile(this.memoryFilePath, \"utf-8\");\n\t\tthis.lastWrittenUser = await fs.readFile(this.userFilePath, \"utf-8\");\n\t}\n\n\tpublic systemPromptBlock(budget?: MemoryPromptBudget): string {\n\t\tconst sanitize = (content: string) => {\n\t\t\t// Strip hidden/bidi-control chars before injecting memory into the prompt (defence in depth: the\n\t\t\t// write path already blocks them, but a file edited out-of-band could carry them). Strip #31.\n\t\t\tconst lines = stripInvisibleUnicode(content).cleaned.split(\"\\n\");\n\t\t\tconst sanitizedLines = lines.map((line) => {\n\t\t\t\tconst threats = scanContextFileThreats(line);\n\t\t\t\tif (threats.length > 0) {\n\t\t\t\t\treturn `[BLOCKED: potential threat detected (${threats.join(\", \")})]`;\n\t\t\t\t}\n\t\t\t\treturn line;\n\t\t\t});\n\t\t\treturn sanitizedLines.join(\"\\n\");\n\t\t};\n\n\t\t// Read-time budget guard (cost): the memory tool already caps writes at BUDGET_*, but a file edited\n\t\t// externally (or by any path that bypasses the tool) could be arbitrarily large and would then\n\t\t// bloat the system prompt on EVERY turn. Cap the injected view to the same budget so the per-turn\n\t\t// cost stays bounded; the file on disk is untouched and the model is told it was truncated.\n\t\tconst cap = (content: string, limit: number) => {\n\t\t\tif (content.length <= limit) return content;\n\t\t\treturn `${content.slice(0, limit)}\\n[…truncated to ${limit} chars for the prompt; full file is on disk]`;\n\t\t};\n\n\t\tconst mem = cap(sanitize(this.lastWrittenMemory), FileStoreProvider.BUDGET_MEMORY);\n\t\tconst usr = cap(sanitize(this.lastWrittenUser), FileStoreProvider.BUDGET_USER);\n\n\t\tconst blocks: string[] = [];\n\t\tif (mem.trim()) {\n\t\t\tblocks.push(`## MEMORY.md:\\n${mem}`);\n\t\t}\n\t\tif (usr.trim()) {\n\t\t\tblocks.push(`## USER.md:\\n${usr}`);\n\t\t}\n\n\t\tif (blocks.length === 0) {\n\t\t\treturn \"\";\n\t\t}\n\n\t\tconst block = `=== Persistent Memory (file-store) ===\\n[System Note: Below is a snapshot of your persistent memory. You can update these using the 'memory' tool.]\\n\\n${blocks.join(\"\\n\\n\")}`;\n\t\tif (budget?.compact && (block.split(\"\\n\").length > budget.maxLines || block.length > budget.maxChars)) {\n\t\t\treturn \"\";\n\t\t}\n\t\treturn block;\n\t}\n\n\tpublic async prefetch(_query: string): Promise<string> {\n\t\t// static system prompt block is sufficient for file-store default; no-op prefetch\n\t\treturn \"\";\n\t}\n\n\tpublic async shutdown(): Promise<void> {\n\t\t// no-op\n\t}\n\n\tpublic getContextMarkers(): string[] {\n\t\treturn [];\n\t}\n\n\tpublic getToolDefinitions(): ToolDefinition[] {\n\t\treturn [\n\t\t\t{\n\t\t\t\tname: \"memory\",\n\t\t\t\tlabel: \"Persistent Memory Manager\",\n\t\t\t\tdescription: \"Add, replace, or remove contents in persistent memory files (MEMORY.md/USER.md).\",\n\t\t\t\tparameters: memorySchema,\n\t\t\t\texecute: async (_toolCallId, params: MemoryParams, _signal, _onUpdate, _execCtx) => {\n\t\t\t\t\tif (this.ctx?.isChildSession) {\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tcontent: [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\t\t\ttext: \"Error: Writes to persistent memory are not allowed in child sessions (subagents).\",\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\tdetails: { success: false, error: \"Child session write-gated\" },\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\n\t\t\t\t\tconst { action, target, content, oldContent } = params;\n\n\t\t\t\t\t// Strict-scope injection guard on the high-privilege WRITE path (agy #31): a poisoned\n\t\t\t\t\t// memory entry persists across sessions and is injected into every future system prompt,\n\t\t\t\t\t// so block outright rather than strip. Hidden/bidi-control chars have no legitimate place\n\t\t\t\t\t// in a memory note, so reject those too.\n\t\t\t\t\tif ((action === \"add\" || action === \"replace\") && content !== undefined) {\n\t\t\t\t\t\tif (hasInvisibleUnicode(content)) {\n\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\tcontent: [\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\t\t\t\ttext: \"Error: memory write rejected — contains hidden/bidirectional control characters.\",\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\tdetails: { success: false, error: \"Invisible unicode in memory write\" },\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconst threats = scanContextFileThreats(content, \"strict\");\n\t\t\t\t\t\tif (threats.length > 0) {\n\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\tcontent: [\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\t\t\t\ttext: `Error: memory write rejected — potential injection/exfiltration detected (${threats.join(\", \")}).`,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\tdetails: { success: false, error: \"Threat in memory write\" },\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tconst filePath = target === \"memory\" ? this.memoryFilePath : this.userFilePath;\n\t\t\t\t\tconst budget = target === \"memory\" ? FileStoreProvider.BUDGET_MEMORY : FileStoreProvider.BUDGET_USER;\n\n\t\t\t\t\tlet release: (() => Promise<void>) | undefined;\n\t\t\t\t\ttry {\n\t\t\t\t\t\t// File lock\n\t\t\t\t\t\trelease = await lockfile.lock(filePath, { realpath: false, retries: 5 });\n\n\t\t\t\t\t\tconst lastWritten = target === \"memory\" ? this.lastWrittenMemory : this.lastWrittenUser;\n\t\t\t\t\t\t// Read current file content on disk for drift detection\n\t\t\t\t\t\tconst currentOnDisk = await fs.readFile(filePath, \"utf-8\");\n\t\t\t\t\t\tif (currentOnDisk !== lastWritten) {\n\t\t\t\t\t\t\t// Drift detected. Backup current file and refuse write.\n\t\t\t\t\t\t\tconst backupPath = `${filePath}.bak.${Date.now()}`;\n\t\t\t\t\t\t\tawait fs.writeFile(backupPath, currentOnDisk, \"utf-8\");\n\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\tcontent: [\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\t\t\t\ttext: `Error: Drift detected. The memory file has been modified out-of-band by an external process. A backup was created at ${backupPath}. Operation aborted.`,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\tdetails: { success: false, error: \"Drift detected\" },\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tlet newContent = currentOnDisk;\n\t\t\t\t\t\tif (action === \"add\") {\n\t\t\t\t\t\t\tif (content === undefined) {\n\t\t\t\t\t\t\t\tthrow new Error(\"Parameter 'content' is required for action 'add'.\");\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t// R5: confront before write. If this fact is a near-duplicate of an existing line,\n\t\t\t\t\t\t\t// supersede it in place instead of appending a redundant copy (prevents append-rot).\n\t\t\t\t\t\t\tconst superseded = supersedeNearDuplicateLine(currentOnDisk, content);\n\t\t\t\t\t\t\tif (superseded !== null) {\n\t\t\t\t\t\t\t\tnewContent = superseded;\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tnewContent =\n\t\t\t\t\t\t\t\t\tnewContent.endsWith(\"\\n\") || newContent === \"\"\n\t\t\t\t\t\t\t\t\t\t? `${newContent}${content}\\n`\n\t\t\t\t\t\t\t\t\t\t: `${newContent}\\n${content}\\n`;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else if (action === \"replace\") {\n\t\t\t\t\t\t\tif (content === undefined || oldContent === undefined) {\n\t\t\t\t\t\t\t\tthrow new Error(\"Parameters 'content' and 'oldContent' are required for action 'replace'.\");\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (!currentOnDisk.includes(oldContent)) {\n\t\t\t\t\t\t\t\tthrow new Error(`The content to replace ('oldContent') was not found in the file.`);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tnewContent = currentOnDisk.replace(oldContent, content);\n\t\t\t\t\t\t} else if (action === \"remove\") {\n\t\t\t\t\t\t\tif (oldContent === undefined) {\n\t\t\t\t\t\t\t\tthrow new Error(\"Parameter 'oldContent' is required for action 'remove'.\");\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (!currentOnDisk.includes(oldContent)) {\n\t\t\t\t\t\t\t\tthrow new Error(`The content to remove ('oldContent') was not found in the file.`);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tnewContent = currentOnDisk.replace(oldContent, \"\");\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Budget check\n\t\t\t\t\t\tif (newContent.length > budget) {\n\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\tcontent: [\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\t\t\t\ttext: `Error: Memory budget exceeded. ${target === \"memory\" ? \"MEMORY.md\" : \"USER.md\"} limit is ${budget} characters. Current operation would result in ${newContent.length} characters.`,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\tdetails: { success: false, error: \"Memory budget exceeded\" },\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Atomic write\n\t\t\t\t\t\tconst tmpPath = `${filePath}.tmp`;\n\t\t\t\t\t\tawait fs.writeFile(tmpPath, newContent, \"utf-8\");\n\t\t\t\t\t\tawait fs.rename(tmpPath, filePath);\n\n\t\t\t\t\t\t// Update in-memory tracker\n\t\t\t\t\t\tif (target === \"memory\") {\n\t\t\t\t\t\t\tthis.lastWrittenMemory = newContent;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tthis.lastWrittenUser = newContent;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tcontent: [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\t\t\ttext: `Successfully updated ${target === \"memory\" ? \"MEMORY.md\" : \"USER.md\"}.`,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\tdetails: { success: true },\n\t\t\t\t\t\t};\n\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tcontent: [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\t\t\ttext: `Error: Failed to perform memory operation: ${String(err)}`,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\tdetails: { success: false, error: String(err) },\n\t\t\t\t\t\t};\n\t\t\t\t\t} finally {\n\t\t\t\t\t\tif (release) {\n\t\t\t\t\t\t\tawait release();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t},\n\t\t];\n\t}\n}\n"]}
1
+ {"version":3,"file":"file-store.js","sourceRoot":"","sources":["../../../../src/core/memory/providers/file-store.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync, promises as fs, mkdirSync, writeFileSync } from \"fs\";\nimport lockfile from \"proper-lockfile\";\nimport { type Static, Type } from \"typebox\";\nimport { configFile } from \"../../agent-paths.ts\";\nimport type { MemoryPromptBudget } from \"../../context/memory-prompt-budget.ts\";\nimport type { ToolDefinition } from \"../../extensions/types.ts\";\nimport { hasInvisibleUnicode, scanContextFileThreats, stripInvisibleUnicode } from \"../../resource-loader.ts\";\nimport { jaccard, tokenize } from \"../../tools/skill-audit.ts\";\nimport type { MemoryLifecycleContext, MemoryProvider } from \"../memory-provider.ts\";\n\n/**\n * Confront-before-write (anti append-rot): if `content` is a near-duplicate of an existing\n * non-empty line (token Jaccard ≥ threshold — i.e. the same fact reworded), supersede that line in\n * place and return the rewritten file; otherwise return null (the caller appends normally).\n */\nexport function supersedeNearDuplicateLine(existing: string, content: string): string | null {\n\tconst NEAR_DUP_THRESHOLD = 0.6;\n\tconst contentTokens = tokenize(content);\n\tif (contentTokens.length === 0) return null;\n\tconst lines = existing.split(\"\\n\");\n\tlet bestIdx = -1;\n\tlet bestScore = NEAR_DUP_THRESHOLD;\n\tfor (let i = 0; i < lines.length; i++) {\n\t\tconst line = lines[i].trim();\n\t\tif (!line) continue;\n\t\t// Never supersede structural Markdown (headings, list markers as headings) — a fact must not\n\t\t// silently overwrite section structure.\n\t\tif (line.startsWith(\"#\")) continue;\n\t\tconst score = jaccard(contentTokens, tokenize(line));\n\t\tif (score >= bestScore) {\n\t\t\tbestScore = score;\n\t\t\tbestIdx = i;\n\t\t}\n\t}\n\tif (bestIdx === -1) return null;\n\tlines[bestIdx] = content;\n\treturn lines.join(\"\\n\");\n}\n\nconst memorySchema = Type.Object({\n\taction: Type.Union([Type.Literal(\"add\"), Type.Literal(\"replace\"), Type.Literal(\"remove\")], {\n\t\tdescription: \"Action to perform: add new content, replace existing content, or remove content\",\n\t}),\n\ttarget: Type.Union([Type.Literal(\"memory\"), Type.Literal(\"user\")], {\n\t\tdescription: \"Target file: 'memory' for MEMORY.md, 'user' for USER.md\",\n\t}),\n\tcontent: Type.Optional(Type.String({ description: \"Content to write (required for 'add' or 'replace')\" })),\n\toldContent: Type.Optional(\n\t\tType.String({ description: \"Exact substring to replace or remove (required for 'replace' or 'remove')\" }),\n\t),\n});\n\ntype MemoryParams = Static<typeof memorySchema>;\n\nexport class FileStoreProvider implements MemoryProvider {\n\tpublic readonly name = \"file-store\";\n\tpublic readonly egress = \"local\";\n\n\tprivate ctx?: MemoryLifecycleContext;\n\tprivate memoryFilePath = \"\";\n\tprivate userFilePath = \"\";\n\n\tprivate lastWrittenMemory = \"\";\n\tprivate lastWrittenUser = \"\";\n\n\t// Character budgets\n\tprivate static readonly BUDGET_MEMORY = 2200;\n\tprivate static readonly BUDGET_USER = 1375;\n\n\tpublic isAvailable(): boolean {\n\t\treturn true;\n\t}\n\n\tpublic getCapabilities() {\n\t\treturn { surfaces: [\"context\" as const] };\n\t}\n\n\tpublic async initialize(_sessionId: string, ctx: MemoryLifecycleContext): Promise<void> {\n\t\tthis.ctx = ctx;\n\t\tthis.memoryFilePath = configFile(ctx.agentDir, \"MEMORY.md\");\n\t\tthis.userFilePath = configFile(ctx.agentDir, \"USER.md\");\n\n\t\t// Ensure agentDir exists\n\t\tif (!existsSync(ctx.agentDir)) {\n\t\t\tmkdirSync(ctx.agentDir, { recursive: true });\n\t\t}\n\n\t\t// Initialize files if they do not exist\n\t\tif (!existsSync(this.memoryFilePath)) {\n\t\t\twriteFileSync(this.memoryFilePath, \"\", \"utf-8\");\n\t\t}\n\t\tif (!existsSync(this.userFilePath)) {\n\t\t\twriteFileSync(this.userFilePath, \"\", \"utf-8\");\n\t\t}\n\n\t\t// Load initial contents\n\t\tthis.lastWrittenMemory = await fs.readFile(this.memoryFilePath, \"utf-8\");\n\t\tthis.lastWrittenUser = await fs.readFile(this.userFilePath, \"utf-8\");\n\t}\n\n\tpublic systemPromptBlock(budget?: MemoryPromptBudget): string {\n\t\tconst sanitize = (content: string) => {\n\t\t\t// Strip hidden/bidi-control chars before injecting memory into the prompt (defence in depth: the\n\t\t\t// write path already blocks them, but a file edited out-of-band could carry them). Strip #31.\n\t\t\tconst lines = stripInvisibleUnicode(content).cleaned.split(\"\\n\");\n\t\t\tconst sanitizedLines = lines.map((line) => {\n\t\t\t\tconst threats = scanContextFileThreats(line);\n\t\t\t\tif (threats.length > 0) {\n\t\t\t\t\treturn `[BLOCKED: potential threat detected (${threats.join(\", \")})]`;\n\t\t\t\t}\n\t\t\t\treturn line;\n\t\t\t});\n\t\t\treturn sanitizedLines.join(\"\\n\");\n\t\t};\n\n\t\t// Read-time budget guard (cost): the memory tool already caps writes at BUDGET_*, but a file edited\n\t\t// externally (or by any path that bypasses the tool) could be arbitrarily large and would then\n\t\t// bloat the system prompt on EVERY turn. Cap the injected view to the same budget so the per-turn\n\t\t// cost stays bounded; the file on disk is untouched and the model is told it was truncated.\n\t\tconst cap = (content: string, limit: number) => {\n\t\t\tif (content.length <= limit) return content;\n\t\t\treturn `${content.slice(0, limit)}\\n[…truncated to ${limit} chars for the prompt; full file is on disk]`;\n\t\t};\n\n\t\tconst mem = cap(sanitize(this.lastWrittenMemory), FileStoreProvider.BUDGET_MEMORY);\n\t\tconst usr = cap(sanitize(this.lastWrittenUser), FileStoreProvider.BUDGET_USER);\n\n\t\tconst blocks: string[] = [];\n\t\tif (mem.trim()) {\n\t\t\tblocks.push(`## MEMORY.md:\\n${mem}`);\n\t\t}\n\t\tif (usr.trim()) {\n\t\t\tblocks.push(`## USER.md:\\n${usr}`);\n\t\t}\n\n\t\tif (blocks.length === 0) {\n\t\t\treturn \"\";\n\t\t}\n\n\t\tconst block = `=== Persistent Memory (file-store) ===\\n[System Note: Below is a snapshot of your persistent memory. You can update these using the 'memory' tool.]\\n\\n${blocks.join(\"\\n\\n\")}`;\n\t\tif (budget?.compact && (block.split(\"\\n\").length > budget.maxLines || block.length > budget.maxChars)) {\n\t\t\treturn \"\";\n\t\t}\n\t\treturn block;\n\t}\n\n\tpublic async prefetch(_query: string): Promise<string> {\n\t\t// static system prompt block is sufficient for file-store default; no-op prefetch\n\t\treturn \"\";\n\t}\n\n\tpublic async shutdown(): Promise<void> {\n\t\t// no-op\n\t}\n\n\tpublic getContextMarkers(): string[] {\n\t\treturn [];\n\t}\n\n\tpublic getToolDefinitions(): ToolDefinition[] {\n\t\treturn [\n\t\t\t{\n\t\t\t\tname: \"memory\",\n\t\t\t\tlabel: \"Persistent Memory Manager\",\n\t\t\t\tdescription: \"Add, replace, or remove contents in persistent memory files (MEMORY.md/USER.md).\",\n\t\t\t\tparameters: memorySchema,\n\t\t\t\texecute: async (_toolCallId, params: MemoryParams, _signal, _onUpdate, _execCtx) => {\n\t\t\t\t\tif (this.ctx?.isChildSession) {\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tcontent: [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\t\t\ttext: \"Error: Writes to persistent memory are not allowed in child sessions (subagents).\",\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\tdetails: { success: false, error: \"Child session write-gated\" },\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\n\t\t\t\t\tconst { action, target, content, oldContent } = params;\n\n\t\t\t\t\t// Strict-scope injection guard on the high-privilege WRITE path (agy #31): a poisoned\n\t\t\t\t\t// memory entry persists across sessions and is injected into every future system prompt,\n\t\t\t\t\t// so block outright rather than strip. Hidden/bidi-control chars have no legitimate place\n\t\t\t\t\t// in a memory note, so reject those too.\n\t\t\t\t\tif ((action === \"add\" || action === \"replace\") && content !== undefined) {\n\t\t\t\t\t\tif (hasInvisibleUnicode(content)) {\n\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\tcontent: [\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\t\t\t\ttext: \"Error: memory write rejected — contains hidden/bidirectional control characters.\",\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\tdetails: { success: false, error: \"Invisible unicode in memory write\" },\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconst threats = scanContextFileThreats(content, \"strict\");\n\t\t\t\t\t\tif (threats.length > 0) {\n\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\tcontent: [\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\t\t\t\ttext: `Error: memory write rejected — potential injection/exfiltration detected (${threats.join(\", \")}).`,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\tdetails: { success: false, error: \"Threat in memory write\" },\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tconst filePath = target === \"memory\" ? this.memoryFilePath : this.userFilePath;\n\t\t\t\t\tconst budget = target === \"memory\" ? FileStoreProvider.BUDGET_MEMORY : FileStoreProvider.BUDGET_USER;\n\n\t\t\t\t\tlet release: (() => Promise<void>) | undefined;\n\t\t\t\t\ttry {\n\t\t\t\t\t\t// File lock\n\t\t\t\t\t\trelease = await lockfile.lock(filePath, { realpath: false, retries: 5 });\n\n\t\t\t\t\t\tconst lastWritten = target === \"memory\" ? this.lastWrittenMemory : this.lastWrittenUser;\n\t\t\t\t\t\t// Read current file content on disk for drift detection\n\t\t\t\t\t\tconst currentOnDisk = await fs.readFile(filePath, \"utf-8\");\n\t\t\t\t\t\tif (currentOnDisk !== lastWritten) {\n\t\t\t\t\t\t\t// Drift detected. Backup current file and refuse write.\n\t\t\t\t\t\t\tconst backupPath = `${filePath}.bak.${Date.now()}`;\n\t\t\t\t\t\t\tawait fs.writeFile(backupPath, currentOnDisk, \"utf-8\");\n\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\tcontent: [\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\t\t\t\ttext: `Error: Drift detected. The memory file has been modified out-of-band by an external process. A backup was created at ${backupPath}. Operation aborted.`,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\tdetails: { success: false, error: \"Drift detected\" },\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tlet newContent = currentOnDisk;\n\t\t\t\t\t\tif (action === \"add\") {\n\t\t\t\t\t\t\tif (content === undefined) {\n\t\t\t\t\t\t\t\tthrow new Error(\"Parameter 'content' is required for action 'add'.\");\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t// Confront before write. If this fact is a near-duplicate of an existing line,\n\t\t\t\t\t\t\t// supersede it in place instead of appending a redundant copy (prevents append-rot).\n\t\t\t\t\t\t\tconst superseded = supersedeNearDuplicateLine(currentOnDisk, content);\n\t\t\t\t\t\t\tif (superseded !== null) {\n\t\t\t\t\t\t\t\tnewContent = superseded;\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tnewContent =\n\t\t\t\t\t\t\t\t\tnewContent.endsWith(\"\\n\") || newContent === \"\"\n\t\t\t\t\t\t\t\t\t\t? `${newContent}${content}\\n`\n\t\t\t\t\t\t\t\t\t\t: `${newContent}\\n${content}\\n`;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else if (action === \"replace\") {\n\t\t\t\t\t\t\tif (content === undefined || oldContent === undefined) {\n\t\t\t\t\t\t\t\tthrow new Error(\"Parameters 'content' and 'oldContent' are required for action 'replace'.\");\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (!currentOnDisk.includes(oldContent)) {\n\t\t\t\t\t\t\t\tthrow new Error(`The content to replace ('oldContent') was not found in the file.`);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tnewContent = currentOnDisk.replace(oldContent, content);\n\t\t\t\t\t\t} else if (action === \"remove\") {\n\t\t\t\t\t\t\tif (oldContent === undefined) {\n\t\t\t\t\t\t\t\tthrow new Error(\"Parameter 'oldContent' is required for action 'remove'.\");\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (!currentOnDisk.includes(oldContent)) {\n\t\t\t\t\t\t\t\tthrow new Error(`The content to remove ('oldContent') was not found in the file.`);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tnewContent = currentOnDisk.replace(oldContent, \"\");\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Budget check\n\t\t\t\t\t\tif (newContent.length > budget) {\n\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\tcontent: [\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\t\t\t\ttext: `Error: Memory budget exceeded. ${target === \"memory\" ? \"MEMORY.md\" : \"USER.md\"} limit is ${budget} characters. Current operation would result in ${newContent.length} characters.`,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\tdetails: { success: false, error: \"Memory budget exceeded\" },\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Atomic write\n\t\t\t\t\t\tconst tmpPath = `${filePath}.tmp`;\n\t\t\t\t\t\tawait fs.writeFile(tmpPath, newContent, \"utf-8\");\n\t\t\t\t\t\tawait fs.rename(tmpPath, filePath);\n\n\t\t\t\t\t\t// Update in-memory tracker\n\t\t\t\t\t\tif (target === \"memory\") {\n\t\t\t\t\t\t\tthis.lastWrittenMemory = newContent;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tthis.lastWrittenUser = newContent;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tcontent: [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\t\t\ttext: `Successfully updated ${target === \"memory\" ? \"MEMORY.md\" : \"USER.md\"}.`,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\tdetails: { success: true },\n\t\t\t\t\t\t};\n\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tcontent: [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\t\t\ttext: `Error: Failed to perform memory operation: ${String(err)}`,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\tdetails: { success: false, error: String(err) },\n\t\t\t\t\t\t};\n\t\t\t\t\t} finally {\n\t\t\t\t\t\tif (release) {\n\t\t\t\t\t\t\tawait release();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t},\n\t\t];\n\t}\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"memory-controller.d.ts","sourceRoot":"","sources":["../../src/core/memory-controller.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Memory controller: the session's plug-and-play memory subsystem — the read-only OKF retrieval\n * provider, the bounded prompt-evidence surfacing pilot, cross-session recall effectiveness, and the\n * live {@link MemoryManager} (bundled file-store + transcript-recall providers plus any extension\n * contributions).\n *\n * Extracted verbatim from agent-session.ts (god-file decomposition). Owns the lazily-built OKF\n * provider, the latest retrieval/prompt-inclusion reports, the recreated-on-reload MemoryManager, the\n * recall {@link EffectivenessTracker}, and the extension-contributed pending providers. Everything\n * else it needs — settings, the current turn index, agent/workspace dirs, the session id, the\n * child-session flag, and the tool-registry refresh — is reached through narrow deps accessors rather\n * than the whole AgentSession.\n *\n * Context-transform boundary (deliberate): {@link runMemoryRetrieval} and\n * {@link maybeAppendMemoryEvidenceBlock} are invoked from the session's context transform as one-line\n * delegations. This controller deliberately imports no compaction/context-pipeline internals — it only\n * ever reads settings and builds the retrieval report + the bounded evidence block, so the transform\n * stays the single owner of the pass ordering.\n */\n\nimport { join } from \"node:path\";\nimport type { AgentMessage, CustomMessage } from \"@caupulican/pi-agent-core\";\nimport { collectCurrentWorkMemory } from \"./context/current-work-memory.ts\";\nimport { createFileStoreMemoryProvider } from \"./context/file-store-memory-provider.ts\";\nimport { shouldQueryLongTermMemory } from \"./context/long-term-memory-trigger.ts\";\nimport {\n\tdefaultMemoryPromptInclusionReport,\n\ttype MemoryPromptInclusionReport,\n\ttype MemoryRetrievalDiagnostics,\n\tsanitizeMemoryRetrievalReportForDiagnostics,\n} from \"./context/memory-diagnostics.ts\";\nimport { type MemoryPromptBudget, resolveMemoryPromptBudget } from \"./context/memory-prompt-budget.ts\";\nimport {\n\ttype MemoryProvider as ContextMemoryProvider,\n\tDEFAULT_EXTERNAL_MEMORY_EGRESS_POLICY,\n\tDEFAULT_LOCAL_MEMORY_EGRESS_POLICY,\n} from \"./context/memory-provider-contract.ts\";\nimport { type MemoryRetrievalReport, retrieveMemoryForContext } from \"./context/memory-retrieval.ts\";\nimport { composeTieredMemoryPromptBlock, type MemoryTierCandidate } from \"./context/memory-tier-composer.ts\";\nimport { createOkfMemoryProvider } from \"./context/okf-memory-provider.ts\";\nimport type { GoalState } from \"./goals/goal-state.ts\";\nimport { EffectivenessTracker } from \"./memory/effectiveness-tracker.ts\";\nimport { MemoryManager } from \"./memory/memory-manager.ts\";\nimport type { MemoryProvider } from \"./memory/memory-provider.ts\";\nimport { FileStoreProvider } from \"./memory/providers/file-store.ts\";\nimport { TranscriptRecallProvider } from \"./memory/providers/transcript-recall.ts\";\nimport { wrapUntrustedText } from \"./security/untrusted-boundary.ts\";\nimport type { SettingsManager } from \"./settings-manager.ts\";\n\n/**\n * Text of the most recent user message, or \"\" if there is none (e.g. goal-continuation\n * turns with no new user input). An empty query is still valid: standing user preferences may\n * surface from the file-store retrieval fallback when the static memory prompt cannot fit,\n * while long-term providers remain gated by shouldQueryLongTermMemory().\n */\nfunction latestUserMessageText(messages: AgentMessage[]): string {\n\tfor (let index = messages.length - 1; index >= 0; index--) {\n\t\tconst message = messages[index];\n\t\tif (message.role !== \"user\") continue;\n\t\tif (typeof message.content === \"string\") return message.content;\n\t\tconst parts: string[] = [];\n\t\tfor (const part of message.content) {\n\t\t\tif (part.type === \"text\") parts.push(part.text);\n\t\t}\n\t\treturn parts.join(\"\\n\");\n\t}\n\treturn \"\";\n}\n\nfunction emptyMemoryRetrievalReport(maxResults: number): MemoryRetrievalReport {\n\treturn { request: { query: \"\", maxResults }, providerReports: [], results: [], contextItems: [] };\n}\n\nconst ENABLED_EXTERNAL_MEMORY_EGRESS_POLICY = {\n\t...DEFAULT_EXTERNAL_MEMORY_EGRESS_POLICY,\n\tenabled: true,\n\tallowedScopes: DEFAULT_LOCAL_MEMORY_EGRESS_POLICY.allowedScopes,\n\tallowExternalEgress: true,\n} as const;\n\nexport interface MemoryControllerDeps {\n\t/** Memory-retrieval + prompt-inclusion settings (default-on gates for retrieval and surfacing). */\n\tgetSettingsManager(): SettingsManager;\n\t/** Current turn index, stamped into a retrieval request's `createdAtTurn`. */\n\tgetTurnIndex(): number;\n\t/** Agent root — the durable OKF memory docs live under `<agentDir>/okf-memory`. */\n\tgetAgentDir(): string;\n\t/** Workspace root, passed to provider initialization. */\n\tgetCwd(): string;\n\t/** This session's id, passed to provider initialization. */\n\tgetSessionId(): string;\n\t/** Child sessions gate durable memory writes; passed to provider initialization. */\n\tisChildSession(): boolean;\n\t/** Re-derive the tool registry after (re)init so the newly-surfaced memory tools take effect. */\n\trefreshToolRegistry(): void;\n\t/** Active model context window, used to cap prompt-visible memory. */\n\tgetContextWindow(): number | undefined;\n\t/** Latest active goal state, used for short-term current-work memory. */\n\tgetGoalState(): GoalState | undefined;\n}\n\n/** Extension-contributed memory state staged across an atomic runtime reload. */\nexport interface MemoryControllerReloadSnapshot {\n\tpendingMemoryProviders: MemoryProvider[];\n\tpendingContextMemoryProviders: ContextMemoryProvider[];\n\tmemoryOkfProvider: ContextMemoryProvider | undefined;\n\tfileStoreMemoryProvider: ContextMemoryProvider | undefined;\n}\n\nexport class MemoryController {\n\tprivate _memoryOkfProvider: ContextMemoryProvider | undefined = undefined;\n\tprivate _fileStoreMemoryProvider: ContextMemoryProvider | undefined = undefined;\n\tprivate _latestMemoryRetrievalReport: MemoryRetrievalReport | undefined = undefined;\n\tprivate _latestMemoryPromptInclusionReport: MemoryPromptInclusionReport | undefined = undefined;\n\t/** Plug-and-play memory subsystem. Recreated on each (re)initialize so reload is safe. */\n\tprivate _memoryManager: MemoryManager = new MemoryManager();\n\t/** R4: tracks whether injected recall is actually used, to adapt the recall gate. */\n\tprivate readonly _effectivenessTracker = new EffectivenessTracker();\n\t/** Memory providers registered by extensions via pi.registerMemoryProvider, applied on (re)init. */\n\tprivate _pendingMemoryProviders: MemoryProvider[] = [];\n\t/** Context-memory providers registered by extensions via pi.registerContextMemoryProvider. */\n\tprivate _pendingContextMemoryProviders: ContextMemoryProvider[] = [];\n\n\tprivate readonly deps: MemoryControllerDeps;\n\n\tconstructor(deps: MemoryControllerDeps) {\n\t\tthis.deps = deps;\n\t}\n\n\t/** The live memory manager. Callers reach prefetch / tool-definitions / markers / shutdown through it. */\n\tgetMemoryManager(): MemoryManager {\n\t\treturn this._memoryManager;\n\t}\n\n\t/**\n\t * Fixed path for this slice's local Pi OKF memory documents, shared across sessions\n\t * under this agentDir (not session-scoped, unlike tool-artifacts/context-gc, since OKF\n\t * memory represents durable cross-session knowledge, not a per-session capture). Not\n\t * yet user-configurable -- see the memory-retrieval settings doc comment.\n\t */\n\tprivate _memoryOkfDir(): string {\n\t\treturn join(this.deps.getAgentDir(), \"okf-memory\");\n\t}\n\n\t/**\n\t * Session-scoped, read-only local OKF memory provider. Lazily created ONLY when memory\n\t * retrieval is enabled (see `runMemoryRetrieval`) -- never force-created, so a session\n\t * with the setting off never touches `_memoryOkfDir()` at all (no directory access, no\n\t * creation; `createOkfMemoryProvider` itself never writes/mkdirs either way).\n\t */\n\tprivate _getMemoryOkfProvider(): ContextMemoryProvider {\n\t\tthis._memoryOkfProvider ??= createOkfMemoryProvider({ rootDir: this._memoryOkfDir() });\n\t\treturn this._memoryOkfProvider;\n\t}\n\n\tprivate _getFileStoreMemoryProvider(): ContextMemoryProvider {\n\t\tthis._fileStoreMemoryProvider ??= createFileStoreMemoryProvider({\n\t\t\tmemoryFilePath: join(this.deps.getAgentDir(), \"MEMORY.md\"),\n\t\t\tuserFilePath: join(this.deps.getAgentDir(), \"USER.md\"),\n\t\t});\n\t\treturn this._fileStoreMemoryProvider;\n\t}\n\n\tprivate _memoryBudget(configuredMaxResults: number) {\n\t\treturn resolveMemoryPromptBudget({\n\t\t\tcontextWindow: this.deps.getContextWindow(),\n\t\t\tconfiguredMaxResults,\n\t\t});\n\t}\n\n\tprivate _shouldQueryFileStoreFallback(budget: MemoryPromptBudget): boolean {\n\t\t// MEMORY.md/USER.md are already injected through the static file-store prompt on\n\t\t// normal windows, so querying them again would duplicate provider-visible memory.\n\t\t// In compact windows the static block can be omitted because it does not fit; only\n\t\t// then use the retrieval view to surface a few budget-pruned lines.\n\t\tif (!budget.enabled || !budget.compact) return false;\n\t\treturn this._memoryManager.buildSystemPromptBlock(budget).trim().length === 0;\n\t}\n\n\t/**\n\t * Observe-only local memory retrieval (see context/memory-retrieval.ts and\n\t * context/okf-memory-provider.ts): default-on, but settings-gated. When disabled,\n\t * never constructs built-in context-memory providers (no directory access under\n\t * `_memoryOkfDir()` at all) and returns an empty report -- fully fail-closed. When enabled,\n\t * queries local, read-only providers with the latest user message text (empty if there is\n\t * none, e.g. a goal-continuation turn) under `DEFAULT_LOCAL_MEMORY_EGRESS_POLICY`.\n\t * Retrieved items are only ever stored in the report; nothing here touches `messages`,\n\t * the transcript, or the provider-visible prompt. Never throws into a live turn: any\n\t * failure (including a provider search error) degrades to an empty report.\n\t */\n\tasync runMemoryRetrieval(messages: AgentMessage[]): Promise<MemoryRetrievalReport> {\n\t\ttry {\n\t\t\tconst settings = this.deps.getSettingsManager().getMemoryRetrievalSettings();\n\t\t\tif (!settings.enabled) {\n\t\t\t\tconst report = emptyMemoryRetrievalReport(settings.maxResults);\n\t\t\t\tthis._latestMemoryRetrievalReport = report;\n\t\t\t\treturn report;\n\t\t\t}\n\t\t\tconst query = latestUserMessageText(messages);\n\t\t\tconst budget = this._memoryBudget(settings.maxResults);\n\t\t\tconst currentWork = collectCurrentWorkMemory({ goalState: this.deps.getGoalState() });\n\t\t\tconst longTermDecision = shouldQueryLongTermMemory({\n\t\t\t\tlatestUserText: query,\n\t\t\t\tgoalState: this.deps.getGoalState(),\n\t\t\t\tbudget,\n\t\t\t\tcurrentWorkCandidateCount: currentWork.length,\n\t\t\t});\n\t\t\tconst providers = this._shouldQueryFileStoreFallback(budget) ? [this._getFileStoreMemoryProvider()] : [];\n\t\t\tif (longTermDecision.shouldQuery) {\n\t\t\t\tproviders.push(this._getMemoryOkfProvider(), ...this._pendingContextMemoryProviders);\n\t\t\t}\n\t\t\tconst maxResults = budget.enabled ? Math.min(settings.maxResults, budget.maxResults) : settings.maxResults;\n\t\t\tconst report = await retrieveMemoryForContext(\n\t\t\t\tproviders,\n\t\t\t\t{ query, maxResults },\n\t\t\t\t{\n\t\t\t\t\tcreatedAtTurn: this.deps.getTurnIndex(),\n\t\t\t\t\tmaxResults,\n\t\t\t\t\tdefaultLocalPolicy: DEFAULT_LOCAL_MEMORY_EGRESS_POLICY,\n\t\t\t\t\tdefaultExternalPolicy: settings.allowExternalEgress\n\t\t\t\t\t\t? ENABLED_EXTERNAL_MEMORY_EGRESS_POLICY\n\t\t\t\t\t\t: DEFAULT_EXTERNAL_MEMORY_EGRESS_POLICY,\n\t\t\t\t},\n\t\t\t);\n\t\t\tthis._latestMemoryRetrievalReport = report;\n\t\t\treturn report;\n\t\t} catch {\n\t\t\tconst report = emptyMemoryRetrievalReport(0);\n\t\t\tthis._latestMemoryRetrievalReport = report;\n\t\t\treturn report;\n\t\t}\n\t}\n\n\t/** Read-only inspection of the latest memory-retrieval report, for tests/debugging. */\n\tgetMemoryRetrievalReport(): MemoryRetrievalReport {\n\t\treturn this._latestMemoryRetrievalReport ?? emptyMemoryRetrievalReport(0);\n\t}\n\n\tprivate _candidateForContextItem(\n\t\titem: MemoryRetrievalReport[\"contextItems\"][number],\n\t): MemoryTierCandidate | undefined {\n\t\tconst summary = item.summary?.trim();\n\t\tif (!summary) return undefined;\n\t\tconst ref = item.primaryRef?.type === \"memory\" ? item.primaryRef.ref : undefined;\n\t\tconst sourceLabel =\n\t\t\tref?.providerId === \"pi-file-store\" && ref.kind === \"user_preference\"\n\t\t\t\t? \"rule:user\"\n\t\t\t\t: `memory:${ref?.providerId ?? item.source}`;\n\t\tconst tier = ref?.kind === \"user_preference\" ? \"standing\" : \"long_term\";\n\t\treturn {\n\t\t\tid: item.id,\n\t\t\ttier,\n\t\t\tsourceLabel,\n\t\t\tsummary,\n\t\t\tscore: 0.5,\n\t\t\tevidenceRefs: item.evidenceRefs,\n\t\t};\n\t}\n\n\tprivate _memoryCandidates(report: MemoryRetrievalReport): MemoryTierCandidate[] {\n\t\treturn [\n\t\t\t...collectCurrentWorkMemory({ goalState: this.deps.getGoalState() }),\n\t\t\t...report.contextItems.flatMap((item) => {\n\t\t\t\tconst candidate = this._candidateForContextItem(item);\n\t\t\t\treturn candidate === undefined ? [] : [candidate];\n\t\t\t}),\n\t\t];\n\t}\n\n\t/**\n\t * Bounded prompt-surfacing for local memory evidence (see context/memory-tier-composer.ts):\n\t * default-on, but gated on TWO settings (`enabled` AND `includeInPrompt`) plus at least one\n\t * current-work, standing, or retrieved memory candidate -- the first\n\t * two are belt-and-suspenders on top of the fact that `runMemoryRetrieval` already\n\t * leaves `contextItems` empty whenever `enabled` is false, regardless of\n\t * `includeInPrompt`. Reuses the `report` this pass's `runMemoryRetrieval` call already\n\t * computed -- never re-queries the provider here.\n\t *\n\t * Appends exactly one ephemeral `custom`/\"memory_evidence\" message wrapped by\n\t * `wrapUntrustedText` (the same nonce-fenced boundary + always-on system-prompt rule\n\t * used for other untrusted content) to the END of `messages`. This is purely additive\n\t * (never mutates an existing message) and purely transient: `messages` here is the\n\t * array about to be sent to the provider, not `this.agent.state.messages` or anything\n\t * persisted via `sessionManager` -- so the injected message can never reach the\n\t * transcript, regardless of how many times this pass runs.\n\t *\n\t * Also records a `MemoryPromptInclusionReport` (context/memory-diagnostics.ts) at each\n\t * branch below, for context_audit's diagnostic surface only -- this is pure bookkeeping\n\t * alongside the existing branches, not a new branch/condition: the messages returned\n\t * are unchanged by this recording.\n\t */\n\tmaybeAppendMemoryEvidenceBlock(messages: AgentMessage[], report: MemoryRetrievalReport): AgentMessage[] {\n\t\ttry {\n\t\t\tconst settings = this.deps.getSettingsManager().getMemoryRetrievalSettings();\n\t\t\tconst candidates = this._memoryCandidates(report);\n\t\t\tconst base = {\n\t\t\t\tenabled: settings.enabled,\n\t\t\t\tincludeInPrompt: settings.includeInPrompt,\n\t\t\t\tselectedItemCount: candidates.length,\n\t\t\t};\n\t\t\tif (!settings.enabled) {\n\t\t\t\tthis._latestMemoryPromptInclusionReport = {\n\t\t\t\t\t...base,\n\t\t\t\t\tstatus: \"disabled\",\n\t\t\t\t\tincludedCount: 0,\n\t\t\t\t\tomittedCount: 0,\n\t\t\t\t\tblockChars: 0,\n\t\t\t\t};\n\t\t\t\treturn messages;\n\t\t\t}\n\t\t\tif (!settings.includeInPrompt) {\n\t\t\t\tthis._latestMemoryPromptInclusionReport = {\n\t\t\t\t\t...base,\n\t\t\t\t\tstatus: \"include_disabled\",\n\t\t\t\t\tincludedCount: 0,\n\t\t\t\t\tomittedCount: 0,\n\t\t\t\t\tblockChars: 0,\n\t\t\t\t};\n\t\t\t\treturn messages;\n\t\t\t}\n\t\t\tif (candidates.length === 0) {\n\t\t\t\tthis._latestMemoryPromptInclusionReport = {\n\t\t\t\t\t...base,\n\t\t\t\t\tstatus: \"no_results\",\n\t\t\t\t\tincludedCount: 0,\n\t\t\t\t\tomittedCount: 0,\n\t\t\t\t\tblockChars: 0,\n\t\t\t\t};\n\t\t\t\treturn messages;\n\t\t\t}\n\n\t\t\tconst budget = this._memoryBudget(settings.maxResults);\n\t\t\tconst block = composeTieredMemoryPromptBlock(candidates, budget);\n\t\t\tif (!block.text) {\n\t\t\t\tthis._latestMemoryPromptInclusionReport = {\n\t\t\t\t\t...base,\n\t\t\t\t\tstatus: \"empty_block\",\n\t\t\t\t\tincludedCount: block.includedCount,\n\t\t\t\t\tomittedCount: block.omittedCount,\n\t\t\t\t\tblockChars: 0,\n\t\t\t\t};\n\t\t\t\treturn messages;\n\t\t\t}\n\n\t\t\tconst wrapped = wrapUntrustedText(block.text, \"memory:tiered\");\n\t\t\tconst evidenceMessage: CustomMessage = {\n\t\t\t\trole: \"custom\",\n\t\t\t\tcustomType: \"memory_evidence\",\n\t\t\t\tcontent: [{ type: \"text\", text: wrapped }],\n\t\t\t\tdisplay: false,\n\t\t\t\ttimestamp: Date.now(),\n\t\t\t};\n\t\t\tthis._latestMemoryPromptInclusionReport = {\n\t\t\t\t...base,\n\t\t\t\tstatus: \"included\",\n\t\t\t\tincludedCount: block.includedCount,\n\t\t\t\tomittedCount: block.omittedCount,\n\t\t\t\tblockChars: wrapped.length,\n\t\t\t\tsourceLabel: \"memory:tiered\",\n\t\t\t};\n\t\t\treturn [...messages, evidenceMessage];\n\t\t} catch {\n\t\t\t// `base` may not exist yet if the throw happened before it was computed (e.g.\n\t\t\t// settings access or `report.contextItems` itself threw), so this branch cannot\n\t\t\t// rely on it -- fall back to safe, fixed defaults rather than risk referencing\n\t\t\t// a partially-evaluated value.\n\t\t\tthis._latestMemoryPromptInclusionReport = {\n\t\t\t\tenabled: false,\n\t\t\t\tincludeInPrompt: false,\n\t\t\t\tselectedItemCount: 0,\n\t\t\t\tstatus: \"failed\",\n\t\t\t\tincludedCount: 0,\n\t\t\t\tomittedCount: 0,\n\t\t\t\tblockChars: 0,\n\t\t\t};\n\t\t\treturn messages;\n\t\t}\n\t}\n\n\t/** Read-only inspection of the latest memory-prompt-inclusion decision, for tests/debugging and context_audit. */\n\tgetMemoryPromptInclusionReport(): MemoryPromptInclusionReport {\n\t\treturn this._latestMemoryPromptInclusionReport ?? defaultMemoryPromptInclusionReport();\n\t}\n\n\t/**\n\t * Combines the already-stored, no-arg latest reports (never re-queries the provider or\n\t * touches the OKF directory) into the safe, allow-list-projected shape context_audit\n\t * exposes. See context/memory-diagnostics.ts for why this projection is allow-list\n\t * based rather than a spread-then-delete of the raw report.\n\t */\n\tgetMemoryAuditDiagnostics(): {\n\t\tretrieval: MemoryRetrievalDiagnostics;\n\t\tpromptInclusion: MemoryPromptInclusionReport;\n\t} {\n\t\tconst settings = this.deps.getSettingsManager().getMemoryRetrievalSettings();\n\t\treturn {\n\t\t\tretrieval: sanitizeMemoryRetrievalReportForDiagnostics(this.getMemoryRetrievalReport(), settings),\n\t\t\tpromptInclusion: this.getMemoryPromptInclusionReport(),\n\t\t};\n\t}\n\n\t/**\n\t * Zero-I/O gate for cross-session recall (R3): skip trivial turns (short acks, slash commands) so\n\t * recall only runs when it could plausibly help. The provider's similarity cutoff is the real\n\t * filter — this just avoids the index query on turns that obviously don't warrant it.\n\t */\n\tshouldAttemptRecall(text: string): boolean {\n\t\tif (!this.deps.getSettingsManager().getMemoryRetrievalSettings().enabled) return false;\n\t\tconst t = text.trim();\n\t\tif (t.length < 12 || t.startsWith(\"/\")) return false;\n\t\tconst words = t.split(/\\s+/).filter((w) => w.length >= 3);\n\t\t// R4 adaptive gate: if recall has rarely been used lately (enough samples to trust the signal),\n\t\t// raise the bar so we only recall on clearly substantial turns — and relax it again once recall\n\t\t// starts paying off. Never fully disabled, so the loop can recover.\n\t\tconst recallRarelyUseful =\n\t\t\tthis._effectivenessTracker.sampleCount >= 5 && this._effectivenessTracker.usefulLately() < 0.15;\n\t\treturn words.length >= (recallRarelyUseful ? 6 : 3);\n\t}\n\n\t/** Legacy recall prefetch with the same hard-off and explicit external-egress policy as context retrieval. */\n\tasync prefetchRecall(query: string): Promise<string> {\n\t\tconst settings = this.deps.getSettingsManager().getMemoryRetrievalSettings();\n\t\tif (!settings.enabled) return \"\";\n\t\treturn this._memoryManager.prefetch(query, {\n\t\t\texternalEgressPolicy: settings.allowExternalEgress\n\t\t\t\t? ENABLED_EXTERNAL_MEMORY_EGRESS_POLICY\n\t\t\t\t: DEFAULT_EXTERNAL_MEMORY_EGRESS_POLICY,\n\t\t});\n\t}\n\n\t/** Bounded, read-only memory view for an explicitly authorized delegated worker. */\n\tasync readMemoryForLane(query: string): Promise<string> {\n\t\tconst settings = this.deps.getSettingsManager().getMemoryRetrievalSettings();\n\t\tif (!settings.enabled) return \"Memory retrieval is disabled by policy.\";\n\t\tconst budget = this._memoryBudget(settings.maxResults);\n\t\tconst staticBlock = this._memoryManager\n\t\t\t.buildSystemPromptBlockFresh(budget)\n\t\t\t.replace(\n\t\t\t\t\"[System Note: Below is a snapshot of your persistent memory. You can update these using the 'memory' tool.]\",\n\t\t\t\t\"[Read-only snapshot for a delegated worker.]\",\n\t\t\t);\n\t\tconst recalled = await this.prefetchRecall(query);\n\t\tconst combined = [staticBlock, recalled]\n\t\t\t.filter((part) => part.trim().length > 0)\n\t\t\t.join(\"\\n\\n\")\n\t\t\t.slice(0, 8000);\n\t\treturn combined.length > 0\n\t\t\t? wrapUntrustedText(combined, \"worker-memory\")\n\t\t\t: \"No relevant standing memory was found.\";\n\t}\n\n\t/** R4: score whether the agent actually used an injected recall page, so the recall gate can adapt. */\n\trecordRecallOutcome(recallText: string, queryText: string, responseText: string): void {\n\t\tthis._effectivenessTracker.recordRecallOutcome(recallText, queryText, responseText);\n\t}\n\n\t/**\n\t * (Re)build the memory subsystem: a fresh MemoryManager (reload-safe), register the bundled\n\t * file-store + any extension-contributed providers, initialize, then surface the memory tools and\n\t * the frozen system-prompt block. Best-effort: never throws into the session lifecycle.\n\t */\n\tasync initialize(): Promise<void> {\n\t\ttry {\n\t\t\t// Release the previous generation's providers (locks/handles) before recreating, so a\n\t\t\t// reload does not orphan the old MemoryManager. No-op on first init / for file-store.\n\t\t\tawait this._memoryManager.shutdownAll().catch(() => {});\n\t\t\tconst manager = new MemoryManager();\n\t\t\tmanager.registerProvider(new FileStoreProvider());\n\t\t\t// Bundled read-only cross-session recall (R3): indexes past-session transcripts and answers\n\t\t\t// prefetch() with a <memory_context> page. Never writes.\n\t\t\tmanager.registerProvider(new TranscriptRecallProvider());\n\t\t\tfor (const provider of this._pendingMemoryProviders) {\n\t\t\t\ttry {\n\t\t\t\t\tmanager.registerProvider(provider);\n\t\t\t\t} catch {\n\t\t\t\t\t// Duplicate name or reserved-tool collision — skip this provider, keep the rest.\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis._memoryManager = manager;\n\t\t\tawait manager.initializeAll(this.deps.getSessionId(), {\n\t\t\t\tagentDir: this.deps.getAgentDir(),\n\t\t\t\tcwd: this.deps.getCwd(),\n\t\t\t\tisChildSession: this.deps.isChildSession(),\n\t\t\t});\n\t\t\t// Surface memory tools + the frozen memory block now that providers are initialized.\n\t\t\t// refreshToolRegistry() ends in setActiveToolsByName(), which rebuilds AND assigns the\n\t\t\t// system prompt (including the memory block), so no explicit _rebuildSystemPrompt is needed.\n\t\t\tthis.deps.refreshToolRegistry();\n\t\t} catch (error) {\n\t\t\tconsole.error(\"Memory subsystem init failed:\", error instanceof Error ? error.message : String(error));\n\t\t}\n\t}\n\n\t/** Register a memory provider contributed by an extension; applied on the next memory (re)init. */\n\tregisterMemoryProvider(provider: MemoryProvider): void {\n\t\tif (!this._pendingMemoryProviders.some((p) => p.name === provider.name)) {\n\t\t\tthis._pendingMemoryProviders.push(provider);\n\t\t}\n\t}\n\n\t/** Register a retrieval-style context memory provider contributed by an extension. */\n\tregisterContextMemoryProvider(provider: ContextMemoryProvider): void {\n\t\tif (!this._pendingContextMemoryProviders.some((p) => p.id === provider.id)) {\n\t\t\tthis._pendingContextMemoryProviders.push(provider);\n\t\t}\n\t}\n\n\tcreateReloadSnapshot(): MemoryControllerReloadSnapshot {\n\t\treturn {\n\t\t\tpendingMemoryProviders: [...this._pendingMemoryProviders],\n\t\t\tpendingContextMemoryProviders: [...this._pendingContextMemoryProviders],\n\t\t\tmemoryOkfProvider: this._memoryOkfProvider,\n\t\t\tfileStoreMemoryProvider: this._fileStoreMemoryProvider,\n\t\t};\n\t}\n\n\trestoreReloadSnapshot(snapshot: MemoryControllerReloadSnapshot): void {\n\t\tthis._pendingMemoryProviders = [...snapshot.pendingMemoryProviders];\n\t\tthis._pendingContextMemoryProviders = [...snapshot.pendingContextMemoryProviders];\n\t\tthis._memoryOkfProvider = snapshot.memoryOkfProvider;\n\t\tthis._fileStoreMemoryProvider = snapshot.fileStoreMemoryProvider;\n\t}\n\n\t/** Reload starts memory providers fresh; loaded extensions re-register before the next `initialize()`. */\n\tclearPendingProviders(): void {\n\t\tthis._pendingMemoryProviders = [];\n\t\tthis._pendingContextMemoryProviders = [];\n\t\tthis._memoryOkfProvider = undefined;\n\t\tthis._fileStoreMemoryProvider = undefined;\n\t}\n}\n"]}
1
+ {"version":3,"file":"memory-controller.d.ts","sourceRoot":"","sources":["../../src/core/memory-controller.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Memory controller: the session's plug-and-play memory subsystem — the read-only OKF retrieval\n * provider, the bounded prompt-evidence surfacing pilot, cross-session recall effectiveness, and the\n * live {@link MemoryManager} (bundled file-store + transcript-recall providers plus any extension\n * contributions).\n *\n * Extracted verbatim from agent-session.ts (god-file decomposition). Owns the lazily-built OKF\n * provider, the latest retrieval/prompt-inclusion reports, the recreated-on-reload MemoryManager, the\n * recall {@link EffectivenessTracker}, and the extension-contributed pending providers. Everything\n * else it needs — settings, the current turn index, agent/workspace dirs, the session id, the\n * child-session flag, and the tool-registry refresh — is reached through narrow deps accessors rather\n * than the whole AgentSession.\n *\n * Context-transform boundary (deliberate): {@link runMemoryRetrieval} and\n * {@link maybeAppendMemoryEvidenceBlock} are invoked from the session's context transform as one-line\n * delegations. This controller deliberately imports no compaction/context-pipeline internals — it only\n * ever reads settings and builds the retrieval report + the bounded evidence block, so the transform\n * stays the single owner of the pass ordering.\n */\n\nimport type { AgentMessage, CustomMessage } from \"@caupulican/pi-agent-core\";\nimport { configFile, okfMemoryDir } from \"./agent-paths.ts\";\nimport { collectCurrentWorkMemory } from \"./context/current-work-memory.ts\";\nimport { createFileStoreMemoryProvider } from \"./context/file-store-memory-provider.ts\";\nimport { shouldQueryLongTermMemory } from \"./context/long-term-memory-trigger.ts\";\nimport {\n\tdefaultMemoryPromptInclusionReport,\n\ttype MemoryPromptInclusionReport,\n\ttype MemoryRetrievalDiagnostics,\n\tsanitizeMemoryRetrievalReportForDiagnostics,\n} from \"./context/memory-diagnostics.ts\";\nimport { type MemoryPromptBudget, resolveMemoryPromptBudget } from \"./context/memory-prompt-budget.ts\";\nimport {\n\ttype MemoryProvider as ContextMemoryProvider,\n\tDEFAULT_EXTERNAL_MEMORY_EGRESS_POLICY,\n\tDEFAULT_LOCAL_MEMORY_EGRESS_POLICY,\n} from \"./context/memory-provider-contract.ts\";\nimport { type MemoryRetrievalReport, retrieveMemoryForContext } from \"./context/memory-retrieval.ts\";\nimport { composeTieredMemoryPromptBlock, type MemoryTierCandidate } from \"./context/memory-tier-composer.ts\";\nimport { createOkfMemoryProvider } from \"./context/okf-memory-provider.ts\";\nimport type { GoalState } from \"./goals/goal-state.ts\";\nimport { EffectivenessTracker } from \"./memory/effectiveness-tracker.ts\";\nimport { MemoryManager } from \"./memory/memory-manager.ts\";\nimport type { MemoryProvider } from \"./memory/memory-provider.ts\";\nimport { FileStoreProvider } from \"./memory/providers/file-store.ts\";\nimport { TranscriptRecallProvider } from \"./memory/providers/transcript-recall.ts\";\nimport { wrapUntrustedText } from \"./security/untrusted-boundary.ts\";\nimport type { SettingsManager } from \"./settings-manager.ts\";\n\n/**\n * Text of the most recent user message, or \"\" if there is none (e.g. goal-continuation\n * turns with no new user input). An empty query is still valid: standing user preferences may\n * surface from the file-store retrieval fallback when the static memory prompt cannot fit,\n * while long-term providers remain gated by shouldQueryLongTermMemory().\n */\nfunction latestUserMessageText(messages: AgentMessage[]): string {\n\tfor (let index = messages.length - 1; index >= 0; index--) {\n\t\tconst message = messages[index];\n\t\tif (message.role !== \"user\") continue;\n\t\tif (typeof message.content === \"string\") return message.content;\n\t\tconst parts: string[] = [];\n\t\tfor (const part of message.content) {\n\t\t\tif (part.type === \"text\") parts.push(part.text);\n\t\t}\n\t\treturn parts.join(\"\\n\");\n\t}\n\treturn \"\";\n}\n\nfunction emptyMemoryRetrievalReport(maxResults: number): MemoryRetrievalReport {\n\treturn { request: { query: \"\", maxResults }, providerReports: [], results: [], contextItems: [] };\n}\n\nconst ENABLED_EXTERNAL_MEMORY_EGRESS_POLICY = {\n\t...DEFAULT_EXTERNAL_MEMORY_EGRESS_POLICY,\n\tenabled: true,\n\tallowedScopes: DEFAULT_LOCAL_MEMORY_EGRESS_POLICY.allowedScopes,\n\tallowExternalEgress: true,\n} as const;\n\nexport interface MemoryControllerDeps {\n\t/** Memory-retrieval + prompt-inclusion settings (default-on gates for retrieval and surfacing). */\n\tgetSettingsManager(): SettingsManager;\n\t/** Current turn index, stamped into a retrieval request's `createdAtTurn`. */\n\tgetTurnIndex(): number;\n\t/** Agent root — the durable OKF memory docs live under `<agentDir>/okf-memory`. */\n\tgetAgentDir(): string;\n\t/** Workspace root, passed to provider initialization. */\n\tgetCwd(): string;\n\t/** This session's id, passed to provider initialization. */\n\tgetSessionId(): string;\n\t/** Child sessions gate durable memory writes; passed to provider initialization. */\n\tisChildSession(): boolean;\n\t/** Re-derive the tool registry after (re)init so the newly-surfaced memory tools take effect. */\n\trefreshToolRegistry(): void;\n\t/** Active model context window, used to cap prompt-visible memory. */\n\tgetContextWindow(): number | undefined;\n\t/** Latest active goal state, used for short-term current-work memory. */\n\tgetGoalState(): GoalState | undefined;\n}\n\n/** Extension-contributed memory state staged across an atomic runtime reload. */\nexport interface MemoryControllerReloadSnapshot {\n\tpendingMemoryProviders: MemoryProvider[];\n\tpendingContextMemoryProviders: ContextMemoryProvider[];\n\tmemoryOkfProvider: ContextMemoryProvider | undefined;\n\tfileStoreMemoryProvider: ContextMemoryProvider | undefined;\n}\n\nexport class MemoryController {\n\tprivate _memoryOkfProvider: ContextMemoryProvider | undefined = undefined;\n\tprivate _fileStoreMemoryProvider: ContextMemoryProvider | undefined = undefined;\n\tprivate _latestMemoryRetrievalReport: MemoryRetrievalReport | undefined = undefined;\n\tprivate _latestMemoryPromptInclusionReport: MemoryPromptInclusionReport | undefined = undefined;\n\t/** Plug-and-play memory subsystem. Recreated on each (re)initialize so reload is safe. */\n\tprivate _memoryManager: MemoryManager = new MemoryManager();\n\t/** R4: tracks whether injected recall is actually used, to adapt the recall gate. */\n\tprivate readonly _effectivenessTracker = new EffectivenessTracker();\n\t/** Memory providers registered by extensions via pi.registerMemoryProvider, applied on (re)init. */\n\tprivate _pendingMemoryProviders: MemoryProvider[] = [];\n\t/** Context-memory providers registered by extensions via pi.registerContextMemoryProvider. */\n\tprivate _pendingContextMemoryProviders: ContextMemoryProvider[] = [];\n\n\tprivate readonly deps: MemoryControllerDeps;\n\n\tconstructor(deps: MemoryControllerDeps) {\n\t\tthis.deps = deps;\n\t}\n\n\t/** The live memory manager. Callers reach prefetch / tool-definitions / markers / shutdown through it. */\n\tgetMemoryManager(): MemoryManager {\n\t\treturn this._memoryManager;\n\t}\n\n\t/**\n\t * Fixed path for this slice's local Pi OKF memory documents, shared across sessions\n\t * under this agentDir (not session-scoped, unlike tool-artifacts/context-gc, since OKF\n\t * memory represents durable cross-session knowledge, not a per-session capture). Not\n\t * yet user-configurable -- see the memory-retrieval settings doc comment.\n\t */\n\tprivate _memoryOkfDir(): string {\n\t\treturn okfMemoryDir(this.deps.getAgentDir());\n\t}\n\n\t/**\n\t * Session-scoped, read-only local OKF memory provider. Lazily created ONLY when memory\n\t * retrieval is enabled (see `runMemoryRetrieval`) -- never force-created, so a session\n\t * with the setting off never touches `_memoryOkfDir()` at all (no directory access, no\n\t * creation; `createOkfMemoryProvider` itself never writes/mkdirs either way).\n\t */\n\tprivate _getMemoryOkfProvider(): ContextMemoryProvider {\n\t\tthis._memoryOkfProvider ??= createOkfMemoryProvider({ rootDir: this._memoryOkfDir() });\n\t\treturn this._memoryOkfProvider;\n\t}\n\n\tprivate _getFileStoreMemoryProvider(): ContextMemoryProvider {\n\t\tthis._fileStoreMemoryProvider ??= createFileStoreMemoryProvider({\n\t\t\tmemoryFilePath: configFile(this.deps.getAgentDir(), \"MEMORY.md\"),\n\t\t\tuserFilePath: configFile(this.deps.getAgentDir(), \"USER.md\"),\n\t\t});\n\t\treturn this._fileStoreMemoryProvider;\n\t}\n\n\tprivate _memoryBudget(configuredMaxResults: number) {\n\t\treturn resolveMemoryPromptBudget({\n\t\t\tcontextWindow: this.deps.getContextWindow(),\n\t\t\tconfiguredMaxResults,\n\t\t});\n\t}\n\n\tprivate _shouldQueryFileStoreFallback(budget: MemoryPromptBudget): boolean {\n\t\t// MEMORY.md/USER.md are already injected through the static file-store prompt on\n\t\t// normal windows, so querying them again would duplicate provider-visible memory.\n\t\t// In compact windows the static block can be omitted because it does not fit; only\n\t\t// then use the retrieval view to surface a few budget-pruned lines.\n\t\tif (!budget.enabled || !budget.compact) return false;\n\t\treturn this._memoryManager.buildSystemPromptBlock(budget).trim().length === 0;\n\t}\n\n\t/**\n\t * Observe-only local memory retrieval (see context/memory-retrieval.ts and\n\t * context/okf-memory-provider.ts): default-on, but settings-gated. When disabled,\n\t * never constructs built-in context-memory providers (no directory access under\n\t * `_memoryOkfDir()` at all) and returns an empty report -- fully fail-closed. When enabled,\n\t * queries local, read-only providers with the latest user message text (empty if there is\n\t * none, e.g. a goal-continuation turn) under `DEFAULT_LOCAL_MEMORY_EGRESS_POLICY`.\n\t * Retrieved items are only ever stored in the report; nothing here touches `messages`,\n\t * the transcript, or the provider-visible prompt. Never throws into a live turn: any\n\t * failure (including a provider search error) degrades to an empty report.\n\t */\n\tasync runMemoryRetrieval(messages: AgentMessage[]): Promise<MemoryRetrievalReport> {\n\t\ttry {\n\t\t\tconst settings = this.deps.getSettingsManager().getMemoryRetrievalSettings();\n\t\t\tif (!settings.enabled) {\n\t\t\t\tconst report = emptyMemoryRetrievalReport(settings.maxResults);\n\t\t\t\tthis._latestMemoryRetrievalReport = report;\n\t\t\t\treturn report;\n\t\t\t}\n\t\t\tconst query = latestUserMessageText(messages);\n\t\t\tconst budget = this._memoryBudget(settings.maxResults);\n\t\t\tconst currentWork = collectCurrentWorkMemory({ goalState: this.deps.getGoalState() });\n\t\t\tconst longTermDecision = shouldQueryLongTermMemory({\n\t\t\t\tlatestUserText: query,\n\t\t\t\tgoalState: this.deps.getGoalState(),\n\t\t\t\tbudget,\n\t\t\t\tcurrentWorkCandidateCount: currentWork.length,\n\t\t\t});\n\t\t\tconst providers = this._shouldQueryFileStoreFallback(budget) ? [this._getFileStoreMemoryProvider()] : [];\n\t\t\tif (longTermDecision.shouldQuery) {\n\t\t\t\tproviders.push(this._getMemoryOkfProvider(), ...this._pendingContextMemoryProviders);\n\t\t\t}\n\t\t\tconst maxResults = budget.enabled ? Math.min(settings.maxResults, budget.maxResults) : settings.maxResults;\n\t\t\tconst report = await retrieveMemoryForContext(\n\t\t\t\tproviders,\n\t\t\t\t{ query, maxResults },\n\t\t\t\t{\n\t\t\t\t\tcreatedAtTurn: this.deps.getTurnIndex(),\n\t\t\t\t\tmaxResults,\n\t\t\t\t\tdefaultLocalPolicy: DEFAULT_LOCAL_MEMORY_EGRESS_POLICY,\n\t\t\t\t\tdefaultExternalPolicy: settings.allowExternalEgress\n\t\t\t\t\t\t? ENABLED_EXTERNAL_MEMORY_EGRESS_POLICY\n\t\t\t\t\t\t: DEFAULT_EXTERNAL_MEMORY_EGRESS_POLICY,\n\t\t\t\t},\n\t\t\t);\n\t\t\tthis._latestMemoryRetrievalReport = report;\n\t\t\treturn report;\n\t\t} catch {\n\t\t\tconst report = emptyMemoryRetrievalReport(0);\n\t\t\tthis._latestMemoryRetrievalReport = report;\n\t\t\treturn report;\n\t\t}\n\t}\n\n\t/** Read-only inspection of the latest memory-retrieval report, for tests/debugging. */\n\tgetMemoryRetrievalReport(): MemoryRetrievalReport {\n\t\treturn this._latestMemoryRetrievalReport ?? emptyMemoryRetrievalReport(0);\n\t}\n\n\tprivate _candidateForContextItem(\n\t\titem: MemoryRetrievalReport[\"contextItems\"][number],\n\t): MemoryTierCandidate | undefined {\n\t\tconst summary = item.summary?.trim();\n\t\tif (!summary) return undefined;\n\t\tconst ref = item.primaryRef?.type === \"memory\" ? item.primaryRef.ref : undefined;\n\t\tconst sourceLabel =\n\t\t\tref?.providerId === \"pi-file-store\" && ref.kind === \"user_preference\"\n\t\t\t\t? \"rule:user\"\n\t\t\t\t: `memory:${ref?.providerId ?? item.source}`;\n\t\tconst tier = ref?.kind === \"user_preference\" ? \"standing\" : \"long_term\";\n\t\treturn {\n\t\t\tid: item.id,\n\t\t\ttier,\n\t\t\tsourceLabel,\n\t\t\tsummary,\n\t\t\tscore: 0.5,\n\t\t\tevidenceRefs: item.evidenceRefs,\n\t\t};\n\t}\n\n\tprivate _memoryCandidates(report: MemoryRetrievalReport): MemoryTierCandidate[] {\n\t\treturn [\n\t\t\t...collectCurrentWorkMemory({ goalState: this.deps.getGoalState() }),\n\t\t\t...report.contextItems.flatMap((item) => {\n\t\t\t\tconst candidate = this._candidateForContextItem(item);\n\t\t\t\treturn candidate === undefined ? [] : [candidate];\n\t\t\t}),\n\t\t];\n\t}\n\n\t/**\n\t * Bounded prompt-surfacing for local memory evidence (see context/memory-tier-composer.ts):\n\t * default-on, but gated on TWO settings (`enabled` AND `includeInPrompt`) plus at least one\n\t * current-work, standing, or retrieved memory candidate -- the first\n\t * two are belt-and-suspenders on top of the fact that `runMemoryRetrieval` already\n\t * leaves `contextItems` empty whenever `enabled` is false, regardless of\n\t * `includeInPrompt`. Reuses the `report` this pass's `runMemoryRetrieval` call already\n\t * computed -- never re-queries the provider here.\n\t *\n\t * Appends exactly one ephemeral `custom`/\"memory_evidence\" message wrapped by\n\t * `wrapUntrustedText` (the same nonce-fenced boundary + always-on system-prompt rule\n\t * used for other untrusted content) to the END of `messages`. This is purely additive\n\t * (never mutates an existing message) and purely transient: `messages` here is the\n\t * array about to be sent to the provider, not `this.agent.state.messages` or anything\n\t * persisted via `sessionManager` -- so the injected message can never reach the\n\t * transcript, regardless of how many times this pass runs.\n\t *\n\t * Also records a `MemoryPromptInclusionReport` (context/memory-diagnostics.ts) at each\n\t * branch below, for context_audit's diagnostic surface only -- this is pure bookkeeping\n\t * alongside the existing branches, not a new branch/condition: the messages returned\n\t * are unchanged by this recording.\n\t */\n\tmaybeAppendMemoryEvidenceBlock(messages: AgentMessage[], report: MemoryRetrievalReport): AgentMessage[] {\n\t\ttry {\n\t\t\tconst settings = this.deps.getSettingsManager().getMemoryRetrievalSettings();\n\t\t\tconst candidates = this._memoryCandidates(report);\n\t\t\tconst base = {\n\t\t\t\tenabled: settings.enabled,\n\t\t\t\tincludeInPrompt: settings.includeInPrompt,\n\t\t\t\tselectedItemCount: candidates.length,\n\t\t\t};\n\t\t\tif (!settings.enabled) {\n\t\t\t\tthis._latestMemoryPromptInclusionReport = {\n\t\t\t\t\t...base,\n\t\t\t\t\tstatus: \"disabled\",\n\t\t\t\t\tincludedCount: 0,\n\t\t\t\t\tomittedCount: 0,\n\t\t\t\t\tblockChars: 0,\n\t\t\t\t};\n\t\t\t\treturn messages;\n\t\t\t}\n\t\t\tif (!settings.includeInPrompt) {\n\t\t\t\tthis._latestMemoryPromptInclusionReport = {\n\t\t\t\t\t...base,\n\t\t\t\t\tstatus: \"include_disabled\",\n\t\t\t\t\tincludedCount: 0,\n\t\t\t\t\tomittedCount: 0,\n\t\t\t\t\tblockChars: 0,\n\t\t\t\t};\n\t\t\t\treturn messages;\n\t\t\t}\n\t\t\tif (candidates.length === 0) {\n\t\t\t\tthis._latestMemoryPromptInclusionReport = {\n\t\t\t\t\t...base,\n\t\t\t\t\tstatus: \"no_results\",\n\t\t\t\t\tincludedCount: 0,\n\t\t\t\t\tomittedCount: 0,\n\t\t\t\t\tblockChars: 0,\n\t\t\t\t};\n\t\t\t\treturn messages;\n\t\t\t}\n\n\t\t\tconst budget = this._memoryBudget(settings.maxResults);\n\t\t\tconst block = composeTieredMemoryPromptBlock(candidates, budget);\n\t\t\tif (!block.text) {\n\t\t\t\tthis._latestMemoryPromptInclusionReport = {\n\t\t\t\t\t...base,\n\t\t\t\t\tstatus: \"empty_block\",\n\t\t\t\t\tincludedCount: block.includedCount,\n\t\t\t\t\tomittedCount: block.omittedCount,\n\t\t\t\t\tblockChars: 0,\n\t\t\t\t};\n\t\t\t\treturn messages;\n\t\t\t}\n\n\t\t\tconst wrapped = wrapUntrustedText(block.text, \"memory:tiered\");\n\t\t\tconst evidenceMessage: CustomMessage = {\n\t\t\t\trole: \"custom\",\n\t\t\t\tcustomType: \"memory_evidence\",\n\t\t\t\tcontent: [{ type: \"text\", text: wrapped }],\n\t\t\t\tdisplay: false,\n\t\t\t\ttimestamp: Date.now(),\n\t\t\t};\n\t\t\tthis._latestMemoryPromptInclusionReport = {\n\t\t\t\t...base,\n\t\t\t\tstatus: \"included\",\n\t\t\t\tincludedCount: block.includedCount,\n\t\t\t\tomittedCount: block.omittedCount,\n\t\t\t\tblockChars: wrapped.length,\n\t\t\t\tsourceLabel: \"memory:tiered\",\n\t\t\t};\n\t\t\treturn [...messages, evidenceMessage];\n\t\t} catch {\n\t\t\t// `base` may not exist yet if the throw happened before it was computed (e.g.\n\t\t\t// settings access or `report.contextItems` itself threw), so this branch cannot\n\t\t\t// rely on it -- fall back to safe, fixed defaults rather than risk referencing\n\t\t\t// a partially-evaluated value.\n\t\t\tthis._latestMemoryPromptInclusionReport = {\n\t\t\t\tenabled: false,\n\t\t\t\tincludeInPrompt: false,\n\t\t\t\tselectedItemCount: 0,\n\t\t\t\tstatus: \"failed\",\n\t\t\t\tincludedCount: 0,\n\t\t\t\tomittedCount: 0,\n\t\t\t\tblockChars: 0,\n\t\t\t};\n\t\t\treturn messages;\n\t\t}\n\t}\n\n\t/** Read-only inspection of the latest memory-prompt-inclusion decision, for tests/debugging and context_audit. */\n\tgetMemoryPromptInclusionReport(): MemoryPromptInclusionReport {\n\t\treturn this._latestMemoryPromptInclusionReport ?? defaultMemoryPromptInclusionReport();\n\t}\n\n\t/**\n\t * Combines the already-stored, no-arg latest reports (never re-queries the provider or\n\t * touches the OKF directory) into the safe, allow-list-projected shape context_audit\n\t * exposes. See context/memory-diagnostics.ts for why this projection is allow-list\n\t * based rather than a spread-then-delete of the raw report.\n\t */\n\tgetMemoryAuditDiagnostics(): {\n\t\tretrieval: MemoryRetrievalDiagnostics;\n\t\tpromptInclusion: MemoryPromptInclusionReport;\n\t} {\n\t\tconst settings = this.deps.getSettingsManager().getMemoryRetrievalSettings();\n\t\treturn {\n\t\t\tretrieval: sanitizeMemoryRetrievalReportForDiagnostics(this.getMemoryRetrievalReport(), settings),\n\t\t\tpromptInclusion: this.getMemoryPromptInclusionReport(),\n\t\t};\n\t}\n\n\t/**\n\t * Zero-I/O gate for cross-session recall (R3): skip trivial turns (short acks, slash commands) so\n\t * recall only runs when it could plausibly help. The provider's similarity cutoff is the real\n\t * filter — this just avoids the index query on turns that obviously don't warrant it.\n\t */\n\tshouldAttemptRecall(text: string): boolean {\n\t\tif (!this.deps.getSettingsManager().getMemoryRetrievalSettings().enabled) return false;\n\t\tconst t = text.trim();\n\t\tif (t.length < 12 || t.startsWith(\"/\")) return false;\n\t\tconst words = t.split(/\\s+/).filter((w) => w.length >= 3);\n\t\t// R4 adaptive gate: if recall has rarely been used lately (enough samples to trust the signal),\n\t\t// raise the bar so we only recall on clearly substantial turns — and relax it again once recall\n\t\t// starts paying off. Never fully disabled, so the loop can recover.\n\t\tconst recallRarelyUseful =\n\t\t\tthis._effectivenessTracker.sampleCount >= 5 && this._effectivenessTracker.usefulLately() < 0.15;\n\t\treturn words.length >= (recallRarelyUseful ? 6 : 3);\n\t}\n\n\t/** Legacy recall prefetch with the same hard-off and explicit external-egress policy as context retrieval. */\n\tasync prefetchRecall(query: string): Promise<string> {\n\t\tconst settings = this.deps.getSettingsManager().getMemoryRetrievalSettings();\n\t\tif (!settings.enabled) return \"\";\n\t\treturn this._memoryManager.prefetch(query, {\n\t\t\texternalEgressPolicy: settings.allowExternalEgress\n\t\t\t\t? ENABLED_EXTERNAL_MEMORY_EGRESS_POLICY\n\t\t\t\t: DEFAULT_EXTERNAL_MEMORY_EGRESS_POLICY,\n\t\t});\n\t}\n\n\t/** Bounded, read-only memory view for an explicitly authorized delegated worker. */\n\tasync readMemoryForLane(query: string): Promise<string> {\n\t\tconst settings = this.deps.getSettingsManager().getMemoryRetrievalSettings();\n\t\tif (!settings.enabled) return \"Memory retrieval is disabled by policy.\";\n\t\tconst budget = this._memoryBudget(settings.maxResults);\n\t\tconst staticBlock = this._memoryManager\n\t\t\t.buildSystemPromptBlockFresh(budget)\n\t\t\t.replace(\n\t\t\t\t\"[System Note: Below is a snapshot of your persistent memory. You can update these using the 'memory' tool.]\",\n\t\t\t\t\"[Read-only snapshot for a delegated worker.]\",\n\t\t\t);\n\t\tconst recalled = await this.prefetchRecall(query);\n\t\tconst combined = [staticBlock, recalled]\n\t\t\t.filter((part) => part.trim().length > 0)\n\t\t\t.join(\"\\n\\n\")\n\t\t\t.slice(0, 8000);\n\t\treturn combined.length > 0\n\t\t\t? wrapUntrustedText(combined, \"worker-memory\")\n\t\t\t: \"No relevant standing memory was found.\";\n\t}\n\n\t/** R4: score whether the agent actually used an injected recall page, so the recall gate can adapt. */\n\trecordRecallOutcome(recallText: string, queryText: string, responseText: string): void {\n\t\tthis._effectivenessTracker.recordRecallOutcome(recallText, queryText, responseText);\n\t}\n\n\t/**\n\t * (Re)build the memory subsystem: a fresh MemoryManager (reload-safe), register the bundled\n\t * file-store + any extension-contributed providers, initialize, then surface the memory tools and\n\t * the frozen system-prompt block. Best-effort: never throws into the session lifecycle.\n\t */\n\tasync initialize(): Promise<void> {\n\t\ttry {\n\t\t\t// Release the previous generation's providers (locks/handles) before recreating, so a\n\t\t\t// reload does not orphan the old MemoryManager. No-op on first init / for file-store.\n\t\t\tawait this._memoryManager.shutdownAll().catch(() => {});\n\t\t\tconst manager = new MemoryManager();\n\t\t\tmanager.registerProvider(new FileStoreProvider());\n\t\t\t// Bundled read-only cross-session recall (R3): indexes past-session transcripts and answers\n\t\t\t// prefetch() with a <memory_context> page. Never writes.\n\t\t\tmanager.registerProvider(new TranscriptRecallProvider());\n\t\t\tfor (const provider of this._pendingMemoryProviders) {\n\t\t\t\ttry {\n\t\t\t\t\tmanager.registerProvider(provider);\n\t\t\t\t} catch {\n\t\t\t\t\t// Duplicate name or reserved-tool collision — skip this provider, keep the rest.\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis._memoryManager = manager;\n\t\t\tawait manager.initializeAll(this.deps.getSessionId(), {\n\t\t\t\tagentDir: this.deps.getAgentDir(),\n\t\t\t\tcwd: this.deps.getCwd(),\n\t\t\t\tisChildSession: this.deps.isChildSession(),\n\t\t\t});\n\t\t\t// Surface memory tools + the frozen memory block now that providers are initialized.\n\t\t\t// refreshToolRegistry() ends in setActiveToolsByName(), which rebuilds AND assigns the\n\t\t\t// system prompt (including the memory block), so no explicit _rebuildSystemPrompt is needed.\n\t\t\tthis.deps.refreshToolRegistry();\n\t\t} catch (error) {\n\t\t\tconsole.error(\"Memory subsystem init failed:\", error instanceof Error ? error.message : String(error));\n\t\t}\n\t}\n\n\t/** Register a memory provider contributed by an extension; applied on the next memory (re)init. */\n\tregisterMemoryProvider(provider: MemoryProvider): void {\n\t\tif (!this._pendingMemoryProviders.some((p) => p.name === provider.name)) {\n\t\t\tthis._pendingMemoryProviders.push(provider);\n\t\t}\n\t}\n\n\t/** Register a retrieval-style context memory provider contributed by an extension. */\n\tregisterContextMemoryProvider(provider: ContextMemoryProvider): void {\n\t\tif (!this._pendingContextMemoryProviders.some((p) => p.id === provider.id)) {\n\t\t\tthis._pendingContextMemoryProviders.push(provider);\n\t\t}\n\t}\n\n\tcreateReloadSnapshot(): MemoryControllerReloadSnapshot {\n\t\treturn {\n\t\t\tpendingMemoryProviders: [...this._pendingMemoryProviders],\n\t\t\tpendingContextMemoryProviders: [...this._pendingContextMemoryProviders],\n\t\t\tmemoryOkfProvider: this._memoryOkfProvider,\n\t\t\tfileStoreMemoryProvider: this._fileStoreMemoryProvider,\n\t\t};\n\t}\n\n\trestoreReloadSnapshot(snapshot: MemoryControllerReloadSnapshot): void {\n\t\tthis._pendingMemoryProviders = [...snapshot.pendingMemoryProviders];\n\t\tthis._pendingContextMemoryProviders = [...snapshot.pendingContextMemoryProviders];\n\t\tthis._memoryOkfProvider = snapshot.memoryOkfProvider;\n\t\tthis._fileStoreMemoryProvider = snapshot.fileStoreMemoryProvider;\n\t}\n\n\t/** Reload starts memory providers fresh; loaded extensions re-register before the next `initialize()`. */\n\tclearPendingProviders(): void {\n\t\tthis._pendingMemoryProviders = [];\n\t\tthis._pendingContextMemoryProviders = [];\n\t\tthis._memoryOkfProvider = undefined;\n\t\tthis._fileStoreMemoryProvider = undefined;\n\t}\n}\n"]}
@@ -17,7 +17,7 @@
17
17
  * ever reads settings and builds the retrieval report + the bounded evidence block, so the transform
18
18
  * stays the single owner of the pass ordering.
19
19
  */
20
- import { join } from "node:path";
20
+ import { configFile, okfMemoryDir } from "./agent-paths.js";
21
21
  import { collectCurrentWorkMemory } from "./context/current-work-memory.js";
22
22
  import { createFileStoreMemoryProvider } from "./context/file-store-memory-provider.js";
23
23
  import { shouldQueryLongTermMemory } from "./context/long-term-memory-trigger.js";
@@ -91,7 +91,7 @@ export class MemoryController {
91
91
  * yet user-configurable -- see the memory-retrieval settings doc comment.
92
92
  */
93
93
  _memoryOkfDir() {
94
- return join(this.deps.getAgentDir(), "okf-memory");
94
+ return okfMemoryDir(this.deps.getAgentDir());
95
95
  }
96
96
  /**
97
97
  * Session-scoped, read-only local OKF memory provider. Lazily created ONLY when memory
@@ -105,8 +105,8 @@ export class MemoryController {
105
105
  }
106
106
  _getFileStoreMemoryProvider() {
107
107
  this._fileStoreMemoryProvider ??= createFileStoreMemoryProvider({
108
- memoryFilePath: join(this.deps.getAgentDir(), "MEMORY.md"),
109
- userFilePath: join(this.deps.getAgentDir(), "USER.md"),
108
+ memoryFilePath: configFile(this.deps.getAgentDir(), "MEMORY.md"),
109
+ userFilePath: configFile(this.deps.getAgentDir(), "USER.md"),
110
110
  });
111
111
  return this._fileStoreMemoryProvider;
112
112
  }
@@ -1 +1 @@
1
- {"version":3,"file":"memory-controller.js","sourceRoot":"","sources":["../../src/core/memory-controller.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Memory controller: the session's plug-and-play memory subsystem — the read-only OKF retrieval\n * provider, the bounded prompt-evidence surfacing pilot, cross-session recall effectiveness, and the\n * live {@link MemoryManager} (bundled file-store + transcript-recall providers plus any extension\n * contributions).\n *\n * Extracted verbatim from agent-session.ts (god-file decomposition). Owns the lazily-built OKF\n * provider, the latest retrieval/prompt-inclusion reports, the recreated-on-reload MemoryManager, the\n * recall {@link EffectivenessTracker}, and the extension-contributed pending providers. Everything\n * else it needs — settings, the current turn index, agent/workspace dirs, the session id, the\n * child-session flag, and the tool-registry refresh — is reached through narrow deps accessors rather\n * than the whole AgentSession.\n *\n * Context-transform boundary (deliberate): {@link runMemoryRetrieval} and\n * {@link maybeAppendMemoryEvidenceBlock} are invoked from the session's context transform as one-line\n * delegations. This controller deliberately imports no compaction/context-pipeline internals — it only\n * ever reads settings and builds the retrieval report + the bounded evidence block, so the transform\n * stays the single owner of the pass ordering.\n */\n\nimport { join } from \"node:path\";\nimport type { AgentMessage, CustomMessage } from \"@caupulican/pi-agent-core\";\nimport { collectCurrentWorkMemory } from \"./context/current-work-memory.ts\";\nimport { createFileStoreMemoryProvider } from \"./context/file-store-memory-provider.ts\";\nimport { shouldQueryLongTermMemory } from \"./context/long-term-memory-trigger.ts\";\nimport {\n\tdefaultMemoryPromptInclusionReport,\n\ttype MemoryPromptInclusionReport,\n\ttype MemoryRetrievalDiagnostics,\n\tsanitizeMemoryRetrievalReportForDiagnostics,\n} from \"./context/memory-diagnostics.ts\";\nimport { type MemoryPromptBudget, resolveMemoryPromptBudget } from \"./context/memory-prompt-budget.ts\";\nimport {\n\ttype MemoryProvider as ContextMemoryProvider,\n\tDEFAULT_EXTERNAL_MEMORY_EGRESS_POLICY,\n\tDEFAULT_LOCAL_MEMORY_EGRESS_POLICY,\n} from \"./context/memory-provider-contract.ts\";\nimport { type MemoryRetrievalReport, retrieveMemoryForContext } from \"./context/memory-retrieval.ts\";\nimport { composeTieredMemoryPromptBlock, type MemoryTierCandidate } from \"./context/memory-tier-composer.ts\";\nimport { createOkfMemoryProvider } from \"./context/okf-memory-provider.ts\";\nimport type { GoalState } from \"./goals/goal-state.ts\";\nimport { EffectivenessTracker } from \"./memory/effectiveness-tracker.ts\";\nimport { MemoryManager } from \"./memory/memory-manager.ts\";\nimport type { MemoryProvider } from \"./memory/memory-provider.ts\";\nimport { FileStoreProvider } from \"./memory/providers/file-store.ts\";\nimport { TranscriptRecallProvider } from \"./memory/providers/transcript-recall.ts\";\nimport { wrapUntrustedText } from \"./security/untrusted-boundary.ts\";\nimport type { SettingsManager } from \"./settings-manager.ts\";\n\n/**\n * Text of the most recent user message, or \"\" if there is none (e.g. goal-continuation\n * turns with no new user input). An empty query is still valid: standing user preferences may\n * surface from the file-store retrieval fallback when the static memory prompt cannot fit,\n * while long-term providers remain gated by shouldQueryLongTermMemory().\n */\nfunction latestUserMessageText(messages: AgentMessage[]): string {\n\tfor (let index = messages.length - 1; index >= 0; index--) {\n\t\tconst message = messages[index];\n\t\tif (message.role !== \"user\") continue;\n\t\tif (typeof message.content === \"string\") return message.content;\n\t\tconst parts: string[] = [];\n\t\tfor (const part of message.content) {\n\t\t\tif (part.type === \"text\") parts.push(part.text);\n\t\t}\n\t\treturn parts.join(\"\\n\");\n\t}\n\treturn \"\";\n}\n\nfunction emptyMemoryRetrievalReport(maxResults: number): MemoryRetrievalReport {\n\treturn { request: { query: \"\", maxResults }, providerReports: [], results: [], contextItems: [] };\n}\n\nconst ENABLED_EXTERNAL_MEMORY_EGRESS_POLICY = {\n\t...DEFAULT_EXTERNAL_MEMORY_EGRESS_POLICY,\n\tenabled: true,\n\tallowedScopes: DEFAULT_LOCAL_MEMORY_EGRESS_POLICY.allowedScopes,\n\tallowExternalEgress: true,\n} as const;\n\nexport interface MemoryControllerDeps {\n\t/** Memory-retrieval + prompt-inclusion settings (default-on gates for retrieval and surfacing). */\n\tgetSettingsManager(): SettingsManager;\n\t/** Current turn index, stamped into a retrieval request's `createdAtTurn`. */\n\tgetTurnIndex(): number;\n\t/** Agent root — the durable OKF memory docs live under `<agentDir>/okf-memory`. */\n\tgetAgentDir(): string;\n\t/** Workspace root, passed to provider initialization. */\n\tgetCwd(): string;\n\t/** This session's id, passed to provider initialization. */\n\tgetSessionId(): string;\n\t/** Child sessions gate durable memory writes; passed to provider initialization. */\n\tisChildSession(): boolean;\n\t/** Re-derive the tool registry after (re)init so the newly-surfaced memory tools take effect. */\n\trefreshToolRegistry(): void;\n\t/** Active model context window, used to cap prompt-visible memory. */\n\tgetContextWindow(): number | undefined;\n\t/** Latest active goal state, used for short-term current-work memory. */\n\tgetGoalState(): GoalState | undefined;\n}\n\n/** Extension-contributed memory state staged across an atomic runtime reload. */\nexport interface MemoryControllerReloadSnapshot {\n\tpendingMemoryProviders: MemoryProvider[];\n\tpendingContextMemoryProviders: ContextMemoryProvider[];\n\tmemoryOkfProvider: ContextMemoryProvider | undefined;\n\tfileStoreMemoryProvider: ContextMemoryProvider | undefined;\n}\n\nexport class MemoryController {\n\tprivate _memoryOkfProvider: ContextMemoryProvider | undefined = undefined;\n\tprivate _fileStoreMemoryProvider: ContextMemoryProvider | undefined = undefined;\n\tprivate _latestMemoryRetrievalReport: MemoryRetrievalReport | undefined = undefined;\n\tprivate _latestMemoryPromptInclusionReport: MemoryPromptInclusionReport | undefined = undefined;\n\t/** Plug-and-play memory subsystem. Recreated on each (re)initialize so reload is safe. */\n\tprivate _memoryManager: MemoryManager = new MemoryManager();\n\t/** R4: tracks whether injected recall is actually used, to adapt the recall gate. */\n\tprivate readonly _effectivenessTracker = new EffectivenessTracker();\n\t/** Memory providers registered by extensions via pi.registerMemoryProvider, applied on (re)init. */\n\tprivate _pendingMemoryProviders: MemoryProvider[] = [];\n\t/** Context-memory providers registered by extensions via pi.registerContextMemoryProvider. */\n\tprivate _pendingContextMemoryProviders: ContextMemoryProvider[] = [];\n\n\tprivate readonly deps: MemoryControllerDeps;\n\n\tconstructor(deps: MemoryControllerDeps) {\n\t\tthis.deps = deps;\n\t}\n\n\t/** The live memory manager. Callers reach prefetch / tool-definitions / markers / shutdown through it. */\n\tgetMemoryManager(): MemoryManager {\n\t\treturn this._memoryManager;\n\t}\n\n\t/**\n\t * Fixed path for this slice's local Pi OKF memory documents, shared across sessions\n\t * under this agentDir (not session-scoped, unlike tool-artifacts/context-gc, since OKF\n\t * memory represents durable cross-session knowledge, not a per-session capture). Not\n\t * yet user-configurable -- see the memory-retrieval settings doc comment.\n\t */\n\tprivate _memoryOkfDir(): string {\n\t\treturn join(this.deps.getAgentDir(), \"okf-memory\");\n\t}\n\n\t/**\n\t * Session-scoped, read-only local OKF memory provider. Lazily created ONLY when memory\n\t * retrieval is enabled (see `runMemoryRetrieval`) -- never force-created, so a session\n\t * with the setting off never touches `_memoryOkfDir()` at all (no directory access, no\n\t * creation; `createOkfMemoryProvider` itself never writes/mkdirs either way).\n\t */\n\tprivate _getMemoryOkfProvider(): ContextMemoryProvider {\n\t\tthis._memoryOkfProvider ??= createOkfMemoryProvider({ rootDir: this._memoryOkfDir() });\n\t\treturn this._memoryOkfProvider;\n\t}\n\n\tprivate _getFileStoreMemoryProvider(): ContextMemoryProvider {\n\t\tthis._fileStoreMemoryProvider ??= createFileStoreMemoryProvider({\n\t\t\tmemoryFilePath: join(this.deps.getAgentDir(), \"MEMORY.md\"),\n\t\t\tuserFilePath: join(this.deps.getAgentDir(), \"USER.md\"),\n\t\t});\n\t\treturn this._fileStoreMemoryProvider;\n\t}\n\n\tprivate _memoryBudget(configuredMaxResults: number) {\n\t\treturn resolveMemoryPromptBudget({\n\t\t\tcontextWindow: this.deps.getContextWindow(),\n\t\t\tconfiguredMaxResults,\n\t\t});\n\t}\n\n\tprivate _shouldQueryFileStoreFallback(budget: MemoryPromptBudget): boolean {\n\t\t// MEMORY.md/USER.md are already injected through the static file-store prompt on\n\t\t// normal windows, so querying them again would duplicate provider-visible memory.\n\t\t// In compact windows the static block can be omitted because it does not fit; only\n\t\t// then use the retrieval view to surface a few budget-pruned lines.\n\t\tif (!budget.enabled || !budget.compact) return false;\n\t\treturn this._memoryManager.buildSystemPromptBlock(budget).trim().length === 0;\n\t}\n\n\t/**\n\t * Observe-only local memory retrieval (see context/memory-retrieval.ts and\n\t * context/okf-memory-provider.ts): default-on, but settings-gated. When disabled,\n\t * never constructs built-in context-memory providers (no directory access under\n\t * `_memoryOkfDir()` at all) and returns an empty report -- fully fail-closed. When enabled,\n\t * queries local, read-only providers with the latest user message text (empty if there is\n\t * none, e.g. a goal-continuation turn) under `DEFAULT_LOCAL_MEMORY_EGRESS_POLICY`.\n\t * Retrieved items are only ever stored in the report; nothing here touches `messages`,\n\t * the transcript, or the provider-visible prompt. Never throws into a live turn: any\n\t * failure (including a provider search error) degrades to an empty report.\n\t */\n\tasync runMemoryRetrieval(messages: AgentMessage[]): Promise<MemoryRetrievalReport> {\n\t\ttry {\n\t\t\tconst settings = this.deps.getSettingsManager().getMemoryRetrievalSettings();\n\t\t\tif (!settings.enabled) {\n\t\t\t\tconst report = emptyMemoryRetrievalReport(settings.maxResults);\n\t\t\t\tthis._latestMemoryRetrievalReport = report;\n\t\t\t\treturn report;\n\t\t\t}\n\t\t\tconst query = latestUserMessageText(messages);\n\t\t\tconst budget = this._memoryBudget(settings.maxResults);\n\t\t\tconst currentWork = collectCurrentWorkMemory({ goalState: this.deps.getGoalState() });\n\t\t\tconst longTermDecision = shouldQueryLongTermMemory({\n\t\t\t\tlatestUserText: query,\n\t\t\t\tgoalState: this.deps.getGoalState(),\n\t\t\t\tbudget,\n\t\t\t\tcurrentWorkCandidateCount: currentWork.length,\n\t\t\t});\n\t\t\tconst providers = this._shouldQueryFileStoreFallback(budget) ? [this._getFileStoreMemoryProvider()] : [];\n\t\t\tif (longTermDecision.shouldQuery) {\n\t\t\t\tproviders.push(this._getMemoryOkfProvider(), ...this._pendingContextMemoryProviders);\n\t\t\t}\n\t\t\tconst maxResults = budget.enabled ? Math.min(settings.maxResults, budget.maxResults) : settings.maxResults;\n\t\t\tconst report = await retrieveMemoryForContext(\n\t\t\t\tproviders,\n\t\t\t\t{ query, maxResults },\n\t\t\t\t{\n\t\t\t\t\tcreatedAtTurn: this.deps.getTurnIndex(),\n\t\t\t\t\tmaxResults,\n\t\t\t\t\tdefaultLocalPolicy: DEFAULT_LOCAL_MEMORY_EGRESS_POLICY,\n\t\t\t\t\tdefaultExternalPolicy: settings.allowExternalEgress\n\t\t\t\t\t\t? ENABLED_EXTERNAL_MEMORY_EGRESS_POLICY\n\t\t\t\t\t\t: DEFAULT_EXTERNAL_MEMORY_EGRESS_POLICY,\n\t\t\t\t},\n\t\t\t);\n\t\t\tthis._latestMemoryRetrievalReport = report;\n\t\t\treturn report;\n\t\t} catch {\n\t\t\tconst report = emptyMemoryRetrievalReport(0);\n\t\t\tthis._latestMemoryRetrievalReport = report;\n\t\t\treturn report;\n\t\t}\n\t}\n\n\t/** Read-only inspection of the latest memory-retrieval report, for tests/debugging. */\n\tgetMemoryRetrievalReport(): MemoryRetrievalReport {\n\t\treturn this._latestMemoryRetrievalReport ?? emptyMemoryRetrievalReport(0);\n\t}\n\n\tprivate _candidateForContextItem(\n\t\titem: MemoryRetrievalReport[\"contextItems\"][number],\n\t): MemoryTierCandidate | undefined {\n\t\tconst summary = item.summary?.trim();\n\t\tif (!summary) return undefined;\n\t\tconst ref = item.primaryRef?.type === \"memory\" ? item.primaryRef.ref : undefined;\n\t\tconst sourceLabel =\n\t\t\tref?.providerId === \"pi-file-store\" && ref.kind === \"user_preference\"\n\t\t\t\t? \"rule:user\"\n\t\t\t\t: `memory:${ref?.providerId ?? item.source}`;\n\t\tconst tier = ref?.kind === \"user_preference\" ? \"standing\" : \"long_term\";\n\t\treturn {\n\t\t\tid: item.id,\n\t\t\ttier,\n\t\t\tsourceLabel,\n\t\t\tsummary,\n\t\t\tscore: 0.5,\n\t\t\tevidenceRefs: item.evidenceRefs,\n\t\t};\n\t}\n\n\tprivate _memoryCandidates(report: MemoryRetrievalReport): MemoryTierCandidate[] {\n\t\treturn [\n\t\t\t...collectCurrentWorkMemory({ goalState: this.deps.getGoalState() }),\n\t\t\t...report.contextItems.flatMap((item) => {\n\t\t\t\tconst candidate = this._candidateForContextItem(item);\n\t\t\t\treturn candidate === undefined ? [] : [candidate];\n\t\t\t}),\n\t\t];\n\t}\n\n\t/**\n\t * Bounded prompt-surfacing for local memory evidence (see context/memory-tier-composer.ts):\n\t * default-on, but gated on TWO settings (`enabled` AND `includeInPrompt`) plus at least one\n\t * current-work, standing, or retrieved memory candidate -- the first\n\t * two are belt-and-suspenders on top of the fact that `runMemoryRetrieval` already\n\t * leaves `contextItems` empty whenever `enabled` is false, regardless of\n\t * `includeInPrompt`. Reuses the `report` this pass's `runMemoryRetrieval` call already\n\t * computed -- never re-queries the provider here.\n\t *\n\t * Appends exactly one ephemeral `custom`/\"memory_evidence\" message wrapped by\n\t * `wrapUntrustedText` (the same nonce-fenced boundary + always-on system-prompt rule\n\t * used for other untrusted content) to the END of `messages`. This is purely additive\n\t * (never mutates an existing message) and purely transient: `messages` here is the\n\t * array about to be sent to the provider, not `this.agent.state.messages` or anything\n\t * persisted via `sessionManager` -- so the injected message can never reach the\n\t * transcript, regardless of how many times this pass runs.\n\t *\n\t * Also records a `MemoryPromptInclusionReport` (context/memory-diagnostics.ts) at each\n\t * branch below, for context_audit's diagnostic surface only -- this is pure bookkeeping\n\t * alongside the existing branches, not a new branch/condition: the messages returned\n\t * are unchanged by this recording.\n\t */\n\tmaybeAppendMemoryEvidenceBlock(messages: AgentMessage[], report: MemoryRetrievalReport): AgentMessage[] {\n\t\ttry {\n\t\t\tconst settings = this.deps.getSettingsManager().getMemoryRetrievalSettings();\n\t\t\tconst candidates = this._memoryCandidates(report);\n\t\t\tconst base = {\n\t\t\t\tenabled: settings.enabled,\n\t\t\t\tincludeInPrompt: settings.includeInPrompt,\n\t\t\t\tselectedItemCount: candidates.length,\n\t\t\t};\n\t\t\tif (!settings.enabled) {\n\t\t\t\tthis._latestMemoryPromptInclusionReport = {\n\t\t\t\t\t...base,\n\t\t\t\t\tstatus: \"disabled\",\n\t\t\t\t\tincludedCount: 0,\n\t\t\t\t\tomittedCount: 0,\n\t\t\t\t\tblockChars: 0,\n\t\t\t\t};\n\t\t\t\treturn messages;\n\t\t\t}\n\t\t\tif (!settings.includeInPrompt) {\n\t\t\t\tthis._latestMemoryPromptInclusionReport = {\n\t\t\t\t\t...base,\n\t\t\t\t\tstatus: \"include_disabled\",\n\t\t\t\t\tincludedCount: 0,\n\t\t\t\t\tomittedCount: 0,\n\t\t\t\t\tblockChars: 0,\n\t\t\t\t};\n\t\t\t\treturn messages;\n\t\t\t}\n\t\t\tif (candidates.length === 0) {\n\t\t\t\tthis._latestMemoryPromptInclusionReport = {\n\t\t\t\t\t...base,\n\t\t\t\t\tstatus: \"no_results\",\n\t\t\t\t\tincludedCount: 0,\n\t\t\t\t\tomittedCount: 0,\n\t\t\t\t\tblockChars: 0,\n\t\t\t\t};\n\t\t\t\treturn messages;\n\t\t\t}\n\n\t\t\tconst budget = this._memoryBudget(settings.maxResults);\n\t\t\tconst block = composeTieredMemoryPromptBlock(candidates, budget);\n\t\t\tif (!block.text) {\n\t\t\t\tthis._latestMemoryPromptInclusionReport = {\n\t\t\t\t\t...base,\n\t\t\t\t\tstatus: \"empty_block\",\n\t\t\t\t\tincludedCount: block.includedCount,\n\t\t\t\t\tomittedCount: block.omittedCount,\n\t\t\t\t\tblockChars: 0,\n\t\t\t\t};\n\t\t\t\treturn messages;\n\t\t\t}\n\n\t\t\tconst wrapped = wrapUntrustedText(block.text, \"memory:tiered\");\n\t\t\tconst evidenceMessage: CustomMessage = {\n\t\t\t\trole: \"custom\",\n\t\t\t\tcustomType: \"memory_evidence\",\n\t\t\t\tcontent: [{ type: \"text\", text: wrapped }],\n\t\t\t\tdisplay: false,\n\t\t\t\ttimestamp: Date.now(),\n\t\t\t};\n\t\t\tthis._latestMemoryPromptInclusionReport = {\n\t\t\t\t...base,\n\t\t\t\tstatus: \"included\",\n\t\t\t\tincludedCount: block.includedCount,\n\t\t\t\tomittedCount: block.omittedCount,\n\t\t\t\tblockChars: wrapped.length,\n\t\t\t\tsourceLabel: \"memory:tiered\",\n\t\t\t};\n\t\t\treturn [...messages, evidenceMessage];\n\t\t} catch {\n\t\t\t// `base` may not exist yet if the throw happened before it was computed (e.g.\n\t\t\t// settings access or `report.contextItems` itself threw), so this branch cannot\n\t\t\t// rely on it -- fall back to safe, fixed defaults rather than risk referencing\n\t\t\t// a partially-evaluated value.\n\t\t\tthis._latestMemoryPromptInclusionReport = {\n\t\t\t\tenabled: false,\n\t\t\t\tincludeInPrompt: false,\n\t\t\t\tselectedItemCount: 0,\n\t\t\t\tstatus: \"failed\",\n\t\t\t\tincludedCount: 0,\n\t\t\t\tomittedCount: 0,\n\t\t\t\tblockChars: 0,\n\t\t\t};\n\t\t\treturn messages;\n\t\t}\n\t}\n\n\t/** Read-only inspection of the latest memory-prompt-inclusion decision, for tests/debugging and context_audit. */\n\tgetMemoryPromptInclusionReport(): MemoryPromptInclusionReport {\n\t\treturn this._latestMemoryPromptInclusionReport ?? defaultMemoryPromptInclusionReport();\n\t}\n\n\t/**\n\t * Combines the already-stored, no-arg latest reports (never re-queries the provider or\n\t * touches the OKF directory) into the safe, allow-list-projected shape context_audit\n\t * exposes. See context/memory-diagnostics.ts for why this projection is allow-list\n\t * based rather than a spread-then-delete of the raw report.\n\t */\n\tgetMemoryAuditDiagnostics(): {\n\t\tretrieval: MemoryRetrievalDiagnostics;\n\t\tpromptInclusion: MemoryPromptInclusionReport;\n\t} {\n\t\tconst settings = this.deps.getSettingsManager().getMemoryRetrievalSettings();\n\t\treturn {\n\t\t\tretrieval: sanitizeMemoryRetrievalReportForDiagnostics(this.getMemoryRetrievalReport(), settings),\n\t\t\tpromptInclusion: this.getMemoryPromptInclusionReport(),\n\t\t};\n\t}\n\n\t/**\n\t * Zero-I/O gate for cross-session recall (R3): skip trivial turns (short acks, slash commands) so\n\t * recall only runs when it could plausibly help. The provider's similarity cutoff is the real\n\t * filter — this just avoids the index query on turns that obviously don't warrant it.\n\t */\n\tshouldAttemptRecall(text: string): boolean {\n\t\tif (!this.deps.getSettingsManager().getMemoryRetrievalSettings().enabled) return false;\n\t\tconst t = text.trim();\n\t\tif (t.length < 12 || t.startsWith(\"/\")) return false;\n\t\tconst words = t.split(/\\s+/).filter((w) => w.length >= 3);\n\t\t// R4 adaptive gate: if recall has rarely been used lately (enough samples to trust the signal),\n\t\t// raise the bar so we only recall on clearly substantial turns — and relax it again once recall\n\t\t// starts paying off. Never fully disabled, so the loop can recover.\n\t\tconst recallRarelyUseful =\n\t\t\tthis._effectivenessTracker.sampleCount >= 5 && this._effectivenessTracker.usefulLately() < 0.15;\n\t\treturn words.length >= (recallRarelyUseful ? 6 : 3);\n\t}\n\n\t/** Legacy recall prefetch with the same hard-off and explicit external-egress policy as context retrieval. */\n\tasync prefetchRecall(query: string): Promise<string> {\n\t\tconst settings = this.deps.getSettingsManager().getMemoryRetrievalSettings();\n\t\tif (!settings.enabled) return \"\";\n\t\treturn this._memoryManager.prefetch(query, {\n\t\t\texternalEgressPolicy: settings.allowExternalEgress\n\t\t\t\t? ENABLED_EXTERNAL_MEMORY_EGRESS_POLICY\n\t\t\t\t: DEFAULT_EXTERNAL_MEMORY_EGRESS_POLICY,\n\t\t});\n\t}\n\n\t/** Bounded, read-only memory view for an explicitly authorized delegated worker. */\n\tasync readMemoryForLane(query: string): Promise<string> {\n\t\tconst settings = this.deps.getSettingsManager().getMemoryRetrievalSettings();\n\t\tif (!settings.enabled) return \"Memory retrieval is disabled by policy.\";\n\t\tconst budget = this._memoryBudget(settings.maxResults);\n\t\tconst staticBlock = this._memoryManager\n\t\t\t.buildSystemPromptBlockFresh(budget)\n\t\t\t.replace(\n\t\t\t\t\"[System Note: Below is a snapshot of your persistent memory. You can update these using the 'memory' tool.]\",\n\t\t\t\t\"[Read-only snapshot for a delegated worker.]\",\n\t\t\t);\n\t\tconst recalled = await this.prefetchRecall(query);\n\t\tconst combined = [staticBlock, recalled]\n\t\t\t.filter((part) => part.trim().length > 0)\n\t\t\t.join(\"\\n\\n\")\n\t\t\t.slice(0, 8000);\n\t\treturn combined.length > 0\n\t\t\t? wrapUntrustedText(combined, \"worker-memory\")\n\t\t\t: \"No relevant standing memory was found.\";\n\t}\n\n\t/** R4: score whether the agent actually used an injected recall page, so the recall gate can adapt. */\n\trecordRecallOutcome(recallText: string, queryText: string, responseText: string): void {\n\t\tthis._effectivenessTracker.recordRecallOutcome(recallText, queryText, responseText);\n\t}\n\n\t/**\n\t * (Re)build the memory subsystem: a fresh MemoryManager (reload-safe), register the bundled\n\t * file-store + any extension-contributed providers, initialize, then surface the memory tools and\n\t * the frozen system-prompt block. Best-effort: never throws into the session lifecycle.\n\t */\n\tasync initialize(): Promise<void> {\n\t\ttry {\n\t\t\t// Release the previous generation's providers (locks/handles) before recreating, so a\n\t\t\t// reload does not orphan the old MemoryManager. No-op on first init / for file-store.\n\t\t\tawait this._memoryManager.shutdownAll().catch(() => {});\n\t\t\tconst manager = new MemoryManager();\n\t\t\tmanager.registerProvider(new FileStoreProvider());\n\t\t\t// Bundled read-only cross-session recall (R3): indexes past-session transcripts and answers\n\t\t\t// prefetch() with a <memory_context> page. Never writes.\n\t\t\tmanager.registerProvider(new TranscriptRecallProvider());\n\t\t\tfor (const provider of this._pendingMemoryProviders) {\n\t\t\t\ttry {\n\t\t\t\t\tmanager.registerProvider(provider);\n\t\t\t\t} catch {\n\t\t\t\t\t// Duplicate name or reserved-tool collision — skip this provider, keep the rest.\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis._memoryManager = manager;\n\t\t\tawait manager.initializeAll(this.deps.getSessionId(), {\n\t\t\t\tagentDir: this.deps.getAgentDir(),\n\t\t\t\tcwd: this.deps.getCwd(),\n\t\t\t\tisChildSession: this.deps.isChildSession(),\n\t\t\t});\n\t\t\t// Surface memory tools + the frozen memory block now that providers are initialized.\n\t\t\t// refreshToolRegistry() ends in setActiveToolsByName(), which rebuilds AND assigns the\n\t\t\t// system prompt (including the memory block), so no explicit _rebuildSystemPrompt is needed.\n\t\t\tthis.deps.refreshToolRegistry();\n\t\t} catch (error) {\n\t\t\tconsole.error(\"Memory subsystem init failed:\", error instanceof Error ? error.message : String(error));\n\t\t}\n\t}\n\n\t/** Register a memory provider contributed by an extension; applied on the next memory (re)init. */\n\tregisterMemoryProvider(provider: MemoryProvider): void {\n\t\tif (!this._pendingMemoryProviders.some((p) => p.name === provider.name)) {\n\t\t\tthis._pendingMemoryProviders.push(provider);\n\t\t}\n\t}\n\n\t/** Register a retrieval-style context memory provider contributed by an extension. */\n\tregisterContextMemoryProvider(provider: ContextMemoryProvider): void {\n\t\tif (!this._pendingContextMemoryProviders.some((p) => p.id === provider.id)) {\n\t\t\tthis._pendingContextMemoryProviders.push(provider);\n\t\t}\n\t}\n\n\tcreateReloadSnapshot(): MemoryControllerReloadSnapshot {\n\t\treturn {\n\t\t\tpendingMemoryProviders: [...this._pendingMemoryProviders],\n\t\t\tpendingContextMemoryProviders: [...this._pendingContextMemoryProviders],\n\t\t\tmemoryOkfProvider: this._memoryOkfProvider,\n\t\t\tfileStoreMemoryProvider: this._fileStoreMemoryProvider,\n\t\t};\n\t}\n\n\trestoreReloadSnapshot(snapshot: MemoryControllerReloadSnapshot): void {\n\t\tthis._pendingMemoryProviders = [...snapshot.pendingMemoryProviders];\n\t\tthis._pendingContextMemoryProviders = [...snapshot.pendingContextMemoryProviders];\n\t\tthis._memoryOkfProvider = snapshot.memoryOkfProvider;\n\t\tthis._fileStoreMemoryProvider = snapshot.fileStoreMemoryProvider;\n\t}\n\n\t/** Reload starts memory providers fresh; loaded extensions re-register before the next `initialize()`. */\n\tclearPendingProviders(): void {\n\t\tthis._pendingMemoryProviders = [];\n\t\tthis._pendingContextMemoryProviders = [];\n\t\tthis._memoryOkfProvider = undefined;\n\t\tthis._fileStoreMemoryProvider = undefined;\n\t}\n}\n"]}
1
+ {"version":3,"file":"memory-controller.js","sourceRoot":"","sources":["../../src/core/memory-controller.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Memory controller: the session's plug-and-play memory subsystem — the read-only OKF retrieval\n * provider, the bounded prompt-evidence surfacing pilot, cross-session recall effectiveness, and the\n * live {@link MemoryManager} (bundled file-store + transcript-recall providers plus any extension\n * contributions).\n *\n * Extracted verbatim from agent-session.ts (god-file decomposition). Owns the lazily-built OKF\n * provider, the latest retrieval/prompt-inclusion reports, the recreated-on-reload MemoryManager, the\n * recall {@link EffectivenessTracker}, and the extension-contributed pending providers. Everything\n * else it needs — settings, the current turn index, agent/workspace dirs, the session id, the\n * child-session flag, and the tool-registry refresh — is reached through narrow deps accessors rather\n * than the whole AgentSession.\n *\n * Context-transform boundary (deliberate): {@link runMemoryRetrieval} and\n * {@link maybeAppendMemoryEvidenceBlock} are invoked from the session's context transform as one-line\n * delegations. This controller deliberately imports no compaction/context-pipeline internals — it only\n * ever reads settings and builds the retrieval report + the bounded evidence block, so the transform\n * stays the single owner of the pass ordering.\n */\n\nimport type { AgentMessage, CustomMessage } from \"@caupulican/pi-agent-core\";\nimport { configFile, okfMemoryDir } from \"./agent-paths.ts\";\nimport { collectCurrentWorkMemory } from \"./context/current-work-memory.ts\";\nimport { createFileStoreMemoryProvider } from \"./context/file-store-memory-provider.ts\";\nimport { shouldQueryLongTermMemory } from \"./context/long-term-memory-trigger.ts\";\nimport {\n\tdefaultMemoryPromptInclusionReport,\n\ttype MemoryPromptInclusionReport,\n\ttype MemoryRetrievalDiagnostics,\n\tsanitizeMemoryRetrievalReportForDiagnostics,\n} from \"./context/memory-diagnostics.ts\";\nimport { type MemoryPromptBudget, resolveMemoryPromptBudget } from \"./context/memory-prompt-budget.ts\";\nimport {\n\ttype MemoryProvider as ContextMemoryProvider,\n\tDEFAULT_EXTERNAL_MEMORY_EGRESS_POLICY,\n\tDEFAULT_LOCAL_MEMORY_EGRESS_POLICY,\n} from \"./context/memory-provider-contract.ts\";\nimport { type MemoryRetrievalReport, retrieveMemoryForContext } from \"./context/memory-retrieval.ts\";\nimport { composeTieredMemoryPromptBlock, type MemoryTierCandidate } from \"./context/memory-tier-composer.ts\";\nimport { createOkfMemoryProvider } from \"./context/okf-memory-provider.ts\";\nimport type { GoalState } from \"./goals/goal-state.ts\";\nimport { EffectivenessTracker } from \"./memory/effectiveness-tracker.ts\";\nimport { MemoryManager } from \"./memory/memory-manager.ts\";\nimport type { MemoryProvider } from \"./memory/memory-provider.ts\";\nimport { FileStoreProvider } from \"./memory/providers/file-store.ts\";\nimport { TranscriptRecallProvider } from \"./memory/providers/transcript-recall.ts\";\nimport { wrapUntrustedText } from \"./security/untrusted-boundary.ts\";\nimport type { SettingsManager } from \"./settings-manager.ts\";\n\n/**\n * Text of the most recent user message, or \"\" if there is none (e.g. goal-continuation\n * turns with no new user input). An empty query is still valid: standing user preferences may\n * surface from the file-store retrieval fallback when the static memory prompt cannot fit,\n * while long-term providers remain gated by shouldQueryLongTermMemory().\n */\nfunction latestUserMessageText(messages: AgentMessage[]): string {\n\tfor (let index = messages.length - 1; index >= 0; index--) {\n\t\tconst message = messages[index];\n\t\tif (message.role !== \"user\") continue;\n\t\tif (typeof message.content === \"string\") return message.content;\n\t\tconst parts: string[] = [];\n\t\tfor (const part of message.content) {\n\t\t\tif (part.type === \"text\") parts.push(part.text);\n\t\t}\n\t\treturn parts.join(\"\\n\");\n\t}\n\treturn \"\";\n}\n\nfunction emptyMemoryRetrievalReport(maxResults: number): MemoryRetrievalReport {\n\treturn { request: { query: \"\", maxResults }, providerReports: [], results: [], contextItems: [] };\n}\n\nconst ENABLED_EXTERNAL_MEMORY_EGRESS_POLICY = {\n\t...DEFAULT_EXTERNAL_MEMORY_EGRESS_POLICY,\n\tenabled: true,\n\tallowedScopes: DEFAULT_LOCAL_MEMORY_EGRESS_POLICY.allowedScopes,\n\tallowExternalEgress: true,\n} as const;\n\nexport interface MemoryControllerDeps {\n\t/** Memory-retrieval + prompt-inclusion settings (default-on gates for retrieval and surfacing). */\n\tgetSettingsManager(): SettingsManager;\n\t/** Current turn index, stamped into a retrieval request's `createdAtTurn`. */\n\tgetTurnIndex(): number;\n\t/** Agent root — the durable OKF memory docs live under `<agentDir>/okf-memory`. */\n\tgetAgentDir(): string;\n\t/** Workspace root, passed to provider initialization. */\n\tgetCwd(): string;\n\t/** This session's id, passed to provider initialization. */\n\tgetSessionId(): string;\n\t/** Child sessions gate durable memory writes; passed to provider initialization. */\n\tisChildSession(): boolean;\n\t/** Re-derive the tool registry after (re)init so the newly-surfaced memory tools take effect. */\n\trefreshToolRegistry(): void;\n\t/** Active model context window, used to cap prompt-visible memory. */\n\tgetContextWindow(): number | undefined;\n\t/** Latest active goal state, used for short-term current-work memory. */\n\tgetGoalState(): GoalState | undefined;\n}\n\n/** Extension-contributed memory state staged across an atomic runtime reload. */\nexport interface MemoryControllerReloadSnapshot {\n\tpendingMemoryProviders: MemoryProvider[];\n\tpendingContextMemoryProviders: ContextMemoryProvider[];\n\tmemoryOkfProvider: ContextMemoryProvider | undefined;\n\tfileStoreMemoryProvider: ContextMemoryProvider | undefined;\n}\n\nexport class MemoryController {\n\tprivate _memoryOkfProvider: ContextMemoryProvider | undefined = undefined;\n\tprivate _fileStoreMemoryProvider: ContextMemoryProvider | undefined = undefined;\n\tprivate _latestMemoryRetrievalReport: MemoryRetrievalReport | undefined = undefined;\n\tprivate _latestMemoryPromptInclusionReport: MemoryPromptInclusionReport | undefined = undefined;\n\t/** Plug-and-play memory subsystem. Recreated on each (re)initialize so reload is safe. */\n\tprivate _memoryManager: MemoryManager = new MemoryManager();\n\t/** R4: tracks whether injected recall is actually used, to adapt the recall gate. */\n\tprivate readonly _effectivenessTracker = new EffectivenessTracker();\n\t/** Memory providers registered by extensions via pi.registerMemoryProvider, applied on (re)init. */\n\tprivate _pendingMemoryProviders: MemoryProvider[] = [];\n\t/** Context-memory providers registered by extensions via pi.registerContextMemoryProvider. */\n\tprivate _pendingContextMemoryProviders: ContextMemoryProvider[] = [];\n\n\tprivate readonly deps: MemoryControllerDeps;\n\n\tconstructor(deps: MemoryControllerDeps) {\n\t\tthis.deps = deps;\n\t}\n\n\t/** The live memory manager. Callers reach prefetch / tool-definitions / markers / shutdown through it. */\n\tgetMemoryManager(): MemoryManager {\n\t\treturn this._memoryManager;\n\t}\n\n\t/**\n\t * Fixed path for this slice's local Pi OKF memory documents, shared across sessions\n\t * under this agentDir (not session-scoped, unlike tool-artifacts/context-gc, since OKF\n\t * memory represents durable cross-session knowledge, not a per-session capture). Not\n\t * yet user-configurable -- see the memory-retrieval settings doc comment.\n\t */\n\tprivate _memoryOkfDir(): string {\n\t\treturn okfMemoryDir(this.deps.getAgentDir());\n\t}\n\n\t/**\n\t * Session-scoped, read-only local OKF memory provider. Lazily created ONLY when memory\n\t * retrieval is enabled (see `runMemoryRetrieval`) -- never force-created, so a session\n\t * with the setting off never touches `_memoryOkfDir()` at all (no directory access, no\n\t * creation; `createOkfMemoryProvider` itself never writes/mkdirs either way).\n\t */\n\tprivate _getMemoryOkfProvider(): ContextMemoryProvider {\n\t\tthis._memoryOkfProvider ??= createOkfMemoryProvider({ rootDir: this._memoryOkfDir() });\n\t\treturn this._memoryOkfProvider;\n\t}\n\n\tprivate _getFileStoreMemoryProvider(): ContextMemoryProvider {\n\t\tthis._fileStoreMemoryProvider ??= createFileStoreMemoryProvider({\n\t\t\tmemoryFilePath: configFile(this.deps.getAgentDir(), \"MEMORY.md\"),\n\t\t\tuserFilePath: configFile(this.deps.getAgentDir(), \"USER.md\"),\n\t\t});\n\t\treturn this._fileStoreMemoryProvider;\n\t}\n\n\tprivate _memoryBudget(configuredMaxResults: number) {\n\t\treturn resolveMemoryPromptBudget({\n\t\t\tcontextWindow: this.deps.getContextWindow(),\n\t\t\tconfiguredMaxResults,\n\t\t});\n\t}\n\n\tprivate _shouldQueryFileStoreFallback(budget: MemoryPromptBudget): boolean {\n\t\t// MEMORY.md/USER.md are already injected through the static file-store prompt on\n\t\t// normal windows, so querying them again would duplicate provider-visible memory.\n\t\t// In compact windows the static block can be omitted because it does not fit; only\n\t\t// then use the retrieval view to surface a few budget-pruned lines.\n\t\tif (!budget.enabled || !budget.compact) return false;\n\t\treturn this._memoryManager.buildSystemPromptBlock(budget).trim().length === 0;\n\t}\n\n\t/**\n\t * Observe-only local memory retrieval (see context/memory-retrieval.ts and\n\t * context/okf-memory-provider.ts): default-on, but settings-gated. When disabled,\n\t * never constructs built-in context-memory providers (no directory access under\n\t * `_memoryOkfDir()` at all) and returns an empty report -- fully fail-closed. When enabled,\n\t * queries local, read-only providers with the latest user message text (empty if there is\n\t * none, e.g. a goal-continuation turn) under `DEFAULT_LOCAL_MEMORY_EGRESS_POLICY`.\n\t * Retrieved items are only ever stored in the report; nothing here touches `messages`,\n\t * the transcript, or the provider-visible prompt. Never throws into a live turn: any\n\t * failure (including a provider search error) degrades to an empty report.\n\t */\n\tasync runMemoryRetrieval(messages: AgentMessage[]): Promise<MemoryRetrievalReport> {\n\t\ttry {\n\t\t\tconst settings = this.deps.getSettingsManager().getMemoryRetrievalSettings();\n\t\t\tif (!settings.enabled) {\n\t\t\t\tconst report = emptyMemoryRetrievalReport(settings.maxResults);\n\t\t\t\tthis._latestMemoryRetrievalReport = report;\n\t\t\t\treturn report;\n\t\t\t}\n\t\t\tconst query = latestUserMessageText(messages);\n\t\t\tconst budget = this._memoryBudget(settings.maxResults);\n\t\t\tconst currentWork = collectCurrentWorkMemory({ goalState: this.deps.getGoalState() });\n\t\t\tconst longTermDecision = shouldQueryLongTermMemory({\n\t\t\t\tlatestUserText: query,\n\t\t\t\tgoalState: this.deps.getGoalState(),\n\t\t\t\tbudget,\n\t\t\t\tcurrentWorkCandidateCount: currentWork.length,\n\t\t\t});\n\t\t\tconst providers = this._shouldQueryFileStoreFallback(budget) ? [this._getFileStoreMemoryProvider()] : [];\n\t\t\tif (longTermDecision.shouldQuery) {\n\t\t\t\tproviders.push(this._getMemoryOkfProvider(), ...this._pendingContextMemoryProviders);\n\t\t\t}\n\t\t\tconst maxResults = budget.enabled ? Math.min(settings.maxResults, budget.maxResults) : settings.maxResults;\n\t\t\tconst report = await retrieveMemoryForContext(\n\t\t\t\tproviders,\n\t\t\t\t{ query, maxResults },\n\t\t\t\t{\n\t\t\t\t\tcreatedAtTurn: this.deps.getTurnIndex(),\n\t\t\t\t\tmaxResults,\n\t\t\t\t\tdefaultLocalPolicy: DEFAULT_LOCAL_MEMORY_EGRESS_POLICY,\n\t\t\t\t\tdefaultExternalPolicy: settings.allowExternalEgress\n\t\t\t\t\t\t? ENABLED_EXTERNAL_MEMORY_EGRESS_POLICY\n\t\t\t\t\t\t: DEFAULT_EXTERNAL_MEMORY_EGRESS_POLICY,\n\t\t\t\t},\n\t\t\t);\n\t\t\tthis._latestMemoryRetrievalReport = report;\n\t\t\treturn report;\n\t\t} catch {\n\t\t\tconst report = emptyMemoryRetrievalReport(0);\n\t\t\tthis._latestMemoryRetrievalReport = report;\n\t\t\treturn report;\n\t\t}\n\t}\n\n\t/** Read-only inspection of the latest memory-retrieval report, for tests/debugging. */\n\tgetMemoryRetrievalReport(): MemoryRetrievalReport {\n\t\treturn this._latestMemoryRetrievalReport ?? emptyMemoryRetrievalReport(0);\n\t}\n\n\tprivate _candidateForContextItem(\n\t\titem: MemoryRetrievalReport[\"contextItems\"][number],\n\t): MemoryTierCandidate | undefined {\n\t\tconst summary = item.summary?.trim();\n\t\tif (!summary) return undefined;\n\t\tconst ref = item.primaryRef?.type === \"memory\" ? item.primaryRef.ref : undefined;\n\t\tconst sourceLabel =\n\t\t\tref?.providerId === \"pi-file-store\" && ref.kind === \"user_preference\"\n\t\t\t\t? \"rule:user\"\n\t\t\t\t: `memory:${ref?.providerId ?? item.source}`;\n\t\tconst tier = ref?.kind === \"user_preference\" ? \"standing\" : \"long_term\";\n\t\treturn {\n\t\t\tid: item.id,\n\t\t\ttier,\n\t\t\tsourceLabel,\n\t\t\tsummary,\n\t\t\tscore: 0.5,\n\t\t\tevidenceRefs: item.evidenceRefs,\n\t\t};\n\t}\n\n\tprivate _memoryCandidates(report: MemoryRetrievalReport): MemoryTierCandidate[] {\n\t\treturn [\n\t\t\t...collectCurrentWorkMemory({ goalState: this.deps.getGoalState() }),\n\t\t\t...report.contextItems.flatMap((item) => {\n\t\t\t\tconst candidate = this._candidateForContextItem(item);\n\t\t\t\treturn candidate === undefined ? [] : [candidate];\n\t\t\t}),\n\t\t];\n\t}\n\n\t/**\n\t * Bounded prompt-surfacing for local memory evidence (see context/memory-tier-composer.ts):\n\t * default-on, but gated on TWO settings (`enabled` AND `includeInPrompt`) plus at least one\n\t * current-work, standing, or retrieved memory candidate -- the first\n\t * two are belt-and-suspenders on top of the fact that `runMemoryRetrieval` already\n\t * leaves `contextItems` empty whenever `enabled` is false, regardless of\n\t * `includeInPrompt`. Reuses the `report` this pass's `runMemoryRetrieval` call already\n\t * computed -- never re-queries the provider here.\n\t *\n\t * Appends exactly one ephemeral `custom`/\"memory_evidence\" message wrapped by\n\t * `wrapUntrustedText` (the same nonce-fenced boundary + always-on system-prompt rule\n\t * used for other untrusted content) to the END of `messages`. This is purely additive\n\t * (never mutates an existing message) and purely transient: `messages` here is the\n\t * array about to be sent to the provider, not `this.agent.state.messages` or anything\n\t * persisted via `sessionManager` -- so the injected message can never reach the\n\t * transcript, regardless of how many times this pass runs.\n\t *\n\t * Also records a `MemoryPromptInclusionReport` (context/memory-diagnostics.ts) at each\n\t * branch below, for context_audit's diagnostic surface only -- this is pure bookkeeping\n\t * alongside the existing branches, not a new branch/condition: the messages returned\n\t * are unchanged by this recording.\n\t */\n\tmaybeAppendMemoryEvidenceBlock(messages: AgentMessage[], report: MemoryRetrievalReport): AgentMessage[] {\n\t\ttry {\n\t\t\tconst settings = this.deps.getSettingsManager().getMemoryRetrievalSettings();\n\t\t\tconst candidates = this._memoryCandidates(report);\n\t\t\tconst base = {\n\t\t\t\tenabled: settings.enabled,\n\t\t\t\tincludeInPrompt: settings.includeInPrompt,\n\t\t\t\tselectedItemCount: candidates.length,\n\t\t\t};\n\t\t\tif (!settings.enabled) {\n\t\t\t\tthis._latestMemoryPromptInclusionReport = {\n\t\t\t\t\t...base,\n\t\t\t\t\tstatus: \"disabled\",\n\t\t\t\t\tincludedCount: 0,\n\t\t\t\t\tomittedCount: 0,\n\t\t\t\t\tblockChars: 0,\n\t\t\t\t};\n\t\t\t\treturn messages;\n\t\t\t}\n\t\t\tif (!settings.includeInPrompt) {\n\t\t\t\tthis._latestMemoryPromptInclusionReport = {\n\t\t\t\t\t...base,\n\t\t\t\t\tstatus: \"include_disabled\",\n\t\t\t\t\tincludedCount: 0,\n\t\t\t\t\tomittedCount: 0,\n\t\t\t\t\tblockChars: 0,\n\t\t\t\t};\n\t\t\t\treturn messages;\n\t\t\t}\n\t\t\tif (candidates.length === 0) {\n\t\t\t\tthis._latestMemoryPromptInclusionReport = {\n\t\t\t\t\t...base,\n\t\t\t\t\tstatus: \"no_results\",\n\t\t\t\t\tincludedCount: 0,\n\t\t\t\t\tomittedCount: 0,\n\t\t\t\t\tblockChars: 0,\n\t\t\t\t};\n\t\t\t\treturn messages;\n\t\t\t}\n\n\t\t\tconst budget = this._memoryBudget(settings.maxResults);\n\t\t\tconst block = composeTieredMemoryPromptBlock(candidates, budget);\n\t\t\tif (!block.text) {\n\t\t\t\tthis._latestMemoryPromptInclusionReport = {\n\t\t\t\t\t...base,\n\t\t\t\t\tstatus: \"empty_block\",\n\t\t\t\t\tincludedCount: block.includedCount,\n\t\t\t\t\tomittedCount: block.omittedCount,\n\t\t\t\t\tblockChars: 0,\n\t\t\t\t};\n\t\t\t\treturn messages;\n\t\t\t}\n\n\t\t\tconst wrapped = wrapUntrustedText(block.text, \"memory:tiered\");\n\t\t\tconst evidenceMessage: CustomMessage = {\n\t\t\t\trole: \"custom\",\n\t\t\t\tcustomType: \"memory_evidence\",\n\t\t\t\tcontent: [{ type: \"text\", text: wrapped }],\n\t\t\t\tdisplay: false,\n\t\t\t\ttimestamp: Date.now(),\n\t\t\t};\n\t\t\tthis._latestMemoryPromptInclusionReport = {\n\t\t\t\t...base,\n\t\t\t\tstatus: \"included\",\n\t\t\t\tincludedCount: block.includedCount,\n\t\t\t\tomittedCount: block.omittedCount,\n\t\t\t\tblockChars: wrapped.length,\n\t\t\t\tsourceLabel: \"memory:tiered\",\n\t\t\t};\n\t\t\treturn [...messages, evidenceMessage];\n\t\t} catch {\n\t\t\t// `base` may not exist yet if the throw happened before it was computed (e.g.\n\t\t\t// settings access or `report.contextItems` itself threw), so this branch cannot\n\t\t\t// rely on it -- fall back to safe, fixed defaults rather than risk referencing\n\t\t\t// a partially-evaluated value.\n\t\t\tthis._latestMemoryPromptInclusionReport = {\n\t\t\t\tenabled: false,\n\t\t\t\tincludeInPrompt: false,\n\t\t\t\tselectedItemCount: 0,\n\t\t\t\tstatus: \"failed\",\n\t\t\t\tincludedCount: 0,\n\t\t\t\tomittedCount: 0,\n\t\t\t\tblockChars: 0,\n\t\t\t};\n\t\t\treturn messages;\n\t\t}\n\t}\n\n\t/** Read-only inspection of the latest memory-prompt-inclusion decision, for tests/debugging and context_audit. */\n\tgetMemoryPromptInclusionReport(): MemoryPromptInclusionReport {\n\t\treturn this._latestMemoryPromptInclusionReport ?? defaultMemoryPromptInclusionReport();\n\t}\n\n\t/**\n\t * Combines the already-stored, no-arg latest reports (never re-queries the provider or\n\t * touches the OKF directory) into the safe, allow-list-projected shape context_audit\n\t * exposes. See context/memory-diagnostics.ts for why this projection is allow-list\n\t * based rather than a spread-then-delete of the raw report.\n\t */\n\tgetMemoryAuditDiagnostics(): {\n\t\tretrieval: MemoryRetrievalDiagnostics;\n\t\tpromptInclusion: MemoryPromptInclusionReport;\n\t} {\n\t\tconst settings = this.deps.getSettingsManager().getMemoryRetrievalSettings();\n\t\treturn {\n\t\t\tretrieval: sanitizeMemoryRetrievalReportForDiagnostics(this.getMemoryRetrievalReport(), settings),\n\t\t\tpromptInclusion: this.getMemoryPromptInclusionReport(),\n\t\t};\n\t}\n\n\t/**\n\t * Zero-I/O gate for cross-session recall (R3): skip trivial turns (short acks, slash commands) so\n\t * recall only runs when it could plausibly help. The provider's similarity cutoff is the real\n\t * filter — this just avoids the index query on turns that obviously don't warrant it.\n\t */\n\tshouldAttemptRecall(text: string): boolean {\n\t\tif (!this.deps.getSettingsManager().getMemoryRetrievalSettings().enabled) return false;\n\t\tconst t = text.trim();\n\t\tif (t.length < 12 || t.startsWith(\"/\")) return false;\n\t\tconst words = t.split(/\\s+/).filter((w) => w.length >= 3);\n\t\t// R4 adaptive gate: if recall has rarely been used lately (enough samples to trust the signal),\n\t\t// raise the bar so we only recall on clearly substantial turns — and relax it again once recall\n\t\t// starts paying off. Never fully disabled, so the loop can recover.\n\t\tconst recallRarelyUseful =\n\t\t\tthis._effectivenessTracker.sampleCount >= 5 && this._effectivenessTracker.usefulLately() < 0.15;\n\t\treturn words.length >= (recallRarelyUseful ? 6 : 3);\n\t}\n\n\t/** Legacy recall prefetch with the same hard-off and explicit external-egress policy as context retrieval. */\n\tasync prefetchRecall(query: string): Promise<string> {\n\t\tconst settings = this.deps.getSettingsManager().getMemoryRetrievalSettings();\n\t\tif (!settings.enabled) return \"\";\n\t\treturn this._memoryManager.prefetch(query, {\n\t\t\texternalEgressPolicy: settings.allowExternalEgress\n\t\t\t\t? ENABLED_EXTERNAL_MEMORY_EGRESS_POLICY\n\t\t\t\t: DEFAULT_EXTERNAL_MEMORY_EGRESS_POLICY,\n\t\t});\n\t}\n\n\t/** Bounded, read-only memory view for an explicitly authorized delegated worker. */\n\tasync readMemoryForLane(query: string): Promise<string> {\n\t\tconst settings = this.deps.getSettingsManager().getMemoryRetrievalSettings();\n\t\tif (!settings.enabled) return \"Memory retrieval is disabled by policy.\";\n\t\tconst budget = this._memoryBudget(settings.maxResults);\n\t\tconst staticBlock = this._memoryManager\n\t\t\t.buildSystemPromptBlockFresh(budget)\n\t\t\t.replace(\n\t\t\t\t\"[System Note: Below is a snapshot of your persistent memory. You can update these using the 'memory' tool.]\",\n\t\t\t\t\"[Read-only snapshot for a delegated worker.]\",\n\t\t\t);\n\t\tconst recalled = await this.prefetchRecall(query);\n\t\tconst combined = [staticBlock, recalled]\n\t\t\t.filter((part) => part.trim().length > 0)\n\t\t\t.join(\"\\n\\n\")\n\t\t\t.slice(0, 8000);\n\t\treturn combined.length > 0\n\t\t\t? wrapUntrustedText(combined, \"worker-memory\")\n\t\t\t: \"No relevant standing memory was found.\";\n\t}\n\n\t/** R4: score whether the agent actually used an injected recall page, so the recall gate can adapt. */\n\trecordRecallOutcome(recallText: string, queryText: string, responseText: string): void {\n\t\tthis._effectivenessTracker.recordRecallOutcome(recallText, queryText, responseText);\n\t}\n\n\t/**\n\t * (Re)build the memory subsystem: a fresh MemoryManager (reload-safe), register the bundled\n\t * file-store + any extension-contributed providers, initialize, then surface the memory tools and\n\t * the frozen system-prompt block. Best-effort: never throws into the session lifecycle.\n\t */\n\tasync initialize(): Promise<void> {\n\t\ttry {\n\t\t\t// Release the previous generation's providers (locks/handles) before recreating, so a\n\t\t\t// reload does not orphan the old MemoryManager. No-op on first init / for file-store.\n\t\t\tawait this._memoryManager.shutdownAll().catch(() => {});\n\t\t\tconst manager = new MemoryManager();\n\t\t\tmanager.registerProvider(new FileStoreProvider());\n\t\t\t// Bundled read-only cross-session recall (R3): indexes past-session transcripts and answers\n\t\t\t// prefetch() with a <memory_context> page. Never writes.\n\t\t\tmanager.registerProvider(new TranscriptRecallProvider());\n\t\t\tfor (const provider of this._pendingMemoryProviders) {\n\t\t\t\ttry {\n\t\t\t\t\tmanager.registerProvider(provider);\n\t\t\t\t} catch {\n\t\t\t\t\t// Duplicate name or reserved-tool collision — skip this provider, keep the rest.\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis._memoryManager = manager;\n\t\t\tawait manager.initializeAll(this.deps.getSessionId(), {\n\t\t\t\tagentDir: this.deps.getAgentDir(),\n\t\t\t\tcwd: this.deps.getCwd(),\n\t\t\t\tisChildSession: this.deps.isChildSession(),\n\t\t\t});\n\t\t\t// Surface memory tools + the frozen memory block now that providers are initialized.\n\t\t\t// refreshToolRegistry() ends in setActiveToolsByName(), which rebuilds AND assigns the\n\t\t\t// system prompt (including the memory block), so no explicit _rebuildSystemPrompt is needed.\n\t\t\tthis.deps.refreshToolRegistry();\n\t\t} catch (error) {\n\t\t\tconsole.error(\"Memory subsystem init failed:\", error instanceof Error ? error.message : String(error));\n\t\t}\n\t}\n\n\t/** Register a memory provider contributed by an extension; applied on the next memory (re)init. */\n\tregisterMemoryProvider(provider: MemoryProvider): void {\n\t\tif (!this._pendingMemoryProviders.some((p) => p.name === provider.name)) {\n\t\t\tthis._pendingMemoryProviders.push(provider);\n\t\t}\n\t}\n\n\t/** Register a retrieval-style context memory provider contributed by an extension. */\n\tregisterContextMemoryProvider(provider: ContextMemoryProvider): void {\n\t\tif (!this._pendingContextMemoryProviders.some((p) => p.id === provider.id)) {\n\t\t\tthis._pendingContextMemoryProviders.push(provider);\n\t\t}\n\t}\n\n\tcreateReloadSnapshot(): MemoryControllerReloadSnapshot {\n\t\treturn {\n\t\t\tpendingMemoryProviders: [...this._pendingMemoryProviders],\n\t\t\tpendingContextMemoryProviders: [...this._pendingContextMemoryProviders],\n\t\t\tmemoryOkfProvider: this._memoryOkfProvider,\n\t\t\tfileStoreMemoryProvider: this._fileStoreMemoryProvider,\n\t\t};\n\t}\n\n\trestoreReloadSnapshot(snapshot: MemoryControllerReloadSnapshot): void {\n\t\tthis._pendingMemoryProviders = [...snapshot.pendingMemoryProviders];\n\t\tthis._pendingContextMemoryProviders = [...snapshot.pendingContextMemoryProviders];\n\t\tthis._memoryOkfProvider = snapshot.memoryOkfProvider;\n\t\tthis._fileStoreMemoryProvider = snapshot.fileStoreMemoryProvider;\n\t}\n\n\t/** Reload starts memory providers fresh; loaded extensions re-register before the next `initialize()`. */\n\tclearPendingProviders(): void {\n\t\tthis._pendingMemoryProviders = [];\n\t\tthis._pendingContextMemoryProviders = [];\n\t\tthis._memoryOkfProvider = undefined;\n\t\tthis._fileStoreMemoryProvider = undefined;\n\t}\n}\n"]}