agdex 0.2.0 → 0.3.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 (37) hide show
  1. package/README.md +108 -2
  2. package/dist/cli/index.js +394 -92
  3. package/dist/index-4shp3mqh.js +1871 -0
  4. package/dist/index-57bfejpe.js +1357 -0
  5. package/dist/index-5h59833k.js +1270 -0
  6. package/dist/index-9gy9s47s.js +1366 -0
  7. package/dist/index-p0xjkwcp.js +1283 -0
  8. package/dist/index-zrmn6fd2.js +1903 -0
  9. package/dist/index.d.ts +3 -1
  10. package/dist/index.d.ts.map +1 -1
  11. package/dist/index.js +7 -1
  12. package/dist/lib/agents-md.d.ts.map +1 -1
  13. package/dist/lib/config.d.ts +13 -0
  14. package/dist/lib/config.d.ts.map +1 -0
  15. package/dist/lib/providers/basedpyright.d.ts +3 -0
  16. package/dist/lib/providers/basedpyright.d.ts.map +1 -0
  17. package/dist/lib/providers/convex.d.ts +3 -0
  18. package/dist/lib/providers/convex.d.ts.map +1 -0
  19. package/dist/lib/providers/delta-rs.d.ts +3 -0
  20. package/dist/lib/providers/delta-rs.d.ts.map +1 -0
  21. package/dist/lib/providers/index.d.ts +8 -0
  22. package/dist/lib/providers/index.d.ts.map +1 -1
  23. package/dist/lib/providers/polars.d.ts +3 -0
  24. package/dist/lib/providers/polars.d.ts.map +1 -0
  25. package/dist/lib/providers/ruff.d.ts +3 -0
  26. package/dist/lib/providers/ruff.d.ts.map +1 -0
  27. package/dist/lib/providers/svelte.d.ts +3 -0
  28. package/dist/lib/providers/svelte.d.ts.map +1 -0
  29. package/dist/lib/providers/tailwind.d.ts +3 -0
  30. package/dist/lib/providers/tailwind.d.ts.map +1 -0
  31. package/dist/lib/providers/ty.d.ts +3 -0
  32. package/dist/lib/providers/ty.d.ts.map +1 -0
  33. package/dist/lib/skills.d.ts +5 -0
  34. package/dist/lib/skills.d.ts.map +1 -1
  35. package/dist/lib/types.d.ts +5 -1
  36. package/dist/lib/types.d.ts.map +1 -1
  37. package/package.json +2 -2
