docspack 0.0.1 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (155) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +59 -0
  3. package/bin/docspack.js +25 -0
  4. package/dist/build.d.ts +31 -0
  5. package/dist/build.d.ts.map +1 -0
  6. package/dist/build.js +435 -0
  7. package/dist/build.js.map +1 -0
  8. package/dist/cli.d.ts +3 -0
  9. package/dist/cli.d.ts.map +1 -0
  10. package/dist/cli.js +763 -0
  11. package/dist/cli.js.map +1 -0
  12. package/dist/config.d.ts +41 -0
  13. package/dist/config.d.ts.map +1 -0
  14. package/dist/config.js +118 -0
  15. package/dist/config.js.map +1 -0
  16. package/dist/db.d.ts +60 -0
  17. package/dist/db.d.ts.map +1 -0
  18. package/dist/db.js +204 -0
  19. package/dist/db.js.map +1 -0
  20. package/dist/discovery.d.ts +31 -0
  21. package/dist/discovery.d.ts.map +1 -0
  22. package/dist/discovery.js +126 -0
  23. package/dist/discovery.js.map +1 -0
  24. package/dist/doctor.d.ts +25 -0
  25. package/dist/doctor.d.ts.map +1 -0
  26. package/dist/doctor.js +276 -0
  27. package/dist/doctor.js.map +1 -0
  28. package/dist/document.d.ts +13 -0
  29. package/dist/document.d.ts.map +1 -0
  30. package/dist/document.js +47 -0
  31. package/dist/document.js.map +1 -0
  32. package/dist/errors.d.ts +9 -0
  33. package/dist/errors.d.ts.map +1 -0
  34. package/dist/errors.js +10 -0
  35. package/dist/errors.js.map +1 -0
  36. package/dist/exports.d.ts +20 -0
  37. package/dist/exports.d.ts.map +1 -0
  38. package/dist/exports.js +100 -0
  39. package/dist/exports.js.map +1 -0
  40. package/dist/feedback.d.ts +68 -0
  41. package/dist/feedback.d.ts.map +1 -0
  42. package/dist/feedback.js +0 -0
  43. package/dist/feedback.js.map +1 -0
  44. package/dist/html.d.ts +4 -0
  45. package/dist/html.d.ts.map +1 -0
  46. package/dist/html.js +23 -0
  47. package/dist/html.js.map +1 -0
  48. package/dist/http.d.ts +30 -0
  49. package/dist/http.d.ts.map +1 -0
  50. package/dist/http.js +144 -0
  51. package/dist/http.js.map +1 -0
  52. package/dist/index.d.ts +25 -0
  53. package/dist/index.d.ts.map +1 -0
  54. package/dist/index.js +25 -0
  55. package/dist/index.js.map +1 -0
  56. package/dist/init/detect.d.ts +16 -0
  57. package/dist/init/detect.d.ts.map +1 -0
  58. package/dist/init/detect.js +120 -0
  59. package/dist/init/detect.js.map +1 -0
  60. package/dist/init/plan.d.ts +43 -0
  61. package/dist/init/plan.d.ts.map +1 -0
  62. package/dist/init/plan.js +145 -0
  63. package/dist/init/plan.js.map +1 -0
  64. package/dist/init/run.d.ts +28 -0
  65. package/dist/init/run.d.ts.map +1 -0
  66. package/dist/init/run.js +96 -0
  67. package/dist/init/run.js.map +1 -0
  68. package/dist/init/templates.d.ts +24 -0
  69. package/dist/init/templates.d.ts.map +1 -0
  70. package/dist/init/templates.js +181 -0
  71. package/dist/init/templates.js.map +1 -0
  72. package/dist/init/write.d.ts +20 -0
  73. package/dist/init/write.d.ts.map +1 -0
  74. package/dist/init/write.js +56 -0
  75. package/dist/init/write.js.map +1 -0
  76. package/dist/kinds.d.ts +14 -0
  77. package/dist/kinds.d.ts.map +1 -0
  78. package/dist/kinds.js +15 -0
  79. package/dist/kinds.js.map +1 -0
  80. package/dist/llms-txt.d.ts +25 -0
  81. package/dist/llms-txt.d.ts.map +1 -0
  82. package/dist/llms-txt.js +94 -0
  83. package/dist/llms-txt.js.map +1 -0
  84. package/dist/mcp.d.ts +15 -0
  85. package/dist/mcp.d.ts.map +1 -0
  86. package/dist/mcp.js +158 -0
  87. package/dist/mcp.js.map +1 -0
  88. package/dist/preview.d.ts +18 -0
  89. package/dist/preview.d.ts.map +1 -0
  90. package/dist/preview.js +72 -0
  91. package/dist/preview.js.map +1 -0
  92. package/dist/prompt.d.ts +27 -0
  93. package/dist/prompt.d.ts.map +1 -0
  94. package/dist/prompt.js +79 -0
  95. package/dist/prompt.js.map +1 -0
  96. package/dist/search.d.ts +41 -0
  97. package/dist/search.d.ts.map +1 -0
  98. package/dist/search.js +60 -0
  99. package/dist/search.js.map +1 -0
  100. package/dist/snippet.d.ts +20 -0
  101. package/dist/snippet.d.ts.map +1 -0
  102. package/dist/snippet.js +29 -0
  103. package/dist/snippet.js.map +1 -0
  104. package/dist/spec.d.ts +38 -0
  105. package/dist/spec.d.ts.map +1 -0
  106. package/dist/spec.js +105 -0
  107. package/dist/spec.js.map +1 -0
  108. package/dist/style.d.ts +33 -0
  109. package/dist/style.d.ts.map +1 -0
  110. package/dist/style.js +94 -0
  111. package/dist/style.js.map +1 -0
  112. package/dist/submit.d.ts +61 -0
  113. package/dist/submit.d.ts.map +1 -0
  114. package/dist/submit.js +111 -0
  115. package/dist/submit.js.map +1 -0
  116. package/dist/sync.d.ts +29 -0
  117. package/dist/sync.d.ts.map +1 -0
  118. package/dist/sync.js +73 -0
  119. package/dist/sync.js.map +1 -0
  120. package/dist/verify.d.ts +44 -0
  121. package/dist/verify.d.ts.map +1 -0
  122. package/dist/verify.js +291 -0
  123. package/dist/verify.js.map +1 -0
  124. package/package.json +60 -5
  125. package/src/build.ts +572 -0
  126. package/src/cli.ts +883 -0
  127. package/src/config.ts +158 -0
  128. package/src/db.ts +261 -0
  129. package/src/discovery.ts +161 -0
  130. package/src/doctor.ts +344 -0
  131. package/src/document.ts +59 -0
  132. package/src/errors.ts +10 -0
  133. package/src/exports.ts +120 -0
  134. package/src/feedback.ts +0 -0
  135. package/src/html.ts +24 -0
  136. package/src/http.ts +190 -0
  137. package/src/index.ts +132 -0
  138. package/src/init/detect.ts +142 -0
  139. package/src/init/plan.ts +215 -0
  140. package/src/init/run.ts +142 -0
  141. package/src/init/templates.ts +200 -0
  142. package/src/init/write.ts +83 -0
  143. package/src/kinds.ts +17 -0
  144. package/src/llms-txt.ts +116 -0
  145. package/src/mcp.ts +196 -0
  146. package/src/preview.ts +98 -0
  147. package/src/prompt.ts +103 -0
  148. package/src/search.ts +96 -0
  149. package/src/snippet.ts +30 -0
  150. package/src/spec.ts +138 -0
  151. package/src/style.ts +111 -0
  152. package/src/submit.ts +189 -0
  153. package/src/sync.ts +112 -0
  154. package/src/verify.ts +355 -0
  155. package/bin/cli.js +0 -2
