@xopcai/xopc 0.0.176 → 0.0.178
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-BzGX__8I.js} +1 -1
- package/dist/gateway/static/root/assets/{agent-avatar-dicebear-DvdMLOga.js → agent-avatar-dicebear-BzxntcaZ.js} +1 -1
- package/dist/gateway/static/root/assets/agents-DC9F12Kw.js +2 -0
- package/dist/gateway/static/root/assets/{api-BdPLCCBm.js → api-hi6f2Xtp.js} +1 -1
- package/dist/gateway/static/root/assets/{app-management-settings-panel-DMLDOHul.js → app-management-settings-panel-fTY1F7ac.js} +1 -1
- package/dist/gateway/static/root/assets/{appearance-settings-DbI9foFR.js → appearance-settings-BZ-IxQfB.js} +1 -1
- package/dist/gateway/static/root/assets/apps-page-5bKr05Fa.js +1 -0
- package/dist/gateway/static/root/assets/{archive-plugin-Dfdxuwvb.js → archive-plugin-ZSLLG8wB.js} +1 -1
- package/dist/gateway/static/root/assets/{attachment-load-Dn3RlnYD.js → attachment-load-D4YktqIF.js} +1 -1
- package/dist/gateway/static/root/assets/{automation-suggestion-card-Bc0Y7A9u.js → automation-suggestion-card-B7mxFRtf.js} +1 -1
- package/dist/gateway/static/root/assets/automations-page-Dg6dmt5g.js +6 -0
- package/dist/gateway/static/root/assets/{binary-plugins-0XtB-xC0.js → binary-plugins-BIkPxfxj.js} +1 -1
- package/dist/gateway/static/root/assets/{block-editor-C4fXWbEE.js → block-editor-Q3v_YQom.js} +6 -6
- package/dist/gateway/static/root/assets/{browser-settings-page-lC86-drr.js → browser-settings-page-BHoo6Rpq.js} +4 -4
- package/dist/gateway/static/root/assets/{browser-workflow-inputs-CZmzNymN.js → browser-workflow-inputs-M5lTEW1I.js} +1 -1
- package/dist/gateway/static/root/assets/{browser-workflows-page-CBYM9HqG.js → browser-workflows-page-B3T1KYk4.js} +2 -2
- package/dist/gateway/static/root/assets/capabilities-settings-panel-BlsqN8Fu.js +7 -0
- package/dist/gateway/static/root/assets/{capability-presets-api-BiJxmmhW.js → capability-presets-api-DE09c0VB.js} +1 -1
- package/dist/gateway/static/root/assets/capability-presets-settings-panel-DJeT8_B4.js +1 -0
- package/dist/gateway/static/root/assets/{channel-recipient-api-BKTUZDp-.js → channel-recipient-api-CFR5FBfS.js} +1 -1
- package/dist/gateway/static/root/assets/channels-settings-C4VVjYEm.js +1 -0
- package/dist/gateway/static/root/assets/channels-status-swr-vdf8kB16.js +1 -0
- package/dist/gateway/static/root/assets/{connector-logo-Pr4RIKjj.js → connector-logo-B1mD-3pM.js} +1 -1
- package/dist/gateway/static/root/assets/connectors-page-DNcrDThX.js +2 -0
- package/dist/gateway/static/root/assets/desktop-pet-B1urphOZ.js +1 -0
- package/dist/gateway/static/root/assets/{desktop-pet-settings-CEQacUDF.js → desktop-pet-settings-DTL6J3EP.js} +1 -1
- package/dist/gateway/static/root/assets/{directory-picker-path-field-DWnxdZtc.js → directory-picker-path-field-BYQJ2XUS.js} +1 -1
- package/dist/gateway/static/root/assets/{dreaming-settings-D2e2w2Ho.js → dreaming-settings-BXcb8fwx.js} +3 -3
- package/dist/gateway/static/root/assets/{extension-debug-page-BLjTGbv3.js → extension-debug-page-O1Xu1r4Q.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-D2_UC6hy.js → extension-page-C2Jraq8l.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-settings-page-BsH6o_PX.js → extension-settings-page-DcXQDTpG.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-config-api-C-DkC6UJ.js → gateway-config-api-DmPIZrvg.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-settings-DEOGiimF.js → gateway-settings-DmObBx9b.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-startup-retry-BlSLh1TF.js → gateway-startup-retry-BZEkOdPm.js} +1 -1
- package/dist/gateway/static/root/assets/{goal-create-dialog-CSFcRE_N.js → goal-create-dialog-BRhmmBe9.js} +1 -1
- package/dist/gateway/static/root/assets/goal-detail-page-C1k7_s_O.js +4 -0
- package/dist/gateway/static/root/assets/{goals-config-api-CcdS9qek.js → goals-config-api-Fwu1wjEP.js} +1 -1
- package/dist/gateway/static/root/assets/{goals-page-BAcErdch.js → goals-page-hOu9uA3q.js} +2 -2
- package/dist/gateway/static/root/assets/{goals-settings-BY7crl0z.js → goals-settings-DY-JjvHz.js} +1 -1
- package/dist/gateway/static/root/assets/{heartbeat-settings-DtTkS0gs.js → heartbeat-settings-BtKu2NWT.js} +1 -1
- package/dist/gateway/static/root/assets/{image-generation-api-WGgkbwDZ.js → image-generation-api-05Gg8wsU.js} +1 -1
- package/dist/gateway/static/root/assets/{index-2UImfRDC.js → index-C0CGebQ1.js} +65 -65
- package/dist/gateway/static/root/assets/index-eqq25gvV.css +1 -0
- package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-C5lpWQ3f.js → keyboard-shortcuts-settings-CfmDR9Sc.js} +1 -1
- package/dist/gateway/static/root/assets/local-app-workbench-page-EjsNT7nJ.js +2 -0
- package/dist/gateway/static/root/assets/{local-apps-page-b05wWvXG.js → local-apps-page-Df8BW1A_.js} +1 -1
- package/dist/gateway/static/root/assets/{locale-store-sToMfHX_.js → locale-store-CTwSy7yW.js} +1 -1
- package/dist/gateway/static/root/assets/{logs-page-cDE1jLJv.js → logs-page-Dswjlraa.js} +3 -3
- package/dist/gateway/static/root/assets/{markdown-split-0gPVst5y.js → markdown-split-B3FvKbaP.js} +1 -1
- package/dist/gateway/static/root/assets/{media-plugins-Rxyq_KTm.js → media-plugins-DsjrvvB6.js} +1 -1
- package/dist/gateway/static/root/assets/messages-DP6tPKk-.js +3 -0
- package/dist/gateway/static/root/assets/{notes-page-DRhNDl_Q.js → notes-page-tuzIwy3c.js} +1 -1
- package/dist/gateway/static/root/assets/notes-workbench-DSh3-hMY.js +4 -0
- package/dist/gateway/static/root/assets/{page-tabs-cOEOQqHh.js → page-tabs-ke9s4nYi.js} +1 -1
- package/dist/gateway/static/root/assets/{preview-open-alternatives-BopOLFvu.js → preview-open-alternatives-Cp1eI4S9.js} +1 -1
- package/dist/gateway/static/root/assets/{product-open-page-DWVPmmOq.js → product-open-page-dXQCMAtH.js} +1 -1
- package/dist/gateway/static/root/assets/project-detail-page-D0QPRHR_.js +1 -0
- package/dist/gateway/static/root/assets/projects-page-CI5Vz62F.js +1 -0
- package/dist/gateway/static/root/assets/remote-access-hub-S1jpzBS5.js +1 -0
- package/dist/gateway/static/root/assets/{save-bar-controls-BfZmKe1t.js → save-bar-controls-Bl30zjHc.js} +1 -1
- package/dist/gateway/static/root/assets/{schedule-field-Cpi4jCRV.js → schedule-field-DqhmXQKo.js} +1 -1
- package/dist/gateway/static/root/assets/{schema-form-OXFkcZQe.js → schema-form-DkUCy6vf.js} +1 -1
- package/dist/gateway/static/root/assets/sessions-page-CTm66k7h.js +1 -0
- package/dist/gateway/static/root/assets/settings-advanced-gate-CU52AUVD.js +1 -0
- package/dist/gateway/static/root/assets/{settings-form-section-BwqkZCHJ.js → settings-form-section-C6ZbNpdy.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-loading-skeleton-BbqH_S3Y.js → settings-loading-skeleton-Bk58_cr7.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-page-BoxC-JSa.js → settings-page-k8iE_NdX.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-page-layout-Ddu2iGaW.js → settings-page-layout-DgFSya2e.js} +1 -1
- package/dist/gateway/static/root/assets/{setup-status-panel-z1Lwv0js.js → setup-status-panel-B_KDlyZA.js} +1 -1
- package/dist/gateway/static/root/assets/{share-preview-page-CVazOFjy.js → share-preview-page-CV7nL_J9.js} +1 -1
- package/dist/gateway/static/root/assets/shares-settings-DK6XK95e.js +1 -0
- package/dist/gateway/static/root/assets/skill-reload-api-Bvv_u4ii.js +1 -0
- package/dist/gateway/static/root/assets/skills-page-BGHvVbay.js +2 -0
- package/dist/gateway/static/root/assets/{skills-page.utils-DgyB1tSo.js → skills-page.utils-kahBIHg0.js} +1 -1
- package/dist/gateway/static/root/assets/{system-settings-panel-BoLSQL65.js → system-settings-panel-JV3-MG5F.js} +1 -1
- package/dist/gateway/static/root/assets/{theme-store-CBNcGOfj.js → theme-store-DFLyzoLO.js} +1 -1
- package/dist/gateway/static/root/assets/{time-picker-gochWrny.js → time-picker-XwpxdZFr.js} +1 -1
- package/dist/gateway/static/root/assets/{typed-models-lib-DvRnr7YB.js → typed-models-lib-60Aqo-UJ.js} +1 -1
- package/dist/gateway/static/root/assets/{use-channel-catalog-CA9BFVB7.js → use-channel-catalog-CnTkHDnw.js} +1 -1
- package/dist/gateway/static/root/assets/user-context-page-DBCMk-Vn.js +1 -0
- package/dist/gateway/static/root/assets/{voice-api-key-field-v8tgylEZ.js → voice-api-key-field-CNa8qUgS.js} +1 -1
- package/dist/gateway/static/root/assets/work-discovery-page-C1UIdsCl.js +1 -0
- package/dist/gateway/static/root/assets/work-item-detail-page-DEAQepB8.js +1 -0
- package/dist/gateway/static/root/assets/work-page-D5qYmCTq.js +3 -0
- package/dist/gateway/static/root/assets/{workflow-run-setup-panel-CC3cJn5k.js → workflow-run-setup-panel-yV_x595t.js} +2 -2
- package/dist/gateway/static/root/assets/workflows-page-yrK17ZZ5.js +11 -0
- package/dist/gateway/static/root/index.html +7 -7
- package/dist/package.js +1 -1
- package/dist/src/agent/embedded/model-runtime.js +3 -0
- package/dist/src/agent/embedded/run-for-session.js +18 -5
- package/dist/src/agent/embedded/run-turn.js +6 -3
- package/dist/src/agent/embedded/types.d.ts +2 -0
- 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/connectors/composio-sessions.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/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/providers/provider-auth-service.js +3 -0
- package/dist/src/providers/register-bundled-oauth-flows.d.ts +2 -0
- package/dist/src/providers/register-bundled-oauth-flows.js +16 -0
- package/dist/src/session/store.d.ts +2 -0
- package/dist/src/session/store.js +30 -0
- 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 +3 -11
- 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
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import type { FocusCandidate, FocusCandidateStatus, FocusEvidence } from './types.js';
|
|
2
|
-
import type { Focus } from './types.js';
|
|
3
|
-
export declare function getFocusCandidate(id: string): FocusCandidate | null;
|
|
4
|
-
export declare function listFocusCandidates(status?: FocusCandidateStatus, limit?: number): FocusCandidate[];
|
|
5
|
-
export declare function upsertFocusCandidate(input: {
|
|
6
|
-
canonicalKey: string;
|
|
7
|
-
title: string;
|
|
8
|
-
summary: string;
|
|
9
|
-
confidence: number;
|
|
10
|
-
evidence?: FocusEvidence[];
|
|
11
|
-
projectIds?: string[];
|
|
12
|
-
nowMs?: number;
|
|
13
|
-
}): FocusCandidate;
|
|
14
|
-
export declare function setFocusCandidateStatus(id: string, status: FocusCandidateStatus, nowMs?: number): FocusCandidate | null;
|
|
15
|
-
export declare function acceptFocusCandidate(id: string, nowMs?: number): Focus | null;
|
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
import { requireXopcDatabase } from "../storage/sqlite/connection.js";
|
|
2
|
-
import { runSqliteWriteTransaction } from "../storage/sqlite/transaction.js";
|
|
3
|
-
import { getFocus } from "./repository.js";
|
|
4
|
-
import { randomUUID } from "node:crypto";
|
|
5
|
-
//#region src/focuses/candidate-repository.ts
|
|
6
|
-
function projectIdsForCandidate(db, id) {
|
|
7
|
-
return db.prepare("SELECT project_id FROM focus_candidate_projects WHERE candidate_id = ? ORDER BY created_at, project_id").all(id).map((row) => row.project_id);
|
|
8
|
-
}
|
|
9
|
-
function candidateFromRow(db, row) {
|
|
10
|
-
let evidence = [];
|
|
11
|
-
try {
|
|
12
|
-
const parsed = JSON.parse(row.evidence_json);
|
|
13
|
-
if (Array.isArray(parsed)) evidence = parsed;
|
|
14
|
-
} catch {
|
|
15
|
-
evidence = [];
|
|
16
|
-
}
|
|
17
|
-
return {
|
|
18
|
-
id: row.candidate_id,
|
|
19
|
-
canonicalKey: row.canonical_key,
|
|
20
|
-
title: row.title,
|
|
21
|
-
summary: row.summary,
|
|
22
|
-
confidence: row.confidence,
|
|
23
|
-
evidence,
|
|
24
|
-
projectIds: projectIdsForCandidate(db, row.candidate_id),
|
|
25
|
-
status: row.status,
|
|
26
|
-
discoveredAt: row.discovered_at,
|
|
27
|
-
updatedAt: row.updated_at
|
|
28
|
-
};
|
|
29
|
-
}
|
|
30
|
-
function getFocusCandidate(id) {
|
|
31
|
-
const { db } = requireXopcDatabase();
|
|
32
|
-
const row = db.prepare("SELECT * FROM focus_candidates WHERE candidate_id = ?").get(id);
|
|
33
|
-
return row ? candidateFromRow(db, row) : null;
|
|
34
|
-
}
|
|
35
|
-
function listFocusCandidates(status = "pending", limit = 20) {
|
|
36
|
-
const { db } = requireXopcDatabase();
|
|
37
|
-
return db.prepare("SELECT * FROM focus_candidates WHERE status = ? ORDER BY updated_at DESC LIMIT ?").all(status, Math.max(1, Math.min(100, limit))).map((row) => candidateFromRow(db, row));
|
|
38
|
-
}
|
|
39
|
-
function upsertFocusCandidate(input) {
|
|
40
|
-
const now = input.nowMs ?? Date.now();
|
|
41
|
-
const id = randomUUID();
|
|
42
|
-
runSqliteWriteTransaction((db) => {
|
|
43
|
-
db.prepare(`INSERT INTO focus_candidates (
|
|
44
|
-
candidate_id, canonical_key, title, summary, confidence, evidence_json,
|
|
45
|
-
status, discovered_at, updated_at
|
|
46
|
-
) VALUES (?, ?, ?, ?, ?, ?, 'pending', ?, ?)
|
|
47
|
-
ON CONFLICT(canonical_key) DO UPDATE SET
|
|
48
|
-
title = CASE WHEN focus_candidates.status = 'pending' THEN excluded.title ELSE focus_candidates.title END,
|
|
49
|
-
summary = CASE WHEN focus_candidates.status = 'pending' THEN excluded.summary ELSE focus_candidates.summary END,
|
|
50
|
-
confidence = CASE WHEN focus_candidates.status = 'pending' THEN excluded.confidence ELSE focus_candidates.confidence END,
|
|
51
|
-
evidence_json = CASE WHEN focus_candidates.status = 'pending' THEN excluded.evidence_json ELSE focus_candidates.evidence_json END,
|
|
52
|
-
updated_at = excluded.updated_at`).run(id, input.canonicalKey.trim().slice(0, 300), input.title.trim().slice(0, 200), input.summary.trim().slice(0, 2e3), Math.max(0, Math.min(1, input.confidence)), JSON.stringify(input.evidence ?? []), now, now);
|
|
53
|
-
const row = db.prepare("SELECT candidate_id, status FROM focus_candidates WHERE canonical_key = ?").get(input.canonicalKey.trim().slice(0, 300));
|
|
54
|
-
if (row.status === "pending") {
|
|
55
|
-
db.prepare("DELETE FROM focus_candidate_projects WHERE candidate_id = ?").run(row.candidate_id);
|
|
56
|
-
const insertProject = db.prepare("INSERT INTO focus_candidate_projects (candidate_id, project_id, created_at) VALUES (?, ?, ?)");
|
|
57
|
-
for (const projectId of [...new Set(input.projectIds ?? [])].slice(0, 20)) insertProject.run(row.candidate_id, projectId, now);
|
|
58
|
-
}
|
|
59
|
-
});
|
|
60
|
-
const { db } = requireXopcDatabase();
|
|
61
|
-
return candidateFromRow(db, db.prepare("SELECT * FROM focus_candidates WHERE canonical_key = ?").get(input.canonicalKey.trim().slice(0, 300)));
|
|
62
|
-
}
|
|
63
|
-
function setFocusCandidateStatus(id, status, nowMs = Date.now()) {
|
|
64
|
-
let changed = false;
|
|
65
|
-
runSqliteWriteTransaction((db) => {
|
|
66
|
-
changed = db.prepare("UPDATE focus_candidates SET status = ?, updated_at = ? WHERE candidate_id = ?").run(status, nowMs, id).changes > 0;
|
|
67
|
-
});
|
|
68
|
-
return changed ? getFocusCandidate(id) : null;
|
|
69
|
-
}
|
|
70
|
-
function acceptFocusCandidate(id, nowMs = Date.now()) {
|
|
71
|
-
const candidate = getFocusCandidate(id);
|
|
72
|
-
if (!candidate) return null;
|
|
73
|
-
const existing = requireXopcDatabase().db.prepare("SELECT focus_id FROM focuses WHERE source_candidate_id = ?").get(id);
|
|
74
|
-
if (existing) return getFocus(existing.focus_id);
|
|
75
|
-
const focusId = randomUUID();
|
|
76
|
-
runSqliteWriteTransaction((db) => {
|
|
77
|
-
db.prepare(`INSERT INTO focuses (
|
|
78
|
-
focus_id, title, summary, status, source, source_candidate_id,
|
|
79
|
-
created_at, updated_at, last_activity_at
|
|
80
|
-
) VALUES (?, ?, ?, 'active', 'discovery', ?, ?, ?, ?)`).run(focusId, candidate.title, candidate.summary, candidate.id, nowMs, nowMs, nowMs);
|
|
81
|
-
const insertProject = db.prepare("INSERT INTO focus_projects (focus_id, project_id, created_at) VALUES (?, ?, ?)");
|
|
82
|
-
for (const projectId of candidate.projectIds) insertProject.run(focusId, projectId, nowMs);
|
|
83
|
-
db.prepare(`INSERT INTO focus_activities (
|
|
84
|
-
activity_id, focus_id, type, summary, details_json, created_at
|
|
85
|
-
) VALUES (?, ?, 'created', 'Focus created from discovery', '{}', ?)`).run(randomUUID(), focusId, nowMs);
|
|
86
|
-
db.prepare("UPDATE focus_candidates SET status = 'accepted', updated_at = ? WHERE candidate_id = ?").run(nowMs, candidate.id);
|
|
87
|
-
});
|
|
88
|
-
return getFocus(focusId);
|
|
89
|
-
}
|
|
90
|
-
//#endregion
|
|
91
|
-
export { acceptFocusCandidate, getFocusCandidate, listFocusCandidates, setFocusCandidateStatus, upsertFocusCandidate };
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import { createFocus, createFocusActivity, deleteFocus, getFocus, getFocusMonitor, getFocusMonitorByAutomationId, listAllFocusMonitors, listFocusActivities, listFocusMonitors, listFocuses, updateFocus, updateFocusMonitorRuntime, upsertFocusMonitor } from "./repository.js";
|
|
2
|
-
import { acceptFocusCandidate, getFocusCandidate, listFocusCandidates, setFocusCandidateStatus, upsertFocusCandidate } from "./candidate-repository.js";
|
|
3
|
-
import { createFocusInsight, getFocusInsight, listFocusInsights, setFocusInsightStatus } from "./insight-repository.js";
|
|
4
|
-
import { FocusService } from "./service.js";
|
|
5
|
-
import { parseFocusMonitorResult, processFocusMonitorRun } from "./run-processor.js";
|
|
6
|
-
import { startFocusReconciler } from "./reconciler.js";
|
|
7
|
-
export { FocusService, acceptFocusCandidate, createFocus, createFocusActivity, createFocusInsight, deleteFocus, getFocus, getFocusCandidate, getFocusInsight, getFocusMonitor, getFocusMonitorByAutomationId, listAllFocusMonitors, listFocusActivities, listFocusCandidates, listFocusInsights, listFocusMonitors, listFocuses, parseFocusMonitorResult, processFocusMonitorRun, setFocusCandidateStatus, setFocusInsightStatus, startFocusReconciler, updateFocus, updateFocusMonitorRuntime, upsertFocusCandidate, upsertFocusMonitor };
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import type { FocusEvidence, FocusInsight, FocusInsightStatus, FocusMonitorKind } from './types.js';
|
|
2
|
-
export declare function getFocusInsight(id: string): FocusInsight | null;
|
|
3
|
-
export declare function listFocusInsights(input: {
|
|
4
|
-
focusId: string;
|
|
5
|
-
statuses?: FocusInsightStatus[];
|
|
6
|
-
limit?: number;
|
|
7
|
-
}): FocusInsight[];
|
|
8
|
-
export declare function createFocusInsight(input: {
|
|
9
|
-
focusId: string;
|
|
10
|
-
monitorId: string;
|
|
11
|
-
runId: string;
|
|
12
|
-
kind: FocusMonitorKind;
|
|
13
|
-
title: string;
|
|
14
|
-
summary: string;
|
|
15
|
-
whyItMatters: string;
|
|
16
|
-
nextAction: string;
|
|
17
|
-
evidence: FocusEvidence[];
|
|
18
|
-
valueScore?: number;
|
|
19
|
-
valueReasons?: string[];
|
|
20
|
-
nowMs?: number;
|
|
21
|
-
}): FocusInsight | null;
|
|
22
|
-
export declare function setFocusInsightStatus(id: string, status: FocusInsightStatus, expectedStatus?: FocusInsightStatus, nowMs?: number): FocusInsight | null;
|
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
import { requireXopcDatabase } from "../storage/sqlite/connection.js";
|
|
2
|
-
import { runSqliteWriteTransaction } from "../storage/sqlite/transaction.js";
|
|
3
|
-
import { createHash, randomUUID } from "node:crypto";
|
|
4
|
-
//#region src/focuses/insight-repository.ts
|
|
5
|
-
function parseArray(value) {
|
|
6
|
-
try {
|
|
7
|
-
const parsed = JSON.parse(value);
|
|
8
|
-
return Array.isArray(parsed) ? parsed : [];
|
|
9
|
-
} catch {
|
|
10
|
-
return [];
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
function insightFromRow(row) {
|
|
14
|
-
return {
|
|
15
|
-
id: row.insight_id,
|
|
16
|
-
focusId: row.focus_id,
|
|
17
|
-
monitorId: row.monitor_id,
|
|
18
|
-
runId: row.run_id,
|
|
19
|
-
kind: row.kind,
|
|
20
|
-
title: row.title,
|
|
21
|
-
summary: row.summary,
|
|
22
|
-
whyItMatters: row.why_it_matters,
|
|
23
|
-
nextAction: row.next_action,
|
|
24
|
-
evidence: parseArray(row.evidence_json),
|
|
25
|
-
status: row.status,
|
|
26
|
-
valueScore: row.value_score,
|
|
27
|
-
valueReasons: parseArray(row.value_reasons_json),
|
|
28
|
-
createdAt: row.created_at,
|
|
29
|
-
updatedAt: row.updated_at
|
|
30
|
-
};
|
|
31
|
-
}
|
|
32
|
-
function getFocusInsight(id) {
|
|
33
|
-
const { db } = requireXopcDatabase();
|
|
34
|
-
const row = db.prepare("SELECT * FROM focus_insights WHERE insight_id = ?").get(id);
|
|
35
|
-
return row ? insightFromRow(row) : null;
|
|
36
|
-
}
|
|
37
|
-
function listFocusInsights(input) {
|
|
38
|
-
const statuses = input.statuses ?? ["unread", "approved"];
|
|
39
|
-
if (statuses.length === 0) return [];
|
|
40
|
-
const { db } = requireXopcDatabase();
|
|
41
|
-
return db.prepare(`SELECT * FROM focus_insights WHERE focus_id = ?
|
|
42
|
-
AND status IN (${statuses.map(() => "?").join(", ")})
|
|
43
|
-
ORDER BY created_at DESC LIMIT ?`).all(input.focusId, ...statuses, Math.max(1, Math.min(100, input.limit ?? 20))).map(insightFromRow);
|
|
44
|
-
}
|
|
45
|
-
function createFocusInsight(input) {
|
|
46
|
-
const now = input.nowMs ?? Date.now();
|
|
47
|
-
const id = randomUUID();
|
|
48
|
-
const normalized = JSON.stringify({
|
|
49
|
-
kind: input.kind,
|
|
50
|
-
title: input.title.trim().toLocaleLowerCase(),
|
|
51
|
-
evidence: input.evidence.map((item) => [
|
|
52
|
-
item.label.trim().toLocaleLowerCase(),
|
|
53
|
-
item.source?.trim().toLocaleLowerCase() ?? "",
|
|
54
|
-
item.publishedAt ?? ""
|
|
55
|
-
])
|
|
56
|
-
});
|
|
57
|
-
const contentHash = createHash("sha256").update(normalized).digest("hex");
|
|
58
|
-
let created = false;
|
|
59
|
-
runSqliteWriteTransaction((db) => {
|
|
60
|
-
created = db.prepare(`INSERT OR IGNORE INTO focus_insights (
|
|
61
|
-
insight_id, focus_id, monitor_id, run_id, kind, title, summary,
|
|
62
|
-
why_it_matters, next_action, evidence_json, content_hash, status,
|
|
63
|
-
value_score, value_reasons_json, created_at, updated_at
|
|
64
|
-
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'unread', ?, ?, ?, ?)`).run(id, input.focusId, input.monitorId, input.runId, input.kind, input.title.trim().slice(0, 200), input.summary.trim().slice(0, 2e3), input.whyItMatters.trim().slice(0, 2e3), input.nextAction.trim().slice(0, 2e3), JSON.stringify(input.evidence), contentHash, input.valueScore ?? 0, JSON.stringify(input.valueReasons ?? []), now, now).changes > 0;
|
|
65
|
-
});
|
|
66
|
-
return created ? getFocusInsight(id) : null;
|
|
67
|
-
}
|
|
68
|
-
function setFocusInsightStatus(id, status, expectedStatus, nowMs = Date.now()) {
|
|
69
|
-
let changed = false;
|
|
70
|
-
runSqliteWriteTransaction((db) => {
|
|
71
|
-
changed = db.prepare(`UPDATE focus_insights SET status = ?, updated_at = ? WHERE insight_id = ?
|
|
72
|
-
${expectedStatus ? "AND status = ?" : ""}`).run(status, nowMs, id, ...expectedStatus ? [expectedStatus] : []).changes > 0;
|
|
73
|
-
});
|
|
74
|
-
return changed ? getFocusInsight(id) : null;
|
|
75
|
-
}
|
|
76
|
-
//#endregion
|
|
77
|
-
export { createFocusInsight, getFocusInsight, listFocusInsights, setFocusInsightStatus };
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
//#region src/focuses/prompts.ts
|
|
2
|
-
function buildFocusMonitorInstruction(focus, kind) {
|
|
3
|
-
const intent = kind === "progress" ? "Look for meaningful progress, blockers, and the most useful next step." : "Search for external changes published since the previous check. Prefer primary sources and include publication dates and canonical URLs.";
|
|
4
|
-
return [
|
|
5
|
-
"Monitor this user-confirmed focus in suggest-only mode.",
|
|
6
|
-
`Focus: ${focus.title}`,
|
|
7
|
-
`Context: ${focus.summary}`,
|
|
8
|
-
intent,
|
|
9
|
-
"Inspect only evidence that changed since the previous check.",
|
|
10
|
-
"Do not modify files, send messages, publish content, or claim progress without evidence.",
|
|
11
|
-
"Return JSON only, with no markdown.",
|
|
12
|
-
"If nothing materially changed: {\"meaningful\":false}.",
|
|
13
|
-
"Otherwise return {\"meaningful\":true,\"title\":\"short title\",\"summary\":\"what changed\",\"whyItMatters\":\"concrete impact\",\"nextAction\":\"one next action\",\"evidence\":[{\"label\":\"specific evidence\",\"source\":\"file, event, or canonical URL\",\"publishedAt\":\"ISO date for external changes\"}]}.",
|
|
14
|
-
"A meaningful result requires specific evidence. Never invent evidence."
|
|
15
|
-
].join("\n");
|
|
16
|
-
}
|
|
17
|
-
//#endregion
|
|
18
|
-
export { buildFocusMonitorInstruction };
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import { createLogger } from "../utils/logger/index.js";
|
|
2
|
-
import { init_logger } from "../utils/logger.js";
|
|
3
|
-
//#region src/focuses/reconciler.ts
|
|
4
|
-
init_logger();
|
|
5
|
-
const log = createLogger("FocusReconciler");
|
|
6
|
-
const DEFAULT_INTERVAL_MS = 6e4;
|
|
7
|
-
function startFocusReconciler(service, intervalMs = DEFAULT_INTERVAL_MS) {
|
|
8
|
-
let stopped = false;
|
|
9
|
-
let pending = null;
|
|
10
|
-
const reconcile = () => {
|
|
11
|
-
if (stopped || pending) return;
|
|
12
|
-
pending = service.reconcile().catch((err) => log.warn({ err }, "Focus state reconciliation failed")).finally(() => {
|
|
13
|
-
pending = null;
|
|
14
|
-
});
|
|
15
|
-
};
|
|
16
|
-
reconcile();
|
|
17
|
-
const timer = setInterval(reconcile, intervalMs);
|
|
18
|
-
timer.unref();
|
|
19
|
-
return async () => {
|
|
20
|
-
stopped = true;
|
|
21
|
-
clearInterval(timer);
|
|
22
|
-
await pending;
|
|
23
|
-
};
|
|
24
|
-
}
|
|
25
|
-
//#endregion
|
|
26
|
-
export { startFocusReconciler };
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
import type { Focus, FocusActivity, FocusActivityType, FocusCadence, FocusMonitor, FocusMonitorKind, FocusMonitorRunState, FocusSource, FocusStatus } from './types.js';
|
|
2
|
-
export declare function getFocus(id: string): Focus | null;
|
|
3
|
-
export declare function listFocuses(options?: {
|
|
4
|
-
statuses?: FocusStatus[];
|
|
5
|
-
limit?: number;
|
|
6
|
-
}): Focus[];
|
|
7
|
-
export declare function createFocus(input: {
|
|
8
|
-
title: string;
|
|
9
|
-
summary: string;
|
|
10
|
-
source?: FocusSource;
|
|
11
|
-
sourceCandidateId?: string;
|
|
12
|
-
projectIds?: string[];
|
|
13
|
-
goalId?: string;
|
|
14
|
-
nowMs?: number;
|
|
15
|
-
}): Focus;
|
|
16
|
-
export declare function updateFocus(input: {
|
|
17
|
-
id: string;
|
|
18
|
-
title?: string;
|
|
19
|
-
summary?: string;
|
|
20
|
-
status?: FocusStatus;
|
|
21
|
-
projectIds?: string[];
|
|
22
|
-
nowMs?: number;
|
|
23
|
-
}): Focus | null;
|
|
24
|
-
export declare function deleteFocus(id: string): boolean;
|
|
25
|
-
export declare function getFocusMonitor(focusId: string, kind: FocusMonitorKind): FocusMonitor | null;
|
|
26
|
-
export declare function getFocusMonitorByAutomationId(automationId: string): FocusMonitor | null;
|
|
27
|
-
export declare function listFocusMonitors(focusId: string): FocusMonitor[];
|
|
28
|
-
export declare function listAllFocusMonitors(): FocusMonitor[];
|
|
29
|
-
export declare function upsertFocusMonitor(input: {
|
|
30
|
-
focusId: string;
|
|
31
|
-
kind: FocusMonitorKind;
|
|
32
|
-
enabled: boolean;
|
|
33
|
-
runState?: FocusMonitorRunState;
|
|
34
|
-
cadence: FocusCadence;
|
|
35
|
-
automationId?: string | null;
|
|
36
|
-
nowMs?: number;
|
|
37
|
-
}): FocusMonitor;
|
|
38
|
-
export declare function updateFocusMonitorRuntime(input: {
|
|
39
|
-
id: string;
|
|
40
|
-
runState: FocusMonitorRunState;
|
|
41
|
-
automationId?: string | null;
|
|
42
|
-
lastRunId?: string;
|
|
43
|
-
lastRunAt?: number;
|
|
44
|
-
nextRunAt?: number | null;
|
|
45
|
-
meaningful?: boolean;
|
|
46
|
-
error?: string | null;
|
|
47
|
-
nowMs?: number;
|
|
48
|
-
}): FocusMonitor | null;
|
|
49
|
-
export declare function createFocusActivity(input: {
|
|
50
|
-
focusId: string;
|
|
51
|
-
monitorId?: string;
|
|
52
|
-
type: FocusActivityType;
|
|
53
|
-
summary: string;
|
|
54
|
-
details?: Record<string, unknown>;
|
|
55
|
-
nowMs?: number;
|
|
56
|
-
}): FocusActivity;
|
|
57
|
-
export declare function listFocusActivities(input: {
|
|
58
|
-
focusId: string;
|
|
59
|
-
before?: number;
|
|
60
|
-
limit?: number;
|
|
61
|
-
}): FocusActivity[];
|
|
@@ -1,214 +0,0 @@
|
|
|
1
|
-
import { requireXopcDatabase } from "../storage/sqlite/connection.js";
|
|
2
|
-
import { runSqliteWriteTransaction } from "../storage/sqlite/transaction.js";
|
|
3
|
-
import { randomUUID } from "node:crypto";
|
|
4
|
-
//#region src/focuses/repository.ts
|
|
5
|
-
function parseObject(value) {
|
|
6
|
-
try {
|
|
7
|
-
const parsed = JSON.parse(value);
|
|
8
|
-
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
|
|
9
|
-
} catch {
|
|
10
|
-
return {};
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
function parseCadence(value) {
|
|
14
|
-
const parsed = parseObject(value);
|
|
15
|
-
return {
|
|
16
|
-
kind: "interval",
|
|
17
|
-
everyMs: typeof parsed.everyMs === "number" && parsed.everyMs > 0 ? parsed.everyMs : 864e5
|
|
18
|
-
};
|
|
19
|
-
}
|
|
20
|
-
function projectIdsForFocus(db, focusId) {
|
|
21
|
-
return db.prepare("SELECT project_id FROM focus_projects WHERE focus_id = ? ORDER BY created_at, project_id").all(focusId).map((row) => row.project_id);
|
|
22
|
-
}
|
|
23
|
-
function focusFromRow(db, row) {
|
|
24
|
-
return {
|
|
25
|
-
id: row.focus_id,
|
|
26
|
-
title: row.title,
|
|
27
|
-
summary: row.summary,
|
|
28
|
-
status: row.status,
|
|
29
|
-
source: row.source,
|
|
30
|
-
...row.source_candidate_id ? { sourceCandidateId: row.source_candidate_id } : {},
|
|
31
|
-
projectIds: projectIdsForFocus(db, row.focus_id),
|
|
32
|
-
...row.goal_id ? { goalId: row.goal_id } : {},
|
|
33
|
-
createdAt: row.created_at,
|
|
34
|
-
updatedAt: row.updated_at,
|
|
35
|
-
...row.completed_at != null ? { completedAt: row.completed_at } : {},
|
|
36
|
-
...row.last_activity_at != null ? { lastActivityAt: row.last_activity_at } : {}
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
|
-
function monitorFromRow(row) {
|
|
40
|
-
return {
|
|
41
|
-
id: row.monitor_id,
|
|
42
|
-
focusId: row.focus_id,
|
|
43
|
-
kind: row.kind,
|
|
44
|
-
enabled: row.enabled === 1,
|
|
45
|
-
runState: row.run_state,
|
|
46
|
-
cadence: parseCadence(row.cadence_json),
|
|
47
|
-
...row.automation_id ? { automationId: row.automation_id } : {},
|
|
48
|
-
...row.last_run_id ? { lastRunId: row.last_run_id } : {},
|
|
49
|
-
...row.last_run_at != null ? { lastRunAt: row.last_run_at } : {},
|
|
50
|
-
...row.next_run_at != null ? { nextRunAt: row.next_run_at } : {},
|
|
51
|
-
...row.last_meaningful_result_at != null ? { lastMeaningfulResultAt: row.last_meaningful_result_at } : {},
|
|
52
|
-
...row.last_error ? { lastError: row.last_error } : {},
|
|
53
|
-
consecutiveFailures: row.consecutive_failures,
|
|
54
|
-
createdAt: row.created_at,
|
|
55
|
-
updatedAt: row.updated_at
|
|
56
|
-
};
|
|
57
|
-
}
|
|
58
|
-
function activityFromRow(row) {
|
|
59
|
-
return {
|
|
60
|
-
id: row.activity_id,
|
|
61
|
-
focusId: row.focus_id,
|
|
62
|
-
...row.monitor_id ? { monitorId: row.monitor_id } : {},
|
|
63
|
-
type: row.type,
|
|
64
|
-
summary: row.summary,
|
|
65
|
-
details: parseObject(row.details_json),
|
|
66
|
-
createdAt: row.created_at
|
|
67
|
-
};
|
|
68
|
-
}
|
|
69
|
-
function getFocus(id) {
|
|
70
|
-
const { db } = requireXopcDatabase();
|
|
71
|
-
const row = db.prepare("SELECT * FROM focuses WHERE focus_id = ?").get(id);
|
|
72
|
-
return row ? focusFromRow(db, row) : null;
|
|
73
|
-
}
|
|
74
|
-
function listFocuses(options = {}) {
|
|
75
|
-
const statuses = options.statuses ?? ["active", "paused"];
|
|
76
|
-
if (statuses.length === 0) return [];
|
|
77
|
-
const limit = Math.max(1, Math.min(200, options.limit ?? 50));
|
|
78
|
-
const { db } = requireXopcDatabase();
|
|
79
|
-
return db.prepare(`SELECT * FROM focuses WHERE status IN (${statuses.map(() => "?").join(", ")})
|
|
80
|
-
ORDER BY COALESCE(last_activity_at, updated_at) DESC LIMIT ?`).all(...statuses, limit).map((row) => focusFromRow(db, row));
|
|
81
|
-
}
|
|
82
|
-
function createFocus(input) {
|
|
83
|
-
const id = randomUUID();
|
|
84
|
-
const now = input.nowMs ?? Date.now();
|
|
85
|
-
runSqliteWriteTransaction((db) => {
|
|
86
|
-
db.prepare(`INSERT INTO focuses (
|
|
87
|
-
focus_id, title, summary, status, source, source_candidate_id, goal_id,
|
|
88
|
-
created_at, updated_at, last_activity_at
|
|
89
|
-
) VALUES (?, ?, ?, 'active', ?, ?, ?, ?, ?, ?)`).run(id, input.title.trim().slice(0, 200), input.summary.trim().slice(0, 2e3), input.source ?? "user", input.sourceCandidateId ?? null, input.goalId ?? null, now, now, now);
|
|
90
|
-
const insertProject = db.prepare("INSERT INTO focus_projects (focus_id, project_id, created_at) VALUES (?, ?, ?)");
|
|
91
|
-
for (const projectId of [...new Set(input.projectIds ?? [])].slice(0, 20)) insertProject.run(id, projectId, now);
|
|
92
|
-
insertFocusActivity(db, {
|
|
93
|
-
focusId: id,
|
|
94
|
-
type: "created",
|
|
95
|
-
summary: "Focus created",
|
|
96
|
-
nowMs: now
|
|
97
|
-
});
|
|
98
|
-
});
|
|
99
|
-
return getFocus(id);
|
|
100
|
-
}
|
|
101
|
-
function updateFocus(input) {
|
|
102
|
-
const current = getFocus(input.id);
|
|
103
|
-
if (!current) return null;
|
|
104
|
-
const now = input.nowMs ?? Date.now();
|
|
105
|
-
const status = input.status ?? current.status;
|
|
106
|
-
runSqliteWriteTransaction((db) => {
|
|
107
|
-
db.prepare(`UPDATE focuses SET title = ?, summary = ?, status = ?, completed_at = ?, updated_at = ?
|
|
108
|
-
WHERE focus_id = ?`).run(input.title?.trim().slice(0, 200) || current.title, input.summary?.trim().slice(0, 2e3) || current.summary, status, status === "completed" ? current.completedAt ?? now : null, now, input.id);
|
|
109
|
-
if (input.projectIds) {
|
|
110
|
-
db.prepare("DELETE FROM focus_projects WHERE focus_id = ?").run(input.id);
|
|
111
|
-
const insertProject = db.prepare("INSERT INTO focus_projects (focus_id, project_id, created_at) VALUES (?, ?, ?)");
|
|
112
|
-
for (const projectId of [...new Set(input.projectIds)].slice(0, 20)) insertProject.run(input.id, projectId, now);
|
|
113
|
-
}
|
|
114
|
-
});
|
|
115
|
-
return getFocus(input.id);
|
|
116
|
-
}
|
|
117
|
-
function deleteFocus(id) {
|
|
118
|
-
let deleted = false;
|
|
119
|
-
runSqliteWriteTransaction((db) => {
|
|
120
|
-
deleted = db.prepare("DELETE FROM focuses WHERE focus_id = ?").run(id).changes > 0;
|
|
121
|
-
});
|
|
122
|
-
return deleted;
|
|
123
|
-
}
|
|
124
|
-
function getFocusMonitor(focusId, kind) {
|
|
125
|
-
const { db } = requireXopcDatabase();
|
|
126
|
-
const row = db.prepare("SELECT * FROM focus_monitors WHERE focus_id = ? AND kind = ?").get(focusId, kind);
|
|
127
|
-
return row ? monitorFromRow(row) : null;
|
|
128
|
-
}
|
|
129
|
-
function getFocusMonitorByAutomationId(automationId) {
|
|
130
|
-
const { db } = requireXopcDatabase();
|
|
131
|
-
const row = db.prepare("SELECT * FROM focus_monitors WHERE automation_id = ?").get(automationId);
|
|
132
|
-
return row ? monitorFromRow(row) : null;
|
|
133
|
-
}
|
|
134
|
-
function listFocusMonitors(focusId) {
|
|
135
|
-
const { db } = requireXopcDatabase();
|
|
136
|
-
return db.prepare("SELECT * FROM focus_monitors WHERE focus_id = ? ORDER BY kind").all(focusId).map(monitorFromRow);
|
|
137
|
-
}
|
|
138
|
-
function listAllFocusMonitors() {
|
|
139
|
-
const { db } = requireXopcDatabase();
|
|
140
|
-
return db.prepare("SELECT * FROM focus_monitors ORDER BY updated_at DESC").all().map(monitorFromRow);
|
|
141
|
-
}
|
|
142
|
-
function upsertFocusMonitor(input) {
|
|
143
|
-
const existing = getFocusMonitor(input.focusId, input.kind);
|
|
144
|
-
const id = existing?.id ?? randomUUID();
|
|
145
|
-
const now = input.nowMs ?? Date.now();
|
|
146
|
-
runSqliteWriteTransaction((db) => {
|
|
147
|
-
db.prepare(`INSERT INTO focus_monitors (
|
|
148
|
-
monitor_id, focus_id, kind, enabled, run_state, cadence_json, automation_id,
|
|
149
|
-
consecutive_failures, created_at, updated_at
|
|
150
|
-
) VALUES (?, ?, ?, ?, ?, ?, ?, 0, ?, ?)
|
|
151
|
-
ON CONFLICT(focus_id, kind) DO UPDATE SET
|
|
152
|
-
enabled = excluded.enabled,
|
|
153
|
-
run_state = excluded.run_state,
|
|
154
|
-
cadence_json = excluded.cadence_json,
|
|
155
|
-
automation_id = excluded.automation_id,
|
|
156
|
-
last_error = CASE WHEN excluded.enabled = 1 THEN NULL ELSE focus_monitors.last_error END,
|
|
157
|
-
updated_at = excluded.updated_at`).run(id, input.focusId, input.kind, input.enabled ? 1 : 0, input.runState ?? "idle", JSON.stringify(input.cadence), input.automationId === void 0 ? existing?.automationId ?? null : input.automationId, existing?.createdAt ?? now, now);
|
|
158
|
-
});
|
|
159
|
-
return getFocusMonitor(input.focusId, input.kind);
|
|
160
|
-
}
|
|
161
|
-
function updateFocusMonitorRuntime(input) {
|
|
162
|
-
const now = input.nowMs ?? Date.now();
|
|
163
|
-
let changed = false;
|
|
164
|
-
runSqliteWriteTransaction((db) => {
|
|
165
|
-
changed = db.prepare(`UPDATE focus_monitors SET
|
|
166
|
-
run_state = ?,
|
|
167
|
-
automation_id = COALESCE(?, automation_id),
|
|
168
|
-
last_run_id = COALESCE(?, last_run_id),
|
|
169
|
-
last_run_at = COALESCE(?, last_run_at),
|
|
170
|
-
next_run_at = CASE WHEN ? = 1 THEN ? ELSE next_run_at END,
|
|
171
|
-
last_meaningful_result_at = CASE WHEN ? = 1 THEN ? ELSE last_meaningful_result_at END,
|
|
172
|
-
last_error = ?,
|
|
173
|
-
consecutive_failures = CASE WHEN ? IS NOT NULL THEN consecutive_failures + 1 ELSE 0 END,
|
|
174
|
-
updated_at = ?
|
|
175
|
-
WHERE monitor_id = ?`).run(input.runState, input.automationId ?? null, input.lastRunId ?? null, input.lastRunAt ?? null, input.nextRunAt === void 0 ? 0 : 1, input.nextRunAt ?? null, input.meaningful ? 1 : 0, now, input.error ?? null, input.error ?? null, now, input.id).changes > 0;
|
|
176
|
-
});
|
|
177
|
-
if (!changed) return null;
|
|
178
|
-
const { db } = requireXopcDatabase();
|
|
179
|
-
return monitorFromRow(db.prepare("SELECT * FROM focus_monitors WHERE monitor_id = ?").get(input.id));
|
|
180
|
-
}
|
|
181
|
-
function insertFocusActivity(db, input) {
|
|
182
|
-
const id = randomUUID();
|
|
183
|
-
db.prepare(`INSERT INTO focus_activities (
|
|
184
|
-
activity_id, focus_id, monitor_id, type, summary, details_json, created_at
|
|
185
|
-
) VALUES (?, ?, ?, ?, ?, ?, ?)`).run(id, input.focusId, input.monitorId ?? null, input.type, input.summary.slice(0, 500), JSON.stringify(input.details ?? {}), input.nowMs);
|
|
186
|
-
db.prepare("UPDATE focuses SET last_activity_at = ?, updated_at = MAX(updated_at, ?) WHERE focus_id = ?").run(input.nowMs, input.nowMs, input.focusId);
|
|
187
|
-
return {
|
|
188
|
-
id,
|
|
189
|
-
focusId: input.focusId,
|
|
190
|
-
...input.monitorId ? { monitorId: input.monitorId } : {},
|
|
191
|
-
type: input.type,
|
|
192
|
-
summary: input.summary.slice(0, 500),
|
|
193
|
-
details: input.details ?? {},
|
|
194
|
-
createdAt: input.nowMs
|
|
195
|
-
};
|
|
196
|
-
}
|
|
197
|
-
function createFocusActivity(input) {
|
|
198
|
-
let activity;
|
|
199
|
-
runSqliteWriteTransaction((db) => {
|
|
200
|
-
activity = insertFocusActivity(db, {
|
|
201
|
-
...input,
|
|
202
|
-
nowMs: input.nowMs ?? Date.now()
|
|
203
|
-
});
|
|
204
|
-
});
|
|
205
|
-
return activity;
|
|
206
|
-
}
|
|
207
|
-
function listFocusActivities(input) {
|
|
208
|
-
const limit = Math.max(1, Math.min(100, input.limit ?? 30));
|
|
209
|
-
const { db } = requireXopcDatabase();
|
|
210
|
-
return db.prepare(`SELECT * FROM focus_activities WHERE focus_id = ? AND created_at < ?
|
|
211
|
-
ORDER BY created_at DESC, activity_id DESC LIMIT ?`).all(input.focusId, input.before ?? Number.MAX_SAFE_INTEGER, limit).map(activityFromRow);
|
|
212
|
-
}
|
|
213
|
-
//#endregion
|
|
214
|
-
export { createFocus, createFocusActivity, deleteFocus, getFocus, getFocusMonitor, getFocusMonitorByAutomationId, listAllFocusMonitors, listFocusActivities, listFocusMonitors, listFocuses, updateFocus, updateFocusMonitorRuntime, upsertFocusMonitor };
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import type { AutomationRun } from '../automations/index.js';
|
|
2
|
-
import type { FocusEvidence, FocusInsight } from './types.js';
|
|
3
|
-
interface MeaningfulResult {
|
|
4
|
-
meaningful: true;
|
|
5
|
-
title: string;
|
|
6
|
-
summary: string;
|
|
7
|
-
whyItMatters: string;
|
|
8
|
-
nextAction: string;
|
|
9
|
-
evidence: FocusEvidence[];
|
|
10
|
-
}
|
|
11
|
-
export declare function parseFocusMonitorResult(summary: string): MeaningfulResult | {
|
|
12
|
-
meaningful: false;
|
|
13
|
-
} | null;
|
|
14
|
-
export declare function processFocusMonitorRun(run: AutomationRun): {
|
|
15
|
-
handled: boolean;
|
|
16
|
-
insight?: FocusInsight;
|
|
17
|
-
};
|
|
18
|
-
export {};
|