@goondocks/myco 0.15.0 → 0.15.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.
Files changed (93) hide show
  1. package/dist/{agent-run-DUOJ3KDI.js → agent-run-T433ENJS.js} +4 -4
  2. package/dist/{agent-tasks-LUWBY5JD.js → agent-tasks-TAIU3V5I.js} +4 -4
  3. package/dist/{chunk-DK5VEBB5.js → chunk-2QMDRZPJ.js} +17 -13
  4. package/dist/chunk-2QMDRZPJ.js.map +1 -0
  5. package/dist/{chunk-R3YW7XVF.js → chunk-4O3QNM5I.js} +2 -2
  6. package/dist/{chunk-GZ7MXWYX.js → chunk-6GG2IVNV.js} +2 -2
  7. package/dist/{chunk-OMZCVRX6.js → chunk-BFM6AM6R.js} +2 -2
  8. package/dist/{chunk-DKGUCEWU.js → chunk-GCCBXCHF.js} +2 -2
  9. package/dist/{chunk-B3SF2CCW.js → chunk-TQO4PF5K.js} +2 -2
  10. package/dist/{cli-YBD2GPK4.js → cli-W37MRZHD.js} +35 -35
  11. package/dist/{client-CJ3X252K.js → client-YNTTC75R.js} +3 -3
  12. package/dist/{doctor-JR7NEL7K.js → doctor-PAAQU5AS.js} +5 -5
  13. package/dist/{executor-7XOKS6HS.js → executor-4OXDK4ZA.js} +359 -72
  14. package/dist/executor-4OXDK4ZA.js.map +1 -0
  15. package/dist/{init-PDLKYWQ4.js → init-PHQAQANR.js} +7 -7
  16. package/dist/{init-wizard-WH3SXNMB.js → init-wizard-RFD46XAJ.js} +2 -2
  17. package/dist/{llm-DK44LYO6.js → llm-D4VWYUK7.js} +2 -2
  18. package/dist/{main-JB3R3DQE.js → main-ADLCOYKM.js} +13 -10
  19. package/dist/{main-JB3R3DQE.js.map → main-ADLCOYKM.js.map} +1 -1
  20. package/dist/{open-AADZPSLW.js → open-3VPUP3HD.js} +4 -4
  21. package/dist/{post-compact-KNQ4DYLM.js → post-compact-5NYLOC46.js} +4 -4
  22. package/dist/{post-tool-use-OMWHFQLM.js → post-tool-use-SNNXSZ5Y.js} +3 -3
  23. package/dist/{post-tool-use-failure-KFP6MB7Z.js → post-tool-use-failure-POKVXQHY.js} +4 -4
  24. package/dist/{pre-compact-2ZYE2HRB.js → pre-compact-ZUICBJEX.js} +4 -4
  25. package/dist/{remove-QT7634L5.js → remove-SVU2V4Q7.js} +4 -4
  26. package/dist/{restart-YQNQEHOU.js → restart-NBB5CXJ4.js} +5 -5
  27. package/dist/{search-C6JTQDWY.js → search-YUQZFRZX.js} +4 -4
  28. package/dist/{server-QJ3RWZZZ.js → server-NBRX56VL.js} +3 -3
  29. package/dist/{session-JLVL5TYX.js → session-2QP4HMZ5.js} +4 -4
  30. package/dist/{session-end-XFZRRP5H.js → session-end-NNFBW7CQ.js} +3 -3
  31. package/dist/{session-start-XGINISXO.js → session-start-NPNP4IXX.js} +3 -3
  32. package/dist/{setup-llm-X2OCM6R7.js → setup-llm-C3IGFLRN.js} +4 -4
  33. package/dist/src/cli.js +1 -1
  34. package/dist/src/daemon/main.js +1 -1
  35. package/dist/src/hooks/post-tool-use.js +1 -1
  36. package/dist/src/hooks/session-end.js +1 -1
  37. package/dist/src/hooks/session-start.js +1 -1
  38. package/dist/src/hooks/stop.js +1 -1
  39. package/dist/src/hooks/user-prompt-submit.js +1 -1
  40. package/dist/src/mcp/server.js +1 -1
  41. package/dist/{stats-2EAETG2T.js → stats-FEEXIRMS.js} +5 -5
  42. package/dist/{stop-WOBDYTSA.js → stop-FGDGWXTK.js} +3 -3
  43. package/dist/{stop-failure-QEC7ZGBQ.js → stop-failure-5YAGH2TQ.js} +4 -4
  44. package/dist/{subagent-start-H6DVRVOE.js → subagent-start-UCKVJDR4.js} +4 -4
  45. package/dist/{subagent-stop-LKENKJ65.js → subagent-stop-H25B3QEC.js} +4 -4
  46. package/dist/{task-completed-ZZ47PRPD.js → task-completed-2JGZN2CF.js} +4 -4
  47. package/dist/{team-J62N7VMG.js → team-TG5WZXWO.js} +2 -2
  48. package/dist/ui/assets/{index-Bx9l8uxa.js → index-7Vimyg7g.js} +1 -1
  49. package/dist/ui/index.html +1 -1
  50. package/dist/{update-LX3CJ4TJ.js → update-EG3N2EXI.js} +4 -4
  51. package/dist/{user-prompt-submit-NNMLY3EW.js → user-prompt-submit-7FFQ3ORA.js} +3 -3
  52. package/dist/{verify-AMRQXQ3K.js → verify-2M3DYHEY.js} +2 -2
  53. package/dist/{version-6OJH5HLZ.js → version-JUQU5W22.js} +2 -2
  54. package/package.json +2 -2
  55. package/dist/chunk-DK5VEBB5.js.map +0 -1
  56. package/dist/executor-7XOKS6HS.js.map +0 -1
  57. /package/dist/{agent-run-DUOJ3KDI.js.map → agent-run-T433ENJS.js.map} +0 -0
  58. /package/dist/{agent-tasks-LUWBY5JD.js.map → agent-tasks-TAIU3V5I.js.map} +0 -0
  59. /package/dist/{chunk-R3YW7XVF.js.map → chunk-4O3QNM5I.js.map} +0 -0
  60. /package/dist/{chunk-GZ7MXWYX.js.map → chunk-6GG2IVNV.js.map} +0 -0
  61. /package/dist/{chunk-OMZCVRX6.js.map → chunk-BFM6AM6R.js.map} +0 -0
  62. /package/dist/{chunk-DKGUCEWU.js.map → chunk-GCCBXCHF.js.map} +0 -0
  63. /package/dist/{chunk-B3SF2CCW.js.map → chunk-TQO4PF5K.js.map} +0 -0
  64. /package/dist/{cli-YBD2GPK4.js.map → cli-W37MRZHD.js.map} +0 -0
  65. /package/dist/{client-CJ3X252K.js.map → client-YNTTC75R.js.map} +0 -0
  66. /package/dist/{doctor-JR7NEL7K.js.map → doctor-PAAQU5AS.js.map} +0 -0
  67. /package/dist/{init-PDLKYWQ4.js.map → init-PHQAQANR.js.map} +0 -0
  68. /package/dist/{init-wizard-WH3SXNMB.js.map → init-wizard-RFD46XAJ.js.map} +0 -0
  69. /package/dist/{llm-DK44LYO6.js.map → llm-D4VWYUK7.js.map} +0 -0
  70. /package/dist/{open-AADZPSLW.js.map → open-3VPUP3HD.js.map} +0 -0
  71. /package/dist/{post-compact-KNQ4DYLM.js.map → post-compact-5NYLOC46.js.map} +0 -0
  72. /package/dist/{post-tool-use-OMWHFQLM.js.map → post-tool-use-SNNXSZ5Y.js.map} +0 -0
  73. /package/dist/{post-tool-use-failure-KFP6MB7Z.js.map → post-tool-use-failure-POKVXQHY.js.map} +0 -0
  74. /package/dist/{pre-compact-2ZYE2HRB.js.map → pre-compact-ZUICBJEX.js.map} +0 -0
  75. /package/dist/{remove-QT7634L5.js.map → remove-SVU2V4Q7.js.map} +0 -0
  76. /package/dist/{restart-YQNQEHOU.js.map → restart-NBB5CXJ4.js.map} +0 -0
  77. /package/dist/{search-C6JTQDWY.js.map → search-YUQZFRZX.js.map} +0 -0
  78. /package/dist/{server-QJ3RWZZZ.js.map → server-NBRX56VL.js.map} +0 -0
  79. /package/dist/{session-JLVL5TYX.js.map → session-2QP4HMZ5.js.map} +0 -0
  80. /package/dist/{session-end-XFZRRP5H.js.map → session-end-NNFBW7CQ.js.map} +0 -0
  81. /package/dist/{session-start-XGINISXO.js.map → session-start-NPNP4IXX.js.map} +0 -0
  82. /package/dist/{setup-llm-X2OCM6R7.js.map → setup-llm-C3IGFLRN.js.map} +0 -0
  83. /package/dist/{stats-2EAETG2T.js.map → stats-FEEXIRMS.js.map} +0 -0
  84. /package/dist/{stop-WOBDYTSA.js.map → stop-FGDGWXTK.js.map} +0 -0
  85. /package/dist/{stop-failure-QEC7ZGBQ.js.map → stop-failure-5YAGH2TQ.js.map} +0 -0
  86. /package/dist/{subagent-start-H6DVRVOE.js.map → subagent-start-UCKVJDR4.js.map} +0 -0
  87. /package/dist/{subagent-stop-LKENKJ65.js.map → subagent-stop-H25B3QEC.js.map} +0 -0
  88. /package/dist/{task-completed-ZZ47PRPD.js.map → task-completed-2JGZN2CF.js.map} +0 -0
  89. /package/dist/{team-J62N7VMG.js.map → team-TG5WZXWO.js.map} +0 -0
  90. /package/dist/{update-LX3CJ4TJ.js.map → update-EG3N2EXI.js.map} +0 -0
  91. /package/dist/{user-prompt-submit-NNMLY3EW.js.map → user-prompt-submit-7FFQ3ORA.js.map} +0 -0
  92. /package/dist/{verify-AMRQXQ3K.js.map → verify-2M3DYHEY.js.map} +0 -0
  93. /package/dist/{version-6OJH5HLZ.js.map → version-JUQU5W22.js.map} +0 -0
