agdex 0.6.1 → 0.8.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/README.md +41 -11
- package/dist/cli/index.js +293 -28
- package/dist/index-38fpcrpr.js +2558 -0
- package/dist/index-3d051m1n.js +2557 -0
- package/dist/{index-cm3qmz9v.js → index-e7c8d7rq.js} +10 -9
- package/dist/{index-1v32v5tn.js → index-gg9mmf42.js} +9 -8
- package/dist/index-thmt54kg.js +2302 -0
- package/dist/index.d.ts +8 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +19 -3
- package/dist/lib/agents-md.d.ts +2 -2
- package/dist/lib/agents-md.d.ts.map +1 -1
- package/dist/lib/index-maintenance.d.ts +33 -0
- package/dist/lib/index-maintenance.d.ts.map +1 -0
- package/dist/lib/lockfile.d.ts +36 -0
- package/dist/lib/lockfile.d.ts.map +1 -0
- package/dist/lib/types.d.ts +3 -1
- package/dist/lib/types.d.ts.map +1 -1
- package/dist/{index-dtcewfnz.js → url-scraper-fme0jdje.js} +10 -6
- package/package.json +1 -1
- package/dist/index-sh9kr6eq.js +0 -22433
- package/dist/url-scraper-5sj8c56t.js +0 -8
- package/dist/url-scraper-9xq4d56t.js +0 -8
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# agdex
|
|
2
2
|
|
|
3
|
-
Embed compressed documentation indexes into
|
|
3
|
+
Embed compressed documentation indexes into local agent instruction files.
|
|
4
4
|
|
|
5
5
|
This package helps AI coding agents (Claude, Cursor, etc.) work with version-matched framework documentation by embedding a compressed docs index directly into your project's markdown file. Based on [Vercel's research](https://vercel.com/blog/teaching-ai-agents-how-to-use-nextjs) showing that embedded docs achieve 100% pass rates compared to 79% for skills.
|
|
6
6
|
|
|
@@ -10,8 +10,9 @@ AI coding agents rely on training data that becomes outdated. When agents don't
|
|
|
10
10
|
|
|
11
11
|
1. Downloads version-matched documentation from GitHub
|
|
12
12
|
2. Creates a compressed index (~8KB for Next.js)
|
|
13
|
-
3.
|
|
14
|
-
4.
|
|
13
|
+
3. Stores the docs in local `.agdex/` cache
|
|
14
|
+
4. Embeds an index in your local agent instruction file
|
|
15
|
+
5. Agents can then retrieve specific docs on demand
|
|
15
16
|
|
|
16
17
|
The key instruction embedded tells agents to **prefer retrieval-led reasoning over pre-training-led reasoning**.
|
|
17
18
|
|
|
@@ -38,7 +39,7 @@ Create a `.agdexrc.json` file in your project root:
|
|
|
38
39
|
|
|
39
40
|
```json
|
|
40
41
|
{
|
|
41
|
-
"output": "CLAUDE.md"
|
|
42
|
+
"output": "CLAUDE.local.md"
|
|
42
43
|
}
|
|
43
44
|
```
|
|
44
45
|
|
|
@@ -50,7 +51,7 @@ Add an `agdex` field to your `package.json`:
|
|
|
50
51
|
{
|
|
51
52
|
"name": "my-project",
|
|
52
53
|
"agdex": {
|
|
53
|
-
"output": "CLAUDE.md"
|
|
54
|
+
"output": "CLAUDE.local.md"
|
|
54
55
|
}
|
|
55
56
|
}
|
|
56
57
|
```
|
|
@@ -61,7 +62,7 @@ Add an `agdex` field to your `package.json`:
|
|
|
61
62
|
|
|
62
63
|
| Option | Type | Default | Description |
|
|
63
64
|
|----------|--------|-------------|-------------|
|
|
64
|
-
| `output` | string | `CLAUDE.md` | Default output file for indexes |
|
|
65
|
+
| `output` | string | `CLAUDE.local.md` | Default output file for indexes |
|
|
65
66
|
|
|
66
67
|
## CLI Usage
|
|
67
68
|
|
|
@@ -112,10 +113,10 @@ npx agdex --provider nextjs --description "Project uses App Router only"
|
|
|
112
113
|
```bash
|
|
113
114
|
-p, --provider <name> Documentation provider (nextjs, react, etc.)
|
|
114
115
|
--fw-version <version> Framework version (auto-detected if not provided)
|
|
115
|
-
-o, --output <file> Target file (default: from config or CLAUDE.md)
|
|
116
|
+
-o, --output <file> Target file (default: from config or CLAUDE.local.md)
|
|
116
117
|
-d, --description <text> Additional description to include in the index
|
|
117
|
-
-g, --global Use global cache ~/.cache/agdex/
|
|
118
|
-
-l, --local Use local .agdex/
|
|
118
|
+
-g, --global Use global cache ~/.cache/agdex/ instead of local .agdex/
|
|
119
|
+
-l, --local Use local .agdex/ (default)
|
|
119
120
|
```
|
|
120
121
|
|
|
121
122
|
### Custom GitHub Repository
|
|
@@ -209,6 +210,35 @@ npx agdex remove --docs
|
|
|
209
210
|
npx agdex remove --skills
|
|
210
211
|
```
|
|
211
212
|
|
|
213
|
+
### Maintaining Indexes
|
|
214
|
+
|
|
215
|
+
Successful embeds write local maintenance state to `.agdex/agdex.lock`. The lockfile records the target agent instruction file, marker, source metadata, cache path, and display command for each last-known-good index. It is generated local state and should stay unversioned with `.agdex/`.
|
|
216
|
+
|
|
217
|
+
Inspect index health:
|
|
218
|
+
|
|
219
|
+
```bash
|
|
220
|
+
npx agdex status
|
|
221
|
+
npx agdex status --check
|
|
222
|
+
npx agdex status --json
|
|
223
|
+
npx agdex status --output AGENTS.md
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
Refresh lockfile-backed indexes:
|
|
227
|
+
|
|
228
|
+
```bash
|
|
229
|
+
npx agdex refresh
|
|
230
|
+
npx agdex refresh --force
|
|
231
|
+
npx agdex refresh --repair
|
|
232
|
+
npx agdex refresh --provider nextjs
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
Create lockfile entries for existing embedded docs markers when agdex can safely infer marker and cache metadata:
|
|
236
|
+
|
|
237
|
+
```bash
|
|
238
|
+
npx agdex migrate
|
|
239
|
+
npx agdex migrate --output AGENTS.md
|
|
240
|
+
```
|
|
241
|
+
|
|
212
242
|
### List Available Providers
|
|
213
243
|
|
|
214
244
|
```bash
|
|
@@ -224,7 +254,7 @@ import { embed, nextjsProvider, createProvider } from 'agdex'
|
|
|
224
254
|
const result = await embed({
|
|
225
255
|
cwd: process.cwd(),
|
|
226
256
|
provider: nextjsProvider,
|
|
227
|
-
output: '
|
|
257
|
+
output: 'CLAUDE.local.md'
|
|
228
258
|
})
|
|
229
259
|
|
|
230
260
|
// Create custom provider
|
|
@@ -240,7 +270,7 @@ await embed({
|
|
|
240
270
|
cwd: process.cwd(),
|
|
241
271
|
provider: myProvider,
|
|
242
272
|
version: '1.0.0',
|
|
243
|
-
output: 'CLAUDE.md'
|
|
273
|
+
output: 'CLAUDE.local.md'
|
|
244
274
|
})
|
|
245
275
|
```
|
|
246
276
|
|
package/dist/cli/index.js
CHANGED
|
@@ -6,11 +6,14 @@ import {
|
|
|
6
6
|
collectAllSkills,
|
|
7
7
|
collectDocFiles,
|
|
8
8
|
convexProvider,
|
|
9
|
+
createIndexId,
|
|
9
10
|
createProvider,
|
|
11
|
+
createStatusReport,
|
|
10
12
|
deltaRsProvider,
|
|
11
13
|
discoverSkillsShRepo,
|
|
12
14
|
embed,
|
|
13
15
|
embedSkills,
|
|
16
|
+
ensureGitignoreEntry,
|
|
14
17
|
fetchSkillsShSearch,
|
|
15
18
|
ffmpegProvider,
|
|
16
19
|
generateIndex,
|
|
@@ -32,19 +35,21 @@ import {
|
|
|
32
35
|
pixiProvider,
|
|
33
36
|
polarsProvider,
|
|
34
37
|
rattlerBuildProvider,
|
|
38
|
+
readIndexLockfile,
|
|
35
39
|
removeDocsIndex,
|
|
36
40
|
removeSkillsIndex,
|
|
37
41
|
ruffProvider,
|
|
38
42
|
svelteProvider,
|
|
39
43
|
tailwindProvider,
|
|
40
44
|
tauriProvider,
|
|
41
|
-
tyProvider
|
|
42
|
-
|
|
45
|
+
tyProvider,
|
|
46
|
+
upsertIndexLockEntry
|
|
47
|
+
} from "../index-38fpcrpr.js";
|
|
43
48
|
import {
|
|
44
49
|
__commonJS,
|
|
45
50
|
__require,
|
|
46
51
|
__toESM
|
|
47
|
-
} from "../
|
|
52
|
+
} from "../url-scraper-fme0jdje.js";
|
|
48
53
|
|
|
49
54
|
// node_modules/commander/lib/error.js
|
|
50
55
|
var require_error = __commonJS((exports) => {
|
|
@@ -2109,7 +2114,7 @@ var require_clear = __commonJS((exports, module) => {
|
|
|
2109
2114
|
if (it)
|
|
2110
2115
|
o = it;
|
|
2111
2116
|
var i = 0;
|
|
2112
|
-
var F = function
|
|
2117
|
+
var F = function F() {};
|
|
2113
2118
|
return { s: F, n: function n() {
|
|
2114
2119
|
if (i >= o.length)
|
|
2115
2120
|
return { done: true };
|
|
@@ -4441,7 +4446,7 @@ var require_dist = __commonJS((exports, module) => {
|
|
|
4441
4446
|
if (it)
|
|
4442
4447
|
o = it;
|
|
4443
4448
|
var i = 0;
|
|
4444
|
-
var F = function
|
|
4449
|
+
var F = function F() {};
|
|
4445
4450
|
return { s: F, n: function n() {
|
|
4446
4451
|
if (i >= o.length)
|
|
4447
4452
|
return { done: true };
|
|
@@ -4544,7 +4549,7 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
|
|
|
4544
4549
|
}
|
|
4545
4550
|
return question2.format ? yield question2.format(answer2, answers) : answer2;
|
|
4546
4551
|
});
|
|
4547
|
-
return function
|
|
4552
|
+
return function getFormattedAnswer(_x, _x2) {
|
|
4548
4553
|
return _ref.apply(this, arguments);
|
|
4549
4554
|
};
|
|
4550
4555
|
}();
|
|
@@ -7048,12 +7053,21 @@ function onCancel() {
|
|
|
7048
7053
|
Cancelled.`));
|
|
7049
7054
|
process.exit(0);
|
|
7050
7055
|
}
|
|
7056
|
+
function resolveGlobalCacheOption(options) {
|
|
7057
|
+
if (options.global && options.local) {
|
|
7058
|
+
console.error(import_picocolors2.default.red("Choose either --global or --local, not both."));
|
|
7059
|
+
process.exit(1);
|
|
7060
|
+
}
|
|
7061
|
+
return options.global ? true : false;
|
|
7062
|
+
}
|
|
7051
7063
|
async function runEmbed(options) {
|
|
7052
7064
|
const cwd = process.cwd();
|
|
7065
|
+
const globalCache = resolveGlobalCacheOption(options);
|
|
7053
7066
|
if (options.url) {
|
|
7054
7067
|
await runUrl(options.url, {
|
|
7055
7068
|
output: options.output,
|
|
7056
|
-
name: options.description
|
|
7069
|
+
name: options.description,
|
|
7070
|
+
global: globalCache
|
|
7057
7071
|
});
|
|
7058
7072
|
return;
|
|
7059
7073
|
}
|
|
@@ -7085,8 +7099,7 @@ async function runEmbed(options) {
|
|
|
7085
7099
|
provider = result.provider;
|
|
7086
7100
|
version = result.version;
|
|
7087
7101
|
output = result.output;
|
|
7088
|
-
|
|
7089
|
-
await executeEmbed(cwd, provider, version, output, useGlobal, result.description);
|
|
7102
|
+
await executeEmbed(cwd, provider, version, output, globalCache, result.description, version ? "auto" : "unknown");
|
|
7090
7103
|
return;
|
|
7091
7104
|
}
|
|
7092
7105
|
} else {
|
|
@@ -7094,8 +7107,7 @@ async function runEmbed(options) {
|
|
|
7094
7107
|
provider = result.provider;
|
|
7095
7108
|
version = result.version;
|
|
7096
7109
|
output = result.output;
|
|
7097
|
-
|
|
7098
|
-
await executeEmbed(cwd, provider, version, output, useGlobal, result.description);
|
|
7110
|
+
await executeEmbed(cwd, provider, version, output, globalCache, result.description, version ? "auto" : "unknown");
|
|
7099
7111
|
return;
|
|
7100
7112
|
}
|
|
7101
7113
|
output = options.output || getDefaultOutput();
|
|
@@ -7103,10 +7115,9 @@ async function runEmbed(options) {
|
|
|
7103
7115
|
console.error(import_picocolors2.default.red(`Provider ${provider.displayName} requires --version flag since auto-detection is not supported.`));
|
|
7104
7116
|
process.exit(1);
|
|
7105
7117
|
}
|
|
7106
|
-
|
|
7107
|
-
await executeEmbed(cwd, provider, version, output, useGlobalCache, options.description);
|
|
7118
|
+
await executeEmbed(cwd, provider, version, output, globalCache, options.description, options.fwVersion ? "pinned" : version ? "auto" : "unknown");
|
|
7108
7119
|
}
|
|
7109
|
-
async function executeEmbed(cwd, provider, version, output, globalCache, description) {
|
|
7120
|
+
async function executeEmbed(cwd, provider, version, output, globalCache, description, versionMode) {
|
|
7110
7121
|
let resolvedVersion = version;
|
|
7111
7122
|
let usingDefaultBranch = false;
|
|
7112
7123
|
if (!resolvedVersion && provider.urlConfig) {
|
|
@@ -7122,8 +7133,10 @@ async function executeEmbed(cwd, provider, version, output, globalCache, descrip
|
|
|
7122
7133
|
`));
|
|
7123
7134
|
resolvedVersion = fallbackBranch;
|
|
7124
7135
|
usingDefaultBranch = true;
|
|
7136
|
+
versionMode = versionMode || "default-branch";
|
|
7125
7137
|
} else {
|
|
7126
7138
|
resolvedVersion = detected.version;
|
|
7139
|
+
versionMode = versionMode || "auto";
|
|
7127
7140
|
}
|
|
7128
7141
|
}
|
|
7129
7142
|
const versionLabel = usingDefaultBranch ? "latest" : resolvedVersion;
|
|
@@ -7133,6 +7146,7 @@ Embedding ${import_picocolors2.default.cyan(provider.displayName)} ${import_pico
|
|
|
7133
7146
|
cwd,
|
|
7134
7147
|
provider,
|
|
7135
7148
|
version: resolvedVersion,
|
|
7149
|
+
versionMode,
|
|
7136
7150
|
output,
|
|
7137
7151
|
globalCache,
|
|
7138
7152
|
description
|
|
@@ -7347,15 +7361,17 @@ No providers selected.
|
|
|
7347
7361
|
const output = await promptForOutputFile();
|
|
7348
7362
|
for (const item of selected) {
|
|
7349
7363
|
const provider = getProvider(item.value);
|
|
7350
|
-
await executeEmbed(cwd, provider, item.version, output, undefined, item.description || undefined);
|
|
7364
|
+
await executeEmbed(cwd, provider, item.version, output, undefined, item.description || undefined, item.version ? "pinned" : "auto");
|
|
7351
7365
|
}
|
|
7352
7366
|
process.exit(0);
|
|
7353
7367
|
}
|
|
7354
7368
|
async function promptForOutputFile() {
|
|
7355
7369
|
const defaultOutput = getDefaultOutput();
|
|
7356
7370
|
const choices = [
|
|
7357
|
-
{ title: "
|
|
7371
|
+
{ title: "CLAUDE.local.md", value: "CLAUDE.local.md" },
|
|
7372
|
+
{ title: "AGENTS.local.md", value: "AGENTS.local.md" },
|
|
7358
7373
|
{ title: "CLAUDE.md", value: "CLAUDE.md" },
|
|
7374
|
+
{ title: "AGENTS.md", value: "AGENTS.md" },
|
|
7359
7375
|
{ title: "Custom...", value: "__custom__" }
|
|
7360
7376
|
];
|
|
7361
7377
|
const defaultIndex = choices.findIndex((c) => c.value === defaultOutput);
|
|
@@ -7562,6 +7578,21 @@ Building index from ${import_picocolors2.default.cyan(docsPath)}...`);
|
|
|
7562
7578
|
const newContent = injectIndex(existingContent, indexContent, providerName);
|
|
7563
7579
|
fs.writeFileSync(targetPath, newContent, "utf-8");
|
|
7564
7580
|
const sizeAfter = Buffer.byteLength(newContent, "utf-8");
|
|
7581
|
+
upsertIndexLockEntry(cwd, {
|
|
7582
|
+
id: createIndexId("docs", providerName, output),
|
|
7583
|
+
kind: "docs",
|
|
7584
|
+
source: {
|
|
7585
|
+
type: "local-docs",
|
|
7586
|
+
name: providerName,
|
|
7587
|
+
displayName: name,
|
|
7588
|
+
docsPath,
|
|
7589
|
+
versionMode: "unknown"
|
|
7590
|
+
},
|
|
7591
|
+
targetFile: output,
|
|
7592
|
+
marker: providerName,
|
|
7593
|
+
cachePath: absoluteDocsPath,
|
|
7594
|
+
command: `npx agdex local ${docsPath} --name "${name}" --output ${output}`
|
|
7595
|
+
});
|
|
7565
7596
|
const action = isNewFile ? "Created" : "Updated";
|
|
7566
7597
|
const sizeInfo = isNewFile ? formatSize(sizeAfter) : `${formatSize(sizeBefore)} → ${formatSize(sizeAfter)}`;
|
|
7567
7598
|
console.log(`${import_picocolors2.default.green("✓")} ${action} ${import_picocolors2.default.bold(output)} (${sizeInfo})`);
|
|
@@ -7569,13 +7600,15 @@ Building index from ${import_picocolors2.default.cyan(docsPath)}...`);
|
|
|
7569
7600
|
}
|
|
7570
7601
|
async function runUrl(url, options) {
|
|
7571
7602
|
const cwd = process.cwd();
|
|
7572
|
-
const { createUrlProvider } = await import("../url-scraper-
|
|
7573
|
-
const { pullDocsFromUrl } = await import("../url-scraper-
|
|
7603
|
+
const { createUrlProvider } = await import("../url-scraper-fme0jdje.js");
|
|
7604
|
+
const { pullDocsFromUrl } = await import("../url-scraper-fme0jdje.js");
|
|
7574
7605
|
const name = options.name || new URL(url).hostname.replace(/^docs\./, "").replace(/\.\w+$/, "");
|
|
7575
7606
|
const providerName = name.toLowerCase().replace(/\s+/g, "-");
|
|
7576
7607
|
const output = options.output || getDefaultOutput();
|
|
7577
|
-
const
|
|
7578
|
-
const
|
|
7608
|
+
const globalCache = resolveGlobalCacheOption(options);
|
|
7609
|
+
const docsDir = globalCache ? path.join(os.homedir(), ".cache", "agdex", providerName) : path.join(".agdex", providerName);
|
|
7610
|
+
const docsPath = path.isAbsolute(docsDir) ? docsDir : path.join(cwd, docsDir);
|
|
7611
|
+
const docsLinkPath = globalCache ? docsPath : `./${docsDir}`;
|
|
7579
7612
|
console.log(`
|
|
7580
7613
|
Scraping documentation from ${import_picocolors2.default.cyan(url)}...`);
|
|
7581
7614
|
const cacheHit = fs.existsSync(docsPath) && fs.readdirSync(docsPath).length > 0;
|
|
@@ -7614,19 +7647,41 @@ ${import_picocolors2.default.green("✓")} Downloaded docs to ${import_picocolor
|
|
|
7614
7647
|
const docFiles = collectDocFiles(docsPath, { extensions: [".md"] });
|
|
7615
7648
|
const sections = buildDocTree(docFiles);
|
|
7616
7649
|
const indexContent = generateIndex({
|
|
7617
|
-
docsPath,
|
|
7650
|
+
docsPath: docsLinkPath,
|
|
7618
7651
|
sections,
|
|
7619
7652
|
outputFile: output,
|
|
7620
7653
|
providerName: name,
|
|
7621
7654
|
instruction: `IMPORTANT: Prefer retrieval-led reasoning over pre-training-led reasoning for any ${name} tasks.`,
|
|
7622
|
-
regenerateCommand: `npx agdex url "${url}" --name "${name}" --output ${output}`
|
|
7655
|
+
regenerateCommand: `npx agdex url "${url}" --name "${name}" --output ${output}${globalCache ? " --global" : ""}`
|
|
7623
7656
|
});
|
|
7624
7657
|
const newContent = injectIndex(existingContent, indexContent, providerName);
|
|
7625
7658
|
fs.writeFileSync(targetPath, newContent, "utf-8");
|
|
7626
7659
|
const sizeAfter = Buffer.byteLength(newContent, "utf-8");
|
|
7660
|
+
upsertIndexLockEntry(cwd, {
|
|
7661
|
+
id: createIndexId("docs", providerName, output),
|
|
7662
|
+
kind: "docs",
|
|
7663
|
+
source: {
|
|
7664
|
+
type: "url-docs",
|
|
7665
|
+
name: providerName,
|
|
7666
|
+
displayName: name,
|
|
7667
|
+
url,
|
|
7668
|
+
version: "latest",
|
|
7669
|
+
versionMode: "default-branch"
|
|
7670
|
+
},
|
|
7671
|
+
targetFile: output,
|
|
7672
|
+
marker: providerName,
|
|
7673
|
+
cachePath: docsPath,
|
|
7674
|
+
command: `npx agdex url "${url}" --name "${name}" --output ${output}${globalCache ? " --global" : ""}`
|
|
7675
|
+
});
|
|
7627
7676
|
const action = isNewFile ? "Created" : "Updated";
|
|
7628
7677
|
const sizeInfo = isNewFile ? formatSize(sizeAfter) : `${formatSize(sizeBefore)} → ${formatSize(sizeAfter)}`;
|
|
7629
7678
|
console.log(`${import_picocolors2.default.green("✓")} ${action} ${import_picocolors2.default.bold(output)} (${sizeInfo})`);
|
|
7679
|
+
if (!globalCache) {
|
|
7680
|
+
const gitignoreResult = ensureGitignoreEntry(cwd, ".agdex");
|
|
7681
|
+
if (gitignoreResult.updated) {
|
|
7682
|
+
console.log(`${import_picocolors2.default.green("✓")} Added ${import_picocolors2.default.bold(".agdex")} to .gitignore`);
|
|
7683
|
+
}
|
|
7684
|
+
}
|
|
7630
7685
|
console.log("");
|
|
7631
7686
|
}
|
|
7632
7687
|
function runList() {
|
|
@@ -7675,10 +7730,191 @@ Sources you can index:
|
|
|
7675
7730
|
• Claude Code skills
|
|
7676
7731
|
|
|
7677
7732
|
Run 'agdex' without arguments for interactive mode.`).version("0.4.2");
|
|
7678
|
-
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: from config or CLAUDE.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/)
|
|
7679
|
-
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: from config or CLAUDE.md)").option("-e, --extensions <exts>", "File extensions to include (comma-separated, default: .md,.mdx)").action(runLocal);
|
|
7680
|
-
program2.command("url <url>").description("Scrape documentation from a website URL and build index").option("-n, --name <name>", "Display name for the documentation (default: derived from URL)").option("-o, --output <file>", "Target file (default: from config or CLAUDE.md)").option("-s, --selector <css>", "CSS selector for main content (default: main#main-content, main, article)").option("-c, --concurrency <n>", "Max concurrent fetches (default: 5)").option("--delay <ms>", "Delay between fetch batches in ms (default: 200)").action(runUrl);
|
|
7733
|
+
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: from config or CLAUDE.local.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/").option("-l, --local", "Store docs in local .agdex/ (default)").option("-d, --description <text>", "Additional description to include in the index").option("-u, --url <url>", "Scrape documentation from a website URL").action(runEmbed);
|
|
7734
|
+
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: from config or CLAUDE.local.md)").option("-e, --extensions <exts>", "File extensions to include (comma-separated, default: .md,.mdx)").action(runLocal);
|
|
7735
|
+
program2.command("url <url>").description("Scrape documentation from a website URL and build index").option("-n, --name <name>", "Display name for the documentation (default: derived from URL)").option("-o, --output <file>", "Target file (default: from config or CLAUDE.local.md)").option("-s, --selector <css>", "CSS selector for main content (default: main#main-content, main, article)").option("-c, --concurrency <n>", "Max concurrent fetches (default: 5)").option("--delay <ms>", "Delay between fetch batches in ms (default: 200)").option("-g, --global", "Store docs in global cache (~/.cache/agdex/) instead of local .agdex/").option("-l, --local", "Store docs in local .agdex/ (default)").action(runUrl);
|
|
7681
7736
|
program2.command("list").description("List available documentation providers").action(runList);
|
|
7737
|
+
function runStatus(options) {
|
|
7738
|
+
const report = createStatusReport({
|
|
7739
|
+
cwd: process.cwd(),
|
|
7740
|
+
targetFile: options.output
|
|
7741
|
+
});
|
|
7742
|
+
const unhealthy = report.indexes.filter((index) => index.health !== "ok");
|
|
7743
|
+
if (options.json) {
|
|
7744
|
+
console.log(JSON.stringify(report, null, 2));
|
|
7745
|
+
} else {
|
|
7746
|
+
printStatusReport(report.indexes, report.scannedFiles);
|
|
7747
|
+
}
|
|
7748
|
+
if (options.check && unhealthy.length > 0) {
|
|
7749
|
+
process.exit(1);
|
|
7750
|
+
}
|
|
7751
|
+
}
|
|
7752
|
+
function printStatusReport(indexes, scannedFiles) {
|
|
7753
|
+
console.log(import_picocolors2.default.cyan(`
|
|
7754
|
+
agdex status
|
|
7755
|
+
`));
|
|
7756
|
+
console.log(import_picocolors2.default.gray(` Scanned: ${scannedFiles.length > 0 ? scannedFiles.join(", ") : "no agent instruction files found"}`));
|
|
7757
|
+
if (indexes.length === 0) {
|
|
7758
|
+
console.log(import_picocolors2.default.yellow(`
|
|
7759
|
+
No indexes found.
|
|
7760
|
+
`));
|
|
7761
|
+
return;
|
|
7762
|
+
}
|
|
7763
|
+
console.log("");
|
|
7764
|
+
for (const index of indexes) {
|
|
7765
|
+
const symbol = index.health === "ok" ? import_picocolors2.default.green("✓") : import_picocolors2.default.yellow("!");
|
|
7766
|
+
const source = index.source?.displayName || index.source?.name || index.marker;
|
|
7767
|
+
console.log(` ${symbol} ${import_picocolors2.default.bold(index.kind)} ${source} ${import_picocolors2.default.gray(`(${index.targetFile})`)}`);
|
|
7768
|
+
console.log(` health: ${formatHealth(index.health)}`);
|
|
7769
|
+
if (index.cachePath) {
|
|
7770
|
+
console.log(` cache: ${index.cachePath}`);
|
|
7771
|
+
}
|
|
7772
|
+
if (index.health !== "ok") {
|
|
7773
|
+
console.log(` action: ${index.suggestedAction}`);
|
|
7774
|
+
}
|
|
7775
|
+
}
|
|
7776
|
+
console.log("");
|
|
7777
|
+
}
|
|
7778
|
+
function formatHealth(health) {
|
|
7779
|
+
if (health === "ok")
|
|
7780
|
+
return import_picocolors2.default.green(health);
|
|
7781
|
+
return import_picocolors2.default.yellow(health);
|
|
7782
|
+
}
|
|
7783
|
+
program2.command("status").description("Inspect lockfile-backed index health").option("-o, --output <file>", "Scope status to one agent instruction file").option("--json", "Print machine-readable JSON").option("--check", "Exit non-zero when any discovered index is unhealthy").action(runStatus);
|
|
7784
|
+
async function runRefresh(options) {
|
|
7785
|
+
const cwd = process.cwd();
|
|
7786
|
+
const lockfile = readIndexLockfile(cwd);
|
|
7787
|
+
const repairIds = options.repair ? new Set(createStatusReport({ cwd, targetFile: options.output }).indexes.filter((index) => index.lockfileEntry && index.health !== "ok").map((index) => index.id)) : null;
|
|
7788
|
+
const entries = lockfile.indexes.filter((entry) => {
|
|
7789
|
+
if (options.output && entry.targetFile !== options.output)
|
|
7790
|
+
return false;
|
|
7791
|
+
if (options.kind && entry.kind !== options.kind)
|
|
7792
|
+
return false;
|
|
7793
|
+
if (options.provider && entry.source.name !== options.provider && entry.marker !== options.provider)
|
|
7794
|
+
return false;
|
|
7795
|
+
if (repairIds && !repairIds.has(entry.id))
|
|
7796
|
+
return false;
|
|
7797
|
+
return true;
|
|
7798
|
+
});
|
|
7799
|
+
if (entries.length === 0) {
|
|
7800
|
+
console.log(import_picocolors2.default.yellow(`
|
|
7801
|
+
No lockfile-backed indexes matched refresh filters.
|
|
7802
|
+
`));
|
|
7803
|
+
return;
|
|
7804
|
+
}
|
|
7805
|
+
for (const entry of entries) {
|
|
7806
|
+
if (options.force && entry.kind === "docs") {
|
|
7807
|
+
const cachePath = path.isAbsolute(entry.cachePath) ? entry.cachePath : path.join(cwd, entry.cachePath);
|
|
7808
|
+
if (fs.existsSync(cachePath)) {
|
|
7809
|
+
fs.rmSync(cachePath, { recursive: true, force: true });
|
|
7810
|
+
}
|
|
7811
|
+
}
|
|
7812
|
+
if (entry.kind === "skills") {
|
|
7813
|
+
if (entry.source.type === "skills-sh" && entry.source.repo) {
|
|
7814
|
+
await runSkillsEmbed({ repo: entry.source.repo, output: entry.targetFile });
|
|
7815
|
+
} else {
|
|
7816
|
+
await runSkillsEmbed({ output: entry.targetFile });
|
|
7817
|
+
}
|
|
7818
|
+
continue;
|
|
7819
|
+
}
|
|
7820
|
+
if (entry.source.type === "local-docs" && entry.source.docsPath) {
|
|
7821
|
+
await runLocal(entry.source.docsPath, {
|
|
7822
|
+
name: entry.source.displayName || entry.source.name,
|
|
7823
|
+
output: entry.targetFile
|
|
7824
|
+
});
|
|
7825
|
+
continue;
|
|
7826
|
+
}
|
|
7827
|
+
if (entry.source.type === "url-docs" && entry.source.url) {
|
|
7828
|
+
await runUrl(entry.source.url, {
|
|
7829
|
+
name: entry.source.displayName || entry.source.name,
|
|
7830
|
+
output: entry.targetFile,
|
|
7831
|
+
global: path.isAbsolute(entry.cachePath)
|
|
7832
|
+
});
|
|
7833
|
+
continue;
|
|
7834
|
+
}
|
|
7835
|
+
const provider = entry.source.type === "builtin-provider" ? getProvider(entry.source.name) : entry.source.repo && entry.source.docsPath ? createProvider({
|
|
7836
|
+
name: entry.source.name,
|
|
7837
|
+
displayName: entry.source.displayName || entry.source.name,
|
|
7838
|
+
repo: entry.source.repo,
|
|
7839
|
+
docsPath: entry.source.docsPath
|
|
7840
|
+
}) : null;
|
|
7841
|
+
if (!provider) {
|
|
7842
|
+
console.log(import_picocolors2.default.yellow(`Skipped ${entry.id}: source metadata is incomplete.`));
|
|
7843
|
+
continue;
|
|
7844
|
+
}
|
|
7845
|
+
const version = entry.source.versionMode === "pinned" ? entry.source.version : undefined;
|
|
7846
|
+
await executeEmbed(cwd, provider, version, entry.targetFile, path.isAbsolute(entry.cachePath), undefined, entry.source.versionMode);
|
|
7847
|
+
}
|
|
7848
|
+
}
|
|
7849
|
+
program2.command("refresh").description("Refresh lockfile-backed indexes").option("-o, --output <file>", "Refresh indexes in one agent instruction file").option("-p, --provider <name>", "Refresh one provider or marker name").option("--kind <kind>", "Refresh only docs or skills indexes").option("--force", "Delete existing documentation caches before refreshing").option("--repair", "Refresh only unhealthy lockfile-backed indexes").action(runRefresh);
|
|
7850
|
+
function runMigrate(options) {
|
|
7851
|
+
const cwd = process.cwd();
|
|
7852
|
+
const targets = options.output ? [options.output] : ["AGENTS.md", "AGENTS.local.md", "CLAUDE.md", "CLAUDE.local.md"];
|
|
7853
|
+
const migrated = [];
|
|
7854
|
+
const skipped = [];
|
|
7855
|
+
for (const targetFile of targets) {
|
|
7856
|
+
const targetPath = path.join(cwd, targetFile);
|
|
7857
|
+
if (!fs.existsSync(targetPath))
|
|
7858
|
+
continue;
|
|
7859
|
+
const content = fs.readFileSync(targetPath, "utf-8");
|
|
7860
|
+
const regex = /<!-- AGENTS-MD-EMBED-START:(\S+?) -->\n([\s\S]*?)\n<!-- AGENTS-MD-EMBED-END:\1 -->/g;
|
|
7861
|
+
let match;
|
|
7862
|
+
while ((match = regex.exec(content)) !== null) {
|
|
7863
|
+
const marker = match[1];
|
|
7864
|
+
const block = match[2];
|
|
7865
|
+
const rootMatch = block.match(/(?:^|\|)root:\s*([^|]+)/);
|
|
7866
|
+
if (!rootMatch) {
|
|
7867
|
+
skipped.push({ targetFile, marker, reason: "missing root metadata" });
|
|
7868
|
+
continue;
|
|
7869
|
+
}
|
|
7870
|
+
const cachePath = rootMatch[1].trim().replace(/^\.\//, "");
|
|
7871
|
+
const provider = getProvider(marker);
|
|
7872
|
+
const source = provider ? {
|
|
7873
|
+
type: "builtin-provider",
|
|
7874
|
+
name: provider.name,
|
|
7875
|
+
displayName: provider.displayName,
|
|
7876
|
+
repo: provider.repo,
|
|
7877
|
+
docsPath: provider.docsPath,
|
|
7878
|
+
versionMode: "unknown"
|
|
7879
|
+
} : {
|
|
7880
|
+
type: "local-docs",
|
|
7881
|
+
name: marker,
|
|
7882
|
+
displayName: marker,
|
|
7883
|
+
docsPath: cachePath,
|
|
7884
|
+
versionMode: "unknown"
|
|
7885
|
+
};
|
|
7886
|
+
const entry = upsertIndexLockEntry(cwd, {
|
|
7887
|
+
id: createIndexId("docs", marker, targetFile),
|
|
7888
|
+
kind: "docs",
|
|
7889
|
+
source,
|
|
7890
|
+
targetFile,
|
|
7891
|
+
marker,
|
|
7892
|
+
cachePath,
|
|
7893
|
+
command: `npx agdex --provider ${marker} --output ${targetFile}`
|
|
7894
|
+
});
|
|
7895
|
+
migrated.push(entry.id);
|
|
7896
|
+
}
|
|
7897
|
+
}
|
|
7898
|
+
const result = { migrated, skipped };
|
|
7899
|
+
if (options.json) {
|
|
7900
|
+
console.log(JSON.stringify(result, null, 2));
|
|
7901
|
+
return;
|
|
7902
|
+
}
|
|
7903
|
+
console.log(import_picocolors2.default.cyan(`
|
|
7904
|
+
agdex migrate
|
|
7905
|
+
`));
|
|
7906
|
+
for (const id of migrated) {
|
|
7907
|
+
console.log(`${import_picocolors2.default.green("✓")} Created lockfile entry ${import_picocolors2.default.bold(id)}`);
|
|
7908
|
+
}
|
|
7909
|
+
for (const item of skipped) {
|
|
7910
|
+
console.log(`${import_picocolors2.default.yellow("!")} Skipped ${item.marker} in ${item.targetFile}: ${item.reason}`);
|
|
7911
|
+
}
|
|
7912
|
+
if (migrated.length === 0 && skipped.length === 0) {
|
|
7913
|
+
console.log(import_picocolors2.default.yellow(" No migratable indexes found."));
|
|
7914
|
+
}
|
|
7915
|
+
console.log("");
|
|
7916
|
+
}
|
|
7917
|
+
program2.command("migrate").description("Create lockfile entries from existing embedded markers when safe").option("-o, --output <file>", "Migrate one agent instruction file").option("--json", "Print machine-readable JSON").action(runMigrate);
|
|
7682
7918
|
async function runRemove(options) {
|
|
7683
7919
|
const cwd = process.cwd();
|
|
7684
7920
|
const output = options.output || getDefaultOutput();
|
|
@@ -7778,7 +8014,7 @@ No indices found to remove.
|
|
|
7778
8014
|
console.log(import_picocolors2.default.gray(` (${formatSize(sizeBefore)} → ${formatSize(sizeAfter)})`));
|
|
7779
8015
|
console.log("");
|
|
7780
8016
|
}
|
|
7781
|
-
program2.command("remove").description("Remove embedded indices from AGENTS.md/CLAUDE.md").option("-o, --output <file>", "Target file (default: from config or CLAUDE.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);
|
|
8017
|
+
program2.command("remove").description("Remove embedded indices from AGENTS.md/CLAUDE.md").option("-o, --output <file>", "Target file (default: from config or CLAUDE.local.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);
|
|
7782
8018
|
var skillsCommand = program2.command("skills").description("Manage Claude Code skills indexing");
|
|
7783
8019
|
async function runSkillsEmbed(options) {
|
|
7784
8020
|
const cwd = process.cwd();
|
|
@@ -7838,6 +8074,21 @@ Fetching skills from ${import_picocolors2.default.cyan(repoName)}...`);
|
|
|
7838
8074
|
const newContent = injectSkillsIndex(existingContent, indexContent);
|
|
7839
8075
|
fs.writeFileSync(targetPath, newContent, "utf-8");
|
|
7840
8076
|
const sizeAfter = Buffer.byteLength(newContent, "utf-8");
|
|
8077
|
+
upsertIndexLockEntry(cwd, {
|
|
8078
|
+
id: createIndexId("skills", `skills-sh:${repoName}`, output),
|
|
8079
|
+
kind: "skills",
|
|
8080
|
+
source: {
|
|
8081
|
+
type: "skills-sh",
|
|
8082
|
+
name: `skills-sh:${repoName}`,
|
|
8083
|
+
displayName: repoName,
|
|
8084
|
+
repo: repoName,
|
|
8085
|
+
versionMode: "default-branch"
|
|
8086
|
+
},
|
|
8087
|
+
targetFile: output,
|
|
8088
|
+
marker: "skills",
|
|
8089
|
+
cachePath: cacheDir,
|
|
8090
|
+
command: `npx agdex skills embed --repo ${repoName}`
|
|
8091
|
+
});
|
|
7841
8092
|
const action2 = isNewFile ? "Created" : "Updated";
|
|
7842
8093
|
const sizeInfo2 = isNewFile ? formatSize(sizeAfter) : `${formatSize(sizeBefore)} → ${formatSize(sizeAfter)}`;
|
|
7843
8094
|
console.log(`${import_picocolors2.default.green("✓")} ${action2} ${import_picocolors2.default.bold(output)} (${sizeInfo2})`);
|
|
@@ -7860,6 +8111,20 @@ Discovering skills from ${import_picocolors2.default.cyan(sources.length.toStrin
|
|
|
7860
8111
|
const sizeInfo = result.isNewFile ? formatSize(result.sizeAfter) : `${formatSize(result.sizeBefore)} → ${formatSize(result.sizeAfter)}`;
|
|
7861
8112
|
console.log(`${import_picocolors2.default.green("✓")} ${action} ${import_picocolors2.default.bold(result.targetFile)} (${sizeInfo})`);
|
|
7862
8113
|
console.log(`${import_picocolors2.default.green("✓")} Indexed ${import_picocolors2.default.bold(result.skillCount.toString())} skills`);
|
|
8114
|
+
upsertIndexLockEntry(cwd, {
|
|
8115
|
+
id: createIndexId("skills", "local-skills", output),
|
|
8116
|
+
kind: "skills",
|
|
8117
|
+
source: {
|
|
8118
|
+
type: "skills-local",
|
|
8119
|
+
name: "local-skills",
|
|
8120
|
+
displayName: "Local skills",
|
|
8121
|
+
versionMode: "unknown"
|
|
8122
|
+
},
|
|
8123
|
+
targetFile: output,
|
|
8124
|
+
marker: "skills",
|
|
8125
|
+
cachePath: cwd,
|
|
8126
|
+
command: "npx agdex skills embed"
|
|
8127
|
+
});
|
|
7863
8128
|
if (result.sourceBreakdown) {
|
|
7864
8129
|
const breakdown = [];
|
|
7865
8130
|
if (result.sourceBreakdown.plugin > 0) {
|
|
@@ -8015,8 +8280,8 @@ Selected ${import_picocolors2.default.bold(selected.name)} from ${import_picocol
|
|
|
8015
8280
|
process.exit(1);
|
|
8016
8281
|
}
|
|
8017
8282
|
}
|
|
8018
|
-
skillsCommand.command("embed").description("Embed skills index into AGENTS.md").option("-o, --output <file>", "Target file (default: from config or CLAUDE.md)").option("--plugin <path...>", "Additional plugin repo paths (with plugins/ structure)").option("--plugins", "Include enabled plugins from settings.json (default: true)").option("--no-plugins", "Exclude enabled plugins from settings.json").option("--user", "Include ~/.claude/skills (default: true)").option("--no-user", "Exclude ~/.claude/skills").option("--project", "Include .claude/skills (default: true)").option("--no-project", "Exclude .claude/skills").option("--repo <owner/repo>", "Fetch and index skills from a skills.sh-compatible GitHub repository").action(runSkillsEmbed);
|
|
8283
|
+
skillsCommand.command("embed").description("Embed skills index into AGENTS.md").option("-o, --output <file>", "Target file (default: from config or CLAUDE.local.md)").option("--plugin <path...>", "Additional plugin repo paths (with plugins/ structure)").option("--plugins", "Include enabled plugins from settings.json (default: true)").option("--no-plugins", "Exclude enabled plugins from settings.json").option("--user", "Include ~/.claude/skills (default: true)").option("--no-user", "Exclude ~/.claude/skills").option("--project", "Include .claude/skills (default: true)").option("--no-project", "Exclude .claude/skills").option("--repo <owner/repo>", "Fetch and index skills from a skills.sh-compatible GitHub repository").action(runSkillsEmbed);
|
|
8019
8284
|
skillsCommand.command("list").description("List discovered skills").option("--plugin <path...>", "Additional plugin repo paths (with plugins/ structure)").option("--plugins", "Include enabled plugins from settings.json (default: true)").option("--no-plugins", "Exclude enabled plugins from settings.json").option("--user", "Include ~/.claude/skills (default: true)").option("--no-user", "Exclude ~/.claude/skills").option("--project", "Include .claude/skills (default: true)").option("--no-project", "Exclude .claude/skills").action(runSkillsList);
|
|
8020
|
-
skillsCommand.command("local <skills-path>").description("Index skills from a local path").option("-o, --output <file>", "Target file (default: from config or CLAUDE.md)").option("-n, --name <name>", "Label for this skill source").action(runSkillsLocal);
|
|
8285
|
+
skillsCommand.command("local <skills-path>").description("Index skills from a local path").option("-o, --output <file>", "Target file (default: from config or CLAUDE.local.md)").option("-n, --name <name>", "Label for this skill source").action(runSkillsLocal);
|
|
8021
8286
|
skillsCommand.command("find [query]").description("Search skills.sh for agent skills").option("-l, --limit <n>", "Max results (default: 20)", parseInt).option("-o, --output <file>", "Target file for embedding").action(runSkillsFind);
|
|
8022
8287
|
program2.parse();
|