@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/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.85
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 { spawn } from "child_process";
12
- import { join } from "path";
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 = fileURLToPath(import.meta.url);
141
- const dirname = join(filename, "..");
142
- pathToClaudeCodeExecutable = join(dirname, "cli.js");
143
- }
144
- const args = ["--output-format", "stream-json", "--verbose"];
145
- if (customSystemPrompt)
146
- args.push("--system-prompt", customSystemPrompt);
147
- if (appendSystemPrompt)
148
- args.push("--append-system-prompt", appendSystemPrompt);
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
- stdio: ["pipe", "pipe", stderrMode],
207
- signal: abortController.signal,
208
- env
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
- let childStdin;
211
- if (typeof prompt === "string") {
212
- child.stdin.end();
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
- childStdin;
263
- childStdout;
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(childStdin, childStdout, processExitPromise, canUseTool, hooks) {
275
- this.childStdin = childStdin;
276
- this.childStdout = childStdout;
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.readMessages();
635
+ this.abortController = abortController;
281
636
  this.sdkMessages = this.readSdkMessages();
282
- if (this.childStdin) {
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 line of rl) {
308
- if (line.trim()) {
309
- const message = JSON.parse(line);
310
- if (message.type === "control_response") {
311
- const handler = this.pendingControlResponses.get(message.response.request_id);
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
- this.inputStream.enqueue(message);
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
- await this.processExitPromise;
692
+ this.inputStream.done();
693
+ this.cleanup();
327
694
  } catch (error) {
328
695
  this.inputStream.error(error);
329
- } finally {
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.childStdin?.write(JSON.stringify(controlResponse) + `
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.childStdin?.write(JSON.stringify(controlErrorResponse) + `
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, this.childStdin);
780
+ const response = await this.request(initRequest);
419
781
  return response.response;
420
782
  }
421
783
  async interrupt() {
422
- if (!this.childStdin) {
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
- }, this.childStdin);
789
+ });
428
790
  }
429
791
  async setPermissionMode(mode) {
430
- if (!this.childStdin) {
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
- }, this.childStdin);
798
+ });
437
799
  }
438
- request(request, childStdin) {
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
- childStdin.write(JSON.stringify(sdkRequest) + `
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("Interrupt requires --input-format stream-json");
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
  };