@@ -77,7 +77,7 @@ import {
77
77
  } from "./chunk-MYX5NCRH.js";
78
78
  import {
79
79
  getPluginVersion
80
- } from "./chunk-OMZCVRX6.js";
80
+ } from "./chunk-BFM6AM6R.js";
81
81
  import {
82
82
  findPackageRoot
83
83
  } from "./chunk-LPUQPDC2.js";
@@ -649,12 +649,115 @@ import { tool as tool4 } from "@anthropic-ai/claude-agent-sdk";
649
649
  var MAX_SKILL_LINES = 500;
650
650
  var REQUIRED_FRONTMATTER_FIELDS = ["name", "description", "managed_by", "user-invocable", "allowed-tools"];
651
651
  var PROTECTED_FRONTMATTER_FIELDS = ["user-invocable", "allowed-tools"];
652
+ var ALLOWED_CLAUDE_CODE_TOOLS = /* @__PURE__ */ new Set([
653
+ "Read",
654
+ "Edit",
655
+ "Write",
656
+ "MultiEdit",
657
+ "Bash",
658
+ "Grep",
659
+ "Glob",
660
+ "NotebookRead",
661
+ "NotebookEdit",
662
+ "WebFetch",
663
+ "WebSearch",
664
+ "Task",
665
+ "TodoWrite"
666
+ ]);
652
667
  function extractFrontmatterField(content, field) {
653
668
  const fmMatch = content.match(/^---\n([\s\S]*?)\n---/);
654
669
  if (!fmMatch) return void 0;
655
670
  const match = fmMatch[1].match(new RegExp(`^${field}:\\s*(.+)$`, "m"));
656
671
  return match?.[1].trim();
657
672
  }
