@vantaloom/runtime-win32-x64 0.10.11 → 0.11.1
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/VERSION +1 -1
- package/bin/vantaloom-agent.exe +0 -0
- package/bin/vantaloom-api.exe +0 -0
- package/bin/vantaloom-browser.exe +0 -0
- package/bin/vantaloomctl.exe +0 -0
- package/cli/adapters/claude-sdk-bridge/index.mjs +454 -0
- package/cli/adapters/claude-sdk-bridge/package.json +17 -0
- package/cli/package.json +2 -1
- package/cli/src/cli.mjs +47 -456
- package/manifest.json +2 -2
- package/package.json +1 -1
- package/web/404.html +1 -1
- package/web/__next.__PAGE__.txt +2 -2
- package/web/__next._full.txt +20 -18
- package/web/__next._head.txt +1 -1
- package/web/__next._index.txt +8 -6
- package/web/__next._tree.txt +2 -2
- package/web/_next/static/chunks/365fd0af80ece230.js +52 -0
- package/web/_next/static/chunks/4852e34afa6e1a19.js +1 -0
- package/web/_next/static/chunks/750370220a00a0ed.js +1 -0
- package/web/_next/static/chunks/c45d4f98e2235102.css +2 -0
- package/web/_not-found/__next._full.txt +16 -14
- package/web/_not-found/__next._head.txt +3 -3
- package/web/_not-found/__next._index.txt +8 -6
- package/web/_not-found/__next._not-found/__PAGE__.txt +2 -2
- package/web/_not-found/__next._not-found.txt +3 -3
- package/web/_not-found/__next._tree.txt +2 -2
- package/web/_not-found.html +1 -1
- package/web/_not-found.txt +16 -14
- package/web/index.html +1 -1
- package/web/index.txt +20 -18
- package/web/_next/static/chunks/2f05240e9e23a8f9.js +0 -1
- package/web/_next/static/chunks/32465f0c99c890c8.css +0 -2
- package/web/_next/static/chunks/54432276d2af80d0.js +0 -52
- package/web/_next/static/chunks/83c973dd6794ff6b.js +0 -1
- /package/web/_next/static/{IRzQpsBb3w0QZKmP52ZBv → 0-LGbsF0Rq-AxpdHYl3F6}/_buildManifest.js +0 -0
- /package/web/_next/static/{IRzQpsBb3w0QZKmP52ZBv → 0-LGbsF0Rq-AxpdHYl3F6}/_clientMiddlewareManifest.json +0 -0
- /package/web/_next/static/{IRzQpsBb3w0QZKmP52ZBv → 0-LGbsF0Rq-AxpdHYl3F6}/_ssgManifest.js +0 -0
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
902c03d
|
package/bin/vantaloom-agent.exe
CHANGED
|
Binary file
|
package/bin/vantaloom-api.exe
CHANGED
|
Binary file
|
|
Binary file
|
package/bin/vantaloomctl.exe
CHANGED
|
Binary file
|
|
@@ -0,0 +1,454 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Vantaloom Claude SDK bridge.
|
|
3
|
+
//
|
|
4
|
+
// A thin, long-lived Node sidecar (one process per conversation) that runs the
|
|
5
|
+
// official @anthropic-ai/claude-agent-sdk `query()` and pipes its NATIVE
|
|
6
|
+
// stream-json to the Go runtime over stdio NDJSON. This replaces the lossy
|
|
7
|
+
// generic ACP adapter: every SDKMessage is forwarded verbatim so the Go mapper
|
|
8
|
+
// gets full fidelity (real token usage, tool_use{id,name,input}, tool_result,
|
|
9
|
+
// parent_tool_use_id subagent links, partial streaming) instead of guessing.
|
|
10
|
+
//
|
|
11
|
+
// Protocol (one JSON object per line):
|
|
12
|
+
//
|
|
13
|
+
// Go → bridge (stdin):
|
|
14
|
+
// {"t":"init", cwd, claudeExecutable?, appendSystemPrompt?, mode?, model?, resume?, settingSources?}
|
|
15
|
+
// {"t":"prompt", runId, text, images?:[{mime,data}]}
|
|
16
|
+
// {"t":"permission_response", id, behavior:"allow"|"deny", updatedInput?, message?, interrupt?}
|
|
17
|
+
// {"t":"interrupt"}
|
|
18
|
+
// {"t":"set_model", model}
|
|
19
|
+
// {"t":"set_mode", mode}
|
|
20
|
+
// {"t":"shutdown"}
|
|
21
|
+
//
|
|
22
|
+
// bridge → Go (stdout):
|
|
23
|
+
// {"t":"ready", sdkVersion}
|
|
24
|
+
// {"t":"sdk", msg} // verbatim SDKMessage
|
|
25
|
+
// {"t":"permission_request", id, toolName, input, toolUseId}
|
|
26
|
+
// {"t":"session", sessionId} // captured from system/init
|
|
27
|
+
// {"t":"result", runId, subtype, usage?, sessionId?}
|
|
28
|
+
// {"t":"error", runId?, message}
|
|
29
|
+
// {"t":"log", level, message}
|
|
30
|
+
//
|
|
31
|
+
// stdout carries ONLY protocol JSON; all diagnostics go to stderr (and are
|
|
32
|
+
// surfaced as {"t":"log"} from the SDK's stderr callback).
|
|
33
|
+
|
|
34
|
+
import { spawn } from "node:child_process";
|
|
35
|
+
import process from "node:process";
|
|
36
|
+
import readline from "node:readline";
|
|
37
|
+
import { readFileSync } from "node:fs";
|
|
38
|
+
import path from "node:path";
|
|
39
|
+
import { fileURLToPath } from "node:url";
|
|
40
|
+
|
|
41
|
+
const bridgeDir = path.dirname(fileURLToPath(import.meta.url));
|
|
42
|
+
|
|
43
|
+
let query;
|
|
44
|
+
let sdkVersion = "unknown";
|
|
45
|
+
try {
|
|
46
|
+
({ query } = await import("@anthropic-ai/claude-agent-sdk"));
|
|
47
|
+
try {
|
|
48
|
+
// The SDK's package.json isn't exposed via "exports", so read it directly from
|
|
49
|
+
// the node_modules tree we bundle next to this bridge (best-effort).
|
|
50
|
+
const pkgPath = path.join(
|
|
51
|
+
bridgeDir,
|
|
52
|
+
"node_modules",
|
|
53
|
+
"@anthropic-ai",
|
|
54
|
+
"claude-agent-sdk",
|
|
55
|
+
"package.json",
|
|
56
|
+
);
|
|
57
|
+
sdkVersion = JSON.parse(readFileSync(pkgPath, "utf8")).version || "unknown";
|
|
58
|
+
} catch {
|
|
59
|
+
/* version is best-effort */
|
|
60
|
+
}
|
|
61
|
+
} catch (err) {
|
|
62
|
+
// The SDK is missing — emit a fatal error the Go side can surface, then exit.
|
|
63
|
+
process.stdout.write(
|
|
64
|
+
JSON.stringify({
|
|
65
|
+
t: "error",
|
|
66
|
+
message:
|
|
67
|
+
"无法加载 @anthropic-ai/claude-agent-sdk:" +
|
|
68
|
+
(err && err.message ? err.message : String(err)) +
|
|
69
|
+
"(请随运行时安装 SDK 桥,或检查 adapters/claude-sdk-bridge/node_modules)",
|
|
70
|
+
}) + "\n",
|
|
71
|
+
);
|
|
72
|
+
process.exit(1);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// ---- stdout framing -------------------------------------------------------
|
|
76
|
+
|
|
77
|
+
function send(obj) {
|
|
78
|
+
process.stdout.write(JSON.stringify(obj) + "\n");
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function logLine(level, message) {
|
|
82
|
+
send({ t: "log", level, message: String(message) });
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// ---- async input queue feeding query()'s prompt iterable ------------------
|
|
86
|
+
//
|
|
87
|
+
// query() consumes an AsyncIterable<SDKUserMessage>. We back it with a queue so
|
|
88
|
+
// each `prompt` control message pushes one user turn into the live session.
|
|
89
|
+
|
|
90
|
+
function createInputQueue() {
|
|
91
|
+
/** @type {any[]} */
|
|
92
|
+
const buffered = [];
|
|
93
|
+
/** @type {null | ((r: {value: any, done: boolean}) => void)} */
|
|
94
|
+
let waiting = null;
|
|
95
|
+
let closed = false;
|
|
96
|
+
|
|
97
|
+
return {
|
|
98
|
+
push(msg) {
|
|
99
|
+
if (waiting) {
|
|
100
|
+
const resolve = waiting;
|
|
101
|
+
waiting = null;
|
|
102
|
+
resolve({ value: msg, done: false });
|
|
103
|
+
} else {
|
|
104
|
+
buffered.push(msg);
|
|
105
|
+
}
|
|
106
|
+
},
|
|
107
|
+
close() {
|
|
108
|
+
closed = true;
|
|
109
|
+
if (waiting) {
|
|
110
|
+
const resolve = waiting;
|
|
111
|
+
waiting = null;
|
|
112
|
+
resolve({ value: undefined, done: true });
|
|
113
|
+
}
|
|
114
|
+
},
|
|
115
|
+
iterable: {
|
|
116
|
+
[Symbol.asyncIterator]() {
|
|
117
|
+
return {
|
|
118
|
+
next() {
|
|
119
|
+
if (buffered.length > 0) {
|
|
120
|
+
return Promise.resolve({ value: buffered.shift(), done: false });
|
|
121
|
+
}
|
|
122
|
+
if (closed) {
|
|
123
|
+
return Promise.resolve({ value: undefined, done: true });
|
|
124
|
+
}
|
|
125
|
+
return new Promise((resolve) => {
|
|
126
|
+
waiting = resolve;
|
|
127
|
+
});
|
|
128
|
+
},
|
|
129
|
+
};
|
|
130
|
+
},
|
|
131
|
+
},
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// ---- Windows-aware process spawn (mirrors paseo's spawnClaudeCodeProcess) --
|
|
136
|
+
//
|
|
137
|
+
// The SDK lets us own the child spawn. On Windows the default routing through
|
|
138
|
+
// cmd.exe can mangle args; we spawn explicitly with windowsHide and pick shell
|
|
139
|
+
// only for .cmd/.bat shims (which CreateProcess cannot launch directly). We
|
|
140
|
+
// pass no inline-JSON args (no --mcp-config), so shell:true for .cmd is safe.
|
|
141
|
+
|
|
142
|
+
function makeSpawnClaude(stderrSink) {
|
|
143
|
+
return function spawnClaudeCodeProcess(spawnOptions) {
|
|
144
|
+
let command = spawnOptions.command;
|
|
145
|
+
let args = [...spawnOptions.args];
|
|
146
|
+
// The SDK may ask for a generic JS runtime; use the node actually running us.
|
|
147
|
+
if (command === "node" || command === "bun") {
|
|
148
|
+
command = process.execPath;
|
|
149
|
+
}
|
|
150
|
+
const lower = command.toLowerCase();
|
|
151
|
+
const isWindows = process.platform === "win32";
|
|
152
|
+
const isCmdShim = isWindows && (lower.endsWith(".cmd") || lower.endsWith(".bat"));
|
|
153
|
+
const child = spawn(command, args, {
|
|
154
|
+
cwd: spawnOptions.cwd,
|
|
155
|
+
env: spawnOptions.env,
|
|
156
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
157
|
+
windowsHide: true,
|
|
158
|
+
shell: isCmdShim,
|
|
159
|
+
});
|
|
160
|
+
if (child.stderr) {
|
|
161
|
+
child.stderr.on("data", (chunk) => {
|
|
162
|
+
try {
|
|
163
|
+
stderrSink(chunk.toString());
|
|
164
|
+
} catch {
|
|
165
|
+
/* ignore */
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
return child;
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// ---- bridge session state -------------------------------------------------
|
|
174
|
+
|
|
175
|
+
const state = {
|
|
176
|
+
/** @type {ReturnType<typeof createInputQueue> | null} */
|
|
177
|
+
input: null,
|
|
178
|
+
/** @type {any} */
|
|
179
|
+
query: null,
|
|
180
|
+
cwd: process.cwd(),
|
|
181
|
+
claudeExecutable: undefined,
|
|
182
|
+
appendSystemPrompt: "",
|
|
183
|
+
mode: "default",
|
|
184
|
+
model: undefined,
|
|
185
|
+
resume: undefined,
|
|
186
|
+
settingSources: ["user", "project", "local"],
|
|
187
|
+
sessionId: "",
|
|
188
|
+
currentRunId: "",
|
|
189
|
+
started: false,
|
|
190
|
+
/** @type {Map<string, (result: any) => void>} pending canUseTool resolvers */
|
|
191
|
+
pendingPermissions: new Map(),
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
let permissionSeq = 0;
|
|
195
|
+
|
|
196
|
+
// canUseTool: emit a permission_request and await the matching response. The
|
|
197
|
+
// run ctx (user STOP) aborts via the provided AbortSignal.
|
|
198
|
+
function canUseTool(toolName, input, options) {
|
|
199
|
+
const id = "perm-" + ++permissionSeq;
|
|
200
|
+
const toolUseId = (options && options.toolUseID) || "";
|
|
201
|
+
return new Promise((resolve) => {
|
|
202
|
+
let settled = false;
|
|
203
|
+
const finish = (result) => {
|
|
204
|
+
if (settled) return;
|
|
205
|
+
settled = true;
|
|
206
|
+
state.pendingPermissions.delete(id);
|
|
207
|
+
resolve(result);
|
|
208
|
+
};
|
|
209
|
+
state.pendingPermissions.set(id, finish);
|
|
210
|
+
if (options && options.signal) {
|
|
211
|
+
if (options.signal.aborted) {
|
|
212
|
+
finish({ behavior: "deny", message: "用户已停止", interrupt: true });
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
options.signal.addEventListener(
|
|
216
|
+
"abort",
|
|
217
|
+
() => finish({ behavior: "deny", message: "用户已停止", interrupt: true }),
|
|
218
|
+
{ once: true },
|
|
219
|
+
);
|
|
220
|
+
}
|
|
221
|
+
send({ t: "permission_request", id, toolName, input: input ?? {}, toolUseId });
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
function extractSessionId(msg) {
|
|
226
|
+
if (!msg || typeof msg !== "object") return "";
|
|
227
|
+
if (typeof msg.session_id === "string") return msg.session_id;
|
|
228
|
+
if (typeof msg.sessionId === "string") return msg.sessionId;
|
|
229
|
+
if (msg.session && typeof msg.session.id === "string") return msg.session.id;
|
|
230
|
+
return "";
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// Build query() and start draining its async generator. Runs once per session.
|
|
234
|
+
function startQuery() {
|
|
235
|
+
if (state.started) return;
|
|
236
|
+
state.started = true;
|
|
237
|
+
|
|
238
|
+
state.input = createInputQueue();
|
|
239
|
+
const options = {
|
|
240
|
+
cwd: state.cwd,
|
|
241
|
+
includePartialMessages: true,
|
|
242
|
+
permissionMode: state.mode || "default",
|
|
243
|
+
allowDangerouslySkipPermissions: true,
|
|
244
|
+
canUseTool,
|
|
245
|
+
settingSources: state.settingSources,
|
|
246
|
+
enableFileCheckpointing: true,
|
|
247
|
+
systemPrompt: {
|
|
248
|
+
type: "preset",
|
|
249
|
+
preset: "claude_code",
|
|
250
|
+
append: state.appendSystemPrompt || "",
|
|
251
|
+
},
|
|
252
|
+
stderr: (data) => logLine("warn", data),
|
|
253
|
+
spawnClaudeCodeProcess: makeSpawnClaude((d) => logLine("warn", d)),
|
|
254
|
+
};
|
|
255
|
+
if (state.claudeExecutable) options.pathToClaudeCodeExecutable = state.claudeExecutable;
|
|
256
|
+
if (state.model) options.model = state.model;
|
|
257
|
+
if (state.resume) options.resume = state.resume;
|
|
258
|
+
|
|
259
|
+
let q;
|
|
260
|
+
try {
|
|
261
|
+
q = query({ prompt: state.input.iterable, options });
|
|
262
|
+
} catch (err) {
|
|
263
|
+
send({ t: "error", message: "query() 启动失败:" + (err?.message ?? String(err)) });
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
state.query = q;
|
|
267
|
+
|
|
268
|
+
(async () => {
|
|
269
|
+
try {
|
|
270
|
+
for await (const msg of q) {
|
|
271
|
+
// Forward verbatim — the Go mapper owns all interpretation.
|
|
272
|
+
send({ t: "sdk", msg });
|
|
273
|
+
|
|
274
|
+
// Capture the session id (for resume) the first time we see it.
|
|
275
|
+
const sid = extractSessionId(msg);
|
|
276
|
+
if (sid && sid !== state.sessionId) {
|
|
277
|
+
state.sessionId = sid;
|
|
278
|
+
send({ t: "session", sessionId: sid });
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// A `result` message ends the current turn.
|
|
282
|
+
if (msg && msg.type === "result") {
|
|
283
|
+
send({
|
|
284
|
+
t: "result",
|
|
285
|
+
runId: state.currentRunId,
|
|
286
|
+
subtype: msg.subtype ?? "success",
|
|
287
|
+
usage: msg.usage ?? null,
|
|
288
|
+
sessionId: state.sessionId,
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
// Generator completed (session closed by the SDK).
|
|
293
|
+
send({ t: "log", level: "info", message: "query 生成器已结束" });
|
|
294
|
+
} catch (err) {
|
|
295
|
+
send({ t: "error", runId: state.currentRunId, message: err?.message ?? String(err) });
|
|
296
|
+
}
|
|
297
|
+
})();
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// ---- control message handling ---------------------------------------------
|
|
301
|
+
|
|
302
|
+
function toSdkUserMessage(text, images) {
|
|
303
|
+
const content = [];
|
|
304
|
+
if (Array.isArray(images)) {
|
|
305
|
+
for (const img of images) {
|
|
306
|
+
if (img && typeof img.data === "string" && img.data.length > 0) {
|
|
307
|
+
content.push({
|
|
308
|
+
type: "image",
|
|
309
|
+
source: {
|
|
310
|
+
type: "base64",
|
|
311
|
+
media_type: img.mime || "image/png",
|
|
312
|
+
data: img.data,
|
|
313
|
+
},
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
if (typeof text === "string" && text.length > 0) {
|
|
319
|
+
content.push({ type: "text", text });
|
|
320
|
+
}
|
|
321
|
+
if (content.length === 0) content.push({ type: "text", text: "" });
|
|
322
|
+
return {
|
|
323
|
+
type: "user",
|
|
324
|
+
message: { role: "user", content },
|
|
325
|
+
parent_tool_use_id: null,
|
|
326
|
+
session_id: state.sessionId || "",
|
|
327
|
+
};
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
async function handleControl(raw) {
|
|
331
|
+
let cmd;
|
|
332
|
+
try {
|
|
333
|
+
cmd = JSON.parse(raw);
|
|
334
|
+
} catch {
|
|
335
|
+
return; // ignore malformed lines
|
|
336
|
+
}
|
|
337
|
+
switch (cmd.t) {
|
|
338
|
+
case "init": {
|
|
339
|
+
state.cwd = cmd.cwd || process.cwd();
|
|
340
|
+
state.claudeExecutable = cmd.claudeExecutable || undefined;
|
|
341
|
+
state.appendSystemPrompt = cmd.appendSystemPrompt || "";
|
|
342
|
+
state.mode = cmd.mode || "default";
|
|
343
|
+
state.model = cmd.model || undefined;
|
|
344
|
+
state.resume = cmd.resume || undefined;
|
|
345
|
+
if (Array.isArray(cmd.settingSources) && cmd.settingSources.length > 0) {
|
|
346
|
+
state.settingSources = cmd.settingSources;
|
|
347
|
+
}
|
|
348
|
+
startQuery();
|
|
349
|
+
break;
|
|
350
|
+
}
|
|
351
|
+
case "prompt": {
|
|
352
|
+
if (!state.started) startQuery();
|
|
353
|
+
state.currentRunId = cmd.runId || "";
|
|
354
|
+
if (state.input) {
|
|
355
|
+
state.input.push(toSdkUserMessage(cmd.text, cmd.images));
|
|
356
|
+
}
|
|
357
|
+
break;
|
|
358
|
+
}
|
|
359
|
+
case "permission_response": {
|
|
360
|
+
const resolve = state.pendingPermissions.get(cmd.id);
|
|
361
|
+
if (resolve) {
|
|
362
|
+
if (cmd.behavior === "allow") {
|
|
363
|
+
const result = { behavior: "allow" };
|
|
364
|
+
if (cmd.updatedInput && typeof cmd.updatedInput === "object") {
|
|
365
|
+
result.updatedInput = cmd.updatedInput;
|
|
366
|
+
}
|
|
367
|
+
resolve(result);
|
|
368
|
+
} else {
|
|
369
|
+
resolve({
|
|
370
|
+
behavior: "deny",
|
|
371
|
+
message: cmd.message || "已拒绝",
|
|
372
|
+
interrupt: cmd.interrupt === true,
|
|
373
|
+
});
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
break;
|
|
377
|
+
}
|
|
378
|
+
case "interrupt": {
|
|
379
|
+
if (state.query && typeof state.query.interrupt === "function") {
|
|
380
|
+
try {
|
|
381
|
+
await state.query.interrupt();
|
|
382
|
+
} catch (err) {
|
|
383
|
+
logLine("warn", "interrupt 失败:" + (err?.message ?? String(err)));
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
break;
|
|
387
|
+
}
|
|
388
|
+
case "set_model": {
|
|
389
|
+
state.model = cmd.model || undefined;
|
|
390
|
+
if (state.query && typeof state.query.setModel === "function") {
|
|
391
|
+
try {
|
|
392
|
+
await state.query.setModel(cmd.model || undefined);
|
|
393
|
+
} catch (err) {
|
|
394
|
+
logLine("warn", "setModel 失败:" + (err?.message ?? String(err)));
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
break;
|
|
398
|
+
}
|
|
399
|
+
case "set_mode": {
|
|
400
|
+
state.mode = cmd.mode || "default";
|
|
401
|
+
if (state.query && typeof state.query.setPermissionMode === "function") {
|
|
402
|
+
try {
|
|
403
|
+
await state.query.setPermissionMode(state.mode);
|
|
404
|
+
} catch (err) {
|
|
405
|
+
logLine("warn", "setPermissionMode 失败:" + (err?.message ?? String(err)));
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
break;
|
|
409
|
+
}
|
|
410
|
+
case "shutdown": {
|
|
411
|
+
cleanupAndExit(0);
|
|
412
|
+
break;
|
|
413
|
+
}
|
|
414
|
+
default:
|
|
415
|
+
break;
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
function cleanupAndExit(code) {
|
|
420
|
+
try {
|
|
421
|
+
// Reject any pending permissions so the SDK doesn't hang on close.
|
|
422
|
+
for (const resolve of state.pendingPermissions.values()) {
|
|
423
|
+
resolve({ behavior: "deny", message: "桥已关闭", interrupt: true });
|
|
424
|
+
}
|
|
425
|
+
state.pendingPermissions.clear();
|
|
426
|
+
if (state.input) state.input.close();
|
|
427
|
+
if (state.query && typeof state.query.return === "function") {
|
|
428
|
+
try {
|
|
429
|
+
state.query.return();
|
|
430
|
+
} catch {
|
|
431
|
+
/* ignore */
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
} finally {
|
|
435
|
+
process.exit(code);
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
// ---- main loop ------------------------------------------------------------
|
|
440
|
+
|
|
441
|
+
const rl = readline.createInterface({ input: process.stdin });
|
|
442
|
+
rl.on("line", (line) => {
|
|
443
|
+
const trimmed = line.trim();
|
|
444
|
+
if (trimmed.length === 0) return;
|
|
445
|
+
handleControl(trimmed).catch((err) => {
|
|
446
|
+
logLine("error", "control 处理异常:" + (err?.message ?? String(err)));
|
|
447
|
+
});
|
|
448
|
+
});
|
|
449
|
+
rl.on("close", () => cleanupAndExit(0));
|
|
450
|
+
|
|
451
|
+
process.on("SIGTERM", () => cleanupAndExit(0));
|
|
452
|
+
process.on("SIGINT", () => cleanupAndExit(0));
|
|
453
|
+
|
|
454
|
+
send({ t: "ready", sdkVersion });
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@vantaloom/claude-sdk-bridge",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"description": "Thin Node sidecar that runs @anthropic-ai/claude-agent-sdk query() and bridges its native stream-json to the Vantaloom Go runtime over stdio NDJSON.",
|
|
7
|
+
"bin": {
|
|
8
|
+
"claude-sdk-bridge": "index.mjs"
|
|
9
|
+
},
|
|
10
|
+
"main": "index.mjs",
|
|
11
|
+
"dependencies": {
|
|
12
|
+
"@anthropic-ai/claude-agent-sdk": "^0.2.133"
|
|
13
|
+
},
|
|
14
|
+
"engines": {
|
|
15
|
+
"node": ">=20"
|
|
16
|
+
}
|
|
17
|
+
}
|
package/cli/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vantaloom/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "Vantaloom local runtime manager.",
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
"files": [
|
|
11
11
|
"bin",
|
|
12
12
|
"src",
|
|
13
|
+
"adapters",
|
|
13
14
|
"package.json",
|
|
14
15
|
"README.md"
|
|
15
16
|
],
|