@xopcai/xopc 0.0.95 → 0.0.96

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 (428) hide show
  1. package/dist/browser-ext/manifest.json +1 -1
  2. package/dist/extensions/feishu/src/outbound/media-load.js +1 -1
  3. package/dist/extensions/feishu/src/workflow-progress.js +1 -1
  4. package/dist/extensions/telegram/src/plugin.js +1 -1
  5. package/dist/extensions/telegram/src/routing-integration.js +2 -2
  6. package/dist/extensions/telegram/src/workflow-progress.js +1 -1
  7. package/dist/extensions/telegram/xopc.extension.json +1 -1
  8. package/dist/extensions/weixin/src/api/api.js +2 -2
  9. package/dist/extensions/weixin/src/auth/accounts.js +1 -1
  10. package/dist/extensions/weixin/src/cdn/upload.js +1 -1
  11. package/dist/extensions/weixin/src/media/data-url.js +1 -1
  12. package/dist/extensions/weixin/src/messaging/debug-mode.js +1 -1
  13. package/dist/extensions/weixin/src/messaging/inbound.js +1 -1
  14. package/dist/extensions/weixin/src/messaging/process-message.js +1 -1
  15. package/dist/extensions/weixin/src/plugin.js +1 -1
  16. package/dist/extensions/weixin/src/storage/sync-buf.js +1 -1
  17. package/dist/extensions/weixin/src/workflow-progress.js +1 -1
  18. package/dist/gateway/static/root/assets/{agents-CKe2LMnz.js → agents-DmIuSaOE.js} +2 -2
  19. package/dist/gateway/static/root/assets/{apps-page-Mi9mMIZ1.js → apps-page-DFcHBxLw.js} +1 -1
  20. package/dist/gateway/static/root/assets/{channels-settings-BrdyC101.js → channels-settings-DDUf55C5.js} +1 -1
  21. package/dist/gateway/static/root/assets/{channels-status-swr-D55Bu0nn.js → channels-status-swr-BxF-_nzD.js} +1 -1
  22. package/dist/gateway/static/root/assets/{cron-api-CPpx2l-E.js → cron-api-DylQtnb_.js} +1 -1
  23. package/dist/gateway/static/root/assets/{cron-page-Bx2jB0YN.js → cron-page-BO0d9Pf-.js} +1 -1
  24. package/dist/gateway/static/root/assets/{dist-D_AiG_Kg.js → dist-BskF0qDS.js} +1 -1
  25. package/dist/gateway/static/root/assets/{extension-debug-page-6ieHsxRE.js → extension-debug-page-BcZdTdjJ.js} +1 -1
  26. package/dist/gateway/static/root/assets/{extension-page-B8nywHRO.js → extension-page-D2iuDa1D.js} +1 -1
  27. package/dist/gateway/static/root/assets/{extension-settings-page-DrskdEIV.js → extension-settings-page-BKpQCgLc.js} +1 -1
  28. package/dist/gateway/static/root/assets/{fetch-B0aeeY0q.js → fetch-CtNDpjij.js} +1 -1
  29. package/dist/gateway/static/root/assets/{field-primitives--9ooY8Xl.js → field-primitives-2PekrGZF.js} +1 -1
  30. package/dist/gateway/static/root/assets/{heartbeat-config-api-DUZ_W1w-.js → heartbeat-config-api-D3D7SW8A.js} +1 -1
  31. package/dist/gateway/static/root/assets/index-BvEhL9RQ.css +1 -0
  32. package/dist/gateway/static/root/assets/{index-Dj9FuxCm.js → index-Db9fd_X4.js} +74 -74
  33. package/dist/gateway/static/root/assets/{logs-page-CaXqhpKf.js → logs-page-B3I1a26m.js} +1 -1
  34. package/dist/gateway/static/root/assets/{note-detail-page-DYzym2B0.js → note-detail-page-BOizhtJ8.js} +54 -53
  35. package/dist/gateway/static/root/assets/{note-detail-page-B91pLkEI.css → note-detail-page-D4ZIVQbk.css} +1 -1
  36. package/dist/gateway/static/root/assets/{note-time-B-vSi2dR.js → note-time-CjUGtqKr.js} +1 -1
  37. package/dist/gateway/static/root/assets/{notes-page-BkhWdGiT.js → notes-page-BB8-I0Of.js} +1 -1
  38. package/dist/gateway/static/root/assets/{sessions-page-53YFokoe.js → sessions-page-BcH-1K9i.js} +1 -1
  39. package/dist/gateway/static/root/assets/{settings-advanced-gate-BaZmaklx.js → settings-advanced-gate-Czn8nnjN.js} +1 -1
  40. package/dist/gateway/static/root/assets/{settings-form-section-DIJPKpTR.js → settings-form-section-ZZWDwgVe.js} +1 -1
  41. package/dist/gateway/static/root/assets/{settings-page-Dvb230FF.js → settings-page-BX8c_zrN.js} +1 -1
  42. package/dist/gateway/static/root/assets/{share-preview-page-CRyjTAG6.js → share-preview-page-Ch3_6Qah.js} +1 -1
  43. package/dist/gateway/static/root/assets/{skills-page-C5ZJbfAe.js → skills-page-WO0bbJ54.js} +1 -1
  44. package/dist/gateway/static/root/assets/{theme-store-Cg_SuBw0.js → theme-store-XxRFRZDX.js} +1 -1
  45. package/dist/gateway/static/root/assets/url-6zpynn1R.js +3 -0
  46. package/dist/gateway/static/root/assets/{utils-lMYoWhqo.js → utils-uTYKh54l.js} +1 -1
  47. package/dist/gateway/static/root/assets/{voice-api-key-field-Dda2pcUU.js → voice-api-key-field-BIAYHRs-.js} +1 -1
  48. package/dist/gateway/static/root/assets/{workflow-page.utils-KIladUrU.js → workflow-page.utils-BbWhqD36.js} +1 -1
  49. package/dist/gateway/static/root/assets/{workflows-page-BTis4Z7Y.js → workflows-page-D4RIF7E1.js} +1 -1
  50. package/dist/gateway/static/root/index.html +5 -5
  51. package/dist/package.js +1 -1
  52. package/dist/src/agent/agent-manager.js +15 -9
  53. package/dist/src/agent/agent-manager.js.map +1 -1
  54. package/dist/src/agent/agent-scope.d.ts +0 -1
  55. package/dist/src/agent/agent-scope.js +2 -5
  56. package/dist/src/agent/agent-scope.js.map +1 -1
  57. package/dist/src/agent/bootstrap/bootstrap-cache.d.ts +3 -0
  58. package/dist/src/agent/bootstrap/bootstrap-cache.js +13 -3
  59. package/dist/src/agent/bootstrap/bootstrap-cache.js.map +1 -1
  60. package/dist/src/agent/bootstrap/bootstrap-files.d.ts +6 -0
  61. package/dist/src/agent/bootstrap/bootstrap-files.js +35 -12
  62. package/dist/src/agent/bootstrap/bootstrap-files.js.map +1 -1
  63. package/dist/src/agent/bootstrap/load-bootstrap-files.d.ts +5 -2
  64. package/dist/src/agent/bootstrap/load-bootstrap-files.js +12 -3
  65. package/dist/src/agent/bootstrap/load-bootstrap-files.js.map +1 -1
  66. package/dist/src/agent/context/workspace-seed.js +8 -4
  67. package/dist/src/agent/context/workspace-seed.js.map +1 -1
  68. package/dist/src/agent/context/workspace-state.d.ts +52 -0
  69. package/dist/src/agent/context/workspace-state.js +101 -0
  70. package/dist/src/agent/context/workspace-state.js.map +1 -0
  71. package/dist/src/agent/embedded/index.d.ts +2 -2
  72. package/dist/src/agent/embedded/index.js +3 -3
  73. package/dist/src/agent/embedded/run-turn.js +0 -3
  74. package/dist/src/agent/embedded/run-turn.js.map +1 -1
  75. package/dist/src/agent/embedded/session-manager-init.d.ts +0 -17
  76. package/dist/src/agent/embedded/session-manager-init.js +1 -36
  77. package/dist/src/agent/embedded/session-manager-init.js.map +1 -1
  78. package/dist/src/agent/embedded/session-runner.d.ts +3 -12
  79. package/dist/src/agent/embedded/session-runner.js +12 -26
  80. package/dist/src/agent/embedded/session-runner.js.map +1 -1
  81. package/dist/src/agent/embedded/session-tool-result-guard.js +2 -4
  82. package/dist/src/agent/embedded/session-tool-result-guard.js.map +1 -1
  83. package/dist/src/agent/embedded/sqlite-hydrating-session-manager.d.ts +10 -0
  84. package/dist/src/agent/embedded/sqlite-hydrating-session-manager.js +34 -0
  85. package/dist/src/agent/embedded/sqlite-hydrating-session-manager.js.map +1 -0
  86. package/dist/src/agent/goals/goal-run-store.js +4 -4
  87. package/dist/src/agent/goals/persistent-goal-service.js +8 -15
  88. package/dist/src/agent/goals/persistent-goal-service.js.map +1 -1
  89. package/dist/src/agent/goals/post-turn.js +2 -2
  90. package/dist/src/agent/image/load-image-media.js +2 -2
  91. package/dist/src/agent/ipc/bus.js +1 -1
  92. package/dist/src/agent/ipc/inbox.js +2 -2
  93. package/dist/src/agent/ipc/socket.js +1 -1
  94. package/dist/src/agent/mcp/bundle-mcp-materialize.js +1 -1
  95. package/dist/src/agent/mcp/bundle-mcp-runtime.js +2 -2
  96. package/dist/src/agent/mcp/mcp-transport-config.js +1 -1
  97. package/dist/src/agent/mcp/mcp-transport.js +1 -1
  98. package/dist/src/agent/memory/builtin-memory-store.js +1 -1
  99. package/dist/src/agent/memory/dreaming/deep-promotion.js +1 -1
  100. package/dist/src/agent/memory/dreaming/events.js +1 -1
  101. package/dist/src/agent/memory/dreaming/last-run.js +1 -1
  102. package/dist/src/agent/memory/dreaming/light-sweep.js +1 -1
  103. package/dist/src/agent/memory/dreaming/preview.js +1 -1
  104. package/dist/src/agent/memory/dreaming/rem-patterns.js +1 -1
  105. package/dist/src/agent/memory/dreaming/short-term-store.js +1 -1
  106. package/dist/src/agent/memory/dreaming/utils.js +1 -1
  107. package/dist/src/agent/memory/plugin-discovery.js +1 -1
  108. package/dist/src/agent/models/manager.js +1 -1
  109. package/dist/src/agent/prompt/memory/index.d.ts +1 -0
  110. package/dist/src/agent/prompt/memory/index.js +34 -80
  111. package/dist/src/agent/prompt/memory/index.js.map +1 -1
  112. package/dist/src/agent/prompt/service-prompt-builder.js +2 -2
  113. package/dist/src/agent/reply/post-compaction-context.js +1 -1
  114. package/dist/src/agent/reply/workspace-boundary-read.js +1 -1
  115. package/dist/src/agent/sandbox/path-policy.js +2 -2
  116. package/dist/src/agent/service/build-direct-message-content.js +1 -1
  117. package/dist/src/agent/service/process-direct-one-shot.js +8 -17
  118. package/dist/src/agent/service/process-direct-one-shot.js.map +1 -1
  119. package/dist/src/agent/service/process-direct-streaming.js +14 -23
  120. package/dist/src/agent/service/process-direct-streaming.js.map +1 -1
  121. package/dist/src/agent/service.js +7 -11
  122. package/dist/src/agent/service.js.map +1 -1
  123. package/dist/src/agent/session/session-inspector.js +1 -1
  124. package/dist/src/agent/skills/config.js +1 -1
  125. package/dist/src/agent/skills/hub-hash.js +2 -2
  126. package/dist/src/agent/skills/hub-lock.js +1 -1
  127. package/dist/src/agent/skills/hub-pull.js +3 -3
  128. package/dist/src/agent/skills/index.js +1 -1
  129. package/dist/src/agent/skills/managed-store.js +1 -1
  130. package/dist/src/agent/skills/scanner.js +1 -1
  131. package/dist/src/agent/skills/skill-manage-ops.js +1 -1
  132. package/dist/src/agent/skills/skill-manager.js +1 -1
  133. package/dist/src/agent/tools/dreaming-tool.js +1 -1
  134. package/dist/src/agent/tools/factory.js +1 -1
  135. package/dist/src/agent/tools/image-generate-tool.js +1 -1
  136. package/dist/src/agent/tools/index.d.ts +0 -1
  137. package/dist/src/agent/tools/index.js +1 -2
  138. package/dist/src/agent/tools/send-media.js +1 -1
  139. package/dist/src/agent/tools/session-search-tool.d.ts +0 -1
  140. package/dist/src/agent/tools/session-search-tool.js +11 -6
  141. package/dist/src/agent/tools/session-search-tool.js.map +1 -1
  142. package/dist/src/agent/tools/skill-manage-tool.js +1 -1
  143. package/dist/src/agent/tools/workflow-tool.js +1 -1
  144. package/dist/src/agent/tools/write.js +1 -1
  145. package/dist/src/agent/workflow/catalog.js +1 -1
  146. package/dist/src/auth/credentials.js +3 -3
  147. package/dist/src/auth/profiles/store.js +1 -1
  148. package/dist/src/auth/sync-provider-auth.js +1 -1
  149. package/dist/src/browser/cache-dir-policy.js +1 -1
  150. package/dist/src/browser/cdp-local-launcher.js +2 -2
  151. package/dist/src/browser/providers/browser-ext-install.js +4 -4
  152. package/dist/src/browser/providers/cloakbrowser.js +4 -4
  153. package/dist/src/browser/providers/playwright-doctor.js +1 -1
  154. package/dist/src/browser/stealth.js +1 -1
  155. package/dist/src/channels/attachments/inbound-persist.js +1 -1
  156. package/dist/src/channels/attachments/outbound-tts-persist.js +1 -1
  157. package/dist/src/channels/outbound/persist-store.js +1 -1
  158. package/dist/src/channels/pairing/allow-from-file.js +1 -1
  159. package/dist/src/channels/pairing/pairing-store.js +2 -2
  160. package/dist/src/chat-commands/agent-edit.js +2 -2
  161. package/dist/src/chat-commands/builtins/config.js +2 -2
  162. package/dist/src/chat-commands/context.js +1 -1
  163. package/dist/src/cli/commands/config.js +1 -1
  164. package/dist/src/cli/commands/doctor/checks/config-health.js +1 -1
  165. package/dist/src/cli/commands/doctor/checks/provider-auth.js +1 -1
  166. package/dist/src/cli/commands/doctor/checks/session-integrity.js +32 -95
  167. package/dist/src/cli/commands/doctor/checks/session-integrity.js.map +1 -1
  168. package/dist/src/cli/commands/doctor/checks/state-integrity.js +1 -1
  169. package/dist/src/cli/commands/doctor/checks/workspace-status.js +1 -1
  170. package/dist/src/cli/commands/extension-dev.js +1 -1
  171. package/dist/src/cli/commands/extension-marketplace.js +1 -1
  172. package/dist/src/cli/commands/extension-pack.js +1 -1
  173. package/dist/src/cli/commands/gateway/logs.js +1 -1
  174. package/dist/src/cli/commands/image.js +1 -1
  175. package/dist/src/cli/commands/init.js +5 -7
  176. package/dist/src/cli/commands/init.js.map +1 -1
  177. package/dist/src/cli/commands/onboard.js +1 -1
  178. package/dist/src/cli/utils/init-workspace-core.js +2 -2
  179. package/dist/src/commands/agents.config.js +1 -1
  180. package/dist/src/config/agent-profile.js +1 -1
  181. package/dist/src/config/gateway-bind.js +1 -1
  182. package/dist/src/config/index.js +7 -8
  183. package/dist/src/config/index.js.map +1 -1
  184. package/dist/src/config/loader.js +2 -2
  185. package/dist/src/config/models-json.js +2 -2
  186. package/dist/src/config/paths-state.d.ts +3 -0
  187. package/dist/src/config/paths-state.js +7 -3
  188. package/dist/src/config/paths-state.js.map +1 -1
  189. package/dist/src/config/paths.d.ts +5 -35
  190. package/dist/src/config/paths.js +6 -50
  191. package/dist/src/config/paths.js.map +1 -1
  192. package/dist/src/config/profile.js +2 -2
  193. package/dist/src/config/schema.d.ts +15 -0
  194. package/dist/src/config/schema.js +11 -0
  195. package/dist/src/config/schema.js.map +1 -1
  196. package/dist/src/config/workspace-path.js +1 -1
  197. package/dist/src/cron/execution-types.d.ts +42 -0
  198. package/dist/src/cron/executor.js +2 -2
  199. package/dist/src/cron/persistence.js +1 -1
  200. package/dist/src/cron/run-log-store.d.ts +4 -8
  201. package/dist/src/cron/run-log-store.js +26 -78
  202. package/dist/src/cron/run-log-store.js.map +1 -1
  203. package/dist/src/cron/service.d.ts +3 -3
  204. package/dist/src/cron/service.js +2 -2
  205. package/dist/src/cron/service.js.map +1 -1
  206. package/dist/src/cron/types.d.ts +1 -42
  207. package/dist/src/daemon/constants.js +1 -1
  208. package/dist/src/daemon/install-plan.js +2 -2
  209. package/dist/src/daemon/launchd.js +2 -2
  210. package/dist/src/daemon/schtasks.js +2 -2
  211. package/dist/src/daemon/systemd.js +2 -2
  212. package/dist/src/extensions/bundle-mcp.js +1 -1
  213. package/dist/src/extensions/discover-extensions.js +1 -1
  214. package/dist/src/extensions/health.js +1 -1
  215. package/dist/src/extensions/loader.js +1 -1
  216. package/dist/src/extensions/lockfile.js +2 -2
  217. package/dist/src/extensions/update.js +1 -1
  218. package/dist/src/gateway/agents-admin.js +8 -3
  219. package/dist/src/gateway/agents-admin.js.map +1 -1
  220. package/dist/src/gateway/file-path-classifier.d.ts +0 -1
  221. package/dist/src/gateway/file-path-classifier.js +2 -8
  222. package/dist/src/gateway/file-path-classifier.js.map +1 -1
  223. package/dist/src/gateway/hono/lib/config-payload.js +1 -1
  224. package/dist/src/gateway/hono/lib/extension-store.js +2 -2
  225. package/dist/src/gateway/hono/lib/static-ui.js +2 -2
  226. package/dist/src/gateway/hono/oauth.js +1 -1
  227. package/dist/src/gateway/hono/routes/agents.js +1 -1
  228. package/dist/src/gateway/hono/routes/auth-registry-extensions.js +1 -1
  229. package/dist/src/gateway/hono/routes/config-patch/misc.js +1 -1
  230. package/dist/src/gateway/hono/routes/dreaming.js +1 -1
  231. package/dist/src/gateway/hono/routes/host-fs.js +2 -2
  232. package/dist/src/gateway/hono/routes/models.js +1 -1
  233. package/dist/src/gateway/hono/routes/shares.js +1 -1
  234. package/dist/src/gateway/hono/routes/workspace.js +2 -2
  235. package/dist/src/gateway/lock.js +3 -3
  236. package/dist/src/gateway/ports.js +1 -1
  237. package/dist/src/gateway/service/agent-runner.js +2 -2
  238. package/dist/src/gateway/service/marketplace-service.js +2 -2
  239. package/dist/src/gateway/service.js +5 -1
  240. package/dist/src/gateway/service.js.map +1 -1
  241. package/dist/src/gateway/session-reset-service.d.ts +1 -1
  242. package/dist/src/gateway/session-reset-service.js +1 -1
  243. package/dist/src/gateway/session-reset-service.js.map +1 -1
  244. package/dist/src/gateway/workspace-fs-file-list.js +1 -1
  245. package/dist/src/infra/brew.js +1 -1
  246. package/dist/src/infra/node-sqlite.d.ts +1 -0
  247. package/dist/src/infra/node-sqlite.js +17 -0
  248. package/dist/src/infra/node-sqlite.js.map +1 -0
  249. package/dist/src/infra/package-json.js +1 -1
  250. package/dist/src/infra/package-update-steps.js +1 -1
  251. package/dist/src/infra/path-env.js +2 -2
  252. package/dist/src/infra/restart.js +2 -2
  253. package/dist/src/infra/sqlite-errors.d.ts +1 -0
  254. package/dist/src/infra/sqlite-errors.js +77 -0
  255. package/dist/src/infra/sqlite-errors.js.map +1 -0
  256. package/dist/src/infra/stable-node-path.js +1 -1
  257. package/dist/src/infra/unhandled-rejections.d.ts +1 -0
  258. package/dist/src/infra/unhandled-rejections.js +25 -0
  259. package/dist/src/infra/unhandled-rejections.js.map +1 -0
  260. package/dist/src/infra/update-check.js +1 -1
  261. package/dist/src/infra/update-global.js +1 -1
  262. package/dist/src/infra/update-lock.js +3 -3
  263. package/dist/src/infra/update-runner.js +1 -1
  264. package/dist/src/infra/update-startup.js +2 -2
  265. package/dist/src/infra/warning-filter.d.ts +7 -0
  266. package/dist/src/infra/warning-filter.js +59 -0
  267. package/dist/src/infra/warning-filter.js.map +1 -0
  268. package/dist/src/infra/write-file-atomic.js +2 -2
  269. package/dist/src/notes/store.d.ts +3 -9
  270. package/dist/src/notes/store.js +22 -196
  271. package/dist/src/notes/store.js.map +1 -1
  272. package/dist/src/providers/auth-runtime/auth-profile-store.js +1 -1
  273. package/dist/src/providers/index.js +2 -2
  274. package/dist/src/providers/model-registry.js +1 -1
  275. package/dist/src/session/config-store.d.ts +6 -75
  276. package/dist/src/session/config-store.js +38 -144
  277. package/dist/src/session/config-store.js.map +1 -1
  278. package/dist/src/session/config-types.d.ts +15 -0
  279. package/dist/src/session/config-types.js +1 -0
  280. package/dist/src/session/index.d.ts +1 -3
  281. package/dist/src/session/index.js +3 -5
  282. package/dist/src/session/init-session-turn.d.ts +0 -6
  283. package/dist/src/session/init-session-turn.js +18 -18
  284. package/dist/src/session/init-session-turn.js.map +1 -1
  285. package/dist/src/session/lifecycle-timestamps.d.ts +5 -2
  286. package/dist/src/session/lifecycle-timestamps.js.map +1 -1
  287. package/dist/src/session/{parity/load-jsonl-entries.js → load-jsonl-entries.js} +1 -1
  288. package/dist/src/session/load-jsonl-entries.js.map +1 -0
  289. package/dist/src/session/manager.d.ts +5 -3
  290. package/dist/src/session/manager.js +1 -5
  291. package/dist/src/session/manager.js.map +1 -1
  292. package/dist/src/session/resolve-session.d.ts +3 -6
  293. package/dist/src/session/resolve-session.js +26 -31
  294. package/dist/src/session/resolve-session.js.map +1 -1
  295. package/dist/src/session/session-context-for-llm.js +5 -1
  296. package/dist/src/session/session-context-for-llm.js.map +1 -1
  297. package/dist/src/session/session-id.js +12 -0
  298. package/dist/src/session/session-id.js.map +1 -0
  299. package/dist/src/session/session-title.js +2 -2
  300. package/dist/src/session/session-workspace.d.ts +1 -1
  301. package/dist/src/session/session-workspace.js.map +1 -1
  302. package/dist/src/session/store.d.ts +14 -63
  303. package/dist/src/session/store.js +172 -847
  304. package/dist/src/session/store.js.map +1 -1
  305. package/dist/src/session/stored-rows-to-file-entries.d.ts +11 -0
  306. package/dist/src/session/stored-rows-to-file-entries.js +95 -0
  307. package/dist/src/session/stored-rows-to-file-entries.js.map +1 -0
  308. package/dist/src/session/transcript-events.d.ts +1 -2
  309. package/dist/src/session/transcript-events.js +5 -12
  310. package/dist/src/session/transcript-events.js.map +1 -1
  311. package/dist/src/session/transcript-format.d.ts +1 -1
  312. package/dist/src/session/transcript-format.js.map +1 -1
  313. package/dist/src/session/transcript-stats.d.ts +1 -0
  314. package/dist/src/session/transcript-stats.js +10 -0
  315. package/dist/src/session/transcript-stats.js.map +1 -0
  316. package/dist/src/share/share-auto.js +2 -2
  317. package/dist/src/share/share-store.js +3 -3
  318. package/dist/src/share/share-thumbnail.js +2 -2
  319. package/dist/src/share/share-zip.js +1 -1
  320. package/dist/src/share/site-share-store.js +3 -3
  321. package/dist/src/share/site-static-serve.js +1 -1
  322. package/dist/src/storage/sqlite/config-repository.d.ts +6 -0
  323. package/dist/src/storage/sqlite/config-repository.js +56 -0
  324. package/dist/src/storage/sqlite/config-repository.js.map +1 -0
  325. package/dist/src/storage/sqlite/connection.d.ts +38 -0
  326. package/dist/src/storage/sqlite/connection.js +258 -0
  327. package/dist/src/storage/sqlite/connection.js.map +1 -0
  328. package/dist/src/storage/sqlite/cron-run-repository.d.ts +5 -0
  329. package/dist/src/storage/sqlite/cron-run-repository.js +97 -0
  330. package/dist/src/storage/sqlite/cron-run-repository.js.map +1 -0
  331. package/dist/src/storage/sqlite/fts.d.ts +2 -0
  332. package/dist/src/storage/sqlite/fts.js +11 -0
  333. package/dist/src/storage/sqlite/fts.js.map +1 -0
  334. package/dist/src/storage/sqlite/index.d.ts +12 -0
  335. package/dist/src/storage/sqlite/index.js +13 -0
  336. package/dist/src/storage/sqlite/memory-index-repository.d.ts +18 -0
  337. package/dist/src/storage/sqlite/memory-index-repository.js +132 -0
  338. package/dist/src/storage/sqlite/memory-index-repository.js.map +1 -0
  339. package/dist/src/storage/sqlite/notes-repository.d.ts +11 -0
  340. package/dist/src/storage/sqlite/notes-repository.js +191 -0
  341. package/dist/src/storage/sqlite/notes-repository.js.map +1 -0
  342. package/dist/src/storage/sqlite/paths.d.ts +1 -0
  343. package/dist/src/storage/sqlite/paths.js +7 -0
  344. package/dist/src/storage/sqlite/paths.js.map +1 -0
  345. package/dist/src/storage/sqlite/row-mappers.d.ts +82 -0
  346. package/dist/src/storage/sqlite/row-mappers.js +164 -0
  347. package/dist/src/storage/sqlite/row-mappers.js.map +1 -0
  348. package/dist/src/storage/sqlite/schema.d.ts +5 -0
  349. package/dist/src/storage/sqlite/schema.js +43 -0
  350. package/dist/src/storage/sqlite/schema.js.map +1 -0
  351. package/dist/src/storage/sqlite/schema.sql +195 -0
  352. package/dist/src/storage/sqlite/session-metadata.d.ts +8 -0
  353. package/dist/src/storage/sqlite/session-metadata.js +83 -0
  354. package/dist/src/storage/sqlite/session-metadata.js.map +1 -0
  355. package/dist/src/storage/sqlite/session-repository.d.ts +29 -0
  356. package/dist/src/storage/sqlite/session-repository.js +268 -0
  357. package/dist/src/storage/sqlite/session-repository.js.map +1 -0
  358. package/dist/src/storage/sqlite/transaction.d.ts +11 -0
  359. package/dist/src/storage/sqlite/transaction.js +115 -0
  360. package/dist/src/storage/sqlite/transaction.js.map +1 -0
  361. package/dist/src/storage/sqlite/transcript-repository.d.ts +34 -0
  362. package/dist/src/storage/sqlite/transcript-repository.js +241 -0
  363. package/dist/src/storage/sqlite/transcript-repository.js.map +1 -0
  364. package/dist/src/tui/clipboard-image.js +3 -3
  365. package/dist/src/tui/theme-manager.js +1 -1
  366. package/dist/src/tui/tui-keybindings-file.js +1 -1
  367. package/dist/src/tui/tui-scoped-models.js +2 -2
  368. package/dist/src/tui/tui-settings.js +1 -1
  369. package/dist/src/tui/tui.js +3 -3
  370. package/dist/src/tunnel/frpc-binary.js +3 -3
  371. package/dist/src/tunnel/frpc-config.js +1 -1
  372. package/dist/src/tunnel/frpc-extract.js +1 -1
  373. package/dist/src/tunnel/tunnel-state.js +1 -1
  374. package/dist/src/utils/logger/audit.js +1 -1
  375. package/dist/src/utils/logger/log-store.js +1 -1
  376. package/dist/src/utils/logger/rotation.js +1 -1
  377. package/dist/src/voice/tts/audio.js +1 -1
  378. package/dist/src/voice/tts/providers/edge-speech.js +2 -2
  379. package/dist/src/workflows/service/workflow-session-bridge.js +41 -64
  380. package/dist/src/workflows/service/workflow-session-bridge.js.map +1 -1
  381. package/dist/src/workflows/store/event-store.js +1 -1
  382. package/dist/src/workflows/store/run-store.js +1 -1
  383. package/package.json +2 -2
  384. package/dist/gateway/static/root/assets/index-Bj_l8QDp.css +0 -1
  385. package/dist/gateway/static/root/assets/url-BHHmdJYc.js +0 -3
  386. package/dist/src/agent/embedded/session-manager-cache.d.ts +0 -19
  387. package/dist/src/agent/embedded/session-manager-cache.js +0 -48
  388. package/dist/src/agent/embedded/session-manager-cache.js.map +0 -1
  389. package/dist/src/session/parity/artifacts.d.ts +0 -16
  390. package/dist/src/session/parity/artifacts.js +0 -80
  391. package/dist/src/session/parity/artifacts.js.map +0 -1
  392. package/dist/src/session/parity/jsonl-transcript-io.d.ts +0 -54
  393. package/dist/src/session/parity/jsonl-transcript-io.js +0 -236
  394. package/dist/src/session/parity/jsonl-transcript-io.js.map +0 -1
  395. package/dist/src/session/parity/load-jsonl-entries.js.map +0 -1
  396. package/dist/src/session/parity/session-id.js +0 -18
  397. package/dist/src/session/parity/session-id.js.map +0 -1
  398. package/dist/src/session/parity/sessions-json-cache.d.ts +0 -14
  399. package/dist/src/session/parity/sessions-json-cache.js +0 -98
  400. package/dist/src/session/parity/sessions-json-cache.js.map +0 -1
  401. package/dist/src/session/parity/sessions-json-file-read.d.ts +0 -6
  402. package/dist/src/session/parity/sessions-json-file-read.js +0 -19
  403. package/dist/src/session/parity/sessions-json-file-read.js.map +0 -1
  404. package/dist/src/session/parity/sessions-json-file.d.ts +0 -11
  405. package/dist/src/session/parity/sessions-json-file.js +0 -52
  406. package/dist/src/session/parity/sessions-json-file.js.map +0 -1
  407. package/dist/src/session/parity/sessions-json-patch.d.ts +0 -14
  408. package/dist/src/session/parity/sessions-json-patch.js +0 -40
  409. package/dist/src/session/parity/sessions-json-patch.js.map +0 -1
  410. package/dist/src/session/parity/transcript-file-lock.d.ts +0 -22
  411. package/dist/src/session/parity/transcript-file-lock.js +0 -142
  412. package/dist/src/session/parity/transcript-file-lock.js.map +0 -1
  413. package/dist/src/session/parity/transcript-pagination.d.ts +0 -29
  414. package/dist/src/session/parity/transcript-pagination.js +0 -132
  415. package/dist/src/session/parity/transcript-pagination.js.map +0 -1
  416. package/dist/src/session/parity/transcript-paths.d.ts +0 -13
  417. package/dist/src/session/parity/transcript-paths.js +0 -64
  418. package/dist/src/session/parity/transcript-paths.js.map +0 -1
  419. package/dist/src/session/parity/xopc-session-disk-entry.d.ts +0 -22
  420. package/dist/src/session/search-index-cache.d.ts +0 -6
  421. package/dist/src/session/search-index-cache.js +0 -44
  422. package/dist/src/session/search-index-cache.js.map +0 -1
  423. package/dist/src/session/search-index.d.ts +0 -20
  424. package/dist/src/session/search-index.js +0 -124
  425. package/dist/src/session/search-index.js.map +0 -1
  426. /package/dist/src/{session/parity/xopc-session-disk-entry.js → cron/execution-types.js} +0 -0
  427. /package/dist/src/session/{parity/load-jsonl-entries.d.ts → load-jsonl-entries.d.ts} +0 -0
  428. /package/dist/src/session/{parity/session-id.d.ts → session-id.d.ts} +0 -0