673
+ function parseAllowedTools(rawValue) {
674
+ if (!rawValue) return null;
675
+ let stripped = rawValue.trim();
676
+ if (stripped.length === 0) return null;
677
+ if (stripped.startsWith("[") && stripped.endsWith("]")) {
678
+ stripped = stripped.slice(1, -1).trim();
679
+ }
680
+ if (stripped.length === 0) return null;
681
+ const parts = stripped.split(",").map((s) => s.trim().replace(/^['"]|['"]$/g, "")).filter((s) => s.length > 0);
682
+ if (parts.length === 0) return null;
683
+ const sentinels = /* @__PURE__ */ new Set(["None", "none", "null", "Null", "~"]);
684
+ if (parts.some((p) => sentinels.has(p))) return null;
685
+ return parts;
686
+ }
687
+ function tokenSet(text) {
688
+ const stopwords = /* @__PURE__ */ new Set([
689
+ "the",
690
+ "a",
691
+ "an",
692
+ "and",
693
+ "or",
694
+ "but",
695
+ "is",
696
+ "are",
697
+ "was",
698
+ "were",
699
+ "be",
700
+ "been",
701
+ "being",
702
+ "have",
703
+ "has",
704
+ "had",
705
+ "do",
706
+ "does",
707
+ "did",
708
+ "will",
709
+ "would",
710
+ "should",
711
+ "could",
712
+ "may",
713
+ "might",
714
+ "must",
715
+ "can",
716
+ "this",
717
+ "that",
718
+ "these",
719
+ "those",
720
+ "with",
721
+ "from",
722
+ "into",
723
+ "onto",
724
+ "for",
725
+ "when",
726
+ "where",
727
+ "which",
728
+ "what",
729
+ "who",
730
+ "how",
731
+ "why",
732
+ "use",
733
+ "uses",
734
+ "used",
735
+ "using",
736
+ "not",
737
+ "also",
738
+ "than",
739
+ "then",
740
+ "ensure",
741
+ "ensures",
742
+ "make",
743
+ "makes"
744
+ ]);
745
+ return new Set(
746
+ text.toLowerCase().replace(/[^a-z0-9_\s]/g, " ").split(/\s+/).filter((w) => w.length >= 4 && !stopwords.has(w))
747
+ );
748
+ }
749
+ function descriptionSimilarity(a, b) {
750
+ const aTokens = tokenSet(a);
751
+ const bTokens = tokenSet(b);
752
+ if (aTokens.size === 0 || bTokens.size === 0) return 0;
753
+ let intersection = 0;
754
+ for (const token of aTokens) {
755
+ if (bTokens.has(token)) intersection++;
756
+ }
757
+ const union = aTokens.size + bTokens.size - intersection;
758
+ return union === 0 ? 0 : intersection / union;
759
+ }
760
+ var DESCRIPTION_DUPLICATE_THRESHOLD = 0.4;
658
761
  function checkFrontmatterPreservation(existing, incoming) {
659
762
  const violations = [];
660
763
  for (const field of PROTECTED_FRONTMATTER_FIELDS) {
@@ -696,11 +799,25 @@ function validateSkillContent(content, dirName) {
696
799
  }
697
800
  const allowedToolsMatch = frontmatter.match(/^allowed-tools:\s*(.+)$/m);
698
801
  if (allowedToolsMatch) {
699
- const toolsValue = allowedToolsMatch[1].trim();
700
- if (toolsValue.includes("vault_")) {
802
+ const rawValue = allowedToolsMatch[1].trim();
803
+ if (rawValue.includes("vault_")) {
701
804
  issues.push(
702
805
  "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
806
  );
807
+ } else {
808
+ const parsed = parseAllowedTools(rawValue);
809
+ if (parsed === null) {
810
+ issues.push(
811
+ `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.`
812
+ );
813
+ } else {
814
+ const unknown = parsed.filter((t) => !ALLOWED_CLAUDE_CODE_TOOLS.has(t));
815
+ if (unknown.length > 0) {
816
+ issues.push(
817
+ `allowed-tools contains unknown tool name(s): ${unknown.join(", ")}. Valid Claude Code tools: ${[...ALLOWED_CLAUDE_CODE_TOOLS].join(", ")}.`
818
+ );
819
+ }
820
+ }
704
821
  }
705
822
  }
706
823
  const listToolLines = frontmatter.match(/^\s+-\s+vault_\w+/gm);
@@ -915,6 +1032,48 @@ function createSkillTools(deps) {
915
1032
  error: 'Invalid skill name: must be a simple directory name without path separators or ".."'
916
1033
  });
917
1034
  }
1035
+ const existingSameName = getSkillRecordByName(args.name);
1036
+ if (!existingSameName) {
1037
+ if (args.candidate_id) {
1038
+ const candidate = getCandidate(args.candidate_id);
1039
+ if (candidate?.skill_id) {
1040
+ const linkedSkill = getSkillRecord(candidate.skill_id);
1041
+ if (linkedSkill && linkedSkill.name !== args.name) {
1042
+ recordTurn("vault_write_skill", args);
1043
+ return textResult({
1044
+ 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.`,
1045
+ existing_skill: {
1046
+ id: linkedSkill.id,
1047
+ name: linkedSkill.name,
1048
+ description: linkedSkill.description,
1049
+ path: linkedSkill.path
1050
+ }
1051
+ });
1052
+ }
1053
+ }
1054
+ }
1055
+ const activeSkills = listSkillRecords({ agent_id: agentId, status: "active", limit: 200 });
1056
+ let bestMatch = null;
1057
+ for (const skill of activeSkills) {
1058
+ const score = descriptionSimilarity(args.description, skill.description);
1059
+ if (score >= DESCRIPTION_DUPLICATE_THRESHOLD && (!bestMatch || score > bestMatch.score)) {
1060
+ bestMatch = { skill, score };
1061
+ }
1062
+ }
1063
+ if (bestMatch) {
1064
+ recordTurn("vault_write_skill", args);
1065
+ return textResult({
1066
+ 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.`,
1067
+ overlapping_skill: {
1068
+ id: bestMatch.skill.id,
1069
+ name: bestMatch.skill.name,
1070
+ description: bestMatch.skill.description,
1071
+ path: bestMatch.skill.path
1072
+ },
1073
+ similarity: bestMatch.score
1074
+ });
1075
+ }
1076
+ }
918
1077
  const root = projectRoot ?? process.cwd();
919
1078
  const skillDir = resolve(root, ".agents", "skills", args.name);
920
1079
  const skillPath = resolve(skillDir, "SKILL.md");
@@ -929,6 +1088,15 @@ function createSkillTools(deps) {
929
1088
  });
930
1089
  }
931
1090
  }
1091
+ const skillDirPreexisted = existsSync(skillDir);
1092
+ let priorSkillContent = null;
1093
+ if (existsSync(skillPath)) {
1094
+ try {
1095
+ priorSkillContent = readFileSync(skillPath, "utf-8");
1096
+ } catch {
1097
+ priorSkillContent = null;
1098
+ }
1099
+ }
932
1100
  try {
933
1101
  mkdirSync(skillDir, { recursive: true });
934
1102
  writeFileSync(skillPath, args.content, "utf-8");
@@ -947,77 +1115,98 @@ function createSkillTools(deps) {
947
1115
  let recordId = "";
948
1116
  let generation = 0;
949
1117
  const txDb = getDatabase();
950
- txDb.transaction(() => {
951
- if (existing) {
952
- generation = existing.generation + 1;
953
- recordId = existing.id;
954
- updateSkillRecord(existing.id, {
955
- display_name: args.display_name,
956
- description: args.description,
957
- generation,
958
- ...args.source_ids !== void 0 ? { source_ids: args.source_ids } : {},
959
- path: relativePath,
960
- updated_at: now
961
- });
962
- insertLineage({
963
- id: crypto2.randomUUID(),
964
- skill_id: existing.id,
965
- generation,
966
- action: "updated",
967
- rationale: args.rationale ?? "Skill content updated",
968
- source_ids_added: args.source_ids,
969
- content_snapshot: args.content,
970
- created_at: now
971
- });
972
- } else {
973
- recordId = crypto2.randomUUID();
974
- generation = 1;
975
- insertSkillRecord({
976
- id: recordId,
977
- agent_id: agentId,
978
- machine_id: machineId,
979
- name: args.name,
980
- display_name: args.display_name,
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,
1118
+ try {
1119
+ txDb.transaction(() => {
1120
+ if (existing) {
1121
+ generation = existing.generation + 1;
1122
+ recordId = existing.id;
1123
+ updateSkillRecord(existing.id, {
1124
+ display_name: args.display_name,
1125
+ description: args.description,
1126
+ generation,
1127
+ ...args.source_ids !== void 0 ? { source_ids: args.source_ids } : {},
1128
+ path: relativePath,
1004
1129
  updated_at: now
1005
1130
  });
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, {
1131
+ insertLineage({
1132
+ id: crypto2.randomUUID(),
1133
+ skill_id: existing.id,
1134
+ generation,
1135
+ action: "updated",
1136
+ rationale: args.rationale ?? "Skill content updated",
1137
+ source_ids_added: args.source_ids,
1138
+ content_snapshot: args.content,
1139
+ created_at: now
1140
+ });
1141
+ } else {
1142
+ recordId = crypto2.randomUUID();
1143
+ generation = 1;
1144
+ insertSkillRecord({
1145
+ id: recordId,
1146
+ agent_id: agentId,
1147
+ machine_id: machineId,
1148
+ name: args.name,
1149
+ display_name: args.display_name,
1150
+ description: args.description,
1151
+ candidate_id: args.candidate_id ?? null,
1152
+ source_ids: args.source_ids,
1153
+ path: relativePath,
1154
+ created_at: now,
1155
+ updated_at: now
1156
+ });
1157
+ insertLineage({
1158
+ id: crypto2.randomUUID(),
1159
+ skill_id: recordId,
1160
+ generation,
1161
+ action: "created",
1162
+ rationale: args.rationale ?? "Initial skill creation",
1163
+ source_ids_added: args.source_ids,
1164
+ content_snapshot: args.content,
1165
+ created_at: now
1166
+ });
1167
+ const approvedCandidates = listCandidates({ status: "approved", limit: 10 });
1168
+ let linkedCandidate = false;
1169
+ if (args.candidate_id && !linkedCandidate) {
1170
+ const exact = updateCandidate(args.candidate_id, {
1012
1171
  status: "generated",
1013
1172
  skill_id: recordId,
1014
1173
  updated_at: now
1015
1174
  });
1016
- linkedCandidate = true;
1175
+ if (exact) linkedCandidate = true;
1176
+ }
1177
+ if (args.candidate_id && !linkedCandidate) {
1178
+ const prefixMatch = approvedCandidates.find((c) => c.id.startsWith(args.candidate_id));
1179
+ if (prefixMatch) {
1180
+ updateCandidate(prefixMatch.id, {
1181
+ status: "generated",
1182
+ skill_id: recordId,
1183
+ updated_at: now
1184
+ });
1185
+ linkedCandidate = true;
1186
+ }
1017
1187
  }
1018
1188
  }
1189
+ })();
1190
+ } catch (err) {
1191
+ try {
1192
+ if (priorSkillContent !== null) {
1193
+ writeFileSync(skillPath, priorSkillContent, "utf-8");
1194
+ } else if (!skillDirPreexisted) {
1195
+ rmSync(skillDir, { recursive: true, force: true });
1196
+ } else {
1197
+ rmSync(skillPath, { force: true });
1198
+ }
1199
+ } catch (rollbackErr) {
1200
+ console.warn(
1201
+ "[vault_write_skill] file rollback after DB failure also failed:",
1202
+ rollbackErr instanceof Error ? rollbackErr.message : rollbackErr
1203
+ );
1019
1204
  }
1020
- })();
1205
+ recordTurn("vault_write_skill", args);
1206
+ return textResult({
1207
+ error: `Skill write aborted: database transaction failed and on-disk state was rolled back. ${err instanceof Error ? err.message : String(err)}`
1208
+ });
1209
+ }
1021
1210
  const isNew = generation === 1;
1022
1211
  notify(vaultDir, {
1023
1212
  domain: "skills",
@@ -1534,6 +1723,7 @@ import { writeFileSync as writeFileSync2, unlinkSync } from "fs";
1534
1723
  import { tmpdir } from "os";
1535
1724
  import { join } from "path";
1536
1725
  var OLLAMA_PRELOAD_TIMEOUT_MS = 3e4;
1726
+ var DEFAULT_OLLAMA_CONTEXT_LENGTH = 32768;
1537
1727
  async function ensureOllamaContextVariant(model, contextLength) {
1538
1728
  const baseName = model.replace(/:latest$/, "");
1539
1729
  const variantName = `${baseName}-ctx${contextLength}`;
@@ -1560,6 +1750,60 @@ PARAMETER num_ctx ${contextLength}
1560
1750
  return model;
1561
1751
  }
1562
1752
  }
1753
+ async function resolveOllamaContextVariants(taskProvider, phaseOverrides, createVariant = ensureOllamaContextVariant) {
1754
+ const seen = /* @__PURE__ */ new Map();
1755
+ const recordOllama = (p) => {
1756
+ if (p?.type !== "ollama" || !p.model) return;
1757
+ const ctx = p.contextLength ?? DEFAULT_OLLAMA_CONTEXT_LENGTH;
1758
+ const set = seen.get(p.model) ?? /* @__PURE__ */ new Set();
1759
+ set.add(ctx);
1760
+ seen.set(p.model, set);
1761
+ };
1762
+ recordOllama(taskProvider);
1763
+ for (const override of Object.values(phaseOverrides)) {
1764
+ recordOllama(override.provider);
1765
+ }
1766
+ if (seen.size === 0) {
1767
+ return { taskProvider, phaseOverrides, conflicts: [] };
1768
+ }
1769
+ const resolvedContext = /* @__PURE__ */ new Map();
1770
+ const conflicts = [];
1771
+ for (const [model, values] of seen) {
1772
+ const sorted = [...values].sort((a, b) => a - b);
1773
+ const max = sorted[sorted.length - 1];
1774
+ resolvedContext.set(model, max);
1775
+ if (sorted.length > 1) {
1776
+ conflicts.push({ model, values: sorted, resolved: max });
1777
+ }
1778
+ }
1779
+ const variantEntries = await Promise.all(
1780
+ [...resolvedContext.entries()].map(async ([model, ctx]) => {
1781
+ const variant = await createVariant(model, ctx);
1782
+ return [model, variant];
1783
+ })
1784
+ );
1785
+ const variantByModel = new Map(variantEntries);
1786
+ const rewriteProvider = (p) => {
1787
+ if (!p) return p;
1788
+ if (p.type !== "ollama" || !p.model) return p;
1789
+ const variant = variantByModel.get(p.model);
1790
+ const resolvedCtx = resolvedContext.get(p.model);
1791
+ if (!variant) return p;
1792
+ return { ...p, model: variant, contextLength: resolvedCtx };
1793
+ };
1794
+ const rewrittenPhaseOverrides = {};
1795
+ for (const [name, override] of Object.entries(phaseOverrides)) {
1796
+ rewrittenPhaseOverrides[name] = {
1797
+ ...override,
1798
+ ...override.provider ? { provider: rewriteProvider(override.provider) } : {}
1799
+ };
1800
+ }
1801
+ return {
1802
+ taskProvider: rewriteProvider(taskProvider),
1803
+ phaseOverrides: rewrittenPhaseOverrides,
1804
+ conflicts
1805
+ };
1806
+ }
1563
1807
 
1564
1808
  // src/agent/wave-computation.ts
1565
1809
  import crypto3 from "crypto";
@@ -1624,6 +1868,38 @@ var MCP_SERVER_NAME = "myco-vault";
1624
1868
  var PERSIST_SESSION = true;
1625
1869
  var PROMPT_SECTION_PRIOR_PHASES = "## Prior Phase Results";
1626
1870
  var PROMPT_SECTION_CURRENT_PHASE = "## Current Phase: ";
1871
+ var DEBUG_TOOL_CALLS = process.env.MYCO_AGENT_DEBUG === "1";
1872
+ var TOOL_DEBUG_PREVIEW_CHARS = 240;
1873
+ function previewPayload(value) {
1874
+ const str = typeof value === "string" ? value : JSON.stringify(value);
1875
+ if (str === void 0) return "";
1876
+ return str.length > TOOL_DEBUG_PREVIEW_CHARS ? `${str.slice(0, TOOL_DEBUG_PREVIEW_CHARS)}\u2026(${str.length - TOOL_DEBUG_PREVIEW_CHARS} more chars)` : str;
1877
+ }
1878
+ function logToolUseBlocks(phaseName, message) {
1879
+ if (!DEBUG_TOOL_CALLS) return;
1880
+ const blocks = message.message?.content;
1881
+ if (!Array.isArray(blocks)) return;
1882
+ for (const block of blocks) {
1883
+ if (block.type === "tool_use") {
1884
+ console.log(
1885
+ `[agent:debug] ${phaseName} tool_use: ${block.name ?? "unknown"} input=${previewPayload(block.input)}`
1886
+ );
1887
+ }
1888
+ }
1889
+ }
1890
+ function logToolResultBlocks(phaseName, message) {
1891
+ if (!DEBUG_TOOL_CALLS) return;
1892
+ const blocks = message.message?.content;
1893
+ if (!Array.isArray(blocks)) return;
1894
+ for (const block of blocks) {
1895
+ if (block.type === "tool_result") {
1896
+ const flag = block.is_error ? " [ERROR]" : "";
1897
+ console.log(
1898
+ `[agent:debug] ${phaseName} tool_result${flag}: ${previewPayload(block.content)}`
1899
+ );
1900
+ }
1901
+ }
1902
+ }
1627
1903
  function composeTaskPrompt(vaultContext, taskDisplayName, taskPrompt, instruction) {
1628
1904
  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
1905
  const sessionId = sessionIdMatch?.[1] ?? "";
@@ -1690,6 +1966,10 @@ async function executePhase(query, phasePrompt, phaseModel, systemPrompt, toolSe
1690
1966
  })) {
1691
1967
  if (message.type === "assistant") {
1692
1968
  agenticTurns++;
1969
+ logToolUseBlocks(phase.name, message);
1970
+ }
1971
+ if (message.type === "user") {
1972
+ logToolResultBlocks(phase.name, message);
1693
1973
  }
1694
1974
  if (message.type === "result") {
1695
1975
  phaseCost = message.total_cost_usd ?? 0;
@@ -1885,9 +2165,10 @@ async function runAgent(vaultDir, options) {
1885
2165
  config,
1886
2166
  definitionsDir,
1887
2167
  taskProviderOverride: resolvedTaskProvider,
1888
- phaseProviderOverrides
2168
+ phaseProviderOverrides: resolvedPhaseOverrides
1889
2169
  } = resolveRunConfig(agentId, requestedTask, vaultDir);
1890
2170
  let taskProviderOverride = resolvedTaskProvider;
2171
+ let phaseProviderOverrides = resolvedPhaseOverrides;
1891
2172
  const runId = options?.resumeRunId ?? crypto4.randomUUID();
1892
2173
  const now = epochSeconds();
1893
2174
  if (!options?.resumeRunId) {
@@ -1909,12 +2190,18 @@ async function runAgent(vaultDir, options) {
1909
2190
  provider: effectiveProvider?.type ?? "cloud",
1910
2191
  ...effectiveProvider?.baseUrl ? { baseUrl: effectiveProvider.baseUrl } : {}
1911
2192
  };
1912
- if (effectiveProvider?.type === "ollama" && effectiveProvider.contextLength && effectiveProvider.model) {
1913
- const variantModel = await ensureOllamaContextVariant(
1914
- effectiveProvider.model,
1915
- effectiveProvider.contextLength
2193
+ {
2194
+ const resolved = await resolveOllamaContextVariants(
2195
+ taskProviderOverride,
2196
+ phaseProviderOverrides
1916
2197
  );
1917
- taskProviderOverride = { ...taskProviderOverride, model: variantModel };
2198
+ taskProviderOverride = resolved.taskProvider;
2199
+ phaseProviderOverrides = resolved.phaseOverrides;
2200
+ for (const conflict of resolved.conflicts) {
2201
+ console.warn(
2202
+ `[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.`
2203
+ );
2204
+ }
1918
2205
  }
1919
2206
  const taskAbortController = new AbortController();
1920
2207
  const timeoutMs = config.timeoutSeconds * MS_PER_SECOND;
@@ -2025,4 +2312,4 @@ export {
2025
2312
  computeWaves,
2026
2313
  runAgent
2027
2314
  };
2028
- //# sourceMappingURL=executor-7XOKS6HS.js.map
2315
+ //# sourceMappingURL=executor-4OXDK4ZA.js.map