agdex 0.7.0 → 0.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +41 -11
- package/dist/cli/index.js +285 -23
- package/dist/{index-ecjc59t4.js → index-9k6cxm1y.js} +445 -231
- package/dist/index-pyanjjwn.js +21 -0
- package/dist/index.d.ts +8 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +21 -4
- 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/providers/generic.d.ts +12 -1
- package/dist/lib/providers/generic.d.ts.map +1 -1
- package/dist/lib/providers/index.d.ts +1 -2
- package/dist/lib/providers/index.d.ts.map +1 -1
- package/dist/lib/types.d.ts +3 -1
- package/dist/lib/types.d.ts.map +1 -1
- package/dist/lib/url-scraper.d.ts +0 -11
- package/dist/lib/url-scraper.d.ts.map +1 -1
- package/dist/{index-dtcewfnz.js → url-scraper-axfs3dz7.js} +14 -38
- package/package.json +2 -2
- package/dist/index-1v32v5tn.js +0 -2356
- package/dist/index-cm3qmz9v.js +0 -2356
- 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-9k6cxm1y.js";
|
|
43
48
|
import {
|
|
44
49
|
__commonJS,
|
|
45
50
|
__require,
|
|
46
51
|
__toESM
|
|
47
|
-
} from "../index-
|
|
52
|
+
} from "../index-pyanjjwn.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,7 +7361,7 @@ 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
|
}
|
|
@@ -7564,6 +7578,21 @@ Building index from ${import_picocolors2.default.cyan(docsPath)}...`);
|
|
|
7564
7578
|
const newContent = injectIndex(existingContent, indexContent, providerName);
|
|
7565
7579
|
fs.writeFileSync(targetPath, newContent, "utf-8");
|
|
7566
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
|
+
});
|
|
7567
7596
|
const action = isNewFile ? "Created" : "Updated";
|
|
7568
7597
|
const sizeInfo = isNewFile ? formatSize(sizeAfter) : `${formatSize(sizeBefore)} → ${formatSize(sizeAfter)}`;
|
|
7569
7598
|
console.log(`${import_picocolors2.default.green("✓")} ${action} ${import_picocolors2.default.bold(output)} (${sizeInfo})`);
|
|
@@ -7571,13 +7600,14 @@ Building index from ${import_picocolors2.default.cyan(docsPath)}...`);
|
|
|
7571
7600
|
}
|
|
7572
7601
|
async function runUrl(url, options) {
|
|
7573
7602
|
const cwd = process.cwd();
|
|
7574
|
-
const {
|
|
7575
|
-
const { pullDocsFromUrl } = await import("../url-scraper-5sj8c56t.js");
|
|
7603
|
+
const { pullDocsFromUrl } = await import("../url-scraper-axfs3dz7.js");
|
|
7576
7604
|
const name = options.name || new URL(url).hostname.replace(/^docs\./, "").replace(/\.\w+$/, "");
|
|
7577
7605
|
const providerName = name.toLowerCase().replace(/\s+/g, "-");
|
|
7578
7606
|
const output = options.output || getDefaultOutput();
|
|
7579
|
-
const
|
|
7580
|
-
const
|
|
7607
|
+
const globalCache = resolveGlobalCacheOption(options);
|
|
7608
|
+
const docsDir = globalCache ? path.join(os.homedir(), ".cache", "agdex", providerName) : path.join(".agdex", providerName);
|
|
7609
|
+
const docsPath = path.isAbsolute(docsDir) ? docsDir : path.join(cwd, docsDir);
|
|
7610
|
+
const docsLinkPath = globalCache ? docsPath : `./${docsDir}`;
|
|
7581
7611
|
console.log(`
|
|
7582
7612
|
Scraping documentation from ${import_picocolors2.default.cyan(url)}...`);
|
|
7583
7613
|
const cacheHit = fs.existsSync(docsPath) && fs.readdirSync(docsPath).length > 0;
|
|
@@ -7616,19 +7646,41 @@ ${import_picocolors2.default.green("✓")} Downloaded docs to ${import_picocolor
|
|
|
7616
7646
|
const docFiles = collectDocFiles(docsPath, { extensions: [".md"] });
|
|
7617
7647
|
const sections = buildDocTree(docFiles);
|
|
7618
7648
|
const indexContent = generateIndex({
|
|
7619
|
-
docsPath,
|
|
7649
|
+
docsPath: docsLinkPath,
|
|
7620
7650
|
sections,
|
|
7621
7651
|
outputFile: output,
|
|
7622
7652
|
providerName: name,
|
|
7623
7653
|
instruction: `IMPORTANT: Prefer retrieval-led reasoning over pre-training-led reasoning for any ${name} tasks.`,
|
|
7624
|
-
regenerateCommand: `npx agdex url "${url}" --name "${name}" --output ${output}`
|
|
7654
|
+
regenerateCommand: `npx agdex url "${url}" --name "${name}" --output ${output}${globalCache ? " --global" : ""}`
|
|
7625
7655
|
});
|
|
7626
7656
|
const newContent = injectIndex(existingContent, indexContent, providerName);
|
|
7627
7657
|
fs.writeFileSync(targetPath, newContent, "utf-8");
|
|
7628
7658
|
const sizeAfter = Buffer.byteLength(newContent, "utf-8");
|
|
7659
|
+
upsertIndexLockEntry(cwd, {
|
|
7660
|
+
id: createIndexId("docs", providerName, output),
|
|
7661
|
+
kind: "docs",
|
|
7662
|
+
source: {
|
|
7663
|
+
type: "url-docs",
|
|
7664
|
+
name: providerName,
|
|
7665
|
+
displayName: name,
|
|
7666
|
+
url,
|
|
7667
|
+
version: "latest",
|
|
7668
|
+
versionMode: "default-branch"
|
|
7669
|
+
},
|
|
7670
|
+
targetFile: output,
|
|
7671
|
+
marker: providerName,
|
|
7672
|
+
cachePath: docsPath,
|
|
7673
|
+
command: `npx agdex url "${url}" --name "${name}" --output ${output}${globalCache ? " --global" : ""}`
|
|
7674
|
+
});
|
|
7629
7675
|
const action = isNewFile ? "Created" : "Updated";
|
|
7630
7676
|
const sizeInfo = isNewFile ? formatSize(sizeAfter) : `${formatSize(sizeBefore)} → ${formatSize(sizeAfter)}`;
|
|
7631
7677
|
console.log(`${import_picocolors2.default.green("✓")} ${action} ${import_picocolors2.default.bold(output)} (${sizeInfo})`);
|
|
7678
|
+
if (!globalCache) {
|
|
7679
|
+
const gitignoreResult = ensureGitignoreEntry(cwd, ".agdex");
|
|
7680
|
+
if (gitignoreResult.updated) {
|
|
7681
|
+
console.log(`${import_picocolors2.default.green("✓")} Added ${import_picocolors2.default.bold(".agdex")} to .gitignore`);
|
|
7682
|
+
}
|
|
7683
|
+
}
|
|
7632
7684
|
console.log("");
|
|
7633
7685
|
}
|
|
7634
7686
|
function runList() {
|
|
@@ -7677,10 +7729,191 @@ Sources you can index:
|
|
|
7677
7729
|
• Claude Code skills
|
|
7678
7730
|
|
|
7679
7731
|
Run 'agdex' without arguments for interactive mode.`).version("0.4.2");
|
|
7680
|
-
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/)
|
|
7732
|
+
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);
|
|
7681
7733
|
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);
|
|
7682
|
-
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)").action(runUrl);
|
|
7734
|
+
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);
|
|
7683
7735
|
program2.command("list").description("List available documentation providers").action(runList);
|
|
7736
|
+
function runStatus(options) {
|
|
7737
|
+
const report = createStatusReport({
|
|
7738
|
+
cwd: process.cwd(),
|
|
7739
|
+
targetFile: options.output
|
|
7740
|
+
});
|
|
7741
|
+
const unhealthy = report.indexes.filter((index) => index.health !== "ok");
|
|
7742
|
+
if (options.json) {
|
|
7743
|
+
console.log(JSON.stringify(report, null, 2));
|
|
7744
|
+
} else {
|
|
7745
|
+
printStatusReport(report.indexes, report.scannedFiles);
|
|
7746
|
+
}
|
|
7747
|
+
if (options.check && unhealthy.length > 0) {
|
|
7748
|
+
process.exit(1);
|
|
7749
|
+
}
|
|
7750
|
+
}
|
|
7751
|
+
function printStatusReport(indexes, scannedFiles) {
|
|
7752
|
+
console.log(import_picocolors2.default.cyan(`
|
|
7753
|
+
agdex status
|
|
7754
|
+
`));
|
|
7755
|
+
console.log(import_picocolors2.default.gray(` Scanned: ${scannedFiles.length > 0 ? scannedFiles.join(", ") : "no agent instruction files found"}`));
|
|
7756
|
+
if (indexes.length === 0) {
|
|
7757
|
+
console.log(import_picocolors2.default.yellow(`
|
|
7758
|
+
No indexes found.
|
|
7759
|
+
`));
|
|
7760
|
+
return;
|
|
7761
|
+
}
|
|
7762
|
+
console.log("");
|
|
7763
|
+
for (const index of indexes) {
|
|
7764
|
+
const symbol = index.health === "ok" ? import_picocolors2.default.green("✓") : import_picocolors2.default.yellow("!");
|
|
7765
|
+
const source = index.source?.displayName || index.source?.name || index.marker;
|
|
7766
|
+
console.log(` ${symbol} ${import_picocolors2.default.bold(index.kind)} ${source} ${import_picocolors2.default.gray(`(${index.targetFile})`)}`);
|
|
7767
|
+
console.log(` health: ${formatHealth(index.health)}`);
|
|
7768
|
+
if (index.cachePath) {
|
|
7769
|
+
console.log(` cache: ${index.cachePath}`);
|
|
7770
|
+
}
|
|
7771
|
+
if (index.health !== "ok") {
|
|
7772
|
+
console.log(` action: ${index.suggestedAction}`);
|
|
7773
|
+
}
|
|
7774
|
+
}
|
|
7775
|
+
console.log("");
|
|
7776
|
+
}
|
|
7777
|
+
function formatHealth(health) {
|
|
7778
|
+
if (health === "ok")
|
|
7779
|
+
return import_picocolors2.default.green(health);
|
|
7780
|
+
return import_picocolors2.default.yellow(health);
|
|
7781
|
+
}
|
|
7782
|
+
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);
|
|
7783
|
+
async function runRefresh(options) {
|
|
7784
|
+
const cwd = process.cwd();
|
|
7785
|
+
const lockfile = readIndexLockfile(cwd);
|
|
7786
|
+
const repairIds = options.repair ? new Set(createStatusReport({ cwd, targetFile: options.output }).indexes.filter((index) => index.lockfileEntry && index.health !== "ok").map((index) => index.id)) : null;
|
|
7787
|
+
const entries = lockfile.indexes.filter((entry) => {
|
|
7788
|
+
if (options.output && entry.targetFile !== options.output)
|
|
7789
|
+
return false;
|
|
7790
|
+
if (options.kind && entry.kind !== options.kind)
|
|
7791
|
+
return false;
|
|
7792
|
+
if (options.provider && entry.source.name !== options.provider && entry.marker !== options.provider)
|
|
7793
|
+
return false;
|
|
7794
|
+
if (repairIds && !repairIds.has(entry.id))
|
|
7795
|
+
return false;
|
|
7796
|
+
return true;
|
|
7797
|
+
});
|
|
7798
|
+
if (entries.length === 0) {
|
|
7799
|
+
console.log(import_picocolors2.default.yellow(`
|
|
7800
|
+
No lockfile-backed indexes matched refresh filters.
|
|
7801
|
+
`));
|
|
7802
|
+
return;
|
|
7803
|
+
}
|
|
7804
|
+
for (const entry of entries) {
|
|
7805
|
+
if (options.force && entry.kind === "docs") {
|
|
7806
|
+
const cachePath = path.isAbsolute(entry.cachePath) ? entry.cachePath : path.join(cwd, entry.cachePath);
|
|
7807
|
+
if (fs.existsSync(cachePath)) {
|
|
7808
|
+
fs.rmSync(cachePath, { recursive: true, force: true });
|
|
7809
|
+
}
|
|
7810
|
+
}
|
|
7811
|
+
if (entry.kind === "skills") {
|
|
7812
|
+
if (entry.source.type === "skills-sh" && entry.source.repo) {
|
|
7813
|
+
await runSkillsEmbed({ repo: entry.source.repo, output: entry.targetFile });
|
|
7814
|
+
} else {
|
|
7815
|
+
await runSkillsEmbed({ output: entry.targetFile });
|
|
7816
|
+
}
|
|
7817
|
+
continue;
|
|
7818
|
+
}
|
|
7819
|
+
if (entry.source.type === "local-docs" && entry.source.docsPath) {
|
|
7820
|
+
await runLocal(entry.source.docsPath, {
|
|
7821
|
+
name: entry.source.displayName || entry.source.name,
|
|
7822
|
+
output: entry.targetFile
|
|
7823
|
+
});
|
|
7824
|
+
continue;
|
|
7825
|
+
}
|
|
7826
|
+
if (entry.source.type === "url-docs" && entry.source.url) {
|
|
7827
|
+
await runUrl(entry.source.url, {
|
|
7828
|
+
name: entry.source.displayName || entry.source.name,
|
|
7829
|
+
output: entry.targetFile,
|
|
7830
|
+
global: path.isAbsolute(entry.cachePath)
|
|
7831
|
+
});
|
|
7832
|
+
continue;
|
|
7833
|
+
}
|
|
7834
|
+
const provider = entry.source.type === "builtin-provider" ? getProvider(entry.source.name) : entry.source.repo && entry.source.docsPath ? createProvider({
|
|
7835
|
+
name: entry.source.name,
|
|
7836
|
+
displayName: entry.source.displayName || entry.source.name,
|
|
7837
|
+
repo: entry.source.repo,
|
|
7838
|
+
docsPath: entry.source.docsPath
|
|
7839
|
+
}) : null;
|
|
7840
|
+
if (!provider) {
|
|
7841
|
+
console.log(import_picocolors2.default.yellow(`Skipped ${entry.id}: source metadata is incomplete.`));
|
|
7842
|
+
continue;
|
|
7843
|
+
}
|
|
7844
|
+
const version = entry.source.versionMode === "pinned" ? entry.source.version : undefined;
|
|
7845
|
+
await executeEmbed(cwd, provider, version, entry.targetFile, path.isAbsolute(entry.cachePath), undefined, entry.source.versionMode);
|
|
7846
|
+
}
|
|
7847
|
+
}
|
|
7848
|
+
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);
|
|
7849
|
+
function runMigrate(options) {
|
|
7850
|
+
const cwd = process.cwd();
|
|
7851
|
+
const targets = options.output ? [options.output] : ["AGENTS.md", "AGENTS.local.md", "CLAUDE.md", "CLAUDE.local.md"];
|
|
7852
|
+
const migrated = [];
|
|
7853
|
+
const skipped = [];
|
|
7854
|
+
for (const targetFile of targets) {
|
|
7855
|
+
const targetPath = path.join(cwd, targetFile);
|
|
7856
|
+
if (!fs.existsSync(targetPath))
|
|
7857
|
+
continue;
|
|
7858
|
+
const content = fs.readFileSync(targetPath, "utf-8");
|
|
7859
|
+
const regex = /<!-- AGENTS-MD-EMBED-START:(\S+?) -->\n([\s\S]*?)\n<!-- AGENTS-MD-EMBED-END:\1 -->/g;
|
|
7860
|
+
let match;
|
|
7861
|
+
while ((match = regex.exec(content)) !== null) {
|
|
7862
|
+
const marker = match[1];
|
|
7863
|
+
const block = match[2];
|
|
7864
|
+
const rootMatch = block.match(/(?:^|\|)root:\s*([^|]+)/);
|
|
7865
|
+
if (!rootMatch) {
|
|
7866
|
+
skipped.push({ targetFile, marker, reason: "missing root metadata" });
|
|
7867
|
+
continue;
|
|
7868
|
+
}
|
|
7869
|
+
const cachePath = rootMatch[1].trim().replace(/^\.\//, "");
|
|
7870
|
+
const provider = getProvider(marker);
|
|
7871
|
+
const source = provider ? {
|
|
7872
|
+
type: "builtin-provider",
|
|
7873
|
+
name: provider.name,
|
|
7874
|
+
displayName: provider.displayName,
|
|
7875
|
+
repo: provider.repo,
|
|
7876
|
+
docsPath: provider.docsPath,
|
|
7877
|
+
versionMode: "unknown"
|
|
7878
|
+
} : {
|
|
7879
|
+
type: "local-docs",
|
|
7880
|
+
name: marker,
|
|
7881
|
+
displayName: marker,
|
|
7882
|
+
docsPath: cachePath,
|
|
7883
|
+
versionMode: "unknown"
|
|
7884
|
+
};
|
|
7885
|
+
const entry = upsertIndexLockEntry(cwd, {
|
|
7886
|
+
id: createIndexId("docs", marker, targetFile),
|
|
7887
|
+
kind: "docs",
|
|
7888
|
+
source,
|
|
7889
|
+
targetFile,
|
|
7890
|
+
marker,
|
|
7891
|
+
cachePath,
|
|
7892
|
+
command: `npx agdex --provider ${marker} --output ${targetFile}`
|
|
7893
|
+
});
|
|
7894
|
+
migrated.push(entry.id);
|
|
7895
|
+
}
|
|
7896
|
+
}
|
|
7897
|
+
const result = { migrated, skipped };
|
|
7898
|
+
if (options.json) {
|
|
7899
|
+
console.log(JSON.stringify(result, null, 2));
|
|
7900
|
+
return;
|
|
7901
|
+
}
|
|
7902
|
+
console.log(import_picocolors2.default.cyan(`
|
|
7903
|
+
agdex migrate
|
|
7904
|
+
`));
|
|
7905
|
+
for (const id of migrated) {
|
|
7906
|
+
console.log(`${import_picocolors2.default.green("✓")} Created lockfile entry ${import_picocolors2.default.bold(id)}`);
|
|
7907
|
+
}
|
|
7908
|
+
for (const item of skipped) {
|
|
7909
|
+
console.log(`${import_picocolors2.default.yellow("!")} Skipped ${item.marker} in ${item.targetFile}: ${item.reason}`);
|
|
7910
|
+
}
|
|
7911
|
+
if (migrated.length === 0 && skipped.length === 0) {
|
|
7912
|
+
console.log(import_picocolors2.default.yellow(" No migratable indexes found."));
|
|
7913
|
+
}
|
|
7914
|
+
console.log("");
|
|
7915
|
+
}
|
|
7916
|
+
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);
|
|
7684
7917
|
async function runRemove(options) {
|
|
7685
7918
|
const cwd = process.cwd();
|
|
7686
7919
|
const output = options.output || getDefaultOutput();
|
|
@@ -7840,6 +8073,21 @@ Fetching skills from ${import_picocolors2.default.cyan(repoName)}...`);
|
|
|
7840
8073
|
const newContent = injectSkillsIndex(existingContent, indexContent);
|
|
7841
8074
|
fs.writeFileSync(targetPath, newContent, "utf-8");
|
|
7842
8075
|
const sizeAfter = Buffer.byteLength(newContent, "utf-8");
|
|
8076
|
+
upsertIndexLockEntry(cwd, {
|
|
8077
|
+
id: createIndexId("skills", `skills-sh:${repoName}`, output),
|
|
8078
|
+
kind: "skills",
|
|
8079
|
+
source: {
|
|
8080
|
+
type: "skills-sh",
|
|
8081
|
+
name: `skills-sh:${repoName}`,
|
|
8082
|
+
displayName: repoName,
|
|
8083
|
+
repo: repoName,
|
|
8084
|
+
versionMode: "default-branch"
|
|
8085
|
+
},
|
|
8086
|
+
targetFile: output,
|
|
8087
|
+
marker: "skills",
|
|
8088
|
+
cachePath: cacheDir,
|
|
8089
|
+
command: `npx agdex skills embed --repo ${repoName}`
|
|
8090
|
+
});
|
|
7843
8091
|
const action2 = isNewFile ? "Created" : "Updated";
|
|
7844
8092
|
const sizeInfo2 = isNewFile ? formatSize(sizeAfter) : `${formatSize(sizeBefore)} → ${formatSize(sizeAfter)}`;
|
|
7845
8093
|
console.log(`${import_picocolors2.default.green("✓")} ${action2} ${import_picocolors2.default.bold(output)} (${sizeInfo2})`);
|
|
@@ -7862,6 +8110,20 @@ Discovering skills from ${import_picocolors2.default.cyan(sources.length.toStrin
|
|
|
7862
8110
|
const sizeInfo = result.isNewFile ? formatSize(result.sizeAfter) : `${formatSize(result.sizeBefore)} → ${formatSize(result.sizeAfter)}`;
|
|
7863
8111
|
console.log(`${import_picocolors2.default.green("✓")} ${action} ${import_picocolors2.default.bold(result.targetFile)} (${sizeInfo})`);
|
|
7864
8112
|
console.log(`${import_picocolors2.default.green("✓")} Indexed ${import_picocolors2.default.bold(result.skillCount.toString())} skills`);
|
|
8113
|
+
upsertIndexLockEntry(cwd, {
|
|
8114
|
+
id: createIndexId("skills", "local-skills", output),
|
|
8115
|
+
kind: "skills",
|
|
8116
|
+
source: {
|
|
8117
|
+
type: "skills-local",
|
|
8118
|
+
name: "local-skills",
|
|
8119
|
+
displayName: "Local skills",
|
|
8120
|
+
versionMode: "unknown"
|
|
8121
|
+
},
|
|
8122
|
+
targetFile: output,
|
|
8123
|
+
marker: "skills",
|
|
8124
|
+
cachePath: cwd,
|
|
8125
|
+
command: "npx agdex skills embed"
|
|
8126
|
+
});
|
|
7865
8127
|
if (result.sourceBreakdown) {
|
|
7866
8128
|
const breakdown = [];
|
|
7867
8129
|
if (result.sourceBreakdown.plugin > 0) {
|