codebase-snapshot 0.9.1 → 0.9.4
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/CHANGELOG.md +181 -0
- package/README.md +141 -127
- package/dist/bin.js +2543 -506
- package/dist/chunk-EWZYK3VX.js +2577 -0
- package/dist/{chunk-HT7J3NWT.js → chunk-FCWD4LY7.js} +493 -362
- package/dist/cli.cjs +2450 -435
- package/dist/cli.d.cts +11 -1
- package/dist/cli.d.ts +11 -1
- package/dist/cli.js +68 -750
- package/dist/index.cjs +481 -360
- package/dist/index.d.cts +111 -5
- package/dist/index.d.ts +111 -5
- package/dist/index.js +1 -1
- package/dist/mcp.cjs +9398 -0
- package/dist/mcp.d.cts +399 -0
- package/dist/mcp.d.ts +399 -0
- package/dist/mcp.js +4 -0
- package/docs/agent.md +36 -0
- package/docs/cli.md +85 -14
- package/docs/codebase-token-budget.md +98 -0
- package/docs/configuration.md +12 -2
- package/docs/how-to-feed-a-repo-to-claude.md +4 -2
- package/docs/install.md +39 -11
- package/docs/mcp.md +149 -0
- package/docs/stale-context-is-your-bug.md +118 -0
- package/docs/troubleshooting.md +13 -0
- package/docs/vs-repomix.md +4 -2
- package/package.json +29 -14
package/dist/mcp.d.ts
ADDED
|
@@ -0,0 +1,399 @@
|
|
|
1
|
+
import { Readable, Writable } from 'node:stream';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* JSON-RPC 2.0 envelopes and the Model Context Protocol revisions this server speaks.
|
|
5
|
+
*
|
|
6
|
+
* Two protocol eras coexist and this file is the only place that knows which revision belongs
|
|
7
|
+
* to which era. The legacy era (`2025-11-25` and earlier) opens every connection with an
|
|
8
|
+
* `initialize` handshake. The modern era (`2026-07-28`) removed the handshake: every request
|
|
9
|
+
* carries the protocol version and client capabilities in `_meta`, `server/discover` is
|
|
10
|
+
* mandatory, every result carries `resultType`, and `ping` no longer exists.
|
|
11
|
+
*
|
|
12
|
+
* The constants are read by the negotiation in `era.ts`, by the dispatch in `server.ts` and by
|
|
13
|
+
* the `describe` contract, so a revision cannot be added to one of them and forgotten in the
|
|
14
|
+
* others.
|
|
15
|
+
*/
|
|
16
|
+
/** A JSON object as it appears on the wire: the shape every `params`/`result` takes. */
|
|
17
|
+
type JsonObject = Record<string, unknown>;
|
|
18
|
+
type JsonRpcId = string | number;
|
|
19
|
+
interface JsonRpcError {
|
|
20
|
+
code: number;
|
|
21
|
+
message: string;
|
|
22
|
+
data?: unknown;
|
|
23
|
+
}
|
|
24
|
+
interface JsonRpcSuccessResponse {
|
|
25
|
+
jsonrpc: "2.0";
|
|
26
|
+
id: JsonRpcId | null;
|
|
27
|
+
result: JsonObject;
|
|
28
|
+
}
|
|
29
|
+
interface JsonRpcErrorResponse {
|
|
30
|
+
jsonrpc: "2.0";
|
|
31
|
+
id: JsonRpcId | null;
|
|
32
|
+
error: JsonRpcError;
|
|
33
|
+
}
|
|
34
|
+
type JsonRpcResponse = JsonRpcSuccessResponse | JsonRpcErrorResponse;
|
|
35
|
+
/**
|
|
36
|
+
* Revisions that open with the `initialize` handshake, newest first.
|
|
37
|
+
*
|
|
38
|
+
* The server echoes the requested revision when it is in this list and otherwise answers with
|
|
39
|
+
* the newest entry: the legacy lifecycle says a server that cannot speak the requested version
|
|
40
|
+
* responds with one it does speak, and the client decides whether to continue.
|
|
41
|
+
*/
|
|
42
|
+
declare const LEGACY_PROTOCOL_VERSIONS: readonly string[];
|
|
43
|
+
/** Revisions that carry version and capabilities on every request, newest first. */
|
|
44
|
+
declare const MODERN_PROTOCOL_VERSIONS: readonly string[];
|
|
45
|
+
/** Everything advertised in `server/discover` and in an unsupported-version error. */
|
|
46
|
+
declare const SUPPORTED_PROTOCOL_VERSIONS: readonly string[];
|
|
47
|
+
/**
|
|
48
|
+
* JSON-RPC error codes, plus the one the modern era added.
|
|
49
|
+
*
|
|
50
|
+
* `-32022` is not a generic bad-params error: a client that receives it knows to read
|
|
51
|
+
* `data.supported` and retry with a mutually supported revision. Reporting it as `-32602`
|
|
52
|
+
* would leave a modern client with no way to recover.
|
|
53
|
+
*/
|
|
54
|
+
declare const ERROR_CODES: {
|
|
55
|
+
readonly parseError: -32700;
|
|
56
|
+
readonly invalidRequest: -32600;
|
|
57
|
+
readonly methodNotFound: -32601;
|
|
58
|
+
readonly invalidParams: -32602;
|
|
59
|
+
readonly internalError: -32603;
|
|
60
|
+
readonly unsupportedProtocolVersion: -32022;
|
|
61
|
+
};
|
|
62
|
+
/** Method names, kept as constants so a typo is a compile error rather than a `-32601`. */
|
|
63
|
+
declare const METHOD: {
|
|
64
|
+
readonly initialize: "initialize";
|
|
65
|
+
readonly initialized: "notifications/initialized";
|
|
66
|
+
readonly discover: "server/discover";
|
|
67
|
+
readonly ping: "ping";
|
|
68
|
+
readonly toolsList: "tools/list";
|
|
69
|
+
readonly toolsCall: "tools/call";
|
|
70
|
+
readonly resourcesList: "resources/list";
|
|
71
|
+
readonly resourcesRead: "resources/read";
|
|
72
|
+
readonly resourceTemplatesList: "resources/templates/list";
|
|
73
|
+
readonly promptsList: "prompts/list";
|
|
74
|
+
readonly promptsGet: "prompts/get";
|
|
75
|
+
readonly cancelled: "notifications/cancelled";
|
|
76
|
+
};
|
|
77
|
+
/**
|
|
78
|
+
* A JSON Schema subset, as far as this server needs it.
|
|
79
|
+
*
|
|
80
|
+
* Deliberately not `unknown`: the tool table is authored by hand, and the compiler catching a
|
|
81
|
+
* misspelled keyword is worth more than accepting every dialect feature we never emit.
|
|
82
|
+
*/
|
|
83
|
+
interface JsonSchema {
|
|
84
|
+
type?: "object" | "string" | "number" | "integer" | "boolean" | "array";
|
|
85
|
+
description?: string;
|
|
86
|
+
properties?: Record<string, JsonSchema>;
|
|
87
|
+
required?: string[];
|
|
88
|
+
items?: JsonSchema;
|
|
89
|
+
enum?: readonly string[];
|
|
90
|
+
default?: string | number | boolean;
|
|
91
|
+
additionalProperties?: boolean;
|
|
92
|
+
minimum?: number;
|
|
93
|
+
maximum?: number;
|
|
94
|
+
minLength?: number;
|
|
95
|
+
maxLength?: number;
|
|
96
|
+
}
|
|
97
|
+
/** An `inputSchema` root: MCP requires a top-level object schema. */
|
|
98
|
+
interface InputSchema extends JsonSchema {
|
|
99
|
+
type: "object";
|
|
100
|
+
properties: Record<string, JsonSchema>;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
type ProtocolEra = "legacy" | "modern";
|
|
104
|
+
/** Per-connection state. The modern era has no session, so this stays empty until legacy init. */
|
|
105
|
+
interface SessionState {
|
|
106
|
+
/** Which era the connection committed to, or null before the first decisive request. */
|
|
107
|
+
era: ProtocolEra | null;
|
|
108
|
+
/** The revision in force. Null in legacy until `initialize` has been negotiated. */
|
|
109
|
+
protocolVersion: string | null;
|
|
110
|
+
/** True once `initialize` has been answered, which is the legacy lifecycle's gate. */
|
|
111
|
+
ready: boolean;
|
|
112
|
+
}
|
|
113
|
+
declare function createSession(): SessionState;
|
|
114
|
+
/** The modern request metadata, when a request carries it at all. */
|
|
115
|
+
interface ModernMeta {
|
|
116
|
+
version: string;
|
|
117
|
+
clientCapabilities: JsonObject;
|
|
118
|
+
clientInfo: JsonObject | null;
|
|
119
|
+
}
|
|
120
|
+
type MetaInspection = {
|
|
121
|
+
kind: "absent";
|
|
122
|
+
} | {
|
|
123
|
+
kind: "incomplete";
|
|
124
|
+
missing: string;
|
|
125
|
+
} | {
|
|
126
|
+
kind: "present";
|
|
127
|
+
meta: ModernMeta;
|
|
128
|
+
};
|
|
129
|
+
/**
|
|
130
|
+
* Reads `_meta` from a request.
|
|
131
|
+
*
|
|
132
|
+
* `absent` and `incomplete` are different answers: a request with no `_meta` at all is a legacy
|
|
133
|
+
* client, while a request with `_meta` that lacks a required key is a modern client making a
|
|
134
|
+
* mistake — and telling those two apart is what keeps the legacy era from being rejected for a
|
|
135
|
+
* field it never had.
|
|
136
|
+
*/
|
|
137
|
+
declare function inspectModernMeta(params: JsonObject | undefined): MetaInspection;
|
|
138
|
+
type EraDecision = {
|
|
139
|
+
kind: "era";
|
|
140
|
+
era: ProtocolEra;
|
|
141
|
+
version: string | null;
|
|
142
|
+
} | {
|
|
143
|
+
kind: "error";
|
|
144
|
+
code: number;
|
|
145
|
+
message: string;
|
|
146
|
+
data?: unknown;
|
|
147
|
+
};
|
|
148
|
+
/**
|
|
149
|
+
* Decides which era a request belongs to, and whether its version is acceptable.
|
|
150
|
+
*
|
|
151
|
+
* Once a connection commits to an era it stays committed. A legacy client that suddenly sends
|
|
152
|
+
* modern `_meta` is confused rather than clever, and silently switching would answer half a
|
|
153
|
+
* session in each shape.
|
|
154
|
+
*/
|
|
155
|
+
declare function classifyRequest(method: string, params: JsonObject | undefined, session: SessionState): EraDecision;
|
|
156
|
+
interface LegacyNegotiation {
|
|
157
|
+
version: string;
|
|
158
|
+
/** False when the client asked for something we cannot speak and was negotiated down. */
|
|
159
|
+
matched: boolean;
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Legacy version negotiation: echo a supported request, otherwise answer with our best.
|
|
163
|
+
*
|
|
164
|
+
* A client that asked for a modern revision here gets the newest *legacy* revision, not an error:
|
|
165
|
+
* under this lifecycle the server's answer is the offer, and the client decides.
|
|
166
|
+
*/
|
|
167
|
+
declare function negotiateLegacyVersion(requested: unknown): LegacyNegotiation;
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* The capability records the MCP server serves.
|
|
171
|
+
*
|
|
172
|
+
* These are the shapes the protocol layer deals in, kept apart from the handlers that fill them so
|
|
173
|
+
* the server can be tested with a fixed set of stubs and the tool table can be built without a
|
|
174
|
+
* running transport.
|
|
175
|
+
*/
|
|
176
|
+
|
|
177
|
+
/** Everything a handler may touch. Deliberately small: no transport, no session, no protocol. */
|
|
178
|
+
interface ToolContext {
|
|
179
|
+
/** Repository the server was launched for; every relative path resolves against it. */
|
|
180
|
+
cwd: string;
|
|
181
|
+
/** Absolute directories a `root` argument is allowed to resolve into. */
|
|
182
|
+
roots: string[];
|
|
183
|
+
/** Writes one line to stderr. Never stdout, which carries protocol messages only. */
|
|
184
|
+
log: (line: string) => void;
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Client-facing hints.
|
|
188
|
+
*
|
|
189
|
+
* `readOnlyHint` is the one that changes behaviour rather than appearance: clients use it to
|
|
190
|
+
* auto-approve a call. Six of the seven tools never touch the filesystem, so they are marked
|
|
191
|
+
* read-only and only `snapshot_generate` prompts.
|
|
192
|
+
*/
|
|
193
|
+
interface ToolAnnotations {
|
|
194
|
+
readOnlyHint: boolean;
|
|
195
|
+
destructiveHint: boolean;
|
|
196
|
+
idempotentHint: boolean;
|
|
197
|
+
openWorldHint: boolean;
|
|
198
|
+
}
|
|
199
|
+
/** What a handler returns. The protocol layer turns this into a `CallToolResult`. */
|
|
200
|
+
interface ToolOutcome {
|
|
201
|
+
/** The text block a model reads. Keep it short: bulk content belongs in a windowed read. */
|
|
202
|
+
text: string;
|
|
203
|
+
/** Typed mirror of `text`, declared by the tool's `outputSchema`. */
|
|
204
|
+
structured?: JsonObject;
|
|
205
|
+
/** True for a tool-level failure. Reported inside the result, not as a JSON-RPC error. */
|
|
206
|
+
isError?: boolean;
|
|
207
|
+
}
|
|
208
|
+
interface McpTool {
|
|
209
|
+
name: string;
|
|
210
|
+
title: string;
|
|
211
|
+
description: string;
|
|
212
|
+
inputSchema: InputSchema;
|
|
213
|
+
outputSchema?: InputSchema;
|
|
214
|
+
annotations: ToolAnnotations;
|
|
215
|
+
handler(args: JsonObject, context: ToolContext): Promise<ToolOutcome>;
|
|
216
|
+
}
|
|
217
|
+
/** One addressable resource, as `resources/list` reports it. */
|
|
218
|
+
interface McpResourceDescriptor {
|
|
219
|
+
uri: string;
|
|
220
|
+
name: string;
|
|
221
|
+
title?: string;
|
|
222
|
+
description: string;
|
|
223
|
+
mimeType: string;
|
|
224
|
+
}
|
|
225
|
+
interface McpResourceContents {
|
|
226
|
+
uri: string;
|
|
227
|
+
mimeType: string;
|
|
228
|
+
text: string;
|
|
229
|
+
}
|
|
230
|
+
/** A parameterised resource family, as `resources/templates/list` reports it. */
|
|
231
|
+
interface McpResourceTemplate {
|
|
232
|
+
uriTemplate: string;
|
|
233
|
+
name: string;
|
|
234
|
+
title?: string;
|
|
235
|
+
description: string;
|
|
236
|
+
mimeType: string;
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Resources are computed per call rather than declared once.
|
|
240
|
+
*
|
|
241
|
+
* The list depends on what is on disk — a snapshot that has not been generated has manifest
|
|
242
|
+
* resources that do not exist yet — so a static table would advertise resources whose read then
|
|
243
|
+
* fails, which is worse than an honest short list.
|
|
244
|
+
*/
|
|
245
|
+
interface ResourceProvider {
|
|
246
|
+
list(context: ToolContext): Promise<McpResourceDescriptor[]>;
|
|
247
|
+
templates(): McpResourceTemplate[];
|
|
248
|
+
/** Resolves one URI. Returns null when this server does not own it. */
|
|
249
|
+
read(uri: string, context: ToolContext): Promise<McpResourceContents | null>;
|
|
250
|
+
}
|
|
251
|
+
interface PromptArgument {
|
|
252
|
+
name: string;
|
|
253
|
+
description: string;
|
|
254
|
+
required: boolean;
|
|
255
|
+
}
|
|
256
|
+
interface PromptMessage {
|
|
257
|
+
role: "user" | "assistant";
|
|
258
|
+
content: {
|
|
259
|
+
type: "text";
|
|
260
|
+
text: string;
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
interface McpPrompt {
|
|
264
|
+
name: string;
|
|
265
|
+
title?: string;
|
|
266
|
+
description: string;
|
|
267
|
+
arguments: PromptArgument[];
|
|
268
|
+
build(args: JsonObject): {
|
|
269
|
+
description: string;
|
|
270
|
+
messages: PromptMessage[];
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
/** Identity reported at handshake and in every modern result's `_meta`. */
|
|
274
|
+
interface McpServerInfo {
|
|
275
|
+
name: string;
|
|
276
|
+
title: string;
|
|
277
|
+
version: string;
|
|
278
|
+
websiteUrl: string;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
interface McpServerOptions {
|
|
282
|
+
info: McpServerInfo;
|
|
283
|
+
instructions: string;
|
|
284
|
+
tools: McpTool[];
|
|
285
|
+
resources: ResourceProvider;
|
|
286
|
+
prompts: McpPrompt[];
|
|
287
|
+
context: ToolContext;
|
|
288
|
+
}
|
|
289
|
+
interface McpServer {
|
|
290
|
+
/** Handles one already-parsed message. Returns null when no response is due. */
|
|
291
|
+
handle(message: unknown): Promise<JsonRpcResponse | null>;
|
|
292
|
+
/** Exposed for tests and for `mcp --list`, which prints the negotiation table. */
|
|
293
|
+
readonly session: SessionState;
|
|
294
|
+
}
|
|
295
|
+
declare function createMcpServer(options: McpServerOptions): McpServer;
|
|
296
|
+
|
|
297
|
+
/** Every tool this server exposes, in the order a first-time caller should read them. */
|
|
298
|
+
declare function buildTools(): McpTool[];
|
|
299
|
+
|
|
300
|
+
declare function buildPrompts(): McpPrompt[];
|
|
301
|
+
|
|
302
|
+
declare function buildResourceProvider(): ResourceProvider;
|
|
303
|
+
|
|
304
|
+
interface ServerOptions {
|
|
305
|
+
/** Repository the tools operate on. Also the only directory they may read. */
|
|
306
|
+
cwd: string;
|
|
307
|
+
/** Additional directories callers may name as `root`. Defaults to `cwd` alone. */
|
|
308
|
+
roots?: string[];
|
|
309
|
+
/** Where operational notes go. Never stdout, which carries protocol messages only. */
|
|
310
|
+
log?: (line: string) => void;
|
|
311
|
+
}
|
|
312
|
+
/** Builds a server with every capability this package implements. */
|
|
313
|
+
declare function createServer(options: ServerOptions): McpServer;
|
|
314
|
+
/**
|
|
315
|
+
* Serves MCP over stdio until the client closes the stream.
|
|
316
|
+
*
|
|
317
|
+
* Writes are serialised through one promise chain: two tool calls finishing together must not
|
|
318
|
+
* interleave half-written lines, and a single response can be large. Reading is not serialised —
|
|
319
|
+
* a slow tool must not stop a cancellation notification from being read — and the process waits
|
|
320
|
+
* for every accepted request to answer before it resolves.
|
|
321
|
+
*/
|
|
322
|
+
declare function runStdioServer(options: ServerOptions): Promise<number>;
|
|
323
|
+
|
|
324
|
+
/**
|
|
325
|
+
* The stdio transport: one JSON-RPC message per line, UTF-8, nothing else on the stream.
|
|
326
|
+
*
|
|
327
|
+
* MCP's stdio binding is newline-delimited JSON, not LSP's `Content-Length` framing, and the
|
|
328
|
+
* server MUST NOT write anything to stdout that is not a valid message. `JSON.stringify` escapes
|
|
329
|
+
* newlines inside strings, so serialising a message can never produce a second line — the writer
|
|
330
|
+
* deliberately does not pretty-print, because `JSON.stringify(value, null, 2)` would.
|
|
331
|
+
*
|
|
332
|
+
* Framing is separated from parsing on purpose: this module hands raw lines to its caller and the
|
|
333
|
+
* server decides what a bad line means (a `-32700` response), which keeps the line splitting
|
|
334
|
+
* testable without a running server.
|
|
335
|
+
*/
|
|
336
|
+
|
|
337
|
+
/**
|
|
338
|
+
* Largest single message this transport will buffer.
|
|
339
|
+
*
|
|
340
|
+
* A line with no newline grows the buffer until the process runs out of memory, so an oversized
|
|
341
|
+
* message is discarded rather than accepted: the snapshot itself is never this large, and a
|
|
342
|
+
* client that streams more than this is not sending a message.
|
|
343
|
+
*/
|
|
344
|
+
declare const MAX_LINE_BYTES: number;
|
|
345
|
+
interface MessageWriter {
|
|
346
|
+
/** Serialises one message onto the stream. Rejects if the stream reports a write error. */
|
|
347
|
+
write(value: unknown): Promise<void>;
|
|
348
|
+
}
|
|
349
|
+
/**
|
|
350
|
+
* Creates a writer that emits exactly one line per message.
|
|
351
|
+
*
|
|
352
|
+
* Writes are awaited through the stream's callback rather than fire-and-forget: a tool result can
|
|
353
|
+
* be tens of kilobytes, and queueing several without backpressure interleaves them with the next
|
|
354
|
+
* response on a slow pipe.
|
|
355
|
+
*/
|
|
356
|
+
declare function createWriter(output: Writable): MessageWriter;
|
|
357
|
+
interface LineReaderOptions {
|
|
358
|
+
/** Called for every complete, non-empty line, with the trailing CR already removed. */
|
|
359
|
+
onLine: (line: string) => void;
|
|
360
|
+
/** Called when one line exceeds {@link MAX_LINE_BYTES}; the line is discarded. */
|
|
361
|
+
onOverflow?: (bytes: number) => void;
|
|
362
|
+
}
|
|
363
|
+
/**
|
|
364
|
+
* Reads newline-delimited lines from `input` until it ends.
|
|
365
|
+
*
|
|
366
|
+
* Three details are what make this work against real clients rather than against our own tests:
|
|
367
|
+
* a chunk boundary can fall anywhere inside a line (including inside a multi-byte character,
|
|
368
|
+
* which `setEncoding` handles); a Windows client may terminate lines with CRLF; and the final
|
|
369
|
+
* line may arrive without a newline before the stream ends.
|
|
370
|
+
*
|
|
371
|
+
* Returns a function that removes the listeners, so a caller can shut a transport down without
|
|
372
|
+
* racing a late `end` event.
|
|
373
|
+
*/
|
|
374
|
+
declare function createLineReader(input: Readable, options: LineReaderOptions): () => void;
|
|
375
|
+
|
|
376
|
+
/**
|
|
377
|
+
* The instructions an MCP client shows its model at handshake.
|
|
378
|
+
*
|
|
379
|
+
* This text is the cheapest documentation the project has: it arrives before the first tool call,
|
|
380
|
+
* in the model's own context, on every client that supports the field. It is therefore about
|
|
381
|
+
* *order* rather than features — an agent that reads a part end to end has already lost the
|
|
382
|
+
* budget this tool exists to protect.
|
|
383
|
+
*/
|
|
384
|
+
declare const SERVER_INSTRUCTIONS: string;
|
|
385
|
+
|
|
386
|
+
/**
|
|
387
|
+
* A JSON Schema checker for tool arguments, sized to the schemas this server publishes.
|
|
388
|
+
*
|
|
389
|
+
* The alternative was Ajv, which is the right answer for arbitrary schemas and the wrong one for
|
|
390
|
+
* a package whose single dependency is a compiler. Every schema here is a flat object of scalar
|
|
391
|
+
* properties, so the checker is small, readable and — unlike a general-purpose validator — it can
|
|
392
|
+
* reject unknown properties by default, which is what turns an agent's typo (`maxPartByte`) into a
|
|
393
|
+
* named error instead of a silently ignored option.
|
|
394
|
+
*/
|
|
395
|
+
|
|
396
|
+
/** Human-readable problems, each prefixed with the argument path that caused it. */
|
|
397
|
+
declare function validateArguments(schema: InputSchema, value: unknown): string[];
|
|
398
|
+
|
|
399
|
+
export { ERROR_CODES, type JsonRpcResponse, type JsonSchema, LEGACY_PROTOCOL_VERSIONS, type LineReaderOptions, MAX_LINE_BYTES, METHOD, MODERN_PROTOCOL_VERSIONS, type McpPrompt, type McpResourceContents, type McpResourceDescriptor, type McpResourceTemplate, type McpServer, type McpServerInfo, type McpServerOptions, type McpTool, type MessageWriter, type ProtocolEra, type ResourceProvider, SERVER_INSTRUCTIONS, SUPPORTED_PROTOCOL_VERSIONS, type ServerOptions, type SessionState, type ToolAnnotations, type ToolContext, type ToolOutcome, buildPrompts, buildResourceProvider, buildTools, classifyRequest, createLineReader, createMcpServer, createServer, createSession, createWriter, inspectModernMeta, negotiateLegacyVersion, runStdioServer, validateArguments };
|
package/dist/mcp.js
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { ERROR_CODES, LEGACY_PROTOCOL_VERSIONS, MAX_LINE_BYTES, METHOD, MODERN_PROTOCOL_VERSIONS, SERVER_INSTRUCTIONS, SUPPORTED_PROTOCOL_VERSIONS, buildPrompts, buildResourceProvider, buildTools, classifyRequest, createLineReader, createMcpServer, createServer, createSession, createWriter, inspectModernMeta, negotiateLegacyVersion, runStdioServer, validateArguments } from './chunk-EWZYK3VX.js';
|
|
2
|
+
import './chunk-FCWD4LY7.js';
|
|
3
|
+
//# sourceMappingURL=mcp.js.map
|
|
4
|
+
//# sourceMappingURL=mcp.js.map
|
package/docs/agent.md
CHANGED
|
@@ -22,6 +22,26 @@ npx codebase-snapshot validate
|
|
|
22
22
|
The bare package name works; pin an exact version (`npx codebase-snapshot --version` prints the current one) when the same version must run on every
|
|
23
23
|
machine.
|
|
24
24
|
|
|
25
|
+
### One command instead of three
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
npx codebase-snapshot --autopilot
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Sets the project up — config, npm scripts, devDependency, `.gitignore`, install — and generates,
|
|
32
|
+
with no prompts. It keeps an existing config, and `--no-install` avoids touching the lockfile.
|
|
33
|
+
`setup` is the same operation as a command word.
|
|
34
|
+
|
|
35
|
+
### Do not rely on the bare command
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
npx codebase-snapshot # ❌ in an unconfigured project this exits 2
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
An agent has no terminal, so the guided first run cannot ask its question and refuses instead of
|
|
42
|
+
generating with settings nobody chose. That exit `2` is the tool being honest, not broken: say
|
|
43
|
+
which setup you want — `--autopilot`, `init --yes`, or `generate` on the documented defaults.
|
|
44
|
+
|
|
25
45
|
## The contract
|
|
26
46
|
|
|
27
47
|
`describe --format json` returns the whole tool as data on stdout:
|
|
@@ -93,6 +113,22 @@ added.
|
|
|
93
113
|
`codebase-snapshot init` does none of this: it writes the config, the npm scripts, the
|
|
94
114
|
devDependency and the `.gitignore` entries for the snapshot directory, and nothing else.
|
|
95
115
|
|
|
116
|
+
## When the client speaks MCP
|
|
117
|
+
|
|
118
|
+
`codebase-snapshot mcp` serves the repository to a Model Context Protocol client over stdio: seven
|
|
119
|
+
tools, `snapshot://` resources and two prompts. Prefer it over shelling out when the agent already
|
|
120
|
+
has an MCP connection, for two reasons that are properties of the design rather than of the wiring:
|
|
121
|
+
|
|
122
|
+
- **Reads come from the snapshot, not the working tree.** `snapshot_read` extracts a file's section
|
|
123
|
+
from the emitted part, so a file the snapshot excluded cannot be read back and a redacted value
|
|
124
|
+
stays redacted.
|
|
125
|
+
- **Staleness is a first-class question.** `snapshot_validate` answers "has the code moved since
|
|
126
|
+
this was built", which an agent with only a filesystem tool has no way to ask.
|
|
127
|
+
|
|
128
|
+
The tools are listed in [the MCP guide](mcp.md) and in the `mcp` block of
|
|
129
|
+
`describe --format json`. A `root` argument may name a sub-directory of the directory the server was
|
|
130
|
+
started for, and nothing outside it.
|
|
131
|
+
|
|
96
132
|
## Why both a contract and a skill
|
|
97
133
|
|
|
98
134
|
The contract is for **doing** — the data an agent needs to pick correct commands and options.
|
package/docs/cli.md
CHANGED
|
@@ -4,12 +4,53 @@
|
|
|
4
4
|
npx codebase-snapshot <command> [options]
|
|
5
5
|
```
|
|
6
6
|
|
|
7
|
-
The package installs one executable
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
`
|
|
7
|
+
The package installs one executable under two names: **`codebase-snapshot`** (canonical, and the
|
|
8
|
+
one to script against) and **`snapshot`** (the short command a global install puts on your
|
|
9
|
+
`PATH`). Both are the same file. From a project dependency use `npx codebase-snapshot` or
|
|
10
|
+
`npx snapshot` — both resolve the local copy first.
|
|
11
11
|
|
|
12
|
-
Running with no command is the
|
|
12
|
+
Running with no command is the guided first run: in a project with no configuration it asks
|
|
13
|
+
once, sets the project up and generates; in a configured project it is the same as `generate`.
|
|
14
|
+
Naming the command (`codebase-snapshot generate`) always means "do exactly this", on the
|
|
15
|
+
documented defaults. `--autopilot` sets the project up first without asking.
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
snapshot # global install: guided first run, then generate
|
|
19
|
+
npx codebase-snapshot # the same, from a project dependency
|
|
20
|
+
npx codebase-snapshot --autopilot # the same with no questions
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## The first run
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
snapshot # global install
|
|
27
|
+
npx codebase-snapshot # from a project dependency
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
In a project with no configuration the tool reports what it recognised **and what it keyed on**,
|
|
31
|
+
then asks one question:
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
codebase-snapshot
|
|
35
|
+
|
|
36
|
+
Detected nextjs
|
|
37
|
+
Because next.config.ts
|
|
38
|
+
Directory /Users/you/app
|
|
39
|
+
|
|
40
|
+
◆ How should I set this up?
|
|
41
|
+
❯ Use the recommended setup nextjs · config · npm scripts · install · generate
|
|
42
|
+
Go through each setting every question starts on its default
|
|
43
|
+
Pick a different preset everything else stays at the defaults
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
The first entry is the whole setup in one keystroke. The second walks through the settings, and
|
|
47
|
+
every prompt starts on its answer, so pressing `enter` through the lot is the recommended setup
|
|
48
|
+
spelled out. When nothing matched, the tool says so, names the manifests it looked for, and asks
|
|
49
|
+
which preset is closest — the one case where it needs an answer it cannot find itself.
|
|
50
|
+
|
|
51
|
+
A project that already has a config, or one this tool generated before, skips all of it and just
|
|
52
|
+
generates. `--autopilot` does the same work with no questions at all, and reports each decision
|
|
53
|
+
as it makes it.
|
|
13
54
|
|
|
14
55
|
## Contents
|
|
15
56
|
|
|
@@ -17,6 +58,7 @@ Running with no command is the same as `generate`.
|
|
|
17
58
|
- [`generate`](#generate)
|
|
18
59
|
- [`validate` / `check`](#validate--check)
|
|
19
60
|
- [`report`](#report)
|
|
61
|
+
- [`setup`](#setup)
|
|
20
62
|
- [`init`](#init)
|
|
21
63
|
- [`explain <path>`](#explain-path)
|
|
22
64
|
- [`diff <before> <after>`](#diff-before-after)
|
|
@@ -35,8 +77,15 @@ Running with no command is the same as `generate`.
|
|
|
35
77
|
codebase-snapshot generate [options]
|
|
36
78
|
```
|
|
37
79
|
|
|
38
|
-
Scans the repository and writes the snapshot to `outDir` (default `./snapshot`).
|
|
39
|
-
|
|
80
|
+
Scans the repository and writes the snapshot to `outDir` (default `./snapshot`).
|
|
81
|
+
|
|
82
|
+
Naming the command is the deterministic form: it runs on the documented defaults and writes nothing
|
|
83
|
+
but the snapshot. Without a command word an unconfigured project gets the
|
|
84
|
+
[guided first run](#the-first-run) first; `--autopilot` asks for that setup from an explicit
|
|
85
|
+
`generate` too, and never prompts.
|
|
86
|
+
|
|
87
|
+
A first run neither form can resolve — no config, no previous snapshot, no `--autopilot`, no
|
|
88
|
+
terminal — exits `2` and names the alternatives. It does not quietly generate on defaults.
|
|
40
89
|
|
|
41
90
|
Detection is automatic: a preset is chosen from the 25 in the
|
|
42
91
|
[preset table](configuration.md#project-presets), which supplies layers, kinds and ecosystem
|
|
@@ -107,7 +156,8 @@ is `validate`, which re-reads the repository and exits `1` on drift.
|
|
|
107
156
|
codebase-snapshot setup
|
|
108
157
|
```
|
|
109
158
|
|
|
110
|
-
The whole first run in one command, with defaults and no prompts
|
|
159
|
+
The whole first run in one command, with defaults and no prompts. This is the same implementation
|
|
160
|
+
`--autopilot` uses, spelled as a command word:
|
|
111
161
|
|
|
112
162
|
1. Detects the project preset.
|
|
113
163
|
2. Writes `snapshot.config.ts` (or `.mjs`) — **only when the repository has none**. An existing
|
|
@@ -124,7 +174,7 @@ The whole first run in one command, with defaults and no prompts:
|
|
|
124
174
|
🚀 Setup for: /path/to/repo
|
|
125
175
|
✅ Created snapshot.config.ts (preset: nextjs)
|
|
126
176
|
Added npm scripts: snapshot, snapshot:validate
|
|
127
|
-
Added devDependency: codebase-snapshot ^0.9.
|
|
177
|
+
Added devDependency: codebase-snapshot ^0.9.4
|
|
128
178
|
Added to .gitignore: snapshot/, snapshot.tmp/
|
|
129
179
|
⏳ Installing dependencies…
|
|
130
180
|
✅ Installed dependencies (npm install, 2.1s)
|
|
@@ -161,7 +211,7 @@ It also has three side effects on files you own, and it says so when it does the
|
|
|
161
211
|
```
|
|
162
212
|
✅ Created snapshot.config.ts (preset: node-lib)
|
|
163
213
|
Added npm scripts: snapshot, snapshot:validate
|
|
164
|
-
Added devDependency: codebase-snapshot ^0.9.
|
|
214
|
+
Added devDependency: codebase-snapshot ^0.9.4
|
|
165
215
|
Added to .gitignore: snapshot/, snapshot.tmp/
|
|
166
216
|
```
|
|
167
217
|
|
|
@@ -311,6 +361,25 @@ unchanged, plus the ignore entries it added.
|
|
|
311
361
|
|
|
312
362
|
Printing goes to **stdout** so it can be redirected: `codebase-snapshot skill > SKILL.md`.
|
|
313
363
|
|
|
364
|
+
### `mcp`
|
|
365
|
+
|
|
366
|
+
```bash
|
|
367
|
+
codebase-snapshot mcp # serve the current directory over stdio
|
|
368
|
+
codebase-snapshot mcp --cwd <path> # serve another repository
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
Serves the repository to a Model Context Protocol client over stdio: seven tools, `snapshot://`
|
|
372
|
+
resources and two prompts. Stdout carries JSON-RPC messages and nothing else; every note goes to
|
|
373
|
+
stderr. It speaks both protocol eras — the legacy `initialize` handshake and the stateless
|
|
374
|
+
`2026-07-28` revision — and answers whichever the client starts with.
|
|
375
|
+
|
|
376
|
+
`--cwd` is the only directory it will read. A tool's `root` argument can name a sub-directory of it
|
|
377
|
+
and nothing outside, symlinks included. It never installs packages and never writes a config file.
|
|
378
|
+
|
|
379
|
+
There is no `--format` here, because stdout *is* the protocol stream. The full tool list, resource
|
|
380
|
+
URIs and protocol versions appear in [the MCP server guide](mcp.md) and in
|
|
381
|
+
`describe --format json` under `mcp`.
|
|
382
|
+
|
|
314
383
|
## Options
|
|
315
384
|
|
|
316
385
|
An option a command does not accept is **rejected**, not ignored: exit `2` and a message
|
|
@@ -328,9 +397,11 @@ narrowest cases of the same rule.
|
|
|
328
397
|
| `--include-sensitive-files` | flag | off | generate, validate, report, explain, init | Emit `.env`, `*.pem`, `.npmrc` and similar. Off by default; they are reported as skipped. |
|
|
329
398
|
| `--skip-artifacts <names>` | list | unset | generate, validate, report, explain, init | Comma-separated artifacts to omit. |
|
|
330
399
|
| `--only-artifacts <names>` | list | unset | generate, validate, report, explain, init | Write only these. Cannot be combined with `--skip-artifacts`. |
|
|
331
|
-
| `--format <text\|json>` | enum | `text` | generate, validate, report, explain, init, diff, describe, skill | `json` writes a pure JSON payload to stdout. Every command honours it, and `describe` reports the same
|
|
332
|
-
| `--dry-run` | flag | off | generate, init | Compute everything, print it, write nothing. |
|
|
400
|
+
| `--format <text\|json>` | enum | `text` | generate, validate, report, explain, init, setup, diff, describe, skill | `json` writes a pure JSON payload to stdout. Every command honours it, and `describe` reports the same nine-command list. |
|
|
401
|
+
| `--dry-run` | flag | off | generate, init, setup | Compute everything, print it, write nothing. |
|
|
333
402
|
| `--watch` | flag | off | generate | Regenerate on every change until interrupted. |
|
|
403
|
+
| `--autopilot` | flag | off | generate | Set the project up without asking — config, `.gitignore`, npm scripts, devDependency, install — then generate. Never overwrites an existing config; refuses an empty directory (exit `1`); contradicts `--no-config` (exit `2`). |
|
|
404
|
+
| `--no-install` | flag | off | setup, generate `--autopilot` | Skip the dependency install. Anywhere else it is a usage error, because it would change nothing. |
|
|
334
405
|
| `--no-config` | flag | off | generate, validate, report, explain, diff | Ignore every `snapshot.config.*` file and run on the built-in defaults. `diff` never loads a config anyway and accepts the flag for consistency. |
|
|
335
406
|
| `--discovery <mode>` | enum | `auto` | generate, validate, explain | How files are found: `auto` lists through git when git works and refuses when a `.git` directory cannot be listed; `git` requires git; `walk` scans the tree and reads `.gitignore` files directly. The escape hatch for a broken `.git`. |
|
|
336
407
|
| `--preset <name>` | name | detected | *init only* | Force a preset instead of detecting one. |
|
|
@@ -341,7 +412,7 @@ narrowest cases of the same rule.
|
|
|
341
412
|
| `--install` | flag | off | *skill only* | Write the skill into the repository instead of printing it. |
|
|
342
413
|
| `--target <name>` | enum | `all` | *skill only* | `claude`, `cursor` or `all`. |
|
|
343
414
|
| `-h`, `--help` | flag | — | every command | Print usage. |
|
|
344
|
-
| `-v`, `--version` | flag | — | every command | Print the version on stdout: a bare `v`-prefixed semver
|
|
415
|
+
| `-v`, `--version` | flag | — | every command | Print the version on stdout: a bare `v`-prefixed semver (for example `v1.2.3`), with no package name. |
|
|
345
416
|
|
|
346
417
|
The artifact and size options apply to `validate`, `report` and `explain` as well as
|
|
347
418
|
`generate` because those commands re-read the snapshot: pass the selection you generated
|
|
@@ -373,7 +444,7 @@ reason to use it, and the positional form is the documented one.
|
|
|
373
444
|
| :--- | :--- |
|
|
374
445
|
| `0` | Success. For `validate`/`check`, no drift. |
|
|
375
446
|
| `1` | Drift detected, generation refused or failed (nothing was written), or the state the command needed was not there. |
|
|
376
|
-
| `2` | Usage error: unknown flag or command, an option the command does not accept, bad value, wrong argument count. |
|
|
447
|
+
| `2` | Usage error: unknown flag or command, an option the command does not accept, bad value, wrong argument count. Also a first run that needs an answer and has no terminal — run `--autopilot`, `init --yes`, or name the command. |
|
|
377
448
|
|
|
378
449
|
`1` covers the cases where the tool did the right thing but the state is not what you wanted
|
|
379
450
|
— drift, a refused output directory, an unparseable config. `2` means the command itself was
|