@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.
- package/dist/browser-ext/manifest.json +1 -1
- package/dist/extensions/telegram/xopc.extension.json +1 -1
- package/dist/gateway/static/root/assets/{activity-store-iPtG94qr.js → activity-store-B0BTIk9j.js} +1 -1
- package/dist/gateway/static/root/assets/{agent-avatar-dicebear-DQ74xqLi.js → agent-avatar-dicebear-Dc-0QZTQ.js} +1 -1
- package/dist/gateway/static/root/assets/agent-defaults-settings-panel-CcmqK1Sc.js +1 -0
- package/dist/gateway/static/root/assets/agents-B_7PVt7S.js +1 -0
- package/dist/gateway/static/root/assets/api-COG_Tzpv.js +1 -0
- package/dist/gateway/static/root/assets/{api-KMJzMqvZ.js → api-Coly9ab6.js} +1 -1
- package/dist/gateway/static/root/assets/{app-management-settings-panel-B42TpqIb.js → app-management-settings-panel-TWBO-msg.js} +1 -1
- package/dist/gateway/static/root/assets/{appearance-settings-D9Lfe7Sk.js → appearance-settings-CpTZ2KuT.js} +1 -1
- package/dist/gateway/static/root/assets/apps-page-6qxxKFsK.js +1 -0
- package/dist/gateway/static/root/assets/{archive-plugin-BdmQwj4x.js → archive-plugin-z_u6alob.js} +1 -1
- package/dist/gateway/static/root/assets/{attachment-load-B4S0_nji.js → attachment-load-C2nS04TC.js} +1 -1
- package/dist/gateway/static/root/assets/{automations-page-B3TmHNjQ.js → automations-page-aIBsw9zR.js} +1 -1
- package/dist/gateway/static/root/assets/automations-workspace-BRQlU4qk.js +6 -0
- package/dist/gateway/static/root/assets/{binary-plugins-B3cXF_DP.js → binary-plugins-CGmXoZnl.js} +1 -1
- package/dist/gateway/static/root/assets/{block-editor-05zyBXBe.js → block-editor-CtvzCZhC.js} +3 -3
- package/dist/gateway/static/root/assets/{browser-automation-inputs-BTIufVbM.js → browser-automation-inputs-BOTU1isH.js} +1 -1
- package/dist/gateway/static/root/assets/{browser-automations-page-DRBA9nwe.js → browser-automations-page-BwU5V8J0.js} +2 -2
- package/dist/gateway/static/root/assets/browser-settings-page-DDjbDeHQ.js +8 -0
- package/dist/gateway/static/root/assets/capabilities-settings-panel-DM1Bcf1x.js +8 -0
- package/dist/gateway/static/root/assets/channels-settings-Bq36CUxL.js +1 -0
- package/dist/gateway/static/root/assets/{channels-status-swr-DMYQNs-J.js → channels-status-swr-Dfi0Desh.js} +1 -1
- package/dist/gateway/static/root/assets/{chat-terminal-dock-Dx5KQyo5.js → chat-terminal-dock-B0MvcO6j.js} +2 -2
- package/dist/gateway/static/root/assets/connectors-page-L8JehrxF.js +2 -0
- package/dist/gateway/static/root/assets/{date-picker-CkDROZoe.js → date-picker-DXOvbHCr.js} +1 -1
- package/dist/gateway/static/root/assets/{dependency-picker-Bl8HcvzL.js → dependency-picker-BEnC-eS0.js} +1 -1
- package/dist/gateway/static/root/assets/{desktop-pet-BcknAjbW.js → desktop-pet-DtPNvznL.js} +1 -1
- package/dist/gateway/static/root/assets/{desktop-pet-settings-BuCpXQPm.js → desktop-pet-settings-CYyjcSn6.js} +1 -1
- package/dist/gateway/static/root/assets/device-pairing-wizard-BPMGvAKE.js +1 -0
- package/dist/gateway/static/root/assets/{extension-debug-page-qRpb2FFa.js → extension-debug-page-H_aPMGXW.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-C7gs9wu4.js → extension-page-C1JnpeMt.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-settings-page-CyJP1CMZ.js → extension-settings-page-C75kCOqe.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-config-swr-Cpmyrr6j.js → gateway-config-swr-G2lQt7Ak.js} +1 -1
- package/dist/gateway/static/root/assets/gateway-settings-BCF732TU.js +1 -0
- package/dist/gateway/static/root/assets/{gateway-startup-retry-DoiPeb65.js → gateway-startup-retry-GP31PUrG.js} +1 -1
- package/dist/gateway/static/root/assets/{heartbeat-settings-CV6Dolcn.js → heartbeat-settings-C7fjiowt.js} +1 -1
- package/dist/gateway/static/root/assets/home-page-DZXeXdUL.js +1 -0
- package/dist/gateway/static/root/assets/{image-generation-api-CqjHWl2T.js → image-generation-api-CKFhfHSw.js} +1 -1
- package/dist/gateway/static/root/assets/imports-page-GROumhj8.js +1 -0
- package/dist/gateway/static/root/assets/{index-CHgOG1aR.js → index-ChIrvv3t.js} +47 -47
- package/dist/gateway/static/root/assets/index-R1VNlHjj.css +2 -0
- package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-B3XqA41D.js → keyboard-shortcuts-settings-zcI822m_.js} +1 -1
- package/dist/gateway/static/root/assets/local-app-workbench-page-CAEKGTAg.js +2 -0
- package/dist/gateway/static/root/assets/{local-apps-page-BcIVYp0J.js → local-apps-page-BtgDJ92Q.js} +1 -1
- package/dist/gateway/static/root/assets/{locale-store-1urrBBCQ.js → locale-store-DlOv7896.js} +1 -1
- package/dist/gateway/static/root/assets/logs-page-DHZ4BEkG.js +2 -0
- package/dist/gateway/static/root/assets/{management-settings-DNFCdgzR.js → management-settings-DasZxCyD.js} +1 -1
- package/dist/gateway/static/root/assets/{markdown-view-BZmcFIWa.js → markdown-view-6oYdBahT.js} +1 -1
- package/dist/gateway/static/root/assets/{media-plugins-BDxNhoBC.js → media-plugins-CxthbBvk.js} +1 -1
- package/dist/gateway/static/root/assets/messages-Ls1Aaiqd.js +3 -0
- package/dist/gateway/static/root/assets/note-detail-panel-BcWq3ddw.js +5 -0
- package/dist/gateway/static/root/assets/notes-page-DfZ8QWyv.js +8 -0
- package/dist/gateway/static/root/assets/{page-tabs-agH3a2PI.js → page-tabs-BG39KidE.js} +1 -1
- package/dist/gateway/static/root/assets/{preview-open-alternatives-XEZ7zDOP.js → preview-open-alternatives-Bevpbq9f.js} +1 -1
- package/dist/gateway/static/root/assets/proactive-page-D2U_xQaS.js +1 -0
- package/dist/gateway/static/root/assets/{product-open-page-lXAbj85Z.js → product-open-page-Bi1seZpM.js} +1 -1
- package/dist/gateway/static/root/assets/project-detail-page-CzlGTW4F.js +1 -0
- package/dist/gateway/static/root/assets/projects-page-mQsM-TsP.js +1 -0
- package/dist/gateway/static/root/assets/{registry-api-CxQstD00.js → registry-api-D0ddwBFj.js} +1 -1
- package/dist/gateway/static/root/assets/remote-access-hub-Cb56JcO1.js +1 -0
- package/dist/gateway/static/root/assets/{runtime-tools-settings-panel-DErKZlVJ.js → runtime-tools-settings-panel-Wkru8_My.js} +2 -2
- package/dist/gateway/static/root/assets/{schema-form-DhCmJQVJ.js → schema-form-CSMRzj9Y.js} +1 -1
- package/dist/gateway/static/root/assets/sessions-page-Hj9uFcIO.js +1 -0
- package/dist/gateway/static/root/assets/settings-advanced-gate-CV4-_EVA.js +1 -0
- package/dist/gateway/static/root/assets/{settings-form-section-Dg6chotg.js → settings-form-section-wcAdCkK8.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-page-LyuN5N3M.js → settings-page-BcQGAnCs.js} +1 -1
- package/dist/gateway/static/root/assets/setup-status-panel-DzxmsaQG.js +1 -0
- package/dist/gateway/static/root/assets/{share-preview-page-CZvmf4Ob.js → share-preview-page-DQocUl-1.js} +1 -1
- package/dist/gateway/static/root/assets/shares-settings-xlJh1ccG.js +1 -0
- package/dist/gateway/static/root/assets/skill-reload-api-wSXJRSxX.js +1 -0
- package/dist/gateway/static/root/assets/skills-page-AmqtBJo7.js +2 -0
- package/dist/gateway/static/root/assets/{skills-page.utils-Eu0WVHTS.js → skills-page.utils-DtlfCgJp.js} +1 -1
- package/dist/gateway/static/root/assets/{system-settings-panel-DQKkM7B2.js → system-settings-panel-Ct698Nf-.js} +1 -1
- package/dist/gateway/static/root/assets/task-detail-page-sQpwq5-c.js +1 -0
- package/dist/gateway/static/root/assets/{theme-store-Dc5s20V3.js → theme-store-ng8KJsAT.js} +1 -1
- package/dist/gateway/static/root/assets/{tunnel-api-TKQpPVd6.js → tunnel-api-Boajol0M.js} +1 -1
- package/dist/gateway/static/root/assets/{use-autosave-CkVlrFk1.js → use-autosave-BSyxRHt2.js} +1 -1
- package/dist/gateway/static/root/assets/user-model-page-DIEHnAER.js +2 -0
- package/dist/gateway/static/root/assets/{voice-api-key-field-B12fFN-L.js → voice-api-key-field-SE3OQI1s.js} +1 -1
- package/dist/gateway/static/root/assets/{voice-config-api-Mk78BrpP.js → voice-config-api-VNuCmdFe.js} +1 -1
- package/dist/gateway/static/root/assets/{work-discovery-overlay-CT9Zy36i.js → work-discovery-overlay-Dn1vy2oq.js} +1 -1
- package/dist/gateway/static/root/assets/{workflow-run-setup-panel-BwefQliE.js → workflow-run-setup-panel-BJEfGY-k.js} +2 -2
- package/dist/gateway/static/root/assets/workflows-page-DgRNIyr7.js +6 -0
- package/dist/gateway/static/root/index.html +10 -10
- package/dist/package.js +1 -1
- package/dist/packages/gateway-contract/src/proactive.js +13 -4
- package/dist/src/agent/coding/repository-instructions.js +1 -1
- package/dist/src/agent/coding/workspace-revision.js +1 -1
- package/dist/src/agent/commands/command-isolation.js +1 -1
- package/dist/src/agent/tools/factory.js +7 -3
- package/dist/src/agent/tools/review-workspace.js +1 -1
- package/dist/src/browser/providers/browser-ext-install.js +10 -2
- package/dist/src/cli/command-loaders.js +1 -0
- package/dist/src/cli/command-manifest.js +4 -0
- package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
- package/dist/src/cli/commands/gateway/lifecycle.js +1 -1
- package/dist/src/cli/commands/gateway/run-foreground.js +3 -0
- package/dist/src/cli/commands/import.d.ts +2 -0
- package/dist/src/cli/commands/import.js +78 -0
- package/dist/src/discussions/action-tasks.js +1 -1
- package/dist/src/discussions/edits.js +1 -1
- package/dist/src/discussions/index.js +1 -1
- package/dist/src/discussions/organizer.js +1 -1
- package/dist/src/discussions/recording.js +1 -1
- package/dist/src/discussions/sealer.js +1 -1
- package/dist/src/discussions/service.js +2 -2
- package/dist/src/endpoint-tools/invocation-service.d.ts +2 -0
- package/dist/src/endpoint-tools/invocation-service.js +48 -19
- package/dist/src/gateway/heartbeat/check-store.d.ts +18 -0
- package/dist/src/gateway/heartbeat/check-store.js +73 -0
- package/dist/src/gateway/heartbeat/service.d.ts +12 -3
- package/dist/src/gateway/heartbeat/service.js +61 -44
- package/dist/src/gateway/hono/routes/discussions.js +2 -2
- package/dist/src/gateway/hono/routes/imports.d.ts +3 -0
- package/dist/src/gateway/hono/routes/imports.js +56 -0
- package/dist/src/gateway/hono/routes/lazy-bundles.js +8 -0
- package/dist/src/gateway/hono/routes/proactive-control.js +2 -1
- package/dist/src/gateway/service.d.ts +7 -0
- package/dist/src/gateway/service.js +26 -9
- package/dist/src/imports/compatibility.d.ts +7 -0
- package/dist/src/imports/compatibility.js +174 -0
- package/dist/src/imports/contextImport.d.ts +3 -0
- package/dist/src/imports/contextImport.js +56 -0
- package/dist/src/imports/files.d.ts +13 -0
- package/dist/src/imports/files.js +77 -0
- package/dist/src/imports/importService.d.ts +50 -0
- package/dist/src/imports/importService.js +414 -0
- package/dist/src/imports/inventory.d.ts +11 -0
- package/dist/src/imports/inventory.js +202 -0
- package/dist/src/imports/planner.d.ts +11 -0
- package/dist/src/imports/planner.js +98 -0
- package/dist/src/imports/productImport.d.ts +10 -0
- package/dist/src/imports/productImport.js +241 -0
- package/dist/src/imports/runtime.d.ts +5 -0
- package/dist/src/imports/runtime.js +61 -0
- package/dist/src/imports/scanner.d.ts +14 -0
- package/dist/src/imports/scanner.js +159 -0
- package/dist/src/imports/secrets.d.ts +2 -0
- package/dist/src/imports/secrets.js +9 -0
- package/dist/src/imports/sources.d.ts +37 -0
- package/dist/src/imports/sources.js +75 -0
- package/dist/src/imports/types.d.ts +144 -0
- package/dist/src/imports/types.js +11 -0
- package/dist/src/infra/background-task.d.ts +2 -0
- package/dist/src/infra/background-task.js +25 -0
- package/dist/src/infra/process-diagnostics.d.ts +5 -0
- package/dist/src/infra/process-diagnostics.js +97 -0
- package/dist/src/infra/unhandled-rejections.js +6 -3
- package/dist/src/infra/update-restart.js +1 -1
- package/dist/src/knowledge/ingestion-service.js +1 -0
- package/dist/src/knowledge-memory/repository.js +4 -2
- package/dist/src/media-shared/http/ssrf-guard.js +1 -1
- package/dist/src/notifications/proactive-policy.js +7 -5
- package/dist/src/proactive/execution/authorization.d.ts +2 -0
- package/dist/src/proactive/execution/authorization.js +10 -1
- package/dist/src/proactive/execution/context.js +1 -0
- package/dist/src/proactive/execution/repository.d.ts +2 -0
- package/dist/src/proactive/execution/repository.js +19 -2
- package/dist/src/proactive/execution/worker.js +14 -4
- package/dist/src/proactive/experience.d.ts +4 -1
- package/dist/src/proactive/experience.js +3 -0
- package/dist/src/proactive/follow-ups.d.ts +5 -0
- package/dist/src/proactive/follow-ups.js +18 -7
- package/dist/src/proactive/inbox/cards.js +2 -1
- package/dist/src/proactive/inbox/delivery.js +6 -7
- package/dist/src/proactive/inbox/digest.d.ts +1 -1
- package/dist/src/proactive/inbox/digest.js +23 -13
- package/dist/src/proactive/inbox/notification-policy.d.ts +1 -1
- package/dist/src/proactive/inbox/notification-policy.js +9 -6
- package/dist/src/proactive/inbox/repository.js +3 -2
- package/dist/src/proactive/inbox/service.d.ts +6 -0
- package/dist/src/proactive/inbox/service.js +18 -0
- package/dist/src/proactive/inbox/types.d.ts +1 -0
- package/dist/src/proactive/policy/presence.d.ts +1 -1
- package/dist/src/proactive/policy/presence.js +7 -5
- package/dist/src/proactive/policy/service.d.ts +8 -5
- package/dist/src/proactive/policy/service.js +12 -12
- package/dist/src/proactive/scenarios/control.d.ts +3 -3
- package/dist/src/proactive/scenarios/control.js +12 -2
- package/dist/src/proactive/source-freshness.d.ts +8 -0
- package/dist/src/proactive/source-freshness.js +27 -0
- package/dist/src/proactive/status.d.ts +2 -0
- package/dist/src/proactive/status.js +21 -0
- package/dist/src/proactive/temporal/worker.js +2 -1
- package/dist/src/realtime/runtime.js +31 -5
- package/dist/src/realtime/writer.js +16 -9
- package/dist/src/storage/sqlite/import-repository.d.ts +18 -0
- package/dist/src/storage/sqlite/import-repository.js +35 -0
- package/dist/src/storage/sqlite/import-selection-repository.d.ts +15 -0
- package/dist/src/storage/sqlite/import-selection-repository.js +28 -0
- package/dist/src/storage/sqlite/knowledge-repository.d.ts +1 -0
- package/dist/src/storage/sqlite/knowledge-repository.js +2 -2
- package/dist/src/storage/sqlite/migrations/174_capability_imports.sql +11 -0
- package/dist/src/storage/sqlite/migrations/175_import_selections.sql +8 -0
- package/dist/src/storage/sqlite/migrations/176_proactive_quality.sql +5 -0
- package/dist/src/storage/sqlite/migrations/177_proactive_check_controls.sql +25 -0
- package/dist/src/storage/sqlite/migrations/runner.d.ts +1 -1
- package/dist/src/storage/sqlite/migrations/runner.js +3 -3
- package/dist/src/storage/sqlite/migrations/runner.ts +1 -1
- package/dist/src/storage/sqlite/schema.js +1 -1
- package/dist/src/work-discovery/candidate-discovery.js +1 -1
- package/dist/src/work-discovery/probe.js +1 -1
- package/package.json +4 -3
- package/dist/gateway/static/root/assets/agent-defaults-settings-panel-SElFkQd6.js +0 -1
- package/dist/gateway/static/root/assets/agents-DYazUaZ6.js +0 -1
- package/dist/gateway/static/root/assets/apps-page-BzrodN8C.js +0 -1
- package/dist/gateway/static/root/assets/automations-workspace--A4I0jMu.js +0 -6
- package/dist/gateway/static/root/assets/browser-settings-page-DDTXUNWK.js +0 -8
- package/dist/gateway/static/root/assets/capabilities-settings-panel-Ll5UeXq5.js +0 -8
- package/dist/gateway/static/root/assets/channels-settings-BzL15bkU.js +0 -1
- package/dist/gateway/static/root/assets/connectors-page-RPw1AOMb.js +0 -2
- package/dist/gateway/static/root/assets/device-pairing-wizard-D0_tCX49.js +0 -1
- package/dist/gateway/static/root/assets/gateway-settings-DOeeTdWE.js +0 -1
- package/dist/gateway/static/root/assets/home-page-Djw1H_Go.js +0 -1
- package/dist/gateway/static/root/assets/index-B_Sg5BKz.css +0 -2
- package/dist/gateway/static/root/assets/local-app-workbench-page-BPqgyYJq.js +0 -2
- package/dist/gateway/static/root/assets/logs-page-BHax3XlS.js +0 -2
- package/dist/gateway/static/root/assets/messages-DYFcjtmG.js +0 -3
- package/dist/gateway/static/root/assets/note-detail-panel-Cs46LFXO.js +0 -5
- package/dist/gateway/static/root/assets/notes-page-BUkcn_0t.js +0 -8
- package/dist/gateway/static/root/assets/proactive-page-Bn484J9v.js +0 -1
- package/dist/gateway/static/root/assets/project-detail-page-LcH21ixD.js +0 -1
- package/dist/gateway/static/root/assets/projects-page-DelBiwyB.js +0 -1
- package/dist/gateway/static/root/assets/remote-access-hub-3BjFYXCf.js +0 -1
- package/dist/gateway/static/root/assets/sessions-page-CVFirgVd.js +0 -1
- package/dist/gateway/static/root/assets/settings-advanced-gate-DyfBpqkY.js +0 -1
- package/dist/gateway/static/root/assets/setup-status-panel-CrXhTzHr.js +0 -1
- package/dist/gateway/static/root/assets/shares-settings-DyM_D8hM.js +0 -1
- package/dist/gateway/static/root/assets/skill-reload-api-Bys58-15.js +0 -1
- package/dist/gateway/static/root/assets/skills-page-sWNvFo6D.js +0 -2
- package/dist/gateway/static/root/assets/task-detail-page-B18NcZQJ.js +0 -1
- package/dist/gateway/static/root/assets/user-model-page-ul-zr58b.js +0 -2
- 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
|
|
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,
|
|
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: "
|
|
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: "
|
|
16
|
+
level: "active" | "quiet" | "balanced";
|
|
17
17
|
settings: {
|
|
18
18
|
revision: number;
|
|
19
|
-
level: "
|
|
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: "
|
|
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
|
-
|
|
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 (
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
db.prepare(
|
|
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 =
|
|
45
|
+
const level = settings.level ?? preferences.level;
|
|
49
46
|
return {
|
|
50
|
-
enabled: Boolean(sub?.enabled) && !settings.completedAt &&
|
|
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: "
|
|
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: "
|
|
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: "
|
|
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,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
|
-
|
|
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
|
-
|
|
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.
|
|
73
|
-
|
|
74
|
-
|
|
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 =
|
|
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 =
|
|
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 ??
|
|
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 ??
|
|
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 =
|
|
22
|
+
export const XOPC_DB_SCHEMA_VERSION = 177;
|
|
23
23
|
|
|
24
24
|
const MODULE_DIR = dirname(fileURLToPath(import.meta.url));
|
|
25
25
|
|
|
@@ -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;
|