skill-tree 0.2.0 → 0.3.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 (130) hide show
  1. package/README.md +75 -0
  2. package/dist/bowser-CQI7RKRA.mjs +2821 -0
  3. package/dist/bowser-XBWM4HVL.mjs +2821 -0
  4. package/dist/chunk-2NL4MXNX.mjs +3156 -0
  5. package/dist/chunk-2STDJU5Y.mjs +1174 -0
  6. package/dist/chunk-3BCRI4CA.mjs +101 -0
  7. package/dist/chunk-3MV4GQ3N.mjs +19 -0
  8. package/dist/chunk-3SRB47JW.mjs +8344 -0
  9. package/dist/chunk-43YOKLZP.mjs +6081 -0
  10. package/dist/chunk-4AGZU52D.mjs +7918 -0
  11. package/dist/chunk-4HXHCEFH.mjs +9157 -0
  12. package/dist/chunk-4OC5QFIF.mjs +11267 -0
  13. package/dist/chunk-4QGSDVGH.mjs +580 -0
  14. package/dist/chunk-4TFMKAVC.mjs +1225 -0
  15. package/dist/chunk-55SMGVTP.mjs +7126 -0
  16. package/dist/chunk-5C4MEQMR.mjs +125 -0
  17. package/dist/chunk-6AZMD3Q3.mjs +1243 -0
  18. package/dist/chunk-6FX4IK4Z.mjs +5368 -0
  19. package/dist/chunk-6UPDN5QM.mjs +163 -0
  20. package/dist/chunk-7EGDKOHV.mjs +9439 -0
  21. package/dist/chunk-7IHYDFWW.mjs +163 -0
  22. package/dist/chunk-7LMOQW5H.mjs +4893 -0
  23. package/dist/chunk-7QIQJVNP.mjs +14206 -0
  24. package/dist/chunk-7VB4ZRZO.mjs +7127 -0
  25. package/dist/chunk-A3SILZYX.mjs +8360 -0
  26. package/dist/chunk-BPVRW25O.mjs +6089 -0
  27. package/dist/chunk-BZ2JKJ54.mjs +1057 -0
  28. package/dist/chunk-CI4476KM.mjs +6607 -0
  29. package/dist/chunk-DCRKELD5.mjs +46 -0
  30. package/dist/chunk-DDXYQ74I.mjs +13969 -0
  31. package/dist/chunk-DQOFJXBX.mjs +6595 -0
  32. package/dist/chunk-E2CVK23F.mjs +8751 -0
  33. package/dist/chunk-F3YEUQAP.mjs +654 -0
  34. package/dist/chunk-FKJJ4RJG.mjs +13874 -0
  35. package/dist/chunk-GBIK7WMX.mjs +9293 -0
  36. package/dist/chunk-GFK5SZRJ.mjs +580 -0
  37. package/dist/chunk-GPN6UQVR.mjs +9238 -0
  38. package/dist/chunk-II7DECZQ.mjs +9111 -0
  39. package/dist/chunk-INKVOZXK.mjs +15898 -0
  40. package/dist/chunk-J2JM7HAK.mjs +8787 -0
  41. package/dist/chunk-K6NRCSAZ.mjs +4355 -0
  42. package/dist/chunk-LACI6YL4.mjs +1379 -0
  43. package/dist/chunk-M4RPUUZT.mjs +3156 -0
  44. package/dist/chunk-MBF2MJS5.mjs +1230 -0
  45. package/dist/chunk-MBIGW6KU.mjs +644 -0
  46. package/dist/chunk-MR4TVINH.mjs +1234 -0
  47. package/dist/chunk-OOECXYLU.mjs +1379 -0
  48. package/dist/chunk-OYHYXKXO.mjs +7297 -0
  49. package/dist/chunk-P5GJJ4JB.mjs +9237 -0
  50. package/dist/chunk-PDPN7FW7.mjs +1045 -0
  51. package/dist/chunk-PJJJQXJL.mjs +1174 -0
  52. package/dist/chunk-PK3BAIFW.mjs +9294 -0
  53. package/dist/chunk-QNK3WYNA.mjs +8971 -0
  54. package/dist/chunk-QZ7TP4HQ.mjs +7 -0
  55. package/dist/chunk-RJYJGJO3.mjs +349 -0
  56. package/dist/chunk-T4PVQW5O.mjs +124 -0
  57. package/dist/chunk-TENXZJB3.mjs +349 -0
  58. package/dist/chunk-TEUB6DZR.mjs +6453 -0
  59. package/dist/chunk-TWPEHDW4.mjs +1067 -0
  60. package/dist/chunk-VHFTX33A.mjs +6724 -0
  61. package/dist/chunk-VNZSS2WY.mjs +1057 -0
  62. package/dist/chunk-WJP5XYS7.mjs +2102 -0
  63. package/dist/chunk-WX6N7KNO.mjs +1239 -0
  64. package/dist/chunk-Y54UK2J3.mjs +13071 -0
  65. package/dist/chunk-YDNGMDXC.mjs +9294 -0
  66. package/dist/chunk-YDVZIFIU.mjs +2102 -0
  67. package/dist/chunk-YJ6NZQLT.mjs +9237 -0
  68. package/dist/chunk-YWRKGXK4.mjs +9300 -0
  69. package/dist/chunk-ZI4AIAWQ.mjs +46 -0
  70. package/dist/chunk-ZQVS7MQK.mjs +6081 -0
  71. package/dist/chunk-ZYKRDDFO.mjs +163 -0
  72. package/dist/cli/index.js +1173 -324
  73. package/dist/cli/index.mjs +202 -9164
  74. package/dist/dist-es-27NPMXP7.mjs +22 -0
  75. package/dist/dist-es-2JG6ZWFR.mjs +69 -0
  76. package/dist/dist-es-2JGXQKUP.mjs +6077 -0
  77. package/dist/dist-es-5QD5QJS2.mjs +495 -0
  78. package/dist/dist-es-5ZD454R2.mjs +317 -0
  79. package/dist/dist-es-644EP2LP.mjs +317 -0
  80. package/dist/dist-es-DSNCHWLJ.mjs +170 -0
  81. package/dist/dist-es-DYHMPEKZ.mjs +170 -0
  82. package/dist/dist-es-FIVW7BUZ.mjs +317 -0
  83. package/dist/dist-es-GXJAFBE5.mjs +22 -0
  84. package/dist/dist-es-HRBPKDMR.mjs +935 -0
  85. package/dist/dist-es-L5AMJHSY.mjs +935 -0
  86. package/dist/dist-es-LHPJ63IO.mjs +4437 -0
  87. package/dist/dist-es-LT2AQAG7.mjs +4437 -0
  88. package/dist/dist-es-OK2J7EV3.mjs +378 -0
  89. package/dist/dist-es-ORE4PQTL.mjs +87 -0
  90. package/dist/dist-es-TLCYJJ25.mjs +495 -0
  91. package/dist/dist-es-V4LHTSRG.mjs +69 -0
  92. package/dist/dist-es-XFAHNA2L.mjs +69 -0
  93. package/dist/dist-es-XHTU3ZU2.mjs +935 -0
  94. package/dist/dist-es-XPNJAJI7.mjs +4437 -0
  95. package/dist/dist-es-Y2MPJ6IO.mjs +378 -0
  96. package/dist/dist-es-Y4JPNLF3.mjs +6077 -0
  97. package/dist/dist-es-ZGPJUGVW.mjs +87 -0
  98. package/dist/dist-es-ZYHLY2E6.mjs +487 -0
  99. package/dist/event-streams-6MFHPNRF.mjs +42 -0
  100. package/dist/event-streams-KIAAAC7Z.mjs +42 -0
  101. package/dist/index.d.mts +1189 -13
  102. package/dist/index.d.ts +1189 -13
  103. package/dist/index.js +38737 -601
  104. package/dist/index.mjs +131 -9693
  105. package/dist/lib-B245IUXF.mjs +778 -0
  106. package/dist/loadSso-CAWKILED.mjs +579 -0
  107. package/dist/loadSso-NPRY7QRT.mjs +579 -0
  108. package/dist/loadSso-OYKG6ZRE.mjs +579 -0
  109. package/dist/signin-KUENA7ZD.mjs +743 -0
  110. package/dist/signin-LMFNL434.mjs +665 -0
  111. package/dist/signin-LUKXFXSI.mjs +743 -0
  112. package/dist/sqlite-5LHEQTBD.mjs +7 -0
  113. package/dist/sqlite-BZK5GF76.mjs +7 -0
  114. package/dist/sqlite-MG45OOTV.mjs +6 -0
  115. package/dist/sqlite-OLU72GHB.mjs +6 -0
  116. package/dist/sqlite-RR2SJ3SR.mjs +7 -0
  117. package/dist/sqlite-V6GFGHTD.mjs +7 -0
  118. package/dist/sqlite-XJRPMNAJ.mjs +6 -0
  119. package/dist/sqlite-ZKQKQKPT.mjs +7 -0
  120. package/dist/sso-oidc-3VGFPMFD.mjs +832 -0
  121. package/dist/sso-oidc-NNH6SQIH.mjs +832 -0
  122. package/dist/sso-oidc-STZH2XK2.mjs +832 -0
  123. package/dist/sts-EF755UBF.mjs +6290 -0
  124. package/dist/sts-QGXULWRT.mjs +6290 -0
  125. package/dist/sts-ZIS4G6FQ.mjs +6290 -0
  126. package/dist/sync-4DCV43GA.mjs +15 -0
  127. package/dist/sync-BSWMMDA6.mjs +14 -0
  128. package/dist/sync-WHIIDHML.mjs +14 -0
  129. package/dist/sync-XRWFQYBY.mjs +15 -0
  130. package/package.json +9 -2
