@goondocks/myco 0.14.4 → 0.15.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.
Files changed (172) hide show
  1. package/dist/{agent-run-GZ5UVLDV.js → agent-run-DUOJ3KDI.js} +6 -6
  2. package/dist/{agent-tasks-KKQ2GBBB.js → agent-tasks-LUWBY5JD.js} +6 -6
  3. package/dist/{chunk-X34OFKYU.js → chunk-23FJUKCN.js} +2 -2
  4. package/dist/{chunk-KNTJOMWY.js → chunk-3MEOYXOW.js} +2 -2
  5. package/dist/{chunk-PSYLKCWQ.js → chunk-4BQ5QE76.js} +24 -5
  6. package/dist/chunk-4BQ5QE76.js.map +1 -0
  7. package/dist/{chunk-JTYZRPX5.js → chunk-5ZT2Q6P5.js} +1 -1
  8. package/dist/{chunk-JJXVDCEX.js → chunk-75J2BR4P.js} +486 -488
  9. package/dist/chunk-75J2BR4P.js.map +1 -0
  10. package/dist/{chunk-GMTWRMLP.js → chunk-B3SF2CCW.js} +3 -3
  11. package/dist/{chunk-S6I62FAH.js → chunk-CUADDHHU.js} +4 -2
  12. package/dist/{chunk-S6I62FAH.js.map → chunk-CUADDHHU.js.map} +1 -1
  13. package/dist/{chunk-4VF6KQ2Z.js → chunk-DJQOYEK3.js} +87 -84
  14. package/dist/chunk-DJQOYEK3.js.map +1 -0
  15. package/dist/{chunk-LD6U3L6O.js → chunk-DK5VEBB5.js} +5 -5
  16. package/dist/{chunk-STBNNKL5.js → chunk-DKGUCEWU.js} +6 -6
  17. package/dist/{chunk-OQVKLTQY.js → chunk-EYMKBNRP.js} +2 -2
  18. package/dist/{chunk-KH64DHOY.js → chunk-GDY63YAW.js} +279 -277
  19. package/dist/chunk-GDY63YAW.js.map +1 -0
  20. package/dist/{chunk-ZESTWGJT.js → chunk-GYIA6XLB.js} +2 -2
  21. package/dist/{chunk-BCKYVLUZ.js → chunk-GZ7MXWYX.js} +3 -3
  22. package/dist/{chunk-S66YG6QK.js → chunk-LF5Z62X6.js} +46 -7
  23. package/dist/chunk-LF5Z62X6.js.map +1 -0
  24. package/dist/{chunk-TFBAV3PV.js → chunk-OMZCVRX6.js} +2 -2
  25. package/dist/{chunk-UZ5Y6XMP.js → chunk-R3YW7XVF.js} +2 -2
  26. package/dist/{chunk-PX5KIOKY.js → chunk-SPJGJEFV.js} +10 -2
  27. package/dist/{chunk-PX5KIOKY.js.map → chunk-SPJGJEFV.js.map} +1 -1
  28. package/dist/{chunk-QFMBZ72S.js → chunk-SV6UCB2Z.js} +2 -2
  29. package/dist/{chunk-NVCGF2DS.js → chunk-X4XFJG6I.js} +10 -6
  30. package/dist/chunk-X4XFJG6I.js.map +1 -0
  31. package/dist/{chunk-TNCBMGWB.js → chunk-X5IXK5KO.js} +262 -226
  32. package/dist/chunk-X5IXK5KO.js.map +1 -0
  33. package/dist/{chunk-TVV6PZOC.js → chunk-Z7TZJ2SP.js} +2 -2
  34. package/dist/{cli-JLDCZ77U.js → cli-YBD2GPK4.js} +45 -44
  35. package/dist/cli-YBD2GPK4.js.map +1 -0
  36. package/dist/{client-LRQMMKLP.js → client-CJ3X252K.js} +4 -4
  37. package/dist/{config-H657SF6B.js → config-MOWCOJJ4.js} +4 -4
  38. package/dist/{detect-27DN6UTL.js → detect-GFYKKHLJ.js} +3 -3
  39. package/dist/{detect-providers-PAVE2X6O.js → detect-providers-EU35RUL3.js} +2 -2
  40. package/dist/{doctor-IG3CXMI7.js → doctor-JR7NEL7K.js} +38 -19
  41. package/dist/doctor-JR7NEL7K.js.map +1 -0
  42. package/dist/{executor-HKNINUWO.js → executor-7XOKS6HS.js} +439 -248
  43. package/dist/executor-7XOKS6HS.js.map +1 -0
  44. package/dist/{init-RHQUINC2.js → init-PDLKYWQ4.js} +41 -23
  45. package/dist/init-PDLKYWQ4.js.map +1 -0
  46. package/dist/{init-wizard-ZB3JRDLE.js → init-wizard-WH3SXNMB.js} +7 -7
  47. package/dist/{installer-25TSX4SR.js → installer-BTUNKWOU.js} +2 -2
  48. package/dist/{llm-T3QVHC3Y.js → llm-DK44LYO6.js} +4 -4
  49. package/dist/{loader-WQKVWL5D.js → loader-WC4U5NM5.js} +4 -4
  50. package/dist/{loader-JQLO6K44.js → loader-WGDVRGLM.js} +6 -4
  51. package/dist/{logs-LXHPDKUA.js → logs-WFBX2I7C.js} +3 -3
  52. package/dist/{main-MVXPBP5Z.js → main-JB3R3DQE.js} +2346 -1912
  53. package/dist/main-JB3R3DQE.js.map +1 -0
  54. package/dist/{open-CVEMRH3Z.js → open-AADZPSLW.js} +6 -6
  55. package/dist/{openai-embeddings-5T5ZP7LO.js → openai-embeddings-SEIV7AM3.js} +2 -2
  56. package/dist/{openrouter-RD2COFC7.js → openrouter-ELODIZRP.js} +2 -2
  57. package/dist/{post-compact-ALQ2UGZ7.js → post-compact-KNQ4DYLM.js} +9 -9
  58. package/dist/{post-tool-use-SPL7HIYU.js → post-tool-use-OMWHFQLM.js} +10 -10
  59. package/dist/{post-tool-use-failure-B3CUYBTR.js → post-tool-use-failure-KFP6MB7Z.js} +9 -9
  60. package/dist/{pre-compact-KPWC4V64.js → pre-compact-2ZYE2HRB.js} +9 -9
  61. package/dist/{provider-check-QN7OGXZA.js → provider-check-B66E5PWS.js} +2 -2
  62. package/dist/{registry-2XQMCPA6.js → registry-DHWVHXWY.js} +5 -5
  63. package/dist/{remove-O2WCN6RC.js → remove-QT7634L5.js} +52 -20
  64. package/dist/remove-QT7634L5.js.map +1 -0
  65. package/dist/{resolution-events-5EVUEWHS.js → resolution-events-DBCRVZGU.js} +4 -4
  66. package/dist/{restart-S52VV3SP.js → restart-YQNQEHOU.js} +7 -7
  67. package/dist/{search-IOJ5O37S.js → search-C6JTQDWY.js} +6 -6
  68. package/dist/{server-T4VPK6FU.js → server-QJ3RWZZZ.js} +8 -8
  69. package/dist/{session-ID6BX72K.js → session-JLVL5TYX.js} +8 -8
  70. package/dist/{session-end-I7ZABXRI.js → session-end-XFZRRP5H.js} +10 -10
  71. package/dist/{session-start-VPOUY42U.js → session-start-XGINISXO.js} +15 -15
  72. package/dist/{setup-llm-G5UG5N3T.js → setup-llm-X2OCM6R7.js} +8 -8
  73. package/dist/src/agent/definitions/tasks/full-intelligence.yaml +8 -7
  74. package/dist/src/agent/definitions/tasks/skill-evolve.yaml +71 -144
  75. package/dist/src/agent/definitions/tasks/skill-generate.yaml +10 -62
  76. package/dist/src/agent/definitions/tasks/skill-survey.yaml +87 -53
  77. package/dist/src/agent/prompts/agent.md +1 -0
  78. package/dist/src/cli.js +1 -1
  79. package/dist/src/daemon/main.js +1 -1
  80. package/dist/src/hooks/post-tool-use.js +1 -1
  81. package/dist/src/hooks/session-end.js +1 -1
  82. package/dist/src/hooks/session-start.js +1 -1
  83. package/dist/src/hooks/stop.js +1 -1
  84. package/dist/src/hooks/user-prompt-submit.js +1 -1
  85. package/dist/src/mcp/server.js +1 -1
  86. package/dist/src/worker/src/schema.ts +14 -0
  87. package/dist/{stats-GRI4MTS2.js → stats-2EAETG2T.js} +9 -9
  88. package/dist/{stop-UTZ2CXI2.js → stop-WOBDYTSA.js} +10 -10
  89. package/dist/{stop-failure-CECM5NB7.js → stop-failure-QEC7ZGBQ.js} +9 -9
  90. package/dist/{subagent-start-SYZGJYUN.js → subagent-start-H6DVRVOE.js} +9 -9
  91. package/dist/{subagent-stop-7WWW7TGQ.js → subagent-stop-LKENKJ65.js} +9 -9
  92. package/dist/{task-completed-N7SIY6T6.js → task-completed-ZZ47PRPD.js} +9 -9
  93. package/dist/{team-SJPDXELY.js → team-J62N7VMG.js} +34 -26
  94. package/dist/team-J62N7VMG.js.map +1 -0
  95. package/dist/ui/assets/index-Bx9l8uxa.js +837 -0
  96. package/dist/ui/assets/{index-BmsHIwjl.css → index-DlEQ8A8Y.css} +1 -1
  97. package/dist/ui/index.html +2 -2
  98. package/dist/{update-DZZYQ4NJ.js → update-LX3CJ4TJ.js} +30 -14
  99. package/dist/update-LX3CJ4TJ.js.map +1 -0
  100. package/dist/{user-prompt-submit-UUNRRS5P.js → user-prompt-submit-NNMLY3EW.js} +10 -10
  101. package/dist/{verify-JHIMXTY5.js → verify-AMRQXQ3K.js} +6 -6
  102. package/dist/{version-VKNCAPZW.js → version-6OJH5HLZ.js} +2 -2
  103. package/package.json +2 -2
  104. package/dist/chunk-4VF6KQ2Z.js.map +0 -1
  105. package/dist/chunk-JJXVDCEX.js.map +0 -1
  106. package/dist/chunk-KH64DHOY.js.map +0 -1
  107. package/dist/chunk-NVCGF2DS.js.map +0 -1
  108. package/dist/chunk-PSYLKCWQ.js.map +0 -1
  109. package/dist/chunk-S66YG6QK.js.map +0 -1
  110. package/dist/chunk-TNCBMGWB.js.map +0 -1
  111. package/dist/cli-JLDCZ77U.js.map +0 -1
  112. package/dist/doctor-IG3CXMI7.js.map +0 -1
  113. package/dist/executor-HKNINUWO.js.map +0 -1
  114. package/dist/init-RHQUINC2.js.map +0 -1
  115. package/dist/main-MVXPBP5Z.js.map +0 -1
  116. package/dist/remove-O2WCN6RC.js.map +0 -1
  117. package/dist/resolve-3FEUV462.js +0 -9
  118. package/dist/team-SJPDXELY.js.map +0 -1
  119. package/dist/ui/assets/index-Cn6cQwJy.js +0 -842
  120. package/dist/update-DZZYQ4NJ.js.map +0 -1
  121. package/dist/version-VKNCAPZW.js.map +0 -1
  122. /package/dist/{agent-run-GZ5UVLDV.js.map → agent-run-DUOJ3KDI.js.map} +0 -0
  123. /package/dist/{agent-tasks-KKQ2GBBB.js.map → agent-tasks-LUWBY5JD.js.map} +0 -0
  124. /package/dist/{chunk-X34OFKYU.js.map → chunk-23FJUKCN.js.map} +0 -0
  125. /package/dist/{chunk-KNTJOMWY.js.map → chunk-3MEOYXOW.js.map} +0 -0
  126. /package/dist/{chunk-JTYZRPX5.js.map → chunk-5ZT2Q6P5.js.map} +0 -0
  127. /package/dist/{chunk-GMTWRMLP.js.map → chunk-B3SF2CCW.js.map} +0 -0
  128. /package/dist/{chunk-LD6U3L6O.js.map → chunk-DK5VEBB5.js.map} +0 -0
  129. /package/dist/{chunk-STBNNKL5.js.map → chunk-DKGUCEWU.js.map} +0 -0
  130. /package/dist/{chunk-OQVKLTQY.js.map → chunk-EYMKBNRP.js.map} +0 -0
  131. /package/dist/{chunk-ZESTWGJT.js.map → chunk-GYIA6XLB.js.map} +0 -0
  132. /package/dist/{chunk-BCKYVLUZ.js.map → chunk-GZ7MXWYX.js.map} +0 -0
  133. /package/dist/{chunk-TFBAV3PV.js.map → chunk-OMZCVRX6.js.map} +0 -0
  134. /package/dist/{chunk-UZ5Y6XMP.js.map → chunk-R3YW7XVF.js.map} +0 -0
  135. /package/dist/{chunk-QFMBZ72S.js.map → chunk-SV6UCB2Z.js.map} +0 -0
  136. /package/dist/{chunk-TVV6PZOC.js.map → chunk-Z7TZJ2SP.js.map} +0 -0
  137. /package/dist/{client-LRQMMKLP.js.map → client-CJ3X252K.js.map} +0 -0
  138. /package/dist/{config-H657SF6B.js.map → config-MOWCOJJ4.js.map} +0 -0
  139. /package/dist/{detect-27DN6UTL.js.map → detect-GFYKKHLJ.js.map} +0 -0
  140. /package/dist/{detect-providers-PAVE2X6O.js.map → detect-providers-EU35RUL3.js.map} +0 -0
  141. /package/dist/{init-wizard-ZB3JRDLE.js.map → init-wizard-WH3SXNMB.js.map} +0 -0
  142. /package/dist/{installer-25TSX4SR.js.map → installer-BTUNKWOU.js.map} +0 -0
  143. /package/dist/{llm-T3QVHC3Y.js.map → llm-DK44LYO6.js.map} +0 -0
  144. /package/dist/{loader-JQLO6K44.js.map → loader-WC4U5NM5.js.map} +0 -0
  145. /package/dist/{loader-WQKVWL5D.js.map → loader-WGDVRGLM.js.map} +0 -0
  146. /package/dist/{logs-LXHPDKUA.js.map → logs-WFBX2I7C.js.map} +0 -0
  147. /package/dist/{open-CVEMRH3Z.js.map → open-AADZPSLW.js.map} +0 -0
  148. /package/dist/{openai-embeddings-5T5ZP7LO.js.map → openai-embeddings-SEIV7AM3.js.map} +0 -0
  149. /package/dist/{openrouter-RD2COFC7.js.map → openrouter-ELODIZRP.js.map} +0 -0
  150. /package/dist/{post-compact-ALQ2UGZ7.js.map → post-compact-KNQ4DYLM.js.map} +0 -0
  151. /package/dist/{post-tool-use-SPL7HIYU.js.map → post-tool-use-OMWHFQLM.js.map} +0 -0
  152. /package/dist/{post-tool-use-failure-B3CUYBTR.js.map → post-tool-use-failure-KFP6MB7Z.js.map} +0 -0
  153. /package/dist/{pre-compact-KPWC4V64.js.map → pre-compact-2ZYE2HRB.js.map} +0 -0
  154. /package/dist/{provider-check-QN7OGXZA.js.map → provider-check-B66E5PWS.js.map} +0 -0
  155. /package/dist/{registry-2XQMCPA6.js.map → registry-DHWVHXWY.js.map} +0 -0
  156. /package/dist/{resolution-events-5EVUEWHS.js.map → resolution-events-DBCRVZGU.js.map} +0 -0
  157. /package/dist/{restart-S52VV3SP.js.map → restart-YQNQEHOU.js.map} +0 -0
  158. /package/dist/{search-IOJ5O37S.js.map → search-C6JTQDWY.js.map} +0 -0
  159. /package/dist/{server-T4VPK6FU.js.map → server-QJ3RWZZZ.js.map} +0 -0
  160. /package/dist/{session-ID6BX72K.js.map → session-JLVL5TYX.js.map} +0 -0
  161. /package/dist/{session-end-I7ZABXRI.js.map → session-end-XFZRRP5H.js.map} +0 -0
  162. /package/dist/{session-start-VPOUY42U.js.map → session-start-XGINISXO.js.map} +0 -0
  163. /package/dist/{setup-llm-G5UG5N3T.js.map → setup-llm-X2OCM6R7.js.map} +0 -0
  164. /package/dist/{stats-GRI4MTS2.js.map → stats-2EAETG2T.js.map} +0 -0
  165. /package/dist/{stop-UTZ2CXI2.js.map → stop-WOBDYTSA.js.map} +0 -0
  166. /package/dist/{stop-failure-CECM5NB7.js.map → stop-failure-QEC7ZGBQ.js.map} +0 -0
  167. /package/dist/{subagent-start-SYZGJYUN.js.map → subagent-start-H6DVRVOE.js.map} +0 -0
  168. /package/dist/{subagent-stop-7WWW7TGQ.js.map → subagent-stop-LKENKJ65.js.map} +0 -0
  169. /package/dist/{task-completed-N7SIY6T6.js.map → task-completed-ZZ47PRPD.js.map} +0 -0
  170. /package/dist/{user-prompt-submit-UUNRRS5P.js.map → user-prompt-submit-NNMLY3EW.js.map} +0 -0
  171. /package/dist/{verify-JHIMXTY5.js.map → verify-AMRQXQ3K.js.map} +0 -0
  172. /package/dist/{resolve-3FEUV462.js.map → version-6OJH5HLZ.js.map} +0 -0
