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