@goondocks/myco 0.20.2 → 0.21.1
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/bin/myco-run +68 -7
- package/dist/agent-eval-YK2VP2S4.js +356 -0
- package/dist/agent-eval-YK2VP2S4.js.map +1 -0
- package/dist/{agent-run-X25Q2A6T.js → agent-run-GEJBD2YD.js} +10 -8
- package/dist/{agent-run-X25Q2A6T.js.map → agent-run-GEJBD2YD.js.map} +1 -1
- package/dist/{agent-tasks-7B6OFERB.js → agent-tasks-5XSRGTRX.js} +10 -8
- package/dist/{agent-tasks-7B6OFERB.js.map → agent-tasks-5XSRGTRX.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-XATDZX7U.js → chunk-6ALVMIB4.js} +19 -5
- package/dist/{chunk-XATDZX7U.js.map → chunk-6ALVMIB4.js.map} +1 -1
- package/dist/{chunk-FLLBJLHM.js → chunk-6C6QZ4PM.js} +9 -5
- package/dist/chunk-6C6QZ4PM.js.map +1 -0
- package/dist/{chunk-CCRGY3QW.js → chunk-AUIXX33A.js} +24 -95
- package/dist/chunk-AUIXX33A.js.map +1 -0
- package/dist/chunk-CISWUP5W.js +101 -0
- package/dist/chunk-CISWUP5W.js.map +1 -0
- package/dist/{chunk-MYOZLMB2.js → chunk-DTWUHHFI.js} +576 -20
- package/dist/chunk-DTWUHHFI.js.map +1 -0
- package/dist/chunk-EEOJWLMP.js +582 -0
- package/dist/chunk-EEOJWLMP.js.map +1 -0
- package/dist/{chunk-XG5RRUYF.js → chunk-ENZR5NG7.js} +2 -2
- 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-US4LNCAT.js → chunk-IPPMYQ2Y.js} +5 -1
- package/dist/chunk-IPPMYQ2Y.js.map +1 -0
- package/dist/{chunk-VVNL26WX.js → chunk-KTTSXYEK.js} +22 -10
- package/dist/chunk-KTTSXYEK.js.map +1 -0
- package/dist/chunk-LQIPXVDH.js +17 -0
- package/dist/chunk-LQIPXVDH.js.map +1 -0
- package/dist/{chunk-DCSGJ7W4.js → chunk-N2DGFACQ.js} +3 -3
- package/dist/chunk-N7Z3LUEZ.js +858 -0
- package/dist/chunk-N7Z3LUEZ.js.map +1 -0
- package/dist/{chunk-2PDWCDKY.js → chunk-NFO7BRCO.js} +10 -7
- package/dist/{chunk-2PDWCDKY.js.map → chunk-NFO7BRCO.js.map} +1 -1
- package/dist/{chunk-Q36VMZST.js → chunk-OTQH5KZW.js} +89 -38
- package/dist/chunk-OTQH5KZW.js.map +1 -0
- package/dist/chunk-OUJSQSKE.js +113 -0
- package/dist/chunk-OUJSQSKE.js.map +1 -0
- package/dist/chunk-OZ3FBAK5.js +50 -0
- package/dist/chunk-OZ3FBAK5.js.map +1 -0
- package/dist/chunk-QATYARI5.js +408 -0
- package/dist/chunk-QATYARI5.js.map +1 -0
- package/dist/{chunk-KESLPBKV.js → chunk-QDLVIW2O.js} +4 -4
- package/dist/{chunk-5XIVBO25.js → chunk-QLLBJEM7.js} +6 -2
- package/dist/chunk-QLLBJEM7.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-TSM6VESW.js +25 -0
- package/dist/chunk-TSM6VESW.js.map +1 -0
- package/dist/{chunk-6X2ERTQV.js → chunk-USVFEWYL.js} +6 -4
- package/dist/{chunk-6X2ERTQV.js.map → chunk-USVFEWYL.js.map} +1 -1
- package/dist/{chunk-JZGN33AY.js → chunk-VRI56337.js} +4 -4
- package/dist/chunk-X2IRGXGF.js +14103 -0
- package/dist/chunk-X2IRGXGF.js.map +1 -0
- 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/{chunk-NGROSFOH.js → chunk-Z66IT5KL.js} +14 -9
- package/dist/chunk-Z66IT5KL.js.map +1 -0
- package/dist/{cli-GGPWH4UO.js → cli-HSLIG7EX.js} +50 -43
- package/dist/cli-HSLIG7EX.js.map +1 -0
- package/dist/{client-YXQUTXVZ.js → client-Z43DNLJH.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-PXNM6TA7.js → detect-7NUD5B5R.js} +2 -2
- package/dist/{detect-providers-5KOPZ7J2.js → detect-providers-ILLQZROY.js} +4 -4
- package/dist/{doctor-5JXJ36KA.js → doctor-HJCWHAU4.js} +49 -16
- package/dist/doctor-HJCWHAU4.js.map +1 -0
- package/dist/executor-DO6QFC6G.js +45 -0
- package/dist/{init-LMYOVZAV.js → init-4KVK7W2E.js} +16 -14
- package/dist/{init-LMYOVZAV.js.map → init-4KVK7W2E.js.map} +1 -1
- package/dist/{installer-FS257JRZ.js → installer-N4UTEACX.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-UDNUMEDA.js} +5 -3
- package/dist/{main-YTBVRTBI.js → main-4J4QZZTZ.js} +2518 -656
- package/dist/main-4J4QZZTZ.js.map +1 -0
- package/dist/{open-HG2DX6RN.js → open-7TXJQM3H.js} +10 -8
- package/dist/{open-HG2DX6RN.js.map → open-7TXJQM3H.js.map} +1 -1
- package/dist/{post-compact-JSECI44W.js → post-compact-7AEFVCZS.js} +8 -8
- package/dist/{post-tool-use-POGPTJBA.js → post-tool-use-TZINWWDH.js} +11 -9
- package/dist/post-tool-use-TZINWWDH.js.map +1 -0
- package/dist/{post-tool-use-failure-OT7BFWQW.js → post-tool-use-failure-TCFEU2GI.js} +8 -8
- package/dist/{pre-compact-OXVODKH4.js → pre-compact-LO2VZCGR.js} +8 -8
- package/dist/{provider-check-43LAMSMH.js → provider-check-ZEV5P4KM.js} +4 -4
- package/dist/{registry-U4CHXK6R.js → registry-F3THYC5M.js} +6 -4
- package/dist/{remove-N7ZPELFU.js → remove-F77AAALE.js} +12 -10
- package/dist/{remove-N7ZPELFU.js.map → remove-F77AAALE.js.map} +1 -1
- package/dist/{restart-ADG5GBTB.js → restart-UEFDPMLT.js} +11 -9
- package/dist/{restart-ADG5GBTB.js.map → restart-UEFDPMLT.js.map} +1 -1
- package/dist/{search-AHZEUNRR.js → search-NHNVUAQQ.js} +11 -9
- package/dist/{search-AHZEUNRR.js.map → search-NHNVUAQQ.js.map} +1 -1
- package/dist/{server-AGVYZVP5.js → server-AZJSTQEK.js} +369 -270
- package/dist/server-AZJSTQEK.js.map +1 -0
- package/dist/{session-6IU4AXYP.js → session-3HLC5KOD.js} +11 -9
- package/dist/{session-6IU4AXYP.js.map → session-3HLC5KOD.js.map} +1 -1
- package/dist/{session-end-FT27DWYZ.js → session-end-FS46UARX.js} +7 -7
- package/dist/session-start-46KPFV2H.js +134 -0
- package/dist/session-start-46KPFV2H.js.map +1 -0
- package/dist/{setup-llm-77MP4I2G.js → setup-llm-JMWSNQ2C.js} +11 -9
- package/dist/{setup-llm-77MP4I2G.js.map → setup-llm-JMWSNQ2C.js.map} +1 -1
- package/dist/src/agent/definitions/agent.yaml +9 -5
- package/dist/src/agent/definitions/tasks/cortex-instructions.yaml +115 -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 +181 -25
- package/dist/src/agent/definitions/tasks/skill-generate.yaml +21 -7
- 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} +74 -129
- 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/opencode.yaml +7 -0
- package/dist/src/symbionts/manifests/pi.yaml +22 -0
- package/dist/src/symbionts/templates/agents-starter.md +1 -1
- 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-MKMETHMA.js} +11 -9
- package/dist/{stats-NVPWOYTE.js.map → stats-MKMETHMA.js.map} +1 -1
- package/dist/{stop-ZPIKVLH4.js → stop-OUEX6KA4.js} +7 -7
- package/dist/{stop-failure-2PX67YJC.js → stop-failure-2BWVNZEG.js} +8 -8
- package/dist/{subagent-start-UUE6EHQD.js → subagent-start-J4VV6DEE.js} +8 -8
- package/dist/{subagent-stop-KQWWWPE6.js → subagent-stop-JMLVEPIA.js} +8 -8
- package/dist/{task-completed-WMHOFQ7B.js → task-completed-65CHMMKA.js} +8 -8
- package/dist/{team-LRZ6GTQK.js → team-U2LDKIS4.js} +7 -5
- package/dist/{turns-YFNI5CQC.js → turns-HU2CTZAP.js} +2 -2
- package/dist/ui/assets/index-BUGor9dk.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-ZSHVXWSQ.js} +12 -10
- package/dist/{update-O6V4RC4W.js.map → update-ZSHVXWSQ.js.map} +1 -1
- package/dist/{user-prompt-submit-N36KUPHI.js → user-prompt-submit-APMO6FVU.js} +10 -9
- package/dist/{user-prompt-submit-N36KUPHI.js.map → user-prompt-submit-APMO6FVU.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-TXPPS3L5.js} +2 -2
- package/dist/version-TXPPS3L5.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-rules/SKILL.md +94 -0
- package/skills/{rules → myco-rules}/references/rules-bad-example.md +1 -1
- package/skills/{rules → myco-rules}/references/rules-good-example.md +1 -1
- package/dist/chunk-4YFKBL3F.js +0 -195
- package/dist/chunk-4YFKBL3F.js.map +0 -1
- package/dist/chunk-5XIVBO25.js.map +0 -1
- package/dist/chunk-CCRGY3QW.js.map +0 -1
- package/dist/chunk-CUDIZJY7.js +0 -36
- package/dist/chunk-CUDIZJY7.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-NGROSFOH.js.map +0 -1
- package/dist/chunk-OD4AA7PV.js.map +0 -1
- package/dist/chunk-Q36VMZST.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/skills/myco-curate/SKILL.md +0 -86
- package/skills/rules/SKILL.md +0 -214
- /package/dist/{chunk-XG5RRUYF.js.map → chunk-ENZR5NG7.js.map} +0 -0
- /package/dist/{chunk-DCSGJ7W4.js.map → chunk-N2DGFACQ.js.map} +0 -0
- /package/dist/{chunk-KESLPBKV.js.map → chunk-QDLVIW2O.js.map} +0 -0
- /package/dist/{chunk-BPRIYNLE.js.map → chunk-TKAJ3JVF.js.map} +0 -0
- /package/dist/{chunk-JZGN33AY.js.map → chunk-VRI56337.js.map} +0 -0
- /package/dist/{client-YXQUTXVZ.js.map → client-Z43DNLJH.js.map} +0 -0
- /package/dist/{detect-PXNM6TA7.js.map → detect-7NUD5B5R.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-DO6QFC6G.js.map} +0 -0
- /package/dist/{llm-TH4NLIRM.js.map → installer-N4UTEACX.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-UDNUMEDA.js.map} +0 -0
- /package/dist/{post-compact-JSECI44W.js.map → post-compact-7AEFVCZS.js.map} +0 -0
- /package/dist/{post-tool-use-failure-OT7BFWQW.js.map → post-tool-use-failure-TCFEU2GI.js.map} +0 -0
- /package/dist/{pre-compact-OXVODKH4.js.map → pre-compact-LO2VZCGR.js.map} +0 -0
- /package/dist/{registry-U4CHXK6R.js.map → provider-check-ZEV5P4KM.js.map} +0 -0
- /package/dist/{team-LRZ6GTQK.js.map → registry-F3THYC5M.js.map} +0 -0
- /package/dist/{session-end-FT27DWYZ.js.map → session-end-FS46UARX.js.map} +0 -0
- /package/dist/{stop-ZPIKVLH4.js.map → stop-OUEX6KA4.js.map} +0 -0
- /package/dist/{stop-failure-2PX67YJC.js.map → stop-failure-2BWVNZEG.js.map} +0 -0
- /package/dist/{subagent-start-UUE6EHQD.js.map → subagent-start-J4VV6DEE.js.map} +0 -0
- /package/dist/{subagent-stop-KQWWWPE6.js.map → subagent-stop-JMLVEPIA.js.map} +0 -0
- /package/dist/{task-completed-WMHOFQ7B.js.map → task-completed-65CHMMKA.js.map} +0 -0
- /package/dist/{turns-YFNI5CQC.js.map → team-U2LDKIS4.js.map} +0 -0
- /package/dist/{version-XMPPJQHR.js.map → turns-HU2CTZAP.js.map} +0 -0
|
@@ -0,0 +1,408 @@
|
|
|
1
|
+
import { createRequire as __cr } from 'node:module'; const require = __cr(import.meta.url);
|
|
2
|
+
import {
|
|
3
|
+
errorMessage
|
|
4
|
+
} from "./chunk-LQIPXVDH.js";
|
|
5
|
+
|
|
6
|
+
// src/agent/executor-state.ts
|
|
7
|
+
var SESSION_RESUME_ERROR_PATTERNS = [
|
|
8
|
+
/session/,
|
|
9
|
+
/resume/,
|
|
10
|
+
/previous[_ ]response/,
|
|
11
|
+
/conversation/
|
|
12
|
+
];
|
|
13
|
+
var EXPIRED_SESSION_ERROR_PATTERNS = [
|
|
14
|
+
/exited with code/i,
|
|
15
|
+
/session[\s_-]*not[\s_-]*found/i,
|
|
16
|
+
/session[\s_-]*expired/i,
|
|
17
|
+
/session[\s_-]*(is|was)?[\s_-]*(gone|missing|invalid)/i
|
|
18
|
+
];
|
|
19
|
+
function abortReasonMessage(abortController) {
|
|
20
|
+
if (!abortController?.signal.aborted) return null;
|
|
21
|
+
const reason = abortController.signal.reason;
|
|
22
|
+
if (reason instanceof Error) return reason.message;
|
|
23
|
+
if (typeof reason === "string" && reason.length > 0) return reason;
|
|
24
|
+
return "Agent run aborted";
|
|
25
|
+
}
|
|
26
|
+
function isSessionResumeFailure(error) {
|
|
27
|
+
const message = errorMessage(error).toLowerCase();
|
|
28
|
+
return SESSION_RESUME_ERROR_PATTERNS.some((pattern) => pattern.test(message));
|
|
29
|
+
}
|
|
30
|
+
function isExpiredSessionError(error) {
|
|
31
|
+
const message = errorMessage(error);
|
|
32
|
+
return EXPIRED_SESSION_ERROR_PATTERNS.some((pattern) => pattern.test(message));
|
|
33
|
+
}
|
|
34
|
+
function parseCheckpointState(raw) {
|
|
35
|
+
if (!raw) {
|
|
36
|
+
return { runtime: "claude-sdk", phases: {} };
|
|
37
|
+
}
|
|
38
|
+
try {
|
|
39
|
+
const parsed = JSON.parse(raw);
|
|
40
|
+
return {
|
|
41
|
+
runtime: parsed.runtime ?? "claude-sdk",
|
|
42
|
+
provider: parsed.provider,
|
|
43
|
+
providerConfig: parsed.providerConfig,
|
|
44
|
+
model: parsed.model,
|
|
45
|
+
sessionRef: parsed.sessionRef,
|
|
46
|
+
sessionData: parsed.sessionData,
|
|
47
|
+
phases: parsed.phases ?? {}
|
|
48
|
+
};
|
|
49
|
+
} catch {
|
|
50
|
+
return { runtime: "claude-sdk", phases: {} };
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
function checkpointResultsForResume(config, checkpointState) {
|
|
54
|
+
if (!config.phases) return [];
|
|
55
|
+
const order = new Map(config.phases.map((phase, index) => [phase.name, index]));
|
|
56
|
+
return Object.values(checkpointState.phases).filter((phase) => phase.status === "completed").sort((a, b) => (order.get(a.name) ?? 0) - (order.get(b.name) ?? 0)).map((phase) => buildPhaseResult({
|
|
57
|
+
name: phase.name,
|
|
58
|
+
status: "completed",
|
|
59
|
+
summary: phase.summary ?? "",
|
|
60
|
+
turnsUsed: phase.turnsUsed,
|
|
61
|
+
tokensUsed: phase.tokensUsed,
|
|
62
|
+
costUsd: phase.costUsd,
|
|
63
|
+
costSource: phase.costSource,
|
|
64
|
+
costData: phase.costData,
|
|
65
|
+
usage: phase.usage,
|
|
66
|
+
sessionRef: phase.sessionRef
|
|
67
|
+
}));
|
|
68
|
+
}
|
|
69
|
+
function buildPhaseResult(input) {
|
|
70
|
+
const {
|
|
71
|
+
name,
|
|
72
|
+
status,
|
|
73
|
+
summary,
|
|
74
|
+
usage,
|
|
75
|
+
costData,
|
|
76
|
+
turnsUsed,
|
|
77
|
+
tokensUsed,
|
|
78
|
+
costUsd,
|
|
79
|
+
costSource,
|
|
80
|
+
sessionRef,
|
|
81
|
+
sessionData
|
|
82
|
+
} = input;
|
|
83
|
+
return {
|
|
84
|
+
name,
|
|
85
|
+
status,
|
|
86
|
+
turnsUsed: turnsUsed ?? usage?.requests ?? 0,
|
|
87
|
+
tokensUsed: tokensUsed ?? usage?.totalTokens ?? 0,
|
|
88
|
+
costUsd: costUsd ?? costData?.costUsd ?? 0,
|
|
89
|
+
...costData ? { costSource: costData.source, costData } : costSource ? { costSource } : {},
|
|
90
|
+
...usage ? { usage } : {},
|
|
91
|
+
...sessionRef ? { sessionRef } : {},
|
|
92
|
+
...sessionData !== void 0 ? { sessionData } : {},
|
|
93
|
+
summary
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
function serializeCheckpointState(state) {
|
|
97
|
+
return JSON.stringify(state);
|
|
98
|
+
}
|
|
99
|
+
function aggregateUsage(usages) {
|
|
100
|
+
const aggregate = {
|
|
101
|
+
requests: 0,
|
|
102
|
+
inputTokens: 0,
|
|
103
|
+
outputTokens: 0,
|
|
104
|
+
totalTokens: 0,
|
|
105
|
+
reasoningTokens: 0,
|
|
106
|
+
cachedTokens: 0,
|
|
107
|
+
durationMs: 0
|
|
108
|
+
};
|
|
109
|
+
let sawCost = false;
|
|
110
|
+
for (const usage of usages) {
|
|
111
|
+
if (!usage) continue;
|
|
112
|
+
aggregate.requests = (aggregate.requests ?? 0) + (usage.requests ?? 0);
|
|
113
|
+
aggregate.inputTokens = (aggregate.inputTokens ?? 0) + (usage.inputTokens ?? 0);
|
|
114
|
+
aggregate.outputTokens = (aggregate.outputTokens ?? 0) + (usage.outputTokens ?? 0);
|
|
115
|
+
aggregate.totalTokens = (aggregate.totalTokens ?? 0) + (usage.totalTokens ?? 0);
|
|
116
|
+
aggregate.reasoningTokens = (aggregate.reasoningTokens ?? 0) + (usage.reasoningTokens ?? 0);
|
|
117
|
+
aggregate.cachedTokens = (aggregate.cachedTokens ?? 0) + (usage.cachedTokens ?? 0);
|
|
118
|
+
aggregate.durationMs = (aggregate.durationMs ?? 0) + (usage.durationMs ?? 0);
|
|
119
|
+
if (usage.costUsd !== void 0 && usage.costUsd !== null) {
|
|
120
|
+
aggregate.costUsd = (aggregate.costUsd ?? 0) + usage.costUsd;
|
|
121
|
+
sawCost = true;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
if (!sawCost) {
|
|
125
|
+
delete aggregate.costUsd;
|
|
126
|
+
}
|
|
127
|
+
return aggregate;
|
|
128
|
+
}
|
|
129
|
+
function buildUsageData(runUsage, runCost, phaseResults, runBudget) {
|
|
130
|
+
return JSON.stringify({
|
|
131
|
+
run: runUsage,
|
|
132
|
+
runCost: runCost ?? null,
|
|
133
|
+
runBudget: runBudget ?? null,
|
|
134
|
+
phases: phaseResults?.map((phase) => ({
|
|
135
|
+
name: phase.name,
|
|
136
|
+
usage: phase.usage ?? null,
|
|
137
|
+
turnsUsed: phase.turnsUsed,
|
|
138
|
+
tokensUsed: phase.tokensUsed,
|
|
139
|
+
costUsd: phase.costUsd,
|
|
140
|
+
costSource: phase.costSource ?? null,
|
|
141
|
+
costData: phase.costData ?? null
|
|
142
|
+
})) ?? []
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
function buildActionsTaken(runtime, provider, model, phaseResults) {
|
|
146
|
+
return JSON.stringify({
|
|
147
|
+
runtime,
|
|
148
|
+
model,
|
|
149
|
+
provider: provider?.type ?? "anthropic",
|
|
150
|
+
...provider?.baseUrl ? { baseUrl: provider.baseUrl } : {},
|
|
151
|
+
...phaseResults ? { phases: phaseResults } : {}
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
function resolveProviderForResume(currentProvider, resumedRun, checkpointState, runtime, model) {
|
|
155
|
+
const persistedType = resumedRun?.provider ?? checkpointState.provider;
|
|
156
|
+
const persistedProvider = checkpointState.providerConfig;
|
|
157
|
+
if (!persistedType && !persistedProvider) return currentProvider;
|
|
158
|
+
const matchingCurrentProvider = currentProvider?.type === persistedType ? currentProvider : void 0;
|
|
159
|
+
return {
|
|
160
|
+
...persistedProvider ?? {},
|
|
161
|
+
...matchingCurrentProvider ?? {},
|
|
162
|
+
runtime,
|
|
163
|
+
type: persistedType ?? persistedProvider?.type ?? currentProvider?.type ?? "anthropic",
|
|
164
|
+
model
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// src/agent/context-windows.ts
|
|
169
|
+
var DEFAULT_LOCAL_AGENT_CONTEXT_WINDOW_TOKENS = 32768;
|
|
170
|
+
var DEFAULT_FRONTIER_CONTEXT_WINDOW_TOKENS = 2e5;
|
|
171
|
+
var DEFAULT_COMPATIBLE_CONTEXT_WINDOW_TOKENS = 128e3;
|
|
172
|
+
|
|
173
|
+
// src/agent/provider-runtime.ts
|
|
174
|
+
var PROVIDER_METADATA_BY_TYPE = {
|
|
175
|
+
anthropic: {
|
|
176
|
+
runtime: "claude-sdk",
|
|
177
|
+
defaultContextWindowTokens: DEFAULT_FRONTIER_CONTEXT_WINDOW_TOKENS
|
|
178
|
+
},
|
|
179
|
+
ollama: {
|
|
180
|
+
runtime: "claude-sdk",
|
|
181
|
+
defaultContextWindowTokens: DEFAULT_LOCAL_AGENT_CONTEXT_WINDOW_TOKENS
|
|
182
|
+
},
|
|
183
|
+
lmstudio: {
|
|
184
|
+
runtime: "claude-sdk",
|
|
185
|
+
defaultContextWindowTokens: DEFAULT_LOCAL_AGENT_CONTEXT_WINDOW_TOKENS
|
|
186
|
+
},
|
|
187
|
+
openai: {
|
|
188
|
+
runtime: "openai-agents",
|
|
189
|
+
defaultContextWindowTokens: DEFAULT_FRONTIER_CONTEXT_WINDOW_TOKENS
|
|
190
|
+
},
|
|
191
|
+
openrouter: {
|
|
192
|
+
runtime: "openai-agents",
|
|
193
|
+
defaultContextWindowTokens: DEFAULT_FRONTIER_CONTEXT_WINDOW_TOKENS
|
|
194
|
+
},
|
|
195
|
+
"openai-compatible": {
|
|
196
|
+
runtime: "openai-agents",
|
|
197
|
+
defaultContextWindowTokens: DEFAULT_COMPATIBLE_CONTEXT_WINDOW_TOKENS
|
|
198
|
+
}
|
|
199
|
+
};
|
|
200
|
+
function getProviderMetadata(providerType) {
|
|
201
|
+
if (!providerType) return void 0;
|
|
202
|
+
return PROVIDER_METADATA_BY_TYPE[providerType];
|
|
203
|
+
}
|
|
204
|
+
function inferRuntimeFromProviderType(providerType) {
|
|
205
|
+
return getProviderMetadata(providerType)?.runtime;
|
|
206
|
+
}
|
|
207
|
+
function inferDefaultContextWindowFromProviderType(providerType) {
|
|
208
|
+
return getProviderMetadata(providerType)?.defaultContextWindowTokens ?? null;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// src/agent/run-accounting.ts
|
|
212
|
+
var TOKEN_BUDGET_WARNING_PERCENT = 75;
|
|
213
|
+
var TOKEN_BUDGET_CRITICAL_PERCENT = 90;
|
|
214
|
+
function runDurationMs(run) {
|
|
215
|
+
if (run.started_at === null || run.completed_at === null) return null;
|
|
216
|
+
return (run.completed_at - run.started_at) * 1e3;
|
|
217
|
+
}
|
|
218
|
+
function toRequestTokenNumber(entry, key) {
|
|
219
|
+
const value = entry[key];
|
|
220
|
+
return typeof value === "number" ? value : 0;
|
|
221
|
+
}
|
|
222
|
+
function resolveContextWindow(provider, usage) {
|
|
223
|
+
if (provider?.contextLength) {
|
|
224
|
+
return { tokens: provider.contextLength, source: "provider-config" };
|
|
225
|
+
}
|
|
226
|
+
const providerData = usage.providerData;
|
|
227
|
+
if (providerData) {
|
|
228
|
+
const candidates = [
|
|
229
|
+
providerData.contextWindowTokens,
|
|
230
|
+
providerData.context_window,
|
|
231
|
+
providerData.maxContextTokens,
|
|
232
|
+
providerData.max_context_tokens
|
|
233
|
+
];
|
|
234
|
+
for (const candidate of candidates) {
|
|
235
|
+
if (typeof candidate === "number" && candidate > 0) {
|
|
236
|
+
return { tokens: candidate, source: "provider-metadata" };
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
const providerDefault = inferDefaultContextWindowFromProviderType(provider?.type);
|
|
241
|
+
if (providerDefault) {
|
|
242
|
+
return { tokens: providerDefault, source: "provider-default" };
|
|
243
|
+
}
|
|
244
|
+
return { tokens: null };
|
|
245
|
+
}
|
|
246
|
+
function analyzeRuntimeTokenBudget(usage, provider) {
|
|
247
|
+
const requestEntries = usage.requestUsageEntries && usage.requestUsageEntries.length > 0 ? usage.requestUsageEntries : [{
|
|
248
|
+
inputTokens: usage.inputTokens ?? 0,
|
|
249
|
+
outputTokens: usage.outputTokens ?? 0,
|
|
250
|
+
totalTokens: usage.totalTokens ?? (usage.inputTokens ?? 0) + (usage.outputTokens ?? 0)
|
|
251
|
+
}];
|
|
252
|
+
let peakRequestInputTokens = 0;
|
|
253
|
+
let peakRequestOutputTokens = 0;
|
|
254
|
+
let peakRequestTotalTokens = 0;
|
|
255
|
+
for (const entry of requestEntries) {
|
|
256
|
+
const input = toRequestTokenNumber(entry, "inputTokens");
|
|
257
|
+
const output = toRequestTokenNumber(entry, "outputTokens");
|
|
258
|
+
const total = toRequestTokenNumber(entry, "totalTokens");
|
|
259
|
+
if (input > peakRequestInputTokens) peakRequestInputTokens = input;
|
|
260
|
+
if (output > peakRequestOutputTokens) peakRequestOutputTokens = output;
|
|
261
|
+
if (total > peakRequestTotalTokens) peakRequestTotalTokens = total;
|
|
262
|
+
}
|
|
263
|
+
const { tokens: contextWindowTokens, source: contextWindowSource } = resolveContextWindow(provider, usage);
|
|
264
|
+
if (!contextWindowTokens) {
|
|
265
|
+
return {
|
|
266
|
+
contextWindowTokens: null,
|
|
267
|
+
peakRequestInputTokens: peakRequestInputTokens || null,
|
|
268
|
+
peakRequestOutputTokens: peakRequestOutputTokens || null,
|
|
269
|
+
peakRequestTotalTokens: peakRequestTotalTokens || null,
|
|
270
|
+
utilizationPercent: null,
|
|
271
|
+
headroomTokens: null,
|
|
272
|
+
status: "unknown",
|
|
273
|
+
message: "Context window unavailable for this provider/model."
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
const utilizationPercent = peakRequestTotalTokens > 0 ? Math.round(peakRequestTotalTokens / contextWindowTokens * 100) : 0;
|
|
277
|
+
const headroomTokens = Math.max(0, contextWindowTokens - peakRequestTotalTokens);
|
|
278
|
+
const status = utilizationPercent >= TOKEN_BUDGET_CRITICAL_PERCENT ? "post_run_pressure" : utilizationPercent >= TOKEN_BUDGET_WARNING_PERCENT ? "warning" : "ok";
|
|
279
|
+
const statusMessage = status === "post_run_pressure" ? "Run operated near the model context limit." : status === "warning" ? "Run used a large share of the model context window." : void 0;
|
|
280
|
+
const isInferredWindow = contextWindowSource === "provider-default";
|
|
281
|
+
const message = isInferredWindow ? statusMessage ? `${statusMessage} Using inferred provider default context window.` : "Using inferred provider default context window." : statusMessage;
|
|
282
|
+
return {
|
|
283
|
+
contextWindowTokens,
|
|
284
|
+
...contextWindowSource ? { contextWindowSource } : {},
|
|
285
|
+
peakRequestInputTokens: peakRequestInputTokens || null,
|
|
286
|
+
peakRequestOutputTokens: peakRequestOutputTokens || null,
|
|
287
|
+
peakRequestTotalTokens: peakRequestTotalTokens || null,
|
|
288
|
+
utilizationPercent,
|
|
289
|
+
headroomTokens,
|
|
290
|
+
status,
|
|
291
|
+
...message ? { message } : {}
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
function serializeCostData(cost) {
|
|
295
|
+
return cost ? JSON.stringify(cost) : null;
|
|
296
|
+
}
|
|
297
|
+
function summarizePhaseCosts(phaseResults) {
|
|
298
|
+
const costedPhases = phaseResults.filter(
|
|
299
|
+
(phase) => phase.costData !== void 0 && phase.costData !== null && phase.costData.costUsd !== null
|
|
300
|
+
);
|
|
301
|
+
if (costedPhases.length === 0) {
|
|
302
|
+
return {
|
|
303
|
+
source: "unavailable",
|
|
304
|
+
costUsd: null,
|
|
305
|
+
actualCostUsd: null,
|
|
306
|
+
estimatedCostUsd: null,
|
|
307
|
+
breakdown: {
|
|
308
|
+
inputTokens: 0,
|
|
309
|
+
cachedInputTokens: 0,
|
|
310
|
+
uncachedInputTokens: 0,
|
|
311
|
+
outputTokens: 0,
|
|
312
|
+
reasoningTokens: 0,
|
|
313
|
+
requestCount: 0
|
|
314
|
+
},
|
|
315
|
+
pricingVersion: null,
|
|
316
|
+
message: "No phase cost data available"
|
|
317
|
+
};
|
|
318
|
+
}
|
|
319
|
+
const firstCost = costedPhases[0].costData;
|
|
320
|
+
const aggregate = {
|
|
321
|
+
costUsd: 0,
|
|
322
|
+
actualCostUsd: 0,
|
|
323
|
+
estimatedCostUsd: 0,
|
|
324
|
+
breakdown: {
|
|
325
|
+
inputTokens: 0,
|
|
326
|
+
cachedInputTokens: 0,
|
|
327
|
+
uncachedInputTokens: 0,
|
|
328
|
+
outputTokens: 0,
|
|
329
|
+
reasoningTokens: 0,
|
|
330
|
+
requestCount: 0,
|
|
331
|
+
inputCostUsd: 0,
|
|
332
|
+
cachedInputCostUsd: 0,
|
|
333
|
+
outputCostUsd: 0,
|
|
334
|
+
reasoningCostUsd: 0,
|
|
335
|
+
requestCostUsd: 0,
|
|
336
|
+
cacheSavingsUsd: 0,
|
|
337
|
+
totalCostUsd: 0
|
|
338
|
+
}
|
|
339
|
+
};
|
|
340
|
+
for (const phase of costedPhases) {
|
|
341
|
+
const cost = phase.costData;
|
|
342
|
+
const breakdown = cost.breakdown;
|
|
343
|
+
aggregate.costUsd += cost.costUsd ?? 0;
|
|
344
|
+
aggregate.actualCostUsd += cost.actualCostUsd ?? 0;
|
|
345
|
+
aggregate.estimatedCostUsd += cost.estimatedCostUsd ?? 0;
|
|
346
|
+
aggregate.breakdown.inputTokens += breakdown.inputTokens;
|
|
347
|
+
aggregate.breakdown.cachedInputTokens += breakdown.cachedInputTokens;
|
|
348
|
+
aggregate.breakdown.uncachedInputTokens += breakdown.uncachedInputTokens;
|
|
349
|
+
aggregate.breakdown.outputTokens += breakdown.outputTokens;
|
|
350
|
+
aggregate.breakdown.reasoningTokens += breakdown.reasoningTokens;
|
|
351
|
+
aggregate.breakdown.requestCount += breakdown.requestCount;
|
|
352
|
+
aggregate.breakdown.inputCostUsd += breakdown.inputCostUsd ?? 0;
|
|
353
|
+
aggregate.breakdown.cachedInputCostUsd += breakdown.cachedInputCostUsd ?? 0;
|
|
354
|
+
aggregate.breakdown.outputCostUsd += breakdown.outputCostUsd ?? 0;
|
|
355
|
+
aggregate.breakdown.reasoningCostUsd += breakdown.reasoningCostUsd ?? 0;
|
|
356
|
+
aggregate.breakdown.requestCostUsd += breakdown.requestCostUsd ?? 0;
|
|
357
|
+
aggregate.breakdown.cacheSavingsUsd += breakdown.cacheSavingsUsd ?? 0;
|
|
358
|
+
}
|
|
359
|
+
aggregate.breakdown.totalCostUsd = aggregate.costUsd;
|
|
360
|
+
const allActual = phaseResults.every((phase) => phase.costData?.source === "actual");
|
|
361
|
+
const hasUnavailable = phaseResults.some((phase) => phase.costData?.source === "unavailable");
|
|
362
|
+
return {
|
|
363
|
+
source: allActual ? "actual" : "estimated",
|
|
364
|
+
costUsd: aggregate.costUsd,
|
|
365
|
+
actualCostUsd: allActual ? aggregate.actualCostUsd : null,
|
|
366
|
+
estimatedCostUsd: allActual ? null : aggregate.costUsd,
|
|
367
|
+
breakdown: aggregate.breakdown,
|
|
368
|
+
pricingVersion: costedPhases.every((phase) => phase.costData?.pricingVersion === firstCost.pricingVersion) ? firstCost.pricingVersion ?? null : null,
|
|
369
|
+
...hasUnavailable ? { message: "Some phase costs were unavailable; total reflects known phase costs only" } : {}
|
|
370
|
+
};
|
|
371
|
+
}
|
|
372
|
+
function buildRunAccountingUpdate(input) {
|
|
373
|
+
const tokenBudget = analyzeRuntimeTokenBudget(input.usage, input.provider);
|
|
374
|
+
return {
|
|
375
|
+
runtime: input.runtime,
|
|
376
|
+
provider: input.provider?.type ?? null,
|
|
377
|
+
model: input.model,
|
|
378
|
+
session_ref: input.sessionRef ?? input.checkpointState.sessionRef ?? null,
|
|
379
|
+
checkpoints: serializeCheckpointState(input.checkpointState),
|
|
380
|
+
usage_data: buildUsageData(input.usage, input.costData, input.phaseResults, tokenBudget),
|
|
381
|
+
cost_usd: input.costData.costUsd ?? null,
|
|
382
|
+
actual_cost_usd: input.costData.actualCostUsd,
|
|
383
|
+
estimated_cost_usd: input.costData.estimatedCostUsd,
|
|
384
|
+
cost_source: input.costData.source,
|
|
385
|
+
cost_data: serializeCostData(input.costData),
|
|
386
|
+
actions_taken: buildActionsTaken(input.runtime, input.provider, input.model, input.phaseResults)
|
|
387
|
+
};
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
export {
|
|
391
|
+
DEFAULT_LOCAL_AGENT_CONTEXT_WINDOW_TOKENS,
|
|
392
|
+
inferRuntimeFromProviderType,
|
|
393
|
+
abortReasonMessage,
|
|
394
|
+
isSessionResumeFailure,
|
|
395
|
+
isExpiredSessionError,
|
|
396
|
+
parseCheckpointState,
|
|
397
|
+
checkpointResultsForResume,
|
|
398
|
+
buildPhaseResult,
|
|
399
|
+
serializeCheckpointState,
|
|
400
|
+
aggregateUsage,
|
|
401
|
+
buildUsageData,
|
|
402
|
+
resolveProviderForResume,
|
|
403
|
+
runDurationMs,
|
|
404
|
+
analyzeRuntimeTokenBudget,
|
|
405
|
+
summarizePhaseCosts,
|
|
406
|
+
buildRunAccountingUpdate
|
|
407
|
+
};
|
|
408
|
+
//# sourceMappingURL=chunk-QATYARI5.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/agent/executor-state.ts","../src/agent/context-windows.ts","../src/agent/provider-runtime.ts","../src/agent/run-accounting.ts"],"sourcesContent":["import { errorMessage as toErrorMessage } from '@myco/utils/error-message.js';\nimport type { CostResolution, CostSource } from './cost/types.js';\nimport type {\n EffectiveConfig,\n PhaseResult,\n ProviderConfig,\n ProviderType,\n RuntimeId,\n RuntimeTokenBudget,\n RuntimeUsage,\n} from './types.js';\n\n/** Error patterns that indicate an SDK/runtime session could not be resumed. */\nconst SESSION_RESUME_ERROR_PATTERNS = [\n /session/,\n /resume/,\n /previous[_ ]response/,\n /conversation/,\n];\n\n/**\n * Error patterns that specifically indicate the Claude Agent SDK subprocess\n * crashed while trying to attach to an expired or missing session.\n *\n * The SDK TTLs its sessions on Anthropic's side (hours to days). When the\n * scheduler resumes a run after that TTL, the `claude` subprocess exits 1\n * within ~100 seconds with 0 turns recorded — the generic \"Claude Code\n * process exited with code 1\" message contains no `session`/`resume`\n * substring, so `SESSION_RESUME_ERROR_PATTERNS` misses it and the resume\n * keeps re-queuing forever.\n *\n * These patterns are only safe to apply in contexts where a `sessionRef`\n * was passed to the runtime (see `isExpiredSessionError` callers), since\n * \"exited with code\" also fires on unrelated SDK crashes.\n */\nconst EXPIRED_SESSION_ERROR_PATTERNS = [\n /exited with code/i,\n /session[\\s_-]*not[\\s_-]*found/i,\n /session[\\s_-]*expired/i,\n /session[\\s_-]*(is|was)?[\\s_-]*(gone|missing|invalid)/i,\n];\n\nexport interface PhaseCheckpoint {\n name: string;\n status: 'pending' | 'running' | 'completed' | 'failed';\n summary?: string;\n turnsUsed?: number;\n tokensUsed?: number;\n costUsd?: number;\n costSource?: CostSource;\n costData?: CostResolution;\n sessionRef?: string;\n sessionData?: unknown;\n usage?: RuntimeUsage;\n updatedAt: number;\n}\n\nexport interface RunCheckpointState {\n runtime: RuntimeId;\n provider?: ProviderType;\n providerConfig?: ProviderConfig;\n model?: string;\n sessionRef?: string;\n sessionData?: unknown;\n phases: Record<string, PhaseCheckpoint>;\n}\n\nexport function abortReasonMessage(abortController?: AbortController): string | null {\n if (!abortController?.signal.aborted) return null;\n const reason = abortController.signal.reason;\n if (reason instanceof Error) return reason.message;\n if (typeof reason === 'string' && reason.length > 0) return reason;\n return 'Agent run aborted';\n}\n\nexport function isSessionResumeFailure(error: unknown): boolean {\n const message = toErrorMessage(error).toLowerCase();\n return SESSION_RESUME_ERROR_PATTERNS.some((pattern) => pattern.test(message));\n}\n\n/**\n * Matches errors that look like \"the Claude SDK session we tried to resume\n * is no longer alive.\" Callers MUST gate this on actually having passed a\n * `sessionRef` — otherwise an unrelated \"exited with code\" SDK crash would\n * be falsely classified as expired-session and the run would stop being\n * retried.\n */\nexport function isExpiredSessionError(error: unknown): boolean {\n const message = toErrorMessage(error);\n return EXPIRED_SESSION_ERROR_PATTERNS.some((pattern) => pattern.test(message));\n}\n\nexport function parseCheckpointState(raw: string | null | undefined): RunCheckpointState {\n if (!raw) {\n return { runtime: 'claude-sdk', phases: {} };\n }\n try {\n const parsed = JSON.parse(raw) as Partial<RunCheckpointState>;\n return {\n runtime: parsed.runtime ?? 'claude-sdk',\n provider: parsed.provider,\n providerConfig: parsed.providerConfig,\n model: parsed.model,\n sessionRef: parsed.sessionRef,\n sessionData: parsed.sessionData,\n phases: parsed.phases ?? {},\n };\n } catch {\n return { runtime: 'claude-sdk', phases: {} };\n }\n}\n\nexport function checkpointResultsForResume(\n config: EffectiveConfig,\n checkpointState: RunCheckpointState,\n): PhaseResult[] {\n if (!config.phases) return [];\n const order = new Map(config.phases.map((phase, index) => [phase.name, index]));\n return Object.values(checkpointState.phases)\n .filter((phase) => phase.status === 'completed')\n .sort((a, b) => (order.get(a.name) ?? 0) - (order.get(b.name) ?? 0))\n .map((phase) => buildPhaseResult({\n name: phase.name,\n status: 'completed',\n summary: phase.summary ?? '',\n turnsUsed: phase.turnsUsed,\n tokensUsed: phase.tokensUsed,\n costUsd: phase.costUsd,\n costSource: phase.costSource,\n costData: phase.costData,\n usage: phase.usage,\n sessionRef: phase.sessionRef,\n }));\n}\n\n/**\n * Construct a `PhaseResult` from whatever telemetry is available.\n *\n * Three callers hit this: (1) executePhase's success path has a full\n * `RuntimeUsage` + `CostResolution`; (2) executePhase's failure path has\n * partial telemetry attached to a `RuntimeExecutionError`; (3)\n * `checkpointResultsForResume` has pre-computed scalar fields from a\n * persisted checkpoint. Each caller passes what it has — the helper\n * derives `turnsUsed`/`tokensUsed`/`costUsd` from `usage` + `costData`\n * when available, and falls back to the direct scalar fields when not.\n */\nexport function buildPhaseResult(input: {\n name: string;\n status: PhaseResult['status'];\n summary: string;\n usage?: RuntimeUsage;\n costData?: CostResolution;\n turnsUsed?: number;\n tokensUsed?: number;\n costUsd?: number;\n costSource?: CostSource;\n sessionRef?: string;\n sessionData?: unknown;\n}): PhaseResult & { sessionData?: unknown } {\n const {\n name, status, summary, usage, costData,\n turnsUsed, tokensUsed, costUsd, costSource,\n sessionRef, sessionData,\n } = input;\n return {\n name,\n status,\n turnsUsed: turnsUsed ?? usage?.requests ?? 0,\n tokensUsed: tokensUsed ?? usage?.totalTokens ?? 0,\n costUsd: costUsd ?? costData?.costUsd ?? 0,\n ...(costData ? { costSource: costData.source, costData } : costSource ? { costSource } : {}),\n ...(usage ? { usage } : {}),\n ...(sessionRef ? { sessionRef } : {}),\n ...(sessionData !== undefined ? { sessionData } : {}),\n summary,\n };\n}\n\nexport function serializeCheckpointState(state: RunCheckpointState): string {\n return JSON.stringify(state);\n}\n\nexport function aggregateUsage(usages: Array<RuntimeUsage | undefined>): RuntimeUsage {\n const aggregate: RuntimeUsage = {\n requests: 0,\n inputTokens: 0,\n outputTokens: 0,\n totalTokens: 0,\n reasoningTokens: 0,\n cachedTokens: 0,\n durationMs: 0,\n };\n let sawCost = false;\n\n for (const usage of usages) {\n if (!usage) continue;\n aggregate.requests = (aggregate.requests ?? 0) + (usage.requests ?? 0);\n aggregate.inputTokens = (aggregate.inputTokens ?? 0) + (usage.inputTokens ?? 0);\n aggregate.outputTokens = (aggregate.outputTokens ?? 0) + (usage.outputTokens ?? 0);\n aggregate.totalTokens = (aggregate.totalTokens ?? 0) + (usage.totalTokens ?? 0);\n aggregate.reasoningTokens = (aggregate.reasoningTokens ?? 0) + (usage.reasoningTokens ?? 0);\n aggregate.cachedTokens = (aggregate.cachedTokens ?? 0) + (usage.cachedTokens ?? 0);\n aggregate.durationMs = (aggregate.durationMs ?? 0) + (usage.durationMs ?? 0);\n if (usage.costUsd !== undefined && usage.costUsd !== null) {\n aggregate.costUsd = (aggregate.costUsd ?? 0) + usage.costUsd;\n sawCost = true;\n }\n }\n\n if (!sawCost) {\n delete aggregate.costUsd;\n }\n\n return aggregate;\n}\n\nexport function buildUsageData(\n runUsage: RuntimeUsage,\n runCost?: CostResolution,\n phaseResults?: PhaseResult[],\n runBudget?: RuntimeTokenBudget,\n): string {\n return JSON.stringify({\n run: runUsage,\n runCost: runCost ?? null,\n runBudget: runBudget ?? null,\n phases: phaseResults?.map((phase) => ({\n name: phase.name,\n usage: phase.usage ?? null,\n turnsUsed: phase.turnsUsed,\n tokensUsed: phase.tokensUsed,\n costUsd: phase.costUsd,\n costSource: phase.costSource ?? null,\n costData: phase.costData ?? null,\n })) ?? [],\n });\n}\n\nexport function buildActionsTaken(\n runtime: RuntimeId,\n provider: ProviderConfig | undefined,\n model: string,\n phaseResults?: PhaseResult[],\n): string {\n return JSON.stringify({\n runtime,\n model,\n provider: provider?.type ?? 'anthropic',\n ...(provider?.baseUrl ? { baseUrl: provider.baseUrl } : {}),\n ...(phaseResults ? { phases: phaseResults } : {}),\n });\n}\n\nexport function resolveProviderForResume(\n currentProvider: ProviderConfig | undefined,\n resumedRun: {\n provider: ProviderType | null;\n } | null,\n checkpointState: RunCheckpointState,\n runtime: RuntimeId,\n model: string,\n): ProviderConfig | undefined {\n const persistedType = resumedRun?.provider ?? checkpointState.provider;\n const persistedProvider = checkpointState.providerConfig;\n if (!persistedType && !persistedProvider) return currentProvider;\n const matchingCurrentProvider = currentProvider?.type === persistedType ? currentProvider : undefined;\n\n return {\n ...(persistedProvider ?? {}),\n ...(matchingCurrentProvider ?? {}),\n runtime,\n type: persistedType ?? persistedProvider?.type ?? currentProvider?.type ?? 'anthropic',\n model,\n };\n}\n","/** Default context window Myco applies for local agent runs when no override is set. */\nexport const DEFAULT_LOCAL_AGENT_CONTEXT_WINDOW_TOKENS = 32_768;\n\n/** Inferred frontier-model context window when the provider does not expose one. */\nexport const DEFAULT_FRONTIER_CONTEXT_WINDOW_TOKENS = 200_000;\n\n/** Inferred OpenAI-compatible cloud context window when the provider does not expose one. */\nexport const DEFAULT_COMPATIBLE_CONTEXT_WINDOW_TOKENS = 128_000;\n","import type { ProviderType, RuntimeId } from './types.js';\nimport {\n DEFAULT_COMPATIBLE_CONTEXT_WINDOW_TOKENS,\n DEFAULT_FRONTIER_CONTEXT_WINDOW_TOKENS,\n DEFAULT_LOCAL_AGENT_CONTEXT_WINDOW_TOKENS,\n} from './context-windows.js';\n\ninterface ProviderMetadata {\n runtime: RuntimeId;\n defaultContextWindowTokens?: number;\n}\n\nconst PROVIDER_METADATA_BY_TYPE: Record<ProviderType, ProviderMetadata> = {\n anthropic: {\n runtime: 'claude-sdk',\n defaultContextWindowTokens: DEFAULT_FRONTIER_CONTEXT_WINDOW_TOKENS,\n },\n ollama: {\n runtime: 'claude-sdk',\n defaultContextWindowTokens: DEFAULT_LOCAL_AGENT_CONTEXT_WINDOW_TOKENS,\n },\n lmstudio: {\n runtime: 'claude-sdk',\n defaultContextWindowTokens: DEFAULT_LOCAL_AGENT_CONTEXT_WINDOW_TOKENS,\n },\n openai: {\n runtime: 'openai-agents',\n defaultContextWindowTokens: DEFAULT_FRONTIER_CONTEXT_WINDOW_TOKENS,\n },\n openrouter: {\n runtime: 'openai-agents',\n defaultContextWindowTokens: DEFAULT_FRONTIER_CONTEXT_WINDOW_TOKENS,\n },\n 'openai-compatible': {\n runtime: 'openai-agents',\n defaultContextWindowTokens: DEFAULT_COMPATIBLE_CONTEXT_WINDOW_TOKENS,\n },\n};\n\nexport function getProviderMetadata(providerType: ProviderType | undefined): ProviderMetadata | undefined {\n if (!providerType) return undefined;\n return PROVIDER_METADATA_BY_TYPE[providerType];\n}\n\nexport function inferRuntimeFromProviderType(providerType: ProviderType | undefined): RuntimeId | undefined {\n return getProviderMetadata(providerType)?.runtime;\n}\n\nexport function inferDefaultContextWindowFromProviderType(providerType: ProviderType | undefined): number | null {\n return getProviderMetadata(providerType)?.defaultContextWindowTokens ?? null;\n}\n","import type { RunUpdate } from '@myco/db/queries/runs.js';\nimport type { CostResolution } from './cost/types.js';\nimport {\n buildActionsTaken,\n buildUsageData,\n serializeCheckpointState,\n type RunCheckpointState,\n} from './executor-state.js';\nimport { inferDefaultContextWindowFromProviderType } from './provider-runtime.js';\nimport type { PhaseResult, ProviderConfig, RuntimeId, RuntimeTokenBudget, RuntimeUsage } from './types.js';\n\nconst TOKEN_BUDGET_WARNING_PERCENT = 75;\nconst TOKEN_BUDGET_CRITICAL_PERCENT = 90;\n\n/**\n * Compute the elapsed duration of a run in milliseconds. Returns `null`\n * unless both timestamps are populated. Started/completed timestamps on\n * `agent_runs` are stored in seconds; this helper converts to ms for UI\n * consumers that expect millisecond precision.\n */\nexport function runDurationMs(run: {\n started_at: number | null;\n completed_at: number | null;\n}): number | null {\n if (run.started_at === null || run.completed_at === null) return null;\n return (run.completed_at - run.started_at) * 1000;\n}\n\nfunction toRequestTokenNumber(\n entry: Record<string, unknown>,\n key: 'inputTokens' | 'outputTokens' | 'totalTokens',\n): number {\n const value = entry[key];\n return typeof value === 'number' ? value : 0;\n}\n\nfunction resolveContextWindow(\n provider: ProviderConfig | undefined,\n usage: RuntimeUsage,\n): { tokens: number | null; source?: RuntimeTokenBudget['contextWindowSource'] } {\n if (provider?.contextLength) {\n return { tokens: provider.contextLength, source: 'provider-config' };\n }\n const providerData = usage.providerData;\n if (providerData) {\n const candidates = [\n providerData.contextWindowTokens,\n providerData.context_window,\n providerData.maxContextTokens,\n providerData.max_context_tokens,\n ];\n for (const candidate of candidates) {\n if (typeof candidate === 'number' && candidate > 0) {\n return { tokens: candidate, source: 'provider-metadata' };\n }\n }\n }\n const providerDefault = inferDefaultContextWindowFromProviderType(provider?.type);\n if (providerDefault) {\n return { tokens: providerDefault, source: 'provider-default' };\n }\n return { tokens: null };\n}\n\nexport function analyzeRuntimeTokenBudget(\n usage: RuntimeUsage,\n provider?: ProviderConfig,\n): RuntimeTokenBudget {\n const requestEntries = usage.requestUsageEntries && usage.requestUsageEntries.length > 0\n ? usage.requestUsageEntries\n : [{\n inputTokens: usage.inputTokens ?? 0,\n outputTokens: usage.outputTokens ?? 0,\n totalTokens: usage.totalTokens ?? (\n (usage.inputTokens ?? 0) + (usage.outputTokens ?? 0)\n ),\n }];\n let peakRequestInputTokens = 0;\n let peakRequestOutputTokens = 0;\n let peakRequestTotalTokens = 0;\n for (const entry of requestEntries) {\n const input = toRequestTokenNumber(entry, 'inputTokens');\n const output = toRequestTokenNumber(entry, 'outputTokens');\n const total = toRequestTokenNumber(entry, 'totalTokens');\n if (input > peakRequestInputTokens) peakRequestInputTokens = input;\n if (output > peakRequestOutputTokens) peakRequestOutputTokens = output;\n if (total > peakRequestTotalTokens) peakRequestTotalTokens = total;\n }\n const { tokens: contextWindowTokens, source: contextWindowSource } = resolveContextWindow(provider, usage);\n\n if (!contextWindowTokens) {\n return {\n contextWindowTokens: null,\n peakRequestInputTokens: peakRequestInputTokens || null,\n peakRequestOutputTokens: peakRequestOutputTokens || null,\n peakRequestTotalTokens: peakRequestTotalTokens || null,\n utilizationPercent: null,\n headroomTokens: null,\n status: 'unknown',\n message: 'Context window unavailable for this provider/model.',\n };\n }\n\n const utilizationPercent = peakRequestTotalTokens > 0\n ? Math.round((peakRequestTotalTokens / contextWindowTokens) * 100)\n : 0;\n const headroomTokens = Math.max(0, contextWindowTokens - peakRequestTotalTokens);\n const status = utilizationPercent >= TOKEN_BUDGET_CRITICAL_PERCENT\n ? 'post_run_pressure'\n : utilizationPercent >= TOKEN_BUDGET_WARNING_PERCENT\n ? 'warning'\n : 'ok';\n const statusMessage = status === 'post_run_pressure'\n ? 'Run operated near the model context limit.'\n : status === 'warning'\n ? 'Run used a large share of the model context window.'\n : undefined;\n const isInferredWindow = contextWindowSource === 'provider-default';\n const message = isInferredWindow\n ? (statusMessage\n ? `${statusMessage} Using inferred provider default context window.`\n : 'Using inferred provider default context window.')\n : statusMessage;\n\n return {\n contextWindowTokens,\n ...(contextWindowSource ? { contextWindowSource } : {}),\n peakRequestInputTokens: peakRequestInputTokens || null,\n peakRequestOutputTokens: peakRequestOutputTokens || null,\n peakRequestTotalTokens: peakRequestTotalTokens || null,\n utilizationPercent,\n headroomTokens,\n status,\n ...(message ? { message } : {}),\n };\n}\n\nexport function serializeCostData(cost: CostResolution | undefined): string | null {\n return cost ? JSON.stringify(cost) : null;\n}\n\nexport function summarizePhaseCosts(phaseResults: PhaseResult[]): CostResolution {\n const costedPhases = phaseResults.filter(\n (phase): phase is PhaseResult & { costData: CostResolution } =>\n phase.costData !== undefined && phase.costData !== null && phase.costData.costUsd !== null,\n );\n if (costedPhases.length === 0) {\n return {\n source: 'unavailable',\n costUsd: null,\n actualCostUsd: null,\n estimatedCostUsd: null,\n breakdown: {\n inputTokens: 0,\n cachedInputTokens: 0,\n uncachedInputTokens: 0,\n outputTokens: 0,\n reasoningTokens: 0,\n requestCount: 0,\n },\n pricingVersion: null,\n message: 'No phase cost data available',\n };\n }\n\n const firstCost = costedPhases[0].costData;\n const aggregate = {\n costUsd: 0,\n actualCostUsd: 0,\n estimatedCostUsd: 0,\n breakdown: {\n inputTokens: 0,\n cachedInputTokens: 0,\n uncachedInputTokens: 0,\n outputTokens: 0,\n reasoningTokens: 0,\n requestCount: 0,\n inputCostUsd: 0,\n cachedInputCostUsd: 0,\n outputCostUsd: 0,\n reasoningCostUsd: 0,\n requestCostUsd: 0,\n cacheSavingsUsd: 0,\n totalCostUsd: 0,\n },\n };\n\n for (const phase of costedPhases) {\n const cost = phase.costData;\n const breakdown = cost.breakdown;\n aggregate.costUsd += cost.costUsd ?? 0;\n aggregate.actualCostUsd += cost.actualCostUsd ?? 0;\n aggregate.estimatedCostUsd += cost.estimatedCostUsd ?? 0;\n aggregate.breakdown.inputTokens += breakdown.inputTokens;\n aggregate.breakdown.cachedInputTokens += breakdown.cachedInputTokens;\n aggregate.breakdown.uncachedInputTokens += breakdown.uncachedInputTokens;\n aggregate.breakdown.outputTokens += breakdown.outputTokens;\n aggregate.breakdown.reasoningTokens += breakdown.reasoningTokens;\n aggregate.breakdown.requestCount += breakdown.requestCount;\n aggregate.breakdown.inputCostUsd += breakdown.inputCostUsd ?? 0;\n aggregate.breakdown.cachedInputCostUsd += breakdown.cachedInputCostUsd ?? 0;\n aggregate.breakdown.outputCostUsd += breakdown.outputCostUsd ?? 0;\n aggregate.breakdown.reasoningCostUsd += breakdown.reasoningCostUsd ?? 0;\n aggregate.breakdown.requestCostUsd += breakdown.requestCostUsd ?? 0;\n aggregate.breakdown.cacheSavingsUsd += breakdown.cacheSavingsUsd ?? 0;\n }\n aggregate.breakdown.totalCostUsd = aggregate.costUsd;\n\n const allActual = phaseResults.every((phase) => phase.costData?.source === 'actual');\n const hasUnavailable = phaseResults.some((phase) => phase.costData?.source === 'unavailable');\n return {\n source: allActual ? 'actual' : 'estimated',\n costUsd: aggregate.costUsd,\n actualCostUsd: allActual ? aggregate.actualCostUsd : null,\n estimatedCostUsd: allActual ? null : aggregate.costUsd,\n breakdown: aggregate.breakdown,\n pricingVersion: costedPhases.every((phase) => phase.costData?.pricingVersion === firstCost.pricingVersion)\n ? firstCost.pricingVersion ?? null\n : null,\n ...(hasUnavailable ? { message: 'Some phase costs were unavailable; total reflects known phase costs only' } : {}),\n };\n}\n\ninterface RunAccountingUpdateInput {\n runtime: RuntimeId;\n provider?: ProviderConfig;\n model: string;\n checkpointState: RunCheckpointState;\n usage: RuntimeUsage;\n costData: CostResolution;\n phaseResults?: PhaseResult[];\n sessionRef?: string | null;\n}\n\ninterface RunAccountingUpdateFields extends Pick<\n RunUpdate,\n | 'runtime'\n | 'provider'\n | 'model'\n | 'session_ref'\n | 'checkpoints'\n | 'usage_data'\n | 'cost_usd'\n | 'actual_cost_usd'\n | 'estimated_cost_usd'\n | 'cost_source'\n | 'cost_data'\n> {\n actions_taken: string;\n}\n\nexport function buildRunAccountingUpdate(input: RunAccountingUpdateInput): RunAccountingUpdateFields {\n const tokenBudget = analyzeRuntimeTokenBudget(input.usage, input.provider);\n return {\n runtime: input.runtime,\n provider: input.provider?.type ?? null,\n model: input.model,\n session_ref: input.sessionRef ?? input.checkpointState.sessionRef ?? null,\n checkpoints: serializeCheckpointState(input.checkpointState),\n usage_data: buildUsageData(input.usage, input.costData, input.phaseResults, tokenBudget),\n cost_usd: input.costData.costUsd ?? null,\n actual_cost_usd: input.costData.actualCostUsd,\n estimated_cost_usd: input.costData.estimatedCostUsd,\n cost_source: input.costData.source,\n cost_data: serializeCostData(input.costData),\n actions_taken: buildActionsTaken(input.runtime, input.provider, input.model, input.phaseResults),\n };\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { createRequire as __cr } from 'node:module'; const require = __cr(import.meta.url);
|
|
2
2
|
import {
|
|
3
3
|
SymbiontInstaller
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-OTQH5KZW.js";
|
|
5
5
|
import {
|
|
6
6
|
LmStudioBackend,
|
|
7
7
|
OllamaBackend
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-X3IGT5RV.js";
|
|
9
9
|
import {
|
|
10
10
|
closeDatabase,
|
|
11
11
|
initDatabase,
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
} from "./chunk-MYX5NCRH.js";
|
|
14
14
|
import {
|
|
15
15
|
DaemonClient
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-KTTSXYEK.js";
|
|
17
17
|
|
|
18
18
|
// src/cli/shared.ts
|
|
19
19
|
import fs from "fs";
|
|
@@ -126,4 +126,4 @@ export {
|
|
|
126
126
|
VAULT_GITIGNORE,
|
|
127
127
|
registerSymbionts
|
|
128
128
|
};
|
|
129
|
-
//# sourceMappingURL=chunk-
|
|
129
|
+
//# sourceMappingURL=chunk-QDLVIW2O.js.map
|
|
@@ -5,9 +5,12 @@ import {
|
|
|
5
5
|
import {
|
|
6
6
|
SEARCH_PREVIEW_CHARS,
|
|
7
7
|
SEARCH_RESULTS_DEFAULT_LIMIT
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-6C6QZ4PM.js";
|
|
9
9
|
|
|
10
10
|
// src/db/queries/search.ts
|
|
11
|
+
function sanitizeFtsQuery(query) {
|
|
12
|
+
return query.split(/\s+/).filter((tok) => tok.length > 0).map((tok) => /^[\w]+$/.test(tok) ? tok : `"${tok.replace(/"/g, '""')}"`).join(" ");
|
|
13
|
+
}
|
|
11
14
|
function fullTextSearch(query, options = {}) {
|
|
12
15
|
const db = getDatabase();
|
|
13
16
|
const limit = options.limit ?? SEARCH_RESULTS_DEFAULT_LIMIT;
|
|
@@ -225,7 +228,8 @@ function hydrateSearchResults(vectorResults) {
|
|
|
225
228
|
}
|
|
226
229
|
|
|
227
230
|
export {
|
|
231
|
+
sanitizeFtsQuery,
|
|
228
232
|
fullTextSearch,
|
|
229
233
|
hydrateSearchResults
|
|
230
234
|
};
|
|
231
|
-
//# sourceMappingURL=chunk-
|
|
235
|
+
//# sourceMappingURL=chunk-QLLBJEM7.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/db/queries/search.ts"],"sourcesContent":["/**\n * Full-text search using SQLite FTS5.\n *\n * Searches prompt_batches and activities via their FTS5 virtual tables.\n * Semantic search (vector similarity) is handled by the external VectorStore —\n * this module covers text-based retrieval only.\n *\n * All queries use parameterized placeholders throughout.\n */\n\nimport { getDatabase } from '@myco/db/client.js';\nimport {\n SEARCH_RESULTS_DEFAULT_LIMIT,\n SEARCH_PREVIEW_CHARS,\n} from '@myco/constants.js';\nimport type { VectorSearchResult } from '@myco/daemon/embedding/types.js';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/** All result types that can appear in search results. */\nexport type SearchResultType =\n | 'session'\n | 'spore'\n | 'plan'\n | 'artifact'\n | 'prompt_batch'\n | 'activity'\n | 'skill';\n\n/** A single result returned from full-text or semantic search. */\nexport interface SearchResult {\n id: string;\n type: SearchResultType;\n title: string;\n preview: string;\n score: number;\n session_id?: string;\n}\n\n/** Options for fullTextSearch. */\nexport interface SearchOptions {\n /** Restrict results to a single type. */\n type?: string;\n /** Maximum number of results to return (default: SEARCH_RESULTS_DEFAULT_LIMIT). */\n limit?: number;\n /**\n * When explicitly `false`, hide results belonging to sessions still in\n * `status = 'active'` (and active sessions themselves). Intelligence-task\n * reads opt in to this; UI/CLI callers leave it unset.\n */\n includeActive?: boolean;\n}\n\n// ---------------------------------------------------------------------------\n// Query sanitization\n// ---------------------------------------------------------------------------\n\n/**\n * Sanitize a free-form search string for FTS5 MATCH.\n *\n * FTS5 MATCH treats several characters as operators: `-` means NOT, `:` is\n * a column filter, `\"...\"` is a literal phrase, `+` means must-match, `(`/`)`\n * group, `*` is a prefix wildcard, and unquoted hyphens in identifiers\n * (`skill-evolve-inventory`) or slashes in paths (`packages/myco/src/loader.ts`)\n * are routinely rejected as syntax errors.\n *\n * Natural-language callers (agents querying the vault, users typing in a UI\n * search box) don't know or care about FTS5 syntax — they expect their\n * string to \"just work.\" This helper tokenizes on whitespace and wraps any\n * token containing non-word characters in double quotes, turning it into\n * a literal phrase search. Plain alphanumeric/underscore tokens are left\n * unquoted so they AND together with their neighbours normally.\n *\n * Examples:\n * \"packages/myco/src/loader.ts tools\" → \"\\\"packages/myco/src/loader.ts\\\" tools\"\n * \"skill-evolve merge_candidates\" → \"\\\"skill-evolve\\\" merge_candidates\"\n * \"plain words\" → \"plain words\"\n *\n * Callers that DO want FTS5 operator semantics should skip this helper\n * and pass their own pre-formed MATCH expression to `fullTextSearch`.\n */\nexport function sanitizeFtsQuery(query: string): string {\n return query\n .split(/\\s+/)\n .filter((tok) => tok.length > 0)\n .map((tok) => /^[\\w]+$/.test(tok) ? tok : `\"${tok.replace(/\"/g, '\"\"')}\"`)\n .join(' ');\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/**\n * Full-text search across capture tables using SQLite FTS5.\n *\n * Searches prompt_batches (indexed on user_prompt) and activities (indexed\n * on tool_name, tool_input, file_path). The raw query string is passed\n * directly to FTS5 MATCH — callers should sanitize if needed.\n *\n * FTS5 `rank` values are negative (lower = better match). This function\n * converts them to positive scores via `Math.abs()` so higher = better\n * in the returned results.\n *\n * When `options.type` is specified, only the matching table branch is queried.\n *\n * @param query — search string (FTS5 MATCH syntax)\n * @param options — optional type filter and result limit\n * @returns SearchResult[] ordered by score DESC\n */\nexport function fullTextSearch(\n query: string,\n options: SearchOptions = {},\n): SearchResult[] {\n const db = getDatabase();\n const limit = options.limit ?? SEARCH_RESULTS_DEFAULT_LIMIT;\n const typeFilter = options.type;\n const excludeActive = options.includeActive === false;\n\n const results: SearchResult[] = [];\n\n // -- prompt_batches branch ------------------------------------------------\n if (typeFilter === undefined || typeFilter === 'prompt_batch') {\n const activeGate = excludeActive\n ? ` AND EXISTS (SELECT 1 FROM sessions s WHERE s.id = pb.session_id AND s.status != 'active')`\n : '';\n const batchRows = db.prepare(\n `SELECT pb.id, pb.prompt_number, pb.session_id,\n substr(COALESCE(pb.user_prompt, '') || ' ' || COALESCE(pb.response_summary, ''), 1, ?) AS preview,\n fts.rank\n FROM prompt_batches_fts fts\n JOIN prompt_batches pb ON pb.id = fts.rowid\n WHERE prompt_batches_fts MATCH ?${activeGate}\n ORDER BY fts.rank\n LIMIT ?`\n ).all(SEARCH_PREVIEW_CHARS, query, limit) as Array<{\n id: number;\n prompt_number: number | null;\n session_id: string | null;\n preview: string;\n rank: number;\n }>;\n\n for (const row of batchRows) {\n results.push({\n id: String(row.id),\n type: 'prompt_batch',\n title: row.prompt_number != null\n ? `Batch #${row.prompt_number}`\n : `Batch ${row.id}`,\n preview: row.preview,\n score: Math.abs(row.rank),\n ...(row.session_id != null ? { session_id: row.session_id } : {}),\n });\n }\n }\n\n // -- activities branch ----------------------------------------------------\n if (typeFilter === undefined || typeFilter === 'activity') {\n const activeGate = excludeActive\n ? ` AND EXISTS (SELECT 1 FROM sessions s WHERE s.id = a.session_id AND s.status != 'active')`\n : '';\n const activityRows = db.prepare(\n `SELECT a.id, a.tool_name, a.tool_input, a.file_path, a.session_id,\n fts.rank\n FROM activities_fts fts\n JOIN activities a ON a.id = fts.rowid\n WHERE activities_fts MATCH ?${activeGate}\n ORDER BY fts.rank\n LIMIT ?`\n ).all(query, limit) as Array<{\n id: number;\n tool_name: string;\n tool_input: string | null;\n file_path: string | null;\n session_id: string | null;\n rank: number;\n }>;\n\n for (const row of activityRows) {\n const preview = (row.tool_input ?? row.file_path ?? '').slice(0, SEARCH_PREVIEW_CHARS);\n results.push({\n id: String(row.id),\n type: 'activity',\n title: row.tool_name,\n preview,\n score: Math.abs(row.rank),\n ...(row.session_id != null ? { session_id: row.session_id } : {}),\n });\n }\n }\n\n // -- spores branch --------------------------------------------------------\n if (typeFilter === undefined || typeFilter === 'spore') {\n // Spores may have a NULL session_id (agent-authored, no source session),\n // which are always kept; only spores attached to still-active sessions\n // are excluded when the gate is on.\n const activeGate = excludeActive\n ? ` AND (s.session_id IS NULL OR EXISTS (SELECT 1 FROM sessions ss WHERE ss.id = s.session_id AND ss.status != 'active'))`\n : '';\n const sporeRows = db.prepare(\n `SELECT s.id, s.observation_type, s.session_id,\n substr(COALESCE(s.content, ''), 1, ?) AS preview,\n fts.rank\n FROM spores_fts fts\n JOIN spores s ON s.rowid = fts.rowid\n WHERE spores_fts MATCH ?${activeGate}\n ORDER BY fts.rank\n LIMIT ?`\n ).all(SEARCH_PREVIEW_CHARS, query, limit) as Array<{\n id: string;\n observation_type: string;\n session_id: string | null;\n preview: string;\n rank: number;\n }>;\n\n for (const row of sporeRows) {\n results.push({\n id: String(row.id),\n type: 'spore',\n title: row.observation_type,\n preview: row.preview,\n score: Math.abs(row.rank),\n ...(row.session_id != null ? { session_id: row.session_id } : {}),\n });\n }\n }\n\n // -- sessions branch ------------------------------------------------------\n if (typeFilter === undefined || typeFilter === 'session') {\n const activeGate = excludeActive ? ` AND s.status != 'active'` : '';\n const sessionRows = db.prepare(\n `SELECT s.id, s.title,\n substr(COALESCE(s.summary, s.title, ''), 1, ?) AS preview,\n fts.rank\n FROM sessions_fts fts\n JOIN sessions s ON s.rowid = fts.rowid\n WHERE sessions_fts MATCH ?${activeGate}\n ORDER BY fts.rank\n LIMIT ?`\n ).all(SEARCH_PREVIEW_CHARS, query, limit) as Array<{\n id: string;\n title: string | null;\n preview: string;\n rank: number;\n }>;\n\n for (const row of sessionRows) {\n results.push({\n id: String(row.id),\n type: 'session',\n title: row.title ?? `Session ${row.id.slice(-6)}`,\n preview: row.preview,\n score: Math.abs(row.rank),\n });\n }\n }\n\n // Sort combined results by score DESC and apply limit.\n results.sort((a, b) => b.score - a.score);\n return results.slice(0, limit);\n}\n\n// ---------------------------------------------------------------------------\n// Hydration — convert VectorSearchResults into SearchResults\n// ---------------------------------------------------------------------------\n\n/** Row shape returned from sessions table for hydration. */\ninterface SessionRow {\n id: string;\n title: string | null;\n summary: string | null;\n session_id?: undefined;\n}\n\n/** Row shape returned from spores table for hydration. */\ninterface SporeRow {\n id: string;\n observation_type: string;\n content: string;\n session_id: string | null;\n}\n\n/** Row shape returned from plans table for hydration. */\ninterface PlanRow {\n id: string;\n title: string | null;\n content: string | null;\n session_id: string | null;\n}\n\n/** Row shape returned from artifacts table for hydration. */\ninterface ArtifactRow {\n id: string;\n title: string;\n content: string | null;\n}\n\n/**\n * Hydrate vector search results into SearchResults by fetching full records\n * from the record store.\n *\n * Groups results by namespace, queries each table for the relevant IDs, then\n * maps them into SearchResult format with titles and previews.\n */\nexport function hydrateSearchResults(\n vectorResults: VectorSearchResult[],\n): SearchResult[] {\n if (vectorResults.length === 0) return [];\n\n const db = getDatabase();\n const results: SearchResult[] = [];\n\n // Group result IDs by namespace\n const byNamespace = new Map<string, VectorSearchResult[]>();\n for (const vr of vectorResults) {\n const group = byNamespace.get(vr.namespace) ?? [];\n group.push(vr);\n byNamespace.set(vr.namespace, group);\n }\n\n // Use json_each so the statement text is stable and SQLite can cache the plan.\n const sessionStmt = db.prepare(\n `SELECT id, title, summary FROM sessions WHERE id IN (SELECT value FROM json_each(?))`,\n );\n const sporeStmt = db.prepare(\n `SELECT id, observation_type, content, session_id FROM spores WHERE id IN (SELECT value FROM json_each(?))`,\n );\n const planStmt = db.prepare(\n `SELECT id, title, content, session_id FROM plans WHERE id IN (SELECT value FROM json_each(?))`,\n );\n const artifactStmt = db.prepare(\n `SELECT id, title, content FROM artifacts WHERE id IN (SELECT value FROM json_each(?))`,\n );\n const skillStmt = db.prepare(\n `SELECT id, name, display_name, description FROM skill_records WHERE id IN (SELECT value FROM json_each(?))`,\n );\n\n // --- sessions ---\n const sessionResults = byNamespace.get('sessions');\n if (sessionResults && sessionResults.length > 0) {\n const ids = sessionResults.map((r) => r.id);\n const rows = sessionStmt.all(JSON.stringify(ids)) as SessionRow[];\n\n const rowMap = new Map(rows.map((r) => [r.id, r]));\n for (const vr of sessionResults) {\n const row = rowMap.get(vr.id);\n if (!row) continue;\n results.push({\n id: row.id,\n type: 'session',\n title: row.title ?? `Session ${row.id.slice(-6)}`,\n preview: (row.summary ?? '').slice(0, SEARCH_PREVIEW_CHARS),\n score: vr.similarity,\n });\n }\n }\n\n // --- spores ---\n const sporeResults = byNamespace.get('spores');\n if (sporeResults && sporeResults.length > 0) {\n const ids = sporeResults.map((r) => r.id);\n const rows = sporeStmt.all(JSON.stringify(ids)) as SporeRow[];\n\n const rowMap = new Map(rows.map((r) => [r.id, r]));\n for (const vr of sporeResults) {\n const row = rowMap.get(vr.id);\n if (!row) continue;\n results.push({\n id: row.id,\n type: 'spore',\n title: row.observation_type,\n preview: row.content.slice(0, SEARCH_PREVIEW_CHARS),\n score: vr.similarity,\n ...(row.session_id != null ? { session_id: row.session_id } : {}),\n });\n }\n }\n\n // --- plans ---\n const planResults = byNamespace.get('plans');\n if (planResults && planResults.length > 0) {\n const ids = planResults.map((r) => r.id);\n const rows = planStmt.all(JSON.stringify(ids)) as PlanRow[];\n\n const rowMap = new Map(rows.map((r) => [r.id, r]));\n for (const vr of planResults) {\n const row = rowMap.get(vr.id);\n if (!row) continue;\n results.push({\n id: row.id,\n type: 'plan',\n title: row.title ?? `Plan ${row.id.slice(-6)}`,\n preview: (row.content ?? '').slice(0, SEARCH_PREVIEW_CHARS),\n score: vr.similarity,\n ...(row.session_id != null ? { session_id: row.session_id } : {}),\n });\n }\n }\n\n // --- artifacts ---\n const artifactResults = byNamespace.get('artifacts');\n if (artifactResults && artifactResults.length > 0) {\n const ids = artifactResults.map((r) => r.id);\n const rows = artifactStmt.all(JSON.stringify(ids)) as ArtifactRow[];\n\n const rowMap = new Map(rows.map((r) => [r.id, r]));\n for (const vr of artifactResults) {\n const row = rowMap.get(vr.id);\n if (!row) continue;\n results.push({\n id: row.id,\n type: 'artifact',\n title: row.title,\n preview: (row.content ?? '').slice(0, SEARCH_PREVIEW_CHARS),\n score: vr.similarity,\n });\n }\n }\n\n // --- skill_records ---\n const skillResults = byNamespace.get('skill_records');\n if (skillResults && skillResults.length > 0) {\n const ids = skillResults.map((r) => r.id);\n const rows = skillStmt.all(JSON.stringify(ids)) as Array<{ id: string; name: string; display_name: string; description: string }>;\n\n const rowMap = new Map(rows.map((r) => [r.id, r]));\n for (const vr of skillResults) {\n const row = rowMap.get(vr.id);\n if (!row) continue;\n results.push({\n id: row.id,\n type: 'skill',\n title: row.display_name || row.name,\n preview: row.description.slice(0, SEARCH_PREVIEW_CHARS),\n score: vr.similarity,\n });\n }\n }\n\n // Preserve the original similarity-based ordering from vector search\n results.sort((a, b) => b.score - a.score);\n return results;\n}\n"],"mappings":"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","names":[]}
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
} from "./chunk-MYX5NCRH.js";
|
|
5
5
|
import {
|
|
6
6
|
DEFAULT_MACHINE_ID
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-6C6QZ4PM.js";
|
|
8
8
|
|
|
9
9
|
// src/daemon/team-context.ts
|
|
10
10
|
var teamSyncEnabled = false;
|
|
@@ -25,6 +25,12 @@ var BURST_BATCH_SIZE = 200;
|
|
|
25
25
|
var SENT_PRUNE_AGE_SECONDS = 86400;
|
|
26
26
|
var MAX_OUTBOX_RETRIES = 10;
|
|
27
27
|
var MS_PER_SECOND = 1e3;
|
|
28
|
+
var LOCAL_ONLY_OUTBOX_TABLES = /* @__PURE__ */ new Set([
|
|
29
|
+
// Cortex instructions: per-machine operating guidance generated from local
|
|
30
|
+
// digest substrate. Removed from team sync at schema v19. See
|
|
31
|
+
// migrateV18ToV19 for the corresponding safety-net DELETE.
|
|
32
|
+
"cortex_instructions"
|
|
33
|
+
]);
|
|
28
34
|
var OUTBOX_COLUMNS = [
|
|
29
35
|
"id",
|
|
30
36
|
"table_name",
|
|
@@ -63,6 +69,11 @@ function syncRow(tableName, row) {
|
|
|
63
69
|
});
|
|
64
70
|
}
|
|
65
71
|
function enqueueOutbox(data) {
|
|
72
|
+
if (LOCAL_ONLY_OUTBOX_TABLES.has(data.table_name)) {
|
|
73
|
+
throw new Error(
|
|
74
|
+
`enqueueOutbox: table '${data.table_name}' is local-only and must not be synced`
|
|
75
|
+
);
|
|
76
|
+
}
|
|
66
77
|
const db = getDatabase();
|
|
67
78
|
const info = db.prepare(
|
|
68
79
|
`INSERT INTO team_outbox (
|
|
@@ -567,4 +578,4 @@ export {
|
|
|
567
578
|
getSessionImpact,
|
|
568
579
|
deleteSessionCascade
|
|
569
580
|
};
|
|
570
|
-
//# sourceMappingURL=chunk-
|
|
581
|
+
//# sourceMappingURL=chunk-RQSJLWP4.js.map
|