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.
Files changed (77) hide show
  1. package/README.md +25 -1
  2. package/dist/build.d.ts +5 -0
  3. package/dist/build.d.ts.map +1 -1
  4. package/dist/build.js +68 -5
  5. package/dist/build.js.map +1 -1
  6. package/dist/cli-spec.d.ts +3 -0
  7. package/dist/cli-spec.d.ts.map +1 -0
  8. package/dist/cli-spec.js +667 -0
  9. package/dist/cli-spec.js.map +1 -0
  10. package/dist/cli.d.ts +146 -1
  11. package/dist/cli.d.ts.map +1 -1
  12. package/dist/cli.js +80 -14
  13. package/dist/cli.js.map +1 -1
  14. package/dist/cmdspec.json +1219 -0
  15. package/dist/commands.d.ts +78 -0
  16. package/dist/commands.d.ts.map +1 -0
  17. package/dist/commands.js +231 -0
  18. package/dist/commands.js.map +1 -0
  19. package/dist/config.d.ts +1 -0
  20. package/dist/config.d.ts.map +1 -1
  21. package/dist/config.js +2 -0
  22. package/dist/config.js.map +1 -1
  23. package/dist/db.d.ts +6 -1
  24. package/dist/db.d.ts.map +1 -1
  25. package/dist/db.js +7 -1
  26. package/dist/db.js.map +1 -1
  27. package/dist/discovery.d.ts +22 -3
  28. package/dist/discovery.d.ts.map +1 -1
  29. package/dist/discovery.js +91 -12
  30. package/dist/discovery.js.map +1 -1
  31. package/dist/doctor.d.ts.map +1 -1
  32. package/dist/doctor.js +66 -1
  33. package/dist/doctor.js.map +1 -1
  34. package/dist/help.d.ts +10 -6
  35. package/dist/help.d.ts.map +1 -1
  36. package/dist/help.js +118 -371
  37. package/dist/help.js.map +1 -1
  38. package/dist/index.d.ts +1 -1
  39. package/dist/index.d.ts.map +1 -1
  40. package/dist/index.js +1 -1
  41. package/dist/index.js.map +1 -1
  42. package/dist/init/plan.js +4 -3
  43. package/dist/init/plan.js.map +1 -1
  44. package/dist/init/templates.d.ts.map +1 -1
  45. package/dist/init/templates.js +4 -2
  46. package/dist/init/templates.js.map +1 -1
  47. package/dist/preview.d.ts.map +1 -1
  48. package/dist/preview.js +12 -6
  49. package/dist/preview.js.map +1 -1
  50. package/dist/search.d.ts +2 -0
  51. package/dist/search.d.ts.map +1 -1
  52. package/dist/search.js +66 -22
  53. package/dist/search.js.map +1 -1
  54. package/dist/spec.d.ts +21 -1
  55. package/dist/spec.d.ts.map +1 -1
  56. package/dist/spec.js +24 -2
  57. package/dist/spec.js.map +1 -1
  58. package/dist/sync.d.ts.map +1 -1
  59. package/dist/sync.js +99 -1
  60. package/dist/sync.js.map +1 -1
  61. package/package.json +8 -5
  62. package/src/build.ts +86 -7
  63. package/src/cli-spec.ts +688 -0
  64. package/src/cli.ts +90 -17
  65. package/src/commands.ts +298 -0
  66. package/src/config.ts +4 -1
  67. package/src/db.ts +9 -2
  68. package/src/discovery.ts +113 -12
  69. package/src/doctor.ts +67 -0
  70. package/src/help.ts +138 -380
  71. package/src/index.ts +1 -0
  72. package/src/init/plan.ts +4 -3
  73. package/src/init/templates.ts +4 -2
  74. package/src/preview.ts +14 -13
  75. package/src/search.ts +79 -22
  76. package/src/spec.ts +28 -2
  77. 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 { discoverLibraries, discoverPackages } from "./discovery.js";
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;AAE7C,OAAO,EAA0B,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAC7F,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAkCtE;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,OAAoB;IACpD,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,iBAAiB,EAAE,GAAG,MAAM,gBAAgB,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IACtF,MAAM,QAAQ,GAAG,CAAC,GAAG,iBAAiB,CAAC,CAAC;IACxC,MAAM,MAAM,GAAoB,EAAE,CAAC;IAEnC,KAAK,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;QAC3B,IAAI,OAAO,CAAC,KAAK,KAAK,IAAI,IAAI,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC;YAC/D,MAAM,CAAC,IAAI,CAAC;gBACV,EAAE,EAAE,GAAG,CAAC,EAAE;gBACV,IAAI,EAAE,GAAG,CAAC,IAAI;gBACd,OAAO,EAAE,GAAG,CAAC,OAAO;gBACpB,MAAM,EAAE,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC;gBACzC,MAAM,EAAE,CAAC;gBACT,MAAM,EAAE,QAAQ;gBAChB,OAAO,EAAE,GAAG,CAAC,OAAO;gBACpB,IAAI,EAAE,MAAM;aACb,CAAC,CAAC;YACH,SAAS;QACX,CAAC;QAED,OAAO,CAAC,UAAU,EAAE,CAAC,YAAY,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC;QAC3C,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,aAAa,EAAE,GAAG,MAAM,UAAU,CAAC,GAAG,CAAC,CAAC;QAClE,QAAQ,CAAC,IAAI,CAAC,GAAG,aAAa,CAAC,CAAC;QAEhC,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACxB,QAAQ,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC,IAAI,uCAAuC,CAAC,CAAC;YAClE,SAAS;QACX,CAAC;QAED,OAAO,CAAC,KAAK,CAAC,YAAY,CAAC,EAAE,EAAE,EAAE,GAAG,CAAC,EAAE,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE,EAAE,MAAM,CAAC,CAAC;QACzF,MAAM,CAAC,IAAI,CAAC;YACV,EAAE,EAAE,GAAG,CAAC,EAAE;YACV,IAAI,EAAE,GAAG,CAAC,IAAI;YACd,OAAO,EAAE,GAAG,CAAC,OAAO;YACpB,MAAM,EAAE,MAAM,CAAC,MAAM;YACrB,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,KAAK,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;YAChE,MAAM,EAAE,SAAS;YACjB,OAAO,EAAE,GAAG,CAAC,OAAO;YACpB,IAAI,EAAE,MAAM;SACb,CAAC,CAAC;IACL,CAAC;IAED,IAAI,OAAO,CAAC,SAAS,KAAK,KAAK;QAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;IAEhF,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;AACxC,CAAC;AAED;;;;;;GAMG;AACH,KAAK,UAAU,aAAa,CAAC,OAAoB;IAC/C,MAAM,MAAM,GAAoB,EAAE,CAAC;IAEnC,KAAK,MAAM,OAAO,IAAI,MAAM,iBAAiB,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QAC3D,MAAM,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;QAChD,IAAI,OAAO,CAAC,KAAK,KAAK,IAAI,IAAI,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,EAAE,CAAC,EAAE,CAAC;YAC3D,MAAM,CAAC,IAAI,CAAC;gBACV,EAAE;gBACF,IAAI,EAAE,OAAO,CAAC,IAAI;gBAClB,OAAO,EAAE,OAAO,CAAC,OAAO;gBACxB,MAAM,EAAE,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,EAAE,CAAC;gBACrC,MAAM,EAAE,CAAC;gBACT,MAAM,EAAE,QAAQ;gBAChB,OAAO,EAAE,IAAI;gBACb,IAAI,EAAE,UAAU;aACjB,CAAC,CAAC;YACH,SAAS;QACX,CAAC;QAED,OAAO,CAAC,UAAU,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;QACtC,MAAM,QAAQ,GAAG,MAAM,YAAY,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACjD,wFAAwF;QACxF,uDAAuD;QACvD,IAAI,QAAQ,KAAK,SAAS;YAAE,SAAS;QAErC,OAAO,CAAC,KAAK,CAAC,YAAY,CACxB,EAAE,EAAE,EAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,EAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,EAAE,QAAQ,CAAC,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,EACrF,QAAQ,CAAC,MAAM,EACf,QAAQ,CAAC,OAAO,CACjB,CAAC;QACF,MAAM,CAAC,IAAI,CAAC;YACV,EAAE,EAAE,QAAQ,CAAC,EAAE;YACf,IAAI,EAAE,QAAQ,CAAC,IAAI;YACnB,OAAO,EAAE,QAAQ,CAAC,OAAO;YACzB,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM;YAC9B,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,KAAK,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;YACzE,MAAM,EAAE,SAAS;YACjB,OAAO,EAAE,IAAI;YACb,IAAI,EAAE,UAAU;SACjB,CAAC,CAAC;IACL,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,KAAK,UAAU,UAAU,CACvB,GAAsB;IAEtB,MAAM,MAAM,GAAmB,EAAE,CAAC;IAClC,MAAM,QAAQ,GAAa,EAAE,CAAC;IAE9B,KAAK,MAAM,KAAK,IAAI,GAAG,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC;QACxC,IAAI,OAAe,CAAC;QACpB,IAAI,CAAC;YACH,OAAO,GAAG,MAAM,QAAQ,CAAC,gBAAgB,CAAC,GAAG,CAAC,OAAO,EAAE,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,CAAC;QAC9E,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,QAAQ,CAAC,IAAI,CACX,GAAG,GAAG,CAAC,IAAI,WAAW,KAAK,CAAC,EAAE,MAAM,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAC7F,CAAC;YACF,SAAS;QACX,CAAC;QAED,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;QAC5B,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACtB,QAAQ,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC,IAAI,WAAW,KAAK,CAAC,EAAE,YAAY,CAAC,CAAC;YAC1D,SAAS;QACX,CAAC;QAED,MAAM,CAAC,IAAI,CAAC;YACV,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,EAAE,EAAE,KAAK,CAAC,EAAE,CAAC;YAClC,QAAQ,EAAE,KAAK,CAAC,IAAI;YACpB,MAAM,EAAE,KAAK,CAAC,MAAM,IAAI,cAAc,CAAC,IAAI,CAAC;YAC5C,OAAO,EAAE,IAAI;YACb,IAAI,EAAE,CAAC,GAAG,KAAK,CAAC,IAAI,EAAE,GAAG,KAAK,CAAC,QAAQ,CAAC;SACzC,CAAC,CAAC;IACL,CAAC;IAED,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;AAC9B,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.1.0",
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/lapis": "^0.2.0",
49
- "@docspack/openapi": "^0.2.0",
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 || options.openapi !== undefined || options.source !== 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 (options.from !== undefined || options.openapi !== undefined || options.json !== undefined) {
370
- throw new DocspackError("A source cannot be combined with --from, --openapi or --from-json", {
371
- hint: "A mirror is a whole documentation set on its own.",
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
- // OpenAPI document or a set of records should not fail on a `docs/` directory that does not exist.
382
- if (options.from !== undefined || (options.openapi === undefined && options.json === undefined)) {
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 {