@stablekernel/opencode-cursor 0.7.1 → 0.9.0-next.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.
- package/CHANGELOG.md +60 -0
- package/README.md +110 -11
- package/dist/{chunk-RDY3H2LE.js → chunk-YIEC27VB.js} +436 -12
- package/dist/chunk-YIEC27VB.js.map +1 -0
- package/dist/plugin/index.js +934 -34
- package/dist/plugin/index.js.map +1 -1
- package/dist/provider/index.js +264 -32
- package/dist/provider/index.js.map +1 -1
- package/dist/sidecar/plugin-tools-mcp.d.ts +189 -0
- package/dist/sidecar/plugin-tools-mcp.js +163 -0
- package/dist/sidecar/plugin-tools-mcp.js.map +1 -0
- package/package.json +7 -7
- package/dist/chunk-RDY3H2LE.js.map +0 -1
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import { createInterface } from 'node:readline';
|
|
2
|
+
import { fileURLToPath } from 'node:url';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* stdio MCP server that exposes opencode plugins' custom tools to the Cursor
|
|
6
|
+
* agent. Spawned by the plugin with `OPENCODE_PLUGIN_TOOLS_TOKEN` in env; it
|
|
7
|
+
* talks to the host plugin over a localhost HTTP control channel (also
|
|
8
|
+
* token-authenticated) that owns the real tool closures.
|
|
9
|
+
*
|
|
10
|
+
* Wire protocol (control channel):
|
|
11
|
+
* GET /tools → { tools: [{id, description, parameters}] }
|
|
12
|
+
* POST /call {id, args} → { ok, title?, output?, error? }
|
|
13
|
+
*
|
|
14
|
+
* Every `tools/call` from Cursor becomes one POST /call; the host executes
|
|
15
|
+
* the mirrored tool with a permission-gated ToolContext and returns the
|
|
16
|
+
* result. Plain JSON-lines stdio MCP on the other side (see run()).
|
|
17
|
+
*
|
|
18
|
+
* Kept as plain .mjs so tests can spawn it pre-build; tsup bundles it to
|
|
19
|
+
* dist/sidecar/plugin-tools-mcp.js for production.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
const CONTROL_PORT = Number(process.env.OPENCODE_PLUGIN_TOOLS_PORT ?? 0);
|
|
23
|
+
const TOKEN = process.env.OPENCODE_PLUGIN_TOOLS_TOKEN ?? "";
|
|
24
|
+
const SERVER_NAME = "opencode-plugin-tools";
|
|
25
|
+
const SERVER_VERSION = "1.0.0";
|
|
26
|
+
// The single protocol version this server implements. Never echo the
|
|
27
|
+
// client-proposed version — MCP servers must answer with a version they
|
|
28
|
+
// actually support.
|
|
29
|
+
const PROTOCOL_VERSION = "2025-06-18";
|
|
30
|
+
|
|
31
|
+
function logErr(message, extra) {
|
|
32
|
+
try {
|
|
33
|
+
process.stderr.write(
|
|
34
|
+
`[plugin-tools-mcp] ${message}${extra ? ` ${JSON.stringify(extra)}` : ""}\n`,
|
|
35
|
+
);
|
|
36
|
+
} catch {
|
|
37
|
+
// never throw from logging
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
async function controlRequest(path, body, timeoutMs) {
|
|
42
|
+
const res = await fetch(`http://127.0.0.1:${CONTROL_PORT}${path}`, {
|
|
43
|
+
method: body ? "POST" : "GET",
|
|
44
|
+
headers: {
|
|
45
|
+
"content-type": "application/json",
|
|
46
|
+
authorization: `Bearer ${TOKEN}`,
|
|
47
|
+
},
|
|
48
|
+
body: body ? JSON.stringify(body) : undefined,
|
|
49
|
+
// A stale/hung port must not hang Cursor's MCP discovery (tools/list) or
|
|
50
|
+
// block a tool call forever. Loopback list is instant; calls get a
|
|
51
|
+
// generous ceiling because plugin tools can legitimately run for minutes.
|
|
52
|
+
signal: AbortSignal.timeout(timeoutMs),
|
|
53
|
+
});
|
|
54
|
+
const text = await res.text();
|
|
55
|
+
let json;
|
|
56
|
+
try {
|
|
57
|
+
json = JSON.parse(text);
|
|
58
|
+
} catch {
|
|
59
|
+
json = undefined;
|
|
60
|
+
}
|
|
61
|
+
if (!res.ok) {
|
|
62
|
+
const message = json?.error ?? `control channel ${res.status}`;
|
|
63
|
+
throw new Error(message);
|
|
64
|
+
}
|
|
65
|
+
return json;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
async function listTools() {
|
|
69
|
+
try {
|
|
70
|
+
const data = await controlRequest("/tools", undefined, 5_000);
|
|
71
|
+
return data?.tools ?? [];
|
|
72
|
+
} catch (err) {
|
|
73
|
+
logErr("tools/list failed", { error: String(err) });
|
|
74
|
+
return [];
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
async function callTool(name, args) {
|
|
79
|
+
try {
|
|
80
|
+
const data = await controlRequest(
|
|
81
|
+
"/call",
|
|
82
|
+
{ id: name, args: args ?? {} },
|
|
83
|
+
300_000,
|
|
84
|
+
);
|
|
85
|
+
if (data?.ok === false) {
|
|
86
|
+
return {
|
|
87
|
+
isError: true,
|
|
88
|
+
content: [{ type: "text", text: data.error ?? "tool call failed" }],
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
const output = data?.output ?? "";
|
|
92
|
+
const title = data?.title ? `${data.title}\n\n` : "";
|
|
93
|
+
return { content: [{ type: "text", text: `${title}${output}` }] };
|
|
94
|
+
} catch (err) {
|
|
95
|
+
return { isError: true, content: [{ type: "text", text: String(err) }] };
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/** Handle one MCP request and return the response payload (or undefined for notifications). */
|
|
100
|
+
async function handle(msg) {
|
|
101
|
+
const { id, method, params } = msg;
|
|
102
|
+
const reply = (result) => ({ jsonrpc: "2.0", id, result });
|
|
103
|
+
const error = (code, message) => ({
|
|
104
|
+
jsonrpc: "2.0",
|
|
105
|
+
id,
|
|
106
|
+
error: { code, message },
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
switch (method) {
|
|
110
|
+
case "initialize":
|
|
111
|
+
return reply({
|
|
112
|
+
protocolVersion: PROTOCOL_VERSION,
|
|
113
|
+
capabilities: { tools: { listChanged: false } },
|
|
114
|
+
serverInfo: { name: SERVER_NAME, version: SERVER_VERSION },
|
|
115
|
+
instructions:
|
|
116
|
+
"Tools provided by opencode plugins, bridged into the Cursor agent. " +
|
|
117
|
+
"Each call runs the plugin's real implementation inside opencode's runtime.",
|
|
118
|
+
});
|
|
119
|
+
case "notifications/initialized":
|
|
120
|
+
return undefined;
|
|
121
|
+
case "ping":
|
|
122
|
+
return reply({});
|
|
123
|
+
case "tools/list": {
|
|
124
|
+
const tools = await listTools();
|
|
125
|
+
return reply({
|
|
126
|
+
tools: tools.map((t) => ({
|
|
127
|
+
name: t.id,
|
|
128
|
+
description: t.description,
|
|
129
|
+
inputSchema: t.parameters ?? { type: "object", properties: {} },
|
|
130
|
+
})),
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
case "tools/call": {
|
|
134
|
+
const result = await callTool(params?.name, params?.arguments);
|
|
135
|
+
return reply(result);
|
|
136
|
+
}
|
|
137
|
+
default:
|
|
138
|
+
if (id === undefined) return undefined; // unknown notification
|
|
139
|
+
return error(-32601, `method not found: ${method}`);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function run() {
|
|
144
|
+
if (!CONTROL_PORT || !TOKEN) {
|
|
145
|
+
logErr("missing OPENCODE_PLUGIN_TOOLS_PORT/TOKEN env; exiting");
|
|
146
|
+
process.exit(1);
|
|
147
|
+
}
|
|
148
|
+
const rl = createInterface({ input: process.stdin, terminal: false });
|
|
149
|
+
rl.on("line", async (line) => {
|
|
150
|
+
const trimmed = line.trim();
|
|
151
|
+
if (!trimmed) return;
|
|
152
|
+
let msg;
|
|
153
|
+
try {
|
|
154
|
+
msg = JSON.parse(trimmed);
|
|
155
|
+
} catch {
|
|
156
|
+
process.stdout.write(
|
|
157
|
+
JSON.stringify({
|
|
158
|
+
jsonrpc: "2.0",
|
|
159
|
+
id: null,
|
|
160
|
+
error: { code: -32700, message: "parse error" },
|
|
161
|
+
}) + "\n",
|
|
162
|
+
);
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
try {
|
|
166
|
+
const response = await handle(msg);
|
|
167
|
+
if (response !== undefined) {
|
|
168
|
+
process.stdout.write(JSON.stringify(response) + "\n");
|
|
169
|
+
}
|
|
170
|
+
} catch (err) {
|
|
171
|
+
if (msg.id !== undefined) {
|
|
172
|
+
process.stdout.write(
|
|
173
|
+
JSON.stringify({
|
|
174
|
+
jsonrpc: "2.0",
|
|
175
|
+
id: msg.id,
|
|
176
|
+
error: { code: -32603, message: String(err) },
|
|
177
|
+
}) + "\n",
|
|
178
|
+
);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
rl.on("close", () => process.exit(0));
|
|
183
|
+
// Keep the process alive until stdin closes (Cursor owns the lifecycle).
|
|
184
|
+
process.stdin.resume();
|
|
185
|
+
}
|
|
186
|
+
const scriptFile = fileURLToPath(import.meta.url);
|
|
187
|
+
if (process.argv[1] === scriptFile) run();
|
|
188
|
+
|
|
189
|
+
export { callTool, handle, listTools };
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
// src/sidecar/plugin-tools-mcp.mjs
|
|
2
|
+
import { createInterface } from "readline";
|
|
3
|
+
import { fileURLToPath } from "url";
|
|
4
|
+
var CONTROL_PORT = Number(process.env.OPENCODE_PLUGIN_TOOLS_PORT ?? 0);
|
|
5
|
+
var TOKEN = process.env.OPENCODE_PLUGIN_TOOLS_TOKEN ?? "";
|
|
6
|
+
var SERVER_NAME = "opencode-plugin-tools";
|
|
7
|
+
var SERVER_VERSION = "1.0.0";
|
|
8
|
+
var PROTOCOL_VERSION = "2025-06-18";
|
|
9
|
+
function logErr(message, extra) {
|
|
10
|
+
try {
|
|
11
|
+
process.stderr.write(
|
|
12
|
+
`[plugin-tools-mcp] ${message}${extra ? ` ${JSON.stringify(extra)}` : ""}
|
|
13
|
+
`
|
|
14
|
+
);
|
|
15
|
+
} catch {
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
async function controlRequest(path, body, timeoutMs) {
|
|
19
|
+
const res = await fetch(`http://127.0.0.1:${CONTROL_PORT}${path}`, {
|
|
20
|
+
method: body ? "POST" : "GET",
|
|
21
|
+
headers: {
|
|
22
|
+
"content-type": "application/json",
|
|
23
|
+
authorization: `Bearer ${TOKEN}`
|
|
24
|
+
},
|
|
25
|
+
body: body ? JSON.stringify(body) : void 0,
|
|
26
|
+
// A stale/hung port must not hang Cursor's MCP discovery (tools/list) or
|
|
27
|
+
// block a tool call forever. Loopback list is instant; calls get a
|
|
28
|
+
// generous ceiling because plugin tools can legitimately run for minutes.
|
|
29
|
+
signal: AbortSignal.timeout(timeoutMs)
|
|
30
|
+
});
|
|
31
|
+
const text = await res.text();
|
|
32
|
+
let json;
|
|
33
|
+
try {
|
|
34
|
+
json = JSON.parse(text);
|
|
35
|
+
} catch {
|
|
36
|
+
json = void 0;
|
|
37
|
+
}
|
|
38
|
+
if (!res.ok) {
|
|
39
|
+
const message = json?.error ?? `control channel ${res.status}`;
|
|
40
|
+
throw new Error(message);
|
|
41
|
+
}
|
|
42
|
+
return json;
|
|
43
|
+
}
|
|
44
|
+
async function listTools() {
|
|
45
|
+
try {
|
|
46
|
+
const data = await controlRequest("/tools", void 0, 5e3);
|
|
47
|
+
return data?.tools ?? [];
|
|
48
|
+
} catch (err) {
|
|
49
|
+
logErr("tools/list failed", { error: String(err) });
|
|
50
|
+
return [];
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
async function callTool(name, args) {
|
|
54
|
+
try {
|
|
55
|
+
const data = await controlRequest(
|
|
56
|
+
"/call",
|
|
57
|
+
{ id: name, args: args ?? {} },
|
|
58
|
+
3e5
|
|
59
|
+
);
|
|
60
|
+
if (data?.ok === false) {
|
|
61
|
+
return {
|
|
62
|
+
isError: true,
|
|
63
|
+
content: [{ type: "text", text: data.error ?? "tool call failed" }]
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
const output = data?.output ?? "";
|
|
67
|
+
const title = data?.title ? `${data.title}
|
|
68
|
+
|
|
69
|
+
` : "";
|
|
70
|
+
return { content: [{ type: "text", text: `${title}${output}` }] };
|
|
71
|
+
} catch (err) {
|
|
72
|
+
return { isError: true, content: [{ type: "text", text: String(err) }] };
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
async function handle(msg) {
|
|
76
|
+
const { id, method, params } = msg;
|
|
77
|
+
const reply = (result) => ({ jsonrpc: "2.0", id, result });
|
|
78
|
+
const error = (code, message) => ({
|
|
79
|
+
jsonrpc: "2.0",
|
|
80
|
+
id,
|
|
81
|
+
error: { code, message }
|
|
82
|
+
});
|
|
83
|
+
switch (method) {
|
|
84
|
+
case "initialize":
|
|
85
|
+
return reply({
|
|
86
|
+
protocolVersion: PROTOCOL_VERSION,
|
|
87
|
+
capabilities: { tools: { listChanged: false } },
|
|
88
|
+
serverInfo: { name: SERVER_NAME, version: SERVER_VERSION },
|
|
89
|
+
instructions: "Tools provided by opencode plugins, bridged into the Cursor agent. Each call runs the plugin's real implementation inside opencode's runtime."
|
|
90
|
+
});
|
|
91
|
+
case "notifications/initialized":
|
|
92
|
+
return void 0;
|
|
93
|
+
case "ping":
|
|
94
|
+
return reply({});
|
|
95
|
+
case "tools/list": {
|
|
96
|
+
const tools = await listTools();
|
|
97
|
+
return reply({
|
|
98
|
+
tools: tools.map((t) => ({
|
|
99
|
+
name: t.id,
|
|
100
|
+
description: t.description,
|
|
101
|
+
inputSchema: t.parameters ?? { type: "object", properties: {} }
|
|
102
|
+
}))
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
case "tools/call": {
|
|
106
|
+
const result = await callTool(params?.name, params?.arguments);
|
|
107
|
+
return reply(result);
|
|
108
|
+
}
|
|
109
|
+
default:
|
|
110
|
+
if (id === void 0) return void 0;
|
|
111
|
+
return error(-32601, `method not found: ${method}`);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
function run() {
|
|
115
|
+
if (!CONTROL_PORT || !TOKEN) {
|
|
116
|
+
logErr("missing OPENCODE_PLUGIN_TOOLS_PORT/TOKEN env; exiting");
|
|
117
|
+
process.exit(1);
|
|
118
|
+
}
|
|
119
|
+
const rl = createInterface({ input: process.stdin, terminal: false });
|
|
120
|
+
rl.on("line", async (line) => {
|
|
121
|
+
const trimmed = line.trim();
|
|
122
|
+
if (!trimmed) return;
|
|
123
|
+
let msg;
|
|
124
|
+
try {
|
|
125
|
+
msg = JSON.parse(trimmed);
|
|
126
|
+
} catch {
|
|
127
|
+
process.stdout.write(
|
|
128
|
+
JSON.stringify({
|
|
129
|
+
jsonrpc: "2.0",
|
|
130
|
+
id: null,
|
|
131
|
+
error: { code: -32700, message: "parse error" }
|
|
132
|
+
}) + "\n"
|
|
133
|
+
);
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
try {
|
|
137
|
+
const response = await handle(msg);
|
|
138
|
+
if (response !== void 0) {
|
|
139
|
+
process.stdout.write(JSON.stringify(response) + "\n");
|
|
140
|
+
}
|
|
141
|
+
} catch (err) {
|
|
142
|
+
if (msg.id !== void 0) {
|
|
143
|
+
process.stdout.write(
|
|
144
|
+
JSON.stringify({
|
|
145
|
+
jsonrpc: "2.0",
|
|
146
|
+
id: msg.id,
|
|
147
|
+
error: { code: -32603, message: String(err) }
|
|
148
|
+
}) + "\n"
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
rl.on("close", () => process.exit(0));
|
|
154
|
+
process.stdin.resume();
|
|
155
|
+
}
|
|
156
|
+
var scriptFile = fileURLToPath(import.meta.url);
|
|
157
|
+
if (process.argv[1] === scriptFile) run();
|
|
158
|
+
export {
|
|
159
|
+
callTool,
|
|
160
|
+
handle,
|
|
161
|
+
listTools
|
|
162
|
+
};
|
|
163
|
+
//# sourceMappingURL=plugin-tools-mcp.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/sidecar/plugin-tools-mcp.mjs"],"sourcesContent":["/**\n * stdio MCP server that exposes opencode plugins' custom tools to the Cursor\n * agent. Spawned by the plugin with `OPENCODE_PLUGIN_TOOLS_TOKEN` in env; it\n * talks to the host plugin over a localhost HTTP control channel (also\n * token-authenticated) that owns the real tool closures.\n *\n * Wire protocol (control channel):\n * GET /tools → { tools: [{id, description, parameters}] }\n * POST /call {id, args} → { ok, title?, output?, error? }\n *\n * Every `tools/call` from Cursor becomes one POST /call; the host executes\n * the mirrored tool with a permission-gated ToolContext and returns the\n * result. Plain JSON-lines stdio MCP on the other side (see run()).\n *\n * Kept as plain .mjs so tests can spawn it pre-build; tsup bundles it to\n * dist/sidecar/plugin-tools-mcp.js for production.\n */\nimport { createInterface } from \"node:readline\";\n\nconst CONTROL_PORT = Number(process.env.OPENCODE_PLUGIN_TOOLS_PORT ?? 0);\nconst TOKEN = process.env.OPENCODE_PLUGIN_TOOLS_TOKEN ?? \"\";\nconst SERVER_NAME = \"opencode-plugin-tools\";\nconst SERVER_VERSION = \"1.0.0\";\n// The single protocol version this server implements. Never echo the\n// client-proposed version — MCP servers must answer with a version they\n// actually support.\nconst PROTOCOL_VERSION = \"2025-06-18\";\n\nfunction logErr(message, extra) {\n try {\n process.stderr.write(\n `[plugin-tools-mcp] ${message}${extra ? ` ${JSON.stringify(extra)}` : \"\"}\\n`,\n );\n } catch {\n // never throw from logging\n }\n}\n\nasync function controlRequest(path, body, timeoutMs) {\n const res = await fetch(`http://127.0.0.1:${CONTROL_PORT}${path}`, {\n method: body ? \"POST\" : \"GET\",\n headers: {\n \"content-type\": \"application/json\",\n authorization: `Bearer ${TOKEN}`,\n },\n body: body ? JSON.stringify(body) : undefined,\n // A stale/hung port must not hang Cursor's MCP discovery (tools/list) or\n // block a tool call forever. Loopback list is instant; calls get a\n // generous ceiling because plugin tools can legitimately run for minutes.\n signal: AbortSignal.timeout(timeoutMs),\n });\n const text = await res.text();\n let json;\n try {\n json = JSON.parse(text);\n } catch {\n json = undefined;\n }\n if (!res.ok) {\n const message = json?.error ?? `control channel ${res.status}`;\n throw new Error(message);\n }\n return json;\n}\n\nasync function listTools() {\n try {\n const data = await controlRequest(\"/tools\", undefined, 5_000);\n return data?.tools ?? [];\n } catch (err) {\n logErr(\"tools/list failed\", { error: String(err) });\n return [];\n }\n}\n\nasync function callTool(name, args) {\n try {\n const data = await controlRequest(\n \"/call\",\n { id: name, args: args ?? {} },\n 300_000,\n );\n if (data?.ok === false) {\n return {\n isError: true,\n content: [{ type: \"text\", text: data.error ?? \"tool call failed\" }],\n };\n }\n const output = data?.output ?? \"\";\n const title = data?.title ? `${data.title}\\n\\n` : \"\";\n return { content: [{ type: \"text\", text: `${title}${output}` }] };\n } catch (err) {\n return { isError: true, content: [{ type: \"text\", text: String(err) }] };\n }\n}\n\n/** Handle one MCP request and return the response payload (or undefined for notifications). */\nasync function handle(msg) {\n const { id, method, params } = msg;\n const reply = (result) => ({ jsonrpc: \"2.0\", id, result });\n const error = (code, message) => ({\n jsonrpc: \"2.0\",\n id,\n error: { code, message },\n });\n\n switch (method) {\n case \"initialize\":\n return reply({\n protocolVersion: PROTOCOL_VERSION,\n capabilities: { tools: { listChanged: false } },\n serverInfo: { name: SERVER_NAME, version: SERVER_VERSION },\n instructions:\n \"Tools provided by opencode plugins, bridged into the Cursor agent. \" +\n \"Each call runs the plugin's real implementation inside opencode's runtime.\",\n });\n case \"notifications/initialized\":\n return undefined;\n case \"ping\":\n return reply({});\n case \"tools/list\": {\n const tools = await listTools();\n return reply({\n tools: tools.map((t) => ({\n name: t.id,\n description: t.description,\n inputSchema: t.parameters ?? { type: \"object\", properties: {} },\n })),\n });\n }\n case \"tools/call\": {\n const result = await callTool(params?.name, params?.arguments);\n return reply(result);\n }\n default:\n if (id === undefined) return undefined; // unknown notification\n return error(-32601, `method not found: ${method}`);\n }\n}\n\nfunction run() {\n if (!CONTROL_PORT || !TOKEN) {\n logErr(\"missing OPENCODE_PLUGIN_TOOLS_PORT/TOKEN env; exiting\");\n process.exit(1);\n }\n const rl = createInterface({ input: process.stdin, terminal: false });\n rl.on(\"line\", async (line) => {\n const trimmed = line.trim();\n if (!trimmed) return;\n let msg;\n try {\n msg = JSON.parse(trimmed);\n } catch {\n process.stdout.write(\n JSON.stringify({\n jsonrpc: \"2.0\",\n id: null,\n error: { code: -32700, message: \"parse error\" },\n }) + \"\\n\",\n );\n return;\n }\n try {\n const response = await handle(msg);\n if (response !== undefined) {\n process.stdout.write(JSON.stringify(response) + \"\\n\");\n }\n } catch (err) {\n if (msg.id !== undefined) {\n process.stdout.write(\n JSON.stringify({\n jsonrpc: \"2.0\",\n id: msg.id,\n error: { code: -32603, message: String(err) },\n }) + \"\\n\",\n );\n }\n }\n });\n rl.on(\"close\", () => process.exit(0));\n // Keep the process alive until stdin closes (Cursor owns the lifecycle).\n process.stdin.resume();\n}\n\n// Start the stdio loop only when spawned as the entry script (Cursor owns\n// the lifecycle). Tests import the handlers above without triggering it.\nimport { fileURLToPath } from \"node:url\";\nconst scriptFile = fileURLToPath(import.meta.url);\nif (process.argv[1] === scriptFile) run();\n\nexport { handle, listTools, callTool };\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stablekernel/opencode-cursor",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0-next.0",
|
|
4
4
|
"description": "opencode provider plugin backed by the official Cursor SDK (@cursor/sdk) — adds a Cursor provider and lists its models",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -59,11 +59,11 @@
|
|
|
59
59
|
"dependencies": {
|
|
60
60
|
"@connectrpc/connect-node": "^2.1.2",
|
|
61
61
|
"@cursor/sdk": "^1.0.24",
|
|
62
|
-
"@opencode-ai/plugin": "^1.18.
|
|
62
|
+
"@opencode-ai/plugin": "^1.18.21",
|
|
63
63
|
"semver": "^7.8.4"
|
|
64
64
|
},
|
|
65
65
|
"overrides": {
|
|
66
|
-
"undici": "^6.
|
|
66
|
+
"undici": "^6.28.0",
|
|
67
67
|
"tar": "^7.5.11",
|
|
68
68
|
"node-gyp": "^12.4.0",
|
|
69
69
|
"esbuild": "^0.28.1"
|
|
@@ -72,10 +72,10 @@
|
|
|
72
72
|
"@ai-sdk/provider": "^3.0.0"
|
|
73
73
|
},
|
|
74
74
|
"devDependencies": {
|
|
75
|
-
"@ai-sdk/provider": "^3.0.
|
|
76
|
-
"@opencode-ai/sdk": "^1.18.
|
|
77
|
-
"@types/node": "^26.
|
|
78
|
-
"@types/semver": "^7.
|
|
75
|
+
"@ai-sdk/provider": "^3.0.15",
|
|
76
|
+
"@opencode-ai/sdk": "^1.18.21",
|
|
77
|
+
"@types/node": "^26.2.0",
|
|
78
|
+
"@types/semver": "^7.8.0",
|
|
79
79
|
"tsup": "^8.5.1",
|
|
80
80
|
"typescript": "^6.0.3",
|
|
81
81
|
"vitest": "^4.1.8"
|