@@ -1,8 +1,143 @@
1
1
  import { createRequire as __cr } from 'node:module'; const require = __cr(import.meta.url);
2
2
 
3
3
  // src/symbionts/installer.ts
4
+ import fs3 from "fs";
5
+ import path3 from "path";
6
+
7
+ // src/symbionts/toml-helpers.ts
8
+ var TOML_SECTION_RE = /^\[([^\]]+)\]/;
9
+ function findTomlSectionEnd(raw, searchStart, serverName) {
10
+ const subsectionPrefix = `mcp_servers.${serverName}.`;
11
+ const rawLines = raw.slice(searchStart).split("\n");
12
+ let offset = searchStart;
13
+ for (const line of rawLines) {
14
+ offset += line.length + 1;
15
+ const m = line.match(TOML_SECTION_RE);
16
+ if (m && !m[1].startsWith(subsectionPrefix) && m[1] !== `mcp_servers.${serverName}`) {
17
+ return offset - line.length - 1;
18
+ }
19
+ }
20
+ return raw.length;
21
+ }
22
+ function buildTomlMcpSection(raw, serverName, server) {
23
+ const sectionHeader = `[mcp_servers.${serverName}]`;
24
+ const lines = [sectionHeader];
25
+ for (const [key, val] of Object.entries(server)) {
26
+ if (key === "env" && typeof val === "object" && val !== null) continue;
27
+ if (typeof val === "string") {
28
+ lines.push(`${key} = "${val}"`);
29
+ } else if (Array.isArray(val)) {
30
+ lines.push(`${key} = [${val.map((v) => `"${v}"`).join(", ")}]`);
31
+ } else if (typeof val === "boolean") {
32
+ lines.push(`${key} = ${val}`);
33
+ }
34
+ }
35
+ const env = server.env;
36
+ if (env && Object.keys(env).length > 0) {
37
+ lines.push("");
38
+ lines.push(`[mcp_servers.${serverName}.env]`);
39
+ for (const [key, val] of Object.entries(env)) {
40
+ lines.push(`${key} = "${val}"`);
41
+ }
42
+ }
43
+ const block = lines.join("\n");
44
+ let updated;
45
+ if (raw.includes(sectionHeader)) {
46
+ const startIdx = raw.indexOf(sectionHeader);
47
+ const endIdx = findTomlSectionEnd(raw, startIdx + sectionHeader.length, serverName);
48
+ const before = raw.slice(0, startIdx).trimEnd();
49
+ const after = raw.slice(endIdx);
50
+ const separator = before ? "\n\n" : "";
51
+ updated = (before + separator + block + after).trimEnd() + "\n";
52
+ } else {
53
+ const separator = raw.trim() ? "\n\n" : "";
54
+ updated = (raw.trimEnd() + separator + block).trimEnd() + "\n";
55
+ }
56
+ return updated;
57
+ }
58
+
59
+ // src/symbionts/settings-merge.ts
60
+ function deepMergeSettings(target, source) {
61
+ const result = { ...target };
62
+ for (const [key, sourceVal] of Object.entries(source)) {
63
+ const targetVal = result[key];
64
+ if (Array.isArray(sourceVal) && Array.isArray(targetVal)) {
65
+ result[key] = [.../* @__PURE__ */ new Set([...targetVal, ...sourceVal])];
66
+ } else if (isPlainObject(sourceVal) && isPlainObject(targetVal)) {
67
+ result[key] = deepMergeSettings(
68
+ targetVal,
69
+ sourceVal
70
+ );
71
+ } else {
72
+ result[key] = sourceVal;
73
+ }
74
+ }
75
+ return result;
76
+ }
77
+ function isPlainObject(val) {
78
+ return typeof val === "object" && val !== null && !Array.isArray(val);
79
+ }
80
+ function deepRemoveSettings(target, template) {
81
+ let changed = false;
82
+ for (const [key, templateVal] of Object.entries(template)) {
83
+ const targetVal = target[key];
84
+ if (targetVal === void 0) continue;
85
+ if (Array.isArray(templateVal) && Array.isArray(targetVal)) {
86
+ const templateSet = new Set(templateVal.map(String));
87
+ const filtered = targetVal.filter((v) => !templateSet.has(String(v)));
88
+ if (filtered.length !== targetVal.length) {
89
+ if (filtered.length > 0) {
90
+ target[key] = filtered;
91
+ } else {
92
+ delete target[key];
93
+ }
94
+ changed = true;
95
+ }
96
+ } else if (isPlainObject(templateVal) && isPlainObject(targetVal)) {
97
+ if (deepRemoveSettings(targetVal, templateVal)) {
98
+ if (Object.keys(targetVal).length === 0) {
99
+ delete target[key];
100
+ }
101
+ changed = true;
102
+ }
103
+ } else {
104
+ if (String(targetVal) === String(templateVal)) {
105
+ delete target[key];
106
+ changed = true;
107
+ }
108
+ }
109
+ }
110
+ return changed;
111
+ }
112
+
113
+ // src/symbionts/json-helpers.ts
4
114
  import fs from "fs";
