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,181 @@
1
+ import { CONFIG_KEY } from "../config.js";
2
+ import { AGENTS_SNIPPET, FEEDBACK_SNIPPET } from "../snippet.js";
3
+ import { LLMS_DIR } from "../spec.js";
4
+ /** Marker the doctor looks for, so a half-filled template cannot be published as documentation. */
5
+ export const PLACEHOLDER = "TODO:";
6
+ export function packageJson(input) {
7
+ const subject = input.libraryName ?? input.name;
8
+ return `${JSON.stringify({
9
+ name: input.name,
10
+ version: input.version,
11
+ description: `Documentation for ${subject}, for use with docspack.`,
12
+ keywords: ["docspack", "documentation", "ai", "agents", "mcp"],
13
+ ...(input.repository === undefined
14
+ ? {}
15
+ : { repository: { type: "git", url: `git+${input.repository}.git` } }),
16
+ ...(input.license === undefined ? {} : { license: input.license }),
17
+ // Without .llms the published package installs fine and indexes nothing.
18
+ files: [LLMS_DIR, "llms.txt"],
19
+ publishConfig: { access: "public" },
20
+ // `documents` names the library, which is what `docspack verify` checks the docs against.
21
+ [CONFIG_KEY]: {
22
+ ...(input.libraryName === undefined ? {} : { documents: input.libraryName }),
23
+ ...input.build,
24
+ },
25
+ scripts: {
26
+ build: "docspack build",
27
+ // Rebuilds and validates on every publish, so a stale payload cannot reach the registry.
28
+ prepublishOnly: "docspack build && docspack doctor --strict",
29
+ },
30
+ devDependencies: { docspack: `^${input.docspackVersion}` },
31
+ }, null, 2)}\n`;
32
+ }
33
+ export function readme(name, libraryName) {
34
+ const subject = libraryName ?? "this library";
35
+ return `# ${name}
36
+
37
+ Documentation for ${subject}, packaged for [docspack](https://github.com/docspack/docspack)
38
+ so AI coding agents can read it locally, at the version you installed.
39
+
40
+ \`\`\`bash
41
+ npm i -D ${name}
42
+ npx docspack sync
43
+ npx docspack ask "how do I authenticate"
44
+ \`\`\`
45
+
46
+ Give an agent access with one line in AGENTS.md or CLAUDE.md:
47
+
48
+ \`\`\`md
49
+ ${AGENTS_SNIPPET.join("\n")}
50
+ \`\`\`
51
+
52
+ No server needed. \`docspack mcp\` serves the same index over MCP for clients that prefer a
53
+ declared tool; both return identical text, scoped to the version this project depends on.
54
+
55
+ Add this as well if you want the agent to record documentation problems it hits:
56
+
57
+ \`\`\`md
58
+ ${FEEDBACK_SNIPPET.join("\n")}
59
+ \`\`\`
60
+
61
+ ## What is in here
62
+
63
+ \`${LLMS_DIR}/\` holds the machine-readable payload: a manifest and one Markdown file per
64
+ chunk. \`llms.txt\` is the table of contents. Both are generated — see the repository this
65
+ package is built from to change the source documentation.
66
+ `;
67
+ }
68
+ export function gitignore() {
69
+ return `# Generated by \`docspack build\`. Rebuilt on publish by prepublishOnly.
70
+ ${LLMS_DIR}/
71
+ llms.txt
72
+ `;
73
+ }
74
+ /**
75
+ * Three seeds that map onto how retrieval works: one chunk should answer one question. The
76
+ * guidance in them is what `docspack doctor` checks, so following it keeps the package clean.
77
+ */
78
+ export function docSeeds(subject) {
79
+ return [
80
+ {
81
+ path: "docs/01-overview.md",
82
+ contents: `# ${subject} overview
83
+
84
+ ${PLACEHOLDER} one paragraph on what ${subject} is and the problem it solves. Write plainly:
85
+ no marketing adjectives, no "in this guide". Every sentence should carry a fact, because the
86
+ index matches on the words someone would type.
87
+
88
+ ## Mental model
89
+
90
+ ${PLACEHOLDER} the two or three concepts a reader needs before anything else makes sense.
91
+ Name them the way your API names them, in \`inline code\` — those names are indexed.
92
+
93
+ ## When to use it
94
+
95
+ ${PLACEHOLDER} what ${subject} is for, and what it is not for. Keep sentences under 40 words:
96
+ one claim each retrieves better than two joined by a conjunction.
97
+ `,
98
+ },
99
+ {
100
+ path: "docs/02-getting-started.md",
101
+ contents: `# Getting started with ${subject}
102
+
103
+ ## Installation
104
+
105
+ ${PLACEHOLDER} the install command, and any peer requirement.
106
+
107
+ ## Configuration
108
+
109
+ ${PLACEHOLDER} the minimum configuration needed to make a first call. Put option names in
110
+ \`inline code\` — docspack indexes those as entities, which is how an agent finds them.
111
+ Show the call rather than describing it; a chunk with no code is hard to act on.
112
+
113
+ ## Your first call
114
+
115
+ ${PLACEHOLDER} a complete, runnable example. Short and real beats long and abstract.
116
+ `,
117
+ },
118
+ {
119
+ path: "docs/03-api.md",
120
+ contents: `# ${subject} API
121
+
122
+ Give each operation its own \`##\` heading: docspack splits chunks at that level, and one
123
+ chunk that answers one question retrieves far better than one that answers five.
124
+
125
+ ## ${PLACEHOLDER} first operation
126
+
127
+ ${PLACEHOLDER} what it does, its parameters, what it returns, and one example.
128
+
129
+ ## ${PLACEHOLDER} second operation
130
+
131
+ ${PLACEHOLDER} same shape as above.
132
+ `,
133
+ },
134
+ ];
135
+ }
136
+ export function workflow(name, buildArgs) {
137
+ return `# Publishes ${name} on every release, so the documentation version always
138
+ # matches the library version. Needs an NPM_TOKEN secret with publish rights.
139
+
140
+ name: Publish documentation package
141
+
142
+ on:
143
+ release:
144
+ types: [published]
145
+ workflow_dispatch:
146
+ inputs:
147
+ version:
148
+ description: Version to publish
149
+ required: true
150
+
151
+ jobs:
152
+ publish:
153
+ runs-on: ubuntu-latest
154
+ permissions:
155
+ contents: read
156
+ id-token: write
157
+ steps:
158
+ - uses: actions/checkout@v5
159
+
160
+ - uses: actions/setup-node@v5
161
+ with:
162
+ node-version: 24
163
+ registry-url: https://registry.npmjs.org
164
+
165
+ - name: Resolve the version
166
+ id: version
167
+ run: echo "value=\${{ inputs.version || github.event.release.tag_name }}" >> "$GITHUB_OUTPUT"
168
+
169
+ - name: Generate the documentation package
170
+ run: npx docspack build${buildArgs} --pkg-version "\${{ steps.version.outputs.value }}"
171
+
172
+ - name: Validate before publishing
173
+ run: npx docspack doctor --strict
174
+
175
+ - name: Publish to npm
176
+ run: npm publish --access public --provenance
177
+ env:
178
+ NODE_AUTH_TOKEN: \${{ secrets.NPM_TOKEN }}
179
+ `;
180
+ }
181
+ //# sourceMappingURL=templates.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"templates.js","sourceRoot":"","sources":["../../src/init/templates.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ import type { InitPlan } from "./plan.js";
2
+ export type WriteStatus = "created" | "overwritten" | "unchanged" | "skipped";
3
+ export interface WrittenFile {
4
+ readonly path: string;
5
+ readonly status: WriteStatus;
6
+ }
7
+ export interface ApplyOptions {
8
+ /** Overwrite files that already exist and differ. */
9
+ readonly force?: boolean;
10
+ /** Report what would happen without touching the disk. */
11
+ readonly dryRun?: boolean;
12
+ }
13
+ /**
14
+ * Writes a plan. Existing files are left alone unless they are identical or `--force` is set, so
15
+ * re-running `init` in a real project never destroys work.
16
+ */
17
+ export declare function applyPlan(cwd: string, plan: InitPlan, options?: ApplyOptions): Promise<WrittenFile[]>;
18
+ /** Renders a plan as the tree `--dry-run` and the confirmation step print. */
19
+ export declare function renderTree(plan: InitPlan, written?: readonly WrittenFile[]): string;
20
+ //# sourceMappingURL=write.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"write.d.ts","sourceRoot":"","sources":["../../src/init/write.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAE1C,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,aAAa,GAAG,WAAW,GAAG,SAAS,CAAC;AAE9E,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;CAC9B;AAED,MAAM,WAAW,YAAY;IAC3B,qDAAqD;IACrD,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;IACzB,0DAA0D;IAC1D,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED;;;GAGG;AACH,wBAAsB,SAAS,CAC7B,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,QAAQ,EACd,OAAO,GAAE,YAAiB,GACzB,OAAO,CAAC,WAAW,EAAE,CAAC,CA6BxB;AAED,8EAA8E;AAC9E,wBAAgB,UAAU,CAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,CAAC,EAAE,SAAS,WAAW,EAAE,GAAG,MAAM,CAcnF"}
@@ -0,0 +1,56 @@
1
+ import { mkdir, readFile, writeFile } from "node:fs/promises";
2
+ import { dirname, relative, resolve, sep } from "node:path";
3
+ import { DocspackError } from "../errors.js";
4
+ /**
5
+ * Writes a plan. Existing files are left alone unless they are identical or `--force` is set, so
6
+ * re-running `init` in a real project never destroys work.
7
+ */
8
+ export async function applyPlan(cwd, plan, options = {}) {
9
+ const root = resolve(cwd, plan.dir);
10
+ const results = [];
11
+ for (const file of plan.files) {
12
+ const target = resolve(root, file.path);
13
+ const inside = relative(root, target);
14
+ if (inside.length === 0 || inside.startsWith("..") || inside.startsWith(`..${sep}`)) {
15
+ throw new DocspackError(`Refusing to write "${file.path}" outside of ${plan.dir}`);
16
+ }
17
+ const existing = await read(target);
18
+ if (existing === file.contents) {
19
+ results.push({ path: file.path, status: "unchanged" });
20
+ continue;
21
+ }
22
+ if (existing !== undefined && options.force !== true) {
23
+ results.push({ path: file.path, status: "skipped" });
24
+ continue;
25
+ }
26
+ if (options.dryRun !== true) {
27
+ await mkdir(dirname(target), { recursive: true });
28
+ await writeFile(target, file.contents, "utf8");
29
+ }
30
+ results.push({ path: file.path, status: existing === undefined ? "created" : "overwritten" });
31
+ }
32
+ return results;
33
+ }
34
+ /** Renders a plan as the tree `--dry-run` and the confirmation step print. */
35
+ export function renderTree(plan, written) {
36
+ const status = new Map(written?.map((file) => [file.path, file.status]));
37
+ const paths = [...plan.files].map((file) => file.path).sort();
38
+ const lines = [`${plan.dir}/`];
39
+ paths.forEach((path, index) => {
40
+ const marker = index === paths.length - 1 ? "└──" : "├──";
41
+ const state = status.get(path);
42
+ lines.push(`${marker} ${path}${state === undefined || state === "created" ? "" : ` (${state})`}`);
43
+ });
44
+ return lines.join("\n");
45
+ }
46
+ async function read(path) {
47
+ try {
48
+ return await readFile(path, "utf8");
49
+ }
50
+ catch (error) {
51
+ if (error.code === "ENOENT")
52
+ return undefined;
53
+ throw error;
54
+ }
55
+ }
56
+ //# sourceMappingURL=write.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"write.js","sourceRoot":"","sources":["../../src/init/write.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * The kinds of documentation problem docspack records.
3
+ *
4
+ * `drift` is Tier A: a name the documentation uses that the library does not declare, which is
5
+ * a fact about two files and needs no model to establish. The other two are Tier B, where a
6
+ * reader exercised judgment and therefore has to show its work.
7
+ *
8
+ * There is deliberately no kind for "this page is confusing". Unfalsifiable claims are
9
+ * infinitely generatable and of no use to a maintainer.
10
+ */
11
+ export declare const KINDS: readonly ["drift", "incorrect", "missing"];
12
+ export type FindingKind = (typeof KINDS)[number];
13
+ export declare function isFindingKind(value: unknown): value is FindingKind;
14
+ //# sourceMappingURL=kinds.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kinds.d.ts","sourceRoot":"","sources":["../src/kinds.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,eAAO,MAAM,KAAK,4CAA6C,CAAC;AAEhE,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC;AAEjD,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,WAAW,CAElE"}
package/dist/kinds.js ADDED
@@ -0,0 +1,15 @@
1
+ /**
2
+ * The kinds of documentation problem docspack records.
3
+ *
4
+ * `drift` is Tier A: a name the documentation uses that the library does not declare, which is
5
+ * a fact about two files and needs no model to establish. The other two are Tier B, where a
6
+ * reader exercised judgment and therefore has to show its work.
7
+ *
8
+ * There is deliberately no kind for "this page is confusing". Unfalsifiable claims are
9
+ * infinitely generatable and of no use to a maintainer.
10
+ */
11
+ export const KINDS = ["drift", "incorrect", "missing"];
12
+ export function isFindingKind(value) {
13
+ return typeof value === "string" && KINDS.includes(value);
14
+ }
15
+ //# sourceMappingURL=kinds.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kinds.js","sourceRoot":"","sources":["../src/kinds.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,OAAO,EAAE,WAAW,EAAE,SAAS,CAAU,CAAC;AAIhE,MAAM,UAAU,aAAa,CAAC,KAAc;IAC1C,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAK,KAA2B,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AACnF,CAAC"}
@@ -0,0 +1,25 @@
1
+ export interface LlmsTxtLink {
2
+ readonly title: string;
3
+ readonly url: string;
4
+ readonly notes?: string;
5
+ }
6
+ export interface LlmsTxtSection {
7
+ readonly heading: string;
8
+ readonly links: readonly LlmsTxtLink[];
9
+ }
10
+ export interface LlmsTxtDocument {
11
+ readonly title?: string;
12
+ readonly summary?: string;
13
+ readonly sections: readonly LlmsTxtSection[];
14
+ /** Every link in document order, across all sections. */
15
+ readonly links: readonly LlmsTxtLink[];
16
+ }
17
+ /**
18
+ * Parses the llms.txt format (https://llmstxt.org). The parser is deliberately tolerant: real
19
+ * files in the wild omit the H1, start at an H2, put the blockquote before the title, and nest
20
+ * link items several levels deep.
21
+ */
22
+ export declare function parseLlmsTxt(text: string): LlmsTxtDocument;
23
+ /** Absolute http(s) links, de-duplicated, in document order. */
24
+ export declare function fetchableLinks(document: LlmsTxtDocument): readonly LlmsTxtLink[];
25
+ //# sourceMappingURL=llms-txt.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"llms-txt.d.ts","sourceRoot":"","sources":["../src/llms-txt.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,SAAS,WAAW,EAAE,CAAC;CACxC;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,QAAQ,EAAE,SAAS,cAAc,EAAE,CAAC;IAC7C,yDAAyD;IACzD,QAAQ,CAAC,KAAK,EAAE,SAAS,WAAW,EAAE,CAAC;CACxC;AAWD;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe,CAoE1D;AAED,gEAAgE;AAChE,wBAAgB,cAAc,CAAC,QAAQ,EAAE,eAAe,GAAG,SAAS,WAAW,EAAE,CAWhF"}
@@ -0,0 +1,94 @@
1
+ const H1 = /^#\s+(.+?)\s*$/;
2
+ const H2 = /^##\s+(.+?)\s*$/;
3
+ const QUOTE = /^>\s?(.*)$/;
4
+ const LIST_LINK = /^\s*[-*+]\s+\[([^\]]*)\]\(([^)]+)\)\s*(?::\s*(.*))?$/;
5
+ const FENCE = /^\s*(?:```|~~~)/;
6
+ /** Links before the first `##` heading land in this section. */
7
+ const PREAMBLE = "";
8
+ /**
9
+ * Parses the llms.txt format (https://llmstxt.org). The parser is deliberately tolerant: real
10
+ * files in the wild omit the H1, start at an H2, put the blockquote before the title, and nest
11
+ * link items several levels deep.
12
+ */
13
+ export function parseLlmsTxt(text) {
14
+ const lines = text.replace(/^/, "").replace(/\r\n/g, "\n").split("\n");
15
+ let title;
16
+ const summaryLines = [];
17
+ let summaryClosed = false;
18
+ let inFence = false;
19
+ let heading = PREAMBLE;
20
+ const sections = new Map();
21
+ const links = [];
22
+ const push = (link) => {
23
+ const bucket = sections.get(heading);
24
+ if (bucket === undefined)
25
+ sections.set(heading, [link]);
26
+ else
27
+ bucket.push(link);
28
+ links.push(link);
29
+ };
30
+ for (const line of lines) {
31
+ if (FENCE.test(line)) {
32
+ inFence = !inFence;
33
+ continue;
34
+ }
35
+ if (inFence)
36
+ continue;
37
+ const h2 = H2.exec(line);
38
+ if (h2?.[1] !== undefined) {
39
+ heading = h2[1];
40
+ summaryClosed = true;
41
+ if (!sections.has(heading))
42
+ sections.set(heading, []);
43
+ continue;
44
+ }
45
+ const h1 = H1.exec(line);
46
+ if (h1?.[1] !== undefined) {
47
+ title ??= h1[1];
48
+ continue;
49
+ }
50
+ const quote = QUOTE.exec(line);
51
+ if (quote?.[1] !== undefined) {
52
+ if (!summaryClosed)
53
+ summaryLines.push(quote[1].trim());
54
+ continue;
55
+ }
56
+ if (summaryLines.length > 0 && line.trim().length === 0)
57
+ summaryClosed = true;
58
+ const item = LIST_LINK.exec(line);
59
+ if (item?.[1] !== undefined && item[2] !== undefined) {
60
+ const url = item[2].trim().split(/\s+/)[0];
61
+ if (url === undefined || url.length === 0)
62
+ continue;
63
+ const notes = item[3]?.trim();
64
+ push({
65
+ title: item[1].trim(),
66
+ url,
67
+ ...(notes === undefined || notes.length === 0 ? {} : { notes }),
68
+ });
69
+ }
70
+ }
71
+ const summary = summaryLines.join(" ").trim();
72
+ return {
73
+ ...(title === undefined ? {} : { title }),
74
+ ...(summary.length === 0 ? {} : { summary }),
75
+ sections: [...sections].map(([name, sectionLinks]) => ({ heading: name, links: sectionLinks })),
76
+ links,
77
+ };
78
+ }
79
+ /** Absolute http(s) links, de-duplicated, in document order. */
80
+ export function fetchableLinks(document) {
81
+ const seen = new Set();
82
+ const result = [];
83
+ for (const link of document.links) {
84
+ if (!/^https?:\/\//i.test(link.url))
85
+ continue;
86
+ const key = link.url.split("#")[0] ?? link.url;
87
+ if (seen.has(key))
88
+ continue;
89
+ seen.add(key);
90
+ result.push(link);
91
+ }
92
+ return result;
93
+ }
94
+ //# sourceMappingURL=llms-txt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"llms-txt.js","sourceRoot":"","sources":["../src/llms-txt.ts"],"names":[],"mappings":"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"}
package/dist/mcp.d.ts ADDED
@@ -0,0 +1,15 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { type Store } from "./db.js";
3
+ export interface McpOptions {
4
+ readonly cwd: string;
5
+ readonly store: Store;
6
+ readonly version: string;
7
+ /** Only used in the startup banner; defaults to the standard location. */
8
+ readonly storePath?: string;
9
+ readonly limit?: number;
10
+ readonly maxTokens?: number;
11
+ }
12
+ export declare function createMcpServer(options: McpOptions): McpServer;
13
+ /** Runs the server over stdio. stdout carries the protocol, so nothing else may be written to it. */
14
+ export declare function startMcpServer(options: McpOptions): Promise<void>;
15
+ //# sourceMappingURL=mcp.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp.d.ts","sourceRoot":"","sources":["../src/mcp.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAGpE,OAAO,EAAoB,KAAK,KAAK,EAAE,MAAM,SAAS,CAAC;AAMvD,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,0EAA0E;IAC1E,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC7B;AA4BD,wBAAgB,eAAe,CAAC,OAAO,EAAE,UAAU,GAAG,SAAS,CA6I9D;AAED,qGAAqG;AACrG,wBAAsB,cAAc,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAMvE"}
package/dist/mcp.js ADDED
@@ -0,0 +1,158 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
3
+ import { z } from "zod";
4
+ import { defaultStorePath } from "./db.js";
5
+ import { DocspackError } from "./errors.js";
6
+ import { addFinding, feedbackPath } from "./feedback.js";
7
+ import { KINDS } from "./kinds.js";
8
+ import { DEFAULT_LIMIT, DEFAULT_MAX_TOKENS, queryDocs, renderAnswer } from "./search.js";
9
+ const DESCRIPTION = [
10
+ "Search the documentation of this project's installed dependencies.",
11
+ "Returns Markdown excerpts from local, version-matched documentation packages.",
12
+ "Prefer this over recalling API details from memory: the local copy matches the",
13
+ "exact dependency versions in this project.",
14
+ ].join(" ");
15
+ /**
16
+ * A tool description is the only thing shaping how a model uses it, so this one carries the
17
+ * same rules `addFinding` enforces. Saying plainly that the record stops at a human matters
18
+ * most: a model that thinks it is filing an issue behaves differently from one that knows it
19
+ * is appending to a file someone will read.
20
+ */
21
+ const RECORD_DESCRIPTION = [
22
+ "Record a problem in this project's local documentation, after you have hit it.",
23
+ "Use it when documentation contradicts the installed package: a name it uses that",
24
+ "the package does not export (drift), a statement or example that is wrong",
25
+ "(incorrect), or a precondition it omits that made the code fail (missing).",
26
+ "The record is appended to a local file for a human to review. Nothing is sent",
27
+ "anywhere, no issue is filed, and no maintainer is contacted by this tool.",
28
+ "Only record claims that could be shown false. Do not record opinions about",
29
+ "style, clarity or completeness; there is no kind for them and they will be",
30
+ "rejected. incorrect and missing must carry expected, actual and repro, so",
31
+ "record them only after actually running something.",
32
+ ].join(" ");
33
+ export function createMcpServer(options) {
34
+ const server = new McpServer({ name: "docspack", version: options.version }, {
35
+ instructions: "docspack exposes the documentation of this project's dependencies as a local, " +
36
+ "version-accurate search index. Use query_local_docs before answering questions " +
37
+ "about a dependency's API. If that documentation turns out to be wrong, " +
38
+ "record_docs_problem writes the problem to a local file for a human to review; " +
39
+ "it does not contact anyone.",
40
+ });
41
+ server.registerTool("query_local_docs", {
42
+ title: "Query local documentation",
43
+ description: DESCRIPTION,
44
+ inputSchema: {
45
+ query: z.string().min(1).describe("Words to search for, e.g. 'webhook signature'"),
46
+ packageFilter: z
47
+ .string()
48
+ .optional()
49
+ .describe("Restrict to packages whose name contains this text, e.g. 'stripe'"),
50
+ },
51
+ annotations: { readOnlyHint: true, openWorldHint: false },
52
+ }, async ({ query, packageFilter }) => {
53
+ try {
54
+ const result = await queryDocs({
55
+ cwd: options.cwd,
56
+ store: options.store,
57
+ query,
58
+ ...(packageFilter === undefined ? {} : { packageFilter }),
59
+ limit: options.limit ?? DEFAULT_LIMIT,
60
+ maxTokens: options.maxTokens ?? DEFAULT_MAX_TOKENS,
61
+ });
62
+ return { content: [{ type: "text", text: renderAnswer(result, query) }] };
63
+ }
64
+ catch (error) {
65
+ return {
66
+ content: [
67
+ {
68
+ type: "text",
69
+ text: `docspack could not run that query: ${error instanceof Error ? error.message : String(error)}`,
70
+ },
71
+ ],
72
+ isError: true,
73
+ };
74
+ }
75
+ });
76
+ server.registerTool("record_docs_problem", {
77
+ title: "Record a documentation problem",
78
+ description: RECORD_DESCRIPTION,
79
+ inputSchema: {
80
+ chunkId: z
81
+ .string()
82
+ .min(1)
83
+ .describe("The chunk the problem is in, exactly as query_local_docs printed it above the answer, e.g. '@acme/docspack@1.4.0/api-auth'"),
84
+ kind: z
85
+ .enum(KINDS)
86
+ .describe("drift: a name the docs use that the package does not export. incorrect: a statement or example that is wrong. missing: an omitted precondition that made the code fail."),
87
+ evidence: z
88
+ .string()
89
+ .min(1)
90
+ .describe("The claim in one line, naming what is wrong, e.g. 'client.setKey is not exported; setApiKey is'"),
91
+ expected: z
92
+ .string()
93
+ .optional()
94
+ .describe("What the documentation led you to expect. Required unless kind is drift."),
95
+ actual: z
96
+ .string()
97
+ .optional()
98
+ .describe("What happened instead. Required unless kind is drift."),
99
+ repro: z
100
+ .string()
101
+ .optional()
102
+ .describe("Code that demonstrates the problem. Required unless kind is drift. It is stored verbatim, so do not include secrets."),
103
+ },
104
+ // Recording is a write, and a repeat bumps a counter, so it is not idempotent either.
105
+ annotations: {
106
+ readOnlyHint: false,
107
+ destructiveHint: false,
108
+ idempotentHint: false,
109
+ openWorldHint: false,
110
+ },
111
+ }, async ({ chunkId, kind, evidence, expected, actual, repro }) => {
112
+ try {
113
+ // Every rule lives in addFinding, so this tool cannot be a looser way in than the CLI.
114
+ const { finding, repeat } = await addFinding({
115
+ cwd: options.cwd,
116
+ chunkId,
117
+ kind,
118
+ evidence,
119
+ ...(expected === undefined ? {} : { expected }),
120
+ ...(actual === undefined ? {} : { actual }),
121
+ ...(repro === undefined ? {} : { repro }),
122
+ });
123
+ return {
124
+ content: [
125
+ {
126
+ type: "text",
127
+ text: [
128
+ repeat
129
+ ? `This problem was already recorded; it has now been seen ${finding.seen} times.`
130
+ : `Recorded ${finding.fingerprint} in ${feedbackPath(options.cwd)}.`,
131
+ "Nothing was sent. A human reviews the file and decides whether to report it.",
132
+ ].join(" "),
133
+ },
134
+ ],
135
+ };
136
+ }
137
+ catch (error) {
138
+ // Saying which field is missing is what lets a model correct itself and retry, so the
139
+ // hint is passed through. It is written for the CLI, where the fields are flags; here
140
+ // they are parameters, so the dashes come off.
141
+ const hint = error instanceof DocspackError ? error.hint : undefined;
142
+ const message = error instanceof Error ? error.message : String(error);
143
+ const text = hint === undefined ? `Not recorded: ${message}` : `Not recorded: ${message}. ${hint}`;
144
+ return {
145
+ content: [{ type: "text", text: text.replace(/--(?=[a-z])/g, "") }],
146
+ isError: true,
147
+ };
148
+ }
149
+ });
150
+ return server;
151
+ }
152
+ /** Runs the server over stdio. stdout carries the protocol, so nothing else may be written to it. */
153
+ export async function startMcpServer(options) {
154
+ const server = createMcpServer(options);
155
+ process.stderr.write(`docspack mcp: serving ${options.storePath ?? defaultStorePath()} for ${options.cwd}\n`);
156
+ await server.connect(new StdioServerTransport());
157
+ }
158
+ //# sourceMappingURL=mcp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp.js","sourceRoot":"","sources":["../src/mcp.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ import { type QueryHit } from "./search.js";
2
+ export interface PreviewOptions {
3
+ readonly dir: string;
4
+ readonly query: string;
5
+ readonly limit?: number;
6
+ readonly maxTokens?: number;
7
+ }
8
+ export interface PreviewResult {
9
+ readonly hits: readonly QueryHit[];
10
+ readonly tokens: number;
11
+ readonly indexed: number;
12
+ }
13
+ /**
14
+ * Answers a query from a package on disk, through the same ranking and token budget an agent
15
+ * gets. Nothing is published, installed, or written to the global store.
16
+ */
17
+ export declare function previewPackage(options: PreviewOptions): Promise<PreviewResult>;
18
+ //# sourceMappingURL=preview.d.ts.map