@xopcai/xopc 0.0.283 → 0.0.285

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 (234) hide show
  1. package/dist/browser-ext/manifest.json +1 -1
  2. package/dist/extensions/telegram/xopc.extension.json +1 -1
  3. package/dist/gateway/static/root/assets/{activity-store-iPtG94qr.js → activity-store-B0BTIk9j.js} +1 -1
  4. package/dist/gateway/static/root/assets/{agent-avatar-dicebear-DQ74xqLi.js → agent-avatar-dicebear-Dc-0QZTQ.js} +1 -1
  5. package/dist/gateway/static/root/assets/agent-defaults-settings-panel-CcmqK1Sc.js +1 -0
  6. package/dist/gateway/static/root/assets/agents-B_7PVt7S.js +1 -0
  7. package/dist/gateway/static/root/assets/api-COG_Tzpv.js +1 -0
  8. package/dist/gateway/static/root/assets/{api-KMJzMqvZ.js → api-Coly9ab6.js} +1 -1
  9. package/dist/gateway/static/root/assets/{app-management-settings-panel-B42TpqIb.js → app-management-settings-panel-TWBO-msg.js} +1 -1
  10. package/dist/gateway/static/root/assets/{appearance-settings-D9Lfe7Sk.js → appearance-settings-CpTZ2KuT.js} +1 -1
  11. package/dist/gateway/static/root/assets/apps-page-6qxxKFsK.js +1 -0
  12. package/dist/gateway/static/root/assets/{archive-plugin-BdmQwj4x.js → archive-plugin-z_u6alob.js} +1 -1
  13. package/dist/gateway/static/root/assets/{attachment-load-B4S0_nji.js → attachment-load-C2nS04TC.js} +1 -1
  14. package/dist/gateway/static/root/assets/{automations-page-B3TmHNjQ.js → automations-page-aIBsw9zR.js} +1 -1
  15. package/dist/gateway/static/root/assets/automations-workspace-BRQlU4qk.js +6 -0
  16. package/dist/gateway/static/root/assets/{binary-plugins-B3cXF_DP.js → binary-plugins-CGmXoZnl.js} +1 -1
  17. package/dist/gateway/static/root/assets/{block-editor-05zyBXBe.js → block-editor-CtvzCZhC.js} +3 -3
  18. package/dist/gateway/static/root/assets/{browser-automation-inputs-BTIufVbM.js → browser-automation-inputs-BOTU1isH.js} +1 -1
  19. package/dist/gateway/static/root/assets/{browser-automations-page-DRBA9nwe.js → browser-automations-page-BwU5V8J0.js} +2 -2
  20. package/dist/gateway/static/root/assets/browser-settings-page-DDjbDeHQ.js +8 -0
  21. package/dist/gateway/static/root/assets/capabilities-settings-panel-DM1Bcf1x.js +8 -0
  22. package/dist/gateway/static/root/assets/channels-settings-Bq36CUxL.js +1 -0
  23. package/dist/gateway/static/root/assets/{channels-status-swr-DMYQNs-J.js → channels-status-swr-Dfi0Desh.js} +1 -1
  24. package/dist/gateway/static/root/assets/{chat-terminal-dock-Dx5KQyo5.js → chat-terminal-dock-B0MvcO6j.js} +2 -2
  25. package/dist/gateway/static/root/assets/connectors-page-L8JehrxF.js +2 -0
  26. package/dist/gateway/static/root/assets/{date-picker-CkDROZoe.js → date-picker-DXOvbHCr.js} +1 -1
  27. package/dist/gateway/static/root/assets/{dependency-picker-Bl8HcvzL.js → dependency-picker-BEnC-eS0.js} +1 -1
  28. package/dist/gateway/static/root/assets/{desktop-pet-BcknAjbW.js → desktop-pet-DtPNvznL.js} +1 -1
  29. package/dist/gateway/static/root/assets/{desktop-pet-settings-BuCpXQPm.js → desktop-pet-settings-CYyjcSn6.js} +1 -1
  30. package/dist/gateway/static/root/assets/device-pairing-wizard-BPMGvAKE.js +1 -0
  31. package/dist/gateway/static/root/assets/{extension-debug-page-qRpb2FFa.js → extension-debug-page-H_aPMGXW.js} +1 -1
  32. package/dist/gateway/static/root/assets/{extension-page-C7gs9wu4.js → extension-page-C1JnpeMt.js} +1 -1
  33. package/dist/gateway/static/root/assets/{extension-settings-page-CyJP1CMZ.js → extension-settings-page-C75kCOqe.js} +1 -1
  34. package/dist/gateway/static/root/assets/{gateway-config-swr-Cpmyrr6j.js → gateway-config-swr-G2lQt7Ak.js} +1 -1
  35. package/dist/gateway/static/root/assets/gateway-settings-BCF732TU.js +1 -0
  36. package/dist/gateway/static/root/assets/{gateway-startup-retry-DoiPeb65.js → gateway-startup-retry-GP31PUrG.js} +1 -1
  37. package/dist/gateway/static/root/assets/{heartbeat-settings-CV6Dolcn.js → heartbeat-settings-C7fjiowt.js} +1 -1
  38. package/dist/gateway/static/root/assets/home-page-DZXeXdUL.js +1 -0
  39. package/dist/gateway/static/root/assets/{image-generation-api-CqjHWl2T.js → image-generation-api-CKFhfHSw.js} +1 -1
  40. package/dist/gateway/static/root/assets/imports-page-GROumhj8.js +1 -0
  41. package/dist/gateway/static/root/assets/{index-CHgOG1aR.js → index-ChIrvv3t.js} +47 -47
  42. package/dist/gateway/static/root/assets/index-R1VNlHjj.css +2 -0
  43. package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-B3XqA41D.js → keyboard-shortcuts-settings-zcI822m_.js} +1 -1
  44. package/dist/gateway/static/root/assets/local-app-workbench-page-CAEKGTAg.js +2 -0
  45. package/dist/gateway/static/root/assets/{local-apps-page-BcIVYp0J.js → local-apps-page-BtgDJ92Q.js} +1 -1
  46. package/dist/gateway/static/root/assets/{locale-store-1urrBBCQ.js → locale-store-DlOv7896.js} +1 -1
  47. package/dist/gateway/static/root/assets/logs-page-DHZ4BEkG.js +2 -0
  48. package/dist/gateway/static/root/assets/{management-settings-DNFCdgzR.js → management-settings-DasZxCyD.js} +1 -1
  49. package/dist/gateway/static/root/assets/{markdown-view-BZmcFIWa.js → markdown-view-6oYdBahT.js} +1 -1
  50. package/dist/gateway/static/root/assets/{media-plugins-BDxNhoBC.js → media-plugins-CxthbBvk.js} +1 -1
  51. package/dist/gateway/static/root/assets/messages-Ls1Aaiqd.js +3 -0
  52. package/dist/gateway/static/root/assets/note-detail-panel-BcWq3ddw.js +5 -0
  53. package/dist/gateway/static/root/assets/notes-page-DfZ8QWyv.js +8 -0
  54. package/dist/gateway/static/root/assets/{page-tabs-agH3a2PI.js → page-tabs-BG39KidE.js} +1 -1
  55. package/dist/gateway/static/root/assets/{preview-open-alternatives-XEZ7zDOP.js → preview-open-alternatives-Bevpbq9f.js} +1 -1
  56. package/dist/gateway/static/root/assets/proactive-page-D2U_xQaS.js +1 -0
  57. package/dist/gateway/static/root/assets/{product-open-page-lXAbj85Z.js → product-open-page-Bi1seZpM.js} +1 -1
  58. package/dist/gateway/static/root/assets/project-detail-page-CzlGTW4F.js +1 -0
  59. package/dist/gateway/static/root/assets/projects-page-mQsM-TsP.js +1 -0
  60. package/dist/gateway/static/root/assets/{registry-api-CxQstD00.js → registry-api-D0ddwBFj.js} +1 -1
  61. package/dist/gateway/static/root/assets/remote-access-hub-Cb56JcO1.js +1 -0
  62. package/dist/gateway/static/root/assets/{runtime-tools-settings-panel-DErKZlVJ.js → runtime-tools-settings-panel-Wkru8_My.js} +2 -2
  63. package/dist/gateway/static/root/assets/{schema-form-DhCmJQVJ.js → schema-form-CSMRzj9Y.js} +1 -1
  64. package/dist/gateway/static/root/assets/sessions-page-Hj9uFcIO.js +1 -0
  65. package/dist/gateway/static/root/assets/settings-advanced-gate-CV4-_EVA.js +1 -0
  66. package/dist/gateway/static/root/assets/{settings-form-section-Dg6chotg.js → settings-form-section-wcAdCkK8.js} +1 -1
  67. package/dist/gateway/static/root/assets/{settings-page-LyuN5N3M.js → settings-page-BcQGAnCs.js} +1 -1
  68. package/dist/gateway/static/root/assets/setup-status-panel-DzxmsaQG.js +1 -0
  69. package/dist/gateway/static/root/assets/{share-preview-page-CZvmf4Ob.js → share-preview-page-DQocUl-1.js} +1 -1
  70. package/dist/gateway/static/root/assets/shares-settings-xlJh1ccG.js +1 -0
  71. package/dist/gateway/static/root/assets/skill-reload-api-wSXJRSxX.js +1 -0
  72. package/dist/gateway/static/root/assets/skills-page-AmqtBJo7.js +2 -0
  73. package/dist/gateway/static/root/assets/{skills-page.utils-Eu0WVHTS.js → skills-page.utils-DtlfCgJp.js} +1 -1
  74. package/dist/gateway/static/root/assets/{system-settings-panel-DQKkM7B2.js → system-settings-panel-Ct698Nf-.js} +1 -1
  75. package/dist/gateway/static/root/assets/task-detail-page-sQpwq5-c.js +1 -0
  76. package/dist/gateway/static/root/assets/{theme-store-Dc5s20V3.js → theme-store-ng8KJsAT.js} +1 -1
  77. package/dist/gateway/static/root/assets/{tunnel-api-TKQpPVd6.js → tunnel-api-Boajol0M.js} +1 -1
  78. package/dist/gateway/static/root/assets/{use-autosave-CkVlrFk1.js → use-autosave-BSyxRHt2.js} +1 -1
  79. package/dist/gateway/static/root/assets/user-model-page-DIEHnAER.js +2 -0
  80. package/dist/gateway/static/root/assets/{voice-api-key-field-B12fFN-L.js → voice-api-key-field-SE3OQI1s.js} +1 -1
  81. package/dist/gateway/static/root/assets/{voice-config-api-Mk78BrpP.js → voice-config-api-VNuCmdFe.js} +1 -1
  82. package/dist/gateway/static/root/assets/{work-discovery-overlay-CT9Zy36i.js → work-discovery-overlay-Dn1vy2oq.js} +1 -1
  83. package/dist/gateway/static/root/assets/{workflow-run-setup-panel-BwefQliE.js → workflow-run-setup-panel-BJEfGY-k.js} +2 -2
  84. package/dist/gateway/static/root/assets/workflows-page-DgRNIyr7.js +6 -0
  85. package/dist/gateway/static/root/index.html +10 -10
  86. package/dist/package.js +1 -1
  87. package/dist/packages/gateway-contract/src/proactive.js +13 -4
  88. package/dist/src/agent/coding/repository-instructions.js +1 -1
  89. package/dist/src/agent/coding/workspace-revision.js +1 -1
  90. package/dist/src/agent/commands/command-isolation.js +1 -1
  91. package/dist/src/agent/tools/factory.js +7 -3
  92. package/dist/src/agent/tools/review-workspace.js +1 -1
  93. package/dist/src/browser/providers/browser-ext-install.js +10 -2
  94. package/dist/src/cli/command-loaders.js +1 -0
  95. package/dist/src/cli/command-manifest.js +4 -0
  96. package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
  97. package/dist/src/cli/commands/gateway/lifecycle.js +1 -1
  98. package/dist/src/cli/commands/gateway/run-foreground.js +3 -0
  99. package/dist/src/cli/commands/import.d.ts +2 -0
  100. package/dist/src/cli/commands/import.js +78 -0
  101. package/dist/src/discussions/action-tasks.js +1 -1
  102. package/dist/src/discussions/edits.js +1 -1
  103. package/dist/src/discussions/index.js +1 -1
  104. package/dist/src/discussions/organizer.js +1 -1
  105. package/dist/src/discussions/recording.js +1 -1
  106. package/dist/src/discussions/sealer.js +1 -1
  107. package/dist/src/discussions/service.js +2 -2
  108. package/dist/src/endpoint-tools/invocation-service.d.ts +2 -0
  109. package/dist/src/endpoint-tools/invocation-service.js +48 -19
  110. package/dist/src/gateway/heartbeat/check-store.d.ts +18 -0
  111. package/dist/src/gateway/heartbeat/check-store.js +73 -0
  112. package/dist/src/gateway/heartbeat/service.d.ts +12 -3
  113. package/dist/src/gateway/heartbeat/service.js +61 -44
  114. package/dist/src/gateway/hono/routes/discussions.js +2 -2
  115. package/dist/src/gateway/hono/routes/imports.d.ts +3 -0
  116. package/dist/src/gateway/hono/routes/imports.js +56 -0
  117. package/dist/src/gateway/hono/routes/lazy-bundles.js +8 -0
  118. package/dist/src/gateway/hono/routes/proactive-control.js +2 -1
  119. package/dist/src/gateway/service.d.ts +7 -0
  120. package/dist/src/gateway/service.js +26 -9
  121. package/dist/src/imports/compatibility.d.ts +7 -0
  122. package/dist/src/imports/compatibility.js +174 -0
  123. package/dist/src/imports/contextImport.d.ts +3 -0
  124. package/dist/src/imports/contextImport.js +56 -0
  125. package/dist/src/imports/files.d.ts +13 -0
  126. package/dist/src/imports/files.js +77 -0
  127. package/dist/src/imports/importService.d.ts +50 -0
  128. package/dist/src/imports/importService.js +414 -0
  129. package/dist/src/imports/inventory.d.ts +11 -0
  130. package/dist/src/imports/inventory.js +202 -0
  131. package/dist/src/imports/planner.d.ts +11 -0
  132. package/dist/src/imports/planner.js +98 -0
  133. package/dist/src/imports/productImport.d.ts +10 -0
  134. package/dist/src/imports/productImport.js +241 -0
  135. package/dist/src/imports/runtime.d.ts +5 -0
  136. package/dist/src/imports/runtime.js +61 -0
  137. package/dist/src/imports/scanner.d.ts +14 -0
  138. package/dist/src/imports/scanner.js +159 -0
  139. package/dist/src/imports/secrets.d.ts +2 -0
  140. package/dist/src/imports/secrets.js +9 -0
  141. package/dist/src/imports/sources.d.ts +37 -0
  142. package/dist/src/imports/sources.js +75 -0
  143. package/dist/src/imports/types.d.ts +144 -0
  144. package/dist/src/imports/types.js +11 -0
  145. package/dist/src/infra/background-task.d.ts +2 -0
  146. package/dist/src/infra/background-task.js +25 -0
  147. package/dist/src/infra/process-diagnostics.d.ts +5 -0
  148. package/dist/src/infra/process-diagnostics.js +97 -0
  149. package/dist/src/infra/unhandled-rejections.js +6 -3
  150. package/dist/src/infra/update-restart.js +1 -1
  151. package/dist/src/knowledge/ingestion-service.js +1 -0
  152. package/dist/src/knowledge-memory/repository.js +4 -2
  153. package/dist/src/media-shared/http/ssrf-guard.js +1 -1
  154. package/dist/src/notifications/proactive-policy.js +7 -5
  155. package/dist/src/proactive/execution/authorization.d.ts +2 -0
  156. package/dist/src/proactive/execution/authorization.js +10 -1
  157. package/dist/src/proactive/execution/context.js +1 -0
  158. package/dist/src/proactive/execution/repository.d.ts +2 -0
  159. package/dist/src/proactive/execution/repository.js +19 -2
  160. package/dist/src/proactive/execution/worker.js +14 -4
  161. package/dist/src/proactive/experience.d.ts +4 -1
  162. package/dist/src/proactive/experience.js +3 -0
  163. package/dist/src/proactive/follow-ups.d.ts +5 -0
  164. package/dist/src/proactive/follow-ups.js +18 -7
  165. package/dist/src/proactive/inbox/cards.js +2 -1
  166. package/dist/src/proactive/inbox/delivery.js +6 -7
  167. package/dist/src/proactive/inbox/digest.d.ts +1 -1
  168. package/dist/src/proactive/inbox/digest.js +23 -13
  169. package/dist/src/proactive/inbox/notification-policy.d.ts +1 -1
  170. package/dist/src/proactive/inbox/notification-policy.js +9 -6
  171. package/dist/src/proactive/inbox/repository.js +3 -2
  172. package/dist/src/proactive/inbox/service.d.ts +6 -0
  173. package/dist/src/proactive/inbox/service.js +18 -0
  174. package/dist/src/proactive/inbox/types.d.ts +1 -0
  175. package/dist/src/proactive/policy/presence.d.ts +1 -1
  176. package/dist/src/proactive/policy/presence.js +7 -5
  177. package/dist/src/proactive/policy/service.d.ts +8 -5
  178. package/dist/src/proactive/policy/service.js +12 -12
  179. package/dist/src/proactive/scenarios/control.d.ts +3 -3
  180. package/dist/src/proactive/scenarios/control.js +12 -2
  181. package/dist/src/proactive/source-freshness.d.ts +8 -0
  182. package/dist/src/proactive/source-freshness.js +27 -0
  183. package/dist/src/proactive/status.d.ts +2 -0
  184. package/dist/src/proactive/status.js +21 -0
  185. package/dist/src/proactive/temporal/worker.js +2 -1
  186. package/dist/src/realtime/runtime.js +31 -5
  187. package/dist/src/realtime/writer.js +16 -9
  188. package/dist/src/storage/sqlite/import-repository.d.ts +18 -0
  189. package/dist/src/storage/sqlite/import-repository.js +35 -0
  190. package/dist/src/storage/sqlite/import-selection-repository.d.ts +15 -0
  191. package/dist/src/storage/sqlite/import-selection-repository.js +28 -0
  192. package/dist/src/storage/sqlite/knowledge-repository.d.ts +1 -0
  193. package/dist/src/storage/sqlite/knowledge-repository.js +2 -2
  194. package/dist/src/storage/sqlite/migrations/174_capability_imports.sql +11 -0
  195. package/dist/src/storage/sqlite/migrations/175_import_selections.sql +8 -0
  196. package/dist/src/storage/sqlite/migrations/176_proactive_quality.sql +5 -0
  197. package/dist/src/storage/sqlite/migrations/177_proactive_check_controls.sql +25 -0
  198. package/dist/src/storage/sqlite/migrations/runner.d.ts +1 -1
  199. package/dist/src/storage/sqlite/migrations/runner.js +3 -3
  200. package/dist/src/storage/sqlite/migrations/runner.ts +1 -1
  201. package/dist/src/storage/sqlite/schema.js +1 -1
  202. package/dist/src/work-discovery/candidate-discovery.js +1 -1
  203. package/dist/src/work-discovery/probe.js +1 -1
  204. package/package.json +4 -3
  205. package/dist/gateway/static/root/assets/agent-defaults-settings-panel-SElFkQd6.js +0 -1
  206. package/dist/gateway/static/root/assets/agents-DYazUaZ6.js +0 -1
  207. package/dist/gateway/static/root/assets/apps-page-BzrodN8C.js +0 -1
  208. package/dist/gateway/static/root/assets/automations-workspace--A4I0jMu.js +0 -6
  209. package/dist/gateway/static/root/assets/browser-settings-page-DDTXUNWK.js +0 -8
  210. package/dist/gateway/static/root/assets/capabilities-settings-panel-Ll5UeXq5.js +0 -8
  211. package/dist/gateway/static/root/assets/channels-settings-BzL15bkU.js +0 -1
  212. package/dist/gateway/static/root/assets/connectors-page-RPw1AOMb.js +0 -2
  213. package/dist/gateway/static/root/assets/device-pairing-wizard-D0_tCX49.js +0 -1
  214. package/dist/gateway/static/root/assets/gateway-settings-DOeeTdWE.js +0 -1
  215. package/dist/gateway/static/root/assets/home-page-Djw1H_Go.js +0 -1
  216. package/dist/gateway/static/root/assets/index-B_Sg5BKz.css +0 -2
  217. package/dist/gateway/static/root/assets/local-app-workbench-page-BPqgyYJq.js +0 -2
  218. package/dist/gateway/static/root/assets/logs-page-BHax3XlS.js +0 -2
  219. package/dist/gateway/static/root/assets/messages-DYFcjtmG.js +0 -3
  220. package/dist/gateway/static/root/assets/note-detail-panel-Cs46LFXO.js +0 -5
  221. package/dist/gateway/static/root/assets/notes-page-BUkcn_0t.js +0 -8
  222. package/dist/gateway/static/root/assets/proactive-page-Bn484J9v.js +0 -1
  223. package/dist/gateway/static/root/assets/project-detail-page-LcH21ixD.js +0 -1
  224. package/dist/gateway/static/root/assets/projects-page-DelBiwyB.js +0 -1
  225. package/dist/gateway/static/root/assets/remote-access-hub-3BjFYXCf.js +0 -1
  226. package/dist/gateway/static/root/assets/sessions-page-CVFirgVd.js +0 -1
  227. package/dist/gateway/static/root/assets/settings-advanced-gate-DyfBpqkY.js +0 -1
  228. package/dist/gateway/static/root/assets/setup-status-panel-CrXhTzHr.js +0 -1
  229. package/dist/gateway/static/root/assets/shares-settings-DyM_D8hM.js +0 -1
  230. package/dist/gateway/static/root/assets/skill-reload-api-Bys58-15.js +0 -1
  231. package/dist/gateway/static/root/assets/skills-page-sWNvFo6D.js +0 -2
  232. package/dist/gateway/static/root/assets/task-detail-page-B18NcZQJ.js +0 -1
  233. package/dist/gateway/static/root/assets/user-model-page-ul-zr58b.js +0 -2
  234. package/dist/gateway/static/root/assets/workflows-page-BY_AWs7S.js +0 -6
