@xopcai/xopc 0.0.205 → 0.0.207

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 (208) hide show
  1. package/README.md +7 -7
  2. package/README.zh-CN.md +7 -7
  3. package/dist/browser-ext/manifest.json +1 -1
  4. package/dist/extensions/telegram/xopc.extension.json +1 -1
  5. package/dist/gateway/static/root/assets/{activity-store-DJBadfSX.js → activity-store-BmpM0zwM.js} +1 -1
  6. package/dist/gateway/static/root/assets/{agent-avatar-dicebear-Br6C32BX.js → agent-avatar-dicebear-DhK5wi6_.js} +1 -1
  7. package/dist/gateway/static/root/assets/agents-Bc3Lc-n2.js +68 -0
  8. package/dist/gateway/static/root/assets/{api-B5O7fKXa.js → api-CzaAcDOn.js} +1 -1
  9. package/dist/gateway/static/root/assets/{app-management-settings-panel-Le1vJ1OO.js → app-management-settings-panel-Dqj5G_cd.js} +1 -1
  10. package/dist/gateway/static/root/assets/{appearance-settings-CZlAU60t.js → appearance-settings-Bm1uLGMi.js} +1 -1
  11. package/dist/gateway/static/root/assets/apps-page-BKtwU47-.js +1 -0
  12. package/dist/gateway/static/root/assets/{archive-plugin-CRzXRXPE.js → archive-plugin-CgnzBplN.js} +1 -1
  13. package/dist/gateway/static/root/assets/{attachment-load-CYAAQ6Qi.js → attachment-load-Cuybcmhn.js} +1 -1
  14. package/dist/gateway/static/root/assets/automations-page-ilGeRLDN.js +6 -0
  15. package/dist/gateway/static/root/assets/{binary-plugins-CVR5cUmS.js → binary-plugins-D6BBx6Ps.js} +1 -1
  16. package/dist/gateway/static/root/assets/{block-editor-CFe74rWi.js → block-editor-Dk1c3Spa.js} +46 -46
  17. package/dist/gateway/static/root/assets/browser-settings-page-BCu8AZbs.js +8 -0
  18. package/dist/gateway/static/root/assets/{browser-workflow-inputs-Bd68yluo.js → browser-workflow-inputs-DvfIzCgV.js} +1 -1
  19. package/dist/gateway/static/root/assets/{browser-workflows-page-B0uiDLga.js → browser-workflows-page-DZScuPlF.js} +2 -2
  20. package/dist/gateway/static/root/assets/capabilities-settings-panel-BbWQBtTe.js +7 -0
  21. package/dist/gateway/static/root/assets/{capability-presets-api-BerPMp6f.js → capability-presets-api-hoA8R_J1.js} +1 -1
  22. package/dist/gateway/static/root/assets/capability-presets-settings-panel-BTVU46Yn.js +3 -0
  23. package/dist/gateway/static/root/assets/{channel-recipient-api-D2d21_XA.js → channel-recipient-api-BS8I65NT.js} +1 -1
  24. package/dist/gateway/static/root/assets/channels-settings-BEQsC9a9.js +1 -0
  25. package/dist/gateway/static/root/assets/channels-status-swr-DRwbgtOT.js +1 -0
  26. package/dist/gateway/static/root/assets/chat-terminal-dock-BIPhWBDI.js +36 -0
  27. package/dist/gateway/static/root/assets/chat-terminal-dock-uQUnjRtf.css +1 -0
  28. package/dist/gateway/static/root/assets/{connectors-api-Bq_vUzxP.js → connectors-api-B_78jmvM.js} +1 -1
  29. package/dist/gateway/static/root/assets/connectors-page-w_3kpqbc.js +2 -0
  30. package/dist/gateway/static/root/assets/{cron-expression-DZBxmKGR.js → cron-expression-BBheaBIr.js} +1 -1
  31. package/dist/gateway/static/root/assets/{date-picker-BNHd7HT7.js → date-picker-CDwj7UrT.js} +1 -1
  32. package/dist/gateway/static/root/assets/{dependency-picker-D1kJBknt.js → dependency-picker-Dnrc2qZe.js} +1 -1
  33. package/dist/gateway/static/root/assets/{desktop-pet-Di75oHkC.js → desktop-pet-Bj_vUjXp.js} +1 -1
  34. package/dist/gateway/static/root/assets/{desktop-pet-settings-D6tD1uym.js → desktop-pet-settings-uiCwJJk4.js} +1 -1
  35. package/dist/gateway/static/root/assets/directory-picker-path-field-D0zUQ-TO.js +1 -0
  36. package/dist/gateway/static/root/assets/{extension-debug-page-D91_S7NQ.js → extension-debug-page-_GZ4y2da.js} +1 -1
  37. package/dist/gateway/static/root/assets/{extension-page-DHzmmr_N.js → extension-page-scR96Edg.js} +1 -1
  38. package/dist/gateway/static/root/assets/{extension-settings-page-BpJNtePi.js → extension-settings-page-CILsAwxx.js} +1 -1
  39. package/dist/gateway/static/root/assets/{gateway-config-api-BAzLYTKZ.js → gateway-config-api-984O_4wM.js} +1 -1
  40. package/dist/gateway/static/root/assets/{gateway-config-swr-VVcfd3sG.js → gateway-config-swr-D4hvsdJA.js} +1 -1
  41. package/dist/gateway/static/root/assets/{gateway-settings-C5-aKkTp.js → gateway-settings-aF4eQHo3.js} +1 -1
  42. package/dist/gateway/static/root/assets/{gateway-startup-retry-qAX_T2t2.js → gateway-startup-retry-Deo5-O87.js} +1 -1
  43. package/dist/gateway/static/root/assets/heartbeat-settings-D5DrFWH6.js +1 -0
  44. package/dist/gateway/static/root/assets/home-page-DiMWxngC.js +3 -0
  45. package/dist/gateway/static/root/assets/index-DzKLVgY-.js +85 -0
  46. package/dist/gateway/static/root/assets/index-wR5jX-lw.css +2 -0
  47. package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-fpNjXnJK.js → keyboard-shortcuts-settings-DGmOlNcB.js} +1 -1
  48. package/dist/gateway/static/root/assets/local-app-workbench-page-De8vuwu1.js +2 -0
  49. package/dist/gateway/static/root/assets/{local-apps-page-DBpQIfNd.js → local-apps-page-CzS2sCxg.js} +1 -1
  50. package/dist/gateway/static/root/assets/{locale-store-CbPVxonP.js → locale-store-C7xtkP3D.js} +1 -1
  51. package/dist/gateway/static/root/assets/logs-page-BI9stsVO.js +2 -0
  52. package/dist/gateway/static/root/assets/{management-settings-CiK7Xkvi.js → management-settings-Cpxs43JB.js} +1 -1
  53. package/dist/gateway/static/root/assets/{markdown-split-DVgpcOze.js → markdown-split-CQvFHxUa.js} +1 -1
  54. package/dist/gateway/static/root/assets/{markdown-view-Dl-0_9JR.js → markdown-view-BRwrSbwM.js} +1 -1
  55. package/dist/gateway/static/root/assets/{media-plugins-DMj1lW-n.js → media-plugins-Bs9MsiaM.js} +1 -1
  56. package/dist/gateway/static/root/assets/messages-Dxk5Rzj_.js +3 -0
  57. package/dist/gateway/static/root/assets/{notes-page-DvX1sTlf.js → notes-page-Dux_g6aZ.js} +1 -1
  58. package/dist/gateway/static/root/assets/notes-workbench-CGafcgJ8.js +4 -0
  59. package/dist/gateway/static/root/assets/{preview-open-alternatives-DvsLigha.js → preview-open-alternatives-fvhtN4Y2.js} +1 -1
  60. package/dist/gateway/static/root/assets/{product-open-page-DbCraAI3.js → product-open-page-f_jbg-9N.js} +1 -1
  61. package/dist/gateway/static/root/assets/project-detail-page-C6mNsjYr.js +1 -0
  62. package/dist/gateway/static/root/assets/projects-page-D1G6VIxR.js +1 -0
  63. package/dist/gateway/static/root/assets/remote-access-hub-CIez6X0x.js +1 -0
  64. package/dist/gateway/static/root/assets/{runtime-tools-settings-panel-DzuUglQo.js → runtime-tools-settings-panel-zapSiJrv.js} +1 -1
  65. package/dist/gateway/static/root/assets/{schema-form-plDnazVj.js → schema-form-CFyz8y5v.js} +1 -1
  66. package/dist/gateway/static/root/assets/sessions-page-6irxQjHb.js +1 -0
  67. package/dist/gateway/static/root/assets/settings-advanced-gate-CRb0QTG2.js +1 -0
  68. package/dist/gateway/static/root/assets/{settings-form-section-BwAxX_7e.js → settings-form-section-DCiK4TIq.js} +1 -1
  69. package/dist/gateway/static/root/assets/{settings-loading-skeleton-B3OiTnF9.js → settings-loading-skeleton-DFUJEv4G.js} +1 -1
  70. package/dist/gateway/static/root/assets/{settings-page-DvIWXBvp.js → settings-page-Cnp9Bdd0.js} +1 -1
  71. package/dist/gateway/static/root/assets/{setup-status-panel-DThKKjLV.js → setup-status-panel-BFMGTGBO.js} +1 -1
  72. package/dist/gateway/static/root/assets/{share-preview-page-CFnoGHJb.js → share-preview-page-DA8nA4cz.js} +1 -1
  73. package/dist/gateway/static/root/assets/shares-settings-CaKfvJzQ.js +1 -0
  74. package/dist/gateway/static/root/assets/skill-reload-api-BOBUcYr5.js +1 -0
  75. package/dist/gateway/static/root/assets/{skills-page-B38fY22S.js → skills-page-BJJACxzz.js} +1 -1
  76. package/dist/gateway/static/root/assets/{skills-page.utils-vLIlk1c3.js → skills-page.utils--1-vOg3V.js} +1 -1
  77. package/dist/gateway/static/root/assets/{system-settings-panel-DRV2wljT.js → system-settings-panel-DY0lIaXY.js} +1 -1
  78. package/dist/gateway/static/root/assets/task-detail-page-Ciuwe7AG.js +1 -0
  79. package/dist/gateway/static/root/assets/{theme-store-Bc_eRUev.js → theme-store-DoyRfkoi.js} +1 -1
  80. package/dist/gateway/static/root/assets/{use-autosave-DTu23D9J.js → use-autosave-DzIR5Lxf.js} +1 -1
  81. package/dist/gateway/static/root/assets/{user-context-page-DCwqzN03.js → user-context-page-yf18T_BZ.js} +1 -1
  82. package/dist/gateway/static/root/assets/{voice-api-key-field-CVDMesWc.js → voice-api-key-field-B7MZS8tS.js} +1 -1
  83. package/dist/gateway/static/root/assets/{work-discovery-overlay-cyt93k0V.js → work-discovery-overlay-zyX6yxxF.js} +1 -1
  84. package/dist/gateway/static/root/assets/work-discovery-page-2e5J0sIp.js +1 -0
  85. package/dist/gateway/static/root/assets/workflow-run-setup-panel-Cj1vPWRM.js +3 -0
  86. package/dist/gateway/static/root/assets/workflows-page-D37zWlWY.js +5 -0
  87. package/dist/gateway/static/root/assets/{working-directory-picker-modal-CYWdZUJ5.js → working-directory-picker-modal-Bm7cox3y.js} +1 -1
  88. package/dist/gateway/static/root/index.html +10 -10
  89. package/dist/package.js +1 -1
  90. package/dist/src/agent/agent-manager.d.ts +11 -0
  91. package/dist/src/agent/agent-manager.js +36 -6
  92. package/dist/src/agent/embedded/transcript-runtime.d.ts +2 -1
  93. package/dist/src/agent/embedded/transcript-runtime.js +38 -4
  94. package/dist/src/agent/inbound/inbound-loop.d.ts +1 -1
  95. package/dist/src/agent/memory/compaction-ledger.d.ts +11 -0
  96. package/dist/src/agent/memory/compaction-ledger.js +108 -0
  97. package/dist/src/agent/memory/compaction-serializer.d.ts +2 -0
  98. package/dist/src/agent/memory/compaction-serializer.js +52 -0
  99. package/dist/src/agent/memory/compaction-source-planner.d.ts +20 -0
  100. package/dist/src/agent/memory/compaction-source-planner.js +67 -0
  101. package/dist/src/agent/memory/compaction.d.ts +11 -5
  102. package/dist/src/agent/memory/compaction.js +245 -153
  103. package/dist/src/agent/prompt/sections/behavior.js +1 -1
  104. package/dist/src/agent/prompt/sections/memory-skills.js +4 -2
  105. package/dist/src/agent/prompt/sections/tooling.js +2 -0
  106. package/dist/src/agent/service.d.ts +4 -1
  107. package/dist/src/agent/service.js +12 -0
  108. package/dist/src/agent/tool-manuals/xopc-use.d.ts +1 -1
  109. package/dist/src/agent/tool-manuals/xopc-use.js +1 -1
  110. package/dist/src/agent/tools/factory.js +5 -0
  111. package/dist/src/agent/tools/index.d.ts +1 -0
  112. package/dist/src/agent/tools/index.js +2 -1
  113. package/dist/src/agent/tools/session-recall-tool.d.ts +7 -0
  114. package/dist/src/agent/tools/session-recall-tool.js +82 -0
  115. package/dist/src/agent/tools/xopc-use-tool.js +6 -2
  116. package/dist/src/automations/api/routes.js +8 -0
  117. package/dist/src/automations/domain/index.js +2 -2
  118. package/dist/src/automations/domain/types.d.ts +17 -12
  119. package/dist/src/automations/domain/validation.d.ts +30 -32
  120. package/dist/src/automations/domain/validation.js +8 -10
  121. package/dist/src/automations/draft/automation-draft-prompt.js +9 -5
  122. package/dist/src/automations/draft/automation-draft-validator.d.ts +3 -8
  123. package/dist/src/automations/draft/automation-draft-validator.js +3 -3
  124. package/dist/src/automations/index.js +2 -2
  125. package/dist/src/automations/service/action-executor.js +13 -4
  126. package/dist/src/automations/service/automation-service.d.ts +5 -1
  127. package/dist/src/automations/service/automation-service.js +19 -12
  128. package/dist/src/automations/storage/automation-repository.js +8 -4
  129. package/dist/src/automations/storage/automation-run-repository.d.ts +5 -0
  130. package/dist/src/automations/storage/automation-run-repository.js +24 -8
  131. package/dist/src/automations/storage/index.js +2 -2
  132. package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
  133. package/dist/src/config/agent-profile.js +1 -1
  134. package/dist/src/config/schema.d.ts +1 -0
  135. package/dist/src/gateway/agents-admin.js +1 -1
  136. package/dist/src/gateway/automation-agent-session.d.ts +4 -0
  137. package/dist/src/gateway/automation-agent-session.js +40 -0
  138. package/dist/src/gateway/dreaming-automation-reconciler.js +3 -2
  139. package/dist/src/gateway/heartbeat/service.js +1 -1
  140. package/dist/src/gateway/hono/lib/config-payload.d.ts +1 -0
  141. package/dist/src/gateway/hono/routes/commands-skills.js +36 -2
  142. package/dist/src/gateway/hono/routes/lazy-bundles.js +1 -0
  143. package/dist/src/gateway/service/marketplace-service.d.ts +4 -1
  144. package/dist/src/gateway/service/marketplace-service.js +9 -0
  145. package/dist/src/gateway/service/run-gateway-agent.js +3 -3
  146. package/dist/src/gateway/service.js +19 -2
  147. package/dist/src/heartbeat/index.js +1 -1
  148. package/dist/src/mobile/notification-service.js +7 -4
  149. package/dist/src/session/compaction-types.d.ts +30 -0
  150. package/dist/src/session/compaction-types.js +35 -0
  151. package/dist/src/session/manager.d.ts +3 -0
  152. package/dist/src/session/session-context-for-llm.d.ts +4 -2
  153. package/dist/src/session/session-context-for-llm.js +2 -1
  154. package/dist/src/session/store.d.ts +10 -1
  155. package/dist/src/session/store.js +55 -23
  156. package/dist/src/session/types.d.ts +3 -2
  157. package/dist/src/storage/sqlite/index.d.ts +1 -1
  158. package/dist/src/storage/sqlite/index.js +2 -2
  159. package/dist/src/storage/sqlite/migrations/121_automation_inbox.sql +24 -0
  160. package/dist/src/storage/sqlite/migrations/122_automation_session_projects.sql +18 -0
  161. package/dist/src/storage/sqlite/migrations/123_remove_v2_compaction_boundaries.sql +25 -0
  162. package/dist/src/storage/sqlite/migrations/runner.d.ts +1 -1
  163. package/dist/src/storage/sqlite/migrations/runner.js +3 -3
  164. package/dist/src/storage/sqlite/migrations/runner.ts +1 -1
  165. package/dist/src/storage/sqlite/schema.js +1 -1
  166. package/dist/src/storage/sqlite/transcript-repository.d.ts +24 -1
  167. package/dist/src/storage/sqlite/transcript-repository.js +78 -29
  168. package/dist/src/user-context/config.d.ts +4 -0
  169. package/dist/src/user-context/config.js +2 -0
  170. package/package.json +4 -3
  171. package/skills/THIRD_PARTY_NOTICES.md +1 -1
  172. package/skills/engineering/define-task/SKILL.md +48 -0
  173. package/skills/engineering/define-task/references/task-contract-rubric.md +15 -0
  174. package/dist/gateway/static/root/assets/agents-DnFIy8Ye.js +0 -68
  175. package/dist/gateway/static/root/assets/apps-page-CONlVc-f.js +0 -1
  176. package/dist/gateway/static/root/assets/automations-page-DuG69tIj.js +0 -6
  177. package/dist/gateway/static/root/assets/browser-settings-page-Cvt-8fqE.js +0 -8
  178. package/dist/gateway/static/root/assets/capabilities-settings-panel-yk3QkGBP.js +0 -7
  179. package/dist/gateway/static/root/assets/capability-presets-settings-panel-DJjVOCJY.js +0 -3
  180. package/dist/gateway/static/root/assets/channels-settings-CaNnYUQo.js +0 -1
  181. package/dist/gateway/static/root/assets/channels-status-swr-CZ5P9jbB.js +0 -1
  182. package/dist/gateway/static/root/assets/connectors-page-DTpCnOsQ.js +0 -2
  183. package/dist/gateway/static/root/assets/directory-picker-path-field-Ly0TUflq.js +0 -1
  184. package/dist/gateway/static/root/assets/heartbeat-settings-CMZr1_Op.js +0 -1
  185. package/dist/gateway/static/root/assets/home-page-CBG9Bk-1.js +0 -3
  186. package/dist/gateway/static/root/assets/index-BBw9QL0p.js +0 -85
  187. package/dist/gateway/static/root/assets/index-Dm-cvIpl.css +0 -2
  188. package/dist/gateway/static/root/assets/local-app-workbench-page-Bi_0Sknt.js +0 -2
  189. package/dist/gateway/static/root/assets/logs-page-BmXcJCKz.js +0 -2
  190. package/dist/gateway/static/root/assets/messages-9zCa8KkW.js +0 -3
  191. package/dist/gateway/static/root/assets/notes-workbench-CMyosgjY.js +0 -4
  192. package/dist/gateway/static/root/assets/project-detail-page-DkS-kbpj.js +0 -1
  193. package/dist/gateway/static/root/assets/projects-page-B3NxP6S4.js +0 -1
  194. package/dist/gateway/static/root/assets/remote-access-hub-DwhrMhjl.js +0 -1
  195. package/dist/gateway/static/root/assets/sessions-page-BOfXXmBL.js +0 -1
  196. package/dist/gateway/static/root/assets/settings-advanced-gate-sPrZfZVR.js +0 -1
  197. package/dist/gateway/static/root/assets/shares-settings-Dvl13Udt.js +0 -1
  198. package/dist/gateway/static/root/assets/skill-reload-api-D9elkZOz.js +0 -1
  199. package/dist/gateway/static/root/assets/task-detail-page-Xd8PlB24.js +0 -1
  200. package/dist/gateway/static/root/assets/work-discovery-page--DTi90d5.js +0 -1
  201. package/dist/gateway/static/root/assets/workflow-run-setup-panel-DrdcfX_N.js +0 -3
  202. package/dist/gateway/static/root/assets/workflows-page-DXyButkm.js +0 -5
  203. package/dist/src/agent/memory/compaction-planner.d.ts +0 -16
  204. package/dist/src/agent/memory/compaction-planner.js +0 -168
  205. package/dist/src/agent/memory/summary-generator.d.ts +0 -46
  206. package/dist/src/agent/memory/summary-generator.js +0 -229
  207. package/skills/engineering/define-goal/SKILL.md +0 -41
  208. package/skills/engineering/define-goal/references/objective-rubric.md +0 -12
