@gullabs/claude-cli 0.6.0 → 0.7.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/LICENSE +84 -73
- package/README.md +25 -7
- package/dist/index.cjs +84 -15
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +14 -4
- package/dist/index.d.ts +14 -4
- package/dist/index.js +81 -14
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/LICENSE
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
|
|
1
2
|
Apache License
|
|
2
3
|
Version 2.0, January 2004
|
|
3
4
|
http://www.apache.org/licenses/
|
|
@@ -32,33 +33,36 @@
|
|
|
32
33
|
not limited to compiled object code, generated documentation,
|
|
33
34
|
and conversions to other media types.
|
|
34
35
|
|
|
35
|
-
"Work" shall mean the work of authorship
|
|
36
|
-
the License, as indicated by a
|
|
37
|
-
|
|
36
|
+
"Work" shall mean the work of authorship, whether in Source or
|
|
37
|
+
Object form, made available under the License, as indicated by a
|
|
38
|
+
copyright notice that is included in or attached to the work
|
|
39
|
+
(an example is provided in the Appendix below).
|
|
38
40
|
|
|
39
41
|
"Derivative Works" shall mean any work, whether in Source or Object
|
|
40
42
|
form, that is based on (or derived from) the Work and for which the
|
|
41
|
-
editorial revisions, annotations, elaborations, or other
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
"Contribution" shall mean
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
or
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
43
|
+
editorial revisions, annotations, elaborations, or other modifications
|
|
44
|
+
represent, as a whole, an original work of authorship. For the purposes
|
|
45
|
+
of this License, Derivative Works shall not include works that remain
|
|
46
|
+
separable from, or merely link (or bind by name) to the interfaces of,
|
|
47
|
+
the Work and Derivative Works thereof.
|
|
48
|
+
|
|
49
|
+
"Contribution" shall mean any work of authorship, including
|
|
50
|
+
the original version of the Work and any modifications or additions
|
|
51
|
+
to that Work or Derivative Works thereof, that is intentionally
|
|
52
|
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
53
|
+
or by an individual or Legal Entity authorized to submit on behalf of
|
|
54
|
+
the copyright owner. For the purposes of this definition, "submitted"
|
|
55
|
+
means any form of electronic, verbal, or written communication sent
|
|
56
|
+
to the Licensor or its representatives, including but not limited to
|
|
57
|
+
communication on electronic mailing lists, source code control systems,
|
|
58
|
+
and issue tracking systems that are managed by, or on behalf of, the
|
|
59
|
+
Licensor for the purpose of discussing and improving the Work, but
|
|
60
|
+
excluding communication that is conspicuously marked or otherwise
|
|
61
|
+
designated in writing by the copyright owner as "Not a Contribution."
|
|
62
|
+
|
|
63
|
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
64
|
+
on behalf of whom a Contribution has been received by Licensor and
|
|
65
|
+
subsequently incorporated within the Work.
|
|
62
66
|
|
|
63
67
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
64
68
|
this License, each Contributor hereby grants to You a perpetual,
|
|
@@ -74,22 +78,22 @@
|
|
|
74
78
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
75
79
|
where such license applies only to those patent claims licensable
|
|
76
80
|
by such Contributor that are necessarily infringed by their
|
|
77
|
-
Contribution(s) alone or by
|
|
81
|
+
Contribution(s) alone or by combination of their Contribution(s)
|
|
78
82
|
with the Work to which such Contribution(s) was submitted. If You
|
|
79
|
-
institute patent litigation against any entity (including a
|
|
80
|
-
or counterclaim in a lawsuit) alleging that the Work
|
|
81
|
-
|
|
82
|
-
infringement, then any patent licenses
|
|
83
|
-
License for that Work shall terminate
|
|
84
|
-
is filed.
|
|
83
|
+
institute patent litigation against any entity (including a
|
|
84
|
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
85
|
+
or a Contribution incorporated within the Work constitutes direct
|
|
86
|
+
or contributory patent infringement, then any patent licenses
|
|
87
|
+
granted to You under this License for that Work shall terminate
|
|
88
|
+
as of the date such litigation is filed.
|
|
85
89
|
|
|
86
90
|
4. Redistribution. You may reproduce and distribute copies of the
|
|
87
91
|
Work or Derivative Works thereof in any medium, with or without
|
|
88
92
|
modifications, and in Source or Object form, provided that You
|
|
89
93
|
meet the following conditions:
|
|
90
94
|
|
|
91
|
-
(a) You must give any other recipients of the Work or
|
|
92
|
-
Works a copy of this License; and
|
|
95
|
+
(a) You must give any other recipients of the Work or
|
|
96
|
+
Derivative Works a copy of this License; and
|
|
93
97
|
|
|
94
98
|
(b) You must cause any modified files to carry prominent notices
|
|
95
99
|
stating that You changed the files; and
|
|
@@ -101,25 +105,28 @@
|
|
|
101
105
|
the Derivative Works; and
|
|
102
106
|
|
|
103
107
|
(d) If the Work includes a "NOTICE" text file as part of its
|
|
104
|
-
distribution,
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
the
|
|
109
|
-
Derivative Works;
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
may
|
|
121
|
-
|
|
122
|
-
|
|
108
|
+
distribution, then any Derivative Works that You distribute must
|
|
109
|
+
include a readable copy of the attribution notices contained
|
|
110
|
+
within such NOTICE file, excluding those notices that do not
|
|
111
|
+
pertain to any part of the Derivative Works, in at least one
|
|
112
|
+
of the following places: within a NOTICE text file distributed
|
|
113
|
+
as part of the Derivative Works; within the Source form or
|
|
114
|
+
documentation, if provided along with the Derivative Works; or,
|
|
115
|
+
within a display generated by the Derivative Works, if and
|
|
116
|
+
wherever such third-party notices normally appear. The contents
|
|
117
|
+
of the NOTICE file are for informational purposes only and
|
|
118
|
+
do not modify the License. You may add Your own attribution
|
|
119
|
+
notices within Derivative Works that You distribute, alongside
|
|
120
|
+
or as an addendum to the NOTICE text from the Work, provided
|
|
121
|
+
that such additional attribution notices cannot be construed
|
|
122
|
+
as modifying the License.
|
|
123
|
+
|
|
124
|
+
You may add Your own copyright statement to Your modifications and
|
|
125
|
+
may provide additional or different license terms and conditions
|
|
126
|
+
for use, reproduction, or distribution of Your modifications, or
|
|
127
|
+
for any such Derivative Works as a whole, provided Your use,
|
|
128
|
+
reproduction, and distribution of the Work otherwise complies with
|
|
129
|
+
the conditions stated in this License.
|
|
123
130
|
|
|
124
131
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
125
132
|
any Contribution intentionally submitted for inclusion in the Work
|
|
@@ -141,7 +148,7 @@
|
|
|
141
148
|
implied, including, without limitation, any warranties or conditions
|
|
142
149
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
143
150
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
144
|
-
appropriateness of using or
|
|
151
|
+
appropriateness of using or redistributing the Work and assume any
|
|
145
152
|
risks associated with Your exercise of permissions under this License.
|
|
146
153
|
|
|
147
154
|
8. Limitation of Liability. In no event and under no legal theory,
|
|
@@ -149,21 +156,23 @@
|
|
|
149
156
|
unless required by applicable law (such as deliberate and grossly
|
|
150
157
|
negligent acts) or agreed to in writing, shall any Contributor be
|
|
151
158
|
liable to You for damages, including any direct, indirect, special,
|
|
152
|
-
incidental, or
|
|
159
|
+
incidental, or consequential damages of any character arising as a
|
|
153
160
|
result of this License or out of the use or inability to use the
|
|
154
161
|
Work (including but not limited to damages for loss of goodwill,
|
|
155
|
-
work stoppage, computer failure or malfunction, or all
|
|
156
|
-
commercial damages or losses), even if such Contributor
|
|
157
|
-
advised of the possibility of such damages.
|
|
162
|
+
work stoppage, computer failure or malfunction, or any and all
|
|
163
|
+
other commercial damages or losses), even if such Contributor
|
|
164
|
+
has been advised of the possibility of such damages.
|
|
158
165
|
|
|
159
166
|
9. Accepting Warranty or Additional Liability. While redistributing
|
|
160
167
|
the Work or Derivative Works thereof, You may choose to offer,
|
|
161
168
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
162
169
|
or other liability obligations and/or rights consistent with this
|
|
163
|
-
License. However, in accepting such obligations, You may
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
170
|
+
License. However, in accepting such obligations, You may act only
|
|
171
|
+
on Your own behalf and on Your sole responsibility, not on behalf
|
|
172
|
+
of any other Contributor, and only if You agree to indemnify,
|
|
173
|
+
defend, and hold each Contributor harmless for any liability
|
|
174
|
+
incurred by, or claims asserted against, such Contributor by reason
|
|
175
|
+
of your accepting any such warranty or additional liability.
|
|
167
176
|
|
|
168
177
|
END OF TERMS AND CONDITIONS
|
|
169
178
|
|
|
@@ -173,19 +182,21 @@
|
|
|
173
182
|
boilerplate notice, with the fields enclosed by brackets "[]"
|
|
174
183
|
replaced with your own identifying information. (Don't include
|
|
175
184
|
the brackets!) The text should be enclosed in the appropriate
|
|
176
|
-
comment syntax for the file format
|
|
177
|
-
|
|
185
|
+
comment syntax for the file format. We also recommend that a
|
|
186
|
+
file or class name and description of purpose be included on the
|
|
187
|
+
same "printed page" as the copyright notice for easier
|
|
188
|
+
identification within third-party archives.
|
|
178
189
|
|
|
179
|
-
|
|
190
|
+
Copyright [yyyy] [name of copyright owner]
|
|
180
191
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
192
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
193
|
+
you may not use this file except in compliance with the License.
|
|
194
|
+
You may obtain a copy of the License at
|
|
184
195
|
|
|
185
|
-
|
|
196
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
186
197
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
198
|
+
Unless required by applicable law or agreed to in writing, software
|
|
199
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
200
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
201
|
+
See the License for the specific language governing permissions and
|
|
202
|
+
limitations under the License.
|
package/README.md
CHANGED
|
@@ -62,10 +62,27 @@ would break subscription-based Claude Code auth and defeat the entire point
|
|
|
62
62
|
of this package (working with **zero** API-key configuration). The full
|
|
63
63
|
invariant argv (never caller-configurable) is:
|
|
64
64
|
|
|
65
|
+
The quotes below illustrate argument boundaries; the runner passes an argv
|
|
66
|
+
array directly without a shell.
|
|
67
|
+
|
|
65
68
|
```
|
|
66
|
-
-p --output-format json --safe-mode --tools "" --disable-slash-commands --no-session-persistence
|
|
69
|
+
-p --output-format json --safe-mode --tools "" --disable-slash-commands --no-session-persistence --settings '{"switchModelsOnFlag":false}'
|
|
67
70
|
```
|
|
68
71
|
|
|
72
|
+
`--settings` requests that the CLI disable silent model switches on a safety
|
|
73
|
+
flag; the CLI does not provide strict validation for this setting. Enforcement
|
|
74
|
+
comes from the post-run `modelUsage` check: a successful response must report
|
|
75
|
+
the requested id and no other model. Any other model id throws
|
|
76
|
+
`LlmError` kind `server` (not retryable). A successful envelope with
|
|
77
|
+
`stop_reason: "refusal"` returns `finishReason: 'content_filter'` and preserves
|
|
78
|
+
its billed usage; an error envelope throws `content_filter`.
|
|
79
|
+
|
|
80
|
+
P-A1 was captured on 2026-09-26 with Claude Code 2.1.282: the invariant argv
|
|
81
|
+
and `--json-schema` completed for all four registered ids, and each success
|
|
82
|
+
envelope contained only its requested id as a `modelUsage` key. The sanitized
|
|
83
|
+
responses are in `src/__fixtures__/model-refresh-p-a1.json`. The full installed CLI version and
|
|
84
|
+
envelope shape are runtime dependencies; an absent `modelUsage` fails closed.
|
|
85
|
+
|
|
69
86
|
`--model`, `--effort`, `--system-prompt`, and `--json-schema` are appended
|
|
70
87
|
from the request when applicable; the prompt itself is always sent over
|
|
71
88
|
stdin, never as a positional argv entry.
|
|
@@ -78,9 +95,10 @@ semaphore, defaulting to `maxConcurrency: 2`. Override via
|
|
|
78
95
|
|
|
79
96
|
## Supported models
|
|
80
97
|
|
|
81
|
-
`claude-fable-5`, `claude-opus-
|
|
82
|
-
`claude-haiku-4-5-20251001`.
|
|
83
|
-
`{ reasoning: { effort }, timeoutMs }`
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
rejects unknown keys.
|
|
98
|
+
`claude-fable-5-1`, `claude-opus-5-5`, `claude-sonnet-5`,
|
|
99
|
+
`claude-haiku-4-5-20251001`. Fable 5.1, Opus 5.5, and Sonnet 5 accept
|
|
100
|
+
`{ reasoning: { effort }, timeoutMs }` with effort `low | medium | high |
|
|
101
|
+
xhigh | max`. Haiku 4.5 has no `reasoning` key — the CLI drops `--effort`.
|
|
102
|
+
No sampling knobs (`temperature`/`topP`/`topK`/`maxOutputTokens`/`stopSequences`)
|
|
103
|
+
are accepted; the strict config schema rejects unknown keys. `claude-fable-5`
|
|
104
|
+
and `claude-opus-4-8` are deleted with no alias.
|
package/dist/index.cjs
CHANGED
|
@@ -126,6 +126,8 @@ function mapFinishReason(stopReason) {
|
|
|
126
126
|
switch (stopReason) {
|
|
127
127
|
case "end_turn":
|
|
128
128
|
return "stop";
|
|
129
|
+
case "refusal":
|
|
130
|
+
return "content_filter";
|
|
129
131
|
case "tool_use":
|
|
130
132
|
return "stop";
|
|
131
133
|
default:
|
|
@@ -185,7 +187,38 @@ function looksAuthy(text) {
|
|
|
185
187
|
function looksRateLimited(text) {
|
|
186
188
|
return /rate limit|429/i.test(text);
|
|
187
189
|
}
|
|
190
|
+
function assertServedModel(envelope, requestedModel) {
|
|
191
|
+
const modelUsage = envelope.modelUsage;
|
|
192
|
+
if (modelUsage === null || typeof modelUsage !== "object" || Array.isArray(modelUsage)) {
|
|
193
|
+
throw new core.LlmError("claude CLI did not report a valid modelUsage object.", {
|
|
194
|
+
kind: "server",
|
|
195
|
+
retryable: false,
|
|
196
|
+
provider: "claude-cli"
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
for (const served of Object.keys(modelUsage)) {
|
|
200
|
+
if (served !== requestedModel) {
|
|
201
|
+
throw new core.LlmError(
|
|
202
|
+
`claude CLI served model "${served}" but the request asked for "${requestedModel}".`,
|
|
203
|
+
{ kind: "server", retryable: false, provider: "claude-cli" }
|
|
204
|
+
);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
if (!Object.hasOwn(modelUsage, requestedModel)) {
|
|
208
|
+
throw new core.LlmError(
|
|
209
|
+
`claude CLI did not report the requested model "${requestedModel}" in modelUsage.`,
|
|
210
|
+
{ kind: "server", retryable: false, provider: "claude-cli" }
|
|
211
|
+
);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
188
214
|
function classifyRunFailure(envelope, result) {
|
|
215
|
+
if (envelope?.stop_reason === "refusal") {
|
|
216
|
+
return new core.LlmError("claude CLI refused the prompt (stop_reason: refusal).", {
|
|
217
|
+
kind: "content_filter",
|
|
218
|
+
retryable: false,
|
|
219
|
+
provider: "claude-cli"
|
|
220
|
+
});
|
|
221
|
+
}
|
|
189
222
|
const combinedText = `${envelope?.subtype ?? ""} ${result.stderr}`;
|
|
190
223
|
if (looksAuthy(combinedText)) {
|
|
191
224
|
return new core.LlmError(
|
|
@@ -243,6 +276,27 @@ function claudeCliAdapter(opts) {
|
|
|
243
276
|
const warnings = [];
|
|
244
277
|
const model = req.model;
|
|
245
278
|
const config = req.config;
|
|
279
|
+
if (req.modelDescriptor?.model !== model || req.modelDescriptor.provider !== "claude-cli") {
|
|
280
|
+
throw new core.LlmError(`No matching Claude model descriptor for "${model}".`, {
|
|
281
|
+
kind: "bad_request",
|
|
282
|
+
retryable: false,
|
|
283
|
+
provider: "claude-cli"
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
if (req.transientProviderState !== void 0) {
|
|
287
|
+
throw new core.LlmError(`Model "${model}" does not admit transientProviderState.`, {
|
|
288
|
+
kind: "bad_request",
|
|
289
|
+
retryable: false,
|
|
290
|
+
provider: "claude-cli"
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
if (config.reasoning !== void 0 && req.modelDescriptor.capabilities?.reasoningApi === void 0) {
|
|
294
|
+
throw new core.LlmError(`Model "${model}" does not admit reasoning.`, {
|
|
295
|
+
kind: "bad_request",
|
|
296
|
+
retryable: false,
|
|
297
|
+
provider: "claude-cli"
|
|
298
|
+
});
|
|
299
|
+
}
|
|
246
300
|
const prompt = buildPrompt(req.messages);
|
|
247
301
|
const args = [
|
|
248
302
|
"-p",
|
|
@@ -252,7 +306,9 @@ function claudeCliAdapter(opts) {
|
|
|
252
306
|
"--tools",
|
|
253
307
|
"",
|
|
254
308
|
"--disable-slash-commands",
|
|
255
|
-
"--no-session-persistence"
|
|
309
|
+
"--no-session-persistence",
|
|
310
|
+
"--settings",
|
|
311
|
+
'{"switchModelsOnFlag":false}'
|
|
256
312
|
];
|
|
257
313
|
args.push("--model", model);
|
|
258
314
|
const effort = config.reasoning?.effort;
|
|
@@ -315,6 +371,7 @@ function claudeCliAdapter(opts) {
|
|
|
315
371
|
if (result.exitCode !== 0 || envelope?.is_error === true || envelope === void 0) {
|
|
316
372
|
throw classifyRunFailure(envelope, result);
|
|
317
373
|
}
|
|
374
|
+
assertServedModel(envelope, model);
|
|
318
375
|
const text = envelope.result ?? "";
|
|
319
376
|
let rawStructured;
|
|
320
377
|
if (req.outputJsonSchema !== void 0) {
|
|
@@ -349,13 +406,13 @@ function claudeCliAdapter(opts) {
|
|
|
349
406
|
};
|
|
350
407
|
}
|
|
351
408
|
var CLAUDE_CLI_MODEL_IDS = [
|
|
352
|
-
"claude-fable-5",
|
|
353
|
-
"claude-opus-
|
|
409
|
+
"claude-fable-5-1",
|
|
410
|
+
"claude-opus-5-5",
|
|
354
411
|
"claude-sonnet-5",
|
|
355
412
|
"claude-haiku-4-5-20251001"
|
|
356
413
|
];
|
|
357
414
|
var CLAUDE_CLI_EFFORTS = ["low", "medium", "high", "xhigh", "max"];
|
|
358
|
-
function
|
|
415
|
+
function buildEffortConfigSchema(modelName) {
|
|
359
416
|
return zod.z.strictObject({
|
|
360
417
|
reasoning: zod.z.strictObject({
|
|
361
418
|
effort: zod.z.enum(CLAUDE_CLI_EFFORTS).meta({
|
|
@@ -375,15 +432,24 @@ function buildClaudeCliConfigSchema(modelName) {
|
|
|
375
432
|
description: `Strict claude-cli config for model ${modelName}. Text-only, no sampling knobs, effort-based reasoning.`
|
|
376
433
|
});
|
|
377
434
|
}
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
)
|
|
435
|
+
function buildHaikuConfigSchema() {
|
|
436
|
+
return zod.z.strictObject({
|
|
437
|
+
timeoutMs: zod.z.number().int().positive().max(18e5).optional().meta({
|
|
438
|
+
title: "Timeout",
|
|
439
|
+
description: "Logical request timeout in milliseconds; forwarded to the CLI runner."
|
|
440
|
+
})
|
|
441
|
+
}).meta({
|
|
442
|
+
title: "claude-haiku-4-5-20251001Config",
|
|
443
|
+
description: "Strict claude-cli config for claude-haiku-4-5-20251001. No reasoning key: the CLI drops --effort."
|
|
444
|
+
});
|
|
445
|
+
}
|
|
446
|
+
var ClaudeFable51ConfigSchema = buildEffortConfigSchema("claude-fable-5-1");
|
|
447
|
+
var ClaudeOpus55ConfigSchema = buildEffortConfigSchema("claude-opus-5-5");
|
|
448
|
+
var ClaudeSonnet5ConfigSchema = buildEffortConfigSchema("claude-sonnet-5");
|
|
449
|
+
var ClaudeHaiku45ConfigSchema = buildHaikuConfigSchema();
|
|
384
450
|
var CONFIG_SCHEMAS = {
|
|
385
|
-
"claude-fable-5":
|
|
386
|
-
"claude-opus-
|
|
451
|
+
"claude-fable-5-1": ClaudeFable51ConfigSchema,
|
|
452
|
+
"claude-opus-5-5": ClaudeOpus55ConfigSchema,
|
|
387
453
|
"claude-sonnet-5": ClaudeSonnet5ConfigSchema,
|
|
388
454
|
"claude-haiku-4-5-20251001": ClaudeHaiku45ConfigSchema
|
|
389
455
|
};
|
|
@@ -396,7 +462,8 @@ var claudeCliModelDescriptors = CLAUDE_CLI_MODEL_IDS.map(
|
|
|
396
462
|
capabilities: {
|
|
397
463
|
structuredOutput: true,
|
|
398
464
|
nativeStructuredOutput: true,
|
|
399
|
-
reasoningApi: "level",
|
|
465
|
+
...id !== "claude-haiku-4-5-20251001" ? { reasoningApi: "level" } : {},
|
|
466
|
+
admittedReasoningEfforts: id === "claude-haiku-4-5-20251001" ? [] : CLAUDE_CLI_EFFORTS,
|
|
400
467
|
sampling: "fixed",
|
|
401
468
|
vision: false
|
|
402
469
|
},
|
|
@@ -418,9 +485,11 @@ function claudeCliProvider(opts) {
|
|
|
418
485
|
};
|
|
419
486
|
}
|
|
420
487
|
|
|
421
|
-
exports.
|
|
488
|
+
exports.CLAUDE_CLI_EFFORTS = CLAUDE_CLI_EFFORTS;
|
|
489
|
+
exports.CLAUDE_CLI_MODEL_IDS = CLAUDE_CLI_MODEL_IDS;
|
|
490
|
+
exports.ClaudeFable51ConfigSchema = ClaudeFable51ConfigSchema;
|
|
422
491
|
exports.ClaudeHaiku45ConfigSchema = ClaudeHaiku45ConfigSchema;
|
|
423
|
-
exports.
|
|
492
|
+
exports.ClaudeOpus55ConfigSchema = ClaudeOpus55ConfigSchema;
|
|
424
493
|
exports.ClaudeSonnet5ConfigSchema = ClaudeSonnet5ConfigSchema;
|
|
425
494
|
exports.buildClaudeCliRunner = buildClaudeCliRunner;
|
|
426
495
|
exports.claudeCliAdapter = claudeCliAdapter;
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/runner.ts","../src/adapter.ts","../src/models.ts","../src/provider.ts"],"names":["spawn","LlmError","mkdtemp","join","tmpdir","rm","z","toConfigJsonSchema","zodToStandardSchema","createModelRegistry"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * ClaudeCliRunner — the process-execution seam for @gullabs/claude-cli.\n *\n * Adapters depend on the {@link ClaudeCliRunner} interface only.\n * {@link buildClaudeCliRunner} is the sole factory that touches\n * `node:child_process`; committed tests inject a hand-written fake instead of\n * exercising it, so no real `claude` subprocess is ever spawned in CI.\n *\n * @module\n */\n\nimport { spawn } from 'node:child_process'\n\n/**\n * The result of a single `claude` CLI invocation.\n */\nexport interface ClaudeCliRunResult {\n stdout: string\n stderr: string\n exitCode: number | null\n}\n\n/**\n * Options accepted by {@link ClaudeCliRunner.run}.\n */\nexport interface ClaudeCliRunOptions {\n /** Working directory for the subprocess (the adapter owns tmpdir lifecycle). */\n cwd: string\n /** Kill the subprocess if it has not exited within this many milliseconds. */\n timeoutMs?: number\n /** Kill the subprocess if this signal fires. */\n signal?: AbortSignal\n}\n\n/**\n * The process-execution seam consumed by {@link claudeCliAdapter}.\n *\n * Implementations run the `claude` binary with `args`, write `input` to its\n * stdin (the rendered prompt), and resolve with captured stdout/stderr/exit\n * code. Implementations must never throw for a non-zero exit code — that is\n * the adapter's error-classification job; the one exception is a spawn-time\n * failure (e.g. `ENOENT` when the binary is missing), which should reject.\n */\nexport interface ClaudeCliRunner {\n run(\n args: string[],\n input: string,\n opts: ClaudeCliRunOptions,\n ): Promise<ClaudeCliRunResult>\n}\n\n/**\n * Build the real {@link ClaudeCliRunner}, backed by `node:child_process`.\n *\n * Never exercised by committed tests — only the real dev workflow invokes\n * this factory; tests inject a hand-written fake implementing\n * {@link ClaudeCliRunner} instead.\n *\n * @param claudePath - Path or bare command name for the `claude` binary.\n * Defaults to `'claude'`, resolved via `PATH`.\n */\nexport function buildClaudeCliRunner(claudePath = 'claude'): ClaudeCliRunner {\n return {\n run(args, input, opts) {\n return new Promise((resolve, reject) => {\n if (opts.signal?.aborted === true) {\n const err = new Error('claude-cli call aborted')\n err.name = 'AbortError'\n reject(err)\n return\n }\n\n // NOTE: the argv itself (including the `--safe-mode` vs `--bare`\n // choice) is owned by the adapter (see adapter.ts) — this runner is\n // a dumb pipe. We repeat the rule here only as a pointer: never pass\n // `--bare`, it disables OAuth/keychain auth.\n const child = spawn(claudePath, args, {\n cwd: opts.cwd,\n stdio: ['pipe', 'pipe', 'pipe'],\n })\n\n let stdout = ''\n let stderr = ''\n let settled = false\n // Set once a timeout/abort has begun killing the child. The\n // returned promise is NOT rejected with this until the child's\n // 'close' event actually fires — the caller (the adapter) must\n // never observe settlement while the OS process may still be\n // alive and writing to its scratch cwd.\n let pendingError: Error | undefined\n let timeoutHandle: ReturnType<typeof setTimeout> | undefined\n let killTimeoutHandle: ReturnType<typeof setTimeout> | undefined\n\n const cleanupTimers = (): void => {\n if (timeoutHandle !== undefined) clearTimeout(timeoutHandle)\n if (killTimeoutHandle !== undefined) clearTimeout(killTimeoutHandle)\n }\n\n const cleanup = (): void => {\n cleanupTimers()\n if (opts.signal !== undefined) {\n opts.signal.removeEventListener('abort', onAbort)\n }\n }\n\n const killChild = (): void => {\n child.kill('SIGTERM')\n killTimeoutHandle = setTimeout(() => {\n child.kill('SIGKILL')\n }, 5_000)\n }\n\n const beginReject = (err: Error): void => {\n if (settled || pendingError !== undefined) return\n pendingError = err\n cleanupTimers()\n killChild()\n }\n\n const onAbort = (): void => {\n const err = new Error('claude-cli call aborted')\n err.name = 'AbortError'\n beginReject(err)\n }\n\n // The pre-aborted case is handled above, before `spawn` — by this\n // point `opts.signal`, if present, is guaranteed not yet aborted.\n if (opts.signal !== undefined) {\n opts.signal.addEventListener('abort', onAbort, { once: true })\n }\n\n if (opts.timeoutMs !== undefined) {\n timeoutHandle = setTimeout(() => {\n const err = new Error(`claude-cli call exceeded ${opts.timeoutMs}ms timeout`)\n err.name = 'TimeoutError'\n beginReject(err)\n }, opts.timeoutMs)\n }\n\n child.stdout.on('data', (chunk: Buffer) => {\n stdout += chunk.toString('utf8')\n })\n child.stderr.on('data', (chunk: Buffer) => {\n stderr += chunk.toString('utf8')\n })\n\n child.once('error', (err) => {\n if (settled) return\n settled = true\n cleanup()\n reject(pendingError ?? err)\n })\n\n child.once('close', (exitCode) => {\n if (settled) return\n settled = true\n cleanup()\n if (pendingError !== undefined) {\n reject(pendingError)\n } else {\n resolve({ stdout, stderr, exitCode })\n }\n })\n\n child.stdin.end(input, 'utf8')\n })\n },\n }\n}\n","/**\n * claudeCliAdapter — @gullabs/claude-cli provider adapter.\n *\n * Pure request⇄response mapping over the locally-authenticated `claude`\n * (Claude Code) CLI, via {@link ClaudeCliRunner}. Never persists, never\n * computes cost, never retries, never reads `process.env`.\n *\n * DEV-ONLY: this adapter requires `ctx.auth = { cliSession: true }` — it\n * shells out to a `claude` binary that owns its own local login/session\n * state. It is never usable in a production/serverless environment because\n * there is no interactive CLI login there by construction.\n *\n * @module\n */\n\nimport { mkdtemp, rm } from 'node:fs/promises'\nimport { tmpdir } from 'node:os'\nimport { join } from 'node:path'\n\nimport { LlmError } from '@gullabs/core'\nimport type {\n ProviderAdapter,\n ResolvedRequest,\n AdapterCtx,\n AdapterResult,\n Usage,\n Warning,\n FinishReason,\n JsonValue,\n Message,\n Part,\n} from '@gullabs/core'\nimport { buildClaudeCliRunner } from './runner.js'\nimport type { ClaudeCliRunner, ClaudeCliRunResult } from './runner.js'\n\n// ---------------------------------------------------------------------------\n// Captured CLI envelope shape (see repo notes for the two captured fixtures)\n// ---------------------------------------------------------------------------\n\n/**\n * The `usage` object nested inside the `claude -p --output-format json`\n * result envelope. Only the fields this adapter consumes are typed here;\n * the full object is preserved verbatim in `Usage.raw`.\n */\nexport interface ClaudeCliUsageShape {\n input_tokens: number\n output_tokens: number\n cache_read_input_tokens?: number\n cache_creation_input_tokens?: number\n [key: string]: unknown\n}\n\n/**\n * The top-level JSON envelope emitted on stdout by\n * `claude -p ... --output-format json` on completion (success or error).\n */\nexport interface ClaudeCliEnvelope {\n type: string\n subtype?: string\n is_error?: boolean\n result?: string\n stop_reason?: string\n session_id?: string\n total_cost_usd?: number\n num_turns?: number\n usage?: ClaudeCliUsageShape\n [key: string]: unknown\n}\n\n// ---------------------------------------------------------------------------\n// Tiny in-file semaphore — adapter-internal concurrency control\n// ---------------------------------------------------------------------------\n\nclass Semaphore {\n private available: number\n private readonly queue: Array<() => void> = []\n\n constructor(max: number) {\n this.available = max\n }\n\n async acquire(): Promise<() => void> {\n if (this.available > 0) {\n this.available -= 1\n return () => {\n this.release()\n }\n }\n await new Promise<void>((resolve) => {\n this.queue.push(resolve)\n })\n this.available -= 1\n return () => {\n this.release()\n }\n }\n\n private release(): void {\n this.available += 1\n const next = this.queue.shift()\n if (next !== undefined) next()\n }\n}\n\n// ---------------------------------------------------------------------------\n// FinishReason mapping\n// ---------------------------------------------------------------------------\n\nfunction mapFinishReason(stopReason: string | undefined): FinishReason | undefined {\n if (stopReason === undefined) return undefined\n switch (stopReason) {\n case 'end_turn':\n return 'stop'\n case 'tool_use':\n // The CLI's own final answer, not a caller-visible tool call — treat\n // as a successful completion for our purposes.\n return 'stop'\n default:\n return 'other'\n }\n}\n\n// ---------------------------------------------------------------------------\n// Usage mapping — GROSS convention\n//\n// `totalTokens` is not reported by the claude-cli usage payload — it is\n// derived as `inputTokens + outputTokens` whenever a usage payload was\n// present; left undefined when there was no usage payload at all.\n// ---------------------------------------------------------------------------\n\nfunction mapUsage(usage: ClaudeCliUsageShape | undefined): Usage {\n const inputTokens = usage?.input_tokens ?? 0\n const outputTokens = usage?.output_tokens ?? 0\n const cachedInputTokens = usage?.cache_read_input_tokens\n const totalTokens = usage !== undefined ? inputTokens + outputTokens : undefined\n\n const details: Record<string, number> = {\n input: inputTokens,\n output: outputTokens,\n ...(cachedInputTokens !== undefined ? { cached: cachedInputTokens } : {}),\n ...(totalTokens !== undefined ? { total: totalTokens } : {}),\n }\n\n const raw: JsonValue = usage !== undefined ? (usage as unknown as JsonValue) : null\n\n return {\n inputTokens,\n outputTokens,\n details,\n raw,\n ...(cachedInputTokens !== undefined ? { cachedInputTokens } : {}),\n ...(totalTokens !== undefined ? { totalTokens } : {}),\n }\n}\n\n// ---------------------------------------------------------------------------\n// Prompt serialization\n// ---------------------------------------------------------------------------\n\nfunction partText(part: Part): string {\n if (part.kind !== 'text') {\n throw new LlmError(\n 'claude-cli is text-only; non-text message parts (inline media, file URIs, tool-call, tool-result) are not supported',\n {\n kind: 'bad_request',\n retryable: false,\n provider: 'claude-cli',\n },\n )\n }\n return part.text\n}\n\nfunction messageText(msg: Message): string {\n return msg.parts.map(partText).join('')\n}\n\n/**\n * Serialize `req.messages` into the single string sent to the CLI over\n * stdin.\n *\n * - Single user message, single text part → the text verbatim.\n * - Otherwise → a role-labelled transcript, blocks separated by a blank line.\n */\nfunction buildPrompt(messages: Message[]): string {\n if (messages.length === 1 && messages[0]?.parts.length === 1) {\n return partText(messages[0].parts[0] as Part)\n }\n\n return messages\n .map((msg) => {\n const label = msg.role === 'assistant' ? 'Assistant' : 'User'\n return `${label}:\\n${messageText(msg)}`\n })\n .join('\\n\\n')\n}\n\n// ---------------------------------------------------------------------------\n// Error classification\n// ---------------------------------------------------------------------------\n\nfunction looksAuthy(text: string): boolean {\n return /login|auth|unauthorized/i.test(text)\n}\n\nfunction looksRateLimited(text: string): boolean {\n return /rate limit|429/i.test(text)\n}\n\nfunction classifyRunFailure(\n envelope: ClaudeCliEnvelope | undefined,\n result: ClaudeCliRunResult,\n): LlmError {\n const combinedText = `${envelope?.subtype ?? ''} ${result.stderr}`\n\n if (looksAuthy(combinedText)) {\n return new LlmError(\n `claude CLI reported an authentication failure: ${result.stderr.slice(-500)}`,\n { kind: 'invalid_auth', retryable: false, provider: 'claude-cli' },\n )\n }\n\n if (looksRateLimited(combinedText)) {\n return new LlmError(\n `claude CLI reported rate limiting: ${result.stderr.slice(-500)}`,\n {\n kind: 'rate_limited',\n retryable: true,\n provider: 'claude-cli',\n },\n )\n }\n\n if (envelope?.is_error === true) {\n return new LlmError(\n `claude CLI reported an error (subtype: ${envelope.subtype ?? 'unknown'}): ${result.stderr.slice(-500)}`,\n { kind: 'server', retryable: false, provider: 'claude-cli' },\n )\n }\n\n const stderrTail = result.stderr.slice(-500)\n return new LlmError(\n `claude CLI exited with code ${String(result.exitCode)}: ${stderrTail}`,\n { kind: 'unknown', retryable: false, provider: 'claude-cli' },\n )\n}\n\n// ---------------------------------------------------------------------------\n// Adapter options\n// ---------------------------------------------------------------------------\n\nexport interface ClaudeCliAdapterOptions {\n /** Inject a runner (real or fake). Defaults to `buildClaudeCliRunner()`. */\n runner?: ClaudeCliRunner\n /** Path or bare command name for the `claude` binary. Defaults to `'claude'`. */\n claudePath?: string\n /** Max concurrent CLI invocations. Defaults to `2`. */\n maxConcurrency?: number\n}\n\n// ---------------------------------------------------------------------------\n// claudeCliAdapter factory\n// ---------------------------------------------------------------------------\n\n/**\n * Create a dev-only Claude Code CLI provider adapter.\n *\n * Requires `ctx.auth = { cliSession: true }` — see module docs.\n */\nexport function claudeCliAdapter(opts?: ClaudeCliAdapterOptions): ProviderAdapter {\n // Constructed eagerly but never invoked unless `opts.runner` is absent —\n // `buildClaudeCliRunner` only closes over `node:child_process`, it does not\n // spawn anything until `.run()` is called.\n const runner: ClaudeCliRunner = opts?.runner ?? buildClaudeCliRunner(opts?.claudePath)\n\n const semaphore = new Semaphore(opts?.maxConcurrency ?? 2)\n\n return {\n id: 'claude-cli',\n\n async run(req: ResolvedRequest, ctx: AdapterCtx): Promise<AdapterResult> {\n // ------------------------------------------------------------------\n // 1. Auth — CliSessionAuth only.\n // ------------------------------------------------------------------\n const hasCliSession = 'cliSession' in ctx.auth && ctx.auth.cliSession\n if (!hasCliSession) {\n throw new LlmError(\n '@gullabs/claude-cli requires auth: { cliSession: true } — these dev-only providers route through a locally-authenticated `claude` CLI session, not an API key',\n { kind: 'invalid_auth', retryable: false, provider: 'claude-cli' },\n )\n }\n\n if (req.provider !== 'claude-cli') {\n throw new LlmError(\n `@gullabs/claude-cli received a request routed for provider \"${req.provider}\" — this adapter only serves \"claude-cli\"`,\n { kind: 'bad_request', retryable: false, provider: 'claude-cli' },\n )\n }\n if (req.tools !== undefined && req.tools.length > 0) {\n throw new LlmError(\n 'claude-cli does not support LlmRequest.tools; CLI runtimes are out of the function-calling seam.',\n { kind: 'bad_request', retryable: false, provider: 'claude-cli' },\n )\n }\n\n const warnings: Warning[] = []\n const model = req.model\n const config = req.config\n\n // ------------------------------------------------------------------\n // 2. Prompt serialization (throws bad_request on non-text parts).\n // ------------------------------------------------------------------\n const prompt = buildPrompt(req.messages)\n\n // ------------------------------------------------------------------\n // 3. Invariant argv — adapter-owned, never caller-configurable.\n //\n // We use --safe-mode, NEVER --bare: --bare disables OAuth/keychain\n // auth and would break subscription-based Claude Code auth — the\n // exact mechanism that lets these dev-only providers work with zero\n // API-key configuration at all.\n // ------------------------------------------------------------------\n const args: string[] = [\n '-p',\n '--output-format',\n 'json',\n '--safe-mode',\n '--tools',\n '',\n '--disable-slash-commands',\n '--no-session-persistence',\n ]\n\n args.push('--model', model)\n\n const effort = config.reasoning?.effort\n if (effort !== undefined) {\n // `effort` was already validated against this package's own zod\n // schema at the config layer before the engine called us — forward\n // verbatim, no re-validation, no `any` cast.\n args.push('--effort', String(effort))\n }\n\n if (req.system !== undefined) {\n args.push('--system-prompt', req.system)\n }\n\n if (req.outputJsonSchema !== undefined) {\n args.push('--json-schema', JSON.stringify(req.outputJsonSchema))\n }\n\n // ------------------------------------------------------------------\n // 4. Timeout + scratch dir + runner invocation.\n // ------------------------------------------------------------------\n const timeoutMs = req.attemptTimeoutMs ?? config.timeoutMs\n\n // The runner owns timeout/abort enforcement end-to-end: it only\n // settles (resolve OR reject) once the child process has actually\n // exited (its 'close' event fired). We deliberately do NOT race an\n // independent timer against `runner.run(...)` here — doing so could\n // let this adapter move on (and release the semaphore / rm the\n // scratch dir) while the real OS child process is still alive and\n // possibly still writing into `cwd`. We simply await the runner\n // promise and classify whatever it settles with.\n const cwd = await mkdtemp(join(tmpdir(), 'claude-cli-'))\n const release = await semaphore.acquire()\n let result: ClaudeCliRunResult\n try {\n result = await runner.run(args, prompt, {\n cwd,\n ...(timeoutMs !== undefined ? { timeoutMs } : {}),\n ...(ctx.signal !== undefined ? { signal: ctx.signal } : {}),\n })\n } catch (rawErr) {\n release()\n await rm(cwd, { recursive: true, force: true })\n\n if (rawErr instanceof LlmError) throw rawErr\n\n if (\n typeof rawErr === 'object' &&\n rawErr !== null &&\n 'code' in rawErr &&\n (rawErr as { code?: unknown }).code === 'ENOENT'\n ) {\n throw new LlmError(\n 'claude CLI not found on PATH — install Claude Code and run `claude auth login`',\n { kind: 'unknown', retryable: false, provider: 'claude-cli' },\n )\n }\n\n if (rawErr instanceof Error && rawErr.name === 'AbortError') {\n throw new LlmError(rawErr.message || 'claude-cli call aborted', {\n kind: 'aborted',\n retryable: false,\n provider: 'claude-cli',\n })\n }\n\n if (rawErr instanceof Error && rawErr.name === 'TimeoutError') {\n throw new LlmError(rawErr.message || 'claude-cli call timed out', {\n kind: 'timeout',\n retryable: true,\n provider: 'claude-cli',\n })\n }\n\n throw new LlmError(\n `claude-cli runner failed: ${rawErr instanceof Error ? rawErr.message : String(rawErr)}`,\n { kind: 'unknown', retryable: false, provider: 'claude-cli', cause: rawErr },\n )\n }\n release()\n await rm(cwd, { recursive: true, force: true })\n\n // ------------------------------------------------------------------\n // 5. Parse the envelope from stdout.\n // ------------------------------------------------------------------\n let envelope: ClaudeCliEnvelope | undefined\n try {\n envelope = JSON.parse(result.stdout) as ClaudeCliEnvelope\n } catch {\n envelope = undefined\n }\n\n if (\n result.exitCode !== 0 ||\n envelope?.is_error === true ||\n envelope === undefined\n ) {\n throw classifyRunFailure(envelope, result)\n }\n\n // ------------------------------------------------------------------\n // 6. Map result → AdapterResult.\n // ------------------------------------------------------------------\n const text = envelope.result ?? ''\n\n let rawStructured: unknown\n if (req.outputJsonSchema !== undefined) {\n try {\n rawStructured = JSON.parse(text)\n } catch {\n warnings.push({\n type: 'other',\n message: 'claude-cli: failed to parse structured output as JSON',\n })\n }\n }\n\n const usage = mapUsage(envelope.usage)\n const finishReason = mapFinishReason(envelope.stop_reason)\n\n const providerMetadata: Record<string, JsonValue> = {\n ...(envelope.total_cost_usd !== undefined\n ? { totalCostUsd: envelope.total_cost_usd }\n : {}),\n ...(envelope.session_id !== undefined ? { sessionId: envelope.session_id } : {}),\n ...(envelope.subtype !== undefined ? { subtype: envelope.subtype } : {}),\n ...(envelope.num_turns !== undefined ? { numTurns: envelope.num_turns } : {}),\n }\n\n const adapterResult: AdapterResult = {\n model,\n usage,\n warnings,\n ...(text.length > 0 ? { text } : {}),\n ...(rawStructured !== undefined ? { rawStructured } : {}),\n ...(finishReason !== undefined ? { finishReason } : {}),\n ...(Object.keys(providerMetadata).length > 0 ? { providerMetadata } : {}),\n }\n\n return adapterResult\n },\n }\n}\n","/**\n * Model config schemas + registry for @gullabs/claude-cli.\n *\n * DEVIATION FROM CONVENTION: `@gullabs/core`'s `packages/core/src/model-config/`\n * only carries config schemas for production API providers (Gemini/Gemma).\n * This dev-only CLI provider intentionally keeps its own model config schemas\n * and registry local to this package instead — core stays free of any\n * knowledge of the local-CLI dev workflow.\n *\n * @module\n */\n\nimport { z } from 'zod'\nimport type { ModelDescriptor, ModelRegistry } from '@gullabs/core'\nimport {\n createModelRegistry,\n toConfigJsonSchema,\n zodToStandardSchema,\n} from '@gullabs/core'\n\n// ---------------------------------------------------------------------------\n// Model ids\n// ---------------------------------------------------------------------------\n\n/** Every model id `@gullabs/claude-cli` knows how to route. */\nexport type ClaudeCliModelId =\n 'claude-fable-5' | 'claude-opus-4-8' | 'claude-sonnet-5' | 'claude-haiku-4-5-20251001'\n\nconst CLAUDE_CLI_MODEL_IDS: readonly ClaudeCliModelId[] = [\n 'claude-fable-5',\n 'claude-opus-4-8',\n 'claude-sonnet-5',\n 'claude-haiku-4-5-20251001',\n]\n\n/**\n * Reasoning effort levels admitted by the `claude` CLI's `--effort` flag.\n *\n * A strict superset of `@gullabs/core`'s `ReasoningEffort` union (which is\n * `'none' | 'low' | 'medium' | 'high' | 'xhigh'`) — `'max'` is the extra\n * value the CLI supports that core's engine-level type does not know about.\n * Because of this mismatch, `admittedReasoningEfforts` (typed\n * `ReadonlyArray<ReasoningEffort>` in `ModelDescriptor.capabilities`) is\n * intentionally OMITTED below rather than cast — this package's own zod\n * schema is the sole validator for `reasoning.effort`, so the field is\n * advisory-only and safe to skip.\n */\nconst CLAUDE_CLI_EFFORTS = ['low', 'medium', 'high', 'xhigh', 'max'] as const\n\n/**\n * Build the strict per-model config schema for a `claude-cli` model.\n *\n * No `temperature`/`topP`/`topK`/`maxOutputTokens`/`stopSequences` fields —\n * the CLI does not support tuning any of these, and `z.strictObject` rejects\n * any unknown key outright (reject, don't map/clamp).\n */\nfunction buildClaudeCliConfigSchema(modelName: string): z.ZodType {\n return z\n .strictObject({\n reasoning: z\n .strictObject({\n effort: z.enum(CLAUDE_CLI_EFFORTS).meta({\n title: 'Reasoning Effort',\n description: `Reasoning effort forwarded to the claude CLI's --effort flag for ${modelName}.`,\n }),\n })\n .optional()\n .meta({\n title: 'Reasoning',\n description: `Reasoning configuration for ${modelName}.`,\n }),\n timeoutMs: z.number().int().positive().max(1_800_000).optional().meta({\n title: 'Timeout',\n description:\n 'Logical request timeout in milliseconds; forwarded to the CLI runner.',\n }),\n })\n .meta({\n title: `${modelName}Config`,\n description: `Strict claude-cli config for model ${modelName}. Text-only, no sampling knobs, effort-based reasoning.`,\n })\n}\n\nexport const ClaudeFable5ConfigSchema = buildClaudeCliConfigSchema('claude-fable-5')\nexport const ClaudeOpus48ConfigSchema = buildClaudeCliConfigSchema('claude-opus-4-8')\nexport const ClaudeSonnet5ConfigSchema = buildClaudeCliConfigSchema('claude-sonnet-5')\nexport const ClaudeHaiku45ConfigSchema = buildClaudeCliConfigSchema(\n 'claude-haiku-4-5-20251001',\n)\n\nconst CONFIG_SCHEMAS: Record<ClaudeCliModelId, z.ZodType> = {\n 'claude-fable-5': ClaudeFable5ConfigSchema,\n 'claude-opus-4-8': ClaudeOpus48ConfigSchema,\n 'claude-sonnet-5': ClaudeSonnet5ConfigSchema,\n 'claude-haiku-4-5-20251001': ClaudeHaiku45ConfigSchema,\n}\n\n// ---------------------------------------------------------------------------\n// Descriptors + registry\n// ---------------------------------------------------------------------------\n\nexport const claudeCliModelDescriptors: ModelDescriptor[] = CLAUDE_CLI_MODEL_IDS.map(\n (id): ModelDescriptor => {\n const configSchema = CONFIG_SCHEMAS[id]\n return {\n model: id,\n provider: 'claude-cli',\n capabilities: {\n structuredOutput: true,\n nativeStructuredOutput: true,\n reasoningApi: 'level',\n sampling: 'fixed',\n vision: false,\n },\n configSchema,\n configJsonSchema: toConfigJsonSchema(configSchema),\n validateConfig: zodToStandardSchema(configSchema),\n }\n },\n)\n\nexport const claudeCliRegistry: ModelRegistry = createModelRegistry(\n claudeCliModelDescriptors,\n)\n","/**\n * `claudeCliProvider` — {@link ProviderPlugin} factory for @gullabs/claude-cli.\n *\n * Bundles the dev-only Claude CLI adapter with its model descriptors. This\n * provider is unpriced by design (dev-only CLI, $0 API spend) — the returned\n * plugin has no `pricingSource`.\n *\n * @module\n */\n\nimport type { ProviderPlugin } from '@gullabs/core'\n\nimport { claudeCliAdapter } from './adapter.js'\nimport type { ClaudeCliAdapterOptions } from './adapter.js'\nimport { claudeCliModelDescriptors } from './models.js'\n\n/**\n * Create a {@link ProviderPlugin} for the dev-only Claude Code CLI provider.\n *\n * Unpriced by design: the returned plugin omits `pricingSource` entirely.\n *\n * @param opts - Forwarded to {@link claudeCliAdapter}.\n * @returns A plugin bundling the Claude CLI adapter and its model descriptors.\n *\n * @example\n * ```ts\n * import { createClient, composeProviders } from '@gullabs/core'\n * import { claudeCliProvider } from '@gullabs/claude-cli'\n *\n * const client = createClient({\n * ...composeProviders([claudeCliProvider()]),\n * })\n * ```\n */\nexport function claudeCliProvider(opts?: ClaudeCliAdapterOptions): ProviderPlugin {\n return {\n adapter: claudeCliAdapter(opts),\n modelDescriptors: claudeCliModelDescriptors,\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/runner.ts","../src/adapter.ts","../src/models.ts","../src/provider.ts"],"names":["spawn","LlmError","mkdtemp","join","tmpdir","rm","z","toConfigJsonSchema","zodToStandardSchema","createModelRegistry"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * ClaudeCliRunner — the process-execution seam for @gullabs/claude-cli.\n *\n * Adapters depend on the {@link ClaudeCliRunner} interface only.\n * {@link buildClaudeCliRunner} is the sole factory that touches\n * `node:child_process`; committed tests inject a hand-written fake instead of\n * exercising it, so no real `claude` subprocess is ever spawned in CI.\n *\n * @module\n */\n\nimport { spawn } from 'node:child_process'\n\n/**\n * The result of a single `claude` CLI invocation.\n */\nexport interface ClaudeCliRunResult {\n stdout: string\n stderr: string\n exitCode: number | null\n}\n\n/**\n * Options accepted by {@link ClaudeCliRunner.run}.\n */\nexport interface ClaudeCliRunOptions {\n /** Working directory for the subprocess (the adapter owns tmpdir lifecycle). */\n cwd: string\n /** Kill the subprocess if it has not exited within this many milliseconds. */\n timeoutMs?: number\n /** Kill the subprocess if this signal fires. */\n signal?: AbortSignal\n}\n\n/**\n * The process-execution seam consumed by {@link claudeCliAdapter}.\n *\n * Implementations run the `claude` binary with `args`, write `input` to its\n * stdin (the rendered prompt), and resolve with captured stdout/stderr/exit\n * code. Implementations must never throw for a non-zero exit code — that is\n * the adapter's error-classification job; the one exception is a spawn-time\n * failure (e.g. `ENOENT` when the binary is missing), which should reject.\n */\nexport interface ClaudeCliRunner {\n run(\n args: string[],\n input: string,\n opts: ClaudeCliRunOptions,\n ): Promise<ClaudeCliRunResult>\n}\n\n/**\n * Build the real {@link ClaudeCliRunner}, backed by `node:child_process`.\n *\n * Never exercised by committed tests — only the real dev workflow invokes\n * this factory; tests inject a hand-written fake implementing\n * {@link ClaudeCliRunner} instead.\n *\n * @param claudePath - Path or bare command name for the `claude` binary.\n * Defaults to `'claude'`, resolved via `PATH`.\n */\nexport function buildClaudeCliRunner(claudePath = 'claude'): ClaudeCliRunner {\n return {\n run(args, input, opts) {\n return new Promise((resolve, reject) => {\n if (opts.signal?.aborted === true) {\n const err = new Error('claude-cli call aborted')\n err.name = 'AbortError'\n reject(err)\n return\n }\n\n // NOTE: the argv itself (including the `--safe-mode` vs `--bare`\n // choice) is owned by the adapter (see adapter.ts) — this runner is\n // a dumb pipe. We repeat the rule here only as a pointer: never pass\n // `--bare`, it disables OAuth/keychain auth.\n const child = spawn(claudePath, args, {\n cwd: opts.cwd,\n stdio: ['pipe', 'pipe', 'pipe'],\n })\n\n let stdout = ''\n let stderr = ''\n let settled = false\n // Set once a timeout/abort has begun killing the child. The\n // returned promise is NOT rejected with this until the child's\n // 'close' event actually fires — the caller (the adapter) must\n // never observe settlement while the OS process may still be\n // alive and writing to its scratch cwd.\n let pendingError: Error | undefined\n let timeoutHandle: ReturnType<typeof setTimeout> | undefined\n let killTimeoutHandle: ReturnType<typeof setTimeout> | undefined\n\n const cleanupTimers = (): void => {\n if (timeoutHandle !== undefined) clearTimeout(timeoutHandle)\n if (killTimeoutHandle !== undefined) clearTimeout(killTimeoutHandle)\n }\n\n const cleanup = (): void => {\n cleanupTimers()\n if (opts.signal !== undefined) {\n opts.signal.removeEventListener('abort', onAbort)\n }\n }\n\n const killChild = (): void => {\n child.kill('SIGTERM')\n killTimeoutHandle = setTimeout(() => {\n child.kill('SIGKILL')\n }, 5_000)\n }\n\n const beginReject = (err: Error): void => {\n if (settled || pendingError !== undefined) return\n pendingError = err\n cleanupTimers()\n killChild()\n }\n\n const onAbort = (): void => {\n const err = new Error('claude-cli call aborted')\n err.name = 'AbortError'\n beginReject(err)\n }\n\n // The pre-aborted case is handled above, before `spawn` — by this\n // point `opts.signal`, if present, is guaranteed not yet aborted.\n if (opts.signal !== undefined) {\n opts.signal.addEventListener('abort', onAbort, { once: true })\n }\n\n if (opts.timeoutMs !== undefined) {\n timeoutHandle = setTimeout(() => {\n const err = new Error(`claude-cli call exceeded ${opts.timeoutMs}ms timeout`)\n err.name = 'TimeoutError'\n beginReject(err)\n }, opts.timeoutMs)\n }\n\n child.stdout.on('data', (chunk: Buffer) => {\n stdout += chunk.toString('utf8')\n })\n child.stderr.on('data', (chunk: Buffer) => {\n stderr += chunk.toString('utf8')\n })\n\n child.once('error', (err) => {\n if (settled) return\n settled = true\n cleanup()\n reject(pendingError ?? err)\n })\n\n child.once('close', (exitCode) => {\n if (settled) return\n settled = true\n cleanup()\n if (pendingError !== undefined) {\n reject(pendingError)\n } else {\n resolve({ stdout, stderr, exitCode })\n }\n })\n\n child.stdin.end(input, 'utf8')\n })\n },\n }\n}\n","/**\n * claudeCliAdapter — @gullabs/claude-cli provider adapter.\n *\n * Pure request⇄response mapping over the locally-authenticated `claude`\n * (Claude Code) CLI, via {@link ClaudeCliRunner}. Never persists, never\n * computes cost, never retries, never reads `process.env`.\n *\n * DEV-ONLY: this adapter requires `ctx.auth = { cliSession: true }` — it\n * shells out to a `claude` binary that owns its own local login/session\n * state. It is never usable in a production/serverless environment because\n * there is no interactive CLI login there by construction.\n *\n * @module\n */\n\nimport { mkdtemp, rm } from 'node:fs/promises'\nimport { tmpdir } from 'node:os'\nimport { join } from 'node:path'\n\nimport { LlmError } from '@gullabs/core'\nimport type {\n ProviderAdapter,\n ResolvedRequest,\n AdapterCtx,\n AdapterResult,\n Usage,\n Warning,\n FinishReason,\n JsonValue,\n Message,\n Part,\n} from '@gullabs/core'\nimport { buildClaudeCliRunner } from './runner.js'\nimport type { ClaudeCliRunner, ClaudeCliRunResult } from './runner.js'\n\n// ---------------------------------------------------------------------------\n// Captured CLI envelope shape (see repo notes for the two captured fixtures)\n// ---------------------------------------------------------------------------\n\n/**\n * The `usage` object nested inside the `claude -p --output-format json`\n * result envelope. Only the fields this adapter consumes are typed here;\n * the full object is preserved verbatim in `Usage.raw`.\n */\nexport interface ClaudeCliUsageShape {\n input_tokens: number\n output_tokens: number\n cache_read_input_tokens?: number\n cache_creation_input_tokens?: number\n [key: string]: unknown\n}\n\n/**\n * The top-level JSON envelope emitted on stdout by\n * `claude -p ... --output-format json` on completion (success or error).\n */\nexport interface ClaudeCliEnvelope {\n type: string\n subtype?: string\n is_error?: boolean\n result?: string\n stop_reason?: string\n session_id?: string\n total_cost_usd?: number\n num_turns?: number\n usage?: ClaudeCliUsageShape\n /** Per-model usage, checked for an exact requested-model match on success. */\n modelUsage?: Record<string, unknown>\n [key: string]: unknown\n}\n\n// ---------------------------------------------------------------------------\n// Tiny in-file semaphore — adapter-internal concurrency control\n// ---------------------------------------------------------------------------\n\nclass Semaphore {\n private available: number\n private readonly queue: Array<() => void> = []\n\n constructor(max: number) {\n this.available = max\n }\n\n async acquire(): Promise<() => void> {\n if (this.available > 0) {\n this.available -= 1\n return () => {\n this.release()\n }\n }\n await new Promise<void>((resolve) => {\n this.queue.push(resolve)\n })\n this.available -= 1\n return () => {\n this.release()\n }\n }\n\n private release(): void {\n this.available += 1\n const next = this.queue.shift()\n if (next !== undefined) next()\n }\n}\n\n// ---------------------------------------------------------------------------\n// FinishReason mapping\n// ---------------------------------------------------------------------------\n\nfunction mapFinishReason(stopReason: string | undefined): FinishReason | undefined {\n if (stopReason === undefined) return undefined\n switch (stopReason) {\n case 'end_turn':\n return 'stop'\n case 'refusal':\n return 'content_filter'\n case 'tool_use':\n // The CLI's own final answer, not a caller-visible tool call — treat\n // as a successful completion for our purposes.\n return 'stop'\n default:\n return 'other'\n }\n}\n\n// ---------------------------------------------------------------------------\n// Usage mapping — GROSS convention\n//\n// `totalTokens` is not reported by the claude-cli usage payload — it is\n// derived as `inputTokens + outputTokens` whenever a usage payload was\n// present; left undefined when there was no usage payload at all.\n// ---------------------------------------------------------------------------\n\nfunction mapUsage(usage: ClaudeCliUsageShape | undefined): Usage {\n const inputTokens = usage?.input_tokens ?? 0\n const outputTokens = usage?.output_tokens ?? 0\n const cachedInputTokens = usage?.cache_read_input_tokens\n const totalTokens = usage !== undefined ? inputTokens + outputTokens : undefined\n\n const details: Record<string, number> = {\n input: inputTokens,\n output: outputTokens,\n ...(cachedInputTokens !== undefined ? { cached: cachedInputTokens } : {}),\n ...(totalTokens !== undefined ? { total: totalTokens } : {}),\n }\n\n const raw: JsonValue = usage !== undefined ? (usage as unknown as JsonValue) : null\n\n return {\n inputTokens,\n outputTokens,\n details,\n raw,\n ...(cachedInputTokens !== undefined ? { cachedInputTokens } : {}),\n ...(totalTokens !== undefined ? { totalTokens } : {}),\n }\n}\n\n// ---------------------------------------------------------------------------\n// Prompt serialization\n// ---------------------------------------------------------------------------\n\nfunction partText(part: Part): string {\n if (part.kind !== 'text') {\n throw new LlmError(\n 'claude-cli is text-only; non-text message parts (inline media, file URIs, tool-call, tool-result) are not supported',\n {\n kind: 'bad_request',\n retryable: false,\n provider: 'claude-cli',\n },\n )\n }\n return part.text\n}\n\nfunction messageText(msg: Message): string {\n return msg.parts.map(partText).join('')\n}\n\n/**\n * Serialize `req.messages` into the single string sent to the CLI over\n * stdin.\n *\n * - Single user message, single text part → the text verbatim.\n * - Otherwise → a role-labelled transcript, blocks separated by a blank line.\n */\nfunction buildPrompt(messages: Message[]): string {\n if (messages.length === 1 && messages[0]?.parts.length === 1) {\n return partText(messages[0].parts[0] as Part)\n }\n\n return messages\n .map((msg) => {\n const label = msg.role === 'assistant' ? 'Assistant' : 'User'\n return `${label}:\\n${messageText(msg)}`\n })\n .join('\\n\\n')\n}\n\n// ---------------------------------------------------------------------------\n// Error classification\n// ---------------------------------------------------------------------------\n\nfunction looksAuthy(text: string): boolean {\n return /login|auth|unauthorized/i.test(text)\n}\n\nfunction looksRateLimited(text: string): boolean {\n return /rate limit|429/i.test(text)\n}\n\nfunction assertServedModel(envelope: ClaudeCliEnvelope, requestedModel: string): void {\n const modelUsage: unknown = envelope.modelUsage\n if (\n modelUsage === null ||\n typeof modelUsage !== 'object' ||\n Array.isArray(modelUsage)\n ) {\n throw new LlmError('claude CLI did not report a valid modelUsage object.', {\n kind: 'server',\n retryable: false,\n provider: 'claude-cli',\n })\n }\n for (const served of Object.keys(modelUsage)) {\n if (served !== requestedModel) {\n throw new LlmError(\n `claude CLI served model \"${served}\" but the request asked for \"${requestedModel}\".`,\n { kind: 'server', retryable: false, provider: 'claude-cli' },\n )\n }\n }\n if (!Object.hasOwn(modelUsage, requestedModel)) {\n throw new LlmError(\n `claude CLI did not report the requested model \"${requestedModel}\" in modelUsage.`,\n { kind: 'server', retryable: false, provider: 'claude-cli' },\n )\n }\n}\n\nfunction classifyRunFailure(\n envelope: ClaudeCliEnvelope | undefined,\n result: ClaudeCliRunResult,\n): LlmError {\n if (envelope?.stop_reason === 'refusal') {\n return new LlmError('claude CLI refused the prompt (stop_reason: refusal).', {\n kind: 'content_filter',\n retryable: false,\n provider: 'claude-cli',\n })\n }\n\n const combinedText = `${envelope?.subtype ?? ''} ${result.stderr}`\n\n if (looksAuthy(combinedText)) {\n return new LlmError(\n `claude CLI reported an authentication failure: ${result.stderr.slice(-500)}`,\n { kind: 'invalid_auth', retryable: false, provider: 'claude-cli' },\n )\n }\n\n if (looksRateLimited(combinedText)) {\n return new LlmError(\n `claude CLI reported rate limiting: ${result.stderr.slice(-500)}`,\n {\n kind: 'rate_limited',\n retryable: true,\n provider: 'claude-cli',\n },\n )\n }\n\n if (envelope?.is_error === true) {\n return new LlmError(\n `claude CLI reported an error (subtype: ${envelope.subtype ?? 'unknown'}): ${result.stderr.slice(-500)}`,\n { kind: 'server', retryable: false, provider: 'claude-cli' },\n )\n }\n\n const stderrTail = result.stderr.slice(-500)\n return new LlmError(\n `claude CLI exited with code ${String(result.exitCode)}: ${stderrTail}`,\n { kind: 'unknown', retryable: false, provider: 'claude-cli' },\n )\n}\n\n// ---------------------------------------------------------------------------\n// Adapter options\n// ---------------------------------------------------------------------------\n\nexport interface ClaudeCliAdapterOptions {\n /** Inject a runner (real or fake). Defaults to `buildClaudeCliRunner()`. */\n runner?: ClaudeCliRunner\n /** Path or bare command name for the `claude` binary. Defaults to `'claude'`. */\n claudePath?: string\n /** Max concurrent CLI invocations. Defaults to `2`. */\n maxConcurrency?: number\n}\n\n// ---------------------------------------------------------------------------\n// claudeCliAdapter factory\n// ---------------------------------------------------------------------------\n\n/**\n * Create a dev-only Claude Code CLI provider adapter.\n *\n * Requires `ctx.auth = { cliSession: true }` — see module docs.\n */\nexport function claudeCliAdapter(opts?: ClaudeCliAdapterOptions): ProviderAdapter {\n // Constructed eagerly but never invoked unless `opts.runner` is absent —\n // `buildClaudeCliRunner` only closes over `node:child_process`, it does not\n // spawn anything until `.run()` is called.\n const runner: ClaudeCliRunner = opts?.runner ?? buildClaudeCliRunner(opts?.claudePath)\n\n const semaphore = new Semaphore(opts?.maxConcurrency ?? 2)\n\n return {\n id: 'claude-cli',\n\n async run(req: ResolvedRequest, ctx: AdapterCtx): Promise<AdapterResult> {\n // ------------------------------------------------------------------\n // 1. Auth — CliSessionAuth only.\n // ------------------------------------------------------------------\n const hasCliSession = 'cliSession' in ctx.auth && ctx.auth.cliSession\n if (!hasCliSession) {\n throw new LlmError(\n '@gullabs/claude-cli requires auth: { cliSession: true } — these dev-only providers route through a locally-authenticated `claude` CLI session, not an API key',\n { kind: 'invalid_auth', retryable: false, provider: 'claude-cli' },\n )\n }\n\n if (req.provider !== 'claude-cli') {\n throw new LlmError(\n `@gullabs/claude-cli received a request routed for provider \"${req.provider}\" — this adapter only serves \"claude-cli\"`,\n { kind: 'bad_request', retryable: false, provider: 'claude-cli' },\n )\n }\n if (req.tools !== undefined && req.tools.length > 0) {\n throw new LlmError(\n 'claude-cli does not support LlmRequest.tools; CLI runtimes are out of the function-calling seam.',\n { kind: 'bad_request', retryable: false, provider: 'claude-cli' },\n )\n }\n\n const warnings: Warning[] = []\n const model = req.model\n const config = req.config\n\n if (\n req.modelDescriptor?.model !== model ||\n req.modelDescriptor.provider !== 'claude-cli'\n ) {\n throw new LlmError(`No matching Claude model descriptor for \"${model}\".`, {\n kind: 'bad_request',\n retryable: false,\n provider: 'claude-cli',\n })\n }\n if (req.transientProviderState !== undefined) {\n throw new LlmError(`Model \"${model}\" does not admit transientProviderState.`, {\n kind: 'bad_request',\n retryable: false,\n provider: 'claude-cli',\n })\n }\n if (\n config.reasoning !== undefined &&\n req.modelDescriptor.capabilities?.reasoningApi === undefined\n ) {\n throw new LlmError(`Model \"${model}\" does not admit reasoning.`, {\n kind: 'bad_request',\n retryable: false,\n provider: 'claude-cli',\n })\n }\n\n // ------------------------------------------------------------------\n // 2. Prompt serialization (throws bad_request on non-text parts).\n // ------------------------------------------------------------------\n const prompt = buildPrompt(req.messages)\n\n // ------------------------------------------------------------------\n // 3. Invariant argv — adapter-owned, never caller-configurable.\n //\n // We use --safe-mode, NEVER --bare: --bare disables OAuth/keychain\n // auth and would break subscription-based Claude Code auth — the\n // exact mechanism that lets these dev-only providers work with zero\n // API-key configuration at all.\n // ------------------------------------------------------------------\n const args: string[] = [\n '-p',\n '--output-format',\n 'json',\n '--safe-mode',\n '--tools',\n '',\n '--disable-slash-commands',\n '--no-session-persistence',\n '--settings',\n '{\"switchModelsOnFlag\":false}',\n ]\n\n args.push('--model', model)\n\n const effort = config.reasoning?.effort\n if (effort !== undefined) {\n // `effort` was already validated against this package's own zod\n // schema at the config layer before the engine called us — forward\n // verbatim, no re-validation, no `any` cast.\n args.push('--effort', String(effort))\n }\n\n if (req.system !== undefined) {\n args.push('--system-prompt', req.system)\n }\n\n if (req.outputJsonSchema !== undefined) {\n args.push('--json-schema', JSON.stringify(req.outputJsonSchema))\n }\n\n // ------------------------------------------------------------------\n // 4. Timeout + scratch dir + runner invocation.\n // ------------------------------------------------------------------\n const timeoutMs = req.attemptTimeoutMs ?? config.timeoutMs\n\n // The runner owns timeout/abort enforcement end-to-end: it only\n // settles (resolve OR reject) once the child process has actually\n // exited (its 'close' event fired). We deliberately do NOT race an\n // independent timer against `runner.run(...)` here — doing so could\n // let this adapter move on (and release the semaphore / rm the\n // scratch dir) while the real OS child process is still alive and\n // possibly still writing into `cwd`. We simply await the runner\n // promise and classify whatever it settles with.\n const cwd = await mkdtemp(join(tmpdir(), 'claude-cli-'))\n const release = await semaphore.acquire()\n let result: ClaudeCliRunResult\n try {\n result = await runner.run(args, prompt, {\n cwd,\n ...(timeoutMs !== undefined ? { timeoutMs } : {}),\n ...(ctx.signal !== undefined ? { signal: ctx.signal } : {}),\n })\n } catch (rawErr) {\n release()\n await rm(cwd, { recursive: true, force: true })\n\n if (rawErr instanceof LlmError) throw rawErr\n\n if (\n typeof rawErr === 'object' &&\n rawErr !== null &&\n 'code' in rawErr &&\n (rawErr as { code?: unknown }).code === 'ENOENT'\n ) {\n throw new LlmError(\n 'claude CLI not found on PATH — install Claude Code and run `claude auth login`',\n { kind: 'unknown', retryable: false, provider: 'claude-cli' },\n )\n }\n\n if (rawErr instanceof Error && rawErr.name === 'AbortError') {\n throw new LlmError(rawErr.message || 'claude-cli call aborted', {\n kind: 'aborted',\n retryable: false,\n provider: 'claude-cli',\n })\n }\n\n if (rawErr instanceof Error && rawErr.name === 'TimeoutError') {\n throw new LlmError(rawErr.message || 'claude-cli call timed out', {\n kind: 'timeout',\n retryable: true,\n provider: 'claude-cli',\n })\n }\n\n throw new LlmError(\n `claude-cli runner failed: ${rawErr instanceof Error ? rawErr.message : String(rawErr)}`,\n { kind: 'unknown', retryable: false, provider: 'claude-cli', cause: rawErr },\n )\n }\n release()\n await rm(cwd, { recursive: true, force: true })\n\n // ------------------------------------------------------------------\n // 5. Parse the envelope from stdout.\n // ------------------------------------------------------------------\n let envelope: ClaudeCliEnvelope | undefined\n try {\n envelope = JSON.parse(result.stdout) as ClaudeCliEnvelope\n } catch {\n envelope = undefined\n }\n\n if (\n result.exitCode !== 0 ||\n envelope?.is_error === true ||\n envelope === undefined\n ) {\n throw classifyRunFailure(envelope, result)\n }\n\n assertServedModel(envelope, model)\n\n // ------------------------------------------------------------------\n // 6. Map result → AdapterResult.\n // ------------------------------------------------------------------\n const text = envelope.result ?? ''\n\n let rawStructured: unknown\n if (req.outputJsonSchema !== undefined) {\n try {\n rawStructured = JSON.parse(text)\n } catch {\n warnings.push({\n type: 'other',\n message: 'claude-cli: failed to parse structured output as JSON',\n })\n }\n }\n\n const usage = mapUsage(envelope.usage)\n const finishReason = mapFinishReason(envelope.stop_reason)\n\n const providerMetadata: Record<string, JsonValue> = {\n ...(envelope.total_cost_usd !== undefined\n ? { totalCostUsd: envelope.total_cost_usd }\n : {}),\n ...(envelope.session_id !== undefined ? { sessionId: envelope.session_id } : {}),\n ...(envelope.subtype !== undefined ? { subtype: envelope.subtype } : {}),\n ...(envelope.num_turns !== undefined ? { numTurns: envelope.num_turns } : {}),\n }\n\n const adapterResult: AdapterResult = {\n model,\n usage,\n warnings,\n ...(text.length > 0 ? { text } : {}),\n ...(rawStructured !== undefined ? { rawStructured } : {}),\n ...(finishReason !== undefined ? { finishReason } : {}),\n ...(Object.keys(providerMetadata).length > 0 ? { providerMetadata } : {}),\n }\n\n return adapterResult\n },\n }\n}\n","/**\n * Model config schemas + registry for @gullabs/claude-cli.\n *\n * DEVIATION FROM CONVENTION: `@gullabs/core`'s `packages/core/src/model-config/`\n * only carries config schemas for production API providers (Gemini/Gemma).\n * This dev-only CLI provider intentionally keeps its own model config schemas\n * and registry local to this package instead — core stays free of any\n * knowledge of the local-CLI dev workflow.\n *\n * @module\n */\n\nimport { z } from 'zod'\nimport type { ModelDescriptor, ModelRegistry } from '@gullabs/core'\nimport {\n createModelRegistry,\n toConfigJsonSchema,\n zodToStandardSchema,\n} from '@gullabs/core'\n\n// ---------------------------------------------------------------------------\n// Model ids\n// ---------------------------------------------------------------------------\n\n/** Every model id `@gullabs/claude-cli` knows how to route. */\nexport type ClaudeCliModelId =\n 'claude-fable-5-1' | 'claude-opus-5-5' | 'claude-sonnet-5' | 'claude-haiku-4-5-20251001'\n\nexport const CLAUDE_CLI_MODEL_IDS: readonly ClaudeCliModelId[] = [\n 'claude-fable-5-1',\n 'claude-opus-5-5',\n 'claude-sonnet-5',\n 'claude-haiku-4-5-20251001',\n]\n\n/**\n * Reasoning effort levels admitted by the `claude` CLI's `--effort` flag.\n *\n * The CLI admits `low` through `max` on Fable, Opus, and Sonnet. Haiku drops\n * `--effort`, so its descriptor advertises an empty admitted set.\n */\nexport const CLAUDE_CLI_EFFORTS = ['low', 'medium', 'high', 'xhigh', 'max'] as const\n\n/**\n * Build the strict per-model config schema for a `claude-cli` model that\n * admits `--effort`.\n *\n * No `temperature`/`topP`/`topK`/`maxOutputTokens`/`stopSequences` fields —\n * the CLI does not support tuning any of these, and `z.strictObject` rejects\n * any unknown key outright (reject, don't map/clamp).\n */\nfunction buildEffortConfigSchema(modelName: string): z.ZodType {\n return z\n .strictObject({\n reasoning: z\n .strictObject({\n effort: z.enum(CLAUDE_CLI_EFFORTS).meta({\n title: 'Reasoning Effort',\n description: `Reasoning effort forwarded to the claude CLI's --effort flag for ${modelName}.`,\n }),\n })\n .optional()\n .meta({\n title: 'Reasoning',\n description: `Reasoning configuration for ${modelName}.`,\n }),\n timeoutMs: z.number().int().positive().max(1_800_000).optional().meta({\n title: 'Timeout',\n description:\n 'Logical request timeout in milliseconds; forwarded to the CLI runner.',\n }),\n })\n .meta({\n title: `${modelName}Config`,\n description: `Strict claude-cli config for model ${modelName}. Text-only, no sampling knobs, effort-based reasoning.`,\n })\n}\n\n/**\n * Haiku 4.5 silently drops `--effort`. Accepting a reasoning key would be a\n * silent map, so the schema has no reasoning field.\n */\nfunction buildHaikuConfigSchema(): z.ZodType {\n return z\n .strictObject({\n timeoutMs: z.number().int().positive().max(1_800_000).optional().meta({\n title: 'Timeout',\n description:\n 'Logical request timeout in milliseconds; forwarded to the CLI runner.',\n }),\n })\n .meta({\n title: 'claude-haiku-4-5-20251001Config',\n description:\n 'Strict claude-cli config for claude-haiku-4-5-20251001. No reasoning key: the CLI drops --effort.',\n })\n}\n\nexport const ClaudeFable51ConfigSchema = buildEffortConfigSchema('claude-fable-5-1')\nexport const ClaudeOpus55ConfigSchema = buildEffortConfigSchema('claude-opus-5-5')\nexport const ClaudeSonnet5ConfigSchema = buildEffortConfigSchema('claude-sonnet-5')\nexport const ClaudeHaiku45ConfigSchema = buildHaikuConfigSchema()\n\nconst CONFIG_SCHEMAS: Record<ClaudeCliModelId, z.ZodType> = {\n 'claude-fable-5-1': ClaudeFable51ConfigSchema,\n 'claude-opus-5-5': ClaudeOpus55ConfigSchema,\n 'claude-sonnet-5': ClaudeSonnet5ConfigSchema,\n 'claude-haiku-4-5-20251001': ClaudeHaiku45ConfigSchema,\n}\n\n// ---------------------------------------------------------------------------\n// Descriptors + registry\n// ---------------------------------------------------------------------------\n\nexport const claudeCliModelDescriptors: ModelDescriptor[] = CLAUDE_CLI_MODEL_IDS.map(\n (id): ModelDescriptor => {\n const configSchema = CONFIG_SCHEMAS[id]\n return {\n model: id,\n provider: 'claude-cli',\n capabilities: {\n structuredOutput: true,\n nativeStructuredOutput: true,\n ...(id !== 'claude-haiku-4-5-20251001' ? { reasoningApi: 'level' as const } : {}),\n admittedReasoningEfforts:\n id === 'claude-haiku-4-5-20251001' ? [] : CLAUDE_CLI_EFFORTS,\n sampling: 'fixed',\n vision: false,\n },\n configSchema,\n configJsonSchema: toConfigJsonSchema(configSchema),\n validateConfig: zodToStandardSchema(configSchema),\n }\n },\n)\n\nexport const claudeCliRegistry: ModelRegistry = createModelRegistry(\n claudeCliModelDescriptors,\n)\n","/**\n * `claudeCliProvider` — {@link ProviderPlugin} factory for @gullabs/claude-cli.\n *\n * Bundles the dev-only Claude CLI adapter with its model descriptors. This\n * provider is unpriced by design (dev-only CLI, $0 API spend) — the returned\n * plugin has no `pricingSource`.\n *\n * @module\n */\n\nimport type { ProviderPlugin } from '@gullabs/core'\n\nimport { claudeCliAdapter } from './adapter.js'\nimport type { ClaudeCliAdapterOptions } from './adapter.js'\nimport { claudeCliModelDescriptors } from './models.js'\n\n/**\n * Create a {@link ProviderPlugin} for the dev-only Claude Code CLI provider.\n *\n * Unpriced by design: the returned plugin omits `pricingSource` entirely.\n *\n * @param opts - Forwarded to {@link claudeCliAdapter}.\n * @returns A plugin bundling the Claude CLI adapter and its model descriptors.\n *\n * @example\n * ```ts\n * import { createClient, composeProviders } from '@gullabs/core'\n * import { claudeCliProvider } from '@gullabs/claude-cli'\n *\n * const client = createClient({\n * ...composeProviders([claudeCliProvider()]),\n * })\n * ```\n */\nexport function claudeCliProvider(opts?: ClaudeCliAdapterOptions): ProviderPlugin {\n return {\n adapter: claudeCliAdapter(opts),\n modelDescriptors: claudeCliModelDescriptors,\n }\n}\n"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -95,6 +95,8 @@ interface ClaudeCliEnvelope {
|
|
|
95
95
|
total_cost_usd?: number;
|
|
96
96
|
num_turns?: number;
|
|
97
97
|
usage?: ClaudeCliUsageShape;
|
|
98
|
+
/** Per-model usage, checked for an exact requested-model match on success. */
|
|
99
|
+
modelUsage?: Record<string, unknown>;
|
|
98
100
|
[key: string]: unknown;
|
|
99
101
|
}
|
|
100
102
|
interface ClaudeCliAdapterOptions {
|
|
@@ -155,12 +157,20 @@ declare function claudeCliProvider(opts?: ClaudeCliAdapterOptions): ProviderPlug
|
|
|
155
157
|
*/
|
|
156
158
|
|
|
157
159
|
/** Every model id `@gullabs/claude-cli` knows how to route. */
|
|
158
|
-
type ClaudeCliModelId = 'claude-fable-5' | 'claude-opus-
|
|
159
|
-
declare const
|
|
160
|
-
|
|
160
|
+
type ClaudeCliModelId = 'claude-fable-5-1' | 'claude-opus-5-5' | 'claude-sonnet-5' | 'claude-haiku-4-5-20251001';
|
|
161
|
+
declare const CLAUDE_CLI_MODEL_IDS: readonly ClaudeCliModelId[];
|
|
162
|
+
/**
|
|
163
|
+
* Reasoning effort levels admitted by the `claude` CLI's `--effort` flag.
|
|
164
|
+
*
|
|
165
|
+
* The CLI admits `low` through `max` on Fable, Opus, and Sonnet. Haiku drops
|
|
166
|
+
* `--effort`, so its descriptor advertises an empty admitted set.
|
|
167
|
+
*/
|
|
168
|
+
declare const CLAUDE_CLI_EFFORTS: readonly ["low", "medium", "high", "xhigh", "max"];
|
|
169
|
+
declare const ClaudeFable51ConfigSchema: z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>;
|
|
170
|
+
declare const ClaudeOpus55ConfigSchema: z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>;
|
|
161
171
|
declare const ClaudeSonnet5ConfigSchema: z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>;
|
|
162
172
|
declare const ClaudeHaiku45ConfigSchema: z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>;
|
|
163
173
|
declare const claudeCliModelDescriptors: ModelDescriptor[];
|
|
164
174
|
declare const claudeCliRegistry: ModelRegistry;
|
|
165
175
|
|
|
166
|
-
export { type ClaudeCliAdapterOptions, type ClaudeCliEnvelope, type ClaudeCliModelId, type ClaudeCliRunOptions, type ClaudeCliRunResult, type ClaudeCliRunner, type ClaudeCliUsageShape,
|
|
176
|
+
export { CLAUDE_CLI_EFFORTS, CLAUDE_CLI_MODEL_IDS, type ClaudeCliAdapterOptions, type ClaudeCliEnvelope, type ClaudeCliModelId, type ClaudeCliRunOptions, type ClaudeCliRunResult, type ClaudeCliRunner, type ClaudeCliUsageShape, ClaudeFable51ConfigSchema, ClaudeHaiku45ConfigSchema, ClaudeOpus55ConfigSchema, ClaudeSonnet5ConfigSchema, buildClaudeCliRunner, claudeCliAdapter, claudeCliModelDescriptors, claudeCliProvider, claudeCliRegistry };
|
package/dist/index.d.ts
CHANGED
|
@@ -95,6 +95,8 @@ interface ClaudeCliEnvelope {
|
|
|
95
95
|
total_cost_usd?: number;
|
|
96
96
|
num_turns?: number;
|
|
97
97
|
usage?: ClaudeCliUsageShape;
|
|
98
|
+
/** Per-model usage, checked for an exact requested-model match on success. */
|
|
99
|
+
modelUsage?: Record<string, unknown>;
|
|
98
100
|
[key: string]: unknown;
|
|
99
101
|
}
|
|
100
102
|
interface ClaudeCliAdapterOptions {
|
|
@@ -155,12 +157,20 @@ declare function claudeCliProvider(opts?: ClaudeCliAdapterOptions): ProviderPlug
|
|
|
155
157
|
*/
|
|
156
158
|
|
|
157
159
|
/** Every model id `@gullabs/claude-cli` knows how to route. */
|
|
158
|
-
type ClaudeCliModelId = 'claude-fable-5' | 'claude-opus-
|
|
159
|
-
declare const
|
|
160
|
-
|
|
160
|
+
type ClaudeCliModelId = 'claude-fable-5-1' | 'claude-opus-5-5' | 'claude-sonnet-5' | 'claude-haiku-4-5-20251001';
|
|
161
|
+
declare const CLAUDE_CLI_MODEL_IDS: readonly ClaudeCliModelId[];
|
|
162
|
+
/**
|
|
163
|
+
* Reasoning effort levels admitted by the `claude` CLI's `--effort` flag.
|
|
164
|
+
*
|
|
165
|
+
* The CLI admits `low` through `max` on Fable, Opus, and Sonnet. Haiku drops
|
|
166
|
+
* `--effort`, so its descriptor advertises an empty admitted set.
|
|
167
|
+
*/
|
|
168
|
+
declare const CLAUDE_CLI_EFFORTS: readonly ["low", "medium", "high", "xhigh", "max"];
|
|
169
|
+
declare const ClaudeFable51ConfigSchema: z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>;
|
|
170
|
+
declare const ClaudeOpus55ConfigSchema: z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>;
|
|
161
171
|
declare const ClaudeSonnet5ConfigSchema: z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>;
|
|
162
172
|
declare const ClaudeHaiku45ConfigSchema: z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>;
|
|
163
173
|
declare const claudeCliModelDescriptors: ModelDescriptor[];
|
|
164
174
|
declare const claudeCliRegistry: ModelRegistry;
|
|
165
175
|
|
|
166
|
-
export { type ClaudeCliAdapterOptions, type ClaudeCliEnvelope, type ClaudeCliModelId, type ClaudeCliRunOptions, type ClaudeCliRunResult, type ClaudeCliRunner, type ClaudeCliUsageShape,
|
|
176
|
+
export { CLAUDE_CLI_EFFORTS, CLAUDE_CLI_MODEL_IDS, type ClaudeCliAdapterOptions, type ClaudeCliEnvelope, type ClaudeCliModelId, type ClaudeCliRunOptions, type ClaudeCliRunResult, type ClaudeCliRunner, type ClaudeCliUsageShape, ClaudeFable51ConfigSchema, ClaudeHaiku45ConfigSchema, ClaudeOpus55ConfigSchema, ClaudeSonnet5ConfigSchema, buildClaudeCliRunner, claudeCliAdapter, claudeCliModelDescriptors, claudeCliProvider, claudeCliRegistry };
|
package/dist/index.js
CHANGED
|
@@ -124,6 +124,8 @@ function mapFinishReason(stopReason) {
|
|
|
124
124
|
switch (stopReason) {
|
|
125
125
|
case "end_turn":
|
|
126
126
|
return "stop";
|
|
127
|
+
case "refusal":
|
|
128
|
+
return "content_filter";
|
|
127
129
|
case "tool_use":
|
|
128
130
|
return "stop";
|
|
129
131
|
default:
|
|
@@ -183,7 +185,38 @@ function looksAuthy(text) {
|
|
|
183
185
|
function looksRateLimited(text) {
|
|
184
186
|
return /rate limit|429/i.test(text);
|
|
185
187
|
}
|
|
188
|
+
function assertServedModel(envelope, requestedModel) {
|
|
189
|
+
const modelUsage = envelope.modelUsage;
|
|
190
|
+
if (modelUsage === null || typeof modelUsage !== "object" || Array.isArray(modelUsage)) {
|
|
191
|
+
throw new LlmError("claude CLI did not report a valid modelUsage object.", {
|
|
192
|
+
kind: "server",
|
|
193
|
+
retryable: false,
|
|
194
|
+
provider: "claude-cli"
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
for (const served of Object.keys(modelUsage)) {
|
|
198
|
+
if (served !== requestedModel) {
|
|
199
|
+
throw new LlmError(
|
|
200
|
+
`claude CLI served model "${served}" but the request asked for "${requestedModel}".`,
|
|
201
|
+
{ kind: "server", retryable: false, provider: "claude-cli" }
|
|
202
|
+
);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
if (!Object.hasOwn(modelUsage, requestedModel)) {
|
|
206
|
+
throw new LlmError(
|
|
207
|
+
`claude CLI did not report the requested model "${requestedModel}" in modelUsage.`,
|
|
208
|
+
{ kind: "server", retryable: false, provider: "claude-cli" }
|
|
209
|
+
);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
186
212
|
function classifyRunFailure(envelope, result) {
|
|
213
|
+
if (envelope?.stop_reason === "refusal") {
|
|
214
|
+
return new LlmError("claude CLI refused the prompt (stop_reason: refusal).", {
|
|
215
|
+
kind: "content_filter",
|
|
216
|
+
retryable: false,
|
|
217
|
+
provider: "claude-cli"
|
|
218
|
+
});
|
|
219
|
+
}
|
|
187
220
|
const combinedText = `${envelope?.subtype ?? ""} ${result.stderr}`;
|
|
188
221
|
if (looksAuthy(combinedText)) {
|
|
189
222
|
return new LlmError(
|
|
@@ -241,6 +274,27 @@ function claudeCliAdapter(opts) {
|
|
|
241
274
|
const warnings = [];
|
|
242
275
|
const model = req.model;
|
|
243
276
|
const config = req.config;
|
|
277
|
+
if (req.modelDescriptor?.model !== model || req.modelDescriptor.provider !== "claude-cli") {
|
|
278
|
+
throw new LlmError(`No matching Claude model descriptor for "${model}".`, {
|
|
279
|
+
kind: "bad_request",
|
|
280
|
+
retryable: false,
|
|
281
|
+
provider: "claude-cli"
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
if (req.transientProviderState !== void 0) {
|
|
285
|
+
throw new LlmError(`Model "${model}" does not admit transientProviderState.`, {
|
|
286
|
+
kind: "bad_request",
|
|
287
|
+
retryable: false,
|
|
288
|
+
provider: "claude-cli"
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
if (config.reasoning !== void 0 && req.modelDescriptor.capabilities?.reasoningApi === void 0) {
|
|
292
|
+
throw new LlmError(`Model "${model}" does not admit reasoning.`, {
|
|
293
|
+
kind: "bad_request",
|
|
294
|
+
retryable: false,
|
|
295
|
+
provider: "claude-cli"
|
|
296
|
+
});
|
|
297
|
+
}
|
|
244
298
|
const prompt = buildPrompt(req.messages);
|
|
245
299
|
const args = [
|
|
246
300
|
"-p",
|
|
@@ -250,7 +304,9 @@ function claudeCliAdapter(opts) {
|
|
|
250
304
|
"--tools",
|
|
251
305
|
"",
|
|
252
306
|
"--disable-slash-commands",
|
|
253
|
-
"--no-session-persistence"
|
|
307
|
+
"--no-session-persistence",
|
|
308
|
+
"--settings",
|
|
309
|
+
'{"switchModelsOnFlag":false}'
|
|
254
310
|
];
|
|
255
311
|
args.push("--model", model);
|
|
256
312
|
const effort = config.reasoning?.effort;
|
|
@@ -313,6 +369,7 @@ function claudeCliAdapter(opts) {
|
|
|
313
369
|
if (result.exitCode !== 0 || envelope?.is_error === true || envelope === void 0) {
|
|
314
370
|
throw classifyRunFailure(envelope, result);
|
|
315
371
|
}
|
|
372
|
+
assertServedModel(envelope, model);
|
|
316
373
|
const text = envelope.result ?? "";
|
|
317
374
|
let rawStructured;
|
|
318
375
|
if (req.outputJsonSchema !== void 0) {
|
|
@@ -347,13 +404,13 @@ function claudeCliAdapter(opts) {
|
|
|
347
404
|
};
|
|
348
405
|
}
|
|
349
406
|
var CLAUDE_CLI_MODEL_IDS = [
|
|
350
|
-
"claude-fable-5",
|
|
351
|
-
"claude-opus-
|
|
407
|
+
"claude-fable-5-1",
|
|
408
|
+
"claude-opus-5-5",
|
|
352
409
|
"claude-sonnet-5",
|
|
353
410
|
"claude-haiku-4-5-20251001"
|
|
354
411
|
];
|
|
355
412
|
var CLAUDE_CLI_EFFORTS = ["low", "medium", "high", "xhigh", "max"];
|
|
356
|
-
function
|
|
413
|
+
function buildEffortConfigSchema(modelName) {
|
|
357
414
|
return z.strictObject({
|
|
358
415
|
reasoning: z.strictObject({
|
|
359
416
|
effort: z.enum(CLAUDE_CLI_EFFORTS).meta({
|
|
@@ -373,15 +430,24 @@ function buildClaudeCliConfigSchema(modelName) {
|
|
|
373
430
|
description: `Strict claude-cli config for model ${modelName}. Text-only, no sampling knobs, effort-based reasoning.`
|
|
374
431
|
});
|
|
375
432
|
}
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
)
|
|
433
|
+
function buildHaikuConfigSchema() {
|
|
434
|
+
return z.strictObject({
|
|
435
|
+
timeoutMs: z.number().int().positive().max(18e5).optional().meta({
|
|
436
|
+
title: "Timeout",
|
|
437
|
+
description: "Logical request timeout in milliseconds; forwarded to the CLI runner."
|
|
438
|
+
})
|
|
439
|
+
}).meta({
|
|
440
|
+
title: "claude-haiku-4-5-20251001Config",
|
|
441
|
+
description: "Strict claude-cli config for claude-haiku-4-5-20251001. No reasoning key: the CLI drops --effort."
|
|
442
|
+
});
|
|
443
|
+
}
|
|
444
|
+
var ClaudeFable51ConfigSchema = buildEffortConfigSchema("claude-fable-5-1");
|
|
445
|
+
var ClaudeOpus55ConfigSchema = buildEffortConfigSchema("claude-opus-5-5");
|
|
446
|
+
var ClaudeSonnet5ConfigSchema = buildEffortConfigSchema("claude-sonnet-5");
|
|
447
|
+
var ClaudeHaiku45ConfigSchema = buildHaikuConfigSchema();
|
|
382
448
|
var CONFIG_SCHEMAS = {
|
|
383
|
-
"claude-fable-5":
|
|
384
|
-
"claude-opus-
|
|
449
|
+
"claude-fable-5-1": ClaudeFable51ConfigSchema,
|
|
450
|
+
"claude-opus-5-5": ClaudeOpus55ConfigSchema,
|
|
385
451
|
"claude-sonnet-5": ClaudeSonnet5ConfigSchema,
|
|
386
452
|
"claude-haiku-4-5-20251001": ClaudeHaiku45ConfigSchema
|
|
387
453
|
};
|
|
@@ -394,7 +460,8 @@ var claudeCliModelDescriptors = CLAUDE_CLI_MODEL_IDS.map(
|
|
|
394
460
|
capabilities: {
|
|
395
461
|
structuredOutput: true,
|
|
396
462
|
nativeStructuredOutput: true,
|
|
397
|
-
reasoningApi: "level",
|
|
463
|
+
...id !== "claude-haiku-4-5-20251001" ? { reasoningApi: "level" } : {},
|
|
464
|
+
admittedReasoningEfforts: id === "claude-haiku-4-5-20251001" ? [] : CLAUDE_CLI_EFFORTS,
|
|
398
465
|
sampling: "fixed",
|
|
399
466
|
vision: false
|
|
400
467
|
},
|
|
@@ -416,6 +483,6 @@ function claudeCliProvider(opts) {
|
|
|
416
483
|
};
|
|
417
484
|
}
|
|
418
485
|
|
|
419
|
-
export {
|
|
486
|
+
export { CLAUDE_CLI_EFFORTS, CLAUDE_CLI_MODEL_IDS, ClaudeFable51ConfigSchema, ClaudeHaiku45ConfigSchema, ClaudeOpus55ConfigSchema, ClaudeSonnet5ConfigSchema, buildClaudeCliRunner, claudeCliAdapter, claudeCliModelDescriptors, claudeCliProvider, claudeCliRegistry };
|
|
420
487
|
//# sourceMappingURL=index.js.map
|
|
421
488
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/runner.ts","../src/adapter.ts","../src/models.ts","../src/provider.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * ClaudeCliRunner — the process-execution seam for @gullabs/claude-cli.\n *\n * Adapters depend on the {@link ClaudeCliRunner} interface only.\n * {@link buildClaudeCliRunner} is the sole factory that touches\n * `node:child_process`; committed tests inject a hand-written fake instead of\n * exercising it, so no real `claude` subprocess is ever spawned in CI.\n *\n * @module\n */\n\nimport { spawn } from 'node:child_process'\n\n/**\n * The result of a single `claude` CLI invocation.\n */\nexport interface ClaudeCliRunResult {\n stdout: string\n stderr: string\n exitCode: number | null\n}\n\n/**\n * Options accepted by {@link ClaudeCliRunner.run}.\n */\nexport interface ClaudeCliRunOptions {\n /** Working directory for the subprocess (the adapter owns tmpdir lifecycle). */\n cwd: string\n /** Kill the subprocess if it has not exited within this many milliseconds. */\n timeoutMs?: number\n /** Kill the subprocess if this signal fires. */\n signal?: AbortSignal\n}\n\n/**\n * The process-execution seam consumed by {@link claudeCliAdapter}.\n *\n * Implementations run the `claude` binary with `args`, write `input` to its\n * stdin (the rendered prompt), and resolve with captured stdout/stderr/exit\n * code. Implementations must never throw for a non-zero exit code — that is\n * the adapter's error-classification job; the one exception is a spawn-time\n * failure (e.g. `ENOENT` when the binary is missing), which should reject.\n */\nexport interface ClaudeCliRunner {\n run(\n args: string[],\n input: string,\n opts: ClaudeCliRunOptions,\n ): Promise<ClaudeCliRunResult>\n}\n\n/**\n * Build the real {@link ClaudeCliRunner}, backed by `node:child_process`.\n *\n * Never exercised by committed tests — only the real dev workflow invokes\n * this factory; tests inject a hand-written fake implementing\n * {@link ClaudeCliRunner} instead.\n *\n * @param claudePath - Path or bare command name for the `claude` binary.\n * Defaults to `'claude'`, resolved via `PATH`.\n */\nexport function buildClaudeCliRunner(claudePath = 'claude'): ClaudeCliRunner {\n return {\n run(args, input, opts) {\n return new Promise((resolve, reject) => {\n if (opts.signal?.aborted === true) {\n const err = new Error('claude-cli call aborted')\n err.name = 'AbortError'\n reject(err)\n return\n }\n\n // NOTE: the argv itself (including the `--safe-mode` vs `--bare`\n // choice) is owned by the adapter (see adapter.ts) — this runner is\n // a dumb pipe. We repeat the rule here only as a pointer: never pass\n // `--bare`, it disables OAuth/keychain auth.\n const child = spawn(claudePath, args, {\n cwd: opts.cwd,\n stdio: ['pipe', 'pipe', 'pipe'],\n })\n\n let stdout = ''\n let stderr = ''\n let settled = false\n // Set once a timeout/abort has begun killing the child. The\n // returned promise is NOT rejected with this until the child's\n // 'close' event actually fires — the caller (the adapter) must\n // never observe settlement while the OS process may still be\n // alive and writing to its scratch cwd.\n let pendingError: Error | undefined\n let timeoutHandle: ReturnType<typeof setTimeout> | undefined\n let killTimeoutHandle: ReturnType<typeof setTimeout> | undefined\n\n const cleanupTimers = (): void => {\n if (timeoutHandle !== undefined) clearTimeout(timeoutHandle)\n if (killTimeoutHandle !== undefined) clearTimeout(killTimeoutHandle)\n }\n\n const cleanup = (): void => {\n cleanupTimers()\n if (opts.signal !== undefined) {\n opts.signal.removeEventListener('abort', onAbort)\n }\n }\n\n const killChild = (): void => {\n child.kill('SIGTERM')\n killTimeoutHandle = setTimeout(() => {\n child.kill('SIGKILL')\n }, 5_000)\n }\n\n const beginReject = (err: Error): void => {\n if (settled || pendingError !== undefined) return\n pendingError = err\n cleanupTimers()\n killChild()\n }\n\n const onAbort = (): void => {\n const err = new Error('claude-cli call aborted')\n err.name = 'AbortError'\n beginReject(err)\n }\n\n // The pre-aborted case is handled above, before `spawn` — by this\n // point `opts.signal`, if present, is guaranteed not yet aborted.\n if (opts.signal !== undefined) {\n opts.signal.addEventListener('abort', onAbort, { once: true })\n }\n\n if (opts.timeoutMs !== undefined) {\n timeoutHandle = setTimeout(() => {\n const err = new Error(`claude-cli call exceeded ${opts.timeoutMs}ms timeout`)\n err.name = 'TimeoutError'\n beginReject(err)\n }, opts.timeoutMs)\n }\n\n child.stdout.on('data', (chunk: Buffer) => {\n stdout += chunk.toString('utf8')\n })\n child.stderr.on('data', (chunk: Buffer) => {\n stderr += chunk.toString('utf8')\n })\n\n child.once('error', (err) => {\n if (settled) return\n settled = true\n cleanup()\n reject(pendingError ?? err)\n })\n\n child.once('close', (exitCode) => {\n if (settled) return\n settled = true\n cleanup()\n if (pendingError !== undefined) {\n reject(pendingError)\n } else {\n resolve({ stdout, stderr, exitCode })\n }\n })\n\n child.stdin.end(input, 'utf8')\n })\n },\n }\n}\n","/**\n * claudeCliAdapter — @gullabs/claude-cli provider adapter.\n *\n * Pure request⇄response mapping over the locally-authenticated `claude`\n * (Claude Code) CLI, via {@link ClaudeCliRunner}. Never persists, never\n * computes cost, never retries, never reads `process.env`.\n *\n * DEV-ONLY: this adapter requires `ctx.auth = { cliSession: true }` — it\n * shells out to a `claude` binary that owns its own local login/session\n * state. It is never usable in a production/serverless environment because\n * there is no interactive CLI login there by construction.\n *\n * @module\n */\n\nimport { mkdtemp, rm } from 'node:fs/promises'\nimport { tmpdir } from 'node:os'\nimport { join } from 'node:path'\n\nimport { LlmError } from '@gullabs/core'\nimport type {\n ProviderAdapter,\n ResolvedRequest,\n AdapterCtx,\n AdapterResult,\n Usage,\n Warning,\n FinishReason,\n JsonValue,\n Message,\n Part,\n} from '@gullabs/core'\nimport { buildClaudeCliRunner } from './runner.js'\nimport type { ClaudeCliRunner, ClaudeCliRunResult } from './runner.js'\n\n// ---------------------------------------------------------------------------\n// Captured CLI envelope shape (see repo notes for the two captured fixtures)\n// ---------------------------------------------------------------------------\n\n/**\n * The `usage` object nested inside the `claude -p --output-format json`\n * result envelope. Only the fields this adapter consumes are typed here;\n * the full object is preserved verbatim in `Usage.raw`.\n */\nexport interface ClaudeCliUsageShape {\n input_tokens: number\n output_tokens: number\n cache_read_input_tokens?: number\n cache_creation_input_tokens?: number\n [key: string]: unknown\n}\n\n/**\n * The top-level JSON envelope emitted on stdout by\n * `claude -p ... --output-format json` on completion (success or error).\n */\nexport interface ClaudeCliEnvelope {\n type: string\n subtype?: string\n is_error?: boolean\n result?: string\n stop_reason?: string\n session_id?: string\n total_cost_usd?: number\n num_turns?: number\n usage?: ClaudeCliUsageShape\n [key: string]: unknown\n}\n\n// ---------------------------------------------------------------------------\n// Tiny in-file semaphore — adapter-internal concurrency control\n// ---------------------------------------------------------------------------\n\nclass Semaphore {\n private available: number\n private readonly queue: Array<() => void> = []\n\n constructor(max: number) {\n this.available = max\n }\n\n async acquire(): Promise<() => void> {\n if (this.available > 0) {\n this.available -= 1\n return () => {\n this.release()\n }\n }\n await new Promise<void>((resolve) => {\n this.queue.push(resolve)\n })\n this.available -= 1\n return () => {\n this.release()\n }\n }\n\n private release(): void {\n this.available += 1\n const next = this.queue.shift()\n if (next !== undefined) next()\n }\n}\n\n// ---------------------------------------------------------------------------\n// FinishReason mapping\n// ---------------------------------------------------------------------------\n\nfunction mapFinishReason(stopReason: string | undefined): FinishReason | undefined {\n if (stopReason === undefined) return undefined\n switch (stopReason) {\n case 'end_turn':\n return 'stop'\n case 'tool_use':\n // The CLI's own final answer, not a caller-visible tool call — treat\n // as a successful completion for our purposes.\n return 'stop'\n default:\n return 'other'\n }\n}\n\n// ---------------------------------------------------------------------------\n// Usage mapping — GROSS convention\n//\n// `totalTokens` is not reported by the claude-cli usage payload — it is\n// derived as `inputTokens + outputTokens` whenever a usage payload was\n// present; left undefined when there was no usage payload at all.\n// ---------------------------------------------------------------------------\n\nfunction mapUsage(usage: ClaudeCliUsageShape | undefined): Usage {\n const inputTokens = usage?.input_tokens ?? 0\n const outputTokens = usage?.output_tokens ?? 0\n const cachedInputTokens = usage?.cache_read_input_tokens\n const totalTokens = usage !== undefined ? inputTokens + outputTokens : undefined\n\n const details: Record<string, number> = {\n input: inputTokens,\n output: outputTokens,\n ...(cachedInputTokens !== undefined ? { cached: cachedInputTokens } : {}),\n ...(totalTokens !== undefined ? { total: totalTokens } : {}),\n }\n\n const raw: JsonValue = usage !== undefined ? (usage as unknown as JsonValue) : null\n\n return {\n inputTokens,\n outputTokens,\n details,\n raw,\n ...(cachedInputTokens !== undefined ? { cachedInputTokens } : {}),\n ...(totalTokens !== undefined ? { totalTokens } : {}),\n }\n}\n\n// ---------------------------------------------------------------------------\n// Prompt serialization\n// ---------------------------------------------------------------------------\n\nfunction partText(part: Part): string {\n if (part.kind !== 'text') {\n throw new LlmError(\n 'claude-cli is text-only; non-text message parts (inline media, file URIs, tool-call, tool-result) are not supported',\n {\n kind: 'bad_request',\n retryable: false,\n provider: 'claude-cli',\n },\n )\n }\n return part.text\n}\n\nfunction messageText(msg: Message): string {\n return msg.parts.map(partText).join('')\n}\n\n/**\n * Serialize `req.messages` into the single string sent to the CLI over\n * stdin.\n *\n * - Single user message, single text part → the text verbatim.\n * - Otherwise → a role-labelled transcript, blocks separated by a blank line.\n */\nfunction buildPrompt(messages: Message[]): string {\n if (messages.length === 1 && messages[0]?.parts.length === 1) {\n return partText(messages[0].parts[0] as Part)\n }\n\n return messages\n .map((msg) => {\n const label = msg.role === 'assistant' ? 'Assistant' : 'User'\n return `${label}:\\n${messageText(msg)}`\n })\n .join('\\n\\n')\n}\n\n// ---------------------------------------------------------------------------\n// Error classification\n// ---------------------------------------------------------------------------\n\nfunction looksAuthy(text: string): boolean {\n return /login|auth|unauthorized/i.test(text)\n}\n\nfunction looksRateLimited(text: string): boolean {\n return /rate limit|429/i.test(text)\n}\n\nfunction classifyRunFailure(\n envelope: ClaudeCliEnvelope | undefined,\n result: ClaudeCliRunResult,\n): LlmError {\n const combinedText = `${envelope?.subtype ?? ''} ${result.stderr}`\n\n if (looksAuthy(combinedText)) {\n return new LlmError(\n `claude CLI reported an authentication failure: ${result.stderr.slice(-500)}`,\n { kind: 'invalid_auth', retryable: false, provider: 'claude-cli' },\n )\n }\n\n if (looksRateLimited(combinedText)) {\n return new LlmError(\n `claude CLI reported rate limiting: ${result.stderr.slice(-500)}`,\n {\n kind: 'rate_limited',\n retryable: true,\n provider: 'claude-cli',\n },\n )\n }\n\n if (envelope?.is_error === true) {\n return new LlmError(\n `claude CLI reported an error (subtype: ${envelope.subtype ?? 'unknown'}): ${result.stderr.slice(-500)}`,\n { kind: 'server', retryable: false, provider: 'claude-cli' },\n )\n }\n\n const stderrTail = result.stderr.slice(-500)\n return new LlmError(\n `claude CLI exited with code ${String(result.exitCode)}: ${stderrTail}`,\n { kind: 'unknown', retryable: false, provider: 'claude-cli' },\n )\n}\n\n// ---------------------------------------------------------------------------\n// Adapter options\n// ---------------------------------------------------------------------------\n\nexport interface ClaudeCliAdapterOptions {\n /** Inject a runner (real or fake). Defaults to `buildClaudeCliRunner()`. */\n runner?: ClaudeCliRunner\n /** Path or bare command name for the `claude` binary. Defaults to `'claude'`. */\n claudePath?: string\n /** Max concurrent CLI invocations. Defaults to `2`. */\n maxConcurrency?: number\n}\n\n// ---------------------------------------------------------------------------\n// claudeCliAdapter factory\n// ---------------------------------------------------------------------------\n\n/**\n * Create a dev-only Claude Code CLI provider adapter.\n *\n * Requires `ctx.auth = { cliSession: true }` — see module docs.\n */\nexport function claudeCliAdapter(opts?: ClaudeCliAdapterOptions): ProviderAdapter {\n // Constructed eagerly but never invoked unless `opts.runner` is absent —\n // `buildClaudeCliRunner` only closes over `node:child_process`, it does not\n // spawn anything until `.run()` is called.\n const runner: ClaudeCliRunner = opts?.runner ?? buildClaudeCliRunner(opts?.claudePath)\n\n const semaphore = new Semaphore(opts?.maxConcurrency ?? 2)\n\n return {\n id: 'claude-cli',\n\n async run(req: ResolvedRequest, ctx: AdapterCtx): Promise<AdapterResult> {\n // ------------------------------------------------------------------\n // 1. Auth — CliSessionAuth only.\n // ------------------------------------------------------------------\n const hasCliSession = 'cliSession' in ctx.auth && ctx.auth.cliSession\n if (!hasCliSession) {\n throw new LlmError(\n '@gullabs/claude-cli requires auth: { cliSession: true } — these dev-only providers route through a locally-authenticated `claude` CLI session, not an API key',\n { kind: 'invalid_auth', retryable: false, provider: 'claude-cli' },\n )\n }\n\n if (req.provider !== 'claude-cli') {\n throw new LlmError(\n `@gullabs/claude-cli received a request routed for provider \"${req.provider}\" — this adapter only serves \"claude-cli\"`,\n { kind: 'bad_request', retryable: false, provider: 'claude-cli' },\n )\n }\n if (req.tools !== undefined && req.tools.length > 0) {\n throw new LlmError(\n 'claude-cli does not support LlmRequest.tools; CLI runtimes are out of the function-calling seam.',\n { kind: 'bad_request', retryable: false, provider: 'claude-cli' },\n )\n }\n\n const warnings: Warning[] = []\n const model = req.model\n const config = req.config\n\n // ------------------------------------------------------------------\n // 2. Prompt serialization (throws bad_request on non-text parts).\n // ------------------------------------------------------------------\n const prompt = buildPrompt(req.messages)\n\n // ------------------------------------------------------------------\n // 3. Invariant argv — adapter-owned, never caller-configurable.\n //\n // We use --safe-mode, NEVER --bare: --bare disables OAuth/keychain\n // auth and would break subscription-based Claude Code auth — the\n // exact mechanism that lets these dev-only providers work with zero\n // API-key configuration at all.\n // ------------------------------------------------------------------\n const args: string[] = [\n '-p',\n '--output-format',\n 'json',\n '--safe-mode',\n '--tools',\n '',\n '--disable-slash-commands',\n '--no-session-persistence',\n ]\n\n args.push('--model', model)\n\n const effort = config.reasoning?.effort\n if (effort !== undefined) {\n // `effort` was already validated against this package's own zod\n // schema at the config layer before the engine called us — forward\n // verbatim, no re-validation, no `any` cast.\n args.push('--effort', String(effort))\n }\n\n if (req.system !== undefined) {\n args.push('--system-prompt', req.system)\n }\n\n if (req.outputJsonSchema !== undefined) {\n args.push('--json-schema', JSON.stringify(req.outputJsonSchema))\n }\n\n // ------------------------------------------------------------------\n // 4. Timeout + scratch dir + runner invocation.\n // ------------------------------------------------------------------\n const timeoutMs = req.attemptTimeoutMs ?? config.timeoutMs\n\n // The runner owns timeout/abort enforcement end-to-end: it only\n // settles (resolve OR reject) once the child process has actually\n // exited (its 'close' event fired). We deliberately do NOT race an\n // independent timer against `runner.run(...)` here — doing so could\n // let this adapter move on (and release the semaphore / rm the\n // scratch dir) while the real OS child process is still alive and\n // possibly still writing into `cwd`. We simply await the runner\n // promise and classify whatever it settles with.\n const cwd = await mkdtemp(join(tmpdir(), 'claude-cli-'))\n const release = await semaphore.acquire()\n let result: ClaudeCliRunResult\n try {\n result = await runner.run(args, prompt, {\n cwd,\n ...(timeoutMs !== undefined ? { timeoutMs } : {}),\n ...(ctx.signal !== undefined ? { signal: ctx.signal } : {}),\n })\n } catch (rawErr) {\n release()\n await rm(cwd, { recursive: true, force: true })\n\n if (rawErr instanceof LlmError) throw rawErr\n\n if (\n typeof rawErr === 'object' &&\n rawErr !== null &&\n 'code' in rawErr &&\n (rawErr as { code?: unknown }).code === 'ENOENT'\n ) {\n throw new LlmError(\n 'claude CLI not found on PATH — install Claude Code and run `claude auth login`',\n { kind: 'unknown', retryable: false, provider: 'claude-cli' },\n )\n }\n\n if (rawErr instanceof Error && rawErr.name === 'AbortError') {\n throw new LlmError(rawErr.message || 'claude-cli call aborted', {\n kind: 'aborted',\n retryable: false,\n provider: 'claude-cli',\n })\n }\n\n if (rawErr instanceof Error && rawErr.name === 'TimeoutError') {\n throw new LlmError(rawErr.message || 'claude-cli call timed out', {\n kind: 'timeout',\n retryable: true,\n provider: 'claude-cli',\n })\n }\n\n throw new LlmError(\n `claude-cli runner failed: ${rawErr instanceof Error ? rawErr.message : String(rawErr)}`,\n { kind: 'unknown', retryable: false, provider: 'claude-cli', cause: rawErr },\n )\n }\n release()\n await rm(cwd, { recursive: true, force: true })\n\n // ------------------------------------------------------------------\n // 5. Parse the envelope from stdout.\n // ------------------------------------------------------------------\n let envelope: ClaudeCliEnvelope | undefined\n try {\n envelope = JSON.parse(result.stdout) as ClaudeCliEnvelope\n } catch {\n envelope = undefined\n }\n\n if (\n result.exitCode !== 0 ||\n envelope?.is_error === true ||\n envelope === undefined\n ) {\n throw classifyRunFailure(envelope, result)\n }\n\n // ------------------------------------------------------------------\n // 6. Map result → AdapterResult.\n // ------------------------------------------------------------------\n const text = envelope.result ?? ''\n\n let rawStructured: unknown\n if (req.outputJsonSchema !== undefined) {\n try {\n rawStructured = JSON.parse(text)\n } catch {\n warnings.push({\n type: 'other',\n message: 'claude-cli: failed to parse structured output as JSON',\n })\n }\n }\n\n const usage = mapUsage(envelope.usage)\n const finishReason = mapFinishReason(envelope.stop_reason)\n\n const providerMetadata: Record<string, JsonValue> = {\n ...(envelope.total_cost_usd !== undefined\n ? { totalCostUsd: envelope.total_cost_usd }\n : {}),\n ...(envelope.session_id !== undefined ? { sessionId: envelope.session_id } : {}),\n ...(envelope.subtype !== undefined ? { subtype: envelope.subtype } : {}),\n ...(envelope.num_turns !== undefined ? { numTurns: envelope.num_turns } : {}),\n }\n\n const adapterResult: AdapterResult = {\n model,\n usage,\n warnings,\n ...(text.length > 0 ? { text } : {}),\n ...(rawStructured !== undefined ? { rawStructured } : {}),\n ...(finishReason !== undefined ? { finishReason } : {}),\n ...(Object.keys(providerMetadata).length > 0 ? { providerMetadata } : {}),\n }\n\n return adapterResult\n },\n }\n}\n","/**\n * Model config schemas + registry for @gullabs/claude-cli.\n *\n * DEVIATION FROM CONVENTION: `@gullabs/core`'s `packages/core/src/model-config/`\n * only carries config schemas for production API providers (Gemini/Gemma).\n * This dev-only CLI provider intentionally keeps its own model config schemas\n * and registry local to this package instead — core stays free of any\n * knowledge of the local-CLI dev workflow.\n *\n * @module\n */\n\nimport { z } from 'zod'\nimport type { ModelDescriptor, ModelRegistry } from '@gullabs/core'\nimport {\n createModelRegistry,\n toConfigJsonSchema,\n zodToStandardSchema,\n} from '@gullabs/core'\n\n// ---------------------------------------------------------------------------\n// Model ids\n// ---------------------------------------------------------------------------\n\n/** Every model id `@gullabs/claude-cli` knows how to route. */\nexport type ClaudeCliModelId =\n 'claude-fable-5' | 'claude-opus-4-8' | 'claude-sonnet-5' | 'claude-haiku-4-5-20251001'\n\nconst CLAUDE_CLI_MODEL_IDS: readonly ClaudeCliModelId[] = [\n 'claude-fable-5',\n 'claude-opus-4-8',\n 'claude-sonnet-5',\n 'claude-haiku-4-5-20251001',\n]\n\n/**\n * Reasoning effort levels admitted by the `claude` CLI's `--effort` flag.\n *\n * A strict superset of `@gullabs/core`'s `ReasoningEffort` union (which is\n * `'none' | 'low' | 'medium' | 'high' | 'xhigh'`) — `'max'` is the extra\n * value the CLI supports that core's engine-level type does not know about.\n * Because of this mismatch, `admittedReasoningEfforts` (typed\n * `ReadonlyArray<ReasoningEffort>` in `ModelDescriptor.capabilities`) is\n * intentionally OMITTED below rather than cast — this package's own zod\n * schema is the sole validator for `reasoning.effort`, so the field is\n * advisory-only and safe to skip.\n */\nconst CLAUDE_CLI_EFFORTS = ['low', 'medium', 'high', 'xhigh', 'max'] as const\n\n/**\n * Build the strict per-model config schema for a `claude-cli` model.\n *\n * No `temperature`/`topP`/`topK`/`maxOutputTokens`/`stopSequences` fields —\n * the CLI does not support tuning any of these, and `z.strictObject` rejects\n * any unknown key outright (reject, don't map/clamp).\n */\nfunction buildClaudeCliConfigSchema(modelName: string): z.ZodType {\n return z\n .strictObject({\n reasoning: z\n .strictObject({\n effort: z.enum(CLAUDE_CLI_EFFORTS).meta({\n title: 'Reasoning Effort',\n description: `Reasoning effort forwarded to the claude CLI's --effort flag for ${modelName}.`,\n }),\n })\n .optional()\n .meta({\n title: 'Reasoning',\n description: `Reasoning configuration for ${modelName}.`,\n }),\n timeoutMs: z.number().int().positive().max(1_800_000).optional().meta({\n title: 'Timeout',\n description:\n 'Logical request timeout in milliseconds; forwarded to the CLI runner.',\n }),\n })\n .meta({\n title: `${modelName}Config`,\n description: `Strict claude-cli config for model ${modelName}. Text-only, no sampling knobs, effort-based reasoning.`,\n })\n}\n\nexport const ClaudeFable5ConfigSchema = buildClaudeCliConfigSchema('claude-fable-5')\nexport const ClaudeOpus48ConfigSchema = buildClaudeCliConfigSchema('claude-opus-4-8')\nexport const ClaudeSonnet5ConfigSchema = buildClaudeCliConfigSchema('claude-sonnet-5')\nexport const ClaudeHaiku45ConfigSchema = buildClaudeCliConfigSchema(\n 'claude-haiku-4-5-20251001',\n)\n\nconst CONFIG_SCHEMAS: Record<ClaudeCliModelId, z.ZodType> = {\n 'claude-fable-5': ClaudeFable5ConfigSchema,\n 'claude-opus-4-8': ClaudeOpus48ConfigSchema,\n 'claude-sonnet-5': ClaudeSonnet5ConfigSchema,\n 'claude-haiku-4-5-20251001': ClaudeHaiku45ConfigSchema,\n}\n\n// ---------------------------------------------------------------------------\n// Descriptors + registry\n// ---------------------------------------------------------------------------\n\nexport const claudeCliModelDescriptors: ModelDescriptor[] = CLAUDE_CLI_MODEL_IDS.map(\n (id): ModelDescriptor => {\n const configSchema = CONFIG_SCHEMAS[id]\n return {\n model: id,\n provider: 'claude-cli',\n capabilities: {\n structuredOutput: true,\n nativeStructuredOutput: true,\n reasoningApi: 'level',\n sampling: 'fixed',\n vision: false,\n },\n configSchema,\n configJsonSchema: toConfigJsonSchema(configSchema),\n validateConfig: zodToStandardSchema(configSchema),\n }\n },\n)\n\nexport const claudeCliRegistry: ModelRegistry = createModelRegistry(\n claudeCliModelDescriptors,\n)\n","/**\n * `claudeCliProvider` — {@link ProviderPlugin} factory for @gullabs/claude-cli.\n *\n * Bundles the dev-only Claude CLI adapter with its model descriptors. This\n * provider is unpriced by design (dev-only CLI, $0 API spend) — the returned\n * plugin has no `pricingSource`.\n *\n * @module\n */\n\nimport type { ProviderPlugin } from '@gullabs/core'\n\nimport { claudeCliAdapter } from './adapter.js'\nimport type { ClaudeCliAdapterOptions } from './adapter.js'\nimport { claudeCliModelDescriptors } from './models.js'\n\n/**\n * Create a {@link ProviderPlugin} for the dev-only Claude Code CLI provider.\n *\n * Unpriced by design: the returned plugin omits `pricingSource` entirely.\n *\n * @param opts - Forwarded to {@link claudeCliAdapter}.\n * @returns A plugin bundling the Claude CLI adapter and its model descriptors.\n *\n * @example\n * ```ts\n * import { createClient, composeProviders } from '@gullabs/core'\n * import { claudeCliProvider } from '@gullabs/claude-cli'\n *\n * const client = createClient({\n * ...composeProviders([claudeCliProvider()]),\n * })\n * ```\n */\nexport function claudeCliProvider(opts?: ClaudeCliAdapterOptions): ProviderPlugin {\n return {\n adapter: claudeCliAdapter(opts),\n modelDescriptors: claudeCliModelDescriptors,\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/runner.ts","../src/adapter.ts","../src/models.ts","../src/provider.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * ClaudeCliRunner — the process-execution seam for @gullabs/claude-cli.\n *\n * Adapters depend on the {@link ClaudeCliRunner} interface only.\n * {@link buildClaudeCliRunner} is the sole factory that touches\n * `node:child_process`; committed tests inject a hand-written fake instead of\n * exercising it, so no real `claude` subprocess is ever spawned in CI.\n *\n * @module\n */\n\nimport { spawn } from 'node:child_process'\n\n/**\n * The result of a single `claude` CLI invocation.\n */\nexport interface ClaudeCliRunResult {\n stdout: string\n stderr: string\n exitCode: number | null\n}\n\n/**\n * Options accepted by {@link ClaudeCliRunner.run}.\n */\nexport interface ClaudeCliRunOptions {\n /** Working directory for the subprocess (the adapter owns tmpdir lifecycle). */\n cwd: string\n /** Kill the subprocess if it has not exited within this many milliseconds. */\n timeoutMs?: number\n /** Kill the subprocess if this signal fires. */\n signal?: AbortSignal\n}\n\n/**\n * The process-execution seam consumed by {@link claudeCliAdapter}.\n *\n * Implementations run the `claude` binary with `args`, write `input` to its\n * stdin (the rendered prompt), and resolve with captured stdout/stderr/exit\n * code. Implementations must never throw for a non-zero exit code — that is\n * the adapter's error-classification job; the one exception is a spawn-time\n * failure (e.g. `ENOENT` when the binary is missing), which should reject.\n */\nexport interface ClaudeCliRunner {\n run(\n args: string[],\n input: string,\n opts: ClaudeCliRunOptions,\n ): Promise<ClaudeCliRunResult>\n}\n\n/**\n * Build the real {@link ClaudeCliRunner}, backed by `node:child_process`.\n *\n * Never exercised by committed tests — only the real dev workflow invokes\n * this factory; tests inject a hand-written fake implementing\n * {@link ClaudeCliRunner} instead.\n *\n * @param claudePath - Path or bare command name for the `claude` binary.\n * Defaults to `'claude'`, resolved via `PATH`.\n */\nexport function buildClaudeCliRunner(claudePath = 'claude'): ClaudeCliRunner {\n return {\n run(args, input, opts) {\n return new Promise((resolve, reject) => {\n if (opts.signal?.aborted === true) {\n const err = new Error('claude-cli call aborted')\n err.name = 'AbortError'\n reject(err)\n return\n }\n\n // NOTE: the argv itself (including the `--safe-mode` vs `--bare`\n // choice) is owned by the adapter (see adapter.ts) — this runner is\n // a dumb pipe. We repeat the rule here only as a pointer: never pass\n // `--bare`, it disables OAuth/keychain auth.\n const child = spawn(claudePath, args, {\n cwd: opts.cwd,\n stdio: ['pipe', 'pipe', 'pipe'],\n })\n\n let stdout = ''\n let stderr = ''\n let settled = false\n // Set once a timeout/abort has begun killing the child. The\n // returned promise is NOT rejected with this until the child's\n // 'close' event actually fires — the caller (the adapter) must\n // never observe settlement while the OS process may still be\n // alive and writing to its scratch cwd.\n let pendingError: Error | undefined\n let timeoutHandle: ReturnType<typeof setTimeout> | undefined\n let killTimeoutHandle: ReturnType<typeof setTimeout> | undefined\n\n const cleanupTimers = (): void => {\n if (timeoutHandle !== undefined) clearTimeout(timeoutHandle)\n if (killTimeoutHandle !== undefined) clearTimeout(killTimeoutHandle)\n }\n\n const cleanup = (): void => {\n cleanupTimers()\n if (opts.signal !== undefined) {\n opts.signal.removeEventListener('abort', onAbort)\n }\n }\n\n const killChild = (): void => {\n child.kill('SIGTERM')\n killTimeoutHandle = setTimeout(() => {\n child.kill('SIGKILL')\n }, 5_000)\n }\n\n const beginReject = (err: Error): void => {\n if (settled || pendingError !== undefined) return\n pendingError = err\n cleanupTimers()\n killChild()\n }\n\n const onAbort = (): void => {\n const err = new Error('claude-cli call aborted')\n err.name = 'AbortError'\n beginReject(err)\n }\n\n // The pre-aborted case is handled above, before `spawn` — by this\n // point `opts.signal`, if present, is guaranteed not yet aborted.\n if (opts.signal !== undefined) {\n opts.signal.addEventListener('abort', onAbort, { once: true })\n }\n\n if (opts.timeoutMs !== undefined) {\n timeoutHandle = setTimeout(() => {\n const err = new Error(`claude-cli call exceeded ${opts.timeoutMs}ms timeout`)\n err.name = 'TimeoutError'\n beginReject(err)\n }, opts.timeoutMs)\n }\n\n child.stdout.on('data', (chunk: Buffer) => {\n stdout += chunk.toString('utf8')\n })\n child.stderr.on('data', (chunk: Buffer) => {\n stderr += chunk.toString('utf8')\n })\n\n child.once('error', (err) => {\n if (settled) return\n settled = true\n cleanup()\n reject(pendingError ?? err)\n })\n\n child.once('close', (exitCode) => {\n if (settled) return\n settled = true\n cleanup()\n if (pendingError !== undefined) {\n reject(pendingError)\n } else {\n resolve({ stdout, stderr, exitCode })\n }\n })\n\n child.stdin.end(input, 'utf8')\n })\n },\n }\n}\n","/**\n * claudeCliAdapter — @gullabs/claude-cli provider adapter.\n *\n * Pure request⇄response mapping over the locally-authenticated `claude`\n * (Claude Code) CLI, via {@link ClaudeCliRunner}. Never persists, never\n * computes cost, never retries, never reads `process.env`.\n *\n * DEV-ONLY: this adapter requires `ctx.auth = { cliSession: true }` — it\n * shells out to a `claude` binary that owns its own local login/session\n * state. It is never usable in a production/serverless environment because\n * there is no interactive CLI login there by construction.\n *\n * @module\n */\n\nimport { mkdtemp, rm } from 'node:fs/promises'\nimport { tmpdir } from 'node:os'\nimport { join } from 'node:path'\n\nimport { LlmError } from '@gullabs/core'\nimport type {\n ProviderAdapter,\n ResolvedRequest,\n AdapterCtx,\n AdapterResult,\n Usage,\n Warning,\n FinishReason,\n JsonValue,\n Message,\n Part,\n} from '@gullabs/core'\nimport { buildClaudeCliRunner } from './runner.js'\nimport type { ClaudeCliRunner, ClaudeCliRunResult } from './runner.js'\n\n// ---------------------------------------------------------------------------\n// Captured CLI envelope shape (see repo notes for the two captured fixtures)\n// ---------------------------------------------------------------------------\n\n/**\n * The `usage` object nested inside the `claude -p --output-format json`\n * result envelope. Only the fields this adapter consumes are typed here;\n * the full object is preserved verbatim in `Usage.raw`.\n */\nexport interface ClaudeCliUsageShape {\n input_tokens: number\n output_tokens: number\n cache_read_input_tokens?: number\n cache_creation_input_tokens?: number\n [key: string]: unknown\n}\n\n/**\n * The top-level JSON envelope emitted on stdout by\n * `claude -p ... --output-format json` on completion (success or error).\n */\nexport interface ClaudeCliEnvelope {\n type: string\n subtype?: string\n is_error?: boolean\n result?: string\n stop_reason?: string\n session_id?: string\n total_cost_usd?: number\n num_turns?: number\n usage?: ClaudeCliUsageShape\n /** Per-model usage, checked for an exact requested-model match on success. */\n modelUsage?: Record<string, unknown>\n [key: string]: unknown\n}\n\n// ---------------------------------------------------------------------------\n// Tiny in-file semaphore — adapter-internal concurrency control\n// ---------------------------------------------------------------------------\n\nclass Semaphore {\n private available: number\n private readonly queue: Array<() => void> = []\n\n constructor(max: number) {\n this.available = max\n }\n\n async acquire(): Promise<() => void> {\n if (this.available > 0) {\n this.available -= 1\n return () => {\n this.release()\n }\n }\n await new Promise<void>((resolve) => {\n this.queue.push(resolve)\n })\n this.available -= 1\n return () => {\n this.release()\n }\n }\n\n private release(): void {\n this.available += 1\n const next = this.queue.shift()\n if (next !== undefined) next()\n }\n}\n\n// ---------------------------------------------------------------------------\n// FinishReason mapping\n// ---------------------------------------------------------------------------\n\nfunction mapFinishReason(stopReason: string | undefined): FinishReason | undefined {\n if (stopReason === undefined) return undefined\n switch (stopReason) {\n case 'end_turn':\n return 'stop'\n case 'refusal':\n return 'content_filter'\n case 'tool_use':\n // The CLI's own final answer, not a caller-visible tool call — treat\n // as a successful completion for our purposes.\n return 'stop'\n default:\n return 'other'\n }\n}\n\n// ---------------------------------------------------------------------------\n// Usage mapping — GROSS convention\n//\n// `totalTokens` is not reported by the claude-cli usage payload — it is\n// derived as `inputTokens + outputTokens` whenever a usage payload was\n// present; left undefined when there was no usage payload at all.\n// ---------------------------------------------------------------------------\n\nfunction mapUsage(usage: ClaudeCliUsageShape | undefined): Usage {\n const inputTokens = usage?.input_tokens ?? 0\n const outputTokens = usage?.output_tokens ?? 0\n const cachedInputTokens = usage?.cache_read_input_tokens\n const totalTokens = usage !== undefined ? inputTokens + outputTokens : undefined\n\n const details: Record<string, number> = {\n input: inputTokens,\n output: outputTokens,\n ...(cachedInputTokens !== undefined ? { cached: cachedInputTokens } : {}),\n ...(totalTokens !== undefined ? { total: totalTokens } : {}),\n }\n\n const raw: JsonValue = usage !== undefined ? (usage as unknown as JsonValue) : null\n\n return {\n inputTokens,\n outputTokens,\n details,\n raw,\n ...(cachedInputTokens !== undefined ? { cachedInputTokens } : {}),\n ...(totalTokens !== undefined ? { totalTokens } : {}),\n }\n}\n\n// ---------------------------------------------------------------------------\n// Prompt serialization\n// ---------------------------------------------------------------------------\n\nfunction partText(part: Part): string {\n if (part.kind !== 'text') {\n throw new LlmError(\n 'claude-cli is text-only; non-text message parts (inline media, file URIs, tool-call, tool-result) are not supported',\n {\n kind: 'bad_request',\n retryable: false,\n provider: 'claude-cli',\n },\n )\n }\n return part.text\n}\n\nfunction messageText(msg: Message): string {\n return msg.parts.map(partText).join('')\n}\n\n/**\n * Serialize `req.messages` into the single string sent to the CLI over\n * stdin.\n *\n * - Single user message, single text part → the text verbatim.\n * - Otherwise → a role-labelled transcript, blocks separated by a blank line.\n */\nfunction buildPrompt(messages: Message[]): string {\n if (messages.length === 1 && messages[0]?.parts.length === 1) {\n return partText(messages[0].parts[0] as Part)\n }\n\n return messages\n .map((msg) => {\n const label = msg.role === 'assistant' ? 'Assistant' : 'User'\n return `${label}:\\n${messageText(msg)}`\n })\n .join('\\n\\n')\n}\n\n// ---------------------------------------------------------------------------\n// Error classification\n// ---------------------------------------------------------------------------\n\nfunction looksAuthy(text: string): boolean {\n return /login|auth|unauthorized/i.test(text)\n}\n\nfunction looksRateLimited(text: string): boolean {\n return /rate limit|429/i.test(text)\n}\n\nfunction assertServedModel(envelope: ClaudeCliEnvelope, requestedModel: string): void {\n const modelUsage: unknown = envelope.modelUsage\n if (\n modelUsage === null ||\n typeof modelUsage !== 'object' ||\n Array.isArray(modelUsage)\n ) {\n throw new LlmError('claude CLI did not report a valid modelUsage object.', {\n kind: 'server',\n retryable: false,\n provider: 'claude-cli',\n })\n }\n for (const served of Object.keys(modelUsage)) {\n if (served !== requestedModel) {\n throw new LlmError(\n `claude CLI served model \"${served}\" but the request asked for \"${requestedModel}\".`,\n { kind: 'server', retryable: false, provider: 'claude-cli' },\n )\n }\n }\n if (!Object.hasOwn(modelUsage, requestedModel)) {\n throw new LlmError(\n `claude CLI did not report the requested model \"${requestedModel}\" in modelUsage.`,\n { kind: 'server', retryable: false, provider: 'claude-cli' },\n )\n }\n}\n\nfunction classifyRunFailure(\n envelope: ClaudeCliEnvelope | undefined,\n result: ClaudeCliRunResult,\n): LlmError {\n if (envelope?.stop_reason === 'refusal') {\n return new LlmError('claude CLI refused the prompt (stop_reason: refusal).', {\n kind: 'content_filter',\n retryable: false,\n provider: 'claude-cli',\n })\n }\n\n const combinedText = `${envelope?.subtype ?? ''} ${result.stderr}`\n\n if (looksAuthy(combinedText)) {\n return new LlmError(\n `claude CLI reported an authentication failure: ${result.stderr.slice(-500)}`,\n { kind: 'invalid_auth', retryable: false, provider: 'claude-cli' },\n )\n }\n\n if (looksRateLimited(combinedText)) {\n return new LlmError(\n `claude CLI reported rate limiting: ${result.stderr.slice(-500)}`,\n {\n kind: 'rate_limited',\n retryable: true,\n provider: 'claude-cli',\n },\n )\n }\n\n if (envelope?.is_error === true) {\n return new LlmError(\n `claude CLI reported an error (subtype: ${envelope.subtype ?? 'unknown'}): ${result.stderr.slice(-500)}`,\n { kind: 'server', retryable: false, provider: 'claude-cli' },\n )\n }\n\n const stderrTail = result.stderr.slice(-500)\n return new LlmError(\n `claude CLI exited with code ${String(result.exitCode)}: ${stderrTail}`,\n { kind: 'unknown', retryable: false, provider: 'claude-cli' },\n )\n}\n\n// ---------------------------------------------------------------------------\n// Adapter options\n// ---------------------------------------------------------------------------\n\nexport interface ClaudeCliAdapterOptions {\n /** Inject a runner (real or fake). Defaults to `buildClaudeCliRunner()`. */\n runner?: ClaudeCliRunner\n /** Path or bare command name for the `claude` binary. Defaults to `'claude'`. */\n claudePath?: string\n /** Max concurrent CLI invocations. Defaults to `2`. */\n maxConcurrency?: number\n}\n\n// ---------------------------------------------------------------------------\n// claudeCliAdapter factory\n// ---------------------------------------------------------------------------\n\n/**\n * Create a dev-only Claude Code CLI provider adapter.\n *\n * Requires `ctx.auth = { cliSession: true }` — see module docs.\n */\nexport function claudeCliAdapter(opts?: ClaudeCliAdapterOptions): ProviderAdapter {\n // Constructed eagerly but never invoked unless `opts.runner` is absent —\n // `buildClaudeCliRunner` only closes over `node:child_process`, it does not\n // spawn anything until `.run()` is called.\n const runner: ClaudeCliRunner = opts?.runner ?? buildClaudeCliRunner(opts?.claudePath)\n\n const semaphore = new Semaphore(opts?.maxConcurrency ?? 2)\n\n return {\n id: 'claude-cli',\n\n async run(req: ResolvedRequest, ctx: AdapterCtx): Promise<AdapterResult> {\n // ------------------------------------------------------------------\n // 1. Auth — CliSessionAuth only.\n // ------------------------------------------------------------------\n const hasCliSession = 'cliSession' in ctx.auth && ctx.auth.cliSession\n if (!hasCliSession) {\n throw new LlmError(\n '@gullabs/claude-cli requires auth: { cliSession: true } — these dev-only providers route through a locally-authenticated `claude` CLI session, not an API key',\n { kind: 'invalid_auth', retryable: false, provider: 'claude-cli' },\n )\n }\n\n if (req.provider !== 'claude-cli') {\n throw new LlmError(\n `@gullabs/claude-cli received a request routed for provider \"${req.provider}\" — this adapter only serves \"claude-cli\"`,\n { kind: 'bad_request', retryable: false, provider: 'claude-cli' },\n )\n }\n if (req.tools !== undefined && req.tools.length > 0) {\n throw new LlmError(\n 'claude-cli does not support LlmRequest.tools; CLI runtimes are out of the function-calling seam.',\n { kind: 'bad_request', retryable: false, provider: 'claude-cli' },\n )\n }\n\n const warnings: Warning[] = []\n const model = req.model\n const config = req.config\n\n if (\n req.modelDescriptor?.model !== model ||\n req.modelDescriptor.provider !== 'claude-cli'\n ) {\n throw new LlmError(`No matching Claude model descriptor for \"${model}\".`, {\n kind: 'bad_request',\n retryable: false,\n provider: 'claude-cli',\n })\n }\n if (req.transientProviderState !== undefined) {\n throw new LlmError(`Model \"${model}\" does not admit transientProviderState.`, {\n kind: 'bad_request',\n retryable: false,\n provider: 'claude-cli',\n })\n }\n if (\n config.reasoning !== undefined &&\n req.modelDescriptor.capabilities?.reasoningApi === undefined\n ) {\n throw new LlmError(`Model \"${model}\" does not admit reasoning.`, {\n kind: 'bad_request',\n retryable: false,\n provider: 'claude-cli',\n })\n }\n\n // ------------------------------------------------------------------\n // 2. Prompt serialization (throws bad_request on non-text parts).\n // ------------------------------------------------------------------\n const prompt = buildPrompt(req.messages)\n\n // ------------------------------------------------------------------\n // 3. Invariant argv — adapter-owned, never caller-configurable.\n //\n // We use --safe-mode, NEVER --bare: --bare disables OAuth/keychain\n // auth and would break subscription-based Claude Code auth — the\n // exact mechanism that lets these dev-only providers work with zero\n // API-key configuration at all.\n // ------------------------------------------------------------------\n const args: string[] = [\n '-p',\n '--output-format',\n 'json',\n '--safe-mode',\n '--tools',\n '',\n '--disable-slash-commands',\n '--no-session-persistence',\n '--settings',\n '{\"switchModelsOnFlag\":false}',\n ]\n\n args.push('--model', model)\n\n const effort = config.reasoning?.effort\n if (effort !== undefined) {\n // `effort` was already validated against this package's own zod\n // schema at the config layer before the engine called us — forward\n // verbatim, no re-validation, no `any` cast.\n args.push('--effort', String(effort))\n }\n\n if (req.system !== undefined) {\n args.push('--system-prompt', req.system)\n }\n\n if (req.outputJsonSchema !== undefined) {\n args.push('--json-schema', JSON.stringify(req.outputJsonSchema))\n }\n\n // ------------------------------------------------------------------\n // 4. Timeout + scratch dir + runner invocation.\n // ------------------------------------------------------------------\n const timeoutMs = req.attemptTimeoutMs ?? config.timeoutMs\n\n // The runner owns timeout/abort enforcement end-to-end: it only\n // settles (resolve OR reject) once the child process has actually\n // exited (its 'close' event fired). We deliberately do NOT race an\n // independent timer against `runner.run(...)` here — doing so could\n // let this adapter move on (and release the semaphore / rm the\n // scratch dir) while the real OS child process is still alive and\n // possibly still writing into `cwd`. We simply await the runner\n // promise and classify whatever it settles with.\n const cwd = await mkdtemp(join(tmpdir(), 'claude-cli-'))\n const release = await semaphore.acquire()\n let result: ClaudeCliRunResult\n try {\n result = await runner.run(args, prompt, {\n cwd,\n ...(timeoutMs !== undefined ? { timeoutMs } : {}),\n ...(ctx.signal !== undefined ? { signal: ctx.signal } : {}),\n })\n } catch (rawErr) {\n release()\n await rm(cwd, { recursive: true, force: true })\n\n if (rawErr instanceof LlmError) throw rawErr\n\n if (\n typeof rawErr === 'object' &&\n rawErr !== null &&\n 'code' in rawErr &&\n (rawErr as { code?: unknown }).code === 'ENOENT'\n ) {\n throw new LlmError(\n 'claude CLI not found on PATH — install Claude Code and run `claude auth login`',\n { kind: 'unknown', retryable: false, provider: 'claude-cli' },\n )\n }\n\n if (rawErr instanceof Error && rawErr.name === 'AbortError') {\n throw new LlmError(rawErr.message || 'claude-cli call aborted', {\n kind: 'aborted',\n retryable: false,\n provider: 'claude-cli',\n })\n }\n\n if (rawErr instanceof Error && rawErr.name === 'TimeoutError') {\n throw new LlmError(rawErr.message || 'claude-cli call timed out', {\n kind: 'timeout',\n retryable: true,\n provider: 'claude-cli',\n })\n }\n\n throw new LlmError(\n `claude-cli runner failed: ${rawErr instanceof Error ? rawErr.message : String(rawErr)}`,\n { kind: 'unknown', retryable: false, provider: 'claude-cli', cause: rawErr },\n )\n }\n release()\n await rm(cwd, { recursive: true, force: true })\n\n // ------------------------------------------------------------------\n // 5. Parse the envelope from stdout.\n // ------------------------------------------------------------------\n let envelope: ClaudeCliEnvelope | undefined\n try {\n envelope = JSON.parse(result.stdout) as ClaudeCliEnvelope\n } catch {\n envelope = undefined\n }\n\n if (\n result.exitCode !== 0 ||\n envelope?.is_error === true ||\n envelope === undefined\n ) {\n throw classifyRunFailure(envelope, result)\n }\n\n assertServedModel(envelope, model)\n\n // ------------------------------------------------------------------\n // 6. Map result → AdapterResult.\n // ------------------------------------------------------------------\n const text = envelope.result ?? ''\n\n let rawStructured: unknown\n if (req.outputJsonSchema !== undefined) {\n try {\n rawStructured = JSON.parse(text)\n } catch {\n warnings.push({\n type: 'other',\n message: 'claude-cli: failed to parse structured output as JSON',\n })\n }\n }\n\n const usage = mapUsage(envelope.usage)\n const finishReason = mapFinishReason(envelope.stop_reason)\n\n const providerMetadata: Record<string, JsonValue> = {\n ...(envelope.total_cost_usd !== undefined\n ? { totalCostUsd: envelope.total_cost_usd }\n : {}),\n ...(envelope.session_id !== undefined ? { sessionId: envelope.session_id } : {}),\n ...(envelope.subtype !== undefined ? { subtype: envelope.subtype } : {}),\n ...(envelope.num_turns !== undefined ? { numTurns: envelope.num_turns } : {}),\n }\n\n const adapterResult: AdapterResult = {\n model,\n usage,\n warnings,\n ...(text.length > 0 ? { text } : {}),\n ...(rawStructured !== undefined ? { rawStructured } : {}),\n ...(finishReason !== undefined ? { finishReason } : {}),\n ...(Object.keys(providerMetadata).length > 0 ? { providerMetadata } : {}),\n }\n\n return adapterResult\n },\n }\n}\n","/**\n * Model config schemas + registry for @gullabs/claude-cli.\n *\n * DEVIATION FROM CONVENTION: `@gullabs/core`'s `packages/core/src/model-config/`\n * only carries config schemas for production API providers (Gemini/Gemma).\n * This dev-only CLI provider intentionally keeps its own model config schemas\n * and registry local to this package instead — core stays free of any\n * knowledge of the local-CLI dev workflow.\n *\n * @module\n */\n\nimport { z } from 'zod'\nimport type { ModelDescriptor, ModelRegistry } from '@gullabs/core'\nimport {\n createModelRegistry,\n toConfigJsonSchema,\n zodToStandardSchema,\n} from '@gullabs/core'\n\n// ---------------------------------------------------------------------------\n// Model ids\n// ---------------------------------------------------------------------------\n\n/** Every model id `@gullabs/claude-cli` knows how to route. */\nexport type ClaudeCliModelId =\n 'claude-fable-5-1' | 'claude-opus-5-5' | 'claude-sonnet-5' | 'claude-haiku-4-5-20251001'\n\nexport const CLAUDE_CLI_MODEL_IDS: readonly ClaudeCliModelId[] = [\n 'claude-fable-5-1',\n 'claude-opus-5-5',\n 'claude-sonnet-5',\n 'claude-haiku-4-5-20251001',\n]\n\n/**\n * Reasoning effort levels admitted by the `claude` CLI's `--effort` flag.\n *\n * The CLI admits `low` through `max` on Fable, Opus, and Sonnet. Haiku drops\n * `--effort`, so its descriptor advertises an empty admitted set.\n */\nexport const CLAUDE_CLI_EFFORTS = ['low', 'medium', 'high', 'xhigh', 'max'] as const\n\n/**\n * Build the strict per-model config schema for a `claude-cli` model that\n * admits `--effort`.\n *\n * No `temperature`/`topP`/`topK`/`maxOutputTokens`/`stopSequences` fields —\n * the CLI does not support tuning any of these, and `z.strictObject` rejects\n * any unknown key outright (reject, don't map/clamp).\n */\nfunction buildEffortConfigSchema(modelName: string): z.ZodType {\n return z\n .strictObject({\n reasoning: z\n .strictObject({\n effort: z.enum(CLAUDE_CLI_EFFORTS).meta({\n title: 'Reasoning Effort',\n description: `Reasoning effort forwarded to the claude CLI's --effort flag for ${modelName}.`,\n }),\n })\n .optional()\n .meta({\n title: 'Reasoning',\n description: `Reasoning configuration for ${modelName}.`,\n }),\n timeoutMs: z.number().int().positive().max(1_800_000).optional().meta({\n title: 'Timeout',\n description:\n 'Logical request timeout in milliseconds; forwarded to the CLI runner.',\n }),\n })\n .meta({\n title: `${modelName}Config`,\n description: `Strict claude-cli config for model ${modelName}. Text-only, no sampling knobs, effort-based reasoning.`,\n })\n}\n\n/**\n * Haiku 4.5 silently drops `--effort`. Accepting a reasoning key would be a\n * silent map, so the schema has no reasoning field.\n */\nfunction buildHaikuConfigSchema(): z.ZodType {\n return z\n .strictObject({\n timeoutMs: z.number().int().positive().max(1_800_000).optional().meta({\n title: 'Timeout',\n description:\n 'Logical request timeout in milliseconds; forwarded to the CLI runner.',\n }),\n })\n .meta({\n title: 'claude-haiku-4-5-20251001Config',\n description:\n 'Strict claude-cli config for claude-haiku-4-5-20251001. No reasoning key: the CLI drops --effort.',\n })\n}\n\nexport const ClaudeFable51ConfigSchema = buildEffortConfigSchema('claude-fable-5-1')\nexport const ClaudeOpus55ConfigSchema = buildEffortConfigSchema('claude-opus-5-5')\nexport const ClaudeSonnet5ConfigSchema = buildEffortConfigSchema('claude-sonnet-5')\nexport const ClaudeHaiku45ConfigSchema = buildHaikuConfigSchema()\n\nconst CONFIG_SCHEMAS: Record<ClaudeCliModelId, z.ZodType> = {\n 'claude-fable-5-1': ClaudeFable51ConfigSchema,\n 'claude-opus-5-5': ClaudeOpus55ConfigSchema,\n 'claude-sonnet-5': ClaudeSonnet5ConfigSchema,\n 'claude-haiku-4-5-20251001': ClaudeHaiku45ConfigSchema,\n}\n\n// ---------------------------------------------------------------------------\n// Descriptors + registry\n// ---------------------------------------------------------------------------\n\nexport const claudeCliModelDescriptors: ModelDescriptor[] = CLAUDE_CLI_MODEL_IDS.map(\n (id): ModelDescriptor => {\n const configSchema = CONFIG_SCHEMAS[id]\n return {\n model: id,\n provider: 'claude-cli',\n capabilities: {\n structuredOutput: true,\n nativeStructuredOutput: true,\n ...(id !== 'claude-haiku-4-5-20251001' ? { reasoningApi: 'level' as const } : {}),\n admittedReasoningEfforts:\n id === 'claude-haiku-4-5-20251001' ? [] : CLAUDE_CLI_EFFORTS,\n sampling: 'fixed',\n vision: false,\n },\n configSchema,\n configJsonSchema: toConfigJsonSchema(configSchema),\n validateConfig: zodToStandardSchema(configSchema),\n }\n },\n)\n\nexport const claudeCliRegistry: ModelRegistry = createModelRegistry(\n claudeCliModelDescriptors,\n)\n","/**\n * `claudeCliProvider` — {@link ProviderPlugin} factory for @gullabs/claude-cli.\n *\n * Bundles the dev-only Claude CLI adapter with its model descriptors. This\n * provider is unpriced by design (dev-only CLI, $0 API spend) — the returned\n * plugin has no `pricingSource`.\n *\n * @module\n */\n\nimport type { ProviderPlugin } from '@gullabs/core'\n\nimport { claudeCliAdapter } from './adapter.js'\nimport type { ClaudeCliAdapterOptions } from './adapter.js'\nimport { claudeCliModelDescriptors } from './models.js'\n\n/**\n * Create a {@link ProviderPlugin} for the dev-only Claude Code CLI provider.\n *\n * Unpriced by design: the returned plugin omits `pricingSource` entirely.\n *\n * @param opts - Forwarded to {@link claudeCliAdapter}.\n * @returns A plugin bundling the Claude CLI adapter and its model descriptors.\n *\n * @example\n * ```ts\n * import { createClient, composeProviders } from '@gullabs/core'\n * import { claudeCliProvider } from '@gullabs/claude-cli'\n *\n * const client = createClient({\n * ...composeProviders([claudeCliProvider()]),\n * })\n * ```\n */\nexport function claudeCliProvider(opts?: ClaudeCliAdapterOptions): ProviderPlugin {\n return {\n adapter: claudeCliAdapter(opts),\n modelDescriptors: claudeCliModelDescriptors,\n }\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gullabs/claude-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "Dev-only Claude Code CLI provider adapter for any-llm — routes calls through a locally-authenticated `claude` CLI session for $0 API spend during workflow iteration. NOT for production use.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -23,11 +23,11 @@
|
|
|
23
23
|
"dist"
|
|
24
24
|
],
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@gullabs/core": "0.
|
|
27
|
-
"zod": "^4.
|
|
26
|
+
"@gullabs/core": "0.15.0",
|
|
27
|
+
"zod": "^4.6.5"
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|
|
30
|
-
"@gullabs/testing": "0.8.
|
|
30
|
+
"@gullabs/testing": "0.8.2"
|
|
31
31
|
},
|
|
32
32
|
"engines": {
|
|
33
33
|
"node": ">=22.12.0"
|