@@ -8,7 +8,9 @@ const PresenceSchema = z.object({
8
8
  "web",
9
9
  "electron",
10
10
  "mobile"
11
- ])
11
+ ]),
12
+ inboxItemId: z.string().min(1).max(128).optional(),
13
+ notificationRevision: z.number().int().positive().optional()
12
14
  }).strict();
13
15
  function recordProactivePresence(workspaceId, value, now = Date.now()) {
14
16
  const input = PresenceSchema.parse(value);
@@ -18,10 +20,10 @@ function recordProactivePresence(workspaceId, value, now = Date.now()) {
18
20
  db.prepare("DELETE FROM proactive_presence WHERE workspace_id = ? AND client_id = ?").run(workspaceId, input.clientId);
19
21
  return;
20
22
  }
21
- db.prepare(`INSERT INTO proactive_presence VALUES (?, ?, ?, ?) ON CONFLICT(workspace_id, client_id) DO UPDATE SET surface = excluded.surface, expires_at = excluded.expires_at`).run(workspaceId, input.clientId, input.surface, now + 75e3);
23
+ db.prepare(`INSERT INTO proactive_presence(workspace_id, client_id, surface, expires_at, inbox_item_id, notification_revision) VALUES (?, ?, ?, ?, ?, ?) ON CONFLICT(workspace_id, client_id) DO UPDATE SET surface = excluded.surface, expires_at = excluded.expires_at, inbox_item_id = excluded.inbox_item_id, notification_revision = excluded.notification_revision`).run(workspaceId, input.clientId, input.surface, now + 75e3, input.inboxItemId ?? null, input.notificationRevision ?? null);
22
24
  }
