@goondocks/myco 0.20.2 → 0.21.0
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/agent-eval-RJSQI5S2.js +355 -0
- package/dist/agent-eval-RJSQI5S2.js.map +1 -0
- package/dist/{agent-run-X25Q2A6T.js → agent-run-2JSYFOKU.js} +10 -8
- package/dist/{agent-run-X25Q2A6T.js.map → agent-run-2JSYFOKU.js.map} +1 -1
- package/dist/{agent-tasks-7B6OFERB.js → agent-tasks-APFJIM2T.js} +10 -8
- package/dist/{agent-tasks-7B6OFERB.js.map → agent-tasks-APFJIM2T.js.map} +1 -1
- package/dist/{chunk-OD4AA7PV.js → chunk-53RPGOEN.js} +56 -8
- package/dist/chunk-53RPGOEN.js.map +1 -0
- package/dist/chunk-54SXG5HF.js +26 -0
- package/dist/chunk-54SXG5HF.js.map +1 -0
- package/dist/{chunk-DCSGJ7W4.js → chunk-5ZG4RMUH.js} +2 -2
- package/dist/{chunk-FLLBJLHM.js → chunk-6C6QZ4PM.js} +9 -5
- package/dist/chunk-6C6QZ4PM.js.map +1 -0
- package/dist/chunk-6LB7XELY.js +406 -0
- package/dist/chunk-6LB7XELY.js.map +1 -0
- package/dist/{chunk-JZGN33AY.js → chunk-75Z7UKDY.js} +4 -4
- package/dist/{chunk-XG5RRUYF.js → chunk-BUTL6IFS.js} +2 -2
- package/dist/chunk-CESKJD44.js +586 -0
- package/dist/chunk-CESKJD44.js.map +1 -0
- package/dist/chunk-CISWUP5W.js +101 -0
- package/dist/chunk-CISWUP5W.js.map +1 -0
- package/dist/chunk-DJ3IHNYO.js +50 -0
- package/dist/chunk-DJ3IHNYO.js.map +1 -0
- package/dist/chunk-F3OEQYLS.js +847 -0
- package/dist/chunk-F3OEQYLS.js.map +1 -0
- package/dist/{chunk-6RFZWV4R.js → chunk-FCJ5JV54.js} +1 -1
- package/dist/{chunk-6RFZWV4R.js.map → chunk-FCJ5JV54.js.map} +1 -1
- package/dist/{chunk-2PDWCDKY.js → chunk-G6QIBNZM.js} +9 -6
- package/dist/{chunk-2PDWCDKY.js.map → chunk-G6QIBNZM.js.map} +1 -1
- package/dist/{chunk-6X2ERTQV.js → chunk-ILJPRYES.js} +6 -4
- package/dist/{chunk-6X2ERTQV.js.map → chunk-ILJPRYES.js.map} +1 -1
- package/dist/{chunk-US4LNCAT.js → chunk-IPPMYQ2Y.js} +5 -1
- package/dist/chunk-IPPMYQ2Y.js.map +1 -0
- package/dist/{chunk-KESLPBKV.js → chunk-JR54LTPP.js} +4 -4
- package/dist/{chunk-CCRGY3QW.js → chunk-JZS6GZ6T.js} +16 -94
- package/dist/chunk-JZS6GZ6T.js.map +1 -0
- package/dist/{chunk-5XIVBO25.js → chunk-LVIY7P35.js} +2 -2
- package/dist/chunk-NGH7U6A3.js +13844 -0
- package/dist/chunk-NGH7U6A3.js.map +1 -0
- package/dist/chunk-OUJSQSKE.js +113 -0
- package/dist/chunk-OUJSQSKE.js.map +1 -0
- package/dist/{chunk-VVNL26WX.js → chunk-P66DLD6G.js} +22 -10
- package/dist/chunk-P66DLD6G.js.map +1 -0
- package/dist/{chunk-XATDZX7U.js → chunk-R2JIJBCL.js} +18 -4
- package/dist/{chunk-XATDZX7U.js.map → chunk-R2JIJBCL.js.map} +1 -1
- package/dist/{chunk-MYOZLMB2.js → chunk-RL5R4CQU.js} +538 -19
- package/dist/chunk-RL5R4CQU.js.map +1 -0
- package/dist/{chunk-EVDQKYCG.js → chunk-RQSJLWP4.js} +13 -2
- package/dist/chunk-RQSJLWP4.js.map +1 -0
- package/dist/{chunk-BPRIYNLE.js → chunk-TKAJ3JVF.js} +3 -3
- package/dist/{chunk-Q36VMZST.js → chunk-VHNRMM4O.js} +3 -2
- package/dist/{chunk-FMRZ26U5.js → chunk-X3IGT5RV.js} +5 -2
- package/dist/{chunk-FMRZ26U5.js.map → chunk-X3IGT5RV.js.map} +1 -1
- package/dist/{chunk-KHT24OWC.js → chunk-YDUOSRGD.js} +8 -94
- package/dist/{chunk-KHT24OWC.js.map → chunk-YDUOSRGD.js.map} +1 -1
- package/dist/{cli-GGPWH4UO.js → cli-LNYSTDQM.js} +49 -42
- package/dist/cli-LNYSTDQM.js.map +1 -0
- package/dist/{client-YXQUTXVZ.js → client-NWE4TCNO.js} +4 -4
- package/dist/{config-OMCYHG2S.js → config-VC4ACP42.js} +6 -4
- package/dist/{config-OMCYHG2S.js.map → config-VC4ACP42.js.map} +1 -1
- package/dist/{detect-providers-5KOPZ7J2.js → detect-providers-ILLQZROY.js} +4 -4
- package/dist/{doctor-5JXJ36KA.js → doctor-TI7EZ3RW.js} +48 -15
- package/dist/doctor-TI7EZ3RW.js.map +1 -0
- package/dist/executor-F2YU7HXJ.js +44 -0
- package/dist/{init-LMYOVZAV.js → init-KG3TYVGE.js} +14 -12
- package/dist/{init-LMYOVZAV.js.map → init-KG3TYVGE.js.map} +1 -1
- package/dist/{installer-FS257JRZ.js → installer-UMH7OJ5A.js} +6 -4
- package/dist/{llm-TH4NLIRM.js → llm-AGVEF5XD.js} +5 -4
- package/dist/{loader-CQYTFHEW.js → loader-LX7TFRM6.js} +5 -3
- package/dist/{loader-NOMBJUPW.js → loader-NAVVZK63.js} +4 -3
- package/dist/{main-YTBVRTBI.js → main-5PRQNEEE.js} +2453 -650
- package/dist/main-5PRQNEEE.js.map +1 -0
- package/dist/{open-HG2DX6RN.js → open-5A27BCSB.js} +10 -8
- package/dist/{open-HG2DX6RN.js.map → open-5A27BCSB.js.map} +1 -1
- package/dist/{post-compact-JSECI44W.js → post-compact-USAODKPQ.js} +6 -6
- package/dist/{post-tool-use-POGPTJBA.js → post-tool-use-GMMSYBII.js} +9 -7
- package/dist/post-tool-use-GMMSYBII.js.map +1 -0
- package/dist/{post-tool-use-failure-OT7BFWQW.js → post-tool-use-failure-NZVSL2PO.js} +6 -6
- package/dist/{pre-compact-OXVODKH4.js → pre-compact-LZ57DLUS.js} +6 -6
- package/dist/{provider-check-43LAMSMH.js → provider-check-ZEV5P4KM.js} +4 -4
- package/dist/{registry-U4CHXK6R.js → registry-M2Z5QBWH.js} +5 -4
- package/dist/{remove-N7ZPELFU.js → remove-T3KE6C5N.js} +10 -8
- package/dist/{remove-N7ZPELFU.js.map → remove-T3KE6C5N.js.map} +1 -1
- package/dist/{restart-ADG5GBTB.js → restart-YWDEVZUJ.js} +11 -9
- package/dist/{restart-ADG5GBTB.js.map → restart-YWDEVZUJ.js.map} +1 -1
- package/dist/{search-AHZEUNRR.js → search-GKFDGELR.js} +11 -9
- package/dist/{search-AHZEUNRR.js.map → search-GKFDGELR.js.map} +1 -1
- package/dist/{server-AGVYZVP5.js → server-AHUR6CWF.js} +368 -269
- package/dist/server-AHUR6CWF.js.map +1 -0
- package/dist/{session-6IU4AXYP.js → session-2ZEPLWW6.js} +11 -9
- package/dist/{session-6IU4AXYP.js.map → session-2ZEPLWW6.js.map} +1 -1
- package/dist/{session-end-FT27DWYZ.js → session-end-LWJYQAXX.js} +5 -5
- package/dist/session-start-WTA6GCOQ.js +134 -0
- package/dist/session-start-WTA6GCOQ.js.map +1 -0
- package/dist/{setup-llm-77MP4I2G.js → setup-llm-E7UU5IO7.js} +11 -9
- package/dist/{setup-llm-77MP4I2G.js.map → setup-llm-E7UU5IO7.js.map} +1 -1
- package/dist/src/agent/definitions/agent.yaml +9 -5
- package/dist/src/agent/definitions/tasks/cortex-instructions.yaml +93 -0
- package/dist/src/agent/definitions/tasks/cortex-prompt-builder.yaml +67 -0
- package/dist/src/agent/definitions/tasks/digest-only.yaml +1 -1
- package/dist/src/agent/definitions/tasks/extract-only.yaml +1 -1
- package/dist/src/agent/definitions/tasks/review-session.yaml +10 -39
- package/dist/src/agent/definitions/tasks/skill-evolve.yaml +4 -4
- package/dist/src/agent/definitions/tasks/skill-generate.yaml +1 -1
- package/dist/src/agent/definitions/tasks/skill-survey.yaml +2 -6
- package/dist/src/agent/definitions/tasks/supersession-sweep.yaml +1 -1
- package/dist/src/agent/definitions/tasks/title-summary.yaml +12 -19
- package/dist/src/agent/definitions/tasks/{full-intelligence.yaml → vault-evolve.yaml} +17 -82
- package/dist/src/agent/definitions/tasks/vault-seed.yaml +370 -0
- package/dist/src/agent/prompts/agent.md +12 -38
- package/dist/src/cli.js +1 -1
- package/dist/src/daemon/main.js +1 -1
- package/dist/src/hooks/post-tool-use.js +1 -1
- package/dist/src/hooks/session-end.js +1 -1
- package/dist/src/hooks/session-start.js +1 -1
- package/dist/src/hooks/stop.js +1 -1
- package/dist/src/hooks/user-prompt-submit.js +1 -1
- package/dist/src/mcp/server.js +1 -1
- package/dist/src/symbionts/manifests/claude-code.yaml +4 -0
- package/dist/src/symbionts/manifests/pi.yaml +22 -0
- package/dist/src/symbionts/templates/pi/package.json +6 -0
- package/dist/src/symbionts/templates/pi/plugin.ts +559 -0
- package/dist/{stats-NVPWOYTE.js → stats-DFG6S23S.js} +11 -9
- package/dist/{stats-NVPWOYTE.js.map → stats-DFG6S23S.js.map} +1 -1
- package/dist/{stop-ZPIKVLH4.js → stop-WRBTXEVT.js} +5 -5
- package/dist/{stop-failure-2PX67YJC.js → stop-failure-32MGIG2Q.js} +6 -6
- package/dist/{subagent-start-UUE6EHQD.js → subagent-start-VFGHQFVL.js} +6 -6
- package/dist/{subagent-stop-KQWWWPE6.js → subagent-stop-663FXG3P.js} +6 -6
- package/dist/{task-completed-WMHOFQ7B.js → task-completed-ZCQYEFMZ.js} +6 -6
- package/dist/{team-LRZ6GTQK.js → team-JTI5CDUO.js} +7 -5
- package/dist/{turns-YFNI5CQC.js → turns-HU2CTZAP.js} +2 -2
- package/dist/ui/assets/index-DGf1h-Ha.js +842 -0
- package/dist/ui/assets/index-_OP4ifzH.css +1 -0
- package/dist/ui/index.html +2 -2
- package/dist/{update-O6V4RC4W.js → update-3NBQTG32.js} +10 -8
- package/dist/{update-O6V4RC4W.js.map → update-3NBQTG32.js.map} +1 -1
- package/dist/{user-prompt-submit-N36KUPHI.js → user-prompt-submit-ME2TBKOS.js} +8 -7
- package/dist/{user-prompt-submit-N36KUPHI.js.map → user-prompt-submit-ME2TBKOS.js.map} +1 -1
- package/dist/{verify-LXPV7NYG.js → verify-R76ZFJSZ.js} +8 -5
- package/dist/{verify-LXPV7NYG.js.map → verify-R76ZFJSZ.js.map} +1 -1
- package/dist/{version-XMPPJQHR.js → version-GQAFBBPX.js} +2 -2
- package/dist/version-GQAFBBPX.js.map +1 -0
- package/package.json +3 -1
- package/skills/myco/SKILL.md +16 -1
- package/skills/myco/references/cli-usage.md +1 -1
- package/skills/myco-curate/SKILL.md +1 -1
- package/dist/chunk-4YFKBL3F.js +0 -195
- package/dist/chunk-4YFKBL3F.js.map +0 -1
- package/dist/chunk-CCRGY3QW.js.map +0 -1
- package/dist/chunk-EVDQKYCG.js.map +0 -1
- package/dist/chunk-FLLBJLHM.js.map +0 -1
- package/dist/chunk-MYOZLMB2.js.map +0 -1
- package/dist/chunk-OD4AA7PV.js.map +0 -1
- package/dist/chunk-US4LNCAT.js.map +0 -1
- package/dist/chunk-UYMFCYBF.js +0 -2326
- package/dist/chunk-UYMFCYBF.js.map +0 -1
- package/dist/chunk-VVNL26WX.js.map +0 -1
- package/dist/cli-GGPWH4UO.js.map +0 -1
- package/dist/doctor-5JXJ36KA.js.map +0 -1
- package/dist/executor-HWW2QNZQ.js +0 -2472
- package/dist/executor-HWW2QNZQ.js.map +0 -1
- package/dist/main-YTBVRTBI.js.map +0 -1
- package/dist/post-tool-use-POGPTJBA.js.map +0 -1
- package/dist/server-AGVYZVP5.js.map +0 -1
- package/dist/session-start-LAFICHII.js +0 -189
- package/dist/session-start-LAFICHII.js.map +0 -1
- package/dist/src/agent/definitions/tasks/graph-maintenance.yaml +0 -93
- package/dist/ui/assets/index-C2JuNtRB.css +0 -1
- package/dist/ui/assets/index-JLVaQKV2.js +0 -832
- /package/dist/{chunk-DCSGJ7W4.js.map → chunk-5ZG4RMUH.js.map} +0 -0
- /package/dist/{chunk-JZGN33AY.js.map → chunk-75Z7UKDY.js.map} +0 -0
- /package/dist/{chunk-XG5RRUYF.js.map → chunk-BUTL6IFS.js.map} +0 -0
- /package/dist/{chunk-KESLPBKV.js.map → chunk-JR54LTPP.js.map} +0 -0
- /package/dist/{chunk-5XIVBO25.js.map → chunk-LVIY7P35.js.map} +0 -0
- /package/dist/{chunk-BPRIYNLE.js.map → chunk-TKAJ3JVF.js.map} +0 -0
- /package/dist/{chunk-Q36VMZST.js.map → chunk-VHNRMM4O.js.map} +0 -0
- /package/dist/{client-YXQUTXVZ.js.map → client-NWE4TCNO.js.map} +0 -0
- /package/dist/{detect-providers-5KOPZ7J2.js.map → detect-providers-ILLQZROY.js.map} +0 -0
- /package/dist/{installer-FS257JRZ.js.map → executor-F2YU7HXJ.js.map} +0 -0
- /package/dist/{llm-TH4NLIRM.js.map → installer-UMH7OJ5A.js.map} +0 -0
- /package/dist/{loader-CQYTFHEW.js.map → llm-AGVEF5XD.js.map} +0 -0
- /package/dist/{loader-NOMBJUPW.js.map → loader-LX7TFRM6.js.map} +0 -0
- /package/dist/{provider-check-43LAMSMH.js.map → loader-NAVVZK63.js.map} +0 -0
- /package/dist/{post-compact-JSECI44W.js.map → post-compact-USAODKPQ.js.map} +0 -0
- /package/dist/{post-tool-use-failure-OT7BFWQW.js.map → post-tool-use-failure-NZVSL2PO.js.map} +0 -0
- /package/dist/{pre-compact-OXVODKH4.js.map → pre-compact-LZ57DLUS.js.map} +0 -0
- /package/dist/{registry-U4CHXK6R.js.map → provider-check-ZEV5P4KM.js.map} +0 -0
- /package/dist/{team-LRZ6GTQK.js.map → registry-M2Z5QBWH.js.map} +0 -0
- /package/dist/{session-end-FT27DWYZ.js.map → session-end-LWJYQAXX.js.map} +0 -0
- /package/dist/{stop-ZPIKVLH4.js.map → stop-WRBTXEVT.js.map} +0 -0
- /package/dist/{stop-failure-2PX67YJC.js.map → stop-failure-32MGIG2Q.js.map} +0 -0
- /package/dist/{subagent-start-UUE6EHQD.js.map → subagent-start-VFGHQFVL.js.map} +0 -0
- /package/dist/{subagent-stop-KQWWWPE6.js.map → subagent-stop-663FXG3P.js.map} +0 -0
- /package/dist/{task-completed-WMHOFQ7B.js.map → task-completed-ZCQYEFMZ.js.map} +0 -0
- /package/dist/{turns-YFNI5CQC.js.map → team-JTI5CDUO.js.map} +0 -0
- /package/dist/{version-XMPPJQHR.js.map → turns-HU2CTZAP.js.map} +0 -0
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import { createRequire as __cr } from 'node:module'; const require = __cr(import.meta.url);
|
|
2
|
+
import {
|
|
3
|
+
enumerateMatrixCells
|
|
4
|
+
} from "./chunk-54SXG5HF.js";
|
|
2
5
|
import {
|
|
3
6
|
DaemonLogger,
|
|
4
7
|
LEVEL_ORDER
|
|
5
8
|
} from "./chunk-3WOS4TAR.js";
|
|
6
9
|
import {
|
|
7
10
|
withTaskConfig
|
|
8
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-IPPMYQ2Y.js";
|
|
9
12
|
import {
|
|
10
13
|
EMBEDDABLE_TABLES,
|
|
11
14
|
EMBEDDABLE_TEXT_COLUMNS,
|
|
@@ -15,16 +18,19 @@ import {
|
|
|
15
18
|
getEmbeddingQueueDepth,
|
|
16
19
|
getUnembedded,
|
|
17
20
|
markEmbedded
|
|
18
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-75Z7UKDY.js";
|
|
19
22
|
import {
|
|
23
|
+
deleteSecrets,
|
|
20
24
|
getTeamPackageVersion,
|
|
21
25
|
loadSecrets,
|
|
22
26
|
readJsonConfig,
|
|
23
27
|
readSecrets,
|
|
24
28
|
resolveVaultConfigPath,
|
|
25
29
|
writeSecret
|
|
26
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-R2JIJBCL.js";
|
|
27
31
|
import {
|
|
32
|
+
DEFAULT_OPENAI_URL,
|
|
33
|
+
DEFAULT_OPENROUTER_URL,
|
|
28
34
|
SKILL_SURVEY_TASK,
|
|
29
35
|
buildTaskInstruction,
|
|
30
36
|
closeOpenBatches,
|
|
@@ -33,19 +39,24 @@ import {
|
|
|
33
39
|
countNotifications,
|
|
34
40
|
countRuns,
|
|
35
41
|
countSkillRecords,
|
|
42
|
+
countWriteIntents,
|
|
43
|
+
countWriteIntentsByTool,
|
|
44
|
+
countWriteIntentsByToolForEvaluation,
|
|
36
45
|
createBatchLineage,
|
|
46
|
+
createLocalOpenAIBackend,
|
|
37
47
|
deleteCandidate,
|
|
38
48
|
deleteSkillRecordCascade,
|
|
39
49
|
dismissAllNotifications,
|
|
40
|
-
errorMessage,
|
|
41
50
|
findBatchByPromptPrefix,
|
|
42
51
|
getAllDomains,
|
|
43
52
|
getCandidate,
|
|
44
|
-
getDigestExtract,
|
|
45
|
-
getEntity,
|
|
46
53
|
getGraphForNode,
|
|
47
54
|
getLatestBatch,
|
|
55
|
+
getLatestOpenBatch,
|
|
56
|
+
getLatestResumableRunForTask,
|
|
48
57
|
getLatestRunId,
|
|
58
|
+
getLocalOpenAIBackendDefaultBaseUrl,
|
|
59
|
+
getLocalOpenAIBackendLabel,
|
|
49
60
|
getNotification,
|
|
50
61
|
getRun,
|
|
51
62
|
getSkillRecord,
|
|
@@ -54,47 +65,56 @@ import {
|
|
|
54
65
|
hasConfiguredProvider,
|
|
55
66
|
incrementActivityCount,
|
|
56
67
|
incrementSkillUsageCount,
|
|
68
|
+
inferLocalOpenAIBackendKind,
|
|
57
69
|
insertBatchStateless,
|
|
58
70
|
insertResolutionEvent,
|
|
59
71
|
isInstructionRequiredTask,
|
|
60
72
|
listBatchesBySession,
|
|
61
73
|
listCandidatesWithCount,
|
|
62
|
-
listDigestExtracts,
|
|
63
|
-
listEntities,
|
|
64
74
|
listLineageForSkill,
|
|
65
75
|
listNotifications,
|
|
66
76
|
listReports,
|
|
67
77
|
listRuns,
|
|
78
|
+
listRunsForEvaluation,
|
|
68
79
|
listSkillRecords,
|
|
69
80
|
listSkillRecordsWithCount,
|
|
81
|
+
listWriteIntentTools,
|
|
82
|
+
listWriteIntents,
|
|
70
83
|
markAllRead,
|
|
84
|
+
markRunningRunsInterrupted,
|
|
71
85
|
notify,
|
|
72
86
|
populateBatchResponses,
|
|
73
87
|
register,
|
|
88
|
+
runAgent,
|
|
74
89
|
setResponseSummary,
|
|
90
|
+
tryParseJson,
|
|
75
91
|
updateCandidate,
|
|
76
92
|
updateNotificationStatus
|
|
77
|
-
} from "./chunk-
|
|
93
|
+
} from "./chunk-NGH7U6A3.js";
|
|
94
|
+
import {
|
|
95
|
+
errorMessage,
|
|
96
|
+
parseCheckpointState,
|
|
97
|
+
runDurationMs
|
|
98
|
+
} from "./chunk-6LB7XELY.js";
|
|
78
99
|
import {
|
|
79
100
|
fullTextSearch,
|
|
80
101
|
hydrateSearchResults
|
|
81
|
-
} from "./chunk-
|
|
102
|
+
} from "./chunk-LVIY7P35.js";
|
|
82
103
|
import {
|
|
83
104
|
copyTaskToUser,
|
|
84
105
|
deleteUserTask,
|
|
85
106
|
loadAllTasks,
|
|
86
107
|
validateTaskName,
|
|
87
108
|
writeUserTask
|
|
88
|
-
} from "./chunk-
|
|
109
|
+
} from "./chunk-ILJPRYES.js";
|
|
89
110
|
import {
|
|
90
|
-
AgentTaskSchema,
|
|
91
111
|
registerAgent,
|
|
92
112
|
resolveDefinitionsDir,
|
|
93
113
|
taskFromParsed
|
|
94
|
-
} from "./chunk-
|
|
114
|
+
} from "./chunk-JZS6GZ6T.js";
|
|
95
115
|
import {
|
|
96
116
|
listTurnsByRun
|
|
97
|
-
} from "./chunk-
|
|
117
|
+
} from "./chunk-FCJ5JV54.js";
|
|
98
118
|
import {
|
|
99
119
|
cleanupStagedSkill,
|
|
100
120
|
listStaleStagingDirs
|
|
@@ -102,7 +122,11 @@ import {
|
|
|
102
122
|
import {
|
|
103
123
|
Anthropic,
|
|
104
124
|
createEmbeddingProvider
|
|
105
|
-
} from "./chunk-
|
|
125
|
+
} from "./chunk-YDUOSRGD.js";
|
|
126
|
+
import {
|
|
127
|
+
OPENAI_API_KEY_ENV,
|
|
128
|
+
OPENROUTER_API_KEY_ENV
|
|
129
|
+
} from "./chunk-CISWUP5W.js";
|
|
106
130
|
import {
|
|
107
131
|
getMachineId
|
|
108
132
|
} from "./chunk-ENWBFX7F.js";
|
|
@@ -111,26 +135,42 @@ import {
|
|
|
111
135
|
cleanStaleBuffers,
|
|
112
136
|
listBufferSessionIds
|
|
113
137
|
} from "./chunk-V7XG6V6C.js";
|
|
114
|
-
import "./chunk-
|
|
115
|
-
import "./chunk-KESLPBKV.js";
|
|
138
|
+
import "./chunk-JR54LTPP.js";
|
|
116
139
|
import "./chunk-SAKJMNSR.js";
|
|
117
140
|
import {
|
|
118
141
|
SymbiontInstaller
|
|
119
|
-
} from "./chunk-
|
|
142
|
+
} from "./chunk-VHNRMM4O.js";
|
|
120
143
|
import {
|
|
121
144
|
checkLocalProvider
|
|
122
|
-
} from "./chunk-
|
|
145
|
+
} from "./chunk-TKAJ3JVF.js";
|
|
123
146
|
import {
|
|
124
147
|
LmStudioBackend,
|
|
125
148
|
OllamaBackend
|
|
126
|
-
} from "./chunk-
|
|
149
|
+
} from "./chunk-X3IGT5RV.js";
|
|
150
|
+
import {
|
|
151
|
+
composeSessionStartContext,
|
|
152
|
+
shouldInjectSessionStartDigest
|
|
153
|
+
} from "./chunk-DJ3IHNYO.js";
|
|
127
154
|
import {
|
|
155
|
+
buildCortexInstructionsInput,
|
|
128
156
|
countSpores,
|
|
157
|
+
deletePlan,
|
|
158
|
+
getCortexInstructions,
|
|
159
|
+
getPlan,
|
|
160
|
+
getPlanByLogicalKey,
|
|
129
161
|
getSpore,
|
|
130
162
|
insertSpore,
|
|
163
|
+
listDigestExtracts,
|
|
164
|
+
listDigestRevisions,
|
|
165
|
+
listPlans,
|
|
166
|
+
listPlansBySession,
|
|
131
167
|
listSpores,
|
|
132
|
-
|
|
133
|
-
|
|
168
|
+
resolveInstructionDelivery,
|
|
169
|
+
rollbackDigestExtract,
|
|
170
|
+
shouldInjectCortex,
|
|
171
|
+
updateSporeStatus,
|
|
172
|
+
upsertPlan
|
|
173
|
+
} from "./chunk-F3OEQYLS.js";
|
|
134
174
|
import {
|
|
135
175
|
backfillUnsynced,
|
|
136
176
|
closeSession,
|
|
@@ -153,20 +193,29 @@ import {
|
|
|
153
193
|
pruneOld,
|
|
154
194
|
reactivateSessionIfCompleted,
|
|
155
195
|
retryDeadLettered,
|
|
156
|
-
syncRow,
|
|
157
196
|
updateSession,
|
|
158
197
|
upsertSession
|
|
159
|
-
} from "./chunk-
|
|
198
|
+
} from "./chunk-RQSJLWP4.js";
|
|
160
199
|
import {
|
|
161
200
|
evaluateSessionCaptureRules,
|
|
162
201
|
readTranscriptMeta
|
|
163
202
|
} from "./chunk-XL75KZGI.js";
|
|
203
|
+
import {
|
|
204
|
+
PLAN_STATUSES
|
|
205
|
+
} from "./chunk-CESKJD44.js";
|
|
164
206
|
import {
|
|
165
207
|
EMBEDDING_DIMENSIONS,
|
|
166
208
|
REST_SETTABLE_STATUSES,
|
|
167
209
|
SCHEMA_VERSION,
|
|
168
|
-
|
|
169
|
-
|
|
210
|
+
TRANSCRIPT_SOURCE_PREFIX,
|
|
211
|
+
buildPathPlanLogicalKey,
|
|
212
|
+
buildPlanId,
|
|
213
|
+
buildSessionPlanLogicalKey,
|
|
214
|
+
buildSessionTagPlanLogicalKey,
|
|
215
|
+
createSchema,
|
|
216
|
+
humanizePlanToken,
|
|
217
|
+
normalizePlanSourcePath
|
|
218
|
+
} from "./chunk-RL5R4CQU.js";
|
|
170
219
|
import {
|
|
171
220
|
CONFIG_FILENAME,
|
|
172
221
|
MycoConfigSchema,
|
|
@@ -179,7 +228,11 @@ import {
|
|
|
179
228
|
updateConfig,
|
|
180
229
|
updateLocalConfig,
|
|
181
230
|
updateTeamConfig
|
|
182
|
-
} from "./chunk-
|
|
231
|
+
} from "./chunk-53RPGOEN.js";
|
|
232
|
+
import {
|
|
233
|
+
AgentTaskSchema
|
|
234
|
+
} from "./chunk-OUJSQSKE.js";
|
|
235
|
+
import "./chunk-POEPHBQK.js";
|
|
183
236
|
import {
|
|
184
237
|
closeDatabase,
|
|
185
238
|
getDatabase,
|
|
@@ -191,10 +244,10 @@ import {
|
|
|
191
244
|
} from "./chunk-ZXZPJJN3.js";
|
|
192
245
|
import {
|
|
193
246
|
resolveCliEntryPath
|
|
194
|
-
} from "./chunk-
|
|
247
|
+
} from "./chunk-P66DLD6G.js";
|
|
195
248
|
import {
|
|
196
249
|
getPluginVersion
|
|
197
|
-
} from "./chunk-
|
|
250
|
+
} from "./chunk-BUTL6IFS.js";
|
|
198
251
|
import {
|
|
199
252
|
loadManifests,
|
|
200
253
|
resolvePackageRoot
|
|
@@ -210,6 +263,7 @@ import {
|
|
|
210
263
|
DEFAULT_AGENT_ID,
|
|
211
264
|
DEFAULT_LIST_LIMIT,
|
|
212
265
|
DEFAULT_RELEASE_CHANNEL,
|
|
266
|
+
DEFAULT_SYMBIONT_NAME,
|
|
213
267
|
EMBEDDING_BATCH_SIZE,
|
|
214
268
|
EXCLUDED_SPORE_STATUSES,
|
|
215
269
|
FEED_DEFAULT_LIMIT,
|
|
@@ -243,8 +297,10 @@ import {
|
|
|
243
297
|
SYNC_PROTOCOL_VERSION,
|
|
244
298
|
TEAM_API_KEY_SECRET,
|
|
245
299
|
TEAM_HEALTH_TIMEOUT_MS,
|
|
300
|
+
TEAM_REQUEST_TIMEOUT_MS,
|
|
246
301
|
TEAM_SEARCH_TIMEOUT_MS,
|
|
247
302
|
TEAM_SOURCE_PREFIX,
|
|
303
|
+
TEAM_SYNC_TIMEOUT_MS,
|
|
248
304
|
UPDATE_CHECK_CACHE_PATH,
|
|
249
305
|
UPDATE_CHECK_INTERVAL_HOURS,
|
|
250
306
|
UPDATE_CONFIG_PATH,
|
|
@@ -257,7 +313,7 @@ import {
|
|
|
257
313
|
USER_TASK_SOURCE,
|
|
258
314
|
epochSeconds,
|
|
259
315
|
estimateTokens
|
|
260
|
-
} from "./chunk-
|
|
316
|
+
} from "./chunk-6C6QZ4PM.js";
|
|
261
317
|
import {
|
|
262
318
|
LOG_KINDS,
|
|
263
319
|
kindToComponent
|
|
@@ -428,13 +484,24 @@ var DaemonServer = class {
|
|
|
428
484
|
uptime: process.uptime()
|
|
429
485
|
}
|
|
430
486
|
}));
|
|
487
|
+
this.registerRoute("GET", "/api/version", async () => ({
|
|
488
|
+
body: { version: this.version }
|
|
489
|
+
}));
|
|
431
490
|
}
|
|
432
491
|
async handleRequest(req, res) {
|
|
433
492
|
const match = this.router.match(req.method, req.url);
|
|
434
493
|
if (match) {
|
|
494
|
+
const rejection = validateLoopbackRequest(req, this.port);
|
|
495
|
+
if (rejection) {
|
|
496
|
+
res.writeHead(rejection.status, { "Content-Type": "application/json" });
|
|
497
|
+
res.end(JSON.stringify({ error: rejection.error }));
|
|
498
|
+
return;
|
|
499
|
+
}
|
|
435
500
|
this.onRequest?.();
|
|
501
|
+
const versionHeader = { "X-Myco-Api-Version": this.version };
|
|
436
502
|
try {
|
|
437
|
-
const
|
|
503
|
+
const needsBody = req.method === "POST" || req.method === "PUT" || req.method === "PATCH" || req.method === "DELETE";
|
|
504
|
+
const body = needsBody ? await readBody(req) : void 0;
|
|
438
505
|
const result = await match.handler({
|
|
439
506
|
body,
|
|
440
507
|
query: match.query,
|
|
@@ -443,11 +510,11 @@ var DaemonServer = class {
|
|
|
443
510
|
});
|
|
444
511
|
const status = result.status ?? DEFAULT_STATUS;
|
|
445
512
|
if (Buffer.isBuffer(result.body)) {
|
|
446
|
-
res.writeHead(status, result.headers
|
|
513
|
+
res.writeHead(status, { ...versionHeader, ...result.headers });
|
|
447
514
|
res.end(result.body);
|
|
448
515
|
return;
|
|
449
516
|
}
|
|
450
|
-
const headers = { "Content-Type": "application/json", ...result.headers };
|
|
517
|
+
const headers = { "Content-Type": "application/json", ...versionHeader, ...result.headers };
|
|
451
518
|
res.writeHead(status, headers);
|
|
452
519
|
res.end(JSON.stringify(result.body));
|
|
453
520
|
} catch (error) {
|
|
@@ -455,7 +522,7 @@ var DaemonServer = class {
|
|
|
455
522
|
path: req.url,
|
|
456
523
|
error: error.message
|
|
457
524
|
});
|
|
458
|
-
res.writeHead(500, { "Content-Type": "application/json" });
|
|
525
|
+
res.writeHead(500, { "Content-Type": "application/json", ...versionHeader });
|
|
459
526
|
res.end(JSON.stringify({ error: error.message }));
|
|
460
527
|
}
|
|
461
528
|
return;
|
|
@@ -578,6 +645,36 @@ function readBody(req) {
|
|
|
578
645
|
req.on("error", reject);
|
|
579
646
|
});
|
|
580
647
|
}
|
|
648
|
+
function validateLoopbackRequest(req, port) {
|
|
649
|
+
const host = req.headers.host;
|
|
650
|
+
if (host && !isLoopbackHost(host, port)) {
|
|
651
|
+
return { status: 403, error: "forbidden_host" };
|
|
652
|
+
}
|
|
653
|
+
const origin = req.headers.origin;
|
|
654
|
+
if (origin && !isLoopbackOrigin(origin, port)) {
|
|
655
|
+
return { status: 403, error: "forbidden_origin" };
|
|
656
|
+
}
|
|
657
|
+
const method = (req.method ?? "").toUpperCase();
|
|
658
|
+
const isMutating = method === "POST" || method === "PUT" || method === "PATCH" || method === "DELETE";
|
|
659
|
+
if (!isMutating) return null;
|
|
660
|
+
const contentLengthHeader = req.headers["content-length"];
|
|
661
|
+
const contentLength = contentLengthHeader ? Number(contentLengthHeader) : NaN;
|
|
662
|
+
const hasBody = Number.isFinite(contentLength) ? contentLength > 0 : (req.headers["transfer-encoding"] ?? "").length > 0;
|
|
663
|
+
if (!hasBody) return null;
|
|
664
|
+
const contentType = (req.headers["content-type"] ?? "").toLowerCase();
|
|
665
|
+
if (!contentType.includes("application/json")) {
|
|
666
|
+
return { status: 415, error: "unsupported_media_type" };
|
|
667
|
+
}
|
|
668
|
+
return null;
|
|
669
|
+
}
|
|
670
|
+
function isLoopbackHost(host, port) {
|
|
671
|
+
const portStr = String(port);
|
|
672
|
+
return host === `127.0.0.1:${portStr}` || host === `localhost:${portStr}`;
|
|
673
|
+
}
|
|
674
|
+
function isLoopbackOrigin(origin, port) {
|
|
675
|
+
const portStr = String(port);
|
|
676
|
+
return origin === `http://127.0.0.1:${portStr}` || origin === `http://localhost:${portStr}`;
|
|
677
|
+
}
|
|
581
678
|
|
|
582
679
|
// src/daemon/lifecycle.ts
|
|
583
680
|
var SessionRegistry = class {
|
|
@@ -2599,7 +2696,7 @@ var TeamSyncClient = class _TeamSyncClient {
|
|
|
2599
2696
|
content_hash: data.content_hash ?? null
|
|
2600
2697
|
};
|
|
2601
2698
|
})
|
|
2602
|
-
});
|
|
2699
|
+
}, { timeoutMs: TEAM_SYNC_TIMEOUT_MS });
|
|
2603
2700
|
return res;
|
|
2604
2701
|
}
|
|
2605
2702
|
/**
|
|
@@ -2699,17 +2796,25 @@ var TeamSyncClient = class _TeamSyncClient {
|
|
|
2699
2796
|
"Content-Type": "application/json"
|
|
2700
2797
|
};
|
|
2701
2798
|
}
|
|
2702
|
-
async request(method,
|
|
2703
|
-
const
|
|
2704
|
-
|
|
2705
|
-
|
|
2706
|
-
|
|
2707
|
-
|
|
2708
|
-
|
|
2709
|
-
|
|
2710
|
-
|
|
2799
|
+
async request(method, path25, body, options = {}) {
|
|
2800
|
+
const timeoutMs = options.timeoutMs ?? TEAM_REQUEST_TIMEOUT_MS;
|
|
2801
|
+
const controller = new AbortController();
|
|
2802
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
2803
|
+
try {
|
|
2804
|
+
const res = await this.fetchFn(`${this.workerUrl}${path25}`, {
|
|
2805
|
+
method,
|
|
2806
|
+
headers: this.headers(),
|
|
2807
|
+
body: body !== void 0 ? JSON.stringify(body) : void 0,
|
|
2808
|
+
signal: controller.signal
|
|
2809
|
+
});
|
|
2810
|
+
if (!res.ok) {
|
|
2811
|
+
const text = await res.text().catch(() => "");
|
|
2812
|
+
throw new Error(`Team sync request ${method} ${path25} failed: ${res.status} ${text}`);
|
|
2813
|
+
}
|
|
2814
|
+
return res.json();
|
|
2815
|
+
} finally {
|
|
2816
|
+
clearTimeout(timer);
|
|
2711
2817
|
}
|
|
2712
|
-
return res.json();
|
|
2713
2818
|
}
|
|
2714
2819
|
};
|
|
2715
2820
|
|
|
@@ -2840,7 +2945,7 @@ function createTeamHandlers(deps) {
|
|
|
2840
2945
|
return { body: { retried: count } };
|
|
2841
2946
|
}
|
|
2842
2947
|
async function handleUpgradeWorker(_req) {
|
|
2843
|
-
const { upgradeWorker } = await import("./team-
|
|
2948
|
+
const { upgradeWorker } = await import("./team-JTI5CDUO.js");
|
|
2844
2949
|
logger.info("team-sync.upgrade.start", "Starting worker upgrade");
|
|
2845
2950
|
const result = upgradeWorker(vaultDir);
|
|
2846
2951
|
if (!result.success) {
|
|
@@ -3232,7 +3337,7 @@ function createSkillRecordDeleteHandler(deps) {
|
|
|
3232
3337
|
logger.warn(LOG_KINDS.PROCESSOR_BATCH, "Failed to remove skill directory", { name: record.name, error: String(err) });
|
|
3233
3338
|
}
|
|
3234
3339
|
try {
|
|
3235
|
-
const { syncSkillSymlinks } = await import("./installer-
|
|
3340
|
+
const { syncSkillSymlinks } = await import("./installer-UMH7OJ5A.js");
|
|
3236
3341
|
syncSkillSymlinks(projectRoot, record.name, { remove: true });
|
|
3237
3342
|
} catch (err) {
|
|
3238
3343
|
logger.warn(LOG_KINDS.PROCESSOR_BATCH, "Failed to remove skill symlinks", { name: record.name, error: String(err) });
|
|
@@ -3451,6 +3556,10 @@ async function handleGetProgress(tracker, token) {
|
|
|
3451
3556
|
|
|
3452
3557
|
// src/daemon/api/models.ts
|
|
3453
3558
|
var MODEL_LIST_TIMEOUT_MS = 5e3;
|
|
3559
|
+
var REMOTE_MODELS_ENDPOINT = "/models";
|
|
3560
|
+
var OPENAI_DEFAULT_BASE_URL = "https://api.openai.com/v1";
|
|
3561
|
+
var OPENROUTER_DEFAULT_BASE_URL = "https://openrouter.ai/api/v1";
|
|
3562
|
+
var REMOTE_PROVIDER_TIMEOUT_MS = 5e3;
|
|
3454
3563
|
var ANTHROPIC_MODELS = [
|
|
3455
3564
|
"claude-sonnet-4-6",
|
|
3456
3565
|
"claude-opus-4-6",
|
|
@@ -3476,22 +3585,60 @@ function filterLlmModels(models) {
|
|
|
3476
3585
|
return !EMBEDDING_PATTERNS.some((p) => name.includes(p));
|
|
3477
3586
|
});
|
|
3478
3587
|
}
|
|
3588
|
+
var REMOTE_PROVIDER_DEFAULTS = {
|
|
3589
|
+
openai: OPENAI_DEFAULT_BASE_URL,
|
|
3590
|
+
openrouter: OPENROUTER_DEFAULT_BASE_URL
|
|
3591
|
+
};
|
|
3592
|
+
var REMOTE_PROVIDER_ENV_VARS = {
|
|
3593
|
+
openai: OPENAI_API_KEY_ENV,
|
|
3594
|
+
openrouter: OPENROUTER_API_KEY_ENV
|
|
3595
|
+
};
|
|
3596
|
+
function getRemoteProviderApiKey(provider) {
|
|
3597
|
+
const preferredKey = process.env[REMOTE_PROVIDER_ENV_VARS[provider]];
|
|
3598
|
+
if (preferredKey) return preferredKey;
|
|
3599
|
+
if (provider === "openai") {
|
|
3600
|
+
return process.env.OPENAI_API_KEY;
|
|
3601
|
+
}
|
|
3602
|
+
return void 0;
|
|
3603
|
+
}
|
|
3604
|
+
async function fetchRemoteProviderModels(provider, _baseUrl, timeoutMs = REMOTE_PROVIDER_TIMEOUT_MS) {
|
|
3605
|
+
const apiKey = getRemoteProviderApiKey(provider);
|
|
3606
|
+
if (!apiKey) return [];
|
|
3607
|
+
const baseUrl = REMOTE_PROVIDER_DEFAULTS[provider];
|
|
3608
|
+
const response = await fetch(`${baseUrl}${REMOTE_MODELS_ENDPOINT}`, {
|
|
3609
|
+
headers: {
|
|
3610
|
+
Authorization: `Bearer ${apiKey}`
|
|
3611
|
+
},
|
|
3612
|
+
signal: AbortSignal.timeout(timeoutMs)
|
|
3613
|
+
});
|
|
3614
|
+
if (!response.ok) {
|
|
3615
|
+
throw new Error(`${provider} models request failed with ${response.status}`);
|
|
3616
|
+
}
|
|
3617
|
+
const data = await response.json();
|
|
3618
|
+
const modelIds = (data.data ?? []).map((entry) => entry.id).filter((id) => typeof id === "string" && id.length > 0);
|
|
3619
|
+
return filterLlmModels(modelIds);
|
|
3620
|
+
}
|
|
3479
3621
|
async function handleGetModels(req) {
|
|
3480
3622
|
const provider = req.query.provider;
|
|
3481
3623
|
const type = req.query.type;
|
|
3624
|
+
const localBackend = req.query.local_backend;
|
|
3482
3625
|
if (!provider) {
|
|
3483
3626
|
return { status: 400, body: { error: "provider query parameter required" } };
|
|
3484
3627
|
}
|
|
3485
3628
|
let models = [];
|
|
3486
3629
|
try {
|
|
3487
|
-
|
|
3488
|
-
|
|
3489
|
-
|
|
3490
|
-
|
|
3491
|
-
|
|
3630
|
+
const localBackendKind = inferLocalOpenAIBackendKind({
|
|
3631
|
+
type: provider === "lm-studio" ? "lmstudio" : provider,
|
|
3632
|
+
localBackend,
|
|
3633
|
+
baseUrl: req.query.base_url
|
|
3634
|
+
});
|
|
3635
|
+
if (localBackendKind) {
|
|
3636
|
+
const backend = createLocalOpenAIBackend(localBackendKind, req.query.base_url);
|
|
3492
3637
|
models = await backend.listModels(MODEL_LIST_TIMEOUT_MS);
|
|
3493
3638
|
} else if (provider === "anthropic") {
|
|
3494
3639
|
models = ANTHROPIC_MODELS;
|
|
3640
|
+
} else if (provider === "openai" || provider === "openrouter") {
|
|
3641
|
+
models = await fetchRemoteProviderModels(provider, void 0, MODEL_LIST_TIMEOUT_MS);
|
|
3495
3642
|
}
|
|
3496
3643
|
} catch {
|
|
3497
3644
|
}
|
|
@@ -3709,138 +3856,6 @@ function getAttachmentByFilePath(filePath) {
|
|
|
3709
3856
|
return row ? toAttachmentRow(row) : null;
|
|
3710
3857
|
}
|
|
3711
3858
|
|
|
3712
|
-
// src/db/queries/plans.ts
|
|
3713
|
-
var DEFAULT_LIST_LIMIT2 = 100;
|
|
3714
|
-
var DEFAULT_STATUS2 = "active";
|
|
3715
|
-
var DEFAULT_PROCESSED2 = 0;
|
|
3716
|
-
var PLAN_COLUMNS = [
|
|
3717
|
-
"id",
|
|
3718
|
-
"status",
|
|
3719
|
-
"author",
|
|
3720
|
-
"title",
|
|
3721
|
-
"content",
|
|
3722
|
-
"source_path",
|
|
3723
|
-
"tags",
|
|
3724
|
-
"session_id",
|
|
3725
|
-
"prompt_batch_id",
|
|
3726
|
-
"content_hash",
|
|
3727
|
-
"processed",
|
|
3728
|
-
"embedded",
|
|
3729
|
-
"created_at",
|
|
3730
|
-
"updated_at",
|
|
3731
|
-
"machine_id",
|
|
3732
|
-
"synced_at"
|
|
3733
|
-
];
|
|
3734
|
-
var SELECT_COLUMNS4 = PLAN_COLUMNS.join(", ");
|
|
3735
|
-
function toPlanRow(row) {
|
|
3736
|
-
return {
|
|
3737
|
-
id: row.id,
|
|
3738
|
-
status: row.status,
|
|
3739
|
-
author: row.author ?? null,
|
|
3740
|
-
title: row.title ?? null,
|
|
3741
|
-
content: row.content ?? null,
|
|
3742
|
-
source_path: row.source_path ?? null,
|
|
3743
|
-
tags: row.tags ?? null,
|
|
3744
|
-
session_id: row.session_id ?? null,
|
|
3745
|
-
prompt_batch_id: row.prompt_batch_id ?? null,
|
|
3746
|
-
content_hash: row.content_hash ?? null,
|
|
3747
|
-
processed: row.processed,
|
|
3748
|
-
embedded: row.embedded ?? 0,
|
|
3749
|
-
created_at: row.created_at,
|
|
3750
|
-
updated_at: row.updated_at ?? null,
|
|
3751
|
-
machine_id: row.machine_id ?? "local",
|
|
3752
|
-
synced_at: row.synced_at ?? null
|
|
3753
|
-
};
|
|
3754
|
-
}
|
|
3755
|
-
function upsertPlan(data) {
|
|
3756
|
-
const db = getDatabase();
|
|
3757
|
-
db.prepare(
|
|
3758
|
-
`INSERT INTO plans (
|
|
3759
|
-
id, status, author, title, content,
|
|
3760
|
-
source_path, tags, session_id, prompt_batch_id, content_hash,
|
|
3761
|
-
processed, created_at, updated_at, machine_id
|
|
3762
|
-
) VALUES (
|
|
3763
|
-
?, ?, ?, ?, ?,
|
|
3764
|
-
?, ?, ?, ?, ?,
|
|
3765
|
-
?, ?, ?, ?
|
|
3766
|
-
)
|
|
3767
|
-
ON CONFLICT (id) DO UPDATE SET
|
|
3768
|
-
status = EXCLUDED.status,
|
|
3769
|
-
author = EXCLUDED.author,
|
|
3770
|
-
title = EXCLUDED.title,
|
|
3771
|
-
content = EXCLUDED.content,
|
|
3772
|
-
source_path = EXCLUDED.source_path,
|
|
3773
|
-
tags = EXCLUDED.tags,
|
|
3774
|
-
session_id = EXCLUDED.session_id,
|
|
3775
|
-
prompt_batch_id = EXCLUDED.prompt_batch_id,
|
|
3776
|
-
content_hash = EXCLUDED.content_hash,
|
|
3777
|
-
processed = EXCLUDED.processed,
|
|
3778
|
-
updated_at = EXCLUDED.updated_at,
|
|
3779
|
-
embedded = CASE
|
|
3780
|
-
WHEN EXCLUDED.content_hash != plans.content_hash THEN 0
|
|
3781
|
-
ELSE plans.embedded
|
|
3782
|
-
END`
|
|
3783
|
-
).run(
|
|
3784
|
-
data.id,
|
|
3785
|
-
data.status ?? DEFAULT_STATUS2,
|
|
3786
|
-
data.author ?? null,
|
|
3787
|
-
data.title ?? null,
|
|
3788
|
-
data.content ?? null,
|
|
3789
|
-
data.source_path ?? null,
|
|
3790
|
-
data.tags ?? null,
|
|
3791
|
-
data.session_id ?? null,
|
|
3792
|
-
data.prompt_batch_id ?? null,
|
|
3793
|
-
data.content_hash ?? null,
|
|
3794
|
-
data.processed ?? DEFAULT_PROCESSED2,
|
|
3795
|
-
data.created_at,
|
|
3796
|
-
data.updated_at ?? null,
|
|
3797
|
-
data.machine_id ?? getTeamMachineId()
|
|
3798
|
-
);
|
|
3799
|
-
const row = toPlanRow(
|
|
3800
|
-
db.prepare(`SELECT ${SELECT_COLUMNS4} FROM plans WHERE id = ?`).get(data.id)
|
|
3801
|
-
);
|
|
3802
|
-
syncRow("plans", row);
|
|
3803
|
-
return row;
|
|
3804
|
-
}
|
|
3805
|
-
function getPlan(id) {
|
|
3806
|
-
const db = getDatabase();
|
|
3807
|
-
const row = db.prepare(
|
|
3808
|
-
`SELECT ${SELECT_COLUMNS4} FROM plans WHERE id = ?`
|
|
3809
|
-
).get(id);
|
|
3810
|
-
if (!row) return null;
|
|
3811
|
-
return toPlanRow(row);
|
|
3812
|
-
}
|
|
3813
|
-
function listPlans(options = {}) {
|
|
3814
|
-
const db = getDatabase();
|
|
3815
|
-
const conditions = [];
|
|
3816
|
-
const params = [];
|
|
3817
|
-
if (options.status !== void 0) {
|
|
3818
|
-
conditions.push(`status = ?`);
|
|
3819
|
-
params.push(options.status);
|
|
3820
|
-
}
|
|
3821
|
-
const where = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
3822
|
-
const limit = options.limit ?? DEFAULT_LIST_LIMIT2;
|
|
3823
|
-
params.push(limit);
|
|
3824
|
-
const rows = db.prepare(
|
|
3825
|
-
`SELECT ${SELECT_COLUMNS4}
|
|
3826
|
-
FROM plans
|
|
3827
|
-
${where}
|
|
3828
|
-
ORDER BY created_at DESC
|
|
3829
|
-
LIMIT ?`
|
|
3830
|
-
).all(...params);
|
|
3831
|
-
return rows.map(toPlanRow);
|
|
3832
|
-
}
|
|
3833
|
-
function listPlansBySession(sessionId) {
|
|
3834
|
-
const db = getDatabase();
|
|
3835
|
-
const rows = db.prepare(
|
|
3836
|
-
`SELECT ${SELECT_COLUMNS4}
|
|
3837
|
-
FROM plans
|
|
3838
|
-
WHERE session_id = ?
|
|
3839
|
-
ORDER BY created_at DESC`
|
|
3840
|
-
).all(sessionId);
|
|
3841
|
-
return rows.map(toPlanRow);
|
|
3842
|
-
}
|
|
3843
|
-
|
|
3844
3859
|
// src/daemon/jobs/session-cleanup.ts
|
|
3845
3860
|
import { unlink, glob } from "fs/promises";
|
|
3846
3861
|
async function cleanupAfterSessionCascade(sessionId, result, embeddingManager, vaultDir) {
|
|
@@ -3885,8 +3900,8 @@ async function triggerTitleSummary(sessionId, deps) {
|
|
|
3885
3900
|
if (config.agent.summary_batch_interval <= 0) return;
|
|
3886
3901
|
if (config.agent.event_tasks_enabled === false) return;
|
|
3887
3902
|
try {
|
|
3888
|
-
const { runAgent } = await import("./executor-
|
|
3889
|
-
|
|
3903
|
+
const { runAgent: runAgent2 } = await import("./executor-F2YU7HXJ.js");
|
|
3904
|
+
runAgent2(vaultDir, {
|
|
3890
3905
|
task: "title-summary",
|
|
3891
3906
|
instruction: `Process session ${sessionId} only`,
|
|
3892
3907
|
embeddingManager
|
|
@@ -3900,11 +3915,16 @@ async function triggerTitleSummary(sessionId, deps) {
|
|
|
3900
3915
|
}
|
|
3901
3916
|
}
|
|
3902
3917
|
|
|
3918
|
+
// src/daemon/api/error-envelope.ts
|
|
3919
|
+
function errorBody(code, message) {
|
|
3920
|
+
return { error: { code, message } };
|
|
3921
|
+
}
|
|
3922
|
+
|
|
3903
3923
|
// src/daemon/api/sessions.ts
|
|
3904
|
-
var
|
|
3924
|
+
var DEFAULT_LIST_LIMIT2 = 50;
|
|
3905
3925
|
var DEFAULT_LIST_OFFSET2 = 0;
|
|
3906
3926
|
async function handleListSessions(req) {
|
|
3907
|
-
const limit = req.query.limit ? Number(req.query.limit) :
|
|
3927
|
+
const limit = req.query.limit ? Number(req.query.limit) : DEFAULT_LIST_LIMIT2;
|
|
3908
3928
|
const offset = req.query.offset ? Number(req.query.offset) : DEFAULT_LIST_OFFSET2;
|
|
3909
3929
|
const status = req.query.status || void 0;
|
|
3910
3930
|
const agent = req.query.agent || void 0;
|
|
@@ -3947,7 +3967,7 @@ async function handleGetSessionAttachments(req) {
|
|
|
3947
3967
|
}
|
|
3948
3968
|
async function handleGetSessionPlans(req) {
|
|
3949
3969
|
const plans = listPlansBySession(req.params.id);
|
|
3950
|
-
return { body: plans };
|
|
3970
|
+
return { body: { plans } };
|
|
3951
3971
|
}
|
|
3952
3972
|
function createSessionMutationHandlers(deps) {
|
|
3953
3973
|
const { embeddingManager, vaultDir, logger, liveConfig } = deps;
|
|
@@ -3988,7 +4008,125 @@ function createSessionMutationHandlers(deps) {
|
|
|
3988
4008
|
const impact = getSessionImpact(sessionId);
|
|
3989
4009
|
return { body: impact };
|
|
3990
4010
|
}
|
|
3991
|
-
|
|
4011
|
+
async function handleDeletePlan(req) {
|
|
4012
|
+
const existing = getPlan(req.params.id);
|
|
4013
|
+
if (!existing) return { status: 404, body: errorBody("plan-not-found", "Plan not found") };
|
|
4014
|
+
const localMachineId = getTeamMachineId();
|
|
4015
|
+
const body = req.body;
|
|
4016
|
+
const forceRemote = body?.force_remote === true;
|
|
4017
|
+
if (existing.machine_id !== localMachineId && !forceRemote) {
|
|
4018
|
+
logger.warn(LOG_KINDS.API_SESSION_DELETE, "Cross-machine plan delete rejected", {
|
|
4019
|
+
plan_id: existing.id,
|
|
4020
|
+
plan_machine_id: existing.machine_id,
|
|
4021
|
+
local_machine_id: localMachineId
|
|
4022
|
+
});
|
|
4023
|
+
return {
|
|
4024
|
+
status: 403,
|
|
4025
|
+
body: errorBody(
|
|
4026
|
+
"cross-machine-delete",
|
|
4027
|
+
'Plan belongs to another machine; pass {"force_remote": true} to delete.'
|
|
4028
|
+
)
|
|
4029
|
+
};
|
|
4030
|
+
}
|
|
4031
|
+
if (existing.machine_id !== localMachineId && forceRemote) {
|
|
4032
|
+
logger.warn(LOG_KINDS.API_SESSION_DELETE, "Cross-machine plan delete allowed by force_remote", {
|
|
4033
|
+
plan_id: existing.id,
|
|
4034
|
+
plan_machine_id: existing.machine_id,
|
|
4035
|
+
local_machine_id: localMachineId
|
|
4036
|
+
});
|
|
4037
|
+
}
|
|
4038
|
+
const deleted = deletePlan(req.params.id);
|
|
4039
|
+
if (!deleted) return { status: 404, body: errorBody("plan-not-found", "Plan not found") };
|
|
4040
|
+
embeddingManager.onRemoved("plans", deleted.id);
|
|
4041
|
+
logger.info(LOG_KINDS.API_SESSION_DELETE, "Plan deleted", {
|
|
4042
|
+
plan_id: deleted.id,
|
|
4043
|
+
session_id: deleted.session_id,
|
|
4044
|
+
logical_key: deleted.logical_key
|
|
4045
|
+
});
|
|
4046
|
+
return {
|
|
4047
|
+
body: {
|
|
4048
|
+
ok: true,
|
|
4049
|
+
id: deleted.id,
|
|
4050
|
+
session_id: deleted.session_id
|
|
4051
|
+
}
|
|
4052
|
+
};
|
|
4053
|
+
}
|
|
4054
|
+
return { handleDeleteSession, handleCompleteSession, handleGetSessionImpact, handleDeletePlan };
|
|
4055
|
+
}
|
|
4056
|
+
|
|
4057
|
+
// src/db/queries/entities.ts
|
|
4058
|
+
var DEFAULT_LIST_LIMIT3 = 100;
|
|
4059
|
+
var ENTITY_COLUMNS = [
|
|
4060
|
+
"id",
|
|
4061
|
+
"agent_id",
|
|
4062
|
+
"type",
|
|
4063
|
+
"name",
|
|
4064
|
+
"properties",
|
|
4065
|
+
"first_seen",
|
|
4066
|
+
"last_seen",
|
|
4067
|
+
"status",
|
|
4068
|
+
"machine_id",
|
|
4069
|
+
"synced_at"
|
|
4070
|
+
];
|
|
4071
|
+
var SELECT_COLUMNS4 = ENTITY_COLUMNS.join(", ");
|
|
4072
|
+
function toEntityRow(row) {
|
|
4073
|
+
return {
|
|
4074
|
+
id: row.id,
|
|
4075
|
+
agent_id: row.agent_id,
|
|
4076
|
+
type: row.type,
|
|
4077
|
+
name: row.name,
|
|
4078
|
+
properties: row.properties ?? null,
|
|
4079
|
+
first_seen: row.first_seen,
|
|
4080
|
+
last_seen: row.last_seen,
|
|
4081
|
+
status: row.status ?? "active",
|
|
4082
|
+
machine_id: row.machine_id ?? "local",
|
|
4083
|
+
synced_at: row.synced_at ?? null
|
|
4084
|
+
};
|
|
4085
|
+
}
|
|
4086
|
+
function listEntities(options = {}) {
|
|
4087
|
+
const db = getDatabase();
|
|
4088
|
+
const conditions = [];
|
|
4089
|
+
const params = [];
|
|
4090
|
+
if (options.agent_id !== void 0) {
|
|
4091
|
+
conditions.push(`agent_id = ?`);
|
|
4092
|
+
params.push(options.agent_id);
|
|
4093
|
+
}
|
|
4094
|
+
if (options.type !== void 0) {
|
|
4095
|
+
conditions.push(`type = ?`);
|
|
4096
|
+
params.push(options.type);
|
|
4097
|
+
}
|
|
4098
|
+
if (options.name !== void 0) {
|
|
4099
|
+
conditions.push(`name = ?`);
|
|
4100
|
+
params.push(options.name);
|
|
4101
|
+
}
|
|
4102
|
+
if (options.status !== void 0) {
|
|
4103
|
+
conditions.push(`status = ?`);
|
|
4104
|
+
params.push(options.status);
|
|
4105
|
+
} else {
|
|
4106
|
+
conditions.push(`status = ?`);
|
|
4107
|
+
params.push("active");
|
|
4108
|
+
}
|
|
4109
|
+
if (options.mentioned_in !== void 0 && options.note_type !== void 0) {
|
|
4110
|
+
conditions.push(
|
|
4111
|
+
`id IN (SELECT entity_id FROM entity_mentions WHERE note_id = ? AND note_type = ?)`
|
|
4112
|
+
);
|
|
4113
|
+
params.push(options.mentioned_in);
|
|
4114
|
+
params.push(options.note_type);
|
|
4115
|
+
}
|
|
4116
|
+
const where = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
4117
|
+
const limit = options.limit ?? DEFAULT_LIST_LIMIT3;
|
|
4118
|
+
const offset = options.offset ?? 0;
|
|
4119
|
+
params.push(limit);
|
|
4120
|
+
params.push(offset);
|
|
4121
|
+
const rows = db.prepare(
|
|
4122
|
+
`SELECT ${SELECT_COLUMNS4}
|
|
4123
|
+
FROM entities
|
|
4124
|
+
${where}
|
|
4125
|
+
ORDER BY last_seen DESC
|
|
4126
|
+
LIMIT ?
|
|
4127
|
+
OFFSET ?`
|
|
4128
|
+
).all(...params);
|
|
4129
|
+
return rows.map(toEntityRow);
|
|
3992
4130
|
}
|
|
3993
4131
|
|
|
3994
4132
|
// src/daemon/api/mycelium.ts
|
|
@@ -3997,7 +4135,6 @@ var DEFAULT_LIST_OFFSET3 = 0;
|
|
|
3997
4135
|
var DEFAULT_GRAPH_DEPTH = 1;
|
|
3998
4136
|
var MAX_GRAPH_DEPTH = 3;
|
|
3999
4137
|
var SPORE_NAME_PREVIEW_CHARS = 60;
|
|
4000
|
-
var GRAPH_SEED_ENTITY_LIMIT = 4;
|
|
4001
4138
|
var GRAPH_SEED_SPORE_LIMIT = 4;
|
|
4002
4139
|
var GRAPH_SEED_SESSION_LIMIT = 4;
|
|
4003
4140
|
var EXCLUDED_GRAPH_EDGE_TYPES = /* @__PURE__ */ new Set(["HAS_BATCH", "EXTRACTED_FROM"]);
|
|
@@ -4056,15 +4193,6 @@ async function handleGetGraphSeeds(_req) {
|
|
|
4056
4193
|
ORDER BY started_at DESC
|
|
4057
4194
|
LIMIT ?`
|
|
4058
4195
|
).all(GRAPH_SEED_SESSION_LIMIT);
|
|
4059
|
-
const entityRows = db.prepare(
|
|
4060
|
-
`SELECT e.id, e.type, e.name, e.status, e.first_seen as created_at, COUNT(em.entity_id) as mention_count
|
|
4061
|
-
FROM entities e
|
|
4062
|
-
LEFT JOIN entity_mentions em ON em.entity_id = e.id
|
|
4063
|
-
WHERE e.agent_id = ? AND e.status = 'active'
|
|
4064
|
-
GROUP BY e.id
|
|
4065
|
-
ORDER BY mention_count DESC, e.last_seen DESC
|
|
4066
|
-
LIMIT ?`
|
|
4067
|
-
).all(DEFAULT_AGENT_ID, GRAPH_SEED_ENTITY_LIMIT);
|
|
4068
4196
|
const sporeSeeds = sporeRows.map((row) => ({
|
|
4069
4197
|
id: row.id,
|
|
4070
4198
|
name: (row.content ?? "").slice(0, SPORE_NAME_PREVIEW_CHARS),
|
|
@@ -4082,20 +4210,66 @@ async function handleGetGraphSeeds(_req) {
|
|
|
4082
4210
|
created_at: row.created_at,
|
|
4083
4211
|
content: row.summary ?? void 0
|
|
4084
4212
|
}));
|
|
4085
|
-
const
|
|
4086
|
-
|
|
4087
|
-
|
|
4088
|
-
|
|
4089
|
-
|
|
4090
|
-
|
|
4091
|
-
|
|
4092
|
-
|
|
4213
|
+
const topConnectedRow = db.prepare(
|
|
4214
|
+
`SELECT node_id FROM (
|
|
4215
|
+
SELECT source_id AS node_id, COUNT(*) AS cnt
|
|
4216
|
+
FROM graph_edges
|
|
4217
|
+
WHERE agent_id = ?
|
|
4218
|
+
AND type NOT IN ('HAS_BATCH', 'EXTRACTED_FROM')
|
|
4219
|
+
AND source_type IN ('spore', 'session')
|
|
4220
|
+
GROUP BY source_id
|
|
4221
|
+
UNION ALL
|
|
4222
|
+
SELECT target_id, COUNT(*)
|
|
4223
|
+
FROM graph_edges
|
|
4224
|
+
WHERE agent_id = ?
|
|
4225
|
+
AND type NOT IN ('HAS_BATCH', 'EXTRACTED_FROM')
|
|
4226
|
+
AND target_type IN ('spore', 'session')
|
|
4227
|
+
GROUP BY target_id
|
|
4228
|
+
)
|
|
4229
|
+
GROUP BY node_id
|
|
4230
|
+
ORDER BY SUM(cnt) DESC
|
|
4231
|
+
LIMIT 1`
|
|
4232
|
+
).get(DEFAULT_AGENT_ID, DEFAULT_AGENT_ID);
|
|
4233
|
+
let topSeed = null;
|
|
4234
|
+
if (topConnectedRow?.node_id) {
|
|
4235
|
+
const topId = topConnectedRow.node_id;
|
|
4236
|
+
const sporeHit = db.prepare(
|
|
4237
|
+
`SELECT id, observation_type, status, content, created_at
|
|
4238
|
+
FROM spores WHERE id = ?`
|
|
4239
|
+
).get(topId);
|
|
4240
|
+
if (sporeHit) {
|
|
4241
|
+
topSeed = {
|
|
4242
|
+
id: sporeHit.id,
|
|
4243
|
+
name: (sporeHit.content ?? "").slice(0, SPORE_NAME_PREVIEW_CHARS),
|
|
4244
|
+
type: "spore",
|
|
4245
|
+
status: sporeHit.status ?? void 0,
|
|
4246
|
+
created_at: sporeHit.created_at,
|
|
4247
|
+
content: sporeHit.content,
|
|
4248
|
+
observation_type: sporeHit.observation_type
|
|
4249
|
+
};
|
|
4250
|
+
} else {
|
|
4251
|
+
const sessionHit = db.prepare(
|
|
4252
|
+
`SELECT id, title, summary, status, started_at as created_at
|
|
4253
|
+
FROM sessions WHERE id = ?`
|
|
4254
|
+
).get(topId);
|
|
4255
|
+
if (sessionHit) {
|
|
4256
|
+
topSeed = {
|
|
4257
|
+
id: sessionHit.id,
|
|
4258
|
+
name: sessionHit.title ?? `Session ${sessionHit.id.slice(-6)}`,
|
|
4259
|
+
type: "session",
|
|
4260
|
+
status: sessionHit.status ?? void 0,
|
|
4261
|
+
created_at: sessionHit.created_at,
|
|
4262
|
+
content: sessionHit.summary ?? void 0
|
|
4263
|
+
};
|
|
4264
|
+
}
|
|
4265
|
+
}
|
|
4266
|
+
}
|
|
4093
4267
|
const seeds = [
|
|
4094
|
-
...
|
|
4095
|
-
...sessionSeeds,
|
|
4096
|
-
...sporeSeeds
|
|
4268
|
+
...topSeed ? [topSeed] : [],
|
|
4269
|
+
...sessionSeeds.filter((s) => s.id !== topSeed?.id),
|
|
4270
|
+
...sporeSeeds.filter((s) => s.id !== topSeed?.id)
|
|
4097
4271
|
];
|
|
4098
|
-
const recommendedId =
|
|
4272
|
+
const recommendedId = topSeed?.id ?? sessionSeeds[0]?.id ?? sporeSeeds[0]?.id ?? null;
|
|
4099
4273
|
return {
|
|
4100
4274
|
body: {
|
|
4101
4275
|
seeds,
|
|
@@ -4106,32 +4280,19 @@ async function handleGetGraphSeeds(_req) {
|
|
|
4106
4280
|
async function handleGetGraph(req) {
|
|
4107
4281
|
const depth = Math.min(Number(req.query.depth) || DEFAULT_GRAPH_DEPTH, MAX_GRAPH_DEPTH);
|
|
4108
4282
|
const id = req.params.id;
|
|
4109
|
-
let
|
|
4110
|
-
|
|
4111
|
-
|
|
4112
|
-
if (
|
|
4113
|
-
|
|
4114
|
-
centerType = "entity";
|
|
4283
|
+
let centerType;
|
|
4284
|
+
if (getSpore(id)) {
|
|
4285
|
+
centerType = "spore";
|
|
4286
|
+
} else if (getSession(id)) {
|
|
4287
|
+
centerType = "session";
|
|
4115
4288
|
} else {
|
|
4116
|
-
|
|
4117
|
-
if (spore) {
|
|
4118
|
-
centerNode = spore;
|
|
4119
|
-
centerType = "spore";
|
|
4120
|
-
} else {
|
|
4121
|
-
const session = getSession(id);
|
|
4122
|
-
if (session) {
|
|
4123
|
-
centerNode = session;
|
|
4124
|
-
centerType = "session";
|
|
4125
|
-
}
|
|
4126
|
-
}
|
|
4289
|
+
return { status: 404, body: { error: "not_found" } };
|
|
4127
4290
|
}
|
|
4128
|
-
if (!centerNode) return { status: 404, body: { error: "not_found" } };
|
|
4129
4291
|
const graph = getGraphForNode(id, centerType, { depth });
|
|
4130
4292
|
const filteredEdges = graph.edges.filter(
|
|
4131
4293
|
(e) => !EXCLUDED_GRAPH_EDGE_TYPES.has(e.type)
|
|
4132
4294
|
);
|
|
4133
4295
|
const graphDb = getDatabase();
|
|
4134
|
-
const entityIds = /* @__PURE__ */ new Set();
|
|
4135
4296
|
const sporeIds = /* @__PURE__ */ new Set();
|
|
4136
4297
|
const sessionIds = /* @__PURE__ */ new Set();
|
|
4137
4298
|
for (const edge of filteredEdges) {
|
|
@@ -4139,70 +4300,23 @@ async function handleGetGraph(req) {
|
|
|
4139
4300
|
[edge.source_id, edge.source_type],
|
|
4140
4301
|
[edge.target_id, edge.target_type]
|
|
4141
4302
|
]) {
|
|
4142
|
-
|
|
4143
|
-
|
|
4144
|
-
entityIds.add(nodeId);
|
|
4145
|
-
break;
|
|
4146
|
-
case "spore":
|
|
4147
|
-
sporeIds.add(nodeId);
|
|
4148
|
-
break;
|
|
4149
|
-
case "session":
|
|
4150
|
-
sessionIds.add(nodeId);
|
|
4151
|
-
break;
|
|
4152
|
-
}
|
|
4303
|
+
if (type === "spore") sporeIds.add(nodeId);
|
|
4304
|
+
else if (type === "session") sessionIds.add(nodeId);
|
|
4153
4305
|
}
|
|
4154
4306
|
}
|
|
4155
|
-
if (centerType === "entity") entityIds.add(id);
|
|
4156
4307
|
if (centerType === "spore") sporeIds.add(id);
|
|
4157
|
-
|
|
4158
|
-
const entityIdArray = Array.from(entityIds);
|
|
4159
|
-
let entityNodes = [];
|
|
4160
|
-
if (entityIdArray.length > 0) {
|
|
4161
|
-
const placeholders = entityIdArray.map(() => "?").join(", ");
|
|
4162
|
-
entityNodes = graphDb.prepare(
|
|
4163
|
-
`SELECT id, type, name, properties, status, first_seen as created_at
|
|
4164
|
-
FROM entities WHERE id IN (${placeholders})`
|
|
4165
|
-
).all(...entityIdArray);
|
|
4166
|
-
}
|
|
4308
|
+
else sessionIds.add(id);
|
|
4167
4309
|
const sporeIdArray = Array.from(sporeIds);
|
|
4168
|
-
|
|
4169
|
-
|
|
4170
|
-
|
|
4171
|
-
|
|
4172
|
-
`SELECT id, observation_type, status, content, properties, created_at
|
|
4173
|
-
FROM spores WHERE id IN (${placeholders})`
|
|
4174
|
-
).all(...sporeIdArray);
|
|
4175
|
-
}
|
|
4310
|
+
const sporeNodes = sporeIdArray.length > 0 ? graphDb.prepare(
|
|
4311
|
+
`SELECT id, observation_type, status, content, properties, created_at
|
|
4312
|
+
FROM spores WHERE id IN (${sporeIdArray.map(() => "?").join(", ")})`
|
|
4313
|
+
).all(...sporeIdArray) : [];
|
|
4176
4314
|
const sessionIdArray = Array.from(sessionIds);
|
|
4177
|
-
|
|
4178
|
-
|
|
4179
|
-
|
|
4180
|
-
|
|
4181
|
-
`SELECT id, title, summary, status, started_at as created_at
|
|
4182
|
-
FROM sessions WHERE id IN (${placeholders})`
|
|
4183
|
-
).all(...sessionIdArray);
|
|
4184
|
-
}
|
|
4185
|
-
const mentionCounts = /* @__PURE__ */ new Map();
|
|
4186
|
-
if (entityIdArray.length > 0) {
|
|
4187
|
-
const placeholders = entityIdArray.map(() => "?").join(", ");
|
|
4188
|
-
const mentionRows = graphDb.prepare(
|
|
4189
|
-
`SELECT entity_id, COUNT(*) as count FROM entity_mentions
|
|
4190
|
-
WHERE entity_id IN (${placeholders}) GROUP BY entity_id`
|
|
4191
|
-
).all(...entityIdArray);
|
|
4192
|
-
for (const row of mentionRows) {
|
|
4193
|
-
mentionCounts.set(row.entity_id, Number(row.count));
|
|
4194
|
-
}
|
|
4195
|
-
}
|
|
4315
|
+
const sessionNodes = sessionIdArray.length > 0 ? graphDb.prepare(
|
|
4316
|
+
`SELECT id, title, summary, status, started_at as created_at
|
|
4317
|
+
FROM sessions WHERE id IN (${sessionIdArray.map(() => "?").join(", ")})`
|
|
4318
|
+
).all(...sessionIdArray) : [];
|
|
4196
4319
|
const allNodes = [
|
|
4197
|
-
...entityNodes.map((n) => ({
|
|
4198
|
-
id: n.id,
|
|
4199
|
-
name: n.name,
|
|
4200
|
-
type: n.type,
|
|
4201
|
-
status: n.status ?? void 0,
|
|
4202
|
-
created_at: n.created_at,
|
|
4203
|
-
properties: n.properties ?? void 0,
|
|
4204
|
-
mention_count: mentionCounts.get(n.id) ?? 0
|
|
4205
|
-
})),
|
|
4206
4320
|
...sporeNodes.map((n) => ({
|
|
4207
4321
|
id: n.id,
|
|
4208
4322
|
name: (n.content ?? "").slice(0, SPORE_NAME_PREVIEW_CHARS),
|
|
@@ -4241,10 +4355,6 @@ async function handleGetGraph(req) {
|
|
|
4241
4355
|
var FULL_GRAPH_NODE_LIMIT = 500;
|
|
4242
4356
|
async function handleGetFullGraph(_req) {
|
|
4243
4357
|
const db = getDatabase();
|
|
4244
|
-
const entityRows = db.prepare(
|
|
4245
|
-
`SELECT id, type, name, properties, status, first_seen as created_at
|
|
4246
|
-
FROM entities WHERE agent_id = ? LIMIT ?`
|
|
4247
|
-
).all(DEFAULT_AGENT_ID, FULL_GRAPH_NODE_LIMIT);
|
|
4248
4358
|
const sporeRows = db.prepare(
|
|
4249
4359
|
`SELECT id, observation_type, status, content, properties, created_at
|
|
4250
4360
|
FROM spores WHERE agent_id = ? AND status = 'active' LIMIT ?`
|
|
@@ -4254,43 +4364,21 @@ async function handleGetFullGraph(_req) {
|
|
|
4254
4364
|
FROM sessions ORDER BY created_at DESC LIMIT ?`
|
|
4255
4365
|
).all(FULL_GRAPH_NODE_LIMIT);
|
|
4256
4366
|
const allIds = /* @__PURE__ */ new Set();
|
|
4257
|
-
for (const r of [...
|
|
4367
|
+
for (const r of [...sporeRows, ...sessionRows]) {
|
|
4258
4368
|
allIds.add(r.id);
|
|
4259
4369
|
}
|
|
4260
4370
|
const excludedTypes = Array.from(EXCLUDED_GRAPH_EDGE_TYPES).map(() => "?").join(", ");
|
|
4261
4371
|
const allIdsList = Array.from(allIds);
|
|
4262
4372
|
const idPlaceholders = allIdsList.map(() => "?").join(", ");
|
|
4263
|
-
const edgeRows = db.prepare(
|
|
4373
|
+
const edgeRows = allIdsList.length > 0 ? db.prepare(
|
|
4264
4374
|
`SELECT source_id, source_type, target_id, target_type, type, confidence
|
|
4265
|
-
|
|
4266
|
-
|
|
4267
|
-
|
|
4268
|
-
|
|
4269
|
-
|
|
4270
|
-
).all(DEFAULT_AGENT_ID, ...Array.from(EXCLUDED_GRAPH_EDGE_TYPES), ...allIdsList, ...allIdsList);
|
|
4271
|
-
const filteredEdges = edgeRows;
|
|
4272
|
-
const mentionCounts = /* @__PURE__ */ new Map();
|
|
4273
|
-
const entityIdArray = entityRows.map((r) => r.id);
|
|
4274
|
-
if (entityIdArray.length > 0) {
|
|
4275
|
-
const placeholders = entityIdArray.map(() => "?").join(", ");
|
|
4276
|
-
const mentionRows = db.prepare(
|
|
4277
|
-
`SELECT entity_id, COUNT(*) as count FROM entity_mentions
|
|
4278
|
-
WHERE entity_id IN (${placeholders}) GROUP BY entity_id`
|
|
4279
|
-
).all(...entityIdArray);
|
|
4280
|
-
for (const row of mentionRows) {
|
|
4281
|
-
mentionCounts.set(row.entity_id, Number(row.count));
|
|
4282
|
-
}
|
|
4283
|
-
}
|
|
4375
|
+
FROM graph_edges
|
|
4376
|
+
WHERE agent_id = ?
|
|
4377
|
+
AND type NOT IN (${excludedTypes})
|
|
4378
|
+
AND source_id IN (${idPlaceholders})
|
|
4379
|
+
AND target_id IN (${idPlaceholders})`
|
|
4380
|
+
).all(DEFAULT_AGENT_ID, ...Array.from(EXCLUDED_GRAPH_EDGE_TYPES), ...allIdsList, ...allIdsList) : [];
|
|
4284
4381
|
const nodes = [
|
|
4285
|
-
...entityRows.map((n) => ({
|
|
4286
|
-
id: n.id,
|
|
4287
|
-
name: n.name,
|
|
4288
|
-
type: n.type,
|
|
4289
|
-
status: n.status ?? void 0,
|
|
4290
|
-
created_at: n.created_at,
|
|
4291
|
-
properties: n.properties ?? void 0,
|
|
4292
|
-
mention_count: mentionCounts.get(n.id) ?? 0
|
|
4293
|
-
})),
|
|
4294
4382
|
...sporeRows.map((n) => ({
|
|
4295
4383
|
id: n.id,
|
|
4296
4384
|
name: (n.content ?? "").slice(0, SPORE_NAME_PREVIEW_CHARS),
|
|
@@ -4310,7 +4398,7 @@ async function handleGetFullGraph(_req) {
|
|
|
4310
4398
|
content: n.summary ?? void 0
|
|
4311
4399
|
}))
|
|
4312
4400
|
];
|
|
4313
|
-
const edges =
|
|
4401
|
+
const edges = edgeRows.map((e) => ({
|
|
4314
4402
|
source_id: e.source_id,
|
|
4315
4403
|
target_id: e.target_id,
|
|
4316
4404
|
label: e.type,
|
|
@@ -4393,75 +4481,305 @@ function createSearchHandler(deps) {
|
|
|
4393
4481
|
};
|
|
4394
4482
|
}
|
|
4395
4483
|
|
|
4396
|
-
// src/
|
|
4397
|
-
|
|
4398
|
-
|
|
4399
|
-
|
|
4400
|
-
|
|
4401
|
-
|
|
4402
|
-
|
|
4403
|
-
|
|
4404
|
-
|
|
4405
|
-
|
|
4406
|
-
|
|
4407
|
-
|
|
4408
|
-
|
|
4409
|
-
|
|
4410
|
-
|
|
4411
|
-
|
|
4412
|
-
|
|
4413
|
-
const { logger, liveConfig } = deps;
|
|
4414
|
-
const config = liveConfig.current;
|
|
4415
|
-
logger.debug(LOG_KINDS.CONTEXT_QUERY, "Session context query", { session_id });
|
|
4416
|
-
try {
|
|
4417
|
-
const parts = [];
|
|
4418
|
-
const tier = config.context.digest_tier;
|
|
4419
|
-
const extract = getDigestExtract(DEFAULT_AGENT_ID, tier);
|
|
4420
|
-
if (extract) {
|
|
4421
|
-
parts.push(extract.content);
|
|
4422
|
-
logger.info(LOG_KINDS.CONTEXT_DIGEST, "Digest extract found", {
|
|
4423
|
-
session_id,
|
|
4424
|
-
tier,
|
|
4425
|
-
content_length: extract.content.length,
|
|
4426
|
-
generated_at: extract.generated_at
|
|
4427
|
-
});
|
|
4428
|
-
} else {
|
|
4429
|
-
logger.debug(LOG_KINDS.CONTEXT_DIGEST, "No digest extract available", { session_id, tier });
|
|
4430
|
-
}
|
|
4431
|
-
if (branch) {
|
|
4432
|
-
parts.push(`Branch:: \`${branch}\``);
|
|
4433
|
-
}
|
|
4434
|
-
parts.push(`Session:: \`${session_id}\``);
|
|
4435
|
-
const source = extract ? "digest" : "basic";
|
|
4436
|
-
const contextText = parts.join("\n\n");
|
|
4437
|
-
const estimatedTokens = estimateTokens(contextText);
|
|
4438
|
-
logger.info(
|
|
4439
|
-
LOG_KINDS.CONTEXT_SESSION,
|
|
4440
|
-
`Session context: ${estimatedTokens} est. tokens, source=${source}${extract ? `, tier=${tier}` : ""}`,
|
|
4441
|
-
{
|
|
4442
|
-
session_id,
|
|
4443
|
-
source,
|
|
4444
|
-
tier: extract ? tier : void 0,
|
|
4445
|
-
text_length: contextText.length,
|
|
4446
|
-
estimated_tokens: estimatedTokens,
|
|
4447
|
-
generated_at: extract?.generated_at,
|
|
4448
|
-
injected_text: contextText
|
|
4449
|
-
}
|
|
4450
|
-
);
|
|
4451
|
-
return {
|
|
4452
|
-
body: {
|
|
4453
|
-
text: contextText,
|
|
4454
|
-
source,
|
|
4455
|
-
...extract ? { tier } : {}
|
|
4456
|
-
}
|
|
4457
|
-
};
|
|
4458
|
-
} catch (error) {
|
|
4459
|
-
logger.error(LOG_KINDS.CONTEXT_SESSION, "Session context failed", { error: error.message });
|
|
4460
|
-
return { body: { text: "" } };
|
|
4484
|
+
// src/symbionts/injection-support.ts
|
|
4485
|
+
import fs16 from "fs";
|
|
4486
|
+
import path17 from "path";
|
|
4487
|
+
var SESSION_START_SIGNALS = ["hook session-start", '"/context"', '"/context/resume"'];
|
|
4488
|
+
var PROMPT_SUBMIT_SIGNALS = ["hook user-prompt-submit", '"/context/prompt"'];
|
|
4489
|
+
function resolveTemplateCandidates(manifest) {
|
|
4490
|
+
const packageRoot = resolvePackageRoot();
|
|
4491
|
+
const templateFile = manifest.registration?.hooksFormat === "plugin-file" ? "plugin.ts" : "hooks.json";
|
|
4492
|
+
return [
|
|
4493
|
+
path17.join(packageRoot, "src", "symbionts", "templates", manifest.name, templateFile),
|
|
4494
|
+
path17.join(packageRoot, "dist", "src", "symbionts", "templates", manifest.name, templateFile)
|
|
4495
|
+
];
|
|
4496
|
+
}
|
|
4497
|
+
function readHooksTemplate(manifest) {
|
|
4498
|
+
for (const candidate of resolveTemplateCandidates(manifest)) {
|
|
4499
|
+
if (fs16.existsSync(candidate)) {
|
|
4500
|
+
return fs16.readFileSync(candidate, "utf-8");
|
|
4461
4501
|
}
|
|
4502
|
+
}
|
|
4503
|
+
return "";
|
|
4504
|
+
}
|
|
4505
|
+
function hasAnySignal(template, signals) {
|
|
4506
|
+
return signals.some((signal) => template.includes(signal));
|
|
4507
|
+
}
|
|
4508
|
+
function detectSymbiontInjectionSupport(manifest) {
|
|
4509
|
+
const template = readHooksTemplate(manifest);
|
|
4510
|
+
return {
|
|
4511
|
+
supportsSessionStartInjection: hasAnySignal(template, SESSION_START_SIGNALS),
|
|
4512
|
+
supportsPromptSubmitInjection: hasAnySignal(template, PROMPT_SUBMIT_SIGNALS)
|
|
4462
4513
|
};
|
|
4463
4514
|
}
|
|
4464
|
-
|
|
4515
|
+
|
|
4516
|
+
// src/daemon/api/symbionts.ts
|
|
4517
|
+
function listSymbiontInfos(vaultDir) {
|
|
4518
|
+
const manifests = loadManifests();
|
|
4519
|
+
let enabledNames = null;
|
|
4520
|
+
try {
|
|
4521
|
+
enabledNames = getEnabledSymbiontNames(loadMergedConfig(vaultDir));
|
|
4522
|
+
} catch {
|
|
4523
|
+
}
|
|
4524
|
+
return manifests.map((manifest) => ({
|
|
4525
|
+
name: manifest.name,
|
|
4526
|
+
displayName: manifest.displayName,
|
|
4527
|
+
binary: manifest.binary,
|
|
4528
|
+
enabled: enabledNames ? enabledNames.has(manifest.name) : true,
|
|
4529
|
+
...manifest.resumeCommand ? { resumeCommand: manifest.resumeCommand } : {},
|
|
4530
|
+
...detectSymbiontInjectionSupport(manifest)
|
|
4531
|
+
}));
|
|
4532
|
+
}
|
|
4533
|
+
async function handleListSymbionts(vaultDir) {
|
|
4534
|
+
return { body: { symbionts: listSymbiontInfos(vaultDir) } };
|
|
4535
|
+
}
|
|
4536
|
+
|
|
4537
|
+
// src/daemon/cortex.ts
|
|
4538
|
+
var CORTEX_PROMPT_BUILDER_TASK = "cortex-prompt-builder";
|
|
4539
|
+
var CORTEX_INSTRUCTIONS_TASK = "cortex-instructions";
|
|
4540
|
+
var JSON_INDENT = 2;
|
|
4541
|
+
function isCortexPromptBuilderDetails(value) {
|
|
4542
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
4543
|
+
}
|
|
4544
|
+
function getLatestReportForAction(runId, action) {
|
|
4545
|
+
const reports = listReports(runId);
|
|
4546
|
+
for (let i = reports.length - 1; i >= 0; i -= 1) {
|
|
4547
|
+
if (reports[i]?.action === action) return reports[i];
|
|
4548
|
+
}
|
|
4549
|
+
return void 0;
|
|
4550
|
+
}
|
|
4551
|
+
function getCortexInstructionsSnapshot(config) {
|
|
4552
|
+
const row = getCortexInstructions(DEFAULT_AGENT_ID);
|
|
4553
|
+
return {
|
|
4554
|
+
content: row?.content ?? "",
|
|
4555
|
+
generatedAt: row?.generated_at ?? null,
|
|
4556
|
+
sourceRunId: row?.source_run_id ?? null,
|
|
4557
|
+
enabled: config.context.cortex_enabled,
|
|
4558
|
+
stored: Boolean(row)
|
|
4559
|
+
};
|
|
4560
|
+
}
|
|
4561
|
+
function resolvePromptBuilderSymbiont(vaultDir, requestedName) {
|
|
4562
|
+
const enabledSymbionts = listSymbiontInfos(vaultDir).filter((symbiont) => symbiont.enabled);
|
|
4563
|
+
if (enabledSymbionts.length === 0) return null;
|
|
4564
|
+
if (!requestedName) return enabledSymbionts[0] ?? null;
|
|
4565
|
+
return enabledSymbionts.find((symbiont) => symbiont.name === requestedName) ?? null;
|
|
4566
|
+
}
|
|
4567
|
+
async function buildCortexPrompt(vaultDir, deps, goal, requestedSymbiont) {
|
|
4568
|
+
const targetSymbiont = resolvePromptBuilderSymbiont(vaultDir, requestedSymbiont);
|
|
4569
|
+
const delivery = resolveInstructionDelivery(deps.config.context, targetSymbiont);
|
|
4570
|
+
const instructions = delivery.inlineInstructions ? getCortexInstructions(DEFAULT_AGENT_ID) : null;
|
|
4571
|
+
const builderInstruction = [
|
|
4572
|
+
`Goal:
|
|
4573
|
+
${goal.trim()}`,
|
|
4574
|
+
"",
|
|
4575
|
+
"## Target symbiont",
|
|
4576
|
+
JSON.stringify(
|
|
4577
|
+
targetSymbiont ? {
|
|
4578
|
+
name: targetSymbiont.name,
|
|
4579
|
+
displayName: targetSymbiont.displayName,
|
|
4580
|
+
supportsSessionStartInjection: targetSymbiont.supportsSessionStartInjection,
|
|
4581
|
+
supportsPromptSubmitInjection: targetSymbiont.supportsPromptSubmitInjection
|
|
4582
|
+
} : null,
|
|
4583
|
+
null,
|
|
4584
|
+
JSON_INDENT
|
|
4585
|
+
),
|
|
4586
|
+
"",
|
|
4587
|
+
"## Delivery contract",
|
|
4588
|
+
JSON.stringify(
|
|
4589
|
+
{
|
|
4590
|
+
inline_instructions: delivery.inlineInstructions,
|
|
4591
|
+
reason: delivery.reason
|
|
4592
|
+
},
|
|
4593
|
+
null,
|
|
4594
|
+
JSON_INDENT
|
|
4595
|
+
),
|
|
4596
|
+
"",
|
|
4597
|
+
delivery.inlineInstructions ? [
|
|
4598
|
+
"## Current Cortex session-start instructions",
|
|
4599
|
+
instructions?.content || "No current Cortex instructions are available.",
|
|
4600
|
+
""
|
|
4601
|
+
].join("\n") : "## Current Cortex session-start instructions\nOmit them from the prompt because this symbiont receives session-start injection.\n"
|
|
4602
|
+
].join("\n");
|
|
4603
|
+
const resultPromise = runAgent(vaultDir, {
|
|
4604
|
+
task: CORTEX_PROMPT_BUILDER_TASK,
|
|
4605
|
+
agentId: DEFAULT_AGENT_ID,
|
|
4606
|
+
instruction: builderInstruction,
|
|
4607
|
+
embeddingManager: deps.embeddingManager
|
|
4608
|
+
});
|
|
4609
|
+
const runId = getLatestRunId(DEFAULT_AGENT_ID, CORTEX_PROMPT_BUILDER_TASK);
|
|
4610
|
+
const tracked = resultPromise.catch((err) => {
|
|
4611
|
+
deps.logger.warn(LOG_KINDS.AGENT_ERROR, "cortex-prompt-builder task failed", {
|
|
4612
|
+
run_id: runId ?? void 0,
|
|
4613
|
+
error: String(err)
|
|
4614
|
+
});
|
|
4615
|
+
});
|
|
4616
|
+
deps.registerInflightRun?.(tracked);
|
|
4617
|
+
return {
|
|
4618
|
+
started: true,
|
|
4619
|
+
runId,
|
|
4620
|
+
inlineInstructions: delivery.inlineInstructions,
|
|
4621
|
+
targetSymbiont
|
|
4622
|
+
};
|
|
4623
|
+
}
|
|
4624
|
+
function getCortexPromptResult(runId) {
|
|
4625
|
+
const run = getRun(runId);
|
|
4626
|
+
if (!run) return null;
|
|
4627
|
+
const reports = listReports(runId);
|
|
4628
|
+
const promptReport = getLatestReportForAction(runId, "cortex_prompt_builder");
|
|
4629
|
+
const details = tryParseJson(promptReport?.details, isCortexPromptBuilderDetails);
|
|
4630
|
+
return {
|
|
4631
|
+
runId,
|
|
4632
|
+
status: run.status,
|
|
4633
|
+
prompt: details?.prompt ?? "",
|
|
4634
|
+
reports: reports.map((report) => ({
|
|
4635
|
+
id: report.id,
|
|
4636
|
+
action: report.action,
|
|
4637
|
+
summary: report.summary,
|
|
4638
|
+
created_at: report.created_at
|
|
4639
|
+
})),
|
|
4640
|
+
error: run.error
|
|
4641
|
+
};
|
|
4642
|
+
}
|
|
4643
|
+
async function triggerCortexInstructions(deps) {
|
|
4644
|
+
const { vaultDir, embeddingManager, liveConfig, logger, getTeamClient } = deps;
|
|
4645
|
+
const loadExecutor = deps.loadExecutor ?? (() => import("./executor-F2YU7HXJ.js"));
|
|
4646
|
+
const config = liveConfig.current;
|
|
4647
|
+
if (config.agent.event_tasks_enabled === false) {
|
|
4648
|
+
return { started: false, reason: "event-tasks-disabled" };
|
|
4649
|
+
}
|
|
4650
|
+
if (!hasConfiguredProvider(config, CORTEX_INSTRUCTIONS_TASK)) {
|
|
4651
|
+
return { started: false, reason: "provider-not-configured" };
|
|
4652
|
+
}
|
|
4653
|
+
let runAgentFn;
|
|
4654
|
+
try {
|
|
4655
|
+
({ runAgent: runAgentFn } = await loadExecutor());
|
|
4656
|
+
} catch (err) {
|
|
4657
|
+
logger.warn(LOG_KINDS.AGENT_ERROR, "cortex-instructions: agent module unavailable", {
|
|
4658
|
+
error: String(err)
|
|
4659
|
+
});
|
|
4660
|
+
return {
|
|
4661
|
+
started: false,
|
|
4662
|
+
reason: "agent-module-unavailable",
|
|
4663
|
+
error: String(err)
|
|
4664
|
+
};
|
|
4665
|
+
}
|
|
4666
|
+
try {
|
|
4667
|
+
const built = await buildCortexInstructionsInput(config, getTeamClient);
|
|
4668
|
+
const resultPromise = runAgentFn(vaultDir, {
|
|
4669
|
+
task: CORTEX_INSTRUCTIONS_TASK,
|
|
4670
|
+
agentId: DEFAULT_AGENT_ID,
|
|
4671
|
+
instruction: built.instruction,
|
|
4672
|
+
runContext: { cortex_instruction_input_hash: built.inputHash },
|
|
4673
|
+
embeddingManager
|
|
4674
|
+
});
|
|
4675
|
+
const runId = getLatestRunId(DEFAULT_AGENT_ID, CORTEX_INSTRUCTIONS_TASK);
|
|
4676
|
+
const tracked = resultPromise.catch((err) => {
|
|
4677
|
+
logger.warn(LOG_KINDS.AGENT_ERROR, "Cortex instructions task failed", {
|
|
4678
|
+
error: String(err),
|
|
4679
|
+
run_id: runId ?? void 0
|
|
4680
|
+
});
|
|
4681
|
+
});
|
|
4682
|
+
deps.registerInflightRun?.(tracked);
|
|
4683
|
+
return { started: true, runId };
|
|
4684
|
+
} catch (err) {
|
|
4685
|
+
logger.warn(LOG_KINDS.AGENT_ERROR, "Failed to start cortex-instructions task", {
|
|
4686
|
+
error: String(err)
|
|
4687
|
+
});
|
|
4688
|
+
return {
|
|
4689
|
+
started: false,
|
|
4690
|
+
reason: "startup-failed",
|
|
4691
|
+
error: String(err)
|
|
4692
|
+
};
|
|
4693
|
+
}
|
|
4694
|
+
}
|
|
4695
|
+
|
|
4696
|
+
// src/daemon/api/context.ts
|
|
4697
|
+
var SessionContextBody = external_exports.object({
|
|
4698
|
+
session_id: external_exports.string().optional(),
|
|
4699
|
+
branch: external_exports.string().optional()
|
|
4700
|
+
});
|
|
4701
|
+
var ResumeContextBody = external_exports.object({
|
|
4702
|
+
session_id: external_exports.string(),
|
|
4703
|
+
parent_session_id: external_exports.string().optional(),
|
|
4704
|
+
branch: external_exports.string().optional()
|
|
4705
|
+
});
|
|
4706
|
+
var PromptContextBody = external_exports.object({
|
|
4707
|
+
prompt: external_exports.string(),
|
|
4708
|
+
session_id: external_exports.string().optional()
|
|
4709
|
+
});
|
|
4710
|
+
function createSessionContextHandler(deps) {
|
|
4711
|
+
return async function handleSessionContext(req) {
|
|
4712
|
+
const { session_id, branch } = SessionContextBody.parse(req.body);
|
|
4713
|
+
const { logger, liveConfig } = deps;
|
|
4714
|
+
const config = liveConfig.current;
|
|
4715
|
+
logger.debug(LOG_KINDS.CONTEXT_QUERY, "Session context query", { session_id });
|
|
4716
|
+
try {
|
|
4717
|
+
const cortexEnabled = shouldInjectCortex(config.context);
|
|
4718
|
+
const digestEnabled = shouldInjectSessionStartDigest(config.context);
|
|
4719
|
+
if (!cortexEnabled && !digestEnabled) {
|
|
4720
|
+
logger.debug(LOG_KINDS.CONTEXT_SESSION, "Session-start context disabled", { session_id });
|
|
4721
|
+
return { body: { text: "" } };
|
|
4722
|
+
}
|
|
4723
|
+
let sourceRunId = null;
|
|
4724
|
+
let cortexContent = "";
|
|
4725
|
+
if (cortexEnabled) {
|
|
4726
|
+
const snapshot = getCortexInstructionsSnapshot(config);
|
|
4727
|
+
if (snapshot.content) {
|
|
4728
|
+
cortexContent = snapshot.content;
|
|
4729
|
+
sourceRunId = snapshot.sourceRunId;
|
|
4730
|
+
} else {
|
|
4731
|
+
logger.debug(LOG_KINDS.CONTEXT_SESSION, "No stored Cortex instructions available for session start", {
|
|
4732
|
+
session_id
|
|
4733
|
+
});
|
|
4734
|
+
}
|
|
4735
|
+
}
|
|
4736
|
+
const composed = composeSessionStartContext(config, cortexContent);
|
|
4737
|
+
const textParts = composed.parts.map((p) => p.text);
|
|
4738
|
+
const sourceParts = composed.parts.map(
|
|
4739
|
+
(p) => p.kind === "cortex" ? "cortex" : `digest:${p.tier ?? config.context.digest_tier}`
|
|
4740
|
+
);
|
|
4741
|
+
if (digestEnabled && !composed.parts.some((p) => p.kind === "digest")) {
|
|
4742
|
+
logger.debug(LOG_KINDS.CONTEXT_SESSION, "No preferred digest extract available for session start", {
|
|
4743
|
+
session_id,
|
|
4744
|
+
preferred_tier: config.context.digest_tier
|
|
4745
|
+
});
|
|
4746
|
+
}
|
|
4747
|
+
if (textParts.length === 0) {
|
|
4748
|
+
return { body: { text: "" } };
|
|
4749
|
+
}
|
|
4750
|
+
if (branch) {
|
|
4751
|
+
textParts.push(`Branch:: \`${branch}\``);
|
|
4752
|
+
}
|
|
4753
|
+
textParts.push(`Session:: \`${session_id}\``);
|
|
4754
|
+
const source = sourceParts.join("+");
|
|
4755
|
+
const contextText = textParts.join("\n\n");
|
|
4756
|
+
const estimatedTokens = estimateTokens(contextText);
|
|
4757
|
+
logger.info(
|
|
4758
|
+
LOG_KINDS.CONTEXT_SESSION,
|
|
4759
|
+
`Session context: ${estimatedTokens} est. tokens, source=${source}`,
|
|
4760
|
+
{
|
|
4761
|
+
session_id,
|
|
4762
|
+
source,
|
|
4763
|
+
branch,
|
|
4764
|
+
source_run_id: sourceRunId,
|
|
4765
|
+
text_length: contextText.length,
|
|
4766
|
+
estimated_tokens: estimatedTokens,
|
|
4767
|
+
injected_text: contextText
|
|
4768
|
+
}
|
|
4769
|
+
);
|
|
4770
|
+
return {
|
|
4771
|
+
body: {
|
|
4772
|
+
text: contextText,
|
|
4773
|
+
source
|
|
4774
|
+
}
|
|
4775
|
+
};
|
|
4776
|
+
} catch (error) {
|
|
4777
|
+
logger.error(LOG_KINDS.CONTEXT_SESSION, "Session context failed", { error: error.message });
|
|
4778
|
+
return { body: { text: "" } };
|
|
4779
|
+
}
|
|
4780
|
+
};
|
|
4781
|
+
}
|
|
4782
|
+
function createResumeContextHandler(deps) {
|
|
4465
4783
|
return async function handleResumeContext(req) {
|
|
4466
4784
|
const { session_id, parent_session_id, branch } = ResumeContextBody.parse(req.body);
|
|
4467
4785
|
const { logger } = deps;
|
|
@@ -4557,9 +4875,7 @@ function createPromptContextHandler(deps) {
|
|
|
4557
4875
|
raw_results: vectorResults.length,
|
|
4558
4876
|
top_similarity: vectorResults[0]?.similarity
|
|
4559
4877
|
});
|
|
4560
|
-
if (vectorResults.length === 0) {
|
|
4561
|
-
return { body: { text: "" } };
|
|
4562
|
-
}
|
|
4878
|
+
if (vectorResults.length === 0) return { body: { text: "" } };
|
|
4563
4879
|
const eligible = vectorResults.filter(
|
|
4564
4880
|
(r) => !EXCLUDED_SPORE_STATUSES.has(r.metadata.status)
|
|
4565
4881
|
);
|
|
@@ -4570,20 +4886,22 @@ function createPromptContextHandler(deps) {
|
|
|
4570
4886
|
const topResults = eligible.slice(0, maxSpores);
|
|
4571
4887
|
const hydrated = hydrateSearchResults(topResults);
|
|
4572
4888
|
const spores = hydrated.filter((r) => r.type === "spore");
|
|
4573
|
-
if (spores.length === 0) {
|
|
4574
|
-
return { body: { text: "" } };
|
|
4575
|
-
}
|
|
4889
|
+
if (spores.length === 0) return { body: { text: "" } };
|
|
4576
4890
|
const text = formatSporeContext(spores);
|
|
4577
4891
|
const promptTokens = estimateTokens(text);
|
|
4578
4892
|
const titles = spores.map((s) => s.title);
|
|
4579
|
-
logger.info(
|
|
4580
|
-
|
|
4581
|
-
|
|
4582
|
-
|
|
4583
|
-
|
|
4584
|
-
|
|
4585
|
-
|
|
4586
|
-
|
|
4893
|
+
logger.info(
|
|
4894
|
+
LOG_KINDS.CONTEXT_PROMPT,
|
|
4895
|
+
`Prompt context: ${spores.length} spores [${titles.join(", ")}] (~${promptTokens} tokens)`,
|
|
4896
|
+
{
|
|
4897
|
+
session_id,
|
|
4898
|
+
spore_count: spores.length,
|
|
4899
|
+
spore_titles: titles,
|
|
4900
|
+
scores: spores.map((s) => s.score.toFixed(3)),
|
|
4901
|
+
estimated_tokens: promptTokens,
|
|
4902
|
+
injected_text: text
|
|
4903
|
+
}
|
|
4904
|
+
);
|
|
4587
4905
|
return { body: { text } };
|
|
4588
4906
|
};
|
|
4589
4907
|
}
|
|
@@ -4602,6 +4920,75 @@ function formatSporeContext(spores) {
|
|
|
4602
4920
|
return text === header ? "" : text;
|
|
4603
4921
|
}
|
|
4604
4922
|
|
|
4923
|
+
// src/daemon/api/cortex.ts
|
|
4924
|
+
var PromptBuilderBody = external_exports.object({
|
|
4925
|
+
goal: external_exports.string().trim().min(1),
|
|
4926
|
+
symbiont: external_exports.string().trim().optional()
|
|
4927
|
+
});
|
|
4928
|
+
var PromptBuilderStatusParams = external_exports.object({
|
|
4929
|
+
runId: external_exports.string().trim().min(1)
|
|
4930
|
+
});
|
|
4931
|
+
function createCortexHandlers(vaultDir, deps) {
|
|
4932
|
+
async function handleGetInstructions() {
|
|
4933
|
+
const snapshot = getCortexInstructionsSnapshot(deps.liveConfig.current);
|
|
4934
|
+
return { body: snapshot };
|
|
4935
|
+
}
|
|
4936
|
+
async function handleRefreshInstructions() {
|
|
4937
|
+
const result = await triggerCortexInstructions({
|
|
4938
|
+
vaultDir,
|
|
4939
|
+
embeddingManager: deps.embeddingManager,
|
|
4940
|
+
liveConfig: deps.liveConfig,
|
|
4941
|
+
logger: deps.logger,
|
|
4942
|
+
getTeamClient: deps.getTeamClient,
|
|
4943
|
+
registerInflightRun: deps.registerInflightRun
|
|
4944
|
+
});
|
|
4945
|
+
if (!result.started && (result.reason === "provider-not-configured" || result.reason === "event-tasks-disabled")) {
|
|
4946
|
+
return {
|
|
4947
|
+
status: 400,
|
|
4948
|
+
body: {
|
|
4949
|
+
...errorBody(
|
|
4950
|
+
result.reason,
|
|
4951
|
+
result.reason === "provider-not-configured" ? "No agent provider configured. Configure one in Settings." : "Event-driven tasks are disabled. Enable them in Settings."
|
|
4952
|
+
),
|
|
4953
|
+
started: false,
|
|
4954
|
+
reason: result.reason
|
|
4955
|
+
}
|
|
4956
|
+
};
|
|
4957
|
+
}
|
|
4958
|
+
return { body: result };
|
|
4959
|
+
}
|
|
4960
|
+
async function handleBuildPrompt(req) {
|
|
4961
|
+
const { goal, symbiont } = PromptBuilderBody.parse(req.body);
|
|
4962
|
+
const result = await buildCortexPrompt(
|
|
4963
|
+
vaultDir,
|
|
4964
|
+
{
|
|
4965
|
+
config: deps.liveConfig.current,
|
|
4966
|
+
embeddingManager: deps.embeddingManager,
|
|
4967
|
+
getTeamClient: deps.getTeamClient,
|
|
4968
|
+
logger: deps.logger,
|
|
4969
|
+
registerInflightRun: deps.registerInflightRun
|
|
4970
|
+
},
|
|
4971
|
+
goal,
|
|
4972
|
+
symbiont
|
|
4973
|
+
);
|
|
4974
|
+
return { body: result };
|
|
4975
|
+
}
|
|
4976
|
+
async function handleGetPromptResult(req) {
|
|
4977
|
+
const { runId } = PromptBuilderStatusParams.parse(req.params);
|
|
4978
|
+
const result = getCortexPromptResult(runId);
|
|
4979
|
+
if (!result) {
|
|
4980
|
+
return { status: 404, body: errorBody("run-not-found", "Run not found") };
|
|
4981
|
+
}
|
|
4982
|
+
return { body: result };
|
|
4983
|
+
}
|
|
4984
|
+
return {
|
|
4985
|
+
handleGetInstructions,
|
|
4986
|
+
handleRefreshInstructions,
|
|
4987
|
+
handleBuildPrompt,
|
|
4988
|
+
handleGetPromptResult
|
|
4989
|
+
};
|
|
4990
|
+
}
|
|
4991
|
+
|
|
4605
4992
|
// src/db/queries/feed.ts
|
|
4606
4993
|
function getActivityFeed(limit = FEED_DEFAULT_LIMIT) {
|
|
4607
4994
|
const db = getDatabase();
|
|
@@ -4640,24 +5027,6 @@ async function handleGetFeed(req) {
|
|
|
4640
5027
|
return { body: feed };
|
|
4641
5028
|
}
|
|
4642
5029
|
|
|
4643
|
-
// src/daemon/api/symbionts.ts
|
|
4644
|
-
async function handleListSymbionts(vaultDir) {
|
|
4645
|
-
const manifests = loadManifests();
|
|
4646
|
-
let enabledNames = null;
|
|
4647
|
-
try {
|
|
4648
|
-
enabledNames = getEnabledSymbiontNames(loadMergedConfig(vaultDir));
|
|
4649
|
-
} catch {
|
|
4650
|
-
}
|
|
4651
|
-
const symbionts = manifests.map((m) => ({
|
|
4652
|
-
name: m.name,
|
|
4653
|
-
displayName: m.displayName,
|
|
4654
|
-
binary: m.binary,
|
|
4655
|
-
enabled: enabledNames ? enabledNames.has(m.name) : true,
|
|
4656
|
-
...m.resumeCommand ? { resumeCommand: m.resumeCommand } : {}
|
|
4657
|
-
}));
|
|
4658
|
-
return { body: { symbionts } };
|
|
4659
|
-
}
|
|
4660
|
-
|
|
4661
5030
|
// src/daemon/api/embedding.ts
|
|
4662
5031
|
var EMBEDDING_STATUS_IDLE = "idle";
|
|
4663
5032
|
var EMBEDDING_STATUS_PENDING = "pending";
|
|
@@ -5661,17 +6030,17 @@ var SqliteRecordSource = class {
|
|
|
5661
6030
|
};
|
|
5662
6031
|
|
|
5663
6032
|
// src/daemon/database/manager.ts
|
|
5664
|
-
import
|
|
6033
|
+
import fs18 from "fs";
|
|
5665
6034
|
|
|
5666
6035
|
// src/db/queries/database.ts
|
|
5667
|
-
import
|
|
6036
|
+
import fs17 from "fs";
|
|
5668
6037
|
function pragmaScalar(name) {
|
|
5669
6038
|
const db = getDatabase();
|
|
5670
6039
|
return db.pragma(name, { simple: true });
|
|
5671
6040
|
}
|
|
5672
6041
|
function safeFileSize(filePath) {
|
|
5673
6042
|
try {
|
|
5674
|
-
return
|
|
6043
|
+
return fs17.statSync(filePath).size;
|
|
5675
6044
|
} catch (err) {
|
|
5676
6045
|
if (err.code === "ENOENT") return 0;
|
|
5677
6046
|
throw err;
|
|
@@ -5943,7 +6312,7 @@ var DatabaseMaintenanceManager = class {
|
|
|
5943
6312
|
}
|
|
5944
6313
|
async vacuum() {
|
|
5945
6314
|
const size_before = this.fileSize();
|
|
5946
|
-
const stats = await
|
|
6315
|
+
const stats = await fs18.promises.statfs(this.vaultDir);
|
|
5947
6316
|
const free_bytes = Number(stats.bavail) * Number(stats.bsize);
|
|
5948
6317
|
const required_bytes = size_before * VACUUM_FREE_SPACE_MULTIPLIER;
|
|
5949
6318
|
if (free_bytes < required_bytes) {
|
|
@@ -5991,7 +6360,7 @@ var DatabaseMaintenanceManager = class {
|
|
|
5991
6360
|
}
|
|
5992
6361
|
fileSize() {
|
|
5993
6362
|
try {
|
|
5994
|
-
return
|
|
6363
|
+
return fs18.statSync(this.dbPath).size;
|
|
5995
6364
|
} catch {
|
|
5996
6365
|
return 0;
|
|
5997
6366
|
}
|
|
@@ -6308,6 +6677,16 @@ async function handleUpdateTaskConfig(req, vaultDir) {
|
|
|
6308
6677
|
};
|
|
6309
6678
|
}
|
|
6310
6679
|
|
|
6680
|
+
// src/agent/types.ts
|
|
6681
|
+
var PROVIDER_TYPES = [
|
|
6682
|
+
"anthropic",
|
|
6683
|
+
"ollama",
|
|
6684
|
+
"lmstudio",
|
|
6685
|
+
"openai",
|
|
6686
|
+
"openrouter",
|
|
6687
|
+
"openai-compatible"
|
|
6688
|
+
];
|
|
6689
|
+
|
|
6311
6690
|
// src/daemon/api/providers.ts
|
|
6312
6691
|
var ANTHROPIC_MODELS_TIMEOUT_MS = 5e3;
|
|
6313
6692
|
var ANTHROPIC_MODELS_CACHE_TTL_MS = 10 * 60 * 1e3;
|
|
@@ -6315,33 +6694,79 @@ var anthropicModelsCache = null;
|
|
|
6315
6694
|
var HTTP_OK2 = 200;
|
|
6316
6695
|
var HTTP_BAD_REQUEST2 = 400;
|
|
6317
6696
|
async function handleGetProviders() {
|
|
6318
|
-
const
|
|
6319
|
-
|
|
6320
|
-
|
|
6321
|
-
|
|
6322
|
-
|
|
6697
|
+
const detectionPlan = [
|
|
6698
|
+
{
|
|
6699
|
+
detect: () => detectAnthropic(),
|
|
6700
|
+
fallback: { type: "anthropic", runtime: "claude-sdk", available: false, models: [] }
|
|
6701
|
+
},
|
|
6702
|
+
{
|
|
6703
|
+
detect: () => detectLocalProviderInfo("ollama", OllamaBackend.DEFAULT_BASE_URL),
|
|
6704
|
+
fallback: { type: "ollama", runtime: "claude-sdk", available: false, baseUrl: OllamaBackend.DEFAULT_BASE_URL, models: [] }
|
|
6705
|
+
},
|
|
6706
|
+
{
|
|
6707
|
+
detect: () => detectLocalProviderInfo("lmstudio", LmStudioBackend.DEFAULT_BASE_URL),
|
|
6708
|
+
fallback: { type: "lmstudio", runtime: "claude-sdk", available: false, baseUrl: LmStudioBackend.DEFAULT_BASE_URL, models: [] }
|
|
6709
|
+
},
|
|
6710
|
+
{
|
|
6711
|
+
detect: () => detectRemoteProviderInfo("openai", DEFAULT_OPENAI_URL),
|
|
6712
|
+
fallback: { type: "openai", runtime: "openai-agents", available: false, authConfigured: false, baseUrl: DEFAULT_OPENAI_URL, models: [] }
|
|
6713
|
+
},
|
|
6714
|
+
{
|
|
6715
|
+
detect: () => detectRemoteProviderInfo("openrouter", DEFAULT_OPENROUTER_URL),
|
|
6716
|
+
fallback: { type: "openrouter", runtime: "openai-agents", available: false, authConfigured: false, baseUrl: DEFAULT_OPENROUTER_URL, models: [] }
|
|
6717
|
+
},
|
|
6718
|
+
{
|
|
6719
|
+
detect: () => detectLocalProviderInfo("openai-compatible", LmStudioBackend.DEFAULT_BASE_URL),
|
|
6720
|
+
fallback: { type: "openai-compatible", runtime: "openai-agents", available: false, baseUrl: LmStudioBackend.DEFAULT_BASE_URL, models: [] }
|
|
6721
|
+
}
|
|
6722
|
+
];
|
|
6723
|
+
const results = await Promise.allSettled(detectionPlan.map((entry) => entry.detect()));
|
|
6323
6724
|
const providers = results.map(
|
|
6324
|
-
(
|
|
6725
|
+
(result, index) => result.status === "fulfilled" ? result.value : detectionPlan[index].fallback
|
|
6325
6726
|
);
|
|
6326
6727
|
return { status: HTTP_OK2, body: { providers } };
|
|
6327
6728
|
}
|
|
6729
|
+
var ProviderTestBody = external_exports.object({
|
|
6730
|
+
type: external_exports.enum(PROVIDER_TYPES),
|
|
6731
|
+
baseUrl: external_exports.string().optional(),
|
|
6732
|
+
/**
|
|
6733
|
+
* Deprecated: `base_url` is the legacy snake_case key. Accepted for one
|
|
6734
|
+
* release and then removed. Use `baseUrl` going forward.
|
|
6735
|
+
*/
|
|
6736
|
+
base_url: external_exports.string().optional(),
|
|
6737
|
+
local_backend: external_exports.enum(["ollama", "lmstudio"]).optional(),
|
|
6738
|
+
model: external_exports.string().optional()
|
|
6739
|
+
});
|
|
6328
6740
|
async function handleTestProvider(req) {
|
|
6329
|
-
const
|
|
6330
|
-
|
|
6331
|
-
if (!type || !["anthropic", "ollama", "lmstudio"].includes(type)) {
|
|
6741
|
+
const parse = ProviderTestBody.safeParse(req.body);
|
|
6742
|
+
if (!parse.success) {
|
|
6332
6743
|
return {
|
|
6333
6744
|
status: HTTP_BAD_REQUEST2,
|
|
6334
|
-
body: { error:
|
|
6745
|
+
body: { error: `type is required and must be one of: ${PROVIDER_TYPES.join(", ")}` }
|
|
6335
6746
|
};
|
|
6336
6747
|
}
|
|
6337
|
-
const
|
|
6748
|
+
const parsed = parse.data;
|
|
6749
|
+
if (parsed.base_url !== void 0 && parsed.baseUrl === void 0) {
|
|
6750
|
+
process.stderr.write(
|
|
6751
|
+
"[myco providers] POST /api/providers/test: base_url is deprecated; use baseUrl\n"
|
|
6752
|
+
);
|
|
6753
|
+
}
|
|
6754
|
+
const type = parsed.type;
|
|
6755
|
+
const baseUrl = parsed.baseUrl ?? parsed.base_url;
|
|
6756
|
+
const localBackend = parsed.local_backend;
|
|
6338
6757
|
const start = performance.now();
|
|
6339
6758
|
let result;
|
|
6340
6759
|
try {
|
|
6341
6760
|
if (type === "ollama") {
|
|
6342
|
-
result = await
|
|
6761
|
+
result = await testResolvedLocalProvider("ollama", baseUrl);
|
|
6343
6762
|
} else if (type === "lmstudio") {
|
|
6344
|
-
result = await
|
|
6763
|
+
result = await testResolvedLocalProvider("lmstudio", baseUrl);
|
|
6764
|
+
} else if (type === "openai-compatible") {
|
|
6765
|
+
result = await testResolvedLocalProvider("openai-compatible", baseUrl, localBackend);
|
|
6766
|
+
} else if (type === "openai") {
|
|
6767
|
+
result = await testRemoteProvider("openai", "OpenAI");
|
|
6768
|
+
} else if (type === "openrouter") {
|
|
6769
|
+
result = await testRemoteProvider("openrouter", "OpenRouter");
|
|
6345
6770
|
} else {
|
|
6346
6771
|
result = testAnthropic();
|
|
6347
6772
|
}
|
|
@@ -6354,15 +6779,21 @@ async function handleTestProvider(req) {
|
|
|
6354
6779
|
return { status: HTTP_OK2, body: result };
|
|
6355
6780
|
}
|
|
6356
6781
|
async function detectLocalProviderInfo(type, defaultBaseUrl) {
|
|
6357
|
-
const status = await checkLocalProvider(type);
|
|
6782
|
+
const status = await checkLocalProvider(type === "openai-compatible" ? "lmstudio" : type);
|
|
6358
6783
|
const variantFiltered = status.models.filter((m) => !/-ctx\d+/.test(m));
|
|
6359
6784
|
const models = filterLlmModels(variantFiltered);
|
|
6360
|
-
return {
|
|
6785
|
+
return {
|
|
6786
|
+
type,
|
|
6787
|
+
runtime: type === "openai-compatible" ? "openai-agents" : "claude-sdk",
|
|
6788
|
+
available: status.available,
|
|
6789
|
+
baseUrl: defaultBaseUrl,
|
|
6790
|
+
models
|
|
6791
|
+
};
|
|
6361
6792
|
}
|
|
6362
6793
|
async function detectAnthropic() {
|
|
6363
6794
|
const now = Date.now();
|
|
6364
6795
|
if (anthropicModelsCache && now - anthropicModelsCache.ts < ANTHROPIC_MODELS_CACHE_TTL_MS) {
|
|
6365
|
-
return { type: "anthropic", available: true, models: anthropicModelsCache.models };
|
|
6796
|
+
return { type: "anthropic", runtime: "claude-sdk", available: true, models: anthropicModelsCache.models };
|
|
6366
6797
|
}
|
|
6367
6798
|
let models = ANTHROPIC_MODELS;
|
|
6368
6799
|
try {
|
|
@@ -6378,7 +6809,28 @@ async function detectAnthropic() {
|
|
|
6378
6809
|
} catch {
|
|
6379
6810
|
}
|
|
6380
6811
|
anthropicModelsCache = { ts: now, models };
|
|
6381
|
-
return { type: "anthropic", available: true, models };
|
|
6812
|
+
return { type: "anthropic", runtime: "claude-sdk", available: true, models };
|
|
6813
|
+
}
|
|
6814
|
+
async function detectRemoteProviderInfo(type, baseUrl) {
|
|
6815
|
+
const authConfigured = Boolean(getRemoteProviderApiKey(type));
|
|
6816
|
+
let models = [];
|
|
6817
|
+
let available = false;
|
|
6818
|
+
if (authConfigured) {
|
|
6819
|
+
try {
|
|
6820
|
+
models = await fetchRemoteProviderModels(type, void 0, ANTHROPIC_MODELS_TIMEOUT_MS);
|
|
6821
|
+
available = true;
|
|
6822
|
+
} catch {
|
|
6823
|
+
available = false;
|
|
6824
|
+
}
|
|
6825
|
+
}
|
|
6826
|
+
return {
|
|
6827
|
+
type,
|
|
6828
|
+
runtime: "openai-agents",
|
|
6829
|
+
available,
|
|
6830
|
+
authConfigured,
|
|
6831
|
+
baseUrl,
|
|
6832
|
+
models
|
|
6833
|
+
};
|
|
6382
6834
|
}
|
|
6383
6835
|
async function testLocalProvider(backend, label, defaultBaseUrl, baseUrl) {
|
|
6384
6836
|
const available = await backend.isAvailable();
|
|
@@ -6387,9 +6839,114 @@ async function testLocalProvider(backend, label, defaultBaseUrl, baseUrl) {
|
|
|
6387
6839
|
}
|
|
6388
6840
|
return { ok: true };
|
|
6389
6841
|
}
|
|
6842
|
+
async function testResolvedLocalProvider(type, baseUrl, localBackend) {
|
|
6843
|
+
const kind = inferLocalOpenAIBackendKind({ type, localBackend, baseUrl }) ?? "lmstudio";
|
|
6844
|
+
const label = type === "openai-compatible" ? `OpenAI-compatible ${getLocalOpenAIBackendLabel(kind)} provider` : getLocalOpenAIBackendLabel(kind);
|
|
6845
|
+
return testLocalProvider(
|
|
6846
|
+
createLocalOpenAIBackend(kind, baseUrl),
|
|
6847
|
+
label,
|
|
6848
|
+
getLocalOpenAIBackendDefaultBaseUrl(kind),
|
|
6849
|
+
baseUrl
|
|
6850
|
+
);
|
|
6851
|
+
}
|
|
6390
6852
|
function testAnthropic() {
|
|
6391
6853
|
return { ok: true };
|
|
6392
6854
|
}
|
|
6855
|
+
async function testRemoteProvider(provider, label) {
|
|
6856
|
+
if (!getRemoteProviderApiKey(provider)) {
|
|
6857
|
+
return { ok: false, error: `${label} API key not configured in daemon secrets or environment` };
|
|
6858
|
+
}
|
|
6859
|
+
try {
|
|
6860
|
+
await fetchRemoteProviderModels(provider);
|
|
6861
|
+
return { ok: true };
|
|
6862
|
+
} catch (error) {
|
|
6863
|
+
return { ok: false, error: error instanceof Error ? error.message : `${label} connection failed` };
|
|
6864
|
+
}
|
|
6865
|
+
}
|
|
6866
|
+
|
|
6867
|
+
// src/daemon/api/provider-secrets.ts
|
|
6868
|
+
var SECRET_PREVIEW_PREFIX_CHARS = 8;
|
|
6869
|
+
var SECRET_PREVIEW_SUFFIX_CHARS = 4;
|
|
6870
|
+
var SECRET_ENV_BY_PROVIDER = {
|
|
6871
|
+
openai: OPENAI_API_KEY_ENV,
|
|
6872
|
+
openrouter: OPENROUTER_API_KEY_ENV
|
|
6873
|
+
};
|
|
6874
|
+
function isSecretProvider(value) {
|
|
6875
|
+
return value === "openai" || value === "openrouter";
|
|
6876
|
+
}
|
|
6877
|
+
function maskSecret(secret) {
|
|
6878
|
+
if (secret.length <= SECRET_PREVIEW_PREFIX_CHARS + SECRET_PREVIEW_SUFFIX_CHARS) {
|
|
6879
|
+
return "*".repeat(secret.length);
|
|
6880
|
+
}
|
|
6881
|
+
return `${secret.slice(0, SECRET_PREVIEW_PREFIX_CHARS)}${"*".repeat(secret.length - SECRET_PREVIEW_PREFIX_CHARS - SECRET_PREVIEW_SUFFIX_CHARS)}${secret.slice(-SECRET_PREVIEW_SUFFIX_CHARS)}`;
|
|
6882
|
+
}
|
|
6883
|
+
function buildSecretInfo(provider, storedSecrets) {
|
|
6884
|
+
const envKey = SECRET_ENV_BY_PROVIDER[provider];
|
|
6885
|
+
const storedValue = storedSecrets[envKey];
|
|
6886
|
+
const envValue = process.env[envKey];
|
|
6887
|
+
const effectiveValue = storedValue ?? envValue;
|
|
6888
|
+
return {
|
|
6889
|
+
configured: Boolean(effectiveValue),
|
|
6890
|
+
envKey,
|
|
6891
|
+
maskedValue: effectiveValue ? maskSecret(effectiveValue) : null,
|
|
6892
|
+
source: storedValue ? "vault" : envValue ? "env" : "none"
|
|
6893
|
+
};
|
|
6894
|
+
}
|
|
6895
|
+
function getSecretInfo(vaultDir, provider) {
|
|
6896
|
+
return buildSecretInfo(provider, readSecrets(vaultDir));
|
|
6897
|
+
}
|
|
6898
|
+
async function handleGetProviderSecrets(vaultDir) {
|
|
6899
|
+
const storedSecrets = readSecrets(vaultDir);
|
|
6900
|
+
return {
|
|
6901
|
+
body: {
|
|
6902
|
+
secrets: {
|
|
6903
|
+
openai: buildSecretInfo("openai", storedSecrets),
|
|
6904
|
+
openrouter: buildSecretInfo("openrouter", storedSecrets)
|
|
6905
|
+
}
|
|
6906
|
+
}
|
|
6907
|
+
};
|
|
6908
|
+
}
|
|
6909
|
+
async function handlePutProviderSecret(vaultDir, req) {
|
|
6910
|
+
const provider = req.params.provider;
|
|
6911
|
+
const body = req.body;
|
|
6912
|
+
if (!provider || !isSecretProvider(provider)) {
|
|
6913
|
+
return { status: 400, body: { error: "provider must be one of: openai, openrouter" } };
|
|
6914
|
+
}
|
|
6915
|
+
if (!body?.api_key?.trim()) {
|
|
6916
|
+
return { status: 400, body: { error: "api_key is required" } };
|
|
6917
|
+
}
|
|
6918
|
+
const envKey = SECRET_ENV_BY_PROVIDER[provider];
|
|
6919
|
+
const apiKey = body.api_key.trim();
|
|
6920
|
+
writeSecret(vaultDir, envKey, apiKey);
|
|
6921
|
+
process.env[envKey] = apiKey;
|
|
6922
|
+
if (provider === "openai") {
|
|
6923
|
+
process.env.OPENAI_API_KEY = apiKey;
|
|
6924
|
+
}
|
|
6925
|
+
return {
|
|
6926
|
+
body: {
|
|
6927
|
+
provider,
|
|
6928
|
+
secret: getSecretInfo(vaultDir, provider)
|
|
6929
|
+
}
|
|
6930
|
+
};
|
|
6931
|
+
}
|
|
6932
|
+
async function handleDeleteProviderSecret(vaultDir, req) {
|
|
6933
|
+
const provider = req.params.provider;
|
|
6934
|
+
if (!provider || !isSecretProvider(provider)) {
|
|
6935
|
+
return { status: 400, body: { error: "provider must be one of: openai, openrouter" } };
|
|
6936
|
+
}
|
|
6937
|
+
const envKey = SECRET_ENV_BY_PROVIDER[provider];
|
|
6938
|
+
deleteSecrets(vaultDir, [envKey]);
|
|
6939
|
+
delete process.env[envKey];
|
|
6940
|
+
if (provider === "openai") {
|
|
6941
|
+
delete process.env.OPENAI_API_KEY;
|
|
6942
|
+
}
|
|
6943
|
+
return {
|
|
6944
|
+
body: {
|
|
6945
|
+
provider,
|
|
6946
|
+
secret: getSecretInfo(vaultDir, provider)
|
|
6947
|
+
}
|
|
6948
|
+
};
|
|
6949
|
+
}
|
|
6393
6950
|
|
|
6394
6951
|
// src/daemon/task-scheduling.ts
|
|
6395
6952
|
import { resolve } from "path";
|
|
@@ -6442,7 +6999,7 @@ function buildScheduledJobs(tasks, configOverrides, context, initialLastRuns) {
|
|
|
6442
6999
|
// src/daemon/task-scheduling.ts
|
|
6443
7000
|
var SCHEDULED_JOB_PREFIX = "scheduled:";
|
|
6444
7001
|
async function registerScheduledTasks(powerManager, deps) {
|
|
6445
|
-
const { definitionsDir, vaultDir, embeddingManager, logger, liveConfig } = deps;
|
|
7002
|
+
const { definitionsDir, vaultDir, embeddingManager, logger, liveConfig, getTeamClient } = deps;
|
|
6446
7003
|
const runningTasks = /* @__PURE__ */ new Set();
|
|
6447
7004
|
if (!definitionsDir) {
|
|
6448
7005
|
logger.warn(LOG_KINDS.AGENT_ERROR, "Skipping dynamic task scheduling \u2014 definitions directory unavailable");
|
|
@@ -6452,7 +7009,7 @@ async function registerScheduledTasks(powerManager, deps) {
|
|
|
6452
7009
|
if (!lastEnabled) {
|
|
6453
7010
|
logger.info(LOG_KINDS.AGENT_RUN, "Scheduled agent tasks disabled (agent.scheduled_tasks_enabled: false) \u2014 jobs registered but will no-op until enabled");
|
|
6454
7011
|
}
|
|
6455
|
-
const { loadAllTasks: loadAllTasks2 } = await import("./registry-
|
|
7012
|
+
const { loadAllTasks: loadAllTasks2 } = await import("./registry-M2Z5QBWH.js");
|
|
6456
7013
|
const allTasks = Array.from(loadAllTasks2(definitionsDir, vaultDir).values());
|
|
6457
7014
|
const taskAgentMap = /* @__PURE__ */ new Map();
|
|
6458
7015
|
for (const task of allTasks) {
|
|
@@ -6488,10 +7045,33 @@ async function registerScheduledTasks(powerManager, deps) {
|
|
|
6488
7045
|
lastEnabled = enabled;
|
|
6489
7046
|
}
|
|
6490
7047
|
if (!enabled) return;
|
|
6491
|
-
const { runAgent } = await import("./executor-
|
|
7048
|
+
const { runAgent: runAgent2 } = await import("./executor-F2YU7HXJ.js");
|
|
7049
|
+
const resumableRun = getLatestResumableRunForTask(DEFAULT_AGENT_ID, taskName);
|
|
7050
|
+
if (resumableRun) {
|
|
7051
|
+
const resumed = await runAgent2(vaultDir, {
|
|
7052
|
+
agentId: DEFAULT_AGENT_ID,
|
|
7053
|
+
task: taskName,
|
|
7054
|
+
resumeRunId: resumableRun.id,
|
|
7055
|
+
resumeMode: "scheduled",
|
|
7056
|
+
embeddingManager
|
|
7057
|
+
});
|
|
7058
|
+
logger.info(LOG_KINDS.AGENT_RUN, `Scheduled task ${taskName} resumed`, {
|
|
7059
|
+
status: resumed.status,
|
|
7060
|
+
runId: resumed.runId
|
|
7061
|
+
});
|
|
7062
|
+
return;
|
|
7063
|
+
}
|
|
6492
7064
|
const taskConfig = config.agent.tasks?.[taskName];
|
|
6493
7065
|
const projectRoot = resolve(vaultDir, "..");
|
|
6494
|
-
const built = buildTaskInstruction(
|
|
7066
|
+
const built = await buildTaskInstruction(
|
|
7067
|
+
taskName,
|
|
7068
|
+
taskConfig?.params,
|
|
7069
|
+
taskAgentMap.get(taskName),
|
|
7070
|
+
projectRoot,
|
|
7071
|
+
embeddingManager,
|
|
7072
|
+
config,
|
|
7073
|
+
getTeamClient
|
|
7074
|
+
);
|
|
6495
7075
|
if (isInstructionRequiredTask(taskName) && !built) {
|
|
6496
7076
|
logger.info(
|
|
6497
7077
|
LOG_KINDS.AGENT_RUN,
|
|
@@ -6500,7 +7080,7 @@ async function registerScheduledTasks(powerManager, deps) {
|
|
|
6500
7080
|
);
|
|
6501
7081
|
return;
|
|
6502
7082
|
}
|
|
6503
|
-
const result = await
|
|
7083
|
+
const result = await runAgent2(vaultDir, {
|
|
6504
7084
|
task: taskName,
|
|
6505
7085
|
instruction: built?.instruction,
|
|
6506
7086
|
runContext: built?.context,
|
|
@@ -6527,7 +7107,7 @@ async function registerScheduledTasks(powerManager, deps) {
|
|
|
6527
7107
|
link: `/agent?run=${result.runId}`,
|
|
6528
7108
|
metadata: { taskName, runId: result.runId }
|
|
6529
7109
|
}, config);
|
|
6530
|
-
const { countToolCallsByRun } = await import("./turns-
|
|
7110
|
+
const { countToolCallsByRun } = await import("./turns-HU2CTZAP.js");
|
|
6531
7111
|
const counts = countToolCallsByRun(result.runId, ["vault_create_spore", "vault_write_digest"]);
|
|
6532
7112
|
const sporeCount = counts["vault_create_spore"] ?? 0;
|
|
6533
7113
|
const digestCount = counts["vault_write_digest"] ?? 0;
|
|
@@ -6602,32 +7182,171 @@ function listTeamMembers() {
|
|
|
6602
7182
|
).all();
|
|
6603
7183
|
}
|
|
6604
7184
|
|
|
6605
|
-
// src/daemon/
|
|
6606
|
-
|
|
6607
|
-
|
|
6608
|
-
|
|
6609
|
-
|
|
6610
|
-
|
|
6611
|
-
|
|
6612
|
-
|
|
6613
|
-
|
|
6614
|
-
|
|
6615
|
-
|
|
6616
|
-
|
|
6617
|
-
|
|
6618
|
-
}
|
|
6619
|
-
|
|
6620
|
-
|
|
6621
|
-
|
|
6622
|
-
|
|
6623
|
-
|
|
6624
|
-
|
|
6625
|
-
|
|
6626
|
-
|
|
6627
|
-
|
|
6628
|
-
|
|
6629
|
-
|
|
6630
|
-
|
|
7185
|
+
// src/daemon/plan-capture.ts
|
|
7186
|
+
import { createHash as createHash4 } from "crypto";
|
|
7187
|
+
import os8 from "os";
|
|
7188
|
+
import path18 from "path";
|
|
7189
|
+
function extractTaggedPlans(text, tags) {
|
|
7190
|
+
const results = [];
|
|
7191
|
+
for (const tag of tags) {
|
|
7192
|
+
const regex = new RegExp(`<${tag}>\\n?([\\s\\S]*?)\\n?</${tag}>`, "g");
|
|
7193
|
+
let match;
|
|
7194
|
+
while ((match = regex.exec(text)) !== null) {
|
|
7195
|
+
const content = match[1].trim();
|
|
7196
|
+
if (content) results.push({ tag, content });
|
|
7197
|
+
}
|
|
7198
|
+
}
|
|
7199
|
+
return results;
|
|
7200
|
+
}
|
|
7201
|
+
var FILE_WRITE_TOOLS = /* @__PURE__ */ new Set([
|
|
7202
|
+
"Write",
|
|
7203
|
+
"Edit",
|
|
7204
|
+
"Create",
|
|
7205
|
+
"write",
|
|
7206
|
+
"edit",
|
|
7207
|
+
"patch",
|
|
7208
|
+
"create"
|
|
7209
|
+
]);
|
|
7210
|
+
var HEADING_REGEX = /^#\s+(.+)$/m;
|
|
7211
|
+
var TRANSCRIPT_SOURCE_TITLE_PREFIX = `${TRANSCRIPT_SOURCE_PREFIX}`;
|
|
7212
|
+
function resolvePlanWatchDir(watchDir, projectRoot) {
|
|
7213
|
+
const expanded = watchDir.startsWith("~/") ? path18.join(os8.homedir(), watchDir.slice(2)) : watchDir;
|
|
7214
|
+
return path18.isAbsolute(expanded) ? expanded : path18.resolve(projectRoot, expanded);
|
|
7215
|
+
}
|
|
7216
|
+
function isInPlanDirectory(filePath, watchDirs, projectRoot) {
|
|
7217
|
+
const abs = path18.isAbsolute(filePath) ? filePath : path18.resolve(projectRoot, filePath);
|
|
7218
|
+
return watchDirs.some((dir) => {
|
|
7219
|
+
const absDir = resolvePlanWatchDir(dir, projectRoot);
|
|
7220
|
+
const prefix = absDir.endsWith(path18.sep) ? absDir : absDir + path18.sep;
|
|
7221
|
+
return abs === absDir || abs.startsWith(prefix);
|
|
7222
|
+
});
|
|
7223
|
+
}
|
|
7224
|
+
function isPlanWriteEvent(toolName, toolInput, config) {
|
|
7225
|
+
if (!FILE_WRITE_TOOLS.has(toolName)) return null;
|
|
7226
|
+
const filePath = toolInput?.file_path ?? toolInput?.path ?? toolInput?.filePath;
|
|
7227
|
+
if (typeof filePath !== "string") return null;
|
|
7228
|
+
if (!isInPlanDirectory(filePath, config.watchDirs, config.projectRoot)) return null;
|
|
7229
|
+
if (config.extensions?.length) {
|
|
7230
|
+
const ext = path18.extname(filePath).toLowerCase();
|
|
7231
|
+
if (!config.extensions.includes(ext)) return null;
|
|
7232
|
+
}
|
|
7233
|
+
return filePath;
|
|
7234
|
+
}
|
|
7235
|
+
function parsePlanTitle(content, filename) {
|
|
7236
|
+
const match = HEADING_REGEX.exec(content);
|
|
7237
|
+
if (match) return match[1].trim();
|
|
7238
|
+
return filename ?? null;
|
|
7239
|
+
}
|
|
7240
|
+
function normalizePlanTags(tags) {
|
|
7241
|
+
if (tags === void 0 || tags === null) return null;
|
|
7242
|
+
return Array.isArray(tags) ? tags.join(", ") : tags;
|
|
7243
|
+
}
|
|
7244
|
+
function fileTitleFromSourcePath(sourcePath) {
|
|
7245
|
+
if (!sourcePath || sourcePath.startsWith(TRANSCRIPT_SOURCE_TITLE_PREFIX)) return null;
|
|
7246
|
+
return path18.basename(sourcePath);
|
|
7247
|
+
}
|
|
7248
|
+
function resolvePlanTitle(input) {
|
|
7249
|
+
const explicitTitle = input.title?.trim();
|
|
7250
|
+
if (explicitTitle) return explicitTitle;
|
|
7251
|
+
const headingTitle = parsePlanTitle(input.content);
|
|
7252
|
+
if (headingTitle) return headingTitle;
|
|
7253
|
+
const sourcePathTitle = fileTitleFromSourcePath(input.sourcePath);
|
|
7254
|
+
if (sourcePathTitle) return sourcePathTitle;
|
|
7255
|
+
return input.planKey ? humanizePlanToken(input.planKey) : null;
|
|
7256
|
+
}
|
|
7257
|
+
function persistPlan(input) {
|
|
7258
|
+
const createdAt = input.createdAt ?? Math.floor(Date.now() / 1e3);
|
|
7259
|
+
const updatedAt = input.updatedAt ?? createdAt;
|
|
7260
|
+
const contentHash = createHash4(CONTENT_HASH_ALGORITHM).update(input.content).digest("hex");
|
|
7261
|
+
const existingPlan = getPlanByLogicalKey(input.logicalKey);
|
|
7262
|
+
const status = input.status ?? existingPlan?.status ?? "active";
|
|
7263
|
+
const promptBatchId = input.promptBatchId === void 0 ? existingPlan?.prompt_batch_id ?? null : input.promptBatchId;
|
|
7264
|
+
const resolvedTitle = resolvePlanTitle({
|
|
7265
|
+
content: input.content,
|
|
7266
|
+
title: input.title,
|
|
7267
|
+
sourcePath: input.sourcePath,
|
|
7268
|
+
planKey: input.planKey
|
|
7269
|
+
});
|
|
7270
|
+
if (existingPlan && existingPlan.content_hash === contentHash && existingPlan.title === resolvedTitle && existingPlan.status === status) {
|
|
7271
|
+
return existingPlan;
|
|
7272
|
+
}
|
|
7273
|
+
if (existingPlan && existingPlan.content_hash !== contentHash) {
|
|
7274
|
+
const priorSource = existingPlan.source_path ?? null;
|
|
7275
|
+
const newSource = input.sourcePath ?? null;
|
|
7276
|
+
if (priorSource !== newSource) {
|
|
7277
|
+
input.logger?.warn(LOG_KINDS.CAPTURE_PLAN, "Plan overwritten mid-session", {
|
|
7278
|
+
logical_key: input.logicalKey,
|
|
7279
|
+
session_id: input.sessionId,
|
|
7280
|
+
prior_source: priorSource,
|
|
7281
|
+
new_source: newSource,
|
|
7282
|
+
prior_updated_at: existingPlan.updated_at
|
|
7283
|
+
});
|
|
7284
|
+
}
|
|
7285
|
+
}
|
|
7286
|
+
return upsertPlan({
|
|
7287
|
+
id: buildPlanId(input.logicalKey),
|
|
7288
|
+
logical_key: input.logicalKey,
|
|
7289
|
+
title: resolvedTitle,
|
|
7290
|
+
content: input.content,
|
|
7291
|
+
source_path: input.sourcePath ?? null,
|
|
7292
|
+
tags: normalizePlanTags(input.tags),
|
|
7293
|
+
session_id: input.sessionId,
|
|
7294
|
+
prompt_batch_id: promptBatchId,
|
|
7295
|
+
content_hash: contentHash,
|
|
7296
|
+
status,
|
|
7297
|
+
created_at: createdAt,
|
|
7298
|
+
updated_at: updatedAt
|
|
7299
|
+
});
|
|
7300
|
+
}
|
|
7301
|
+
function capturePlan(input) {
|
|
7302
|
+
const normalizedSourcePath = normalizePlanSourcePath(input.sourcePath, input.projectRoot);
|
|
7303
|
+
return persistPlan({
|
|
7304
|
+
sessionId: input.sessionId,
|
|
7305
|
+
content: input.content,
|
|
7306
|
+
logicalKey: buildPathPlanLogicalKey(normalizedSourcePath),
|
|
7307
|
+
sourcePath: normalizedSourcePath,
|
|
7308
|
+
promptBatchId: input.promptBatchId,
|
|
7309
|
+
logger: input.logger
|
|
7310
|
+
});
|
|
7311
|
+
}
|
|
7312
|
+
function captureTaggedPlan(input) {
|
|
7313
|
+
return persistPlan({
|
|
7314
|
+
sessionId: input.sessionId,
|
|
7315
|
+
content: input.content,
|
|
7316
|
+
logicalKey: buildSessionTagPlanLogicalKey(input.sessionId, input.tag),
|
|
7317
|
+
sourcePath: `${TRANSCRIPT_SOURCE_PREFIX}${input.tag}`,
|
|
7318
|
+
promptBatchId: input.promptBatchId,
|
|
7319
|
+
planKey: input.tag,
|
|
7320
|
+
logger: input.logger
|
|
7321
|
+
});
|
|
7322
|
+
}
|
|
7323
|
+
|
|
7324
|
+
// src/daemon/api/mcp-proxy.ts
|
|
7325
|
+
var SPORE_ID_RANDOM_BYTES = 4;
|
|
7326
|
+
var RESOLUTION_ID_RANDOM_BYTES = 8;
|
|
7327
|
+
var MIN_CONSOLIDATE_SOURCES = 2;
|
|
7328
|
+
var RememberBody = external_exports.object({
|
|
7329
|
+
content: external_exports.string(),
|
|
7330
|
+
type: external_exports.string().optional(),
|
|
7331
|
+
tags: external_exports.array(external_exports.string()).optional()
|
|
7332
|
+
});
|
|
7333
|
+
var SupersedeBody = external_exports.object({
|
|
7334
|
+
old_spore_id: external_exports.string(),
|
|
7335
|
+
new_spore_id: external_exports.string(),
|
|
7336
|
+
reason: external_exports.string().optional()
|
|
7337
|
+
});
|
|
7338
|
+
function isoToEpochSeconds(iso) {
|
|
7339
|
+
const ms = Date.parse(iso);
|
|
7340
|
+
return Number.isNaN(ms) ? void 0 : Math.floor(ms / 1e3);
|
|
7341
|
+
}
|
|
7342
|
+
function registerMcpUserAgent(createdAt) {
|
|
7343
|
+
registerAgent({
|
|
7344
|
+
id: USER_AGENT_ID,
|
|
7345
|
+
name: USER_AGENT_NAME,
|
|
7346
|
+
created_at: createdAt
|
|
7347
|
+
});
|
|
7348
|
+
}
|
|
7349
|
+
function toPlanProgress(content) {
|
|
6631
7350
|
const planContent = content ?? "";
|
|
6632
7351
|
const checked = (planContent.match(/- \[x\]/gi) ?? []).length;
|
|
6633
7352
|
const unchecked = (planContent.match(/- \[ \]/g) ?? []).length;
|
|
@@ -6644,8 +7363,20 @@ var ConsolidateBody = external_exports.object({
|
|
|
6644
7363
|
tags: external_exports.array(external_exports.string()).optional(),
|
|
6645
7364
|
reason: external_exports.string().optional()
|
|
6646
7365
|
});
|
|
7366
|
+
var SavePlanBody = external_exports.object({
|
|
7367
|
+
session_id: external_exports.string(),
|
|
7368
|
+
content: external_exports.string().min(1),
|
|
7369
|
+
source_path: external_exports.string().min(1).optional(),
|
|
7370
|
+
plan_key: external_exports.string().min(1).optional(),
|
|
7371
|
+
title: external_exports.string().min(1).optional(),
|
|
7372
|
+
status: external_exports.enum(PLAN_STATUSES).optional(),
|
|
7373
|
+
tags: external_exports.array(external_exports.string()).optional()
|
|
7374
|
+
}).refine(
|
|
7375
|
+
(value) => Boolean(value.source_path) !== Boolean(value.plan_key),
|
|
7376
|
+
{ message: "Provide exactly one of source_path or plan_key" }
|
|
7377
|
+
);
|
|
6647
7378
|
function createMcpProxyHandlers(deps) {
|
|
6648
|
-
const { machineId, embeddingManager } = deps;
|
|
7379
|
+
const { machineId, embeddingManager, projectRoot, logger } = deps;
|
|
6649
7380
|
function toPlanSummary(row) {
|
|
6650
7381
|
return {
|
|
6651
7382
|
id: row.id,
|
|
@@ -6769,8 +7500,46 @@ function createMcpProxyHandlers(deps) {
|
|
|
6769
7500
|
}
|
|
6770
7501
|
};
|
|
6771
7502
|
}
|
|
7503
|
+
async function handleSavePlan(req) {
|
|
7504
|
+
const { session_id, content, source_path, plan_key, title, status, tags } = SavePlanBody.parse(req.body);
|
|
7505
|
+
const session = getSession(session_id);
|
|
7506
|
+
if (!session) return { status: 404, body: errorBody("session-not-found", "Session not found") };
|
|
7507
|
+
const openBatch = getLatestOpenBatch(session_id);
|
|
7508
|
+
const normalizedSourcePath = source_path ? normalizePlanSourcePath(source_path, projectRoot) : null;
|
|
7509
|
+
const logicalKey = normalizedSourcePath ? buildPathPlanLogicalKey(normalizedSourcePath) : buildSessionPlanLogicalKey(session_id, plan_key);
|
|
7510
|
+
const row = persistPlan({
|
|
7511
|
+
sessionId: session_id,
|
|
7512
|
+
content,
|
|
7513
|
+
logicalKey,
|
|
7514
|
+
sourcePath: normalizedSourcePath,
|
|
7515
|
+
promptBatchId: openBatch?.id,
|
|
7516
|
+
title,
|
|
7517
|
+
status,
|
|
7518
|
+
tags,
|
|
7519
|
+
planKey: plan_key ?? null,
|
|
7520
|
+
logger
|
|
7521
|
+
});
|
|
7522
|
+
return {
|
|
7523
|
+
body: {
|
|
7524
|
+
id: row.id,
|
|
7525
|
+
logical_key: row.logical_key,
|
|
7526
|
+
title: row.title,
|
|
7527
|
+
status: row.status,
|
|
7528
|
+
source_path: row.source_path,
|
|
7529
|
+
session_id: row.session_id,
|
|
7530
|
+
prompt_batch_id: row.prompt_batch_id,
|
|
7531
|
+
tags: toPlanTags(row.tags),
|
|
7532
|
+
created_at: row.created_at,
|
|
7533
|
+
updated_at: row.updated_at
|
|
7534
|
+
}
|
|
7535
|
+
};
|
|
7536
|
+
}
|
|
6772
7537
|
async function handlePlans(req) {
|
|
6773
7538
|
const id = typeof req.query.id === "string" ? req.query.id : void 0;
|
|
7539
|
+
const session = typeof req.query.session === "string" ? req.query.session : void 0;
|
|
7540
|
+
if (id && session) {
|
|
7541
|
+
return { status: 400, body: errorBody("mutually-exclusive-query", "Pass either id or session, not both") };
|
|
7542
|
+
}
|
|
6774
7543
|
if (id) {
|
|
6775
7544
|
const row = getPlan(id);
|
|
6776
7545
|
if (!row) return { body: { plans: [] } };
|
|
@@ -6783,6 +7552,11 @@ function createMcpProxyHandlers(deps) {
|
|
|
6783
7552
|
}
|
|
6784
7553
|
};
|
|
6785
7554
|
}
|
|
7555
|
+
if (session) {
|
|
7556
|
+
const rows2 = listPlansBySession(session);
|
|
7557
|
+
const plans2 = rows2.map(toPlanSummary);
|
|
7558
|
+
return { body: { plans: plans2 } };
|
|
7559
|
+
}
|
|
6786
7560
|
const statusFilter = req.query.status === "all" ? void 0 : req.query.status;
|
|
6787
7561
|
const limit = req.query.limit ? Number(req.query.limit) : void 0;
|
|
6788
7562
|
const rows = listPlans({ status: statusFilter, limit });
|
|
@@ -6836,6 +7610,7 @@ function createMcpProxyHandlers(deps) {
|
|
|
6836
7610
|
handleSupersede,
|
|
6837
7611
|
handleConsolidate,
|
|
6838
7612
|
handlePlans,
|
|
7613
|
+
handleSavePlan,
|
|
6839
7614
|
handleSessions,
|
|
6840
7615
|
handleTeam
|
|
6841
7616
|
};
|
|
@@ -6843,16 +7618,386 @@ function createMcpProxyHandlers(deps) {
|
|
|
6843
7618
|
|
|
6844
7619
|
// src/daemon/api/agent-runs.ts
|
|
6845
7620
|
import { resolve as resolve2 } from "path";
|
|
7621
|
+
|
|
7622
|
+
// src/services/phase-audit.ts
|
|
7623
|
+
function isStoredUsageData(value) {
|
|
7624
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
7625
|
+
}
|
|
7626
|
+
function parseUsageData(raw) {
|
|
7627
|
+
return tryParseJson(raw, isStoredUsageData) ?? {};
|
|
7628
|
+
}
|
|
7629
|
+
function normalizeStatus(raw) {
|
|
7630
|
+
if (raw === "completed" || raw === "failed" || raw === "skipped") return raw;
|
|
7631
|
+
return "pending";
|
|
7632
|
+
}
|
|
7633
|
+
function aggregateTurnCounts(turns) {
|
|
7634
|
+
const toolCalls = {};
|
|
7635
|
+
for (const turn of turns) {
|
|
7636
|
+
toolCalls[turn.tool_name] = (toolCalls[turn.tool_name] ?? 0) + 1;
|
|
7637
|
+
}
|
|
7638
|
+
const toolErrors = {};
|
|
7639
|
+
return [toolCalls, toolErrors];
|
|
7640
|
+
}
|
|
7641
|
+
function aggregateWriteIntents(intents) {
|
|
7642
|
+
const byPhase = {};
|
|
7643
|
+
const unattributedByTool = {};
|
|
7644
|
+
const totalByTool = {};
|
|
7645
|
+
for (const intent of intents) {
|
|
7646
|
+
const tool = intent.tool_name;
|
|
7647
|
+
totalByTool[tool] = (totalByTool[tool] ?? 0) + 1;
|
|
7648
|
+
if (intent.phase_id) {
|
|
7649
|
+
if (!byPhase[intent.phase_id]) byPhase[intent.phase_id] = {};
|
|
7650
|
+
byPhase[intent.phase_id][tool] = (byPhase[intent.phase_id][tool] ?? 0) + 1;
|
|
7651
|
+
} else {
|
|
7652
|
+
unattributedByTool[tool] = (unattributedByTool[tool] ?? 0) + 1;
|
|
7653
|
+
}
|
|
7654
|
+
}
|
|
7655
|
+
return {
|
|
7656
|
+
total: intents.length,
|
|
7657
|
+
byPhase,
|
|
7658
|
+
unattributedByTool,
|
|
7659
|
+
totalByTool
|
|
7660
|
+
};
|
|
7661
|
+
}
|
|
7662
|
+
function serializeReports(reports) {
|
|
7663
|
+
return reports.map((r) => ({
|
|
7664
|
+
action: r.action,
|
|
7665
|
+
summary: r.summary ?? null,
|
|
7666
|
+
details: r.details ?? null,
|
|
7667
|
+
createdAt: r.created_at
|
|
7668
|
+
}));
|
|
7669
|
+
}
|
|
7670
|
+
function buildPhaseAudit(runId) {
|
|
7671
|
+
const run = getRun(runId);
|
|
7672
|
+
if (!run) return null;
|
|
7673
|
+
const dryRun = run.dry_run;
|
|
7674
|
+
const usageData = parseUsageData(run.usage_data);
|
|
7675
|
+
const checkpointState = parseCheckpointState(run.checkpoints);
|
|
7676
|
+
const usageByName = new Map(
|
|
7677
|
+
(usageData.phases ?? []).map((p) => [p.name, p])
|
|
7678
|
+
);
|
|
7679
|
+
const checkpointByName = new Map(
|
|
7680
|
+
Object.entries(checkpointState.phases).map(([key, cp]) => [
|
|
7681
|
+
cp.name ?? key,
|
|
7682
|
+
cp
|
|
7683
|
+
])
|
|
7684
|
+
);
|
|
7685
|
+
const phaseNames = [];
|
|
7686
|
+
const seen = /* @__PURE__ */ new Set();
|
|
7687
|
+
for (const p of usageData.phases ?? []) {
|
|
7688
|
+
if (!seen.has(p.name)) {
|
|
7689
|
+
phaseNames.push(p.name);
|
|
7690
|
+
seen.add(p.name);
|
|
7691
|
+
}
|
|
7692
|
+
}
|
|
7693
|
+
for (const name of checkpointByName.keys()) {
|
|
7694
|
+
if (!seen.has(name)) {
|
|
7695
|
+
phaseNames.push(name);
|
|
7696
|
+
seen.add(name);
|
|
7697
|
+
}
|
|
7698
|
+
}
|
|
7699
|
+
const reports = listReports(runId);
|
|
7700
|
+
const turns = listTurnsByRun(runId);
|
|
7701
|
+
const [toolCalls, toolErrors] = aggregateTurnCounts(turns);
|
|
7702
|
+
const serializedReports = serializeReports(reports);
|
|
7703
|
+
let intentSummary = null;
|
|
7704
|
+
if (dryRun) {
|
|
7705
|
+
const intents = listWriteIntentTools(runId);
|
|
7706
|
+
intentSummary = aggregateWriteIntents(intents);
|
|
7707
|
+
}
|
|
7708
|
+
if (phaseNames.length === 0 && turns.length > 0) {
|
|
7709
|
+
const runStatus = normalizeStatus(run.status);
|
|
7710
|
+
const durationMs = runDurationMs(run);
|
|
7711
|
+
let writeIntents = null;
|
|
7712
|
+
if (intentSummary) {
|
|
7713
|
+
writeIntents = {
|
|
7714
|
+
total: intentSummary.total,
|
|
7715
|
+
byTool: intentSummary.totalByTool
|
|
7716
|
+
};
|
|
7717
|
+
}
|
|
7718
|
+
const summary = run.status === "failed" ? run.error ?? null : null;
|
|
7719
|
+
return {
|
|
7720
|
+
runId,
|
|
7721
|
+
taskName: run.task ?? null,
|
|
7722
|
+
dryRun,
|
|
7723
|
+
phases: [
|
|
7724
|
+
{
|
|
7725
|
+
phaseName: "run",
|
|
7726
|
+
status: runStatus,
|
|
7727
|
+
summary,
|
|
7728
|
+
turnsUsed: turns.length,
|
|
7729
|
+
maxTurns: null,
|
|
7730
|
+
tokensUsed: run.tokens_used ?? 0,
|
|
7731
|
+
costUsd: run.cost_usd ?? null,
|
|
7732
|
+
costSource: run.cost_source ?? null,
|
|
7733
|
+
durationMs,
|
|
7734
|
+
startedAt: run.started_at,
|
|
7735
|
+
completedAt: run.completed_at,
|
|
7736
|
+
skipReason: null,
|
|
7737
|
+
toolCalls,
|
|
7738
|
+
toolErrors,
|
|
7739
|
+
writeIntents,
|
|
7740
|
+
reports: serializedReports
|
|
7741
|
+
}
|
|
7742
|
+
]
|
|
7743
|
+
};
|
|
7744
|
+
}
|
|
7745
|
+
const phases = phaseNames.map((phaseName) => {
|
|
7746
|
+
const usage = usageByName.get(phaseName);
|
|
7747
|
+
const cp = checkpointByName.get(phaseName);
|
|
7748
|
+
const status = normalizeStatus(cp?.status ?? (usage ? "pending" : "pending"));
|
|
7749
|
+
const tokensUsed = cp?.tokensUsed ?? usage?.tokensUsed ?? usage?.usage?.totalTokens ?? 0;
|
|
7750
|
+
const costUsd = cp?.costUsd !== void 0 ? cp.costUsd : usage?.costUsd !== void 0 ? usage.costUsd : null;
|
|
7751
|
+
const costSource = cp?.costSource ?? usage?.costSource ?? null;
|
|
7752
|
+
const durationMs = usage?.usage?.durationMs ?? null;
|
|
7753
|
+
const completedAt = status === "completed" || status === "failed" ? cp?.updatedAt ?? null : null;
|
|
7754
|
+
const startedAt = null;
|
|
7755
|
+
const skipReason = null;
|
|
7756
|
+
let writeIntents = null;
|
|
7757
|
+
if (intentSummary) {
|
|
7758
|
+
const phaseByTool = intentSummary.byPhase[phaseName] ?? {};
|
|
7759
|
+
writeIntents = {
|
|
7760
|
+
// Phase total = sum of tool calls attributed to this phase
|
|
7761
|
+
total: Object.values(phaseByTool).reduce((sum, n) => sum + n, 0),
|
|
7762
|
+
byTool: phaseByTool
|
|
7763
|
+
};
|
|
7764
|
+
}
|
|
7765
|
+
return {
|
|
7766
|
+
phaseName,
|
|
7767
|
+
status,
|
|
7768
|
+
summary: cp?.summary ?? null,
|
|
7769
|
+
turnsUsed: cp?.turnsUsed ?? 0,
|
|
7770
|
+
maxTurns: null,
|
|
7771
|
+
// Not persisted — see module JSDoc
|
|
7772
|
+
tokensUsed,
|
|
7773
|
+
costUsd,
|
|
7774
|
+
costSource,
|
|
7775
|
+
durationMs,
|
|
7776
|
+
startedAt,
|
|
7777
|
+
completedAt,
|
|
7778
|
+
skipReason,
|
|
7779
|
+
toolCalls,
|
|
7780
|
+
// run-level aggregate (no per-phase turn attribution)
|
|
7781
|
+
toolErrors,
|
|
7782
|
+
// always empty — no error flag on turn rows
|
|
7783
|
+
writeIntents,
|
|
7784
|
+
reports: serializedReports
|
|
7785
|
+
// all reports; no phase column exists
|
|
7786
|
+
};
|
|
7787
|
+
});
|
|
7788
|
+
return {
|
|
7789
|
+
runId,
|
|
7790
|
+
taskName: run.task ?? null,
|
|
7791
|
+
dryRun,
|
|
7792
|
+
phases
|
|
7793
|
+
};
|
|
7794
|
+
}
|
|
7795
|
+
|
|
7796
|
+
// src/daemon/api/schemas/execution-overrides.ts
|
|
7797
|
+
var ReasoningLevelEnum = external_exports.enum(["low", "default", "high"]);
|
|
7798
|
+
var RuntimeIdEnum = external_exports.enum(["claude-sdk", "openai-agents"]);
|
|
7799
|
+
var ProviderTypeEnum = external_exports.enum([
|
|
7800
|
+
"anthropic",
|
|
7801
|
+
"ollama",
|
|
7802
|
+
"lmstudio",
|
|
7803
|
+
"openai",
|
|
7804
|
+
"openrouter",
|
|
7805
|
+
"openai-compatible"
|
|
7806
|
+
]);
|
|
7807
|
+
var ProviderOverrideWireSchema = external_exports.object({
|
|
7808
|
+
runtime: RuntimeIdEnum.optional(),
|
|
7809
|
+
type: ProviderTypeEnum,
|
|
7810
|
+
localBackend: external_exports.enum(["ollama", "lmstudio"]).optional(),
|
|
7811
|
+
baseUrl: external_exports.string().optional(),
|
|
7812
|
+
model: external_exports.string().optional(),
|
|
7813
|
+
reasoningMap: external_exports.object({
|
|
7814
|
+
low: external_exports.string().optional(),
|
|
7815
|
+
default: external_exports.string().optional(),
|
|
7816
|
+
high: external_exports.string().optional()
|
|
7817
|
+
}).optional(),
|
|
7818
|
+
contextLength: external_exports.number().int().positive().optional()
|
|
7819
|
+
});
|
|
7820
|
+
var PhaseExecutionOverrideBody = external_exports.object({
|
|
7821
|
+
reasoningLevel: ReasoningLevelEnum.optional(),
|
|
7822
|
+
model: external_exports.string().optional(),
|
|
7823
|
+
provider: ProviderOverrideWireSchema.optional(),
|
|
7824
|
+
maxTurns: external_exports.number().int().positive().optional()
|
|
7825
|
+
});
|
|
7826
|
+
var ExecutionOverrideBody = external_exports.object({
|
|
7827
|
+
runtime: RuntimeIdEnum.optional(),
|
|
7828
|
+
reasoningLevel: ReasoningLevelEnum.optional(),
|
|
7829
|
+
model: external_exports.string().optional(),
|
|
7830
|
+
provider: ProviderOverrideWireSchema.optional(),
|
|
7831
|
+
phases: external_exports.record(external_exports.string(), PhaseExecutionOverrideBody).optional()
|
|
7832
|
+
}).optional();
|
|
7833
|
+
|
|
7834
|
+
// src/daemon/api/schemas/execution-overrides-traversal.ts
|
|
7835
|
+
function transformProviderOverrides(overrides, transform) {
|
|
7836
|
+
if (overrides === null || overrides === void 0) {
|
|
7837
|
+
return overrides ?? null;
|
|
7838
|
+
}
|
|
7839
|
+
if (typeof overrides !== "object") return overrides;
|
|
7840
|
+
const cloned = { ...overrides };
|
|
7841
|
+
if (isPlainObject(cloned.provider)) {
|
|
7842
|
+
const next = transform({ ...cloned.provider });
|
|
7843
|
+
if (next === null) {
|
|
7844
|
+
delete cloned.provider;
|
|
7845
|
+
} else {
|
|
7846
|
+
cloned.provider = next;
|
|
7847
|
+
}
|
|
7848
|
+
}
|
|
7849
|
+
if (isPlainObject(cloned.phases)) {
|
|
7850
|
+
const nextPhases = {};
|
|
7851
|
+
for (const [name, phase] of Object.entries(cloned.phases)) {
|
|
7852
|
+
if (!isPlainObject(phase)) {
|
|
7853
|
+
nextPhases[name] = phase;
|
|
7854
|
+
continue;
|
|
7855
|
+
}
|
|
7856
|
+
const clonedPhase = { ...phase };
|
|
7857
|
+
if (isPlainObject(clonedPhase.provider)) {
|
|
7858
|
+
const nextProvider = transform({ ...clonedPhase.provider });
|
|
7859
|
+
if (nextProvider === null) {
|
|
7860
|
+
delete clonedPhase.provider;
|
|
7861
|
+
} else {
|
|
7862
|
+
clonedPhase.provider = nextProvider;
|
|
7863
|
+
}
|
|
7864
|
+
}
|
|
7865
|
+
nextPhases[name] = clonedPhase;
|
|
7866
|
+
}
|
|
7867
|
+
cloned.phases = nextPhases;
|
|
7868
|
+
}
|
|
7869
|
+
return cloned;
|
|
7870
|
+
}
|
|
7871
|
+
function isPlainObject(value) {
|
|
7872
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
7873
|
+
}
|
|
7874
|
+
|
|
7875
|
+
// src/daemon/api/run-serializer.ts
|
|
7876
|
+
function buildPhaseCheckpointSummary(checkpointsRaw) {
|
|
7877
|
+
if (!checkpointsRaw) return [];
|
|
7878
|
+
try {
|
|
7879
|
+
const parsed = JSON.parse(checkpointsRaw);
|
|
7880
|
+
return Object.entries(parsed.phases ?? {}).map(([name, phase]) => ({
|
|
7881
|
+
name: phase.name ?? name,
|
|
7882
|
+
status: phase.status ?? "pending",
|
|
7883
|
+
updatedAt: phase.updatedAt ?? 0,
|
|
7884
|
+
...phase.tokensUsed !== void 0 ? { tokensUsed: phase.tokensUsed } : {},
|
|
7885
|
+
...phase.costUsd !== void 0 ? { costUsd: phase.costUsd } : {},
|
|
7886
|
+
...phase.costSource !== void 0 ? { costSource: phase.costSource } : {}
|
|
7887
|
+
}));
|
|
7888
|
+
} catch {
|
|
7889
|
+
return [];
|
|
7890
|
+
}
|
|
7891
|
+
}
|
|
7892
|
+
function scrubExecutionOverrides(overrides) {
|
|
7893
|
+
if (!overrides || typeof overrides !== "object") return overrides;
|
|
7894
|
+
const topLevelStripped = { ...overrides };
|
|
7895
|
+
if ("apiKey" in topLevelStripped) delete topLevelStripped.apiKey;
|
|
7896
|
+
return transformProviderOverrides(topLevelStripped, stripApiKey);
|
|
7897
|
+
}
|
|
7898
|
+
function stripApiKey(provider) {
|
|
7899
|
+
const cloned = { ...provider };
|
|
7900
|
+
if ("apiKey" in cloned) delete cloned.apiKey;
|
|
7901
|
+
return cloned;
|
|
7902
|
+
}
|
|
7903
|
+
function serializeRun(run, opts = {}) {
|
|
7904
|
+
const {
|
|
7905
|
+
includeResumeFields = true,
|
|
7906
|
+
includePhaseCheckpoints = true,
|
|
7907
|
+
writeIntents,
|
|
7908
|
+
duration_ms
|
|
7909
|
+
} = opts;
|
|
7910
|
+
const base = {
|
|
7911
|
+
id: run.id,
|
|
7912
|
+
agent_id: run.agent_id,
|
|
7913
|
+
task: run.task,
|
|
7914
|
+
instruction: run.instruction,
|
|
7915
|
+
status: run.status,
|
|
7916
|
+
runtime: run.runtime,
|
|
7917
|
+
provider: run.provider,
|
|
7918
|
+
model: run.model,
|
|
7919
|
+
session_ref: run.session_ref,
|
|
7920
|
+
started_at: run.started_at,
|
|
7921
|
+
completed_at: run.completed_at,
|
|
7922
|
+
tokens_used: run.tokens_used,
|
|
7923
|
+
cost_usd: run.cost_usd,
|
|
7924
|
+
actual_cost_usd: run.actual_cost_usd,
|
|
7925
|
+
estimated_cost_usd: run.estimated_cost_usd,
|
|
7926
|
+
cost_source: run.cost_source,
|
|
7927
|
+
cost_data: run.cost_data,
|
|
7928
|
+
actions_taken: run.actions_taken,
|
|
7929
|
+
usage_data: run.usage_data,
|
|
7930
|
+
error: run.error,
|
|
7931
|
+
dry_run: run.dry_run,
|
|
7932
|
+
evaluation_id: run.evaluation_id,
|
|
7933
|
+
reasoning_level: run.reasoning_level,
|
|
7934
|
+
// Strip `apiKey` from historical rows defensively — before this PR the
|
|
7935
|
+
// API accepted apiKey in executionOverrides and stored it unmasked.
|
|
7936
|
+
execution_overrides: scrubExecutionOverrides(run.execution_overrides)
|
|
7937
|
+
};
|
|
7938
|
+
return {
|
|
7939
|
+
...base,
|
|
7940
|
+
...includeResumeFields ? {
|
|
7941
|
+
resumable: run.resumable === 1,
|
|
7942
|
+
resume_status: run.resume_status,
|
|
7943
|
+
resume_mode: run.resume_mode,
|
|
7944
|
+
resumed_at: run.resumed_at,
|
|
7945
|
+
checkpoints: run.checkpoints
|
|
7946
|
+
} : {},
|
|
7947
|
+
...includePhaseCheckpoints ? { phase_checkpoints: buildPhaseCheckpointSummary(run.checkpoints) } : {},
|
|
7948
|
+
...writeIntents !== void 0 && writeIntents !== null ? { write_intents: writeIntents } : {},
|
|
7949
|
+
...duration_ms !== void 0 ? { duration_ms } : {}
|
|
7950
|
+
};
|
|
7951
|
+
}
|
|
7952
|
+
|
|
7953
|
+
// src/daemon/api/agent-runs.ts
|
|
6846
7954
|
var AGENT_RUNS_DEFAULT_LIMIT = 50;
|
|
7955
|
+
var REMOTE_PROVIDER_TYPES = /* @__PURE__ */ new Set(["openai", "openrouter"]);
|
|
7956
|
+
function stripBaseUrlForRemoteProviders(provider) {
|
|
7957
|
+
const type = provider.type;
|
|
7958
|
+
if (typeof type === "string" && REMOTE_PROVIDER_TYPES.has(type)) {
|
|
7959
|
+
const { baseUrl: _dropped, ...rest } = provider;
|
|
7960
|
+
return rest;
|
|
7961
|
+
}
|
|
7962
|
+
return provider;
|
|
7963
|
+
}
|
|
7964
|
+
function sanitizeExecutionOverrides(overrides) {
|
|
7965
|
+
if (!overrides) return overrides;
|
|
7966
|
+
const result = transformProviderOverrides(
|
|
7967
|
+
overrides,
|
|
7968
|
+
stripBaseUrlForRemoteProviders
|
|
7969
|
+
);
|
|
7970
|
+
return result;
|
|
7971
|
+
}
|
|
6847
7972
|
var AgentRunBody = external_exports.object({
|
|
6848
7973
|
task: external_exports.string().optional(),
|
|
6849
7974
|
instruction: external_exports.string().optional(),
|
|
6850
|
-
agentId: external_exports.string().optional()
|
|
7975
|
+
agentId: external_exports.string().optional(),
|
|
7976
|
+
/**
|
|
7977
|
+
* Run in dry-run mode — writes intercepted by the tool surface and
|
|
7978
|
+
* recorded to `agent_run_write_intents` instead of mutating the vault.
|
|
7979
|
+
*/
|
|
7980
|
+
dryRun: external_exports.boolean().optional(),
|
|
7981
|
+
/** Evaluation matrix this run belongs to, if any. */
|
|
7982
|
+
evaluationId: external_exports.string().nullable().optional(),
|
|
7983
|
+
/** Per-run runtime/reasoning/model overrides; also per-phase overrides. */
|
|
7984
|
+
executionOverrides: ExecutionOverrideBody
|
|
7985
|
+
});
|
|
7986
|
+
var ResumeRunBody = external_exports.object({
|
|
7987
|
+
mode: external_exports.enum(["manual", "scheduled"]).optional()
|
|
6851
7988
|
});
|
|
6852
7989
|
function createAgentRunHandlers(deps) {
|
|
6853
|
-
const { vaultDir, embeddingManager, logger } = deps;
|
|
7990
|
+
const { vaultDir, embeddingManager, logger, getTeamClient } = deps;
|
|
6854
7991
|
async function handleRun(req) {
|
|
6855
|
-
const {
|
|
7992
|
+
const {
|
|
7993
|
+
task,
|
|
7994
|
+
instruction: rawInstruction,
|
|
7995
|
+
agentId,
|
|
7996
|
+
dryRun,
|
|
7997
|
+
evaluationId,
|
|
7998
|
+
executionOverrides: rawExecutionOverrides
|
|
7999
|
+
} = AgentRunBody.parse(req.body);
|
|
8000
|
+
const executionOverrides = sanitizeExecutionOverrides(rawExecutionOverrides);
|
|
6856
8001
|
const mycoConfig = loadMergedConfig(vaultDir);
|
|
6857
8002
|
if (!hasConfiguredProvider(mycoConfig, task)) {
|
|
6858
8003
|
return {
|
|
@@ -6870,10 +8015,10 @@ function createAgentRunHandlers(deps) {
|
|
|
6870
8015
|
try {
|
|
6871
8016
|
const taskParams = mycoConfig.agent.tasks?.[task]?.params;
|
|
6872
8017
|
const projectRoot = resolve2(vaultDir, "..");
|
|
6873
|
-
built = buildTaskInstruction(task, taskParams, agentId, projectRoot, embeddingManager);
|
|
8018
|
+
built = await buildTaskInstruction(task, taskParams, agentId, projectRoot, embeddingManager, mycoConfig, getTeamClient);
|
|
6874
8019
|
} catch {
|
|
6875
8020
|
const projectRoot = resolve2(vaultDir, "..");
|
|
6876
|
-
built = buildTaskInstruction(task, void 0, agentId, projectRoot, embeddingManager);
|
|
8021
|
+
built = await buildTaskInstruction(task, void 0, agentId, projectRoot, embeddingManager, mycoConfig, getTeamClient);
|
|
6877
8022
|
}
|
|
6878
8023
|
instruction = built?.instruction;
|
|
6879
8024
|
runContext = built?.context;
|
|
@@ -6888,13 +8033,16 @@ function createAgentRunHandlers(deps) {
|
|
|
6888
8033
|
};
|
|
6889
8034
|
}
|
|
6890
8035
|
}
|
|
6891
|
-
const { runAgent } = await import("./executor-
|
|
6892
|
-
const resultPromise =
|
|
8036
|
+
const { runAgent: runAgent2 } = await import("./executor-F2YU7HXJ.js");
|
|
8037
|
+
const resultPromise = runAgent2(vaultDir, {
|
|
6893
8038
|
task,
|
|
6894
8039
|
instruction,
|
|
6895
8040
|
agentId,
|
|
6896
8041
|
embeddingManager,
|
|
6897
|
-
runContext
|
|
8042
|
+
runContext,
|
|
8043
|
+
dryRun,
|
|
8044
|
+
evaluationId,
|
|
8045
|
+
executionOverrides
|
|
6898
8046
|
});
|
|
6899
8047
|
const effectiveAgentId = agentId ?? "myco-agent";
|
|
6900
8048
|
const runId = getLatestRunId(effectiveAgentId, task);
|
|
@@ -6946,14 +8094,57 @@ function createAgentRunHandlers(deps) {
|
|
|
6946
8094
|
const filterOpts = { agent_id: agentId, status, task, search };
|
|
6947
8095
|
const runs = listRuns({ ...filterOpts, limit, offset });
|
|
6948
8096
|
const total = countRuns(filterOpts);
|
|
6949
|
-
return { body: { runs, total, offset, limit } };
|
|
8097
|
+
return { body: { runs: runs.map((run) => serializeRun(run)), total, offset, limit } };
|
|
6950
8098
|
}
|
|
6951
8099
|
async function handleGetRun(req) {
|
|
6952
8100
|
const run = getRun(req.params.id);
|
|
6953
8101
|
if (!run) {
|
|
6954
8102
|
return { status: 404, body: { error: "Run not found" } };
|
|
6955
8103
|
}
|
|
6956
|
-
|
|
8104
|
+
const byTool = countWriteIntentsByTool(run.id);
|
|
8105
|
+
const total = Object.values(byTool).reduce((acc, n) => acc + n, 0);
|
|
8106
|
+
return {
|
|
8107
|
+
body: {
|
|
8108
|
+
run: serializeRun(run, {
|
|
8109
|
+
writeIntents: { total, by_tool: byTool },
|
|
8110
|
+
duration_ms: runDurationMs(run)
|
|
8111
|
+
})
|
|
8112
|
+
}
|
|
8113
|
+
};
|
|
8114
|
+
}
|
|
8115
|
+
async function handleResumeRun(req) {
|
|
8116
|
+
const run = getRun(req.params.id);
|
|
8117
|
+
if (!run) {
|
|
8118
|
+
return { status: 404, body: { error: "Run not found" } };
|
|
8119
|
+
}
|
|
8120
|
+
if (run.resumable !== 1 || run.status !== "failed") {
|
|
8121
|
+
return { status: 400, body: { error: "Run is not resumable" } };
|
|
8122
|
+
}
|
|
8123
|
+
const { mode } = ResumeRunBody.parse(req.body ?? {});
|
|
8124
|
+
const { runAgent: runAgent2 } = await import("./executor-F2YU7HXJ.js");
|
|
8125
|
+
const resultPromise = runAgent2(vaultDir, {
|
|
8126
|
+
agentId: run.agent_id,
|
|
8127
|
+
task: run.task ?? void 0,
|
|
8128
|
+
instruction: run.instruction ?? void 0,
|
|
8129
|
+
resumeRunId: run.id,
|
|
8130
|
+
resumeMode: mode ?? "manual",
|
|
8131
|
+
embeddingManager
|
|
8132
|
+
});
|
|
8133
|
+
resultPromise.then((result) => {
|
|
8134
|
+
logger.info(LOG_KINDS.AGENT_RUN, "Agent run resumed", {
|
|
8135
|
+
runId: result.runId,
|
|
8136
|
+
status: result.status,
|
|
8137
|
+
runtime: result.runtime,
|
|
8138
|
+
provider: result.provider,
|
|
8139
|
+
model: result.model
|
|
8140
|
+
});
|
|
8141
|
+
}).catch((err) => {
|
|
8142
|
+
logger.error(LOG_KINDS.AGENT_ERROR, "Agent run resume threw unhandled error", {
|
|
8143
|
+
runId: run.id,
|
|
8144
|
+
error: err instanceof Error ? err.message : String(err)
|
|
8145
|
+
});
|
|
8146
|
+
});
|
|
8147
|
+
return { body: { ok: true, message: "Agent resume started", runId: run.id } };
|
|
6957
8148
|
}
|
|
6958
8149
|
async function handleGetRunReports(req) {
|
|
6959
8150
|
const reports = listReports(req.params.id);
|
|
@@ -6963,18 +8154,376 @@ function createAgentRunHandlers(deps) {
|
|
|
6963
8154
|
const turns = listTurnsByRun(req.params.id);
|
|
6964
8155
|
return { body: turns };
|
|
6965
8156
|
}
|
|
8157
|
+
async function handleGetRunWriteIntents(req) {
|
|
8158
|
+
const rawLimit = req.query.limit ? Number(req.query.limit) : void 0;
|
|
8159
|
+
const rawOffset = req.query.offset ? Number(req.query.offset) : void 0;
|
|
8160
|
+
const limit = Number.isFinite(rawLimit) && rawLimit !== void 0 && rawLimit > 0 ? Math.min(rawLimit, 5e3) : 500;
|
|
8161
|
+
const offset = Number.isFinite(rawOffset) && rawOffset !== void 0 && rawOffset >= 0 ? rawOffset : 0;
|
|
8162
|
+
const intents = listWriteIntents(req.params.id, { limit, offset });
|
|
8163
|
+
const total = countWriteIntents(req.params.id);
|
|
8164
|
+
return { body: { intents, count: intents.length, total } };
|
|
8165
|
+
}
|
|
8166
|
+
async function handleGetRunAudit(req) {
|
|
8167
|
+
const audit = buildPhaseAudit(req.params.id);
|
|
8168
|
+
if (!audit) {
|
|
8169
|
+
return { status: 404, body: { error: "Run not found" } };
|
|
8170
|
+
}
|
|
8171
|
+
return { body: { audit } };
|
|
8172
|
+
}
|
|
6966
8173
|
return {
|
|
6967
8174
|
handleRun,
|
|
6968
8175
|
handleListRuns,
|
|
6969
8176
|
handleGetRun,
|
|
8177
|
+
handleResumeRun,
|
|
6970
8178
|
handleGetRunReports,
|
|
6971
|
-
handleGetRunTurns
|
|
8179
|
+
handleGetRunTurns,
|
|
8180
|
+
handleGetRunWriteIntents,
|
|
8181
|
+
handleGetRunAudit
|
|
8182
|
+
};
|
|
8183
|
+
}
|
|
8184
|
+
|
|
8185
|
+
// src/daemon/api/agent-evaluations.ts
|
|
8186
|
+
import crypto from "crypto";
|
|
8187
|
+
|
|
8188
|
+
// src/db/queries/evaluations.ts
|
|
8189
|
+
var DEFAULT_LIMIT = 50;
|
|
8190
|
+
var EVAL_STATUS_PENDING = "pending";
|
|
8191
|
+
var EVAL_STATUS_RUNNING = "running";
|
|
8192
|
+
var EVAL_STATUS_COMPLETED = "completed";
|
|
8193
|
+
var EVAL_STATUS_FAILED = "failed";
|
|
8194
|
+
var EVAL_COLUMNS = [
|
|
8195
|
+
"id",
|
|
8196
|
+
"task_id",
|
|
8197
|
+
"matrix_json",
|
|
8198
|
+
"notes",
|
|
8199
|
+
"status",
|
|
8200
|
+
"created_at",
|
|
8201
|
+
"completed_at"
|
|
8202
|
+
];
|
|
8203
|
+
var SELECT_COLUMNS5 = EVAL_COLUMNS.join(", ");
|
|
8204
|
+
function toEvaluationRow(row) {
|
|
8205
|
+
const matrixJson = row.matrix_json;
|
|
8206
|
+
let matrix = null;
|
|
8207
|
+
if (matrixJson) {
|
|
8208
|
+
try {
|
|
8209
|
+
matrix = JSON.parse(matrixJson);
|
|
8210
|
+
} catch {
|
|
8211
|
+
matrix = null;
|
|
8212
|
+
}
|
|
8213
|
+
}
|
|
8214
|
+
return {
|
|
8215
|
+
id: row.id,
|
|
8216
|
+
task_id: row.task_id,
|
|
8217
|
+
matrix,
|
|
8218
|
+
notes: row.notes ?? null,
|
|
8219
|
+
status: row.status,
|
|
8220
|
+
created_at: row.created_at,
|
|
8221
|
+
completed_at: row.completed_at ?? null
|
|
8222
|
+
};
|
|
8223
|
+
}
|
|
8224
|
+
function insertEvaluation(data) {
|
|
8225
|
+
const db = getDatabase();
|
|
8226
|
+
const createdAt = data.createdAt ?? epochSeconds();
|
|
8227
|
+
db.prepare(
|
|
8228
|
+
`INSERT INTO agent_run_evaluations
|
|
8229
|
+
(id, task_id, matrix_json, notes, status, created_at, completed_at)
|
|
8230
|
+
VALUES (?, ?, ?, ?, ?, ?, NULL)`
|
|
8231
|
+
).run(
|
|
8232
|
+
data.id,
|
|
8233
|
+
data.taskId,
|
|
8234
|
+
JSON.stringify(data.matrix ?? null),
|
|
8235
|
+
data.notes ?? null,
|
|
8236
|
+
EVAL_STATUS_PENDING,
|
|
8237
|
+
createdAt
|
|
8238
|
+
);
|
|
8239
|
+
return getEvaluation(data.id);
|
|
8240
|
+
}
|
|
8241
|
+
function getEvaluation(id) {
|
|
8242
|
+
const db = getDatabase();
|
|
8243
|
+
const row = db.prepare(
|
|
8244
|
+
`SELECT ${SELECT_COLUMNS5} FROM agent_run_evaluations WHERE id = ?`
|
|
8245
|
+
).get(id);
|
|
8246
|
+
return row ? toEvaluationRow(row) : null;
|
|
8247
|
+
}
|
|
8248
|
+
function listEvaluations(options = {}) {
|
|
8249
|
+
const db = getDatabase();
|
|
8250
|
+
const limit = options.limit ?? DEFAULT_LIMIT;
|
|
8251
|
+
const offset = options.offset ?? 0;
|
|
8252
|
+
const rows = db.prepare(
|
|
8253
|
+
`SELECT ${SELECT_COLUMNS5}
|
|
8254
|
+
FROM agent_run_evaluations
|
|
8255
|
+
ORDER BY created_at DESC, id DESC
|
|
8256
|
+
LIMIT ? OFFSET ?`
|
|
8257
|
+
).all(limit, offset);
|
|
8258
|
+
return rows.map(toEvaluationRow);
|
|
8259
|
+
}
|
|
8260
|
+
function updateEvaluationStatus(id, status, completedAt) {
|
|
8261
|
+
const db = getDatabase();
|
|
8262
|
+
if (completedAt === void 0) {
|
|
8263
|
+
db.prepare(
|
|
8264
|
+
`UPDATE agent_run_evaluations SET status = ? WHERE id = ?`
|
|
8265
|
+
).run(status, id);
|
|
8266
|
+
} else {
|
|
8267
|
+
db.prepare(
|
|
8268
|
+
`UPDATE agent_run_evaluations SET status = ?, completed_at = ? WHERE id = ?`
|
|
8269
|
+
).run(status, completedAt, id);
|
|
8270
|
+
}
|
|
8271
|
+
return getEvaluation(id);
|
|
8272
|
+
}
|
|
8273
|
+
|
|
8274
|
+
// src/daemon/api/agent-evaluations.ts
|
|
8275
|
+
var DEFAULT_LIMIT2 = 50;
|
|
8276
|
+
var CreateEvaluationBody = external_exports.object({
|
|
8277
|
+
taskId: external_exports.string(),
|
|
8278
|
+
matrix: external_exports.object({
|
|
8279
|
+
runtimes: external_exports.array(RuntimeIdEnum).optional(),
|
|
8280
|
+
reasoningLevels: external_exports.array(ReasoningLevelEnum).optional(),
|
|
8281
|
+
models: external_exports.array(external_exports.string()).optional(),
|
|
8282
|
+
dryRun: external_exports.boolean().optional(),
|
|
8283
|
+
notes: external_exports.string().optional(),
|
|
8284
|
+
/**
|
|
8285
|
+
* Phase-level overrides applied to EVERY cell in the matrix. The matrix
|
|
8286
|
+
* dimensions (runtimes / reasoningLevels / models) vary the top-level
|
|
8287
|
+
* execution per cell; phase overrides here let you pin specific phases
|
|
8288
|
+
* to fixed reasoning/model/provider/maxTurns regardless of what the cell
|
|
8289
|
+
* is varying at the top level.
|
|
8290
|
+
*
|
|
8291
|
+
* Merged into each cell's `executionOverrides.phases` before runAgent
|
|
8292
|
+
* is invoked. Unknown phase names are ignored by the executor (a
|
|
8293
|
+
* one-shot warning is logged at run startup).
|
|
8294
|
+
*/
|
|
8295
|
+
phases: external_exports.record(external_exports.string(), PhaseExecutionOverrideBody).optional()
|
|
8296
|
+
}),
|
|
8297
|
+
notes: external_exports.string().optional()
|
|
8298
|
+
});
|
|
8299
|
+
function aggregateRuns(runs) {
|
|
8300
|
+
let completed = 0;
|
|
8301
|
+
let failed = 0;
|
|
8302
|
+
let skipped = 0;
|
|
8303
|
+
let totalTokens = 0;
|
|
8304
|
+
let totalCostUsd = 0;
|
|
8305
|
+
for (const run of runs) {
|
|
8306
|
+
if (run.status === "completed") completed++;
|
|
8307
|
+
else if (run.status === "failed") failed++;
|
|
8308
|
+
else if (run.status === "skipped") skipped++;
|
|
8309
|
+
totalTokens += run.tokens_used ?? 0;
|
|
8310
|
+
totalCostUsd += run.cost_usd ?? 0;
|
|
8311
|
+
}
|
|
8312
|
+
return {
|
|
8313
|
+
total: runs.length,
|
|
8314
|
+
completed,
|
|
8315
|
+
failed,
|
|
8316
|
+
skipped,
|
|
8317
|
+
totalTokens,
|
|
8318
|
+
totalCostUsd
|
|
6972
8319
|
};
|
|
6973
8320
|
}
|
|
8321
|
+
function summarizeFromByTool(byTool) {
|
|
8322
|
+
const tools = byTool ?? {};
|
|
8323
|
+
let total = 0;
|
|
8324
|
+
for (const count of Object.values(tools)) total += count;
|
|
8325
|
+
return { total, by_tool: tools };
|
|
8326
|
+
}
|
|
8327
|
+
function createAgentEvaluationHandlers(deps) {
|
|
8328
|
+
const { vaultDir, embeddingManager, logger } = deps;
|
|
8329
|
+
async function handleCreate(req) {
|
|
8330
|
+
const parsed = CreateEvaluationBody.safeParse(req.body);
|
|
8331
|
+
if (!parsed.success) {
|
|
8332
|
+
return {
|
|
8333
|
+
status: 400,
|
|
8334
|
+
body: { error: "Invalid request body", details: parsed.error.flatten() }
|
|
8335
|
+
};
|
|
8336
|
+
}
|
|
8337
|
+
const body = parsed.data;
|
|
8338
|
+
const cells = enumerateMatrixCells(body.matrix);
|
|
8339
|
+
if (cells.length === 0) {
|
|
8340
|
+
return {
|
|
8341
|
+
status: 400,
|
|
8342
|
+
body: { error: "Matrix produced zero cells" }
|
|
8343
|
+
};
|
|
8344
|
+
}
|
|
8345
|
+
const evalId = crypto.randomUUID();
|
|
8346
|
+
insertEvaluation({
|
|
8347
|
+
id: evalId,
|
|
8348
|
+
taskId: body.taskId,
|
|
8349
|
+
matrix: body.matrix,
|
|
8350
|
+
notes: body.notes ?? null
|
|
8351
|
+
});
|
|
8352
|
+
const dryRun = body.matrix.dryRun ?? false;
|
|
8353
|
+
void (async () => {
|
|
8354
|
+
const { runAgent: runAgent2 } = await import("./executor-F2YU7HXJ.js");
|
|
8355
|
+
let anyCompleted = false;
|
|
8356
|
+
let transitionedToRunning = false;
|
|
8357
|
+
const sharedPhases = body.matrix.phases;
|
|
8358
|
+
for (const cell of cells) {
|
|
8359
|
+
const cellOptions = {
|
|
8360
|
+
task: body.taskId,
|
|
8361
|
+
evaluationId: evalId,
|
|
8362
|
+
dryRun,
|
|
8363
|
+
embeddingManager,
|
|
8364
|
+
executionOverrides: {
|
|
8365
|
+
...cell.runtime ? { runtime: cell.runtime } : {},
|
|
8366
|
+
...cell.reasoningLevel ? { reasoningLevel: cell.reasoningLevel } : {},
|
|
8367
|
+
...cell.model ? { model: cell.model } : {},
|
|
8368
|
+
...sharedPhases && Object.keys(sharedPhases).length > 0 ? { phases: sharedPhases } : {}
|
|
8369
|
+
}
|
|
8370
|
+
};
|
|
8371
|
+
if (!transitionedToRunning) {
|
|
8372
|
+
updateEvaluationStatus(evalId, EVAL_STATUS_RUNNING);
|
|
8373
|
+
transitionedToRunning = true;
|
|
8374
|
+
}
|
|
8375
|
+
try {
|
|
8376
|
+
const result = await runAgent2(vaultDir, cellOptions);
|
|
8377
|
+
if (result.status === "completed") {
|
|
8378
|
+
anyCompleted = true;
|
|
8379
|
+
}
|
|
8380
|
+
logger.info(LOG_KINDS.AGENT_RUN, "Evaluation cell finished", {
|
|
8381
|
+
evaluationId: evalId,
|
|
8382
|
+
runId: result.runId,
|
|
8383
|
+
status: result.status,
|
|
8384
|
+
runtime: cell.runtime,
|
|
8385
|
+
reasoningLevel: cell.reasoningLevel,
|
|
8386
|
+
model: cell.model
|
|
8387
|
+
});
|
|
8388
|
+
} catch (err) {
|
|
8389
|
+
logger.error(LOG_KINDS.AGENT_ERROR, "Evaluation cell threw", {
|
|
8390
|
+
evaluationId: evalId,
|
|
8391
|
+
runtime: cell.runtime,
|
|
8392
|
+
reasoningLevel: cell.reasoningLevel,
|
|
8393
|
+
model: cell.model,
|
|
8394
|
+
error: err instanceof Error ? err.message : String(err)
|
|
8395
|
+
});
|
|
8396
|
+
}
|
|
8397
|
+
}
|
|
8398
|
+
const status = anyCompleted ? EVAL_STATUS_COMPLETED : EVAL_STATUS_FAILED;
|
|
8399
|
+
updateEvaluationStatus(evalId, status, epochSeconds());
|
|
8400
|
+
logger.info(LOG_KINDS.AGENT_RUN, "Evaluation finished", {
|
|
8401
|
+
evaluationId: evalId,
|
|
8402
|
+
status,
|
|
8403
|
+
cellCount: cells.length
|
|
8404
|
+
});
|
|
8405
|
+
})().catch((err) => {
|
|
8406
|
+
logger.error(LOG_KINDS.AGENT_ERROR, "Evaluation fan-out failed", {
|
|
8407
|
+
evaluationId: evalId,
|
|
8408
|
+
error: err instanceof Error ? err.message : String(err)
|
|
8409
|
+
});
|
|
8410
|
+
});
|
|
8411
|
+
return { body: { evaluationId: evalId, cellCount: cells.length } };
|
|
8412
|
+
}
|
|
8413
|
+
async function handleGet(req) {
|
|
8414
|
+
const evaluation = getEvaluation(req.params.id);
|
|
8415
|
+
if (!evaluation) {
|
|
8416
|
+
return { status: 404, body: { error: "Evaluation not found" } };
|
|
8417
|
+
}
|
|
8418
|
+
const runs = listRunsForEvaluation(evaluation.id);
|
|
8419
|
+
const writeIntentsByRun = countWriteIntentsByToolForEvaluation(evaluation.id);
|
|
8420
|
+
return {
|
|
8421
|
+
body: {
|
|
8422
|
+
evaluation: {
|
|
8423
|
+
id: evaluation.id,
|
|
8424
|
+
taskId: evaluation.task_id,
|
|
8425
|
+
matrix: evaluation.matrix,
|
|
8426
|
+
notes: evaluation.notes,
|
|
8427
|
+
status: evaluation.status,
|
|
8428
|
+
createdAt: evaluation.created_at,
|
|
8429
|
+
completedAt: evaluation.completed_at
|
|
8430
|
+
},
|
|
8431
|
+
runs: runs.map(
|
|
8432
|
+
(run) => serializeRun(run, {
|
|
8433
|
+
includeResumeFields: false,
|
|
8434
|
+
includePhaseCheckpoints: false,
|
|
8435
|
+
writeIntents: summarizeFromByTool(writeIntentsByRun[run.id]),
|
|
8436
|
+
duration_ms: runDurationMs(run)
|
|
8437
|
+
})
|
|
8438
|
+
),
|
|
8439
|
+
aggregate: aggregateRuns(runs)
|
|
8440
|
+
}
|
|
8441
|
+
};
|
|
8442
|
+
}
|
|
8443
|
+
async function handleList(req) {
|
|
8444
|
+
const limit = req.query.limit ? Number(req.query.limit) : DEFAULT_LIMIT2;
|
|
8445
|
+
const offset = req.query.offset ? Number(req.query.offset) : 0;
|
|
8446
|
+
const evaluations = listEvaluations({ limit, offset });
|
|
8447
|
+
return {
|
|
8448
|
+
body: {
|
|
8449
|
+
evaluations: evaluations.map((e) => ({
|
|
8450
|
+
id: e.id,
|
|
8451
|
+
taskId: e.task_id,
|
|
8452
|
+
matrix: e.matrix,
|
|
8453
|
+
notes: e.notes,
|
|
8454
|
+
status: e.status,
|
|
8455
|
+
createdAt: e.created_at,
|
|
8456
|
+
completedAt: e.completed_at
|
|
8457
|
+
})),
|
|
8458
|
+
total: evaluations.length
|
|
8459
|
+
}
|
|
8460
|
+
};
|
|
8461
|
+
}
|
|
8462
|
+
return { handleCreate, handleGet, handleList };
|
|
8463
|
+
}
|
|
8464
|
+
|
|
8465
|
+
// src/daemon/api/digest-revisions.ts
|
|
8466
|
+
var DEFAULT_LIMIT3 = 50;
|
|
8467
|
+
var RestoreBody = external_exports.object({
|
|
8468
|
+
/** If supplied, recorded on the new revision row as the run that triggered the restore. */
|
|
8469
|
+
runId: external_exports.string().optional()
|
|
8470
|
+
});
|
|
8471
|
+
function createDigestRevisionHandlers(deps) {
|
|
8472
|
+
const { logger } = deps;
|
|
8473
|
+
async function handleList(req) {
|
|
8474
|
+
const agentId = req.query.agentId || DEFAULT_AGENT_ID;
|
|
8475
|
+
const tierRaw = req.query.tier;
|
|
8476
|
+
if (!tierRaw) {
|
|
8477
|
+
return { status: 400, body: { error: "tier is required" } };
|
|
8478
|
+
}
|
|
8479
|
+
const tier = Number(tierRaw);
|
|
8480
|
+
if (!Number.isFinite(tier)) {
|
|
8481
|
+
return { status: 400, body: { error: `tier must be numeric, got ${tierRaw}` } };
|
|
8482
|
+
}
|
|
8483
|
+
const limit = req.query.limit ? Number(req.query.limit) : DEFAULT_LIMIT3;
|
|
8484
|
+
const revisions = listDigestRevisions({ agentId, tier, limit });
|
|
8485
|
+
return { body: { revisions, count: revisions.length } };
|
|
8486
|
+
}
|
|
8487
|
+
async function handleRestore(req) {
|
|
8488
|
+
const revisionId = Number(req.params.id);
|
|
8489
|
+
if (!Number.isFinite(revisionId)) {
|
|
8490
|
+
return { status: 400, body: { error: "Invalid revision id" } };
|
|
8491
|
+
}
|
|
8492
|
+
const parsed = RestoreBody.safeParse(req.body ?? {});
|
|
8493
|
+
if (!parsed.success) {
|
|
8494
|
+
return {
|
|
8495
|
+
status: 400,
|
|
8496
|
+
body: { error: "Invalid request body", details: parsed.error.flatten() }
|
|
8497
|
+
};
|
|
8498
|
+
}
|
|
8499
|
+
const result = rollbackDigestExtract({
|
|
8500
|
+
revisionId,
|
|
8501
|
+
runId: parsed.data.runId ?? null
|
|
8502
|
+
});
|
|
8503
|
+
if (!result) {
|
|
8504
|
+
return { status: 404, body: { error: "Revision not found" } };
|
|
8505
|
+
}
|
|
8506
|
+
logger.info(LOG_KINDS.AGENT_RUN, "Digest revision restored", {
|
|
8507
|
+
revisionId,
|
|
8508
|
+
newRevisionId: result.newRevisionId,
|
|
8509
|
+
agentId: result.row.agent_id,
|
|
8510
|
+
tier: result.row.tier,
|
|
8511
|
+
triggeredBy: parsed.data.runId ?? "operator"
|
|
8512
|
+
});
|
|
8513
|
+
return {
|
|
8514
|
+
body: {
|
|
8515
|
+
ok: true,
|
|
8516
|
+
restored: revisionId,
|
|
8517
|
+
newRevisionId: result.newRevisionId
|
|
8518
|
+
}
|
|
8519
|
+
};
|
|
8520
|
+
}
|
|
8521
|
+
return { handleList, handleRestore };
|
|
8522
|
+
}
|
|
6974
8523
|
|
|
6975
8524
|
// src/daemon/api/attachments.ts
|
|
6976
|
-
import
|
|
6977
|
-
import
|
|
8525
|
+
import fs19 from "fs";
|
|
8526
|
+
import path19 from "path";
|
|
6978
8527
|
var ATTACHMENT_MEDIA_TYPES = {
|
|
6979
8528
|
png: "image/png",
|
|
6980
8529
|
jpg: "image/jpeg",
|
|
@@ -6994,14 +8543,14 @@ function createAttachmentHandler(deps) {
|
|
|
6994
8543
|
const contentType2 = att.media_type ?? "application/octet-stream";
|
|
6995
8544
|
return { status: 200, headers: { "Content-Type": contentType2 }, body: att.data };
|
|
6996
8545
|
}
|
|
6997
|
-
const filePath =
|
|
8546
|
+
const filePath = path19.join(vaultDir, "attachments", filename);
|
|
6998
8547
|
let diskData;
|
|
6999
8548
|
try {
|
|
7000
|
-
diskData =
|
|
8549
|
+
diskData = fs19.readFileSync(filePath);
|
|
7001
8550
|
} catch {
|
|
7002
8551
|
return { status: 404, body: { error: "not_found" } };
|
|
7003
8552
|
}
|
|
7004
|
-
const ext =
|
|
8553
|
+
const ext = path19.extname(filename).slice(1).toLowerCase();
|
|
7005
8554
|
const contentType = ATTACHMENT_MEDIA_TYPES[ext] ?? "application/octet-stream";
|
|
7006
8555
|
return { status: 200, headers: { "Content-Type": contentType }, body: diskData };
|
|
7007
8556
|
}
|
|
@@ -7009,19 +8558,19 @@ function createAttachmentHandler(deps) {
|
|
|
7009
8558
|
}
|
|
7010
8559
|
|
|
7011
8560
|
// src/daemon/log-reconcile.ts
|
|
7012
|
-
import
|
|
7013
|
-
import
|
|
8561
|
+
import fs20 from "fs";
|
|
8562
|
+
import path20 from "path";
|
|
7014
8563
|
function reconcileLogBuffer(logDir, sinceTimestamp) {
|
|
7015
8564
|
let replayed = 0;
|
|
7016
8565
|
const files = [];
|
|
7017
8566
|
for (let i = 3; i >= 1; i--) {
|
|
7018
|
-
const rotated =
|
|
7019
|
-
if (
|
|
8567
|
+
const rotated = path20.join(logDir, `daemon.${i}.log`);
|
|
8568
|
+
if (fs20.existsSync(rotated)) files.push(rotated);
|
|
7020
8569
|
}
|
|
7021
|
-
const current =
|
|
7022
|
-
if (
|
|
8570
|
+
const current = path20.join(logDir, "daemon.log");
|
|
8571
|
+
if (fs20.existsSync(current)) files.push(current);
|
|
7023
8572
|
for (const file of files) {
|
|
7024
|
-
const content =
|
|
8573
|
+
const content = fs20.readFileSync(file, "utf-8");
|
|
7025
8574
|
for (const line of content.split("\n")) {
|
|
7026
8575
|
if (!line.trim()) continue;
|
|
7027
8576
|
try {
|
|
@@ -7049,11 +8598,14 @@ function reconcileLogBuffer(logDir, sinceTimestamp) {
|
|
|
7049
8598
|
// src/config/focus.ts
|
|
7050
8599
|
var CONFIG_FOCUS_SECTION_PARAM = "configSection";
|
|
7051
8600
|
var CONFIG_FOCUS_FIELD_PARAM = "configField";
|
|
8601
|
+
var CONFIG_FOCUS_TAB_PARAM = "tab";
|
|
7052
8602
|
var CONFIG_SECTION_IDS = {
|
|
7053
8603
|
appearance: "config-section-appearance",
|
|
8604
|
+
cortexInstructions: "config-section-cortex-instructions",
|
|
8605
|
+
cortexBuilder: "config-section-cortex-builder",
|
|
8606
|
+
cortexDigest: "config-section-cortex-digest",
|
|
7054
8607
|
settingsAgent: "config-section-settings-agent",
|
|
7055
8608
|
settingsEmbedding: "config-section-settings-embedding",
|
|
7056
|
-
settingsContextInjection: "config-section-settings-context-injection",
|
|
7057
8609
|
settingsNotifications: "config-section-settings-notifications",
|
|
7058
8610
|
settingsPlanCapture: "config-section-settings-plan-capture",
|
|
7059
8611
|
settingsProject: "config-section-settings-project",
|
|
@@ -7080,11 +8632,30 @@ var SECTION_RULES = [
|
|
|
7080
8632
|
sectionId: CONFIG_SECTION_IDS.settingsEmbedding,
|
|
7081
8633
|
sectionLabel: "Embedding"
|
|
7082
8634
|
},
|
|
8635
|
+
{
|
|
8636
|
+
prefix: "context.digest_tier",
|
|
8637
|
+
page: "/cortex",
|
|
8638
|
+
sectionId: CONFIG_SECTION_IDS.cortexDigest,
|
|
8639
|
+
sectionLabel: "Digest",
|
|
8640
|
+
searchParams: { [CONFIG_FOCUS_TAB_PARAM]: "digest" }
|
|
8641
|
+
},
|
|
8642
|
+
{
|
|
8643
|
+
prefix: "context.cortex",
|
|
8644
|
+
page: "/cortex",
|
|
8645
|
+
sectionId: CONFIG_SECTION_IDS.cortexInstructions,
|
|
8646
|
+
sectionLabel: "Instructions"
|
|
8647
|
+
},
|
|
8648
|
+
{
|
|
8649
|
+
prefix: "context.prompt",
|
|
8650
|
+
page: "/cortex",
|
|
8651
|
+
sectionId: CONFIG_SECTION_IDS.cortexInstructions,
|
|
8652
|
+
sectionLabel: "Instructions"
|
|
8653
|
+
},
|
|
7083
8654
|
{
|
|
7084
8655
|
prefix: "context",
|
|
7085
|
-
page: "/
|
|
7086
|
-
sectionId: CONFIG_SECTION_IDS.
|
|
7087
|
-
sectionLabel: "
|
|
8656
|
+
page: "/cortex",
|
|
8657
|
+
sectionId: CONFIG_SECTION_IDS.cortexInstructions,
|
|
8658
|
+
sectionLabel: "Instructions"
|
|
7088
8659
|
},
|
|
7089
8660
|
{
|
|
7090
8661
|
prefix: "notifications",
|
|
@@ -7151,7 +8722,9 @@ var EXACT_FIELD_LABELS = {
|
|
|
7151
8722
|
"embedding.provider": "Provider",
|
|
7152
8723
|
"embedding.model": "Model",
|
|
7153
8724
|
"embedding.base_url": "Base URL",
|
|
7154
|
-
"context.digest_tier": "Digest Tier",
|
|
8725
|
+
"context.digest_tier": "Preferred Digest Tier",
|
|
8726
|
+
"context.session_start_digest_enabled": "Session-Start Digest",
|
|
8727
|
+
"context.cortex_enabled": "Session-Start Instructions",
|
|
7155
8728
|
"context.prompt_search": "Prompt Search",
|
|
7156
8729
|
"context.prompt_max_spores": "Max Spores per Prompt",
|
|
7157
8730
|
"notifications.enabled": "Notifications",
|
|
@@ -7172,8 +8745,8 @@ var EXACT_FIELD_LABELS = {
|
|
|
7172
8745
|
var DYNAMIC_FIELD_LABEL_RULES = [
|
|
7173
8746
|
{
|
|
7174
8747
|
prefix: "notifications.domains.",
|
|
7175
|
-
format: (
|
|
7176
|
-
const match = /^notifications\.domains\.([^.]+)\.(enabled|mode)$/.exec(
|
|
8748
|
+
format: (path25) => {
|
|
8749
|
+
const match = /^notifications\.domains\.([^.]+)\.(enabled|mode)$/.exec(path25);
|
|
7177
8750
|
if (!match) return null;
|
|
7178
8751
|
const [, domain, leaf] = match;
|
|
7179
8752
|
const domainLabel = humanizeToken(domain);
|
|
@@ -7182,13 +8755,13 @@ var DYNAMIC_FIELD_LABEL_RULES = [
|
|
|
7182
8755
|
}
|
|
7183
8756
|
];
|
|
7184
8757
|
var SAVE_MESSAGE_LABEL_LIMIT = 3;
|
|
7185
|
-
function resolveConfigFocusTarget(
|
|
7186
|
-
const section = findSectionRule(
|
|
8758
|
+
function resolveConfigFocusTarget(path25) {
|
|
8759
|
+
const section = findSectionRule(path25);
|
|
7187
8760
|
if (!section) return null;
|
|
7188
8761
|
return {
|
|
7189
8762
|
...section,
|
|
7190
|
-
fieldPath:
|
|
7191
|
-
fieldLabel: resolveFieldLabel(
|
|
8763
|
+
fieldPath: path25,
|
|
8764
|
+
fieldLabel: resolveFieldLabel(path25)
|
|
7192
8765
|
};
|
|
7193
8766
|
}
|
|
7194
8767
|
function buildConfigFocusLink(target) {
|
|
@@ -7223,25 +8796,25 @@ function buildScopedConfigSaveNotification(scope, touchedPaths) {
|
|
|
7223
8796
|
}
|
|
7224
8797
|
};
|
|
7225
8798
|
}
|
|
7226
|
-
function findSectionRule(
|
|
8799
|
+
function findSectionRule(path25) {
|
|
7227
8800
|
for (const rule of SECTION_RULES) {
|
|
7228
|
-
if (
|
|
8801
|
+
if (path25 === rule.prefix || path25.startsWith(`${rule.prefix}.`)) {
|
|
7229
8802
|
const { page, sectionId, sectionLabel, searchParams } = rule;
|
|
7230
8803
|
return { page, sectionId, sectionLabel, searchParams };
|
|
7231
8804
|
}
|
|
7232
8805
|
}
|
|
7233
8806
|
return null;
|
|
7234
8807
|
}
|
|
7235
|
-
function resolveFieldLabel(
|
|
7236
|
-
const exact = EXACT_FIELD_LABELS[
|
|
8808
|
+
function resolveFieldLabel(path25) {
|
|
8809
|
+
const exact = EXACT_FIELD_LABELS[path25];
|
|
7237
8810
|
if (exact) return exact;
|
|
7238
8811
|
for (const rule of DYNAMIC_FIELD_LABEL_RULES) {
|
|
7239
|
-
if (
|
|
7240
|
-
const label = rule.format(
|
|
8812
|
+
if (path25 === rule.prefix || path25.startsWith(rule.prefix)) {
|
|
8813
|
+
const label = rule.format(path25);
|
|
7241
8814
|
if (label) return label;
|
|
7242
8815
|
}
|
|
7243
8816
|
}
|
|
7244
|
-
return humanizeToken(
|
|
8817
|
+
return humanizeToken(path25.split(".").pop() ?? "setting");
|
|
7245
8818
|
}
|
|
7246
8819
|
function humanizeToken(value) {
|
|
7247
8820
|
return value.split(/[-_]/g).filter(Boolean).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join(" ");
|
|
@@ -7361,6 +8934,48 @@ var PowerManager = class {
|
|
|
7361
8934
|
}
|
|
7362
8935
|
};
|
|
7363
8936
|
|
|
8937
|
+
// src/daemon/inflight-runs.ts
|
|
8938
|
+
var DEFAULT_DRAIN_TIMEOUT_MS = 3e4;
|
|
8939
|
+
var InflightRunRegistry = class {
|
|
8940
|
+
runs = /* @__PURE__ */ new Set();
|
|
8941
|
+
/**
|
|
8942
|
+
* Track a fire-and-forget agent run. The promise is removed from the
|
|
8943
|
+
* registry in a finally handler so a resolved/rejected run does not hold
|
|
8944
|
+
* memory. Resolves immediately — callers must not await this directly.
|
|
8945
|
+
*/
|
|
8946
|
+
register(promise) {
|
|
8947
|
+
const tracked = Promise.resolve(promise).finally(() => {
|
|
8948
|
+
this.runs.delete(tracked);
|
|
8949
|
+
});
|
|
8950
|
+
this.runs.add(tracked);
|
|
8951
|
+
}
|
|
8952
|
+
/** Number of runs currently being tracked. */
|
|
8953
|
+
get size() {
|
|
8954
|
+
return this.runs.size;
|
|
8955
|
+
}
|
|
8956
|
+
/**
|
|
8957
|
+
* Wait for every tracked run to settle, up to `timeoutMs`. Returns when
|
|
8958
|
+
* either every run completes or the deadline elapses — whichever happens
|
|
8959
|
+
* first. The 30-second default mirrors a typical daemon shutdown budget;
|
|
8960
|
+
* callers are free to override for tests or tighter environments.
|
|
8961
|
+
*/
|
|
8962
|
+
async drain(timeoutMs = DEFAULT_DRAIN_TIMEOUT_MS) {
|
|
8963
|
+
if (this.runs.size === 0) return { settled: true, remaining: 0 };
|
|
8964
|
+
const snapshot = Array.from(this.runs);
|
|
8965
|
+
let timer;
|
|
8966
|
+
const timeoutPromise = new Promise((resolve3) => {
|
|
8967
|
+
timer = setTimeout(() => resolve3("timeout"), timeoutMs);
|
|
8968
|
+
});
|
|
8969
|
+
const allSettled = Promise.allSettled(snapshot).then(() => "settled");
|
|
8970
|
+
try {
|
|
8971
|
+
const outcome = await Promise.race([allSettled, timeoutPromise]);
|
|
8972
|
+
return { settled: outcome === "settled", remaining: this.runs.size };
|
|
8973
|
+
} finally {
|
|
8974
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
8975
|
+
}
|
|
8976
|
+
}
|
|
8977
|
+
};
|
|
8978
|
+
|
|
7364
8979
|
// src/daemon/jobs/session-maintenance.ts
|
|
7365
8980
|
function completeStaleActiveSessions(thresholdSeconds = STALE_SESSION_THRESHOLD_MS / MS_PER_SECOND) {
|
|
7366
8981
|
const db = getDatabase();
|
|
@@ -7505,8 +9120,8 @@ function registerPowerJobs(powerManager, deps) {
|
|
|
7505
9120
|
}
|
|
7506
9121
|
|
|
7507
9122
|
// src/daemon/reconciliation.ts
|
|
7508
|
-
import
|
|
7509
|
-
import
|
|
9123
|
+
import fs21 from "fs";
|
|
9124
|
+
import path21 from "path";
|
|
7510
9125
|
|
|
7511
9126
|
// src/daemon/event-handlers.ts
|
|
7512
9127
|
var TOOL_INPUT_STORE_LIMIT = 4e3;
|
|
@@ -7675,10 +9290,10 @@ function createReconciler({ bufferDir, logger }) {
|
|
|
7675
9290
|
function reconcileSession(sessionId) {
|
|
7676
9291
|
if (reconciledSessions.has(sessionId)) return;
|
|
7677
9292
|
reconciledSessions.add(sessionId);
|
|
7678
|
-
const bufferPath =
|
|
9293
|
+
const bufferPath = path21.join(bufferDir, `${sessionId}.jsonl`);
|
|
7679
9294
|
let content;
|
|
7680
9295
|
try {
|
|
7681
|
-
content =
|
|
9296
|
+
content = fs21.readFileSync(bufferPath, "utf-8").trim();
|
|
7682
9297
|
} catch {
|
|
7683
9298
|
return;
|
|
7684
9299
|
}
|
|
@@ -7747,7 +9362,19 @@ function createReconciler({ bufferDir, logger }) {
|
|
|
7747
9362
|
}
|
|
7748
9363
|
|
|
7749
9364
|
// src/daemon/stop-processing.ts
|
|
7750
|
-
import
|
|
9365
|
+
import fs22 from "fs";
|
|
9366
|
+
import path22 from "path";
|
|
9367
|
+
|
|
9368
|
+
// src/daemon/capture-gating.ts
|
|
9369
|
+
function gateEventByCaptureRules(event, options) {
|
|
9370
|
+
const transcriptMeta = event.transcriptPath ? readTranscriptMeta(event.transcriptPath) ?? void 0 : void 0;
|
|
9371
|
+
const manifests = options?.manifests ?? loadManifests();
|
|
9372
|
+
const decision = evaluateSessionCaptureRules(manifests, event.agent, {
|
|
9373
|
+
transcriptPath: event.transcriptPath,
|
|
9374
|
+
transcriptMeta
|
|
9375
|
+
});
|
|
9376
|
+
return { decision, hadTranscriptMeta: transcriptMeta !== void 0 };
|
|
9377
|
+
}
|
|
7751
9378
|
|
|
7752
9379
|
// src/daemon/capture-images.ts
|
|
7753
9380
|
var SESSION_SHORT_LEN = 6;
|
|
@@ -7784,80 +9411,8 @@ function captureBatchImages(input) {
|
|
|
7784
9411
|
}
|
|
7785
9412
|
}
|
|
7786
9413
|
|
|
7787
|
-
// src/daemon/plan-capture.ts
|
|
7788
|
-
import { createHash as createHash4 } from "crypto";
|
|
7789
|
-
import os8 from "os";
|
|
7790
|
-
import path20 from "path";
|
|
7791
|
-
function extractTaggedPlans(text, tags) {
|
|
7792
|
-
const results = [];
|
|
7793
|
-
for (const tag of tags) {
|
|
7794
|
-
const regex = new RegExp(`<${tag}>\\n?([\\s\\S]*?)\\n?</${tag}>`, "g");
|
|
7795
|
-
let match;
|
|
7796
|
-
while ((match = regex.exec(text)) !== null) {
|
|
7797
|
-
const content = match[1].trim();
|
|
7798
|
-
if (content) results.push({ tag, content });
|
|
7799
|
-
}
|
|
7800
|
-
}
|
|
7801
|
-
return results;
|
|
7802
|
-
}
|
|
7803
|
-
var TRANSCRIPT_SOURCE_PREFIX = "transcript:";
|
|
7804
|
-
var FILE_WRITE_TOOLS = /* @__PURE__ */ new Set([
|
|
7805
|
-
"Write",
|
|
7806
|
-
"Edit",
|
|
7807
|
-
"Create",
|
|
7808
|
-
"write",
|
|
7809
|
-
"edit",
|
|
7810
|
-
"patch",
|
|
7811
|
-
"create"
|
|
7812
|
-
]);
|
|
7813
|
-
var HEADING_REGEX = /^#\s+(.+)$/m;
|
|
7814
|
-
var PLAN_ID_HASH_LENGTH = 16;
|
|
7815
|
-
function isInPlanDirectory(filePath, watchDirs, projectRoot) {
|
|
7816
|
-
const abs = path20.isAbsolute(filePath) ? filePath : path20.resolve(projectRoot, filePath);
|
|
7817
|
-
return watchDirs.some((dir) => {
|
|
7818
|
-
const expanded = dir.startsWith("~/") ? path20.join(os8.homedir(), dir.slice(2)) : dir;
|
|
7819
|
-
const absDir = path20.isAbsolute(expanded) ? expanded : path20.resolve(projectRoot, expanded);
|
|
7820
|
-
const prefix = absDir.endsWith(path20.sep) ? absDir : absDir + path20.sep;
|
|
7821
|
-
return abs === absDir || abs.startsWith(prefix);
|
|
7822
|
-
});
|
|
7823
|
-
}
|
|
7824
|
-
function isPlanWriteEvent(toolName, toolInput, config) {
|
|
7825
|
-
if (!FILE_WRITE_TOOLS.has(toolName)) return null;
|
|
7826
|
-
const filePath = toolInput?.file_path ?? toolInput?.path ?? toolInput?.filePath;
|
|
7827
|
-
if (typeof filePath !== "string") return null;
|
|
7828
|
-
if (!isInPlanDirectory(filePath, config.watchDirs, config.projectRoot)) return null;
|
|
7829
|
-
if (config.extensions?.length) {
|
|
7830
|
-
const ext = path20.extname(filePath).toLowerCase();
|
|
7831
|
-
if (!config.extensions.includes(ext)) return null;
|
|
7832
|
-
}
|
|
7833
|
-
return filePath;
|
|
7834
|
-
}
|
|
7835
|
-
function parsePlanTitle(content, filename) {
|
|
7836
|
-
const match = HEADING_REGEX.exec(content);
|
|
7837
|
-
if (match) return match[1].trim();
|
|
7838
|
-
return filename ?? null;
|
|
7839
|
-
}
|
|
7840
|
-
function capturePlan(input) {
|
|
7841
|
-
const now = Math.floor(Date.now() / 1e3);
|
|
7842
|
-
const contentHash = createHash4(CONTENT_HASH_ALGORITHM).update(input.content).digest("hex");
|
|
7843
|
-
const id = createHash4("md5").update(input.sourcePath).digest("hex").slice(0, PLAN_ID_HASH_LENGTH);
|
|
7844
|
-
const title = parsePlanTitle(input.content, path20.basename(input.sourcePath));
|
|
7845
|
-
return upsertPlan({
|
|
7846
|
-
id,
|
|
7847
|
-
title,
|
|
7848
|
-
content: input.content,
|
|
7849
|
-
source_path: input.sourcePath,
|
|
7850
|
-
session_id: input.sessionId,
|
|
7851
|
-
prompt_batch_id: input.promptBatchId ?? null,
|
|
7852
|
-
content_hash: contentHash,
|
|
7853
|
-
status: "active",
|
|
7854
|
-
created_at: now,
|
|
7855
|
-
updated_at: now
|
|
7856
|
-
});
|
|
7857
|
-
}
|
|
7858
|
-
|
|
7859
9414
|
// src/daemon/skill-usage.ts
|
|
7860
|
-
import
|
|
9415
|
+
import crypto2 from "crypto";
|
|
7861
9416
|
var SKILL_USAGE_DETECTION_ENABLED = false;
|
|
7862
9417
|
var MAX_ACTIVE_SKILLS_CHECK = 1e3;
|
|
7863
9418
|
function detectSkillUsage(sessionId, transcriptContent) {
|
|
@@ -7877,7 +9432,7 @@ function detectSkillUsage(sessionId, transcriptContent) {
|
|
|
7877
9432
|
if (!pattern.test(transcriptContent)) continue;
|
|
7878
9433
|
if (hasUsageForSkillAndSession(skill.id, sessionId)) continue;
|
|
7879
9434
|
insertSkillUsage({
|
|
7880
|
-
id:
|
|
9435
|
+
id: crypto2.randomUUID(),
|
|
7881
9436
|
skill_id: skill.id,
|
|
7882
9437
|
session_id: sessionId,
|
|
7883
9438
|
detected_at: now
|
|
@@ -7892,6 +9447,46 @@ function escapeRegex(s) {
|
|
|
7892
9447
|
}
|
|
7893
9448
|
|
|
7894
9449
|
// src/daemon/stop-processing.ts
|
|
9450
|
+
var MILLISECONDS_PER_SECOND = 1e3;
|
|
9451
|
+
function isEligiblePlanExtension(filePath, extensions) {
|
|
9452
|
+
if (!extensions || extensions.length === 0) return true;
|
|
9453
|
+
const extension = path22.extname(filePath).toLowerCase();
|
|
9454
|
+
return extensions.includes(extension);
|
|
9455
|
+
}
|
|
9456
|
+
function collectPlanFiles(rootDir, extensions) {
|
|
9457
|
+
const files = [];
|
|
9458
|
+
const stack = [rootDir];
|
|
9459
|
+
while (stack.length > 0) {
|
|
9460
|
+
const currentDir = stack.pop();
|
|
9461
|
+
if (!currentDir) continue;
|
|
9462
|
+
let entries;
|
|
9463
|
+
try {
|
|
9464
|
+
entries = fs22.readdirSync(currentDir, { withFileTypes: true });
|
|
9465
|
+
} catch {
|
|
9466
|
+
continue;
|
|
9467
|
+
}
|
|
9468
|
+
for (const entry of entries) {
|
|
9469
|
+
const absolutePath = path22.join(currentDir, entry.name);
|
|
9470
|
+
if (entry.isDirectory()) {
|
|
9471
|
+
stack.push(absolutePath);
|
|
9472
|
+
continue;
|
|
9473
|
+
}
|
|
9474
|
+
if (entry.isFile() && isEligiblePlanExtension(absolutePath, extensions)) {
|
|
9475
|
+
files.push(absolutePath);
|
|
9476
|
+
}
|
|
9477
|
+
}
|
|
9478
|
+
}
|
|
9479
|
+
return files;
|
|
9480
|
+
}
|
|
9481
|
+
function resolvePromptBatchIdForPlanWrite(batches, modifiedAtSeconds) {
|
|
9482
|
+
for (let index = batches.length - 1; index >= 0; index--) {
|
|
9483
|
+
const startedAt = batches[index].started_at;
|
|
9484
|
+
if (startedAt !== null && startedAt <= modifiedAtSeconds) {
|
|
9485
|
+
return batches[index].id;
|
|
9486
|
+
}
|
|
9487
|
+
}
|
|
9488
|
+
return void 0;
|
|
9489
|
+
}
|
|
7895
9490
|
function enrichTurnsWithToolMetadata(turns, events) {
|
|
7896
9491
|
if (events.length === 0 || turns.length === 0) return;
|
|
7897
9492
|
const toolEvents = events.filter((e) => e.type === "tool_use");
|
|
@@ -7919,7 +9514,7 @@ function enrichTurnsWithToolMetadata(turns, events) {
|
|
|
7919
9514
|
}
|
|
7920
9515
|
}
|
|
7921
9516
|
function createStopProcessor(deps) {
|
|
7922
|
-
const { registry, sessionBuffers, transcriptMiner, embeddingManager, logger, liveConfig, vaultDir } = deps;
|
|
9517
|
+
const { registry, sessionBuffers, transcriptMiner, embeddingManager, logger, liveConfig, vaultDir, planWatchConfig } = deps;
|
|
7923
9518
|
let activeStopProcessing = null;
|
|
7924
9519
|
const sessionTitleCache = /* @__PURE__ */ new Map();
|
|
7925
9520
|
const StopBody = external_exports.object({
|
|
@@ -8021,7 +9616,7 @@ function createStopProcessor(deps) {
|
|
|
8021
9616
|
let transcriptText = null;
|
|
8022
9617
|
if (hookTranscriptPath) {
|
|
8023
9618
|
try {
|
|
8024
|
-
transcriptText =
|
|
9619
|
+
transcriptText = fs22.readFileSync(hookTranscriptPath, "utf-8");
|
|
8025
9620
|
} catch {
|
|
8026
9621
|
}
|
|
8027
9622
|
}
|
|
@@ -8053,11 +9648,12 @@ function createStopProcessor(deps) {
|
|
|
8053
9648
|
const taggedPlans = extractTaggedPlans(turn.aiResponse, deps.planTags);
|
|
8054
9649
|
for (const { tag, content } of taggedPlans) {
|
|
8055
9650
|
try {
|
|
8056
|
-
|
|
8057
|
-
|
|
9651
|
+
captureTaggedPlan({
|
|
9652
|
+
tag,
|
|
8058
9653
|
content,
|
|
8059
9654
|
sessionId,
|
|
8060
|
-
promptBatchId: latestBatch?.id ?? null
|
|
9655
|
+
promptBatchId: latestBatch?.id ?? null,
|
|
9656
|
+
logger
|
|
8061
9657
|
});
|
|
8062
9658
|
logger.info(LOG_KINDS.CAPTURE_PLAN, "Plan captured from transcript tag", {
|
|
8063
9659
|
session_id: sessionId,
|
|
@@ -8074,6 +9670,50 @@ function createStopProcessor(deps) {
|
|
|
8074
9670
|
}
|
|
8075
9671
|
}
|
|
8076
9672
|
}
|
|
9673
|
+
const sessionStartedAt = currentSession?.started_at ?? (sessionMeta?.started_at ? Math.floor(new Date(sessionMeta.started_at).getTime() / MILLISECONDS_PER_SECOND) : epochSeconds());
|
|
9674
|
+
const sessionStopMs = Date.now();
|
|
9675
|
+
const sessionBatches = listBatchesBySession(sessionId);
|
|
9676
|
+
for (const watchDir of planWatchConfig.watchDirs) {
|
|
9677
|
+
const absoluteWatchDir = resolvePlanWatchDir(watchDir, planWatchConfig.projectRoot);
|
|
9678
|
+
if (!fs22.existsSync(absoluteWatchDir)) continue;
|
|
9679
|
+
const planFiles = collectPlanFiles(absoluteWatchDir, planWatchConfig.extensions);
|
|
9680
|
+
for (const planFile of planFiles) {
|
|
9681
|
+
let stats;
|
|
9682
|
+
try {
|
|
9683
|
+
stats = fs22.statSync(planFile);
|
|
9684
|
+
} catch {
|
|
9685
|
+
continue;
|
|
9686
|
+
}
|
|
9687
|
+
if (stats.mtimeMs < sessionStartedAt * MILLISECONDS_PER_SECOND || stats.mtimeMs > sessionStopMs) {
|
|
9688
|
+
continue;
|
|
9689
|
+
}
|
|
9690
|
+
try {
|
|
9691
|
+
const content = fs22.readFileSync(planFile, "utf-8");
|
|
9692
|
+
const promptBatchId = resolvePromptBatchIdForPlanWrite(
|
|
9693
|
+
sessionBatches,
|
|
9694
|
+
Math.floor(stats.mtimeMs / MILLISECONDS_PER_SECOND)
|
|
9695
|
+
);
|
|
9696
|
+
capturePlan({
|
|
9697
|
+
sourcePath: planFile,
|
|
9698
|
+
projectRoot: planWatchConfig.projectRoot,
|
|
9699
|
+
content,
|
|
9700
|
+
sessionId,
|
|
9701
|
+
promptBatchId,
|
|
9702
|
+
logger
|
|
9703
|
+
});
|
|
9704
|
+
logger.info(LOG_KINDS.CAPTURE_PLAN, "Plan reconciled from configured plan dir", {
|
|
9705
|
+
session_id: sessionId,
|
|
9706
|
+
source_path: planFile
|
|
9707
|
+
});
|
|
9708
|
+
} catch (err) {
|
|
9709
|
+
logger.warn(LOG_KINDS.CAPTURE_PLAN, "Failed to reconcile plan from configured plan dir", {
|
|
9710
|
+
session_id: sessionId,
|
|
9711
|
+
source_path: planFile,
|
|
9712
|
+
error: err.message
|
|
9713
|
+
});
|
|
9714
|
+
}
|
|
9715
|
+
}
|
|
9716
|
+
}
|
|
8077
9717
|
if (!hasTitle) {
|
|
8078
9718
|
triggerTitleSummary2(sessionId);
|
|
8079
9719
|
}
|
|
@@ -8120,12 +9760,11 @@ function createStopProcessor(deps) {
|
|
|
8120
9760
|
last_assistant_message: lastAssistantMessage
|
|
8121
9761
|
} = StopBody.parse(req.body);
|
|
8122
9762
|
if (hookTranscriptPath) {
|
|
8123
|
-
const transcriptMeta = readTranscriptMeta(hookTranscriptPath) ?? void 0;
|
|
8124
9763
|
const detectedAgent = agent ?? getSession(sessionId)?.agent ?? "claude-code";
|
|
8125
|
-
const decision =
|
|
8126
|
-
transcriptPath: hookTranscriptPath,
|
|
8127
|
-
|
|
8128
|
-
|
|
9764
|
+
const { decision } = gateEventByCaptureRules(
|
|
9765
|
+
{ agent: detectedAgent, transcriptPath: hookTranscriptPath },
|
|
9766
|
+
{ manifests: loadManifests() }
|
|
9767
|
+
);
|
|
8129
9768
|
if (decision.action === "drop") {
|
|
8130
9769
|
const deleted = cleanupInvalidCapturedSession(sessionId);
|
|
8131
9770
|
logger.info(LOG_KINDS.HOOKS_STOP, "Stop ignored \u2014 invalid captured session", {
|
|
@@ -8180,9 +9819,10 @@ function createStopProcessor(deps) {
|
|
|
8180
9819
|
}
|
|
8181
9820
|
|
|
8182
9821
|
// src/daemon/event-dispatch.ts
|
|
8183
|
-
import
|
|
8184
|
-
import
|
|
9822
|
+
import fs23 from "fs";
|
|
9823
|
+
import path23 from "path";
|
|
8185
9824
|
var EventBody = external_exports.object({ type: external_exports.string(), session_id: external_exports.string() }).passthrough();
|
|
9825
|
+
var DROP_DECISION_CACHE_MAX = 1024;
|
|
8186
9826
|
function createEventDispatcher(deps) {
|
|
8187
9827
|
const {
|
|
8188
9828
|
registry,
|
|
@@ -8197,6 +9837,39 @@ function createEventDispatcher(deps) {
|
|
|
8197
9837
|
triggerTitleSummary: triggerTitleSummary2
|
|
8198
9838
|
} = deps;
|
|
8199
9839
|
const projectRoot = process.cwd();
|
|
9840
|
+
const manifests = loadManifests();
|
|
9841
|
+
const planTagsByAgent = new Map(
|
|
9842
|
+
manifests.map((manifest) => [manifest.name, manifest.capture?.planTags ?? []])
|
|
9843
|
+
);
|
|
9844
|
+
const droppedSessions = /* @__PURE__ */ new Map();
|
|
9845
|
+
function rememberDropped(sessionId, reason, hadTranscriptMeta) {
|
|
9846
|
+
if (droppedSessions.size >= DROP_DECISION_CACHE_MAX) {
|
|
9847
|
+
const oldest = droppedSessions.keys().next().value;
|
|
9848
|
+
if (oldest !== void 0) droppedSessions.delete(oldest);
|
|
9849
|
+
}
|
|
9850
|
+
droppedSessions.set(sessionId, { reason, hadTranscriptMeta });
|
|
9851
|
+
}
|
|
9852
|
+
function evaluateAutoRegistration(event) {
|
|
9853
|
+
const transcriptPath = typeof event.transcript_path === "string" && event.transcript_path.length > 0 ? event.transcript_path : void 0;
|
|
9854
|
+
const detectedAgent = typeof event.agent === "string" ? event.agent : DEFAULT_SYMBIONT_NAME;
|
|
9855
|
+
try {
|
|
9856
|
+
return gateEventByCaptureRules(
|
|
9857
|
+
{ agent: detectedAgent, transcriptPath },
|
|
9858
|
+
{ manifests }
|
|
9859
|
+
);
|
|
9860
|
+
} catch (err) {
|
|
9861
|
+
logger.error(LOG_KINDS.LIFECYCLE_AUTO_REGISTER, "Capture-rules evaluator threw", {
|
|
9862
|
+
error: String(err),
|
|
9863
|
+
session_id: typeof event.session_id === "string" ? event.session_id : void 0,
|
|
9864
|
+
agent: detectedAgent
|
|
9865
|
+
});
|
|
9866
|
+
return { decision: { action: "pass" }, hadTranscriptMeta: false };
|
|
9867
|
+
}
|
|
9868
|
+
}
|
|
9869
|
+
function getPlanTagsForAgent(agent) {
|
|
9870
|
+
const agentName = typeof agent === "string" && agent.length > 0 ? agent : DEFAULT_SYMBIONT_NAME;
|
|
9871
|
+
return planTagsByAgent.get(agentName) ?? [];
|
|
9872
|
+
}
|
|
8200
9873
|
return async (req) => {
|
|
8201
9874
|
const validated = EventBody.parse(req.body);
|
|
8202
9875
|
const event = {
|
|
@@ -8205,13 +9878,38 @@ function createEventDispatcher(deps) {
|
|
|
8205
9878
|
};
|
|
8206
9879
|
logger.debug(LOG_KINDS.HOOKS_EVENT, "Event received", { type: event.type, session_id: event.session_id });
|
|
8207
9880
|
if (!registry.getSession(event.session_id)) {
|
|
9881
|
+
const cached = droppedSessions.get(event.session_id);
|
|
9882
|
+
const hasTranscriptNow = typeof event.transcript_path === "string" && event.transcript_path.length > 0;
|
|
9883
|
+
const shouldReevaluate = cached && !cached.hadTranscriptMeta && hasTranscriptNow;
|
|
9884
|
+
if (cached && !shouldReevaluate) {
|
|
9885
|
+
const reason = cached.reason ?? "rule";
|
|
9886
|
+
logger.debug(LOG_KINDS.LIFECYCLE_AUTO_REGISTER, "Ignored event for previously-dropped session", {
|
|
9887
|
+
session_id: event.session_id,
|
|
9888
|
+
type: event.type,
|
|
9889
|
+
reason
|
|
9890
|
+
});
|
|
9891
|
+
return { body: { ok: true, ignored: reason } };
|
|
9892
|
+
}
|
|
9893
|
+
if (shouldReevaluate) {
|
|
9894
|
+
droppedSessions.delete(event.session_id);
|
|
9895
|
+
}
|
|
9896
|
+
const { decision, hadTranscriptMeta } = evaluateAutoRegistration(event);
|
|
9897
|
+
if (decision.action === "drop") {
|
|
9898
|
+
rememberDropped(event.session_id, decision.reason, hadTranscriptMeta);
|
|
9899
|
+
logger.info(LOG_KINDS.LIFECYCLE_AUTO_REGISTER, "Ignored event that failed session capture rules", {
|
|
9900
|
+
session_id: event.session_id,
|
|
9901
|
+
type: event.type,
|
|
9902
|
+
reason: decision.reason ?? "rule"
|
|
9903
|
+
});
|
|
9904
|
+
return { body: { ok: true, ignored: decision.reason ?? "rule" } };
|
|
9905
|
+
}
|
|
8208
9906
|
registry.register(event.session_id, { started_at: event.timestamp });
|
|
8209
9907
|
logger.debug(LOG_KINDS.LIFECYCLE_AUTO_REGISTER, "Auto-registered session from event", { session_id: event.session_id });
|
|
8210
9908
|
const now = epochSeconds();
|
|
8211
9909
|
const startedEpoch = Math.floor(new Date(event.timestamp).getTime() / 1e3);
|
|
8212
9910
|
upsertSession({
|
|
8213
9911
|
id: event.session_id,
|
|
8214
|
-
agent: event.agent ??
|
|
9912
|
+
agent: event.agent ?? DEFAULT_SYMBIONT_NAME,
|
|
8215
9913
|
status: "active",
|
|
8216
9914
|
started_at: startedEpoch,
|
|
8217
9915
|
created_at: now,
|
|
@@ -8220,7 +9918,7 @@ function createEventDispatcher(deps) {
|
|
|
8220
9918
|
reconcileSession(event.session_id);
|
|
8221
9919
|
}
|
|
8222
9920
|
if (!sessionBuffers.has(event.session_id)) {
|
|
8223
|
-
const bufferDir =
|
|
9921
|
+
const bufferDir = path23.join(vaultDir, "buffer");
|
|
8224
9922
|
sessionBuffers.set(event.session_id, new EventBuffer(bufferDir, event.session_id));
|
|
8225
9923
|
}
|
|
8226
9924
|
sessionBuffers.get(event.session_id).append(event);
|
|
@@ -8246,6 +9944,29 @@ function createEventDispatcher(deps) {
|
|
|
8246
9944
|
try {
|
|
8247
9945
|
const { batchId, promptNumber } = handleUserPrompt(event.session_id, promptText || void 0);
|
|
8248
9946
|
logger.debug(LOG_KINDS.CAPTURE_BATCH, "Batch opened", { session_id: event.session_id, batch_id: batchId, prompt_number: promptNumber });
|
|
9947
|
+
const taggedPlans = extractTaggedPlans(promptText, getPlanTagsForAgent(event.agent));
|
|
9948
|
+
for (const { tag, content } of taggedPlans) {
|
|
9949
|
+
try {
|
|
9950
|
+
captureTaggedPlan({
|
|
9951
|
+
tag,
|
|
9952
|
+
content,
|
|
9953
|
+
sessionId: event.session_id,
|
|
9954
|
+
promptBatchId: batchId,
|
|
9955
|
+
logger
|
|
9956
|
+
});
|
|
9957
|
+
logger.info(LOG_KINDS.CAPTURE_PLAN, "Plan captured from prompt tag", {
|
|
9958
|
+
session_id: event.session_id,
|
|
9959
|
+
tag,
|
|
9960
|
+
content_length: content.length
|
|
9961
|
+
});
|
|
9962
|
+
} catch (err) {
|
|
9963
|
+
logger.warn(LOG_KINDS.CAPTURE_PLAN, "Failed to capture plan from prompt tag", {
|
|
9964
|
+
session_id: event.session_id,
|
|
9965
|
+
tag,
|
|
9966
|
+
error: err.message
|
|
9967
|
+
});
|
|
9968
|
+
}
|
|
9969
|
+
}
|
|
8249
9970
|
const eventImages = event.images;
|
|
8250
9971
|
if (Array.isArray(eventImages) && eventImages.length > 0) {
|
|
8251
9972
|
captureBatchImages({
|
|
@@ -8279,13 +10000,15 @@ function createEventDispatcher(deps) {
|
|
|
8279
10000
|
);
|
|
8280
10001
|
if (planFilePath) {
|
|
8281
10002
|
const captureSessionId = event.session_id;
|
|
8282
|
-
|
|
10003
|
+
fs23.promises.readFile(planFilePath, "utf-8").then((planContent) => {
|
|
8283
10004
|
const latestBatch = getLatestBatch(captureSessionId);
|
|
8284
10005
|
capturePlan({
|
|
8285
|
-
sourcePath:
|
|
10006
|
+
sourcePath: planFilePath,
|
|
10007
|
+
projectRoot,
|
|
8286
10008
|
content: planContent,
|
|
8287
10009
|
sessionId: captureSessionId,
|
|
8288
|
-
promptBatchId: latestBatch?.id ?? null
|
|
10010
|
+
promptBatchId: latestBatch?.id ?? null,
|
|
10011
|
+
logger
|
|
8289
10012
|
});
|
|
8290
10013
|
logger.info(LOG_KINDS.CAPTURE_PLAN, "Plan captured", {
|
|
8291
10014
|
session_id: captureSessionId,
|
|
@@ -8445,8 +10168,8 @@ function createConfigReactionRegistry(logger) {
|
|
|
8445
10168
|
function shouldFire(registeredPaths, touched) {
|
|
8446
10169
|
if (registeredPaths.length === 0) return true;
|
|
8447
10170
|
for (const prefix of registeredPaths) {
|
|
8448
|
-
for (const
|
|
8449
|
-
if (
|
|
10171
|
+
for (const path25 of touched) {
|
|
10172
|
+
if (path25 === prefix || path25.startsWith(`${prefix}.`)) return true;
|
|
8450
10173
|
}
|
|
8451
10174
|
}
|
|
8452
10175
|
return false;
|
|
@@ -8480,13 +10203,13 @@ function createPlanWatchReaction(deps) {
|
|
|
8480
10203
|
}
|
|
8481
10204
|
|
|
8482
10205
|
// src/daemon/main.ts
|
|
8483
|
-
import
|
|
8484
|
-
import
|
|
10206
|
+
import fs24 from "fs";
|
|
10207
|
+
import path24 from "path";
|
|
8485
10208
|
function killStaleDaemon(vaultDir, logger) {
|
|
8486
|
-
const daemonJsonPath =
|
|
10209
|
+
const daemonJsonPath = path24.join(vaultDir, "daemon.json");
|
|
8487
10210
|
try {
|
|
8488
|
-
if (!
|
|
8489
|
-
const info = JSON.parse(
|
|
10211
|
+
if (!fs24.existsSync(daemonJsonPath)) return;
|
|
10212
|
+
const info = JSON.parse(fs24.readFileSync(daemonJsonPath, "utf-8"));
|
|
8490
10213
|
if (!info.pid) return;
|
|
8491
10214
|
if (info.pid === process.pid) return;
|
|
8492
10215
|
try {
|
|
@@ -8495,7 +10218,7 @@ function killStaleDaemon(vaultDir, logger) {
|
|
|
8495
10218
|
logger.info(LOG_KINDS.DAEMON_START, "Killed stale daemon", { pid: info.pid });
|
|
8496
10219
|
} catch {
|
|
8497
10220
|
}
|
|
8498
|
-
|
|
10221
|
+
fs24.unlinkSync(daemonJsonPath);
|
|
8499
10222
|
} catch {
|
|
8500
10223
|
}
|
|
8501
10224
|
}
|
|
@@ -8505,7 +10228,7 @@ async function main() {
|
|
|
8505
10228
|
process.stderr.write("Usage: mycod --vault <path>\n");
|
|
8506
10229
|
process.exit(1);
|
|
8507
10230
|
}
|
|
8508
|
-
const vaultDir =
|
|
10231
|
+
const vaultDir = path24.resolve(vaultArg);
|
|
8509
10232
|
loadSecrets(vaultDir);
|
|
8510
10233
|
const config = loadMergedConfig(vaultDir);
|
|
8511
10234
|
const liveConfig = { current: config };
|
|
@@ -8518,7 +10241,7 @@ async function main() {
|
|
|
8518
10241
|
projectRoot,
|
|
8519
10242
|
extensions: config.capture.artifact_extensions
|
|
8520
10243
|
};
|
|
8521
|
-
const logger = new DaemonLogger(
|
|
10244
|
+
const logger = new DaemonLogger(path24.join(vaultDir, "logs"), {
|
|
8522
10245
|
level: config.daemon.log_level
|
|
8523
10246
|
});
|
|
8524
10247
|
if (config.daemon.log_level === "debug") {
|
|
@@ -8547,7 +10270,7 @@ async function main() {
|
|
|
8547
10270
|
const devCliEntry = detectDevBuild(
|
|
8548
10271
|
globalPrefix,
|
|
8549
10272
|
process.argv[1],
|
|
8550
|
-
|
|
10273
|
+
fs24.realpathSync
|
|
8551
10274
|
);
|
|
8552
10275
|
if (devCliEntry) {
|
|
8553
10276
|
setDevBuildCliEntry(devCliEntry);
|
|
@@ -8559,13 +10282,19 @@ async function main() {
|
|
|
8559
10282
|
const db = initDatabase(vaultDbPath(vaultDir));
|
|
8560
10283
|
createSchema(db, machineId);
|
|
8561
10284
|
registerBuiltinDomains();
|
|
10285
|
+
const interruptedRuns = markRunningRunsInterrupted("Daemon restarted before the run completed");
|
|
10286
|
+
if (interruptedRuns > 0) {
|
|
10287
|
+
logger.warn(LOG_KINDS.AGENT_RUN, "Marked stale running runs as resumable after daemon restart", {
|
|
10288
|
+
count: interruptedRuns
|
|
10289
|
+
});
|
|
10290
|
+
}
|
|
8562
10291
|
logger.info(LOG_KINDS.DAEMON_START, "SQLite initialized", { vault: vaultDir });
|
|
8563
10292
|
{
|
|
8564
|
-
const reasonPath =
|
|
10293
|
+
const reasonPath = path24.join(vaultDir, RESTART_REASON_FILENAME);
|
|
8565
10294
|
try {
|
|
8566
|
-
if (
|
|
8567
|
-
const raw = JSON.parse(
|
|
8568
|
-
|
|
10295
|
+
if (fs24.existsSync(reasonPath)) {
|
|
10296
|
+
const raw = JSON.parse(fs24.readFileSync(reasonPath, "utf-8"));
|
|
10297
|
+
fs24.unlinkSync(reasonPath);
|
|
8569
10298
|
if (raw.reason === "version_sync" && raw.to_version) {
|
|
8570
10299
|
const message = raw.local_update_ran ? "Restarted and updated local project hooks." : "Restarted to pick up the latest version.";
|
|
8571
10300
|
notify(vaultDir, {
|
|
@@ -8607,13 +10336,13 @@ async function main() {
|
|
|
8607
10336
|
});
|
|
8608
10337
|
const lastLogTimestamp = getMaxTimestamp();
|
|
8609
10338
|
if (lastLogTimestamp) {
|
|
8610
|
-
const logDir =
|
|
10339
|
+
const logDir = path24.join(vaultDir, "logs");
|
|
8611
10340
|
const replayedCount = reconcileLogBuffer(logDir, lastLogTimestamp);
|
|
8612
10341
|
if (replayedCount > 0) {
|
|
8613
10342
|
logger.info(LOG_KINDS.DAEMON_RECONCILE, `Replayed ${replayedCount} log entries from buffer`, { replayed: replayedCount });
|
|
8614
10343
|
}
|
|
8615
10344
|
}
|
|
8616
|
-
const vectorsDbPath =
|
|
10345
|
+
const vectorsDbPath = path24.join(vaultDir, "vectors.db");
|
|
8617
10346
|
const vectorStore = new SqliteVecVectorStore(vectorsDbPath);
|
|
8618
10347
|
const llmProvider = createEmbeddingProvider(config.embedding);
|
|
8619
10348
|
const embeddingProvider = new EmbeddingProviderAdapter(llmProvider, config.embedding);
|
|
@@ -8623,7 +10352,7 @@ async function main() {
|
|
|
8623
10352
|
const databaseManager = new DatabaseMaintenanceManager(vaultDbPath(vaultDir), vaultDir, logger);
|
|
8624
10353
|
let definitionsDir;
|
|
8625
10354
|
try {
|
|
8626
|
-
const { registerBuiltInAgentsAndTasks, resolveDefinitionsDir: resolveDefinitionsDir2 } = await import("./loader-
|
|
10355
|
+
const { registerBuiltInAgentsAndTasks, resolveDefinitionsDir: resolveDefinitionsDir2 } = await import("./loader-NAVVZK63.js");
|
|
8627
10356
|
definitionsDir = resolveDefinitionsDir2();
|
|
8628
10357
|
await registerBuiltInAgentsAndTasks(definitionsDir, vaultDir);
|
|
8629
10358
|
logger.info(LOG_KINDS.AGENT_TASK, "Built-in agents and tasks registered");
|
|
@@ -8660,10 +10389,10 @@ async function main() {
|
|
|
8660
10389
|
}
|
|
8661
10390
|
let uiDir = null;
|
|
8662
10391
|
{
|
|
8663
|
-
const root = findPackageRoot(
|
|
10392
|
+
const root = findPackageRoot(path24.dirname(new URL(import.meta.url).pathname));
|
|
8664
10393
|
if (root) {
|
|
8665
|
-
const candidate =
|
|
8666
|
-
if (
|
|
10394
|
+
const candidate = path24.join(root, "dist", "ui");
|
|
10395
|
+
if (fs24.existsSync(candidate)) uiDir = candidate;
|
|
8667
10396
|
}
|
|
8668
10397
|
}
|
|
8669
10398
|
if (uiDir) {
|
|
@@ -8677,6 +10406,7 @@ async function main() {
|
|
|
8677
10406
|
sleepIntervalMs: POWER_SLEEP_INTERVAL_MS,
|
|
8678
10407
|
logger
|
|
8679
10408
|
});
|
|
10409
|
+
const inflightRuns = new InflightRunRegistry();
|
|
8680
10410
|
const server = new DaemonServer({
|
|
8681
10411
|
vaultDir,
|
|
8682
10412
|
logger,
|
|
@@ -8696,7 +10426,7 @@ async function main() {
|
|
|
8696
10426
|
(p) => createPerProjectAdapter(p, claudeCodeAdapter.parseTurns)
|
|
8697
10427
|
)
|
|
8698
10428
|
});
|
|
8699
|
-
const bufferDir =
|
|
10429
|
+
const bufferDir = path24.join(vaultDir, "buffer");
|
|
8700
10430
|
const sessionBuffers = /* @__PURE__ */ new Map();
|
|
8701
10431
|
const reconciler = createReconciler({ bufferDir, logger });
|
|
8702
10432
|
reconciler.runStartupReconciliation();
|
|
@@ -8708,7 +10438,8 @@ async function main() {
|
|
|
8708
10438
|
logger,
|
|
8709
10439
|
liveConfig,
|
|
8710
10440
|
vaultDir,
|
|
8711
|
-
planTags: symbiontPlanTags
|
|
10441
|
+
planTags: symbiontPlanTags,
|
|
10442
|
+
planWatchConfig
|
|
8712
10443
|
});
|
|
8713
10444
|
const sessionLifecycle = createSessionLifecycleHandlers({
|
|
8714
10445
|
registry,
|
|
@@ -8738,14 +10469,32 @@ async function main() {
|
|
|
8738
10469
|
});
|
|
8739
10470
|
server.registerRoute("POST", "/events", eventDispatcher);
|
|
8740
10471
|
server.registerRoute("POST", "/events/stop", stopProcessor.handleStopRoute);
|
|
8741
|
-
|
|
10472
|
+
let teamSync;
|
|
10473
|
+
const contextDeps = {
|
|
10474
|
+
vaultDir,
|
|
10475
|
+
embeddingManager,
|
|
10476
|
+
liveConfig,
|
|
10477
|
+
logger,
|
|
10478
|
+
getTeamClient: () => teamSync.getTeamClient()
|
|
10479
|
+
};
|
|
8742
10480
|
server.registerRoute("POST", "/context", createSessionContextHandler(contextDeps));
|
|
8743
10481
|
server.registerRoute("POST", "/context/resume", createResumeContextHandler(contextDeps));
|
|
8744
10482
|
server.registerRoute("POST", "/context/prompt", createPromptContextHandler(contextDeps));
|
|
8745
10483
|
const progressTracker = new ProgressTracker();
|
|
8746
10484
|
let configHash = computeConfigHash(vaultDir);
|
|
10485
|
+
const cortexHandlers = createCortexHandlers(vaultDir, {
|
|
10486
|
+
liveConfig,
|
|
10487
|
+
embeddingManager,
|
|
10488
|
+
logger,
|
|
10489
|
+
getTeamClient: () => teamSync.getTeamClient(),
|
|
10490
|
+
registerInflightRun: (p) => inflightRuns.register(p)
|
|
10491
|
+
});
|
|
8747
10492
|
server.registerRoute("GET", "/api/config", async () => handleGetConfig(vaultDir));
|
|
8748
10493
|
server.registerRoute("GET", "/api/symbionts", async () => handleListSymbionts(vaultDir));
|
|
10494
|
+
server.registerRoute("GET", "/api/cortex/instructions", cortexHandlers.handleGetInstructions);
|
|
10495
|
+
server.registerRoute("POST", "/api/cortex/instructions/refresh", cortexHandlers.handleRefreshInstructions);
|
|
10496
|
+
server.registerRoute("POST", "/api/cortex/prompt-builder", cortexHandlers.handleBuildPrompt);
|
|
10497
|
+
server.registerRoute("GET", "/api/cortex/prompt-builder/:runId", cortexHandlers.handleGetPromptResult);
|
|
8749
10498
|
server.registerRoute("GET", "/api/config/merged", async () => handleGetMergedConfig(vaultDir));
|
|
8750
10499
|
server.registerRoute("GET", "/api/config/local", async () => handleGetLocalConfig(vaultDir));
|
|
8751
10500
|
const symbiontPlanDirsByAgent = {};
|
|
@@ -8761,7 +10510,7 @@ async function main() {
|
|
|
8761
10510
|
liveConfig.current = ctx;
|
|
8762
10511
|
});
|
|
8763
10512
|
reactions.on(["capture", "symbionts"], (ctx) => {
|
|
8764
|
-
reconcileConfiguredSymbionts(
|
|
10513
|
+
reconcileConfiguredSymbionts(path24.dirname(vaultDir), vaultDir, ctx);
|
|
8765
10514
|
});
|
|
8766
10515
|
reactions.on(["capture"], createPlanWatchReaction({
|
|
8767
10516
|
symbiontPlanDirs,
|
|
@@ -8776,7 +10525,14 @@ async function main() {
|
|
|
8776
10525
|
}
|
|
8777
10526
|
});
|
|
8778
10527
|
async function syncScheduledTasks() {
|
|
8779
|
-
await registerScheduledTasks(powerManager, {
|
|
10528
|
+
await registerScheduledTasks(powerManager, {
|
|
10529
|
+
definitionsDir,
|
|
10530
|
+
vaultDir,
|
|
10531
|
+
embeddingManager,
|
|
10532
|
+
logger,
|
|
10533
|
+
liveConfig,
|
|
10534
|
+
getTeamClient: () => teamSync.getTeamClient()
|
|
10535
|
+
});
|
|
8780
10536
|
}
|
|
8781
10537
|
reactions.on(["agent.tasks"], async () => {
|
|
8782
10538
|
await syncScheduledTasks();
|
|
@@ -8830,7 +10586,7 @@ async function main() {
|
|
|
8830
10586
|
server.registerRoute("POST", "/api/log", createLogIngestionHandler(logger));
|
|
8831
10587
|
server.registerRoute("GET", "/api/models", async (req) => handleGetModels(req));
|
|
8832
10588
|
server.registerRoute("POST", "/api/restart", async (req) => handleRestart({ vaultDir, progressTracker }, req.body));
|
|
8833
|
-
const updateProjectRoot =
|
|
10589
|
+
const updateProjectRoot = path24.dirname(vaultDir);
|
|
8834
10590
|
const updateHandlers = createUpdateHandlers({
|
|
8835
10591
|
vaultDir,
|
|
8836
10592
|
projectRoot: updateProjectRoot,
|
|
@@ -8853,6 +10609,7 @@ async function main() {
|
|
|
8853
10609
|
server.registerRoute("GET", "/api/sessions/:id/impact", sessionMutations.handleGetSessionImpact);
|
|
8854
10610
|
server.registerRoute("POST", "/api/sessions/:id/complete", sessionMutations.handleCompleteSession);
|
|
8855
10611
|
server.registerRoute("DELETE", "/api/sessions/:id", sessionMutations.handleDeleteSession);
|
|
10612
|
+
server.registerRoute("DELETE", "/api/plans/:id", sessionMutations.handleDeletePlan);
|
|
8856
10613
|
server.registerRoute("GET", "/api/sessions/:id/batches", handleGetSessionBatches);
|
|
8857
10614
|
server.registerRoute("GET", "/api/batches/:id/activities", handleGetBatchActivities);
|
|
8858
10615
|
server.registerRoute("GET", "/api/sessions/:id/attachments", handleGetSessionAttachments);
|
|
@@ -8873,12 +10630,27 @@ async function main() {
|
|
|
8873
10630
|
server.registerRoute("GET", "/api/digest", handleGetDigest);
|
|
8874
10631
|
const attachments = createAttachmentHandler({ vaultDir });
|
|
8875
10632
|
server.registerRoute("GET", "/api/attachments/:filename", attachments.handleGetAttachment);
|
|
8876
|
-
const agentRunHandlers = createAgentRunHandlers({
|
|
10633
|
+
const agentRunHandlers = createAgentRunHandlers({
|
|
10634
|
+
vaultDir,
|
|
10635
|
+
embeddingManager,
|
|
10636
|
+
logger,
|
|
10637
|
+
getTeamClient: () => teamSync.getTeamClient()
|
|
10638
|
+
});
|
|
8877
10639
|
server.registerRoute("POST", "/api/agent/run", agentRunHandlers.handleRun);
|
|
8878
10640
|
server.registerRoute("GET", "/api/agent/runs", agentRunHandlers.handleListRuns);
|
|
8879
10641
|
server.registerRoute("GET", "/api/agent/runs/:id", agentRunHandlers.handleGetRun);
|
|
10642
|
+
server.registerRoute("POST", "/api/agent/runs/:id/resume", agentRunHandlers.handleResumeRun);
|
|
8880
10643
|
server.registerRoute("GET", "/api/agent/runs/:id/reports", agentRunHandlers.handleGetRunReports);
|
|
8881
10644
|
server.registerRoute("GET", "/api/agent/runs/:id/turns", agentRunHandlers.handleGetRunTurns);
|
|
10645
|
+
server.registerRoute("GET", "/api/agent/runs/:id/write-intents", agentRunHandlers.handleGetRunWriteIntents);
|
|
10646
|
+
server.registerRoute("GET", "/api/agent/runs/:id/audit", agentRunHandlers.handleGetRunAudit);
|
|
10647
|
+
const agentEvalHandlers = createAgentEvaluationHandlers({ vaultDir, embeddingManager, logger });
|
|
10648
|
+
server.registerRoute("POST", "/api/agent/evaluations", agentEvalHandlers.handleCreate);
|
|
10649
|
+
server.registerRoute("GET", "/api/agent/evaluations", agentEvalHandlers.handleList);
|
|
10650
|
+
server.registerRoute("GET", "/api/agent/evaluations/:id", agentEvalHandlers.handleGet);
|
|
10651
|
+
const digestRevisionHandlers = createDigestRevisionHandlers({ vaultDir, logger });
|
|
10652
|
+
server.registerRoute("GET", "/api/digest/revisions", digestRevisionHandlers.handleList);
|
|
10653
|
+
server.registerRoute("POST", "/api/digest/revisions/:id/restore", digestRevisionHandlers.handleRestore);
|
|
8882
10654
|
server.registerRoute("GET", "/api/agent/tasks", async (req) => handleListTasks(req, vaultDir));
|
|
8883
10655
|
server.registerRoute("GET", "/api/agent/tasks/:id", async (req) => handleGetTask(req, vaultDir));
|
|
8884
10656
|
server.registerRoute("GET", "/api/agent/tasks/:id/yaml", async (req) => handleGetTaskYaml(req, vaultDir));
|
|
@@ -8920,11 +10692,15 @@ async function main() {
|
|
|
8920
10692
|
});
|
|
8921
10693
|
server.registerRoute("GET", "/api/providers", async () => handleGetProviders());
|
|
8922
10694
|
server.registerRoute("POST", "/api/providers/test", async (req) => handleTestProvider(req));
|
|
8923
|
-
|
|
10695
|
+
server.registerRoute("GET", "/api/providers/secrets", async () => handleGetProviderSecrets(vaultDir));
|
|
10696
|
+
server.registerRoute("PUT", "/api/providers/secrets/:provider", async (req) => handlePutProviderSecret(vaultDir, req));
|
|
10697
|
+
server.registerRoute("DELETE", "/api/providers/secrets/:provider", async (req) => handleDeleteProviderSecret(vaultDir, req));
|
|
10698
|
+
const mcpProxy = createMcpProxyHandlers({ machineId, embeddingManager, projectRoot, logger });
|
|
8924
10699
|
server.registerRoute("POST", "/api/mcp/remember", mcpProxy.handleRemember);
|
|
8925
10700
|
server.registerRoute("POST", "/api/mcp/supersede", mcpProxy.handleSupersede);
|
|
8926
10701
|
server.registerRoute("POST", "/api/mcp/consolidate", mcpProxy.handleConsolidate);
|
|
8927
10702
|
server.registerRoute("GET", "/api/mcp/plans", mcpProxy.handlePlans);
|
|
10703
|
+
server.registerRoute("POST", "/api/mcp/plans", mcpProxy.handleSavePlan);
|
|
8928
10704
|
server.registerRoute("GET", "/api/mcp/sessions", mcpProxy.handleSessions);
|
|
8929
10705
|
server.registerRoute("GET", "/api/mcp/team", mcpProxy.handleTeam);
|
|
8930
10706
|
const backupHandlers = createBackupHandlers({ db, machineId, vaultDir, liveConfig });
|
|
@@ -8941,7 +10717,7 @@ async function main() {
|
|
|
8941
10717
|
}
|
|
8942
10718
|
return result;
|
|
8943
10719
|
});
|
|
8944
|
-
|
|
10720
|
+
teamSync = initTeamSync({ liveConfig, machineId, logger, vaultDir, serverVersion: server.version });
|
|
8945
10721
|
reactions.on(["team"], async () => {
|
|
8946
10722
|
await teamSync.reconcileClient();
|
|
8947
10723
|
});
|
|
@@ -8950,7 +10726,7 @@ async function main() {
|
|
|
8950
10726
|
vaultDir,
|
|
8951
10727
|
machineId,
|
|
8952
10728
|
logger,
|
|
8953
|
-
getTeamClient: teamSync.getTeamClient,
|
|
10729
|
+
getTeamClient: () => teamSync.getTeamClient(),
|
|
8954
10730
|
setTeamClient: teamSync.setTeamClient
|
|
8955
10731
|
});
|
|
8956
10732
|
server.registerRoute("POST", "/api/team/connect", async (req) => {
|
|
@@ -8973,14 +10749,14 @@ async function main() {
|
|
|
8973
10749
|
server.registerRoute("POST", "/api/team/upgrade-worker", teamHandlers.handleUpgradeWorker);
|
|
8974
10750
|
server.registerRoute("POST", "/api/team/rotate-mcp-token", teamHandlers.handleRotateMcpToken);
|
|
8975
10751
|
const collectiveHandlers = createCollectiveHandlers({
|
|
8976
|
-
getTeamClient: teamSync.getTeamClient
|
|
10752
|
+
getTeamClient: () => teamSync.getTeamClient()
|
|
8977
10753
|
});
|
|
8978
10754
|
server.registerRoute("GET", "/api/collective/status", collectiveHandlers.handleStatus);
|
|
8979
10755
|
server.registerRoute("GET", "/api/collective/search", collectiveHandlers.handleSearch);
|
|
8980
10756
|
server.registerRoute("GET", "/api/collective/projects", collectiveHandlers.handleProjects);
|
|
8981
10757
|
server.registerRoute("GET", "/api/collective/project", collectiveHandlers.handleProject);
|
|
8982
10758
|
server.registerRoute("GET", "/api/collective/settings", collectiveHandlers.handleSettings);
|
|
8983
|
-
server.registerRoute("GET", "/api/search", createSearchHandler({ embeddingManager, getTeamClient: teamSync.getTeamClient, machineId }));
|
|
10759
|
+
server.registerRoute("GET", "/api/search", createSearchHandler({ embeddingManager, getTeamClient: () => teamSync.getTeamClient(), machineId }));
|
|
8984
10760
|
server.registerRoute("GET", "/api/activity", handleGetFeed);
|
|
8985
10761
|
server.registerRoute("GET", "/api/embedding/status", async () => handleGetEmbeddingStatus(vaultDir));
|
|
8986
10762
|
server.registerRoute("GET", "/api/embedding/details", async () => handleEmbeddingDetails(embeddingManager));
|
|
@@ -9018,9 +10794,25 @@ async function main() {
|
|
|
9018
10794
|
logger.warn(LOG_KINDS.DAEMON_CONFIG, "Failed to persist auto-derived port", { error: err.message });
|
|
9019
10795
|
}
|
|
9020
10796
|
}
|
|
9021
|
-
registerPowerJobs(powerManager, {
|
|
10797
|
+
registerPowerJobs(powerManager, {
|
|
10798
|
+
embeddingManager,
|
|
10799
|
+
registry,
|
|
10800
|
+
logger,
|
|
10801
|
+
liveConfig,
|
|
10802
|
+
db,
|
|
10803
|
+
machineId,
|
|
10804
|
+
vaultDir,
|
|
10805
|
+
databaseManager
|
|
10806
|
+
});
|
|
9022
10807
|
teamSync.registerFlushJob(powerManager);
|
|
9023
|
-
await registerScheduledTasks(powerManager, {
|
|
10808
|
+
await registerScheduledTasks(powerManager, {
|
|
10809
|
+
definitionsDir,
|
|
10810
|
+
vaultDir,
|
|
10811
|
+
embeddingManager,
|
|
10812
|
+
logger,
|
|
10813
|
+
liveConfig,
|
|
10814
|
+
getTeamClient: () => teamSync.getTeamClient()
|
|
10815
|
+
});
|
|
9024
10816
|
powerManager.start();
|
|
9025
10817
|
const shutdown = async (signal) => {
|
|
9026
10818
|
logger.info(LOG_KINDS.DAEMON_START, `${signal} received`);
|
|
@@ -9030,6 +10822,17 @@ async function main() {
|
|
|
9030
10822
|
logger.info(LOG_KINDS.DAEMON_START, "Waiting for active stop processing to complete...");
|
|
9031
10823
|
await activeStopProcessing;
|
|
9032
10824
|
}
|
|
10825
|
+
if (inflightRuns.size > 0) {
|
|
10826
|
+
logger.info(LOG_KINDS.DAEMON_START, "Draining in-flight agent runs before shutdown...", {
|
|
10827
|
+
inflight_count: inflightRuns.size
|
|
10828
|
+
});
|
|
10829
|
+
const outcome = await inflightRuns.drain();
|
|
10830
|
+
if (!outcome.settled) {
|
|
10831
|
+
logger.warn(LOG_KINDS.DAEMON_START, "Some in-flight runs did not settle before shutdown timeout", {
|
|
10832
|
+
remaining: outcome.remaining
|
|
10833
|
+
});
|
|
10834
|
+
}
|
|
10835
|
+
}
|
|
9033
10836
|
registry.destroy();
|
|
9034
10837
|
await server.stop();
|
|
9035
10838
|
vectorStore.close();
|
|
@@ -9052,4 +10855,4 @@ export {
|
|
|
9052
10855
|
handleUserPrompt,
|
|
9053
10856
|
main
|
|
9054
10857
|
};
|
|
9055
|
-
//# sourceMappingURL=main-
|
|
10858
|
+
//# sourceMappingURL=main-5PRQNEEE.js.map
|