5
115
  import path from "path";
116
+ function readJsonFile(filePath) {
117
+ try {
118
+ return JSON.parse(fs.readFileSync(filePath, "utf-8"));
119
+ } catch {
120
+ return {};
121
+ }
122
+ }
123
+ function writeJsonFile(filePath, data) {
124
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
125
+ fs.writeFileSync(filePath, JSON.stringify(data, null, 2) + "\n", "utf-8");
126
+ }
127
+ function writeOrDeleteJsonFile(filePath, data) {
128
+ if (Object.keys(data).length === 0) {
129
+ try {
130
+ fs.unlinkSync(filePath);
131
+ } catch {
132
+ }
133
+ } else {
134
+ writeJsonFile(filePath, data);
135
+ }
136
+ }
137
+
138
+ // src/symbionts/install-helpers.ts
139
+ import fs2 from "fs";
140
+ import path2 from "path";
6
141
  var MYCO_HOOK_COMMAND_PREFIX = "myco-run";
7
142
  var MYCO_HOOK_GUARD_PREFIX = "node .agents/myco-hook.cjs";
8
143
  function isMycoHookCommand(command) {
@@ -13,6 +148,35 @@ function isMycoHookGroup(group) {
13
148
  if (typeof group.command === "string" && isMycoHookCommand(group.command)) return true;
14
149
  return false;
15
150
  }
151
+ function ensureAgentsMd(projectRoot, packageRoot) {
152
+ const agentsMdPath = path2.join(projectRoot, "AGENTS.md");
153
+ if (fs2.existsSync(agentsMdPath)) return;
154
+ const candidates = [
155
+ path2.join(packageRoot, "src/symbionts/templates/agents-starter.md"),
156
+ path2.join(packageRoot, "dist/src/symbionts/templates/agents-starter.md")
157
+ ];
158
+ for (const p of candidates) {
159
+ try {
160
+ const content = fs2.readFileSync(p, "utf-8");
161
+ fs2.writeFileSync(agentsMdPath, content, "utf-8");
162
+ return;
163
+ } catch {
164
+ }
165
+ }
166
+ }
167
+ function ensureSymlink(linkPath, target) {
168
+ try {
169
+ if (fs2.readlinkSync(linkPath) === target) return;
170
+ } catch {
171
+ }
172
+ try {
173
+ fs2.rmSync(linkPath, { recursive: true, force: true });
174
+ } catch {
175
+ }
176
+ fs2.symlinkSync(target, linkPath);
177
+ }
178
+
179
+ // src/symbionts/installer.ts
16
180
  var GITIGNORE_COMMENT = "# Myco managed (machine-specific)";
17
181
  var GITIGNORE_SKILLS_COMMENT_LEGACY = "# Myco skill symlinks (machine-specific)";
18
182
  var WRANGLER_CACHE_DIR = ".wrangler/";
@@ -46,13 +210,13 @@ var SymbiontInstaller = class {
46
210
  if (!reg?.hooksTarget) return false;
47
211
  const guardTemplate = this.loadHookGuardTemplate();
48
212
  if (!guardTemplate) return false;
49
- const targetPath = path.join(this.projectRoot, HOOK_GUARD_PROJECT_PATH);
213
+ const targetPath = path3.join(this.projectRoot, HOOK_GUARD_PROJECT_PATH);
50
214
  try {
51
- if (fs.readFileSync(targetPath, "utf-8") === guardTemplate) return false;
215
+ if (fs3.readFileSync(targetPath, "utf-8") === guardTemplate) return false;
52
216
  } catch {
53
217
  }
54
- fs.mkdirSync(path.dirname(targetPath), { recursive: true });
55
- fs.writeFileSync(targetPath, guardTemplate, "utf-8");
218
+ fs3.mkdirSync(path3.dirname(targetPath), { recursive: true });
219
+ fs3.writeFileSync(targetPath, guardTemplate, "utf-8");
56
220
  return true;
57
221
  }
58
222
  /**
@@ -62,9 +226,9 @@ var SymbiontInstaller = class {
62
226
  uninstallHookGuard() {
63
227
  const reg = this.manifest.registration;
64
228
  if (!reg?.hooksTarget) return false;
65
- const targetPath = path.join(this.projectRoot, HOOK_GUARD_PROJECT_PATH);
229
+ const targetPath = path3.join(this.projectRoot, HOOK_GUARD_PROJECT_PATH);
66
230
  try {
67
- fs.unlinkSync(targetPath);
231
+ fs3.unlinkSync(targetPath);
68
232
  return true;
69
233
  } catch {
70
234
  return false;
@@ -73,12 +237,12 @@ var SymbiontInstaller = class {
73
237
  /** Load the hook-guard template from package root. */
74
238
  loadHookGuardTemplate() {
75
239
  const candidates = [
76
- path.join(this.packageRoot, TEMPLATES_SUBDIR, HOOK_GUARD_TEMPLATE_FILENAME),
77
- path.join(this.packageRoot, "dist", TEMPLATES_SUBDIR, HOOK_GUARD_TEMPLATE_FILENAME)
240
+ path3.join(this.packageRoot, TEMPLATES_SUBDIR, HOOK_GUARD_TEMPLATE_FILENAME),
241
+ path3.join(this.packageRoot, "dist", TEMPLATES_SUBDIR, HOOK_GUARD_TEMPLATE_FILENAME)
78
242
  ];
79
243
  for (const p of candidates) {
80
244
  try {
81
- return fs.readFileSync(p, "utf-8");
245
+ return fs3.readFileSync(p, "utf-8");
82
246
  } catch {
83
247
  }
84
248
  }
@@ -87,13 +251,13 @@ var SymbiontInstaller = class {
87
251
  /** Load a JSON template file for this symbiont. Returns null if not found. */
88
252
  loadTemplate(name) {
89
253
  const candidates = [
90
- path.join(this.packageRoot, TEMPLATES_SUBDIR, this.manifest.name, `${name}.json`),
254
+ path3.join(this.packageRoot, TEMPLATES_SUBDIR, this.manifest.name, `${name}.json`),
91
255
  // tsup preserves the src/ prefix under dist/, so the same subdir works in both layouts
92
- path.join(this.packageRoot, "dist", TEMPLATES_SUBDIR, this.manifest.name, `${name}.json`)
256
+ path3.join(this.packageRoot, "dist", TEMPLATES_SUBDIR, this.manifest.name, `${name}.json`)
93
257
  ];
94
258
  for (const filePath of candidates) {
95
259
  try {
96
- return JSON.parse(fs.readFileSync(filePath, "utf-8"));
260
+ return JSON.parse(fs3.readFileSync(filePath, "utf-8"));
97
261
  } catch {
98
262
  }
99
263
  }
@@ -130,7 +294,7 @@ var SymbiontInstaller = class {
130
294
  * Single read → apply all transforms in memory → single write.
131
295
  */
132
296
  installBatchedJson(reg) {
133
- const targetPath = path.join(this.projectRoot, reg.hooksTarget ?? reg.mcpTarget ?? reg.settingsTarget);
297
+ const targetPath = path3.join(this.projectRoot, reg.hooksTarget ?? reg.mcpTarget ?? reg.settingsTarget);
134
298
  let data = readJsonFile(targetPath);
135
299
  let hooks = false, mcp = false, settings = false;
136
300
  const hooksTemplate = reg.hooksTarget ? this.loadTemplate("hooks") : null;
@@ -188,7 +352,7 @@ var SymbiontInstaller = class {
188
352
  * Batched uninstall for agents where hooks, MCP, and settings share one JSON file.
189
353
  */
190
354
  uninstallBatchedJson(reg) {
191
- const targetPath = path.join(this.projectRoot, reg.hooksTarget ?? reg.mcpTarget ?? reg.settingsTarget);
355
+ const targetPath = path3.join(this.projectRoot, reg.hooksTarget ?? reg.mcpTarget ?? reg.settingsTarget);
192
356
  const data = readJsonFile(targetPath);
193
357
  if (Object.keys(data).length === 0) {
194
358
  return { hooks: false, mcp: false, skills: this.uninstallSkills(), settings: false, instructions: this.uninstallInstructions() };
@@ -238,35 +402,35 @@ var SymbiontInstaller = class {
238
402
  const reg = this.manifest.registration;
239
403
  if (!reg?.instructionsFile) return false;
240
404
  ensureAgentsMd(this.projectRoot, this.packageRoot);
241
- const targetPath = path.join(this.projectRoot, reg.instructionsFile);
405
+ const targetPath = path3.join(this.projectRoot, reg.instructionsFile);
242
406
  let existing = null;
243
407
  try {
244
- existing = fs.readFileSync(targetPath, "utf-8");
408
+ existing = fs3.readFileSync(targetPath, "utf-8");
245
409
  } catch {
246
410
  }
247
411
  if (existing !== null) {
248
412
  if (existing.includes(INSTRUCTIONS_REF_START) || existing.includes(INSTRUCTIONS_STUB_MARKER)) {
249
413
  return false;
250
414
  }
251
- fs.writeFileSync(targetPath, INSTRUCTIONS_REF_BLOCK + existing, "utf-8");
415
+ fs3.writeFileSync(targetPath, INSTRUCTIONS_REF_BLOCK + existing, "utf-8");
252
416
  return true;
253
417
  }
254
418
  const templateCandidates = [
255
- path.join(this.packageRoot, "src/symbionts/templates/instructions-stub.md"),
256
- path.join(this.packageRoot, "dist/src/symbionts/templates/instructions-stub.md")
419
+ path3.join(this.packageRoot, "src/symbionts/templates/instructions-stub.md"),
420
+ path3.join(this.packageRoot, "dist/src/symbionts/templates/instructions-stub.md")
257
421
  ];
258
422
  let stub = null;
259
423
  for (const p of templateCandidates) {
260
424
  try {
261
- stub = fs.readFileSync(p, "utf-8");
425
+ stub = fs3.readFileSync(p, "utf-8");
262
426
  break;
263
427
  } catch {
264
428
  }
265
429
  }
266
430
  if (!stub) return false;
267
431
  stub = stub.replace("{agentDisplayName}", this.manifest.displayName);
268
- fs.mkdirSync(path.dirname(targetPath), { recursive: true });
269
- fs.writeFileSync(targetPath, stub, "utf-8");
432
+ fs3.mkdirSync(path3.dirname(targetPath), { recursive: true });
433
+ fs3.writeFileSync(targetPath, stub, "utf-8");
270
434
  return true;
271
435
  }
272
436
  /**
@@ -277,15 +441,15 @@ var SymbiontInstaller = class {
277
441
  uninstallInstructions() {
278
442
  const reg = this.manifest.registration;
279
443
  if (!reg?.instructionsFile) return false;
280
- const targetPath = path.join(this.projectRoot, reg.instructionsFile);
444
+ const targetPath = path3.join(this.projectRoot, reg.instructionsFile);
281
445
  let content;
282
446
  try {
283
- content = fs.readFileSync(targetPath, "utf-8");
447
+ content = fs3.readFileSync(targetPath, "utf-8");
284
448
  } catch {
285
449
  return false;
286
450
  }
287
451
  if (content.includes(INSTRUCTIONS_STUB_MARKER)) {
288
- fs.unlinkSync(targetPath);
452
+ fs3.unlinkSync(targetPath);
289
453
  return true;
290
454
  }
291
455
  if (content.includes(INSTRUCTIONS_REF_START)) {
@@ -294,7 +458,7 @@ var SymbiontInstaller = class {
294
458
  if (endIdx > startIdx) {
295
459
  const afterEnd = endIdx + INSTRUCTIONS_REF_END.length;
296
460
  const cleaned = (content.slice(0, startIdx) + content.slice(afterEnd)).replace(/^\n+/, "");
297
- fs.writeFileSync(targetPath, cleaned, "utf-8");
461
+ fs3.writeFileSync(targetPath, cleaned, "utf-8");
298
462
  return true;
299
463
  }
300
464
  }
@@ -303,7 +467,7 @@ var SymbiontInstaller = class {
303
467
  /** List skill directory names from the package root. Returns empty array if not found. */
304
468
  listSkillDirs() {
305
469
  try {
306
- return fs.readdirSync(path.join(this.packageRoot, SKILLS_SUBDIR), { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
470
+ return fs3.readdirSync(path3.join(this.packageRoot, SKILLS_SUBDIR), { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
307
471
  } catch {
308
472
  return [];
309
473
  }
@@ -319,13 +483,12 @@ var SymbiontInstaller = class {
319
483
  const skillNames = this.listSkillDirs();
320
484
  const desired = [
321
485
  ...skillNames.map((name) => `${CANONICAL_SKILLS_DIR}/${name}`),
322
- ...reg.skillsTarget !== CANONICAL_SKILLS_DIR ? skillNames.map((name) => `${reg.skillsTarget}/${name}`) : [],
323
486
  WRANGLER_CACHE_DIR
324
487
  ];
325
- const gitignorePath = path.join(this.projectRoot, ".gitignore");
488
+ const gitignorePath = path3.join(this.projectRoot, ".gitignore");
326
489
  let content = "";
327
490
  try {
328
- content = fs.readFileSync(gitignorePath, "utf-8");
491
+ content = fs3.readFileSync(gitignorePath, "utf-8");
329
492
  } catch {
330
493
  }
331
494
  const stripped = this.stripMycoGitignoreBlock(content, skillNames);
@@ -337,7 +500,7 @@ ${desired.join("\n")}
337
500
  const spacer = stripped.length > 0 && desiredBlock.length > 0 ? "\n" : "";
338
501
  const result = stripped + separator + spacer + desiredBlock;
339
502
  if (result === content) return;
340
- fs.writeFileSync(gitignorePath, result, "utf-8");
503
+ fs3.writeFileSync(gitignorePath, result, "utf-8");
341
504
  }
342
505
  /**
343
506
  * Remove all Myco-owned gitignore entries: the comment header, per-skill
@@ -372,7 +535,7 @@ ${desired.join("\n")}
372
535
  if (!reg?.hooksTarget) return false;
373
536
  const template = this.loadTemplate("hooks");
374
537
  if (!template) return false;
375
- const targetPath = path.join(this.projectRoot, reg.hooksTarget);
538
+ const targetPath = path3.join(this.projectRoot, reg.hooksTarget);
376
539
  const settings = readJsonFile(targetPath);
377
540
  const existingHooks = settings.hooks ?? {};
378
541
  const mergedHooks = {};
@@ -400,7 +563,7 @@ ${desired.join("\n")}
400
563
  if (!reg?.mcpTarget) return false;
401
564
  const template = this.loadTemplate("mcp");
402
565
  if (!template) return false;
403
- const targetPath = path.join(this.projectRoot, reg.mcpTarget);
566
+ const targetPath = path3.join(this.projectRoot, reg.mcpTarget);
404
567
  const mcpFormat = reg.mcpFormat ?? "json";
405
568
  if (mcpFormat === "toml") {
406
569
  return this.installMcpToml(targetPath, template);
@@ -422,14 +585,14 @@ ${desired.join("\n")}
422
585
  installMcpToml(targetPath, template) {
423
586
  let raw = "";
424
587
  try {
425
- raw = fs.readFileSync(targetPath, "utf-8");
588
+ raw = fs3.readFileSync(targetPath, "utf-8");
426
589
  } catch {
427
590
  }
428
591
  for (const [name, def] of Object.entries(template)) {
429
592
  raw = buildTomlMcpSection(raw, name, def);
430
593
  }
431
- fs.mkdirSync(path.dirname(targetPath), { recursive: true });
432
- fs.writeFileSync(targetPath, raw, "utf-8");
594
+ fs3.mkdirSync(path3.dirname(targetPath), { recursive: true });
595
+ fs3.writeFileSync(targetPath, raw, "utf-8");
433
596
  return true;
434
597
  }
435
598
  /**
@@ -442,23 +605,24 @@ ${desired.join("\n")}
442
605
  if (!reg?.skillsTarget) return false;
443
606
  const skillNames = this.listSkillDirs();
444
607
  if (skillNames.length === 0) return false;
445
- const skillsSrc = path.join(this.packageRoot, SKILLS_SUBDIR);
446
- const canonicalDir = path.join(this.projectRoot, CANONICAL_SKILLS_DIR);
447
- fs.mkdirSync(canonicalDir, { recursive: true });
608
+ const skillsSrc = path3.join(this.packageRoot, SKILLS_SUBDIR);
609
+ const canonicalDir = path3.join(this.projectRoot, CANONICAL_SKILLS_DIR);
610
+ fs3.mkdirSync(canonicalDir, { recursive: true });
448
611
  for (const name of skillNames) {
449
- const canonicalLink = path.join(canonicalDir, name);
450
- const target = path.join(skillsSrc, name);
612
+ const canonicalLink = path3.join(canonicalDir, name);
613
+ const target = path3.join(skillsSrc, name);
451
614
  ensureSymlink(canonicalLink, target);
452
615
  }
453
- const agentSkillsDir = path.join(this.projectRoot, reg.skillsTarget);
454
- const canonicalRel = path.relative(agentSkillsDir, canonicalDir);
616
+ const agentSkillsDir = path3.join(this.projectRoot, reg.skillsTarget);
617
+ const canonicalRel = path3.relative(agentSkillsDir, canonicalDir);
455
618
  if (reg.skillsTarget !== CANONICAL_SKILLS_DIR) {
456
- fs.mkdirSync(agentSkillsDir, { recursive: true });
619
+ fs3.mkdirSync(agentSkillsDir, { recursive: true });
457
620
  for (const name of skillNames) {
458
- const agentLink = path.join(agentSkillsDir, name);
459
- const relTarget = path.join(canonicalRel, name);
621
+ const agentLink = path3.join(agentSkillsDir, name);
622
+ const relTarget = path3.join(canonicalRel, name);
460
623
  ensureSymlink(agentLink, relTarget);
461
624
  }
625
+ ensureLocalSkillsGitignore(agentSkillsDir);
462
626
  }
463
627
  return true;
464
628
  }
@@ -471,7 +635,7 @@ ${desired.join("\n")}
471
635
  if (!reg?.settingsTarget) return false;
472
636
  const template = this.loadTemplate("settings");
473
637
  if (!template) return false;
474
- const targetPath = path.join(this.projectRoot, reg.settingsTarget);
638
+ const targetPath = path3.join(this.projectRoot, reg.settingsTarget);
475
639
  const existing = readJsonFile(targetPath);
476
640
  const merged = deepMergeSettings(existing, template);
477
641
  writeJsonFile(targetPath, merged);
@@ -488,7 +652,7 @@ ${desired.join("\n")}
488
652
  if (!reg?.settingsTarget) return false;
489
653
  const template = this.loadTemplate("settings");
490
654
  if (!template) return false;
491
- const targetPath = path.join(this.projectRoot, reg.settingsTarget);
655
+ const targetPath = path3.join(this.projectRoot, reg.settingsTarget);
492
656
  const settings = readJsonFile(targetPath);
493
657
  if (Object.keys(settings).length === 0) return false;
494
658
  const changed = deepRemoveSettings(settings, template);
@@ -500,7 +664,7 @@ ${desired.join("\n")}
500
664
  uninstallHooks() {
501
665
  const reg = this.manifest.registration;
502
666
  if (!reg?.hooksTarget) return false;
503
- const targetPath = path.join(this.projectRoot, reg.hooksTarget);
667
+ const targetPath = path3.join(this.projectRoot, reg.hooksTarget);
504
668
  const settings = readJsonFile(targetPath);
505
669
  const existingHooks = settings.hooks ?? {};
506
670
  if (Object.keys(existingHooks).length === 0) return false;
@@ -525,7 +689,7 @@ ${desired.join("\n")}
525
689
  uninstallMcp() {
526
690
  const reg = this.manifest.registration;
527
691
  if (!reg?.mcpTarget) return false;
528
- const targetPath = path.join(this.projectRoot, reg.mcpTarget);
692
+ const targetPath = path3.join(this.projectRoot, reg.mcpTarget);
529
693
  const mcpFormat = reg.mcpFormat ?? "json";
530
694
  if (mcpFormat === "toml") {
531
695
  return this.uninstallMcpToml(targetPath);
@@ -548,7 +712,7 @@ ${desired.join("\n")}
548
712
  uninstallMcpToml(targetPath) {
549
713
  let raw = "";
550
714
  try {
551
- raw = fs.readFileSync(targetPath, "utf-8");
715
+ raw = fs3.readFileSync(targetPath, "utf-8");
552
716
  } catch {
553
717
  return false;
554
718
  }
@@ -561,11 +725,11 @@ ${desired.join("\n")}
561
725
  const updated = (before + (before && after ? "\n\n" : "") + after).trimEnd();
562
726
  if (!updated.trim()) {
563
727
  try {
564
- fs.unlinkSync(targetPath);
728
+ fs3.unlinkSync(targetPath);
565
729
  } catch {
566
730
  }
567
731
  } else {
568
- fs.writeFileSync(targetPath, updated + "\n", "utf-8");
732
+ fs3.writeFileSync(targetPath, updated + "\n", "utf-8");
569
733
  }
570
734
  return true;
571
735
  }
@@ -578,214 +742,69 @@ ${desired.join("\n")}
578
742
  let removed = false;
579
743
  if (reg.skillsTarget !== CANONICAL_SKILLS_DIR) {
580
744
  for (const name of skillNames) {
581
- const link = path.join(this.projectRoot, reg.skillsTarget, name);
745
+ const link = path3.join(this.projectRoot, reg.skillsTarget, name);
582
746
  try {
583
- fs.unlinkSync(link);
747
+ fs3.unlinkSync(link);
584
748
  removed = true;
585
749
  } catch {
586
750
  }
587
751
  }
588
752
  try {
589
- fs.rmdirSync(path.join(this.projectRoot, reg.skillsTarget));
753
+ fs3.rmdirSync(path3.join(this.projectRoot, reg.skillsTarget));
590
754
  } catch {
591
755
  }
592
756
  }
593
- const canonicalDir = path.join(this.projectRoot, CANONICAL_SKILLS_DIR);
757
+ const canonicalDir = path3.join(this.projectRoot, CANONICAL_SKILLS_DIR);
594
758
  for (const name of skillNames) {
595
- const link = path.join(canonicalDir, name);
759
+ const link = path3.join(canonicalDir, name);
596
760
  try {
597
- fs.unlinkSync(link);
761
+ fs3.unlinkSync(link);
598
762
  removed = true;
599
763
  } catch {
600
764
  }
601
765
  }
602
766
  try {
603
- fs.rmdirSync(canonicalDir);
767
+ fs3.rmdirSync(canonicalDir);
604
768
  } catch {
605
769
  }
606
770
  try {
607
- fs.rmdirSync(path.join(this.projectRoot, ".agents"));
771
+ fs3.rmdirSync(path3.join(this.projectRoot, ".agents"));
608
772
  } catch {
609
773
  }
610
774
  return removed;
611
775
  }
612
776
  /** Remove Myco entries from project .gitignore. */
613
777
  cleanGitignore() {
614
- const gitignorePath = path.join(this.projectRoot, ".gitignore");
778
+ const gitignorePath = path3.join(this.projectRoot, ".gitignore");
615
779
  let content = "";
616
780
  try {
617
- content = fs.readFileSync(gitignorePath, "utf-8");
781
+ content = fs3.readFileSync(gitignorePath, "utf-8");
618
782
  } catch {
619
783
  return;
620
784
  }
621
785
  const cleaned = this.stripMycoGitignoreBlock(content, this.listSkillDirs()).trim();
622
786
  if (cleaned) {
623
- fs.writeFileSync(gitignorePath, cleaned + "\n", "utf-8");
787
+ fs3.writeFileSync(gitignorePath, cleaned + "\n", "utf-8");
624
788
  } else {
625
789
  try {
626
- fs.unlinkSync(gitignorePath);
790
+ fs3.unlinkSync(gitignorePath);
627
791
  } catch {
628
792
  }
629
793
  }
630
794
  }
631
795
  };
632
- var TOML_SECTION_RE = /^\[([^\]]+)\]/;
633
- function findTomlSectionEnd(raw, searchStart, serverName) {
634
- const subsectionPrefix = `mcp_servers.${serverName}.`;
635
- const rawLines = raw.slice(searchStart).split("\n");
636
- let offset = searchStart;
637
- for (const line of rawLines) {
638
- offset += line.length + 1;
639
- const m = line.match(TOML_SECTION_RE);
640
- if (m && !m[1].startsWith(subsectionPrefix) && m[1] !== `mcp_servers.${serverName}`) {
641
- return offset - line.length - 1;
642
- }
643
- }
644
- return raw.length;
645
- }
646
- function buildTomlMcpSection(raw, serverName, server) {
647
- const sectionHeader = `[mcp_servers.${serverName}]`;
648
- const lines = [sectionHeader];
649
- for (const [key, val] of Object.entries(server)) {
650
- if (key === "env" && typeof val === "object" && val !== null) continue;
651
- if (typeof val === "string") {
652
- lines.push(`${key} = "${val}"`);
653
- } else if (Array.isArray(val)) {
654
- lines.push(`${key} = [${val.map((v) => `"${v}"`).join(", ")}]`);
655
- } else if (typeof val === "boolean") {
656
- lines.push(`${key} = ${val}`);
657
- }
658
- }
659
- const env = server.env;
660
- if (env && Object.keys(env).length > 0) {
661
- lines.push("");
662
- lines.push(`[mcp_servers.${serverName}.env]`);
663
- for (const [key, val] of Object.entries(env)) {
664
- lines.push(`${key} = "${val}"`);
665
- }
666
- }
667
- const block = lines.join("\n");
668
- let updated;
669
- if (raw.includes(sectionHeader)) {
670
- const startIdx = raw.indexOf(sectionHeader);
671
- const endIdx = findTomlSectionEnd(raw, startIdx + sectionHeader.length, serverName);
672
- const before = raw.slice(0, startIdx).trimEnd();
673
- const after = raw.slice(endIdx);
674
- const separator = before ? "\n\n" : "";
675
- updated = (before + separator + block + after).trimEnd() + "\n";
676
- } else {
677
- const separator = raw.trim() ? "\n\n" : "";
678
- updated = (raw.trimEnd() + separator + block).trimEnd() + "\n";
679
- }
680
- return updated;
681
- }
682
- function deepMergeSettings(target, source) {
683
- const result = { ...target };
684
- for (const [key, sourceVal] of Object.entries(source)) {
685
- const targetVal = result[key];
686
- if (Array.isArray(sourceVal) && Array.isArray(targetVal)) {
687
- result[key] = [.../* @__PURE__ */ new Set([...targetVal, ...sourceVal])];
688
- } else if (isPlainObject(sourceVal) && isPlainObject(targetVal)) {
689
- result[key] = deepMergeSettings(
690
- targetVal,
691
- sourceVal
692
- );
693
- } else {
694
- result[key] = sourceVal;
695
- }
696
- }
697
- return result;
698
- }
699
- function isPlainObject(val) {
700
- return typeof val === "object" && val !== null && !Array.isArray(val);
701
- }
702
- function deepRemoveSettings(target, template) {
703
- let changed = false;
704
- for (const [key, templateVal] of Object.entries(template)) {
705
- const targetVal = target[key];
706
- if (targetVal === void 0) continue;
707
- if (Array.isArray(templateVal) && Array.isArray(targetVal)) {
708
- const templateSet = new Set(templateVal.map(String));
709
- const filtered = targetVal.filter((v) => !templateSet.has(String(v)));
710
- if (filtered.length !== targetVal.length) {
711
- if (filtered.length > 0) {
712
- target[key] = filtered;
713
- } else {
714
- delete target[key];
715
- }
716
- changed = true;
717
- }
718
- } else if (isPlainObject(templateVal) && isPlainObject(targetVal)) {
719
- if (deepRemoveSettings(targetVal, templateVal)) {
720
- if (Object.keys(targetVal).length === 0) {
721
- delete target[key];
722
- }
723
- changed = true;
724
- }
725
- } else {
726
- if (String(targetVal) === String(templateVal)) {
727
- delete target[key];
728
- changed = true;
729
- }
730
- }
731
- }
732
- return changed;
733
- }
734
- function readJsonFile(filePath) {
735
- try {
736
- return JSON.parse(fs.readFileSync(filePath, "utf-8"));
737
- } catch {
738
- return {};
739
- }
740
- }
741
- function writeJsonFile(filePath, data) {
742
- fs.mkdirSync(path.dirname(filePath), { recursive: true });
743
- fs.writeFileSync(filePath, JSON.stringify(data, null, 2) + "\n", "utf-8");
744
- }
745
- function writeOrDeleteJsonFile(filePath, data) {
746
- if (Object.keys(data).length === 0) {
747
- try {
748
- fs.unlinkSync(filePath);
749
- } catch {
750
- }
751
- } else {
752
- writeJsonFile(filePath, data);
753
- }
754
- }
755
- function ensureAgentsMd(projectRoot, packageRoot) {
756
- const agentsMdPath = path.join(projectRoot, "AGENTS.md");
757
- if (fs.existsSync(agentsMdPath)) return;
796
+ function syncSkillSymlinks(projectRoot, skillName, opts) {
797
+ const selfDir = path3.dirname(new URL(import.meta.url).pathname);
758
798
  const candidates = [
759
- path.join(packageRoot, "src/symbionts/templates/agents-starter.md"),
760
- path.join(packageRoot, "dist/src/symbionts/templates/agents-starter.md")
799
+ path3.join(selfDir, "manifests"),
800
+ path3.join(selfDir, "src", "symbionts", "manifests")
761
801
  ];
762
- for (const p of candidates) {
763
- try {
764
- const content = fs.readFileSync(p, "utf-8");
765
- fs.writeFileSync(agentsMdPath, content, "utf-8");
766
- return;
767
- } catch {
768
- }
769
- }
770
- }
771
- function ensureSymlink(linkPath, target) {
772
- try {
773
- if (fs.readlinkSync(linkPath) === target) return;
774
- } catch {
775
- }
776
- try {
777
- fs.rmSync(linkPath, { recursive: true, force: true });
778
- } catch {
779
- }
780
- fs.symlinkSync(target, linkPath);
781
- }
782
- function syncSkillSymlinks(projectRoot, skillName, opts) {
783
- const manifestDir = path.join(path.dirname(new URL(import.meta.url).pathname), "manifests");
784
- if (!fs.existsSync(manifestDir)) return;
802
+ const manifestDir = candidates.find((d) => fs3.existsSync(d));
803
+ if (!manifestDir) return;
785
804
  const targets = /* @__PURE__ */ new Set();
786
- for (const file of fs.readdirSync(manifestDir).filter((f) => f.endsWith(".yaml"))) {
805
+ for (const file of fs3.readdirSync(manifestDir).filter((f) => f.endsWith(".yaml"))) {
787
806
  try {
788
- const content = fs.readFileSync(path.join(manifestDir, file), "utf-8");
807
+ const content = fs3.readFileSync(path3.join(manifestDir, file), "utf-8");
789
808
  const match = content.match(/skillsTarget:\s*(.+)/);
790
809
  if (match) targets.add(match[1].trim());
791
810
  } catch {
@@ -793,29 +812,46 @@ function syncSkillSymlinks(projectRoot, skillName, opts) {
793
812
  }
794
813
  for (const target of targets) {
795
814
  if (target === CANONICAL_SKILLS_DIR) continue;
796
- const agentSkillsDir = path.join(projectRoot, target);
797
- const linkPath = path.join(agentSkillsDir, skillName);
815
+ const agentSkillsDir = path3.join(projectRoot, target);
816
+ const linkPath = path3.join(agentSkillsDir, skillName);
798
817
  if (opts?.remove) {
799
818
  try {
800
- fs.unlinkSync(linkPath);
819
+ fs3.unlinkSync(linkPath);
801
820
  } catch {
802
821
  }
803
822
  try {
804
- fs.rmdirSync(agentSkillsDir);
823
+ fs3.rmdirSync(agentSkillsDir);
805
824
  } catch {
806
825
  }
807
826
  } else {
808
- fs.mkdirSync(agentSkillsDir, { recursive: true });
809
- const canonicalDir = path.join(projectRoot, CANONICAL_SKILLS_DIR);
810
- const relTarget = path.join(path.relative(agentSkillsDir, canonicalDir), skillName);
827
+ fs3.mkdirSync(agentSkillsDir, { recursive: true });
828
+ const canonicalDir = path3.join(projectRoot, CANONICAL_SKILLS_DIR);
829
+ const relTarget = path3.join(path3.relative(agentSkillsDir, canonicalDir), skillName);
811
830
  ensureSymlink(linkPath, relTarget);
831
+ ensureLocalSkillsGitignore(agentSkillsDir);
812
832
  }
813
833
  }
814
834
  }
835
+ var LOCAL_SKILLS_GITIGNORE = `# Myco-managed symlinks \u2014 generated skills are symlinked here automatically.
836
+ # The canonical location for all skills is .agents/skills/.
837
+ #
838
+ # To add your own skill to this directory, un-ignore it:
839
+ # !my-skill
840
+ *
841
+ !.gitignore
842
+ `;
843
+ function ensureLocalSkillsGitignore(agentSkillsDir) {
844
+ const gitignorePath = path3.join(agentSkillsDir, ".gitignore");
845
+ try {
846
+ if (fs3.readFileSync(gitignorePath, "utf-8") === LOCAL_SKILLS_GITIGNORE) return;
847
+ } catch {
848
+ }
849
+ fs3.writeFileSync(gitignorePath, LOCAL_SKILLS_GITIGNORE, "utf-8");
850
+ }
815
851
 
816
852
  export {
817
853
  MYCO_MCP_SERVER_NAME,
818
854
  SymbiontInstaller,
819
855
  syncSkillSymlinks
820
856
  };
821
- //# sourceMappingURL=chunk-TNCBMGWB.js.map
857
+ //# sourceMappingURL=chunk-X5IXK5KO.js.map