@@ -0,0 +1,1270 @@
1
+ import { createRequire } from "node:module";
2
+ var __create = Object.create;
3
+ var __getProtoOf = Object.getPrototypeOf;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __toESM = (mod, isNodeMode, target) => {
8
+ target = mod != null ? __create(__getProtoOf(mod)) : {};
9
+ const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
10
+ for (let key of __getOwnPropNames(mod))
11
+ if (!__hasOwnProp.call(to, key))
12
+ __defProp(to, key, {
13
+ get: () => mod[key],
14
+ enumerable: true
15
+ });
16
+ return to;
17
+ };
18
+ var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
19
+ var __require = /* @__PURE__ */ createRequire(import.meta.url);
20
+
21
+ // src/lib/agents-md.ts
22
+ import { execSync } from "child_process";
23
+ import fs from "fs";
24
+ import path from "path";
25
+ import os from "os";
26
+ var START_MARKER_PREFIX = "<!-- AGENTS-MD-EMBED-START";
27
+ var END_MARKER_PREFIX = "<!-- AGENTS-MD-EMBED-END";
28
+ var MARKER_SUFFIX = " -->";
29
+ function getStartMarker(providerName) {
30
+ return providerName ? `${START_MARKER_PREFIX}:${providerName}${MARKER_SUFFIX}` : `${START_MARKER_PREFIX}${MARKER_SUFFIX}`;
31
+ }
32
+ function getEndMarker(providerName) {
33
+ return providerName ? `${END_MARKER_PREFIX}:${providerName}${MARKER_SUFFIX}` : `${END_MARKER_PREFIX}${MARKER_SUFFIX}`;
34
+ }
35
+ async function pullDocs(provider, options) {
36
+ const { cwd, version: versionOverride, docsDir } = options;
37
+ let version;
38
+ if (versionOverride) {
39
+ version = versionOverride;
40
+ } else if (provider.detectVersion) {
41
+ const versionResult = provider.detectVersion(cwd);
42
+ if (!versionResult.version) {
43
+ return {
44
+ success: false,
45
+ error: versionResult.error || `Could not detect ${provider.displayName} version`
46
+ };
47
+ }
48
+ version = versionResult.version;
49
+ } else {
50
+ return {
51
+ success: false,
52
+ error: `No version provided and ${provider.displayName} does not support auto-detection`
53
+ };
54
+ }
55
+ const docsPath = docsDir ?? fs.mkdtempSync(path.join(os.tmpdir(), "agdex-"));
56
+ const useTempDir = !docsDir;
57
+ try {
58
+ if (fs.existsSync(docsPath)) {
59
+ fs.rmSync(docsPath, { recursive: true });
60
+ }
61
+ const tag = provider.versionToTag ? provider.versionToTag(version) : `v${version}`;
62
+ await cloneDocsFolder(provider.repo, provider.docsPath, tag, docsPath);
63
+ return {
64
+ success: true,
65
+ docsPath,
66
+ version
67
+ };
68
+ } catch (error) {
69
+ if (useTempDir && fs.existsSync(docsPath)) {
70
+ fs.rmSync(docsPath, { recursive: true });
71
+ }
72
+ return {
73
+ success: false,
74
+ error: error instanceof Error ? error.message : String(error)
75
+ };
76
+ }
77
+ }
78
+ async function cloneDocsFolder(repo, docsFolder, tag, destDir) {
79
+ const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "agdex-clone-"));
80
+ try {
81
+ try {
82
+ execSync(`git clone --depth 1 --filter=blob:none --sparse --branch ${tag} https://github.com/${repo}.git .`, { cwd: tempDir, stdio: "pipe" });
83
+ } catch (error) {
84
+ const message = error instanceof Error ? error.message : String(error);
85
+ if (message.includes("not found") || message.includes("did not match")) {
86
+ throw new Error(`Could not find documentation for tag ${tag}. This version may not exist on GitHub yet.`);
87
+ }
88
+ throw error;
89
+ }
90
+ execSync(`git sparse-checkout set ${docsFolder}`, { cwd: tempDir, stdio: "pipe" });
91
+ const sourceDocsDir = path.join(tempDir, docsFolder);
92
+ if (!fs.existsSync(sourceDocsDir)) {
93
+ throw new Error(`${docsFolder} folder not found in cloned repository`);
94
+ }
95
+ if (fs.existsSync(destDir)) {
96
+ fs.rmSync(destDir, { recursive: true });
97
+ }
98
+ fs.mkdirSync(destDir, { recursive: true });
99
+ fs.cpSync(sourceDocsDir, destDir, { recursive: true });
100
+ } finally {
101
+ if (fs.existsSync(tempDir)) {
102
+ fs.rmSync(tempDir, { recursive: true });
103
+ }
104
+ }
105
+ }
106
+ function collectDocFiles(dir, options) {
107
+ const extensions = options?.extensions || [".mdx", ".md"];
108
+ const excludePatterns = options?.excludePatterns || [];
109
+ const files = fs.readdirSync(dir, { recursive: true });
110
+ return files.filter((f) => {
111
+ const hasValidExtension = extensions.some((ext) => f.endsWith(ext));
112
+ if (!hasValidExtension)
113
+ return false;
114
+ for (const pattern of excludePatterns) {
115
+ if (pattern.startsWith("**/") && pattern.endsWith("/**")) {
116
+ const dirName = pattern.slice(3, -3);
117
+ if (f.includes(`/${dirName}/`) || f.startsWith(`${dirName}/`))
118
+ return false;
119
+ } else if (pattern.startsWith("**/")) {
120
+ const suffix = pattern.slice(3);
121
+ if (f.endsWith(suffix) || f === suffix)
122
+ return false;
123
+ } else if (pattern.startsWith("*")) {
124
+ const suffix = pattern.slice(1);
125
+ if (f.endsWith(suffix))
126
+ return false;
127
+ } else if (f === pattern || f.endsWith("/" + pattern)) {
128
+ return false;
129
+ }
130
+ }
131
+ if (f.endsWith("/index.mdx") || f.endsWith("/index.md") || f.startsWith("index.")) {
132
+ return false;
133
+ }
134
+ return true;
135
+ }).sort().map((f) => ({ relativePath: f }));
136
+ }
137
+ function buildDocTree(files) {
138
+ const sections = new Map;
139
+ for (const file of files) {
140
+ const parts = file.relativePath.split("/");
141
+ if (parts.length === 1) {
142
+ if (!sections.has(".")) {
143
+ sections.set(".", {
144
+ name: ".",
145
+ files: [],
146
+ subsections: []
147
+ });
148
+ }
149
+ sections.get(".").files.push({ relativePath: file.relativePath });
150
+ continue;
151
+ }
152
+ const topLevelDir = parts[0];
153
+ if (!sections.has(topLevelDir)) {
154
+ sections.set(topLevelDir, {
155
+ name: topLevelDir,
156
+ files: [],
157
+ subsections: []
158
+ });
159
+ }
160
+ const section = sections.get(topLevelDir);
161
+ if (parts.length === 2) {
162
+ section.files.push({ relativePath: file.relativePath });
163
+ } else {
164
+ const subsectionDir = parts[1];
165
+ let subsection = section.subsections.find((s) => s.name === subsectionDir);
166
+ if (!subsection) {
167
+ subsection = { name: subsectionDir, files: [], subsections: [] };
168
+ section.subsections.push(subsection);
169
+ }
170
+ if (parts.length === 3) {
171
+ subsection.files.push({ relativePath: file.relativePath });
172
+ } else {
173
+ const subSubDir = parts[2];
174
+ let subSubsection = subsection.subsections.find((s) => s.name === subSubDir);
175
+ if (!subSubsection) {
176
+ subSubsection = { name: subSubDir, files: [], subsections: [] };
177
+ subsection.subsections.push(subSubsection);
178
+ }
179
+ subSubsection.files.push({ relativePath: file.relativePath });
180
+ }
181
+ }
182
+ }
183
+ const sortedSections = Array.from(sections.values()).sort((a, b) => a.name.localeCompare(b.name));
184
+ for (const section of sortedSections) {
185
+ section.files.sort((a, b) => a.relativePath.localeCompare(b.relativePath));
186
+ section.subsections.sort((a, b) => a.name.localeCompare(b.name));
187
+ for (const subsection of section.subsections) {
188
+ subsection.files.sort((a, b) => a.relativePath.localeCompare(b.relativePath));
189
+ subsection.subsections.sort((a, b) => a.name.localeCompare(b.name));
190
+ for (const subSubsection of subsection.subsections) {
191
+ subSubsection.files.sort((a, b) => a.relativePath.localeCompare(b.relativePath));
192
+ }
193
+ }
194
+ }
195
+ return sortedSections;
196
+ }
197
+ function generateIndex(options) {
198
+ const { docsPath, sections, outputFile, providerName, instruction, description, regenerateCommand } = options;
199
+ const parts = [];
200
+ const header = providerName ? `[${providerName} Docs Index]` : "[Docs Index]";
201
+ parts.push(header);
202
+ parts.push(`root: ${docsPath}`);
203
+ if (instruction) {
204
+ parts.push(instruction);
205
+ }
206
+ if (description) {
207
+ parts.push(description);
208
+ }
209
+ const targetFile = outputFile || "AGENTS.md";
210
+ const cmd = regenerateCommand || `npx agdex --output ${targetFile}`;
211
+ parts.push(`If docs missing, run: ${cmd}`);
212
+ const allFiles = collectAllFilesFromSections(sections);
213
+ const grouped = groupByDirectory(allFiles);
214
+ for (const [dir, files] of grouped) {
215
+ parts.push(`${dir}:{${files.join(",")}}`);
216
+ }
217
+ return parts.join("|");
218
+ }
219
+ function collectAllFilesFromSections(sections) {
220
+ const files = [];
221
+ for (const section of sections) {
222
+ for (const file of section.files) {
223
+ files.push(file.relativePath);
224
+ }
225
+ files.push(...collectAllFilesFromSections(section.subsections));
226
+ }
227
+ return files;
228
+ }
229
+ function groupByDirectory(files) {
230
+ const grouped = new Map;
231
+ for (const filePath of files) {
232
+ const lastSlash = filePath.lastIndexOf("/");
233
+ const dir = lastSlash === -1 ? "." : filePath.slice(0, lastSlash);
234
+ const fileName = lastSlash === -1 ? filePath : filePath.slice(lastSlash + 1);
235
+ const existing = grouped.get(dir);
236
+ if (existing) {
237
+ existing.push(fileName);
238
+ } else {
239
+ grouped.set(dir, [fileName]);
240
+ }
241
+ }
242
+ return grouped;
243
+ }
244
+ function hasExistingIndex(content, providerName) {
245
+ if (providerName) {
246
+ return content.includes(getStartMarker(providerName));
247
+ }
248
+ return content.includes(START_MARKER_PREFIX);
249
+ }
250
+ function removeDocsIndex(content, providerName) {
251
+ if (!hasExistingIndex(content, providerName)) {
252
+ return content;
253
+ }
254
+ let result = content;
255
+ if (providerName) {
256
+ const startMarker = getStartMarker(providerName);
257
+ const endMarker = getEndMarker(providerName);
258
+ const startIdx = result.indexOf(startMarker);
259
+ const endIdx = result.indexOf(endMarker) + endMarker.length;
260
+ if (startIdx !== -1 && endIdx > startIdx) {
261
+ result = result.slice(0, startIdx) + result.slice(endIdx);
262
+ }
263
+ } else {
264
+ let startIdx;
265
+ while ((startIdx = result.indexOf(START_MARKER_PREFIX)) !== -1) {
266
+ const startMarkerEnd = result.indexOf(MARKER_SUFFIX, startIdx) + MARKER_SUFFIX.length;
267
+ const startMarkerContent = result.slice(startIdx, startMarkerEnd);
268
+ const providerMatch = startMarkerContent.match(/:([^-\s]+)/);
269
+ const provider = providerMatch ? providerMatch[1] : undefined;
270
+ const endMarker = getEndMarker(provider);
271
+ const endIdx = result.indexOf(endMarker);
272
+ if (endIdx !== -1) {
273
+ result = result.slice(0, startIdx) + result.slice(endIdx + endMarker.length);
274
+ } else {
275
+ result = result.slice(0, startIdx) + result.slice(startMarkerEnd);
276
+ }
277
+ }
278
+ }
279
+ result = result.replace(/\n{3,}/g, `
280
+
281
+ `);
282
+ result = result.trimEnd();
283
+ if (result.length > 0) {
284
+ result += `
285
+ `;
286
+ }
287
+ return result;
288
+ }
289
+ function wrapWithMarkers(content, providerName) {
290
+ const startMarker = getStartMarker(providerName);
291
+ const endMarker = getEndMarker(providerName);
292
+ return `${startMarker}
293
+ ${content}
294
+ ${endMarker}`;
295
+ }
296
+ function injectIndex(existingContent, indexContent, providerName) {
297
+ const wrappedContent = wrapWithMarkers(indexContent, providerName);
298
+ if (hasExistingIndex(existingContent, providerName)) {
299
+ const startMarker = getStartMarker(providerName);
300
+ const endMarker = getEndMarker(providerName);
301
+ const startIdx = existingContent.indexOf(startMarker);
302
+ const endIdx = existingContent.indexOf(endMarker) + endMarker.length;
303
+ return existingContent.slice(0, startIdx) + wrappedContent + existingContent.slice(endIdx);
304
+ }
305
+ const separator = existingContent.endsWith(`
306
+ `) ? `
307
+ ` : `
308
+
309
+ `;
310
+ return existingContent + separator + wrappedContent + `
311
+ `;
312
+ }
313
+ function ensureGitignoreEntry(cwd, docsDir) {
314
+ const gitignorePath = path.join(cwd, ".gitignore");
315
+ const entry = docsDir.endsWith("/") ? docsDir : `${docsDir}/`;
316
+ const entryRegex = new RegExp(`^\\s*${docsDir.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}(?:/.*)?$`);
317
+ let content = "";
318
+ if (fs.existsSync(gitignorePath)) {
319
+ content = fs.readFileSync(gitignorePath, "utf-8");
320
+ }
321
+ const hasEntry = content.split(/\r?\n/).some((line) => entryRegex.test(line));
322
+ if (hasEntry) {
323
+ return { path: gitignorePath, updated: false, alreadyPresent: true };
324
+ }
325
+ const needsNewline = content.length > 0 && !content.endsWith(`
326
+ `);
327
+ const header = content.includes("# agdex") ? "" : `# agdex
328
+ `;
329
+ const newContent = content + (needsNewline ? `
330
+ ` : "") + header + `${entry}
331
+ `;
332
+ fs.writeFileSync(gitignorePath, newContent, "utf-8");
333
+ return { path: gitignorePath, updated: true, alreadyPresent: false };
334
+ }
335
+ function getGlobalCacheDir() {
336
+ return path.join(os.homedir(), ".cache", "agdex");
337
+ }
338
+ function getLocalCacheDir(cwd) {
339
+ return path.join(cwd, ".agdex");
340
+ }
341
+ async function embed(options) {
342
+ const {
343
+ cwd,
344
+ provider,
345
+ version,
346
+ output = "AGENTS.md",
347
+ docsDir: customDocsDir,
348
+ globalCache = false,
349
+ description
350
+ } = options;
351
+ let docsPath;
352
+ let docsLinkPath;
353
+ let docsDir;
354
+ if (customDocsDir) {
355
+ docsDir = customDocsDir;
356
+ docsPath = path.isAbsolute(customDocsDir) ? customDocsDir : path.join(cwd, customDocsDir);
357
+ docsLinkPath = path.isAbsolute(customDocsDir) ? customDocsDir : `./${customDocsDir}`;
358
+ } else if (globalCache) {
359
+ const cacheBase = getGlobalCacheDir();
360
+ docsDir = path.join(cacheBase, provider.name);
361
+ docsPath = docsDir;
362
+ docsLinkPath = docsPath;
363
+ } else {
364
+ docsDir = `.agdex/${provider.name}`;
365
+ docsPath = path.join(cwd, docsDir);
366
+ docsLinkPath = `./${docsDir}`;
367
+ }
368
+ const targetPath = path.join(cwd, output);
369
+ let sizeBefore = 0;
370
+ let isNewFile = true;
371
+ let existingContent = "";
372
+ if (fs.existsSync(targetPath)) {
373
+ existingContent = fs.readFileSync(targetPath, "utf-8");
374
+ sizeBefore = Buffer.byteLength(existingContent, "utf-8");
375
+ isNewFile = false;
376
+ }
377
+ const pullResult = await pullDocs(provider, {
378
+ cwd,
379
+ version,
380
+ docsDir: docsPath
381
+ });
382
+ if (!pullResult.success) {
383
+ return {
384
+ success: false,
385
+ error: pullResult.error
386
+ };
387
+ }
388
+ const docFiles = collectDocFiles(docsPath, {
389
+ extensions: provider.extensions,
390
+ excludePatterns: provider.excludePatterns
391
+ });
392
+ const sections = buildDocTree(docFiles);
393
+ const globalFlag = globalCache ? " --global" : "";
394
+ const regenerateCommand = `npx agdex --provider ${provider.name} --output ${output}${globalFlag}`;
395
+ const indexContent = generateIndex({
396
+ docsPath: docsLinkPath,
397
+ sections,
398
+ outputFile: output,
399
+ providerName: provider.displayName,
400
+ instruction: provider.instruction,
401
+ description,
402
+ regenerateCommand
403
+ });
404
+ const newContent = injectIndex(existingContent, indexContent, provider.name);
405
+ fs.writeFileSync(targetPath, newContent, "utf-8");
406
+ const sizeAfter = Buffer.byteLength(newContent, "utf-8");
407
+ let gitignoreUpdated = false;
408
+ if (!globalCache && !customDocsDir) {
409
+ const gitignoreResult = ensureGitignoreEntry(cwd, ".agdex");
410
+ gitignoreUpdated = gitignoreResult.updated;
411
+ } else if (!globalCache && customDocsDir && !path.isAbsolute(customDocsDir)) {
412
+ const gitignoreResult = ensureGitignoreEntry(cwd, customDocsDir);
413
+ gitignoreUpdated = gitignoreResult.updated;
414
+ }
415
+ return {
416
+ success: true,
417
+ targetFile: output,
418
+ docsPath: globalCache ? docsPath : docsDir,
419
+ version: pullResult.version,
420
+ sizeBefore,
421
+ sizeAfter,
422
+ isNewFile,
423
+ gitignoreUpdated
424
+ };
425
+ }
426
+
427
+ // src/lib/providers/nextjs.ts
428
+ import fs2 from "fs";
429
+ import path2 from "path";
430
+ function detectWorkspace(cwd) {
431
+ const packageJsonPath = path2.join(cwd, "package.json");
432
+ const pnpmWorkspacePath = path2.join(cwd, "pnpm-workspace.yaml");
433
+ if (fs2.existsSync(pnpmWorkspacePath)) {
434
+ const packages = parsePnpmWorkspace(pnpmWorkspacePath);
435
+ if (packages.length > 0) {
436
+ return { isMonorepo: true, type: "pnpm", packages };
437
+ }
438
+ }
439
+ if (fs2.existsSync(packageJsonPath)) {
440
+ const packages = parsePackageJsonWorkspaces(packageJsonPath);
441
+ if (packages.length > 0) {
442
+ return { isMonorepo: true, type: "npm", packages };
443
+ }
444
+ }
445
+ return { isMonorepo: false, type: null, packages: [] };
446
+ }
447
+ function parsePnpmWorkspace(filePath) {
448
+ try {
449
+ const content = fs2.readFileSync(filePath, "utf-8");
450
+ const lines = content.split(`
451
+ `);
452
+ const packages = [];
453
+ let inPackages = false;
454
+ for (const line of lines) {
455
+ const trimmed = line.trim();
456
+ if (trimmed === "packages:") {
457
+ inPackages = true;
458
+ continue;
459
+ }
460
+ if (inPackages) {
461
+ if (trimmed && !trimmed.startsWith("-") && !trimmed.startsWith("#")) {
462
+ break;
463
+ }
464
+ const match = trimmed.match(/^-\s*['"]?([^'"]+)['"]?$/);
465
+ if (match) {
466
+ packages.push(match[1]);
467
+ }
468
+ }
469
+ }
470
+ return packages;
471
+ } catch {
472
+ return [];
473
+ }
474
+ }
475
+ function parsePackageJsonWorkspaces(filePath) {
476
+ try {
477
+ const content = fs2.readFileSync(filePath, "utf-8");
478
+ const pkg = JSON.parse(content);
479
+ if (Array.isArray(pkg.workspaces)) {
480
+ return pkg.workspaces;
481
+ }
482
+ if (pkg.workspaces?.packages && Array.isArray(pkg.workspaces.packages)) {
483
+ return pkg.workspaces.packages;
484
+ }
485
+ return [];
486
+ } catch {
487
+ return [];
488
+ }
489
+ }
490
+ function expandWorkspacePatterns(cwd, patterns) {
491
+ const packagePaths = [];
492
+ for (const pattern of patterns) {
493
+ if (pattern.startsWith("!"))
494
+ continue;
495
+ if (pattern.includes("*")) {
496
+ const basePath = path2.join(cwd, pattern.replace("/*", "").replace("/**", ""));
497
+ if (fs2.existsSync(basePath)) {
498
+ try {
499
+ const entries = fs2.readdirSync(basePath);
500
+ for (const entry of entries) {
501
+ const fullPath = path2.join(basePath, entry);
502
+ if (fs2.statSync(fullPath).isDirectory()) {
503
+ packagePaths.push(fullPath);
504
+ }
505
+ }
506
+ } catch {}
507
+ }
508
+ } else {
509
+ const fullPath = path2.join(cwd, pattern);
510
+ if (fs2.existsSync(fullPath)) {
511
+ packagePaths.push(fullPath);
512
+ }
513
+ }
514
+ }
515
+ return [...new Set(packagePaths)];
516
+ }
517
+ function compareVersions(a, b) {
518
+ const parseVersion = (v) => {
519
+ const match = v.match(/^(\d+)\.(\d+)\.(\d+)/);
520
+ if (!match)
521
+ return [0, 0, 0];
522
+ return [parseInt(match[1]), parseInt(match[2]), parseInt(match[3])];
523
+ };
524
+ const [aMajor, aMinor, aPatch] = parseVersion(a);
525
+ const [bMajor, bMinor, bPatch] = parseVersion(b);
526
+ if (aMajor !== bMajor)
527
+ return aMajor - bMajor;
528
+ if (aMinor !== bMinor)
529
+ return aMinor - bMinor;
530
+ return aPatch - bPatch;
531
+ }
532
+ function findNextjsInWorkspace(cwd, patterns) {
533
+ const packagePaths = expandWorkspacePatterns(cwd, patterns);
534
+ const versions = [];
535
+ for (const pkgPath of packagePaths) {
536
+ const packageJsonPath = path2.join(pkgPath, "package.json");
537
+ if (!fs2.existsSync(packageJsonPath))
538
+ continue;
539
+ try {
540
+ const content = fs2.readFileSync(packageJsonPath, "utf-8");
541
+ const pkg = JSON.parse(content);
542
+ const nextVersion = pkg.dependencies?.next || pkg.devDependencies?.next;
543
+ if (nextVersion) {
544
+ versions.push(nextVersion.replace(/^[\^~>=<]+/, ""));
545
+ }
546
+ } catch {}
547
+ }
548
+ if (versions.length === 0)
549
+ return null;
550
+ if (versions.length === 1)
551
+ return versions[0];
552
+ return versions.reduce((highest, current) => {
553
+ return compareVersions(current, highest) > 0 ? current : highest;
554
+ });
555
+ }
556
+ function detectVersion(cwd) {
557
+ const packageJsonPath = path2.join(cwd, "package.json");
558
+ if (!fs2.existsSync(packageJsonPath)) {
559
+ return {
560
+ version: null,
561
+ error: "No package.json found in the current directory"
562
+ };
563
+ }
564
+ try {
565
+ const packageJson = JSON.parse(fs2.readFileSync(packageJsonPath, "utf-8"));
566
+ const dependencies = packageJson.dependencies || {};
567
+ const devDependencies = packageJson.devDependencies || {};
568
+ const nextVersion = dependencies.next || devDependencies.next;
569
+ if (nextVersion) {
570
+ const cleanVersion = nextVersion.replace(/^[\^~>=<]+/, "");
571
+ return { version: cleanVersion };
572
+ }
573
+ const workspace = detectWorkspace(cwd);
574
+ if (workspace.isMonorepo && workspace.packages.length > 0) {
575
+ const highestVersion = findNextjsInWorkspace(cwd, workspace.packages);
576
+ if (highestVersion) {
577
+ return { version: highestVersion };
578
+ }
579
+ return {
580
+ version: null,
581
+ error: `No Next.js found in ${workspace.type} workspace packages.`
582
+ };
583
+ }
584
+ return {
585
+ version: null,
586
+ error: "Next.js is not installed in this project."
587
+ };
588
+ } catch (err) {
589
+ return {
590
+ version: null,
591
+ error: `Failed to parse package.json: ${err instanceof Error ? err.message : String(err)}`
592
+ };
593
+ }
594
+ }
595
+ var nextjsProvider = {
596
+ name: "nextjs",
597
+ displayName: "Next.js",
598
+ repo: "vercel/next.js",
599
+ docsPath: "docs",
600
+ extensions: [".mdx", ".md"],
601
+ detectVersion,
602
+ versionToTag: (version) => version.startsWith("v") ? version : `v${version}`,
603
+ excludePatterns: ["**/index.mdx", "**/index.md"],
604
+ instruction: "IMPORTANT: Prefer retrieval-led reasoning over pre-training-led reasoning for any Next.js tasks."
605
+ };
606
+
607
+ // src/lib/providers/react.ts
608
+ import fs3 from "fs";
609
+ import path3 from "path";
610
+ function detectVersion2(cwd) {
611
+ const packageJsonPath = path3.join(cwd, "package.json");
612
+ if (!fs3.existsSync(packageJsonPath)) {
613
+ return {
614
+ version: null,
615
+ error: "No package.json found in the current directory"
616
+ };
617
+ }
618
+ try {
619
+ const packageJson = JSON.parse(fs3.readFileSync(packageJsonPath, "utf-8"));
620
+ const dependencies = packageJson.dependencies || {};
621
+ const devDependencies = packageJson.devDependencies || {};
622
+ const reactVersion = dependencies.react || devDependencies.react;
623
+ if (reactVersion) {
624
+ const cleanVersion = reactVersion.replace(/^[\^~>=<]+/, "");
625
+ return { version: cleanVersion };
626
+ }
627
+ return {
628
+ version: null,
629
+ error: "React is not installed in this project."
630
+ };
631
+ } catch (err) {
632
+ return {
633
+ version: null,
634
+ error: `Failed to parse package.json: ${err instanceof Error ? err.message : String(err)}`
635
+ };
636
+ }
637
+ }
638
+ var reactProvider = {
639
+ name: "react",
640
+ displayName: "React",
641
+ repo: "reactjs/react.dev",
642
+ docsPath: "src/content",
643
+ extensions: [".md", ".mdx"],
644
+ detectVersion: detectVersion2,
645
+ versionToTag: (version) => `v${version}`,
646
+ excludePatterns: ["**/index.md"],
647
+ instruction: "IMPORTANT: Prefer retrieval-led reasoning over pre-training-led reasoning for any React tasks."
648
+ };
649
+
650
+ // src/lib/providers/pixi.ts
651
+ import fs4 from "fs";
652
+ import path4 from "path";
653
+ function parsePixiVersion(content) {
654
+ const requiresPixiMatch = content.match(/requires-pixi\s*=\s*["']([^"']+)["']/);
655
+ if (requiresPixiMatch) {
656
+ const versionMatch = requiresPixiMatch[1].match(/[\d]+\.[\d]+\.[\d]+/);
657
+ if (versionMatch) {
658
+ return versionMatch[0];
659
+ }
660
+ }
661
+ return null;
662
+ }
663
+ function detectVersion3(cwd) {
664
+ const pixiTomlPath = path4.join(cwd, "pixi.toml");
665
+ if (fs4.existsSync(pixiTomlPath)) {
666
+ try {
667
+ const content = fs4.readFileSync(pixiTomlPath, "utf-8");
668
+ const version = parsePixiVersion(content);
669
+ if (version) {
670
+ return { version };
671
+ }
672
+ } catch {}
673
+ }
674
+ const pyprojectPath = path4.join(cwd, "pyproject.toml");
675
+ if (fs4.existsSync(pyprojectPath)) {
676
+ try {
677
+ const content = fs4.readFileSync(pyprojectPath, "utf-8");
678
+ if (content.includes("[tool.pixi")) {
679
+ const version = parsePixiVersion(content);
680
+ if (version) {
681
+ return { version };
682
+ }
683
+ }
684
+ } catch {}
685
+ }
686
+ try {
687
+ const { execSync: execSync2 } = __require("child_process");
688
+ const output = execSync2("pixi --version", { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] });
689
+ const versionMatch = output.match(/pixi ([\d]+\.[\d]+\.[\d]+)/);
690
+ if (versionMatch) {
691
+ return { version: versionMatch[1] };
692
+ }
693
+ } catch {}
694
+ return {
695
+ version: null,
696
+ error: "Could not detect pixi version. Use --fw-version to specify."
697
+ };
698
+ }
699
+ var pixiProvider = {
700
+ name: "pixi",
701
+ displayName: "Pixi",
702
+ repo: "prefix-dev/pixi",
703
+ docsPath: "docs",
704
+ extensions: [".md"],
705
+ detectVersion: detectVersion3,
706
+ versionToTag: (version) => version.startsWith("v") ? version : `v${version}`,
707
+ excludePatterns: [
708
+ "**/index.md",
709
+ "**/__README.md",
710
+ "**/partials/**",
711
+ "**/assets/**",
712
+ "**/stylesheets/**",
713
+ "**/javascripts/**",
714
+ "**/overrides/**",
715
+ "**/layouts/**"
716
+ ],
717
+ instruction: "IMPORTANT: Prefer retrieval-led reasoning over pre-training-led reasoning for any pixi tasks. Pixi is a cross-platform package manager for conda environments."
718
+ };
719
+
720
+ // src/lib/providers/rattler-build.ts
721
+ import fs5 from "fs";
722
+ import path5 from "path";
723
+ function detectVersion4(cwd) {
724
+ const pixiTomlPath = path5.join(cwd, "pixi.toml");
725
+ if (fs5.existsSync(pixiTomlPath)) {
726
+ try {
727
+ const content = fs5.readFileSync(pixiTomlPath, "utf-8");
728
+ const match = content.match(/rattler-build\s*=\s*["']([^"']+)["']/);
729
+ if (match) {
730
+ const versionMatch = match[1].match(/[\d]+\.[\d]+\.[\d]+/);
731
+ if (versionMatch) {
732
+ return { version: versionMatch[0] };
733
+ }
734
+ }
735
+ } catch {}
736
+ }
737
+ const pyprojectPath = path5.join(cwd, "pyproject.toml");
738
+ if (fs5.existsSync(pyprojectPath)) {
739
+ try {
740
+ const content = fs5.readFileSync(pyprojectPath, "utf-8");
741
+ const match = content.match(/rattler-build\s*=\s*["']([^"']+)["']/);
742
+ if (match) {
743
+ const versionMatch = match[1].match(/[\d]+\.[\d]+\.[\d]+/);
744
+ if (versionMatch) {
745
+ return { version: versionMatch[0] };
746
+ }
747
+ }
748
+ } catch {}
749
+ }
750
+ try {
751
+ const { execSync: execSync2 } = __require("child_process");
752
+ const output = execSync2("rattler-build --version", {
753
+ encoding: "utf-8",
754
+ stdio: ["pipe", "pipe", "pipe"]
755
+ });
756
+ const versionMatch = output.match(/rattler-build ([\d]+\.[\d]+\.[\d]+)/);
757
+ if (versionMatch) {
758
+ return { version: versionMatch[1] };
759
+ }
760
+ } catch {}
761
+ return {
762
+ version: null,
763
+ error: "Could not detect rattler-build version. Use --fw-version to specify."
764
+ };
765
+ }
766
+ var rattlerBuildProvider = {
767
+ name: "rattler-build",
768
+ displayName: "rattler-build",
769
+ repo: "prefix-dev/rattler-build",
770
+ docsPath: "docs",
771
+ extensions: [".md"],
772
+ detectVersion: detectVersion4,
773
+ versionToTag: (version) => version.startsWith("v") ? version : `v${version}`,
774
+ excludePatterns: [
775
+ "**/index.md",
776
+ "**/assets/**",
777
+ "**/stylesheets/**",
778
+ "**/layouts/**",
779
+ "**/overrides/**",
780
+ "**/generator/**"
781
+ ],
782
+ instruction: "IMPORTANT: Prefer retrieval-led reasoning over pre-training-led reasoning for any rattler-build tasks. rattler-build is a tool for building conda packages from recipe.yaml files."
783
+ };
784
+
785
+ // src/lib/providers/tauri.ts
786
+ import fs6 from "fs";
787
+ import path6 from "path";
788
+ function detectVersion5(cwd) {
789
+ const packageJsonPath = path6.join(cwd, "package.json");
790
+ if (fs6.existsSync(packageJsonPath)) {
791
+ try {
792
+ const content = fs6.readFileSync(packageJsonPath, "utf-8");
793
+ const pkg = JSON.parse(content);
794
+ const deps = { ...pkg.dependencies, ...pkg.devDependencies };
795
+ const tauriApi = deps["@tauri-apps/api"];
796
+ const tauriCli = deps["@tauri-apps/cli"];
797
+ if (tauriApi || tauriCli) {
798
+ const version = tauriApi || tauriCli;
799
+ const versionMatch = version.match(/(\d+)\./);
800
+ if (versionMatch) {
801
+ const major = parseInt(versionMatch[1]);
802
+ return { version: major >= 2 ? "v2" : "v1" };
803
+ }
804
+ return { version: "v2" };
805
+ }
806
+ } catch {}
807
+ }
808
+ const tauriConfPath = path6.join(cwd, "src-tauri", "tauri.conf.json");
809
+ if (fs6.existsSync(tauriConfPath)) {
810
+ return { version: "v2" };
811
+ }
812
+ const cargoTomlPath = path6.join(cwd, "src-tauri", "Cargo.toml");
813
+ if (fs6.existsSync(cargoTomlPath)) {
814
+ try {
815
+ const content = fs6.readFileSync(cargoTomlPath, "utf-8");
816
+ const match = content.match(/tauri\s*=\s*.*?"(\d+)\./);
817
+ if (match) {
818
+ const major = parseInt(match[1]);
819
+ return { version: major >= 2 ? "v2" : "v1" };
820
+ }
821
+ return { version: "v2" };
822
+ } catch {}
823
+ }
824
+ return {
825
+ version: null,
826
+ error: "Could not detect Tauri version. Use --fw-version to specify (v1 or v2)."
827
+ };
828
+ }
829
+ var tauriProvider = {
830
+ name: "tauri",
831
+ displayName: "Tauri",
832
+ repo: "tauri-apps/tauri-docs",
833
+ docsPath: "src/content/docs",
834
+ extensions: [".md", ".mdx"],
835
+ detectVersion: detectVersion5,
836
+ versionToTag: (version) => version,
837
+ excludePatterns: [
838
+ "**/index.mdx",
839
+ "**/index.md",
840
+ "**/_fragments/**",
841
+ "**/_it/**",
842
+ "**/es/**",
843
+ "**/fr/**",
844
+ "**/it/**",
845
+ "**/ja/**",
846
+ "**/ko/**",
847
+ "**/zh-cn/**",
848
+ "**/404.md",
849
+ "**/rss.mdx"
850
+ ],
851
+ instruction: "IMPORTANT: Prefer retrieval-led reasoning over pre-training-led reasoning for any Tauri tasks. Tauri is a framework for building desktop and mobile apps with web frontends."
852
+ };
853
+
854
+ // src/lib/providers/conda-forge.ts
855
+ function detectVersion6(_cwd) {
856
+ return { version: "main" };
857
+ }
858
+ var condaForgeProvider = {
859
+ name: "conda-forge",
860
+ displayName: "conda-forge",
861
+ repo: "conda-forge/conda-forge.github.io",
862
+ docsPath: "docs",
863
+ extensions: [".md", ".mdx"],
864
+ detectVersion: detectVersion6,
865
+ versionToTag: (version) => version,
866
+ excludePatterns: [
867
+ "**/index.md",
868
+ "**/_sidebar.js",
869
+ "**/_sidebar.json",
870
+ "**/_sidebar_diataxis.json"
871
+ ],
872
+ instruction: "IMPORTANT: Prefer retrieval-led reasoning over pre-training-led reasoning for any conda-forge tasks. conda-forge is a community-led collection of recipes, build infrastructure, and packages for conda."
873
+ };
874
+
875
+ // src/lib/providers/bun.ts
876
+ import fs7 from "fs";
877
+ import path7 from "path";
878
+ import { execSync as execSync2 } from "child_process";
879
+ function detectVersion7(cwd) {
880
+ const bunLockPath = path7.join(cwd, "bun.lockb");
881
+ const hasBunLock = fs7.existsSync(bunLockPath);
882
+ const bunfigPath = path7.join(cwd, "bunfig.toml");
883
+ const hasBunfig = fs7.existsSync(bunfigPath);
884
+ if (!hasBunLock && !hasBunfig) {
885
+ return {
886
+ version: null,
887
+ error: "No bun.lockb or bunfig.toml found in the current directory"
888
+ };
889
+ }
890
+ try {
891
+ const output = execSync2("bun --version", { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] });
892
+ const versionMatch = output.match(/([\d]+\.[\d]+\.[\d]+)/);
893
+ if (versionMatch) {
894
+ return { version: versionMatch[1] };
895
+ }
896
+ } catch {}
897
+ return {
898
+ version: null,
899
+ error: "Bun project detected but could not determine version. Please specify with --fw-version."
900
+ };
901
+ }
902
+ var bunProvider = {
903
+ name: "bun",
904
+ displayName: "Bun",
905
+ repo: "oven-sh/bun",
906
+ docsPath: "docs",
907
+ extensions: [".md", ".mdx"],
908
+ detectVersion: detectVersion7,
909
+ versionToTag: (version) => `bun-v${version}`,
910
+ excludePatterns: ["**/README.md"],
911
+ instruction: "IMPORTANT: Prefer retrieval-led reasoning over pre-training-led reasoning for any Bun tasks."
912
+ };
913
+
914
+ // src/lib/providers/generic.ts
915
+ import fs8 from "fs";
916
+ import path8 from "path";
917
+ function createProvider(options) {
918
+ const {
919
+ name,
920
+ displayName,
921
+ repo,
922
+ docsPath,
923
+ extensions = [".mdx", ".md"],
924
+ packageName,
925
+ versionToTag = (v) => v.startsWith("v") ? v : `v${v}`,
926
+ excludePatterns = ["**/index.mdx", "**/index.md"],
927
+ instruction
928
+ } = options;
929
+ const detectVersion8 = packageName ? (cwd) => {
930
+ const packageJsonPath = path8.join(cwd, "package.json");
931
+ if (!fs8.existsSync(packageJsonPath)) {
932
+ return {
933
+ version: null,
934
+ error: "No package.json found in the current directory"
935
+ };
936
+ }
937
+ try {
938
+ const packageJson = JSON.parse(fs8.readFileSync(packageJsonPath, "utf-8"));
939
+ const dependencies = packageJson.dependencies || {};
940
+ const devDependencies = packageJson.devDependencies || {};
941
+ const version = dependencies[packageName] || devDependencies[packageName];
942
+ if (version) {
943
+ const cleanVersion = version.replace(/^[\^~>=<]+/, "");
944
+ return { version: cleanVersion };
945
+ }
946
+ return {
947
+ version: null,
948
+ error: `${displayName} (${packageName}) is not installed in this project.`
949
+ };
950
+ } catch (err) {
951
+ return {
952
+ version: null,
953
+ error: `Failed to parse package.json: ${err instanceof Error ? err.message : String(err)}`
954
+ };
955
+ }
956
+ } : undefined;
957
+ return {
958
+ name,
959
+ displayName,
960
+ repo,
961
+ docsPath,
962
+ extensions,
963
+ detectVersion: detectVersion8,
964
+ versionToTag,
965
+ excludePatterns,
966
+ instruction: instruction || `IMPORTANT: Prefer retrieval-led reasoning over pre-training-led reasoning for any ${displayName} tasks.`
967
+ };
968
+ }
969
+ function createLocalProvider(options) {
970
+ return {
971
+ name: options.name,
972
+ displayName: options.displayName,
973
+ repo: "",
974
+ docsPath: options.localPath,
975
+ extensions: options.extensions || [".mdx", ".md"],
976
+ excludePatterns: options.excludePatterns || ["**/index.mdx", "**/index.md"],
977
+ instruction: options.instruction || `IMPORTANT: Prefer retrieval-led reasoning over pre-training-led reasoning for any ${options.displayName} tasks.`
978
+ };
979
+ }
980
+ // src/lib/providers/index.ts
981
+ function getProvider(preset) {
982
+ switch (preset) {
983
+ case "nextjs":
984
+ return nextjsProvider;
985
+ case "react":
986
+ return reactProvider;
987
+ case "pixi":
988
+ return pixiProvider;
989
+ case "rattler-build":
990
+ return rattlerBuildProvider;
991
+ case "tauri":
992
+ return tauriProvider;
993
+ case "conda-forge":
994
+ return condaForgeProvider;
995
+ case "bun":
996
+ return bunProvider;
997
+ case "vue":
998
+ case "svelte":
999
+ case "astro":
1000
+ return null;
1001
+ default:
1002
+ return null;
1003
+ }
1004
+ }
1005
+ function listProviders() {
1006
+ return ["nextjs", "react", "pixi", "rattler-build", "tauri", "conda-forge", "bun", "vue", "svelte", "astro"];
1007
+ }
1008
+ function isProviderAvailable(preset) {
1009
+ return getProvider(preset) !== null;
1010
+ }
1011
+
1012
+ // src/lib/skills.ts
1013
+ import fs9 from "fs";
1014
+ import path9 from "path";
1015
+ import os2 from "os";
1016
+ var SKILLS_START_MARKER = "<!-- AGENTS-MD-SKILLS-START -->";
1017
+ var SKILLS_END_MARKER = "<!-- AGENTS-MD-SKILLS-END -->";
1018
+ function parseSkillFrontmatter(content) {
1019
+ const match = content.match(/^---\s*\n([\s\S]*?)\n---/);
1020
+ if (!match)
1021
+ return null;
1022
+ const frontmatter = match[1];
1023
+ const result = { name: "", description: "" };
1024
+ const nameMatch = frontmatter.match(/^name:\s*(.+)$/m);
1025
+ const descMatch = frontmatter.match(/^description:\s*(.+)$/m);
1026
+ if (nameMatch) {
1027
+ result.name = nameMatch[1].trim().replace(/^["']|["']$/g, "");
1028
+ }
1029
+ if (descMatch) {
1030
+ result.description = descMatch[1].trim().replace(/^["']|["']$/g, "");
1031
+ }
1032
+ if (!result.name || !result.description) {
1033
+ return null;
1034
+ }
1035
+ return result;
1036
+ }
1037
+ function getSiblingFiles(skillMdPath) {
1038
+ const dir = path9.dirname(skillMdPath);
1039
+ if (!fs9.existsSync(dir))
1040
+ return [];
1041
+ try {
1042
+ const files = fs9.readdirSync(dir);
1043
+ return files.filter((f) => f !== "SKILL.md" && !f.startsWith(".")).sort();
1044
+ } catch {
1045
+ return [];
1046
+ }
1047
+ }
1048
+ function discoverPluginSkills(pluginsPath, label) {
1049
+ const skills = [];
1050
+ const pluginsDir = path9.join(pluginsPath, "plugins");
1051
+ if (!fs9.existsSync(pluginsDir)) {
1052
+ return skills;
1053
+ }
1054
+ const plugins = fs9.readdirSync(pluginsDir, { withFileTypes: true }).filter((d) => d.isDirectory());
1055
+ for (const plugin of plugins) {
1056
+ const skillsDir = path9.join(pluginsDir, plugin.name, "skills");
1057
+ if (!fs9.existsSync(skillsDir))
1058
+ continue;
1059
+ const skillDirs = fs9.readdirSync(skillsDir, { withFileTypes: true }).filter((d) => d.isDirectory());
1060
+ for (const skillDir of skillDirs) {
1061
+ const skillMdPath = path9.join(skillsDir, skillDir.name, "SKILL.md");
1062
+ if (!fs9.existsSync(skillMdPath))
1063
+ continue;
1064
+ try {
1065
+ const content = fs9.readFileSync(skillMdPath, "utf-8");
1066
+ const frontmatter = parseSkillFrontmatter(content);
1067
+ if (!frontmatter)
1068
+ continue;
1069
+ skills.push({
1070
+ name: frontmatter.name,
1071
+ description: frontmatter.description,
1072
+ skillMdPath,
1073
+ siblingFiles: getSiblingFiles(skillMdPath),
1074
+ source: "plugin",
1075
+ pluginName: plugin.name
1076
+ });
1077
+ } catch {}
1078
+ }
1079
+ }
1080
+ return skills;
1081
+ }
1082
+ function discoverFlatSkills(skillsPath, source, label) {
1083
+ const skills = [];
1084
+ if (!fs9.existsSync(skillsPath)) {
1085
+ return skills;
1086
+ }
1087
+ const skillDirs = fs9.readdirSync(skillsPath, { withFileTypes: true }).filter((d) => d.isDirectory());
1088
+ for (const skillDir of skillDirs) {
1089
+ const skillMdPath = path9.join(skillsPath, skillDir.name, "SKILL.md");
1090
+ if (!fs9.existsSync(skillMdPath))
1091
+ continue;
1092
+ try {
1093
+ const content = fs9.readFileSync(skillMdPath, "utf-8");
1094
+ const frontmatter = parseSkillFrontmatter(content);
1095
+ if (!frontmatter)
1096
+ continue;
1097
+ skills.push({
1098
+ name: frontmatter.name,
1099
+ description: frontmatter.description,
1100
+ skillMdPath,
1101
+ siblingFiles: getSiblingFiles(skillMdPath),
1102
+ source
1103
+ });
1104
+ } catch {}
1105
+ }
1106
+ return skills;
1107
+ }
1108
+ function collectAllSkills(sources) {
1109
+ const allSkills = [];
1110
+ for (const source of sources) {
1111
+ if (source.type === "plugin") {
1112
+ allSkills.push(...discoverPluginSkills(source.path, source.label));
1113
+ } else {
1114
+ allSkills.push(...discoverFlatSkills(source.path, source.type, source.label));
1115
+ }
1116
+ }
1117
+ return allSkills;
1118
+ }
1119
+ function generateSkillsIndex(skills, options = {}) {
1120
+ const parts = ["[Skills Index]"];
1121
+ const pluginSkills = new Map;
1122
+ const userSkills = [];
1123
+ const projectSkills = [];
1124
+ for (const skill of skills) {
1125
+ if (skill.source === "plugin" && skill.pluginName) {
1126
+ const existing = pluginSkills.get(skill.pluginName) || [];
1127
+ existing.push(skill);
1128
+ pluginSkills.set(skill.pluginName, existing);
1129
+ } else if (skill.source === "user") {
1130
+ userSkills.push(skill);
1131
+ } else if (skill.source === "project") {
1132
+ projectSkills.push(skill);
1133
+ }
1134
+ }
1135
+ for (const [pluginName, entries] of pluginSkills) {
1136
+ const skillParts = entries.map((s) => formatSkillEntry(s)).join(";");
1137
+ parts.push(`plugin:${pluginName}:{${skillParts}}`);
1138
+ }
1139
+ if (userSkills.length > 0) {
1140
+ const skillParts = userSkills.map((s) => formatSkillEntry(s)).join(";");
1141
+ parts.push(`user:{${skillParts}}`);
1142
+ }
1143
+ if (projectSkills.length > 0) {
1144
+ const skillParts = projectSkills.map((s) => formatSkillEntry(s)).join(";");
1145
+ parts.push(`project:{${skillParts}}`);
1146
+ }
1147
+ const cmd = options.regenerateCommand || "npx agdex skills embed";
1148
+ parts.push(`Regen: ${cmd}`);
1149
+ return parts.join("|");
1150
+ }
1151
+ function formatSkillEntry(skill) {
1152
+ const desc = skill.description.replace(/\|/g, "\\|").replace(/;/g, "\\;").replace(/:/g, "\\:").replace(/\[/g, "\\[").replace(/\]/g, "\\]").replace(/\{/g, "\\{").replace(/\}/g, "\\}");
1153
+ if (skill.siblingFiles.length > 0) {
1154
+ return `${skill.name}:${desc}[${skill.siblingFiles.join(",")}]`;
1155
+ }
1156
+ return `${skill.name}:${desc}`;
1157
+ }
1158
+ function hasExistingSkillsIndex(content) {
1159
+ return content.includes(SKILLS_START_MARKER);
1160
+ }
1161
+ function removeSkillsIndex(content) {
1162
+ if (!hasExistingSkillsIndex(content)) {
1163
+ return content;
1164
+ }
1165
+ const startIdx = content.indexOf(SKILLS_START_MARKER);
1166
+ const endIdx = content.indexOf(SKILLS_END_MARKER) + SKILLS_END_MARKER.length;
1167
+ let result = content.slice(0, startIdx) + content.slice(endIdx);
1168
+ result = result.replace(/\n{3,}/g, `
1169
+
1170
+ `);
1171
+ result = result.trimEnd();
1172
+ if (result.length > 0) {
1173
+ result += `
1174
+ `;
1175
+ }
1176
+ return result;
1177
+ }
1178
+ function injectSkillsIndex(existingContent, indexContent) {
1179
+ const wrappedContent = `${SKILLS_START_MARKER}
1180
+ ${indexContent}
1181
+ ${SKILLS_END_MARKER}`;
1182
+ if (hasExistingSkillsIndex(existingContent)) {
1183
+ const startIdx = existingContent.indexOf(SKILLS_START_MARKER);
1184
+ const endIdx = existingContent.indexOf(SKILLS_END_MARKER) + SKILLS_END_MARKER.length;
1185
+ return existingContent.slice(0, startIdx) + wrappedContent + existingContent.slice(endIdx);
1186
+ }
1187
+ const separator = existingContent.endsWith(`
1188
+ `) ? `
1189
+ ` : `
1190
+
1191
+ `;
1192
+ return existingContent + separator + wrappedContent + `
1193
+ `;
1194
+ }
1195
+ function getDefaultSkillSources(cwd, options = {}) {
1196
+ const sources = [];
1197
+ const {
1198
+ includeUser = true,
1199
+ includeProject = true,
1200
+ pluginPaths = []
1201
+ } = options;
1202
+ for (const pluginPath of pluginPaths) {
1203
+ sources.push({
1204
+ type: "plugin",
1205
+ path: pluginPath,
1206
+ label: path9.basename(pluginPath)
1207
+ });
1208
+ }
1209
+ if (includeUser) {
1210
+ const userSkillsPath = path9.join(os2.homedir(), ".claude", "skills");
1211
+ sources.push({
1212
+ type: "user",
1213
+ path: userSkillsPath,
1214
+ label: "user"
1215
+ });
1216
+ }
1217
+ if (includeProject) {
1218
+ const projectSkillsPath = path9.join(cwd, ".claude", "skills");
1219
+ sources.push({
1220
+ type: "project",
1221
+ path: projectSkillsPath,
1222
+ label: "project"
1223
+ });
1224
+ }
1225
+ return sources;
1226
+ }
1227
+ async function embedSkills(options) {
1228
+ const { cwd, sources, output = "AGENTS.md" } = options;
1229
+ const targetPath = path9.join(cwd, output);
1230
+ let sizeBefore = 0;
1231
+ let isNewFile = true;
1232
+ let existingContent = "";
1233
+ if (fs9.existsSync(targetPath)) {
1234
+ existingContent = fs9.readFileSync(targetPath, "utf-8");
1235
+ sizeBefore = Buffer.byteLength(existingContent, "utf-8");
1236
+ isNewFile = false;
1237
+ }
1238
+ const skills = collectAllSkills(sources);
1239
+ if (skills.length === 0) {
1240
+ return {
1241
+ success: false,
1242
+ error: "No skills found in any of the specified sources"
1243
+ };
1244
+ }
1245
+ const sourceBreakdown = {
1246
+ plugin: 0,
1247
+ user: 0,
1248
+ project: 0
1249
+ };
1250
+ for (const skill of skills) {
1251
+ sourceBreakdown[skill.source]++;
1252
+ }
1253
+ const indexContent = generateSkillsIndex(skills, {
1254
+ regenerateCommand: `npx agdex skills embed`
1255
+ });
1256
+ const newContent = injectSkillsIndex(existingContent, indexContent);
1257
+ fs9.writeFileSync(targetPath, newContent, "utf-8");
1258
+ const sizeAfter = Buffer.byteLength(newContent, "utf-8");
1259
+ return {
1260
+ success: true,
1261
+ targetFile: output,
1262
+ skillCount: skills.length,
1263
+ sizeBefore,
1264
+ sizeAfter,
1265
+ isNewFile,
1266
+ sourceBreakdown
1267
+ };
1268
+ }
1269
+
1270
+ export { __toESM, __commonJS, __require, pullDocs, collectDocFiles, buildDocTree, generateIndex, hasExistingIndex, removeDocsIndex, injectIndex, ensureGitignoreEntry, getGlobalCacheDir, getLocalCacheDir, embed, nextjsProvider, reactProvider, pixiProvider, rattlerBuildProvider, tauriProvider, condaForgeProvider, bunProvider, createProvider, createLocalProvider, getProvider, listProviders, isProviderAvailable, parseSkillFrontmatter, discoverPluginSkills, discoverFlatSkills, collectAllSkills, generateSkillsIndex, hasExistingSkillsIndex, removeSkillsIndex, injectSkillsIndex, getDefaultSkillSources, embedSkills };