@xopcai/xopc 0.0.176 → 0.0.177
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-DsFM1upC.js → activity-store-Wu2ikfbM.js} +1 -1
- package/dist/gateway/static/root/assets/{agent-avatar-dicebear-DvdMLOga.js → agent-avatar-dicebear-B0_biISn.js} +1 -1
- package/dist/gateway/static/root/assets/agents-TpIpJk59.js +2 -0
- package/dist/gateway/static/root/assets/{api-BdPLCCBm.js → api-DljBt-N5.js} +1 -1
- package/dist/gateway/static/root/assets/{app-management-settings-panel-DMLDOHul.js → app-management-settings-panel-CKoZRi7Y.js} +1 -1
- package/dist/gateway/static/root/assets/{appearance-settings-DbI9foFR.js → appearance-settings-DOdXhNDo.js} +1 -1
- package/dist/gateway/static/root/assets/apps-page-Cxbn5hy8.js +1 -0
- package/dist/gateway/static/root/assets/{archive-plugin-Dfdxuwvb.js → archive-plugin-D18gyP76.js} +1 -1
- package/dist/gateway/static/root/assets/{attachment-load-Dn3RlnYD.js → attachment-load-CZh9fc8u.js} +1 -1
- package/dist/gateway/static/root/assets/{automation-suggestion-card-Bc0Y7A9u.js → automation-suggestion-card-DKrVoiiK.js} +1 -1
- package/dist/gateway/static/root/assets/automations-page-DYv16QMU.js +6 -0
- package/dist/gateway/static/root/assets/{binary-plugins-0XtB-xC0.js → binary-plugins-DdSyGL6M.js} +1 -1
- package/dist/gateway/static/root/assets/{block-editor-C4fXWbEE.js → block-editor-BOpNApiX.js} +6 -6
- package/dist/gateway/static/root/assets/{browser-settings-page-lC86-drr.js → browser-settings-page-DlcqaGu1.js} +4 -4
- package/dist/gateway/static/root/assets/{browser-workflow-inputs-CZmzNymN.js → browser-workflow-inputs-C0SnSj_R.js} +1 -1
- package/dist/gateway/static/root/assets/{browser-workflows-page-CBYM9HqG.js → browser-workflows-page-CzlzH7HA.js} +2 -2
- package/dist/gateway/static/root/assets/capabilities-settings-panel-QPX4wsGZ.js +7 -0
- package/dist/gateway/static/root/assets/{capability-presets-api-BiJxmmhW.js → capability-presets-api-RM6S7ES5.js} +1 -1
- package/dist/gateway/static/root/assets/capability-presets-settings-panel-DmCeusO8.js +1 -0
- package/dist/gateway/static/root/assets/{channel-recipient-api-BKTUZDp-.js → channel-recipient-api-B4sha-30.js} +1 -1
- package/dist/gateway/static/root/assets/channels-settings-HcKoP1wm.js +1 -0
- package/dist/gateway/static/root/assets/channels-status-swr-D3xr2enH.js +1 -0
- package/dist/gateway/static/root/assets/{connector-logo-Pr4RIKjj.js → connector-logo-BPsKIyoM.js} +1 -1
- package/dist/gateway/static/root/assets/connectors-page-DwbThFvd.js +2 -0
- package/dist/gateway/static/root/assets/desktop-pet-DjL1GWON.js +1 -0
- package/dist/gateway/static/root/assets/{desktop-pet-settings-CEQacUDF.js → desktop-pet-settings-u_abAXh7.js} +1 -1
- package/dist/gateway/static/root/assets/{directory-picker-path-field-DWnxdZtc.js → directory-picker-path-field-BoZGualI.js} +1 -1
- package/dist/gateway/static/root/assets/{dreaming-settings-D2e2w2Ho.js → dreaming-settings-s3gn3f9h.js} +3 -3
- package/dist/gateway/static/root/assets/{extension-debug-page-BLjTGbv3.js → extension-debug-page-DIbMngCF.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-D2_UC6hy.js → extension-page-D94f2bWQ.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-settings-page-BsH6o_PX.js → extension-settings-page-B7TI13ex.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-config-api-C-DkC6UJ.js → gateway-config-api-Do77rV8R.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-settings-DEOGiimF.js → gateway-settings-Dt1PNJmb.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-startup-retry-BlSLh1TF.js → gateway-startup-retry-WaXTw3fi.js} +1 -1
- package/dist/gateway/static/root/assets/{goal-create-dialog-CSFcRE_N.js → goal-create-dialog-DEiOOLGU.js} +1 -1
- package/dist/gateway/static/root/assets/goal-detail-page-C1Qj4o1K.js +4 -0
- package/dist/gateway/static/root/assets/{goals-config-api-CcdS9qek.js → goals-config-api-BL0fAEns.js} +1 -1
- package/dist/gateway/static/root/assets/{goals-page-BAcErdch.js → goals-page-qJDcEDzc.js} +2 -2
- package/dist/gateway/static/root/assets/{goals-settings-BY7crl0z.js → goals-settings-DV3ZlrdI.js} +1 -1
- package/dist/gateway/static/root/assets/{heartbeat-settings-DtTkS0gs.js → heartbeat-settings-C3kzg6ai.js} +1 -1
- package/dist/gateway/static/root/assets/{image-generation-api-WGgkbwDZ.js → image-generation-api-BgISY8i-.js} +1 -1
- package/dist/gateway/static/root/assets/{index-2UImfRDC.js → index-C1h0zkNo.js} +65 -65
- package/dist/gateway/static/root/assets/index-Da36E3WH.css +1 -0
- package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-C5lpWQ3f.js → keyboard-shortcuts-settings-0KSmaPu0.js} +1 -1
- package/dist/gateway/static/root/assets/local-app-workbench-page-DcD4mVId.js +2 -0
- package/dist/gateway/static/root/assets/{local-apps-page-b05wWvXG.js → local-apps-page-BMrU8u7w.js} +1 -1
- package/dist/gateway/static/root/assets/{locale-store-sToMfHX_.js → locale-store-DVGhFXRz.js} +1 -1
- package/dist/gateway/static/root/assets/{logs-page-cDE1jLJv.js → logs-page-CW5m9Cov.js} +3 -3
- package/dist/gateway/static/root/assets/{markdown-split-0gPVst5y.js → markdown-split-BVqbtN9o.js} +1 -1
- package/dist/gateway/static/root/assets/{media-plugins-Rxyq_KTm.js → media-plugins-Dr_wtkNJ.js} +1 -1
- package/dist/gateway/static/root/assets/messages-r8L6Ur3A.js +3 -0
- package/dist/gateway/static/root/assets/{notes-page-DRhNDl_Q.js → notes-page-BWZRXsq6.js} +1 -1
- package/dist/gateway/static/root/assets/notes-workbench-DdnwNz9x.js +4 -0
- package/dist/gateway/static/root/assets/{page-tabs-cOEOQqHh.js → page-tabs-DWWgy0bF.js} +1 -1
- package/dist/gateway/static/root/assets/{preview-open-alternatives-BopOLFvu.js → preview-open-alternatives-Bnfs93ZP.js} +1 -1
- package/dist/gateway/static/root/assets/{product-open-page-DWVPmmOq.js → product-open-page-BR7QFmT-.js} +1 -1
- package/dist/gateway/static/root/assets/project-detail-page-B8GeS4dl.js +1 -0
- package/dist/gateway/static/root/assets/projects-page-DOeu1Hk_.js +1 -0
- package/dist/gateway/static/root/assets/remote-access-hub-De94rxnE.js +1 -0
- package/dist/gateway/static/root/assets/{save-bar-controls-BfZmKe1t.js → save-bar-controls-BzS-rRTP.js} +1 -1
- package/dist/gateway/static/root/assets/{schedule-field-Cpi4jCRV.js → schedule-field-Cl2IIDAN.js} +1 -1
- package/dist/gateway/static/root/assets/{schema-form-OXFkcZQe.js → schema-form-BjKjp5eZ.js} +1 -1
- package/dist/gateway/static/root/assets/sessions-page-A7p8G0OJ.js +1 -0
- package/dist/gateway/static/root/assets/settings-advanced-gate-BsGzjmqx.js +1 -0
- package/dist/gateway/static/root/assets/{settings-form-section-BwqkZCHJ.js → settings-form-section-BSDNBfHn.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-loading-skeleton-BbqH_S3Y.js → settings-loading-skeleton-BD4peoAv.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-page-BoxC-JSa.js → settings-page-S-P3U7at.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-page-layout-Ddu2iGaW.js → settings-page-layout-BQTLh-86.js} +1 -1
- package/dist/gateway/static/root/assets/{setup-status-panel-z1Lwv0js.js → setup-status-panel-W3p6kNyA.js} +1 -1
- package/dist/gateway/static/root/assets/{share-preview-page-CVazOFjy.js → share-preview-page-DQjMxyvw.js} +1 -1
- package/dist/gateway/static/root/assets/shares-settings-Xo3N99PO.js +1 -0
- package/dist/gateway/static/root/assets/skill-reload-api-ByPEG5t1.js +1 -0
- package/dist/gateway/static/root/assets/skills-page-C019Ml5q.js +2 -0
- package/dist/gateway/static/root/assets/{skills-page.utils-DgyB1tSo.js → skills-page.utils-CXnpudm6.js} +1 -1
- package/dist/gateway/static/root/assets/{system-settings-panel-BoLSQL65.js → system-settings-panel-BhFwdYJP.js} +1 -1
- package/dist/gateway/static/root/assets/{theme-store-CBNcGOfj.js → theme-store-DQI-HPL-.js} +1 -1
- package/dist/gateway/static/root/assets/{time-picker-gochWrny.js → time-picker-C0DCya4U.js} +1 -1
- package/dist/gateway/static/root/assets/{typed-models-lib-DvRnr7YB.js → typed-models-lib-C-M3Fv2N.js} +1 -1
- package/dist/gateway/static/root/assets/{use-channel-catalog-CA9BFVB7.js → use-channel-catalog-Bndq4y4I.js} +1 -1
- package/dist/gateway/static/root/assets/user-context-page-fYBzpus-.js +1 -0
- package/dist/gateway/static/root/assets/{voice-api-key-field-v8tgylEZ.js → voice-api-key-field-p_g4UI1-.js} +1 -1
- package/dist/gateway/static/root/assets/work-discovery-page-DI0gCZRw.js +1 -0
- package/dist/gateway/static/root/assets/work-item-detail-page-DnBRP2wI.js +1 -0
- package/dist/gateway/static/root/assets/work-page-Z-nUaS_n.js +3 -0
- package/dist/gateway/static/root/assets/{workflow-run-setup-panel-CC3cJn5k.js → workflow-run-setup-panel-CHEXVvhH.js} +2 -2
- package/dist/gateway/static/root/assets/workflows-page-BDfwnM-Y.js +11 -0
- package/dist/gateway/static/root/index.html +7 -7
- package/dist/package.js +1 -1
- package/dist/src/automations/service/automation-service.d.ts +3 -0
- package/dist/src/automations/service/automation-service.js +37 -7
- 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/update.js +1 -1
- package/dist/src/config/agent-profile.js +1 -1
- package/dist/src/gateway/agents-admin.js +1 -1
- package/dist/src/gateway/heartbeat/service.js +1 -1
- package/dist/src/gateway/hono/routes/browser-install.js +1 -1
- package/dist/src/gateway/hono/routes/home.d.ts +18 -2
- package/dist/src/gateway/hono/routes/home.js +19 -0
- package/dist/src/gateway/hono/routes/index.js +2 -2
- package/dist/src/gateway/hono/routes/local-apps.js +1 -1
- package/dist/src/gateway/hono/routes/proactive.d.ts +4 -0
- package/dist/src/gateway/hono/routes/proactive.js +157 -0
- package/dist/src/gateway/hono/routes/projects.js +2 -2
- package/dist/src/gateway/hono/routes/update.js +2 -2
- package/dist/src/gateway/index.js +1 -1
- package/dist/src/gateway/run-loop.js +1 -1
- package/dist/src/gateway/service.d.ts +10 -1
- package/dist/src/gateway/service.js +36 -36
- package/dist/src/heartbeat/index.js +1 -1
- package/dist/src/infra/gateway-processes.js +1 -1
- package/dist/src/infra/update-restart.js +1 -1
- package/dist/src/infra/update-runner.js +2 -2
- package/dist/src/infra/update-startup.js +1 -1
- package/dist/src/mcp/channel-bridge.js +1 -1
- package/dist/src/mobile/notification-service.d.ts +1 -0
- package/dist/src/mobile/notification-service.js +38 -18
- package/dist/src/mobile/notification-types.d.ts +2 -2
- package/dist/src/proactive/events/envelope.d.ts +2 -0
- package/dist/src/proactive/events/envelope.js +54 -0
- package/dist/src/proactive/events/publisher.d.ts +4 -0
- package/dist/src/proactive/events/repository.d.ts +9 -0
- package/dist/src/proactive/events/repository.js +62 -0
- package/dist/src/proactive/events/types.d.ts +44 -0
- package/dist/src/proactive/events/types.js +15 -0
- package/dist/src/proactive/execution/agent-executor.d.ts +16 -0
- package/dist/src/proactive/execution/agent-executor.js +104 -0
- package/dist/src/proactive/execution/context.d.ts +31 -0
- package/dist/src/proactive/execution/context.js +72 -0
- package/dist/src/proactive/execution/insight.d.ts +4 -0
- package/dist/src/proactive/execution/insight.js +74 -0
- package/dist/src/proactive/execution/repository.d.ts +23 -0
- package/dist/src/proactive/execution/repository.js +122 -0
- package/dist/src/proactive/execution/types.d.ts +54 -0
- package/dist/src/proactive/execution/types.js +1 -0
- package/dist/src/proactive/execution/worker.d.ts +15 -0
- package/dist/src/proactive/execution/worker.js +96 -0
- package/dist/src/proactive/inbox/repository.d.ts +24 -0
- package/dist/src/proactive/inbox/repository.js +117 -0
- package/dist/src/proactive/inbox/service.d.ts +17 -0
- package/dist/src/proactive/inbox/service.js +22 -0
- package/dist/src/proactive/inbox/types.d.ts +38 -0
- package/dist/src/proactive/inbox/types.js +1 -0
- package/dist/src/proactive/inbox/worker.d.ts +12 -0
- package/dist/src/proactive/inbox/worker.js +56 -0
- package/dist/src/proactive/index.d.ts +17 -0
- package/dist/src/proactive/index.js +11 -0
- package/dist/src/proactive/routing/batch-repository.d.ts +27 -0
- package/dist/src/proactive/routing/batch-repository.js +56 -0
- package/dist/src/proactive/routing/matcher.d.ts +5 -0
- package/dist/src/proactive/routing/matcher.js +56 -0
- package/dist/src/proactive/routing/types.d.ts +44 -0
- package/dist/src/proactive/routing/types.js +1 -0
- package/dist/src/proactive/scenarios/prompt-composer.d.ts +14 -0
- package/dist/src/proactive/scenarios/prompt-composer.js +24 -0
- package/dist/src/proactive/scenarios/repository.d.ts +23 -0
- package/dist/src/proactive/scenarios/repository.js +162 -0
- package/dist/src/proactive/scenarios/service.d.ts +15 -0
- package/dist/src/proactive/scenarios/service.js +26 -0
- package/dist/src/proactive/scenarios/types.d.ts +36 -0
- package/dist/src/proactive/scenarios/types.js +1 -0
- package/dist/src/proactive/service.d.ts +18 -0
- package/dist/src/proactive/service.js +61 -0
- package/dist/src/projects/project-service.d.ts +3 -1
- package/dist/src/projects/project-service.js +62 -32
- package/dist/src/storage/sqlite/migrations/068_proactive_event_spine.sql +71 -0
- package/dist/src/storage/sqlite/migrations/069_proactive_scenario_control.sql +69 -0
- package/dist/src/storage/sqlite/migrations/070_proactive_execution.sql +55 -0
- package/dist/src/storage/sqlite/migrations/071_proactive_inbox.sql +45 -0
- package/dist/src/storage/sqlite/migrations/072_proactive_judgments.sql +14 -0
- package/dist/src/storage/sqlite/migrations/073_enable_default_proactive_scenarios.sql +13 -0
- package/dist/src/storage/sqlite/migrations/074_deduplicate_blocked_work_routing.sql +5 -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/thread-service.d.ts +1 -3
- package/dist/src/work-discovery/thread-service.js +13 -25
- package/dist/src/work-items/work-item-service.d.ts +3 -1
- package/dist/src/work-items/work-item-service.js +67 -36
- package/package.json +1 -1
- package/dist/gateway/static/root/assets/agents-BVjlpbeZ.js +0 -2
- package/dist/gateway/static/root/assets/api-Bop4IQRW.js +0 -1
- package/dist/gateway/static/root/assets/apps-page-njqxLWYD.js +0 -1
- package/dist/gateway/static/root/assets/automations-page-D-eweHZJ.js +0 -6
- package/dist/gateway/static/root/assets/capabilities-settings-panel-6tYNfHqJ.js +0 -7
- package/dist/gateway/static/root/assets/capability-presets-settings-panel-Co-ymbd9.js +0 -1
- package/dist/gateway/static/root/assets/channels-settings-D46eVjaQ.js +0 -1
- package/dist/gateway/static/root/assets/channels-status-swr-BMRAO4zZ.js +0 -1
- package/dist/gateway/static/root/assets/connectors-page-Dw1eYbRi.js +0 -2
- package/dist/gateway/static/root/assets/copy-VueTIC2x.js +0 -1
- package/dist/gateway/static/root/assets/desktop-pet-B8cZuQUt.js +0 -1
- package/dist/gateway/static/root/assets/focus-detail-page-BBXUtxRB.js +0 -1
- package/dist/gateway/static/root/assets/goal-detail-page-VjRArfAJ.js +0 -4
- package/dist/gateway/static/root/assets/index-CS9sVShT.css +0 -1
- package/dist/gateway/static/root/assets/local-app-workbench-page-Cl0fcPL4.js +0 -2
- package/dist/gateway/static/root/assets/messages-CarlxqXV.js +0 -3
- package/dist/gateway/static/root/assets/notes-workbench-BKNBk0Uf.js +0 -4
- package/dist/gateway/static/root/assets/project-detail-page-BhjEXNQW.js +0 -1
- package/dist/gateway/static/root/assets/projects-page-B80e69PH.js +0 -1
- package/dist/gateway/static/root/assets/remote-access-hub-CwdVob6H.js +0 -1
- package/dist/gateway/static/root/assets/sessions-page-BGt3Asj6.js +0 -1
- package/dist/gateway/static/root/assets/settings-advanced-gate-BnTdM9Nn.js +0 -1
- package/dist/gateway/static/root/assets/shares-settings-C4lXuyQj.js +0 -1
- package/dist/gateway/static/root/assets/skill-reload-api-DSuIDkeI.js +0 -1
- package/dist/gateway/static/root/assets/skills-page-xgZczqVe.js +0 -2
- package/dist/gateway/static/root/assets/user-context-page-CEfIy4WZ.js +0 -1
- package/dist/gateway/static/root/assets/work-discovery-page-B-3MClaf.js +0 -1
- package/dist/gateway/static/root/assets/work-item-detail-page-CEsFEdax.js +0 -1
- package/dist/gateway/static/root/assets/work-page-CT9AHnq6.js +0 -3
- package/dist/gateway/static/root/assets/workflows-page-C-1-_Zp1.js +0 -11
- package/dist/src/focuses/candidate-repository.d.ts +0 -15
- package/dist/src/focuses/candidate-repository.js +0 -91
- package/dist/src/focuses/index.d.ts +0 -7
- package/dist/src/focuses/index.js +0 -7
- package/dist/src/focuses/insight-repository.d.ts +0 -22
- package/dist/src/focuses/insight-repository.js +0 -77
- package/dist/src/focuses/prompts.d.ts +0 -2
- package/dist/src/focuses/prompts.js +0 -18
- package/dist/src/focuses/reconciler.d.ts +0 -5
- package/dist/src/focuses/reconciler.js +0 -26
- package/dist/src/focuses/repository.d.ts +0 -61
- package/dist/src/focuses/repository.js +0 -214
- package/dist/src/focuses/run-processor.d.ts +0 -18
- package/dist/src/focuses/run-processor.js +0 -162
- package/dist/src/focuses/service.d.ts +0 -42
- package/dist/src/focuses/service.js +0 -241
- package/dist/src/focuses/types.d.ts +0 -89
- package/dist/src/gateway/hono/routes/focuses.d.ts +0 -3
- package/dist/src/gateway/hono/routes/focuses.js +0 -319
- /package/dist/src/{focuses/types.js → proactive/events/publisher.js} +0 -0
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { getSqliteDatabase, runSqliteWriteTransaction } from "../../storage/sqlite/transaction.js";
|
|
2
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
3
|
+
//#region src/proactive/scenarios/repository.ts
|
|
4
|
+
const text = (row, key) => String(row[key]);
|
|
5
|
+
function scenarioFromRow(row) {
|
|
6
|
+
const condition = row.condition_json ? JSON.parse(String(row.condition_json)) : void 0;
|
|
7
|
+
return {
|
|
8
|
+
key: text(row, "scenario_key"),
|
|
9
|
+
version: Number(row.version),
|
|
10
|
+
title: text(row, "title"),
|
|
11
|
+
description: text(row, "description"),
|
|
12
|
+
basePrompt: text(row, "base_prompt"),
|
|
13
|
+
baseTemplateVersion: Number(row.base_template_version),
|
|
14
|
+
eventTypes: JSON.parse(text(row, "event_types_json")),
|
|
15
|
+
...condition ? { condition } : {},
|
|
16
|
+
aggregation: text(row, "aggregation"),
|
|
17
|
+
debounceSeconds: Number(row.debounce_seconds),
|
|
18
|
+
maxWindowSeconds: Number(row.max_window_seconds)
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
function subscriptionFromRow(row) {
|
|
22
|
+
return {
|
|
23
|
+
id: text(row, "subscription_id"),
|
|
24
|
+
scenarioKey: text(row, "scenario_key"),
|
|
25
|
+
workspaceId: text(row, "workspace_id"),
|
|
26
|
+
scopeKind: text(row, "scope_kind"),
|
|
27
|
+
scopeId: text(row, "scope_id"),
|
|
28
|
+
enabled: Number(row.enabled) === 1,
|
|
29
|
+
...row.active_prompt_revision_id ? { activePromptRevisionId: text(row, "active_prompt_revision_id") } : {},
|
|
30
|
+
createdAt: text(row, "created_at"),
|
|
31
|
+
updatedAt: text(row, "updated_at")
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
function revisionFromRow(row) {
|
|
35
|
+
return {
|
|
36
|
+
id: text(row, "revision_id"),
|
|
37
|
+
subscriptionId: text(row, "subscription_id"),
|
|
38
|
+
revision: Number(row.revision),
|
|
39
|
+
status: text(row, "status"),
|
|
40
|
+
baseTemplateVersion: Number(row.base_template_version),
|
|
41
|
+
userInstructions: text(row, "user_instructions"),
|
|
42
|
+
contentHash: text(row, "content_hash"),
|
|
43
|
+
createdAt: text(row, "created_at"),
|
|
44
|
+
...row.published_at ? { publishedAt: text(row, "published_at") } : {}
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
function listScenarios() {
|
|
48
|
+
return getSqliteDatabase().prepare("SELECT * FROM proactive_scenarios ORDER BY scenario_key").all().map(scenarioFromRow);
|
|
49
|
+
}
|
|
50
|
+
function getScenario(key) {
|
|
51
|
+
const row = getSqliteDatabase().prepare("SELECT * FROM proactive_scenarios WHERE scenario_key = ?").get(key);
|
|
52
|
+
return row ? scenarioFromRow(row) : null;
|
|
53
|
+
}
|
|
54
|
+
function upsertSubscription(input, now = /* @__PURE__ */ new Date()) {
|
|
55
|
+
if (!getScenario(input.scenarioKey)) throw new Error("Scenario not found");
|
|
56
|
+
const nowIso = now.toISOString();
|
|
57
|
+
runSqliteWriteTransaction((db) => db.prepare(`INSERT INTO proactive_scenario_subscriptions (
|
|
58
|
+
subscription_id, scenario_key, workspace_id, scope_kind, scope_id, enabled, created_at, updated_at
|
|
59
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
60
|
+
ON CONFLICT(scenario_key, workspace_id, scope_kind, scope_id) DO UPDATE SET enabled = excluded.enabled, updated_at = excluded.updated_at`).run(randomUUID(), input.scenarioKey, input.workspaceId, input.scopeKind, input.scopeId, input.enabled ? 1 : 0, nowIso, nowIso));
|
|
61
|
+
return subscriptionFromRow(getSqliteDatabase().prepare(`SELECT * FROM proactive_scenario_subscriptions
|
|
62
|
+
WHERE scenario_key = ? AND workspace_id = ? AND scope_kind = ? AND scope_id = ?`).get(input.scenarioKey, input.workspaceId, input.scopeKind, input.scopeId));
|
|
63
|
+
}
|
|
64
|
+
function listSubscriptions(scenarioKey) {
|
|
65
|
+
return (scenarioKey ? getSqliteDatabase().prepare("SELECT * FROM proactive_scenario_subscriptions WHERE scenario_key = ? ORDER BY updated_at DESC").all(scenarioKey) : getSqliteDatabase().prepare("SELECT * FROM proactive_scenario_subscriptions ORDER BY updated_at DESC").all()).map(subscriptionFromRow);
|
|
66
|
+
}
|
|
67
|
+
function listEnabledRoutes() {
|
|
68
|
+
return listSubscriptions().filter((item) => item.enabled).flatMap((subscription) => {
|
|
69
|
+
const scenario = getScenario(subscription.scenarioKey);
|
|
70
|
+
if (!scenario) return [];
|
|
71
|
+
return [{
|
|
72
|
+
subscriptionId: subscription.id,
|
|
73
|
+
key: scenario.key,
|
|
74
|
+
version: scenario.version,
|
|
75
|
+
enabled: true,
|
|
76
|
+
eventTypes: scenario.eventTypes,
|
|
77
|
+
...scenario.condition ? { condition: scenario.condition } : {},
|
|
78
|
+
aggregation: scenario.aggregation,
|
|
79
|
+
debounceSeconds: scenario.debounceSeconds,
|
|
80
|
+
maxWindowSeconds: scenario.maxWindowSeconds,
|
|
81
|
+
scope: {
|
|
82
|
+
workspaceId: subscription.workspaceId,
|
|
83
|
+
...subscription.scopeKind === "project" ? { projectId: subscription.scopeId } : {}
|
|
84
|
+
}
|
|
85
|
+
}];
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
function createPromptDraft(subscriptionId, userInstructions, now = /* @__PURE__ */ new Date()) {
|
|
89
|
+
const instructions = userInstructions.trim();
|
|
90
|
+
if (instructions.length > 12e3) throw new Error("User instructions exceed 12000 characters");
|
|
91
|
+
return runSqliteWriteTransaction((db) => {
|
|
92
|
+
const subscription = db.prepare("SELECT * FROM proactive_scenario_subscriptions WHERE subscription_id = ?").get(subscriptionId);
|
|
93
|
+
if (!subscription) throw new Error("Subscription not found");
|
|
94
|
+
const scenario = db.prepare("SELECT * FROM proactive_scenarios WHERE scenario_key = ?").get(text(subscription, "scenario_key"));
|
|
95
|
+
const next = db.prepare("SELECT COALESCE(MAX(revision), 0) + 1 AS revision FROM proactive_prompt_revisions WHERE subscription_id = ?").get(subscriptionId);
|
|
96
|
+
const id = randomUUID();
|
|
97
|
+
const baseTemplateVersion = Number(scenario.base_template_version);
|
|
98
|
+
const hash = createHash("sha256").update(`${baseTemplateVersion}:${instructions}`).digest("hex");
|
|
99
|
+
db.prepare(`INSERT INTO proactive_prompt_revisions
|
|
100
|
+
(revision_id, subscription_id, revision, status, base_template_version, user_instructions, content_hash, created_at)
|
|
101
|
+
VALUES (?, ?, ?, 'draft', ?, ?, ?, ?)`).run(id, subscriptionId, next.revision, baseTemplateVersion, instructions, hash, now.toISOString());
|
|
102
|
+
return revisionFromRow(db.prepare("SELECT * FROM proactive_prompt_revisions WHERE revision_id = ?").get(id));
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
function getPromptRevision(id) {
|
|
106
|
+
const row = getSqliteDatabase().prepare("SELECT * FROM proactive_prompt_revisions WHERE revision_id = ?").get(id);
|
|
107
|
+
return row ? revisionFromRow(row) : null;
|
|
108
|
+
}
|
|
109
|
+
function getSubscription(id) {
|
|
110
|
+
const row = getSqliteDatabase().prepare("SELECT * FROM proactive_scenario_subscriptions WHERE subscription_id = ?").get(id);
|
|
111
|
+
return row ? subscriptionFromRow(row) : null;
|
|
112
|
+
}
|
|
113
|
+
function publishPromptRevision(id, now = /* @__PURE__ */ new Date()) {
|
|
114
|
+
return runSqliteWriteTransaction((db) => {
|
|
115
|
+
const draft = db.prepare("SELECT * FROM proactive_prompt_revisions WHERE revision_id = ?").get(id);
|
|
116
|
+
if (!draft || draft.status !== "draft") throw new Error("Prompt draft not found");
|
|
117
|
+
const nowIso = now.toISOString();
|
|
118
|
+
const subscriptionId = text(draft, "subscription_id");
|
|
119
|
+
db.prepare("UPDATE proactive_prompt_revisions SET status = 'retired' WHERE subscription_id = ? AND status = 'published'").run(subscriptionId);
|
|
120
|
+
db.prepare("UPDATE proactive_prompt_revisions SET status = 'published', published_at = ? WHERE revision_id = ?").run(nowIso, id);
|
|
121
|
+
db.prepare("UPDATE proactive_scenario_subscriptions SET active_prompt_revision_id = ?, updated_at = ? WHERE subscription_id = ?").run(id, nowIso, subscriptionId);
|
|
122
|
+
return revisionFromRow(db.prepare("SELECT * FROM proactive_prompt_revisions WHERE revision_id = ?").get(id));
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
function rollbackPromptRevision(id, now = /* @__PURE__ */ new Date()) {
|
|
126
|
+
return runSqliteWriteTransaction((db) => {
|
|
127
|
+
const target = db.prepare("SELECT * FROM proactive_prompt_revisions WHERE revision_id = ?").get(id);
|
|
128
|
+
if (!target || target.status === "draft") throw new Error("Published prompt revision not found");
|
|
129
|
+
const nowIso = now.toISOString();
|
|
130
|
+
const subscriptionId = text(target, "subscription_id");
|
|
131
|
+
db.prepare("UPDATE proactive_prompt_revisions SET status = 'retired' WHERE subscription_id = ? AND status = 'published'").run(subscriptionId);
|
|
132
|
+
db.prepare("UPDATE proactive_prompt_revisions SET status = 'published', published_at = ? WHERE revision_id = ?").run(nowIso, id);
|
|
133
|
+
db.prepare("UPDATE proactive_scenario_subscriptions SET active_prompt_revision_id = ?, updated_at = ? WHERE subscription_id = ?").run(id, nowIso, subscriptionId);
|
|
134
|
+
return revisionFromRow(db.prepare("SELECT * FROM proactive_prompt_revisions WHERE revision_id = ?").get(id));
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
function publishInstructionFeedback(input, now = /* @__PURE__ */ new Date()) {
|
|
138
|
+
const normalized = input.instruction.trim();
|
|
139
|
+
if (!normalized) throw new Error("instruction is required");
|
|
140
|
+
if (normalized.length > 2e3) throw new Error("instruction exceeds 2000 characters");
|
|
141
|
+
return runSqliteWriteTransaction((db) => {
|
|
142
|
+
const subscription = db.prepare("SELECT * FROM proactive_scenario_subscriptions WHERE subscription_id = ?").get(input.subscriptionId);
|
|
143
|
+
if (!subscription) throw new Error("Subscription not found");
|
|
144
|
+
const scenario = db.prepare("SELECT * FROM proactive_scenarios WHERE scenario_key = ?").get(text(subscription, "scenario_key"));
|
|
145
|
+
const instructions = [(subscription.active_prompt_revision_id ? db.prepare("SELECT user_instructions FROM proactive_prompt_revisions WHERE revision_id = ?").get(text(subscription, "active_prompt_revision_id")) : void 0)?.user_instructions?.trim() ?? "", `User feedback (${now.toISOString()}): ${normalized}`].filter(Boolean).join("\n").slice(-12e3);
|
|
146
|
+
const next = db.prepare("SELECT COALESCE(MAX(revision), 0) + 1 AS revision FROM proactive_prompt_revisions WHERE subscription_id = ?").get(input.subscriptionId);
|
|
147
|
+
const revisionId = randomUUID();
|
|
148
|
+
const baseTemplateVersion = Number(scenario.base_template_version);
|
|
149
|
+
const hash = createHash("sha256").update(`${baseTemplateVersion}:${instructions}`).digest("hex");
|
|
150
|
+
const nowIso = now.toISOString();
|
|
151
|
+
db.prepare("UPDATE proactive_prompt_revisions SET status = 'retired' WHERE subscription_id = ? AND status = 'published'").run(input.subscriptionId);
|
|
152
|
+
db.prepare(`INSERT INTO proactive_prompt_revisions
|
|
153
|
+
(revision_id, subscription_id, revision, status, base_template_version, user_instructions, content_hash, created_at, published_at)
|
|
154
|
+
VALUES (?, ?, ?, 'published', ?, ?, ?, ?, ?)`).run(revisionId, input.subscriptionId, next.revision, baseTemplateVersion, instructions, hash, nowIso, nowIso);
|
|
155
|
+
db.prepare("UPDATE proactive_scenario_subscriptions SET active_prompt_revision_id = ?, updated_at = ? WHERE subscription_id = ?").run(revisionId, nowIso, input.subscriptionId);
|
|
156
|
+
db.prepare(`INSERT INTO proactive_instruction_feedback
|
|
157
|
+
(instruction_id, inbox_item_id, prompt_revision_id, instruction, created_at) VALUES (?, ?, ?, ?, ?)`).run(randomUUID(), input.inboxItemId, revisionId, normalized, nowIso);
|
|
158
|
+
return revisionFromRow(db.prepare("SELECT * FROM proactive_prompt_revisions WHERE revision_id = ?").get(revisionId));
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
//#endregion
|
|
162
|
+
export { createPromptDraft, getPromptRevision, getScenario, getSubscription, listEnabledRoutes, listScenarios, listSubscriptions, publishInstructionFeedback, publishPromptRevision, rollbackPromptRevision, upsertSubscription };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { createPromptDraft, listEnabledRoutes, listScenarios, listSubscriptions, publishPromptRevision, rollbackPromptRevision, upsertSubscription } from './repository.js';
|
|
2
|
+
export declare class ProactiveScenarioService {
|
|
3
|
+
list: typeof listScenarios;
|
|
4
|
+
subscriptions: typeof listSubscriptions;
|
|
5
|
+
routes: typeof listEnabledRoutes;
|
|
6
|
+
subscribe: typeof upsertSubscription;
|
|
7
|
+
createDraft: typeof createPromptDraft;
|
|
8
|
+
publish: typeof publishPromptRevision;
|
|
9
|
+
rollback: typeof rollbackPromptRevision;
|
|
10
|
+
preview(input: {
|
|
11
|
+
scenarioKey: string;
|
|
12
|
+
revisionId?: string;
|
|
13
|
+
runtimeContext?: string;
|
|
14
|
+
}): import("./prompt-composer.js").ComposedPrompt;
|
|
15
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { createPromptDraft, getPromptRevision, getScenario, getSubscription, listEnabledRoutes, listScenarios, listSubscriptions, publishPromptRevision, rollbackPromptRevision, upsertSubscription } from "./repository.js";
|
|
2
|
+
import { composeScenarioPrompt } from "./prompt-composer.js";
|
|
3
|
+
//#region src/proactive/scenarios/service.ts
|
|
4
|
+
var ProactiveScenarioService = class {
|
|
5
|
+
list = listScenarios;
|
|
6
|
+
subscriptions = listSubscriptions;
|
|
7
|
+
routes = listEnabledRoutes;
|
|
8
|
+
subscribe = upsertSubscription;
|
|
9
|
+
createDraft = createPromptDraft;
|
|
10
|
+
publish = publishPromptRevision;
|
|
11
|
+
rollback = rollbackPromptRevision;
|
|
12
|
+
preview(input) {
|
|
13
|
+
const scenario = getScenario(input.scenarioKey);
|
|
14
|
+
if (!scenario) throw new Error("Scenario not found");
|
|
15
|
+
const revision = input.revisionId ? getPromptRevision(input.revisionId) : void 0;
|
|
16
|
+
if (input.revisionId && !revision) throw new Error("Prompt revision not found");
|
|
17
|
+
if (revision && getSubscription(revision.subscriptionId)?.scenarioKey !== scenario.key) throw new Error("Prompt revision does not belong to this scenario");
|
|
18
|
+
return composeScenarioPrompt({
|
|
19
|
+
scenario,
|
|
20
|
+
...revision ? { revision } : {},
|
|
21
|
+
runtimeContext: input.runtimeContext ?? "[runtime context redacted]"
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
//#endregion
|
|
26
|
+
export { ProactiveScenarioService };
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { EventCondition, ScenarioRoute } from '../routing/types.js';
|
|
2
|
+
export interface ScenarioDefinition {
|
|
3
|
+
key: string;
|
|
4
|
+
version: number;
|
|
5
|
+
title: string;
|
|
6
|
+
description: string;
|
|
7
|
+
basePrompt: string;
|
|
8
|
+
baseTemplateVersion: number;
|
|
9
|
+
eventTypes: string[];
|
|
10
|
+
condition?: EventCondition;
|
|
11
|
+
aggregation: ScenarioRoute['aggregation'];
|
|
12
|
+
debounceSeconds: number;
|
|
13
|
+
maxWindowSeconds: number;
|
|
14
|
+
}
|
|
15
|
+
export interface ScenarioSubscription {
|
|
16
|
+
id: string;
|
|
17
|
+
scenarioKey: string;
|
|
18
|
+
workspaceId: string;
|
|
19
|
+
scopeKind: 'workspace' | 'project';
|
|
20
|
+
scopeId: string;
|
|
21
|
+
enabled: boolean;
|
|
22
|
+
activePromptRevisionId?: string;
|
|
23
|
+
createdAt: string;
|
|
24
|
+
updatedAt: string;
|
|
25
|
+
}
|
|
26
|
+
export interface PromptRevision {
|
|
27
|
+
id: string;
|
|
28
|
+
subscriptionId: string;
|
|
29
|
+
revision: number;
|
|
30
|
+
status: 'draft' | 'published' | 'retired';
|
|
31
|
+
baseTemplateVersion: number;
|
|
32
|
+
userInstructions: string;
|
|
33
|
+
contentHash: string;
|
|
34
|
+
createdAt: string;
|
|
35
|
+
publishedAt?: string;
|
|
36
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { listEvents } from './events/repository.js';
|
|
2
|
+
import type { PublishEventInput, PublishedEvent } from './events/types.js';
|
|
3
|
+
import { listBatches, markReadyBatches } from './routing/batch-repository.js';
|
|
4
|
+
import type { ScenarioRoute } from './routing/types.js';
|
|
5
|
+
export declare class ProactiveEventService {
|
|
6
|
+
private readonly routes;
|
|
7
|
+
constructor(routes?: () => readonly ScenarioRoute[]);
|
|
8
|
+
publish(input: PublishEventInput, now?: Date): PublishedEvent;
|
|
9
|
+
listEvents: typeof listEvents;
|
|
10
|
+
listBatches: typeof listBatches;
|
|
11
|
+
markReadyBatches: typeof markReadyBatches;
|
|
12
|
+
health(): {
|
|
13
|
+
events: number;
|
|
14
|
+
collecting: number;
|
|
15
|
+
ready: number;
|
|
16
|
+
oldestReadyAt: string | null;
|
|
17
|
+
};
|
|
18
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { getSqliteDatabase } from "../storage/sqlite/transaction.js";
|
|
2
|
+
import { normalizeEventEnvelope } from "./events/envelope.js";
|
|
3
|
+
import { matchScenario } from "./routing/matcher.js";
|
|
4
|
+
import { getEventByDedupeKey, insertEvent, isEventRouted, listEvents, markEventRouted } from "./events/repository.js";
|
|
5
|
+
import { addEventToBatch, listBatches, markReadyBatches } from "./routing/batch-repository.js";
|
|
6
|
+
//#region src/proactive/service.ts
|
|
7
|
+
var ProactiveEventService = class {
|
|
8
|
+
constructor(routes = () => []) {
|
|
9
|
+
this.routes = routes;
|
|
10
|
+
}
|
|
11
|
+
publish(input, now = /* @__PURE__ */ new Date()) {
|
|
12
|
+
let event = normalizeEventEnvelope(input, now);
|
|
13
|
+
const inserted = insertEvent(event);
|
|
14
|
+
if (!inserted) {
|
|
15
|
+
const existing = getEventByDedupeKey(event.dedupeKey);
|
|
16
|
+
if (!existing) throw new Error(`Proactive event dedupe lookup failed: ${event.dedupeKey}`);
|
|
17
|
+
event = existing;
|
|
18
|
+
if (isEventRouted(event.id)) return {
|
|
19
|
+
event,
|
|
20
|
+
inserted: false,
|
|
21
|
+
batchIds: []
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
const batchIds = this.routes().flatMap((scenario) => {
|
|
25
|
+
const key = matchScenario(event, scenario);
|
|
26
|
+
if (!key) return [];
|
|
27
|
+
return [addEventToBatch({
|
|
28
|
+
event,
|
|
29
|
+
scenario,
|
|
30
|
+
aggregationKey: key,
|
|
31
|
+
now
|
|
32
|
+
}).id];
|
|
33
|
+
});
|
|
34
|
+
markEventRouted(event.id, now.toISOString());
|
|
35
|
+
return {
|
|
36
|
+
event,
|
|
37
|
+
inserted,
|
|
38
|
+
batchIds
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
listEvents = listEvents;
|
|
42
|
+
listBatches = listBatches;
|
|
43
|
+
markReadyBatches = markReadyBatches;
|
|
44
|
+
health() {
|
|
45
|
+
const db = getSqliteDatabase();
|
|
46
|
+
const events = db.prepare("SELECT COUNT(*) AS count FROM proactive_events").get();
|
|
47
|
+
const batches = db.prepare(`SELECT
|
|
48
|
+
SUM(CASE WHEN status = 'collecting' THEN 1 ELSE 0 END) AS collecting,
|
|
49
|
+
SUM(CASE WHEN status = 'ready' THEN 1 ELSE 0 END) AS ready,
|
|
50
|
+
MIN(CASE WHEN status = 'ready' THEN ready_at END) AS oldest_ready_at
|
|
51
|
+
FROM proactive_signal_batches`).get();
|
|
52
|
+
return {
|
|
53
|
+
events: events.count,
|
|
54
|
+
collecting: batches.collecting ?? 0,
|
|
55
|
+
ready: batches.ready ?? 0,
|
|
56
|
+
oldestReadyAt: batches.oldest_ready_at
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
//#endregion
|
|
61
|
+
export { ProactiveEventService };
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ProactiveSignalPublisher } from '../proactive/events/publisher.js';
|
|
1
2
|
import { ProjectStore } from './project-store.js';
|
|
2
3
|
import type { CreateProjectInput, Project, ProjectListQuery, ProjectListResult, ProjectWithDetails, SidebarProjectListQuery, UpdateProjectInput } from './types.js';
|
|
3
4
|
import { type WorkspaceProjectMatch } from './workspace-project.js';
|
|
@@ -9,7 +10,8 @@ export type ProjectSuggestion = {
|
|
|
9
10
|
};
|
|
10
11
|
export declare class ProjectService {
|
|
11
12
|
private readonly store;
|
|
12
|
-
|
|
13
|
+
private readonly signals?;
|
|
14
|
+
constructor(store?: ProjectStore, signals?: ProactiveSignalPublisher);
|
|
13
15
|
private listAllProjects;
|
|
14
16
|
create(input: CreateProjectInput): Project;
|
|
15
17
|
get(id: string): Project | null;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { runSqliteWriteTransaction } from "../storage/sqlite/transaction.js";
|
|
1
2
|
import { getSessionMetadata } from "../storage/sqlite/session-repository.js";
|
|
2
3
|
import "../storage/sqlite/index.js";
|
|
3
4
|
import { changedFieldsFromPatch, emitActivity, systemActivityActor, systemActivitySource } from "../activity/emitter.js";
|
|
@@ -5,10 +6,12 @@ import { ProjectStore } from "./project-store.js";
|
|
|
5
6
|
import { bindGoalToProject, listProjectGoalIds, unbindGoalFromProject } from "./goal-bind.js";
|
|
6
7
|
import { bindSessionToProject, listProjectSessionKeys, unbindSessionFromProject } from "./session-bind.js";
|
|
7
8
|
import { ProjectWorkspaceConflictError, ProjectWorkspaceMissingError, canonicalWorkspacePath, ensureWorkspaceDirectory, inferProjectNameFromWorkspaceRoot, isPathSameOrInsideWorkspace, isSafeAutoCreateWorkspaceRoot, resolveWorkspaceProjectRoot, workspaceDirectoryExists } from "./workspace-project.js";
|
|
9
|
+
import { createHash } from "node:crypto";
|
|
8
10
|
//#region src/projects/project-service.ts
|
|
9
11
|
var ProjectService = class {
|
|
10
|
-
constructor(store = new ProjectStore()) {
|
|
12
|
+
constructor(store = new ProjectStore(), signals) {
|
|
11
13
|
this.store = store;
|
|
14
|
+
this.signals = signals;
|
|
12
15
|
}
|
|
13
16
|
listAllProjects() {
|
|
14
17
|
const items = [];
|
|
@@ -144,38 +147,65 @@ var ProjectService = class {
|
|
|
144
147
|
else throw new ProjectWorkspaceMissingError(workspaceRoot);
|
|
145
148
|
patch.workspaceRoot = workspaceRoot;
|
|
146
149
|
}
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
150
|
+
return runSqliteWriteTransaction(() => {
|
|
151
|
+
const before = this.store.get(id);
|
|
152
|
+
const project = this.store.update(id, patch);
|
|
153
|
+
const changes = changedFieldsFromPatch(patch, ["createWorkspaceRoot"]);
|
|
154
|
+
const type = before?.status !== project.status ? "project.status_changed" : before?.workspaceRoot !== project.workspaceRoot ? "project.workspace_changed" : "project.updated";
|
|
155
|
+
emitActivity({
|
|
156
|
+
type,
|
|
157
|
+
primaryObject: {
|
|
158
|
+
kind: "project",
|
|
159
|
+
id: project.id,
|
|
160
|
+
title: project.name
|
|
161
|
+
},
|
|
162
|
+
actor: systemActivityActor(),
|
|
163
|
+
source: systemActivitySource(),
|
|
164
|
+
payload: {
|
|
165
|
+
changes,
|
|
166
|
+
...type === "project.status_changed" ? {
|
|
167
|
+
from: before?.status,
|
|
168
|
+
to: project.status
|
|
169
|
+
} : {},
|
|
170
|
+
...type === "project.workspace_changed" ? {
|
|
171
|
+
from: before?.workspaceRoot,
|
|
172
|
+
to: project.workspaceRoot
|
|
173
|
+
} : {}
|
|
174
|
+
},
|
|
175
|
+
scopes: [{
|
|
176
|
+
scopeKind: "project",
|
|
177
|
+
scopeId: project.id,
|
|
178
|
+
reason: "object_owner"
|
|
179
|
+
}],
|
|
180
|
+
nowMs: project.updatedAt
|
|
181
|
+
});
|
|
182
|
+
this.signals?.publish({
|
|
183
|
+
type: "project.updated.v1",
|
|
184
|
+
schemaVersion: 1,
|
|
185
|
+
source: {
|
|
186
|
+
kind: "projects",
|
|
187
|
+
id: "local"
|
|
188
|
+
},
|
|
189
|
+
subject: {
|
|
190
|
+
kind: "project",
|
|
191
|
+
id: project.id
|
|
192
|
+
},
|
|
193
|
+
actor: { kind: "system" },
|
|
194
|
+
scope: {
|
|
195
|
+
workspaceId: "default",
|
|
196
|
+
projectId: project.id
|
|
197
|
+
},
|
|
198
|
+
occurredAt: new Date(project.updatedAt).toISOString(),
|
|
199
|
+
dedupeKey: `project:${project.id}:${project.updatedAt}:${createHash("sha256").update(JSON.stringify(patch)).digest("hex")}`,
|
|
200
|
+
sensitivity: "personal",
|
|
201
|
+
payload: {
|
|
202
|
+
before,
|
|
203
|
+
after: project,
|
|
204
|
+
changes
|
|
205
|
+
}
|
|
206
|
+
});
|
|
207
|
+
return project;
|
|
177
208
|
});
|
|
178
|
-
return project;
|
|
179
209
|
}
|
|
180
210
|
pin(id) {
|
|
181
211
|
return this.update(id, { pinnedAt: Date.now() });
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
DROP TABLE IF EXISTS focus_insights;
|
|
2
|
+
DROP TABLE IF EXISTS focus_activities;
|
|
3
|
+
DROP TABLE IF EXISTS focus_monitors;
|
|
4
|
+
DROP TABLE IF EXISTS focus_projects;
|
|
5
|
+
DROP TABLE IF EXISTS focuses;
|
|
6
|
+
DROP TABLE IF EXISTS focus_candidate_projects;
|
|
7
|
+
DROP TABLE IF EXISTS focus_candidates;
|
|
8
|
+
|
|
9
|
+
CREATE TABLE proactive_events (
|
|
10
|
+
event_id TEXT PRIMARY KEY,
|
|
11
|
+
type TEXT NOT NULL,
|
|
12
|
+
schema_version INTEGER NOT NULL CHECK (schema_version > 0),
|
|
13
|
+
source_kind TEXT NOT NULL,
|
|
14
|
+
source_id TEXT NOT NULL,
|
|
15
|
+
device_id TEXT,
|
|
16
|
+
subject_kind TEXT NOT NULL,
|
|
17
|
+
subject_id TEXT NOT NULL,
|
|
18
|
+
actor_kind TEXT NOT NULL CHECK (actor_kind IN ('user', 'agent', 'system', 'integration')),
|
|
19
|
+
actor_id TEXT,
|
|
20
|
+
workspace_id TEXT NOT NULL,
|
|
21
|
+
project_id TEXT,
|
|
22
|
+
agent_id TEXT,
|
|
23
|
+
occurred_at TEXT NOT NULL,
|
|
24
|
+
observed_at TEXT NOT NULL,
|
|
25
|
+
correlation_id TEXT NOT NULL,
|
|
26
|
+
causation_id TEXT,
|
|
27
|
+
dedupe_key TEXT NOT NULL UNIQUE,
|
|
28
|
+
sensitivity TEXT NOT NULL CHECK (sensitivity IN ('public', 'personal', 'confidential', 'restricted')),
|
|
29
|
+
payload_json TEXT NOT NULL,
|
|
30
|
+
routed_at TEXT
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
CREATE TABLE proactive_signal_batches (
|
|
34
|
+
batch_id TEXT PRIMARY KEY,
|
|
35
|
+
scenario_key TEXT NOT NULL,
|
|
36
|
+
scenario_version INTEGER NOT NULL CHECK (scenario_version > 0),
|
|
37
|
+
aggregation_key TEXT NOT NULL,
|
|
38
|
+
window_started_at TEXT NOT NULL,
|
|
39
|
+
window_ends_at TEXT NOT NULL,
|
|
40
|
+
ready_at TEXT NOT NULL,
|
|
41
|
+
status TEXT NOT NULL CHECK (status IN (
|
|
42
|
+
'collecting', 'ready', 'processing', 'processed', 'ignored',
|
|
43
|
+
'failed_retryable', 'failed_permanent', 'expired'
|
|
44
|
+
)),
|
|
45
|
+
event_count INTEGER NOT NULL DEFAULT 0 CHECK (event_count >= 0),
|
|
46
|
+
created_at TEXT NOT NULL,
|
|
47
|
+
updated_at TEXT NOT NULL
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
CREATE TABLE proactive_batch_events (
|
|
51
|
+
batch_id TEXT NOT NULL,
|
|
52
|
+
event_id TEXT NOT NULL,
|
|
53
|
+
added_at TEXT NOT NULL,
|
|
54
|
+
PRIMARY KEY (batch_id, event_id),
|
|
55
|
+
FOREIGN KEY (batch_id) REFERENCES proactive_signal_batches(batch_id) ON DELETE CASCADE,
|
|
56
|
+
FOREIGN KEY (event_id) REFERENCES proactive_events(event_id) ON DELETE CASCADE
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
CREATE INDEX idx_proactive_events_type_observed
|
|
60
|
+
ON proactive_events(type, observed_at DESC);
|
|
61
|
+
CREATE INDEX idx_proactive_events_subject
|
|
62
|
+
ON proactive_events(subject_kind, subject_id, occurred_at DESC);
|
|
63
|
+
CREATE INDEX idx_proactive_events_project
|
|
64
|
+
ON proactive_events(project_id, occurred_at DESC) WHERE project_id IS NOT NULL;
|
|
65
|
+
CREATE INDEX idx_proactive_events_correlation
|
|
66
|
+
ON proactive_events(correlation_id);
|
|
67
|
+
CREATE INDEX idx_proactive_batches_ready
|
|
68
|
+
ON proactive_signal_batches(status, ready_at);
|
|
69
|
+
CREATE UNIQUE INDEX idx_proactive_collecting_batch
|
|
70
|
+
ON proactive_signal_batches(scenario_key, aggregation_key)
|
|
71
|
+
WHERE status = 'collecting';
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
CREATE TABLE proactive_scenarios (
|
|
2
|
+
scenario_key TEXT PRIMARY KEY,
|
|
3
|
+
version INTEGER NOT NULL CHECK (version > 0),
|
|
4
|
+
title TEXT NOT NULL,
|
|
5
|
+
description TEXT NOT NULL,
|
|
6
|
+
base_prompt TEXT NOT NULL,
|
|
7
|
+
base_template_version INTEGER NOT NULL CHECK (base_template_version > 0),
|
|
8
|
+
event_types_json TEXT NOT NULL,
|
|
9
|
+
condition_json TEXT,
|
|
10
|
+
aggregation TEXT NOT NULL CHECK (aggregation IN ('subject', 'project', 'workspace')),
|
|
11
|
+
debounce_seconds INTEGER NOT NULL CHECK (debounce_seconds >= 0),
|
|
12
|
+
max_window_seconds INTEGER NOT NULL CHECK (max_window_seconds > 0),
|
|
13
|
+
created_at TEXT NOT NULL,
|
|
14
|
+
updated_at TEXT NOT NULL
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
CREATE TABLE proactive_scenario_subscriptions (
|
|
18
|
+
subscription_id TEXT PRIMARY KEY,
|
|
19
|
+
scenario_key TEXT NOT NULL,
|
|
20
|
+
workspace_id TEXT NOT NULL,
|
|
21
|
+
scope_kind TEXT NOT NULL CHECK (scope_kind IN ('workspace', 'project')),
|
|
22
|
+
scope_id TEXT NOT NULL,
|
|
23
|
+
enabled INTEGER NOT NULL DEFAULT 0 CHECK (enabled IN (0, 1)),
|
|
24
|
+
active_prompt_revision_id TEXT,
|
|
25
|
+
created_at TEXT NOT NULL,
|
|
26
|
+
updated_at TEXT NOT NULL,
|
|
27
|
+
UNIQUE (scenario_key, workspace_id, scope_kind, scope_id),
|
|
28
|
+
FOREIGN KEY (scenario_key) REFERENCES proactive_scenarios(scenario_key) ON DELETE CASCADE
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
CREATE TABLE proactive_prompt_revisions (
|
|
32
|
+
revision_id TEXT PRIMARY KEY,
|
|
33
|
+
subscription_id TEXT NOT NULL,
|
|
34
|
+
revision INTEGER NOT NULL CHECK (revision > 0),
|
|
35
|
+
status TEXT NOT NULL CHECK (status IN ('draft', 'published', 'retired')),
|
|
36
|
+
base_template_version INTEGER NOT NULL CHECK (base_template_version > 0),
|
|
37
|
+
user_instructions TEXT NOT NULL,
|
|
38
|
+
content_hash TEXT NOT NULL,
|
|
39
|
+
created_at TEXT NOT NULL,
|
|
40
|
+
published_at TEXT,
|
|
41
|
+
UNIQUE (subscription_id, revision),
|
|
42
|
+
FOREIGN KEY (subscription_id) REFERENCES proactive_scenario_subscriptions(subscription_id) ON DELETE CASCADE
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
CREATE INDEX idx_proactive_subscriptions_enabled
|
|
46
|
+
ON proactive_scenario_subscriptions(enabled, workspace_id, scenario_key);
|
|
47
|
+
CREATE INDEX idx_proactive_prompt_revisions_subscription
|
|
48
|
+
ON proactive_prompt_revisions(subscription_id, status, revision DESC);
|
|
49
|
+
|
|
50
|
+
ALTER TABLE proactive_signal_batches ADD COLUMN subscription_id TEXT NOT NULL DEFAULT '';
|
|
51
|
+
DROP INDEX idx_proactive_collecting_batch;
|
|
52
|
+
CREATE UNIQUE INDEX idx_proactive_collecting_batch
|
|
53
|
+
ON proactive_signal_batches(subscription_id, scenario_key, aggregation_key)
|
|
54
|
+
WHERE status = 'collecting';
|
|
55
|
+
|
|
56
|
+
INSERT INTO proactive_scenarios VALUES
|
|
57
|
+
('project_delivery_risk', 1, 'Project delivery risk', 'Detect credible risks to a project commitment.',
|
|
58
|
+
'Identify material changes that create supported schedule, scope, dependency, capacity, or ownership risk. Ignore routine activity and unsupported absence-of-activity claims.',
|
|
59
|
+
1, '["project.updated.v1","work_item.status_changed.v1","work_item.updated.v1"]', NULL,
|
|
60
|
+
'project', 300, 1800, datetime('now'), datetime('now')),
|
|
61
|
+
('blocked_work', 1, 'Blocked work', 'Find work that needs a decision, dependency, or owner intervention.',
|
|
62
|
+
'Confirm that work is truly blocked, identify the blocking object and downstream impact, then propose the smallest supported intervention.',
|
|
63
|
+
1, '["work_item.status_changed.v1","work_item.updated.v1"]',
|
|
64
|
+
'{"op":"any","conditions":[{"op":"eq","field":"payload.after.status","value":"blocked"},{"op":"changed","field":"payload.dependencyIds"}]}',
|
|
65
|
+
'project', 180, 900, datetime('now'), datetime('now')),
|
|
66
|
+
('automation_failure_impact', 1, 'Automation failure impact', 'Explain whether a terminal automation failure affects user outcomes.',
|
|
67
|
+
'Classify the failure, distinguish completed from incomplete work, connect it to a user outcome, and request only supported recovery decisions. Do not repeat raw stack traces.',
|
|
68
|
+
1, '["automation.run_failed.v1"]', NULL,
|
|
69
|
+
'subject', 60, 300, datetime('now'), datetime('now'));
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
CREATE TABLE proactive_context_snapshots (
|
|
2
|
+
snapshot_id TEXT PRIMARY KEY,
|
|
3
|
+
batch_id TEXT NOT NULL,
|
|
4
|
+
content_json TEXT NOT NULL,
|
|
5
|
+
evidence_ids_json TEXT NOT NULL,
|
|
6
|
+
created_at TEXT NOT NULL,
|
|
7
|
+
FOREIGN KEY (batch_id) REFERENCES proactive_signal_batches(batch_id) ON DELETE CASCADE
|
|
8
|
+
);
|
|
9
|
+
|
|
10
|
+
CREATE TABLE proactive_runs (
|
|
11
|
+
run_id TEXT PRIMARY KEY,
|
|
12
|
+
batch_id TEXT NOT NULL UNIQUE,
|
|
13
|
+
subscription_id TEXT NOT NULL,
|
|
14
|
+
scenario_key TEXT NOT NULL,
|
|
15
|
+
scenario_version INTEGER NOT NULL,
|
|
16
|
+
prompt_revision_id TEXT,
|
|
17
|
+
context_snapshot_id TEXT,
|
|
18
|
+
status TEXT NOT NULL CHECK (status IN ('running', 'completed', 'discarded', 'retryable', 'failed')),
|
|
19
|
+
attempt INTEGER NOT NULL DEFAULT 1 CHECK (attempt > 0),
|
|
20
|
+
lease_owner TEXT,
|
|
21
|
+
lease_expires_at TEXT,
|
|
22
|
+
model_ref TEXT,
|
|
23
|
+
raw_output TEXT,
|
|
24
|
+
error_message TEXT,
|
|
25
|
+
next_attempt_at TEXT,
|
|
26
|
+
started_at TEXT NOT NULL,
|
|
27
|
+
completed_at TEXT,
|
|
28
|
+
updated_at TEXT NOT NULL,
|
|
29
|
+
FOREIGN KEY (batch_id) REFERENCES proactive_signal_batches(batch_id) ON DELETE CASCADE,
|
|
30
|
+
FOREIGN KEY (subscription_id) REFERENCES proactive_scenario_subscriptions(subscription_id) ON DELETE CASCADE,
|
|
31
|
+
FOREIGN KEY (prompt_revision_id) REFERENCES proactive_prompt_revisions(revision_id),
|
|
32
|
+
FOREIGN KEY (context_snapshot_id) REFERENCES proactive_context_snapshots(snapshot_id)
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
CREATE TABLE proactive_insights (
|
|
36
|
+
insight_id TEXT PRIMARY KEY,
|
|
37
|
+
run_id TEXT NOT NULL UNIQUE,
|
|
38
|
+
subscription_id TEXT NOT NULL,
|
|
39
|
+
scenario_key TEXT NOT NULL,
|
|
40
|
+
title TEXT NOT NULL,
|
|
41
|
+
summary TEXT NOT NULL,
|
|
42
|
+
why_now TEXT NOT NULL,
|
|
43
|
+
impact TEXT NOT NULL,
|
|
44
|
+
recommendation TEXT NOT NULL,
|
|
45
|
+
urgency TEXT NOT NULL CHECK (urgency IN ('low', 'medium', 'high', 'critical')),
|
|
46
|
+
confidence REAL NOT NULL CHECK (confidence >= 0 AND confidence <= 1),
|
|
47
|
+
value_score REAL NOT NULL CHECK (value_score >= 0 AND value_score <= 1),
|
|
48
|
+
evidence_ids_json TEXT NOT NULL,
|
|
49
|
+
created_at TEXT NOT NULL,
|
|
50
|
+
FOREIGN KEY (run_id) REFERENCES proactive_runs(run_id) ON DELETE CASCADE,
|
|
51
|
+
FOREIGN KEY (subscription_id) REFERENCES proactive_scenario_subscriptions(subscription_id) ON DELETE CASCADE
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
CREATE INDEX idx_proactive_runs_status_lease ON proactive_runs(status, next_attempt_at, lease_expires_at, updated_at);
|
|
55
|
+
CREATE INDEX idx_proactive_insights_created ON proactive_insights(created_at DESC);
|