@xopcai/xopc 0.0.173 → 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-ByVA0N5n.js → activity-store-CyEDJeIt.js} +1 -1
- package/dist/gateway/static/root/assets/{agent-avatar-dicebear-CJ5HvqE7.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-BZtCKzg4.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-B0oNNcFn.js → app-management-settings-panel-B4xJyvDu.js} +1 -1
- package/dist/gateway/static/root/assets/{appearance-settings-DbIj4NQ1.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-BICLQFWJ.js → archive-plugin-DWhBmmjD.js} +1 -1
- package/dist/gateway/static/root/assets/{attachment-load-DV3PteSU.js → attachment-load-BOpZfa_I.js} +1 -1
- package/dist/gateway/static/root/assets/{automation-suggestion-card-CZUImis0.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-D6zkab6N.js → binary-plugins-6AG1qatz.js} +1 -1
- package/dist/gateway/static/root/assets/{block-editor-zCzoQI-g.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-CY3X83xQ.js → browser-workflow-inputs-CBVb4mt9.js} +1 -1
- package/dist/gateway/static/root/assets/{browser-workflows-page-DDRtZLuM.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-pYLW6P7g.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-DxyOH3BO.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-BgANwjt-.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-8CaU1Mhm.js → desktop-pet-settings-CNff5TFb.js} +1 -1
- package/dist/gateway/static/root/assets/{directory-picker-path-field-BtNRUvzM.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-DFjTfx6f.js → extension-debug-page-ZqM_0eUs.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-NyEYtWWg.js → extension-page-D4hvXOMM.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-settings-page-BynTCfgf.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-BzOWImvU.js → gateway-config-api-B4THmgnS.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-settings-DXepE_Jw.js → gateway-settings-CPv-MxGE.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-startup-retry-C2JXXtwg.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-CU3JR9MI.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-DSZguLEx.js → goals-settings-o9QMXvNq.js} +1 -1
- package/dist/gateway/static/root/assets/{heartbeat-settings-KRkYziEF.js → heartbeat-settings-DixwpXnH.js} +1 -1
- package/dist/gateway/static/root/assets/{image-generation-api-Y-n6TaZ_.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-CwrQv952.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-DtITcS4K.js → local-apps-page-GzMmpO7G.js} +1 -1
- package/dist/gateway/static/root/assets/{locale-store-Ccv7tH8B.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-D1oZlq1m.js → markdown-split-CIX8D1pv.js} +1 -1
- package/dist/gateway/static/root/assets/{media-plugins-BKz5V32t.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-DLekBQPa.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-pT4nLfqS.js → page-tabs-BGAYH3Ef.js} +1 -1
- package/dist/gateway/static/root/assets/{preview-open-alternatives-OtAiaJm2.js → preview-open-alternatives-BM6pDkHp.js} +1 -1
- package/dist/gateway/static/root/assets/{product-open-page-CfryBKD9.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-nP1SB3Lf.js → save-bar-controls-BdjV8MK5.js} +1 -1
- package/dist/gateway/static/root/assets/{schedule-field-OEQTsUNz.js → schedule-field-ChlqXU46.js} +1 -1
- package/dist/gateway/static/root/assets/{schema-form-DIcAa7CJ.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-BxNcTbYO.js → settings-form-section-CPG0KGVs.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-loading-skeleton-Dpdxu4sf.js → settings-loading-skeleton-DRSDHucM.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-page-DwPeOm1c.js → settings-page-CeB7_xD0.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-page-layout-CqirFmMn.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-D72gYeux.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-U0tBgW46.js → system-settings-panel-Dp4d5Q1B.js} +1 -1
- package/dist/gateway/static/root/assets/{theme-store-DCKDVPFF.js → theme-store-CbGc1laW.js} +1 -1
- package/dist/gateway/static/root/assets/{time-picker-BpiBF5-d.js → time-picker-BhgCeDuO.js} +1 -1
- package/dist/gateway/static/root/assets/{typed-models-lib-D0XCOCAM.js → typed-models-lib-DwPk3OPL.js} +1 -1
- package/dist/gateway/static/root/assets/{use-channel-catalog-mq_Inao2.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-CKaDitO6.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-s_kS_FYA.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/cli/commands/doctor/checks/database-schema.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/heartbeat/service.js +1 -1
- 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/local-apps.js +1 -1
- 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.d.ts +1 -1
- package/dist/src/gateway/service.js +17 -13
- package/dist/src/heartbeat/index.js +1 -1
- package/dist/src/mcp/channel-bridge.js +1 -1
- 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/dist/gateway/static/root/assets/agents--TQ9jM_1.js +0 -2
- package/dist/gateway/static/root/assets/apps-page-BDsoZDEn.js +0 -1
- package/dist/gateway/static/root/assets/automations-page-CHrNcppN.js +0 -6
- package/dist/gateway/static/root/assets/browser-settings-page-BQoRuQzH.js +0 -8
- package/dist/gateway/static/root/assets/capabilities-settings-panel-BOcU0qeM.js +0 -7
- package/dist/gateway/static/root/assets/capability-presets-settings-panel-CJ1F_hlX.js +0 -1
- package/dist/gateway/static/root/assets/channels-settings-C4vDwRil.js +0 -1
- package/dist/gateway/static/root/assets/channels-status-swr-B0Pgq5x2.js +0 -1
- package/dist/gateway/static/root/assets/connectors-page-D6JEqDEj.js +0 -2
- package/dist/gateway/static/root/assets/desktop-pet-BPjQbPeA.js +0 -1
- package/dist/gateway/static/root/assets/dreaming-settings-Byv-h8XZ.js +0 -3
- package/dist/gateway/static/root/assets/goal-create-dialog-ClOZyG52.js +0 -1
- package/dist/gateway/static/root/assets/goal-detail-page-UbZB77De.js +0 -4
- package/dist/gateway/static/root/assets/goals-page-GMqV8Fwv.js +0 -2
- package/dist/gateway/static/root/assets/index-BCkNJ5cR.css +0 -1
- package/dist/gateway/static/root/assets/index-CAZ9343h.js +0 -212
- package/dist/gateway/static/root/assets/local-app-workbench-page-m5HEyrHT.js +0 -2
- package/dist/gateway/static/root/assets/logs-page-Bf_nk75f.js +0 -7
- package/dist/gateway/static/root/assets/messages-DWrg3c4K.js +0 -3
- package/dist/gateway/static/root/assets/notes-workbench-BTDmprHM.js +0 -4
- package/dist/gateway/static/root/assets/project-detail-page-C7kntu4H.js +0 -1
- package/dist/gateway/static/root/assets/projects-page-3ubcbqHr.js +0 -1
- package/dist/gateway/static/root/assets/remote-access-hub-DoUkN3ik.js +0 -1
- package/dist/gateway/static/root/assets/sessions-page-ElAAlZ-R.js +0 -1
- package/dist/gateway/static/root/assets/settings-advanced-gate-CQn_KBqr.js +0 -1
- package/dist/gateway/static/root/assets/setup-status-panel-DX_LdcTN.js +0 -1
- package/dist/gateway/static/root/assets/shares-settings-nSfe-5xK.js +0 -1
- package/dist/gateway/static/root/assets/skill-reload-api-1tYpZrJf.js +0 -1
- package/dist/gateway/static/root/assets/skills-page-BUJl8LJG.js +0 -2
- package/dist/gateway/static/root/assets/user-context-page-BOC6Hn19.js +0 -1
- package/dist/gateway/static/root/assets/work-discovery-page-DWGYp5yV.js +0 -1
- package/dist/gateway/static/root/assets/work-item-detail-page-CpeWcpSp.js +0 -1
- package/dist/gateway/static/root/assets/work-page-MsEKzmSt.js +0 -1
- package/dist/gateway/static/root/assets/workflows-page-ByhHaUHB.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,30 +0,0 @@
|
|
|
1
|
-
import { createLogger } from "../utils/logger/index.js";
|
|
2
|
-
import { init_logger } from "../utils/logger.js";
|
|
3
|
-
//#region src/proactive/trial-expiry-reconciler.ts
|
|
4
|
-
init_logger();
|
|
5
|
-
const DEFAULT_RECONCILE_INTERVAL_MS = 6e4;
|
|
6
|
-
const log = createLogger("FocusTrialExpiry");
|
|
7
|
-
function startTrialExpiryReconciler(service, intervalMs = DEFAULT_RECONCILE_INTERVAL_MS) {
|
|
8
|
-
let stopped = false;
|
|
9
|
-
let pending = null;
|
|
10
|
-
const reconcile = () => {
|
|
11
|
-
if (stopped || pending) return;
|
|
12
|
-
pending = service.reconcileExpiredTrials().then((pausedCount) => {
|
|
13
|
-
if (pausedCount > 0) log.info({ pausedCount }, "Expired focus watch trials paused");
|
|
14
|
-
}).catch((err) => {
|
|
15
|
-
log.warn({ err }, "Focus watch trial expiry reconciliation failed");
|
|
16
|
-
}).finally(() => {
|
|
17
|
-
pending = null;
|
|
18
|
-
});
|
|
19
|
-
};
|
|
20
|
-
reconcile();
|
|
21
|
-
const timer = setInterval(reconcile, intervalMs);
|
|
22
|
-
timer.unref();
|
|
23
|
-
return async () => {
|
|
24
|
-
stopped = true;
|
|
25
|
-
clearInterval(timer);
|
|
26
|
-
await pending;
|
|
27
|
-
};
|
|
28
|
-
}
|
|
29
|
-
//#endregion
|
|
30
|
-
export { startTrialExpiryReconciler };
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
import type { WorkUnderstandingThread } from '../work-discovery/types.js';
|
|
2
|
-
export type FocusWatchKind = 'progress' | 'staleness' | 'deadline' | 'intelligence';
|
|
3
|
-
export type FocusWatchStatus = 'active' | 'paused';
|
|
4
|
-
export interface FocusWatch {
|
|
5
|
-
id: string;
|
|
6
|
-
threadId: string;
|
|
7
|
-
goalId?: string;
|
|
8
|
-
automationId: string;
|
|
9
|
-
kind: FocusWatchKind;
|
|
10
|
-
status: FocusWatchStatus;
|
|
11
|
-
config: Record<string, unknown>;
|
|
12
|
-
trialEndsAt?: number;
|
|
13
|
-
lastCursor?: string;
|
|
14
|
-
lastRunAt?: number;
|
|
15
|
-
lastUsefulResultAt?: number;
|
|
16
|
-
consecutiveEmptyRuns: number;
|
|
17
|
-
createdAt: number;
|
|
18
|
-
updatedAt: number;
|
|
19
|
-
}
|
|
20
|
-
export interface FocusView {
|
|
21
|
-
id: string;
|
|
22
|
-
title: string;
|
|
23
|
-
summary: string;
|
|
24
|
-
status: WorkUnderstandingThread['status'];
|
|
25
|
-
horizon: WorkUnderstandingThread['horizon'];
|
|
26
|
-
confidence: number;
|
|
27
|
-
focusScore: number;
|
|
28
|
-
userStatus: WorkUnderstandingThread['userStatus'];
|
|
29
|
-
projectIds: string[];
|
|
30
|
-
goalId?: string;
|
|
31
|
-
nextAction?: string;
|
|
32
|
-
blockedReason?: string;
|
|
33
|
-
watches: FocusWatch[];
|
|
34
|
-
lastObservedAt: number;
|
|
35
|
-
}
|
|
36
|
-
export type ProactiveInsightStatus = 'unread' | 'read' | 'approved' | 'dismissed';
|
|
37
|
-
export interface ProactiveEvidence {
|
|
38
|
-
label: string;
|
|
39
|
-
source?: string;
|
|
40
|
-
publishedAt?: string;
|
|
41
|
-
}
|
|
42
|
-
export interface ProactiveInsight {
|
|
43
|
-
id: string;
|
|
44
|
-
watchId: string;
|
|
45
|
-
runId: string;
|
|
46
|
-
kind: FocusWatchKind;
|
|
47
|
-
title: string;
|
|
48
|
-
summary: string;
|
|
49
|
-
whyItMatters: string;
|
|
50
|
-
nextAction: string;
|
|
51
|
-
evidence: ProactiveEvidence[];
|
|
52
|
-
valueScore: number;
|
|
53
|
-
valueReasons: string[];
|
|
54
|
-
status: ProactiveInsightStatus;
|
|
55
|
-
createdAt: number;
|
|
56
|
-
updatedAt: number;
|
|
57
|
-
}
|
|
58
|
-
export interface FocusCalendarSignal {
|
|
59
|
-
id: string;
|
|
60
|
-
focusId: string;
|
|
61
|
-
focusTitle: string;
|
|
62
|
-
title: string;
|
|
63
|
-
startsAt: number;
|
|
64
|
-
endsAt?: number;
|
|
65
|
-
sourceInstanceId: string;
|
|
66
|
-
}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import type { FocusWatchKind } from './types.js';
|
|
2
|
-
export interface ProactiveValueScore {
|
|
3
|
-
score: number;
|
|
4
|
-
reasons: string[];
|
|
5
|
-
shouldDeliver: boolean;
|
|
6
|
-
}
|
|
7
|
-
export declare function scoreProactiveValue(input: {
|
|
8
|
-
kind: FocusWatchKind;
|
|
9
|
-
evidenceCount: number;
|
|
10
|
-
hasNextAction: boolean;
|
|
11
|
-
approvedCount: number;
|
|
12
|
-
dismissedCount: number;
|
|
13
|
-
}): ProactiveValueScore;
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
//#region src/proactive/value-score.ts
|
|
2
|
-
function scoreProactiveValue(input) {
|
|
3
|
-
const reasons = [];
|
|
4
|
-
let score = .15;
|
|
5
|
-
if (input.evidenceCount > 0) {
|
|
6
|
-
score += Math.min(.25, input.evidenceCount * .1);
|
|
7
|
-
reasons.push("evidence_backed");
|
|
8
|
-
}
|
|
9
|
-
if (input.hasNextAction) {
|
|
10
|
-
score += .25;
|
|
11
|
-
reasons.push("actionable");
|
|
12
|
-
}
|
|
13
|
-
const urgency = input.kind === "deadline" ? .25 : input.kind === "staleness" ? .2 : .15;
|
|
14
|
-
score += urgency;
|
|
15
|
-
reasons.push(input.kind === "deadline" ? "time_sensitive" : "focus_relevant");
|
|
16
|
-
const rated = input.approvedCount + input.dismissedCount;
|
|
17
|
-
if (rated > 0) {
|
|
18
|
-
const approvalRate = input.approvedCount / rated;
|
|
19
|
-
score += (approvalRate - .5) * .4;
|
|
20
|
-
reasons.push(approvalRate >= .5 ? "historically_useful" : "historically_dismissed");
|
|
21
|
-
}
|
|
22
|
-
score = Math.max(0, Math.min(1, score));
|
|
23
|
-
return {
|
|
24
|
-
score,
|
|
25
|
-
reasons,
|
|
26
|
-
shouldDeliver: score >= .65
|
|
27
|
-
};
|
|
28
|
-
}
|
|
29
|
-
//#endregion
|
|
30
|
-
export { scoreProactiveValue };
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import type { FocusWatch, FocusWatchKind, FocusWatchStatus } from './types.js';
|
|
2
|
-
export declare function listFocusWatches(options?: {
|
|
3
|
-
threadId?: string;
|
|
4
|
-
status?: FocusWatchStatus;
|
|
5
|
-
}): FocusWatch[];
|
|
6
|
-
export declare function getFocusWatchByThreadAndKind(threadId: string, kind: FocusWatchKind): FocusWatch | null;
|
|
7
|
-
export declare function getFocusWatchByAutomationId(automationId: string): FocusWatch | null;
|
|
8
|
-
export declare function createFocusWatch(input: {
|
|
9
|
-
threadId: string;
|
|
10
|
-
goalId?: string;
|
|
11
|
-
automationId: string;
|
|
12
|
-
kind: FocusWatchKind;
|
|
13
|
-
config?: Record<string, unknown>;
|
|
14
|
-
trialEndsAt?: number;
|
|
15
|
-
nowMs?: number;
|
|
16
|
-
}): FocusWatch;
|
|
17
|
-
export declare function setFocusWatchStatus(id: string, status: FocusWatchStatus, nowMs?: number): FocusWatch | null;
|
|
18
|
-
export declare function restartFocusWatchTrial(id: string, trialEndsAt: number, nowMs?: number): FocusWatch | null;
|
|
19
|
-
export declare function recordFocusWatchRun(input: {
|
|
20
|
-
id: string;
|
|
21
|
-
runId: string;
|
|
22
|
-
outcome: 'meaningful' | 'empty' | 'failed';
|
|
23
|
-
nowMs?: number;
|
|
24
|
-
}): FocusWatch | null;
|
|
25
|
-
export declare function recordFocusWatchFeedback(id: string, useful: boolean, nowMs?: number): {
|
|
26
|
-
watch: FocusWatch;
|
|
27
|
-
consecutiveDismissed: number;
|
|
28
|
-
} | null;
|
|
@@ -1,129 +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/proactive/watch-repository.ts
|
|
5
|
-
function watchFromRow(row) {
|
|
6
|
-
let config = {};
|
|
7
|
-
try {
|
|
8
|
-
const parsed = JSON.parse(row.config_json);
|
|
9
|
-
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) config = parsed;
|
|
10
|
-
} catch {
|
|
11
|
-
config = {};
|
|
12
|
-
}
|
|
13
|
-
return {
|
|
14
|
-
id: row.watch_id,
|
|
15
|
-
threadId: row.thread_id,
|
|
16
|
-
...row.goal_id ? { goalId: row.goal_id } : {},
|
|
17
|
-
automationId: row.automation_id,
|
|
18
|
-
kind: row.kind,
|
|
19
|
-
status: row.status,
|
|
20
|
-
config,
|
|
21
|
-
...row.trial_ends_at != null ? { trialEndsAt: row.trial_ends_at } : {},
|
|
22
|
-
...row.last_cursor ? { lastCursor: row.last_cursor } : {},
|
|
23
|
-
...row.last_run_at != null ? { lastRunAt: row.last_run_at } : {},
|
|
24
|
-
...row.last_useful_result_at != null ? { lastUsefulResultAt: row.last_useful_result_at } : {},
|
|
25
|
-
consecutiveEmptyRuns: row.consecutive_empty_runs,
|
|
26
|
-
createdAt: row.created_at,
|
|
27
|
-
updatedAt: row.updated_at
|
|
28
|
-
};
|
|
29
|
-
}
|
|
30
|
-
function listFocusWatches(options = {}) {
|
|
31
|
-
const clauses = [];
|
|
32
|
-
const values = [];
|
|
33
|
-
if (options.threadId) {
|
|
34
|
-
clauses.push("thread_id = ?");
|
|
35
|
-
values.push(options.threadId);
|
|
36
|
-
}
|
|
37
|
-
if (options.status) {
|
|
38
|
-
clauses.push("status = ?");
|
|
39
|
-
values.push(options.status);
|
|
40
|
-
}
|
|
41
|
-
const { db } = requireXopcDatabase();
|
|
42
|
-
return db.prepare(`SELECT * FROM focus_watches ${clauses.length ? `WHERE ${clauses.join(" AND ")}` : ""}
|
|
43
|
-
ORDER BY updated_at DESC`).all(...values).map(watchFromRow);
|
|
44
|
-
}
|
|
45
|
-
function getFocusWatchByThreadAndKind(threadId, kind) {
|
|
46
|
-
const { db } = requireXopcDatabase();
|
|
47
|
-
const row = db.prepare("SELECT * FROM focus_watches WHERE thread_id = ? AND kind = ?").get(threadId, kind);
|
|
48
|
-
return row ? watchFromRow(row) : null;
|
|
49
|
-
}
|
|
50
|
-
function getFocusWatchByAutomationId(automationId) {
|
|
51
|
-
const { db } = requireXopcDatabase();
|
|
52
|
-
const row = db.prepare("SELECT * FROM focus_watches WHERE automation_id = ?").get(automationId);
|
|
53
|
-
return row ? watchFromRow(row) : null;
|
|
54
|
-
}
|
|
55
|
-
function createFocusWatch(input) {
|
|
56
|
-
const now = input.nowMs ?? Date.now();
|
|
57
|
-
const id = randomUUID();
|
|
58
|
-
runSqliteWriteTransaction((db) => {
|
|
59
|
-
db.prepare(`INSERT INTO focus_watches (
|
|
60
|
-
watch_id, thread_id, goal_id, automation_id, kind, status, config_json,
|
|
61
|
-
trial_ends_at, consecutive_empty_runs, created_at, updated_at
|
|
62
|
-
) VALUES (?, ?, ?, ?, ?, 'active', ?, ?, 0, ?, ?)`).run(id, input.threadId, input.goalId ?? null, input.automationId, input.kind, JSON.stringify(input.config ?? {}), input.trialEndsAt ?? null, now, now);
|
|
63
|
-
});
|
|
64
|
-
return getFocusWatchByThreadAndKind(input.threadId, input.kind);
|
|
65
|
-
}
|
|
66
|
-
function setFocusWatchStatus(id, status, nowMs = Date.now()) {
|
|
67
|
-
let changed = false;
|
|
68
|
-
runSqliteWriteTransaction((db) => {
|
|
69
|
-
changed = db.prepare("UPDATE focus_watches SET status = ?, updated_at = ? WHERE watch_id = ?").run(status, nowMs, id).changes > 0;
|
|
70
|
-
});
|
|
71
|
-
if (!changed) return null;
|
|
72
|
-
const { db } = requireXopcDatabase();
|
|
73
|
-
return watchFromRow(db.prepare("SELECT * FROM focus_watches WHERE watch_id = ?").get(id));
|
|
74
|
-
}
|
|
75
|
-
function restartFocusWatchTrial(id, trialEndsAt, nowMs = Date.now()) {
|
|
76
|
-
let changed = false;
|
|
77
|
-
runSqliteWriteTransaction((db) => {
|
|
78
|
-
changed = db.prepare(`UPDATE focus_watches
|
|
79
|
-
SET status = 'active', trial_ends_at = ?, consecutive_empty_runs = 0, updated_at = ?
|
|
80
|
-
WHERE watch_id = ?`).run(trialEndsAt, nowMs, id).changes > 0;
|
|
81
|
-
});
|
|
82
|
-
if (!changed) return null;
|
|
83
|
-
const { db } = requireXopcDatabase();
|
|
84
|
-
return watchFromRow(db.prepare("SELECT * FROM focus_watches WHERE watch_id = ?").get(id));
|
|
85
|
-
}
|
|
86
|
-
function recordFocusWatchRun(input) {
|
|
87
|
-
const now = input.nowMs ?? Date.now();
|
|
88
|
-
let changed = false;
|
|
89
|
-
runSqliteWriteTransaction((db) => {
|
|
90
|
-
changed = db.prepare(`UPDATE focus_watches SET
|
|
91
|
-
last_cursor = ?,
|
|
92
|
-
last_run_at = ?,
|
|
93
|
-
last_useful_result_at = CASE WHEN ? = 'meaningful' THEN ? ELSE last_useful_result_at END,
|
|
94
|
-
consecutive_empty_runs = CASE
|
|
95
|
-
WHEN ? = 'meaningful' THEN 0
|
|
96
|
-
WHEN ? = 'empty' THEN consecutive_empty_runs + 1
|
|
97
|
-
ELSE consecutive_empty_runs
|
|
98
|
-
END,
|
|
99
|
-
updated_at = ?
|
|
100
|
-
WHERE watch_id = ? AND (last_cursor IS NULL OR last_cursor <> ?)`).run(input.runId, now, input.outcome, now, input.outcome, input.outcome, now, input.id, input.runId).changes > 0;
|
|
101
|
-
});
|
|
102
|
-
if (!changed) return null;
|
|
103
|
-
return listFocusWatches().find((watch) => watch.id === input.id) ?? null;
|
|
104
|
-
}
|
|
105
|
-
function recordFocusWatchFeedback(id, useful, nowMs = Date.now()) {
|
|
106
|
-
const watch = listFocusWatches().find((item) => item.id === id);
|
|
107
|
-
if (!watch) return null;
|
|
108
|
-
const previous = watch.config.feedback && typeof watch.config.feedback === "object" && !Array.isArray(watch.config.feedback) ? watch.config.feedback : {};
|
|
109
|
-
const approved = typeof previous.approved === "number" ? previous.approved : 0;
|
|
110
|
-
const dismissed = typeof previous.dismissed === "number" ? previous.dismissed : 0;
|
|
111
|
-
const consecutiveDismissed = useful ? 0 : (typeof previous.consecutiveDismissed === "number" ? previous.consecutiveDismissed : 0) + 1;
|
|
112
|
-
const config = {
|
|
113
|
-
...watch.config,
|
|
114
|
-
feedback: {
|
|
115
|
-
approved: approved + (useful ? 1 : 0),
|
|
116
|
-
dismissed: dismissed + (useful ? 0 : 1),
|
|
117
|
-
consecutiveDismissed
|
|
118
|
-
}
|
|
119
|
-
};
|
|
120
|
-
runSqliteWriteTransaction((db) => {
|
|
121
|
-
db.prepare("UPDATE focus_watches SET config_json = ?, updated_at = ? WHERE watch_id = ?").run(JSON.stringify(config), nowMs, id);
|
|
122
|
-
});
|
|
123
|
-
return {
|
|
124
|
-
watch: listFocusWatches().find((item) => item.id === id),
|
|
125
|
-
consecutiveDismissed
|
|
126
|
-
};
|
|
127
|
-
}
|
|
128
|
-
//#endregion
|
|
129
|
-
export { createFocusWatch, getFocusWatchByAutomationId, getFocusWatchByThreadAndKind, listFocusWatches, recordFocusWatchFeedback, recordFocusWatchRun, restartFocusWatchTrial, setFocusWatchStatus };
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
export interface WorkUnderstandingSourceLineage {
|
|
2
|
-
sourceId: string;
|
|
3
|
-
evidenceCount: number;
|
|
4
|
-
threadCount: number;
|
|
5
|
-
memoryRecordCount: number;
|
|
6
|
-
discoveryRunCount: number;
|
|
7
|
-
}
|
|
8
|
-
export declare function getWorkUnderstandingSourceLineage(sourceId: string): WorkUnderstandingSourceLineage | null;
|
|
9
|
-
export declare function deleteWorkUnderstandingDerivedData(sourceId: string): {
|
|
10
|
-
deletedMemoryRecords: number;
|
|
11
|
-
evidenceCount: number | bigint;
|
|
12
|
-
deletedThreads: number;
|
|
13
|
-
retainedThreads: number;
|
|
14
|
-
};
|
|
15
|
-
export declare function getWorkUnderstandingMetrics(): {
|
|
16
|
-
completedInvestigations: number;
|
|
17
|
-
averageToolCalls: number;
|
|
18
|
-
activeThreads: number;
|
|
19
|
-
confirmedThreads: number;
|
|
20
|
-
recognitionConfirmationRate: number;
|
|
21
|
-
evidenceBySource: {
|
|
22
|
-
sourceType: string;
|
|
23
|
-
count: number;
|
|
24
|
-
}[];
|
|
25
|
-
};
|
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
import { requireXopcDatabase } from "../storage/sqlite/connection.js";
|
|
2
|
-
import { runSqliteWriteTransaction } from "../storage/sqlite/transaction.js";
|
|
3
|
-
import { deleteMemoryRecord, listMemoryRecords } from "../storage/sqlite/memory-records-repository.js";
|
|
4
|
-
//#region src/work-discovery/governance.ts
|
|
5
|
-
function memoryRecordsForSource(sourceId, rootPath) {
|
|
6
|
-
const { db } = requireXopcDatabase();
|
|
7
|
-
const runIds = rootPath ? db.prepare("SELECT id FROM work_discovery_runs WHERE root_path = ?").all(rootPath).map((row) => row.id) : [];
|
|
8
|
-
const runPaths = new Set(runIds.map((id) => `work-discovery://${id}`));
|
|
9
|
-
const records = [];
|
|
10
|
-
for (let offset = 0;; offset += 500) {
|
|
11
|
-
const page = listMemoryRecords({
|
|
12
|
-
limit: 500,
|
|
13
|
-
offset
|
|
14
|
-
});
|
|
15
|
-
records.push(...page.filter((record) => runPaths.has(record.source.path)));
|
|
16
|
-
if (page.length < 500) break;
|
|
17
|
-
}
|
|
18
|
-
return records;
|
|
19
|
-
}
|
|
20
|
-
function getWorkUnderstandingSourceLineage(sourceId) {
|
|
21
|
-
const { db } = requireXopcDatabase();
|
|
22
|
-
const source = db.prepare("SELECT root_path FROM work_discovery_sources WHERE source_id = ?").get(sourceId);
|
|
23
|
-
if (!source) return null;
|
|
24
|
-
const evidenceCount = db.prepare("SELECT COUNT(*) AS count FROM work_understanding_evidence WHERE source_grant_id = ?").get(sourceId).count;
|
|
25
|
-
const threadCount = db.prepare(`SELECT COUNT(DISTINCT te.thread_id) AS count
|
|
26
|
-
FROM work_understanding_thread_evidence te
|
|
27
|
-
JOIN work_understanding_evidence e ON e.evidence_id = te.evidence_id
|
|
28
|
-
WHERE e.source_grant_id = ?`).get(sourceId).count;
|
|
29
|
-
const discoveryRunCount = source.root_path ? db.prepare("SELECT COUNT(*) AS count FROM work_discovery_runs WHERE root_path = ?").get(source.root_path).count : 0;
|
|
30
|
-
return {
|
|
31
|
-
sourceId,
|
|
32
|
-
evidenceCount,
|
|
33
|
-
threadCount,
|
|
34
|
-
memoryRecordCount: memoryRecordsForSource(sourceId, source.root_path).length,
|
|
35
|
-
discoveryRunCount
|
|
36
|
-
};
|
|
37
|
-
}
|
|
38
|
-
function deleteWorkUnderstandingDerivedData(sourceId) {
|
|
39
|
-
if (!getWorkUnderstandingSourceLineage(sourceId)) return null;
|
|
40
|
-
const { db } = requireXopcDatabase();
|
|
41
|
-
const memoryRecords = memoryRecordsForSource(sourceId, db.prepare("SELECT root_path FROM work_discovery_sources WHERE source_id = ?").get(sourceId).root_path).filter((record) => record.explicitness !== "explicit");
|
|
42
|
-
const affectedThreadIds = db.prepare(`SELECT DISTINCT te.thread_id AS id
|
|
43
|
-
FROM work_understanding_thread_evidence te
|
|
44
|
-
JOIN work_understanding_evidence e ON e.evidence_id = te.evidence_id
|
|
45
|
-
WHERE e.source_grant_id = ?`).all(sourceId).map((row) => row.id);
|
|
46
|
-
const result = runSqliteWriteTransaction((transaction) => {
|
|
47
|
-
transaction.prepare(`DELETE FROM work_understanding_thread_evidence
|
|
48
|
-
WHERE evidence_id IN (SELECT evidence_id FROM work_understanding_evidence WHERE source_grant_id = ?)`).run(sourceId);
|
|
49
|
-
const evidence = transaction.prepare("DELETE FROM work_understanding_evidence WHERE source_grant_id = ?").run(sourceId);
|
|
50
|
-
let deletedThreads = 0;
|
|
51
|
-
let retainedThreads = 0;
|
|
52
|
-
for (const threadId of affectedThreadIds) {
|
|
53
|
-
if (transaction.prepare("SELECT COUNT(*) AS count FROM work_understanding_thread_evidence WHERE thread_id = ?").get(threadId).count > 0) continue;
|
|
54
|
-
const thread = transaction.prepare("SELECT user_status, status FROM work_understanding_threads WHERE thread_id = ?").get(threadId);
|
|
55
|
-
if (!thread) continue;
|
|
56
|
-
if (thread.user_status === "confirmed" || thread.user_status === "corrected") {
|
|
57
|
-
transaction.prepare(`UPDATE work_understanding_threads SET confidence = MIN(confidence, 0.5),
|
|
58
|
-
status = CASE WHEN status IN ('paused', 'completed') THEN status ELSE 'uncertain' END,
|
|
59
|
-
updated_at = ? WHERE thread_id = ?`).run(Date.now(), threadId);
|
|
60
|
-
retainedThreads += 1;
|
|
61
|
-
} else {
|
|
62
|
-
transaction.prepare("DELETE FROM work_understanding_threads WHERE thread_id = ?").run(threadId);
|
|
63
|
-
deletedThreads += 1;
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
return {
|
|
67
|
-
evidenceCount: evidence.changes,
|
|
68
|
-
deletedThreads,
|
|
69
|
-
retainedThreads
|
|
70
|
-
};
|
|
71
|
-
});
|
|
72
|
-
const deletedMemoryRecords = memoryRecords.filter((record) => deleteMemoryRecord(record.id)).length;
|
|
73
|
-
return {
|
|
74
|
-
...result,
|
|
75
|
-
deletedMemoryRecords
|
|
76
|
-
};
|
|
77
|
-
}
|
|
78
|
-
function getWorkUnderstandingMetrics() {
|
|
79
|
-
const { db } = requireXopcDatabase();
|
|
80
|
-
const scalar = (sql) => db.prepare(sql).get().value;
|
|
81
|
-
const evidenceBySource = db.prepare("SELECT source_type AS sourceType, COUNT(*) AS count FROM work_understanding_evidence GROUP BY source_type").all();
|
|
82
|
-
const recognition = db.prepare(`SELECT recognition_decision AS decision, COUNT(*) AS count
|
|
83
|
-
FROM work_discovery_feedback GROUP BY recognition_decision`).all();
|
|
84
|
-
const reviewed = recognition.reduce((sum, item) => sum + (item.decision === "dismissed" ? 0 : item.count), 0);
|
|
85
|
-
const confirmed = recognition.find((item) => item.decision === "confirmed")?.count ?? 0;
|
|
86
|
-
return {
|
|
87
|
-
completedInvestigations: scalar("SELECT COUNT(*) AS value FROM work_understanding_investigations WHERE status = 'completed'"),
|
|
88
|
-
averageToolCalls: scalar("SELECT COALESCE(AVG(tool_call_count), 0) AS value FROM work_understanding_investigations"),
|
|
89
|
-
activeThreads: scalar("SELECT COUNT(*) AS value FROM work_understanding_threads WHERE status IN ('active', 'blocked') AND user_status <> 'rejected'"),
|
|
90
|
-
confirmedThreads: scalar("SELECT COUNT(*) AS value FROM work_understanding_threads WHERE user_status IN ('confirmed', 'corrected')"),
|
|
91
|
-
recognitionConfirmationRate: reviewed ? confirmed / reviewed : 0,
|
|
92
|
-
evidenceBySource
|
|
93
|
-
};
|
|
94
|
-
}
|
|
95
|
-
//#endregion
|
|
96
|
-
export { deleteWorkUnderstandingDerivedData, getWorkUnderstandingMetrics, getWorkUnderstandingSourceLineage };
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import type { WorkUnderstandingThread } from './types.js';
|
|
2
|
-
export declare function getWorkUnderstandingThread(id: string): WorkUnderstandingThread | null;
|
|
3
|
-
export declare function getWorkUnderstandingThreadByCanonicalKey(key: string): WorkUnderstandingThread | null;
|
|
4
|
-
export declare function listWorkUnderstandingThreads(options?: {
|
|
5
|
-
projectId?: string;
|
|
6
|
-
includeRejected?: boolean;
|
|
7
|
-
limit?: number;
|
|
8
|
-
}): WorkUnderstandingThread[];
|
|
9
|
-
export declare function upsertWorkUnderstandingThread(input: {
|
|
10
|
-
canonicalKey: string;
|
|
11
|
-
title: string;
|
|
12
|
-
summary: string;
|
|
13
|
-
status: WorkUnderstandingThread['status'];
|
|
14
|
-
horizon: WorkUnderstandingThread['horizon'];
|
|
15
|
-
focusScore: number;
|
|
16
|
-
confidence: number;
|
|
17
|
-
projectIds: string[];
|
|
18
|
-
evidenceIds: string[];
|
|
19
|
-
observedAt?: number;
|
|
20
|
-
nowMs?: number;
|
|
21
|
-
}): WorkUnderstandingThread;
|
|
22
|
-
export declare function addWorkUnderstandingThreadFeedback(input: {
|
|
23
|
-
threadId: string;
|
|
24
|
-
decision: 'confirmed' | 'corrected' | 'rejected' | 'paused' | 'completed';
|
|
25
|
-
correctedTitle?: string;
|
|
26
|
-
correctedSummary?: string;
|
|
27
|
-
nowMs?: number;
|
|
28
|
-
}): WorkUnderstandingThread | null;
|
|
29
|
-
export declare function attachWorkUnderstandingThreadEvidence(input: {
|
|
30
|
-
threadId: string;
|
|
31
|
-
evidenceId: string;
|
|
32
|
-
projectId?: string;
|
|
33
|
-
nowMs?: number;
|
|
34
|
-
}): WorkUnderstandingThread | null;
|
|
@@ -1,112 +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/work-discovery/thread-repository.ts
|
|
5
|
-
function idsForThread(table, column, id) {
|
|
6
|
-
const { db } = requireXopcDatabase();
|
|
7
|
-
return db.prepare(`SELECT ${column} AS id FROM ${table} WHERE thread_id = ? ORDER BY created_at ASC`).all(id).map((row) => row.id);
|
|
8
|
-
}
|
|
9
|
-
function threadFromRow(row) {
|
|
10
|
-
return {
|
|
11
|
-
id: row.thread_id,
|
|
12
|
-
canonicalKey: row.canonical_key,
|
|
13
|
-
title: row.title,
|
|
14
|
-
summary: row.summary,
|
|
15
|
-
status: row.status,
|
|
16
|
-
horizon: row.horizon,
|
|
17
|
-
focusScore: row.focus_score,
|
|
18
|
-
confidence: row.confidence,
|
|
19
|
-
userStatus: row.user_status,
|
|
20
|
-
projectIds: idsForThread("work_understanding_thread_projects", "project_id", row.thread_id),
|
|
21
|
-
evidenceIds: idsForThread("work_understanding_thread_evidence", "evidence_id", row.thread_id),
|
|
22
|
-
...row.parent_thread_id ? { parentThreadId: row.parent_thread_id } : {},
|
|
23
|
-
firstObservedAt: row.first_observed_at,
|
|
24
|
-
lastObservedAt: row.last_observed_at,
|
|
25
|
-
createdAt: row.created_at,
|
|
26
|
-
updatedAt: row.updated_at
|
|
27
|
-
};
|
|
28
|
-
}
|
|
29
|
-
function getWorkUnderstandingThread(id) {
|
|
30
|
-
const { db } = requireXopcDatabase();
|
|
31
|
-
const row = db.prepare("SELECT * FROM work_understanding_threads WHERE thread_id = ?").get(id);
|
|
32
|
-
return row ? threadFromRow(row) : null;
|
|
33
|
-
}
|
|
34
|
-
function getWorkUnderstandingThreadByCanonicalKey(key) {
|
|
35
|
-
const { db } = requireXopcDatabase();
|
|
36
|
-
const row = db.prepare("SELECT * FROM work_understanding_threads WHERE canonical_key = ?").get(key);
|
|
37
|
-
return row ? threadFromRow(row) : null;
|
|
38
|
-
}
|
|
39
|
-
function listWorkUnderstandingThreads(options = {}) {
|
|
40
|
-
const { db } = requireXopcDatabase();
|
|
41
|
-
const clauses = [];
|
|
42
|
-
const args = [];
|
|
43
|
-
if (!options.includeRejected) clauses.push("t.user_status <> 'rejected'");
|
|
44
|
-
if (options.projectId) {
|
|
45
|
-
clauses.push("EXISTS (SELECT 1 FROM work_understanding_thread_projects p WHERE p.thread_id = t.thread_id AND p.project_id = ?)");
|
|
46
|
-
args.push(options.projectId);
|
|
47
|
-
}
|
|
48
|
-
args.push(Math.max(1, Math.min(200, options.limit ?? 50)));
|
|
49
|
-
return db.prepare(`SELECT t.* FROM work_understanding_threads t
|
|
50
|
-
${clauses.length ? `WHERE ${clauses.join(" AND ")}` : ""}
|
|
51
|
-
ORDER BY t.focus_score DESC, t.last_observed_at DESC LIMIT ?`).all(...args).map(threadFromRow);
|
|
52
|
-
}
|
|
53
|
-
function upsertWorkUnderstandingThread(input) {
|
|
54
|
-
const now = input.nowMs ?? Date.now();
|
|
55
|
-
const observedAt = input.observedAt ?? now;
|
|
56
|
-
const id = getWorkUnderstandingThreadByCanonicalKey(input.canonicalKey)?.id ?? randomUUID();
|
|
57
|
-
runSqliteWriteTransaction((db) => {
|
|
58
|
-
db.prepare(`INSERT INTO work_understanding_threads (
|
|
59
|
-
thread_id, canonical_key, title, summary, status, horizon, focus_score,
|
|
60
|
-
confidence, user_status, first_observed_at, last_observed_at, created_at, updated_at
|
|
61
|
-
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, 'unreviewed', ?, ?, ?, ?)
|
|
62
|
-
ON CONFLICT(canonical_key) DO UPDATE SET
|
|
63
|
-
title = CASE WHEN work_understanding_threads.user_status = 'corrected' THEN work_understanding_threads.title ELSE excluded.title END,
|
|
64
|
-
summary = CASE WHEN work_understanding_threads.user_status = 'corrected' THEN work_understanding_threads.summary ELSE excluded.summary END,
|
|
65
|
-
status = CASE WHEN work_understanding_threads.status IN ('paused', 'completed') THEN work_understanding_threads.status ELSE excluded.status END,
|
|
66
|
-
horizon = excluded.horizon,
|
|
67
|
-
focus_score = CASE WHEN work_understanding_threads.user_status = 'confirmed'
|
|
68
|
-
THEN MIN(100, excluded.focus_score + 12) ELSE excluded.focus_score END,
|
|
69
|
-
confidence = CASE WHEN work_understanding_threads.user_status IN ('confirmed', 'corrected')
|
|
70
|
-
THEN MAX(work_understanding_threads.confidence, excluded.confidence) ELSE excluded.confidence END,
|
|
71
|
-
last_observed_at = excluded.last_observed_at,
|
|
72
|
-
updated_at = excluded.updated_at`).run(id, input.canonicalKey, input.title.slice(0, 200), input.summary.slice(0, 2e3), input.status, input.horizon, Math.max(0, Math.min(100, input.focusScore)), Math.max(0, Math.min(1, input.confidence)), observedAt, observedAt, now, now);
|
|
73
|
-
const row = db.prepare("SELECT thread_id FROM work_understanding_threads WHERE canonical_key = ?").get(input.canonicalKey);
|
|
74
|
-
const projectInsert = db.prepare("INSERT OR IGNORE INTO work_understanding_thread_projects (thread_id, project_id, created_at) VALUES (?, ?, ?)");
|
|
75
|
-
for (const projectId of [...new Set(input.projectIds)].slice(0, 20)) projectInsert.run(row.thread_id, projectId, now);
|
|
76
|
-
const evidenceInsert = db.prepare(`INSERT OR IGNORE INTO work_understanding_thread_evidence (thread_id, evidence_id, relation, created_at)
|
|
77
|
-
VALUES (?, ?, 'supports', ?)`);
|
|
78
|
-
for (const evidenceId of [...new Set(input.evidenceIds)].slice(0, 50)) evidenceInsert.run(row.thread_id, evidenceId, now);
|
|
79
|
-
});
|
|
80
|
-
return getWorkUnderstandingThreadByCanonicalKey(input.canonicalKey);
|
|
81
|
-
}
|
|
82
|
-
function addWorkUnderstandingThreadFeedback(input) {
|
|
83
|
-
const thread = getWorkUnderstandingThread(input.threadId);
|
|
84
|
-
if (!thread) return null;
|
|
85
|
-
const now = input.nowMs ?? Date.now();
|
|
86
|
-
const userStatus = input.decision === "confirmed" ? "confirmed" : input.decision === "corrected" ? "corrected" : input.decision === "rejected" ? "rejected" : thread.userStatus;
|
|
87
|
-
const status = input.decision === "paused" || input.decision === "completed" ? input.decision : thread.status;
|
|
88
|
-
runSqliteWriteTransaction((db) => {
|
|
89
|
-
db.prepare(`INSERT INTO work_understanding_thread_feedback (
|
|
90
|
-
feedback_id, thread_id, decision, corrected_title, corrected_summary, created_at
|
|
91
|
-
) VALUES (?, ?, ?, ?, ?, ?)`).run(randomUUID(), thread.id, input.decision, input.correctedTitle ?? null, input.correctedSummary ?? null, now);
|
|
92
|
-
db.prepare(`UPDATE work_understanding_threads SET title = ?, summary = ?, status = ?, user_status = ?,
|
|
93
|
-
focus_score = ?, confidence = ?, updated_at = ? WHERE thread_id = ?`).run(input.decision === "corrected" && input.correctedTitle?.trim() ? input.correctedTitle.trim().slice(0, 200) : thread.title, input.decision === "corrected" && input.correctedSummary?.trim() ? input.correctedSummary.trim().slice(0, 2e3) : thread.summary, status, userStatus, input.decision === "confirmed" ? Math.min(100, thread.focusScore + 12) : thread.focusScore, input.decision === "confirmed" || input.decision === "corrected" ? 1 : thread.confidence, now, thread.id);
|
|
94
|
-
});
|
|
95
|
-
return getWorkUnderstandingThread(thread.id);
|
|
96
|
-
}
|
|
97
|
-
function attachWorkUnderstandingThreadEvidence(input) {
|
|
98
|
-
const thread = getWorkUnderstandingThread(input.threadId);
|
|
99
|
-
if (!thread) return null;
|
|
100
|
-
const now = input.nowMs ?? Date.now();
|
|
101
|
-
runSqliteWriteTransaction((db) => {
|
|
102
|
-
db.prepare(`INSERT OR IGNORE INTO work_understanding_thread_evidence (thread_id, evidence_id, relation, created_at)
|
|
103
|
-
VALUES (?, ?, 'supports', ?)`).run(thread.id, input.evidenceId, now);
|
|
104
|
-
if (input.projectId) db.prepare("INSERT OR IGNORE INTO work_understanding_thread_projects (thread_id, project_id, created_at) VALUES (?, ?, ?)").run(thread.id, input.projectId, now);
|
|
105
|
-
db.prepare(`UPDATE work_understanding_threads SET confidence = MIN(1, confidence + 0.05),
|
|
106
|
-
focus_score = MIN(100, focus_score + 4), last_observed_at = MAX(last_observed_at, ?), updated_at = ?
|
|
107
|
-
WHERE thread_id = ?`).run(now, now, thread.id);
|
|
108
|
-
});
|
|
109
|
-
return getWorkUnderstandingThread(thread.id);
|
|
110
|
-
}
|
|
111
|
-
//#endregion
|
|
112
|
-
export { addWorkUnderstandingThreadFeedback, attachWorkUnderstandingThreadEvidence, getWorkUnderstandingThread, getWorkUnderstandingThreadByCanonicalKey, listWorkUnderstandingThreads, upsertWorkUnderstandingThread };
|
|
File without changes
|