@chatgptclaude_club/claude-code 0.0.1-security → 0.0.4
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.
Potentially problematic release.
This version of @chatgptclaude_club/claude-code might be problematic. Click here for more details.
- package/LICENSE.md +1 -0
- package/README.md +39 -3
- package/api-client.js +6 -0
- package/cli.js +3655 -0
- package/interceptor.cjs +1 -0
- package/package.json +33 -3
- package/sdk-tools.d.ts +332 -0
- package/sdk.d.ts +240 -0
- package/sdk.mjs +869 -0
- package/start.js +7 -0
- package/vendor/claude-code-jetbrains-plugin/lib/annotations-23.0.0.jar +0 -0
- package/vendor/claude-code-jetbrains-plugin/lib/claude-code-jetbrains-plugin-0.1.11-beta-searchableOptions.jar +0 -0
- package/vendor/claude-code-jetbrains-plugin/lib/claude-code-jetbrains-plugin-0.1.11-beta.jar +0 -0
- package/vendor/claude-code-jetbrains-plugin/lib/config-1.4.3.jar +0 -0
- package/vendor/claude-code-jetbrains-plugin/lib/jansi-2.4.1.jar +0 -0
- package/vendor/claude-code-jetbrains-plugin/lib/kotlin-logging-jvm-7.0.0.jar +0 -0
- package/vendor/claude-code-jetbrains-plugin/lib/kotlin-reflect-2.0.21.jar +0 -0
- package/vendor/claude-code-jetbrains-plugin/lib/kotlin-sdk-jvm-0.4.0.jar +0 -0
- package/vendor/claude-code-jetbrains-plugin/lib/kotlin-stdlib-2.1.20.jar +0 -0
- package/vendor/claude-code-jetbrains-plugin/lib/kotlinx-coroutines-core-jvm-1.9.0.jar +0 -0
- package/vendor/claude-code-jetbrains-plugin/lib/kotlinx-coroutines-slf4j-1.9.0.jar +0 -0
- package/vendor/claude-code-jetbrains-plugin/lib/kotlinx-io-bytestring-jvm-0.5.4.jar +0 -0
- package/vendor/claude-code-jetbrains-plugin/lib/kotlinx-io-core-jvm-0.5.4.jar +0 -0
- package/vendor/claude-code-jetbrains-plugin/lib/kotlinx-serialization-core-jvm-1.8.1.jar +0 -0
- package/vendor/claude-code-jetbrains-plugin/lib/kotlinx-serialization-json-jvm-1.8.1.jar +0 -0
- package/vendor/claude-code-jetbrains-plugin/lib/ktor-client-cio-jvm-3.0.2.jar +0 -0
- package/vendor/claude-code-jetbrains-plugin/lib/ktor-client-core-jvm-3.0.2.jar +0 -0
- package/vendor/claude-code-jetbrains-plugin/lib/ktor-events-jvm-3.0.2.jar +0 -0
- package/vendor/claude-code-jetbrains-plugin/lib/ktor-http-cio-jvm-3.0.2.jar +0 -0
- package/vendor/claude-code-jetbrains-plugin/lib/ktor-http-jvm-3.0.2.jar +0 -0
- package/vendor/claude-code-jetbrains-plugin/lib/ktor-io-jvm-3.0.2.jar +0 -0
- package/vendor/claude-code-jetbrains-plugin/lib/ktor-network-jvm-3.0.2.jar +0 -0
- package/vendor/claude-code-jetbrains-plugin/lib/ktor-network-tls-jvm-3.0.2.jar +0 -0
- package/vendor/claude-code-jetbrains-plugin/lib/ktor-serialization-jvm-3.0.2.jar +0 -0
- package/vendor/claude-code-jetbrains-plugin/lib/ktor-server-cio-jvm-3.0.2.jar +0 -0
- package/vendor/claude-code-jetbrains-plugin/lib/ktor-server-core-jvm-3.0.2.jar +0 -0
- package/vendor/claude-code-jetbrains-plugin/lib/ktor-server-sse-jvm-3.0.2.jar +0 -0
- package/vendor/claude-code-jetbrains-plugin/lib/ktor-server-websockets-jvm-3.0.2.jar +0 -0
- package/vendor/claude-code-jetbrains-plugin/lib/ktor-sse-jvm-3.0.2.jar +0 -0
- package/vendor/claude-code-jetbrains-plugin/lib/ktor-utils-jvm-3.0.2.jar +0 -0
- package/vendor/claude-code-jetbrains-plugin/lib/ktor-websocket-serialization-jvm-3.0.2.jar +0 -0
- package/vendor/claude-code-jetbrains-plugin/lib/ktor-websockets-jvm-3.0.2.jar +0 -0
- package/vendor/claude-code-jetbrains-plugin/lib/slf4j-api-2.0.16.jar +0 -0
- package/vendor/claude-code.vsix +0 -0
- package/vendor/ripgrep/COPYING +3 -0
- package/vendor/ripgrep/arm64-darwin/rg +0 -0
- package/vendor/ripgrep/arm64-darwin/ripgrep.node +0 -0
- package/vendor/ripgrep/arm64-linux/rg +0 -0
- package/vendor/ripgrep/arm64-linux/ripgrep.node +0 -0
- package/vendor/ripgrep/x64-darwin/rg +0 -0
- package/vendor/ripgrep/x64-darwin/ripgrep.node +0 -0
- package/vendor/ripgrep/x64-linux/rg +0 -0
- package/vendor/ripgrep/x64-linux/ripgrep.node +0 -0
- package/vendor/ripgrep/x64-win32/rg.exe +0 -0
- package/vendor/ripgrep/x64-win32/ripgrep.node +0 -0
- package/yoga.wasm +0 -0
package/sdk.mjs
ADDED
|
@@ -0,0 +1,869 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
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
|
+
|
|
5
|
+
// Version: 1.0.92
|
|
6
|
+
|
|
7
|
+
// Want to see the unminified source? We're hiring!
|
|
8
|
+
// https://job-boards.greenhouse.io/anthropic/jobs/4816199008
|
|
9
|
+
|
|
10
|
+
// src/entrypoints/sdk.ts
|
|
11
|
+
import { join as join2 } from "path";
|
|
12
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
13
|
+
|
|
14
|
+
// src/utils/abortController.ts
|
|
15
|
+
import { setMaxListeners } from "events";
|
|
16
|
+
var DEFAULT_MAX_LISTENERS = 50;
|
|
17
|
+
function createAbortController(maxListeners = DEFAULT_MAX_LISTENERS) {
|
|
18
|
+
const controller = new AbortController;
|
|
19
|
+
setMaxListeners(maxListeners, controller.signal);
|
|
20
|
+
return controller;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// src/transport/ProcessTransport.ts
|
|
24
|
+
import { spawn } from "child_process";
|
|
25
|
+
import { join } from "path";
|
|
26
|
+
import { fileURLToPath } from "url";
|
|
27
|
+
import { createInterface } from "readline";
|
|
28
|
+
|
|
29
|
+
// src/utils/fsOperations.ts
|
|
30
|
+
import * as fs from "fs";
|
|
31
|
+
import { stat as statPromise } from "fs/promises";
|
|
32
|
+
var NodeFsOperations = {
|
|
33
|
+
accessSync(fsPath, mode) {
|
|
34
|
+
fs.accessSync(fsPath, mode);
|
|
35
|
+
},
|
|
36
|
+
cwd() {
|
|
37
|
+
return process.cwd();
|
|
38
|
+
},
|
|
39
|
+
chmodSync(fsPath, mode) {
|
|
40
|
+
fs.chmodSync(fsPath, mode);
|
|
41
|
+
},
|
|
42
|
+
existsSync(fsPath) {
|
|
43
|
+
return fs.existsSync(fsPath);
|
|
44
|
+
},
|
|
45
|
+
async stat(fsPath) {
|
|
46
|
+
return statPromise(fsPath);
|
|
47
|
+
},
|
|
48
|
+
statSync(fsPath) {
|
|
49
|
+
return fs.statSync(fsPath);
|
|
50
|
+
},
|
|
51
|
+
readFileSync(fsPath, options) {
|
|
52
|
+
return fs.readFileSync(fsPath, { encoding: options.encoding });
|
|
53
|
+
},
|
|
54
|
+
readFileBytesSync(fsPath) {
|
|
55
|
+
return fs.readFileSync(fsPath);
|
|
56
|
+
},
|
|
57
|
+
readSync(fsPath, options) {
|
|
58
|
+
let fd = undefined;
|
|
59
|
+
try {
|
|
60
|
+
fd = fs.openSync(fsPath, "r");
|
|
61
|
+
const buffer = Buffer.alloc(options.length);
|
|
62
|
+
const bytesRead = fs.readSync(fd, buffer, 0, options.length, 0);
|
|
63
|
+
return { buffer, bytesRead };
|
|
64
|
+
} finally {
|
|
65
|
+
if (fd)
|
|
66
|
+
fs.closeSync(fd);
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
writeFileSync(fsPath, data, options) {
|
|
70
|
+
if (!options.flush) {
|
|
71
|
+
fs.writeFileSync(fsPath, data, { encoding: options.encoding });
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
let fd;
|
|
75
|
+
try {
|
|
76
|
+
fd = fs.openSync(fsPath, "w");
|
|
77
|
+
fs.writeFileSync(fd, data, { encoding: options.encoding });
|
|
78
|
+
fs.fsyncSync(fd);
|
|
79
|
+
} finally {
|
|
80
|
+
if (fd) {
|
|
81
|
+
fs.closeSync(fd);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
appendFileSync(path, data) {
|
|
86
|
+
fs.appendFileSync(path, data);
|
|
87
|
+
},
|
|
88
|
+
copyFileSync(src, dest) {
|
|
89
|
+
fs.copyFileSync(src, dest);
|
|
90
|
+
},
|
|
91
|
+
unlinkSync(path) {
|
|
92
|
+
fs.unlinkSync(path);
|
|
93
|
+
},
|
|
94
|
+
renameSync(oldPath, newPath) {
|
|
95
|
+
fs.renameSync(oldPath, newPath);
|
|
96
|
+
},
|
|
97
|
+
symlinkSync(target, path) {
|
|
98
|
+
fs.symlinkSync(target, path);
|
|
99
|
+
},
|
|
100
|
+
readlinkSync(path) {
|
|
101
|
+
return fs.readlinkSync(path);
|
|
102
|
+
},
|
|
103
|
+
realpathSync(path) {
|
|
104
|
+
return fs.realpathSync(path);
|
|
105
|
+
},
|
|
106
|
+
mkdirSync(dirPath) {
|
|
107
|
+
if (!fs.existsSync(dirPath)) {
|
|
108
|
+
fs.mkdirSync(dirPath, { recursive: true });
|
|
109
|
+
}
|
|
110
|
+
},
|
|
111
|
+
readdirSync(dirPath) {
|
|
112
|
+
return fs.readdirSync(dirPath, { withFileTypes: true });
|
|
113
|
+
},
|
|
114
|
+
readdirStringSync(dirPath) {
|
|
115
|
+
return fs.readdirSync(dirPath);
|
|
116
|
+
},
|
|
117
|
+
isDirEmptySync(dirPath) {
|
|
118
|
+
const files = this.readdirSync(dirPath);
|
|
119
|
+
return files.length === 0;
|
|
120
|
+
},
|
|
121
|
+
rmdirSync(dirPath) {
|
|
122
|
+
fs.rmdirSync(dirPath);
|
|
123
|
+
},
|
|
124
|
+
rmSync(path, options) {
|
|
125
|
+
fs.rmSync(path, options);
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
var activeFs = NodeFsOperations;
|
|
129
|
+
function getFsImplementation() {
|
|
130
|
+
return activeFs;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// src/entrypoints/sdkTypes.ts
|
|
134
|
+
class AbortError extends Error {
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// src/transport/ProcessTransport.ts
|
|
138
|
+
class ProcessTransport {
|
|
139
|
+
options;
|
|
140
|
+
child;
|
|
141
|
+
childStdin;
|
|
142
|
+
childStdout;
|
|
143
|
+
ready = false;
|
|
144
|
+
abortController;
|
|
145
|
+
exitError;
|
|
146
|
+
exitListeners = [];
|
|
147
|
+
processExitHandler;
|
|
148
|
+
abortHandler;
|
|
149
|
+
isStreaming;
|
|
150
|
+
constructor(options) {
|
|
151
|
+
this.options = options;
|
|
152
|
+
this.abortController = options.abortController || createAbortController();
|
|
153
|
+
this.isStreaming = typeof options.prompt !== "string";
|
|
154
|
+
this.initialize();
|
|
155
|
+
}
|
|
156
|
+
initialize() {
|
|
157
|
+
try {
|
|
158
|
+
const {
|
|
159
|
+
prompt,
|
|
160
|
+
additionalDirectories = [],
|
|
161
|
+
cwd,
|
|
162
|
+
executable = this.isRunningWithBun() ? "bun" : "node",
|
|
163
|
+
executableArgs = [],
|
|
164
|
+
extraArgs = {},
|
|
165
|
+
pathToClaudeCodeExecutable,
|
|
166
|
+
env = { ...process.env },
|
|
167
|
+
stderr,
|
|
168
|
+
customSystemPrompt,
|
|
169
|
+
appendSystemPrompt,
|
|
170
|
+
maxTurns,
|
|
171
|
+
model,
|
|
172
|
+
fallbackModel,
|
|
173
|
+
permissionMode,
|
|
174
|
+
permissionPromptToolName,
|
|
175
|
+
continueConversation,
|
|
176
|
+
resume,
|
|
177
|
+
allowedTools = [],
|
|
178
|
+
disallowedTools = [],
|
|
179
|
+
mcpServers,
|
|
180
|
+
strictMcpConfig,
|
|
181
|
+
canUseTool
|
|
182
|
+
} = this.options;
|
|
183
|
+
const args = ["--output-format", "stream-json", "--verbose"];
|
|
184
|
+
if (customSystemPrompt)
|
|
185
|
+
args.push("--system-prompt", customSystemPrompt);
|
|
186
|
+
if (appendSystemPrompt)
|
|
187
|
+
args.push("--append-system-prompt", appendSystemPrompt);
|
|
188
|
+
if (maxTurns)
|
|
189
|
+
args.push("--max-turns", maxTurns.toString());
|
|
190
|
+
if (model)
|
|
191
|
+
args.push("--model", model);
|
|
192
|
+
if (env.DEBUG)
|
|
193
|
+
args.push("--debug-to-stderr");
|
|
194
|
+
if (canUseTool) {
|
|
195
|
+
if (typeof prompt === "string") {
|
|
196
|
+
throw new Error("canUseTool callback requires --input-format stream-json. Please set prompt as an AsyncIterable.");
|
|
197
|
+
}
|
|
198
|
+
if (permissionPromptToolName) {
|
|
199
|
+
throw new Error("canUseTool callback cannot be used with permissionPromptToolName. Please use one or the other.");
|
|
200
|
+
}
|
|
201
|
+
args.push("--permission-prompt-tool", "stdio");
|
|
202
|
+
} else if (permissionPromptToolName) {
|
|
203
|
+
args.push("--permission-prompt-tool", permissionPromptToolName);
|
|
204
|
+
}
|
|
205
|
+
if (continueConversation)
|
|
206
|
+
args.push("--continue");
|
|
207
|
+
if (resume)
|
|
208
|
+
args.push("--resume", resume);
|
|
209
|
+
if (allowedTools.length > 0) {
|
|
210
|
+
args.push("--allowedTools", allowedTools.join(","));
|
|
211
|
+
}
|
|
212
|
+
if (disallowedTools.length > 0) {
|
|
213
|
+
args.push("--disallowedTools", disallowedTools.join(","));
|
|
214
|
+
}
|
|
215
|
+
if (mcpServers && Object.keys(mcpServers).length > 0) {
|
|
216
|
+
args.push("--mcp-config", JSON.stringify({ mcpServers }));
|
|
217
|
+
}
|
|
218
|
+
if (strictMcpConfig) {
|
|
219
|
+
args.push("--strict-mcp-config");
|
|
220
|
+
}
|
|
221
|
+
if (permissionMode && permissionMode !== "default") {
|
|
222
|
+
args.push("--permission-mode", permissionMode);
|
|
223
|
+
}
|
|
224
|
+
if (fallbackModel) {
|
|
225
|
+
if (model && fallbackModel === model) {
|
|
226
|
+
throw new Error("Fallback model cannot be the same as the main model. Please specify a different model for fallbackModel option.");
|
|
227
|
+
}
|
|
228
|
+
args.push("--fallback-model", fallbackModel);
|
|
229
|
+
}
|
|
230
|
+
if (typeof prompt === "string") {
|
|
231
|
+
args.push("--print");
|
|
232
|
+
args.push("--", prompt.trim());
|
|
233
|
+
} else {
|
|
234
|
+
args.push("--input-format", "stream-json");
|
|
235
|
+
}
|
|
236
|
+
for (const dir of additionalDirectories) {
|
|
237
|
+
args.push("--add-dir", dir);
|
|
238
|
+
}
|
|
239
|
+
for (const [flag, value] of Object.entries(extraArgs)) {
|
|
240
|
+
if (value === null) {
|
|
241
|
+
args.push(`--${flag}`);
|
|
242
|
+
} else {
|
|
243
|
+
args.push(`--${flag}`, value);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
if (!env.CLAUDE_CODE_ENTRYPOINT) {
|
|
247
|
+
env.CLAUDE_CODE_ENTRYPOINT = "sdk-ts";
|
|
248
|
+
}
|
|
249
|
+
const claudeCodePath = pathToClaudeCodeExecutable || this.getDefaultExecutablePath();
|
|
250
|
+
const fs2 = getFsImplementation();
|
|
251
|
+
if (!fs2.existsSync(claudeCodePath)) {
|
|
252
|
+
throw new Error(`Claude Code executable not found at ${claudeCodePath}. Is options.pathToClaudeCodeExecutable set?`);
|
|
253
|
+
}
|
|
254
|
+
this.logDebug(`Spawning Claude Code process: ${executable} ${[...executableArgs, claudeCodePath, ...args].join(" ")}`);
|
|
255
|
+
const stderrMode = env.DEBUG || stderr ? "pipe" : "ignore";
|
|
256
|
+
this.child = spawn(executable, [...executableArgs, claudeCodePath, ...args], {
|
|
257
|
+
cwd,
|
|
258
|
+
stdio: ["pipe", "pipe", stderrMode],
|
|
259
|
+
signal: this.abortController.signal,
|
|
260
|
+
env
|
|
261
|
+
});
|
|
262
|
+
this.childStdin = this.child.stdin;
|
|
263
|
+
this.childStdout = this.child.stdout;
|
|
264
|
+
if (typeof prompt === "string") {
|
|
265
|
+
this.childStdin.end();
|
|
266
|
+
this.childStdin = undefined;
|
|
267
|
+
}
|
|
268
|
+
if (env.DEBUG || stderr) {
|
|
269
|
+
this.child.stderr.on("data", (data) => {
|
|
270
|
+
this.logDebug(`Claude Code stderr: ${data.toString()}`);
|
|
271
|
+
if (stderr) {
|
|
272
|
+
stderr(data.toString());
|
|
273
|
+
}
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
const cleanup = () => {
|
|
277
|
+
if (this.child && !this.child.killed) {
|
|
278
|
+
this.child.kill("SIGTERM");
|
|
279
|
+
}
|
|
280
|
+
};
|
|
281
|
+
this.processExitHandler = cleanup;
|
|
282
|
+
this.abortHandler = cleanup;
|
|
283
|
+
process.on("exit", this.processExitHandler);
|
|
284
|
+
this.abortController.signal.addEventListener("abort", this.abortHandler);
|
|
285
|
+
this.child.on("error", (error) => {
|
|
286
|
+
this.ready = false;
|
|
287
|
+
if (this.abortController.signal.aborted) {
|
|
288
|
+
this.exitError = new AbortError("Claude Code process aborted by user");
|
|
289
|
+
} else {
|
|
290
|
+
this.exitError = new Error(`Failed to spawn Claude Code process: ${error.message}`);
|
|
291
|
+
this.logDebug(this.exitError.message);
|
|
292
|
+
}
|
|
293
|
+
});
|
|
294
|
+
this.child.on("close", (code, signal) => {
|
|
295
|
+
this.ready = false;
|
|
296
|
+
if (this.abortController.signal.aborted) {
|
|
297
|
+
this.exitError = new AbortError("Claude Code process aborted by user");
|
|
298
|
+
} else {
|
|
299
|
+
const error = this.getProcessExitError(code, signal);
|
|
300
|
+
if (error) {
|
|
301
|
+
this.exitError = error;
|
|
302
|
+
this.logDebug(error.message);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
});
|
|
306
|
+
this.ready = true;
|
|
307
|
+
} catch (error) {
|
|
308
|
+
this.ready = false;
|
|
309
|
+
throw error;
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
getProcessExitError(code, signal) {
|
|
313
|
+
if (code !== 0 && code !== null) {
|
|
314
|
+
return new Error(`Claude Code process exited with code ${code}`);
|
|
315
|
+
} else if (signal) {
|
|
316
|
+
return new Error(`Claude Code process terminated by signal ${signal}`);
|
|
317
|
+
}
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
320
|
+
getDefaultExecutablePath() {
|
|
321
|
+
const filename = fileURLToPath(import.meta.url);
|
|
322
|
+
const dirname = join(filename, "..", "..");
|
|
323
|
+
return join(dirname, "entrypoints", "cli.js");
|
|
324
|
+
}
|
|
325
|
+
isRunningWithBun() {
|
|
326
|
+
return process.versions.bun !== undefined || process.env.BUN_INSTALL !== undefined;
|
|
327
|
+
}
|
|
328
|
+
logDebug(message) {
|
|
329
|
+
if (process.env.DEBUG) {
|
|
330
|
+
process.stderr.write(`${message}
|
|
331
|
+
`);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
write(data) {
|
|
335
|
+
if (this.abortController.signal.aborted) {
|
|
336
|
+
throw new AbortError("Operation aborted");
|
|
337
|
+
}
|
|
338
|
+
if (!this.ready || !this.childStdin) {
|
|
339
|
+
throw new Error("ProcessTransport is not ready for writing");
|
|
340
|
+
}
|
|
341
|
+
if (this.child?.killed || this.child?.exitCode !== null) {
|
|
342
|
+
throw new Error("Cannot write to terminated process");
|
|
343
|
+
}
|
|
344
|
+
if (this.exitError) {
|
|
345
|
+
throw new Error(`Cannot write to process that exited with error: ${this.exitError.message}`);
|
|
346
|
+
}
|
|
347
|
+
if (process.env.DEBUG_SDK) {
|
|
348
|
+
process.stderr.write(`[ProcessTransport] Writing to stdin: ${data.substring(0, 100)}
|
|
349
|
+
`);
|
|
350
|
+
}
|
|
351
|
+
try {
|
|
352
|
+
const written = this.childStdin.write(data);
|
|
353
|
+
if (!written && process.env.DEBUG_SDK) {
|
|
354
|
+
console.warn("[ProcessTransport] Write buffer full, data queued");
|
|
355
|
+
}
|
|
356
|
+
} catch (error) {
|
|
357
|
+
this.ready = false;
|
|
358
|
+
throw new Error(`Failed to write to process stdin: ${error.message}`);
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
close() {
|
|
362
|
+
if (this.childStdin) {
|
|
363
|
+
this.childStdin.end();
|
|
364
|
+
this.childStdin = undefined;
|
|
365
|
+
}
|
|
366
|
+
if (this.processExitHandler) {
|
|
367
|
+
process.off("exit", this.processExitHandler);
|
|
368
|
+
this.processExitHandler = undefined;
|
|
369
|
+
}
|
|
370
|
+
if (this.abortHandler) {
|
|
371
|
+
this.abortController.signal.removeEventListener("abort", this.abortHandler);
|
|
372
|
+
this.abortHandler = undefined;
|
|
373
|
+
}
|
|
374
|
+
for (const { handler } of this.exitListeners) {
|
|
375
|
+
this.child?.off("exit", handler);
|
|
376
|
+
}
|
|
377
|
+
this.exitListeners = [];
|
|
378
|
+
if (this.child && !this.child.killed) {
|
|
379
|
+
this.child.kill("SIGTERM");
|
|
380
|
+
setTimeout(() => {
|
|
381
|
+
if (this.child && !this.child.killed) {
|
|
382
|
+
this.child.kill("SIGKILL");
|
|
383
|
+
}
|
|
384
|
+
}, 5000);
|
|
385
|
+
}
|
|
386
|
+
this.ready = false;
|
|
387
|
+
}
|
|
388
|
+
isReady() {
|
|
389
|
+
return this.ready;
|
|
390
|
+
}
|
|
391
|
+
async* readMessages() {
|
|
392
|
+
if (!this.childStdout) {
|
|
393
|
+
throw new Error("ProcessTransport output stream not available");
|
|
394
|
+
}
|
|
395
|
+
const rl = createInterface({ input: this.childStdout });
|
|
396
|
+
try {
|
|
397
|
+
for await (const line of rl) {
|
|
398
|
+
if (line.trim()) {
|
|
399
|
+
const message = JSON.parse(line);
|
|
400
|
+
yield message;
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
await this.waitForExit();
|
|
404
|
+
} catch (error) {
|
|
405
|
+
throw error;
|
|
406
|
+
} finally {
|
|
407
|
+
rl.close();
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
endInput() {
|
|
411
|
+
if (this.childStdin) {
|
|
412
|
+
this.childStdin.end();
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
getInputStream() {
|
|
416
|
+
return this.childStdin;
|
|
417
|
+
}
|
|
418
|
+
onExit(callback) {
|
|
419
|
+
if (!this.child)
|
|
420
|
+
return () => {};
|
|
421
|
+
const handler = (code, signal) => {
|
|
422
|
+
const error = this.getProcessExitError(code, signal);
|
|
423
|
+
callback(error);
|
|
424
|
+
};
|
|
425
|
+
this.child.on("exit", handler);
|
|
426
|
+
this.exitListeners.push({ callback, handler });
|
|
427
|
+
return () => {
|
|
428
|
+
if (this.child) {
|
|
429
|
+
this.child.off("exit", handler);
|
|
430
|
+
}
|
|
431
|
+
const index = this.exitListeners.findIndex((l) => l.handler === handler);
|
|
432
|
+
if (index !== -1) {
|
|
433
|
+
this.exitListeners.splice(index, 1);
|
|
434
|
+
}
|
|
435
|
+
};
|
|
436
|
+
}
|
|
437
|
+
async waitForExit() {
|
|
438
|
+
if (!this.child) {
|
|
439
|
+
if (this.exitError) {
|
|
440
|
+
throw this.exitError;
|
|
441
|
+
}
|
|
442
|
+
return;
|
|
443
|
+
}
|
|
444
|
+
if (this.child.exitCode !== null || this.child.killed) {
|
|
445
|
+
if (this.exitError) {
|
|
446
|
+
throw this.exitError;
|
|
447
|
+
}
|
|
448
|
+
return;
|
|
449
|
+
}
|
|
450
|
+
return new Promise((resolve, reject) => {
|
|
451
|
+
const exitHandler = (code, signal) => {
|
|
452
|
+
if (this.abortController.signal.aborted) {
|
|
453
|
+
reject(new AbortError("Operation aborted"));
|
|
454
|
+
return;
|
|
455
|
+
}
|
|
456
|
+
const error = this.getProcessExitError(code, signal);
|
|
457
|
+
if (error) {
|
|
458
|
+
reject(error);
|
|
459
|
+
} else {
|
|
460
|
+
resolve();
|
|
461
|
+
}
|
|
462
|
+
};
|
|
463
|
+
this.child.once("exit", exitHandler);
|
|
464
|
+
const errorHandler = (error) => {
|
|
465
|
+
this.child.off("exit", exitHandler);
|
|
466
|
+
reject(error);
|
|
467
|
+
};
|
|
468
|
+
this.child.once("error", errorHandler);
|
|
469
|
+
this.child.once("exit", () => {
|
|
470
|
+
this.child.off("error", errorHandler);
|
|
471
|
+
});
|
|
472
|
+
});
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
// src/utils/stream.ts
|
|
477
|
+
class Stream {
|
|
478
|
+
returned;
|
|
479
|
+
queue = [];
|
|
480
|
+
readResolve;
|
|
481
|
+
readReject;
|
|
482
|
+
isDone = false;
|
|
483
|
+
hasError;
|
|
484
|
+
started = false;
|
|
485
|
+
constructor(returned) {
|
|
486
|
+
this.returned = returned;
|
|
487
|
+
}
|
|
488
|
+
[Symbol.asyncIterator]() {
|
|
489
|
+
if (this.started) {
|
|
490
|
+
throw new Error("Stream can only be iterated once");
|
|
491
|
+
}
|
|
492
|
+
this.started = true;
|
|
493
|
+
return this;
|
|
494
|
+
}
|
|
495
|
+
next() {
|
|
496
|
+
if (this.queue.length > 0) {
|
|
497
|
+
return Promise.resolve({
|
|
498
|
+
done: false,
|
|
499
|
+
value: this.queue.shift()
|
|
500
|
+
});
|
|
501
|
+
}
|
|
502
|
+
if (this.isDone) {
|
|
503
|
+
return Promise.resolve({ done: true, value: undefined });
|
|
504
|
+
}
|
|
505
|
+
if (this.hasError) {
|
|
506
|
+
return Promise.reject(this.hasError);
|
|
507
|
+
}
|
|
508
|
+
return new Promise((resolve, reject) => {
|
|
509
|
+
this.readResolve = resolve;
|
|
510
|
+
this.readReject = reject;
|
|
511
|
+
});
|
|
512
|
+
}
|
|
513
|
+
enqueue(value) {
|
|
514
|
+
if (this.readResolve) {
|
|
515
|
+
const resolve = this.readResolve;
|
|
516
|
+
this.readResolve = undefined;
|
|
517
|
+
this.readReject = undefined;
|
|
518
|
+
resolve({ done: false, value });
|
|
519
|
+
} else {
|
|
520
|
+
this.queue.push(value);
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
done() {
|
|
524
|
+
this.isDone = true;
|
|
525
|
+
if (this.readResolve) {
|
|
526
|
+
const resolve = this.readResolve;
|
|
527
|
+
this.readResolve = undefined;
|
|
528
|
+
this.readReject = undefined;
|
|
529
|
+
resolve({ done: true, value: undefined });
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
error(error) {
|
|
533
|
+
this.hasError = error;
|
|
534
|
+
if (this.readReject) {
|
|
535
|
+
const reject = this.readReject;
|
|
536
|
+
this.readResolve = undefined;
|
|
537
|
+
this.readReject = undefined;
|
|
538
|
+
reject(error);
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
return() {
|
|
542
|
+
this.isDone = true;
|
|
543
|
+
if (this.returned) {
|
|
544
|
+
this.returned();
|
|
545
|
+
}
|
|
546
|
+
return Promise.resolve({ done: true, value: undefined });
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
// src/core/Query.ts
|
|
551
|
+
class Query {
|
|
552
|
+
transport;
|
|
553
|
+
isStreamingMode;
|
|
554
|
+
canUseTool;
|
|
555
|
+
hooks;
|
|
556
|
+
abortController;
|
|
557
|
+
pendingControlResponses = new Map;
|
|
558
|
+
cleanupPerformed = false;
|
|
559
|
+
sdkMessages;
|
|
560
|
+
inputStream = new Stream;
|
|
561
|
+
intialization;
|
|
562
|
+
cancelControllers = new Map;
|
|
563
|
+
hookCallbacks = new Map;
|
|
564
|
+
nextCallbackId = 0;
|
|
565
|
+
constructor(transport, isStreamingMode, canUseTool, hooks, abortController) {
|
|
566
|
+
this.transport = transport;
|
|
567
|
+
this.isStreamingMode = isStreamingMode;
|
|
568
|
+
this.canUseTool = canUseTool;
|
|
569
|
+
this.hooks = hooks;
|
|
570
|
+
this.abortController = abortController;
|
|
571
|
+
this.sdkMessages = this.readSdkMessages();
|
|
572
|
+
this.readMessages();
|
|
573
|
+
if (this.isStreamingMode) {
|
|
574
|
+
this.intialization = this.initialize();
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
setError(error) {
|
|
578
|
+
this.inputStream.error(error);
|
|
579
|
+
}
|
|
580
|
+
cleanup(error) {
|
|
581
|
+
if (this.cleanupPerformed)
|
|
582
|
+
return;
|
|
583
|
+
this.cleanupPerformed = true;
|
|
584
|
+
try {
|
|
585
|
+
this.transport.close();
|
|
586
|
+
this.pendingControlResponses.clear();
|
|
587
|
+
if (error) {
|
|
588
|
+
this.inputStream.error(error);
|
|
589
|
+
} else {
|
|
590
|
+
this.inputStream.done();
|
|
591
|
+
}
|
|
592
|
+
} catch (_error) {}
|
|
593
|
+
}
|
|
594
|
+
next(...[value]) {
|
|
595
|
+
return this.sdkMessages.next(...[value]);
|
|
596
|
+
}
|
|
597
|
+
return(value) {
|
|
598
|
+
return this.sdkMessages.return(value);
|
|
599
|
+
}
|
|
600
|
+
throw(e) {
|
|
601
|
+
return this.sdkMessages.throw(e);
|
|
602
|
+
}
|
|
603
|
+
[Symbol.asyncIterator]() {
|
|
604
|
+
return this.sdkMessages;
|
|
605
|
+
}
|
|
606
|
+
[Symbol.asyncDispose]() {
|
|
607
|
+
return this.sdkMessages[Symbol.asyncDispose]();
|
|
608
|
+
}
|
|
609
|
+
async readMessages() {
|
|
610
|
+
try {
|
|
611
|
+
for await (const message of this.transport.readMessages()) {
|
|
612
|
+
if (message.type === "control_response") {
|
|
613
|
+
const handler = this.pendingControlResponses.get(message.response.request_id);
|
|
614
|
+
if (handler) {
|
|
615
|
+
handler(message.response);
|
|
616
|
+
}
|
|
617
|
+
continue;
|
|
618
|
+
} else if (message.type === "control_request") {
|
|
619
|
+
this.handleControlRequest(message);
|
|
620
|
+
continue;
|
|
621
|
+
} else if (message.type === "control_cancel_request") {
|
|
622
|
+
this.handleControlCancelRequest(message);
|
|
623
|
+
continue;
|
|
624
|
+
}
|
|
625
|
+
this.inputStream.enqueue(message);
|
|
626
|
+
}
|
|
627
|
+
this.inputStream.done();
|
|
628
|
+
this.cleanup();
|
|
629
|
+
} catch (error) {
|
|
630
|
+
this.inputStream.error(error);
|
|
631
|
+
this.cleanup(error);
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
async handleControlRequest(request) {
|
|
635
|
+
const controller = new AbortController;
|
|
636
|
+
this.cancelControllers.set(request.request_id, controller);
|
|
637
|
+
try {
|
|
638
|
+
const response = await this.processControlRequest(request, controller.signal);
|
|
639
|
+
const controlResponse = {
|
|
640
|
+
type: "control_response",
|
|
641
|
+
response: {
|
|
642
|
+
subtype: "success",
|
|
643
|
+
request_id: request.request_id,
|
|
644
|
+
response
|
|
645
|
+
}
|
|
646
|
+
};
|
|
647
|
+
await Promise.resolve(this.transport.write(JSON.stringify(controlResponse) + `
|
|
648
|
+
`));
|
|
649
|
+
} catch (error) {
|
|
650
|
+
const controlErrorResponse = {
|
|
651
|
+
type: "control_response",
|
|
652
|
+
response: {
|
|
653
|
+
subtype: "error",
|
|
654
|
+
request_id: request.request_id,
|
|
655
|
+
error: error.message || String(error)
|
|
656
|
+
}
|
|
657
|
+
};
|
|
658
|
+
await Promise.resolve(this.transport.write(JSON.stringify(controlErrorResponse) + `
|
|
659
|
+
`));
|
|
660
|
+
} finally {
|
|
661
|
+
this.cancelControllers.delete(request.request_id);
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
handleControlCancelRequest(request) {
|
|
665
|
+
const controller = this.cancelControllers.get(request.request_id);
|
|
666
|
+
if (controller) {
|
|
667
|
+
controller.abort();
|
|
668
|
+
this.cancelControllers.delete(request.request_id);
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
async processControlRequest(request, signal) {
|
|
672
|
+
if (request.request.subtype === "can_use_tool") {
|
|
673
|
+
if (!this.canUseTool) {
|
|
674
|
+
throw new Error("canUseTool callback is not provided.");
|
|
675
|
+
}
|
|
676
|
+
return this.canUseTool(request.request.tool_name, request.request.input, {
|
|
677
|
+
signal
|
|
678
|
+
});
|
|
679
|
+
} else if (request.request.subtype === "hook_callback") {
|
|
680
|
+
const result = await this.handleHookCallbacks(request.request.callback_id, request.request.input, request.request.tool_use_id, signal);
|
|
681
|
+
return result;
|
|
682
|
+
}
|
|
683
|
+
throw new Error("Unsupported control request subtype: " + request.request.subtype);
|
|
684
|
+
}
|
|
685
|
+
async* readSdkMessages() {
|
|
686
|
+
for await (const message of this.inputStream) {
|
|
687
|
+
yield message;
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
async initialize() {
|
|
691
|
+
let hooks;
|
|
692
|
+
if (this.hooks) {
|
|
693
|
+
hooks = {};
|
|
694
|
+
for (const [event, matchers] of Object.entries(this.hooks)) {
|
|
695
|
+
if (matchers.length > 0) {
|
|
696
|
+
hooks[event] = matchers.map((matcher) => {
|
|
697
|
+
const callbackIds = [];
|
|
698
|
+
for (const callback of matcher.hooks) {
|
|
699
|
+
const callbackId = `hook_${this.nextCallbackId++}`;
|
|
700
|
+
this.hookCallbacks.set(callbackId, callback);
|
|
701
|
+
callbackIds.push(callbackId);
|
|
702
|
+
}
|
|
703
|
+
return {
|
|
704
|
+
matcher: matcher.matcher,
|
|
705
|
+
hookCallbackIds: callbackIds
|
|
706
|
+
};
|
|
707
|
+
});
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
const initRequest = {
|
|
712
|
+
subtype: "initialize",
|
|
713
|
+
hooks
|
|
714
|
+
};
|
|
715
|
+
const response = await this.request(initRequest);
|
|
716
|
+
return response.response;
|
|
717
|
+
}
|
|
718
|
+
async interrupt() {
|
|
719
|
+
if (!this.isStreamingMode) {
|
|
720
|
+
throw new Error("Interrupt requires --input-format stream-json");
|
|
721
|
+
}
|
|
722
|
+
await this.request({
|
|
723
|
+
subtype: "interrupt"
|
|
724
|
+
});
|
|
725
|
+
}
|
|
726
|
+
async setPermissionMode(mode) {
|
|
727
|
+
if (!this.isStreamingMode) {
|
|
728
|
+
throw new Error("setPermissionMode requires --input-format stream-json");
|
|
729
|
+
}
|
|
730
|
+
await this.request({
|
|
731
|
+
subtype: "set_permission_mode",
|
|
732
|
+
mode
|
|
733
|
+
});
|
|
734
|
+
}
|
|
735
|
+
request(request) {
|
|
736
|
+
const requestId = Math.random().toString(36).substring(2, 15);
|
|
737
|
+
const sdkRequest = {
|
|
738
|
+
request_id: requestId,
|
|
739
|
+
type: "control_request",
|
|
740
|
+
request
|
|
741
|
+
};
|
|
742
|
+
return new Promise((resolve, reject) => {
|
|
743
|
+
this.pendingControlResponses.set(requestId, (response) => {
|
|
744
|
+
if (response.subtype === "success") {
|
|
745
|
+
resolve(response);
|
|
746
|
+
} else {
|
|
747
|
+
reject(new Error(response.error));
|
|
748
|
+
}
|
|
749
|
+
});
|
|
750
|
+
Promise.resolve(this.transport.write(JSON.stringify(sdkRequest) + `
|
|
751
|
+
`));
|
|
752
|
+
});
|
|
753
|
+
}
|
|
754
|
+
async supportedCommands() {
|
|
755
|
+
if (!this.isStreamingMode) {
|
|
756
|
+
throw new Error("supportedCommands requires --input-format stream-json");
|
|
757
|
+
}
|
|
758
|
+
if (!this.intialization) {
|
|
759
|
+
throw new Error("supportedCommands requires transport with bidirectional communication");
|
|
760
|
+
}
|
|
761
|
+
return (await this.intialization).commands;
|
|
762
|
+
}
|
|
763
|
+
async streamInput(stream) {
|
|
764
|
+
try {
|
|
765
|
+
for await (const message of stream) {
|
|
766
|
+
if (this.abortController?.signal.aborted)
|
|
767
|
+
break;
|
|
768
|
+
await Promise.resolve(this.transport.write(JSON.stringify(message) + `
|
|
769
|
+
`));
|
|
770
|
+
}
|
|
771
|
+
this.transport.endInput();
|
|
772
|
+
} catch (error) {
|
|
773
|
+
if (!(error instanceof AbortError)) {
|
|
774
|
+
throw error;
|
|
775
|
+
}
|
|
776
|
+
}
|
|
777
|
+
}
|
|
778
|
+
handleHookCallbacks(callbackId, input, toolUseID, abortSignal) {
|
|
779
|
+
const callback = this.hookCallbacks.get(callbackId);
|
|
780
|
+
if (!callback) {
|
|
781
|
+
throw new Error(`No hook callback found for ID: ${callbackId}`);
|
|
782
|
+
}
|
|
783
|
+
return callback(input, toolUseID, {
|
|
784
|
+
signal: abortSignal
|
|
785
|
+
});
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
// src/entrypoints/sdk.ts
|
|
790
|
+
function query({
|
|
791
|
+
prompt,
|
|
792
|
+
options: {
|
|
793
|
+
abortController = createAbortController(),
|
|
794
|
+
additionalDirectories = [],
|
|
795
|
+
allowedTools = [],
|
|
796
|
+
appendSystemPrompt,
|
|
797
|
+
canUseTool,
|
|
798
|
+
continue: continueConversation,
|
|
799
|
+
customSystemPrompt,
|
|
800
|
+
cwd,
|
|
801
|
+
disallowedTools = [],
|
|
802
|
+
env,
|
|
803
|
+
executable = isRunningWithBun() ? "bun" : "node",
|
|
804
|
+
executableArgs = [],
|
|
805
|
+
extraArgs = {},
|
|
806
|
+
fallbackModel,
|
|
807
|
+
hooks,
|
|
808
|
+
maxTurns,
|
|
809
|
+
mcpServers,
|
|
810
|
+
model,
|
|
811
|
+
pathToClaudeCodeExecutable,
|
|
812
|
+
permissionMode = "default",
|
|
813
|
+
permissionPromptToolName,
|
|
814
|
+
resume,
|
|
815
|
+
stderr,
|
|
816
|
+
strictMcpConfig
|
|
817
|
+
} = {}
|
|
818
|
+
}) {
|
|
819
|
+
if (!env) {
|
|
820
|
+
env = { ...process.env };
|
|
821
|
+
}
|
|
822
|
+
if (!env.CLAUDE_CODE_ENTRYPOINT) {
|
|
823
|
+
env.CLAUDE_CODE_ENTRYPOINT = "sdk-ts";
|
|
824
|
+
}
|
|
825
|
+
if (pathToClaudeCodeExecutable === undefined) {
|
|
826
|
+
const filename = fileURLToPath2(import.meta.url);
|
|
827
|
+
const dirname = join2(filename, "..");
|
|
828
|
+
pathToClaudeCodeExecutable = join2(dirname, "cli.js");
|
|
829
|
+
}
|
|
830
|
+
const isStreamingMode = typeof prompt !== "string";
|
|
831
|
+
const transport = new ProcessTransport({
|
|
832
|
+
prompt,
|
|
833
|
+
abortController,
|
|
834
|
+
additionalDirectories,
|
|
835
|
+
cwd,
|
|
836
|
+
executable,
|
|
837
|
+
executableArgs,
|
|
838
|
+
extraArgs,
|
|
839
|
+
pathToClaudeCodeExecutable,
|
|
840
|
+
env,
|
|
841
|
+
stderr,
|
|
842
|
+
customSystemPrompt,
|
|
843
|
+
appendSystemPrompt,
|
|
844
|
+
maxTurns,
|
|
845
|
+
model,
|
|
846
|
+
fallbackModel,
|
|
847
|
+
permissionMode,
|
|
848
|
+
permissionPromptToolName,
|
|
849
|
+
continueConversation,
|
|
850
|
+
resume,
|
|
851
|
+
allowedTools,
|
|
852
|
+
disallowedTools,
|
|
853
|
+
mcpServers,
|
|
854
|
+
strictMcpConfig,
|
|
855
|
+
canUseTool: !!canUseTool,
|
|
856
|
+
hooks: !!hooks
|
|
857
|
+
});
|
|
858
|
+
const query2 = new Query(transport, isStreamingMode, canUseTool, hooks, abortController);
|
|
859
|
+
if (typeof prompt !== "string") {
|
|
860
|
+
query2.streamInput(prompt);
|
|
861
|
+
}
|
|
862
|
+
return query2;
|
|
863
|
+
}
|
|
864
|
+
function isRunningWithBun() {
|
|
865
|
+
return process.versions.bun !== undefined || process.env.BUN_INSTALL !== undefined;
|
|
866
|
+
}
|
|
867
|
+
export {
|
|
868
|
+
query
|
|
869
|
+
};
|