lockwire 0.1.32 → 0.1.34
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -0
- package/dist/actions.d.ts +11 -1
- package/dist/actions.d.ts.map +1 -1
- package/dist/actions.js +65 -9
- package/dist/actions.js.map +1 -1
- package/dist/blake3.d.ts +9 -0
- package/dist/blake3.d.ts.map +1 -0
- package/dist/blake3.js +128 -0
- package/dist/blake3.js.map +1 -0
- package/dist/cli.js +27 -3
- package/dist/cli.js.map +1 -1
- package/dist/compat.d.ts +21 -0
- package/dist/compat.d.ts.map +1 -0
- package/dist/compat.js +59 -0
- package/dist/compat.js.map +1 -0
- package/dist/format.d.ts +1 -1
- package/dist/format.d.ts.map +1 -1
- package/dist/format.js +6 -0
- package/dist/format.js.map +1 -1
- package/dist/hash.d.ts.map +1 -1
- package/dist/hash.js +2 -4
- package/dist/hash.js.map +1 -1
- package/dist/hook-claude.d.ts +6 -0
- package/dist/hook-claude.d.ts.map +1 -1
- package/dist/hook-claude.js +26 -0
- package/dist/hook-claude.js.map +1 -1
- package/dist/lockfile.d.ts +2 -0
- package/dist/lockfile.d.ts.map +1 -1
- package/dist/lockfile.js +13 -2
- package/dist/lockfile.js.map +1 -1
- package/dist/mcp-protocol.d.ts +118 -0
- package/dist/mcp-protocol.d.ts.map +1 -0
- package/dist/mcp-protocol.js +231 -0
- package/dist/mcp-protocol.js.map +1 -0
- package/dist/mcp-server.d.ts +1 -1
- package/dist/mcp-server.d.ts.map +1 -1
- package/dist/mcp-server.js +28 -23
- package/dist/mcp-server.js.map +1 -1
- package/dist/moves.d.ts +12 -4
- package/dist/moves.d.ts.map +1 -1
- package/dist/moves.js +80 -21
- package/dist/moves.js.map +1 -1
- package/dist/schema.d.ts +44 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +68 -0
- package/dist/schema.js.map +1 -0
- package/dist/tasks.d.ts.map +1 -1
- package/dist/tasks.js +5 -0
- package/dist/tasks.js.map +1 -1
- package/dist/types.d.ts +5 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +4 -5
package/dist/lockfile.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lockfile.d.ts","sourceRoot":"","sources":["../src/lockfile.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"lockfile.d.ts","sourceRoot":"","sources":["../src/lockfile.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAInD,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAErD;AAED,wBAAsB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,CAetE;AAED,gGAAgG;AAChG,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI,CAOlE;AAED,wBAAsB,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAMvF;AAED,wBAAgB,YAAY,CAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,GAAG,QAAQ,CAIzE;AAED,wBAAgB,YAAY,CAAC,QAAQ,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,GAAG,QAAQ,CAErE;AAED,wBAAgB,cAAc,CAAC,QAAQ,EAAE,QAAQ,EAAE,gBAAgB,EAAE,MAAM,GAAG,MAAM,EAAE,CAErF;AAID,wBAAgB,WAAW,IAAI,MAAM,CAIpC;AAED,+GAA+G;AAC/G,wBAAsB,eAAe,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAgBrF"}
|
package/dist/lockfile.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { existsSync } from "node:fs";
|
|
1
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
2
2
|
import { readFile, realpath, rename, rm, writeFile } from "node:fs/promises";
|
|
3
|
+
import { withLevel } from "./compat.js";
|
|
3
4
|
import { stripBom } from "./repo.js";
|
|
4
5
|
const LOCKFILE_NAME = "lockwire.lock";
|
|
5
6
|
export function lockfilePath(repoRoot) {
|
|
@@ -21,10 +22,20 @@ export async function readLockfile(repoRoot) {
|
|
|
21
22
|
}
|
|
22
23
|
return { version: 1, anchors: parsed.anchors ?? [] };
|
|
23
24
|
}
|
|
25
|
+
/** The lockfile's anchors read synchronously, or null when there's none or it can't be read. */
|
|
26
|
+
export function readLockfileSync(repoRoot) {
|
|
27
|
+
try {
|
|
28
|
+
const raw = stripBom(readFileSync(lockfilePath(repoRoot), "utf8"));
|
|
29
|
+
return { version: 1, anchors: JSON.parse(raw).anchors ?? [] };
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
24
35
|
export async function writeLockfile(repoRoot, lockfile) {
|
|
25
36
|
const sorted = {
|
|
26
37
|
version: 1,
|
|
27
|
-
anchors:
|
|
38
|
+
anchors: lockfile.anchors.map(withLevel).sort((a, b) => a.id.localeCompare(b.id)),
|
|
28
39
|
};
|
|
29
40
|
await writeFileAtomic(lockfilePath(repoRoot), `${JSON.stringify(sorted, null, 2)}\n`);
|
|
30
41
|
}
|
package/dist/lockfile.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lockfile.js","sourceRoot":"","sources":["../src/lockfile.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"lockfile.js","sourceRoot":"","sources":["../src/lockfile.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Model Context Protocol, as much of it as lockwire's server uses: JSON-RPC 2.0 over stdio, the
|
|
3
|
+
* `initialize` handshake, `ping`, and tools and prompts (list, call, get). lockwire implements this
|
|
4
|
+
* itself rather than depend on the MCP SDK, whose package also carries an HTTP stack, OAuth code and
|
|
5
|
+
* demo servers that a stdio-only server never loads but every install downloads and every scanner
|
|
6
|
+
* flags. The tests drive this server with the official SDK client, so it stays compatible with it.
|
|
7
|
+
*/
|
|
8
|
+
import { type Output, type Shape } from "./schema.js";
|
|
9
|
+
/** Protocol versions this server speaks, newest first. A client asking for another gets the newest. */
|
|
10
|
+
export declare const SUPPORTED_PROTOCOL_VERSIONS: readonly ["2025-11-25", "2025-06-18", "2025-03-26", "2024-11-05", "2024-10-07"];
|
|
11
|
+
type Id = string | number;
|
|
12
|
+
export interface JsonRpcMessage {
|
|
13
|
+
jsonrpc: "2.0";
|
|
14
|
+
id?: Id | null;
|
|
15
|
+
method?: string;
|
|
16
|
+
params?: Record<string, unknown>;
|
|
17
|
+
result?: unknown;
|
|
18
|
+
error?: {
|
|
19
|
+
code: number;
|
|
20
|
+
message: string;
|
|
21
|
+
data?: unknown;
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* A message channel, in the shape MCP transports share: the server sets the callbacks, then calls
|
|
26
|
+
* `start`. The SDK's own transports (its in-memory pair, used by the tests) fit it as they are.
|
|
27
|
+
*/
|
|
28
|
+
export interface Transport {
|
|
29
|
+
start(): Promise<void>;
|
|
30
|
+
send(message: JsonRpcMessage): Promise<void>;
|
|
31
|
+
close(): Promise<void>;
|
|
32
|
+
onmessage?: (message: JsonRpcMessage) => void;
|
|
33
|
+
onclose?: () => void;
|
|
34
|
+
onerror?: (error: Error) => void;
|
|
35
|
+
}
|
|
36
|
+
export declare const ErrorCode: {
|
|
37
|
+
readonly ParseError: -32700;
|
|
38
|
+
readonly InvalidRequest: -32600;
|
|
39
|
+
readonly MethodNotFound: -32601;
|
|
40
|
+
readonly InvalidParams: -32602;
|
|
41
|
+
readonly InternalError: -32603;
|
|
42
|
+
};
|
|
43
|
+
export interface ToolResult {
|
|
44
|
+
content: {
|
|
45
|
+
type: "text";
|
|
46
|
+
text: string;
|
|
47
|
+
}[];
|
|
48
|
+
isError?: boolean;
|
|
49
|
+
}
|
|
50
|
+
export interface ToolAnnotations {
|
|
51
|
+
readOnlyHint: boolean;
|
|
52
|
+
destructiveHint: boolean;
|
|
53
|
+
idempotentHint: boolean;
|
|
54
|
+
openWorldHint: boolean;
|
|
55
|
+
}
|
|
56
|
+
interface PromptResult {
|
|
57
|
+
description?: string;
|
|
58
|
+
messages: {
|
|
59
|
+
role: "user" | "assistant";
|
|
60
|
+
content: {
|
|
61
|
+
type: "text";
|
|
62
|
+
text: string;
|
|
63
|
+
};
|
|
64
|
+
}[];
|
|
65
|
+
}
|
|
66
|
+
export declare class McpServer {
|
|
67
|
+
private readonly info;
|
|
68
|
+
/** Told to the client at `initialize`, for its model to read; computed then, so it's current. */
|
|
69
|
+
private readonly instructions?;
|
|
70
|
+
private readonly tools;
|
|
71
|
+
private readonly prompts;
|
|
72
|
+
private transport;
|
|
73
|
+
private clientInfo;
|
|
74
|
+
constructor(info: {
|
|
75
|
+
name: string;
|
|
76
|
+
version: string;
|
|
77
|
+
},
|
|
78
|
+
/** Told to the client at `initialize`, for its model to read; computed then, so it's current. */
|
|
79
|
+
instructions?: (() => string | undefined) | undefined);
|
|
80
|
+
/** The client's own name and version, from its `initialize` request. */
|
|
81
|
+
getClientVersion(): {
|
|
82
|
+
name?: string;
|
|
83
|
+
version?: string;
|
|
84
|
+
} | undefined;
|
|
85
|
+
registerTool<S extends Shape>(name: string, def: {
|
|
86
|
+
title: string;
|
|
87
|
+
description: string;
|
|
88
|
+
inputSchema: S;
|
|
89
|
+
annotations: ToolAnnotations;
|
|
90
|
+
}, handler: (args: Output<S>) => Promise<ToolResult> | ToolResult): void;
|
|
91
|
+
registerPrompt<S extends Shape>(name: string, def: {
|
|
92
|
+
title: string;
|
|
93
|
+
description: string;
|
|
94
|
+
argsSchema: S;
|
|
95
|
+
}, handler: (args: Output<S>) => Promise<PromptResult> | PromptResult): void;
|
|
96
|
+
connect(transport: Transport): Promise<void>;
|
|
97
|
+
close(): Promise<void>;
|
|
98
|
+
private receive;
|
|
99
|
+
private handle;
|
|
100
|
+
/** A tool's failures are results the model can read and act on, not protocol errors. */
|
|
101
|
+
private callTool;
|
|
102
|
+
}
|
|
103
|
+
/** Newline-delimited JSON-RPC on stdin and stdout, as MCP's stdio transport specifies. */
|
|
104
|
+
export declare class StdioServerTransport implements Transport {
|
|
105
|
+
private readonly input;
|
|
106
|
+
private readonly output;
|
|
107
|
+
onmessage?: (message: JsonRpcMessage) => void;
|
|
108
|
+
onclose?: () => void;
|
|
109
|
+
onerror?: (error: Error) => void;
|
|
110
|
+
private buffer;
|
|
111
|
+
constructor(input?: NodeJS.ReadableStream, output?: NodeJS.WritableStream);
|
|
112
|
+
start(): Promise<void>;
|
|
113
|
+
private line;
|
|
114
|
+
send(message: JsonRpcMessage): Promise<void>;
|
|
115
|
+
close(): Promise<void>;
|
|
116
|
+
}
|
|
117
|
+
export {};
|
|
118
|
+
//# sourceMappingURL=mcp-protocol.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-protocol.d.ts","sourceRoot":"","sources":["../src/mcp-protocol.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Model Context Protocol, as much of it as lockwire's server uses: JSON-RPC 2.0 over stdio, the
|
|
3
|
+
* `initialize` handshake, `ping`, and tools and prompts (list, call, get). lockwire implements this
|
|
4
|
+
* itself rather than depend on the MCP SDK, whose package also carries an HTTP stack, OAuth code and
|
|
5
|
+
* demo servers that a stdio-only server never loads but every install downloads and every scanner
|
|
6
|
+
* flags. The tests drive this server with the official SDK client, so it stays compatible with it.
|
|
7
|
+
*/
|
|
8
|
+
import { objectJson, parseObject } from "./schema.js";
|
|
9
|
+
/** Protocol versions this server speaks, newest first. A client asking for another gets the newest. */
|
|
10
|
+
export const SUPPORTED_PROTOCOL_VERSIONS = [
|
|
11
|
+
"2025-11-25",
|
|
12
|
+
"2025-06-18",
|
|
13
|
+
"2025-03-26",
|
|
14
|
+
"2024-11-05",
|
|
15
|
+
"2024-10-07",
|
|
16
|
+
];
|
|
17
|
+
export const ErrorCode = {
|
|
18
|
+
ParseError: -32700,
|
|
19
|
+
InvalidRequest: -32600,
|
|
20
|
+
MethodNotFound: -32601,
|
|
21
|
+
InvalidParams: -32602,
|
|
22
|
+
InternalError: -32603,
|
|
23
|
+
};
|
|
24
|
+
class RpcError extends Error {
|
|
25
|
+
code;
|
|
26
|
+
constructor(code, message) {
|
|
27
|
+
super(message);
|
|
28
|
+
this.code = code;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
export class McpServer {
|
|
32
|
+
info;
|
|
33
|
+
instructions;
|
|
34
|
+
tools = new Map();
|
|
35
|
+
prompts = new Map();
|
|
36
|
+
transport;
|
|
37
|
+
clientInfo;
|
|
38
|
+
constructor(info,
|
|
39
|
+
/** Told to the client at `initialize`, for its model to read; computed then, so it's current. */
|
|
40
|
+
instructions) {
|
|
41
|
+
this.info = info;
|
|
42
|
+
this.instructions = instructions;
|
|
43
|
+
}
|
|
44
|
+
/** The client's own name and version, from its `initialize` request. */
|
|
45
|
+
getClientVersion() {
|
|
46
|
+
return this.clientInfo;
|
|
47
|
+
}
|
|
48
|
+
registerTool(name, def, handler) {
|
|
49
|
+
this.tools.set(name, {
|
|
50
|
+
title: def.title,
|
|
51
|
+
description: def.description,
|
|
52
|
+
input: def.inputSchema,
|
|
53
|
+
annotations: def.annotations,
|
|
54
|
+
handler,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
registerPrompt(name, def, handler) {
|
|
58
|
+
this.prompts.set(name, {
|
|
59
|
+
title: def.title,
|
|
60
|
+
description: def.description,
|
|
61
|
+
args: def.argsSchema,
|
|
62
|
+
handler,
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
async connect(transport) {
|
|
66
|
+
this.transport = transport;
|
|
67
|
+
transport.onmessage = (message) => {
|
|
68
|
+
void this.receive(message);
|
|
69
|
+
};
|
|
70
|
+
await transport.start();
|
|
71
|
+
}
|
|
72
|
+
async close() {
|
|
73
|
+
await this.transport?.close();
|
|
74
|
+
}
|
|
75
|
+
async receive(message) {
|
|
76
|
+
// A response to a request (this server sends none) or a notification needs no answer.
|
|
77
|
+
if (message.method === undefined || message.id === undefined || message.id === null)
|
|
78
|
+
return;
|
|
79
|
+
const id = message.id;
|
|
80
|
+
try {
|
|
81
|
+
const result = await this.handle(message.method, message.params ?? {});
|
|
82
|
+
await this.transport?.send({ jsonrpc: "2.0", id, result });
|
|
83
|
+
}
|
|
84
|
+
catch (err) {
|
|
85
|
+
const code = err instanceof RpcError ? err.code : ErrorCode.InternalError;
|
|
86
|
+
const text = err instanceof Error ? err.message : String(err);
|
|
87
|
+
await this.transport?.send({ jsonrpc: "2.0", id, error: { code, message: text } });
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
async handle(method, params) {
|
|
91
|
+
switch (method) {
|
|
92
|
+
case "initialize": {
|
|
93
|
+
const asked = params.protocolVersion;
|
|
94
|
+
const info = params.clientInfo;
|
|
95
|
+
if (info && typeof info === "object")
|
|
96
|
+
this.clientInfo = info;
|
|
97
|
+
let instructions;
|
|
98
|
+
try {
|
|
99
|
+
instructions = this.instructions?.();
|
|
100
|
+
}
|
|
101
|
+
catch {
|
|
102
|
+
// instructions are a courtesy: never fail the handshake over them
|
|
103
|
+
}
|
|
104
|
+
return {
|
|
105
|
+
...(instructions ? { instructions } : {}),
|
|
106
|
+
protocolVersion: SUPPORTED_PROTOCOL_VERSIONS.find((v) => v === asked)
|
|
107
|
+
? asked
|
|
108
|
+
: SUPPORTED_PROTOCOL_VERSIONS[0],
|
|
109
|
+
capabilities: { tools: { listChanged: false }, prompts: { listChanged: false } },
|
|
110
|
+
serverInfo: this.info,
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
case "ping":
|
|
114
|
+
return {};
|
|
115
|
+
case "tools/list":
|
|
116
|
+
return {
|
|
117
|
+
tools: [...this.tools].map(([name, t]) => ({
|
|
118
|
+
name,
|
|
119
|
+
title: t.title,
|
|
120
|
+
description: t.description,
|
|
121
|
+
inputSchema: objectJson(t.input),
|
|
122
|
+
annotations: t.annotations,
|
|
123
|
+
})),
|
|
124
|
+
};
|
|
125
|
+
case "tools/call":
|
|
126
|
+
return this.callTool(params);
|
|
127
|
+
case "prompts/list":
|
|
128
|
+
return {
|
|
129
|
+
prompts: [...this.prompts].map(([name, p]) => ({
|
|
130
|
+
name,
|
|
131
|
+
title: p.title,
|
|
132
|
+
description: p.description,
|
|
133
|
+
arguments: Object.entries(p.args).map(([arg, field]) => ({
|
|
134
|
+
name: arg,
|
|
135
|
+
required: field.required,
|
|
136
|
+
})),
|
|
137
|
+
})),
|
|
138
|
+
};
|
|
139
|
+
case "prompts/get": {
|
|
140
|
+
const name = String(params.name);
|
|
141
|
+
const prompt = this.prompts.get(name);
|
|
142
|
+
if (!prompt)
|
|
143
|
+
throw new RpcError(ErrorCode.InvalidParams, `Prompt ${name} not found`);
|
|
144
|
+
const parsed = parseObject(prompt.args, params.arguments ?? {});
|
|
145
|
+
if ("problem" in parsed)
|
|
146
|
+
throw new RpcError(ErrorCode.InvalidParams, `Invalid arguments for prompt ${name}: ${parsed.problem}`);
|
|
147
|
+
return prompt.handler(parsed.value);
|
|
148
|
+
}
|
|
149
|
+
default:
|
|
150
|
+
throw new RpcError(ErrorCode.MethodNotFound, `Method not found: ${method}`);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
/** A tool's failures are results the model can read and act on, not protocol errors. */
|
|
154
|
+
async callTool(params) {
|
|
155
|
+
const failed = (text) => ({
|
|
156
|
+
content: [{ type: "text", text }],
|
|
157
|
+
isError: true,
|
|
158
|
+
});
|
|
159
|
+
const name = String(params.name);
|
|
160
|
+
const tool = this.tools.get(name);
|
|
161
|
+
if (!tool)
|
|
162
|
+
return failed(`Tool ${name} not found`);
|
|
163
|
+
const parsed = parseObject(tool.input, params.arguments ?? {});
|
|
164
|
+
if ("problem" in parsed)
|
|
165
|
+
return failed(`Invalid arguments for tool ${name}: ${parsed.problem}`);
|
|
166
|
+
try {
|
|
167
|
+
return await tool.handler(parsed.value);
|
|
168
|
+
}
|
|
169
|
+
catch (err) {
|
|
170
|
+
return failed(err instanceof Error ? err.message : String(err));
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
/** Newline-delimited JSON-RPC on stdin and stdout, as MCP's stdio transport specifies. */
|
|
175
|
+
export class StdioServerTransport {
|
|
176
|
+
input;
|
|
177
|
+
output;
|
|
178
|
+
onmessage;
|
|
179
|
+
onclose;
|
|
180
|
+
onerror;
|
|
181
|
+
buffer = "";
|
|
182
|
+
constructor(input = process.stdin, output = process.stdout) {
|
|
183
|
+
this.input = input;
|
|
184
|
+
this.output = output;
|
|
185
|
+
}
|
|
186
|
+
async start() {
|
|
187
|
+
this.input.setEncoding("utf8");
|
|
188
|
+
this.input.on("data", (chunk) => {
|
|
189
|
+
this.buffer += chunk;
|
|
190
|
+
for (let nl = this.buffer.indexOf("\n"); nl >= 0; nl = this.buffer.indexOf("\n")) {
|
|
191
|
+
const line = this.buffer.slice(0, nl).replace(/\r$/, "");
|
|
192
|
+
this.buffer = this.buffer.slice(nl + 1);
|
|
193
|
+
if (line.trim())
|
|
194
|
+
this.line(line);
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
this.input.on("end", () => this.onclose?.());
|
|
198
|
+
this.input.on("error", (err) => this.onerror?.(err));
|
|
199
|
+
}
|
|
200
|
+
line(line) {
|
|
201
|
+
let message;
|
|
202
|
+
try {
|
|
203
|
+
message = JSON.parse(line);
|
|
204
|
+
}
|
|
205
|
+
catch {
|
|
206
|
+
void this.send({
|
|
207
|
+
jsonrpc: "2.0",
|
|
208
|
+
id: null,
|
|
209
|
+
error: { code: ErrorCode.ParseError, message: "Parse error" },
|
|
210
|
+
});
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
// Batches went out of the protocol in 2025-06-18; an older client's batch is still answered.
|
|
214
|
+
for (const m of Array.isArray(message) ? message : [message])
|
|
215
|
+
if (m && typeof m === "object" && m.jsonrpc === "2.0")
|
|
216
|
+
this.onmessage?.(m);
|
|
217
|
+
}
|
|
218
|
+
send(message) {
|
|
219
|
+
return new Promise((resolve) => {
|
|
220
|
+
if (this.output.write(`${JSON.stringify(message)}\n`))
|
|
221
|
+
resolve();
|
|
222
|
+
else
|
|
223
|
+
this.output.once("drain", () => resolve());
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
async close() {
|
|
227
|
+
this.input.removeAllListeners("data");
|
|
228
|
+
this.onclose?.();
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
//# sourceMappingURL=mcp-protocol.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-protocol.js","sourceRoot":"","sources":["../src/mcp-protocol.ts"],"names":[],"mappings":"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"}
|
package/dist/mcp-server.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
1
|
import type { IndexStats } from "./docindex.js";
|
|
2
|
+
import { McpServer } from "./mcp-protocol.js";
|
|
3
3
|
/** Builds the configured server without connecting a transport -- split out from startMcpServer so tests can drive it over an in-memory transport instead of real stdio. */
|
|
4
4
|
export declare function createServer(repoRoot: string, opts?: {
|
|
5
5
|
onIndexStats?: (stats: IndexStats) => void;
|
package/dist/mcp-server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp-server.d.ts","sourceRoot":"","sources":["../src/mcp-server.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"mcp-server.d.ts","sourceRoot":"","sources":["../src/mcp-server.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAGhD,OAAO,EAAE,SAAS,EAAwB,MAAM,mBAAmB,CAAC;AAsBpE,4KAA4K;AAC5K,wBAAgB,YAAY,CAC1B,QAAQ,EAAE,MAAM,EAChB,IAAI,GAAE;IAAE,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAA;CAAO,GACxD,SAAS,CAgWX;AAED,wBAAsB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAIpE"}
|
package/dist/mcp-server.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { existsSync } from "node:fs";
|
|
2
|
-
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
|
-
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
4
|
-
import { z } from "zod";
|
|
5
2
|
import { ack, check, history, linkDoc, refs, repoint, status, unlinkedFor, waive, } from "./actions.js";
|
|
6
3
|
import { changedFiles } from "./changed.js";
|
|
4
|
+
import { newerWriterNotice } from "./compat.js";
|
|
7
5
|
import { readConfig } from "./config.js";
|
|
8
6
|
import { withRepoLock } from "./lock.js";
|
|
9
|
-
import { lockfilePath } from "./lockfile.js";
|
|
7
|
+
import { lockfilePath, readLockfileSync } from "./lockfile.js";
|
|
8
|
+
import { McpServer, StdioServerTransport } from "./mcp-protocol.js";
|
|
10
9
|
import { toRepoPath } from "./repo.js";
|
|
10
|
+
import { s } from "./schema.js";
|
|
11
11
|
import { fixDocsPrompt, listTasks, resolveTask, taskContext } from "./tasks.js";
|
|
12
12
|
function text(payload) {
|
|
13
13
|
return {
|
|
@@ -27,13 +27,18 @@ function missingLockNote(repoRoot) {
|
|
|
27
27
|
}
|
|
28
28
|
/** Builds the configured server without connecting a transport -- split out from startMcpServer so tests can drive it over an in-memory transport instead of real stdio. */
|
|
29
29
|
export function createServer(repoRoot, opts = {}) {
|
|
30
|
-
|
|
30
|
+
// An older lockwire than the one that stamped some claims says so up front, so the model can
|
|
31
|
+
// suggest updating instead of trusting results for claims it can't check.
|
|
32
|
+
const server = new McpServer({ name: "lockwire", version: "0.1.0" }, () => {
|
|
33
|
+
const lock = readLockfileSync(repoRoot);
|
|
34
|
+
return lock ? (newerWriterNotice(lock, "agent") ?? undefined) : undefined;
|
|
35
|
+
});
|
|
31
36
|
// The server outlives many calls, so it keeps the doc index in memory: the first `claims_for`
|
|
32
37
|
// builds (or loads) it, later ones only re-validate it. Nothing is written to disk.
|
|
33
38
|
const indexSession = {};
|
|
34
39
|
/** Who is acting: the MCP client's own name (claude-code, codex, cursor…) when it gave one. */
|
|
35
40
|
const agentActor = () => {
|
|
36
|
-
const client = server.
|
|
41
|
+
const client = server.getClientVersion();
|
|
37
42
|
return {
|
|
38
43
|
type: "ai",
|
|
39
44
|
tool: client?.name
|
|
@@ -47,7 +52,7 @@ export function createServer(repoRoot, opts = {}) {
|
|
|
47
52
|
server.registerTool("lockwire_claims_for", {
|
|
48
53
|
title: "Claims for code",
|
|
49
54
|
description: "What does the documentation assert about this file or symbol? Call before editing. Returns `anchors` (claims lockwire is checking) and `unlinked` (claims written in a doc about this code that nobody has linked yet, so nothing is checking them — treat them as real claims too).",
|
|
50
|
-
inputSchema: { path:
|
|
55
|
+
inputSchema: { path: s.string(), symbol: s.string().optional() },
|
|
51
56
|
// Pure read (the lockfile and the docs; the doc index is held in memory, never written to disk) --
|
|
52
57
|
// repeat calls are trivially idempotent.
|
|
53
58
|
annotations: {
|
|
@@ -69,7 +74,7 @@ export function createServer(repoRoot, opts = {}) {
|
|
|
69
74
|
server.registerTool("lockwire_refs", {
|
|
70
75
|
title: "Reverse lookup",
|
|
71
76
|
description: "Which documentation claims reference this file or symbol.",
|
|
72
|
-
inputSchema: { path:
|
|
77
|
+
inputSchema: { path: s.string(), symbol: s.string().optional() },
|
|
73
78
|
annotations: {
|
|
74
79
|
readOnlyHint: true,
|
|
75
80
|
destructiveHint: false,
|
|
@@ -81,7 +86,7 @@ export function createServer(repoRoot, opts = {}) {
|
|
|
81
86
|
server.registerTool("lockwire_status", {
|
|
82
87
|
title: "Anchor status",
|
|
83
88
|
description: "Current status of every anchor, optionally filtered by a glob scope.",
|
|
84
|
-
inputSchema: { scope:
|
|
89
|
+
inputSchema: { scope: s.string().optional() },
|
|
85
90
|
annotations: {
|
|
86
91
|
readOnlyHint: true,
|
|
87
92
|
destructiveHint: false,
|
|
@@ -92,7 +97,7 @@ export function createServer(repoRoot, opts = {}) {
|
|
|
92
97
|
server.registerTool("lockwire_verify", {
|
|
93
98
|
title: "Verify a doc",
|
|
94
99
|
description: "Check one document's anchors before committing it.",
|
|
95
|
-
inputSchema: { doc:
|
|
100
|
+
inputSchema: { doc: s.string() },
|
|
96
101
|
// Not read-only: check() writes the lockfile and appends ledger events on state
|
|
97
102
|
// transitions. It IS idempotent -- every transition is guarded by the anchor's current
|
|
98
103
|
// status (e.g. `if (anchor.status !== "drifted")`), so a repeat call with nothing else
|
|
@@ -120,7 +125,7 @@ export function createServer(repoRoot, opts = {}) {
|
|
|
120
125
|
server.registerTool("lockwire_history", {
|
|
121
126
|
title: "Anchor history",
|
|
122
127
|
description: "Ledger timeline for an anchor id, a path#symbol, or a doc path — how many times has this claim broken, and how was it resolved.",
|
|
123
|
-
inputSchema: { ref:
|
|
128
|
+
inputSchema: { ref: s.string() },
|
|
124
129
|
annotations: {
|
|
125
130
|
readOnlyHint: true,
|
|
126
131
|
destructiveHint: false,
|
|
@@ -131,7 +136,7 @@ export function createServer(repoRoot, opts = {}) {
|
|
|
131
136
|
server.registerTool("lockwire_link", {
|
|
132
137
|
title: "Create or refresh an anchor",
|
|
133
138
|
description: "Scan a doc for lockwire markers and stamp fresh fingerprints.",
|
|
134
|
-
inputSchema: { doc:
|
|
139
|
+
inputSchema: { doc: s.string(), reviewed: s.boolean().optional() },
|
|
135
140
|
// A second call with nothing changed in between stamps nothing and appends no ledger event.
|
|
136
141
|
annotations: {
|
|
137
142
|
readOnlyHint: false,
|
|
@@ -144,9 +149,9 @@ export function createServer(repoRoot, opts = {}) {
|
|
|
144
149
|
title: "Acknowledge drift",
|
|
145
150
|
description: "Record that drift was handled and re-stamp the anchor's fingerprints.",
|
|
146
151
|
inputSchema: {
|
|
147
|
-
anchor:
|
|
148
|
-
resolution:
|
|
149
|
-
note:
|
|
152
|
+
anchor: s.string(),
|
|
153
|
+
resolution: s.enum(["updated", "superseded", "false-positive"]),
|
|
154
|
+
note: s.string().optional(),
|
|
150
155
|
},
|
|
151
156
|
// ack() unconditionally appends an anchor.acknowledged event every call, same reasoning
|
|
152
157
|
// as lockwire_link -- each ack is a distinct logged action, so repeat calls are not a
|
|
@@ -161,7 +166,7 @@ export function createServer(repoRoot, opts = {}) {
|
|
|
161
166
|
server.registerTool("lockwire_waive", {
|
|
162
167
|
title: "Waive an anchor",
|
|
163
168
|
description: "Time-boxed, logged, expiring waiver. No permanent suppression.",
|
|
164
|
-
inputSchema: { anchor:
|
|
169
|
+
inputSchema: { anchor: s.string(), reason: s.string(), expires: s.string() },
|
|
165
170
|
// waive() unconditionally appends a waiver.granted event every call -- same reasoning as
|
|
166
171
|
// lockwire_link and lockwire_ack.
|
|
167
172
|
annotations: {
|
|
@@ -175,9 +180,9 @@ export function createServer(repoRoot, opts = {}) {
|
|
|
175
180
|
title: "Re-point moved claims",
|
|
176
181
|
description: "After moving code to another file: point every claim whose symbol moved there, unchanged, at its new path#symbol and rewrite its doc marker. `anchors` limits it to those ids; `to` (with one id) names the new home when lockwire found the code in several places or it changed on the way. A bound tier that differs at the new place stays drifted. `dryRun` reports what would change without writing.",
|
|
177
182
|
inputSchema: {
|
|
178
|
-
anchors:
|
|
179
|
-
to:
|
|
180
|
-
dryRun:
|
|
183
|
+
anchors: s.array(s.string()).optional(),
|
|
184
|
+
to: s.string().optional(),
|
|
185
|
+
dryRun: s.boolean().optional(),
|
|
181
186
|
},
|
|
182
187
|
// Re-pointing an anchor that already points at its new home skips it, so a repeat call with
|
|
183
188
|
// nothing moved in between writes nothing.
|
|
@@ -209,7 +214,7 @@ export function createServer(repoRoot, opts = {}) {
|
|
|
209
214
|
server.registerTool("lockwire_tasks", {
|
|
210
215
|
title: "Documentation tasks",
|
|
211
216
|
description: "Every documentation claim that needs attention, as a task list: claims whose code or value changed, numbers that no longer match their source, claims whose target is gone, and markers nobody has linked. Each task says what is wrong and what to do. Start here when asked to fix or update documentation. `paths` limits it to claims about (or in) those files; `changed` to files this branch touched.",
|
|
212
|
-
inputSchema: { paths:
|
|
217
|
+
inputSchema: { paths: s.array(s.string()).optional(), changed: s.boolean().optional() },
|
|
213
218
|
// A dry run of check: computes everything, writes nothing.
|
|
214
219
|
annotations: {
|
|
215
220
|
readOnlyHint: true,
|
|
@@ -229,7 +234,7 @@ export function createServer(repoRoot, opts = {}) {
|
|
|
229
234
|
server.registerTool("lockwire_task_context", {
|
|
230
235
|
title: "Context for a task",
|
|
231
236
|
description: "Everything needed to fix one task from lockwire_tasks: the whole claim sentence, the bound code (its declaration) or value as it was when the claim was stamped and as it is now, and the claim's history. `stamped.exact` says whether the stamped side is exactly what the claim was checked against.",
|
|
232
|
-
inputSchema: { id:
|
|
237
|
+
inputSchema: { id: s.string() },
|
|
233
238
|
annotations: {
|
|
234
239
|
readOnlyHint: true,
|
|
235
240
|
destructiveHint: false,
|
|
@@ -240,7 +245,7 @@ export function createServer(repoRoot, opts = {}) {
|
|
|
240
245
|
server.registerTool("lockwire_resolve", {
|
|
241
246
|
title: "Resolve a task",
|
|
242
247
|
description: "After you have edited the doc so the claim is true, re-stamp that one claim (nothing else in the doc). It is checked first: a sentence whose number still disagrees with its value is refused, as is a marker whose target still doesn't exist. Pass a short `note` saying what you checked or changed; it goes into the claim's history. Returns resolved / already-fresh / refused (with the reason) and the tasks still open on the same doc.",
|
|
243
|
-
inputSchema: { id:
|
|
248
|
+
inputSchema: { id: s.string(), note: s.string().optional() },
|
|
244
249
|
// Writes the lockfile and ledger. Resolving an already-fresh claim is a no-op, so it is idempotent.
|
|
245
250
|
annotations: {
|
|
246
251
|
readOnlyHint: false,
|
|
@@ -252,7 +257,7 @@ export function createServer(repoRoot, opts = {}) {
|
|
|
252
257
|
server.registerPrompt("fix-docs", {
|
|
253
258
|
title: "Fix documentation drift",
|
|
254
259
|
description: "Work through lockwire's task list: fix every documentation claim that no longer matches the code or data it describes, and check each fix.",
|
|
255
|
-
argsSchema: { scope:
|
|
260
|
+
argsSchema: { scope: s.string().optional() },
|
|
256
261
|
}, ({ scope }) => ({
|
|
257
262
|
messages: [
|
|
258
263
|
{
|