@gullabs/claude-cli 0.4.1 → 0.4.2

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/dist/index.cjs CHANGED
@@ -136,10 +136,12 @@ function mapUsage(usage) {
136
136
  const inputTokens = usage?.input_tokens ?? 0;
137
137
  const outputTokens = usage?.output_tokens ?? 0;
138
138
  const cachedInputTokens = usage?.cache_read_input_tokens;
139
+ const totalTokens = usage !== void 0 ? inputTokens + outputTokens : void 0;
139
140
  const details = {
140
141
  input: inputTokens,
141
142
  output: outputTokens,
142
- ...cachedInputTokens !== void 0 ? { cached: cachedInputTokens } : {}
143
+ ...cachedInputTokens !== void 0 ? { cached: cachedInputTokens } : {},
144
+ ...totalTokens !== void 0 ? { total: totalTokens } : {}
143
145
  };
144
146
  const raw = usage !== void 0 ? usage : null;
145
147
  return {
@@ -147,7 +149,8 @@ function mapUsage(usage) {
147
149
  outputTokens,
148
150
  details,
149
151
  raw,
150
- ...cachedInputTokens !== void 0 ? { cachedInputTokens } : {}
152
+ ...cachedInputTokens !== void 0 ? { cachedInputTokens } : {},
153
+ ...totalTokens !== void 0 ? { totalTokens } : {}
151
154
  };
152
155
  }
153
156
  function partText(part) {
@@ -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\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\n const details: Record<string, number> = {\n input: inputTokens,\n output: outputTokens,\n ...(cachedInputTokens !== undefined ? { cached: cachedInputTokens } : {}),\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 }\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 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\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'` and `'max'` are extra\n * values 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 [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 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\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'` and `'max'` are extra\n * values 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"]}
package/dist/index.js CHANGED
@@ -134,10 +134,12 @@ function mapUsage(usage) {
134
134
  const inputTokens = usage?.input_tokens ?? 0;
135
135
  const outputTokens = usage?.output_tokens ?? 0;
136
136
  const cachedInputTokens = usage?.cache_read_input_tokens;
137
+ const totalTokens = usage !== void 0 ? inputTokens + outputTokens : void 0;
137
138
  const details = {
138
139
  input: inputTokens,
139
140
  output: outputTokens,
140
- ...cachedInputTokens !== void 0 ? { cached: cachedInputTokens } : {}
141
+ ...cachedInputTokens !== void 0 ? { cached: cachedInputTokens } : {},
142
+ ...totalTokens !== void 0 ? { total: totalTokens } : {}
141
143
  };
142
144
  const raw = usage !== void 0 ? usage : null;
143
145
  return {
@@ -145,7 +147,8 @@ function mapUsage(usage) {
145
147
  outputTokens,
146
148
  details,
147
149
  raw,
148
- ...cachedInputTokens !== void 0 ? { cachedInputTokens } : {}
150
+ ...cachedInputTokens !== void 0 ? { cachedInputTokens } : {},
151
+ ...totalTokens !== void 0 ? { totalTokens } : {}
149
152
  };
150
153
  }
151
154
  function partText(part) {
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\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\n const details: Record<string, number> = {\n input: inputTokens,\n output: outputTokens,\n ...(cachedInputTokens !== undefined ? { cached: cachedInputTokens } : {}),\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 }\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 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\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'` and `'max'` are extra\n * values 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 [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 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\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'` and `'max'` are extra\n * values 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"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gullabs/claude-cli",
3
- "version": "0.4.1",
3
+ "version": "0.4.2",
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",
@@ -24,10 +24,10 @@
24
24
  ],
25
25
  "dependencies": {
26
26
  "zod": "^4.4.3",
27
- "@gullabs/core": "0.9.0"
27
+ "@gullabs/core": "0.10.0"
28
28
  },
29
29
  "devDependencies": {
30
- "@gullabs/testing": "0.4.1"
30
+ "@gullabs/testing": "0.4.2"
31
31
  },
32
32
  "engines": {
33
33
  "node": ">=20.9.0"