@gullabs/claude-cli 0.6.1 → 0.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/NOTICE +6 -0
- package/README.md +97 -13
- package/dist/index.cjs +311 -47
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +48 -18
- package/dist/index.d.ts +48 -18
- package/dist/index.js +309 -47
- package/dist/index.js.map +1 -1
- package/package.json +18 -8
package/dist/index.js
CHANGED
|
@@ -1,11 +1,109 @@
|
|
|
1
1
|
import { mkdtemp, rm } from 'fs/promises';
|
|
2
2
|
import { tmpdir } from 'os';
|
|
3
3
|
import { join } from 'path';
|
|
4
|
-
import { zodToStandardSchema, toConfigJsonSchema, createModelRegistry, LlmError } from '@gullabs/core';
|
|
4
|
+
import { zodToStandardSchema, toConfigJsonSchema, toConfigKeys, createModelRegistry, LlmError } from '@gullabs/core';
|
|
5
5
|
import { spawn } from 'child_process';
|
|
6
|
+
import { StringDecoder } from 'string_decoder';
|
|
6
7
|
import { z } from 'zod';
|
|
7
8
|
|
|
8
9
|
// src/adapter.ts
|
|
10
|
+
var INHERITED_NAMES = /* @__PURE__ */ new Set([
|
|
11
|
+
// Process basics.
|
|
12
|
+
"PATH",
|
|
13
|
+
"HOME",
|
|
14
|
+
"USER",
|
|
15
|
+
"LOGNAME",
|
|
16
|
+
"LANG",
|
|
17
|
+
"LANGUAGE",
|
|
18
|
+
"TERM",
|
|
19
|
+
"TMPDIR",
|
|
20
|
+
"TEMP",
|
|
21
|
+
"TMP",
|
|
22
|
+
"SHELL",
|
|
23
|
+
"TZ",
|
|
24
|
+
// Windows equivalents of the above.
|
|
25
|
+
"SYSTEMROOT",
|
|
26
|
+
"SYSTEMDRIVE",
|
|
27
|
+
"WINDIR",
|
|
28
|
+
"COMSPEC",
|
|
29
|
+
"PATHEXT",
|
|
30
|
+
"USERPROFILE",
|
|
31
|
+
"APPDATA",
|
|
32
|
+
"LOCALAPPDATA",
|
|
33
|
+
"PROGRAMDATA",
|
|
34
|
+
"HOMEDRIVE",
|
|
35
|
+
"HOMEPATH",
|
|
36
|
+
// Network: proxies and trust roots.
|
|
37
|
+
"HTTPS_PROXY",
|
|
38
|
+
"HTTP_PROXY",
|
|
39
|
+
"ALL_PROXY",
|
|
40
|
+
"NO_PROXY",
|
|
41
|
+
"https_proxy",
|
|
42
|
+
"http_proxy",
|
|
43
|
+
"all_proxy",
|
|
44
|
+
"no_proxy",
|
|
45
|
+
"NODE_EXTRA_CA_CERTS",
|
|
46
|
+
"SSL_CERT_FILE",
|
|
47
|
+
"SSL_CERT_DIR",
|
|
48
|
+
// The CLI's own documented settings that keep the subscription login usable:
|
|
49
|
+
// where its login lives, the long-lived subscription token from
|
|
50
|
+
// `claude setup-token`, and client certificates for an mTLS proxy.
|
|
51
|
+
"CLAUDE_CONFIG_DIR",
|
|
52
|
+
"CLAUDE_CODE_OAUTH_TOKEN",
|
|
53
|
+
"CLAUDE_CODE_CLIENT_CERT",
|
|
54
|
+
"CLAUDE_CODE_CLIENT_KEY",
|
|
55
|
+
"CLAUDE_CODE_CLIENT_KEY_PASSPHRASE",
|
|
56
|
+
"CLAUDE_CODE_PROXY_RESOLVES_HOSTS"
|
|
57
|
+
]);
|
|
58
|
+
var INHERITED_PREFIXES = ["LC_", "XDG_"];
|
|
59
|
+
function isInherited(name, windows) {
|
|
60
|
+
const key = windows ? name.toUpperCase() : name;
|
|
61
|
+
if (INHERITED_NAMES.has(key)) return true;
|
|
62
|
+
return INHERITED_PREFIXES.some((prefix) => key.startsWith(prefix));
|
|
63
|
+
}
|
|
64
|
+
function buildChildEnv(parent, extra, windows) {
|
|
65
|
+
const env = {};
|
|
66
|
+
for (const [name, value] of Object.entries(parent)) {
|
|
67
|
+
if (value !== void 0 && isInherited(name, windows)) env[name] = value;
|
|
68
|
+
}
|
|
69
|
+
if (extra !== void 0) {
|
|
70
|
+
if (windows) {
|
|
71
|
+
const overridden = new Set(Object.keys(extra).map((name) => name.toUpperCase()));
|
|
72
|
+
for (const name of Object.keys(env)) {
|
|
73
|
+
if (overridden.has(name.toUpperCase())) delete env[name];
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
Object.assign(env, extra);
|
|
77
|
+
}
|
|
78
|
+
return env;
|
|
79
|
+
}
|
|
80
|
+
function badEnv(message) {
|
|
81
|
+
return new LlmError(message, {
|
|
82
|
+
kind: "bad_request",
|
|
83
|
+
retryable: false,
|
|
84
|
+
provider: "claude-cli"
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
function parseExtraEnv(env) {
|
|
88
|
+
if (env === void 0) return void 0;
|
|
89
|
+
if (env === null || typeof env !== "object" || Array.isArray(env)) {
|
|
90
|
+
throw badEnv("claudeCliAdapter: `env` must be an object of string values");
|
|
91
|
+
}
|
|
92
|
+
const copy = {};
|
|
93
|
+
for (const [name, value] of Object.entries(env)) {
|
|
94
|
+
if (name === "" || name.includes("=") || name.includes("\0")) {
|
|
95
|
+
throw badEnv(`claudeCliAdapter: \`env\` has an invalid name "${name}"`);
|
|
96
|
+
}
|
|
97
|
+
if (typeof value !== "string" || value.includes("\0")) {
|
|
98
|
+
throw badEnv(
|
|
99
|
+
`claudeCliAdapter: \`env.${name}\` must be a string without NUL characters`
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
copy[name] = value;
|
|
103
|
+
}
|
|
104
|
+
return Object.freeze(copy);
|
|
105
|
+
}
|
|
106
|
+
var MAX_STDOUT_BYTES = 32 * 1024 * 1024;
|
|
9
107
|
function buildClaudeCliRunner(claudePath = "claude") {
|
|
10
108
|
return {
|
|
11
109
|
run(args, input, opts) {
|
|
@@ -18,9 +116,14 @@ function buildClaudeCliRunner(claudePath = "claude") {
|
|
|
18
116
|
}
|
|
19
117
|
const child = spawn(claudePath, args, {
|
|
20
118
|
cwd: opts.cwd,
|
|
21
|
-
stdio: ["pipe", "pipe", "pipe"]
|
|
119
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
120
|
+
detached: process.platform !== "win32",
|
|
121
|
+
env: buildChildEnv(process.env, opts.env, process.platform === "win32")
|
|
22
122
|
});
|
|
123
|
+
const stdoutDecoder = new StringDecoder("utf8");
|
|
124
|
+
const stderrDecoder = new StringDecoder("utf8");
|
|
23
125
|
let stdout = "";
|
|
126
|
+
let stdoutBytes = 0;
|
|
24
127
|
let stderr = "";
|
|
25
128
|
let settled = false;
|
|
26
129
|
let pendingError;
|
|
@@ -36,12 +139,31 @@ function buildClaudeCliRunner(claudePath = "claude") {
|
|
|
36
139
|
opts.signal.removeEventListener("abort", onAbort);
|
|
37
140
|
}
|
|
38
141
|
};
|
|
142
|
+
const signalTree = (signal) => {
|
|
143
|
+
if (process.platform !== "win32" && child.pid !== void 0) {
|
|
144
|
+
try {
|
|
145
|
+
process.kill(-child.pid, signal);
|
|
146
|
+
return;
|
|
147
|
+
} catch {
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
child.kill(signal);
|
|
151
|
+
};
|
|
39
152
|
const killChild = () => {
|
|
40
|
-
|
|
153
|
+
signalTree("SIGTERM");
|
|
41
154
|
killTimeoutHandle = setTimeout(() => {
|
|
42
|
-
|
|
155
|
+
signalTree("SIGKILL");
|
|
156
|
+
child.stdout.destroy();
|
|
157
|
+
child.stderr.destroy();
|
|
43
158
|
}, 5e3);
|
|
44
159
|
};
|
|
160
|
+
const sweepGroup = () => {
|
|
161
|
+
if (process.platform === "win32" || child.pid === void 0) return;
|
|
162
|
+
try {
|
|
163
|
+
process.kill(-child.pid, "SIGKILL");
|
|
164
|
+
} catch {
|
|
165
|
+
}
|
|
166
|
+
};
|
|
45
167
|
const beginReject = (err) => {
|
|
46
168
|
if (settled || pendingError !== void 0) return;
|
|
47
169
|
pendingError = err;
|
|
@@ -64,10 +186,22 @@ function buildClaudeCliRunner(claudePath = "claude") {
|
|
|
64
186
|
}, opts.timeoutMs);
|
|
65
187
|
}
|
|
66
188
|
child.stdout.on("data", (chunk) => {
|
|
67
|
-
|
|
189
|
+
if (pendingError !== void 0) return;
|
|
190
|
+
stdoutBytes += chunk.length;
|
|
191
|
+
if (stdoutBytes > MAX_STDOUT_BYTES) {
|
|
192
|
+
const err = new Error(
|
|
193
|
+
`claude-cli stdout exceeded ${MAX_STDOUT_BYTES} bytes; the process was killed`
|
|
194
|
+
);
|
|
195
|
+
err.name = "OutputLimitError";
|
|
196
|
+
beginReject(err);
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
stdout += stdoutDecoder.write(chunk);
|
|
68
200
|
});
|
|
69
201
|
child.stderr.on("data", (chunk) => {
|
|
70
|
-
stderr
|
|
202
|
+
stderr = (stderr + stderrDecoder.write(chunk)).slice(-1048576);
|
|
203
|
+
});
|
|
204
|
+
child.stdin.on("error", () => {
|
|
71
205
|
});
|
|
72
206
|
child.once("error", (err) => {
|
|
73
207
|
if (settled) return;
|
|
@@ -80,8 +214,11 @@ function buildClaudeCliRunner(claudePath = "claude") {
|
|
|
80
214
|
settled = true;
|
|
81
215
|
cleanup();
|
|
82
216
|
if (pendingError !== void 0) {
|
|
217
|
+
sweepGroup();
|
|
83
218
|
reject(pendingError);
|
|
84
219
|
} else {
|
|
220
|
+
stdout += stdoutDecoder.end();
|
|
221
|
+
stderr = (stderr + stderrDecoder.end()).slice(-1048576);
|
|
85
222
|
resolve({ stdout, stderr, exitCode });
|
|
86
223
|
}
|
|
87
224
|
});
|
|
@@ -92,31 +229,52 @@ function buildClaudeCliRunner(claudePath = "claude") {
|
|
|
92
229
|
}
|
|
93
230
|
|
|
94
231
|
// src/adapter.ts
|
|
232
|
+
function abortError() {
|
|
233
|
+
const err = new Error("claude-cli call aborted");
|
|
234
|
+
err.name = "AbortError";
|
|
235
|
+
return err;
|
|
236
|
+
}
|
|
95
237
|
var Semaphore = class {
|
|
96
238
|
available;
|
|
97
|
-
|
|
239
|
+
waiters = [];
|
|
98
240
|
constructor(max) {
|
|
99
241
|
this.available = max;
|
|
100
242
|
}
|
|
101
|
-
|
|
243
|
+
/**
|
|
244
|
+
* Take a slot. A caller that has to wait leaves the queue, and rejects with an
|
|
245
|
+
* `AbortError`, as soon as `signal` fires: a call the engine already gave up
|
|
246
|
+
* on must not hold a place in line.
|
|
247
|
+
*/
|
|
248
|
+
acquire(signal) {
|
|
249
|
+
if (signal?.aborted === true) return Promise.reject(abortError());
|
|
102
250
|
if (this.available > 0) {
|
|
103
251
|
this.available -= 1;
|
|
104
|
-
return () => {
|
|
252
|
+
return Promise.resolve(() => {
|
|
105
253
|
this.release();
|
|
106
|
-
};
|
|
254
|
+
});
|
|
107
255
|
}
|
|
108
|
-
|
|
109
|
-
|
|
256
|
+
return new Promise((resolve, reject) => {
|
|
257
|
+
const grant = () => {
|
|
258
|
+
signal?.removeEventListener("abort", onAbort);
|
|
259
|
+
resolve(() => {
|
|
260
|
+
this.release();
|
|
261
|
+
});
|
|
262
|
+
};
|
|
263
|
+
const onAbort = () => {
|
|
264
|
+
const at = this.waiters.indexOf(grant);
|
|
265
|
+
if (at >= 0) this.waiters.splice(at, 1);
|
|
266
|
+
reject(abortError());
|
|
267
|
+
};
|
|
268
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
269
|
+
this.waiters.push(grant);
|
|
110
270
|
});
|
|
111
|
-
this.available -= 1;
|
|
112
|
-
return () => {
|
|
113
|
-
this.release();
|
|
114
|
-
};
|
|
115
271
|
}
|
|
272
|
+
// A freed slot goes straight to the next waiter, so a new caller cannot
|
|
273
|
+
// overtake it between the release and the waiter's wake-up.
|
|
116
274
|
release() {
|
|
117
|
-
this.
|
|
118
|
-
const next = this.queue.shift();
|
|
275
|
+
const next = this.waiters.shift();
|
|
119
276
|
if (next !== void 0) next();
|
|
277
|
+
else this.available += 1;
|
|
120
278
|
}
|
|
121
279
|
};
|
|
122
280
|
function mapFinishReason(stopReason) {
|
|
@@ -124,6 +282,8 @@ function mapFinishReason(stopReason) {
|
|
|
124
282
|
switch (stopReason) {
|
|
125
283
|
case "end_turn":
|
|
126
284
|
return "stop";
|
|
285
|
+
case "refusal":
|
|
286
|
+
return "content_filter";
|
|
127
287
|
case "tool_use":
|
|
128
288
|
return "stop";
|
|
129
289
|
default:
|
|
@@ -131,14 +291,19 @@ function mapFinishReason(stopReason) {
|
|
|
131
291
|
}
|
|
132
292
|
}
|
|
133
293
|
function mapUsage(usage) {
|
|
134
|
-
const
|
|
294
|
+
const cacheRead = usage?.cache_read_input_tokens;
|
|
295
|
+
const cacheWrite = usage?.cache_creation_input_tokens;
|
|
296
|
+
const inputTokens = (usage?.input_tokens ?? 0) + (cacheRead ?? 0) + (cacheWrite ?? 0);
|
|
135
297
|
const outputTokens = usage?.output_tokens ?? 0;
|
|
136
|
-
const cachedInputTokens =
|
|
298
|
+
const cachedInputTokens = cacheRead;
|
|
299
|
+
const thinkingTokens = usage?.output_tokens_details?.thinking_tokens;
|
|
137
300
|
const totalTokens = usage !== void 0 ? inputTokens + outputTokens : void 0;
|
|
138
301
|
const details = {
|
|
139
302
|
input: inputTokens,
|
|
140
303
|
output: outputTokens,
|
|
141
304
|
...cachedInputTokens !== void 0 ? { cached: cachedInputTokens } : {},
|
|
305
|
+
...cacheWrite !== void 0 ? { cacheWrite } : {},
|
|
306
|
+
...thinkingTokens !== void 0 ? { thinking: thinkingTokens } : {},
|
|
142
307
|
...totalTokens !== void 0 ? { total: totalTokens } : {}
|
|
143
308
|
};
|
|
144
309
|
const raw = usage !== void 0 ? usage : null;
|
|
@@ -148,6 +313,7 @@ function mapUsage(usage) {
|
|
|
148
313
|
details,
|
|
149
314
|
raw,
|
|
150
315
|
...cachedInputTokens !== void 0 ? { cachedInputTokens } : {},
|
|
316
|
+
...thinkingTokens !== void 0 ? { thinkingTokens } : {},
|
|
151
317
|
...totalTokens !== void 0 ? { totalTokens } : {}
|
|
152
318
|
};
|
|
153
319
|
}
|
|
@@ -177,20 +343,47 @@ function buildPrompt(messages) {
|
|
|
177
343
|
${messageText(msg)}`;
|
|
178
344
|
}).join("\n\n");
|
|
179
345
|
}
|
|
346
|
+
var AUTH_FAILURE = /\b(?:log ?in|auth|oauth|authentication|unauthori[sz]ed|401)\b/i;
|
|
347
|
+
var RATE_LIMITED = /\brate[ -]?limit(?:ed|s|ing)?\b|\btoo many requests\b|(?<![\w.:/-])429(?![\w-]|\.\d)/i;
|
|
180
348
|
function looksAuthy(text) {
|
|
181
|
-
return
|
|
349
|
+
return AUTH_FAILURE.test(text);
|
|
182
350
|
}
|
|
183
351
|
function looksRateLimited(text) {
|
|
184
|
-
return
|
|
352
|
+
return RATE_LIMITED.test(text);
|
|
185
353
|
}
|
|
186
|
-
function
|
|
187
|
-
const
|
|
188
|
-
if (
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
354
|
+
function assertServedModel(envelope, requestedModel) {
|
|
355
|
+
const modelUsage = envelope.modelUsage;
|
|
356
|
+
if (modelUsage === null || typeof modelUsage !== "object" || Array.isArray(modelUsage)) {
|
|
357
|
+
throw new LlmError("claude CLI did not report a valid modelUsage object.", {
|
|
358
|
+
kind: "server",
|
|
359
|
+
retryable: false,
|
|
360
|
+
provider: "claude-cli"
|
|
361
|
+
});
|
|
362
|
+
}
|
|
363
|
+
for (const served of Object.keys(modelUsage)) {
|
|
364
|
+
if (served !== requestedModel) {
|
|
365
|
+
throw new LlmError(
|
|
366
|
+
`claude CLI served model "${served}" but the request asked for "${requestedModel}".`,
|
|
367
|
+
{ kind: "server", retryable: false, provider: "claude-cli" }
|
|
368
|
+
);
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
if (!Object.hasOwn(modelUsage, requestedModel)) {
|
|
372
|
+
throw new LlmError(
|
|
373
|
+
`claude CLI did not report the requested model "${requestedModel}" in modelUsage.`,
|
|
374
|
+
{ kind: "server", retryable: false, provider: "claude-cli" }
|
|
192
375
|
);
|
|
193
376
|
}
|
|
377
|
+
}
|
|
378
|
+
function classifyRunFailure(envelope, result) {
|
|
379
|
+
if (envelope?.stop_reason === "refusal") {
|
|
380
|
+
return new LlmError("claude CLI refused the prompt (stop_reason: refusal).", {
|
|
381
|
+
kind: "content_filter",
|
|
382
|
+
retryable: false,
|
|
383
|
+
provider: "claude-cli"
|
|
384
|
+
});
|
|
385
|
+
}
|
|
386
|
+
const combinedText = `${envelope?.subtype ?? ""} ${result.stderr}`;
|
|
194
387
|
if (looksRateLimited(combinedText)) {
|
|
195
388
|
return new LlmError(
|
|
196
389
|
`claude CLI reported rate limiting: ${result.stderr.slice(-500)}`,
|
|
@@ -201,6 +394,12 @@ function classifyRunFailure(envelope, result) {
|
|
|
201
394
|
}
|
|
202
395
|
);
|
|
203
396
|
}
|
|
397
|
+
if (looksAuthy(combinedText)) {
|
|
398
|
+
return new LlmError(
|
|
399
|
+
`claude CLI reported an authentication failure: ${result.stderr.slice(-500)}`,
|
|
400
|
+
{ kind: "invalid_auth", retryable: false, provider: "claude-cli" }
|
|
401
|
+
);
|
|
402
|
+
}
|
|
204
403
|
if (envelope?.is_error === true) {
|
|
205
404
|
return new LlmError(
|
|
206
405
|
`claude CLI reported an error (subtype: ${envelope.subtype ?? "unknown"}): ${result.stderr.slice(-500)}`,
|
|
@@ -216,6 +415,7 @@ function classifyRunFailure(envelope, result) {
|
|
|
216
415
|
function claudeCliAdapter(opts) {
|
|
217
416
|
const runner = opts?.runner ?? buildClaudeCliRunner(opts?.claudePath);
|
|
218
417
|
const semaphore = new Semaphore(opts?.maxConcurrency ?? 2);
|
|
418
|
+
const env = parseExtraEnv(opts?.env);
|
|
219
419
|
return {
|
|
220
420
|
id: "claude-cli",
|
|
221
421
|
async run(req, ctx) {
|
|
@@ -241,6 +441,27 @@ function claudeCliAdapter(opts) {
|
|
|
241
441
|
const warnings = [];
|
|
242
442
|
const model = req.model;
|
|
243
443
|
const config = req.config;
|
|
444
|
+
if (req.modelDescriptor?.model !== model || req.modelDescriptor.provider !== "claude-cli") {
|
|
445
|
+
throw new LlmError(`No matching Claude model descriptor for "${model}".`, {
|
|
446
|
+
kind: "bad_request",
|
|
447
|
+
retryable: false,
|
|
448
|
+
provider: "claude-cli"
|
|
449
|
+
});
|
|
450
|
+
}
|
|
451
|
+
if (req.transientProviderState !== void 0) {
|
|
452
|
+
throw new LlmError(`Model "${model}" does not admit transientProviderState.`, {
|
|
453
|
+
kind: "bad_request",
|
|
454
|
+
retryable: false,
|
|
455
|
+
provider: "claude-cli"
|
|
456
|
+
});
|
|
457
|
+
}
|
|
458
|
+
if (config.reasoning !== void 0 && req.modelDescriptor.capabilities?.reasoningApi === void 0) {
|
|
459
|
+
throw new LlmError(`Model "${model}" does not admit reasoning.`, {
|
|
460
|
+
kind: "bad_request",
|
|
461
|
+
retryable: false,
|
|
462
|
+
provider: "claude-cli"
|
|
463
|
+
});
|
|
464
|
+
}
|
|
244
465
|
const prompt = buildPrompt(req.messages);
|
|
245
466
|
const args = [
|
|
246
467
|
"-p",
|
|
@@ -250,7 +471,9 @@ function claudeCliAdapter(opts) {
|
|
|
250
471
|
"--tools",
|
|
251
472
|
"",
|
|
252
473
|
"--disable-slash-commands",
|
|
253
|
-
"--no-session-persistence"
|
|
474
|
+
"--no-session-persistence",
|
|
475
|
+
"--settings",
|
|
476
|
+
'{"switchModelsOnFlag":false}'
|
|
254
477
|
];
|
|
255
478
|
args.push("--model", model);
|
|
256
479
|
const effort = config.reasoning?.effort;
|
|
@@ -264,14 +487,29 @@ function claudeCliAdapter(opts) {
|
|
|
264
487
|
args.push("--json-schema", JSON.stringify(req.outputJsonSchema));
|
|
265
488
|
}
|
|
266
489
|
const timeoutMs = req.attemptTimeoutMs ?? config.timeoutMs;
|
|
267
|
-
|
|
268
|
-
|
|
490
|
+
let release;
|
|
491
|
+
try {
|
|
492
|
+
release = await semaphore.acquire(ctx.signal);
|
|
493
|
+
} catch (waitErr) {
|
|
494
|
+
throw new LlmError(
|
|
495
|
+
waitErr instanceof Error ? waitErr.message : "claude-cli call aborted",
|
|
496
|
+
{ kind: "aborted", retryable: false, provider: "claude-cli" }
|
|
497
|
+
);
|
|
498
|
+
}
|
|
499
|
+
let cwd;
|
|
500
|
+
try {
|
|
501
|
+
cwd = await mkdtemp(join(tmpdir(), "claude-cli-"));
|
|
502
|
+
} catch (mkdirErr) {
|
|
503
|
+
release();
|
|
504
|
+
throw mkdirErr;
|
|
505
|
+
}
|
|
269
506
|
let result;
|
|
270
507
|
try {
|
|
271
508
|
result = await runner.run(args, prompt, {
|
|
272
509
|
cwd,
|
|
273
510
|
...timeoutMs !== void 0 ? { timeoutMs } : {},
|
|
274
|
-
...ctx.signal !== void 0 ? { signal: ctx.signal } : {}
|
|
511
|
+
...ctx.signal !== void 0 ? { signal: ctx.signal } : {},
|
|
512
|
+
...env !== void 0 ? { env } : {}
|
|
275
513
|
});
|
|
276
514
|
} catch (rawErr) {
|
|
277
515
|
release();
|
|
@@ -313,6 +551,7 @@ function claudeCliAdapter(opts) {
|
|
|
313
551
|
if (result.exitCode !== 0 || envelope?.is_error === true || envelope === void 0) {
|
|
314
552
|
throw classifyRunFailure(envelope, result);
|
|
315
553
|
}
|
|
554
|
+
assertServedModel(envelope, model);
|
|
316
555
|
const text = envelope.result ?? "";
|
|
317
556
|
let rawStructured;
|
|
318
557
|
if (req.outputJsonSchema !== void 0) {
|
|
@@ -335,6 +574,10 @@ function claudeCliAdapter(opts) {
|
|
|
335
574
|
};
|
|
336
575
|
const adapterResult = {
|
|
337
576
|
model,
|
|
577
|
+
message: {
|
|
578
|
+
role: "assistant",
|
|
579
|
+
parts: text.length > 0 ? [{ kind: "text", text }] : []
|
|
580
|
+
},
|
|
338
581
|
usage,
|
|
339
582
|
warnings,
|
|
340
583
|
...text.length > 0 ? { text } : {},
|
|
@@ -347,13 +590,13 @@ function claudeCliAdapter(opts) {
|
|
|
347
590
|
};
|
|
348
591
|
}
|
|
349
592
|
var CLAUDE_CLI_MODEL_IDS = [
|
|
350
|
-
"claude-fable-5",
|
|
351
|
-
"claude-opus-
|
|
593
|
+
"claude-fable-5-1",
|
|
594
|
+
"claude-opus-5-5",
|
|
352
595
|
"claude-sonnet-5",
|
|
353
596
|
"claude-haiku-4-5-20251001"
|
|
354
597
|
];
|
|
355
598
|
var CLAUDE_CLI_EFFORTS = ["low", "medium", "high", "xhigh", "max"];
|
|
356
|
-
function
|
|
599
|
+
function buildEffortConfigSchema(modelName) {
|
|
357
600
|
return z.strictObject({
|
|
358
601
|
reasoning: z.strictObject({
|
|
359
602
|
effort: z.enum(CLAUDE_CLI_EFFORTS).meta({
|
|
@@ -373,32 +616,51 @@ function buildClaudeCliConfigSchema(modelName) {
|
|
|
373
616
|
description: `Strict claude-cli config for model ${modelName}. Text-only, no sampling knobs, effort-based reasoning.`
|
|
374
617
|
});
|
|
375
618
|
}
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
)
|
|
619
|
+
function buildHaikuConfigSchema() {
|
|
620
|
+
return z.strictObject({
|
|
621
|
+
timeoutMs: z.number().int().positive().max(18e5).optional().meta({
|
|
622
|
+
title: "Timeout",
|
|
623
|
+
description: "Logical request timeout in milliseconds; forwarded to the CLI runner."
|
|
624
|
+
})
|
|
625
|
+
}).meta({
|
|
626
|
+
title: "claude-haiku-4-5-20251001Config",
|
|
627
|
+
description: "Strict claude-cli config for claude-haiku-4-5-20251001. No reasoning key: the CLI drops --effort."
|
|
628
|
+
});
|
|
629
|
+
}
|
|
630
|
+
var ClaudeFable51ConfigSchema = buildEffortConfigSchema("claude-fable-5-1");
|
|
631
|
+
var ClaudeOpus55ConfigSchema = buildEffortConfigSchema("claude-opus-5-5");
|
|
632
|
+
var ClaudeSonnet5ConfigSchema = buildEffortConfigSchema("claude-sonnet-5");
|
|
633
|
+
var ClaudeHaiku45ConfigSchema = buildHaikuConfigSchema();
|
|
382
634
|
var CONFIG_SCHEMAS = {
|
|
383
|
-
"claude-fable-5":
|
|
384
|
-
"claude-opus-
|
|
635
|
+
"claude-fable-5-1": ClaudeFable51ConfigSchema,
|
|
636
|
+
"claude-opus-5-5": ClaudeOpus55ConfigSchema,
|
|
385
637
|
"claude-sonnet-5": ClaudeSonnet5ConfigSchema,
|
|
386
638
|
"claude-haiku-4-5-20251001": ClaudeHaiku45ConfigSchema
|
|
387
639
|
};
|
|
640
|
+
var CLAUDE_CLI_LIMITS = {
|
|
641
|
+
"claude-fable-5-1": { contextWindow: 1e6, maxOutputTokens: 64e3 },
|
|
642
|
+
"claude-opus-5-5": { contextWindow: 1e6, maxOutputTokens: 128e3 },
|
|
643
|
+
"claude-sonnet-5": { contextWindow: 1e6, maxOutputTokens: 128e3 },
|
|
644
|
+
"claude-haiku-4-5-20251001": { contextWindow: 2e5, maxOutputTokens: 32e3 }
|
|
645
|
+
};
|
|
388
646
|
var claudeCliModelDescriptors = CLAUDE_CLI_MODEL_IDS.map(
|
|
389
647
|
(id) => {
|
|
390
648
|
const configSchema = CONFIG_SCHEMAS[id];
|
|
391
649
|
return {
|
|
392
650
|
model: id,
|
|
393
651
|
provider: "claude-cli",
|
|
652
|
+
limits: CLAUDE_CLI_LIMITS[id],
|
|
394
653
|
capabilities: {
|
|
654
|
+
// The CLI runs text-only: the adapter rejects every non-text part.
|
|
655
|
+
inputMimeTypes: [],
|
|
395
656
|
structuredOutput: true,
|
|
396
657
|
nativeStructuredOutput: true,
|
|
397
|
-
reasoningApi: "level",
|
|
398
|
-
|
|
399
|
-
|
|
658
|
+
...id !== "claude-haiku-4-5-20251001" ? { reasoningApi: "level" } : {},
|
|
659
|
+
admittedReasoningEfforts: id === "claude-haiku-4-5-20251001" ? [] : CLAUDE_CLI_EFFORTS,
|
|
660
|
+
sampling: "fixed"
|
|
400
661
|
},
|
|
401
662
|
configSchema,
|
|
663
|
+
configKeys: toConfigKeys(configSchema),
|
|
402
664
|
configJsonSchema: toConfigJsonSchema(configSchema),
|
|
403
665
|
validateConfig: zodToStandardSchema(configSchema)
|
|
404
666
|
};
|
|
@@ -416,6 +678,6 @@ function claudeCliProvider(opts) {
|
|
|
416
678
|
};
|
|
417
679
|
}
|
|
418
680
|
|
|
419
|
-
export {
|
|
681
|
+
export { CLAUDE_CLI_EFFORTS, CLAUDE_CLI_MODEL_IDS, ClaudeFable51ConfigSchema, ClaudeHaiku45ConfigSchema, ClaudeOpus55ConfigSchema, ClaudeSonnet5ConfigSchema, buildClaudeCliRunner, claudeCliAdapter, claudeCliModelDescriptors, claudeCliProvider, claudeCliRegistry };
|
|
420
682
|
//# sourceMappingURL=index.js.map
|
|
421
683
|
//# sourceMappingURL=index.js.map
|