@@ -0,0 +1,126 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import { dirname, join, resolve } from "node:path";
3
+ import { DocspackError } from "./errors.js";
4
+ import { isCommunityPackage, isDocsPackage, LLMS_DIR, MANIFEST_FILE, packageId, parseManifest, } from "./spec.js";
5
+ /**
6
+ * Finds the documentation packages a project depends on: every `@vendor/docspack` or
7
+ * `@docspack-community/*` entry in `dependencies` or `devDependencies` that is installed and
8
+ * ships a `.llms/manifest.json`.
9
+ */
10
+ export async function discoverPackages(cwd) {
11
+ const root = resolve(cwd);
12
+ const declared = await declaredDocsPackages(root);
13
+ const packages = [];
14
+ const problems = [];
15
+ for (const name of declared) {
16
+ const dir = await resolvePackageDir(name, root);
17
+ if (dir === undefined) {
18
+ problems.push(`${name} is declared in package.json but is not installed`);
19
+ continue;
20
+ }
21
+ let version;
22
+ try {
23
+ version = await installedVersion(name, dir);
24
+ }
25
+ catch (error) {
26
+ problems.push(describe(error));
27
+ continue;
28
+ }
29
+ const llmsDir = join(dir, LLMS_DIR);
30
+ let manifest;
31
+ try {
32
+ const raw = await readFile(join(llmsDir, MANIFEST_FILE), "utf8");
33
+ manifest = parseManifest(JSON.parse(raw), `${name} ${LLMS_DIR}/${MANIFEST_FILE}`);
34
+ }
35
+ catch (error) {
36
+ problems.push(error.code === "ENOENT"
37
+ ? `${name} has no ${LLMS_DIR}/${MANIFEST_FILE} and cannot be indexed`
38
+ : describe(error));
39
+ continue;
40
+ }
41
+ if (manifest.version !== version) {
42
+ problems.push(`${name}: manifest says version ${manifest.version}, package.json says ${version}; using ${version}`);
43
+ }
44
+ packages.push({
45
+ id: packageId(name, version),
46
+ name,
47
+ version,
48
+ dir,
49
+ llmsDir,
50
+ manifest,
51
+ trusted: !isCommunityPackage(name),
52
+ });
53
+ }
54
+ packages.sort((a, b) => a.name.localeCompare(b.name));
55
+ return { packages, problems };
56
+ }
57
+ /** Package ids installed in this project, used to scope queries to the versions actually in use. */
58
+ export async function projectPackageIds(cwd) {
59
+ const { packages } = await discoverPackages(cwd);
60
+ return packages.map((pkg) => pkg.id);
61
+ }
62
+ async function declaredDocsPackages(cwd) {
63
+ let raw;
64
+ try {
65
+ raw = await readFile(join(cwd, "package.json"), "utf8");
66
+ }
67
+ catch (error) {
68
+ if (error.code === "ENOENT") {
69
+ throw new DocspackError(`No package.json found in ${cwd}`, {
70
+ hint: "Run docspack from a project directory, or pass --cwd <dir>.",
71
+ });
72
+ }
73
+ throw error;
74
+ }
75
+ let parsed;
76
+ try {
77
+ parsed = JSON.parse(raw);
78
+ }
79
+ catch (error) {
80
+ throw new DocspackError(`${join(cwd, "package.json")} is not valid JSON`, { cause: error });
81
+ }
82
+ const root = parsed;
83
+ const names = new Set();
84
+ for (const field of [root.dependencies, root.devDependencies]) {
85
+ if (typeof field !== "object" || field === null)
86
+ continue;
87
+ for (const name of Object.keys(field)) {
88
+ if (isDocsPackage(name))
89
+ names.add(name);
90
+ }
91
+ }
92
+ return [...names].sort();
93
+ }
94
+ /**
95
+ * Walks `node_modules` upwards from the project, which resolves npm, pnpm (through its symlinks)
96
+ * and workspace layouts without depending on a package's export map.
97
+ */
98
+ export async function resolvePackageDir(name, cwd) {
99
+ let dir = cwd;
100
+ while (true) {
101
+ const candidate = join(dir, "node_modules", ...name.split("/"));
102
+ try {
103
+ await readFile(join(candidate, "package.json"), "utf8");
104
+ return candidate;
105
+ }
106
+ catch {
107
+ // Not here; keep walking up.
108
+ }
109
+ const parent = dirname(dir);
110
+ if (parent === dir)
111
+ return undefined;
112
+ dir = parent;
113
+ }
114
+ }
115
+ async function installedVersion(name, dir) {
116
+ const parsed = JSON.parse(await readFile(join(dir, "package.json"), "utf8"));
117
+ const version = parsed.version;
118
+ if (typeof version !== "string" || version.length === 0) {
119
+ throw new DocspackError(`${name} has no version in its package.json`);
120
+ }
121
+ return version;
122
+ }
123
+ function describe(error) {
124
+ return error instanceof Error ? error.message : String(error);
125
+ }
126
+ //# sourceMappingURL=discovery.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discovery.js","sourceRoot":"","sources":["../src/discovery.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ export type Severity = "error" | "warn" | "info";
2
+ export interface Finding {
3
+ readonly check: string;
4
+ readonly severity: Severity;
5
+ readonly message: string;
6
+ readonly where?: string;
7
+ readonly fix?: string;
8
+ }
9
+ export interface DoctorReport {
10
+ readonly ok: boolean;
11
+ readonly findings: readonly Finding[];
12
+ readonly chunks: number;
13
+ readonly tokens: number;
14
+ }
15
+ export interface DoctorOptions {
16
+ readonly dir: string;
17
+ /** Treat warnings as failures. Used by prepublishOnly and CI. */
18
+ readonly strict?: boolean;
19
+ }
20
+ /**
21
+ * Checks a documentation package the way the indexer and a reviewer would. A broken docs package
22
+ * still installs and still indexes, so every problem here is one that would otherwise be silent.
23
+ */
24
+ export declare function runDoctor(options: DoctorOptions): Promise<DoctorReport>;
25
+ //# sourceMappingURL=doctor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../src/doctor.ts"],"names":[],"mappings":"AAqBA,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,CAAC;AAEjD,MAAM,WAAW,OAAO;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAC5B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAC;IACrB,QAAQ,CAAC,QAAQ,EAAE,SAAS,OAAO,EAAE,CAAC;IACtC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,iEAAiE;IACjE,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;CAC3B;AAMD;;;GAGG;AACH,wBAAsB,SAAS,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC,CAqK7E"}
package/dist/doctor.js ADDED
@@ -0,0 +1,276 @@
1
+ import { readdir, readFile, stat } from "node:fs/promises";
2
+ import { join } from "node:path";
3
+ import { readBuildConfig } from "./config.js";
4
+ import { PLACEHOLDER } from "./init/templates.js";
5
+ import { estimateTokens, LLMS_DIR, MANIFEST_FILE, parseManifest, resolveChunkFile, } from "./spec.js";
6
+ import { contentFingerprint, findFiller, findLongSentences, hasConcreteContent, withoutCode, } from "./style.js";
7
+ /** Over this, a chunk crowds out the response budget; under it, a chunk answers nothing. */
8
+ const MAX_CHUNK_TOKENS = 1500;
9
+ const MIN_CHUNK_TOKENS = 30;
10
+ /**
11
+ * Checks a documentation package the way the indexer and a reviewer would. A broken docs package
12
+ * still installs and still indexes, so every problem here is one that would otherwise be silent.
13
+ */
14
+ export async function runDoctor(options) {
15
+ const findings = [];
16
+ const llmsDir = join(options.dir, LLMS_DIR);
17
+ const pkg = await readJson(join(options.dir, "package.json"));
18
+ const manifest = await loadManifest(llmsDir, findings);
19
+ if (manifest === undefined) {
20
+ return { ok: false, findings, chunks: 0, tokens: 0 };
21
+ }
22
+ checkPackageJson(pkg, manifest, findings);
23
+ let tokens = 0;
24
+ let newestSource = 0;
25
+ const seen = new Map();
26
+ const abstract = [];
27
+ for (const chunk of manifest.chunks) {
28
+ let contents;
29
+ try {
30
+ contents = await readFile(resolveChunkFile(llmsDir, chunk.file), "utf8");
31
+ }
32
+ catch (error) {
33
+ findings.push({
34
+ check: /outside of/.test(String(error)) ? "chunk-escapes" : "chunk-missing",
35
+ severity: "error",
36
+ message: /outside of/.test(String(error))
37
+ ? `chunk "${chunk.id}" points outside ${LLMS_DIR}/`
38
+ : `chunk "${chunk.id}" is missing its file`,
39
+ where: chunk.file,
40
+ fix: "Rebuild with `docspack build`.",
41
+ });
42
+ continue;
43
+ }
44
+ const text = contents.trim();
45
+ if (text.length === 0) {
46
+ findings.push({
47
+ check: "chunk-empty",
48
+ severity: "error",
49
+ message: `chunk "${chunk.id}" is empty`,
50
+ where: chunk.file,
51
+ fix: "Write the section, or remove it from the manifest.",
52
+ });
53
+ continue;
54
+ }
55
+ const size = chunk.tokens > 0 ? chunk.tokens : estimateTokens(text);
56
+ tokens += size;
57
+ if (size > MAX_CHUNK_TOKENS) {
58
+ findings.push({
59
+ check: "chunk-too-large",
60
+ severity: "warn",
61
+ message: `chunk "${chunk.id}" is ~${size} tokens; it will crowd out a response`,
62
+ where: chunk.file,
63
+ fix: "Split the section with more headings, or lower maxChunkTokens.",
64
+ });
65
+ }
66
+ else if (size < MIN_CHUNK_TOKENS) {
67
+ findings.push({
68
+ check: "chunk-too-small",
69
+ severity: "warn",
70
+ message: `chunk "${chunk.id}" is ~${size} tokens; too small to answer anything`,
71
+ where: chunk.file,
72
+ fix: "Merge it into a neighbouring section.",
73
+ });
74
+ }
75
+ if (chunk.tags.length === 0 && chunk.entities.length === 0) {
76
+ findings.push({
77
+ check: "untagged",
78
+ severity: "warn",
79
+ message: `chunk "${chunk.id}" has no tags or entities; it is findable only by its prose`,
80
+ where: chunk.file,
81
+ fix: "Name the API in `inline code`, or add tags to the manifest.",
82
+ });
83
+ }
84
+ // Prose that mentions the marker inside `code` is documenting it, not leaving one behind.
85
+ if (withoutCode(text).includes(PLACEHOLDER)) {
86
+ findings.push({
87
+ check: "placeholder",
88
+ severity: "warn",
89
+ message: `chunk "${chunk.id}" still contains ${PLACEHOLDER} markers from the template`,
90
+ where: chunk.file,
91
+ fix: "Replace the template text with real documentation.",
92
+ });
93
+ }
94
+ const filler = findFiller(text);
95
+ if (filler.length > 0) {
96
+ const listed = filler
97
+ .slice(0, 3)
98
+ .map((hit) => `"${hit.phrase}"`)
99
+ .join(", ");
100
+ findings.push({
101
+ check: "filler",
102
+ severity: "warn",
103
+ message: `chunk "${chunk.id}" contains narration a model does not need: ${listed}`,
104
+ where: chunk.file,
105
+ fix: "Delete it. Nobody searches for these words and they carry no fact.",
106
+ });
107
+ }
108
+ const long = findLongSentences(text);
109
+ if (long.length > 0) {
110
+ findings.push({
111
+ check: "long-sentence",
112
+ severity: "warn",
113
+ message: `chunk "${chunk.id}" has ${plural(long.length, "sentence")} over 40 words`,
114
+ where: chunk.file,
115
+ fix: "Split them. One claim per sentence retrieves and reads better.",
116
+ });
117
+ }
118
+ if (!hasConcreteContent(text))
119
+ abstract.push(chunk.id);
120
+ const fingerprint = contentFingerprint(text);
121
+ const twin = seen.get(fingerprint);
122
+ if (twin === undefined)
123
+ seen.set(fingerprint, chunk.id);
124
+ else {
125
+ findings.push({
126
+ check: "duplicate-chunk",
127
+ severity: "warn",
128
+ message: `chunk "${chunk.id}" says the same thing as "${twin}"`,
129
+ where: chunk.file,
130
+ fix: "Remove one. Duplicates compete for the same query and waste the response budget.",
131
+ });
132
+ }
133
+ }
134
+ if (abstract.length > 0) {
135
+ findings.push({
136
+ check: "no-example",
137
+ severity: "info",
138
+ message: `${plural(abstract.length, "chunk")} of ${manifest.chunks.length} have no code, list or table: ${abstract.slice(0, 3).join(", ")}${abstract.length > 3 ? ", …" : ""}`,
139
+ fix: "Agents act on concrete text. Add the call, the signature or the values.",
140
+ });
141
+ }
142
+ if (manifest.chunks.every((chunk) => chunk.entities.length === 0)) {
143
+ findings.push({
144
+ check: "no-entities",
145
+ severity: "info",
146
+ message: "no chunk names an identifier; agents searching for an API name may miss this package",
147
+ fix: "Put API names in `inline code` in the source documentation.",
148
+ });
149
+ }
150
+ newestSource = await newestSourceMtime(options.dir);
151
+ const manifestMtime = await mtime(join(llmsDir, MANIFEST_FILE));
152
+ if (newestSource > 0 && manifestMtime > 0 && newestSource > manifestMtime) {
153
+ findings.push({
154
+ check: "payload-stale",
155
+ severity: "warn",
156
+ message: "the documentation source is newer than the generated payload",
157
+ fix: "Run `docspack build`.",
158
+ });
159
+ }
160
+ const failed = findings.some((finding) => finding.severity === "error" || (options.strict === true && finding.severity === "warn"));
161
+ return { ok: !failed, findings, chunks: manifest.chunks.length, tokens };
162
+ }
163
+ function plural(count, noun) {
164
+ return `${count} ${noun}${count === 1 ? "" : "s"}`;
165
+ }
166
+ async function loadManifest(llmsDir, findings) {
167
+ let raw;
168
+ try {
169
+ raw = await readFile(join(llmsDir, MANIFEST_FILE), "utf8");
170
+ }
171
+ catch {
172
+ findings.push({
173
+ check: "manifest-invalid",
174
+ severity: "error",
175
+ message: `no ${LLMS_DIR}/${MANIFEST_FILE}`,
176
+ fix: "Run `docspack build` to generate the payload.",
177
+ });
178
+ return undefined;
179
+ }
180
+ try {
181
+ return parseManifest(JSON.parse(raw), `${LLMS_DIR}/${MANIFEST_FILE}`);
182
+ }
183
+ catch (error) {
184
+ findings.push({
185
+ check: "manifest-invalid",
186
+ severity: "error",
187
+ message: error instanceof Error ? error.message : String(error),
188
+ where: `${LLMS_DIR}/${MANIFEST_FILE}`,
189
+ fix: "Run `docspack build` to regenerate it.",
190
+ });
191
+ return undefined;
192
+ }
193
+ }
194
+ function checkPackageJson(pkg, manifest, findings) {
195
+ if (pkg === undefined) {
196
+ findings.push({
197
+ check: "manifest-invalid",
198
+ severity: "error",
199
+ message: "no package.json next to the payload",
200
+ fix: "Run `docspack init` or add a package.json.",
201
+ });
202
+ return;
203
+ }
204
+ if (typeof pkg.version === "string" && pkg.version !== manifest.version) {
205
+ findings.push({
206
+ check: "version-mismatch",
207
+ severity: "error",
208
+ message: `package.json is ${pkg.version} but the manifest says ${manifest.version}`,
209
+ fix: "Run `docspack build` after bumping the version.",
210
+ });
211
+ }
212
+ if (typeof pkg.name === "string" && pkg.name !== manifest.name) {
213
+ findings.push({
214
+ check: "version-mismatch",
215
+ severity: "error",
216
+ message: `package.json is ${pkg.name} but the manifest says ${manifest.name}`,
217
+ fix: "Run `docspack build` to regenerate the manifest.",
218
+ });
219
+ }
220
+ const files = Array.isArray(pkg.files) ? pkg.files.map(String) : undefined;
221
+ if (files !== undefined &&
222
+ !files.some((entry) => entry.replace(/^\.\//, "").startsWith(LLMS_DIR))) {
223
+ findings.push({
224
+ check: "files-missing-payload",
225
+ severity: "error",
226
+ message: `"files" does not include ${LLMS_DIR}; publishing would ship a package with no documentation`,
227
+ where: "package.json",
228
+ fix: `Add "${LLMS_DIR}" to the files array.`,
229
+ });
230
+ }
231
+ }
232
+ /** Newest mtime across the configured documentation source, used to spot a stale payload. */
233
+ async function newestSourceMtime(dir) {
234
+ const config = await readBuildConfig(dir);
235
+ const source = config.from ?? config.openapi;
236
+ if (source === undefined)
237
+ return 0;
238
+ const target = join(dir, source);
239
+ const single = await mtime(target);
240
+ if (single > 0 && config.openapi !== undefined)
241
+ return single;
242
+ let found;
243
+ try {
244
+ found = await readdir(target, { recursive: true, withFileTypes: true });
245
+ }
246
+ catch {
247
+ return single;
248
+ }
249
+ let newest = 0;
250
+ for (const entry of found) {
251
+ if (!entry.isFile())
252
+ continue;
253
+ newest = Math.max(newest, await mtime(join(entry.parentPath, entry.name)));
254
+ }
255
+ return newest;
256
+ }
257
+ async function mtime(path) {
258
+ try {
259
+ return (await stat(path)).mtimeMs;
260
+ }
261
+ catch {
262
+ return 0;
263
+ }
264
+ }
265
+ async function readJson(path) {
266
+ try {
267
+ const parsed = JSON.parse(await readFile(path, "utf8"));
268
+ return typeof parsed === "object" && parsed !== null
269
+ ? parsed
270
+ : undefined;
271
+ }
272
+ catch {
273
+ return undefined;
274
+ }
275
+ }
276
+ //# sourceMappingURL=doctor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor.js","sourceRoot":"","sources":["../src/doctor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ export interface CleanedDocument {
2
+ readonly text: string;
3
+ /** Title taken from front matter, when the document declares one. */
4
+ readonly title?: string;
5
+ /** Keywords taken from front matter, indexed alongside the prose. */
6
+ readonly tags: readonly string[];
7
+ }
8
+ /**
9
+ * Prepares a source document for chunking: lifts front matter into metadata the index can use,
10
+ * and drops site boilerplate. Prose is left alone — the index matches on it.
11
+ */
12
+ export declare function cleanDocument(raw: string): CleanedDocument;
13
+ //# sourceMappingURL=document.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"document.d.ts","sourceRoot":"","sources":["../src/document.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,qEAAqE;IACrE,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,qEAAqE;IACrE,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;CAClC;AAID;;;GAGG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,eAAe,CAW1D"}
@@ -0,0 +1,47 @@
1
+ import { stripBoilerplate } from "./style.js";
2
+ const FRONT_MATTER = /^?---\r?\n([\s\S]*?)\r?\n---\r?\n?/;
3
+ /**
4
+ * Prepares a source document for chunking: lifts front matter into metadata the index can use,
5
+ * and drops site boilerplate. Prose is left alone — the index matches on it.
6
+ */
7
+ export function cleanDocument(raw) {
8
+ const match = FRONT_MATTER.exec(raw);
9
+ const body = stripBoilerplate(match === null ? raw : raw.slice(match[0].length)).trim();
10
+ if (match?.[1] === undefined)
11
+ return { text: body, tags: [] };
12
+ const meta = parseFrontMatter(match[1]);
13
+ return {
14
+ text: body,
15
+ ...(meta.title === undefined ? {} : { title: meta.title }),
16
+ tags: meta.tags,
17
+ };
18
+ }
19
+ /**
20
+ * Reads the two front matter fields worth indexing. This is deliberately not a YAML parser:
21
+ * anything more complex is not metadata a retrieval index can use.
22
+ */
23
+ function parseFrontMatter(block) {
24
+ let title;
25
+ const tags = [];
26
+ for (const line of block.split("\n")) {
27
+ const entry = /^\s*([A-Za-z_][\w-]*)\s*:\s*(.*)$/.exec(line);
28
+ if (entry?.[1] === undefined || entry[2] === undefined)
29
+ continue;
30
+ const key = entry[1].toLowerCase();
31
+ const value = entry[2].trim().replace(/^["']|["']$/g, "");
32
+ if (key === "title" && value.length > 0)
33
+ title = value;
34
+ if ((key === "tags" || key === "keywords") && value.startsWith("[")) {
35
+ tags.push(...splitList(value));
36
+ }
37
+ }
38
+ return { ...(title === undefined ? {} : { title }), tags };
39
+ }
40
+ function splitList(value) {
41
+ return value
42
+ .replace(/^\[|\]$/g, "")
43
+ .split(",")
44
+ .map((item) => item.trim().replace(/^["']|["']$/g, ""))
45
+ .filter((item) => item.length > 0);
46
+ }
47
+ //# sourceMappingURL=document.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"document.js","sourceRoot":"","sources":["../src/document.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAU9C,MAAM,YAAY,GAAG,qCAAqC,CAAC;AAE3D;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,GAAW;IACvC,MAAM,KAAK,GAAG,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACrC,MAAM,IAAI,GAAG,gBAAgB,CAAC,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IACxF,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC,KAAK,SAAS;QAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC;IAE9D,MAAM,IAAI,GAAG,gBAAgB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IACxC,OAAO;QACL,IAAI,EAAE,IAAI;QACV,GAAG,CAAC,IAAI,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC;QAC1D,IAAI,EAAE,IAAI,CAAC,IAAI;KAChB,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,SAAS,gBAAgB,CAAC,KAAa;IACrC,IAAI,KAAyB,CAAC;IAC9B,MAAM,IAAI,GAAa,EAAE,CAAC;IAE1B,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QACrC,MAAM,KAAK,GAAG,mCAAmC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC7D,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC,KAAK,SAAS,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,SAAS;YAAE,SAAS;QAEjE,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;QACnC,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,cAAc,EAAE,EAAE,CAAC,CAAC;QAC1D,IAAI,GAAG,KAAK,OAAO,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;YAAE,KAAK,GAAG,KAAK,CAAC;QACvD,IAAI,CAAC,GAAG,KAAK,MAAM,IAAI,GAAG,KAAK,UAAU,CAAC,IAAI,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YACpE,IAAI,CAAC,IAAI,CAAC,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC;QACjC,CAAC;IACH,CAAC;IAED,OAAO,EAAE,GAAG,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC;AAC7D,CAAC;AAED,SAAS,SAAS,CAAC,KAAa;IAC9B,OAAO,KAAK;SACT,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC;SACvB,KAAK,CAAC,GAAG,CAAC;SACV,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,cAAc,EAAE,EAAE,CAAC,CAAC;SACtD,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;AACvC,CAAC"}
@@ -0,0 +1,9 @@
1
+ /** An error with a message safe to show to the user, plus an optional next step. */
2
+ export declare class DocspackError extends Error {
3
+ readonly hint: string | undefined;
4
+ constructor(message: string, options?: {
5
+ hint?: string;
6
+ cause?: unknown;
7
+ });
8
+ }
9
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,oFAAoF;AACpF,qBAAa,aAAc,SAAQ,KAAK;IACtC,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;gBAEtB,OAAO,EAAE,MAAM,EAAE,OAAO,GAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,OAAO,CAAA;KAAO;CAK9E"}
package/dist/errors.js ADDED
@@ -0,0 +1,10 @@
1
+ /** An error with a message safe to show to the user, plus an optional next step. */
2
+ export class DocspackError extends Error {
3
+ hint;
4
+ constructor(message, options = {}) {
5
+ super(message, options.cause === undefined ? undefined : { cause: options.cause });
6
+ this.name = "DocspackError";
7
+ this.hint = options.hint;
8
+ }
9
+ }
10
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,oFAAoF;AACpF,MAAM,OAAO,aAAc,SAAQ,KAAK;IAC7B,IAAI,CAAqB;IAElC,YAAY,OAAe,EAAE,UAA8C,EAAE;QAC3E,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC;QACnF,IAAI,CAAC,IAAI,GAAG,eAAe,CAAC;QAC5B,IAAI,CAAC,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAC3B,CAAC;CACF"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * The names a package declares, read statically from its type declarations.
3
+ *
4
+ * Importing the package and reading its keys would be more accurate and would execute
5
+ * third-party code, which is not acceptable for a check that runs over every dependency.
6
+ */
7
+ export interface ExportSurface {
8
+ readonly name: string;
9
+ readonly version: string;
10
+ /** Every identifier declared anywhere in the package's `.d.ts` files. */
11
+ readonly names: ReadonlySet<string>;
12
+ readonly files: number;
13
+ }
14
+ /**
15
+ * Reads every `.d.ts` in an installed package. Reading all of them rather than following the
16
+ * entry points is deliberate: a wider set of known names means fewer false accusations, which
17
+ * matters more here than catching every last rename.
18
+ */
19
+ export declare function readExportSurface(dir: string): Promise<ExportSurface | undefined>;
20
+ //# sourceMappingURL=exports.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exports.d.ts","sourceRoot":"","sources":["../src/exports.ts"],"names":[],"mappings":"AAIA;;;;;GAKG;AACH,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,yEAAyE;IACzE,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IACpC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAaD;;;;GAIG;AACH,wBAAsB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,SAAS,CAAC,CA4BvF"}