@goondocks/myco 0.15.0 → 0.16.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/README.md +6 -4
- package/dist/{agent-run-DUOJ3KDI.js → agent-run-S4MFWUSV.js} +8 -8
- package/dist/{agent-tasks-LUWBY5JD.js → agent-tasks-JZ77AZSK.js} +8 -8
- package/dist/{chunk-TRA3R4EC.js → chunk-34NHDRWI.js} +1 -3
- package/dist/chunk-34NHDRWI.js.map +1 -0
- package/dist/{chunk-LF5Z62X6.js → chunk-4JVHWBZF.js} +2 -2
- package/dist/{chunk-GDCSPMH4.js → chunk-6JZEAOLG.js} +3 -3
- package/dist/{chunk-DK5VEBB5.js → chunk-C3GNF7RJ.js} +21 -17
- package/dist/chunk-C3GNF7RJ.js.map +1 -0
- package/dist/{chunk-DJQOYEK3.js → chunk-CJ2KTRWI.js} +52 -4
- package/dist/chunk-CJ2KTRWI.js.map +1 -0
- package/dist/{chunk-3MEOYXOW.js → chunk-D2NTFSVO.js} +3 -3
- package/dist/{chunk-5YQ6VOFZ.js → chunk-DZWSHCAC.js} +2 -2
- package/dist/{chunk-CUADDHHU.js → chunk-E7NUADTQ.js} +9 -1
- package/dist/chunk-E7NUADTQ.js.map +1 -0
- package/dist/{chunk-R3YW7XVF.js → chunk-G6LM45FD.js} +3 -3
- package/dist/{chunk-SV6UCB2Z.js → chunk-GSKXOCFG.js} +3 -1
- package/dist/chunk-GSKXOCFG.js.map +1 -0
- package/dist/{chunk-RBFECYNA.js → chunk-I3S6L7QC.js} +2 -2
- package/dist/{chunk-SPJGJEFV.js → chunk-IRSNOBGD.js} +2 -2
- package/dist/{chunk-75J2BR4P.js → chunk-KYSLNB3C.js} +580 -415
- package/dist/chunk-KYSLNB3C.js.map +1 -0
- package/dist/{chunk-GYIA6XLB.js → chunk-MVBCON4D.js} +2 -2
- package/dist/chunk-MVBCON4D.js.map +1 -0
- package/dist/{chunk-GZ7MXWYX.js → chunk-OH334Y3J.js} +4 -4
- package/dist/{chunk-Z7TZJ2SP.js → chunk-P6C6ADBU.js} +2 -2
- package/dist/{chunk-OKCSSDFC.js → chunk-RPILIIYT.js} +2 -2
- package/dist/{chunk-X5IXK5KO.js → chunk-TIAYBVSI.js} +153 -18
- package/dist/chunk-TIAYBVSI.js.map +1 -0
- package/dist/{chunk-OMZCVRX6.js → chunk-U255A3RE.js} +2 -2
- package/dist/chunk-U5EW2VIQ.js +86 -0
- package/dist/chunk-U5EW2VIQ.js.map +1 -0
- package/dist/{chunk-DTE3SHYK.js → chunk-UILSK6DK.js} +2 -2
- package/dist/{chunk-EYMKBNRP.js → chunk-V2ZBYKDU.js} +3 -3
- package/dist/{chunk-DKGUCEWU.js → chunk-VEQLNB7E.js} +3 -3
- package/dist/{chunk-B3SF2CCW.js → chunk-VQZPWCBH.js} +4 -4
- package/dist/{chunk-HHZ3RTEI.js → chunk-VWXDSDJU.js} +2 -2
- package/dist/{chunk-X4XFJG6I.js → chunk-W7ZOOZMK.js} +3 -3
- package/dist/{chunk-23FJUKCN.js → chunk-WKAYMCPR.js} +2 -2
- package/dist/{chunk-4BQ5QE76.js → chunk-XAXQ72L3.js} +9 -2
- package/dist/chunk-XAXQ72L3.js.map +1 -0
- package/dist/{cli-YBD2GPK4.js → cli-U2FZT4GP.js} +42 -42
- package/dist/{client-CJ3X252K.js → client-MZL5SFQI.js} +5 -5
- package/dist/{config-MOWCOJJ4.js → config-VHHCGE4F.js} +4 -4
- package/dist/{detect-GFYKKHLJ.js → detect-6FNYONJF.js} +2 -2
- package/dist/{detect-providers-EU35RUL3.js → detect-providers-R7QOB3H6.js} +5 -5
- package/dist/{doctor-JR7NEL7K.js → doctor-OJW7SCDQ.js} +13 -13
- package/dist/{executor-7XOKS6HS.js → executor-HP3Y64PD.js} +718 -93
- package/dist/executor-HP3Y64PD.js.map +1 -0
- package/dist/{init-PDLKYWQ4.js → init-XVAONLZ7.js} +18 -18
- package/dist/{init-wizard-WH3SXNMB.js → init-wizard-3OPLXLNA.js} +8 -8
- package/dist/{installer-BTUNKWOU.js → installer-AARSFXI6.js} +2 -2
- package/dist/llm-LS7U7BHC.js +17 -0
- package/dist/{loader-WGDVRGLM.js → loader-QDWQTBX4.js} +4 -4
- package/dist/{loader-WC4U5NM5.js → loader-YQDG5GI5.js} +4 -4
- package/dist/{logs-WFBX2I7C.js → logs-TMKNLSJY.js} +3 -3
- package/dist/{main-JB3R3DQE.js → main-VAU5UPY7.js} +611 -214
- package/dist/main-VAU5UPY7.js.map +1 -0
- package/dist/{open-AADZPSLW.js → open-ES2AOXL5.js} +8 -8
- package/dist/{openai-embeddings-SEIV7AM3.js → openai-embeddings-FUW6CSN2.js} +5 -5
- package/dist/{openrouter-ELODIZRP.js → openrouter-YSIUSUQL.js} +5 -5
- package/dist/{post-compact-KNQ4DYLM.js → post-compact-CCSP4ZRC.js} +8 -8
- package/dist/{post-tool-use-OMWHFQLM.js → post-tool-use-5UIVOE7I.js} +7 -7
- package/dist/{post-tool-use-failure-KFP6MB7Z.js → post-tool-use-failure-SR2523FX.js} +8 -8
- package/dist/{pre-compact-2ZYE2HRB.js → pre-compact-2G2UWGDZ.js} +8 -8
- package/dist/{provider-check-B66E5PWS.js → provider-check-VEYONGNU.js} +5 -5
- package/dist/{registry-DHWVHXWY.js → registry-5R3DLJQH.js} +5 -5
- package/dist/{remove-QT7634L5.js → remove-L4HNBCSZ.js} +10 -10
- package/dist/{resolution-events-DBCRVZGU.js → resolution-events-CHOKR35X.js} +5 -5
- package/dist/{restart-YQNQEHOU.js → restart-ZQ3QNRF4.js} +9 -9
- package/dist/{search-C6JTQDWY.js → search-ECJ76TU3.js} +9 -9
- package/dist/{server-QJ3RWZZZ.js → server-4MUFDPDP.js} +5 -5
- package/dist/{session-JLVL5TYX.js → session-ZHYO3BBY.js} +10 -10
- package/dist/{session-end-XFZRRP5H.js → session-end-UJM3UODF.js} +7 -7
- package/dist/{session-start-XGINISXO.js → session-start-UXLG36AZ.js} +12 -12
- package/dist/{setup-llm-X2OCM6R7.js → setup-llm-NEN5XPNY.js} +9 -9
- package/dist/skill-staging-SWM7UC5D.js +25 -0
- package/dist/src/agent/definitions/tasks/full-intelligence.yaml +1 -1
- package/dist/src/agent/definitions/tasks/skill-generate.yaml +55 -21
- 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/codex.yaml +1 -0
- package/dist/src/symbionts/templates/codex/settings.json +5 -0
- package/dist/src/worker/src/schema.ts +16 -0
- package/dist/{stats-2EAETG2T.js → stats-AYRSUFHR.js} +10 -10
- package/dist/{stop-WOBDYTSA.js → stop-5WD22XAH.js} +7 -7
- package/dist/{stop-failure-QEC7ZGBQ.js → stop-failure-FLFIOPJY.js} +8 -8
- package/dist/{subagent-start-H6DVRVOE.js → subagent-start-AMCPECUD.js} +8 -8
- package/dist/{subagent-stop-LKENKJ65.js → subagent-stop-4M4BUENR.js} +8 -8
- package/dist/{task-completed-ZZ47PRPD.js → task-completed-QJOEVDXZ.js} +8 -8
- package/dist/{team-J62N7VMG.js → team-FWEVWYIY.js} +6 -6
- package/dist/ui/assets/index-Bjv_ck3c.css +1 -0
- package/dist/ui/assets/index-RYHXSJv1.js +842 -0
- package/dist/ui/index.html +2 -2
- package/dist/{update-LX3CJ4TJ.js → update-F2LPJMUE.js} +10 -10
- package/dist/{user-prompt-submit-NNMLY3EW.js → user-prompt-submit-UOAIU3JW.js} +7 -7
- package/dist/{verify-AMRQXQ3K.js → verify-ITBMLK67.js} +9 -9
- package/dist/{version-6OJH5HLZ.js → version-2NJN3WW6.js} +2 -2
- package/dist/version-2NJN3WW6.js.map +1 -0
- package/package.json +2 -2
- package/dist/chunk-4BQ5QE76.js.map +0 -1
- package/dist/chunk-75J2BR4P.js.map +0 -1
- package/dist/chunk-CUADDHHU.js.map +0 -1
- package/dist/chunk-DJQOYEK3.js.map +0 -1
- package/dist/chunk-DK5VEBB5.js.map +0 -1
- package/dist/chunk-GYIA6XLB.js.map +0 -1
- package/dist/chunk-SV6UCB2Z.js.map +0 -1
- package/dist/chunk-TRA3R4EC.js.map +0 -1
- package/dist/chunk-X5IXK5KO.js.map +0 -1
- package/dist/executor-7XOKS6HS.js.map +0 -1
- package/dist/llm-DK44LYO6.js +0 -17
- package/dist/main-JB3R3DQE.js.map +0 -1
- package/dist/ui/assets/index-Bx9l8uxa.js +0 -837
- package/dist/ui/assets/index-DlEQ8A8Y.css +0 -1
- /package/dist/{agent-run-DUOJ3KDI.js.map → agent-run-S4MFWUSV.js.map} +0 -0
- /package/dist/{agent-tasks-LUWBY5JD.js.map → agent-tasks-JZ77AZSK.js.map} +0 -0
- /package/dist/{chunk-LF5Z62X6.js.map → chunk-4JVHWBZF.js.map} +0 -0
- /package/dist/{chunk-GDCSPMH4.js.map → chunk-6JZEAOLG.js.map} +0 -0
- /package/dist/{chunk-3MEOYXOW.js.map → chunk-D2NTFSVO.js.map} +0 -0
- /package/dist/{chunk-5YQ6VOFZ.js.map → chunk-DZWSHCAC.js.map} +0 -0
- /package/dist/{chunk-R3YW7XVF.js.map → chunk-G6LM45FD.js.map} +0 -0
- /package/dist/{chunk-RBFECYNA.js.map → chunk-I3S6L7QC.js.map} +0 -0
- /package/dist/{chunk-SPJGJEFV.js.map → chunk-IRSNOBGD.js.map} +0 -0
- /package/dist/{chunk-GZ7MXWYX.js.map → chunk-OH334Y3J.js.map} +0 -0
- /package/dist/{chunk-Z7TZJ2SP.js.map → chunk-P6C6ADBU.js.map} +0 -0
- /package/dist/{chunk-OKCSSDFC.js.map → chunk-RPILIIYT.js.map} +0 -0
- /package/dist/{chunk-OMZCVRX6.js.map → chunk-U255A3RE.js.map} +0 -0
- /package/dist/{chunk-DTE3SHYK.js.map → chunk-UILSK6DK.js.map} +0 -0
- /package/dist/{chunk-EYMKBNRP.js.map → chunk-V2ZBYKDU.js.map} +0 -0
- /package/dist/{chunk-DKGUCEWU.js.map → chunk-VEQLNB7E.js.map} +0 -0
- /package/dist/{chunk-B3SF2CCW.js.map → chunk-VQZPWCBH.js.map} +0 -0
- /package/dist/{chunk-HHZ3RTEI.js.map → chunk-VWXDSDJU.js.map} +0 -0
- /package/dist/{chunk-X4XFJG6I.js.map → chunk-W7ZOOZMK.js.map} +0 -0
- /package/dist/{chunk-23FJUKCN.js.map → chunk-WKAYMCPR.js.map} +0 -0
- /package/dist/{cli-YBD2GPK4.js.map → cli-U2FZT4GP.js.map} +0 -0
- /package/dist/{client-CJ3X252K.js.map → client-MZL5SFQI.js.map} +0 -0
- /package/dist/{config-MOWCOJJ4.js.map → config-VHHCGE4F.js.map} +0 -0
- /package/dist/{detect-GFYKKHLJ.js.map → detect-6FNYONJF.js.map} +0 -0
- /package/dist/{detect-providers-EU35RUL3.js.map → detect-providers-R7QOB3H6.js.map} +0 -0
- /package/dist/{doctor-JR7NEL7K.js.map → doctor-OJW7SCDQ.js.map} +0 -0
- /package/dist/{init-PDLKYWQ4.js.map → init-XVAONLZ7.js.map} +0 -0
- /package/dist/{init-wizard-WH3SXNMB.js.map → init-wizard-3OPLXLNA.js.map} +0 -0
- /package/dist/{installer-BTUNKWOU.js.map → installer-AARSFXI6.js.map} +0 -0
- /package/dist/{llm-DK44LYO6.js.map → llm-LS7U7BHC.js.map} +0 -0
- /package/dist/{loader-WC4U5NM5.js.map → loader-QDWQTBX4.js.map} +0 -0
- /package/dist/{loader-WGDVRGLM.js.map → loader-YQDG5GI5.js.map} +0 -0
- /package/dist/{logs-WFBX2I7C.js.map → logs-TMKNLSJY.js.map} +0 -0
- /package/dist/{open-AADZPSLW.js.map → open-ES2AOXL5.js.map} +0 -0
- /package/dist/{openai-embeddings-SEIV7AM3.js.map → openai-embeddings-FUW6CSN2.js.map} +0 -0
- /package/dist/{openrouter-ELODIZRP.js.map → openrouter-YSIUSUQL.js.map} +0 -0
- /package/dist/{post-compact-KNQ4DYLM.js.map → post-compact-CCSP4ZRC.js.map} +0 -0
- /package/dist/{post-tool-use-OMWHFQLM.js.map → post-tool-use-5UIVOE7I.js.map} +0 -0
- /package/dist/{post-tool-use-failure-KFP6MB7Z.js.map → post-tool-use-failure-SR2523FX.js.map} +0 -0
- /package/dist/{pre-compact-2ZYE2HRB.js.map → pre-compact-2G2UWGDZ.js.map} +0 -0
- /package/dist/{provider-check-B66E5PWS.js.map → provider-check-VEYONGNU.js.map} +0 -0
- /package/dist/{registry-DHWVHXWY.js.map → registry-5R3DLJQH.js.map} +0 -0
- /package/dist/{remove-QT7634L5.js.map → remove-L4HNBCSZ.js.map} +0 -0
- /package/dist/{resolution-events-DBCRVZGU.js.map → resolution-events-CHOKR35X.js.map} +0 -0
- /package/dist/{restart-YQNQEHOU.js.map → restart-ZQ3QNRF4.js.map} +0 -0
- /package/dist/{search-C6JTQDWY.js.map → search-ECJ76TU3.js.map} +0 -0
- /package/dist/{server-QJ3RWZZZ.js.map → server-4MUFDPDP.js.map} +0 -0
- /package/dist/{session-JLVL5TYX.js.map → session-ZHYO3BBY.js.map} +0 -0
- /package/dist/{session-end-XFZRRP5H.js.map → session-end-UJM3UODF.js.map} +0 -0
- /package/dist/{session-start-XGINISXO.js.map → session-start-UXLG36AZ.js.map} +0 -0
- /package/dist/{setup-llm-X2OCM6R7.js.map → setup-llm-NEN5XPNY.js.map} +0 -0
- /package/dist/{version-6OJH5HLZ.js.map → skill-staging-SWM7UC5D.js.map} +0 -0
- /package/dist/{stats-2EAETG2T.js.map → stats-AYRSUFHR.js.map} +0 -0
- /package/dist/{stop-WOBDYTSA.js.map → stop-5WD22XAH.js.map} +0 -0
- /package/dist/{stop-failure-QEC7ZGBQ.js.map → stop-failure-FLFIOPJY.js.map} +0 -0
- /package/dist/{subagent-start-H6DVRVOE.js.map → subagent-start-AMCPECUD.js.map} +0 -0
- /package/dist/{subagent-stop-LKENKJ65.js.map → subagent-stop-4M4BUENR.js.map} +0 -0
- /package/dist/{task-completed-ZZ47PRPD.js.map → task-completed-QJOEVDXZ.js.map} +0 -0
- /package/dist/{team-J62N7VMG.js.map → team-FWEVWYIY.js.map} +0 -0
- /package/dist/{update-LX3CJ4TJ.js.map → update-F2LPJMUE.js.map} +0 -0
- /package/dist/{user-prompt-submit-NNMLY3EW.js.map → user-prompt-submit-UOAIU3JW.js.map} +0 -0
- /package/dist/{verify-AMRQXQ3K.js.map → verify-ITBMLK67.js.map} +0 -0
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createRequire as __cr } from 'node:module'; const require = __cr(import.meta.url);
|
|
2
2
|
import {
|
|
3
|
+
SKILL_GENERATE_TASK,
|
|
3
4
|
STATUS_COMPLETED,
|
|
4
5
|
STATUS_FAILED,
|
|
5
6
|
STATUS_RUNNING,
|
|
@@ -30,13 +31,20 @@ import {
|
|
|
30
31
|
updateRunStatus,
|
|
31
32
|
updateSkillRecord,
|
|
32
33
|
upsertDigestExtract
|
|
33
|
-
} from "./chunk-
|
|
34
|
+
} from "./chunk-KYSLNB3C.js";
|
|
34
35
|
import {
|
|
35
36
|
fullTextSearch
|
|
36
|
-
} from "./chunk-
|
|
37
|
+
} from "./chunk-UILSK6DK.js";
|
|
38
|
+
import {
|
|
39
|
+
cleanupStagedSkill,
|
|
40
|
+
readStagedManifest,
|
|
41
|
+
readStagedSkill,
|
|
42
|
+
writeStagedManifest,
|
|
43
|
+
writeStagedSkill
|
|
44
|
+
} from "./chunk-U5EW2VIQ.js";
|
|
37
45
|
import {
|
|
38
46
|
loadAllTasks
|
|
39
|
-
} from "./chunk-
|
|
47
|
+
} from "./chunk-D2NTFSVO.js";
|
|
40
48
|
import {
|
|
41
49
|
getAgent,
|
|
42
50
|
getDefaultTask,
|
|
@@ -45,31 +53,33 @@ import {
|
|
|
45
53
|
loadSystemPrompt,
|
|
46
54
|
resolveDefinitionsDir,
|
|
47
55
|
resolveEffectiveConfig
|
|
48
|
-
} from "./chunk-
|
|
56
|
+
} from "./chunk-W7ZOOZMK.js";
|
|
49
57
|
import {
|
|
50
58
|
insertTurn
|
|
51
59
|
} from "./chunk-QLCD77AN.js";
|
|
52
60
|
import {
|
|
53
61
|
insertResolutionEvent
|
|
54
|
-
} from "./chunk-
|
|
62
|
+
} from "./chunk-P6C6ADBU.js";
|
|
55
63
|
import "./chunk-IB76KGBY.js";
|
|
56
64
|
import {
|
|
57
65
|
DEFAULT_IMPORTANCE,
|
|
58
66
|
insertSpore,
|
|
59
67
|
listSpores,
|
|
60
68
|
updateSporeStatus
|
|
61
|
-
} from "./chunk-
|
|
69
|
+
} from "./chunk-IRSNOBGD.js";
|
|
62
70
|
import {
|
|
63
71
|
listSessions,
|
|
64
72
|
updateSession
|
|
65
|
-
} from "./chunk-
|
|
66
|
-
import "./chunk-
|
|
73
|
+
} from "./chunk-WKAYMCPR.js";
|
|
74
|
+
import "./chunk-4JVHWBZF.js";
|
|
67
75
|
import {
|
|
76
|
+
AGENT_SETTABLE_STATUSES,
|
|
77
|
+
CANDIDATE_STATUS,
|
|
68
78
|
createSchema
|
|
69
|
-
} from "./chunk-
|
|
79
|
+
} from "./chunk-CJ2KTRWI.js";
|
|
70
80
|
import {
|
|
71
81
|
loadConfig
|
|
72
|
-
} from "./chunk-
|
|
82
|
+
} from "./chunk-XAXQ72L3.js";
|
|
73
83
|
import {
|
|
74
84
|
getDatabase,
|
|
75
85
|
initDatabase,
|
|
@@ -77,7 +87,7 @@ import {
|
|
|
77
87
|
} from "./chunk-MYX5NCRH.js";
|
|
78
88
|
import {
|
|
79
89
|
getPluginVersion
|
|
80
|
-
} from "./chunk-
|
|
90
|
+
} from "./chunk-U255A3RE.js";
|
|
81
91
|
import {
|
|
82
92
|
findPackageRoot
|
|
83
93
|
} from "./chunk-LPUQPDC2.js";
|
|
@@ -89,8 +99,8 @@ import {
|
|
|
89
99
|
SEARCH_SIMILARITY_THRESHOLD,
|
|
90
100
|
TEAM_SOURCE_PREFIX,
|
|
91
101
|
epochSeconds
|
|
92
|
-
} from "./chunk-
|
|
93
|
-
import "./chunk-
|
|
102
|
+
} from "./chunk-34NHDRWI.js";
|
|
103
|
+
import "./chunk-E7NUADTQ.js";
|
|
94
104
|
import "./chunk-D7TYRPRM.js";
|
|
95
105
|
import "./chunk-E4VLWIJC.js";
|
|
96
106
|
import {
|
|
@@ -649,12 +659,115 @@ import { tool as tool4 } from "@anthropic-ai/claude-agent-sdk";
|
|
|
649
659
|
var MAX_SKILL_LINES = 500;
|
|
650
660
|
var REQUIRED_FRONTMATTER_FIELDS = ["name", "description", "managed_by", "user-invocable", "allowed-tools"];
|
|
651
661
|
var PROTECTED_FRONTMATTER_FIELDS = ["user-invocable", "allowed-tools"];
|
|
662
|
+
var ALLOWED_CLAUDE_CODE_TOOLS = /* @__PURE__ */ new Set([
|
|
663
|
+
"Read",
|
|
664
|
+
"Edit",
|
|
665
|
+
"Write",
|
|
666
|
+
"MultiEdit",
|
|
667
|
+
"Bash",
|
|
668
|
+
"Grep",
|
|
669
|
+
"Glob",
|
|
670
|
+
"NotebookRead",
|
|
671
|
+
"NotebookEdit",
|
|
672
|
+
"WebFetch",
|
|
673
|
+
"WebSearch",
|
|
674
|
+
"Task",
|
|
675
|
+
"TodoWrite"
|
|
676
|
+
]);
|
|
652
677
|
function extractFrontmatterField(content, field) {
|
|
653
678
|
const fmMatch = content.match(/^---\n([\s\S]*?)\n---/);
|
|
654
679
|
if (!fmMatch) return void 0;
|
|
655
680
|
const match = fmMatch[1].match(new RegExp(`^${field}:\\s*(.+)$`, "m"));
|
|
656
681
|
return match?.[1].trim();
|
|
657
682
|
}
|
|
683
|
+
function parseAllowedTools(rawValue) {
|
|
684
|
+
if (!rawValue) return null;
|
|
685
|
+
let stripped = rawValue.trim();
|
|
686
|
+
if (stripped.length === 0) return null;
|
|
687
|
+
if (stripped.startsWith("[") && stripped.endsWith("]")) {
|
|
688
|
+
stripped = stripped.slice(1, -1).trim();
|
|
689
|
+
}
|
|
690
|
+
if (stripped.length === 0) return null;
|
|
691
|
+
const parts = stripped.split(",").map((s) => s.trim().replace(/^['"]|['"]$/g, "")).filter((s) => s.length > 0);
|
|
692
|
+
if (parts.length === 0) return null;
|
|
693
|
+
const sentinels = /* @__PURE__ */ new Set(["None", "none", "null", "Null", "~"]);
|
|
694
|
+
if (parts.some((p) => sentinels.has(p))) return null;
|
|
695
|
+
return parts;
|
|
696
|
+
}
|
|
697
|
+
function tokenSet(text) {
|
|
698
|
+
const stopwords = /* @__PURE__ */ new Set([
|
|
699
|
+
"the",
|
|
700
|
+
"a",
|
|
701
|
+
"an",
|
|
702
|
+
"and",
|
|
703
|
+
"or",
|
|
704
|
+
"but",
|
|
705
|
+
"is",
|
|
706
|
+
"are",
|
|
707
|
+
"was",
|
|
708
|
+
"were",
|
|
709
|
+
"be",
|
|
710
|
+
"been",
|
|
711
|
+
"being",
|
|
712
|
+
"have",
|
|
713
|
+
"has",
|
|
714
|
+
"had",
|
|
715
|
+
"do",
|
|
716
|
+
"does",
|
|
717
|
+
"did",
|
|
718
|
+
"will",
|
|
719
|
+
"would",
|
|
720
|
+
"should",
|
|
721
|
+
"could",
|
|
722
|
+
"may",
|
|
723
|
+
"might",
|
|
724
|
+
"must",
|
|
725
|
+
"can",
|
|
726
|
+
"this",
|
|
727
|
+
"that",
|
|
728
|
+
"these",
|
|
729
|
+
"those",
|
|
730
|
+
"with",
|
|
731
|
+
"from",
|
|
732
|
+
"into",
|
|
733
|
+
"onto",
|
|
734
|
+
"for",
|
|
735
|
+
"when",
|
|
736
|
+
"where",
|
|
737
|
+
"which",
|
|
738
|
+
"what",
|
|
739
|
+
"who",
|
|
740
|
+
"how",
|
|
741
|
+
"why",
|
|
742
|
+
"use",
|
|
743
|
+
"uses",
|
|
744
|
+
"used",
|
|
745
|
+
"using",
|
|
746
|
+
"not",
|
|
747
|
+
"also",
|
|
748
|
+
"than",
|
|
749
|
+
"then",
|
|
750
|
+
"ensure",
|
|
751
|
+
"ensures",
|
|
752
|
+
"make",
|
|
753
|
+
"makes"
|
|
754
|
+
]);
|
|
755
|
+
return new Set(
|
|
756
|
+
text.toLowerCase().replace(/[^a-z0-9_\s]/g, " ").split(/\s+/).filter((w) => w.length >= 4 && !stopwords.has(w))
|
|
757
|
+
);
|
|
758
|
+
}
|
|
759
|
+
function descriptionSimilarity(a, b) {
|
|
760
|
+
const aTokens = tokenSet(a);
|
|
761
|
+
const bTokens = tokenSet(b);
|
|
762
|
+
if (aTokens.size === 0 || bTokens.size === 0) return 0;
|
|
763
|
+
let intersection = 0;
|
|
764
|
+
for (const token of aTokens) {
|
|
765
|
+
if (bTokens.has(token)) intersection++;
|
|
766
|
+
}
|
|
767
|
+
const union = aTokens.size + bTokens.size - intersection;
|
|
768
|
+
return union === 0 ? 0 : intersection / union;
|
|
769
|
+
}
|
|
770
|
+
var DESCRIPTION_DUPLICATE_THRESHOLD = 0.4;
|
|
658
771
|
function checkFrontmatterPreservation(existing, incoming) {
|
|
659
772
|
const violations = [];
|
|
660
773
|
for (const field of PROTECTED_FRONTMATTER_FIELDS) {
|
|
@@ -696,11 +809,25 @@ function validateSkillContent(content, dirName) {
|
|
|
696
809
|
}
|
|
697
810
|
const allowedToolsMatch = frontmatter.match(/^allowed-tools:\s*(.+)$/m);
|
|
698
811
|
if (allowedToolsMatch) {
|
|
699
|
-
const
|
|
700
|
-
if (
|
|
812
|
+
const rawValue = allowedToolsMatch[1].trim();
|
|
813
|
+
if (rawValue.includes("vault_")) {
|
|
701
814
|
issues.push(
|
|
702
815
|
"allowed-tools contains vault agent tool names (vault_*). Skills run in Claude Code sessions -- use Claude Code tool names instead: Read, Edit, Write, Bash, Grep, Glob"
|
|
703
816
|
);
|
|
817
|
+
} else {
|
|
818
|
+
const parsed = parseAllowedTools(rawValue);
|
|
819
|
+
if (parsed === null) {
|
|
820
|
+
issues.push(
|
|
821
|
+
`allowed-tools value is malformed or empty: "${rawValue}". Provide a comma-separated list of Claude Code tools, e.g. "Read, Edit, Write, Bash, Grep, Glob". Use the narrowest set the skill actually needs.`
|
|
822
|
+
);
|
|
823
|
+
} else {
|
|
824
|
+
const unknown = parsed.filter((t) => !ALLOWED_CLAUDE_CODE_TOOLS.has(t));
|
|
825
|
+
if (unknown.length > 0) {
|
|
826
|
+
issues.push(
|
|
827
|
+
`allowed-tools contains unknown tool name(s): ${unknown.join(", ")}. Valid Claude Code tools: ${[...ALLOWED_CLAUDE_CODE_TOOLS].join(", ")}.`
|
|
828
|
+
);
|
|
829
|
+
}
|
|
830
|
+
}
|
|
704
831
|
}
|
|
705
832
|
}
|
|
706
833
|
const listToolLines = frontmatter.match(/^\s+-\s+vault_\w+/gm);
|
|
@@ -719,6 +846,200 @@ function validateSkillContent(content, dirName) {
|
|
|
719
846
|
// src/agent/tools/skill-tools.ts
|
|
720
847
|
function createSkillTools(deps) {
|
|
721
848
|
const { agentId, machineId, projectRoot, vaultDir, recordTurn } = deps;
|
|
849
|
+
function findOverlappingCandidate(newTopic, existing) {
|
|
850
|
+
let best = null;
|
|
851
|
+
for (const candidate of existing) {
|
|
852
|
+
const score = descriptionSimilarity(newTopic, candidate.topic);
|
|
853
|
+
if (score >= DESCRIPTION_DUPLICATE_THRESHOLD && (!best || score > best.score)) {
|
|
854
|
+
best = { candidate, score };
|
|
855
|
+
}
|
|
856
|
+
}
|
|
857
|
+
return best;
|
|
858
|
+
}
|
|
859
|
+
function candidateOverlapError(match) {
|
|
860
|
+
const common = `already has an existing candidate with a similar topic: "${match.topic}"`;
|
|
861
|
+
switch (match.status) {
|
|
862
|
+
case CANDIDATE_STATUS.DISMISSED:
|
|
863
|
+
return `Candidate rejected: the vault ${common} that was previously dismissed. Do not re-identify dismissed topics.`;
|
|
864
|
+
case CANDIDATE_STATUS.GENERATED:
|
|
865
|
+
return `Candidate rejected: the vault ${common} that was already fulfilled by a generated skill. Do not re-identify.`;
|
|
866
|
+
case CANDIDATE_STATUS.APPROVED:
|
|
867
|
+
return `Candidate rejected: the vault ${common} that is already queued in approved state. Wait for the generate task to process it.`;
|
|
868
|
+
case CANDIDATE_STATUS.IDENTIFIED:
|
|
869
|
+
return `Candidate rejected: the vault ${common} already in the review queue. Update the existing candidate with new evidence (action: update) instead of creating a duplicate.`;
|
|
870
|
+
default:
|
|
871
|
+
return `Candidate rejected: the vault ${common} in status '${match.status}'.`;
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
function requireApprovedCandidate(candidateId) {
|
|
875
|
+
const candidate = getCandidate(candidateId);
|
|
876
|
+
if (!candidate) {
|
|
877
|
+
return {
|
|
878
|
+
error: `Candidate ${candidateId} not found. Skill writes require a candidate in the approved state.`
|
|
879
|
+
};
|
|
880
|
+
}
|
|
881
|
+
if (candidate.status !== CANDIDATE_STATUS.APPROVED) {
|
|
882
|
+
return {
|
|
883
|
+
error: `Candidate ${candidateId} is in '${candidate.status}' state. Skills can only be generated from candidates in 'approved' state \u2014 the human review step. If a candidate in an earlier state needs to become a skill, route it through the normal approval flow first.`,
|
|
884
|
+
candidate_status: candidate.status
|
|
885
|
+
};
|
|
886
|
+
}
|
|
887
|
+
return null;
|
|
888
|
+
}
|
|
889
|
+
function checkDedupGates(args) {
|
|
890
|
+
const existingSameName = getSkillRecordByName(args.name);
|
|
891
|
+
if (existingSameName) {
|
|
892
|
+
if (args.rejectSameName) {
|
|
893
|
+
return {
|
|
894
|
+
error: `Skill "${args.name}" already exists. This path is create-only. Use vault_write_skill to evolve the existing skill (it bumps the generation), or mark the current record stale via vault_skill_records first.`,
|
|
895
|
+
existing_skill: {
|
|
896
|
+
id: existingSameName.id,
|
|
897
|
+
name: existingSameName.name,
|
|
898
|
+
path: existingSameName.path
|
|
899
|
+
}
|
|
900
|
+
};
|
|
901
|
+
}
|
|
902
|
+
return null;
|
|
903
|
+
}
|
|
904
|
+
if (args.candidate_id) {
|
|
905
|
+
const candidate = getCandidate(args.candidate_id);
|
|
906
|
+
if (candidate?.skill_id) {
|
|
907
|
+
const linkedSkill = getSkillRecord(candidate.skill_id);
|
|
908
|
+
if (linkedSkill && linkedSkill.name !== args.name) {
|
|
909
|
+
return {
|
|
910
|
+
error: `Candidate ${args.candidate_id} is already fulfilled by skill "${linkedSkill.name}". Do not create a sibling skill. If the existing skill needs changes, write to the same name to evolve it (this bumps its generation), or mark it stale via vault_skill_records before replacing.`,
|
|
911
|
+
existing_skill: {
|
|
912
|
+
id: linkedSkill.id,
|
|
913
|
+
name: linkedSkill.name,
|
|
914
|
+
description: linkedSkill.description,
|
|
915
|
+
path: linkedSkill.path
|
|
916
|
+
}
|
|
917
|
+
};
|
|
918
|
+
}
|
|
919
|
+
}
|
|
920
|
+
}
|
|
921
|
+
const activeSkills = listSkillRecords({ agent_id: agentId, status: "active", limit: 200 });
|
|
922
|
+
let bestMatch = null;
|
|
923
|
+
for (const skill of activeSkills) {
|
|
924
|
+
const score = descriptionSimilarity(args.description, skill.description);
|
|
925
|
+
if (score >= DESCRIPTION_DUPLICATE_THRESHOLD && (!bestMatch || score > bestMatch.score)) {
|
|
926
|
+
bestMatch = { skill, score };
|
|
927
|
+
}
|
|
928
|
+
}
|
|
929
|
+
if (bestMatch) {
|
|
930
|
+
return {
|
|
931
|
+
error: `Description overlaps with existing active skill "${bestMatch.skill.name}" (Jaccard ${bestMatch.score.toFixed(2)}, threshold ${DESCRIPTION_DUPLICATE_THRESHOLD}). Do not create a duplicate. Either evolve the existing skill by writing to its name ("${bestMatch.skill.name}"), or reframe this skill so its description describes a distinct procedure.`,
|
|
932
|
+
overlapping_skill: {
|
|
933
|
+
id: bestMatch.skill.id,
|
|
934
|
+
name: bestMatch.skill.name,
|
|
935
|
+
description: bestMatch.skill.description,
|
|
936
|
+
path: bestMatch.skill.path
|
|
937
|
+
},
|
|
938
|
+
similarity: bestMatch.score
|
|
939
|
+
};
|
|
940
|
+
}
|
|
941
|
+
return null;
|
|
942
|
+
}
|
|
943
|
+
async function promoteNewSkill(params) {
|
|
944
|
+
const root = projectRoot ?? process.cwd();
|
|
945
|
+
const skillDir = resolve(root, ".agents", "skills", params.name);
|
|
946
|
+
const skillPath = resolve(skillDir, "SKILL.md");
|
|
947
|
+
const skillDirPreexisted = existsSync(skillDir);
|
|
948
|
+
async function cleanupCreatedSkillArtifactsOnRollback() {
|
|
949
|
+
try {
|
|
950
|
+
if (!skillDirPreexisted) {
|
|
951
|
+
rmSync(skillDir, { recursive: true, force: true });
|
|
952
|
+
} else {
|
|
953
|
+
rmSync(skillPath, { force: true });
|
|
954
|
+
}
|
|
955
|
+
} catch (rollbackErr) {
|
|
956
|
+
console.warn(
|
|
957
|
+
`[${params.label}] file rollback after DB failure also failed:`,
|
|
958
|
+
rollbackErr instanceof Error ? rollbackErr.message : rollbackErr
|
|
959
|
+
);
|
|
960
|
+
}
|
|
961
|
+
try {
|
|
962
|
+
const { syncSkillSymlinks } = await import("./installer-AARSFXI6.js");
|
|
963
|
+
syncSkillSymlinks(root, params.name, { remove: true });
|
|
964
|
+
} catch (rollbackErr) {
|
|
965
|
+
console.warn(
|
|
966
|
+
`[${params.label}] symlink rollback after DB failure also failed:`,
|
|
967
|
+
rollbackErr instanceof Error ? rollbackErr.message : rollbackErr
|
|
968
|
+
);
|
|
969
|
+
}
|
|
970
|
+
}
|
|
971
|
+
try {
|
|
972
|
+
mkdirSync(skillDir, { recursive: true });
|
|
973
|
+
writeFileSync(skillPath, params.content, "utf-8");
|
|
974
|
+
} catch (err) {
|
|
975
|
+
return {
|
|
976
|
+
error: `Failed to write skill file: ${err instanceof Error ? err.message : String(err)}`
|
|
977
|
+
};
|
|
978
|
+
}
|
|
979
|
+
try {
|
|
980
|
+
const { syncSkillSymlinks } = await import("./installer-AARSFXI6.js");
|
|
981
|
+
syncSkillSymlinks(root, params.name);
|
|
982
|
+
} catch (err) {
|
|
983
|
+
console.warn(
|
|
984
|
+
`[${params.label}] syncSkillSymlinks failed:`,
|
|
985
|
+
err instanceof Error ? err.message : err
|
|
986
|
+
);
|
|
987
|
+
}
|
|
988
|
+
const now = epochSeconds();
|
|
989
|
+
const relativePath = `.agents/skills/${params.name}/SKILL.md`;
|
|
990
|
+
const recordId = crypto2.randomUUID();
|
|
991
|
+
const generation = 1;
|
|
992
|
+
const txDb = getDatabase();
|
|
993
|
+
try {
|
|
994
|
+
txDb.transaction(() => {
|
|
995
|
+
insertSkillRecord({
|
|
996
|
+
id: recordId,
|
|
997
|
+
agent_id: agentId,
|
|
998
|
+
machine_id: machineId,
|
|
999
|
+
name: params.name,
|
|
1000
|
+
display_name: params.display_name,
|
|
1001
|
+
description: params.description,
|
|
1002
|
+
candidate_id: params.candidate_id ?? null,
|
|
1003
|
+
source_ids: params.source_ids,
|
|
1004
|
+
path: relativePath,
|
|
1005
|
+
created_at: now,
|
|
1006
|
+
updated_at: now
|
|
1007
|
+
});
|
|
1008
|
+
insertLineage({
|
|
1009
|
+
id: crypto2.randomUUID(),
|
|
1010
|
+
skill_id: recordId,
|
|
1011
|
+
generation,
|
|
1012
|
+
action: "created",
|
|
1013
|
+
rationale: params.rationale ?? "Initial skill creation",
|
|
1014
|
+
source_ids_added: params.source_ids,
|
|
1015
|
+
content_snapshot: params.content,
|
|
1016
|
+
created_at: now
|
|
1017
|
+
});
|
|
1018
|
+
params.linkCandidate?.(recordId, now);
|
|
1019
|
+
})();
|
|
1020
|
+
} catch (err) {
|
|
1021
|
+
await cleanupCreatedSkillArtifactsOnRollback();
|
|
1022
|
+
return {
|
|
1023
|
+
error: `Skill write aborted: database transaction failed and on-disk state was rolled back. ${err instanceof Error ? err.message : String(err)}`
|
|
1024
|
+
};
|
|
1025
|
+
}
|
|
1026
|
+
return {
|
|
1027
|
+
id: recordId,
|
|
1028
|
+
name: params.name,
|
|
1029
|
+
path: relativePath,
|
|
1030
|
+
generation
|
|
1031
|
+
};
|
|
1032
|
+
}
|
|
1033
|
+
function emitSkillNotification(kind, opts) {
|
|
1034
|
+
notify(vaultDir, {
|
|
1035
|
+
domain: "skills",
|
|
1036
|
+
type: kind === "created" ? "skill.created" : "skill.evolved",
|
|
1037
|
+
title: `Skill ${kind}: ${opts.display_name}`,
|
|
1038
|
+
message: opts.description.slice(0, 120),
|
|
1039
|
+
link: `/skills?skill=${encodeURIComponent(opts.name)}`,
|
|
1040
|
+
metadata: { skillId: opts.recordId, name: opts.name, generation: opts.generation }
|
|
1041
|
+
});
|
|
1042
|
+
}
|
|
722
1043
|
const vaultSkillCandidates = tool4(
|
|
723
1044
|
"vault_skill_candidates",
|
|
724
1045
|
"Manage skill candidates (identified topics that may become skills). Supports list, get, create, and update actions.",
|
|
@@ -728,7 +1049,9 @@ function createSkillTools(deps) {
|
|
|
728
1049
|
topic: external_exports.string().optional().describe("Skill topic (required for create)"),
|
|
729
1050
|
rationale: external_exports.string().optional().describe("Why this should be a skill (required for create)"),
|
|
730
1051
|
confidence: external_exports.number().optional().describe("Confidence score 0-1"),
|
|
731
|
-
status: external_exports.enum(
|
|
1052
|
+
status: external_exports.enum(AGENT_SETTABLE_STATUSES).optional().describe(
|
|
1053
|
+
"Candidate status \u2014 agent-settable values only. 'identified' is the initial state; 'dismissed' retires a candidate. 'approved' and 'generated' are lifecycle transitions owned by the human UI and vault_finalize_skill respectively."
|
|
1054
|
+
),
|
|
732
1055
|
source_ids: external_exports.string().optional().describe("JSON array of source spore/entity IDs"),
|
|
733
1056
|
skill_id: external_exports.string().optional().describe("Associated skill record ID (after materialization)"),
|
|
734
1057
|
limit: external_exports.number().optional().describe("Maximum candidates to return (for list)")
|
|
@@ -767,6 +1090,19 @@ function createSkillTools(deps) {
|
|
|
767
1090
|
overlapping_skills: overlapping.map((s) => ({ name: s.name, display_name: s.display_name, description: s.description }))
|
|
768
1091
|
});
|
|
769
1092
|
}
|
|
1093
|
+
const allExisting = listCandidates({ agent_id: agentId, limit: 500 });
|
|
1094
|
+
const match = findOverlappingCandidate(args.topic, allExisting);
|
|
1095
|
+
if (match) {
|
|
1096
|
+
return textResult({
|
|
1097
|
+
error: candidateOverlapError(match.candidate),
|
|
1098
|
+
existing_candidate: {
|
|
1099
|
+
id: match.candidate.id,
|
|
1100
|
+
status: match.candidate.status,
|
|
1101
|
+
topic: match.candidate.topic
|
|
1102
|
+
},
|
|
1103
|
+
similarity: match.score
|
|
1104
|
+
});
|
|
1105
|
+
}
|
|
770
1106
|
const now = epochSeconds();
|
|
771
1107
|
const candidate = insertCandidate({
|
|
772
1108
|
id: crypto2.randomUUID(),
|
|
@@ -874,7 +1210,7 @@ function createSkillTools(deps) {
|
|
|
874
1210
|
console.warn("[vault_skill_records] Failed to remove skill directory:", err instanceof Error ? err.message : err);
|
|
875
1211
|
}
|
|
876
1212
|
try {
|
|
877
|
-
const { syncSkillSymlinks } = await import("./installer-
|
|
1213
|
+
const { syncSkillSymlinks } = await import("./installer-AARSFXI6.js");
|
|
878
1214
|
syncSkillSymlinks(root, result.name, { remove: true });
|
|
879
1215
|
} catch (err) {
|
|
880
1216
|
console.warn("[vault_skill_records] Failed to remove symlinks:", err instanceof Error ? err.message : err);
|
|
@@ -915,9 +1251,18 @@ function createSkillTools(deps) {
|
|
|
915
1251
|
error: 'Invalid skill name: must be a simple directory name without path separators or ".."'
|
|
916
1252
|
});
|
|
917
1253
|
}
|
|
1254
|
+
const dedupError = checkDedupGates({
|
|
1255
|
+
candidate_id: args.candidate_id,
|
|
1256
|
+
name: args.name,
|
|
1257
|
+
description: args.description
|
|
1258
|
+
});
|
|
1259
|
+
if (dedupError) {
|
|
1260
|
+
recordTurn("vault_write_skill", args);
|
|
1261
|
+
return textResult(dedupError);
|
|
1262
|
+
}
|
|
1263
|
+
const existing = getSkillRecordByName(args.name);
|
|
918
1264
|
const root = projectRoot ?? process.cwd();
|
|
919
|
-
const
|
|
920
|
-
const skillPath = resolve(skillDir, "SKILL.md");
|
|
1265
|
+
const skillPath = resolve(root, ".agents", "skills", args.name, "SKILL.md");
|
|
921
1266
|
if (existsSync(skillPath)) {
|
|
922
1267
|
const existingContent = readFileSync(skillPath, "utf-8");
|
|
923
1268
|
const violations = checkFrontmatterPreservation(existingContent, args.content);
|
|
@@ -929,28 +1274,73 @@ function createSkillTools(deps) {
|
|
|
929
1274
|
});
|
|
930
1275
|
}
|
|
931
1276
|
}
|
|
1277
|
+
if (!existing) {
|
|
1278
|
+
if (args.candidate_id) {
|
|
1279
|
+
const candidateError = requireApprovedCandidate(args.candidate_id);
|
|
1280
|
+
if (candidateError) {
|
|
1281
|
+
recordTurn("vault_write_skill", args);
|
|
1282
|
+
return textResult(candidateError);
|
|
1283
|
+
}
|
|
1284
|
+
}
|
|
1285
|
+
const linkCandidate = (recordId2, now2) => {
|
|
1286
|
+
if (!args.candidate_id) return;
|
|
1287
|
+
const exact = updateCandidate(args.candidate_id, {
|
|
1288
|
+
status: CANDIDATE_STATUS.GENERATED,
|
|
1289
|
+
skill_id: recordId2,
|
|
1290
|
+
updated_at: now2
|
|
1291
|
+
});
|
|
1292
|
+
if (exact) return;
|
|
1293
|
+
const approvedCandidates = listCandidates({ status: CANDIDATE_STATUS.APPROVED, limit: 10 });
|
|
1294
|
+
const prefixMatch = approvedCandidates.find((c) => c.id.startsWith(args.candidate_id));
|
|
1295
|
+
if (prefixMatch) {
|
|
1296
|
+
updateCandidate(prefixMatch.id, {
|
|
1297
|
+
status: CANDIDATE_STATUS.GENERATED,
|
|
1298
|
+
skill_id: recordId2,
|
|
1299
|
+
updated_at: now2
|
|
1300
|
+
});
|
|
1301
|
+
}
|
|
1302
|
+
};
|
|
1303
|
+
const result = await promoteNewSkill({
|
|
1304
|
+
name: args.name,
|
|
1305
|
+
display_name: args.display_name,
|
|
1306
|
+
description: args.description,
|
|
1307
|
+
content: args.content,
|
|
1308
|
+
source_ids: args.source_ids,
|
|
1309
|
+
candidate_id: args.candidate_id,
|
|
1310
|
+
rationale: args.rationale,
|
|
1311
|
+
linkCandidate,
|
|
1312
|
+
label: "vault_write_skill"
|
|
1313
|
+
});
|
|
1314
|
+
recordTurn("vault_write_skill", args);
|
|
1315
|
+
if ("error" in result) return textResult(result);
|
|
1316
|
+
emitSkillNotification("created", {
|
|
1317
|
+
name: result.name,
|
|
1318
|
+
display_name: args.display_name,
|
|
1319
|
+
description: args.description,
|
|
1320
|
+
recordId: result.id,
|
|
1321
|
+
generation: result.generation
|
|
1322
|
+
});
|
|
1323
|
+
return textResult(result);
|
|
1324
|
+
}
|
|
1325
|
+
const priorSkillContent = readFileSync(skillPath, "utf-8");
|
|
932
1326
|
try {
|
|
933
|
-
mkdirSync(skillDir, { recursive: true });
|
|
934
1327
|
writeFileSync(skillPath, args.content, "utf-8");
|
|
935
1328
|
} catch (err) {
|
|
936
1329
|
return textResult({ error: `Failed to write skill file: ${err instanceof Error ? err.message : String(err)}` });
|
|
937
1330
|
}
|
|
938
1331
|
try {
|
|
939
|
-
const { syncSkillSymlinks } = await import("./installer-
|
|
1332
|
+
const { syncSkillSymlinks } = await import("./installer-AARSFXI6.js");
|
|
940
1333
|
syncSkillSymlinks(root, args.name);
|
|
941
1334
|
} catch (err) {
|
|
942
1335
|
console.warn("[vault_write_skill] syncSkillSymlinks failed:", err instanceof Error ? err.message : err);
|
|
943
1336
|
}
|
|
944
1337
|
const now = epochSeconds();
|
|
945
1338
|
const relativePath = `.agents/skills/${args.name}/SKILL.md`;
|
|
946
|
-
const
|
|
947
|
-
|
|
948
|
-
let generation = 0;
|
|
1339
|
+
const generation = existing.generation + 1;
|
|
1340
|
+
const recordId = existing.id;
|
|
949
1341
|
const txDb = getDatabase();
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
generation = existing.generation + 1;
|
|
953
|
-
recordId = existing.id;
|
|
1342
|
+
try {
|
|
1343
|
+
txDb.transaction(() => {
|
|
954
1344
|
updateSkillRecord(existing.id, {
|
|
955
1345
|
display_name: args.display_name,
|
|
956
1346
|
description: args.description,
|
|
@@ -969,63 +1359,27 @@ function createSkillTools(deps) {
|
|
|
969
1359
|
content_snapshot: args.content,
|
|
970
1360
|
created_at: now
|
|
971
1361
|
});
|
|
972
|
-
}
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
description: args.description,
|
|
982
|
-
candidate_id: args.candidate_id ?? null,
|
|
983
|
-
source_ids: args.source_ids,
|
|
984
|
-
path: relativePath,
|
|
985
|
-
created_at: now,
|
|
986
|
-
updated_at: now
|
|
987
|
-
});
|
|
988
|
-
insertLineage({
|
|
989
|
-
id: crypto2.randomUUID(),
|
|
990
|
-
skill_id: recordId,
|
|
991
|
-
generation,
|
|
992
|
-
action: "created",
|
|
993
|
-
rationale: args.rationale ?? "Initial skill creation",
|
|
994
|
-
source_ids_added: args.source_ids,
|
|
995
|
-
content_snapshot: args.content,
|
|
996
|
-
created_at: now
|
|
997
|
-
});
|
|
998
|
-
const approvedCandidates = listCandidates({ status: "approved", limit: 10 });
|
|
999
|
-
let linkedCandidate = false;
|
|
1000
|
-
if (args.candidate_id && !linkedCandidate) {
|
|
1001
|
-
const exact = updateCandidate(args.candidate_id, {
|
|
1002
|
-
status: "generated",
|
|
1003
|
-
skill_id: recordId,
|
|
1004
|
-
updated_at: now
|
|
1005
|
-
});
|
|
1006
|
-
if (exact) linkedCandidate = true;
|
|
1007
|
-
}
|
|
1008
|
-
if (args.candidate_id && !linkedCandidate) {
|
|
1009
|
-
const prefixMatch = approvedCandidates.find((c) => c.id.startsWith(args.candidate_id));
|
|
1010
|
-
if (prefixMatch) {
|
|
1011
|
-
updateCandidate(prefixMatch.id, {
|
|
1012
|
-
status: "generated",
|
|
1013
|
-
skill_id: recordId,
|
|
1014
|
-
updated_at: now
|
|
1015
|
-
});
|
|
1016
|
-
linkedCandidate = true;
|
|
1017
|
-
}
|
|
1018
|
-
}
|
|
1362
|
+
})();
|
|
1363
|
+
} catch (err) {
|
|
1364
|
+
try {
|
|
1365
|
+
writeFileSync(skillPath, priorSkillContent, "utf-8");
|
|
1366
|
+
} catch (rollbackErr) {
|
|
1367
|
+
console.warn(
|
|
1368
|
+
"[vault_write_skill] file rollback after DB failure also failed:",
|
|
1369
|
+
rollbackErr instanceof Error ? rollbackErr.message : rollbackErr
|
|
1370
|
+
);
|
|
1019
1371
|
}
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1372
|
+
recordTurn("vault_write_skill", args);
|
|
1373
|
+
return textResult({
|
|
1374
|
+
error: `Skill write aborted: database transaction failed and on-disk state was rolled back. ${err instanceof Error ? err.message : String(err)}`
|
|
1375
|
+
});
|
|
1376
|
+
}
|
|
1377
|
+
emitSkillNotification("evolved", {
|
|
1378
|
+
name: args.name,
|
|
1379
|
+
display_name: args.display_name,
|
|
1380
|
+
description: args.description,
|
|
1381
|
+
recordId,
|
|
1382
|
+
generation
|
|
1029
1383
|
});
|
|
1030
1384
|
recordTurn("vault_write_skill", args);
|
|
1031
1385
|
return textResult({
|
|
@@ -1037,10 +1391,145 @@ function createSkillTools(deps) {
|
|
|
1037
1391
|
},
|
|
1038
1392
|
{ annotations: { openWorldHint: true } }
|
|
1039
1393
|
);
|
|
1394
|
+
const vaultStageSkill = tool4(
|
|
1395
|
+
"vault_stage_skill",
|
|
1396
|
+
"Stage a provisional SKILL.md under .myco/staging/skills/<candidate_id>/ for later promotion by vault_finalize_skill. Use this from the skill-generate draft phase. The write is NOT live \u2014 the skill does not appear under .agents/skills/ and no DB rows are created until vault_finalize_skill is called with the same candidate_id.",
|
|
1397
|
+
{
|
|
1398
|
+
candidate_id: external_exports.string().describe(
|
|
1399
|
+
"Candidate ID from the instruction. Required \u2014 staging is keyed by candidate so the validate phase (and on-failure cleanup) can find the staged content."
|
|
1400
|
+
),
|
|
1401
|
+
name: external_exports.string().describe("Final skill directory name (kebab-case, no colon). Stored in the manifest for finalize."),
|
|
1402
|
+
display_name: external_exports.string().describe("Human-readable display name"),
|
|
1403
|
+
description: external_exports.string().describe("Short description \u2014 used for the dedup gate and the final skill record"),
|
|
1404
|
+
content: external_exports.string().describe("Full SKILL.md content in markdown including frontmatter"),
|
|
1405
|
+
source_ids: external_exports.string().optional().describe("JSON array of source spore/entity IDs"),
|
|
1406
|
+
rationale: external_exports.string().optional().describe("Why this skill is being created \u2014 stored in lineage after finalize")
|
|
1407
|
+
},
|
|
1408
|
+
async (args) => {
|
|
1409
|
+
recordTurn("vault_stage_skill", args);
|
|
1410
|
+
if (!vaultDir) {
|
|
1411
|
+
return textResult({
|
|
1412
|
+
error: "vault_stage_skill requires vaultDir on the tool deps \u2014 staging has no location otherwise"
|
|
1413
|
+
});
|
|
1414
|
+
}
|
|
1415
|
+
const validationErrors = validateSkillContent(args.content, args.name);
|
|
1416
|
+
if (validationErrors.length > 0) {
|
|
1417
|
+
return textResult({
|
|
1418
|
+
error: "Skill validation failed. Fix these issues and re-stage.",
|
|
1419
|
+
issues: validationErrors
|
|
1420
|
+
});
|
|
1421
|
+
}
|
|
1422
|
+
if (!args.name || /[/\\]|\.\./.test(args.name)) {
|
|
1423
|
+
return textResult({
|
|
1424
|
+
error: 'Invalid skill name: must be a simple directory name without path separators or ".."'
|
|
1425
|
+
});
|
|
1426
|
+
}
|
|
1427
|
+
const candidateError = requireApprovedCandidate(args.candidate_id);
|
|
1428
|
+
if (candidateError) return textResult(candidateError);
|
|
1429
|
+
const dedupError = checkDedupGates({
|
|
1430
|
+
candidate_id: args.candidate_id,
|
|
1431
|
+
name: args.name,
|
|
1432
|
+
description: args.description,
|
|
1433
|
+
rejectSameName: true
|
|
1434
|
+
});
|
|
1435
|
+
if (dedupError) return textResult(dedupError);
|
|
1436
|
+
let stagingFilePath;
|
|
1437
|
+
try {
|
|
1438
|
+
stagingFilePath = writeStagedSkill(vaultDir, args.candidate_id, args.content);
|
|
1439
|
+
const manifest = {
|
|
1440
|
+
candidate_id: args.candidate_id,
|
|
1441
|
+
name: args.name,
|
|
1442
|
+
display_name: args.display_name,
|
|
1443
|
+
description: args.description,
|
|
1444
|
+
source_ids: args.source_ids ?? "[]",
|
|
1445
|
+
rationale: args.rationale ?? "Initial draft"
|
|
1446
|
+
};
|
|
1447
|
+
writeStagedManifest(vaultDir, args.candidate_id, manifest);
|
|
1448
|
+
} catch (err) {
|
|
1449
|
+
return textResult({
|
|
1450
|
+
error: `Failed to write staged skill: ${err instanceof Error ? err.message : String(err)}`
|
|
1451
|
+
});
|
|
1452
|
+
}
|
|
1453
|
+
return textResult({
|
|
1454
|
+
candidate_id: args.candidate_id,
|
|
1455
|
+
staging_path: stagingFilePath,
|
|
1456
|
+
status: "staged"
|
|
1457
|
+
});
|
|
1458
|
+
},
|
|
1459
|
+
{ annotations: { openWorldHint: true } }
|
|
1460
|
+
);
|
|
1461
|
+
const vaultFinalizeSkill = tool4(
|
|
1462
|
+
"vault_finalize_skill",
|
|
1463
|
+
"Promote a staged skill to live at .agents/skills/<name>/ and insert the skill_records / lineage rows. Call this from skill-generate validate phase after your quality checks pass. Requires vault_stage_skill to have been called earlier with the same candidate_id; reads the staged SKILL.md + manifest rather than taking duplicate metadata.",
|
|
1464
|
+
{
|
|
1465
|
+
candidate_id: external_exports.string().describe("Candidate ID whose staged skill should be promoted. Must match a previous vault_stage_skill call.")
|
|
1466
|
+
},
|
|
1467
|
+
async (args) => {
|
|
1468
|
+
recordTurn("vault_finalize_skill", args);
|
|
1469
|
+
if (!vaultDir) {
|
|
1470
|
+
return textResult({
|
|
1471
|
+
error: "vault_finalize_skill requires vaultDir on the tool deps"
|
|
1472
|
+
});
|
|
1473
|
+
}
|
|
1474
|
+
const stagedContent = readStagedSkill(vaultDir, args.candidate_id);
|
|
1475
|
+
const manifest = readStagedManifest(vaultDir, args.candidate_id);
|
|
1476
|
+
if (!stagedContent || !manifest) {
|
|
1477
|
+
return textResult({
|
|
1478
|
+
error: `No staged skill found for candidate ${args.candidate_id}. Call vault_stage_skill first.`
|
|
1479
|
+
});
|
|
1480
|
+
}
|
|
1481
|
+
const candidateError = requireApprovedCandidate(args.candidate_id);
|
|
1482
|
+
if (candidateError) return textResult(candidateError);
|
|
1483
|
+
const validationErrors = validateSkillContent(stagedContent, manifest.name);
|
|
1484
|
+
if (validationErrors.length > 0) {
|
|
1485
|
+
return textResult({
|
|
1486
|
+
error: "Staged skill failed validation on finalize. Re-stage with valid content.",
|
|
1487
|
+
issues: validationErrors
|
|
1488
|
+
});
|
|
1489
|
+
}
|
|
1490
|
+
const dedupError = checkDedupGates({
|
|
1491
|
+
candidate_id: args.candidate_id,
|
|
1492
|
+
name: manifest.name,
|
|
1493
|
+
description: manifest.description,
|
|
1494
|
+
rejectSameName: true
|
|
1495
|
+
});
|
|
1496
|
+
if (dedupError) return textResult(dedupError);
|
|
1497
|
+
const result = await promoteNewSkill({
|
|
1498
|
+
name: manifest.name,
|
|
1499
|
+
display_name: manifest.display_name,
|
|
1500
|
+
description: manifest.description,
|
|
1501
|
+
content: stagedContent,
|
|
1502
|
+
source_ids: manifest.source_ids,
|
|
1503
|
+
candidate_id: manifest.candidate_id,
|
|
1504
|
+
rationale: manifest.rationale,
|
|
1505
|
+
linkCandidate: (recordId, now) => {
|
|
1506
|
+
updateCandidate(manifest.candidate_id, {
|
|
1507
|
+
status: CANDIDATE_STATUS.GENERATED,
|
|
1508
|
+
skill_id: recordId,
|
|
1509
|
+
updated_at: now
|
|
1510
|
+
});
|
|
1511
|
+
},
|
|
1512
|
+
label: "vault_finalize_skill"
|
|
1513
|
+
});
|
|
1514
|
+
if ("error" in result) return textResult(result);
|
|
1515
|
+
cleanupStagedSkill(vaultDir, args.candidate_id);
|
|
1516
|
+
emitSkillNotification("created", {
|
|
1517
|
+
name: manifest.name,
|
|
1518
|
+
display_name: manifest.display_name,
|
|
1519
|
+
description: manifest.description,
|
|
1520
|
+
recordId: result.id,
|
|
1521
|
+
generation: result.generation
|
|
1522
|
+
});
|
|
1523
|
+
return textResult(result);
|
|
1524
|
+
},
|
|
1525
|
+
{ annotations: { openWorldHint: true } }
|
|
1526
|
+
);
|
|
1040
1527
|
return [
|
|
1041
1528
|
vaultSkillCandidates,
|
|
1042
1529
|
vaultSkillRecords,
|
|
1043
|
-
vaultWriteSkill
|
|
1530
|
+
vaultWriteSkill,
|
|
1531
|
+
vaultStageSkill,
|
|
1532
|
+
vaultFinalizeSkill
|
|
1044
1533
|
];
|
|
1045
1534
|
}
|
|
1046
1535
|
|
|
@@ -1070,8 +1559,11 @@ var OBSERVABILITY_TOOL_NAMES = /* @__PURE__ */ new Set(["vault_report"]);
|
|
|
1070
1559
|
var SKILL_TOOL_NAMES = /* @__PURE__ */ new Set([
|
|
1071
1560
|
"vault_skill_candidates",
|
|
1072
1561
|
"vault_skill_records",
|
|
1073
|
-
"vault_write_skill"
|
|
1562
|
+
"vault_write_skill",
|
|
1563
|
+
"vault_stage_skill",
|
|
1564
|
+
"vault_finalize_skill"
|
|
1074
1565
|
]);
|
|
1566
|
+
var VAULT_TOOL_COUNT = READ_TOOL_NAMES.size + WRITE_TOOL_NAMES.size + OBSERVABILITY_TOOL_NAMES.size + SKILL_TOOL_NAMES.size;
|
|
1075
1567
|
function setsOverlap(a, b) {
|
|
1076
1568
|
for (const item of a) {
|
|
1077
1569
|
if (b.has(item)) return true;
|
|
@@ -1534,6 +2026,7 @@ import { writeFileSync as writeFileSync2, unlinkSync } from "fs";
|
|
|
1534
2026
|
import { tmpdir } from "os";
|
|
1535
2027
|
import { join } from "path";
|
|
1536
2028
|
var OLLAMA_PRELOAD_TIMEOUT_MS = 3e4;
|
|
2029
|
+
var DEFAULT_OLLAMA_CONTEXT_LENGTH = 32768;
|
|
1537
2030
|
async function ensureOllamaContextVariant(model, contextLength) {
|
|
1538
2031
|
const baseName = model.replace(/:latest$/, "");
|
|
1539
2032
|
const variantName = `${baseName}-ctx${contextLength}`;
|
|
@@ -1560,6 +2053,60 @@ PARAMETER num_ctx ${contextLength}
|
|
|
1560
2053
|
return model;
|
|
1561
2054
|
}
|
|
1562
2055
|
}
|
|
2056
|
+
async function resolveOllamaContextVariants(taskProvider, phaseOverrides, createVariant = ensureOllamaContextVariant) {
|
|
2057
|
+
const seen = /* @__PURE__ */ new Map();
|
|
2058
|
+
const recordOllama = (p) => {
|
|
2059
|
+
if (p?.type !== "ollama" || !p.model) return;
|
|
2060
|
+
const ctx = p.contextLength ?? DEFAULT_OLLAMA_CONTEXT_LENGTH;
|
|
2061
|
+
const set = seen.get(p.model) ?? /* @__PURE__ */ new Set();
|
|
2062
|
+
set.add(ctx);
|
|
2063
|
+
seen.set(p.model, set);
|
|
2064
|
+
};
|
|
2065
|
+
recordOllama(taskProvider);
|
|
2066
|
+
for (const override of Object.values(phaseOverrides)) {
|
|
2067
|
+
recordOllama(override.provider);
|
|
2068
|
+
}
|
|
2069
|
+
if (seen.size === 0) {
|
|
2070
|
+
return { taskProvider, phaseOverrides, conflicts: [] };
|
|
2071
|
+
}
|
|
2072
|
+
const resolvedContext = /* @__PURE__ */ new Map();
|
|
2073
|
+
const conflicts = [];
|
|
2074
|
+
for (const [model, values] of seen) {
|
|
2075
|
+
const sorted = [...values].sort((a, b) => a - b);
|
|
2076
|
+
const max = sorted[sorted.length - 1];
|
|
2077
|
+
resolvedContext.set(model, max);
|
|
2078
|
+
if (sorted.length > 1) {
|
|
2079
|
+
conflicts.push({ model, values: sorted, resolved: max });
|
|
2080
|
+
}
|
|
2081
|
+
}
|
|
2082
|
+
const variantEntries = await Promise.all(
|
|
2083
|
+
[...resolvedContext.entries()].map(async ([model, ctx]) => {
|
|
2084
|
+
const variant = await createVariant(model, ctx);
|
|
2085
|
+
return [model, variant];
|
|
2086
|
+
})
|
|
2087
|
+
);
|
|
2088
|
+
const variantByModel = new Map(variantEntries);
|
|
2089
|
+
const rewriteProvider = (p) => {
|
|
2090
|
+
if (!p) return p;
|
|
2091
|
+
if (p.type !== "ollama" || !p.model) return p;
|
|
2092
|
+
const variant = variantByModel.get(p.model);
|
|
2093
|
+
const resolvedCtx = resolvedContext.get(p.model);
|
|
2094
|
+
if (!variant) return p;
|
|
2095
|
+
return { ...p, model: variant, contextLength: resolvedCtx };
|
|
2096
|
+
};
|
|
2097
|
+
const rewrittenPhaseOverrides = {};
|
|
2098
|
+
for (const [name, override] of Object.entries(phaseOverrides)) {
|
|
2099
|
+
rewrittenPhaseOverrides[name] = {
|
|
2100
|
+
...override,
|
|
2101
|
+
...override.provider ? { provider: rewriteProvider(override.provider) } : {}
|
|
2102
|
+
};
|
|
2103
|
+
}
|
|
2104
|
+
return {
|
|
2105
|
+
taskProvider: rewriteProvider(taskProvider),
|
|
2106
|
+
phaseOverrides: rewrittenPhaseOverrides,
|
|
2107
|
+
conflicts
|
|
2108
|
+
};
|
|
2109
|
+
}
|
|
1563
2110
|
|
|
1564
2111
|
// src/agent/wave-computation.ts
|
|
1565
2112
|
import crypto3 from "crypto";
|
|
@@ -1624,6 +2171,38 @@ var MCP_SERVER_NAME = "myco-vault";
|
|
|
1624
2171
|
var PERSIST_SESSION = true;
|
|
1625
2172
|
var PROMPT_SECTION_PRIOR_PHASES = "## Prior Phase Results";
|
|
1626
2173
|
var PROMPT_SECTION_CURRENT_PHASE = "## Current Phase: ";
|
|
2174
|
+
var DEBUG_TOOL_CALLS = process.env.MYCO_AGENT_DEBUG === "1";
|
|
2175
|
+
var TOOL_DEBUG_PREVIEW_CHARS = 240;
|
|
2176
|
+
function previewPayload(value) {
|
|
2177
|
+
const str = typeof value === "string" ? value : JSON.stringify(value);
|
|
2178
|
+
if (str === void 0) return "";
|
|
2179
|
+
return str.length > TOOL_DEBUG_PREVIEW_CHARS ? `${str.slice(0, TOOL_DEBUG_PREVIEW_CHARS)}\u2026(${str.length - TOOL_DEBUG_PREVIEW_CHARS} more chars)` : str;
|
|
2180
|
+
}
|
|
2181
|
+
function logToolUseBlocks(phaseName, message) {
|
|
2182
|
+
if (!DEBUG_TOOL_CALLS) return;
|
|
2183
|
+
const blocks = message.message?.content;
|
|
2184
|
+
if (!Array.isArray(blocks)) return;
|
|
2185
|
+
for (const block of blocks) {
|
|
2186
|
+
if (block.type === "tool_use") {
|
|
2187
|
+
console.log(
|
|
2188
|
+
`[agent:debug] ${phaseName} tool_use: ${block.name ?? "unknown"} input=${previewPayload(block.input)}`
|
|
2189
|
+
);
|
|
2190
|
+
}
|
|
2191
|
+
}
|
|
2192
|
+
}
|
|
2193
|
+
function logToolResultBlocks(phaseName, message) {
|
|
2194
|
+
if (!DEBUG_TOOL_CALLS) return;
|
|
2195
|
+
const blocks = message.message?.content;
|
|
2196
|
+
if (!Array.isArray(blocks)) return;
|
|
2197
|
+
for (const block of blocks) {
|
|
2198
|
+
if (block.type === "tool_result") {
|
|
2199
|
+
const flag = block.is_error ? " [ERROR]" : "";
|
|
2200
|
+
console.log(
|
|
2201
|
+
`[agent:debug] ${phaseName} tool_result${flag}: ${previewPayload(block.content)}`
|
|
2202
|
+
);
|
|
2203
|
+
}
|
|
2204
|
+
}
|
|
2205
|
+
}
|
|
1627
2206
|
function composeTaskPrompt(vaultContext, taskDisplayName, taskPrompt, instruction) {
|
|
1628
2207
|
const sessionIdMatch = instruction?.match(/\b([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\b/i);
|
|
1629
2208
|
const sessionId = sessionIdMatch?.[1] ?? "";
|
|
@@ -1690,6 +2269,10 @@ async function executePhase(query, phasePrompt, phaseModel, systemPrompt, toolSe
|
|
|
1690
2269
|
})) {
|
|
1691
2270
|
if (message.type === "assistant") {
|
|
1692
2271
|
agenticTurns++;
|
|
2272
|
+
logToolUseBlocks(phase.name, message);
|
|
2273
|
+
}
|
|
2274
|
+
if (message.type === "user") {
|
|
2275
|
+
logToolResultBlocks(phase.name, message);
|
|
1693
2276
|
}
|
|
1694
2277
|
if (message.type === "result") {
|
|
1695
2278
|
phaseCost = message.total_cost_usd ?? 0;
|
|
@@ -1885,9 +2468,10 @@ async function runAgent(vaultDir, options) {
|
|
|
1885
2468
|
config,
|
|
1886
2469
|
definitionsDir,
|
|
1887
2470
|
taskProviderOverride: resolvedTaskProvider,
|
|
1888
|
-
phaseProviderOverrides
|
|
2471
|
+
phaseProviderOverrides: resolvedPhaseOverrides
|
|
1889
2472
|
} = resolveRunConfig(agentId, requestedTask, vaultDir);
|
|
1890
2473
|
let taskProviderOverride = resolvedTaskProvider;
|
|
2474
|
+
let phaseProviderOverrides = resolvedPhaseOverrides;
|
|
1891
2475
|
const runId = options?.resumeRunId ?? crypto4.randomUUID();
|
|
1892
2476
|
const now = epochSeconds();
|
|
1893
2477
|
if (!options?.resumeRunId) {
|
|
@@ -1909,12 +2493,18 @@ async function runAgent(vaultDir, options) {
|
|
|
1909
2493
|
provider: effectiveProvider?.type ?? "cloud",
|
|
1910
2494
|
...effectiveProvider?.baseUrl ? { baseUrl: effectiveProvider.baseUrl } : {}
|
|
1911
2495
|
};
|
|
1912
|
-
|
|
1913
|
-
const
|
|
1914
|
-
|
|
1915
|
-
|
|
2496
|
+
{
|
|
2497
|
+
const resolved = await resolveOllamaContextVariants(
|
|
2498
|
+
taskProviderOverride,
|
|
2499
|
+
phaseProviderOverrides
|
|
1916
2500
|
);
|
|
1917
|
-
taskProviderOverride =
|
|
2501
|
+
taskProviderOverride = resolved.taskProvider;
|
|
2502
|
+
phaseProviderOverrides = resolved.phaseOverrides;
|
|
2503
|
+
for (const conflict of resolved.conflicts) {
|
|
2504
|
+
console.warn(
|
|
2505
|
+
`[agent] Ollama model "${conflict.model}" referenced with conflicting context_length values [${conflict.values.join(", ")}] \u2014 reconciled to ${conflict.resolved} to avoid loading multiple variants. Configure one value per model to silence this warning.`
|
|
2506
|
+
);
|
|
2507
|
+
}
|
|
1918
2508
|
}
|
|
1919
2509
|
const taskAbortController = new AbortController();
|
|
1920
2510
|
const timeoutMs = config.timeoutSeconds * MS_PER_SECOND;
|
|
@@ -1946,6 +2536,17 @@ async function runAgent(vaultDir, options) {
|
|
|
1946
2536
|
tokensUsed = result.tokensUsed;
|
|
1947
2537
|
costUsd = result.costUsd;
|
|
1948
2538
|
phaseResults = result.phases;
|
|
2539
|
+
const requiredPhaseNames = new Set(
|
|
2540
|
+
config.phases.filter((p) => p.required).map((p) => p.name)
|
|
2541
|
+
);
|
|
2542
|
+
const failedRequired = phaseResults.find(
|
|
2543
|
+
(p) => p.status === "failed" && requiredPhaseNames.has(p.name)
|
|
2544
|
+
);
|
|
2545
|
+
if (failedRequired) {
|
|
2546
|
+
throw new Error(
|
|
2547
|
+
`Required phase "${failedRequired.name}" failed: ${failedRequired.summary}`
|
|
2548
|
+
);
|
|
2549
|
+
}
|
|
1949
2550
|
} else {
|
|
1950
2551
|
const taskPrompt = composeTaskPrompt(
|
|
1951
2552
|
vaultContext,
|
|
@@ -2011,6 +2612,11 @@ ${err.stack.split("\n").slice(0, 3).join("\n")}`;
|
|
|
2011
2612
|
} catch (dbErr) {
|
|
2012
2613
|
console.error(`[agent] Failed to save error to DB:`, dbErr);
|
|
2013
2614
|
}
|
|
2615
|
+
await cleanupOnTaskFailure({
|
|
2616
|
+
taskName: config.taskName,
|
|
2617
|
+
vaultDir,
|
|
2618
|
+
runContext: options?.runContext
|
|
2619
|
+
});
|
|
2014
2620
|
return {
|
|
2015
2621
|
runId,
|
|
2016
2622
|
status: STATUS_FAILED,
|
|
@@ -2019,10 +2625,29 @@ ${err.stack.split("\n").slice(0, 3).join("\n")}`;
|
|
|
2019
2625
|
};
|
|
2020
2626
|
}
|
|
2021
2627
|
}
|
|
2628
|
+
async function cleanupOnTaskFailure(args) {
|
|
2629
|
+
if (args.taskName !== SKILL_GENERATE_TASK) return;
|
|
2630
|
+
if (!args.vaultDir) return;
|
|
2631
|
+
const candidateId = args.runContext?.candidate_id;
|
|
2632
|
+
if (!candidateId) return;
|
|
2633
|
+
try {
|
|
2634
|
+
const { cleanupStagedSkill: cleanupStagedSkill2 } = await import("./skill-staging-SWM7UC5D.js");
|
|
2635
|
+
cleanupStagedSkill2(args.vaultDir, candidateId);
|
|
2636
|
+
console.warn(
|
|
2637
|
+
`[agent] skill-generate failed \u2014 cleaned up staging for candidate ${candidateId}`
|
|
2638
|
+
);
|
|
2639
|
+
} catch (cleanupErr) {
|
|
2640
|
+
console.warn(
|
|
2641
|
+
`[agent] Failed to clean staging for candidate ${candidateId}:`,
|
|
2642
|
+
cleanupErr instanceof Error ? cleanupErr.message : cleanupErr
|
|
2643
|
+
);
|
|
2644
|
+
}
|
|
2645
|
+
}
|
|
2022
2646
|
export {
|
|
2647
|
+
cleanupOnTaskFailure,
|
|
2023
2648
|
composePhasePrompt,
|
|
2024
2649
|
composeTaskPrompt,
|
|
2025
2650
|
computeWaves,
|
|
2026
2651
|
runAgent
|
|
2027
2652
|
};
|
|
2028
|
-
//# sourceMappingURL=executor-
|
|
2653
|
+
//# sourceMappingURL=executor-HP3Y64PD.js.map
|