23
- function viewingProactiveCards(workspaceId, now = Date.now()) {
24
- return Boolean(getSqliteDatabase().prepare("SELECT 1 FROM proactive_presence WHERE workspace_id = ? AND expires_at > ?").get(workspaceId, now));
25
+ function viewingProactiveCard(workspaceId, itemId, revision, now = Date.now()) {
26
+ return Boolean(getSqliteDatabase().prepare("SELECT 1 FROM proactive_presence WHERE workspace_id = ? AND inbox_item_id = ? AND notification_revision = ? AND expires_at > ?").get(workspaceId, itemId, revision, now));
25
27
  }
26
28
  //#endregion
27
- export { recordProactivePresence, viewingProactiveCards };
29
+ export { recordProactivePresence, viewingProactiveCard };
@@ -3,7 +3,7 @@ export declare class ProactiveConflict extends Error {
3
3
  }
4
4
  export declare function subscriptionSettings(id: string): {
5
5
  revision: number;
6
- level: "off" | "active" | "quiet" | "balanced";
6
+ level: "active" | "quiet" | "balanced";
7
7
  delivery: "digest" | "inbox" | "important";
8
8
  completedAt: string;
9
9
  scanIntervalMinutes: number;
@@ -13,17 +13,17 @@ export declare function proactivePreferences(workspaceId: string): ProactivePref
13
13
  export declare function updateProactivePreferences(workspaceId: string, value: unknown): ProactivePreferences;
14
14
  export declare function effectiveProactivePolicy(subscriptionId: string, now?: Date): {
15
15
  enabled: boolean;
16
- level: "off" | "active" | "quiet" | "balanced";
16
+ level: "active" | "quiet" | "balanced";
17
17
  settings: {
18
18
  revision: number;
19
- level: "off" | "active" | "quiet" | "balanced";
19
+ level: "active" | "quiet" | "balanced";
20
20
  delivery: "digest" | "inbox" | "important";
21
21
  completedAt: string;
22
22
  scanIntervalMinutes: number;
23
23
  userInstructions: string;
24
24
  };
25
25
  preferences: {
26
- level: "off" | "active" | "quiet" | "balanced";
26
+ level: "active" | "quiet" | "balanced";
27
27
  timezone: string;
28
28
  quietStartHour: number;
29
29
  quietEndHour: number;
@@ -38,7 +38,9 @@ export declare function effectiveProactivePolicy(subscriptionId: string, now?: D
38
38
  publicUrl: string;
39
39
  accountId?: string;
40
40
  };
41
- pausedUntil: string;
41
+ checksPaused: boolean;
42
+ checksPausedUntil: string;
43
+ notificationsMuted: boolean;
42
44
  revision: number;
43
45
  };
44
46
  workspaceId: string;
@@ -49,3 +51,4 @@ export declare function quietHoursEnd(preferences: ProactivePreferences, now: Da
49
51
  /** Called in the same transaction as notification persistence. Reservations survive retries. */
50
52
  export declare function reserveProactiveNotification(subscriptionId: string, dedupeKey: string, now?: Date): 'allowed' | 'suppressed' | Date;
51
53
  export declare function nextDigestTime(preferences: ProactivePreferences, after: Date): Date;
54
+ export declare function proactiveChecksAllowed(preferences: ProactivePreferences, now?: Date): boolean;
@@ -29,15 +29,12 @@ function updateProactivePreferences(workspaceId, value) {
29
29
  if (next.preferredChannel === "telegram" && !next.telegram) throw new Error("Telegram destination is required");
30
30
  db.prepare(`INSERT INTO proactive_preferences(workspace_id, preferences_json, revision) VALUES (?, ?, ?)
31
31
  ON CONFLICT(workspace_id) DO UPDATE SET preferences_json = excluded.preferences_json, revision = excluded.revision`).run(workspaceId, JSON.stringify(next), next.revision);
32
- if (next.timezone !== current.timezone || next.digestHour !== current.digestHour || next.digestMinute !== current.digestMinute) db.prepare("UPDATE proactive_digest_queue SET due_at = ? WHERE workspace_id = ? AND mode = 'daily' AND consumed_at IS NULL").run(nextDigestTime(next, /* @__PURE__ */ new Date()).toISOString(), workspaceId);
33
- if (next.level === "off") {
34
- db.prepare("DELETE FROM proactive_digest_queue WHERE workspace_id = ?").run(workspaceId);
35
- db.prepare(`UPDATE proactive_delivery_outbox SET status = 'delivered', error_message = 'proactive_disabled'
36
- WHERE status IN ('pending', 'retryable') AND inbox_item_id IN (
37
- SELECT i.inbox_item_id FROM proactive_inbox_items i JOIN proactive_insights x USING(insight_id)
38
- JOIN proactive_scenario_subscriptions s USING(subscription_id) WHERE s.workspace_id = ?
39
- )`).run(workspaceId);
32
+ if (proactiveChecksAllowed(current) && !proactiveChecksAllowed(next)) {
33
+ db.prepare(`UPDATE proactive_schedule_state SET last_fingerprint = NULL WHERE subscription_id IN
34
+ (SELECT subscription_id FROM proactive_scenario_subscriptions WHERE workspace_id = ?)`).run(workspaceId);
35
+ db.prepare("UPDATE proactive_follow_ups SET last_fingerprint = NULL WHERE workspace_id = ? AND status = 'watching'").run(workspaceId);
40
36
  }
37
+ if (next.timezone !== current.timezone || next.digestHour !== current.digestHour || next.digestMinute !== current.digestMinute) db.prepare("UPDATE proactive_digest_queue SET due_at = ? WHERE workspace_id = ? AND mode = 'daily' AND consumed_at IS NULL").run(nextDigestTime(next, /* @__PURE__ */ new Date()).toISOString(), workspaceId);
41
38
  return next;
42
39
  });
43
40
  }
@@ -45,9 +42,9 @@ function effectiveProactivePolicy(subscriptionId, now = /* @__PURE__ */ new Date
45
42
  const sub = getSqliteDatabase().prepare("SELECT workspace_id, enabled FROM proactive_scenario_subscriptions WHERE subscription_id = ?").get(subscriptionId);
46
43
  const settings = subscriptionSettings(subscriptionId);
47
44
  const preferences = proactivePreferences(sub?.workspace_id ?? "default");
48
- const level = preferences.level === "off" ? "off" : settings.level ?? preferences.level;
45
+ const level = settings.level ?? preferences.level;
49
46
  return {
50
- enabled: Boolean(sub?.enabled) && !settings.completedAt && level !== "off" && !(preferences.pausedUntil && Date.parse(preferences.pausedUntil) > now.getTime()),
47
+ enabled: Boolean(sub?.enabled) && !settings.completedAt && proactiveChecksAllowed(preferences, now),
51
48
  level,
52
49
  settings,
53
50
  preferences,
@@ -84,7 +81,7 @@ function quietHoursEnd(preferences, now) {
84
81
  function reserveProactiveNotification(subscriptionId, dedupeKey, now = /* @__PURE__ */ new Date()) {
85
82
  return runSqliteWriteTransaction((db) => {
86
83
  const policy = effectiveProactivePolicy(subscriptionId, now);
87
- if (!policy.enabled) return "suppressed";
84
+ if (!policy.enabled || policy.preferences.notificationsMuted) return "suppressed";
88
85
  if (policy.level === "quiet" || policy.settings.delivery === "inbox") return "suppressed";
89
86
  const end = quietHoursEnd(policy.preferences, now);
90
87
  if (end) return end;
@@ -116,5 +113,8 @@ function nextDigestTime(preferences, after) {
116
113
  }
117
114
  return new Date(after.getTime() + 864e5);
118
115
  }
116
+ function proactiveChecksAllowed(preferences, now = /* @__PURE__ */ new Date()) {
117
+ return !preferences.checksPaused && !(preferences.checksPausedUntil && Date.parse(preferences.checksPausedUntil) > now.getTime());
118
+ }
119
119
  //#endregion
120
- export { ProactiveConflict, effectiveProactivePolicy, localProactiveDay, nextDigestTime, proactivePreferences, quietHoursEnd, reserveProactiveNotification, subscriptionSettings, updateProactivePreferences };
120
+ export { ProactiveConflict, effectiveProactivePolicy, localProactiveDay, nextDigestTime, proactiveChecksAllowed, proactivePreferences, quietHoursEnd, reserveProactiveNotification, subscriptionSettings, updateProactivePreferences };
@@ -1,7 +1,7 @@
1
1
  export declare function requireSubscription(id: string, workspaceId: string): import("./types.js").ScenarioSubscription;
2
2
  export declare function controlledSubscriptions(workspaceId: string): {
3
3
  revision: number;
4
- level: "off" | "active" | "quiet" | "balanced";
4
+ level: "active" | "quiet" | "balanced";
5
5
  delivery: "digest" | "inbox" | "important";
6
6
  completedAt: string;
7
7
  scanIntervalMinutes: number;
@@ -18,7 +18,7 @@ export declare function controlledSubscriptions(workspaceId: string): {
18
18
  }[];
19
19
  export declare function createControlledSubscription(workspaceId: string, value: unknown): {
20
20
  revision: number;
21
- level: "off" | "active" | "quiet" | "balanced";
21
+ level: "active" | "quiet" | "balanced";
22
22
  delivery: "digest" | "inbox" | "important";
23
23
  completedAt: string;
24
24
  scanIntervalMinutes: number;
@@ -35,7 +35,7 @@ export declare function createControlledSubscription(workspaceId: string, value:
35
35
  };
36
36
  export declare function updateControlledSubscription(workspaceId: string, id: string, value: unknown): {
37
37
  revision: number;
38
- level: "off" | "active" | "quiet" | "balanced";
38
+ level: "active" | "quiet" | "balanced";
39
39
  delivery: "digest" | "inbox" | "important";
40
40
  completedAt: string;
41
41
  scanIntervalMinutes: number;
@@ -18,8 +18,6 @@ function saveSettings(id, value, revision) {
18
18
  const settings = ProactiveSubscriptionSettingsSchema.parse(value);
19
19
  getSqliteDatabase().prepare(`INSERT INTO proactive_subscription_settings(subscription_id, settings_json, revision) VALUES (?, ?, ?)
20
20
  ON CONFLICT(subscription_id) DO UPDATE SET settings_json = excluded.settings_json, revision = excluded.revision`).run(id, JSON.stringify(settings), revision);
21
- getSqliteDatabase().prepare(`INSERT INTO proactive_schedule_state(subscription_id, next_due_at) VALUES (?, ?)
22
- ON CONFLICT(subscription_id) DO UPDATE SET next_due_at = excluded.next_due_at`).run(id, (/* @__PURE__ */ new Date()).toISOString());
23
21
  }
24
22
  function createControlledSubscription(workspaceId, value) {
25
23
  const input = ProactiveSubscriptionCreateSchema.parse(value);
@@ -37,6 +35,7 @@ function createControlledSubscription(workspaceId, value) {
37
35
  });
38
36
  if (input.userInstructions || sub.activePromptRevisionId) publishPromptRevision(createPromptDraft(sub.id, input.userInstructions).id);
39
37
  saveSettings(sub.id, input, 1);
38
+ if (scopeKind === "project") getSqliteDatabase().prepare("INSERT INTO proactive_schedule_state(subscription_id, next_due_at) VALUES (?, ?)").run(sub.id, (/* @__PURE__ */ new Date()).toISOString());
40
39
  return controlledSubscriptions(workspaceId).find((item) => item.id === sub.id);
41
40
  });
42
41
  }
@@ -55,6 +54,17 @@ function updateControlledSubscription(workspaceId, id, value) {
55
54
  ...current,
56
55
  ...patch
57
56
  }, current.revision + 1);
57
+ if (sub.scopeKind === "project") {
58
+ const db = getSqliteDatabase();
59
+ const changedInstructions = patch.userInstructions !== void 0 && patch.userInstructions !== current.userInstructions;
60
+ const resumed = patch.enabled === true && !sub.enabled;
61
+ if (changedInstructions || resumed) db.prepare("UPDATE proactive_schedule_state SET next_due_at = ?, last_fingerprint = NULL WHERE subscription_id = ?").run((/* @__PURE__ */ new Date()).toISOString(), id);
62
+ else if (patch.scanIntervalMinutes !== void 0 && patch.scanIntervalMinutes !== current.scanIntervalMinutes) {
63
+ const schedule = db.prepare("SELECT last_checked_at FROM proactive_schedule_state WHERE subscription_id = ?").get(id);
64
+ const next = Math.max(Date.now(), schedule?.last_checked_at ? Date.parse(schedule.last_checked_at) + (patch.scanIntervalMinutes ?? 120) * 6e4 : Date.now());
65
+ db.prepare("UPDATE proactive_schedule_state SET next_due_at = ? WHERE subscription_id = ?").run(new Date(next).toISOString(), id);
66
+ }
67
+ }
58
68
  return controlledSubscriptions(workspaceId).find((item) => item.id === id);
59
69
  });
60
70
  }
@@ -0,0 +1,8 @@
1
+ /** Only a successful pull of this collection proves its observed coverage. */
2
+ export declare function sourceFreshness(itemId: string, notBefore?: string, now?: number): {
3
+ fresh: boolean;
4
+ lastSyncedAt: string;
5
+ syncFailed: boolean;
6
+ version: string;
7
+ };
8
+ export declare function evidenceSourcesFresh(ids: string[], context?: Record<string, unknown>): boolean;
@@ -0,0 +1,27 @@
1
+ import { getSqliteDatabase } from "../storage/sqlite/transaction.js";
2
+ import { getKnowledgeSourceItem } from "../storage/sqlite/knowledge-repository.js";
3
+ //#region src/proactive/source-freshness.ts
4
+ const MAX_SOURCE_AGE_MS = 30 * 6e4;
5
+ /** Only a successful pull of this collection proves its observed coverage. */
6
+ function sourceFreshness(itemId, notBefore, now = Date.now()) {
7
+ const item = getKnowledgeSourceItem(itemId);
8
+ const row = item ? getSqliteDatabase().prepare(`SELECT run_id, status, started_at, finished_at FROM knowledge_sync_runs
9
+ WHERE source_instance_id = ? AND collection_scope = ? ORDER BY started_at DESC, rowid DESC LIMIT 1`).get(item.sourceInstanceId, item.collectionScope) : void 0;
10
+ const lastSuccess = item ? getSqliteDatabase().prepare("SELECT MAX(finished_at) AS at FROM knowledge_sync_runs WHERE source_instance_id = ? AND collection_scope = ? AND status = 'succeeded'").get(item.sourceInstanceId, item.collectionScope) : void 0;
11
+ return {
12
+ fresh: Boolean(row?.status === "succeeded" && row.finished_at && row.started_at <= now && now - row.started_at <= MAX_SOURCE_AGE_MS && (!notBefore || row.started_at >= Date.parse(notBefore))),
13
+ lastSyncedAt: lastSuccess?.at ? new Date(lastSuccess.at).toISOString() : null,
14
+ syncFailed: Boolean(row && [
15
+ "failed",
16
+ "partial",
17
+ "cancelled"
18
+ ].includes(row.status)),
19
+ version: row?.run_id ?? "unknown"
20
+ };
21
+ }
22
+ function evidenceSourcesFresh(ids, context) {
23
+ const follow = context?.follow_up;
24
+ return ids.every((id) => !id.startsWith("source-item:") || sourceFreshness(id.slice(12), follow?.deadlinePassed ? follow.dueAt : void 0).fresh);
25
+ }
26
+ //#endregion
27
+ export { evidenceSourcesFresh, sourceFreshness };
@@ -0,0 +1,2 @@
1
+ import type { ProactiveCheckStatus } from '@xopcai/gateway-contract';
2
+ export declare function followUpCheckStatus(subscriptionId: string, project: boolean): ProactiveCheckStatus;
@@ -0,0 +1,21 @@
1
+ import { getSqliteDatabase } from "../storage/sqlite/transaction.js";
2
+ import { effectiveProactivePolicy } from "./policy/service.js";
3
+ //#region src/proactive/status.ts
4
+ function followUpCheckStatus(subscriptionId, project) {
5
+ const db = getSqliteDatabase();
6
+ const recent = db.prepare(`SELECT run_id AS id, status, outcome_reason AS outcome, started_at AS startedAt,
7
+ completed_at AS completedAt, next_attempt_at AS retryAt, attempt FROM proactive_runs
8
+ WHERE subscription_id = ? ORDER BY started_at DESC LIMIT 5`).all(subscriptionId);
9
+ const schedule = project ? db.prepare("SELECT last_checked_at, next_due_at FROM proactive_schedule_state WHERE subscription_id = ?").get(subscriptionId) : void 0;
10
+ const pending = db.prepare("SELECT status FROM proactive_signal_batches WHERE subscription_id = ? AND status IN ('collecting', 'ready', 'processing') ORDER BY created_at DESC LIMIT 1").get(subscriptionId);
11
+ const latest = recent[0];
12
+ const enabled = effectiveProactivePolicy(subscriptionId).enabled;
13
+ return {
14
+ health: !enabled ? "waiting" : pending?.status === "processing" ? "running" : pending ? "queued" : latest?.status === "retryable" ? "retrying" : latest?.status === "failed" || latest?.outcome === "source_unavailable" || latest?.outcome === "source_stale" ? "blocked" : "waiting",
15
+ recent,
16
+ lastCheckedAt: schedule?.last_checked_at ?? recent.find((run) => run.status === "completed")?.completedAt ?? null,
17
+ nextCheckAt: !enabled ? null : latest?.status === "retryable" ? latest.retryAt : schedule?.next_due_at ?? null
18
+ };
19
+ }
20
+ //#endregion
21
+ export { followUpCheckStatus };
@@ -1,6 +1,7 @@
1
1
  import { createLogger } from "../../utils/logger/index.js";
2
2
  import { init_logger } from "../../utils/logger.js";
3
3
  import { listKnowledgeSourceItems } from "../../storage/sqlite/knowledge-repository.js";
4
+ import { sourceFreshness } from "../source-freshness.js";
4
5
  import { authorizedConnectedSource } from "../execution/authorization.js";
5
6
  import { effectiveProactivePolicy } from "../policy/service.js";
6
7
  import { listSubscriptions } from "../scenarios/repository.js";
@@ -84,7 +85,7 @@ var ProactiveTemporalWorker = class {
84
85
  const connectorId = metadataString(item.metadata, "connectorId");
85
86
  const agentId = metadataString(item.metadata, "agentId");
86
87
  const window = meetingWindow(item.occurredAt ? Date.parse(item.occurredAt) : NaN, nowMs);
87
- if (!connectionId || !workspaceId || !activeWorkspaces.has(workspaceId) || !connectorId || !window || !isMeetingWorthPreparing(item.normalizedText) || !authorizedConnectedSource(item.id, workspaceId, MEETING_SCENARIO, agentId) || item.sensitivity === "secret" || item.sensitivity === "regulated") {
88
+ if (!connectionId || !workspaceId || !activeWorkspaces.has(workspaceId) || !connectorId || !window || !sourceFreshness(item.id, void 0, now.getTime()).fresh || !isMeetingWorthPreparing(item.normalizedText) || !authorizedConnectedSource(item.id, workspaceId, MEETING_SCENARIO, agentId) || item.sensitivity === "secret" || item.sensitivity === "regulated") {
88
89
  result.skipped += 1;
89
90
  continue;
90
91
  }
@@ -119,14 +119,38 @@ var RealtimeRuntime = class {
119
119
  budgetHeld = false;
120
120
  this.preauthBudget.release(clientIp);
121
121
  };
122
+ const guardConnection = (phase, action) => {
123
+ try {
124
+ action();
125
+ } catch (err) {
126
+ const errorMessage = err instanceof Error ? err.message : String(err);
127
+ log.error({
128
+ err,
129
+ errorMessage,
130
+ phase,
131
+ connectionId,
132
+ endpointId,
133
+ principalId
134
+ }, `Realtime connection failed: ${errorMessage}`);
135
+ socket.terminate();
136
+ }
137
+ };
138
+ socket.on("error", (err) => {
139
+ log.warn({
140
+ err,
141
+ connectionId,
142
+ endpointId
143
+ }, `Realtime socket failed: ${err.message}`);
144
+ socket.terminate();
145
+ });
122
146
  const helloTimer = setTimeout(() => socket.close(4401, "Realtime hello timeout"), REALTIME_HELLO_TIMEOUT_MS);
123
- const heartbeatTimer = setInterval(() => {
147
+ const heartbeatTimer = setInterval(() => guardConnection("heartbeat", () => {
124
148
  if (principalId && !this.isPrincipalActive(principalId)) {
125
149
  socket.terminate();
126
150
  return;
127
151
  }
128
152
  if (Date.now() - lastSeenAt > 45e3) socket.close(4408, "Realtime heartbeat timeout");
129
- }, REALTIME_HEARTBEAT_INTERVAL_MS);
153
+ }), REALTIME_HEARTBEAT_INTERVAL_MS);
130
154
  const sendError = (code, message) => {
131
155
  writer.enqueue(serverMessage("realtime.error", {
132
156
  code,
@@ -166,7 +190,7 @@ var RealtimeRuntime = class {
166
190
  }
167
191
  return true;
168
192
  };
169
- socket.on("message", (data, isBinary) => {
193
+ socket.on("message", (data, isBinary) => guardConnection("message", () => {
170
194
  if (isBinary) {
171
195
  socket.close(4400, "Binary realtime frames are not supported");
172
196
  return;
@@ -267,7 +291,7 @@ var RealtimeRuntime = class {
267
291
  }, "Realtime endpoint message failed");
268
292
  socket.close(4400, "Invalid endpoint message");
269
293
  }
270
- });
294
+ }));
271
295
  socket.on("close", (code, reasonBuffer) => {
272
296
  clearTimeout(helloTimer);
273
297
  clearInterval(heartbeatTimer);
@@ -275,7 +299,9 @@ var RealtimeRuntime = class {
275
299
  writer.close();
276
300
  for (const handle of subscriptions.values()) handle.unsubscribe();
277
301
  subscriptions.clear();
278
- if (endpointId && connectionId) this.endpointTools?.remove(endpointId, connectionId);
302
+ guardConnection("endpoint_remove", () => {
303
+ if (endpointId && connectionId) this.endpointTools?.remove(endpointId, connectionId);
304
+ });
279
305
  if (principalId) {
280
306
  const principalSockets = this.socketsByPrincipal.get(principalId);
281
307
  principalSockets?.delete(socket);
@@ -67,16 +67,23 @@ var RealtimeSocketWriter = class {
67
67
  const item = this.critical.shift() ?? this.normal.shift();
68
68
  if (!item) return;
69
69
  this.sending = true;
70
- this.socket.send(item.data, (error) => {
70
+ try {
71
+ this.socket.send(item.data, (error) => {
72
+ if (this.closed) return;
73
+ this.sending = false;
74
+ this.queuedBytes -= item.bytes;
75
+ if (error) {
76
+ this.socket.close(1011, "Realtime delivery failed");
77
+ this.close();
78
+ return;
79
+ }
80
+ this.flush();
81
+ });
82
+ } catch {
71
83
  this.sending = false;
72
- this.queuedBytes -= item.bytes;
73
- if (error) {
74
- this.socket.close(1011, "Realtime delivery failed");
75
- this.close();
76
- return;
77
- }
78
- this.flush();
79
- });
84
+ this.close();
85
+ this.socket.close(1011, "Realtime delivery failed");
86
+ }
80
87
  }
81
88
  };
82
89
  //#endregion
@@ -0,0 +1,18 @@
1
+ import type { ImportJob, ImportPlan, ImportScan } from '../../imports/types.js';
2
+ type Records = {
3
+ scan: ImportScan;
4
+ plan: ImportPlan;
5
+ job: ImportJob;
6
+ };
7
+ export declare class ImportRepository {
8
+ readonly owner: string;
9
+ constructor(owner: string);
10
+ get<K extends keyof Records>(kind: K, id: string): Records[K];
11
+ save<K extends keyof Records>(kind: K, value: Records[K], key?: string): void;
12
+ byKey(key: string): ImportJob | undefined;
13
+ static owners(): string[];
14
+ scansBefore(time: number): ImportScan[];
15
+ deleteScan(id: string): void;
16
+ jobs(limit?: number): ImportJob[];
17
+ }
18
+ export {};
@@ -0,0 +1,35 @@
1
+ import { requireXopcDatabase } from "./connection.js";
2
+ import { ImportError } from "../../imports/types.js";
3
+ //#region src/storage/sqlite/import-repository.ts
4
+ var ImportRepository = class {
5
+ constructor(owner) {
6
+ this.owner = owner;
7
+ }
8
+ get(kind, id) {
9
+ const row = requireXopcDatabase().db.prepare("SELECT payload FROM capability_imports WHERE owner = ? AND kind = ? AND id = ?").get(this.owner, kind, id);
10
+ if (!row) throw new ImportError("not_found", "Import record not found", 404);
11
+ return JSON.parse(row.payload);
12
+ }
13
+ save(kind, value, key) {
14
+ requireXopcDatabase().db.prepare(`INSERT INTO capability_imports(id, owner, kind, created_at, payload, idempotency_key)
15
+ VALUES (?, ?, ?, ?, ?, ?) ON CONFLICT(id) DO UPDATE SET payload = excluded.payload WHERE capability_imports.owner = excluded.owner`).run(value.id, this.owner, kind, value.createdAt, JSON.stringify(value), key ?? null);
16
+ }
17
+ byKey(key) {
18
+ const row = requireXopcDatabase().db.prepare("SELECT payload FROM capability_imports WHERE owner = ? AND kind = ? AND idempotency_key = ?").get(this.owner, "job", key);
19
+ return row ? JSON.parse(row.payload) : void 0;
20
+ }
21
+ static owners() {
22
+ return requireXopcDatabase().db.prepare("SELECT DISTINCT owner FROM capability_imports").all().map((r) => r.owner);
23
+ }
24
+ scansBefore(time) {
25
+ return requireXopcDatabase().db.prepare("SELECT payload FROM capability_imports WHERE owner = ? AND kind = ? AND created_at < ?").all(this.owner, "scan", time).map((r) => JSON.parse(r.payload));
26
+ }
27
+ deleteScan(id) {
28
+ requireXopcDatabase().db.prepare("DELETE FROM capability_imports WHERE owner = ? AND kind = 'scan' AND id = ?").run(this.owner, id);
29
+ }
30
+ jobs(limit = 100) {
31
+ return requireXopcDatabase().db.prepare("SELECT payload FROM capability_imports WHERE owner = ? AND kind = ? ORDER BY created_at DESC LIMIT ?").all(this.owner, "job", limit).map((r) => JSON.parse(r.payload));
32
+ }
33
+ };
34
+ //#endregion
35
+ export { ImportRepository };
@@ -0,0 +1,15 @@
1
+ import { type StoredInventory, type ProductImportResult } from '../../imports/types.js';
2
+ type Records = {
3
+ inventory: StoredInventory;
4
+ run: ProductImportResult;
5
+ };
6
+ export declare class ImportSelectionRepository {
7
+ readonly owner: string;
8
+ constructor(owner: string);
9
+ get<K extends keyof Records>(kind: K, id: string): Records[K];
10
+ save<K extends keyof Records>(kind: K, value: Records[K]): void;
11
+ list<K extends keyof Records>(kind: K): Records[K][];
12
+ deleteInventory(id: string): void;
13
+ static owners(): string[];
14
+ }
15
+ export {};
@@ -0,0 +1,28 @@
1
+ import { requireXopcDatabase } from "./connection.js";
2
+ import { ImportError } from "../../imports/types.js";
3
+ //#region src/storage/sqlite/import-selection-repository.ts
4
+ var ImportSelectionRepository = class {
5
+ constructor(owner) {
6
+ this.owner = owner;
7
+ }
8
+ get(kind, id) {
9
+ const row = requireXopcDatabase().db.prepare("SELECT payload FROM import_selections WHERE owner = ? AND kind = ? AND id = ?").get(this.owner, kind, id);
10
+ if (!row) throw new ImportError("not_found", "Import record not found", 404);
11
+ return JSON.parse(row.payload);
12
+ }
13
+ save(kind, value) {
14
+ if (!requireXopcDatabase().db.prepare(`INSERT INTO import_selections(id, owner, kind, created_at, payload) VALUES (?, ?, ?, ?, ?)
15
+ ON CONFLICT(id) DO UPDATE SET payload = excluded.payload WHERE import_selections.owner = excluded.owner AND import_selections.kind = excluded.kind`).run(value.id, this.owner, kind, value.createdAt, JSON.stringify(value)).changes) throw new ImportError("conflict", "Import ID is already in use", 409);
16
+ }
17
+ list(kind) {
18
+ return requireXopcDatabase().db.prepare("SELECT payload FROM import_selections WHERE owner = ? AND kind = ? ORDER BY created_at DESC").all(this.owner, kind).map((r) => JSON.parse(r.payload));
19
+ }
20
+ deleteInventory(id) {
21
+ requireXopcDatabase().db.prepare("DELETE FROM import_selections WHERE owner = ? AND kind = 'inventory' AND id = ?").run(this.owner, id);
22
+ }
23
+ static owners() {
24
+ return requireXopcDatabase().db.prepare("SELECT DISTINCT owner FROM import_selections").all().map((r) => r.owner);
25
+ }
26
+ };
27
+ //#endregion
28
+ export { ImportSelectionRepository };
@@ -1,6 +1,7 @@
1
1
  import type { KnowledgeSourceChange, KnowledgeSourceItem, KnowledgeSourceItemInput, KnowledgeSyncRun, KnowledgeSyncRunStatus, KnowledgeSynthesisPipeline, KnowledgeSynthesisStatus, KnowledgeRetentionClass } from '../../knowledge/types.js';
2
2
  export declare function startKnowledgeSyncRun(input: {
3
3
  sourceInstanceId: string;
4
+ collectionScope?: string;
4
5
  cursorBefore?: string;
5
6
  nowMs?: number;
6
7
  }): KnowledgeSyncRun;
@@ -85,8 +85,8 @@ function startKnowledgeSyncRun(input) {
85
85
  const now = input.nowMs ?? Date.now();
86
86
  runSqliteWriteTransaction((db) => {
87
87
  db.prepare(`INSERT INTO knowledge_sync_runs (
88
- run_id, source_instance_id, status, cursor_before, started_at
89
- ) VALUES (?, ?, 'running', ?, ?)`).run(id, input.sourceInstanceId, input.cursorBefore ?? null, now);
88
+ run_id, source_instance_id, status, cursor_before, started_at, collection_scope
89
+ ) VALUES (?, ?, 'running', ?, ?, ?)`).run(id, input.sourceInstanceId, input.cursorBefore ?? null, now, input.collectionScope ?? null);
90
90
  });
91
91
  return {
92
92
  id,
@@ -0,0 +1,11 @@
1
+ CREATE TABLE capability_imports (
2
+ id TEXT PRIMARY KEY,
3
+ owner TEXT NOT NULL,
4
+ kind TEXT NOT NULL CHECK (kind IN ('scan', 'plan', 'job', 'run')),
5
+ created_at INTEGER NOT NULL,
6
+ idempotency_key TEXT,
7
+ payload TEXT NOT NULL
8
+ );
9
+ CREATE INDEX capability_imports_owner_kind ON capability_imports(owner, kind, created_at DESC);
10
+ CREATE UNIQUE INDEX capability_imports_idempotency ON capability_imports(owner, idempotency_key)
11
+ WHERE idempotency_key IS NOT NULL;
@@ -0,0 +1,8 @@
1
+ CREATE TABLE import_selections (
2
+ id TEXT PRIMARY KEY,
3
+ owner TEXT NOT NULL,
4
+ kind TEXT NOT NULL CHECK (kind IN ('inventory', 'run')),
5
+ created_at INTEGER NOT NULL,
6
+ payload TEXT NOT NULL
7
+ );
8
+ CREATE INDEX import_selections_owner_kind ON import_selections(owner, kind, created_at DESC);
@@ -0,0 +1,5 @@
1
+ ALTER TABLE knowledge_sync_runs ADD COLUMN collection_scope TEXT;
2
+ ALTER TABLE proactive_presence ADD COLUMN inbox_item_id TEXT;
3
+ ALTER TABLE proactive_presence ADD COLUMN notification_revision INTEGER;
4
+ ALTER TABLE proactive_inbox_items ADD COLUMN actionable_until TEXT;
5
+ CREATE INDEX knowledge_sync_source_scope ON knowledge_sync_runs(source_instance_id, collection_scope, started_at DESC);
@@ -0,0 +1,25 @@
1
+ UPDATE proactive_preferences SET preferences_json = json_remove(json_set(preferences_json,
2
+ '$.checksPaused', json(CASE WHEN json_extract(preferences_json, '$.level') = 'off' THEN 'true' ELSE 'false' END),
3
+ '$.checksPausedUntil', json_extract(preferences_json, '$.pausedUntil'),
4
+ '$.level', CASE WHEN json_extract(preferences_json, '$.level') = 'off' THEN 'balanced' ELSE COALESCE(json_extract(preferences_json, '$.level'), 'balanced') END), '$.pausedUntil');
5
+ UPDATE proactive_scenario_subscriptions SET enabled = 0 WHERE subscription_id IN
6
+ (SELECT subscription_id FROM proactive_subscription_settings WHERE json_extract(settings_json, '$.level') = 'off');
7
+ UPDATE proactive_subscription_settings SET settings_json = json_set(settings_json, '$.level', NULL)
8
+ WHERE json_extract(settings_json, '$.level') = 'off';
9
+ CREATE TABLE heartbeat_checks (
10
+ id TEXT PRIMARY KEY,
11
+ workspace_id TEXT NOT NULL,
12
+ started_at TEXT NOT NULL,
13
+ completed_at TEXT,
14
+ status TEXT NOT NULL,
15
+ detail TEXT,
16
+ content TEXT,
17
+ target TEXT,
18
+ chat_id TEXT,
19
+ fingerprint TEXT,
20
+ delivery_status TEXT NOT NULL DEFAULT 'none',
21
+ next_attempt_at TEXT,
22
+ expires_at TEXT NOT NULL
23
+ );
24
+ CREATE INDEX heartbeat_checks_recent ON heartbeat_checks(workspace_id, started_at DESC);
25
+ CREATE INDEX heartbeat_checks_pending ON heartbeat_checks(delivery_status, next_attempt_at);
@@ -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 = 173;
6
+ export declare const XOPC_DB_SCHEMA_VERSION = 177;
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 = 173;
15
+ const XOPC_DB_SCHEMA_VERSION = 177;
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 ?? 173;
60
+ const targetVersion = options.targetVersion ?? 177;
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 ?? 173;
97
+ const appVersion = options.targetVersion ?? 177;
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 = 173;
22
+ export const XOPC_DB_SCHEMA_VERSION = 177;
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: 173,
35
+ targetVersion: 177,
36
36
  databasePath: options.databasePath
37
37
  });
38
38
  }
@@ -4,8 +4,8 @@ import { homedir } from "node:os";
4
4
  import { basename, extname, isAbsolute, join, resolve } from "node:path";
5
5
  import { constants } from "node:fs";
6
6
  import { execFile } from "node:child_process";
7
- import { access, readFile, readdir, realpath, stat } from "node:fs/promises";
8
7
  import { promisify } from "node:util";
8
+ import { access, readFile, readdir, realpath, stat } from "node:fs/promises";
9
9
  //#region src/work-discovery/candidate-discovery.ts
10
10
  const execFileAsync = promisify(execFile);
11
11
  const COMMON_WORK_ROOT_NAMES = [
@@ -3,9 +3,9 @@ import "../projects/index.js";
3
3
  import { basename, extname, isAbsolute, relative, resolve, sep } from "node:path";
4
4
  import { constants } from "node:fs";
5
5
  import { execFile } from "node:child_process";
6
+ import { promisify } from "node:util";
6
7
  import { createHash } from "node:crypto";
7
8
  import { access, lstat, readFile, readdir, realpath, stat } from "node:fs/promises";
8
- import { promisify } from "node:util";
9
9
  //#region src/work-discovery/probe.ts
10
10
  const execFileAsync = promisify(execFile);
11
11
  const WORK_DISCOVERY_SCAN_POLICY_VERSION = 1;