docspack 1.1.0 → 1.3.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 +25 -1
- package/dist/build.d.ts +5 -0
- package/dist/build.d.ts.map +1 -1
- package/dist/build.js +68 -5
- package/dist/build.js.map +1 -1
- package/dist/cli-spec.d.ts +3 -0
- package/dist/cli-spec.d.ts.map +1 -0
- package/dist/cli-spec.js +667 -0
- package/dist/cli-spec.js.map +1 -0
- package/dist/cli.d.ts +146 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +80 -14
- package/dist/cli.js.map +1 -1
- package/dist/cmdspec.json +1219 -0
- package/dist/commands.d.ts +78 -0
- package/dist/commands.d.ts.map +1 -0
- package/dist/commands.js +231 -0
- package/dist/commands.js.map +1 -0
- package/dist/config.d.ts +1 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +2 -0
- package/dist/config.js.map +1 -1
- package/dist/db.d.ts +6 -1
- package/dist/db.d.ts.map +1 -1
- package/dist/db.js +7 -1
- package/dist/db.js.map +1 -1
- package/dist/discovery.d.ts +22 -3
- package/dist/discovery.d.ts.map +1 -1
- package/dist/discovery.js +91 -12
- package/dist/discovery.js.map +1 -1
- package/dist/doctor.d.ts.map +1 -1
- package/dist/doctor.js +66 -1
- package/dist/doctor.js.map +1 -1
- package/dist/help.d.ts +10 -6
- package/dist/help.d.ts.map +1 -1
- package/dist/help.js +118 -371
- package/dist/help.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/init/plan.js +4 -3
- package/dist/init/plan.js.map +1 -1
- package/dist/init/templates.d.ts.map +1 -1
- package/dist/init/templates.js +4 -2
- package/dist/init/templates.js.map +1 -1
- package/dist/preview.d.ts.map +1 -1
- package/dist/preview.js +12 -6
- package/dist/preview.js.map +1 -1
- package/dist/search.d.ts +2 -0
- package/dist/search.d.ts.map +1 -1
- package/dist/search.js +66 -22
- package/dist/search.js.map +1 -1
- package/dist/spec.d.ts +21 -1
- package/dist/spec.d.ts.map +1 -1
- package/dist/spec.js +24 -2
- package/dist/spec.js.map +1 -1
- package/dist/sync.d.ts.map +1 -1
- package/dist/sync.js +99 -1
- package/dist/sync.js.map +1 -1
- package/package.json +8 -5
- package/src/build.ts +86 -7
- package/src/cli-spec.ts +688 -0
- package/src/cli.ts +90 -17
- package/src/commands.ts +298 -0
- package/src/config.ts +4 -1
- package/src/db.ts +9 -2
- package/src/discovery.ts +113 -12
- package/src/doctor.ts +67 -0
- package/src/help.ts +138 -380
- package/src/index.ts +1 -0
- package/src/init/plan.ts +4 -3
- package/src/init/templates.ts +4 -2
- package/src/preview.ts +14 -13
- package/src/search.ts +79 -22
- package/src/spec.ts +28 -2
- package/src/sync.ts +120 -1
package/dist/sync.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { readFile } from "node:fs/promises";
|
|
2
|
+
import { relative } from "node:path";
|
|
2
3
|
import { readArtifact } from "./artifact.js";
|
|
3
|
-
import {
|
|
4
|
+
import { COMMAND_ENTITY, commandChunks } from "./commands.js";
|
|
5
|
+
import { discoverCommandLines, discoverLibraries, discoverPackages, } from "./discovery.js";
|
|
4
6
|
import { chunkId, estimateTokens, resolveChunkFile } from "./spec.js";
|
|
5
7
|
/**
|
|
6
8
|
* Indexes every documentation package this project depends on. Packages already present in the
|
|
@@ -46,8 +48,104 @@ export async function syncProject(options) {
|
|
|
46
48
|
}
|
|
47
49
|
if (options.artifacts !== false)
|
|
48
50
|
synced.push(...(await syncArtifacts(options)));
|
|
51
|
+
synced.push(...(await syncCommandLines(options, problems)));
|
|
49
52
|
return { packages: synced, problems };
|
|
50
53
|
}
|
|
54
|
+
/**
|
|
55
|
+
* Indexes the command-line interface each installed library describes in its own `package.json`
|
|
56
|
+
* (`"cmdspec"`, `packages/cmdspec/SPEC.md` §13): one chunk per command, ranked like documentation
|
|
57
|
+
* and addressed by command path, for exactly the version installed.
|
|
58
|
+
*
|
|
59
|
+
* Not tied to `--no-artifacts`. That flag skips the declarations, which are many and machine-made;
|
|
60
|
+
* a CLI's description is one document its authors wrote, and leaving it out would make `ask` report
|
|
61
|
+
* the package as installed but not indexed on every question.
|
|
62
|
+
*/
|
|
63
|
+
async function syncCommandLines(options, problems) {
|
|
64
|
+
const commandLines = await discoverCommandLines(options.cwd);
|
|
65
|
+
if (commandLines.length === 0)
|
|
66
|
+
return [];
|
|
67
|
+
const synced = [];
|
|
68
|
+
for (const cli of commandLines) {
|
|
69
|
+
if (options.force !== true && options.store.hasPackage(cli.id)) {
|
|
70
|
+
synced.push({
|
|
71
|
+
id: cli.id,
|
|
72
|
+
name: cli.name,
|
|
73
|
+
version: cli.version,
|
|
74
|
+
chunks: options.store.countChunks(cli.id),
|
|
75
|
+
tokens: 0,
|
|
76
|
+
status: "cached",
|
|
77
|
+
trusted: true,
|
|
78
|
+
kind: "cli",
|
|
79
|
+
});
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
options.onProgress?.(`reading ${cli.id}`);
|
|
83
|
+
const { chunks, symbols } = await readCommandLine(cli, problems);
|
|
84
|
+
if (chunks.length === 0)
|
|
85
|
+
continue;
|
|
86
|
+
options.store.indexPackage({ id: cli.id, name: cli.name, version: cli.version, kind: "cli" }, chunks, symbols);
|
|
87
|
+
synced.push({
|
|
88
|
+
id: cli.id,
|
|
89
|
+
name: cli.name,
|
|
90
|
+
version: cli.version,
|
|
91
|
+
chunks: chunks.length,
|
|
92
|
+
tokens: chunks.reduce((total, chunk) => total + chunk.tokens, 0),
|
|
93
|
+
status: "indexed",
|
|
94
|
+
trusted: true,
|
|
95
|
+
kind: "cli",
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
return synced;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* A library's CLI descriptions as chunks, and its command paths as names pointing at them.
|
|
102
|
+
*
|
|
103
|
+
* A description that is invalid, or that describes another version than the one installed, is
|
|
104
|
+
* reported and skipped: indexing it would answer with a command line the installed program does
|
|
105
|
+
* not accept, which is the one failure this tool exists to prevent.
|
|
106
|
+
*/
|
|
107
|
+
async function readCommandLine(cli, problems) {
|
|
108
|
+
const { readFile: readDocument } = await import("@docspack/cmdspec/read");
|
|
109
|
+
const chunks = [];
|
|
110
|
+
const symbols = new Map();
|
|
111
|
+
const taken = new Set();
|
|
112
|
+
for (const path of cli.documents) {
|
|
113
|
+
const where = relative(cli.dir, path);
|
|
114
|
+
let document;
|
|
115
|
+
try {
|
|
116
|
+
({ document } = await readDocument(path));
|
|
117
|
+
}
|
|
118
|
+
catch (error) {
|
|
119
|
+
problems.push(`${cli.name}: ${where} ${error instanceof Error ? error.message : String(error)}`);
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
if (document.info.version !== cli.version) {
|
|
123
|
+
problems.push(`${cli.name}: ${where} describes version ${document.info.version}, but ${cli.version} is installed — not indexed`);
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
for (const chunk of commandChunks(document)) {
|
|
127
|
+
// Two executables in one package each have an overview called `cli`.
|
|
128
|
+
let id = chunk.id;
|
|
129
|
+
for (let suffix = 2; taken.has(id); suffix += 1)
|
|
130
|
+
id = `${chunk.id}-${suffix}`;
|
|
131
|
+
taken.add(id);
|
|
132
|
+
const content = `# ${chunk.title}\n\n${chunk.text}`;
|
|
133
|
+
const full = chunkId(cli.id, id);
|
|
134
|
+
chunks.push({
|
|
135
|
+
chunkId: full,
|
|
136
|
+
filePath: chunk.path === undefined ? where : `${where}#${chunk.path}`,
|
|
137
|
+
tokens: estimateTokens(content),
|
|
138
|
+
content,
|
|
139
|
+
tags: [...chunk.tags, ...chunk.entities],
|
|
140
|
+
});
|
|
141
|
+
for (const entity of chunk.entities) {
|
|
142
|
+
if (entity.startsWith(COMMAND_ENTITY))
|
|
143
|
+
symbols.set(entity, full);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
return { chunks, symbols };
|
|
148
|
+
}
|
|
51
149
|
/**
|
|
52
150
|
* Indexes each installed library's exported declarations.
|
|
53
151
|
*
|
package/dist/sync.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sync.js","sourceRoot":"","sources":["../src/sync.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"sync.js","sourceRoot":"","sources":["../src/sync.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "docspack",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "Local, version-locked documentation packages for AI agents, indexed in SQLite and served over MCP.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai",
|
|
@@ -26,13 +26,15 @@
|
|
|
26
26
|
"bin": {
|
|
27
27
|
"docspack": "./bin/docspack.js"
|
|
28
28
|
},
|
|
29
|
+
"cmdspec": "./dist/cmdspec.json",
|
|
29
30
|
"main": "./dist/index.js",
|
|
30
31
|
"types": "./dist/index.d.ts",
|
|
31
32
|
"exports": {
|
|
32
33
|
".": {
|
|
33
34
|
"types": "./dist/index.d.ts",
|
|
34
35
|
"default": "./dist/index.js"
|
|
35
|
-
}
|
|
36
|
+
},
|
|
37
|
+
"./cmdspec.json": "./dist/cmdspec.json"
|
|
36
38
|
},
|
|
37
39
|
"files": [
|
|
38
40
|
"bin",
|
|
@@ -45,8 +47,9 @@
|
|
|
45
47
|
"node": ">=22.5.0"
|
|
46
48
|
},
|
|
47
49
|
"dependencies": {
|
|
48
|
-
"@docspack/
|
|
49
|
-
"@docspack/
|
|
50
|
+
"@docspack/cmdspec": "^0.1.0",
|
|
51
|
+
"@docspack/lapis": "^0.3.0",
|
|
52
|
+
"@docspack/openapi": "^0.2.1",
|
|
50
53
|
"@docspack/registry": "^0.1.1",
|
|
51
54
|
"@modelcontextprotocol/sdk": "1.30.0",
|
|
52
55
|
"turndown": "7.2.4",
|
|
@@ -60,7 +63,7 @@
|
|
|
60
63
|
"vitest": "4.1.10"
|
|
61
64
|
},
|
|
62
65
|
"scripts": {
|
|
63
|
-
"build": "tsc -p tsconfig.json",
|
|
66
|
+
"build": "tsc -p tsconfig.json && node bin/docspack.js --cmdspec > dist/cmdspec.json",
|
|
64
67
|
"check-types": "tsc -p tsconfig.json --noEmit && tsc -p tsconfig.test.json",
|
|
65
68
|
"test": "vitest run"
|
|
66
69
|
}
|
package/src/build.ts
CHANGED
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
operationTitle,
|
|
13
13
|
} from "@docspack/openapi";
|
|
14
14
|
import { findEntry } from "@docspack/registry";
|
|
15
|
+
import { commandChunks, commandFindings } from "./commands.js";
|
|
15
16
|
import { readBuildConfig } from "./config.js";
|
|
16
17
|
import { cleanDocument } from "./document.js";
|
|
17
18
|
import { DocspackError } from "./errors.js";
|
|
@@ -41,6 +42,11 @@ export interface BuildOptions {
|
|
|
41
42
|
readonly from?: string;
|
|
42
43
|
/** OpenAPI document (JSON) to package, one chunk per operation. */
|
|
43
44
|
readonly openapi?: string;
|
|
45
|
+
/**
|
|
46
|
+
* A command-line interface's description — cmdspec, or OpenCLI or Usage, converted — to package,
|
|
47
|
+
* one chunk per command.
|
|
48
|
+
*/
|
|
49
|
+
readonly cmdspec?: string;
|
|
44
50
|
/** Registry id or llms.txt URL to fetch and package. */
|
|
45
51
|
readonly source?: string;
|
|
46
52
|
/**
|
|
@@ -188,7 +194,10 @@ export async function buildPackage(input: BuildOptions): Promise<BuildResult> {
|
|
|
188
194
|
async function withConfig(options: BuildOptions): Promise<BuildOptions> {
|
|
189
195
|
const config = await readBuildConfig(options.out);
|
|
190
196
|
const hasInput =
|
|
191
|
-
options.from !== undefined ||
|
|
197
|
+
options.from !== undefined ||
|
|
198
|
+
options.openapi !== undefined ||
|
|
199
|
+
options.cmdspec !== undefined ||
|
|
200
|
+
options.source !== undefined;
|
|
192
201
|
|
|
193
202
|
return {
|
|
194
203
|
...options,
|
|
@@ -199,6 +208,7 @@ async function withConfig(options: BuildOptions): Promise<BuildOptions> {
|
|
|
199
208
|
// thinks about them; flags stay relative to the working directory.
|
|
200
209
|
...(config.from === undefined ? {} : { from: join(options.out, config.from) }),
|
|
201
210
|
...(config.openapi === undefined ? {} : { openapi: join(options.out, config.openapi) }),
|
|
211
|
+
...(config.cmdspec === undefined ? {} : { cmdspec: join(options.out, config.cmdspec) }),
|
|
202
212
|
...(config.source === undefined ? {} : { source: config.source }),
|
|
203
213
|
}),
|
|
204
214
|
...(options.maxChunkTokens === undefined && config.maxChunkTokens !== undefined
|
|
@@ -366,20 +376,34 @@ async function readStdin(): Promise<string> {
|
|
|
366
376
|
*/
|
|
367
377
|
async function collect(options: BuildOptions, warnings: string[]): Promise<SourceDocument[]> {
|
|
368
378
|
if (options.source !== undefined) {
|
|
369
|
-
if (
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
379
|
+
if (
|
|
380
|
+
options.from !== undefined ||
|
|
381
|
+
options.openapi !== undefined ||
|
|
382
|
+
options.cmdspec !== undefined ||
|
|
383
|
+
options.json !== undefined
|
|
384
|
+
) {
|
|
385
|
+
throw new DocspackError(
|
|
386
|
+
"A source cannot be combined with --from, --openapi, --cmdspec or --from-json",
|
|
387
|
+
{
|
|
388
|
+
hint: "A mirror is a whole documentation set on its own.",
|
|
389
|
+
},
|
|
390
|
+
);
|
|
373
391
|
}
|
|
374
392
|
return collectFromSource(options, warnings);
|
|
375
393
|
}
|
|
376
394
|
|
|
377
395
|
const documents: SourceDocument[] = [];
|
|
378
396
|
if (options.openapi !== undefined) documents.push(...(await collectFromOpenApi(options.openapi)));
|
|
397
|
+
if (options.cmdspec !== undefined) {
|
|
398
|
+
documents.push(...(await collectFromCmdspec(options.cmdspec, warnings)));
|
|
399
|
+
}
|
|
379
400
|
if (options.json !== undefined) documents.push(...(await collectFromJson(options.json)));
|
|
380
401
|
// The default `docs/` directory is only read when nothing else was named: a build given only an
|
|
381
|
-
//
|
|
382
|
-
|
|
402
|
+
// API or CLI description, or a set of records, should not fail on a `docs/` directory that does
|
|
403
|
+
// not exist.
|
|
404
|
+
const named =
|
|
405
|
+
options.openapi !== undefined || options.cmdspec !== undefined || options.json !== undefined;
|
|
406
|
+
if (options.from !== undefined || !named) {
|
|
383
407
|
documents.push(...(await collectFromDirectory(options.from ?? join(options.out, "docs"))));
|
|
384
408
|
}
|
|
385
409
|
return documents;
|
|
@@ -540,6 +564,61 @@ async function collectFromOpenApi(file: string): Promise<SourceDocument[]> {
|
|
|
540
564
|
return documents;
|
|
541
565
|
}
|
|
542
566
|
|
|
567
|
+
/**
|
|
568
|
+
* One chunk per command, plus an overview listing them.
|
|
569
|
+
*
|
|
570
|
+
* Each command's chunk is `@docspack/cmdspec`'s digest — what a help page says, plus what it
|
|
571
|
+
* leaves out: types and defaults, where a value comes from, what the command changes, what it
|
|
572
|
+
* prints and what its exit status means — with the command's own prose before it, where the ranker
|
|
573
|
+
* reads it. The path is recorded as an entity, `$ git remote add`, so a question naming the command
|
|
574
|
+
* pins the chunk (`commands.ts`).
|
|
575
|
+
*
|
|
576
|
+
* The description must be valid. A package built from an invalid one would answer with a command
|
|
577
|
+
* line its program rejects, so the build stops and lists every problem instead.
|
|
578
|
+
*/
|
|
579
|
+
async function collectFromCmdspec(file: string, warnings: string[]): Promise<SourceDocument[]> {
|
|
580
|
+
const { convertText, readSource } = await import("@docspack/cmdspec/read");
|
|
581
|
+
const { validate } = await import("@docspack/cmdspec/validate");
|
|
582
|
+
const { CmdspecError } = await import("@docspack/cmdspec");
|
|
583
|
+
let document: Awaited<ReturnType<typeof convertText>>["document"];
|
|
584
|
+
try {
|
|
585
|
+
({ document } = await convertText(await readSource(file), { where: file }));
|
|
586
|
+
} catch (error) {
|
|
587
|
+
if (error instanceof CmdspecError) {
|
|
588
|
+
throw new DocspackError(error.message, {
|
|
589
|
+
...(error.hint === undefined ? {} : { hint: error.hint }),
|
|
590
|
+
cause: error,
|
|
591
|
+
});
|
|
592
|
+
}
|
|
593
|
+
throw error;
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
const result = validate(document);
|
|
597
|
+
if (!result.valid) {
|
|
598
|
+
throw new DocspackError(
|
|
599
|
+
`${file} is not a valid CLI description (${result.problems.length} problem${result.problems.length === 1 ? "" : "s"})`,
|
|
600
|
+
{
|
|
601
|
+
hint: [
|
|
602
|
+
...result.problems.slice(0, 12).map((problem) => `${problem.at}: ${problem.message}`),
|
|
603
|
+
...(result.problems.length > 12 ? [`…and ${result.problems.length - 12} more`] : []),
|
|
604
|
+
"Run `npx @docspack/cmdspec validate` on it for the full list.",
|
|
605
|
+
].join("\n"),
|
|
606
|
+
},
|
|
607
|
+
);
|
|
608
|
+
}
|
|
609
|
+
warnings.push(...commandFindings(document).map((finding) => `${file}: ${finding.message}`));
|
|
610
|
+
|
|
611
|
+
return commandChunks(document).map((chunk) => ({
|
|
612
|
+
id: chunk.id,
|
|
613
|
+
title: chunk.title,
|
|
614
|
+
origin: chunk.path === undefined ? file : `${file}#${chunk.path}`,
|
|
615
|
+
text: chunk.text,
|
|
616
|
+
atomic: true,
|
|
617
|
+
tags: chunk.tags,
|
|
618
|
+
entities: chunk.entities,
|
|
619
|
+
}));
|
|
620
|
+
}
|
|
621
|
+
|
|
543
622
|
/** The reader's failures, re-reported as the CLI's own error so the hint survives. */
|
|
544
623
|
async function readOpenApi(file: string): Promise<ApiDocument> {
|
|
545
624
|
try {
|