@@ -6,6 +6,7 @@
6
6
  * {@link buildSessionContextForLlm} first (or use {@link SessionStore.loadMessages}, which already does).
7
7
  */
8
8
  import type { AgentMessage } from '@earendil-works/pi-agent-core';
9
+ import { type CompactionAudit, type CompactionHandover } from './compaction-types.js';
9
10
  /** Persisted-only row: never sent to the model as a chat message. */
10
11
  export interface XopcTranscriptContextEntry {
11
12
  kind: 'context';
@@ -73,15 +74,16 @@ export interface XopcTranscriptCompactionEntry {
73
74
  type: 'compaction';
74
75
  at: string;
75
76
  baseSeq: number;
76
- plannerVersion: number;
77
+ plannerVersion: 3;
77
78
  summaryModelRef: string;
78
79
  qualityAudit: 'passed' | 'disabled';
80
+ handover: CompactionHandover;
81
+ audit: CompactionAudit;
79
82
  summary: string;
80
83
  messages: AgentMessage[];
81
84
  firstKeptIndex: number;
82
85
  tokensBefore: number;
83
86
  tokensAfter: number;
84
- restoredFromCompactionId?: string;
85
87
  }
86
88
  /** Persisted label change for a transcript entry. */
87
89
  export interface XopcTranscriptLabelEntry {
@@ -1,3 +1,4 @@
1
+ import { isCompactionAudit, isCompactionHandover } from "./compaction-types.js";
1
2
  //#region src/session/session-context-for-llm.ts
2
3
  function isTranscriptContextEntry(x) {
3
4
  if (!x || typeof x !== "object") return false;
@@ -24,7 +25,7 @@ function isTranscriptSummaryMessageEntry(x) {
24
25
  function isTranscriptCompactionEntry(x) {
25
26
  if (!x || typeof x !== "object") return false;
26
27
  const row = x;
27
- return row.type === "compaction" && typeof row.at === "string" && typeof row.baseSeq === "number" && Number.isInteger(row.baseSeq) && typeof row.plannerVersion === "number" && Number.isInteger(row.plannerVersion) && typeof row.summaryModelRef === "string" && (row.qualityAudit === "passed" || row.qualityAudit === "disabled") && typeof row.summary === "string" && Array.isArray(row.messages) && typeof row.firstKeptIndex === "number" && typeof row.tokensBefore === "number" && typeof row.tokensAfter === "number";
28
+ return row.type === "compaction" && typeof row.at === "string" && typeof row.baseSeq === "number" && Number.isInteger(row.baseSeq) && row.plannerVersion === 3 && typeof row.summaryModelRef === "string" && (row.qualityAudit === "passed" || row.qualityAudit === "disabled") && typeof row.summary === "string" && isCompactionHandover(row.handover) && isCompactionAudit(row.audit) && Array.isArray(row.messages) && typeof row.firstKeptIndex === "number" && typeof row.tokensBefore === "number" && typeof row.tokensAfter === "number";
28
29
  }
29
30
  function isTranscriptLabelEntry(x) {
30
31
  if (!x || typeof x !== "object") return false;
@@ -32,11 +32,13 @@ export declare class SessionStore {
32
32
  private window;
33
33
  private compactor;
34
34
  private compactionHooks;
35
+ private readonly compactionTails;
35
36
  constructor(options: SessionStoreOptions, windowConfig?: Partial<WindowConfig>, compactionConfig?: Partial<CompactionConfig>);
36
37
  setCompactionHooks(hooks: SessionCompactionHooks): void;
37
38
  private runCompactionHook;
38
39
  private resolveWorkspaceCwd;
39
40
  private runStoreMutation;
41
+ private runCompactionExclusive;
40
42
  initialize(): Promise<void>;
41
43
  getSessionsRoot(): string;
42
44
  resolveTranscriptPath(sessionKey: string, options?: {
@@ -142,12 +144,15 @@ export declare class SessionStore {
142
144
  tool: number;
143
145
  needsTrim: boolean;
144
146
  };
145
- applyCompaction(key: string, messages: AgentMessage[], result: CompactionResult): Promise<AgentMessage[]>;
147
+ applyCompaction(key: string, result: CompactionResult, expectedSnapshot?: import("../storage/sqlite/transcript-repository.js").CompactionSourceSnapshot): Promise<AgentMessage[]>;
146
148
  compact(key: string, messages: AgentMessage[], model: Model<Api>, instructions?: string, force?: boolean, executionOptions?: CompactionExecutionOptions): Promise<CompactionResult>;
147
149
  getCompactionStats(key: string): Promise<{
148
150
  compactionCount: number;
149
151
  totalTokensBefore: number;
150
152
  totalTokensAfter: number;
153
+ auditPassedCount: number;
154
+ auditDegradedCount: number;
155
+ auditMissingItemsFound: number;
151
156
  lastCompactionAt: string;
152
157
  }>;
153
158
  listCompactionBoundaries(key: string): Promise<CompactionBoundarySummary[]>;
@@ -158,6 +163,10 @@ export declare class SessionStore {
158
163
  }): Promise<AgentMessage[]>;
159
164
  estimateTokenUsage(_key: string, messages: AgentMessage[]): Promise<number>;
160
165
  searchInSession(key: string, keyword: string): Promise<Message[]>;
166
+ recallSession(key: string, query: string, options?: {
167
+ limit?: number;
168
+ beforeSeq?: number;
169
+ }): import("../storage/sqlite/transcript-repository.js").SessionTranscriptRecallMatch[];
161
170
  exportSession(key: string, format: ExportFormat): Promise<string>;
162
171
  importSessionExport(targetKey: string, jsonContent: string): Promise<{
163
172
  sessionKey: string;
@@ -6,7 +6,7 @@ import "./types.js";
6
6
  import { buildSessionContextForLlm, buildSessionDisplayMessages, isRuntimeOnlyTranscriptMessage, isTranscriptCompactionEntry, mergeLlmMessagesPreservingContextRows, transcriptRowsFromJsonArray } from "./session-context-for-llm.js";
7
7
  import { estimateTokensFromMessages } from "../storage/sqlite/row-mappers.js";
8
8
  import { deleteSessionRecord, ensureSessionRecord, findSessionKeyBySessionId, getGlobalSessionStats, getSessionMetadata, listSessionMetadata, listSessionsByAgent, patchSessionMetadata, resetSessionRecord } from "../storage/sqlite/session-repository.js";
9
- import { appendCompactionBoundary, appendTranscriptEntry, listCompactionBoundaries, loadLlmMessagesForSession, loadTranscriptHistoryRowsForSession, loadTranscriptRowsForSession, paginateTranscriptMessages, replaceTranscriptRows, restoreBeforeCompactionBoundary } from "../storage/sqlite/transcript-repository.js";
9
+ import { appendCompactionBoundaryIfUnchanged, appendTranscriptEntry, listCompactionBoundaries, loadCompactionSourceSnapshot, loadLlmMessagesForSession, loadTranscriptHistoryRowsForSession, loadTranscriptRowsForSession, paginateTranscriptMessages, replaceTranscriptRows, restoreBeforeCompactionBoundary, searchSessionTranscript } from "../storage/sqlite/transcript-repository.js";
10
10
  import "../storage/sqlite/index.js";
11
11
  import { resolveEffectiveAgentProfileForSession } from "../config/agent-profile.js";
12
12
  import { readPostCompactionContext } from "../agent/reply/post-compaction-context.js";
@@ -35,6 +35,7 @@ var SessionStore = class {
35
35
  window;
36
36
  compactor;
37
37
  compactionHooks = {};
38
+ compactionTails = /* @__PURE__ */ new Map();
38
39
  constructor(options, windowConfig, compactionConfig) {
39
40
  this.options = options;
40
41
  this.window = new SlidingWindow(windowConfig);
@@ -64,6 +65,21 @@ var SessionStore = class {
64
65
  async runStoreMutation(fn) {
65
66
  return fn();
66
67
  }
68
+ async runCompactionExclusive(sessionKey, fn) {
69
+ const previous = this.compactionTails.get(sessionKey) ?? Promise.resolve();
70
+ let release;
71
+ const current = new Promise((resolve) => {
72
+ release = resolve;
73
+ });
74
+ this.compactionTails.set(sessionKey, current);
75
+ await previous;
76
+ try {
77
+ return await fn();
78
+ } finally {
79
+ release();
80
+ if (this.compactionTails.get(sessionKey) === current) this.compactionTails.delete(sessionKey);
81
+ }
82
+ }
67
83
  async initialize() {
68
84
  requireXopcDatabase();
69
85
  log.debug("Session store initialized (SQLite)");
@@ -297,12 +313,13 @@ var SessionStore = class {
297
313
  plannerVersion: row.plannerVersion,
298
314
  summaryModelRef: row.summaryModelRef,
299
315
  qualityAudit: row.qualityAudit,
316
+ handover: row.handover,
317
+ audit: row.audit,
300
318
  summary: row.summary,
301
319
  messages: row.messages,
302
320
  firstKeptIndex: row.firstKeptIndex,
303
321
  tokensBefore: row.tokensBefore,
304
- tokensAfter: row.tokensAfter,
305
- restoredFromCompactionId: row.restoredFromCompactionId
322
+ tokensAfter: row.tokensAfter
306
323
  });
307
324
  return {
308
325
  type: "xopc_session_transcript",
@@ -419,21 +436,25 @@ var SessionStore = class {
419
436
  getWindowStats(messages) {
420
437
  return this.window.getStats(messages);
421
438
  }
422
- async applyCompaction(key, messages, result) {
423
- const compacted = this.compactor.applyCompaction(messages, result);
439
+ async applyCompaction(key, result, expectedSnapshot = loadCompactionSourceSnapshot(key)) {
440
+ if (!expectedSnapshot) throw new Error(`Session not found: ${key}`);
441
+ if (!result.compacted || !result.handover || !result.audit) throw new Error("Cannot persist an incomplete compaction result");
442
+ const compacted = result.messages;
424
443
  return this.runStoreMutation(async () => {
425
- appendCompactionBoundary(key, {
444
+ if (!appendCompactionBoundaryIfUnchanged(key, expectedSnapshot, {
426
445
  type: "compaction",
427
446
  at: (/* @__PURE__ */ new Date()).toISOString(),
428
- plannerVersion: result.plannerVersion ?? 2,
447
+ plannerVersion: 3,
429
448
  summaryModelRef: result.summaryModelRef ?? "unknown",
430
449
  qualityAudit: result.qualityAudit ?? "disabled",
450
+ handover: result.handover,
451
+ audit: result.audit,
431
452
  summary: result.summary,
432
453
  messages: compacted,
433
454
  firstKeptIndex: result.firstKeptIndex,
434
455
  tokensBefore: result.tokensBefore,
435
456
  tokensAfter: result.tokensAfter
436
- });
457
+ })) throw new Error(`Session changed while compaction was running: ${key}`);
437
458
  log.info({
438
459
  key,
439
460
  tokensBefore: result.tokensBefore,
@@ -445,23 +466,27 @@ var SessionStore = class {
445
466
  });
446
467
  }
447
468
  async compact(key, messages, model, instructions, force, executionOptions) {
448
- const tokenCount = this.estimateTokens(messages);
449
- await this.runCompactionHook("before", {
450
- sessionKey: key,
451
- messageCount: messages.length,
452
- tokenCount
453
- });
454
- const result = await this.compactor.compact(messages, model, instructions, force, executionOptions);
455
- if (result.compacted) {
456
- const compacted = await this.applyCompaction(key, messages, result);
457
- await this.runCompactionHook("after", {
469
+ return this.runCompactionExclusive(key, async () => {
470
+ const snapshot = loadCompactionSourceSnapshot(key);
471
+ if (!snapshot) throw new Error(`Session not found: ${key}`);
472
+ const tokenCount = this.estimateTokens(messages);
473
+ await this.runCompactionHook("before", {
458
474
  sessionKey: key,
459
- messageCount: compacted.length,
460
- tokenCount: result.tokensAfter,
461
- compactedCount: Math.max(0, Math.min(messages.length, result.firstKeptIndex))
475
+ messageCount: messages.length,
476
+ tokenCount
462
477
  });
463
- }
464
- return result;
478
+ const result = await this.compactor.compact(snapshot.entries, model, instructions, force, executionOptions);
479
+ if (result.compacted) {
480
+ const compacted = await this.applyCompaction(key, result, snapshot);
481
+ await this.runCompactionHook("after", {
482
+ sessionKey: key,
483
+ messageCount: compacted.length,
484
+ tokenCount: result.tokensAfter,
485
+ compactedCount: Math.max(0, Math.min(messages.length, result.firstKeptIndex))
486
+ });
487
+ }
488
+ return result;
489
+ });
465
490
  }
466
491
  async getCompactionStats(key) {
467
492
  if (!await this.getMetadata(key)) return void 0;
@@ -470,6 +495,9 @@ var SessionStore = class {
470
495
  compactionCount: boundaries.length,
471
496
  totalTokensBefore: boundaries.reduce((sum, boundary) => sum + boundary.tokensBefore, 0),
472
497
  totalTokensAfter: boundaries.reduce((sum, boundary) => sum + boundary.tokensAfter, 0),
498
+ auditPassedCount: boundaries.filter((boundary) => boundary.audit.status === "passed").length,
499
+ auditDegradedCount: boundaries.filter((boundary) => boundary.audit.status === "degraded").length,
500
+ auditMissingItemsFound: boundaries.reduce((sum, boundary) => sum + boundary.audit.missingItemsFound, 0),
473
501
  lastCompactionAt: boundaries[0]?.createdAt
474
502
  };
475
503
  }
@@ -498,6 +526,10 @@ var SessionStore = class {
498
526
  const q = keyword.toLowerCase();
499
527
  return this.convertMessages(messages.filter((m) => this.extractTextContent(this.messageContent(m)).toLowerCase().includes(q)));
500
528
  }
529
+ recallSession(key, query, options) {
530
+ requireXopcDatabase();
531
+ return searchSessionTranscript(key, query, options);
532
+ }
501
533
  async exportSession(key, format) {
502
534
  const metadata = await this.getMetadata(key);
503
535
  if (!metadata) throw new Error(`Session not found: ${key}`);
@@ -1,3 +1,4 @@
1
+ import type { CompactionAudit } from './compaction-types.js';
1
2
  import type { TranscriptStoredRow } from './session-context-for-llm.js';
2
3
  export interface Message {
3
4
  role: 'system' | 'user' | 'assistant' | 'tool' | 'toolResult';
@@ -174,7 +175,7 @@ export interface SessionExport {
174
175
  /** Full on-disk rows (LLM + `kind: 'context'`) for audit / round-trip. */
175
176
  transcriptRows: TranscriptStoredRow[];
176
177
  }
177
- /** Append-only context boundary produced by compaction or logical restoration. */
178
+ /** Append-only context boundary produced by compaction. */
178
179
  export interface CompactionBoundarySummary {
179
180
  id: string;
180
181
  seq: number;
@@ -183,5 +184,5 @@ export interface CompactionBoundarySummary {
183
184
  tokensBefore: number;
184
185
  tokensAfter: number;
185
186
  summaryPreview: string;
186
- restoredFromCompactionId?: string;
187
+ audit: CompactionAudit;
187
188
  }
@@ -20,7 +20,7 @@ export { buildRelationshipPrompt, getRelationshipSettings, isProactiveSupportAll
20
20
  export { buildDefaultSessionMetadata, type SessionMetadataSeed, } from './session-metadata.js';
21
21
  export { buildGlobalSessionStats, classifyStoredRow, estimateTokensFromMessages, extractFtsContent, metadataToSessionInsert, sessionConfigRowToConfig, sessionRowToMetadata, transcriptEntryRowToStoredRow, type SessionConfigRow, type SessionRow, type TranscriptEntryRow, } from './row-mappers.js';
22
22
  export { deleteSessionRecord, ensureSessionRecord, getCurrentSessionId, getGlobalSessionStats, findSessionKeyBySessionId, getSessionPersistedLevels, getSessionMetadata, incrementSessionStatsOnAppend, listSessionMetadata, listSessionsByAgent, patchSessionMetadata, resetSessionRecord, resolveSessionAgentId, updateSessionStats, } from './session-repository.js';
23
- export { appendCompactionBoundary, appendTranscriptEntry, listCompactionBoundaries, loadLlmMessagesForSession, loadTranscriptHistoryRowsForSession, loadTranscriptRows, loadTranscriptRowsForSession, paginateTranscriptMessages, replaceTranscriptRows, restoreBeforeCompactionBoundary, } from './transcript-repository.js';
23
+ export { appendCompactionBoundaryIfUnchanged, appendTranscriptEntry, listCompactionBoundaries, loadLlmMessagesForSession, loadTranscriptHistoryRowsForSession, loadTranscriptRows, loadTranscriptRowsForSession, loadCompactionSourceSnapshot, paginateTranscriptMessages, replaceTranscriptRows, restoreBeforeCompactionBoundary, searchSessionTranscript, type CompactionSourceSnapshot, type SessionTranscriptRecallMatch, type TranscriptSourceEntry, } from './transcript-repository.js';
24
24
  export { deleteNoteRecord, getNoteRecord, listNoteRecords, upsertNoteRecord, } from './notes-repository.js';
25
25
  export { deleteNoteAgentContextRecord, getNoteAgentContextRecord, upsertNoteAgentContextRecord, type NoteAgentContextRecord, } from './note-agent-context-repository.js';
26
26
  export { appendMemorySignal, appendMemoryTraceEvent, deleteMemoryRecord, getMemoryProviderState, getMemoryTurnFeedback, getMemoryRecord, hasUnresolvedMemoryConflict, listMemorySignals, listMemoryTraceEvents, listMemoryRecords, markMemoryRecordsConflicted, searchMemoryRecords, setMemoryRecordStatus, setMemoryProviderState, setMemoryTurnFeedback, summarizeMemoryRecallFeedback, upsertMemoryRecord, type AppendMemorySignalInput, type AppendMemoryTraceEventInput, type ListMemoryRecordsOptions, type MemoryRecallFeedbackSummary, type MemorySignalRowPayload, type MemoryFeedback, type MemoryFeedbackRating, type MemoryTraceEventPayload, type SearchMemoryRecordsOptions, type SetMemoryTurnFeedbackInput, type UpsertMemoryRecordInput, } from './memory-records-repository.js';
@@ -21,7 +21,7 @@ import { buildGlobalSessionStats, classifyStoredRow, estimateTokensFromMessages,
21
21
  import { deleteSessionRecord, ensureSessionRecord, findSessionKeyBySessionId, getCurrentSessionId, getGlobalSessionStats, getSessionMetadata, getSessionPersistedLevels, incrementSessionStatsOnAppend, listSessionMetadata, listSessionsByAgent, patchSessionMetadata, resetSessionRecord, resolveSessionAgentId, updateSessionStats } from "./session-repository.js";
22
22
  import { getSessionTaskPlan, setSessionTaskPlan } from "./session-task-plan-repository.js";
23
23
  import { buildRelationshipPrompt, getRelationshipSettings, isProactiveSupportAllowed, updateRelationshipSettings } from "./relationship-settings-repository.js";
24
- import { appendCompactionBoundary, appendTranscriptEntry, listCompactionBoundaries, loadLlmMessagesForSession, loadTranscriptHistoryRowsForSession, loadTranscriptRows, loadTranscriptRowsForSession, paginateTranscriptMessages, replaceTranscriptRows, restoreBeforeCompactionBoundary } from "./transcript-repository.js";
24
+ import { appendCompactionBoundaryIfUnchanged, appendTranscriptEntry, listCompactionBoundaries, loadCompactionSourceSnapshot, loadLlmMessagesForSession, loadTranscriptHistoryRowsForSession, loadTranscriptRows, loadTranscriptRowsForSession, paginateTranscriptMessages, replaceTranscriptRows, restoreBeforeCompactionBoundary, searchSessionTranscript } from "./transcript-repository.js";
25
25
  import { deleteNoteRecord, getNoteRecord, listNoteRecords, upsertNoteRecord } from "./notes-repository.js";
26
26
  import { deleteNoteAgentContextRecord, getNoteAgentContextRecord, upsertNoteAgentContextRecord } from "./note-agent-context-repository.js";
27
27
  import { attachMemoryEvidence, claimKnowledgeSourceItems, completeKnowledgeSourceItemSynthesis, deleteMemoryEvidenceForRecord, finishKnowledgeSyncRun, getKnowledgeConsumerWatermark, getKnowledgeSourceCursor, getKnowledgeSourceItem, listKnowledgeSourceChanges, listKnowledgeSourceItems, listKnowledgeSyncRuns, listMemoryEvidence, pruneBoundedKnowledgeSourceItems, setKnowledgeConsumerWatermark, setKnowledgeSourceCursor, setKnowledgeSourceItemSynthesisStatus, startKnowledgeSyncRun, upsertKnowledgeSourceItems } from "./knowledge-repository.js";
@@ -32,4 +32,4 @@ import { appendConnectorExecutionAudit, claimConnectorWebhookDelivery, completeC
32
32
  import { getConnectorAccount, listConnectorAccounts, reconcileConnectorAccount, refreshConnectorAccountCurrent } from "./connector-account-repository.js";
33
33
  import { getConnectorSyncPolicy, getConnectorSyncPolicyForConnection, listConnectorSyncPolicies, upsertConnectorSyncPolicy } from "./connector-sync-policy-repository.js";
34
34
  import { getUserTrustPolicy, setUserTrustPolicy } from "./user-trust-repository.js";
35
- export { COMPOSER_INPUT_HISTORY_LIMIT, DatabaseSchemaMigrationGapError, DatabaseSchemaTooNewError, SCHEMA_META_SCHEMA_VERSION_KEY, XOPC_DB_BASELINE_SCHEMA_VERSION, XOPC_DB_FILENAME, XOPC_DB_SCHEMA_VERSION, acknowledgeHomeAttention, appendCompactionBoundary, appendComposerInputHistory, appendConnectorExecutionAudit, appendMemorySignal, appendMemoryTraceEvent, appendTranscriptEntry, applyPendingMigrations, attachMemoryEvidence, bindEndpointPrincipal, buildDefaultSessionMetadata, buildGlobalSessionStats, buildRelationshipPrompt, cancelQueuedSessionInput, claimConnectorWebhookDelivery, claimKnowledgeSourceItems, claimNextConnectorLearningJob, claimNextSessionInput, classifyStoredRow, clearComposerInputHistory, closeXopcDatabase, completeConnectorWebhookDelivery, completeKnowledgeSourceItemSynthesis, consumeConnectorApproval, consumeContextConsent, createCollaborationRule, createConnectorApproval, createContextEvidence, createEndpointPrincipal, createObjectLinkRecord, createUnderstanding, decideConnectorApproval, decideContextConsent, deleteCollaborationRule, deleteConnectorConnection, deleteConnectorInstallation, deleteMemoryEvidenceForRecord, deleteMemoryRecord, deleteNoteAgentContextRecord, deleteNoteRecord, deleteObjectLinkRecord, deleteSessionConfig, deleteSessionRecord, deleteUnderstanding, discoverSqlMigrations, enqueueConnectorLearningJob, ensureContextConsent, ensureSessionRecord, ensureXopcDatabaseSchema, estimateTokensFromMessages, extractFtsContent, findSessionInput, findSessionKeyBySessionId, finishContextConsolidationRun, finishEndpointToolInvocationAudit, finishKnowledgeSyncRun, finishSessionInputRun, getActivityEventRecord, getCachedConnectorCatalogEntry, getCollaborationRule, getConnectorAccount, getConnectorApproval, getConnectorConnection, getConnectorInstallation, getConnectorSyncPolicy, getConnectorSyncPolicyForConnection, getContextConsolidationRun, getCurrentSessionId, getEndpointPrincipal, getGlobalSessionStats, getInteractionState, getKnowledgeConsumerWatermark, getKnowledgeSourceCursor, getKnowledgeSourceItem, getMemoryProviderState, getMemoryRecord, getMemoryTurnFeedback, getNoteAgentContextRecord, getNoteRecord, getRelationshipSettings, getSessionConfig, getSessionInputState, getSessionMetadata, getSessionPersistedLevels, getSessionTaskPlan, getSqliteDatabase, getTurnPersonalization, getUnderstanding, getUserProfile, getUserTrustPolicy, getXopcDatabase, hasContextConsent, hasSessionConfig, hasUnresolvedMemoryConflict, incrementSessionStatsOnAppend, insertSessionInput, inspectSchemaMigrationStatus, isHomeAttentionAcknowledged, isProactiveSupportAllowed, isUnderstandingSuppressed, isXopcDatabaseOpen, linkUnderstandingEvidence, listActivityRecords, listCachedConnectorCatalogEntries, listCollaborationRules, listCompactionBoundaries, listComposerInputHistory, listConnectorAccounts, listConnectorActionMetadata, listConnectorApprovals, listConnectorConnections, listConnectorExecutionAudit, listConnectorInstallations, listConnectorLearningJobs, listConnectorSyncPolicies, listContextConsolidationDecisions, listContextConsolidationRuns, listEndpointPrincipals, listEndpointToolInvocationAudits, listKnowledgeSourceChanges, listKnowledgeSourceItems, listKnowledgeSyncRuns, listMemoryEvidence, listMemoryRecords, listMemorySignals, listMemoryTraceEvents, listNoteRecords, listObjectActivityRecords, listObjectLinkRecords, listProjectActivityRecords, listRegisteredMigrationTargets, listSessionMetadata, listSessionsByAgent, listUnderstandingEvidence, listUnderstandings, loadLlmMessagesForSession, loadTranscriptHistoryRowsForSession, loadTranscriptRows, loadTranscriptRowsForSession, markMemoryRecordsConflicted, metadataToSessionInsert, mutateQueuedSessionInput, openXopcDatabase, paginateTranscriptMessages, patchSessionMetadata, pruneBoundedKnowledgeSourceItems, readSchemaVersion, readSchemaVersionForTest, reconcileConnectorAccount, recordActivityEvent, recordContextConsolidationDecision, recordContextFeedback, recordContextRun, recoverSessionInputState, recoverStaleConnectorLearningJobs, refreshConnectorAccountCurrent, rejectUnderstanding, releaseConnectorWebhookDelivery, replaceConnectorCatalogEntries, replaceTranscriptRows, requireXopcDatabase, resetSessionRecord, resetXopcDatabaseSingletonForTest, resolveMigrationsDir, resolveSessionAgentId, resolveXopcDatabasePath, restoreBeforeCompactionBoundary, reviseCollaborationRule, reviseUnderstanding, revokeEndpointPrincipal, runSqliteWriteTransaction, searchMemoryRecords, sessionConfigRowToConfig, sessionRowToMetadata, setCollaborationRuleStatus, setConnectorLearningPaused, setInteractionState, setKnowledgeConsumerWatermark, setKnowledgeSourceCursor, setKnowledgeSourceItemSynthesisStatus, setMemoryProviderState, setMemoryRecordStatus, setMemoryTurnFeedback, setSessionConfig, setSessionInputStatus, setSessionTaskPlan, setUnderstandingStatus, setUserTrustPolicy, startContextConsolidationRun, startEndpointToolInvocationAudit, startKnowledgeSyncRun, summarizeMemoryRecallFeedback, summarizeUserUnderstandingQuality, touchEndpointPrincipal, transcriptEntryRowToStoredRow, updateConnectorLearningJob, updateInteractionStateFromMessage, updateRelationshipSettings, updateSessionConfig, updateSessionStats, updateUserProfile, upsertConnectorActionMetadata, upsertConnectorCatalogEntry, upsertConnectorConnection, upsertConnectorInstallation, upsertConnectorSyncPolicy, upsertKnowledgeSourceItems, upsertMemoryRecord, upsertNoteAgentContextRecord, upsertNoteRecord };
35
+ export { COMPOSER_INPUT_HISTORY_LIMIT, DatabaseSchemaMigrationGapError, DatabaseSchemaTooNewError, SCHEMA_META_SCHEMA_VERSION_KEY, XOPC_DB_BASELINE_SCHEMA_VERSION, XOPC_DB_FILENAME, XOPC_DB_SCHEMA_VERSION, acknowledgeHomeAttention, appendCompactionBoundaryIfUnchanged, appendComposerInputHistory, appendConnectorExecutionAudit, appendMemorySignal, appendMemoryTraceEvent, appendTranscriptEntry, applyPendingMigrations, attachMemoryEvidence, bindEndpointPrincipal, buildDefaultSessionMetadata, buildGlobalSessionStats, buildRelationshipPrompt, cancelQueuedSessionInput, claimConnectorWebhookDelivery, claimKnowledgeSourceItems, claimNextConnectorLearningJob, claimNextSessionInput, classifyStoredRow, clearComposerInputHistory, closeXopcDatabase, completeConnectorWebhookDelivery, completeKnowledgeSourceItemSynthesis, consumeConnectorApproval, consumeContextConsent, createCollaborationRule, createConnectorApproval, createContextEvidence, createEndpointPrincipal, createObjectLinkRecord, createUnderstanding, decideConnectorApproval, decideContextConsent, deleteCollaborationRule, deleteConnectorConnection, deleteConnectorInstallation, deleteMemoryEvidenceForRecord, deleteMemoryRecord, deleteNoteAgentContextRecord, deleteNoteRecord, deleteObjectLinkRecord, deleteSessionConfig, deleteSessionRecord, deleteUnderstanding, discoverSqlMigrations, enqueueConnectorLearningJob, ensureContextConsent, ensureSessionRecord, ensureXopcDatabaseSchema, estimateTokensFromMessages, extractFtsContent, findSessionInput, findSessionKeyBySessionId, finishContextConsolidationRun, finishEndpointToolInvocationAudit, finishKnowledgeSyncRun, finishSessionInputRun, getActivityEventRecord, getCachedConnectorCatalogEntry, getCollaborationRule, getConnectorAccount, getConnectorApproval, getConnectorConnection, getConnectorInstallation, getConnectorSyncPolicy, getConnectorSyncPolicyForConnection, getContextConsolidationRun, getCurrentSessionId, getEndpointPrincipal, getGlobalSessionStats, getInteractionState, getKnowledgeConsumerWatermark, getKnowledgeSourceCursor, getKnowledgeSourceItem, getMemoryProviderState, getMemoryRecord, getMemoryTurnFeedback, getNoteAgentContextRecord, getNoteRecord, getRelationshipSettings, getSessionConfig, getSessionInputState, getSessionMetadata, getSessionPersistedLevels, getSessionTaskPlan, getSqliteDatabase, getTurnPersonalization, getUnderstanding, getUserProfile, getUserTrustPolicy, getXopcDatabase, hasContextConsent, hasSessionConfig, hasUnresolvedMemoryConflict, incrementSessionStatsOnAppend, insertSessionInput, inspectSchemaMigrationStatus, isHomeAttentionAcknowledged, isProactiveSupportAllowed, isUnderstandingSuppressed, isXopcDatabaseOpen, linkUnderstandingEvidence, listActivityRecords, listCachedConnectorCatalogEntries, listCollaborationRules, listCompactionBoundaries, listComposerInputHistory, listConnectorAccounts, listConnectorActionMetadata, listConnectorApprovals, listConnectorConnections, listConnectorExecutionAudit, listConnectorInstallations, listConnectorLearningJobs, listConnectorSyncPolicies, listContextConsolidationDecisions, listContextConsolidationRuns, listEndpointPrincipals, listEndpointToolInvocationAudits, listKnowledgeSourceChanges, listKnowledgeSourceItems, listKnowledgeSyncRuns, listMemoryEvidence, listMemoryRecords, listMemorySignals, listMemoryTraceEvents, listNoteRecords, listObjectActivityRecords, listObjectLinkRecords, listProjectActivityRecords, listRegisteredMigrationTargets, listSessionMetadata, listSessionsByAgent, listUnderstandingEvidence, listUnderstandings, loadCompactionSourceSnapshot, loadLlmMessagesForSession, loadTranscriptHistoryRowsForSession, loadTranscriptRows, loadTranscriptRowsForSession, markMemoryRecordsConflicted, metadataToSessionInsert, mutateQueuedSessionInput, openXopcDatabase, paginateTranscriptMessages, patchSessionMetadata, pruneBoundedKnowledgeSourceItems, readSchemaVersion, readSchemaVersionForTest, reconcileConnectorAccount, recordActivityEvent, recordContextConsolidationDecision, recordContextFeedback, recordContextRun, recoverSessionInputState, recoverStaleConnectorLearningJobs, refreshConnectorAccountCurrent, rejectUnderstanding, releaseConnectorWebhookDelivery, replaceConnectorCatalogEntries, replaceTranscriptRows, requireXopcDatabase, resetSessionRecord, resetXopcDatabaseSingletonForTest, resolveMigrationsDir, resolveSessionAgentId, resolveXopcDatabasePath, restoreBeforeCompactionBoundary, reviseCollaborationRule, reviseUnderstanding, revokeEndpointPrincipal, runSqliteWriteTransaction, searchMemoryRecords, searchSessionTranscript, sessionConfigRowToConfig, sessionRowToMetadata, setCollaborationRuleStatus, setConnectorLearningPaused, setInteractionState, setKnowledgeConsumerWatermark, setKnowledgeSourceCursor, setKnowledgeSourceItemSynthesisStatus, setMemoryProviderState, setMemoryRecordStatus, setMemoryTurnFeedback, setSessionConfig, setSessionInputStatus, setSessionTaskPlan, setUnderstandingStatus, setUserTrustPolicy, startContextConsolidationRun, startEndpointToolInvocationAudit, startKnowledgeSyncRun, summarizeMemoryRecallFeedback, summarizeUserUnderstandingQuality, touchEndpointPrincipal, transcriptEntryRowToStoredRow, updateConnectorLearningJob, updateInteractionStateFromMessage, updateRelationshipSettings, updateSessionConfig, updateSessionStats, updateUserProfile, upsertConnectorActionMetadata, upsertConnectorCatalogEntry, upsertConnectorConnection, upsertConnectorInstallation, upsertConnectorSyncPolicy, upsertKnowledgeSourceItems, upsertMemoryRecord, upsertNoteAgentContextRecord, upsertNoteRecord };
@@ -0,0 +1,24 @@
1
+ ALTER TABLE automations ADD COLUMN conversation_mode TEXT NOT NULL DEFAULT 'new_session'
2
+ CHECK (conversation_mode IN ('new_session', 'continuous'));
3
+ ALTER TABLE automations ADD COLUMN notification_policy TEXT NOT NULL DEFAULT 'attention'
4
+ CHECK (notification_policy IN ('attention', 'all', 'none'));
5
+ ALTER TABLE automations ADD COLUMN completion_webhook_url TEXT;
6
+
7
+ UPDATE automations
8
+ SET completion_webhook_url = json_extract(after_run_json, '$.url')
9
+ WHERE json_extract(after_run_json, '$.kind') = 'webhook';
10
+
11
+ ALTER TABLE automations DROP COLUMN after_run_json;
12
+
13
+ UPDATE automation_runs
14
+ SET current_phase = 'completion_hook'
15
+ WHERE current_phase = 'after_run';
16
+
17
+ UPDATE automation_run_events
18
+ SET type = replace(type, 'after_run.', 'completion_hook.'),
19
+ message = replace(message, 'After-run webhook', 'Completion webhook')
20
+ WHERE type LIKE 'after_run.%';
21
+
22
+ ALTER TABLE automation_runs ADD COLUMN read_at_ms INTEGER;
23
+ CREATE INDEX IF NOT EXISTS idx_automation_runs_unread_created
24
+ ON automation_runs(read_at_ms, created_at_ms DESC);
@@ -0,0 +1,18 @@
1
+ UPDATE sessions
2
+ SET project_id = (
3
+ SELECT a.project_id
4
+ FROM automation_runs r
5
+ JOIN automations a ON a.automation_id = r.automation_id
6
+ WHERE r.session_key = sessions.session_key
7
+ AND a.project_id IS NOT NULL
8
+ ORDER BY r.created_at_ms DESC
9
+ LIMIT 1
10
+ )
11
+ WHERE project_id IS NULL
12
+ AND EXISTS (
13
+ SELECT 1
14
+ FROM automation_runs r
15
+ JOIN automations a ON a.automation_id = r.automation_id
16
+ WHERE r.session_key = sessions.session_key
17
+ AND a.project_id IS NOT NULL
18
+ );
@@ -0,0 +1,25 @@
1
+ DELETE FROM transcript_fts
2
+ WHERE entry_id IN (
3
+ SELECT entry_id
4
+ FROM transcript_entries
5
+ WHERE entry_kind = 'compaction'
6
+ );
7
+
8
+ DELETE FROM transcript_entries
9
+ WHERE entry_kind = 'compaction';
10
+
11
+ UPDATE sessions
12
+ SET
13
+ compacted_count = 0,
14
+ message_count = (
15
+ SELECT COUNT(*)
16
+ FROM transcript_entries e
17
+ WHERE e.session_id = sessions.session_id
18
+ AND e.entry_kind = 'message'
19
+ ),
20
+ estimated_tokens = (
21
+ SELECT COALESCE(SUM((length(COALESCE(json_extract(e.payload_json, '$.content'), '')) + 3) / 4), 0)
22
+ FROM transcript_entries e
23
+ WHERE e.session_id = sessions.session_id
24
+ AND e.entry_kind = 'message'
25
+ );
@@ -3,7 +3,7 @@ import type { ApplyMigrationsOptions } from './types.js';
3
3
  /** Baseline schema version applied from schema.sql on first open. */
4
4
  export declare const XOPC_DB_BASELINE_SCHEMA_VERSION = 11;
5
5
  /** Latest schema version this release supports (increment when adding migrations). */
6
- export declare const XOPC_DB_SCHEMA_VERSION = 120;
6
+ export declare const XOPC_DB_SCHEMA_VERSION = 123;
7
7
  export declare function resolveMigrationsDir(override?: string): string;
8
8
  /**
9
9
  * Apply sequential SQL migrations from (currentVersion + 1) through targetVersion.
@@ -12,7 +12,7 @@ const log = createLogger("Sqlite:Migrations");
12
12
  /** Baseline schema version applied from schema.sql on first open. */
13
13
  const XOPC_DB_BASELINE_SCHEMA_VERSION = 11;
14
14
  /** Latest schema version this release supports (increment when adding migrations). */
15
- const XOPC_DB_SCHEMA_VERSION = 120;
15
+ const XOPC_DB_SCHEMA_VERSION = 123;
16
16
  const MODULE_DIR = dirname(fileURLToPath(import.meta.url));
17
17
  function backupBeforeTaskCutover(db, databasePath) {
18
18
  db.exec("PRAGMA wal_checkpoint(FULL)");
@@ -57,7 +57,7 @@ function applySingleMigration(db, migration) {
57
57
  * Each step runs in its own transaction and updates schema_meta on success.
58
58
  */
59
59
  function applyPendingMigrations(db, options = {}) {
60
- const targetVersion = options.targetVersion ?? 120;
60
+ const targetVersion = options.targetVersion ?? 123;
61
61
  let currentVersion = readSchemaVersion(db);
62
62
  if (currentVersion > targetVersion) throw new DatabaseSchemaTooNewError(currentVersion, targetVersion);
63
63
  if (currentVersion >= targetVersion) return currentVersion;
@@ -94,7 +94,7 @@ function applyPendingMigrations(db, options = {}) {
94
94
  }
95
95
  /** Inspect schema version without mutating the database. */
96
96
  function inspectSchemaMigrationStatus(db, options = {}) {
97
- const appVersion = options.targetVersion ?? 120;
97
+ const appVersion = options.targetVersion ?? 123;
98
98
  const dbVersion = readSchemaVersion(db);
99
99
  if (dbVersion > appVersion) return {
100
100
  dbVersion,
@@ -19,7 +19,7 @@ const log = createLogger('Sqlite:Migrations');
19
19
  export const XOPC_DB_BASELINE_SCHEMA_VERSION = 11;
20
20
 
21
21
  /** Latest schema version this release supports (increment when adding migrations). */
22
- export const XOPC_DB_SCHEMA_VERSION = 120;
22
+ export const XOPC_DB_SCHEMA_VERSION = 123;
23
23
 
24
24
  const MODULE_DIR = dirname(fileURLToPath(import.meta.url));
25
25
 
@@ -32,7 +32,7 @@ function ensureXopcDatabaseSchema(db, options = {}) {
32
32
  currentVersion = 11;
33
33
  }
34
34
  applyPendingMigrations(db, {
35
- targetVersion: 120,
35
+ targetVersion: 123,
36
36
  databasePath: options.databasePath
37
37
  });
38
38
  }
@@ -2,11 +2,34 @@ import type { AgentMessage } from '@earendil-works/pi-agent-core';
2
2
  import type { CompactionBoundarySummary } from '../../session/types.js';
3
3
  import { type TranscriptStoredRow, type XopcTranscriptCompactionEntry } from '../../session/session-context-for-llm.js';
4
4
  import { type TranscriptEntryRow } from './row-mappers.js';
5
+ export interface TranscriptSourceEntry {
6
+ entryId: string;
7
+ seq: number;
8
+ createdAt: number;
9
+ row: TranscriptStoredRow;
10
+ }
11
+ export interface CompactionSourceSnapshot {
12
+ sessionId: string;
13
+ lastSeq: number;
14
+ entries: TranscriptSourceEntry[];
15
+ }
16
+ export interface SessionTranscriptRecallMatch {
17
+ entryId: string;
18
+ seq: number;
19
+ role: string | null;
20
+ createdAt: number;
21
+ content: string;
22
+ }
5
23
  export declare function appendTranscriptEntry(sessionKey: string, row: TranscriptStoredRow, opts?: {
6
24
  sessionId?: string;
7
25
  tokenDelta?: number;
8
26
  }): TranscriptEntryRow;
9
- export declare function appendCompactionBoundary(sessionKey: string, row: Omit<XopcTranscriptCompactionEntry, 'baseSeq'>): TranscriptEntryRow;
27
+ export declare function appendCompactionBoundaryIfUnchanged(sessionKey: string, expected: Pick<CompactionSourceSnapshot, 'sessionId' | 'lastSeq'>, row: Omit<XopcTranscriptCompactionEntry, 'baseSeq'>): TranscriptEntryRow | null;
28
+ export declare function loadCompactionSourceSnapshot(sessionKey: string): CompactionSourceSnapshot | null;
29
+ export declare function searchSessionTranscript(sessionKey: string, query: string, options?: {
30
+ limit?: number;
31
+ beforeSeq?: number;
32
+ }): SessionTranscriptRecallMatch[];
10
33
  export declare function loadTranscriptRowsForSession(sessionKey: string): TranscriptStoredRow[];
11
34
  export declare function loadTranscriptHistoryRowsForSession(sessionKey: string): TranscriptStoredRow[];
12
35
  export declare function loadTranscriptRows(sessionId: string): TranscriptStoredRow[];
@@ -1,6 +1,7 @@
1
1
  import { getSqliteDatabase, runSqliteWriteTransaction } from "./transaction.js";
2
2
  import { buildSessionContextForLlm, isRuntimeOnlyTranscriptMessage } from "../../session/session-context-for-llm.js";
3
3
  import { classifyStoredRow, estimateTokensFromMessages, extractFtsContent, transcriptEntryRowToStoredRow } from "./row-mappers.js";
4
+ import { escapeFts5Query } from "./fts.js";
4
5
  import { getCurrentSessionId, readCurrentSessionId } from "./session-repository.js";
5
6
  import { randomUUID } from "node:crypto";
6
7
  //#region src/storage/sqlite/transcript-repository.ts
@@ -58,13 +59,15 @@ function appendTranscriptEntry(sessionKey, row, opts) {
58
59
  return inserted;
59
60
  });
60
61
  }
61
- function appendCompactionBoundary(sessionKey, row) {
62
+ function appendCompactionBoundaryIfUnchanged(sessionKey, expected, row) {
62
63
  return runSqliteWriteTransaction((db) => {
63
64
  const sessionId = readCurrentSessionId(db, sessionKey);
64
65
  if (!sessionId) throw new Error(`Session not found: ${sessionKey}`);
66
+ if (sessionId !== expected.sessionId) return null;
67
+ if (nextSeq(db, sessionId) - 1 !== expected.lastSeq) return null;
65
68
  const boundary = {
66
69
  ...row,
67
- baseSeq: nextSeq(db, sessionId) - 1
70
+ baseSeq: expected.lastSeq
68
71
  };
69
72
  const inserted = insertEntry(db, {
70
73
  sessionId,
@@ -83,6 +86,65 @@ function appendCompactionBoundary(sessionKey, row) {
83
86
  return inserted;
84
87
  });
85
88
  }
89
+ function loadCompactionSourceSnapshot(sessionKey) {
90
+ const db = getSqliteDatabase();
91
+ const sessionId = getCurrentSessionId(sessionKey);
92
+ if (!sessionId) return null;
93
+ const rows = db.prepare(`SELECT entry_id, session_id, seq, entry_kind, role, payload_json, created_at
94
+ FROM transcript_entries
95
+ WHERE session_id = ?
96
+ ORDER BY seq ASC`).all(sessionId);
97
+ return {
98
+ sessionId,
99
+ lastSeq: rows.at(-1)?.seq ?? 0,
100
+ entries: rows.map((entry) => ({
101
+ entryId: entry.entry_id,
102
+ seq: entry.seq,
103
+ createdAt: entry.created_at,
104
+ row: transcriptEntryRowToStoredRow(entry)
105
+ }))
106
+ };
107
+ }
108
+ function searchSessionTranscript(sessionKey, query, options = {}) {
109
+ const sessionId = getCurrentSessionId(sessionKey);
110
+ const normalized = query.trim();
111
+ if (!sessionId || !normalized) return [];
112
+ const limit = Math.min(20, Math.max(1, options.limit ?? 8));
113
+ const beforeSeq = options.beforeSeq ?? Number.MAX_SAFE_INTEGER;
114
+ const db = getSqliteDatabase();
115
+ const ftsRows = db.prepare(`SELECT e.entry_id, e.seq, e.role, e.created_at, f.content
116
+ FROM transcript_fts f
117
+ JOIN transcript_entries e
118
+ ON e.session_id = f.session_id AND e.entry_id = f.entry_id
119
+ WHERE transcript_fts MATCH ?
120
+ AND f.session_id = ?
121
+ AND e.entry_kind <> 'compaction'
122
+ AND e.seq < ?
123
+ ORDER BY bm25(transcript_fts), e.seq DESC
124
+ LIMIT ?`).all(escapeFts5Query(normalized), sessionId, beforeSeq, limit);
125
+ const escapedLike = normalized.replaceAll("\\", "\\\\").replaceAll("%", "\\%").replaceAll("_", "\\_");
126
+ const literalRows = db.prepare(`SELECT entry_id, seq, role, created_at, payload_json AS content
127
+ FROM transcript_entries
128
+ WHERE session_id = ?
129
+ AND entry_kind <> 'compaction'
130
+ AND seq < ?
131
+ AND payload_json LIKE ? ESCAPE '\\'
132
+ ORDER BY seq DESC
133
+ LIMIT ?`).all(sessionId, beforeSeq, `%${escapedLike}%`, limit);
134
+ const seen = /* @__PURE__ */ new Set();
135
+ return [...ftsRows, ...literalRows].flatMap((row) => {
136
+ const result = row;
137
+ if (seen.has(result.entry_id)) return [];
138
+ seen.add(result.entry_id);
139
+ return [{
140
+ entryId: result.entry_id,
141
+ seq: result.seq,
142
+ role: result.role,
143
+ createdAt: result.created_at,
144
+ content: result.content
145
+ }];
146
+ }).slice(0, limit);
147
+ }
86
148
  function loadTranscriptRowsForSession(sessionKey) {
87
149
  const sessionId = getCurrentSessionId(sessionKey);
88
150
  if (!sessionId) return [];
@@ -210,7 +272,7 @@ function listCompactionBoundaries(sessionKey) {
210
272
  tokensBefore: payload.tokensBefore,
211
273
  tokensAfter: payload.tokensAfter,
212
274
  summaryPreview: payload.summary.slice(0, 500),
213
- restoredFromCompactionId: payload.restoredFromCompactionId
275
+ audit: payload.audit
214
276
  };
215
277
  });
216
278
  }
@@ -221,42 +283,29 @@ function restoreBeforeCompactionBoundary(sessionKey, compactionId) {
221
283
  const boundary = db.prepare(`SELECT seq FROM transcript_entries
222
284
  WHERE session_id = ? AND entry_id = ? AND entry_kind = 'compaction'`).get(sessionId, compactionId);
223
285
  if (!boundary) throw new Error(`Compaction boundary not found: ${compactionId}`);
224
- const restoredMessages = buildSessionContextForLlm(db.prepare(`SELECT entry_id, session_id, seq, entry_kind, role, payload_json, created_at
286
+ const removedEntryIds = db.prepare(`SELECT entry_id
287
+ FROM transcript_entries
288
+ WHERE session_id = ? AND seq >= ?`).all(sessionId, boundary.seq);
289
+ for (const entry of removedEntryIds) db.prepare(`DELETE FROM transcript_fts WHERE entry_id = ?`).run(entry.entry_id);
290
+ db.prepare(`DELETE FROM transcript_entries WHERE session_id = ? AND seq >= ?`).run(sessionId, boundary.seq);
291
+ const remainingEntries = db.prepare(`SELECT entry_id, session_id, seq, entry_kind, role, payload_json, created_at
225
292
  FROM transcript_entries
226
- WHERE session_id = ? AND seq < ?
227
- ORDER BY seq ASC`).all(sessionId, boundary.seq).map(transcriptEntryRowToStoredRow));
293
+ WHERE session_id = ?
294
+ ORDER BY seq ASC`).all(sessionId);
295
+ const restoredMessages = buildSessionContextForLlm(remainingEntries.map(transcriptEntryRowToStoredRow));
228
296
  if (restoredMessages.length === 0) throw new Error(`No restorable context exists before compaction boundary: ${compactionId}`);
229
- const current = db.prepare(`SELECT estimated_tokens FROM sessions WHERE session_key = ?`).get(sessionKey);
230
297
  const tokensAfter = estimateTokensFromMessages(restoredMessages);
231
- const baseSeq = nextSeq(db, sessionId) - 1;
232
- insertEntry(db, {
233
- sessionId,
234
- sessionKey,
235
- row: {
236
- type: "compaction",
237
- at: (/* @__PURE__ */ new Date()).toISOString(),
238
- baseSeq,
239
- plannerVersion: 2,
240
- summaryModelRef: "logical-restore",
241
- qualityAudit: "disabled",
242
- summary: `Restored the effective context that existed before compaction boundary ${compactionId}.`,
243
- messages: restoredMessages,
244
- firstKeptIndex: 0,
245
- tokensBefore: current.estimated_tokens,
246
- tokensAfter,
247
- restoredFromCompactionId: compactionId
248
- }
249
- });
298
+ const compactedCount = remainingEntries.filter((entry) => entry.entry_kind === "compaction").length;
250
299
  const now = Date.now();
251
300
  db.prepare(`UPDATE sessions SET
252
301
  message_count = ?,
253
302
  estimated_tokens = ?,
254
- compacted_count = compacted_count + 1,
303
+ compacted_count = ?,
255
304
  updated_at = ?,
256
305
  last_accessed_at = ?,
257
306
  last_interaction_at = ?
258
- WHERE session_key = ?`).run(restoredMessages.length, tokensAfter, now, now, now, sessionKey);
307
+ WHERE session_key = ?`).run(restoredMessages.length, tokensAfter, compactedCount, now, now, now, sessionKey);
259
308
  });
260
309
  }
261
310
  //#endregion
262
- export { appendCompactionBoundary, appendTranscriptEntry, listCompactionBoundaries, loadLlmMessagesForSession, loadTranscriptHistoryRowsForSession, loadTranscriptRows, loadTranscriptRowsForSession, paginateTranscriptMessages, replaceTranscriptRows, restoreBeforeCompactionBoundary };
311
+ export { appendCompactionBoundaryIfUnchanged, appendTranscriptEntry, listCompactionBoundaries, loadCompactionSourceSnapshot, loadLlmMessagesForSession, loadTranscriptHistoryRowsForSession, loadTranscriptRows, loadTranscriptRowsForSession, paginateTranscriptMessages, replaceTranscriptRows, restoreBeforeCompactionBoundary, searchSessionTranscript };