@anthropic-ai/claude-code 1.0.85 → 1.0.86
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/cli.js +852 -850
- package/package.json +1 -1
- package/sdk-tools.d.ts +4 -1
- package/sdk.d.ts +17 -11
- package/sdk.mjs +546 -179
- package/vendor/claude-code.vsix +0 -0
package/sdk.mjs
CHANGED
|
@@ -2,17 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
// (c) Anthropic PBC. All rights reserved. Use is subject to Anthropic's Commercial Terms of Service (https://www.anthropic.com/legal/commercial-terms).
|
|
4
4
|
|
|
5
|
-
// Version: 1.0.
|
|
5
|
+
// Version: 1.0.86
|
|
6
6
|
|
|
7
7
|
// Want to see the unminified source? We're hiring!
|
|
8
8
|
// https://job-boards.greenhouse.io/anthropic/jobs/4816199008
|
|
9
9
|
|
|
10
10
|
// src/entrypoints/sdk.ts
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import { fileURLToPath } from "url";
|
|
14
|
-
import { createInterface } from "readline";
|
|
15
|
-
import { existsSync } from "fs";
|
|
11
|
+
import { join as join2 } from "path";
|
|
12
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
16
13
|
|
|
17
14
|
// src/utils/stream.ts
|
|
18
15
|
class Stream {
|
|
@@ -97,10 +94,451 @@ function createAbortController(maxListeners = DEFAULT_MAX_LISTENERS) {
|
|
|
97
94
|
return controller;
|
|
98
95
|
}
|
|
99
96
|
|
|
97
|
+
// src/transport/ProcessTransport.ts
|
|
98
|
+
import { spawn } from "child_process";
|
|
99
|
+
import { join } from "path";
|
|
100
|
+
import { fileURLToPath } from "url";
|
|
101
|
+
import { createInterface } from "readline";
|
|
102
|
+
|
|
103
|
+
// src/utils/fsOperations.ts
|
|
104
|
+
import * as fs from "fs";
|
|
105
|
+
import { stat as statPromise } from "fs/promises";
|
|
106
|
+
var NodeFsOperations = {
|
|
107
|
+
accessSync(fsPath, mode) {
|
|
108
|
+
fs.accessSync(fsPath, mode);
|
|
109
|
+
},
|
|
110
|
+
cwd() {
|
|
111
|
+
return process.cwd();
|
|
112
|
+
},
|
|
113
|
+
chmodSync(fsPath, mode) {
|
|
114
|
+
fs.chmodSync(fsPath, mode);
|
|
115
|
+
},
|
|
116
|
+
existsSync(fsPath) {
|
|
117
|
+
return fs.existsSync(fsPath);
|
|
118
|
+
},
|
|
119
|
+
async stat(fsPath) {
|
|
120
|
+
return statPromise(fsPath);
|
|
121
|
+
},
|
|
122
|
+
statSync(fsPath) {
|
|
123
|
+
return fs.statSync(fsPath);
|
|
124
|
+
},
|
|
125
|
+
readFileSync(fsPath, options) {
|
|
126
|
+
return fs.readFileSync(fsPath, { encoding: options.encoding });
|
|
127
|
+
},
|
|
128
|
+
readFileBytesSync(fsPath) {
|
|
129
|
+
return fs.readFileSync(fsPath);
|
|
130
|
+
},
|
|
131
|
+
readSync(fsPath, options) {
|
|
132
|
+
let fd = undefined;
|
|
133
|
+
try {
|
|
134
|
+
fd = fs.openSync(fsPath, "r");
|
|
135
|
+
const buffer = Buffer.alloc(options.length);
|
|
136
|
+
const bytesRead = fs.readSync(fd, buffer, 0, options.length, 0);
|
|
137
|
+
return { buffer, bytesRead };
|
|
138
|
+
} finally {
|
|
139
|
+
if (fd)
|
|
140
|
+
fs.closeSync(fd);
|
|
141
|
+
}
|
|
142
|
+
},
|
|
143
|
+
writeFileSync(fsPath, data, options) {
|
|
144
|
+
if (!options.flush) {
|
|
145
|
+
fs.writeFileSync(fsPath, data, { encoding: options.encoding });
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
let fd;
|
|
149
|
+
try {
|
|
150
|
+
fd = fs.openSync(fsPath, "w");
|
|
151
|
+
fs.writeFileSync(fd, data, { encoding: options.encoding });
|
|
152
|
+
fs.fsyncSync(fd);
|
|
153
|
+
} finally {
|
|
154
|
+
if (fd) {
|
|
155
|
+
fs.closeSync(fd);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
},
|
|
159
|
+
appendFileSync(path, data) {
|
|
160
|
+
fs.appendFileSync(path, data);
|
|
161
|
+
},
|
|
162
|
+
copyFileSync(src, dest) {
|
|
163
|
+
fs.copyFileSync(src, dest);
|
|
164
|
+
},
|
|
165
|
+
unlinkSync(path) {
|
|
166
|
+
fs.unlinkSync(path);
|
|
167
|
+
},
|
|
168
|
+
renameSync(oldPath, newPath) {
|
|
169
|
+
fs.renameSync(oldPath, newPath);
|
|
170
|
+
},
|
|
171
|
+
symlinkSync(target, path) {
|
|
172
|
+
fs.symlinkSync(target, path);
|
|
173
|
+
},
|
|
174
|
+
readlinkSync(path) {
|
|
175
|
+
return fs.readlinkSync(path);
|
|
176
|
+
},
|
|
177
|
+
realpathSync(path) {
|
|
178
|
+
return fs.realpathSync(path);
|
|
179
|
+
},
|
|
180
|
+
mkdirSync(dirPath) {
|
|
181
|
+
if (!fs.existsSync(dirPath)) {
|
|
182
|
+
fs.mkdirSync(dirPath, { recursive: true });
|
|
183
|
+
}
|
|
184
|
+
},
|
|
185
|
+
readdirSync(dirPath) {
|
|
186
|
+
return fs.readdirSync(dirPath, { withFileTypes: true });
|
|
187
|
+
},
|
|
188
|
+
readdirStringSync(dirPath) {
|
|
189
|
+
return fs.readdirSync(dirPath);
|
|
190
|
+
},
|
|
191
|
+
isDirEmptySync(dirPath) {
|
|
192
|
+
const files = this.readdirSync(dirPath);
|
|
193
|
+
return files.length === 0;
|
|
194
|
+
},
|
|
195
|
+
rmdirSync(dirPath) {
|
|
196
|
+
fs.rmdirSync(dirPath);
|
|
197
|
+
},
|
|
198
|
+
rmSync(path, options) {
|
|
199
|
+
fs.rmSync(path, options);
|
|
200
|
+
}
|
|
201
|
+
};
|
|
202
|
+
var activeFs = NodeFsOperations;
|
|
203
|
+
function getFsImplementation() {
|
|
204
|
+
return activeFs;
|
|
205
|
+
}
|
|
206
|
+
|
|
100
207
|
// src/entrypoints/sdkTypes.ts
|
|
101
208
|
class AbortError extends Error {
|
|
102
209
|
}
|
|
103
210
|
|
|
211
|
+
// src/transport/ProcessTransport.ts
|
|
212
|
+
class ProcessTransport {
|
|
213
|
+
options;
|
|
214
|
+
child;
|
|
215
|
+
childStdin;
|
|
216
|
+
childStdout;
|
|
217
|
+
ready = false;
|
|
218
|
+
abortController;
|
|
219
|
+
exitError;
|
|
220
|
+
exitListeners = [];
|
|
221
|
+
processExitHandler;
|
|
222
|
+
abortHandler;
|
|
223
|
+
isStreaming;
|
|
224
|
+
constructor(options) {
|
|
225
|
+
this.options = options;
|
|
226
|
+
this.abortController = options.abortController || createAbortController();
|
|
227
|
+
this.isStreaming = typeof options.prompt !== "string";
|
|
228
|
+
this.initialize();
|
|
229
|
+
}
|
|
230
|
+
initialize() {
|
|
231
|
+
try {
|
|
232
|
+
const {
|
|
233
|
+
prompt,
|
|
234
|
+
additionalDirectories = [],
|
|
235
|
+
cwd,
|
|
236
|
+
executable = this.isRunningWithBun() ? "bun" : "node",
|
|
237
|
+
executableArgs = [],
|
|
238
|
+
pathToClaudeCodeExecutable,
|
|
239
|
+
env = { ...process.env },
|
|
240
|
+
stderr,
|
|
241
|
+
customSystemPrompt,
|
|
242
|
+
appendSystemPrompt,
|
|
243
|
+
maxTurns,
|
|
244
|
+
model,
|
|
245
|
+
fallbackModel,
|
|
246
|
+
permissionMode,
|
|
247
|
+
permissionPromptToolName,
|
|
248
|
+
continueConversation,
|
|
249
|
+
resume,
|
|
250
|
+
allowedTools = [],
|
|
251
|
+
disallowedTools = [],
|
|
252
|
+
mcpServers,
|
|
253
|
+
strictMcpConfig,
|
|
254
|
+
canUseTool
|
|
255
|
+
} = this.options;
|
|
256
|
+
const args = ["--output-format", "stream-json", "--verbose"];
|
|
257
|
+
if (customSystemPrompt)
|
|
258
|
+
args.push("--system-prompt", customSystemPrompt);
|
|
259
|
+
if (appendSystemPrompt)
|
|
260
|
+
args.push("--append-system-prompt", appendSystemPrompt);
|
|
261
|
+
if (maxTurns)
|
|
262
|
+
args.push("--max-turns", maxTurns.toString());
|
|
263
|
+
if (model)
|
|
264
|
+
args.push("--model", model);
|
|
265
|
+
if (env.DEBUG)
|
|
266
|
+
args.push("--debug-to-stderr");
|
|
267
|
+
if (canUseTool) {
|
|
268
|
+
if (typeof prompt === "string") {
|
|
269
|
+
throw new Error("canUseTool callback requires --input-format stream-json. Please set prompt as an AsyncIterable.");
|
|
270
|
+
}
|
|
271
|
+
if (permissionPromptToolName) {
|
|
272
|
+
throw new Error("canUseTool callback cannot be used with permissionPromptToolName. Please use one or the other.");
|
|
273
|
+
}
|
|
274
|
+
args.push("--permission-prompt-tool", "stdio");
|
|
275
|
+
} else if (permissionPromptToolName) {
|
|
276
|
+
args.push("--permission-prompt-tool", permissionPromptToolName);
|
|
277
|
+
}
|
|
278
|
+
if (continueConversation)
|
|
279
|
+
args.push("--continue");
|
|
280
|
+
if (resume)
|
|
281
|
+
args.push("--resume", resume);
|
|
282
|
+
if (allowedTools.length > 0) {
|
|
283
|
+
args.push("--allowedTools", allowedTools.join(","));
|
|
284
|
+
}
|
|
285
|
+
if (disallowedTools.length > 0) {
|
|
286
|
+
args.push("--disallowedTools", disallowedTools.join(","));
|
|
287
|
+
}
|
|
288
|
+
if (mcpServers && Object.keys(mcpServers).length > 0) {
|
|
289
|
+
args.push("--mcp-config", JSON.stringify({ mcpServers }));
|
|
290
|
+
}
|
|
291
|
+
if (strictMcpConfig) {
|
|
292
|
+
args.push("--strict-mcp-config");
|
|
293
|
+
}
|
|
294
|
+
if (permissionMode && permissionMode !== "default") {
|
|
295
|
+
args.push("--permission-mode", permissionMode);
|
|
296
|
+
}
|
|
297
|
+
if (fallbackModel) {
|
|
298
|
+
if (model && fallbackModel === model) {
|
|
299
|
+
throw new Error("Fallback model cannot be the same as the main model. Please specify a different model for fallbackModel option.");
|
|
300
|
+
}
|
|
301
|
+
args.push("--fallback-model", fallbackModel);
|
|
302
|
+
}
|
|
303
|
+
if (typeof prompt === "string") {
|
|
304
|
+
args.push("--print");
|
|
305
|
+
args.push("--", prompt.trim());
|
|
306
|
+
} else {
|
|
307
|
+
args.push("--input-format", "stream-json");
|
|
308
|
+
}
|
|
309
|
+
for (const dir of additionalDirectories) {
|
|
310
|
+
args.push("--add-dir", dir);
|
|
311
|
+
}
|
|
312
|
+
if (!env.CLAUDE_CODE_ENTRYPOINT) {
|
|
313
|
+
env.CLAUDE_CODE_ENTRYPOINT = "sdk-ts";
|
|
314
|
+
}
|
|
315
|
+
const claudeCodePath = pathToClaudeCodeExecutable || this.getDefaultExecutablePath();
|
|
316
|
+
const fs2 = getFsImplementation();
|
|
317
|
+
if (!fs2.existsSync(claudeCodePath)) {
|
|
318
|
+
throw new Error(`Claude Code executable not found at ${claudeCodePath}. Is options.pathToClaudeCodeExecutable set?`);
|
|
319
|
+
}
|
|
320
|
+
this.logDebug(`Spawning Claude Code process: ${executable} ${[...executableArgs, claudeCodePath, ...args].join(" ")}`);
|
|
321
|
+
const stderrMode = env.DEBUG || stderr ? "pipe" : "ignore";
|
|
322
|
+
this.child = spawn(executable, [...executableArgs, claudeCodePath, ...args], {
|
|
323
|
+
cwd,
|
|
324
|
+
stdio: ["pipe", "pipe", stderrMode],
|
|
325
|
+
signal: this.abortController.signal,
|
|
326
|
+
env
|
|
327
|
+
});
|
|
328
|
+
this.childStdin = this.child.stdin;
|
|
329
|
+
this.childStdout = this.child.stdout;
|
|
330
|
+
if (typeof prompt === "string") {
|
|
331
|
+
this.childStdin.end();
|
|
332
|
+
this.childStdin = undefined;
|
|
333
|
+
}
|
|
334
|
+
if (env.DEBUG || stderr) {
|
|
335
|
+
this.child.stderr.on("data", (data) => {
|
|
336
|
+
this.logDebug(`Claude Code stderr: ${data.toString()}`);
|
|
337
|
+
if (stderr) {
|
|
338
|
+
stderr(data.toString());
|
|
339
|
+
}
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
const cleanup = () => {
|
|
343
|
+
if (this.child && !this.child.killed) {
|
|
344
|
+
this.child.kill("SIGTERM");
|
|
345
|
+
}
|
|
346
|
+
};
|
|
347
|
+
this.processExitHandler = cleanup;
|
|
348
|
+
this.abortHandler = cleanup;
|
|
349
|
+
process.on("exit", this.processExitHandler);
|
|
350
|
+
this.abortController.signal.addEventListener("abort", this.abortHandler);
|
|
351
|
+
this.child.on("error", (error) => {
|
|
352
|
+
this.ready = false;
|
|
353
|
+
if (this.abortController.signal.aborted) {
|
|
354
|
+
this.exitError = new AbortError("Claude Code process aborted by user");
|
|
355
|
+
} else {
|
|
356
|
+
this.exitError = new Error(`Failed to spawn Claude Code process: ${error.message}`);
|
|
357
|
+
this.logDebug(this.exitError.message);
|
|
358
|
+
}
|
|
359
|
+
});
|
|
360
|
+
this.child.on("close", (code, signal) => {
|
|
361
|
+
this.ready = false;
|
|
362
|
+
if (this.abortController.signal.aborted) {
|
|
363
|
+
this.exitError = new AbortError("Claude Code process aborted by user");
|
|
364
|
+
} else {
|
|
365
|
+
const error = this.getProcessExitError(code, signal);
|
|
366
|
+
if (error) {
|
|
367
|
+
this.exitError = error;
|
|
368
|
+
this.logDebug(error.message);
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
});
|
|
372
|
+
this.ready = true;
|
|
373
|
+
} catch (error) {
|
|
374
|
+
this.ready = false;
|
|
375
|
+
throw error;
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
getProcessExitError(code, signal) {
|
|
379
|
+
if (code !== 0 && code !== null) {
|
|
380
|
+
return new Error(`Claude Code process exited with code ${code}`);
|
|
381
|
+
} else if (signal) {
|
|
382
|
+
return new Error(`Claude Code process terminated by signal ${signal}`);
|
|
383
|
+
}
|
|
384
|
+
return;
|
|
385
|
+
}
|
|
386
|
+
getDefaultExecutablePath() {
|
|
387
|
+
const filename = fileURLToPath(import.meta.url);
|
|
388
|
+
const dirname = join(filename, "..", "..");
|
|
389
|
+
return join(dirname, "entrypoints", "cli.js");
|
|
390
|
+
}
|
|
391
|
+
isRunningWithBun() {
|
|
392
|
+
return process.versions.bun !== undefined || process.env.BUN_INSTALL !== undefined;
|
|
393
|
+
}
|
|
394
|
+
logDebug(message) {
|
|
395
|
+
if (process.env.DEBUG) {
|
|
396
|
+
process.stderr.write(`${message}
|
|
397
|
+
`);
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
write(data) {
|
|
401
|
+
if (this.abortController.signal.aborted) {
|
|
402
|
+
throw new AbortError("Operation aborted");
|
|
403
|
+
}
|
|
404
|
+
if (!this.ready || !this.childStdin) {
|
|
405
|
+
throw new Error("ProcessTransport is not ready for writing");
|
|
406
|
+
}
|
|
407
|
+
if (this.child?.killed || this.child?.exitCode !== null) {
|
|
408
|
+
throw new Error("Cannot write to terminated process");
|
|
409
|
+
}
|
|
410
|
+
if (this.exitError) {
|
|
411
|
+
throw new Error(`Cannot write to process that exited with error: ${this.exitError.message}`);
|
|
412
|
+
}
|
|
413
|
+
if (process.env.DEBUG_SDK) {
|
|
414
|
+
process.stderr.write(`[ProcessTransport] Writing to stdin: ${data.substring(0, 100)}
|
|
415
|
+
`);
|
|
416
|
+
}
|
|
417
|
+
try {
|
|
418
|
+
const written = this.childStdin.write(data);
|
|
419
|
+
if (!written && process.env.DEBUG_SDK) {
|
|
420
|
+
console.warn("[ProcessTransport] Write buffer full, data queued");
|
|
421
|
+
}
|
|
422
|
+
} catch (error) {
|
|
423
|
+
this.ready = false;
|
|
424
|
+
throw new Error(`Failed to write to process stdin: ${error.message}`);
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
close() {
|
|
428
|
+
if (this.childStdin) {
|
|
429
|
+
this.childStdin.end();
|
|
430
|
+
this.childStdin = undefined;
|
|
431
|
+
}
|
|
432
|
+
if (this.processExitHandler) {
|
|
433
|
+
process.off("exit", this.processExitHandler);
|
|
434
|
+
this.processExitHandler = undefined;
|
|
435
|
+
}
|
|
436
|
+
if (this.abortHandler) {
|
|
437
|
+
this.abortController.signal.removeEventListener("abort", this.abortHandler);
|
|
438
|
+
this.abortHandler = undefined;
|
|
439
|
+
}
|
|
440
|
+
for (const { handler } of this.exitListeners) {
|
|
441
|
+
this.child?.off("exit", handler);
|
|
442
|
+
}
|
|
443
|
+
this.exitListeners = [];
|
|
444
|
+
if (this.child && !this.child.killed) {
|
|
445
|
+
this.child.kill("SIGTERM");
|
|
446
|
+
setTimeout(() => {
|
|
447
|
+
if (this.child && !this.child.killed) {
|
|
448
|
+
this.child.kill("SIGKILL");
|
|
449
|
+
}
|
|
450
|
+
}, 5000);
|
|
451
|
+
}
|
|
452
|
+
this.ready = false;
|
|
453
|
+
}
|
|
454
|
+
isReady() {
|
|
455
|
+
return this.ready;
|
|
456
|
+
}
|
|
457
|
+
async* readMessages() {
|
|
458
|
+
if (!this.childStdout) {
|
|
459
|
+
throw new Error("ProcessTransport output stream not available");
|
|
460
|
+
}
|
|
461
|
+
const rl = createInterface({ input: this.childStdout });
|
|
462
|
+
try {
|
|
463
|
+
for await (const line of rl) {
|
|
464
|
+
if (line.trim()) {
|
|
465
|
+
const message = JSON.parse(line);
|
|
466
|
+
yield message;
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
await this.waitForExit();
|
|
470
|
+
} catch (error) {
|
|
471
|
+
throw error;
|
|
472
|
+
} finally {
|
|
473
|
+
rl.close();
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
endInput() {
|
|
477
|
+
if (this.childStdin) {
|
|
478
|
+
this.childStdin.end();
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
getInputStream() {
|
|
482
|
+
return this.childStdin;
|
|
483
|
+
}
|
|
484
|
+
onExit(callback) {
|
|
485
|
+
if (!this.child)
|
|
486
|
+
return () => {};
|
|
487
|
+
const handler = (code, signal) => {
|
|
488
|
+
const error = this.getProcessExitError(code, signal);
|
|
489
|
+
callback(error);
|
|
490
|
+
};
|
|
491
|
+
this.child.on("exit", handler);
|
|
492
|
+
this.exitListeners.push({ callback, handler });
|
|
493
|
+
return () => {
|
|
494
|
+
if (this.child) {
|
|
495
|
+
this.child.off("exit", handler);
|
|
496
|
+
}
|
|
497
|
+
const index = this.exitListeners.findIndex((l) => l.handler === handler);
|
|
498
|
+
if (index !== -1) {
|
|
499
|
+
this.exitListeners.splice(index, 1);
|
|
500
|
+
}
|
|
501
|
+
};
|
|
502
|
+
}
|
|
503
|
+
async waitForExit() {
|
|
504
|
+
if (!this.child) {
|
|
505
|
+
if (this.exitError) {
|
|
506
|
+
throw this.exitError;
|
|
507
|
+
}
|
|
508
|
+
return;
|
|
509
|
+
}
|
|
510
|
+
if (this.child.exitCode !== null || this.child.killed) {
|
|
511
|
+
if (this.exitError) {
|
|
512
|
+
throw this.exitError;
|
|
513
|
+
}
|
|
514
|
+
return;
|
|
515
|
+
}
|
|
516
|
+
return new Promise((resolve, reject) => {
|
|
517
|
+
const exitHandler = (code, signal) => {
|
|
518
|
+
if (this.abortController.signal.aborted) {
|
|
519
|
+
reject(new AbortError("Operation aborted"));
|
|
520
|
+
return;
|
|
521
|
+
}
|
|
522
|
+
const error = this.getProcessExitError(code, signal);
|
|
523
|
+
if (error) {
|
|
524
|
+
reject(error);
|
|
525
|
+
} else {
|
|
526
|
+
resolve();
|
|
527
|
+
}
|
|
528
|
+
};
|
|
529
|
+
this.child.once("exit", exitHandler);
|
|
530
|
+
const errorHandler = (error) => {
|
|
531
|
+
this.child.off("exit", exitHandler);
|
|
532
|
+
reject(error);
|
|
533
|
+
};
|
|
534
|
+
this.child.once("error", errorHandler);
|
|
535
|
+
this.child.once("exit", () => {
|
|
536
|
+
this.child.off("error", errorHandler);
|
|
537
|
+
});
|
|
538
|
+
});
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
|
|
104
542
|
// src/entrypoints/sdk.ts
|
|
105
543
|
function query({
|
|
106
544
|
prompt,
|
|
@@ -137,155 +575,87 @@ function query({
|
|
|
137
575
|
env.CLAUDE_CODE_ENTRYPOINT = "sdk-ts";
|
|
138
576
|
}
|
|
139
577
|
if (pathToClaudeCodeExecutable === undefined) {
|
|
140
|
-
const filename =
|
|
141
|
-
const dirname =
|
|
142
|
-
pathToClaudeCodeExecutable =
|
|
143
|
-
}
|
|
144
|
-
const
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
if (maxTurns)
|
|
150
|
-
args.push("--max-turns", maxTurns.toString());
|
|
151
|
-
if (model)
|
|
152
|
-
args.push("--model", model);
|
|
153
|
-
if (canUseTool) {
|
|
154
|
-
if (typeof prompt === "string") {
|
|
155
|
-
throw new Error("canUseTool callback requires --input-format stream-json. Please set prompt as an AsyncIterable.");
|
|
156
|
-
}
|
|
157
|
-
if (permissionPromptToolName) {
|
|
158
|
-
throw new Error("canUseTool callback cannot be used with permissionPromptToolName. Please use one or the other.");
|
|
159
|
-
}
|
|
160
|
-
permissionPromptToolName = "stdio";
|
|
161
|
-
}
|
|
162
|
-
if (permissionPromptToolName) {
|
|
163
|
-
args.push("--permission-prompt-tool", permissionPromptToolName);
|
|
164
|
-
}
|
|
165
|
-
if (continueConversation)
|
|
166
|
-
args.push("--continue");
|
|
167
|
-
if (resume)
|
|
168
|
-
args.push("--resume", resume);
|
|
169
|
-
if (allowedTools.length > 0) {
|
|
170
|
-
args.push("--allowedTools", allowedTools.join(","));
|
|
171
|
-
}
|
|
172
|
-
if (disallowedTools.length > 0) {
|
|
173
|
-
args.push("--disallowedTools", disallowedTools.join(","));
|
|
174
|
-
}
|
|
175
|
-
if (mcpServers && Object.keys(mcpServers).length > 0) {
|
|
176
|
-
args.push("--mcp-config", JSON.stringify({ mcpServers }));
|
|
177
|
-
}
|
|
178
|
-
if (strictMcpConfig) {
|
|
179
|
-
args.push("--strict-mcp-config");
|
|
180
|
-
}
|
|
181
|
-
if (permissionMode !== "default") {
|
|
182
|
-
args.push("--permission-mode", permissionMode);
|
|
183
|
-
}
|
|
184
|
-
if (fallbackModel) {
|
|
185
|
-
if (model && fallbackModel === model) {
|
|
186
|
-
throw new Error("Fallback model cannot be the same as the main model. Please specify a different model for fallbackModel option.");
|
|
187
|
-
}
|
|
188
|
-
args.push("--fallback-model", fallbackModel);
|
|
189
|
-
}
|
|
190
|
-
if (typeof prompt === "string") {
|
|
191
|
-
args.push("--print");
|
|
192
|
-
args.push("--", prompt.trim());
|
|
193
|
-
} else {
|
|
194
|
-
args.push("--input-format", "stream-json");
|
|
195
|
-
}
|
|
196
|
-
for (const dir of additionalDirectories) {
|
|
197
|
-
args.push("--add-dir", dir);
|
|
198
|
-
}
|
|
199
|
-
if (!existsSync(pathToClaudeCodeExecutable)) {
|
|
200
|
-
throw new ReferenceError(`Claude Code executable not found at ${pathToClaudeCodeExecutable}. Is options.pathToClaudeCodeExecutable set?`);
|
|
201
|
-
}
|
|
202
|
-
logDebug(`Spawning Claude Code process: ${executable} ${[...executableArgs, pathToClaudeCodeExecutable, ...args].join(" ")}`);
|
|
203
|
-
const stderrMode = env.DEBUG || stderr ? "pipe" : "ignore";
|
|
204
|
-
const child = spawn(executable, [...executableArgs, pathToClaudeCodeExecutable, ...args], {
|
|
578
|
+
const filename = fileURLToPath2(import.meta.url);
|
|
579
|
+
const dirname = join2(filename, "..");
|
|
580
|
+
pathToClaudeCodeExecutable = join2(dirname, "cli.js");
|
|
581
|
+
}
|
|
582
|
+
const isStreamingMode = typeof prompt !== "string";
|
|
583
|
+
const transport = new ProcessTransport({
|
|
584
|
+
prompt,
|
|
585
|
+
abortController,
|
|
586
|
+
additionalDirectories,
|
|
205
587
|
cwd,
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
588
|
+
executable,
|
|
589
|
+
executableArgs,
|
|
590
|
+
pathToClaudeCodeExecutable,
|
|
591
|
+
env,
|
|
592
|
+
stderr,
|
|
593
|
+
customSystemPrompt,
|
|
594
|
+
appendSystemPrompt,
|
|
595
|
+
maxTurns,
|
|
596
|
+
model,
|
|
597
|
+
fallbackModel,
|
|
598
|
+
permissionMode,
|
|
599
|
+
permissionPromptToolName,
|
|
600
|
+
continueConversation,
|
|
601
|
+
resume,
|
|
602
|
+
allowedTools,
|
|
603
|
+
disallowedTools,
|
|
604
|
+
mcpServers,
|
|
605
|
+
strictMcpConfig,
|
|
606
|
+
canUseTool: !!canUseTool,
|
|
607
|
+
hooks: !!hooks
|
|
209
608
|
});
|
|
210
|
-
|
|
211
|
-
if (typeof prompt
|
|
212
|
-
|
|
213
|
-
} else {
|
|
214
|
-
streamToStdin(prompt, child.stdin, abortController);
|
|
215
|
-
childStdin = child.stdin;
|
|
216
|
-
}
|
|
217
|
-
if (env.DEBUG || stderr) {
|
|
218
|
-
child.stderr.on("data", (data) => {
|
|
219
|
-
if (env.DEBUG) {
|
|
220
|
-
console.error("Claude Code stderr:", data.toString());
|
|
221
|
-
}
|
|
222
|
-
if (stderr) {
|
|
223
|
-
stderr(data.toString());
|
|
224
|
-
}
|
|
225
|
-
});
|
|
609
|
+
const query2 = new Query(transport, isStreamingMode, canUseTool, hooks, abortController);
|
|
610
|
+
if (typeof prompt !== "string") {
|
|
611
|
+
query2.streamInput(prompt);
|
|
226
612
|
}
|
|
227
|
-
const cleanup = () => {
|
|
228
|
-
if (!child.killed) {
|
|
229
|
-
child.kill("SIGTERM");
|
|
230
|
-
}
|
|
231
|
-
};
|
|
232
|
-
abortController.signal.addEventListener("abort", cleanup);
|
|
233
|
-
process.on("exit", cleanup);
|
|
234
|
-
const processExitPromise = new Promise((resolve) => {
|
|
235
|
-
child.on("close", (code) => {
|
|
236
|
-
if (abortController.signal.aborted) {
|
|
237
|
-
query2.setError(new AbortError("Claude Code process aborted by user"));
|
|
238
|
-
}
|
|
239
|
-
if (code !== 0) {
|
|
240
|
-
query2.setError(new Error(`Claude Code process exited with code ${code}`));
|
|
241
|
-
} else {
|
|
242
|
-
resolve();
|
|
243
|
-
}
|
|
244
|
-
});
|
|
245
|
-
});
|
|
246
|
-
const query2 = new Query(childStdin, child.stdout, processExitPromise, canUseTool, hooks);
|
|
247
|
-
child.on("error", (error) => {
|
|
248
|
-
if (abortController.signal.aborted) {
|
|
249
|
-
query2.setError(new AbortError("Claude Code process aborted by user"));
|
|
250
|
-
} else {
|
|
251
|
-
query2.setError(new Error(`Failed to spawn Claude Code process: ${error.message}`));
|
|
252
|
-
}
|
|
253
|
-
});
|
|
254
|
-
processExitPromise.finally(() => {
|
|
255
|
-
cleanup();
|
|
256
|
-
abortController.signal.removeEventListener("abort", cleanup);
|
|
257
|
-
});
|
|
258
613
|
return query2;
|
|
259
614
|
}
|
|
260
615
|
|
|
261
616
|
class Query {
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
processExitPromise;
|
|
617
|
+
transport;
|
|
618
|
+
isStreamingMode;
|
|
265
619
|
canUseTool;
|
|
266
620
|
hooks;
|
|
621
|
+
abortController;
|
|
267
622
|
pendingControlResponses = new Map;
|
|
623
|
+
cleanupPerformed = false;
|
|
268
624
|
sdkMessages;
|
|
269
625
|
inputStream = new Stream;
|
|
270
626
|
intialization;
|
|
271
627
|
cancelControllers = new Map;
|
|
272
628
|
hookCallbacks = new Map;
|
|
273
629
|
nextCallbackId = 0;
|
|
274
|
-
constructor(
|
|
275
|
-
this.
|
|
276
|
-
this.
|
|
277
|
-
this.processExitPromise = processExitPromise;
|
|
630
|
+
constructor(transport, isStreamingMode, canUseTool, hooks, abortController) {
|
|
631
|
+
this.transport = transport;
|
|
632
|
+
this.isStreamingMode = isStreamingMode;
|
|
278
633
|
this.canUseTool = canUseTool;
|
|
279
634
|
this.hooks = hooks;
|
|
280
|
-
this.
|
|
635
|
+
this.abortController = abortController;
|
|
281
636
|
this.sdkMessages = this.readSdkMessages();
|
|
282
|
-
|
|
637
|
+
this.readMessages();
|
|
638
|
+
if (this.isStreamingMode) {
|
|
283
639
|
this.intialization = this.initialize();
|
|
284
640
|
}
|
|
285
641
|
}
|
|
286
642
|
setError(error) {
|
|
287
643
|
this.inputStream.error(error);
|
|
288
644
|
}
|
|
645
|
+
cleanup(error) {
|
|
646
|
+
if (this.cleanupPerformed)
|
|
647
|
+
return;
|
|
648
|
+
this.cleanupPerformed = true;
|
|
649
|
+
try {
|
|
650
|
+
this.transport.close();
|
|
651
|
+
this.pendingControlResponses.clear();
|
|
652
|
+
if (error) {
|
|
653
|
+
this.inputStream.error(error);
|
|
654
|
+
} else {
|
|
655
|
+
this.inputStream.done();
|
|
656
|
+
}
|
|
657
|
+
} catch (_error) {}
|
|
658
|
+
}
|
|
289
659
|
next(...[value]) {
|
|
290
660
|
return this.sdkMessages.next(...[value]);
|
|
291
661
|
}
|
|
@@ -302,33 +672,28 @@ class Query {
|
|
|
302
672
|
return this.sdkMessages[Symbol.asyncDispose]();
|
|
303
673
|
}
|
|
304
674
|
async readMessages() {
|
|
305
|
-
const rl = createInterface({ input: this.childStdout });
|
|
306
675
|
try {
|
|
307
|
-
for await (const
|
|
308
|
-
if (
|
|
309
|
-
const
|
|
310
|
-
if (
|
|
311
|
-
|
|
312
|
-
if (handler) {
|
|
313
|
-
handler(message.response);
|
|
314
|
-
}
|
|
315
|
-
continue;
|
|
316
|
-
} else if (message.type === "control_request") {
|
|
317
|
-
this.handleControlRequest(message);
|
|
318
|
-
continue;
|
|
319
|
-
} else if (message.type === "control_cancel_request") {
|
|
320
|
-
this.handleControlCancelRequest(message);
|
|
321
|
-
continue;
|
|
676
|
+
for await (const message of this.transport.readMessages()) {
|
|
677
|
+
if (message.type === "control_response") {
|
|
678
|
+
const handler = this.pendingControlResponses.get(message.response.request_id);
|
|
679
|
+
if (handler) {
|
|
680
|
+
handler(message.response);
|
|
322
681
|
}
|
|
323
|
-
|
|
682
|
+
continue;
|
|
683
|
+
} else if (message.type === "control_request") {
|
|
684
|
+
this.handleControlRequest(message);
|
|
685
|
+
continue;
|
|
686
|
+
} else if (message.type === "control_cancel_request") {
|
|
687
|
+
this.handleControlCancelRequest(message);
|
|
688
|
+
continue;
|
|
324
689
|
}
|
|
690
|
+
this.inputStream.enqueue(message);
|
|
325
691
|
}
|
|
326
|
-
|
|
692
|
+
this.inputStream.done();
|
|
693
|
+
this.cleanup();
|
|
327
694
|
} catch (error) {
|
|
328
695
|
this.inputStream.error(error);
|
|
329
|
-
|
|
330
|
-
this.inputStream.done();
|
|
331
|
-
rl.close();
|
|
696
|
+
this.cleanup(error);
|
|
332
697
|
}
|
|
333
698
|
}
|
|
334
699
|
async handleControlRequest(request) {
|
|
@@ -344,7 +709,7 @@ class Query {
|
|
|
344
709
|
response
|
|
345
710
|
}
|
|
346
711
|
};
|
|
347
|
-
this.
|
|
712
|
+
this.transport.write(JSON.stringify(controlResponse) + `
|
|
348
713
|
`);
|
|
349
714
|
} catch (error) {
|
|
350
715
|
const controlErrorResponse = {
|
|
@@ -355,7 +720,7 @@ class Query {
|
|
|
355
720
|
error: error.message || String(error)
|
|
356
721
|
}
|
|
357
722
|
};
|
|
358
|
-
this.
|
|
723
|
+
this.transport.write(JSON.stringify(controlErrorResponse) + `
|
|
359
724
|
`);
|
|
360
725
|
} finally {
|
|
361
726
|
this.cancelControllers.delete(request.request_id);
|
|
@@ -388,9 +753,6 @@ class Query {
|
|
|
388
753
|
}
|
|
389
754
|
}
|
|
390
755
|
async initialize() {
|
|
391
|
-
if (!this.childStdin) {
|
|
392
|
-
throw new Error("Cannot initialize without child stdin");
|
|
393
|
-
}
|
|
394
756
|
let hooks;
|
|
395
757
|
if (this.hooks) {
|
|
396
758
|
hooks = {};
|
|
@@ -415,27 +777,27 @@ class Query {
|
|
|
415
777
|
subtype: "initialize",
|
|
416
778
|
hooks
|
|
417
779
|
};
|
|
418
|
-
const response = await this.request(initRequest
|
|
780
|
+
const response = await this.request(initRequest);
|
|
419
781
|
return response.response;
|
|
420
782
|
}
|
|
421
783
|
async interrupt() {
|
|
422
|
-
if (!this.
|
|
784
|
+
if (!this.isStreamingMode) {
|
|
423
785
|
throw new Error("Interrupt requires --input-format stream-json");
|
|
424
786
|
}
|
|
425
787
|
await this.request({
|
|
426
788
|
subtype: "interrupt"
|
|
427
|
-
}
|
|
789
|
+
});
|
|
428
790
|
}
|
|
429
791
|
async setPermissionMode(mode) {
|
|
430
|
-
if (!this.
|
|
792
|
+
if (!this.isStreamingMode) {
|
|
431
793
|
throw new Error("setPermissionMode requires --input-format stream-json");
|
|
432
794
|
}
|
|
433
795
|
await this.request({
|
|
434
796
|
subtype: "set_permission_mode",
|
|
435
797
|
mode
|
|
436
|
-
}
|
|
798
|
+
});
|
|
437
799
|
}
|
|
438
|
-
request(request
|
|
800
|
+
request(request) {
|
|
439
801
|
const requestId = Math.random().toString(36).substring(2, 15);
|
|
440
802
|
const sdkRequest = {
|
|
441
803
|
request_id: requestId,
|
|
@@ -450,16 +812,34 @@ class Query {
|
|
|
450
812
|
reject(new Error(response.error));
|
|
451
813
|
}
|
|
452
814
|
});
|
|
453
|
-
|
|
815
|
+
this.transport.write(JSON.stringify(sdkRequest) + `
|
|
454
816
|
`);
|
|
455
817
|
});
|
|
456
818
|
}
|
|
457
819
|
async supportedCommands() {
|
|
820
|
+
if (!this.isStreamingMode) {
|
|
821
|
+
throw new Error("supportedCommands requires --input-format stream-json");
|
|
822
|
+
}
|
|
458
823
|
if (!this.intialization) {
|
|
459
|
-
throw new Error("
|
|
824
|
+
throw new Error("supportedCommands requires transport with bidirectional communication");
|
|
460
825
|
}
|
|
461
826
|
return (await this.intialization).commands;
|
|
462
827
|
}
|
|
828
|
+
async streamInput(stream) {
|
|
829
|
+
try {
|
|
830
|
+
for await (const message of stream) {
|
|
831
|
+
if (this.abortController?.signal.aborted)
|
|
832
|
+
break;
|
|
833
|
+
this.transport.write(JSON.stringify(message) + `
|
|
834
|
+
`);
|
|
835
|
+
}
|
|
836
|
+
this.transport.endInput();
|
|
837
|
+
} catch (error) {
|
|
838
|
+
if (!(error instanceof AbortError)) {
|
|
839
|
+
throw error;
|
|
840
|
+
}
|
|
841
|
+
}
|
|
842
|
+
}
|
|
463
843
|
handleHookCallbacks(callbackId, input, toolUseID, abortSignal) {
|
|
464
844
|
const callback = this.hookCallbacks.get(callbackId);
|
|
465
845
|
if (!callback) {
|
|
@@ -470,24 +850,11 @@ class Query {
|
|
|
470
850
|
});
|
|
471
851
|
}
|
|
472
852
|
}
|
|
473
|
-
async function streamToStdin(stream, stdin, abortController) {
|
|
474
|
-
for await (const message of stream) {
|
|
475
|
-
if (abortController.signal.aborted)
|
|
476
|
-
break;
|
|
477
|
-
stdin.write(JSON.stringify(message) + `
|
|
478
|
-
`);
|
|
479
|
-
}
|
|
480
|
-
stdin.end();
|
|
481
|
-
}
|
|
482
|
-
function logDebug(message) {
|
|
483
|
-
if (process.env.DEBUG) {
|
|
484
|
-
console.debug(message);
|
|
485
|
-
}
|
|
486
|
-
}
|
|
487
853
|
function isRunningWithBun() {
|
|
488
854
|
return process.versions.bun !== undefined || process.env.BUN_INSTALL !== undefined;
|
|
489
855
|
}
|
|
490
856
|
export {
|
|
491
857
|
query,
|
|
492
|
-
Query
|
|
858
|
+
Query,
|
|
859
|
+
AbortError
|
|
493
860
|
};
|