agdex 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli/index.js CHANGED
@@ -24,7 +24,7 @@ import {
24
24
  removeDocsIndex,
25
25
  removeSkillsIndex,
26
26
  tauriProvider
27
- } from "../index-k299aha0.js";
27
+ } from "../index-cfpc7eqp.js";
28
28
 
29
29
  // node_modules/commander/lib/error.js
30
30
  var require_error = __commonJS((exports) => {
@@ -7111,7 +7111,8 @@ Building index from ${import_picocolors.default.cyan(docsPath)}...`);
7111
7111
  instruction: `IMPORTANT: Prefer retrieval-led reasoning over pre-training-led reasoning for any ${name} tasks.`,
7112
7112
  regenerateCommand: `npx agdex local ${docsPath} --name "${name}" --output ${output}`
7113
7113
  });
7114
- const newContent = injectIndex(existingContent, indexContent);
7114
+ const providerName = name.toLowerCase().replace(/\s+/g, "-");
7115
+ const newContent = injectIndex(existingContent, indexContent, providerName);
7115
7116
  fs.writeFileSync(targetPath, newContent, "utf-8");
7116
7117
  const sizeAfter = Buffer.byteLength(newContent, "utf-8");
7117
7118
  const action = isNewFile ? "Created" : "Updated";
@@ -7135,7 +7136,7 @@ Available documentation providers:
7135
7136
  console.log(import_picocolors.default.gray("Use --repo and --docs-path for custom repositories"));
7136
7137
  console.log("");
7137
7138
  }
7138
- program2.name("agdex").description("Embed compressed documentation indexes into AGENTS.md/CLAUDE.md for AI coding agents").version("0.1.0");
7139
+ program2.name("agdex").description("Embed compressed documentation indexes into AGENTS.md/CLAUDE.md for AI coding agents").version("0.2.0");
7139
7140
  program2.command("embed", { isDefault: true }).description("Embed documentation index into AGENTS.md/CLAUDE.md").option("-p, --provider <name>", "Documentation provider (nextjs, react, etc.)").option("--fw-version <version>", "Framework version (auto-detected if not provided)").option("-o, --output <file>", "Target file (default: AGENTS.md)").option("--repo <owner/repo>", "Custom GitHub repository").option("--docs-path <path>", "Path to docs folder in repository").option("-g, --global", "Store docs in global cache (~/.cache/agdex/) instead of local .agdex/").action(runEmbed);
7140
7141
  program2.command("local <docs-path>").description("Build index from local documentation directory").option("-n, --name <name>", "Display name for the documentation").option("-o, --output <file>", "Target file (default: AGENTS.md)").option("-e, --extensions <exts>", "File extensions to include (comma-separated, default: .md,.mdx)").action(runLocal);
7141
7142
  program2.command("list").description("List available documentation providers").action(runList);
@@ -7154,8 +7155,8 @@ function runRemove(options) {
7154
7155
  const removeSkillsIdx = removeAll || options.skills;
7155
7156
  let docsRemoved = false;
7156
7157
  let skillsRemoved = false;
7157
- if (removeDocs && hasExistingIndex(content)) {
7158
- content = removeDocsIndex(content);
7158
+ if (removeDocs && hasExistingIndex(content, options.provider)) {
7159
+ content = removeDocsIndex(content, options.provider);
7159
7160
  docsRemoved = true;
7160
7161
  }
7161
7162
  if (removeSkillsIdx && hasExistingSkillsIndex(content)) {
@@ -7172,7 +7173,8 @@ No indices found to remove.
7172
7173
  const sizeAfter = Buffer.byteLength(content, "utf-8");
7173
7174
  console.log("");
7174
7175
  if (docsRemoved) {
7175
- console.log(`${import_picocolors.default.green("✓")} Removed docs index from ${import_picocolors.default.bold(output)}`);
7176
+ const providerInfo = options.provider ? ` (${options.provider})` : " (all providers)";
7177
+ console.log(`${import_picocolors.default.green("✓")} Removed docs index${providerInfo} from ${import_picocolors.default.bold(output)}`);
7176
7178
  }
7177
7179
  if (skillsRemoved) {
7178
7180
  console.log(`${import_picocolors.default.green("✓")} Removed skills index from ${import_picocolors.default.bold(output)}`);
@@ -7180,7 +7182,7 @@ No indices found to remove.
7180
7182
  console.log(import_picocolors.default.gray(` (${formatSize(sizeBefore)} → ${formatSize(sizeAfter)})`));
7181
7183
  console.log("");
7182
7184
  }
7183
- program2.command("remove").description("Remove embedded indices from AGENTS.md/CLAUDE.md").option("-o, --output <file>", "Target file (default: AGENTS.md)").option("--docs", "Remove only docs index").option("--skills", "Remove only skills index").action(runRemove);
7185
+ program2.command("remove").description("Remove embedded indices from AGENTS.md/CLAUDE.md").option("-o, --output <file>", "Target file (default: AGENTS.md)").option("--docs", "Remove only docs index").option("--skills", "Remove only skills index").option("-p, --provider <name>", "Remove only a specific provider's docs index").action(runRemove);
7184
7186
  var skillsCommand = program2.command("skills").description("Manage Claude Code skills indexing");
7185
7187
  async function runSkillsEmbed(options) {
7186
7188
  const cwd = process.cwd();
@@ -0,0 +1,1265 @@
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, 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
+ const targetFile = outputFile || "AGENTS.md";
207
+ const cmd = regenerateCommand || `npx agdex --output ${targetFile}`;
208
+ parts.push(`If docs missing, run: ${cmd}`);
209
+ const allFiles = collectAllFilesFromSections(sections);
210
+ const grouped = groupByDirectory(allFiles);
211
+ for (const [dir, files] of grouped) {
212
+ parts.push(`${dir}:{${files.join(",")}}`);
213
+ }
214
+ return parts.join("|");
215
+ }
216
+ function collectAllFilesFromSections(sections) {
217
+ const files = [];
218
+ for (const section of sections) {
219
+ for (const file of section.files) {
220
+ files.push(file.relativePath);
221
+ }
222
+ files.push(...collectAllFilesFromSections(section.subsections));
223
+ }
224
+ return files;
225
+ }
226
+ function groupByDirectory(files) {
227
+ const grouped = new Map;
228
+ for (const filePath of files) {
229
+ const lastSlash = filePath.lastIndexOf("/");
230
+ const dir = lastSlash === -1 ? "." : filePath.slice(0, lastSlash);
231
+ const fileName = lastSlash === -1 ? filePath : filePath.slice(lastSlash + 1);
232
+ const existing = grouped.get(dir);
233
+ if (existing) {
234
+ existing.push(fileName);
235
+ } else {
236
+ grouped.set(dir, [fileName]);
237
+ }
238
+ }
239
+ return grouped;
240
+ }
241
+ function hasExistingIndex(content, providerName) {
242
+ if (providerName) {
243
+ return content.includes(getStartMarker(providerName));
244
+ }
245
+ return content.includes(START_MARKER_PREFIX);
246
+ }
247
+ function removeDocsIndex(content, providerName) {
248
+ if (!hasExistingIndex(content, providerName)) {
249
+ return content;
250
+ }
251
+ let result = content;
252
+ if (providerName) {
253
+ const startMarker = getStartMarker(providerName);
254
+ const endMarker = getEndMarker(providerName);
255
+ const startIdx = result.indexOf(startMarker);
256
+ const endIdx = result.indexOf(endMarker) + endMarker.length;
257
+ if (startIdx !== -1 && endIdx > startIdx) {
258
+ result = result.slice(0, startIdx) + result.slice(endIdx);
259
+ }
260
+ } else {
261
+ let startIdx;
262
+ while ((startIdx = result.indexOf(START_MARKER_PREFIX)) !== -1) {
263
+ const startMarkerEnd = result.indexOf(MARKER_SUFFIX, startIdx) + MARKER_SUFFIX.length;
264
+ const startMarkerContent = result.slice(startIdx, startMarkerEnd);
265
+ const providerMatch = startMarkerContent.match(/:([^-\s]+)/);
266
+ const provider = providerMatch ? providerMatch[1] : undefined;
267
+ const endMarker = getEndMarker(provider);
268
+ const endIdx = result.indexOf(endMarker);
269
+ if (endIdx !== -1) {
270
+ result = result.slice(0, startIdx) + result.slice(endIdx + endMarker.length);
271
+ } else {
272
+ result = result.slice(0, startIdx) + result.slice(startMarkerEnd);
273
+ }
274
+ }
275
+ }
276
+ result = result.replace(/\n{3,}/g, `
277
+
278
+ `);
279
+ result = result.trimEnd();
280
+ if (result.length > 0) {
281
+ result += `
282
+ `;
283
+ }
284
+ return result;
285
+ }
286
+ function wrapWithMarkers(content, providerName) {
287
+ const startMarker = getStartMarker(providerName);
288
+ const endMarker = getEndMarker(providerName);
289
+ return `${startMarker}
290
+ ${content}
291
+ ${endMarker}`;
292
+ }
293
+ function injectIndex(existingContent, indexContent, providerName) {
294
+ const wrappedContent = wrapWithMarkers(indexContent, providerName);
295
+ if (hasExistingIndex(existingContent, providerName)) {
296
+ const startMarker = getStartMarker(providerName);
297
+ const endMarker = getEndMarker(providerName);
298
+ const startIdx = existingContent.indexOf(startMarker);
299
+ const endIdx = existingContent.indexOf(endMarker) + endMarker.length;
300
+ return existingContent.slice(0, startIdx) + wrappedContent + existingContent.slice(endIdx);
301
+ }
302
+ const separator = existingContent.endsWith(`
303
+ `) ? `
304
+ ` : `
305
+
306
+ `;
307
+ return existingContent + separator + wrappedContent + `
308
+ `;
309
+ }
310
+ function ensureGitignoreEntry(cwd, docsDir) {
311
+ const gitignorePath = path.join(cwd, ".gitignore");
312
+ const entry = docsDir.endsWith("/") ? docsDir : `${docsDir}/`;
313
+ const entryRegex = new RegExp(`^\\s*${docsDir.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}(?:/.*)?$`);
314
+ let content = "";
315
+ if (fs.existsSync(gitignorePath)) {
316
+ content = fs.readFileSync(gitignorePath, "utf-8");
317
+ }
318
+ const hasEntry = content.split(/\r?\n/).some((line) => entryRegex.test(line));
319
+ if (hasEntry) {
320
+ return { path: gitignorePath, updated: false, alreadyPresent: true };
321
+ }
322
+ const needsNewline = content.length > 0 && !content.endsWith(`
323
+ `);
324
+ const header = content.includes("# agdex") ? "" : `# agdex
325
+ `;
326
+ const newContent = content + (needsNewline ? `
327
+ ` : "") + header + `${entry}
328
+ `;
329
+ fs.writeFileSync(gitignorePath, newContent, "utf-8");
330
+ return { path: gitignorePath, updated: true, alreadyPresent: false };
331
+ }
332
+ function getGlobalCacheDir() {
333
+ return path.join(os.homedir(), ".cache", "agdex");
334
+ }
335
+ function getLocalCacheDir(cwd) {
336
+ return path.join(cwd, ".agdex");
337
+ }
338
+ async function embed(options) {
339
+ const {
340
+ cwd,
341
+ provider,
342
+ version,
343
+ output = "AGENTS.md",
344
+ docsDir: customDocsDir,
345
+ globalCache = false
346
+ } = options;
347
+ let docsPath;
348
+ let docsLinkPath;
349
+ let docsDir;
350
+ if (customDocsDir) {
351
+ docsDir = customDocsDir;
352
+ docsPath = path.isAbsolute(customDocsDir) ? customDocsDir : path.join(cwd, customDocsDir);
353
+ docsLinkPath = path.isAbsolute(customDocsDir) ? customDocsDir : `./${customDocsDir}`;
354
+ } else if (globalCache) {
355
+ const cacheBase = getGlobalCacheDir();
356
+ docsDir = path.join(cacheBase, provider.name);
357
+ docsPath = docsDir;
358
+ docsLinkPath = docsPath;
359
+ } else {
360
+ docsDir = `.agdex/${provider.name}`;
361
+ docsPath = path.join(cwd, docsDir);
362
+ docsLinkPath = `./${docsDir}`;
363
+ }
364
+ const targetPath = path.join(cwd, output);
365
+ let sizeBefore = 0;
366
+ let isNewFile = true;
367
+ let existingContent = "";
368
+ if (fs.existsSync(targetPath)) {
369
+ existingContent = fs.readFileSync(targetPath, "utf-8");
370
+ sizeBefore = Buffer.byteLength(existingContent, "utf-8");
371
+ isNewFile = false;
372
+ }
373
+ const pullResult = await pullDocs(provider, {
374
+ cwd,
375
+ version,
376
+ docsDir: docsPath
377
+ });
378
+ if (!pullResult.success) {
379
+ return {
380
+ success: false,
381
+ error: pullResult.error
382
+ };
383
+ }
384
+ const docFiles = collectDocFiles(docsPath, {
385
+ extensions: provider.extensions,
386
+ excludePatterns: provider.excludePatterns
387
+ });
388
+ const sections = buildDocTree(docFiles);
389
+ const globalFlag = globalCache ? " --global" : "";
390
+ const regenerateCommand = `npx agdex --provider ${provider.name} --output ${output}${globalFlag}`;
391
+ const indexContent = generateIndex({
392
+ docsPath: docsLinkPath,
393
+ sections,
394
+ outputFile: output,
395
+ providerName: provider.displayName,
396
+ instruction: provider.instruction,
397
+ regenerateCommand
398
+ });
399
+ const newContent = injectIndex(existingContent, indexContent, provider.name);
400
+ fs.writeFileSync(targetPath, newContent, "utf-8");
401
+ const sizeAfter = Buffer.byteLength(newContent, "utf-8");
402
+ let gitignoreUpdated = false;
403
+ if (!globalCache && !customDocsDir) {
404
+ const gitignoreResult = ensureGitignoreEntry(cwd, ".agdex");
405
+ gitignoreUpdated = gitignoreResult.updated;
406
+ } else if (!globalCache && customDocsDir && !path.isAbsolute(customDocsDir)) {
407
+ const gitignoreResult = ensureGitignoreEntry(cwd, customDocsDir);
408
+ gitignoreUpdated = gitignoreResult.updated;
409
+ }
410
+ return {
411
+ success: true,
412
+ targetFile: output,
413
+ docsPath: globalCache ? docsPath : docsDir,
414
+ version: pullResult.version,
415
+ sizeBefore,
416
+ sizeAfter,
417
+ isNewFile,
418
+ gitignoreUpdated
419
+ };
420
+ }
421
+
422
+ // src/lib/providers/nextjs.ts
423
+ import fs2 from "fs";
424
+ import path2 from "path";
425
+ function detectWorkspace(cwd) {
426
+ const packageJsonPath = path2.join(cwd, "package.json");
427
+ const pnpmWorkspacePath = path2.join(cwd, "pnpm-workspace.yaml");
428
+ if (fs2.existsSync(pnpmWorkspacePath)) {
429
+ const packages = parsePnpmWorkspace(pnpmWorkspacePath);
430
+ if (packages.length > 0) {
431
+ return { isMonorepo: true, type: "pnpm", packages };
432
+ }
433
+ }
434
+ if (fs2.existsSync(packageJsonPath)) {
435
+ const packages = parsePackageJsonWorkspaces(packageJsonPath);
436
+ if (packages.length > 0) {
437
+ return { isMonorepo: true, type: "npm", packages };
438
+ }
439
+ }
440
+ return { isMonorepo: false, type: null, packages: [] };
441
+ }
442
+ function parsePnpmWorkspace(filePath) {
443
+ try {
444
+ const content = fs2.readFileSync(filePath, "utf-8");
445
+ const lines = content.split(`
446
+ `);
447
+ const packages = [];
448
+ let inPackages = false;
449
+ for (const line of lines) {
450
+ const trimmed = line.trim();
451
+ if (trimmed === "packages:") {
452
+ inPackages = true;
453
+ continue;
454
+ }
455
+ if (inPackages) {
456
+ if (trimmed && !trimmed.startsWith("-") && !trimmed.startsWith("#")) {
457
+ break;
458
+ }
459
+ const match = trimmed.match(/^-\s*['"]?([^'"]+)['"]?$/);
460
+ if (match) {
461
+ packages.push(match[1]);
462
+ }
463
+ }
464
+ }
465
+ return packages;
466
+ } catch {
467
+ return [];
468
+ }
469
+ }
470
+ function parsePackageJsonWorkspaces(filePath) {
471
+ try {
472
+ const content = fs2.readFileSync(filePath, "utf-8");
473
+ const pkg = JSON.parse(content);
474
+ if (Array.isArray(pkg.workspaces)) {
475
+ return pkg.workspaces;
476
+ }
477
+ if (pkg.workspaces?.packages && Array.isArray(pkg.workspaces.packages)) {
478
+ return pkg.workspaces.packages;
479
+ }
480
+ return [];
481
+ } catch {
482
+ return [];
483
+ }
484
+ }
485
+ function expandWorkspacePatterns(cwd, patterns) {
486
+ const packagePaths = [];
487
+ for (const pattern of patterns) {
488
+ if (pattern.startsWith("!"))
489
+ continue;
490
+ if (pattern.includes("*")) {
491
+ const basePath = path2.join(cwd, pattern.replace("/*", "").replace("/**", ""));
492
+ if (fs2.existsSync(basePath)) {
493
+ try {
494
+ const entries = fs2.readdirSync(basePath);
495
+ for (const entry of entries) {
496
+ const fullPath = path2.join(basePath, entry);
497
+ if (fs2.statSync(fullPath).isDirectory()) {
498
+ packagePaths.push(fullPath);
499
+ }
500
+ }
501
+ } catch {}
502
+ }
503
+ } else {
504
+ const fullPath = path2.join(cwd, pattern);
505
+ if (fs2.existsSync(fullPath)) {
506
+ packagePaths.push(fullPath);
507
+ }
508
+ }
509
+ }
510
+ return [...new Set(packagePaths)];
511
+ }
512
+ function compareVersions(a, b) {
513
+ const parseVersion = (v) => {
514
+ const match = v.match(/^(\d+)\.(\d+)\.(\d+)/);
515
+ if (!match)
516
+ return [0, 0, 0];
517
+ return [parseInt(match[1]), parseInt(match[2]), parseInt(match[3])];
518
+ };
519
+ const [aMajor, aMinor, aPatch] = parseVersion(a);
520
+ const [bMajor, bMinor, bPatch] = parseVersion(b);
521
+ if (aMajor !== bMajor)
522
+ return aMajor - bMajor;
523
+ if (aMinor !== bMinor)
524
+ return aMinor - bMinor;
525
+ return aPatch - bPatch;
526
+ }
527
+ function findNextjsInWorkspace(cwd, patterns) {
528
+ const packagePaths = expandWorkspacePatterns(cwd, patterns);
529
+ const versions = [];
530
+ for (const pkgPath of packagePaths) {
531
+ const packageJsonPath = path2.join(pkgPath, "package.json");
532
+ if (!fs2.existsSync(packageJsonPath))
533
+ continue;
534
+ try {
535
+ const content = fs2.readFileSync(packageJsonPath, "utf-8");
536
+ const pkg = JSON.parse(content);
537
+ const nextVersion = pkg.dependencies?.next || pkg.devDependencies?.next;
538
+ if (nextVersion) {
539
+ versions.push(nextVersion.replace(/^[\^~>=<]+/, ""));
540
+ }
541
+ } catch {}
542
+ }
543
+ if (versions.length === 0)
544
+ return null;
545
+ if (versions.length === 1)
546
+ return versions[0];
547
+ return versions.reduce((highest, current) => {
548
+ return compareVersions(current, highest) > 0 ? current : highest;
549
+ });
550
+ }
551
+ function detectVersion(cwd) {
552
+ const packageJsonPath = path2.join(cwd, "package.json");
553
+ if (!fs2.existsSync(packageJsonPath)) {
554
+ return {
555
+ version: null,
556
+ error: "No package.json found in the current directory"
557
+ };
558
+ }
559
+ try {
560
+ const packageJson = JSON.parse(fs2.readFileSync(packageJsonPath, "utf-8"));
561
+ const dependencies = packageJson.dependencies || {};
562
+ const devDependencies = packageJson.devDependencies || {};
563
+ const nextVersion = dependencies.next || devDependencies.next;
564
+ if (nextVersion) {
565
+ const cleanVersion = nextVersion.replace(/^[\^~>=<]+/, "");
566
+ return { version: cleanVersion };
567
+ }
568
+ const workspace = detectWorkspace(cwd);
569
+ if (workspace.isMonorepo && workspace.packages.length > 0) {
570
+ const highestVersion = findNextjsInWorkspace(cwd, workspace.packages);
571
+ if (highestVersion) {
572
+ return { version: highestVersion };
573
+ }
574
+ return {
575
+ version: null,
576
+ error: `No Next.js found in ${workspace.type} workspace packages.`
577
+ };
578
+ }
579
+ return {
580
+ version: null,
581
+ error: "Next.js is not installed in this project."
582
+ };
583
+ } catch (err) {
584
+ return {
585
+ version: null,
586
+ error: `Failed to parse package.json: ${err instanceof Error ? err.message : String(err)}`
587
+ };
588
+ }
589
+ }
590
+ var nextjsProvider = {
591
+ name: "nextjs",
592
+ displayName: "Next.js",
593
+ repo: "vercel/next.js",
594
+ docsPath: "docs",
595
+ extensions: [".mdx", ".md"],
596
+ detectVersion,
597
+ versionToTag: (version) => version.startsWith("v") ? version : `v${version}`,
598
+ excludePatterns: ["**/index.mdx", "**/index.md"],
599
+ instruction: "IMPORTANT: Prefer retrieval-led reasoning over pre-training-led reasoning for any Next.js tasks."
600
+ };
601
+
602
+ // src/lib/providers/react.ts
603
+ import fs3 from "fs";
604
+ import path3 from "path";
605
+ function detectVersion2(cwd) {
606
+ const packageJsonPath = path3.join(cwd, "package.json");
607
+ if (!fs3.existsSync(packageJsonPath)) {
608
+ return {
609
+ version: null,
610
+ error: "No package.json found in the current directory"
611
+ };
612
+ }
613
+ try {
614
+ const packageJson = JSON.parse(fs3.readFileSync(packageJsonPath, "utf-8"));
615
+ const dependencies = packageJson.dependencies || {};
616
+ const devDependencies = packageJson.devDependencies || {};
617
+ const reactVersion = dependencies.react || devDependencies.react;
618
+ if (reactVersion) {
619
+ const cleanVersion = reactVersion.replace(/^[\^~>=<]+/, "");
620
+ return { version: cleanVersion };
621
+ }
622
+ return {
623
+ version: null,
624
+ error: "React is not installed in this project."
625
+ };
626
+ } catch (err) {
627
+ return {
628
+ version: null,
629
+ error: `Failed to parse package.json: ${err instanceof Error ? err.message : String(err)}`
630
+ };
631
+ }
632
+ }
633
+ var reactProvider = {
634
+ name: "react",
635
+ displayName: "React",
636
+ repo: "reactjs/react.dev",
637
+ docsPath: "src/content",
638
+ extensions: [".md", ".mdx"],
639
+ detectVersion: detectVersion2,
640
+ versionToTag: (version) => `v${version}`,
641
+ excludePatterns: ["**/index.md"],
642
+ instruction: "IMPORTANT: Prefer retrieval-led reasoning over pre-training-led reasoning for any React tasks."
643
+ };
644
+
645
+ // src/lib/providers/pixi.ts
646
+ import fs4 from "fs";
647
+ import path4 from "path";
648
+ function parsePixiVersion(content) {
649
+ const requiresPixiMatch = content.match(/requires-pixi\s*=\s*["']([^"']+)["']/);
650
+ if (requiresPixiMatch) {
651
+ const versionMatch = requiresPixiMatch[1].match(/[\d]+\.[\d]+\.[\d]+/);
652
+ if (versionMatch) {
653
+ return versionMatch[0];
654
+ }
655
+ }
656
+ return null;
657
+ }
658
+ function detectVersion3(cwd) {
659
+ const pixiTomlPath = path4.join(cwd, "pixi.toml");
660
+ if (fs4.existsSync(pixiTomlPath)) {
661
+ try {
662
+ const content = fs4.readFileSync(pixiTomlPath, "utf-8");
663
+ const version = parsePixiVersion(content);
664
+ if (version) {
665
+ return { version };
666
+ }
667
+ } catch {}
668
+ }
669
+ const pyprojectPath = path4.join(cwd, "pyproject.toml");
670
+ if (fs4.existsSync(pyprojectPath)) {
671
+ try {
672
+ const content = fs4.readFileSync(pyprojectPath, "utf-8");
673
+ if (content.includes("[tool.pixi")) {
674
+ const version = parsePixiVersion(content);
675
+ if (version) {
676
+ return { version };
677
+ }
678
+ }
679
+ } catch {}
680
+ }
681
+ try {
682
+ const { execSync: execSync2 } = __require("child_process");
683
+ const output = execSync2("pixi --version", { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] });
684
+ const versionMatch = output.match(/pixi ([\d]+\.[\d]+\.[\d]+)/);
685
+ if (versionMatch) {
686
+ return { version: versionMatch[1] };
687
+ }
688
+ } catch {}
689
+ return {
690
+ version: null,
691
+ error: "Could not detect pixi version. Use --fw-version to specify."
692
+ };
693
+ }
694
+ var pixiProvider = {
695
+ name: "pixi",
696
+ displayName: "Pixi",
697
+ repo: "prefix-dev/pixi",
698
+ docsPath: "docs",
699
+ extensions: [".md"],
700
+ detectVersion: detectVersion3,
701
+ versionToTag: (version) => version.startsWith("v") ? version : `v${version}`,
702
+ excludePatterns: [
703
+ "**/index.md",
704
+ "**/__README.md",
705
+ "**/partials/**",
706
+ "**/assets/**",
707
+ "**/stylesheets/**",
708
+ "**/javascripts/**",
709
+ "**/overrides/**",
710
+ "**/layouts/**"
711
+ ],
712
+ 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."
713
+ };
714
+
715
+ // src/lib/providers/rattler-build.ts
716
+ import fs5 from "fs";
717
+ import path5 from "path";
718
+ function detectVersion4(cwd) {
719
+ const pixiTomlPath = path5.join(cwd, "pixi.toml");
720
+ if (fs5.existsSync(pixiTomlPath)) {
721
+ try {
722
+ const content = fs5.readFileSync(pixiTomlPath, "utf-8");
723
+ const match = content.match(/rattler-build\s*=\s*["']([^"']+)["']/);
724
+ if (match) {
725
+ const versionMatch = match[1].match(/[\d]+\.[\d]+\.[\d]+/);
726
+ if (versionMatch) {
727
+ return { version: versionMatch[0] };
728
+ }
729
+ }
730
+ } catch {}
731
+ }
732
+ const pyprojectPath = path5.join(cwd, "pyproject.toml");
733
+ if (fs5.existsSync(pyprojectPath)) {
734
+ try {
735
+ const content = fs5.readFileSync(pyprojectPath, "utf-8");
736
+ const match = content.match(/rattler-build\s*=\s*["']([^"']+)["']/);
737
+ if (match) {
738
+ const versionMatch = match[1].match(/[\d]+\.[\d]+\.[\d]+/);
739
+ if (versionMatch) {
740
+ return { version: versionMatch[0] };
741
+ }
742
+ }
743
+ } catch {}
744
+ }
745
+ try {
746
+ const { execSync: execSync2 } = __require("child_process");
747
+ const output = execSync2("rattler-build --version", {
748
+ encoding: "utf-8",
749
+ stdio: ["pipe", "pipe", "pipe"]
750
+ });
751
+ const versionMatch = output.match(/rattler-build ([\d]+\.[\d]+\.[\d]+)/);
752
+ if (versionMatch) {
753
+ return { version: versionMatch[1] };
754
+ }
755
+ } catch {}
756
+ return {
757
+ version: null,
758
+ error: "Could not detect rattler-build version. Use --fw-version to specify."
759
+ };
760
+ }
761
+ var rattlerBuildProvider = {
762
+ name: "rattler-build",
763
+ displayName: "rattler-build",
764
+ repo: "prefix-dev/rattler-build",
765
+ docsPath: "docs",
766
+ extensions: [".md"],
767
+ detectVersion: detectVersion4,
768
+ versionToTag: (version) => version.startsWith("v") ? version : `v${version}`,
769
+ excludePatterns: [
770
+ "**/index.md",
771
+ "**/assets/**",
772
+ "**/stylesheets/**",
773
+ "**/layouts/**",
774
+ "**/overrides/**",
775
+ "**/generator/**"
776
+ ],
777
+ 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."
778
+ };
779
+
780
+ // src/lib/providers/tauri.ts
781
+ import fs6 from "fs";
782
+ import path6 from "path";
783
+ function detectVersion5(cwd) {
784
+ const packageJsonPath = path6.join(cwd, "package.json");
785
+ if (fs6.existsSync(packageJsonPath)) {
786
+ try {
787
+ const content = fs6.readFileSync(packageJsonPath, "utf-8");
788
+ const pkg = JSON.parse(content);
789
+ const deps = { ...pkg.dependencies, ...pkg.devDependencies };
790
+ const tauriApi = deps["@tauri-apps/api"];
791
+ const tauriCli = deps["@tauri-apps/cli"];
792
+ if (tauriApi || tauriCli) {
793
+ const version = tauriApi || tauriCli;
794
+ const versionMatch = version.match(/(\d+)\./);
795
+ if (versionMatch) {
796
+ const major = parseInt(versionMatch[1]);
797
+ return { version: major >= 2 ? "v2" : "v1" };
798
+ }
799
+ return { version: "v2" };
800
+ }
801
+ } catch {}
802
+ }
803
+ const tauriConfPath = path6.join(cwd, "src-tauri", "tauri.conf.json");
804
+ if (fs6.existsSync(tauriConfPath)) {
805
+ return { version: "v2" };
806
+ }
807
+ const cargoTomlPath = path6.join(cwd, "src-tauri", "Cargo.toml");
808
+ if (fs6.existsSync(cargoTomlPath)) {
809
+ try {
810
+ const content = fs6.readFileSync(cargoTomlPath, "utf-8");
811
+ const match = content.match(/tauri\s*=\s*.*?"(\d+)\./);
812
+ if (match) {
813
+ const major = parseInt(match[1]);
814
+ return { version: major >= 2 ? "v2" : "v1" };
815
+ }
816
+ return { version: "v2" };
817
+ } catch {}
818
+ }
819
+ return {
820
+ version: null,
821
+ error: "Could not detect Tauri version. Use --fw-version to specify (v1 or v2)."
822
+ };
823
+ }
824
+ var tauriProvider = {
825
+ name: "tauri",
826
+ displayName: "Tauri",
827
+ repo: "tauri-apps/tauri-docs",
828
+ docsPath: "src/content/docs",
829
+ extensions: [".md", ".mdx"],
830
+ detectVersion: detectVersion5,
831
+ versionToTag: (version) => version,
832
+ excludePatterns: [
833
+ "**/index.mdx",
834
+ "**/index.md",
835
+ "**/_fragments/**",
836
+ "**/_it/**",
837
+ "**/es/**",
838
+ "**/fr/**",
839
+ "**/it/**",
840
+ "**/ja/**",
841
+ "**/ko/**",
842
+ "**/zh-cn/**",
843
+ "**/404.md",
844
+ "**/rss.mdx"
845
+ ],
846
+ 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."
847
+ };
848
+
849
+ // src/lib/providers/conda-forge.ts
850
+ function detectVersion6(_cwd) {
851
+ return { version: "main" };
852
+ }
853
+ var condaForgeProvider = {
854
+ name: "conda-forge",
855
+ displayName: "conda-forge",
856
+ repo: "conda-forge/conda-forge.github.io",
857
+ docsPath: "docs",
858
+ extensions: [".md", ".mdx"],
859
+ detectVersion: detectVersion6,
860
+ versionToTag: (version) => version,
861
+ excludePatterns: [
862
+ "**/index.md",
863
+ "**/_sidebar.js",
864
+ "**/_sidebar.json",
865
+ "**/_sidebar_diataxis.json"
866
+ ],
867
+ 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."
868
+ };
869
+
870
+ // src/lib/providers/bun.ts
871
+ import fs7 from "fs";
872
+ import path7 from "path";
873
+ import { execSync as execSync2 } from "child_process";
874
+ function detectVersion7(cwd) {
875
+ const bunLockPath = path7.join(cwd, "bun.lockb");
876
+ const hasBunLock = fs7.existsSync(bunLockPath);
877
+ const bunfigPath = path7.join(cwd, "bunfig.toml");
878
+ const hasBunfig = fs7.existsSync(bunfigPath);
879
+ if (!hasBunLock && !hasBunfig) {
880
+ return {
881
+ version: null,
882
+ error: "No bun.lockb or bunfig.toml found in the current directory"
883
+ };
884
+ }
885
+ try {
886
+ const output = execSync2("bun --version", { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] });
887
+ const versionMatch = output.match(/([\d]+\.[\d]+\.[\d]+)/);
888
+ if (versionMatch) {
889
+ return { version: versionMatch[1] };
890
+ }
891
+ } catch {}
892
+ return {
893
+ version: null,
894
+ error: "Bun project detected but could not determine version. Please specify with --fw-version."
895
+ };
896
+ }
897
+ var bunProvider = {
898
+ name: "bun",
899
+ displayName: "Bun",
900
+ repo: "oven-sh/bun",
901
+ docsPath: "docs",
902
+ extensions: [".md", ".mdx"],
903
+ detectVersion: detectVersion7,
904
+ versionToTag: (version) => `bun-v${version}`,
905
+ excludePatterns: ["**/README.md"],
906
+ instruction: "IMPORTANT: Prefer retrieval-led reasoning over pre-training-led reasoning for any Bun tasks."
907
+ };
908
+
909
+ // src/lib/providers/generic.ts
910
+ import fs8 from "fs";
911
+ import path8 from "path";
912
+ function createProvider(options) {
913
+ const {
914
+ name,
915
+ displayName,
916
+ repo,
917
+ docsPath,
918
+ extensions = [".mdx", ".md"],
919
+ packageName,
920
+ versionToTag = (v) => v.startsWith("v") ? v : `v${v}`,
921
+ excludePatterns = ["**/index.mdx", "**/index.md"],
922
+ instruction
923
+ } = options;
924
+ const detectVersion8 = packageName ? (cwd) => {
925
+ const packageJsonPath = path8.join(cwd, "package.json");
926
+ if (!fs8.existsSync(packageJsonPath)) {
927
+ return {
928
+ version: null,
929
+ error: "No package.json found in the current directory"
930
+ };
931
+ }
932
+ try {
933
+ const packageJson = JSON.parse(fs8.readFileSync(packageJsonPath, "utf-8"));
934
+ const dependencies = packageJson.dependencies || {};
935
+ const devDependencies = packageJson.devDependencies || {};
936
+ const version = dependencies[packageName] || devDependencies[packageName];
937
+ if (version) {
938
+ const cleanVersion = version.replace(/^[\^~>=<]+/, "");
939
+ return { version: cleanVersion };
940
+ }
941
+ return {
942
+ version: null,
943
+ error: `${displayName} (${packageName}) is not installed in this project.`
944
+ };
945
+ } catch (err) {
946
+ return {
947
+ version: null,
948
+ error: `Failed to parse package.json: ${err instanceof Error ? err.message : String(err)}`
949
+ };
950
+ }
951
+ } : undefined;
952
+ return {
953
+ name,
954
+ displayName,
955
+ repo,
956
+ docsPath,
957
+ extensions,
958
+ detectVersion: detectVersion8,
959
+ versionToTag,
960
+ excludePatterns,
961
+ instruction: instruction || `IMPORTANT: Prefer retrieval-led reasoning over pre-training-led reasoning for any ${displayName} tasks.`
962
+ };
963
+ }
964
+ function createLocalProvider(options) {
965
+ return {
966
+ name: options.name,
967
+ displayName: options.displayName,
968
+ repo: "",
969
+ docsPath: options.localPath,
970
+ extensions: options.extensions || [".mdx", ".md"],
971
+ excludePatterns: options.excludePatterns || ["**/index.mdx", "**/index.md"],
972
+ instruction: options.instruction || `IMPORTANT: Prefer retrieval-led reasoning over pre-training-led reasoning for any ${options.displayName} tasks.`
973
+ };
974
+ }
975
+ // src/lib/providers/index.ts
976
+ function getProvider(preset) {
977
+ switch (preset) {
978
+ case "nextjs":
979
+ return nextjsProvider;
980
+ case "react":
981
+ return reactProvider;
982
+ case "pixi":
983
+ return pixiProvider;
984
+ case "rattler-build":
985
+ return rattlerBuildProvider;
986
+ case "tauri":
987
+ return tauriProvider;
988
+ case "conda-forge":
989
+ return condaForgeProvider;
990
+ case "bun":
991
+ return bunProvider;
992
+ case "vue":
993
+ case "svelte":
994
+ case "astro":
995
+ return null;
996
+ default:
997
+ return null;
998
+ }
999
+ }
1000
+ function listProviders() {
1001
+ return ["nextjs", "react", "pixi", "rattler-build", "tauri", "conda-forge", "bun", "vue", "svelte", "astro"];
1002
+ }
1003
+ function isProviderAvailable(preset) {
1004
+ return getProvider(preset) !== null;
1005
+ }
1006
+
1007
+ // src/lib/skills.ts
1008
+ import fs9 from "fs";
1009
+ import path9 from "path";
1010
+ import os2 from "os";
1011
+ var SKILLS_START_MARKER = "<!-- AGENTS-MD-SKILLS-START -->";
1012
+ var SKILLS_END_MARKER = "<!-- AGENTS-MD-SKILLS-END -->";
1013
+ function parseSkillFrontmatter(content) {
1014
+ const match = content.match(/^---\s*\n([\s\S]*?)\n---/);
1015
+ if (!match)
1016
+ return null;
1017
+ const frontmatter = match[1];
1018
+ const result = { name: "", description: "" };
1019
+ const nameMatch = frontmatter.match(/^name:\s*(.+)$/m);
1020
+ const descMatch = frontmatter.match(/^description:\s*(.+)$/m);
1021
+ if (nameMatch) {
1022
+ result.name = nameMatch[1].trim().replace(/^["']|["']$/g, "");
1023
+ }
1024
+ if (descMatch) {
1025
+ result.description = descMatch[1].trim().replace(/^["']|["']$/g, "");
1026
+ }
1027
+ if (!result.name || !result.description) {
1028
+ return null;
1029
+ }
1030
+ return result;
1031
+ }
1032
+ function getSiblingFiles(skillMdPath) {
1033
+ const dir = path9.dirname(skillMdPath);
1034
+ if (!fs9.existsSync(dir))
1035
+ return [];
1036
+ try {
1037
+ const files = fs9.readdirSync(dir);
1038
+ return files.filter((f) => f !== "SKILL.md" && !f.startsWith(".")).sort();
1039
+ } catch {
1040
+ return [];
1041
+ }
1042
+ }
1043
+ function discoverPluginSkills(pluginsPath, label) {
1044
+ const skills = [];
1045
+ const pluginsDir = path9.join(pluginsPath, "plugins");
1046
+ if (!fs9.existsSync(pluginsDir)) {
1047
+ return skills;
1048
+ }
1049
+ const plugins = fs9.readdirSync(pluginsDir, { withFileTypes: true }).filter((d) => d.isDirectory());
1050
+ for (const plugin of plugins) {
1051
+ const skillsDir = path9.join(pluginsDir, plugin.name, "skills");
1052
+ if (!fs9.existsSync(skillsDir))
1053
+ continue;
1054
+ const skillDirs = fs9.readdirSync(skillsDir, { withFileTypes: true }).filter((d) => d.isDirectory());
1055
+ for (const skillDir of skillDirs) {
1056
+ const skillMdPath = path9.join(skillsDir, skillDir.name, "SKILL.md");
1057
+ if (!fs9.existsSync(skillMdPath))
1058
+ continue;
1059
+ try {
1060
+ const content = fs9.readFileSync(skillMdPath, "utf-8");
1061
+ const frontmatter = parseSkillFrontmatter(content);
1062
+ if (!frontmatter)
1063
+ continue;
1064
+ skills.push({
1065
+ name: frontmatter.name,
1066
+ description: frontmatter.description,
1067
+ skillMdPath,
1068
+ siblingFiles: getSiblingFiles(skillMdPath),
1069
+ source: "plugin",
1070
+ pluginName: plugin.name
1071
+ });
1072
+ } catch {}
1073
+ }
1074
+ }
1075
+ return skills;
1076
+ }
1077
+ function discoverFlatSkills(skillsPath, source, label) {
1078
+ const skills = [];
1079
+ if (!fs9.existsSync(skillsPath)) {
1080
+ return skills;
1081
+ }
1082
+ const skillDirs = fs9.readdirSync(skillsPath, { withFileTypes: true }).filter((d) => d.isDirectory());
1083
+ for (const skillDir of skillDirs) {
1084
+ const skillMdPath = path9.join(skillsPath, skillDir.name, "SKILL.md");
1085
+ if (!fs9.existsSync(skillMdPath))
1086
+ continue;
1087
+ try {
1088
+ const content = fs9.readFileSync(skillMdPath, "utf-8");
1089
+ const frontmatter = parseSkillFrontmatter(content);
1090
+ if (!frontmatter)
1091
+ continue;
1092
+ skills.push({
1093
+ name: frontmatter.name,
1094
+ description: frontmatter.description,
1095
+ skillMdPath,
1096
+ siblingFiles: getSiblingFiles(skillMdPath),
1097
+ source
1098
+ });
1099
+ } catch {}
1100
+ }
1101
+ return skills;
1102
+ }
1103
+ function collectAllSkills(sources) {
1104
+ const allSkills = [];
1105
+ for (const source of sources) {
1106
+ if (source.type === "plugin") {
1107
+ allSkills.push(...discoverPluginSkills(source.path, source.label));
1108
+ } else {
1109
+ allSkills.push(...discoverFlatSkills(source.path, source.type, source.label));
1110
+ }
1111
+ }
1112
+ return allSkills;
1113
+ }
1114
+ function generateSkillsIndex(skills, options = {}) {
1115
+ const parts = ["[Skills Index]"];
1116
+ const pluginSkills = new Map;
1117
+ const userSkills = [];
1118
+ const projectSkills = [];
1119
+ for (const skill of skills) {
1120
+ if (skill.source === "plugin" && skill.pluginName) {
1121
+ const existing = pluginSkills.get(skill.pluginName) || [];
1122
+ existing.push(skill);
1123
+ pluginSkills.set(skill.pluginName, existing);
1124
+ } else if (skill.source === "user") {
1125
+ userSkills.push(skill);
1126
+ } else if (skill.source === "project") {
1127
+ projectSkills.push(skill);
1128
+ }
1129
+ }
1130
+ for (const [pluginName, entries] of pluginSkills) {
1131
+ const skillParts = entries.map((s) => formatSkillEntry(s)).join(";");
1132
+ parts.push(`plugin:${pluginName}:{${skillParts}}`);
1133
+ }
1134
+ if (userSkills.length > 0) {
1135
+ const skillParts = userSkills.map((s) => formatSkillEntry(s)).join(";");
1136
+ parts.push(`user:{${skillParts}}`);
1137
+ }
1138
+ if (projectSkills.length > 0) {
1139
+ const skillParts = projectSkills.map((s) => formatSkillEntry(s)).join(";");
1140
+ parts.push(`project:{${skillParts}}`);
1141
+ }
1142
+ const cmd = options.regenerateCommand || "npx agdex skills embed";
1143
+ parts.push(`Regen: ${cmd}`);
1144
+ return parts.join("|");
1145
+ }
1146
+ function formatSkillEntry(skill) {
1147
+ const desc = skill.description.replace(/\|/g, "\\|").replace(/;/g, "\\;").replace(/:/g, "\\:").replace(/\[/g, "\\[").replace(/\]/g, "\\]").replace(/\{/g, "\\{").replace(/\}/g, "\\}");
1148
+ if (skill.siblingFiles.length > 0) {
1149
+ return `${skill.name}:${desc}[${skill.siblingFiles.join(",")}]`;
1150
+ }
1151
+ return `${skill.name}:${desc}`;
1152
+ }
1153
+ function hasExistingSkillsIndex(content) {
1154
+ return content.includes(SKILLS_START_MARKER);
1155
+ }
1156
+ function removeSkillsIndex(content) {
1157
+ if (!hasExistingSkillsIndex(content)) {
1158
+ return content;
1159
+ }
1160
+ const startIdx = content.indexOf(SKILLS_START_MARKER);
1161
+ const endIdx = content.indexOf(SKILLS_END_MARKER) + SKILLS_END_MARKER.length;
1162
+ let result = content.slice(0, startIdx) + content.slice(endIdx);
1163
+ result = result.replace(/\n{3,}/g, `
1164
+
1165
+ `);
1166
+ result = result.trimEnd();
1167
+ if (result.length > 0) {
1168
+ result += `
1169
+ `;
1170
+ }
1171
+ return result;
1172
+ }
1173
+ function injectSkillsIndex(existingContent, indexContent) {
1174
+ const wrappedContent = `${SKILLS_START_MARKER}
1175
+ ${indexContent}
1176
+ ${SKILLS_END_MARKER}`;
1177
+ if (hasExistingSkillsIndex(existingContent)) {
1178
+ const startIdx = existingContent.indexOf(SKILLS_START_MARKER);
1179
+ const endIdx = existingContent.indexOf(SKILLS_END_MARKER) + SKILLS_END_MARKER.length;
1180
+ return existingContent.slice(0, startIdx) + wrappedContent + existingContent.slice(endIdx);
1181
+ }
1182
+ const separator = existingContent.endsWith(`
1183
+ `) ? `
1184
+ ` : `
1185
+
1186
+ `;
1187
+ return existingContent + separator + wrappedContent + `
1188
+ `;
1189
+ }
1190
+ function getDefaultSkillSources(cwd, options = {}) {
1191
+ const sources = [];
1192
+ const {
1193
+ includeUser = true,
1194
+ includeProject = true,
1195
+ pluginPaths = []
1196
+ } = options;
1197
+ for (const pluginPath of pluginPaths) {
1198
+ sources.push({
1199
+ type: "plugin",
1200
+ path: pluginPath,
1201
+ label: path9.basename(pluginPath)
1202
+ });
1203
+ }
1204
+ if (includeUser) {
1205
+ const userSkillsPath = path9.join(os2.homedir(), ".claude", "skills");
1206
+ sources.push({
1207
+ type: "user",
1208
+ path: userSkillsPath,
1209
+ label: "user"
1210
+ });
1211
+ }
1212
+ if (includeProject) {
1213
+ const projectSkillsPath = path9.join(cwd, ".claude", "skills");
1214
+ sources.push({
1215
+ type: "project",
1216
+ path: projectSkillsPath,
1217
+ label: "project"
1218
+ });
1219
+ }
1220
+ return sources;
1221
+ }
1222
+ async function embedSkills(options) {
1223
+ const { cwd, sources, output = "AGENTS.md" } = options;
1224
+ const targetPath = path9.join(cwd, output);
1225
+ let sizeBefore = 0;
1226
+ let isNewFile = true;
1227
+ let existingContent = "";
1228
+ if (fs9.existsSync(targetPath)) {
1229
+ existingContent = fs9.readFileSync(targetPath, "utf-8");
1230
+ sizeBefore = Buffer.byteLength(existingContent, "utf-8");
1231
+ isNewFile = false;
1232
+ }
1233
+ const skills = collectAllSkills(sources);
1234
+ if (skills.length === 0) {
1235
+ return {
1236
+ success: false,
1237
+ error: "No skills found in any of the specified sources"
1238
+ };
1239
+ }
1240
+ const sourceBreakdown = {
1241
+ plugin: 0,
1242
+ user: 0,
1243
+ project: 0
1244
+ };
1245
+ for (const skill of skills) {
1246
+ sourceBreakdown[skill.source]++;
1247
+ }
1248
+ const indexContent = generateSkillsIndex(skills, {
1249
+ regenerateCommand: `npx agdex skills embed`
1250
+ });
1251
+ const newContent = injectSkillsIndex(existingContent, indexContent);
1252
+ fs9.writeFileSync(targetPath, newContent, "utf-8");
1253
+ const sizeAfter = Buffer.byteLength(newContent, "utf-8");
1254
+ return {
1255
+ success: true,
1256
+ targetFile: output,
1257
+ skillCount: skills.length,
1258
+ sizeBefore,
1259
+ sizeAfter,
1260
+ isNewFile,
1261
+ sourceBreakdown
1262
+ };
1263
+ }
1264
+
1265
+ 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 };
package/dist/index.js CHANGED
@@ -32,7 +32,7 @@ import {
32
32
  removeDocsIndex,
33
33
  removeSkillsIndex,
34
34
  tauriProvider
35
- } from "./index-k299aha0.js";
35
+ } from "./index-cfpc7eqp.js";
36
36
  export {
37
37
  tauriProvider,
38
38
  removeSkillsIndex,
@@ -23,18 +23,22 @@ export declare function buildDocTree(files: DocFile[]): DocSection[];
23
23
  */
24
24
  export declare function generateIndex(options: IndexOptions): string;
25
25
  /**
26
- * Check if content has an existing embedded index
26
+ * Check if content has an existing embedded index for a specific provider
27
+ * If no provider specified, checks for any index
27
28
  */
28
- export declare function hasExistingIndex(content: string): boolean;
29
+ export declare function hasExistingIndex(content: string, providerName?: string): boolean;
29
30
  /**
30
31
  * Remove the docs index from content
32
+ * If providerName specified, only removes that provider's index
33
+ * If no providerName, removes all indexes
31
34
  * Returns the content with the index removed, or unchanged if no index exists
32
35
  */
33
- export declare function removeDocsIndex(content: string): string;
36
+ export declare function removeDocsIndex(content: string, providerName?: string): string;
34
37
  /**
35
38
  * Inject index into AGENTS.md/CLAUDE.md content
39
+ * If providerName specified, only replaces that provider's index (or appends if not present)
36
40
  */
37
- export declare function injectIndex(existingContent: string, indexContent: string): string;
41
+ export declare function injectIndex(existingContent: string, indexContent: string, providerName?: string): string;
38
42
  /**
39
43
  * Ensure .gitignore has entry for docs directory
40
44
  */
@@ -1 +1 @@
1
- {"version":3,"file":"agents-md.d.ts","sourceRoot":"","sources":["../../src/lib/agents-md.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EACV,WAAW,EACX,OAAO,EACP,UAAU,EACV,UAAU,EACV,eAAe,EACf,YAAY,EACZ,YAAY,EACZ,WAAW,EACZ,MAAM,SAAS,CAAA;AAKhB;;GAEG;AACH,wBAAsB,QAAQ,CAC5B,QAAQ,EAAE,WAAW,EACrB,OAAO,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,GAC3D,OAAO,CAAC,UAAU,CAAC,CAiDrB;AAiDD;;GAEG;AACH,wBAAgB,eAAe,CAC7B,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE;IAAE,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IAAC,eAAe,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE,GAC9D,OAAO,EAAE,CA4CX;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,UAAU,EAAE,CA8E3D;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,YAAY,GAAG,MAAM,CA6B3D;AAkCD;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAEzD;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAqBvD;AASD;;GAEG;AACH,wBAAgB,WAAW,CAAC,eAAe,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM,CAgBjF;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,eAAe,CAuBlF;AAED;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,CAE1C;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED;;GAEG;AACH,wBAAsB,KAAK,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC,CA2GvE;AAGD,YAAY,EACV,WAAW,EACX,OAAO,EACP,UAAU,EACV,UAAU,EACV,eAAe,EACf,YAAY,EACZ,YAAY,EACZ,WAAW,GACZ,MAAM,SAAS,CAAA"}
1
+ {"version":3,"file":"agents-md.d.ts","sourceRoot":"","sources":["../../src/lib/agents-md.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EACV,WAAW,EACX,OAAO,EACP,UAAU,EACV,UAAU,EACV,eAAe,EACf,YAAY,EACZ,YAAY,EACZ,WAAW,EACZ,MAAM,SAAS,CAAA;AAkBhB;;GAEG;AACH,wBAAsB,QAAQ,CAC5B,QAAQ,EAAE,WAAW,EACrB,OAAO,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,GAC3D,OAAO,CAAC,UAAU,CAAC,CAiDrB;AAiDD;;GAEG;AACH,wBAAgB,eAAe,CAC7B,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE;IAAE,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IAAC,eAAe,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE,GAC9D,OAAO,EAAE,CA4CX;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,UAAU,EAAE,CA8E3D;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,YAAY,GAAG,MAAM,CA6B3D;AAkCD;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,OAAO,CAMhF;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,CAkD9E;AAWD;;;GAGG;AACH,wBAAgB,WAAW,CAAC,eAAe,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,CAkBxG;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,eAAe,CAuBlF;AAED;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,CAE1C;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED;;GAEG;AACH,wBAAsB,KAAK,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC,CA2GvE;AAGD,YAAY,EACV,WAAW,EACX,OAAO,EACP,UAAU,EACV,UAAU,EACV,eAAe,EACf,YAAY,EACZ,YAAY,EACZ,WAAW,GACZ,MAAM,SAAS,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agdex",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Embed compressed documentation indexes into AGENTS.md/CLAUDE.md for AI coding agents",
5
5
  "module": "dist/index.js",
6
6
  "main": "dist/index.js",