@@ -1,180 +1,74 @@
1
1
  import { createLogger } from "../utils/logger/index.js";
2
2
  import { init_logger } from "../utils/logger.js";
3
- import { init_write_file_atomic, writeTextAtomic } from "../infra/write-file-atomic.js";
4
- import { join } from "path";
5
- import { existsSync } from "fs";
6
- import { mkdir, readFile } from "fs/promises";
3
+ import { requireXopcDatabase } from "../storage/sqlite/connection.js";
4
+ import { deleteSessionConfig, getSessionConfig, hasSessionConfig, setSessionConfig, updateSessionConfig } from "../storage/sqlite/config-repository.js";
5
+ import "../storage/sqlite/index.js";
7
6
  //#region src/session/config-store.ts
8
- /**
9
- * Session Config Store
10
- *
11
- * Manages session-level configuration persistence.
12
- * Stores thinking level, reasoning visibility, verbose mode, and other
13
- * session-specific settings that can be overridden via commands.
14
- */
15
- init_write_file_atomic();
16
7
  init_logger();
17
8
  const log = createLogger("SessionConfigStore");
18
- /**
19
- * Session config store manager.
20
- * Each session can have its own configuration that overrides agent defaults.
21
- */
22
9
  var SessionConfigStore = class {
23
- configDir;
24
- /** @param agentHomeDir — `resolveAgentHomeDir()` (parent of `sessions/` transcript store) */
25
- constructor(agentHomeDir) {
26
- this.configDir = join(agentHomeDir, "sessions", "config");
10
+ cwd;
11
+ constructor(_agentHomeDir, cwd = process.cwd()) {
12
+ this.cwd = cwd;
27
13
  }
28
- /**
29
- * Initialize the config store
30
- */
31
- async initialize() {
32
- await mkdir(this.configDir, { recursive: true });
33
- log.debug("Session config store initialized");
14
+ requireDatabase() {
15
+ requireXopcDatabase();
34
16
  }
35
- /**
36
- * Get the config file path for a session
37
- */
38
- getConfigPath(sessionKey) {
39
- const safeKey = sessionKey.replace(/[^a-zA-Z0-9_-]/g, "_");
40
- return join(this.configDir, `${safeKey}.json`);
17
+ async initialize() {
18
+ this.requireDatabase();
19
+ log.debug("Session config store initialized (SQLite)");
41
20
  }
42
- /**
43
- * Get config for a session
44
- */
45
21
  async get(sessionKey) {
46
- const configPath = this.getConfigPath(sessionKey);
47
- if (!existsSync(configPath)) return null;
48
- try {
49
- const content = await readFile(configPath, "utf-8");
50
- return JSON.parse(content);
51
- } catch (error) {
52
- const em = error instanceof Error ? error.message : String(error);
53
- log.error({
54
- err: error,
55
- errorMessage: em,
56
- sessionKey,
57
- phase: "session.config"
58
- }, `Failed to read session config: ${em}`);
59
- return null;
60
- }
22
+ this.requireDatabase();
23
+ return getSessionConfig(sessionKey);
61
24
  }
62
- /**
63
- * Set config for a session (full replacement)
64
- */
65
25
  async set(sessionKey, config) {
66
- const configPath = this.getConfigPath(sessionKey);
67
- const configWithTimestamp = {
68
- ...config,
69
- updatedAt: Date.now()
70
- };
71
- try {
72
- await writeTextAtomic(configPath, JSON.stringify(configWithTimestamp, null, 2));
73
- log.debug({ sessionKey }, "Session config saved");
74
- } catch (error) {
75
- const em = error instanceof Error ? error.message : String(error);
76
- log.error({
77
- err: error,
78
- errorMessage: em,
79
- sessionKey,
80
- phase: "session.config"
81
- }, `Failed to save session config: ${em}`);
82
- throw error;
83
- }
26
+ this.requireDatabase();
27
+ setSessionConfig(sessionKey, config, this.cwd);
28
+ log.debug({ sessionKey }, "Session config saved");
84
29
  }
85
- /**
86
- * Update config for a session (partial update)
87
- */
88
30
  async update(sessionKey, partial) {
89
- const updated = {
90
- ...await this.get(sessionKey),
91
- ...partial,
92
- updatedAt: Date.now()
93
- };
94
- await this.set(sessionKey, updated);
31
+ this.requireDatabase();
32
+ const updated = updateSessionConfig(sessionKey, partial, this.cwd);
33
+ log.debug({ sessionKey }, "Session config updated");
95
34
  return updated;
96
35
  }
97
- /**
98
- * Delete config for a session
99
- */
100
36
  async delete(sessionKey) {
101
- const configPath = this.getConfigPath(sessionKey);
102
- if (existsSync(configPath)) try {
103
- const { unlink } = await import("fs/promises");
104
- await unlink(configPath);
105
- log.debug({ sessionKey }, "Session config deleted");
106
- } catch (error) {
107
- log.error({
108
- sessionKey,
109
- error
110
- }, "Failed to delete session config");
111
- throw error;
112
- }
37
+ this.requireDatabase();
38
+ deleteSessionConfig(sessionKey);
39
+ log.debug({ sessionKey }, "Session config deleted");
113
40
  }
114
- /**
115
- * Check if config exists for a session
116
- */
117
41
  async has(sessionKey) {
118
- return existsSync(this.getConfigPath(sessionKey));
42
+ this.requireDatabase();
43
+ return hasSessionConfig(sessionKey);
119
44
  }
120
- /**
121
- * Get all session configs
122
- */
123
45
  async getAll() {
124
- const { readdir } = await import("fs/promises");
46
+ this.requireDatabase();
125
47
  const configs = /* @__PURE__ */ new Map();
126
- try {
127
- const files = await readdir(this.configDir);
128
- for (const file of files) {
129
- if (!file.endsWith(".json")) continue;
130
- const sessionKey = file.replace(".json", "").replace(/_/g, "-");
131
- const config = await this.get(sessionKey);
132
- if (config) configs.set(sessionKey, config);
133
- }
134
- } catch (error) {
135
- log.error({ error }, "Failed to list session configs");
48
+ const { listSessionMetadata } = await import("../storage/sqlite/index.js");
49
+ const { items } = listSessionMetadata({ limit: 1e5 });
50
+ for (const item of items) {
51
+ const config = getSessionConfig(item.key);
52
+ if (config) configs.set(item.key, config);
136
53
  }
137
54
  return configs;
138
55
  }
139
- /**
140
- * Clear all session configs
141
- */
142
56
  async clear() {
143
- const { readdir, rm } = await import("fs/promises");
144
- try {
145
- const files = await readdir(this.configDir);
146
- for (const file of files) if (file.endsWith(".json")) await rm(join(this.configDir, file), { force: true });
147
- log.debug("All session configs cleared");
148
- } catch (error) {
149
- log.error({ error }, "Failed to clear session configs");
150
- throw error;
151
- }
57
+ this.requireDatabase();
58
+ const { listSessionMetadata } = await import("../storage/sqlite/index.js");
59
+ const { items } = listSessionMetadata({ limit: 1e5 });
60
+ for (const item of items) deleteSessionConfig(item.key);
61
+ log.debug("All session configs cleared");
152
62
  }
153
63
  };
154
- /**
155
- * Resolve thinking level for a session.
156
- * Returns session config if set, otherwise falls back to agent defaults.
157
- */
158
64
  async function resolveThinkingLevel(sessionConfigStore, sessionKey, agentDefault) {
159
- const config = await sessionConfigStore.get(sessionKey);
160
- if (config?.thinkingLevel) return config.thinkingLevel;
161
- return agentDefault;
65
+ return (await sessionConfigStore.get(sessionKey))?.thinkingLevel ?? agentDefault;
162
66
  }
163
- /**
164
- * Resolve reasoning level for a session.
165
- */
166
67
  async function resolveReasoningLevel(sessionConfigStore, sessionKey, agentDefault) {
167
- const config = await sessionConfigStore.get(sessionKey);
168
- if (config?.reasoningLevel) return config.reasoningLevel;
169
- return agentDefault;
68
+ return (await sessionConfigStore.get(sessionKey))?.reasoningLevel ?? agentDefault;
170
69
  }
171
- /**
172
- * Resolve verbose level for a session.
173
- */
174
70
  async function resolveVerboseLevel(sessionConfigStore, sessionKey, agentDefault) {
175
- const config = await sessionConfigStore.get(sessionKey);
176
- if (config?.verboseLevel) return config.verboseLevel;
177
- return agentDefault;
71
+ return (await sessionConfigStore.get(sessionKey))?.verboseLevel ?? agentDefault;
178
72
  }
179
73
  //#endregion
180
74
  export { SessionConfigStore, resolveReasoningLevel, resolveThinkingLevel, resolveVerboseLevel };
@@ -1 +1 @@
1
- {"version":3,"file":"config-store.js","names":[],"sources":["../../../src/session/config-store.ts"],"sourcesContent":["/**\n * Session Config Store\n * \n * Manages session-level configuration persistence.\n * Stores thinking level, reasoning visibility, verbose mode, and other\n * session-specific settings that can be overridden via commands.\n */\n\nimport { readFile, mkdir } from 'fs/promises';\nimport { writeTextAtomic } from '../infra/write-file-atomic.js';\nimport { join } from 'path';\nimport { existsSync } from 'fs';\nimport { createLogger } from '../utils/logger.js';\nimport type { ThinkLevel, ReasoningLevel, VerboseLevel, ElevatedMode } from '../agent/transcript/thinking-types.js';\n\nconst log = createLogger('SessionConfigStore');\n\n/**\n * Session-level agent configuration.\n * These settings override agent defaults for a specific session.\n */\nexport interface SessionAgentConfig {\n /** Thinking level for this session */\n thinkingLevel?: ThinkLevel;\n /** Reasoning visibility for this session */\n reasoningLevel?: ReasoningLevel;\n /** Verbose level for this session */\n verboseLevel?: VerboseLevel;\n /** Elevated mode for this session */\n elevatedMode?: ElevatedMode;\n /** Model override for this session */\n modelOverride?: string;\n /** Provider override for this session */\n providerOverride?: string;\n /** Absolute markdown workspace root for this session (set once; immutable after save). */\n workingDirectoryOverride?: string;\n /** Last updated timestamp */\n updatedAt?: number;\n}\n\n/**\n * Session config store manager.\n * Each session can have its own configuration that overrides agent defaults.\n */\nexport class SessionConfigStore {\n private configDir: string;\n\n /** @param agentHomeDir — `resolveAgentHomeDir(…)` (parent of `sessions/` transcript store) */\n constructor(agentHomeDir: string) {\n this.configDir = join(agentHomeDir, 'sessions', 'config');\n }\n\n /**\n * Initialize the config store\n */\n async initialize(): Promise<void> {\n await mkdir(this.configDir, { recursive: true });\n log.debug('Session config store initialized');\n }\n\n /**\n * Get the config file path for a session\n */\n private getConfigPath(sessionKey: string): string {\n // Sanitize session key to be a valid filename\n const safeKey = sessionKey.replace(/[^a-zA-Z0-9_-]/g, '_');\n return join(this.configDir, `${safeKey}.json`);\n }\n\n /**\n * Get config for a session\n */\n async get(sessionKey: string): Promise<SessionAgentConfig | null> {\n const configPath = this.getConfigPath(sessionKey);\n \n if (!existsSync(configPath)) {\n return null;\n }\n\n try {\n const content = await readFile(configPath, 'utf-8');\n const config = JSON.parse(content) as SessionAgentConfig;\n return config;\n } catch (error) {\n const em = error instanceof Error ? error.message : String(error);\n log.error({ err: error, errorMessage: em, sessionKey, phase: 'session.config' }, `Failed to read session config: ${em}`);\n return null;\n }\n }\n\n /**\n * Set config for a session (full replacement)\n */\n async set(sessionKey: string, config: SessionAgentConfig): Promise<void> {\n const configPath = this.getConfigPath(sessionKey);\n const configWithTimestamp = {\n ...config,\n updatedAt: Date.now(),\n };\n\n try {\n await writeTextAtomic(configPath, JSON.stringify(configWithTimestamp, null, 2));\n log.debug({ sessionKey }, 'Session config saved');\n } catch (error) {\n const em = error instanceof Error ? error.message : String(error);\n log.error({ err: error, errorMessage: em, sessionKey, phase: 'session.config' }, `Failed to save session config: ${em}`);\n throw error;\n }\n }\n\n /**\n * Update config for a session (partial update)\n */\n async update(sessionKey: string, partial: Partial<SessionAgentConfig>): Promise<SessionAgentConfig> {\n const existing = await this.get(sessionKey);\n const updated = {\n ...existing,\n ...partial,\n updatedAt: Date.now(),\n };\n \n await this.set(sessionKey, updated);\n return updated;\n }\n\n /**\n * Delete config for a session\n */\n async delete(sessionKey: string): Promise<void> {\n const configPath = this.getConfigPath(sessionKey);\n \n if (existsSync(configPath)) {\n try {\n const { unlink } = await import('fs/promises');\n await unlink(configPath);\n log.debug({ sessionKey }, 'Session config deleted');\n } catch (error) {\n log.error({ sessionKey, error }, 'Failed to delete session config');\n throw error;\n }\n }\n }\n\n /**\n * Check if config exists for a session\n */\n async has(sessionKey: string): Promise<boolean> {\n const configPath = this.getConfigPath(sessionKey);\n return existsSync(configPath);\n }\n\n /**\n * Get all session configs\n */\n async getAll(): Promise<Map<string, SessionAgentConfig>> {\n const { readdir } = await import('fs/promises');\n const configs = new Map<string, SessionAgentConfig>();\n\n try {\n const files = await readdir(this.configDir);\n \n for (const file of files) {\n if (!file.endsWith('.json')) continue;\n \n const sessionKey = file.replace('.json', '').replace(/_/g, '-');\n const config = await this.get(sessionKey);\n \n if (config) {\n configs.set(sessionKey, config);\n }\n }\n } catch (error) {\n log.error({ error }, 'Failed to list session configs');\n }\n\n return configs;\n }\n\n /**\n * Clear all session configs\n */\n async clear(): Promise<void> {\n const { readdir, rm } = await import('fs/promises');\n \n try {\n const files = await readdir(this.configDir);\n \n for (const file of files) {\n if (file.endsWith('.json')) {\n await rm(join(this.configDir, file), { force: true });\n }\n }\n \n log.debug('All session configs cleared');\n } catch (error) {\n log.error({ error }, 'Failed to clear session configs');\n throw error;\n }\n }\n}\n\n// ========== Helper Functions ==========\n\n/**\n * Resolve thinking level for a session.\n * Returns session config if set, otherwise falls back to agent defaults.\n */\nexport async function resolveThinkingLevel(\n sessionConfigStore: SessionConfigStore,\n sessionKey: string,\n agentDefault?: ThinkLevel\n): Promise<ThinkLevel | undefined> {\n const config = await sessionConfigStore.get(sessionKey);\n \n if (config?.thinkingLevel) {\n return config.thinkingLevel;\n }\n \n return agentDefault;\n}\n\n/**\n * Resolve reasoning level for a session.\n */\nexport async function resolveReasoningLevel(\n sessionConfigStore: SessionConfigStore,\n sessionKey: string,\n agentDefault?: ReasoningLevel\n): Promise<ReasoningLevel | undefined> {\n const config = await sessionConfigStore.get(sessionKey);\n \n if (config?.reasoningLevel) {\n return config.reasoningLevel;\n }\n \n return agentDefault;\n}\n\n/**\n * Resolve verbose level for a session.\n */\nexport async function resolveVerboseLevel(\n sessionConfigStore: SessionConfigStore,\n sessionKey: string,\n agentDefault?: VerboseLevel\n): Promise<VerboseLevel | undefined> {\n const config = await sessionConfigStore.get(sessionKey);\n \n if (config?.verboseLevel) {\n return config.verboseLevel;\n }\n \n return agentDefault;\n}\n"],"mappings":";;;;;;;;;;;;;;wBASgE;aAGd;AAGlD,MAAM,MAAM,aAAa,qBAAqB;;;;;AA6B9C,IAAa,qBAAb,MAAgC;CAC9B;;CAGA,YAAY,cAAsB;AAChC,OAAK,YAAY,KAAK,cAAc,YAAY,SAAS;;;;;CAM3D,MAAM,aAA4B;AAChC,QAAM,MAAM,KAAK,WAAW,EAAE,WAAW,MAAM,CAAC;AAChD,MAAI,MAAM,mCAAmC;;;;;CAM/C,cAAsB,YAA4B;EAEhD,MAAM,UAAU,WAAW,QAAQ,mBAAmB,IAAI;AAC1D,SAAO,KAAK,KAAK,WAAW,GAAG,QAAQ,OAAO;;;;;CAMhD,MAAM,IAAI,YAAwD;EAChE,MAAM,aAAa,KAAK,cAAc,WAAW;AAEjD,MAAI,CAAC,WAAW,WAAW,CACzB,QAAO;AAGT,MAAI;GACF,MAAM,UAAU,MAAM,SAAS,YAAY,QAAQ;AAEnD,UADe,KAAK,MAAM,QACb;WACN,OAAO;GACd,MAAM,KAAK,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;AACjE,OAAI,MAAM;IAAE,KAAK;IAAO,cAAc;IAAI;IAAY,OAAO;IAAkB,EAAE,kCAAkC,KAAK;AACxH,UAAO;;;;;;CAOX,MAAM,IAAI,YAAoB,QAA2C;EACvE,MAAM,aAAa,KAAK,cAAc,WAAW;EACjD,MAAM,sBAAsB;GAC1B,GAAG;GACH,WAAW,KAAK,KAAK;GACtB;AAED,MAAI;AACF,SAAM,gBAAgB,YAAY,KAAK,UAAU,qBAAqB,MAAM,EAAE,CAAC;AAC/E,OAAI,MAAM,EAAE,YAAY,EAAE,uBAAuB;WAC1C,OAAO;GACd,MAAM,KAAK,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;AACjE,OAAI,MAAM;IAAE,KAAK;IAAO,cAAc;IAAI;IAAY,OAAO;IAAkB,EAAE,kCAAkC,KAAK;AACxH,SAAM;;;;;;CAOV,MAAM,OAAO,YAAoB,SAAmE;EAElG,MAAM,UAAU;GACd,GAAG,MAFkB,KAAK,IAAI,WAAW;GAGzC,GAAG;GACH,WAAW,KAAK,KAAK;GACtB;AAED,QAAM,KAAK,IAAI,YAAY,QAAQ;AACnC,SAAO;;;;;CAMT,MAAM,OAAO,YAAmC;EAC9C,MAAM,aAAa,KAAK,cAAc,WAAW;AAEjD,MAAI,WAAW,WAAW,CACxB,KAAI;GACF,MAAM,EAAE,WAAW,MAAM,OAAO;AAChC,SAAM,OAAO,WAAW;AACxB,OAAI,MAAM,EAAE,YAAY,EAAE,yBAAyB;WAC5C,OAAO;AACd,OAAI,MAAM;IAAE;IAAY;IAAO,EAAE,kCAAkC;AACnE,SAAM;;;;;;CAQZ,MAAM,IAAI,YAAsC;AAE9C,SAAO,WADY,KAAK,cAAc,WACV,CAAC;;;;;CAM/B,MAAM,SAAmD;EACvD,MAAM,EAAE,YAAY,MAAM,OAAO;EACjC,MAAM,0BAAU,IAAI,KAAiC;AAErD,MAAI;GACF,MAAM,QAAQ,MAAM,QAAQ,KAAK,UAAU;AAE3C,QAAK,MAAM,QAAQ,OAAO;AACxB,QAAI,CAAC,KAAK,SAAS,QAAQ,CAAE;IAE7B,MAAM,aAAa,KAAK,QAAQ,SAAS,GAAG,CAAC,QAAQ,MAAM,IAAI;IAC/D,MAAM,SAAS,MAAM,KAAK,IAAI,WAAW;AAEzC,QAAI,OACF,SAAQ,IAAI,YAAY,OAAO;;WAG5B,OAAO;AACd,OAAI,MAAM,EAAE,OAAO,EAAE,iCAAiC;;AAGxD,SAAO;;;;;CAMT,MAAM,QAAuB;EAC3B,MAAM,EAAE,SAAS,OAAO,MAAM,OAAO;AAErC,MAAI;GACF,MAAM,QAAQ,MAAM,QAAQ,KAAK,UAAU;AAE3C,QAAK,MAAM,QAAQ,MACjB,KAAI,KAAK,SAAS,QAAQ,CACxB,OAAM,GAAG,KAAK,KAAK,WAAW,KAAK,EAAE,EAAE,OAAO,MAAM,CAAC;AAIzD,OAAI,MAAM,8BAA8B;WACjC,OAAO;AACd,OAAI,MAAM,EAAE,OAAO,EAAE,kCAAkC;AACvD,SAAM;;;;;;;;AAWZ,eAAsB,qBACpB,oBACA,YACA,cACiC;CACjC,MAAM,SAAS,MAAM,mBAAmB,IAAI,WAAW;AAEvD,KAAI,QAAQ,cACV,QAAO,OAAO;AAGhB,QAAO;;;;;AAMT,eAAsB,sBACpB,oBACA,YACA,cACqC;CACrC,MAAM,SAAS,MAAM,mBAAmB,IAAI,WAAW;AAEvD,KAAI,QAAQ,eACV,QAAO,OAAO;AAGhB,QAAO;;;;;AAMT,eAAsB,oBACpB,oBACA,YACA,cACmC;CACnC,MAAM,SAAS,MAAM,mBAAmB,IAAI,WAAW;AAEvD,KAAI,QAAQ,aACV,QAAO,OAAO;AAGhB,QAAO"}
1
+ {"version":3,"file":"config-store.js","names":["getSqliteSessionConfig","updateSqliteSessionConfig"],"sources":["../../../src/session/config-store.ts"],"sourcesContent":["import type { ReasoningLevel, ThinkLevel, VerboseLevel } from '../agent/transcript/thinking-types.js';\nimport {\n deleteSessionConfig as deleteSqliteSessionConfig,\n getSessionConfig as getSqliteSessionConfig,\n hasSessionConfig,\n requireXopcDatabase,\n setSessionConfig as setSqliteSessionConfig,\n updateSessionConfig as updateSqliteSessionConfig,\n} from '../storage/sqlite/index.js';\nimport { createLogger } from '../utils/logger.js';\nimport type { SessionAgentConfig } from './config-types.js';\n\nexport type { SessionAgentConfig } from './config-types.js';\n\nconst log = createLogger('SessionConfigStore');\n\nexport class SessionConfigStore {\n private cwd: string;\n\n constructor(_agentHomeDir: string, cwd = process.cwd()) {\n this.cwd = cwd;\n }\n\n private requireDatabase(): void {\n requireXopcDatabase();\n }\n\n async initialize(): Promise<void> {\n this.requireDatabase();\n log.debug('Session config store initialized (SQLite)');\n }\n\n async get(sessionKey: string): Promise<SessionAgentConfig | null> {\n this.requireDatabase();\n return getSqliteSessionConfig(sessionKey);\n }\n\n async set(sessionKey: string, config: SessionAgentConfig): Promise<void> {\n this.requireDatabase();\n setSqliteSessionConfig(sessionKey, config, this.cwd);\n log.debug({ sessionKey }, 'Session config saved');\n }\n\n async update(sessionKey: string, partial: Partial<SessionAgentConfig>): Promise<SessionAgentConfig> {\n this.requireDatabase();\n const updated = updateSqliteSessionConfig(sessionKey, partial, this.cwd);\n log.debug({ sessionKey }, 'Session config updated');\n return updated;\n }\n\n async delete(sessionKey: string): Promise<void> {\n this.requireDatabase();\n deleteSqliteSessionConfig(sessionKey);\n log.debug({ sessionKey }, 'Session config deleted');\n }\n\n async has(sessionKey: string): Promise<boolean> {\n this.requireDatabase();\n return hasSessionConfig(sessionKey);\n }\n\n async getAll(): Promise<Map<string, SessionAgentConfig>> {\n this.requireDatabase();\n const configs = new Map<string, SessionAgentConfig>();\n const { listSessionMetadata } = await import('../storage/sqlite/index.js');\n const { items } = listSessionMetadata({ limit: 100_000 });\n for (const item of items) {\n const config = getSqliteSessionConfig(item.key);\n if (config) {\n configs.set(item.key, config);\n }\n }\n return configs;\n }\n\n async clear(): Promise<void> {\n this.requireDatabase();\n const { listSessionMetadata } = await import('../storage/sqlite/index.js');\n const { items } = listSessionMetadata({ limit: 100_000 });\n for (const item of items) {\n deleteSqliteSessionConfig(item.key);\n }\n log.debug('All session configs cleared');\n }\n}\n\nexport async function resolveThinkingLevel(\n sessionConfigStore: SessionConfigStore,\n sessionKey: string,\n agentDefault?: ThinkLevel,\n): Promise<ThinkLevel | undefined> {\n const config = await sessionConfigStore.get(sessionKey);\n return config?.thinkingLevel ?? agentDefault;\n}\n\nexport async function resolveReasoningLevel(\n sessionConfigStore: SessionConfigStore,\n sessionKey: string,\n agentDefault?: ReasoningLevel,\n): Promise<ReasoningLevel | undefined> {\n const config = await sessionConfigStore.get(sessionKey);\n return config?.reasoningLevel ?? agentDefault;\n}\n\nexport async function resolveVerboseLevel(\n sessionConfigStore: SessionConfigStore,\n sessionKey: string,\n agentDefault?: VerboseLevel,\n): Promise<VerboseLevel | undefined> {\n const config = await sessionConfigStore.get(sessionKey);\n return config?.verboseLevel ?? agentDefault;\n}\n"],"mappings":";;;;;;aASkD;AAKlD,MAAM,MAAM,aAAa,qBAAqB;AAE9C,IAAa,qBAAb,MAAgC;CAC9B;CAEA,YAAY,eAAuB,MAAM,QAAQ,KAAK,EAAE;AACtD,OAAK,MAAM;;CAGb,kBAAgC;AAC9B,uBAAqB;;CAGvB,MAAM,aAA4B;AAChC,OAAK,iBAAiB;AACtB,MAAI,MAAM,4CAA4C;;CAGxD,MAAM,IAAI,YAAwD;AAChE,OAAK,iBAAiB;AACtB,SAAOA,iBAAuB,WAAW;;CAG3C,MAAM,IAAI,YAAoB,QAA2C;AACvE,OAAK,iBAAiB;AACtB,mBAAuB,YAAY,QAAQ,KAAK,IAAI;AACpD,MAAI,MAAM,EAAE,YAAY,EAAE,uBAAuB;;CAGnD,MAAM,OAAO,YAAoB,SAAmE;AAClG,OAAK,iBAAiB;EACtB,MAAM,UAAUC,oBAA0B,YAAY,SAAS,KAAK,IAAI;AACxE,MAAI,MAAM,EAAE,YAAY,EAAE,yBAAyB;AACnD,SAAO;;CAGT,MAAM,OAAO,YAAmC;AAC9C,OAAK,iBAAiB;AACtB,sBAA0B,WAAW;AACrC,MAAI,MAAM,EAAE,YAAY,EAAE,yBAAyB;;CAGrD,MAAM,IAAI,YAAsC;AAC9C,OAAK,iBAAiB;AACtB,SAAO,iBAAiB,WAAW;;CAGrC,MAAM,SAAmD;AACvD,OAAK,iBAAiB;EACtB,MAAM,0BAAU,IAAI,KAAiC;EACrD,MAAM,EAAE,wBAAwB,MAAM,OAAO;EAC7C,MAAM,EAAE,UAAU,oBAAoB,EAAE,OAAO,KAAS,CAAC;AACzD,OAAK,MAAM,QAAQ,OAAO;GACxB,MAAM,SAASD,iBAAuB,KAAK,IAAI;AAC/C,OAAI,OACF,SAAQ,IAAI,KAAK,KAAK,OAAO;;AAGjC,SAAO;;CAGT,MAAM,QAAuB;AAC3B,OAAK,iBAAiB;EACtB,MAAM,EAAE,wBAAwB,MAAM,OAAO;EAC7C,MAAM,EAAE,UAAU,oBAAoB,EAAE,OAAO,KAAS,CAAC;AACzD,OAAK,MAAM,QAAQ,MACjB,qBAA0B,KAAK,IAAI;AAErC,MAAI,MAAM,8BAA8B;;;AAI5C,eAAsB,qBACpB,oBACA,YACA,cACiC;AAEjC,SAAO,MADc,mBAAmB,IAAI,WAAW,GACxC,iBAAiB;;AAGlC,eAAsB,sBACpB,oBACA,YACA,cACqC;AAErC,SAAO,MADc,mBAAmB,IAAI,WAAW,GACxC,kBAAkB;;AAGnC,eAAsB,oBACpB,oBACA,YACA,cACmC;AAEnC,SAAO,MADc,mBAAmB,IAAI,WAAW,GACxC,gBAAgB"}
@@ -0,0 +1,15 @@
1
+ import type { ElevatedMode, ReasoningLevel, ThinkLevel, VerboseLevel } from '../agent/transcript/thinking-types.js';
2
+ /**
3
+ * Session-level agent configuration persisted in SQLite.
4
+ * These settings override agent defaults for a specific session.
5
+ */
6
+ export interface SessionAgentConfig {
7
+ thinkingLevel?: ThinkLevel;
8
+ reasoningLevel?: ReasoningLevel;
9
+ verboseLevel?: VerboseLevel;
10
+ elevatedMode?: ElevatedMode;
11
+ modelOverride?: string;
12
+ providerOverride?: string;
13
+ workingDirectoryOverride?: string;
14
+ updatedAt?: number;
15
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -2,11 +2,9 @@ export { SessionIndex, type SessionIndexConfig } from './manager.js';
2
2
  export { onSessionTranscriptUpdate, emitSessionTranscriptUpdate, type SessionTranscriptUpdate, } from './transcript-events.js';
3
3
  export { SessionStore } from './store.js';
4
4
  export type { SessionStoreOptions } from './store.js';
5
- export { SessionSearchIndex } from './search-index.js';
6
- export { getOrLoadSessionSearchIndex, invalidateSessionSearchIndexCache, } from './search-index-cache.js';
7
5
  export { SessionConfigStore, resolveThinkingLevel, resolveReasoningLevel, resolveVerboseLevel } from './config-store.js';
8
6
  export { resolveEffectiveThinkingLevel, resolveEffectiveReasoningLevel } from './thinking-resolve.js';
9
- export type { SessionAgentConfig } from './config-store.js';
7
+ export type { SessionAgentConfig } from './config-types.js';
10
8
  export { normalizeWorkingDirectoryInput, effectiveWorkspacePathForSession, } from './session-workspace.js';
11
9
  export { SessionStatus, type SessionMetadata, type SessionDetail, type SessionListQuery, type PaginatedResult, type SessionStats, type ExportFormat, type SessionExport, type SessionTranscriptSummary, type CompactionCheckpointSummary, type CompactionCheckpointDetail, } from './types.js';
12
10
  export { normalizeCompactionCheckpointId } from './compaction-checkpoints.js';
@@ -1,10 +1,8 @@
1
- import { emitSessionTranscriptUpdate, onSessionTranscriptUpdate } from "./transcript-events.js";
1
+ import { SessionStatus } from "./types.js";
2
2
  import { buildSessionContextForLlm, isTranscriptContextEntry, mergeLlmMessagesPreservingContextRows, transcriptRowsFromJsonArray } from "./session-context-for-llm.js";
3
- import { SessionSearchIndex } from "./search-index.js";
4
- import { getOrLoadSessionSearchIndex, invalidateSessionSearchIndexCache } from "./search-index-cache.js";
3
+ import { emitSessionTranscriptUpdate, onSessionTranscriptUpdate } from "./transcript-events.js";
5
4
  import { fallbackTitleFromMessages, generateSessionTitleFromMessages, getSessionTitleSource, isWebchatSessionKey, maybeRefineSessionTitleWithLlm, maybeSetProvisionalSessionTitle, provisionalTitleFromUserText, sanitizeSessionTitle, shouldAutoTitleSessionKey, shouldRefineSessionTitleWithLlm } from "./session-title.js";
6
5
  import { normalizeCompactionCheckpointId } from "./compaction-checkpoints.js";
7
- import { SessionStatus } from "./types.js";
8
6
  import { SessionStore } from "./store.js";
9
7
  import { applySessionPatchToMetadata } from "./patch-metadata.js";
10
8
  import { SessionIndex } from "./manager.js";
@@ -20,4 +18,4 @@ import { DEFAULT_RESET_TRIGGERS, RESET_OVERLAP_COMMANDS, bareResetAckMessage, ma
20
18
  import { initSessionTurn } from "./init-session-turn.js";
21
19
  import { flattenMessageContent, messagesToClientHistory } from "./client-history.js";
22
20
  import { CURRENT_SESSION_TRANSCRIPT_VERSION, XOPC_SESSION_TRANSCRIPT_TYPE } from "./transcript-format.js";
23
- export { CURRENT_SESSION_TRANSCRIPT_VERSION, DEFAULT_IDLE_MINUTES, DEFAULT_RESET_AT_HOUR, DEFAULT_RESET_MODE, DEFAULT_RESET_TRIGGERS, RESET_OVERLAP_COMMANDS, SessionConfigStore, SessionIndex, SessionSearchIndex, SessionStatus, SessionStore, XOPC_SESSION_TRANSCRIPT_TYPE, applySessionPatchToMetadata, bareResetAckMessage, buildSessionContextForLlm, effectiveWorkspacePathForSession, emitSessionTranscriptUpdate, evaluateSessionFreshness, fallbackTitleFromMessages, flattenMessageContent, generateSessionTitleFromMessages, getOrLoadSessionSearchIndex, getSessionTitleSource, initSessionTurn, invalidateSessionSearchIndexCache, isThreadSessionKey, isTranscriptContextEntry, isWebchatSessionKey, matchResetTriggers, maybeRefineSessionTitleWithLlm, maybeSetProvisionalSessionTitle, mergeLlmMessagesPreservingContextRows, messagesToClientHistory, normalizeCompactionCheckpointId, normalizeWorkingDirectoryInput, onSessionTranscriptUpdate, provisionalTitleFromUserText, resolveChannelResetConfig, resolveDailyResetAtMs, resolveEffectiveReasoningLevel, resolveEffectiveThinkingLevel, resolveReasoningLevel, resolveResetTriggers, resolveSession, resolveSessionKeyForRequest, resolveSessionLifecycleTimestamps, resolveSessionResetPolicy, resolveSessionResetType, resolveThinkingLevel, resolveVerboseLevel, sanitizeSessionTitle, shouldAutoTitleSessionKey, shouldRefineSessionTitleWithLlm, shouldSkipResetOverlapCommand, shouldSkipWebchatInboundByAbortCutoff, stripLeadingEnvelopeTimestamp, transcriptRowsFromJsonArray };
21
+ export { CURRENT_SESSION_TRANSCRIPT_VERSION, DEFAULT_IDLE_MINUTES, DEFAULT_RESET_AT_HOUR, DEFAULT_RESET_MODE, DEFAULT_RESET_TRIGGERS, RESET_OVERLAP_COMMANDS, SessionConfigStore, SessionIndex, SessionStatus, SessionStore, XOPC_SESSION_TRANSCRIPT_TYPE, applySessionPatchToMetadata, bareResetAckMessage, buildSessionContextForLlm, effectiveWorkspacePathForSession, emitSessionTranscriptUpdate, evaluateSessionFreshness, fallbackTitleFromMessages, flattenMessageContent, generateSessionTitleFromMessages, getSessionTitleSource, initSessionTurn, isThreadSessionKey, isTranscriptContextEntry, isWebchatSessionKey, matchResetTriggers, maybeRefineSessionTitleWithLlm, maybeSetProvisionalSessionTitle, mergeLlmMessagesPreservingContextRows, messagesToClientHistory, normalizeCompactionCheckpointId, normalizeWorkingDirectoryInput, onSessionTranscriptUpdate, provisionalTitleFromUserText, resolveChannelResetConfig, resolveDailyResetAtMs, resolveEffectiveReasoningLevel, resolveEffectiveThinkingLevel, resolveReasoningLevel, resolveResetTriggers, resolveSession, resolveSessionKeyForRequest, resolveSessionLifecycleTimestamps, resolveSessionResetPolicy, resolveSessionResetType, resolveThinkingLevel, resolveVerboseLevel, sanitizeSessionTitle, shouldAutoTitleSessionKey, shouldRefineSessionTitleWithLlm, shouldSkipResetOverlapCommand, shouldSkipWebchatInboundByAbortCutoff, stripLeadingEnvelopeTimestamp, transcriptRowsFromJsonArray };
@@ -19,12 +19,6 @@ export type InitSessionTurnOptions = {
19
19
  sessionKey: string;
20
20
  body?: string;
21
21
  resetSession: SessionResetFn;
22
- /** When true, skip idle/daily implicit rollover (provider-owned CLI sessions). */
23
22
  skipImplicitExpiry?: boolean;
24
23
  };
25
- /**
26
- * Turn-start session init: match `resetTriggers`, evaluate freshness, archive +
27
- * assign new `sessionId` when stale or explicitly reset. OpenClaw `initSessionState`
28
- * equivalent for xopc direct + channel paths.
29
- */
30
24
  export declare function initSessionTurn(opts: InitSessionTurnOptions): Promise<InitSessionTurnResult>;
@@ -1,7 +1,9 @@
1
- import { SessionConfigSchema, init_schema } from "../config/schema.js";
2
- import { init_session_key, parseSessionKey } from "../routing/session-key.js";
3
1
  import { createLogger } from "../utils/logger/index.js";
4
2
  import { init_logger } from "../utils/logger.js";
3
+ import { SessionConfigSchema, init_schema } from "../config/schema.js";
4
+ import { init_session_key, parseSessionKey } from "../routing/session-key.js";
5
+ import { requireXopcDatabase } from "../storage/sqlite/connection.js";
6
+ import "../storage/sqlite/index.js";
5
7
  import { evaluateSessionFreshness, resolveSessionResetPolicy } from "./reset-policy.js";
6
8
  import { resolveChannelResetConfig, resolveSessionResetType } from "./reset-type.js";
7
9
  import { resolveSessionLifecycleTimestamps } from "./lifecycle-timestamps.js";
@@ -13,22 +15,17 @@ init_schema();
13
15
  init_session_key();
14
16
  init_logger();
15
17
  const log = createLogger("InitSessionTurn");
16
- /**
17
- * Turn-start session init: match `resetTriggers`, evaluate freshness, archive +
18
- * assign new `sessionId` when stale or explicitly reset. OpenClaw `initSessionState`
19
- * equivalent for xopc direct + channel paths.
20
- */
21
18
  async function initSessionTurn(opts) {
19
+ requireXopcDatabase();
22
20
  const sessionCfg = opts.cfg.session ?? SessionConfigSchema.parse({});
23
21
  const triggers = resolveResetTriggers(sessionCfg.resetTriggers);
24
22
  const rawBody = opts.body ?? "";
25
23
  const triggerMatch = matchResetTriggers(rawBody, triggers);
26
- const { sessionKey, sessionStore } = await resolveSessionKeyForRequest({
24
+ const { sessionKey, sessionMetadata } = await resolveSessionKeyForRequest({
27
25
  cfg: opts.cfg,
28
26
  sessionKey: opts.sessionKey
29
27
  });
30
28
  const key = sessionKey?.trim() ?? opts.sessionKey.trim();
31
- const sessionEntry = key ? sessionStore[key] : void 0;
32
29
  const parsed = key ? parseSessionKey(key) : null;
33
30
  const peerKind = parsed?.peerKind;
34
31
  const resetType = resolveSessionResetType({
@@ -36,30 +33,33 @@ async function initSessionTurn(opts) {
36
33
  isGroup: peerKind === "group" || peerKind === "channel",
37
34
  isThread: Boolean(parsed?.threadId)
38
35
  });
39
- const meta = sessionEntry?.pluginExtensions?.xopc?.metadata;
40
36
  const resetPolicy = resolveSessionResetPolicy({
41
37
  sessionCfg,
42
38
  resetType,
43
39
  resetOverride: resolveChannelResetConfig({
44
40
  sessionCfg,
45
- channel: parsed?.source ?? meta?.sourceChannel
41
+ channel: parsed?.source ?? sessionMetadata?.sourceChannel
46
42
  })
47
43
  });
48
- const lifecycle = resolveSessionLifecycleTimestamps({ entry: sessionEntry });
44
+ const lifecycle = resolveSessionLifecycleTimestamps({ entry: sessionMetadata ? {
45
+ updatedAt: Date.parse(sessionMetadata.updatedAt),
46
+ sessionStartedAt: sessionMetadata.sessionStartedAt ? Date.parse(sessionMetadata.sessionStartedAt) : void 0,
47
+ lastInteractionAt: sessionMetadata.lastInteractionAt ? Date.parse(sessionMetadata.lastInteractionAt) : void 0
48
+ } : void 0 });
49
49
  const now = Date.now();
50
- const freshness = sessionEntry ? evaluateSessionFreshness({
51
- updatedAt: sessionEntry.updatedAt,
50
+ const freshness = sessionMetadata ? evaluateSessionFreshness({
51
+ updatedAt: Date.parse(sessionMetadata.updatedAt),
52
52
  ...lifecycle,
53
53
  now,
54
54
  policy: resetPolicy
55
55
  }) : { fresh: false };
56
56
  const skipImplicit = opts.skipImplicitExpiry ?? false;
57
- const staleRollover = Boolean(sessionEntry && !skipImplicit && !freshness.fresh);
57
+ const staleRollover = Boolean(sessionMetadata && !skipImplicit && !freshness.fresh);
58
58
  const needsRollover = triggerMatch.resetTriggered || staleRollover;
59
- let sessionId = sessionEntry?.sessionId;
59
+ let sessionId = sessionMetadata?.transcriptId;
60
60
  let previousSessionId;
61
61
  let isNewSession = false;
62
- if (needsRollover && sessionEntry?.sessionId) {
62
+ if (needsRollover && sessionMetadata?.transcriptId) {
63
63
  const outcome = await opts.resetSession(key);
64
64
  if (outcome) {
65
65
  previousSessionId = outcome.previousSessionId;
@@ -78,7 +78,7 @@ async function initSessionTurn(opts) {
78
78
  sessionId = randomUUID();
79
79
  isNewSession = true;
80
80
  }
81
- } else if (!sessionEntry) {
81
+ } else if (!sessionMetadata) {
82
82
  isNewSession = true;
83
83
  sessionId = randomUUID();
84
84
  }
@@ -1 +1 @@
1
- {"version":3,"file":"init-session-turn.js","names":[],"sources":["../../../src/session/init-session-turn.ts"],"sourcesContent":["import { randomUUID } from 'node:crypto';\n\nimport { SessionConfigSchema, type Config } from '../config/schema.js';\nimport { parseSessionKey } from '../routing/session-key.js';\nimport { createLogger } from '../utils/logger.js';\n\nimport { resolveSessionLifecycleTimestamps } from './lifecycle-timestamps.js';\nimport {\n evaluateSessionFreshness,\n resolveSessionResetPolicy,\n} from './reset-policy.js';\nimport {\n bareResetAckMessage,\n matchResetTriggers,\n resolveResetTriggers,\n} from './reset-triggers.js';\nimport { resolveChannelResetConfig, resolveSessionResetType } from './reset-type.js';\nimport { resolveSessionKeyForRequest } from './resolve-session.js';\n\nconst log = createLogger('InitSessionTurn');\n\nexport type SessionResetFn = (\n sessionKey: string,\n) => Promise<{ sessionId: string; previousSessionId: string } | null>;\n\nexport type InitSessionTurnResult = {\n sessionKey: string;\n sessionId?: string;\n previousSessionId?: string;\n isNewSession: boolean;\n resetTriggered: boolean;\n staleRollover: boolean;\n bodyStripped: string;\n bareReset: boolean;\n ackMessage?: string;\n};\n\nexport type InitSessionTurnOptions = {\n cfg: Config;\n sessionKey: string;\n body?: string;\n resetSession: SessionResetFn;\n /** When true, skip idle/daily implicit rollover (provider-owned CLI sessions). */\n skipImplicitExpiry?: boolean;\n};\n\n/**\n * Turn-start session init: match `resetTriggers`, evaluate freshness, archive +\n * assign new `sessionId` when stale or explicitly reset. OpenClaw `initSessionState`\n * equivalent for xopc direct + channel paths.\n */\nexport async function initSessionTurn(\n opts: InitSessionTurnOptions,\n): Promise<InitSessionTurnResult> {\n const sessionCfg = opts.cfg.session ?? SessionConfigSchema.parse({});\n const triggers = resolveResetTriggers(sessionCfg.resetTriggers);\n const rawBody = opts.body ?? '';\n const triggerMatch = matchResetTriggers(rawBody, triggers);\n\n const { sessionKey, sessionStore } = await resolveSessionKeyForRequest({\n cfg: opts.cfg,\n sessionKey: opts.sessionKey,\n });\n const key = sessionKey?.trim() ?? opts.sessionKey.trim();\n const sessionEntry = key ? sessionStore[key] : undefined;\n\n const parsed = key ? parseSessionKey(key) : null;\n const peerKind = parsed?.peerKind;\n const resetType = resolveSessionResetType({\n sessionKey: key,\n isGroup: peerKind === 'group' || peerKind === 'channel',\n isThread: Boolean(parsed?.threadId),\n });\n const meta = sessionEntry?.pluginExtensions?.xopc?.metadata;\n const channelReset = resolveChannelResetConfig({\n sessionCfg,\n channel: parsed?.source ?? meta?.sourceChannel,\n });\n const resetPolicy = resolveSessionResetPolicy({\n sessionCfg,\n resetType,\n resetOverride: channelReset,\n });\n const lifecycle = resolveSessionLifecycleTimestamps({ entry: sessionEntry });\n const now = Date.now();\n const freshness = sessionEntry\n ? evaluateSessionFreshness({\n updatedAt: sessionEntry.updatedAt,\n ...lifecycle,\n now,\n policy: resetPolicy,\n })\n : { fresh: false };\n\n const skipImplicit = opts.skipImplicitExpiry ?? false;\n const staleRollover = Boolean(sessionEntry && !skipImplicit && !freshness.fresh);\n const needsRollover = triggerMatch.resetTriggered || staleRollover;\n\n let sessionId = sessionEntry?.sessionId;\n let previousSessionId: string | undefined;\n let isNewSession = false;\n\n if (needsRollover && sessionEntry?.sessionId) {\n const outcome = await opts.resetSession(key);\n if (outcome) {\n previousSessionId = outcome.previousSessionId;\n sessionId = outcome.sessionId;\n isNewSession = true;\n log.info(\n {\n sessionKey: key,\n sessionId: outcome.sessionId,\n previousSessionId: outcome.previousSessionId,\n resetTriggered: triggerMatch.resetTriggered,\n staleRollover,\n resetType,\n },\n triggerMatch.resetTriggered\n ? 'Session reset via reset trigger'\n : 'Session rolled over (stale freshness)',\n );\n } else {\n log.warn({ sessionKey: key }, 'Session rollover requested but resetSession returned null');\n sessionId = randomUUID();\n isNewSession = true;\n }\n } else if (!sessionEntry) {\n isNewSession = true;\n sessionId = randomUUID();\n }\n\n const bareReset = triggerMatch.resetTriggered && triggerMatch.bareReset;\n const ackMessage = bareReset ? bareResetAckMessage(triggerMatch.matchedTrigger) : undefined;\n\n return {\n sessionKey: key,\n sessionId,\n previousSessionId,\n isNewSession,\n resetTriggered: triggerMatch.resetTriggered,\n staleRollover,\n bodyStripped: triggerMatch.resetTriggered ? triggerMatch.bodyStripped : rawBody,\n bareReset,\n ackMessage,\n };\n}\n"],"mappings":";;;;;;;;;;;aAEuE;kBACX;aACV;AAelD,MAAM,MAAM,aAAa,kBAAkB;;;;;;AAgC3C,eAAsB,gBACpB,MACgC;CAChC,MAAM,aAAa,KAAK,IAAI,WAAW,oBAAoB,MAAM,EAAE,CAAC;CACpE,MAAM,WAAW,qBAAqB,WAAW,cAAc;CAC/D,MAAM,UAAU,KAAK,QAAQ;CAC7B,MAAM,eAAe,mBAAmB,SAAS,SAAS;CAE1D,MAAM,EAAE,YAAY,iBAAiB,MAAM,4BAA4B;EACrE,KAAK,KAAK;EACV,YAAY,KAAK;EAClB,CAAC;CACF,MAAM,MAAM,YAAY,MAAM,IAAI,KAAK,WAAW,MAAM;CACxD,MAAM,eAAe,MAAM,aAAa,OAAO,KAAA;CAE/C,MAAM,SAAS,MAAM,gBAAgB,IAAI,GAAG;CAC5C,MAAM,WAAW,QAAQ;CACzB,MAAM,YAAY,wBAAwB;EACxC,YAAY;EACZ,SAAS,aAAa,WAAW,aAAa;EAC9C,UAAU,QAAQ,QAAQ,SAAS;EACpC,CAAC;CACF,MAAM,OAAO,cAAc,kBAAkB,MAAM;CAKnD,MAAM,cAAc,0BAA0B;EAC5C;EACA;EACA,eAPmB,0BAA0B;GAC7C;GACA,SAAS,QAAQ,UAAU,MAAM;GAClC,CAI4B;EAC5B,CAAC;CACF,MAAM,YAAY,kCAAkC,EAAE,OAAO,cAAc,CAAC;CAC5E,MAAM,MAAM,KAAK,KAAK;CACtB,MAAM,YAAY,eACd,yBAAyB;EACvB,WAAW,aAAa;EACxB,GAAG;EACH;EACA,QAAQ;EACT,CAAC,GACF,EAAE,OAAO,OAAO;CAEpB,MAAM,eAAe,KAAK,sBAAsB;CAChD,MAAM,gBAAgB,QAAQ,gBAAgB,CAAC,gBAAgB,CAAC,UAAU,MAAM;CAChF,MAAM,gBAAgB,aAAa,kBAAkB;CAErD,IAAI,YAAY,cAAc;CAC9B,IAAI;CACJ,IAAI,eAAe;AAEnB,KAAI,iBAAiB,cAAc,WAAW;EAC5C,MAAM,UAAU,MAAM,KAAK,aAAa,IAAI;AAC5C,MAAI,SAAS;AACX,uBAAoB,QAAQ;AAC5B,eAAY,QAAQ;AACpB,kBAAe;AACf,OAAI,KACF;IACE,YAAY;IACZ,WAAW,QAAQ;IACnB,mBAAmB,QAAQ;IAC3B,gBAAgB,aAAa;IAC7B;IACA;IACD,EACD,aAAa,iBACT,oCACA,wCACL;SACI;AACL,OAAI,KAAK,EAAE,YAAY,KAAK,EAAE,4DAA4D;AAC1F,eAAY,YAAY;AACxB,kBAAe;;YAER,CAAC,cAAc;AACxB,iBAAe;AACf,cAAY,YAAY;;CAG1B,MAAM,YAAY,aAAa,kBAAkB,aAAa;CAC9D,MAAM,aAAa,YAAY,oBAAoB,aAAa,eAAe,GAAG,KAAA;AAElF,QAAO;EACL,YAAY;EACZ;EACA;EACA;EACA,gBAAgB,aAAa;EAC7B;EACA,cAAc,aAAa,iBAAiB,aAAa,eAAe;EACxE;EACA;EACD"}
1
+ {"version":3,"file":"init-session-turn.js","names":[],"sources":["../../../src/session/init-session-turn.ts"],"sourcesContent":["import { randomUUID } from 'node:crypto';\n\nimport { SessionConfigSchema, type Config } from '../config/schema.js';\nimport { parseSessionKey } from '../routing/session-key.js';\nimport { createLogger } from '../utils/logger.js';\nimport { requireXopcDatabase } from '../storage/sqlite/index.js';\nimport { resolveSessionLifecycleTimestamps } from './lifecycle-timestamps.js';\nimport {\n evaluateSessionFreshness,\n resolveSessionResetPolicy,\n} from './reset-policy.js';\nimport {\n bareResetAckMessage,\n matchResetTriggers,\n resolveResetTriggers,\n} from './reset-triggers.js';\nimport { resolveChannelResetConfig, resolveSessionResetType } from './reset-type.js';\nimport { resolveSessionKeyForRequest } from './resolve-session.js';\n\nconst log = createLogger('InitSessionTurn');\n\nexport type SessionResetFn = (\n sessionKey: string,\n) => Promise<{ sessionId: string; previousSessionId: string } | null>;\n\nexport type InitSessionTurnResult = {\n sessionKey: string;\n sessionId?: string;\n previousSessionId?: string;\n isNewSession: boolean;\n resetTriggered: boolean;\n staleRollover: boolean;\n bodyStripped: string;\n bareReset: boolean;\n ackMessage?: string;\n};\n\nexport type InitSessionTurnOptions = {\n cfg: Config;\n sessionKey: string;\n body?: string;\n resetSession: SessionResetFn;\n skipImplicitExpiry?: boolean;\n};\n\nexport async function initSessionTurn(\n opts: InitSessionTurnOptions,\n): Promise<InitSessionTurnResult> {\n requireXopcDatabase();\n\n const sessionCfg = opts.cfg.session ?? SessionConfigSchema.parse({});\n const triggers = resolveResetTriggers(sessionCfg.resetTriggers);\n const rawBody = opts.body ?? '';\n const triggerMatch = matchResetTriggers(rawBody, triggers);\n\n const { sessionKey, sessionMetadata } = await resolveSessionKeyForRequest({\n cfg: opts.cfg,\n sessionKey: opts.sessionKey,\n });\n const key = sessionKey?.trim() ?? opts.sessionKey.trim();\n\n const parsed = key ? parseSessionKey(key) : null;\n const peerKind = parsed?.peerKind;\n const resetType = resolveSessionResetType({\n sessionKey: key,\n isGroup: peerKind === 'group' || peerKind === 'channel',\n isThread: Boolean(parsed?.threadId),\n });\n const channelReset = resolveChannelResetConfig({\n sessionCfg,\n channel: parsed?.source ?? sessionMetadata?.sourceChannel,\n });\n const resetPolicy = resolveSessionResetPolicy({\n sessionCfg,\n resetType,\n resetOverride: channelReset,\n });\n const lifecycle = resolveSessionLifecycleTimestamps({\n entry: sessionMetadata\n ? {\n updatedAt: Date.parse(sessionMetadata.updatedAt),\n sessionStartedAt: sessionMetadata.sessionStartedAt\n ? Date.parse(sessionMetadata.sessionStartedAt)\n : undefined,\n lastInteractionAt: sessionMetadata.lastInteractionAt\n ? Date.parse(sessionMetadata.lastInteractionAt)\n : undefined,\n }\n : undefined,\n });\n const now = Date.now();\n const freshness = sessionMetadata\n ? evaluateSessionFreshness({\n updatedAt: Date.parse(sessionMetadata.updatedAt),\n ...lifecycle,\n now,\n policy: resetPolicy,\n })\n : { fresh: false };\n\n const skipImplicit = opts.skipImplicitExpiry ?? false;\n const staleRollover = Boolean(sessionMetadata && !skipImplicit && !freshness.fresh);\n const needsRollover = triggerMatch.resetTriggered || staleRollover;\n\n let sessionId = sessionMetadata?.transcriptId;\n let previousSessionId: string | undefined;\n let isNewSession = false;\n\n if (needsRollover && sessionMetadata?.transcriptId) {\n const outcome = await opts.resetSession(key);\n if (outcome) {\n previousSessionId = outcome.previousSessionId;\n sessionId = outcome.sessionId;\n isNewSession = true;\n log.info(\n {\n sessionKey: key,\n sessionId: outcome.sessionId,\n previousSessionId: outcome.previousSessionId,\n resetTriggered: triggerMatch.resetTriggered,\n staleRollover,\n resetType,\n },\n triggerMatch.resetTriggered\n ? 'Session reset via reset trigger'\n : 'Session rolled over (stale freshness)',\n );\n } else {\n log.warn({ sessionKey: key }, 'Session rollover requested but resetSession returned null');\n sessionId = randomUUID();\n isNewSession = true;\n }\n } else if (!sessionMetadata) {\n isNewSession = true;\n sessionId = randomUUID();\n }\n\n const bareReset = triggerMatch.resetTriggered && triggerMatch.bareReset;\n const ackMessage = bareReset ? bareResetAckMessage(triggerMatch.matchedTrigger) : undefined;\n\n return {\n sessionKey: key,\n sessionId,\n previousSessionId,\n isNewSession,\n resetTriggered: triggerMatch.resetTriggered,\n staleRollover,\n bodyStripped: triggerMatch.resetTriggered ? triggerMatch.bodyStripped : rawBody,\n bareReset,\n ackMessage,\n };\n}\n"],"mappings":";;;;;;;;;;;;;aAEuE;kBACX;aACV;AAelD,MAAM,MAAM,aAAa,kBAAkB;AA0B3C,eAAsB,gBACpB,MACgC;AAChC,sBAAqB;CAErB,MAAM,aAAa,KAAK,IAAI,WAAW,oBAAoB,MAAM,EAAE,CAAC;CACpE,MAAM,WAAW,qBAAqB,WAAW,cAAc;CAC/D,MAAM,UAAU,KAAK,QAAQ;CAC7B,MAAM,eAAe,mBAAmB,SAAS,SAAS;CAE1D,MAAM,EAAE,YAAY,oBAAoB,MAAM,4BAA4B;EACxE,KAAK,KAAK;EACV,YAAY,KAAK;EAClB,CAAC;CACF,MAAM,MAAM,YAAY,MAAM,IAAI,KAAK,WAAW,MAAM;CAExD,MAAM,SAAS,MAAM,gBAAgB,IAAI,GAAG;CAC5C,MAAM,WAAW,QAAQ;CACzB,MAAM,YAAY,wBAAwB;EACxC,YAAY;EACZ,SAAS,aAAa,WAAW,aAAa;EAC9C,UAAU,QAAQ,QAAQ,SAAS;EACpC,CAAC;CAKF,MAAM,cAAc,0BAA0B;EAC5C;EACA;EACA,eAPmB,0BAA0B;GAC7C;GACA,SAAS,QAAQ,UAAU,iBAAiB;GAC7C,CAI4B;EAC5B,CAAC;CACF,MAAM,YAAY,kCAAkC,EAClD,OAAO,kBACH;EACE,WAAW,KAAK,MAAM,gBAAgB,UAAU;EAChD,kBAAkB,gBAAgB,mBAC9B,KAAK,MAAM,gBAAgB,iBAAiB,GAC5C,KAAA;EACJ,mBAAmB,gBAAgB,oBAC/B,KAAK,MAAM,gBAAgB,kBAAkB,GAC7C,KAAA;EACL,GACD,KAAA,GACL,CAAC;CACF,MAAM,MAAM,KAAK,KAAK;CACtB,MAAM,YAAY,kBACd,yBAAyB;EACvB,WAAW,KAAK,MAAM,gBAAgB,UAAU;EAChD,GAAG;EACH;EACA,QAAQ;EACT,CAAC,GACF,EAAE,OAAO,OAAO;CAEpB,MAAM,eAAe,KAAK,sBAAsB;CAChD,MAAM,gBAAgB,QAAQ,mBAAmB,CAAC,gBAAgB,CAAC,UAAU,MAAM;CACnF,MAAM,gBAAgB,aAAa,kBAAkB;CAErD,IAAI,YAAY,iBAAiB;CACjC,IAAI;CACJ,IAAI,eAAe;AAEnB,KAAI,iBAAiB,iBAAiB,cAAc;EAClD,MAAM,UAAU,MAAM,KAAK,aAAa,IAAI;AAC5C,MAAI,SAAS;AACX,uBAAoB,QAAQ;AAC5B,eAAY,QAAQ;AACpB,kBAAe;AACf,OAAI,KACF;IACE,YAAY;IACZ,WAAW,QAAQ;IACnB,mBAAmB,QAAQ;IAC3B,gBAAgB,aAAa;IAC7B;IACA;IACD,EACD,aAAa,iBACT,oCACA,wCACL;SACI;AACL,OAAI,KAAK,EAAE,YAAY,KAAK,EAAE,4DAA4D;AAC1F,eAAY,YAAY;AACxB,kBAAe;;YAER,CAAC,iBAAiB;AAC3B,iBAAe;AACf,cAAY,YAAY;;CAG1B,MAAM,YAAY,aAAa,kBAAkB,aAAa;CAC9D,MAAM,aAAa,YAAY,oBAAoB,aAAa,eAAe,GAAG,KAAA;AAElF,QAAO;EACL,YAAY;EACZ;EACA;EACA;EACA,gBAAgB,aAAa;EAC7B;EACA,cAAc,aAAa,iBAAiB,aAAa,eAAe;EACxE;EACA;EACD"}
@@ -1,5 +1,8 @@
1
- import type { XopcSessionDiskEntry } from './parity/xopc-session-disk-entry.js';
2
- export type SessionLifecycleEntry = Pick<XopcSessionDiskEntry, 'sessionStartedAt' | 'lastInteractionAt' | 'updatedAt'>;
1
+ export type SessionLifecycleEntry = {
2
+ sessionStartedAt?: number;
3
+ lastInteractionAt?: number;
4
+ updatedAt?: number;
5
+ };
3
6
  export declare function resolveSessionLifecycleTimestamps(params: {
4
7
  entry: SessionLifecycleEntry | undefined;
5
8
  }): {
@@ -1 +1 @@
1
- {"version":3,"file":"lifecycle-timestamps.js","names":[],"sources":["../../../src/session/lifecycle-timestamps.ts"],"sourcesContent":["import type { XopcSessionDiskEntry } from './parity/xopc-session-disk-entry.js';\n\nexport type SessionLifecycleEntry = Pick<\n XopcSessionDiskEntry,\n 'sessionStartedAt' | 'lastInteractionAt' | 'updatedAt'\n>;\n\nfunction resolveTimestamp(value: number | undefined): number | undefined {\n return typeof value === 'number' && Number.isFinite(value) && value >= 0 ? value : undefined;\n}\n\nexport function resolveSessionLifecycleTimestamps(params: {\n entry: SessionLifecycleEntry | undefined;\n}): { sessionStartedAt?: number; lastInteractionAt?: number } {\n const entry = params.entry;\n if (!entry) {\n return {};\n }\n return {\n sessionStartedAt: resolveTimestamp(entry.sessionStartedAt),\n lastInteractionAt: resolveTimestamp(entry.lastInteractionAt),\n };\n}\n"],"mappings":";AAOA,SAAS,iBAAiB,OAA+C;AACvE,QAAO,OAAO,UAAU,YAAY,OAAO,SAAS,MAAM,IAAI,SAAS,IAAI,QAAQ,KAAA;;AAGrF,SAAgB,kCAAkC,QAEY;CAC5D,MAAM,QAAQ,OAAO;AACrB,KAAI,CAAC,MACH,QAAO,EAAE;AAEX,QAAO;EACL,kBAAkB,iBAAiB,MAAM,iBAAiB;EAC1D,mBAAmB,iBAAiB,MAAM,kBAAkB;EAC7D"}
1
+ {"version":3,"file":"lifecycle-timestamps.js","names":[],"sources":["../../../src/session/lifecycle-timestamps.ts"],"sourcesContent":["export type SessionLifecycleEntry = {\n sessionStartedAt?: number;\n lastInteractionAt?: number;\n updatedAt?: number;\n};\n\nfunction resolveTimestamp(value: number | undefined): number | undefined {\n return typeof value === 'number' && Number.isFinite(value) && value >= 0 ? value : undefined;\n}\n\nexport function resolveSessionLifecycleTimestamps(params: {\n entry: SessionLifecycleEntry | undefined;\n}): { sessionStartedAt?: number; lastInteractionAt?: number } {\n const entry = params.entry;\n if (!entry) {\n return {};\n }\n return {\n sessionStartedAt: resolveTimestamp(entry.sessionStartedAt),\n lastInteractionAt: resolveTimestamp(entry.lastInteractionAt),\n };\n}\n"],"mappings":";AAMA,SAAS,iBAAiB,OAA+C;AACvE,QAAO,OAAO,UAAU,YAAY,OAAO,SAAS,MAAM,IAAI,SAAS,IAAI,QAAQ,KAAA;;AAGrF,SAAgB,kCAAkC,QAEY;CAC5D,MAAM,QAAQ,OAAO;AACrB,KAAI,CAAC,MACH,QAAO,EAAE;AAEX,QAAO;EACL,kBAAkB,iBAAiB,MAAM,iBAAiB;EAC1D,mBAAmB,iBAAiB,MAAM,kBAAkB;EAC7D"}
@@ -1,5 +1,5 @@
1
1
  import { existsSync, readFileSync } from "node:fs";
2
- //#region src/session/parity/load-jsonl-entries.ts
2
+ //#region src/session/load-jsonl-entries.ts
3
3
  /** Same semantics as pi-coding-agent `loadEntriesFromFile` (package does not export it from the root). */
4
4
  function loadEntriesFromFile(filePath) {
5
5
  if (!existsSync(filePath)) return [];
@@ -0,0 +1 @@
1
+ {"version":3,"file":"load-jsonl-entries.js","names":[],"sources":["../../../src/session/load-jsonl-entries.ts"],"sourcesContent":["import { existsSync, readFileSync } from 'node:fs';\n\nimport type { FileEntry } from '@earendil-works/pi-coding-agent';\n\n/** Same semantics as pi-coding-agent `loadEntriesFromFile` (package does not export it from the root). */\nexport function loadEntriesFromFile(filePath: string): FileEntry[] {\n if (!existsSync(filePath)) {\n return [];\n }\n const content = readFileSync(filePath, 'utf8');\n const entries: FileEntry[] = [];\n for (const line of content.trim().split('\\n')) {\n if (!line.trim()) {\n continue;\n }\n try {\n entries.push(JSON.parse(line) as FileEntry);\n } catch {\n // Skip malformed lines (matches upstream)\n }\n }\n if (entries.length === 0) {\n return entries;\n }\n const header = entries[0];\n if (header.type !== 'session' || typeof (header as { id?: unknown }).id !== 'string') {\n return [];\n }\n return entries;\n}\n"],"mappings":";;;AAKA,SAAgB,oBAAoB,UAA+B;AACjE,KAAI,CAAC,WAAW,SAAS,CACvB,QAAO,EAAE;CAEX,MAAM,UAAU,aAAa,UAAU,OAAO;CAC9C,MAAM,UAAuB,EAAE;AAC/B,MAAK,MAAM,QAAQ,QAAQ,MAAM,CAAC,MAAM,KAAK,EAAE;AAC7C,MAAI,CAAC,KAAK,MAAM,CACd;AAEF,MAAI;AACF,WAAQ,KAAK,KAAK,MAAM,KAAK,CAAc;UACrC;;AAIV,KAAI,QAAQ,WAAW,EACrB,QAAO;CAET,MAAM,SAAS,QAAQ;AACvB,KAAI,OAAO,SAAS,aAAa,OAAQ,OAA4B,OAAO,SAC1E,QAAO,EAAE;AAEX,QAAO"}
@@ -10,8 +10,6 @@ import type { WindowConfig } from '../agent/memory/window.js';
10
10
  import type { Config } from '../config/schema.js';
11
11
  export interface SessionIndexConfig {
12
12
  config: Config;
13
- agentId?: string;
14
- sessionsDir?: string;
15
13
  windowConfig?: Partial<WindowConfig>;
16
14
  compactionConfig?: Partial<CompactionConfig>;
17
15
  }
@@ -140,7 +138,11 @@ export declare class SessionIndex extends EventEmitter {
140
138
  prepareCompaction(key: string, messages: any[], contextWindow: number): {
141
139
  needsCompaction: boolean;
142
140
  messages: import("@earendil-works/pi-agent-core").AgentMessage[];
143
- stats?: ReturnType<any>;
141
+ stats: {
142
+ needed: boolean;
143
+ reason: string;
144
+ usagePercent?: number;
145
+ };
144
146
  };
145
147
  /** Compact session messages */
146
148
  compact(key: string, messages: any[], contextWindow: number, instructions?: string, force?: boolean): Promise<CompactionResult>;
@@ -10,11 +10,7 @@ var SessionIndex = class extends EventEmitter$1 {
10
10
  store;
11
11
  constructor(config) {
12
12
  super();
13
- this.store = new SessionStore({
14
- config: config.config,
15
- agentId: config.agentId,
16
- sessionsDir: config.sessionsDir
17
- }, config.windowConfig, config.compactionConfig);
13
+ this.store = new SessionStore({ config: config.config }, config.windowConfig, config.compactionConfig);
18
14
  }
19
15
  async initialize() {
20
16
  await this.store.initialize();
@@ -1 +1 @@
1
- {"version":3,"file":"manager.js","names":["EventEmitter"],"sources":["../../../src/session/manager.ts"],"sourcesContent":["// Session manager - high-level session management service\n\nimport EventEmitter from 'events';\nimport { createLogger } from '../utils/logger.js';\nimport { SessionStore } from './store.js';\nimport type {\n SessionMetadata,\n SessionDetail,\n SessionListQuery,\n PaginatedResult,\n GlobalSessionStats,\n ExportFormat,\n SessionStatus,\n} from './types.js';\nimport type { Message } from './types.js';\nimport type { CompactionConfig, CompactionResult } from '../agent/memory/compaction.js';\nimport type { XopcSessionTranscriptV1 } from './transcript-format.js';\nimport type { XopcTranscriptContextEntry } from './session-context-for-llm.js';\nimport { applySessionPatchToMetadata, type SessionPatchBody } from './patch-metadata.js';\nimport type { WindowConfig } from '../agent/memory/window.js';\nimport type { Config } from '../config/schema.js';\n\nconst log = createLogger('SessionIndex');\n\nexport interface SessionIndexConfig {\n config: Config;\n agentId?: string;\n sessionsDir?: string;\n windowConfig?: Partial<WindowConfig>;\n compactionConfig?: Partial<CompactionConfig>;\n}\n\nexport class SessionIndex extends EventEmitter {\n private store: SessionStore;\n\n constructor(config: SessionIndexConfig) {\n super();\n this.store = new SessionStore(\n {\n config: config.config,\n agentId: config.agentId,\n sessionsDir: config.sessionsDir,\n },\n config.windowConfig,\n config.compactionConfig\n );\n }\n\n async initialize(): Promise<void> {\n await this.store.initialize();\n this.emit('ready');\n }\n\n /** Low-level store (e.g. cron resolving weixin delivery from session index). */\n getStore(): SessionStore {\n return this.store;\n }\n\n // ========== CRUD Operations ==========\n\n async listSessions(query?: SessionListQuery): Promise<PaginatedResult<SessionMetadata>> {\n return this.store.list(query);\n }\n\n /**\n * List all subagent sessions.\n * Subagent sessions have keys starting with 'subagent:'.\n */\n async listSubagents(query: SessionListQuery = {}): Promise<PaginatedResult<SessionMetadata>> {\n // Filter for subagent sessions only\n const subagentQuery: SessionListQuery = {\n ...query,\n search: query.search ? `subagent:${query.search}` : 'subagent:',\n };\n \n const result = await this.store.list(subagentQuery);\n \n // Additional filtering to ensure only subagent sessions\n const subagentSessions = result.items.filter((s) => s.key.startsWith('subagent:'));\n \n return {\n ...result,\n items: subagentSessions,\n total: subagentSessions.length,\n hasMore: false, // Simplified for now\n };\n }\n\n async getSession(\n key: string,\n options?: { includeTranscriptSummary?: boolean; includeTranscriptRows?: boolean },\n ): Promise<SessionDetail | null> {\n const session = await this.store.get(key, options);\n if (session) {\n this.emit('sessionAccessed', { key });\n }\n return session;\n }\n\n async getSessionMessagePage(\n key: string,\n options?: {\n offset?: number;\n limit?: number;\n before?: string;\n includeTranscriptSummary?: boolean;\n includeTranscriptRows?: boolean;\n },\n ): Promise<{\n session: SessionDetail;\n pagination: {\n total: number;\n limit: number;\n offset: number;\n hasMore: boolean;\n before?: string;\n nextBeforeCursor?: string;\n };\n } | null> {\n const result = await this.store.getMessagePage(key, options);\n if (result) {\n this.emit('sessionAccessed', { key });\n }\n return result;\n }\n\n /**\n * OpenClaw-style `sessions.patch`: partial metadata (name, tags, customData shallow merge).\n */\n async patchSession(\n key: string,\n patch: SessionPatchBody,\n ): Promise<{ ok: true } | { ok: false; error: string }> {\n const meta = await this.store.getMetadata(key);\n if (!meta) {\n return { ok: false, error: 'Session not found' };\n }\n const updates = applySessionPatchToMetadata(meta, patch);\n if (Object.keys(updates).length === 0) {\n return { ok: true };\n }\n await this.store.updateMetadata(key, updates);\n this.emit('sessionUpdated', { key });\n return { ok: true };\n }\n\n async getSessionMetadata(key: string): Promise<SessionMetadata | null> {\n return this.store.getMetadata(key);\n }\n\n async deleteSession(key: string): Promise<boolean> {\n const result = await this.store.delete(key);\n if (result) {\n this.emit('sessionDeleted', { key });\n }\n return result;\n }\n\n async deleteSessions(keys: string[]): Promise<{ success: string[]; failed: string[] }> {\n const result = await this.store.deleteMany(keys);\n for (const key of result.success) {\n this.emit('sessionDeleted', { key });\n }\n return result;\n }\n\n // ========== Metadata Updates ==========\n\n async renameSession(key: string, name: string): Promise<void> {\n const existing = await this.store.getMetadata(key);\n await this.store.updateMetadata(key, {\n name,\n customData: { ...(existing?.customData ?? {}), titleSource: 'user' },\n });\n this.emit('sessionUpdated', { key, name });\n }\n\n /** Partial metadata update (caller merges nested fields like `customData` when needed). */\n async updateSessionMetadata(key: string, updates: Partial<SessionMetadata>): Promise<void> {\n await this.store.updateMetadata(key, updates);\n this.emit('sessionUpdated', { key });\n }\n\n async tagSession(key: string, tags: string[]): Promise<void> {\n const existing = await this.store.getMetadata(key);\n if (!existing) {\n throw new Error(`Session not found: ${key}`);\n }\n\n // Merge tags, remove duplicates\n const mergedTags = [...new Set([...existing.tags, ...tags])];\n await this.store.updateMetadata(key, { tags: mergedTags });\n this.emit('sessionUpdated', { key, tags: mergedTags });\n }\n\n async untagSession(key: string, tags: string[]): Promise<void> {\n const existing = await this.store.getMetadata(key);\n if (!existing) {\n throw new Error(`Session not found: ${key}`);\n }\n\n const filteredTags = existing.tags.filter((t) => !tags.includes(t));\n await this.store.updateMetadata(key, { tags: filteredTags });\n this.emit('sessionUpdated', { key, tags: filteredTags });\n }\n\n async setSessionTags(key: string, tags: string[]): Promise<void> {\n await this.store.updateMetadata(key, { tags: [...new Set(tags)] });\n this.emit('sessionUpdated', { key, tags });\n }\n\n // ========== Status Management ==========\n\n async archiveSession(key: string): Promise<void> {\n await this.store.archive(key);\n this.emit('sessionArchived', { key });\n }\n\n async unarchiveSession(key: string): Promise<void> {\n await this.store.unarchive(key);\n this.emit('sessionRestored', { key });\n }\n\n async pinSession(key: string): Promise<void> {\n await this.store.pin(key);\n this.emit('sessionPinned', { key });\n }\n\n async unpinSession(key: string): Promise<void> {\n await this.store.unpin(key);\n this.emit('sessionUnpinned', { key });\n }\n\n async setSessionStatus(key: string, status: SessionStatus): Promise<void> {\n await this.store.setStatus(key, status);\n this.emit('sessionStatusChanged', { key, status });\n }\n\n // ========== Search ==========\n\n async searchSessions(query: string): Promise<SessionMetadata[]> {\n const result = await this.store.list({ search: query, limit: 100 });\n return result.items;\n }\n\n async searchInSession(key: string, keyword: string): Promise<Message[]> {\n return this.store.searchInSession(key, keyword);\n }\n\n // ========== Export/Import ==========\n\n async exportSession(key: string, format: ExportFormat): Promise<string> {\n return this.store.exportSession(key, format);\n }\n\n // ========== Statistics ==========\n\n async getStats(): Promise<GlobalSessionStats> {\n return this.store.getStats();\n }\n\n // ========== Maintenance ==========\n\n async archiveOldSessions(olderThanDays: number): Promise<number> {\n const count = await this.store.archiveOld(olderThanDays);\n log.info({ count, olderThanDays }, 'Archived old sessions');\n return count;\n }\n\n // ========== Event Helpers ==========\n\n onSessionCreated(callback: (metadata: SessionMetadata) => void): void {\n this.on('sessionCreated', callback);\n }\n\n onSessionUpdated(callback: (data: { key: string; name?: string; tags?: string[] }) => void): void {\n this.on('sessionUpdated', callback);\n }\n\n onSessionDeleted(callback: (data: { key: string }) => void): void {\n this.on('sessionDeleted', callback);\n }\n\n onSessionArchived(callback: (data: { key: string }) => void): void {\n this.on('sessionArchived', callback);\n }\n\n onSessionRestored(callback: (data: { key: string }) => void): void {\n this.on('sessionRestored', callback);\n }\n\n onSessionPinned(callback: (data: { key: string }) => void): void {\n this.on('sessionPinned', callback);\n }\n\n onSessionUnpinned(callback: (data: { key: string }) => void): void {\n this.on('sessionUnpinned', callback);\n }\n\n onSessionStatusChanged(callback: (data: { key: string; status: SessionStatus }) => void): void {\n this.on('sessionStatusChanged', callback);\n }\n\n onSessionAccessed(callback: (data: { key: string }) => void): void {\n this.on('sessionAccessed', callback);\n }\n\n // ========== Store delegation (messages, compaction) ==========\n\n /** Load messages for a session key */\n async loadMessages(key: string) {\n return this.store.loadMessages(key);\n }\n\n /** Wrapped transcript document (stable id, compaction history); null if missing or not a valid envelope. */\n async loadTranscriptDocument(key: string): Promise<XopcSessionTranscriptV1 | null> {\n return this.store.loadTranscriptDocument(key);\n }\n\n /**\n * Runtime turns must use PiTranscriptManager.appendMessage; this entry point\n * is reserved for compaction, tests, and admin tools.\n */\n async saveMessages(key: string, messages: any[]) {\n return this.store.saveMessages(key, messages);\n }\n\n /**\n * Append `kind: 'context'` transcript row (persisted, excluded from {@link loadMessages} / LLM).\n */\n async appendTranscriptContextEntry(\n key: string,\n entry: Omit<XopcTranscriptContextEntry, 'kind'> & Partial<Pick<XopcTranscriptContextEntry, 'kind'>>,\n ): Promise<void> {\n await this.store.appendTranscriptContextEntry(key, entry);\n this.emit('sessionUpdated', { key });\n }\n\n /** Delete session data */\n async delete(key: string): Promise<void> {\n await this.store.delete(key);\n }\n\n /** Archive transcript and start a new session id for the same key. */\n async resetSession(\n key: string,\n ): Promise<{ sessionId: string; previousSessionId: string } | null> {\n const result = await this.store.reset(key);\n if (result) {\n this.emit('sessionUpdated', { key });\n }\n return result;\n }\n\n /** Token/window stats for a message list */\n getWindowStats(messages: any[]) {\n return this.store.getWindowStats(messages);\n }\n\n /** Prepare compaction run */\n prepareCompaction(key: string, messages: any[], contextWindow: number) {\n return this.store.prepareCompaction(key, messages, contextWindow);\n }\n\n /** Compact session messages */\n compact(\n key: string,\n messages: any[],\n contextWindow: number,\n instructions?: string,\n force?: boolean,\n ): Promise<CompactionResult> {\n return this.store.compact(key, messages, contextWindow, instructions, force);\n }\n\n /** Compaction stats for a session */\n async getCompactionStats(key: string) {\n return this.store.getCompactionStats(key);\n }\n\n /** List pre-compaction transcript snapshots (newest first). */\n listCompactionCheckpoints(key: string) {\n return this.store.listCompactionCheckpoints(key);\n }\n\n getCompactionCheckpointDetail(key: string, checkpointId: string) {\n return this.store.getCompactionCheckpointDetail(key, checkpointId);\n }\n\n restoreCompactionCheckpoint(key: string, checkpointId: string) {\n return this.store.restoreCompactionCheckpoint(key, checkpointId);\n }\n\n /** Estimate token usage for messages */\n async estimateTokenUsage(key: string, messages: any[]): Promise<number> {\n return this.store.estimateTokens(messages);\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"manager.js","names":["EventEmitter"],"sources":["../../../src/session/manager.ts"],"sourcesContent":["// Session manager - high-level session management service\n\nimport EventEmitter from 'events';\nimport { createLogger } from '../utils/logger.js';\nimport { SessionStore } from './store.js';\nimport type {\n SessionMetadata,\n SessionDetail,\n SessionListQuery,\n PaginatedResult,\n GlobalSessionStats,\n ExportFormat,\n SessionStatus,\n} from './types.js';\nimport type { Message } from './types.js';\nimport type { CompactionConfig, CompactionResult } from '../agent/memory/compaction.js';\nimport type { XopcSessionTranscriptV1 } from './transcript-format.js';\nimport type { XopcTranscriptContextEntry } from './session-context-for-llm.js';\nimport { applySessionPatchToMetadata, type SessionPatchBody } from './patch-metadata.js';\nimport type { WindowConfig } from '../agent/memory/window.js';\nimport type { Config } from '../config/schema.js';\n\nconst log = createLogger('SessionIndex');\n\nexport interface SessionIndexConfig {\n config: Config;\n windowConfig?: Partial<WindowConfig>;\n compactionConfig?: Partial<CompactionConfig>;\n}\n\nexport class SessionIndex extends EventEmitter {\n private store: SessionStore;\n\n constructor(config: SessionIndexConfig) {\n super();\n this.store = new SessionStore(\n {\n config: config.config,\n },\n config.windowConfig,\n config.compactionConfig\n );\n }\n\n async initialize(): Promise<void> {\n await this.store.initialize();\n this.emit('ready');\n }\n\n /** Low-level store (e.g. cron resolving weixin delivery from session index). */\n getStore(): SessionStore {\n return this.store;\n }\n\n // ========== CRUD Operations ==========\n\n async listSessions(query?: SessionListQuery): Promise<PaginatedResult<SessionMetadata>> {\n return this.store.list(query);\n }\n\n /**\n * List all subagent sessions.\n * Subagent sessions have keys starting with 'subagent:'.\n */\n async listSubagents(query: SessionListQuery = {}): Promise<PaginatedResult<SessionMetadata>> {\n // Filter for subagent sessions only\n const subagentQuery: SessionListQuery = {\n ...query,\n search: query.search ? `subagent:${query.search}` : 'subagent:',\n };\n \n const result = await this.store.list(subagentQuery);\n \n // Additional filtering to ensure only subagent sessions\n const subagentSessions = result.items.filter((s) => s.key.startsWith('subagent:'));\n \n return {\n ...result,\n items: subagentSessions,\n total: subagentSessions.length,\n hasMore: false, // Simplified for now\n };\n }\n\n async getSession(\n key: string,\n options?: { includeTranscriptSummary?: boolean; includeTranscriptRows?: boolean },\n ): Promise<SessionDetail | null> {\n const session = await this.store.get(key, options);\n if (session) {\n this.emit('sessionAccessed', { key });\n }\n return session;\n }\n\n async getSessionMessagePage(\n key: string,\n options?: {\n offset?: number;\n limit?: number;\n before?: string;\n includeTranscriptSummary?: boolean;\n includeTranscriptRows?: boolean;\n },\n ): Promise<{\n session: SessionDetail;\n pagination: {\n total: number;\n limit: number;\n offset: number;\n hasMore: boolean;\n before?: string;\n nextBeforeCursor?: string;\n };\n } | null> {\n const result = await this.store.getMessagePage(key, options);\n if (result) {\n this.emit('sessionAccessed', { key });\n }\n return result;\n }\n\n /**\n * OpenClaw-style `sessions.patch`: partial metadata (name, tags, customData shallow merge).\n */\n async patchSession(\n key: string,\n patch: SessionPatchBody,\n ): Promise<{ ok: true } | { ok: false; error: string }> {\n const meta = await this.store.getMetadata(key);\n if (!meta) {\n return { ok: false, error: 'Session not found' };\n }\n const updates = applySessionPatchToMetadata(meta, patch);\n if (Object.keys(updates).length === 0) {\n return { ok: true };\n }\n await this.store.updateMetadata(key, updates);\n this.emit('sessionUpdated', { key });\n return { ok: true };\n }\n\n async getSessionMetadata(key: string): Promise<SessionMetadata | null> {\n return this.store.getMetadata(key);\n }\n\n async deleteSession(key: string): Promise<boolean> {\n const result = await this.store.delete(key);\n if (result) {\n this.emit('sessionDeleted', { key });\n }\n return result;\n }\n\n async deleteSessions(keys: string[]): Promise<{ success: string[]; failed: string[] }> {\n const result = await this.store.deleteMany(keys);\n for (const key of result.success) {\n this.emit('sessionDeleted', { key });\n }\n return result;\n }\n\n // ========== Metadata Updates ==========\n\n async renameSession(key: string, name: string): Promise<void> {\n const existing = await this.store.getMetadata(key);\n await this.store.updateMetadata(key, {\n name,\n customData: { ...(existing?.customData ?? {}), titleSource: 'user' },\n });\n this.emit('sessionUpdated', { key, name });\n }\n\n /** Partial metadata update (caller merges nested fields like `customData` when needed). */\n async updateSessionMetadata(key: string, updates: Partial<SessionMetadata>): Promise<void> {\n await this.store.updateMetadata(key, updates);\n this.emit('sessionUpdated', { key });\n }\n\n async tagSession(key: string, tags: string[]): Promise<void> {\n const existing = await this.store.getMetadata(key);\n if (!existing) {\n throw new Error(`Session not found: ${key}`);\n }\n\n // Merge tags, remove duplicates\n const mergedTags = [...new Set([...existing.tags, ...tags])];\n await this.store.updateMetadata(key, { tags: mergedTags });\n this.emit('sessionUpdated', { key, tags: mergedTags });\n }\n\n async untagSession(key: string, tags: string[]): Promise<void> {\n const existing = await this.store.getMetadata(key);\n if (!existing) {\n throw new Error(`Session not found: ${key}`);\n }\n\n const filteredTags = existing.tags.filter((t) => !tags.includes(t));\n await this.store.updateMetadata(key, { tags: filteredTags });\n this.emit('sessionUpdated', { key, tags: filteredTags });\n }\n\n async setSessionTags(key: string, tags: string[]): Promise<void> {\n await this.store.updateMetadata(key, { tags: [...new Set(tags)] });\n this.emit('sessionUpdated', { key, tags });\n }\n\n // ========== Status Management ==========\n\n async archiveSession(key: string): Promise<void> {\n await this.store.archive(key);\n this.emit('sessionArchived', { key });\n }\n\n async unarchiveSession(key: string): Promise<void> {\n await this.store.unarchive(key);\n this.emit('sessionRestored', { key });\n }\n\n async pinSession(key: string): Promise<void> {\n await this.store.pin(key);\n this.emit('sessionPinned', { key });\n }\n\n async unpinSession(key: string): Promise<void> {\n await this.store.unpin(key);\n this.emit('sessionUnpinned', { key });\n }\n\n async setSessionStatus(key: string, status: SessionStatus): Promise<void> {\n await this.store.setStatus(key, status);\n this.emit('sessionStatusChanged', { key, status });\n }\n\n // ========== Search ==========\n\n async searchSessions(query: string): Promise<SessionMetadata[]> {\n const result = await this.store.list({ search: query, limit: 100 });\n return result.items;\n }\n\n async searchInSession(key: string, keyword: string): Promise<Message[]> {\n return this.store.searchInSession(key, keyword);\n }\n\n // ========== Export/Import ==========\n\n async exportSession(key: string, format: ExportFormat): Promise<string> {\n return this.store.exportSession(key, format);\n }\n\n // ========== Statistics ==========\n\n async getStats(): Promise<GlobalSessionStats> {\n return this.store.getStats();\n }\n\n // ========== Maintenance ==========\n\n async archiveOldSessions(olderThanDays: number): Promise<number> {\n const count = await this.store.archiveOld(olderThanDays);\n log.info({ count, olderThanDays }, 'Archived old sessions');\n return count;\n }\n\n // ========== Event Helpers ==========\n\n onSessionCreated(callback: (metadata: SessionMetadata) => void): void {\n this.on('sessionCreated', callback);\n }\n\n onSessionUpdated(callback: (data: { key: string; name?: string; tags?: string[] }) => void): void {\n this.on('sessionUpdated', callback);\n }\n\n onSessionDeleted(callback: (data: { key: string }) => void): void {\n this.on('sessionDeleted', callback);\n }\n\n onSessionArchived(callback: (data: { key: string }) => void): void {\n this.on('sessionArchived', callback);\n }\n\n onSessionRestored(callback: (data: { key: string }) => void): void {\n this.on('sessionRestored', callback);\n }\n\n onSessionPinned(callback: (data: { key: string }) => void): void {\n this.on('sessionPinned', callback);\n }\n\n onSessionUnpinned(callback: (data: { key: string }) => void): void {\n this.on('sessionUnpinned', callback);\n }\n\n onSessionStatusChanged(callback: (data: { key: string; status: SessionStatus }) => void): void {\n this.on('sessionStatusChanged', callback);\n }\n\n onSessionAccessed(callback: (data: { key: string }) => void): void {\n this.on('sessionAccessed', callback);\n }\n\n // ========== Store delegation (messages, compaction) ==========\n\n /** Load messages for a session key */\n async loadMessages(key: string) {\n return this.store.loadMessages(key);\n }\n\n /** Wrapped transcript document (stable id, compaction history); null if missing or not a valid envelope. */\n async loadTranscriptDocument(key: string): Promise<XopcSessionTranscriptV1 | null> {\n return this.store.loadTranscriptDocument(key);\n }\n\n /**\n * Runtime turns must use PiTranscriptManager.appendMessage; this entry point\n * is reserved for compaction, tests, and admin tools.\n */\n async saveMessages(key: string, messages: any[]) {\n return this.store.saveMessages(key, messages);\n }\n\n /**\n * Append `kind: 'context'` transcript row (persisted, excluded from {@link loadMessages} / LLM).\n */\n async appendTranscriptContextEntry(\n key: string,\n entry: Omit<XopcTranscriptContextEntry, 'kind'> & Partial<Pick<XopcTranscriptContextEntry, 'kind'>>,\n ): Promise<void> {\n await this.store.appendTranscriptContextEntry(key, entry);\n this.emit('sessionUpdated', { key });\n }\n\n /** Delete session data */\n async delete(key: string): Promise<void> {\n await this.store.delete(key);\n }\n\n /** Archive transcript and start a new session id for the same key. */\n async resetSession(\n key: string,\n ): Promise<{ sessionId: string; previousSessionId: string } | null> {\n const result = await this.store.reset(key);\n if (result) {\n this.emit('sessionUpdated', { key });\n }\n return result;\n }\n\n /** Token/window stats for a message list */\n getWindowStats(messages: any[]) {\n return this.store.getWindowStats(messages);\n }\n\n /** Prepare compaction run */\n prepareCompaction(key: string, messages: any[], contextWindow: number) {\n return this.store.prepareCompaction(key, messages, contextWindow);\n }\n\n /** Compact session messages */\n compact(\n key: string,\n messages: any[],\n contextWindow: number,\n instructions?: string,\n force?: boolean,\n ): Promise<CompactionResult> {\n return this.store.compact(key, messages, contextWindow, instructions, force);\n }\n\n /** Compaction stats for a session */\n async getCompactionStats(key: string) {\n return this.store.getCompactionStats(key);\n }\n\n /** List pre-compaction transcript snapshots (newest first). */\n listCompactionCheckpoints(key: string) {\n return this.store.listCompactionCheckpoints(key);\n }\n\n getCompactionCheckpointDetail(key: string, checkpointId: string) {\n return this.store.getCompactionCheckpointDetail(key, checkpointId);\n }\n\n restoreCompactionCheckpoint(key: string, checkpointId: string) {\n return this.store.restoreCompactionCheckpoint(key, checkpointId);\n }\n\n /** Estimate token usage for messages */\n async estimateTokenUsage(key: string, messages: any[]): Promise<number> {\n return this.store.estimateTokens(messages);\n }\n}\n"],"mappings":"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"}