@xopcai/xopc 0.0.172 → 0.0.174
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-C3Y-bESI.js → activity-store-CyEDJeIt.js} +1 -1
- package/dist/gateway/static/root/assets/{agent-avatar-dicebear-CPyev9P7.js → agent-avatar-dicebear-DF7Bol6I.js} +1 -1
- package/dist/gateway/static/root/assets/agents-BVxEFPQ5.js +2 -0
- package/dist/gateway/static/root/assets/{api-B7qEr_Rw.js → api-DYunqroX.js} +1 -1
- package/dist/gateway/static/root/assets/api-DwyUxpgY.js +1 -0
- package/dist/gateway/static/root/assets/{app-management-settings-panel-Br_9-7fs.js → app-management-settings-panel-B4xJyvDu.js} +1 -1
- package/dist/gateway/static/root/assets/{appearance-settings-uyLcRPai.js → appearance-settings-B2PQxRiu.js} +1 -1
- package/dist/gateway/static/root/assets/apps-page-BtIgd82S.js +1 -0
- package/dist/gateway/static/root/assets/{archive-plugin-B19REnR5.js → archive-plugin-DWhBmmjD.js} +1 -1
- package/dist/gateway/static/root/assets/{attachment-load-DLWCC4Yi.js → attachment-load-BOpZfa_I.js} +1 -1
- package/dist/gateway/static/root/assets/{automation-suggestion-card-ky5S5lly.js → automation-suggestion-card-Byu3I7Rs.js} +1 -1
- package/dist/gateway/static/root/assets/automations-page-CG_SCH5b.js +6 -0
- package/dist/gateway/static/root/assets/{binary-plugins-CtPEzLlo.js → binary-plugins-6AG1qatz.js} +1 -1
- package/dist/gateway/static/root/assets/{block-editor-CQVR4Xij.js → block-editor-CJhrn98_.js} +5 -5
- package/dist/gateway/static/root/assets/browser-settings-page-CfLqPWZC.js +8 -0
- package/dist/gateway/static/root/assets/{browser-workflow-inputs-CimCGbhq.js → browser-workflow-inputs-CBVb4mt9.js} +1 -1
- package/dist/gateway/static/root/assets/{browser-workflows-page-DewuCw3p.js → browser-workflows-page-Cq4XUKbu.js} +2 -2
- package/dist/gateway/static/root/assets/capabilities-settings-panel-DCJmm6cR.js +7 -0
- package/dist/gateway/static/root/assets/{capability-presets-api-B5RTs-Az.js → capability-presets-api-hbW4NAKO.js} +1 -1
- package/dist/gateway/static/root/assets/capability-presets-settings-panel-CnkAYvWI.js +1 -0
- package/dist/gateway/static/root/assets/{channel-recipient-api-Czu0YzIZ.js → channel-recipient-api-CzMjHb17.js} +1 -1
- package/dist/gateway/static/root/assets/channels-settings-DtqqFpDn.js +1 -0
- package/dist/gateway/static/root/assets/channels-status-swr-C-5yHbc0.js +1 -0
- package/dist/gateway/static/root/assets/{connector-logo-Di3gnR_D.js → connector-logo-B9Au6gMZ.js} +1 -1
- package/dist/gateway/static/root/assets/connectors-page-CaHfs8YF.js +2 -0
- package/dist/gateway/static/root/assets/copy-VueTIC2x.js +1 -0
- package/dist/gateway/static/root/assets/desktop-pet-CvFMKYdb.js +1 -0
- package/dist/gateway/static/root/assets/{desktop-pet-settings-C3L6AI8_.js → desktop-pet-settings-CNff5TFb.js} +1 -1
- package/dist/gateway/static/root/assets/{directory-picker-path-field-Dvq4iG6P.js → directory-picker-path-field-Bf956uo-.js} +1 -1
- package/dist/gateway/static/root/assets/dreaming-settings-CHM8FE1g.js +3 -0
- package/dist/gateway/static/root/assets/{extension-debug-page-BecQjU0J.js → extension-debug-page-ZqM_0eUs.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-BeVkPSm-.js → extension-page-D4hvXOMM.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-settings-page-DMoo2mKx.js → extension-settings-page-GsqxaJjA.js} +1 -1
- package/dist/gateway/static/root/assets/focus-detail-page-CE6uwrl1.js +1 -0
- package/dist/gateway/static/root/assets/{gateway-config-api-Bthb3_6v.js → gateway-config-api-B4THmgnS.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-settings-Bh8nPvJQ.js → gateway-settings-CPv-MxGE.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-startup-retry-D3USVm9D.js → gateway-startup-retry-MP3K71pP.js} +1 -1
- package/dist/gateway/static/root/assets/goal-create-dialog-DAeb82xP.js +1 -0
- package/dist/gateway/static/root/assets/goal-detail-page-CwLSp01r.js +4 -0
- package/dist/gateway/static/root/assets/{goals-config-api-C_2QWBtb.js → goals-config-api-DCcDuIjG.js} +1 -1
- package/dist/gateway/static/root/assets/goals-page-DvJQ6_4M.js +2 -0
- package/dist/gateway/static/root/assets/{goals-settings-DhL643tc.js → goals-settings-o9QMXvNq.js} +1 -1
- package/dist/gateway/static/root/assets/{heartbeat-settings-COVFwp7C.js → heartbeat-settings-DixwpXnH.js} +1 -1
- package/dist/gateway/static/root/assets/{image-generation-api-BNQlnwpU.js → image-generation-api-BOGH9FGi.js} +1 -1
- package/dist/gateway/static/root/assets/index-CfXiRNN5.css +1 -0
- package/dist/gateway/static/root/assets/index-eyttVNS_.js +212 -0
- package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-DfdJRJVy.js → keyboard-shortcuts-settings-D4o4ZPF6.js} +1 -1
- package/dist/gateway/static/root/assets/local-app-workbench-page-CPcfqn_A.js +2 -0
- package/dist/gateway/static/root/assets/{local-apps-page-BvCPOgoi.js → local-apps-page-GzMmpO7G.js} +1 -1
- package/dist/gateway/static/root/assets/{locale-store-BP0vD37A.js → locale-store-CAuhEGCn.js} +1 -1
- package/dist/gateway/static/root/assets/logs-page-DXABWCZp.js +7 -0
- package/dist/gateway/static/root/assets/{markdown-split-YO1rDk9m.js → markdown-split-CIX8D1pv.js} +1 -1
- package/dist/gateway/static/root/assets/{media-plugins-CU_RRf-q.js → media-plugins-Bp3eIA45.js} +1 -1
- package/dist/gateway/static/root/assets/messages-BiBdO1-O.js +3 -0
- package/dist/gateway/static/root/assets/{notes-page-CeFiOK3S.js → notes-page-RVFiYAoO.js} +1 -1
- package/dist/gateway/static/root/assets/notes-workbench-DgJzZRX3.js +4 -0
- package/dist/gateway/static/root/assets/{page-tabs-tiHmRJUA.js → page-tabs-BGAYH3Ef.js} +1 -1
- package/dist/gateway/static/root/assets/{preview-open-alternatives-CU6XgaCz.js → preview-open-alternatives-BM6pDkHp.js} +1 -1
- package/dist/gateway/static/root/assets/{product-open-page-Dn4_qor4.js → product-open-page-BiMetEmn.js} +1 -1
- package/dist/gateway/static/root/assets/project-detail-page-DF7F70Vg.js +1 -0
- package/dist/gateway/static/root/assets/projects-page-Cw3jyi5s.js +1 -0
- package/dist/gateway/static/root/assets/remote-access-hub-ChAJsaNY.js +1 -0
- package/dist/gateway/static/root/assets/{save-bar-controls-edDUIbXo.js → save-bar-controls-BdjV8MK5.js} +1 -1
- package/dist/gateway/static/root/assets/{schedule-field-DqJO_5Yb.js → schedule-field-ChlqXU46.js} +1 -1
- package/dist/gateway/static/root/assets/{schema-form-CMh0jzy5.js → schema-form-DDKf5ZSH.js} +1 -1
- package/dist/gateway/static/root/assets/sessions-page-BxZIxt7z.js +1 -0
- package/dist/gateway/static/root/assets/settings-advanced-gate-DcDLS0xV.js +1 -0
- package/dist/gateway/static/root/assets/{settings-form-section-Bb0Bc3nJ.js → settings-form-section-CPG0KGVs.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-loading-skeleton-DQhADvz1.js → settings-loading-skeleton-DRSDHucM.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-page-b0M5HukN.js → settings-page-CeB7_xD0.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-page-layout-hvjtIjvh.js → settings-page-layout-BENrkwd0.js} +1 -1
- package/dist/gateway/static/root/assets/setup-status-panel-4Xa9NA7v.js +1 -0
- package/dist/gateway/static/root/assets/{share-preview-page-rbeaOpTg.js → share-preview-page-DIzczJkG.js} +1 -1
- package/dist/gateway/static/root/assets/shares-settings-BpN0o5Cf.js +1 -0
- package/dist/gateway/static/root/assets/skill-reload-api-DvF2UAaL.js +1 -0
- package/dist/gateway/static/root/assets/skills-page-CGKXpNfy.js +2 -0
- package/dist/gateway/static/root/assets/{system-settings-panel-BHo_hgnL.js → system-settings-panel-Dp4d5Q1B.js} +1 -1
- package/dist/gateway/static/root/assets/{theme-store-C3KnnjcU.js → theme-store-CbGc1laW.js} +1 -1
- package/dist/gateway/static/root/assets/{time-picker-D-G-uwVJ.js → time-picker-BhgCeDuO.js} +1 -1
- package/dist/gateway/static/root/assets/{typed-models-lib-DtRnG-YI.js → typed-models-lib-DwPk3OPL.js} +1 -1
- package/dist/gateway/static/root/assets/{use-channel-catalog-CWWItX2g.js → use-channel-catalog-CXrEu2dw.js} +1 -1
- package/dist/gateway/static/root/assets/user-context-page-Dy_fKAK_.js +1 -0
- package/dist/gateway/static/root/assets/{voice-api-key-field-BTnltQHZ.js → voice-api-key-field-DFoA79LB.js} +1 -1
- package/dist/gateway/static/root/assets/work-discovery-page-BWkjb1NK.js +1 -0
- package/dist/gateway/static/root/assets/work-item-detail-page-DLBNFse5.js +1 -0
- package/dist/gateway/static/root/assets/work-page-Bn5RXMIE.js +1 -0
- package/dist/gateway/static/root/assets/{workflow-run-setup-panel-D7vKChFZ.js → workflow-run-setup-panel-BuniGPO0.js} +2 -2
- package/dist/gateway/static/root/assets/workflows-page-_vFhRrAl.js +11 -0
- package/dist/gateway/static/root/index.html +7 -7
- package/dist/package.js +1 -1
- package/dist/src/agent/agent-manager.d.ts +3 -1
- package/dist/src/agent/agent-manager.js +4 -3
- package/dist/src/agent/capabilities/definitions.d.ts +2 -1
- package/dist/src/agent/capabilities/definitions.js +3 -1
- package/dist/src/agent/prompt/sections/tooling.js +4 -0
- package/dist/src/agent/service.d.ts +2 -1
- package/dist/src/agent/service.js +26 -0
- package/dist/src/agent/skills/hub-pull.js +1 -1
- package/dist/src/agent/skills/index.js +1 -1
- package/dist/src/agent/skills/install-target.js +1 -1
- package/dist/src/agent/skills/marketplace/adapters/clawhub/adapter.d.ts +64 -0
- package/dist/src/agent/skills/marketplace/adapters/clawhub/adapter.js +27 -18
- package/dist/src/agent/skills/marketplace/adapters/store/adapter.js +1 -1
- package/dist/src/agent/skills/marketplace/adapters/store/store-api-client.js +1 -1
- package/dist/src/agent/skills/marketplace/search.d.ts +46 -0
- package/dist/src/agent/skills/marketplace/search.js +193 -0
- package/dist/src/agent/skills/skill-tool-gating.js +2 -1
- package/dist/src/agent/tools/delegate-tool.js +2 -0
- package/dist/src/agent/tools/factory.d.ts +4 -2
- package/dist/src/agent/tools/factory.js +11 -5
- package/dist/src/agent/tools/index.d.ts +2 -1
- package/dist/src/agent/tools/index.js +2 -1
- package/dist/src/agent/tools/skill-install-tool.d.ts +17 -0
- package/dist/src/agent/tools/skill-install-tool.js +76 -8
- package/dist/src/agent/tools/skills-marketplace-search-tool.d.ts +17 -0
- package/dist/src/agent/tools/skills-marketplace-search-tool.js +77 -0
- package/dist/src/browser/providers/cloakbrowser.js +1 -1
- package/dist/src/capabilities/store-connector.js +1 -1
- package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
- package/dist/src/config/agent-profile.js +1 -1
- package/dist/src/extensions/api.js +1 -1
- package/dist/src/extensions/install.js +1 -1
- package/dist/src/focuses/candidate-repository.d.ts +15 -0
- package/dist/src/focuses/candidate-repository.js +91 -0
- package/dist/src/focuses/index.d.ts +7 -0
- package/dist/src/focuses/index.js +7 -0
- package/dist/src/focuses/insight-repository.d.ts +22 -0
- package/dist/src/focuses/insight-repository.js +77 -0
- package/dist/src/focuses/prompts.d.ts +2 -0
- package/dist/src/focuses/prompts.js +18 -0
- package/dist/src/focuses/reconciler.d.ts +5 -0
- package/dist/src/focuses/reconciler.js +26 -0
- package/dist/src/focuses/repository.d.ts +61 -0
- package/dist/src/focuses/repository.js +214 -0
- package/dist/src/focuses/run-processor.d.ts +18 -0
- package/dist/src/focuses/run-processor.js +162 -0
- package/dist/src/focuses/service.d.ts +42 -0
- package/dist/src/focuses/service.js +241 -0
- package/dist/src/focuses/types.d.ts +89 -0
- package/dist/src/gateway/agent-builtin-tools.d.ts +1 -1
- package/dist/src/gateway/agent-builtin-tools.js +2 -0
- package/dist/src/gateway/agents-admin.js +1 -1
- package/dist/src/gateway/hono/routes/commands-skills.js +2 -2
- package/dist/src/gateway/hono/routes/focuses.d.ts +3 -0
- package/dist/src/gateway/hono/routes/focuses.js +319 -0
- package/dist/src/gateway/hono/routes/home.js +15 -17
- package/dist/src/gateway/hono/routes/index.js +2 -0
- package/dist/src/gateway/hono/routes/projects.js +2 -103
- package/dist/src/gateway/hono/routes/work-discovery.js +0 -239
- package/dist/src/gateway/service/marketplace-service.js +1 -1
- package/dist/src/gateway/service.d.ts +1 -1
- package/dist/src/gateway/service.js +15 -11
- package/dist/src/storage/sqlite/migrations/066_first_class_focuses.sql +126 -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/index.d.ts +0 -2
- package/dist/src/work-discovery/index.js +1 -3
- package/dist/src/work-discovery/service.d.ts +0 -30
- package/dist/src/work-discovery/service.js +1 -35
- package/dist/src/work-discovery/thread-service.d.ts +5 -0
- package/dist/src/work-discovery/thread-service.js +36 -88
- package/package.json +1 -1
- package/skills/tools/find-skills/SKILL.md +18 -428
- package/dist/gateway/static/root/assets/agents-Bf_kK2Ay.js +0 -2
- package/dist/gateway/static/root/assets/apps-page-DXFCP5-1.js +0 -1
- package/dist/gateway/static/root/assets/automations-page-D8pT1o2O.js +0 -6
- package/dist/gateway/static/root/assets/browser-settings-page-Bav_skKN.js +0 -8
- package/dist/gateway/static/root/assets/capabilities-settings-panel-BHaYYo9E.js +0 -7
- package/dist/gateway/static/root/assets/capability-presets-settings-panel-BgchTh81.js +0 -1
- package/dist/gateway/static/root/assets/channels-settings-BP0e62wt.js +0 -1
- package/dist/gateway/static/root/assets/channels-status-swr-DBWKfeGe.js +0 -1
- package/dist/gateway/static/root/assets/connectors-page-CC5kh0de.js +0 -2
- package/dist/gateway/static/root/assets/desktop-pet-D-ZUNHhn.js +0 -1
- package/dist/gateway/static/root/assets/dreaming-settings-D9i54kWO.js +0 -3
- package/dist/gateway/static/root/assets/goal-create-dialog-Dp0AyDHI.js +0 -1
- package/dist/gateway/static/root/assets/goal-detail-page-CNt7nrdS.js +0 -4
- package/dist/gateway/static/root/assets/goals-page-Bm_NZFiZ.js +0 -2
- package/dist/gateway/static/root/assets/index-C_XSKOH6.css +0 -1
- package/dist/gateway/static/root/assets/index-DUasAutC.js +0 -212
- package/dist/gateway/static/root/assets/local-app-workbench-page-DZwkD1co.js +0 -2
- package/dist/gateway/static/root/assets/logs-page-dNL0Y1dA.js +0 -7
- package/dist/gateway/static/root/assets/messages-BWtP5TFz.js +0 -3
- package/dist/gateway/static/root/assets/notes-workbench-B8MKxpZb.js +0 -4
- package/dist/gateway/static/root/assets/project-detail-page-CWBuuX-S.js +0 -1
- package/dist/gateway/static/root/assets/projects-page-BJSsLsXH.js +0 -1
- package/dist/gateway/static/root/assets/remote-access-hub-DXJDb8vB.js +0 -1
- package/dist/gateway/static/root/assets/sessions-page-DeHpWgxM.js +0 -1
- package/dist/gateway/static/root/assets/settings-advanced-gate-Cf-TEYUd.js +0 -1
- package/dist/gateway/static/root/assets/setup-status-panel-BFyfed_g.js +0 -1
- package/dist/gateway/static/root/assets/shares-settings-CYnH9sTt.js +0 -1
- package/dist/gateway/static/root/assets/skill-reload-api-Cr8_m-jS.js +0 -1
- package/dist/gateway/static/root/assets/skills-page-Chtc1xDO.js +0 -2
- package/dist/gateway/static/root/assets/user-context-page-D7qMR26X.js +0 -1
- package/dist/gateway/static/root/assets/work-discovery-page-CpqFZze9.js +0 -1
- package/dist/gateway/static/root/assets/work-item-detail-page-t4dXpGC0.js +0 -1
- package/dist/gateway/static/root/assets/work-page-BXwDKiMZ.js +0 -1
- package/dist/gateway/static/root/assets/workflows-page-Bos9HyqT.js +0 -11
- package/dist/src/proactive/calendar-signals.d.ts +0 -4
- package/dist/src/proactive/calendar-signals.js +0 -120
- package/dist/src/proactive/focus-service.d.ts +0 -62
- package/dist/src/proactive/focus-service.js +0 -173
- package/dist/src/proactive/index.d.ts +0 -7
- package/dist/src/proactive/index.js +0 -7
- package/dist/src/proactive/insight-repository.d.ts +0 -21
- package/dist/src/proactive/insight-repository.js +0 -109
- package/dist/src/proactive/run-processor.d.ts +0 -19
- package/dist/src/proactive/run-processor.js +0 -146
- package/dist/src/proactive/trial-expiry-reconciler.d.ts +0 -5
- package/dist/src/proactive/trial-expiry-reconciler.js +0 -30
- package/dist/src/proactive/types.d.ts +0 -66
- package/dist/src/proactive/value-score.d.ts +0 -13
- package/dist/src/proactive/value-score.js +0 -30
- package/dist/src/proactive/watch-repository.d.ts +0 -28
- package/dist/src/proactive/watch-repository.js +0 -129
- package/dist/src/work-discovery/governance.d.ts +0 -25
- package/dist/src/work-discovery/governance.js +0 -96
- package/dist/src/work-discovery/thread-repository.d.ts +0 -34
- package/dist/src/work-discovery/thread-repository.js +0 -112
- /package/dist/src/{proactive → focuses}/types.js +0 -0
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import type { KnowledgeSourceItem } from '../knowledge/types.js';
|
|
2
|
-
import type { FocusCalendarSignal, FocusView } from './types.js';
|
|
3
|
-
export declare function buildFocusCalendarSignals(items: KnowledgeSourceItem[], focuses: FocusView[], nowMs?: number): FocusCalendarSignal[];
|
|
4
|
-
export declare function listFocusCalendarSignals(focuses: FocusView[], nowMs?: number): FocusCalendarSignal[];
|
|
@@ -1,120 +0,0 @@
|
|
|
1
|
-
import { listKnowledgeSourceItems } from "../storage/sqlite/knowledge-repository.js";
|
|
2
|
-
//#region src/proactive/calendar-signals.ts
|
|
3
|
-
const LOOKAHEAD_MS = 7 * 864e5;
|
|
4
|
-
const FIELD_LIMIT = 8;
|
|
5
|
-
const TITLE_KEYS = new Set([
|
|
6
|
-
"summary",
|
|
7
|
-
"title",
|
|
8
|
-
"name",
|
|
9
|
-
"subject"
|
|
10
|
-
]);
|
|
11
|
-
const DESCRIPTION_KEYS = new Set([
|
|
12
|
-
"description",
|
|
13
|
-
"notes",
|
|
14
|
-
"body",
|
|
15
|
-
"agenda"
|
|
16
|
-
]);
|
|
17
|
-
const START_KEYS = new Set([
|
|
18
|
-
"start",
|
|
19
|
-
"starttime",
|
|
20
|
-
"start_time",
|
|
21
|
-
"startat",
|
|
22
|
-
"start_at",
|
|
23
|
-
"datetime"
|
|
24
|
-
]);
|
|
25
|
-
const END_KEYS = new Set([
|
|
26
|
-
"end",
|
|
27
|
-
"endtime",
|
|
28
|
-
"end_time",
|
|
29
|
-
"endat",
|
|
30
|
-
"end_at"
|
|
31
|
-
]);
|
|
32
|
-
const STOP_WORDS = new Set([
|
|
33
|
-
"about",
|
|
34
|
-
"after",
|
|
35
|
-
"before",
|
|
36
|
-
"from",
|
|
37
|
-
"have",
|
|
38
|
-
"meeting",
|
|
39
|
-
"project",
|
|
40
|
-
"review",
|
|
41
|
-
"the",
|
|
42
|
-
"this",
|
|
43
|
-
"with"
|
|
44
|
-
]);
|
|
45
|
-
function parsePayload(item) {
|
|
46
|
-
if (!item.normalizedText) return null;
|
|
47
|
-
try {
|
|
48
|
-
return JSON.parse(item.normalizedText);
|
|
49
|
-
} catch {
|
|
50
|
-
return null;
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
function findStrings(value, keys, depth = 0) {
|
|
54
|
-
if (depth > 6 || value == null) return [];
|
|
55
|
-
if (Array.isArray(value)) return value.flatMap((item) => findStrings(item, keys, depth + 1)).slice(0, FIELD_LIMIT);
|
|
56
|
-
if (typeof value !== "object") return [];
|
|
57
|
-
const record = value;
|
|
58
|
-
const direct = Object.entries(record).flatMap(([key, nested]) => {
|
|
59
|
-
if (!keys.has(key.toLowerCase().replaceAll("-", "_"))) return [];
|
|
60
|
-
if (typeof nested === "string") return [nested];
|
|
61
|
-
return findStrings(nested, new Set([
|
|
62
|
-
"datetime",
|
|
63
|
-
"date",
|
|
64
|
-
"value"
|
|
65
|
-
]), depth + 1);
|
|
66
|
-
});
|
|
67
|
-
if (direct.length > 0) return direct.slice(0, FIELD_LIMIT);
|
|
68
|
-
return Object.values(record).flatMap((nested) => findStrings(nested, keys, depth + 1)).slice(0, FIELD_LIMIT);
|
|
69
|
-
}
|
|
70
|
-
function firstDate(payload, keys) {
|
|
71
|
-
for (const value of findStrings(payload, keys)) {
|
|
72
|
-
const parsed = Date.parse(value);
|
|
73
|
-
if (Number.isFinite(parsed)) return parsed;
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
function terms(value) {
|
|
77
|
-
const normalized = value.toLocaleLowerCase();
|
|
78
|
-
const result = new Set(normalized.match(/[a-z0-9][a-z0-9_-]{2,}/g)?.filter((word) => !STOP_WORDS.has(word)) ?? []);
|
|
79
|
-
for (const sequence of normalized.match(/[\p{Script=Han}]{2,}/gu) ?? []) for (let index = 0; index < sequence.length - 1; index += 1) result.add(sequence.slice(index, index + 2));
|
|
80
|
-
return result;
|
|
81
|
-
}
|
|
82
|
-
function relatedFocus(focuses, text) {
|
|
83
|
-
const eventTerms = terms(text);
|
|
84
|
-
if (eventTerms.size === 0) return void 0;
|
|
85
|
-
return focuses.map((focus) => ({
|
|
86
|
-
focus,
|
|
87
|
-
score: [...terms(`${focus.title} ${focus.summary}`)].filter((term) => eventTerms.has(term)).length
|
|
88
|
-
})).filter((candidate) => candidate.score >= 2).toSorted((left, right) => right.score - left.score || right.focus.focusScore - left.focus.focusScore)[0]?.focus;
|
|
89
|
-
}
|
|
90
|
-
function buildFocusCalendarSignals(items, focuses, nowMs = Date.now()) {
|
|
91
|
-
const end = nowMs + LOOKAHEAD_MS;
|
|
92
|
-
const signals = items.flatMap((item) => {
|
|
93
|
-
if (item.itemType !== "calendar_event") return [];
|
|
94
|
-
const payload = parsePayload(item);
|
|
95
|
-
const title = findStrings(payload, TITLE_KEYS)[0]?.trim();
|
|
96
|
-
const startsAt = firstDate(payload, START_KEYS);
|
|
97
|
-
if (!title || startsAt == null || startsAt < nowMs || startsAt > end) return [];
|
|
98
|
-
const focus = relatedFocus(focuses, `${title} ${findStrings(payload, DESCRIPTION_KEYS).join(" ")}`);
|
|
99
|
-
if (!focus) return [];
|
|
100
|
-
const endsAt = firstDate(payload, END_KEYS);
|
|
101
|
-
return [{
|
|
102
|
-
id: item.id,
|
|
103
|
-
focusId: focus.id,
|
|
104
|
-
focusTitle: focus.title,
|
|
105
|
-
title,
|
|
106
|
-
startsAt,
|
|
107
|
-
...endsAt != null ? { endsAt } : {},
|
|
108
|
-
sourceInstanceId: item.sourceInstanceId
|
|
109
|
-
}];
|
|
110
|
-
}).toSorted((left, right) => left.startsAt - right.startsAt);
|
|
111
|
-
return signals.filter((signal, index) => signals.findIndex((candidate) => candidate.focusId === signal.focusId && candidate.startsAt === signal.startsAt && candidate.title.toLocaleLowerCase() === signal.title.toLocaleLowerCase()) === index).slice(0, 20);
|
|
112
|
-
}
|
|
113
|
-
function listFocusCalendarSignals(focuses, nowMs = Date.now()) {
|
|
114
|
-
return buildFocusCalendarSignals(listKnowledgeSourceItems({
|
|
115
|
-
itemType: "calendar_event",
|
|
116
|
-
limit: 500
|
|
117
|
-
}), focuses, nowMs);
|
|
118
|
-
}
|
|
119
|
-
//#endregion
|
|
120
|
-
export { buildFocusCalendarSignals, listFocusCalendarSignals };
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
import type { Automation, AutomationRun } from '../automations/index.js';
|
|
2
|
-
import type { FocusView, FocusWatch, FocusWatchKind } from './types.js';
|
|
3
|
-
interface AutomationPort {
|
|
4
|
-
create(input: {
|
|
5
|
-
name: string;
|
|
6
|
-
description: string;
|
|
7
|
-
projectId?: string;
|
|
8
|
-
trigger: {
|
|
9
|
-
kind: 'schedule';
|
|
10
|
-
schedule: {
|
|
11
|
-
kind: 'interval';
|
|
12
|
-
everyMs: number;
|
|
13
|
-
};
|
|
14
|
-
};
|
|
15
|
-
action: {
|
|
16
|
-
kind: 'agent';
|
|
17
|
-
instruction: string;
|
|
18
|
-
timeoutSeconds: number;
|
|
19
|
-
};
|
|
20
|
-
safety: {
|
|
21
|
-
mode: 'suggest_only';
|
|
22
|
-
};
|
|
23
|
-
afterRun: {
|
|
24
|
-
kind: 'none';
|
|
25
|
-
};
|
|
26
|
-
reliability: {
|
|
27
|
-
timeoutSeconds: number;
|
|
28
|
-
disableAfterConsecutiveFailures: number;
|
|
29
|
-
};
|
|
30
|
-
}): Promise<Automation>;
|
|
31
|
-
pause(id: string): Promise<Automation | null>;
|
|
32
|
-
resume(id: string): Promise<Automation | null>;
|
|
33
|
-
update(id: string, patch: {
|
|
34
|
-
action: {
|
|
35
|
-
kind: 'agent';
|
|
36
|
-
instruction: string;
|
|
37
|
-
timeoutSeconds: number;
|
|
38
|
-
};
|
|
39
|
-
}): Promise<Automation | null>;
|
|
40
|
-
runNow(id: string): Promise<AutomationRun>;
|
|
41
|
-
}
|
|
42
|
-
export declare class FocusService {
|
|
43
|
-
private readonly automations;
|
|
44
|
-
private readonly goals;
|
|
45
|
-
constructor(automations: AutomationPort);
|
|
46
|
-
list(options?: {
|
|
47
|
-
includeUnreviewed?: boolean;
|
|
48
|
-
}): FocusView[];
|
|
49
|
-
confirm(id: string): FocusView | null;
|
|
50
|
-
activateTrial(input: {
|
|
51
|
-
threadId: string;
|
|
52
|
-
kind?: FocusWatchKind;
|
|
53
|
-
eventContext?: string;
|
|
54
|
-
}): Promise<{
|
|
55
|
-
focus: FocusView;
|
|
56
|
-
watch: FocusWatch;
|
|
57
|
-
}>;
|
|
58
|
-
pauseWatch(id: string): Promise<FocusWatch | null>;
|
|
59
|
-
reconcileExpiredTrials(nowMs?: number): Promise<number>;
|
|
60
|
-
recordInsightFeedback(watchId: string, useful: boolean): Promise<FocusWatch | null>;
|
|
61
|
-
}
|
|
62
|
-
export {};
|
|
@@ -1,173 +0,0 @@
|
|
|
1
|
-
import { createLogger } from "../utils/logger/index.js";
|
|
2
|
-
import { init_logger } from "../utils/logger.js";
|
|
3
|
-
import { GoalService } from "../goals/goal-service.js";
|
|
4
|
-
import "../goals/index.js";
|
|
5
|
-
import { addWorkUnderstandingThreadFeedback, getWorkUnderstandingThread, listWorkUnderstandingThreads } from "../work-discovery/thread-repository.js";
|
|
6
|
-
import { createFocusWatch, getFocusWatchByThreadAndKind, listFocusWatches, recordFocusWatchFeedback, restartFocusWatchTrial, setFocusWatchStatus } from "./watch-repository.js";
|
|
7
|
-
//#region src/proactive/focus-service.ts
|
|
8
|
-
init_logger();
|
|
9
|
-
const TRIAL_DURATION_MS = 7 * 864e5;
|
|
10
|
-
const DAILY_INTERVAL_MS = 1440 * 60 * 1e3;
|
|
11
|
-
const log = createLogger("FocusService");
|
|
12
|
-
function instructionForFocus(title, summary, kind, eventContext) {
|
|
13
|
-
const intent = kind === "progress" ? "Look for meaningful progress, blockers, and the most useful next step." : kind === "staleness" ? "Check whether this focus has stalled and identify the smallest credible unblock." : kind === "deadline" ? "Check upcoming deadlines or meetings and prepare only the material that is needed next." : "Search for external changes published since the previous daily check. Use primary sources when possible, include the publication date and canonical URL, reject generic background news, and explain the concrete impact on this focus.";
|
|
14
|
-
return [
|
|
15
|
-
"Maintain this user-confirmed focus in suggest-only mode.",
|
|
16
|
-
`Focus: ${title}`,
|
|
17
|
-
`Context: ${summary}`,
|
|
18
|
-
...eventContext ? [`Upcoming event selected by the user: ${eventContext}`] : [],
|
|
19
|
-
intent,
|
|
20
|
-
"Inspect only evidence that changed since the previous daily check; use timestamps, history, status, or source revisions to establish the delta.",
|
|
21
|
-
"Use evidence available to the agent. Do not modify files, send messages, publish content, or claim progress without evidence.",
|
|
22
|
-
"Return JSON only, with no markdown.",
|
|
23
|
-
"If nothing materially changed: {\"meaningful\":false}.",
|
|
24
|
-
"Otherwise return {\"meaningful\":true,\"title\":\"short title\",\"summary\":\"what changed\",\"whyItMatters\":\"concrete impact\",\"nextAction\":\"one next action\",\"evidence\":[{\"label\":\"specific observed evidence\",\"source\":\"file, event, or canonical URL\",\"publishedAt\":\"ISO date when this is external news\"}]}.",
|
|
25
|
-
"A meaningful result requires at least one specific evidence item. Never invent evidence. Keep the entire JSON response under 2,000 characters."
|
|
26
|
-
].join("\n");
|
|
27
|
-
}
|
|
28
|
-
var FocusService = class {
|
|
29
|
-
goals = new GoalService();
|
|
30
|
-
constructor(automations) {
|
|
31
|
-
this.automations = automations;
|
|
32
|
-
}
|
|
33
|
-
list(options = {}) {
|
|
34
|
-
const threads = listWorkUnderstandingThreads({ limit: 200 }).filter((thread) => options.includeUnreviewed || thread.userStatus === "confirmed" || thread.userStatus === "corrected");
|
|
35
|
-
const watches = listFocusWatches();
|
|
36
|
-
const goals = this.goals.list({
|
|
37
|
-
status: [
|
|
38
|
-
"active",
|
|
39
|
-
"blocked",
|
|
40
|
-
"needs_input",
|
|
41
|
-
"paused"
|
|
42
|
-
],
|
|
43
|
-
limit: 200
|
|
44
|
-
});
|
|
45
|
-
return threads.map((thread) => {
|
|
46
|
-
const goal = goals.find((candidate) => candidate.projectId && thread.projectIds.includes(candidate.projectId));
|
|
47
|
-
return {
|
|
48
|
-
id: thread.id,
|
|
49
|
-
title: thread.title,
|
|
50
|
-
summary: thread.summary,
|
|
51
|
-
status: thread.status,
|
|
52
|
-
horizon: thread.horizon,
|
|
53
|
-
confidence: thread.confidence,
|
|
54
|
-
focusScore: thread.focusScore,
|
|
55
|
-
userStatus: thread.userStatus,
|
|
56
|
-
projectIds: thread.projectIds,
|
|
57
|
-
...goal ? {
|
|
58
|
-
goalId: goal.id,
|
|
59
|
-
nextAction: goal.nextAction,
|
|
60
|
-
blockedReason: goal.blockedReason
|
|
61
|
-
} : {},
|
|
62
|
-
watches: watches.filter((watch) => watch.threadId === thread.id),
|
|
63
|
-
lastObservedAt: thread.lastObservedAt
|
|
64
|
-
};
|
|
65
|
-
});
|
|
66
|
-
}
|
|
67
|
-
confirm(id) {
|
|
68
|
-
const thread = addWorkUnderstandingThreadFeedback({
|
|
69
|
-
threadId: id,
|
|
70
|
-
decision: "confirmed"
|
|
71
|
-
});
|
|
72
|
-
return thread ? this.list({ includeUnreviewed: true }).find((focus) => focus.id === thread.id) ?? null : null;
|
|
73
|
-
}
|
|
74
|
-
async activateTrial(input) {
|
|
75
|
-
const kind = input.kind ?? "progress";
|
|
76
|
-
let thread = getWorkUnderstandingThread(input.threadId);
|
|
77
|
-
if (!thread || thread.userStatus === "rejected") throw new Error("Focus not found");
|
|
78
|
-
if (thread.userStatus === "unreviewed") thread = addWorkUnderstandingThreadFeedback({
|
|
79
|
-
threadId: thread.id,
|
|
80
|
-
decision: "confirmed"
|
|
81
|
-
});
|
|
82
|
-
if (!thread) throw new Error("Focus not found");
|
|
83
|
-
const existing = getFocusWatchByThreadAndKind(thread.id, kind);
|
|
84
|
-
if (existing) {
|
|
85
|
-
if (input.eventContext) await this.automations.update(existing.automationId, { action: {
|
|
86
|
-
kind: "agent",
|
|
87
|
-
instruction: instructionForFocus(thread.title, thread.summary, kind, input.eventContext),
|
|
88
|
-
timeoutSeconds: 300
|
|
89
|
-
} });
|
|
90
|
-
if (existing.status === "paused") {
|
|
91
|
-
await this.automations.resume(existing.automationId);
|
|
92
|
-
restartFocusWatchTrial(existing.id, Date.now() + TRIAL_DURATION_MS);
|
|
93
|
-
}
|
|
94
|
-
if (input.eventContext) this.automations.runNow(existing.automationId).catch((err) => {
|
|
95
|
-
log.warn({
|
|
96
|
-
err,
|
|
97
|
-
automationId: existing.automationId,
|
|
98
|
-
watchId: existing.id
|
|
99
|
-
}, "Focus event preparation run failed");
|
|
100
|
-
});
|
|
101
|
-
return {
|
|
102
|
-
focus: this.list({ includeUnreviewed: true }).find((item) => item.id === thread.id),
|
|
103
|
-
watch: getFocusWatchByThreadAndKind(thread.id, kind)
|
|
104
|
-
};
|
|
105
|
-
}
|
|
106
|
-
const automation = await this.automations.create({
|
|
107
|
-
name: `Keep moving: ${thread.title}`.slice(0, 200),
|
|
108
|
-
description: `Seven-day ${kind} watch for a user-confirmed focus.`,
|
|
109
|
-
...thread.projectIds[0] ? { projectId: thread.projectIds[0] } : {},
|
|
110
|
-
trigger: {
|
|
111
|
-
kind: "schedule",
|
|
112
|
-
schedule: {
|
|
113
|
-
kind: "interval",
|
|
114
|
-
everyMs: DAILY_INTERVAL_MS
|
|
115
|
-
}
|
|
116
|
-
},
|
|
117
|
-
action: {
|
|
118
|
-
kind: "agent",
|
|
119
|
-
instruction: instructionForFocus(thread.title, thread.summary, kind, input.eventContext),
|
|
120
|
-
timeoutSeconds: 300
|
|
121
|
-
},
|
|
122
|
-
safety: { mode: "suggest_only" },
|
|
123
|
-
afterRun: { kind: "none" },
|
|
124
|
-
reliability: {
|
|
125
|
-
timeoutSeconds: 300,
|
|
126
|
-
disableAfterConsecutiveFailures: 3
|
|
127
|
-
}
|
|
128
|
-
});
|
|
129
|
-
const watch = createFocusWatch({
|
|
130
|
-
threadId: thread.id,
|
|
131
|
-
automationId: automation.id,
|
|
132
|
-
kind,
|
|
133
|
-
config: {
|
|
134
|
-
cadence: "daily",
|
|
135
|
-
notifyOnlyWhenMeaningful: true
|
|
136
|
-
},
|
|
137
|
-
trialEndsAt: Date.now() + TRIAL_DURATION_MS
|
|
138
|
-
});
|
|
139
|
-
this.automations.runNow(automation.id).catch((err) => {
|
|
140
|
-
log.warn({
|
|
141
|
-
err,
|
|
142
|
-
automationId: automation.id,
|
|
143
|
-
watchId: watch.id
|
|
144
|
-
}, "Initial focus watch run failed");
|
|
145
|
-
});
|
|
146
|
-
return {
|
|
147
|
-
focus: this.list({ includeUnreviewed: true }).find((item) => item.id === thread.id),
|
|
148
|
-
watch
|
|
149
|
-
};
|
|
150
|
-
}
|
|
151
|
-
async pauseWatch(id) {
|
|
152
|
-
const watch = listFocusWatches().find((item) => item.id === id);
|
|
153
|
-
if (!watch) return null;
|
|
154
|
-
await this.automations.pause(watch.automationId);
|
|
155
|
-
return setFocusWatchStatus(id, "paused");
|
|
156
|
-
}
|
|
157
|
-
async reconcileExpiredTrials(nowMs = Date.now()) {
|
|
158
|
-
const expired = listFocusWatches({ status: "active" }).filter((watch) => watch.trialEndsAt != null && watch.trialEndsAt <= nowMs);
|
|
159
|
-
for (const watch of expired) {
|
|
160
|
-
await this.automations.pause(watch.automationId);
|
|
161
|
-
setFocusWatchStatus(watch.id, "paused", nowMs);
|
|
162
|
-
}
|
|
163
|
-
return expired.length;
|
|
164
|
-
}
|
|
165
|
-
async recordInsightFeedback(watchId, useful) {
|
|
166
|
-
const result = recordFocusWatchFeedback(watchId, useful);
|
|
167
|
-
if (!result) return null;
|
|
168
|
-
if (!useful && result.consecutiveDismissed >= 3) return this.pauseWatch(watchId);
|
|
169
|
-
return result.watch;
|
|
170
|
-
}
|
|
171
|
-
};
|
|
172
|
-
//#endregion
|
|
173
|
-
export { FocusService };
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
export * from './types.js';
|
|
2
|
-
export * from './calendar-signals.js';
|
|
3
|
-
export * from './focus-service.js';
|
|
4
|
-
export * from './insight-repository.js';
|
|
5
|
-
export * from './run-processor.js';
|
|
6
|
-
export * from './trial-expiry-reconciler.js';
|
|
7
|
-
export * from './watch-repository.js';
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import { buildFocusCalendarSignals, listFocusCalendarSignals } from "./calendar-signals.js";
|
|
2
|
-
import { createFocusWatch, getFocusWatchByAutomationId, getFocusWatchByThreadAndKind, listFocusWatches, recordFocusWatchFeedback, recordFocusWatchRun, restartFocusWatchTrial, setFocusWatchStatus } from "./watch-repository.js";
|
|
3
|
-
import { FocusService } from "./focus-service.js";
|
|
4
|
-
import { claimProactiveInsightApproval, createProactiveInsight, getProactiveInsight, listProactiveInsights, setProactiveInsightStatus } from "./insight-repository.js";
|
|
5
|
-
import { hasValidIntelligenceEvidence, parseFocusRunResult, processFocusAutomationRun } from "./run-processor.js";
|
|
6
|
-
import { startTrialExpiryReconciler } from "./trial-expiry-reconciler.js";
|
|
7
|
-
export { FocusService, buildFocusCalendarSignals, claimProactiveInsightApproval, createFocusWatch, createProactiveInsight, getFocusWatchByAutomationId, getFocusWatchByThreadAndKind, getProactiveInsight, hasValidIntelligenceEvidence, listFocusCalendarSignals, listFocusWatches, listProactiveInsights, parseFocusRunResult, processFocusAutomationRun, recordFocusWatchFeedback, recordFocusWatchRun, restartFocusWatchTrial, setFocusWatchStatus, setProactiveInsightStatus, startTrialExpiryReconciler };
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import type { FocusWatchKind, ProactiveEvidence, ProactiveInsight, ProactiveInsightStatus } from './types.js';
|
|
2
|
-
export declare function getProactiveInsight(id: string): ProactiveInsight | null;
|
|
3
|
-
export declare function listProactiveInsights(options?: {
|
|
4
|
-
status?: ProactiveInsightStatus[];
|
|
5
|
-
limit?: number;
|
|
6
|
-
}): ProactiveInsight[];
|
|
7
|
-
export declare function createProactiveInsight(input: {
|
|
8
|
-
watchId: string;
|
|
9
|
-
runId: string;
|
|
10
|
-
kind: FocusWatchKind;
|
|
11
|
-
title: string;
|
|
12
|
-
summary: string;
|
|
13
|
-
whyItMatters: string;
|
|
14
|
-
nextAction: string;
|
|
15
|
-
evidence: ProactiveEvidence[];
|
|
16
|
-
valueScore: number;
|
|
17
|
-
valueReasons: string[];
|
|
18
|
-
nowMs?: number;
|
|
19
|
-
}): ProactiveInsight | null;
|
|
20
|
-
export declare function setProactiveInsightStatus(id: string, status: ProactiveInsightStatus, nowMs?: number, expectedStatus?: ProactiveInsightStatus): ProactiveInsight | null;
|
|
21
|
-
export declare function claimProactiveInsightApproval(id: string, nowMs?: number): ProactiveInsight | null;
|
|
@@ -1,109 +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/proactive/insight-repository.ts
|
|
5
|
-
function insightFromRow(row) {
|
|
6
|
-
return {
|
|
7
|
-
id: row.insight_id,
|
|
8
|
-
watchId: row.watch_id,
|
|
9
|
-
runId: row.run_id,
|
|
10
|
-
kind: row.kind,
|
|
11
|
-
title: row.title,
|
|
12
|
-
summary: row.summary,
|
|
13
|
-
whyItMatters: row.why_it_matters,
|
|
14
|
-
nextAction: row.next_action,
|
|
15
|
-
evidence: JSON.parse(row.evidence_json),
|
|
16
|
-
status: row.status,
|
|
17
|
-
valueScore: row.value_score,
|
|
18
|
-
valueReasons: JSON.parse(row.value_reasons_json),
|
|
19
|
-
createdAt: row.created_at,
|
|
20
|
-
updatedAt: row.updated_at
|
|
21
|
-
};
|
|
22
|
-
}
|
|
23
|
-
function getProactiveInsight(id) {
|
|
24
|
-
const { db } = requireXopcDatabase();
|
|
25
|
-
const row = db.prepare("SELECT * FROM proactive_insights WHERE insight_id = ?").get(id);
|
|
26
|
-
return row ? insightFromRow(row) : null;
|
|
27
|
-
}
|
|
28
|
-
function listProactiveInsights(options = {}) {
|
|
29
|
-
const statuses = options.status ?? ["unread", "read"];
|
|
30
|
-
if (statuses.length === 0) return [];
|
|
31
|
-
const limit = Math.max(1, Math.min(100, options.limit ?? 20));
|
|
32
|
-
const { db } = requireXopcDatabase();
|
|
33
|
-
return db.prepare(`SELECT * FROM proactive_insights
|
|
34
|
-
WHERE status IN (${statuses.map(() => "?").join(", ")})
|
|
35
|
-
ORDER BY created_at DESC LIMIT ?`).all(...statuses, limit).map(insightFromRow);
|
|
36
|
-
}
|
|
37
|
-
function createProactiveInsight(input) {
|
|
38
|
-
const id = randomUUID();
|
|
39
|
-
const now = input.nowMs ?? Date.now();
|
|
40
|
-
const intelligenceUpdates = input.evidence.map((item) => [
|
|
41
|
-
canonicalSource(item.source),
|
|
42
|
-
canonicalPublishedAt(item.publishedAt),
|
|
43
|
-
normalizeIdentityText(item.label)
|
|
44
|
-
]).filter(([source]) => Boolean(source)).toSorted((left, right) => JSON.stringify(left).localeCompare(JSON.stringify(right)));
|
|
45
|
-
const fingerprint = input.kind === "intelligence" && intelligenceUpdates.length > 0 ? JSON.stringify({
|
|
46
|
-
kind: input.kind,
|
|
47
|
-
updates: intelligenceUpdates
|
|
48
|
-
}) : JSON.stringify({
|
|
49
|
-
kind: input.kind,
|
|
50
|
-
title: input.title.toLocaleLowerCase().trim(),
|
|
51
|
-
summary: input.summary.toLocaleLowerCase().trim(),
|
|
52
|
-
evidence: input.evidence.map((item) => [
|
|
53
|
-
item.label.toLocaleLowerCase().trim(),
|
|
54
|
-
canonicalSource(item.source),
|
|
55
|
-
item.publishedAt ?? ""
|
|
56
|
-
])
|
|
57
|
-
});
|
|
58
|
-
const contentHash = createHash("sha256").update(fingerprint).digest("hex");
|
|
59
|
-
let created = false;
|
|
60
|
-
runSqliteWriteTransaction((db) => {
|
|
61
|
-
created = db.prepare(`INSERT OR IGNORE INTO proactive_insights (
|
|
62
|
-
insight_id, watch_id, run_id, kind, title, summary, why_it_matters,
|
|
63
|
-
next_action, evidence_json, content_hash, status, value_score,
|
|
64
|
-
value_reasons_json, created_at, updated_at
|
|
65
|
-
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'unread', ?, ?, ?, ?)`).run(id, input.watchId, input.runId, input.kind, input.title, input.summary, input.whyItMatters, input.nextAction, JSON.stringify(input.evidence), contentHash, input.valueScore, JSON.stringify(input.valueReasons), now, now).changes > 0;
|
|
66
|
-
});
|
|
67
|
-
return created ? listProactiveInsights({ limit: 100 }).find((item) => item.id === id) ?? null : null;
|
|
68
|
-
}
|
|
69
|
-
function canonicalPublishedAt(value) {
|
|
70
|
-
if (!value) return "";
|
|
71
|
-
const timestamp = Date.parse(value);
|
|
72
|
-
return Number.isFinite(timestamp) ? new Date(timestamp).toISOString() : value.trim();
|
|
73
|
-
}
|
|
74
|
-
function normalizeIdentityText(value) {
|
|
75
|
-
return value.trim().toLocaleLowerCase().replace(/\s+/g, " ");
|
|
76
|
-
}
|
|
77
|
-
function canonicalSource(source) {
|
|
78
|
-
const value = source?.trim();
|
|
79
|
-
if (!value) return "";
|
|
80
|
-
try {
|
|
81
|
-
const url = new URL(value);
|
|
82
|
-
url.hash = "";
|
|
83
|
-
for (const key of [...url.searchParams.keys()]) if (key.toLowerCase().startsWith("utm_") || key === "ref" || key === "source") url.searchParams.delete(key);
|
|
84
|
-
url.pathname = url.pathname.replace(/\/$/, "");
|
|
85
|
-
return url.toString().toLocaleLowerCase();
|
|
86
|
-
} catch {
|
|
87
|
-
return value.toLocaleLowerCase();
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
function setProactiveInsightStatus(id, status, nowMs = Date.now(), expectedStatus) {
|
|
91
|
-
let changed = false;
|
|
92
|
-
runSqliteWriteTransaction((db) => {
|
|
93
|
-
changed = db.prepare(`UPDATE proactive_insights SET status = ?, updated_at = ? WHERE insight_id = ?
|
|
94
|
-
${expectedStatus ? "AND status = ?" : ""}`).run(status, nowMs, id, ...expectedStatus ? [expectedStatus] : []).changes > 0;
|
|
95
|
-
});
|
|
96
|
-
if (!changed) return null;
|
|
97
|
-
const { db } = requireXopcDatabase();
|
|
98
|
-
return insightFromRow(db.prepare("SELECT * FROM proactive_insights WHERE insight_id = ?").get(id));
|
|
99
|
-
}
|
|
100
|
-
function claimProactiveInsightApproval(id, nowMs = Date.now()) {
|
|
101
|
-
let claimed = false;
|
|
102
|
-
runSqliteWriteTransaction((db) => {
|
|
103
|
-
claimed = db.prepare(`UPDATE proactive_insights SET status = 'approved', updated_at = ?
|
|
104
|
-
WHERE insight_id = ? AND status = 'unread'`).run(nowMs, id).changes > 0;
|
|
105
|
-
});
|
|
106
|
-
return claimed ? getProactiveInsight(id) : null;
|
|
107
|
-
}
|
|
108
|
-
//#endregion
|
|
109
|
-
export { claimProactiveInsightApproval, createProactiveInsight, getProactiveInsight, listProactiveInsights, setProactiveInsightStatus };
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import type { AutomationRun } from '../automations/index.js';
|
|
2
|
-
import type { ProactiveEvidence, ProactiveInsight } from './types.js';
|
|
3
|
-
interface MeaningfulResult {
|
|
4
|
-
meaningful: true;
|
|
5
|
-
title: string;
|
|
6
|
-
summary: string;
|
|
7
|
-
whyItMatters: string;
|
|
8
|
-
nextAction: string;
|
|
9
|
-
evidence: ProactiveEvidence[];
|
|
10
|
-
}
|
|
11
|
-
export declare function parseFocusRunResult(summary: string): MeaningfulResult | {
|
|
12
|
-
meaningful: false;
|
|
13
|
-
} | null;
|
|
14
|
-
export declare function hasValidIntelligenceEvidence(evidence: ProactiveEvidence[]): boolean;
|
|
15
|
-
export declare function processFocusAutomationRun(run: AutomationRun): {
|
|
16
|
-
handled: boolean;
|
|
17
|
-
insight?: ProactiveInsight;
|
|
18
|
-
};
|
|
19
|
-
export {};
|
|
@@ -1,146 +0,0 @@
|
|
|
1
|
-
import { createLogger } from "../utils/logger/index.js";
|
|
2
|
-
import { init_logger } from "../utils/logger.js";
|
|
3
|
-
import { getRelationshipSettings, isProactiveSupportAllowed } from "../storage/sqlite/relationship-settings-repository.js";
|
|
4
|
-
import "../storage/sqlite/index.js";
|
|
5
|
-
import { getFocusWatchByAutomationId, recordFocusWatchRun } from "./watch-repository.js";
|
|
6
|
-
import { createProactiveInsight, listProactiveInsights } from "./insight-repository.js";
|
|
7
|
-
import { scoreProactiveValue } from "./value-score.js";
|
|
8
|
-
//#region src/proactive/run-processor.ts
|
|
9
|
-
init_logger();
|
|
10
|
-
const log = createLogger("ProactiveRunProcessor");
|
|
11
|
-
function nonEmptyString(value) {
|
|
12
|
-
return typeof value === "string" && value.trim() ? value.trim() : null;
|
|
13
|
-
}
|
|
14
|
-
function parseFocusRunResult(summary) {
|
|
15
|
-
const start = summary.indexOf("{");
|
|
16
|
-
const end = summary.lastIndexOf("}");
|
|
17
|
-
if (start < 0 || end <= start) return null;
|
|
18
|
-
let value;
|
|
19
|
-
try {
|
|
20
|
-
value = JSON.parse(summary.slice(start, end + 1));
|
|
21
|
-
} catch {
|
|
22
|
-
return null;
|
|
23
|
-
}
|
|
24
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
|
|
25
|
-
const result = value;
|
|
26
|
-
if (result.meaningful === false) return { meaningful: false };
|
|
27
|
-
if (result.meaningful !== true) return null;
|
|
28
|
-
const title = nonEmptyString(result.title);
|
|
29
|
-
const resultSummary = nonEmptyString(result.summary);
|
|
30
|
-
const whyItMatters = nonEmptyString(result.whyItMatters);
|
|
31
|
-
const nextAction = nonEmptyString(result.nextAction);
|
|
32
|
-
const evidence = Array.isArray(result.evidence) ? result.evidence.flatMap((item) => {
|
|
33
|
-
if (!item || typeof item !== "object" || Array.isArray(item)) return [];
|
|
34
|
-
const label = nonEmptyString(item.label);
|
|
35
|
-
const source = nonEmptyString(item.source);
|
|
36
|
-
const publishedAtValue = nonEmptyString(item.publishedAt);
|
|
37
|
-
const publishedAt = publishedAtValue && Number.isFinite(Date.parse(publishedAtValue)) ? new Date(publishedAtValue).toISOString() : null;
|
|
38
|
-
return label ? [{
|
|
39
|
-
label,
|
|
40
|
-
...source ? { source } : {},
|
|
41
|
-
...publishedAt ? { publishedAt } : {}
|
|
42
|
-
}] : [];
|
|
43
|
-
}).slice(0, 8) : [];
|
|
44
|
-
if (!title || !resultSummary || !whyItMatters || !nextAction || evidence.length === 0) return null;
|
|
45
|
-
return {
|
|
46
|
-
meaningful: true,
|
|
47
|
-
title,
|
|
48
|
-
summary: resultSummary,
|
|
49
|
-
whyItMatters,
|
|
50
|
-
nextAction,
|
|
51
|
-
evidence
|
|
52
|
-
};
|
|
53
|
-
}
|
|
54
|
-
function hasValidIntelligenceEvidence(evidence) {
|
|
55
|
-
return evidence.some((item) => {
|
|
56
|
-
if (!item.source || !item.publishedAt) return false;
|
|
57
|
-
try {
|
|
58
|
-
const url = new URL(item.source);
|
|
59
|
-
return (url.protocol === "https:" || url.protocol === "http:") && Number.isFinite(Date.parse(item.publishedAt));
|
|
60
|
-
} catch {
|
|
61
|
-
return false;
|
|
62
|
-
}
|
|
63
|
-
});
|
|
64
|
-
}
|
|
65
|
-
function processFocusAutomationRun(run) {
|
|
66
|
-
const watch = getFocusWatchByAutomationId(run.automationId);
|
|
67
|
-
if (!watch) return { handled: false };
|
|
68
|
-
if (run.status !== "succeeded" || !run.summary) {
|
|
69
|
-
recordFocusWatchRun({
|
|
70
|
-
id: watch.id,
|
|
71
|
-
runId: run.id,
|
|
72
|
-
outcome: "failed",
|
|
73
|
-
nowMs: run.endedAtMs
|
|
74
|
-
});
|
|
75
|
-
return { handled: true };
|
|
76
|
-
}
|
|
77
|
-
const result = parseFocusRunResult(run.summary);
|
|
78
|
-
if (!result) {
|
|
79
|
-
recordFocusWatchRun({
|
|
80
|
-
id: watch.id,
|
|
81
|
-
runId: run.id,
|
|
82
|
-
outcome: "failed",
|
|
83
|
-
nowMs: run.endedAtMs
|
|
84
|
-
});
|
|
85
|
-
log.warn({
|
|
86
|
-
automationId: run.automationId,
|
|
87
|
-
runId: run.id
|
|
88
|
-
}, "Focus watch returned an invalid result");
|
|
89
|
-
return { handled: true };
|
|
90
|
-
}
|
|
91
|
-
if (result.meaningful && watch.kind === "intelligence" && !hasValidIntelligenceEvidence(result.evidence)) {
|
|
92
|
-
recordFocusWatchRun({
|
|
93
|
-
id: watch.id,
|
|
94
|
-
runId: run.id,
|
|
95
|
-
outcome: "failed",
|
|
96
|
-
nowMs: run.endedAtMs
|
|
97
|
-
});
|
|
98
|
-
log.warn({
|
|
99
|
-
automationId: run.automationId,
|
|
100
|
-
runId: run.id
|
|
101
|
-
}, "Intelligence watch result lacked dated web evidence");
|
|
102
|
-
return { handled: true };
|
|
103
|
-
}
|
|
104
|
-
if (!recordFocusWatchRun({
|
|
105
|
-
id: watch.id,
|
|
106
|
-
runId: run.id,
|
|
107
|
-
outcome: result.meaningful ? "meaningful" : "empty",
|
|
108
|
-
nowMs: run.endedAtMs
|
|
109
|
-
})) return { handled: true };
|
|
110
|
-
if (!result.meaningful) return { handled: true };
|
|
111
|
-
if (!isProactiveSupportAllowed(getRelationshipSettings(), {
|
|
112
|
-
now: new Date(run.endedAtMs),
|
|
113
|
-
topic: watch.kind
|
|
114
|
-
})) return { handled: true };
|
|
115
|
-
const history = listProactiveInsights({
|
|
116
|
-
status: ["approved", "dismissed"],
|
|
117
|
-
limit: 50
|
|
118
|
-
});
|
|
119
|
-
const value = scoreProactiveValue({
|
|
120
|
-
kind: watch.kind,
|
|
121
|
-
evidenceCount: result.evidence.length,
|
|
122
|
-
hasNextAction: Boolean(result.nextAction),
|
|
123
|
-
approvedCount: history.filter((item) => item.status === "approved").length,
|
|
124
|
-
dismissedCount: history.filter((item) => item.status === "dismissed").length
|
|
125
|
-
});
|
|
126
|
-
if (!value.shouldDeliver) return { handled: true };
|
|
127
|
-
const insight = createProactiveInsight({
|
|
128
|
-
watchId: watch.id,
|
|
129
|
-
runId: run.id,
|
|
130
|
-
kind: watch.kind,
|
|
131
|
-
title: result.title,
|
|
132
|
-
summary: result.summary,
|
|
133
|
-
whyItMatters: result.whyItMatters,
|
|
134
|
-
nextAction: result.nextAction,
|
|
135
|
-
evidence: result.evidence,
|
|
136
|
-
valueScore: value.score,
|
|
137
|
-
valueReasons: value.reasons,
|
|
138
|
-
nowMs: run.endedAtMs
|
|
139
|
-
});
|
|
140
|
-
return insight ? {
|
|
141
|
-
handled: true,
|
|
142
|
-
insight
|
|
143
|
-
} : { handled: true };
|
|
144
|
-
}
|
|
145
|
-
//#endregion
|
|
146
|
-
export { hasValidIntelligenceEvidence, parseFocusRunResult, processFocusAutomationRun };
|