@@ -0,0 +1,644 @@
1
+ // src/agents/sync.ts
2
+ import * as fs from "fs";
3
+ import * as path from "path";
4
+
5
+ // src/agents/types.ts
6
+ var DEFAULT_AGENTS_CONFIG = {
7
+ format: "xml",
8
+ includeIds: true,
9
+ includeVersions: true,
10
+ groupByTags: false
11
+ };
12
+
13
+ // src/agents/generator.ts
14
+ var AgentsGenerator = class {
15
+ constructor(config) {
16
+ this.config = { ...DEFAULT_AGENTS_CONFIG, ...config };
17
+ }
18
+ /**
19
+ * Generate AGENTS.md content from a skill bank
20
+ */
21
+ async generate(storage) {
22
+ let skills = await storage.listSkills({
23
+ status: this.config.filter?.status || ["active"]
24
+ });
25
+ skills = this.filterSkills(skills, this.config.filter);
26
+ skills.sort((a, b) => a.name.localeCompare(b.name));
27
+ const sections = [];
28
+ if (this.config.header) {
29
+ sections.push(this.config.header);
30
+ } else {
31
+ sections.push(this.generateDefaultHeader());
32
+ }
33
+ if (this.config.groupByTags) {
34
+ sections.push(this.generateGroupedSkills(skills));
35
+ } else {
36
+ sections.push(this.generateSkillsList(skills));
37
+ }
38
+ if (this.config.footer) {
39
+ sections.push(this.config.footer);
40
+ }
41
+ return sections.join("\n\n");
42
+ }
43
+ /**
44
+ * Generate content for a single skill
45
+ */
46
+ generateSkill(skill) {
47
+ switch (this.config.format) {
48
+ case "xml":
49
+ return this.generateXmlSkill(skill);
50
+ case "markdown":
51
+ return this.generateMarkdownSkill(skill);
52
+ case "json":
53
+ return this.generateJsonSkill(skill);
54
+ default:
55
+ return this.generateXmlSkill(skill);
56
+ }
57
+ }
58
+ /**
59
+ * Generate skills list
60
+ */
61
+ generateSkillsList(skills) {
62
+ return skills.map((skill) => this.generateSkill(skill)).join("\n\n");
63
+ }
64
+ /**
65
+ * Generate skills grouped by tags
66
+ */
67
+ generateGroupedSkills(skills) {
68
+ const tagGroups = /* @__PURE__ */ new Map();
69
+ const untagged = [];
70
+ for (const skill of skills) {
71
+ if (skill.tags.length === 0) {
72
+ untagged.push(skill);
73
+ } else {
74
+ const primaryTag = skill.tags[0];
75
+ if (!tagGroups.has(primaryTag)) {
76
+ tagGroups.set(primaryTag, []);
77
+ }
78
+ tagGroups.get(primaryTag).push(skill);
79
+ }
80
+ }
81
+ const sections = [];
82
+ const sortedTags = Array.from(tagGroups.keys()).sort();
83
+ for (const tag of sortedTags) {
84
+ const tagSkills = tagGroups.get(tag);
85
+ sections.push(`## ${this.formatTagName(tag)}
86
+
87
+ ${this.generateSkillsList(tagSkills)}`);
88
+ }
89
+ if (untagged.length > 0) {
90
+ sections.push(`## Other
91
+
92
+ ${this.generateSkillsList(untagged)}`);
93
+ }
94
+ return sections.join("\n\n");
95
+ }
96
+ /**
97
+ * Generate XML format skill (Claude Code native format)
98
+ */
99
+ generateXmlSkill(skill) {
100
+ const lines = [];
101
+ const attrs = [];
102
+ if (this.config.includeIds) {
103
+ attrs.push(`id="${this.escapeXml(skill.id)}"`);
104
+ }
105
+ if (this.config.includeVersions) {
106
+ attrs.push(`version="${this.escapeXml(skill.version)}"`);
107
+ }
108
+ const attrStr = attrs.length > 0 ? ` ${attrs.join(" ")}` : "";
109
+ lines.push(`<skill${attrStr}>`);
110
+ lines.push(` <name>${this.escapeXml(skill.name)}</name>`);
111
+ if (skill.description) {
112
+ lines.push(` <description>${this.escapeXml(skill.description)}</description>`);
113
+ }
114
+ if (skill.instructions) {
115
+ lines.push(` <content>
116
+ ${this.indentContent(skill.instructions, 4)}
117
+ </content>`);
118
+ }
119
+ if (skill.tags.length > 0) {
120
+ lines.push(` <tags>${skill.tags.map((t) => this.escapeXml(t)).join(", ")}</tags>`);
121
+ }
122
+ lines.push("</skill>");
123
+ return lines.join("\n");
124
+ }
125
+ /**
126
+ * Generate Markdown format skill
127
+ */
128
+ generateMarkdownSkill(skill) {
129
+ const lines = [];
130
+ const idSuffix = this.config.includeIds ? ` {#${skill.id}}` : "";
131
+ const versionSuffix = this.config.includeVersions ? ` (v${skill.version})` : "";
132
+ lines.push(`### ${skill.name}${versionSuffix}${idSuffix}`);
133
+ lines.push("");
134
+ if (skill.description) {
135
+ lines.push(`*${skill.description}*`);
136
+ lines.push("");
137
+ }
138
+ if (skill.instructions) {
139
+ lines.push(skill.instructions);
140
+ lines.push("");
141
+ }
142
+ if (skill.tags.length > 0) {
143
+ lines.push(`Tags: ${skill.tags.map((t) => `\`${t}\``).join(", ")}`);
144
+ }
145
+ return lines.join("\n");
146
+ }
147
+ /**
148
+ * Generate JSON format skill
149
+ */
150
+ generateJsonSkill(skill) {
151
+ const obj = {
152
+ name: skill.name,
153
+ description: skill.description
154
+ };
155
+ if (this.config.includeIds) {
156
+ obj.id = skill.id;
157
+ }
158
+ if (this.config.includeVersions) {
159
+ obj.version = skill.version;
160
+ }
161
+ if (skill.instructions) {
162
+ obj.instructions = skill.instructions;
163
+ }
164
+ if (skill.tags.length > 0) {
165
+ obj.tags = skill.tags;
166
+ }
167
+ return "```json\n" + JSON.stringify(obj, null, 2) + "\n```";
168
+ }
169
+ /**
170
+ * Filter skills based on selector
171
+ */
172
+ filterSkills(skills, filter) {
173
+ if (!filter) return skills;
174
+ let result = skills;
175
+ if (filter.ids && filter.ids.length > 0) {
176
+ result = result.filter((s) => filter.ids.includes(s.id));
177
+ }
178
+ if (filter.tags && filter.tags.length > 0) {
179
+ result = result.filter((s) => s.tags.some((t) => filter.tags.includes(t)));
180
+ }
181
+ if (filter.limit) {
182
+ result = result.slice(0, filter.limit);
183
+ }
184
+ return result;
185
+ }
186
+ /**
187
+ * Generate default header
188
+ */
189
+ generateDefaultHeader() {
190
+ return `# Agent Skills
191
+
192
+ This file contains skills for the AI agent. Each skill describes a pattern for solving a specific type of problem.
193
+
194
+ ---`;
195
+ }
196
+ /**
197
+ * Format tag name for section header
198
+ */
199
+ formatTagName(tag) {
200
+ return tag.split("-").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
201
+ }
202
+ /**
203
+ * Escape XML special characters
204
+ */
205
+ escapeXml(str) {
206
+ return str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");
207
+ }
208
+ /**
209
+ * Indent content
210
+ */
211
+ indentContent(content, spaces) {
212
+ const indent = " ".repeat(spaces);
213
+ return content.split("\n").map((line) => indent + line).join("\n");
214
+ }
215
+ };
216
+ function createAgentsGenerator(config) {
217
+ return new AgentsGenerator(config);
218
+ }
219
+
220
+ // src/agents/parser.ts
221
+ var AgentsParser = class {
222
+ /**
223
+ * Parse AGENTS.md content
224
+ */
225
+ parse(content) {
226
+ const warnings = [];
227
+ const skills = [];
228
+ const xmlSkills = this.parseXmlSkills(content);
229
+ if (xmlSkills.length > 0) {
230
+ skills.push(...xmlSkills);
231
+ }
232
+ const mdSkills = this.parseMarkdownSkills(content, xmlSkills);
233
+ if (mdSkills.length > 0) {
234
+ const existingNames = new Set(skills.map((s) => s.name.toLowerCase()));
235
+ for (const skill of mdSkills) {
236
+ if (!existingNames.has(skill.name.toLowerCase())) {
237
+ skills.push(skill);
238
+ }
239
+ }
240
+ }
241
+ const header = this.extractHeader(content, skills);
242
+ const footer = this.extractFooter(content, skills);
243
+ if (skills.length === 0) {
244
+ warnings.push("No skills found in AGENTS.md");
245
+ }
246
+ return { header, skills, footer, warnings };
247
+ }
248
+ /**
249
+ * Convert parsed skill to Skill type
250
+ */
251
+ toSkill(parsed, defaults) {
252
+ const now = /* @__PURE__ */ new Date();
253
+ const id = parsed.id || this.generateId(parsed.name);
254
+ let instructions = parsed.instructions || "";
255
+ if (!instructions) {
256
+ const instructionParts = [];
257
+ if (parsed.problem) instructionParts.push(parsed.problem);
258
+ if (parsed.solution) instructionParts.push(parsed.solution);
259
+ if (parsed.verification) instructionParts.push(parsed.verification);
260
+ if (parsed.notes) instructionParts.push(parsed.notes);
261
+ instructions = instructionParts.length > 0 ? instructionParts.join("\n\n") : "";
262
+ }
263
+ return {
264
+ id,
265
+ name: parsed.name,
266
+ version: parsed.version || "1.0.0",
267
+ description: parsed.description || "",
268
+ instructions,
269
+ author: defaults?.author || "imported",
270
+ tags: parsed.tags || [],
271
+ createdAt: defaults?.createdAt || now,
272
+ updatedAt: now,
273
+ status: "active",
274
+ source: {
275
+ type: "imported",
276
+ location: "AGENTS.md",
277
+ importedAt: now
278
+ },
279
+ ...defaults
280
+ };
281
+ }
282
+ /**
283
+ * Parse XML format skills
284
+ */
285
+ parseXmlSkills(content) {
286
+ const skills = [];
287
+ const skillRegex = /<skill([^>]*)>([\s\S]*?)<\/skill>/gi;
288
+ let match;
289
+ while ((match = skillRegex.exec(content)) !== null) {
290
+ const attrs = match[1];
291
+ const body = match[2];
292
+ const skill = {
293
+ rawContent: match[0],
294
+ name: this.extractXmlTag(body, "name") || "Unnamed Skill",
295
+ description: this.extractXmlTag(body, "description") || ""
296
+ };
297
+ const idMatch = /id="([^"]+)"/.exec(attrs);
298
+ if (idMatch) {
299
+ skill.id = idMatch[1];
300
+ }
301
+ const versionMatch = /version="([^"]+)"/.exec(attrs);
302
+ if (versionMatch) {
303
+ skill.version = versionMatch[1];
304
+ }
305
+ const contentTag = this.extractXmlTag(body, "content");
306
+ if (contentTag) {
307
+ skill.instructions = contentTag;
308
+ } else {
309
+ skill.problem = this.extractXmlTag(body, "problem");
310
+ skill.solution = this.extractXmlTag(body, "solution");
311
+ skill.verification = this.extractXmlTag(body, "verification");
312
+ skill.notes = this.extractXmlTag(body, "notes");
313
+ }
314
+ const tagsStr = this.extractXmlTag(body, "tags");
315
+ if (tagsStr) {
316
+ skill.tags = tagsStr.split(",").map((t) => t.trim()).filter((t) => t);
317
+ }
318
+ skills.push(skill);
319
+ }
320
+ return skills;
321
+ }
322
+ /**
323
+ * Parse Markdown format skills
324
+ */
325
+ parseMarkdownSkills(content, existingSkills) {
326
+ const skills = [];
327
+ const sections = content.split(/(?=^###\s)/m);
328
+ for (const section of sections) {
329
+ const headerMatch = /^###\s+(.+?)(?:\s+\(v([\d.]+)\))?(?:\s+\{#([^}]+)\})?\s*$/m.exec(section);
330
+ if (!headerMatch) continue;
331
+ const name = headerMatch[1].trim();
332
+ const version = headerMatch[2];
333
+ const id = headerMatch[3];
334
+ if (existingSkills.some((s) => s.name.toLowerCase() === name.toLowerCase())) {
335
+ continue;
336
+ }
337
+ const skill = {
338
+ rawContent: section,
339
+ name,
340
+ description: ""
341
+ };
342
+ if (version) skill.version = version;
343
+ if (id) skill.id = id;
344
+ const descMatch = /^\*([^*]+)\*$/m.exec(section);
345
+ if (descMatch) {
346
+ skill.description = descMatch[1];
347
+ }
348
+ const bodyStart = section.indexOf("\n", section.indexOf(headerMatch[0]) + headerMatch[0].length);
349
+ if (bodyStart >= 0) {
350
+ let bodyContent = section.slice(bodyStart).trim();
351
+ bodyContent = bodyContent.replace(/^\*[^*]+\*\s*\n?/, "").trim();
352
+ bodyContent = bodyContent.replace(/\nTags:\s*.+$/m, "").trim();
353
+ if (bodyContent) {
354
+ skill.instructions = bodyContent;
355
+ }
356
+ }
357
+ if (!skill.instructions) {
358
+ skill.problem = this.extractMarkdownSection(section, "Problem");
359
+ skill.solution = this.extractMarkdownSection(section, "Solution");
360
+ skill.verification = this.extractMarkdownSection(section, "Verification");
361
+ skill.notes = this.extractMarkdownSection(section, "Notes");
362
+ }
363
+ const tagsMatch = /Tags:\s*(.+)$/m.exec(section);
364
+ if (tagsMatch) {
365
+ skill.tags = tagsMatch[1].split(",").map((t) => t.replace(/`/g, "").trim()).filter((t) => t);
366
+ }
367
+ skills.push(skill);
368
+ }
369
+ return skills;
370
+ }
371
+ /**
372
+ * Extract content from XML tag
373
+ */
374
+ extractXmlTag(body, tagName) {
375
+ const regex = new RegExp(`<${tagName}>([\\s\\S]*?)<\\/${tagName}>`, "i");
376
+ const match = regex.exec(body);
377
+ if (match) {
378
+ return this.unescapeXml(match[1].trim());
379
+ }
380
+ return void 0;
381
+ }
382
+ /**
383
+ * Extract CDATA content
384
+ */
385
+ extractCData(body, tagName) {
386
+ const regex = new RegExp(`<${tagName}><!\\[CDATA\\[([\\s\\S]*?)\\]\\]><\\/${tagName}>`, "i");
387
+ const match = regex.exec(body);
388
+ if (match) {
389
+ return match[1];
390
+ }
391
+ return void 0;
392
+ }
393
+ /**
394
+ * Unescape XML entities
395
+ */
396
+ unescapeXml(str) {
397
+ return str.replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&quot;/g, '"').replace(/&apos;/g, "'").replace(/&amp;/g, "&");
398
+ }
399
+ /**
400
+ * Extract a markdown section by header
401
+ */
402
+ extractMarkdownSection(content, header) {
403
+ const regex = new RegExp(`\\*\\*${header}:\\*\\*\\s*([\\s\\S]*?)(?=\\*\\*|Tags:|$)`, "i");
404
+ const match = regex.exec(content);
405
+ if (match) {
406
+ return match[1].trim();
407
+ }
408
+ return void 0;
409
+ }
410
+ /**
411
+ * Generate ID from skill name
412
+ */
413
+ generateId(name) {
414
+ return name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
415
+ }
416
+ /**
417
+ * Extract header content
418
+ */
419
+ extractHeader(content, skills) {
420
+ if (skills.length === 0) return content.trim() || void 0;
421
+ const firstSkill = skills[0];
422
+ const idx = content.indexOf(firstSkill.rawContent);
423
+ if (idx > 0) {
424
+ return content.slice(0, idx).trim() || void 0;
425
+ }
426
+ return void 0;
427
+ }
428
+ /**
429
+ * Extract footer content
430
+ */
431
+ extractFooter(content, skills) {
432
+ if (skills.length === 0) return void 0;
433
+ const lastSkill = skills[skills.length - 1];
434
+ const idx = content.indexOf(lastSkill.rawContent);
435
+ if (idx >= 0) {
436
+ const afterIdx = idx + lastSkill.rawContent.length;
437
+ const footer = content.slice(afterIdx).trim();
438
+ return footer || void 0;
439
+ }
440
+ return void 0;
441
+ }
442
+ };
443
+ function createAgentsParser() {
444
+ return new AgentsParser();
445
+ }
446
+
447
+ // src/agents/sync.ts
448
+ var AgentsSync = class {
449
+ constructor() {
450
+ this.generator = new AgentsGenerator();
451
+ this.parser = new AgentsParser();
452
+ }
453
+ /**
454
+ * Sync AGENTS.md with skill bank
455
+ */
456
+ async sync(agentsPath, storage, options) {
457
+ const result = {
458
+ added: [],
459
+ updated: [],
460
+ removed: [],
461
+ unchanged: [],
462
+ warnings: []
463
+ };
464
+ switch (options.direction) {
465
+ case "import":
466
+ await this.importFromAgents(agentsPath, storage, options, result);
467
+ break;
468
+ case "export":
469
+ await this.exportToAgents(agentsPath, storage, options, result);
470
+ break;
471
+ case "bidirectional":
472
+ await this.bidirectionalSync(agentsPath, storage, options, result);
473
+ break;
474
+ }
475
+ return result;
476
+ }
477
+ /**
478
+ * Import skills from AGENTS.md to skill bank
479
+ */
480
+ async importFromAgents(agentsPath, storage, options, result) {
481
+ if (!fs.existsSync(agentsPath)) {
482
+ result.warnings.push(`AGENTS.md not found at ${agentsPath}`);
483
+ return;
484
+ }
485
+ const content = fs.readFileSync(agentsPath, "utf-8");
486
+ const parsed = this.parser.parse(content);
487
+ result.warnings.push(...parsed.warnings);
488
+ const existingSkills = await storage.listSkills();
489
+ const existingById = new Map(existingSkills.map((s) => [s.id, s]));
490
+ const existingByName = new Map(existingSkills.map((s) => [s.name.toLowerCase(), s]));
491
+ const processedIds = /* @__PURE__ */ new Set();
492
+ for (const parsedSkill of parsed.skills) {
493
+ const skill = this.parser.toSkill(parsedSkill);
494
+ processedIds.add(skill.id);
495
+ let existing = existingById.get(skill.id);
496
+ if (!existing) {
497
+ existing = existingByName.get(skill.name.toLowerCase());
498
+ }
499
+ if (existing) {
500
+ const shouldUpdate = this.resolveConflict(existing, skill, options.conflictStrategy);
501
+ if (shouldUpdate) {
502
+ if (!options.dryRun) {
503
+ const merged = this.mergeSkills(existing, skill);
504
+ await storage.saveSkill(merged);
505
+ }
506
+ result.updated.push(skill.id);
507
+ } else {
508
+ result.unchanged.push(skill.id);
509
+ }
510
+ } else {
511
+ if (!options.dryRun) {
512
+ await storage.saveSkill(skill);
513
+ }
514
+ result.added.push(skill.id);
515
+ }
516
+ }
517
+ if (options.removeOrphans) {
518
+ for (const existing of existingSkills) {
519
+ if (!processedIds.has(existing.id)) {
520
+ if (!options.dryRun) {
521
+ await storage.deleteSkill(existing.id);
522
+ }
523
+ result.removed.push(existing.id);
524
+ }
525
+ }
526
+ }
527
+ }
528
+ /**
529
+ * Export skills from skill bank to AGENTS.md
530
+ */
531
+ async exportToAgents(agentsPath, storage, options, result) {
532
+ const generator = new AgentsGenerator(options.generatorConfig);
533
+ const content = await generator.generate(storage);
534
+ let existingContent = "";
535
+ if (fs.existsSync(agentsPath)) {
536
+ existingContent = fs.readFileSync(agentsPath, "utf-8");
537
+ }
538
+ const existingParsed = this.parser.parse(existingContent);
539
+ const existingIds = new Set(existingParsed.skills.map((s) => s.id || s.name.toLowerCase()));
540
+ const skills = await storage.listSkills({
541
+ status: options.generatorConfig?.filter?.status || ["active"]
542
+ });
543
+ for (const skill of skills) {
544
+ if (existingIds.has(skill.id) || existingIds.has(skill.name.toLowerCase())) {
545
+ result.updated.push(skill.id);
546
+ } else {
547
+ result.added.push(skill.id);
548
+ }
549
+ }
550
+ if (!options.dryRun) {
551
+ const dir = path.dirname(agentsPath);
552
+ if (!fs.existsSync(dir)) {
553
+ fs.mkdirSync(dir, { recursive: true });
554
+ }
555
+ fs.writeFileSync(agentsPath, content);
556
+ }
557
+ }
558
+ /**
559
+ * Bidirectional sync
560
+ */
561
+ async bidirectionalSync(agentsPath, storage, options, result) {
562
+ await this.importFromAgents(agentsPath, storage, { ...options, removeOrphans: false }, result);
563
+ const exportResult = {
564
+ added: [],
565
+ updated: [],
566
+ removed: [],
567
+ unchanged: [],
568
+ warnings: []
569
+ };
570
+ await this.exportToAgents(agentsPath, storage, options, exportResult);
571
+ for (const id of exportResult.added) {
572
+ if (!result.added.includes(id) && !result.updated.includes(id)) {
573
+ result.added.push(id);
574
+ }
575
+ }
576
+ }
577
+ /**
578
+ * Resolve conflict between existing and new skill
579
+ */
580
+ resolveConflict(existing, incoming, strategy) {
581
+ switch (strategy) {
582
+ case "bank-wins":
583
+ return false;
584
+ case "agents-wins":
585
+ return true;
586
+ case "newer-wins":
587
+ return incoming.updatedAt > existing.updatedAt;
588
+ case "skip":
589
+ default:
590
+ return false;
591
+ }
592
+ }
593
+ /**
594
+ * Merge skills, preserving important data from existing
595
+ */
596
+ mergeSkills(existing, incoming) {
597
+ return {
598
+ ...incoming,
599
+ id: existing.id,
600
+ // Keep existing ID
601
+ createdAt: existing.createdAt,
602
+ // Preserve creation date
603
+ source: incoming.source || existing.source,
604
+ parentVersion: existing.version
605
+ // Track update lineage
606
+ };
607
+ }
608
+ };
609
+ function createAgentsSync() {
610
+ return new AgentsSync();
611
+ }
612
+ async function generateAgentsMd(storage, config) {
613
+ const generator = new AgentsGenerator(config);
614
+ return generator.generate(storage);
615
+ }
616
+ async function writeAgentsMd(storage, filePath, config) {
617
+ const content = await generateAgentsMd(storage, config);
618
+ const dir = path.dirname(filePath);
619
+ if (dir && !fs.existsSync(dir)) {
620
+ fs.mkdirSync(dir, { recursive: true });
621
+ }
622
+ fs.writeFileSync(filePath, content);
623
+ }
624
+ async function importFromAgentsMd(filePath, storage, options) {
625
+ const sync = new AgentsSync();
626
+ return sync.sync(filePath, storage, {
627
+ direction: "import",
628
+ conflictStrategy: options?.conflictStrategy || "skip",
629
+ dryRun: options?.dryRun
630
+ });
631
+ }
632
+
633
+ export {
634
+ DEFAULT_AGENTS_CONFIG,
635
+ AgentsGenerator,
636
+ createAgentsGenerator,
637
+ AgentsParser,
638
+ createAgentsParser,
639
+ AgentsSync,
640
+ createAgentsSync,
641
+ generateAgentsMd,
642
+ writeAgentsMd,
643
+ importFromAgentsMd
644
+ };