@tangle-network/sdk-provider-claude-code 0.0.0-stage → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,11 @@
1
+ Copyright (c) 2025 Tangle Network
2
+
3
+ All rights reserved.
4
+
5
+ This software and associated documentation files (the "Software") are proprietary
6
+ and confidential. No part of this Software may be reproduced, distributed, or
7
+ transmitted in any form or by any means, including photocopying, recording, or
8
+ other electronic or mechanical methods, without the prior written permission of
9
+ Tangle Network.
10
+
11
+ For licensing inquiries, contact: hello@tangle.tools
@@ -0,0 +1,528 @@
1
+ import { AgentExecutionInput, AgentExecutionOutcome, AgentExecutionResult, BackendCapabilities, InteractionResponse, McpConfig, SdkHostServices, StreamEvent } from "@tangle-network/agent-interface";
2
+ import { CliExecArgs, CliProviderAdapterBase, CliProviderConfig, CliTurnProcess, CliTurnSpawn, ExecutionState, HarnessId, PreparedAttachment, WorkspacePlanApplication } from "@tangle-network/sdk-provider-cli-base";
3
+ import * as _$_tangle_network_sdk_cli_runner0 from "@tangle-network/sdk-cli-runner";
4
+ import { StreamParserConfig } from "@tangle-network/sdk-cli-runner";
5
+
6
+ //#region src/types.d.ts
7
+ /**
8
+ * Authentication mode for Claude Code.
9
+ * - "api-key": Use ANTHROPIC_API_KEY environment variable
10
+ * - "oauth": Use OAuth authentication via `claude auth login` (for Max/Pro subscriptions)
11
+ */
12
+ type ClaudeCodeAuthMode = "api-key" | "oauth";
13
+ /**
14
+ * Claude Code-specific configuration.
15
+ */
16
+ interface ClaudeCodeConfig extends CliProviderConfig {
17
+ /** Path to the claude CLI executable. Default: "claude" */
18
+ cliPath?: string;
19
+ /** Model to use. Default: "claude-sonnet-4-5-20250514" */
20
+ model?: string;
21
+ /**
22
+ * Authentication mode.
23
+ * - "api-key": Use apiKey or ANTHROPIC_API_KEY env var
24
+ * - "oauth": Use CLI-managed OAuth (for Max/Pro subscriptions)
25
+ * Default: "api-key" if apiKey is provided, otherwise "oauth"
26
+ */
27
+ authMode?: ClaudeCodeAuthMode;
28
+ /** Optional auth files to materialize under HOME before invoking the CLI. */
29
+ authFiles?: Array<{
30
+ path: string;
31
+ content: string;
32
+ mode?: number;
33
+ }>;
34
+ /** API key (ANTHROPIC_API_KEY). Only used when authMode is "api-key". */
35
+ apiKey?: string;
36
+ /** Extra flags to pass to the CLI */
37
+ extraFlags?: string[];
38
+ /**
39
+ * Bypass all permission checks.
40
+ * Uses --dangerously-skip-permissions flag.
41
+ * Default: true (for headless/automated use)
42
+ */
43
+ bypassPermissions?: boolean;
44
+ /**
45
+ * Route the agent's tool-permission decisions to a human through the
46
+ * generalized `kind:"permission"` interaction broker instead of bypassing
47
+ * them. When true, the adapter drops `--dangerously-skip-permissions`, hosts
48
+ * a per-execution permission MCP tool, and points the CLI at it via
49
+ * `--permission-prompt-tool`; each tool-use prompt becomes an interaction the
50
+ * sidecar answers with `respondToInteraction`. Opt-in — default headless
51
+ * behavior (bypass) is unchanged.
52
+ */
53
+ interactivePermissions?: boolean;
54
+ /**
55
+ * Run the agent in Claude Code plan mode (`--permission-mode plan`): it works
56
+ * read-only, then calls `ExitPlanMode` to propose a plan. That call is
57
+ * intercepted on the same per-execution permission MCP server and surfaced as a
58
+ * `kind:"plan"` interaction — accept to let the agent proceed, reject to make it
59
+ * revise. Hosts the permission server like `interactivePermissions`. Opt-in.
60
+ */
61
+ planMode?: boolean;
62
+ /**
63
+ * Keep a run that shares the host's own `~/.claude` free of that host's
64
+ * state: only project and local settings load (`--setting-sources
65
+ * project,local`), only this turn's MCP servers load (`--strict-mcp-config`
66
+ * even when there are none), and auto-memory is off. A sandbox with its
67
+ * own HOME leaves it unset. Default: false.
68
+ */
69
+ isolateHostSettings?: boolean;
70
+ }
71
+ /**
72
+ * Claude Code CLI event types based on stream-json output format.
73
+ * These match the JSONL output from `claude --output-format stream-json`.
74
+ */
75
+ /**
76
+ * Init event - emitted at start of execution.
77
+ */
78
+ interface ClaudeCodeInitEvent {
79
+ type: "init";
80
+ session_id: string;
81
+ tools?: string[];
82
+ mcp_servers?: string[];
83
+ model?: string;
84
+ }
85
+ /**
86
+ * System event - system status messages.
87
+ *
88
+ * In stream-json output, the session-init payload arrives as
89
+ * `{type:"system", subtype:"init", session_id, tools, mcp_servers, model}`
90
+ * rather than the documented `{type:"init", ...}` shape, so the init fields
91
+ * are surfaced here as optional and mapInitEvent accepts either variant.
92
+ */
93
+ interface ClaudeCodeSystemEvent {
94
+ type: "system";
95
+ subtype: string;
96
+ message?: string;
97
+ session_id?: string;
98
+ tools?: string[];
99
+ mcp_servers?: string[];
100
+ model?: string;
101
+ }
102
+ /**
103
+ * Assistant text content block start.
104
+ */
105
+ interface ClaudeCodeContentBlockStart {
106
+ type: "content_block_start";
107
+ index: number;
108
+ content_block: {
109
+ type: "text" | "tool_use" | "thinking";
110
+ id?: string;
111
+ name?: string;
112
+ text?: string;
113
+ thinking?: string;
114
+ };
115
+ }
116
+ /**
117
+ * Content block delta - streaming content.
118
+ */
119
+ interface ClaudeCodeContentBlockDelta {
120
+ type: "content_block_delta";
121
+ index: number;
122
+ delta: {
123
+ type: "text_delta" | "input_json_delta" | "thinking_delta";
124
+ text?: string;
125
+ partial_json?: string;
126
+ thinking?: string;
127
+ };
128
+ }
129
+ /**
130
+ * Content block stop.
131
+ */
132
+ interface ClaudeCodeContentBlockStop {
133
+ type: "content_block_stop";
134
+ index: number;
135
+ }
136
+ /**
137
+ * Tool use event - tool invocation.
138
+ */
139
+ interface ClaudeCodeToolUseEvent {
140
+ type: "tool_use";
141
+ id: string;
142
+ name: string;
143
+ input: unknown;
144
+ }
145
+ /**
146
+ * Tool result event - tool execution result.
147
+ *
148
+ * NOTE: the current claude CLI (2.x stream-json) does NOT emit this shape at
149
+ * the top level — tool results arrive wrapped in a `ClaudeCodeUserEvent`
150
+ * (`{type:"user", message:{content:[{type:"tool_result", ...}]}}`). This
151
+ * top-level form is kept for replay fixtures and synthetic feeds.
152
+ */
153
+ interface ClaudeCodeToolResultEvent {
154
+ type: "tool_result";
155
+ tool_use_id: string;
156
+ content: unknown;
157
+ is_error?: boolean;
158
+ }
159
+ /**
160
+ * User message event from stream-json output. The real claude CLI delivers
161
+ * every tool result inside one of these envelopes:
162
+ * `{type:"user", message:{role:"user", content:[{type:"tool_result", ...}]}}`.
163
+ * `content` blocks other than tool_result (e.g. echoed user text) are ignored.
164
+ */
165
+ interface ClaudeCodeUserEvent {
166
+ type: "user";
167
+ message?: {
168
+ role?: string;
169
+ content?: string | Array<Record<string, unknown>>;
170
+ };
171
+ }
172
+ /**
173
+ * Result event - final completion. Token counts are nested under `usage`,
174
+ * alongside `total_cost_usd` at the top level.
175
+ */
176
+ interface ClaudeCodeResultEvent {
177
+ type: "result";
178
+ subtype?: string;
179
+ is_error?: boolean;
180
+ api_error_status?: number;
181
+ terminal_reason?: string;
182
+ errors?: string[];
183
+ stop_reason?: string;
184
+ deferred_tool_use?: {
185
+ id: string;
186
+ name: string;
187
+ input: Record<string, unknown>;
188
+ };
189
+ result?: string;
190
+ session_id?: string;
191
+ /** Cost field emitted by the claude CLI's `result` JSON. */
192
+ total_cost_usd?: number;
193
+ duration_ms?: number;
194
+ /** Token counts for the whole turn. */
195
+ usage?: {
196
+ input_tokens?: number;
197
+ output_tokens?: number;
198
+ cache_read_input_tokens?: number;
199
+ cache_creation_input_tokens?: number;
200
+ };
201
+ /**
202
+ * Per-model usage breakdown, keyed by model id (e.g.
203
+ * "claude-opus-4-7[1m]"). Fields are already camelCase on the wire.
204
+ */
205
+ modelUsage?: Record<string, {
206
+ costUSD?: number;
207
+ inputTokens?: number;
208
+ outputTokens?: number;
209
+ cacheReadInputTokens?: number;
210
+ cacheCreationInputTokens?: number;
211
+ }>;
212
+ }
213
+ /**
214
+ * Error event.
215
+ */
216
+ interface ClaudeCodeErrorEvent {
217
+ type: "error";
218
+ error?: {
219
+ type?: string;
220
+ message: string;
221
+ };
222
+ message?: string;
223
+ }
224
+ /**
225
+ * Assistant message event from stream-json output.
226
+ *
227
+ * Emitted as `{type:"assistant", message:{id, content:[{type, text, ...}]}}`.
228
+ * Content blocks (text, tool_use, thinking) are delivered inline in the
229
+ * message rather than as separate content_block_* events.
230
+ */
231
+ interface ClaudeCodeAssistantContentBlock {
232
+ type: string;
233
+ text?: string;
234
+ thinking?: string;
235
+ id?: string;
236
+ name?: string;
237
+ input?: Record<string, unknown>;
238
+ }
239
+ interface ClaudeCodeAssistantEvent {
240
+ type: "assistant";
241
+ is_api_error_message?: boolean;
242
+ error?: string;
243
+ message?: {
244
+ id?: string;
245
+ content?: ClaudeCodeAssistantContentBlock[];
246
+ usage?: {
247
+ input_tokens?: number;
248
+ output_tokens?: number;
249
+ cache_read_input_tokens?: number;
250
+ cache_creation_input_tokens?: number;
251
+ };
252
+ };
253
+ }
254
+ /**
255
+ * Union of all Claude Code CLI events.
256
+ */
257
+ type ClaudeCodeEvent = ClaudeCodeInitEvent | ClaudeCodeSystemEvent | ClaudeCodeAssistantEvent | ClaudeCodeUserEvent | ClaudeCodeContentBlockStart | ClaudeCodeContentBlockDelta | ClaudeCodeContentBlockStop | ClaudeCodeToolUseEvent | ClaudeCodeToolResultEvent | ClaudeCodeResultEvent | ClaudeCodeErrorEvent | ClaudeCodeRateLimitEvent;
258
+ /** Subscription rate-limit state, emitted when it changes (seconds since epoch). */
259
+ interface ClaudeCodeRateLimitEvent {
260
+ type: "rate_limit_event";
261
+ rate_limit_info?: {
262
+ status?: string;
263
+ resetsAt?: number;
264
+ };
265
+ }
266
+ /**
267
+ * Internal state for tracking content blocks during streaming.
268
+ */
269
+ interface ContentBlockState {
270
+ index: number;
271
+ type: "text" | "tool_use" | "thinking";
272
+ id?: string;
273
+ name?: string;
274
+ buffer: string;
275
+ partId?: string;
276
+ }
277
+ //#endregion
278
+ //#region src/claude-launch-adapter.d.ts
279
+ /** Owns Claude's native launch, authentication, MCP registration, and request routing. */
280
+ declare abstract class ClaudeLaunchAdapter extends CliProviderAdapterBase<ClaudeCodeConfig, ClaudeCodeEvent> {
281
+ readonly provider = "claude-code";
282
+ protected readonly profileHarness: HarnessId;
283
+ protected readonly defaultCliPath = "claude";
284
+ /** Per-turn state must not bleed between concurrent execute calls. */
285
+ private readonly executionContext;
286
+ /**
287
+ * Servers installed at runtime via `addMcp` (hub connections, sandbox
288
+ * capabilities), kept so `buildArgs` can merge them into the single
289
+ * `--mcp-config` object. See the merge site for why the CLI's own config
290
+ * store is not sufficient on its own.
291
+ */
292
+ private readonly runtimeMcpServers;
293
+ /**
294
+ * Image attachments ride the native `--input-format stream-json` path
295
+ * (see `buildExecArgs`) instead of the `[Image: ...]` text marker — the
296
+ * base adapter pre-reads their base64/url into `attachments` and omits
297
+ * the marker for this kind.
298
+ */
299
+ protected nativeAttachmentKinds(): ReadonlyArray<"image" | "file">;
300
+ protected buildExecArgs(params: {
301
+ message: string;
302
+ config: ClaudeCodeConfig;
303
+ model?: string;
304
+ sessionId?: string;
305
+ mintedSessionId?: string;
306
+ workspaceRoot: string;
307
+ systemPrompt?: string;
308
+ appendSystemPrompt?: string;
309
+ attachments?: PreparedAttachment[];
310
+ }): CliExecArgs;
311
+ protected buildExecEnv(config: ClaudeCodeConfig): Record<string, string | undefined>;
312
+ /**
313
+ * Whether a turn launches with its prompt on stdin (`--input-format
314
+ * stream-json`) instead of as an argument: a new session on the box's
315
+ * managed token, sent through the key proxy, with no interaction server to
316
+ * wire. Only such a turn can take a spare process, because the proxy, not
317
+ * the process environment, then carries its correlation headers: a launch
318
+ * the proxy would not route (its own `--settings`, OAuth, an upstream the
319
+ * proxy cannot name) is never held, so no spare starts for it.
320
+ */
321
+ private launchesHeld;
322
+ /**
323
+ * A turn on the box's managed token sends its requests through the sidecar's
324
+ * model-key proxy, which reports the turn's first model request and relays
325
+ * every header unchanged. The correlation headers are bound against the
326
+ * real base URL first (bindExecutionCorrelation, inside super), so the
327
+ * request carries the same headers on either path. A caller's own key, or a
328
+ * box whose proxy is not listening, keeps the direct path.
329
+ */
330
+ protected buildTurnEnvironment(executionConfig: ClaudeCodeConfig, profilePlan: WorkspacePlanApplication | undefined, workspaceRoot: string, correlationHeaders: Readonly<Record<string, string>> | undefined): Record<string, string | undefined>;
331
+ /**
332
+ * Claude Code adds `ANTHROPIC_CUSTOM_HEADERS` (one `Name: Value` per line) to
333
+ * every model request, so the router records this run's trace and execution
334
+ * binding on each dispatch. Only the Tangle router receives them.
335
+ */
336
+ protected bindExecutionCorrelation(environment: Record<string, string | undefined>, correlationHeaders: Readonly<Record<string, string>> | undefined): Record<string, string | undefined>;
337
+ protected buildMcpAddArgs(name: string, config: McpConfig): string[];
338
+ /**
339
+ * Record the server for inline `--mcp-config` merging, then register it with
340
+ * the CLI as before.
341
+ *
342
+ * Both halves are load-bearing and neither replaces the other. The inline
343
+ * merge is what actually reaches the model, because a turn carrying any MCP
344
+ * server also carries `--strict-mcp-config` and the CLI then ignores its own
345
+ * store. The store registration is what `getMcpStatus` / `claude mcp list`
346
+ * report, which the sidecar exposes over `/agents/config/mcp`.
347
+ *
348
+ * Recorded first so a CLI registration failure cannot leave the agent without
349
+ * a server that will work perfectly well inline.
350
+ */
351
+ addMcp(name: string, config: McpConfig): Promise<void>;
352
+ protected buildMcpListArgs(): string[] | null;
353
+ }
354
+ //#endregion
355
+ //#region src/claude-warm-adapter.d.ts
356
+ /** Owns held-process preparation, reservation, and adoption for Claude turns. */
357
+ declare abstract class ClaudeWarmAdapter extends ClaudeLaunchAdapter {
358
+ /**
359
+ * Spares a turn reserved in `mintNativeSessionId`, by native session id.
360
+ * The turn's spawn takes its entry, also when the spare stopped meanwhile.
361
+ */
362
+ private readonly reservedSpares;
363
+ /**
364
+ * Start the process the box's first turn will adopt: the CLI launched as an
365
+ * ordinary new-session managed turn would launch it, with its stdin held
366
+ * open, in this adapter's runtime HOME. `systemPrompt` is the prompt that
367
+ * turn will carry; a turn whose prompt differs stops the process and starts
368
+ * its own. `ready` settles false when no spare could start.
369
+ */
370
+ prewarmProcess(workspaceRootOrUndefined: string | undefined, launch: {
371
+ systemPrompt: string;
372
+ }): Promise<{
373
+ ready: Promise<boolean>;
374
+ }>;
375
+ /**
376
+ * A new session adopts the spare in its HOME when the spare can serve the
377
+ * turn: the same launch, and the key proxy holding the turn's headers for
378
+ * the spare's requests. It then runs under the spare's native session id.
379
+ * Every refusal is made here, before the turn records that id; a refused
380
+ * spare is stopped and the turn runs under an id of its own once the
381
+ * spare's process has exited, so no two processes ever hold one session or
382
+ * share the HOME.
383
+ */
384
+ protected mintNativeSessionId(context: {
385
+ sessionId: string;
386
+ workspaceRoot: string;
387
+ config: ClaudeCodeConfig;
388
+ model?: string;
389
+ env: Record<string, string | undefined>;
390
+ signal: AbortSignal;
391
+ buildExecArgs: (nativeSessionId: string) => CliExecArgs;
392
+ input: AgentExecutionInput;
393
+ timeoutMs?: number;
394
+ }): string | Promise<string>;
395
+ /** A turn that reserved a spare runs on its process; any other starts one. */
396
+ protected spawnExecutionProcess(request: CliTurnSpawn<ClaudeCodeConfig, ClaudeCodeEvent>): CliTurnProcess | Promise<CliTurnProcess>;
397
+ private adoptHeldSpare;
398
+ }
399
+ //#endregion
400
+ //#region src/claude-event-adapter.d.ts
401
+ /** Owns stream-json event translation and assistant/tool part state. */
402
+ declare abstract class ClaudeEventAdapter extends ClaudeWarmAdapter {
403
+ protected createEventParser(state: ExecutionState, onEvent?: (event: StreamEvent) => void): StreamParserConfig<ClaudeCodeEvent>;
404
+ private mapEventToStreamEvents;
405
+ private mapInitEvent;
406
+ private mapSystemEvent;
407
+ /**
408
+ * Maps Claude Code stream-json "assistant" events to stream events.
409
+ * These contain the full message content (thinking, text, tool_use blocks).
410
+ */
411
+ private mapAssistantEvent;
412
+ private mapContentBlockStart;
413
+ private mapContentBlockDelta;
414
+ private mapContentBlockStop;
415
+ /**
416
+ * The real claude CLI (2.x stream-json, verified on 2.1.209) delivers every
417
+ * tool result inside a top-level user event:
418
+ * `{type:"user", message:{content:[{type:"tool_result", tool_use_id,
419
+ * content, is_error?}]}}` — there is NO top-level `{type:"tool_result"}`
420
+ * event on that wire. Each tool_result block routes through the same
421
+ * completion logic as the top-level shape; other block types in the user
422
+ * message (echoed text, etc.) carry no completion signal and are skipped.
423
+ */
424
+ private mapUserEvent;
425
+ /**
426
+ * Top-level `{type:"tool_result"}` shape — not emitted by the current CLI
427
+ * (results arrive via user events, see mapUserEvent) but kept for replay
428
+ * fixtures and synthetic feeds.
429
+ */
430
+ private mapToolResultEvent;
431
+ /** Shared completion path for a tool result, however the wire delivered it. */
432
+ private completeToolResult;
433
+ /**
434
+ * Surfaces files an agent produced this turn from a successful tool result.
435
+ * Built-in write/edit tools carry the path directly on their call input, so
436
+ * detection needs no result content; MCP tools (`mcp__*`) instead report
437
+ * output as content blocks, so an `{type:"image"}` block there becomes a
438
+ * data-URI file part. Every other tool (Bash, Read, Grep, …) has no file
439
+ * signal Claude Code exposes — a shell command's side effects on disk are
440
+ * undetectable from the CLI's tool-result event, so those yield nothing.
441
+ */
442
+ private detectFileParts;
443
+ private mapResultEvent;
444
+ private mapErrorEvent;
445
+ }
446
+ //#endregion
447
+ //#region src/claude-model-auth.d.ts
448
+ /**
449
+ * The URL a Claude Code process with an API key calls, and the key proxy's
450
+ * upstream: the config's own minus any `/vN` (the CLI appends `/v1/messages`,
451
+ * so a box's `<router>/v1` posted `/v1/v1/messages`), else Anthropic.
452
+ */
453
+ declare function resolveClaudeCodeBaseUrl(baseUrl: string | undefined): string;
454
+ /** Native subscription model IDs exclude the profile's provider qualification. */
455
+ declare function normalizeExplicitClaudeModel(model: string, authMode: ClaudeCodeAuthMode): string;
456
+ //#endregion
457
+ //#region src/adapter.d.ts
458
+ /**
459
+ * Claude Code provider adapter.
460
+ *
461
+ * Implements the SdkProviderAdapter interface for the Claude Code CLI tool.
462
+ * Extends CliProviderAdapterBase with Claude Code-specific event parsing and CLI arguments.
463
+ */
464
+ declare class ClaudeCodeProviderAdapter extends ClaudeEventAdapter {
465
+ /** Shared `kind:"permission"` round-trip — see InteractionBroker. */
466
+ private readonly permissions;
467
+ getCapabilities(): BackendCapabilities;
468
+ protected continuationInteractions(base: boolean | Record<string, boolean> | undefined, outcome: "approved" | "rejected"): boolean | Record<string, boolean>;
469
+ /**
470
+ * Host a per-execution interaction MCP server when interactive permissions,
471
+ * permission or question interactions are on.
472
+ * Started BEFORE buildExecArgs runs (so its loopback port + token reach
473
+ * `--mcp-config`) and torn down in finally, denying any decision still pending
474
+ * when the turn unwinds (fail-closed). Plain turns use the base path.
475
+ */
476
+ execute(input: AgentExecutionInput, services: SdkHostServices, onEvent?: (event: StreamEvent) => void): Promise<AgentExecutionResult>;
477
+ /**
478
+ * Make the plan continuation's recorded native Claude session authoritative
479
+ * on the session store so super.execute resumes that conversation. Seed it
480
+ * when the local mapping is missing, and overwrite a mapping that points at a
481
+ * different conversation — an intervening turn can recreate the mapping with a
482
+ * fresh providerSessionId after the plan was submitted (e.g. the box was
483
+ * recycled and the store lost its entry). Leaving a stale, different id in
484
+ * place would resume the wrong conversation, which the plan hook then rejects
485
+ * as a different session than the durable plan. A mapping that already points
486
+ * at the recorded session is left untouched.
487
+ */
488
+ protected reseedNativeSessionForContinuation(input: AgentExecutionInput): Promise<void>;
489
+ respondToInteraction(response: InteractionResponse): Promise<void>;
490
+ /**
491
+ * Build the per-execution interaction MCP server. The `permission` bridge
492
+ * (the `--permission-prompt-tool` decider) is registered only when the turn
493
+ * routes permissions; the `ask_user` model tool only when the question
494
+ * channel is exposed — a question-only turn therefore hosts a server
495
+ * where the permission tool does not even exist.
496
+ */
497
+ private createPermissionServer;
498
+ protected executionOutcome(state: ExecutionState, _input: AgentExecutionInput): Promise<AgentExecutionOutcome>;
499
+ }
500
+ //#endregion
501
+ //#region src/held-spare.d.ts
502
+ /**
503
+ * The spare a turn adopted, handed to the sidecar's key proxy. `upstream` is
504
+ * the model base URL the spare's requests name through the proxy.
505
+ */
506
+ type HeldSpareTurnSink = (input: {
507
+ executionId: string;
508
+ spareId: string;
509
+ upstream: string;
510
+ headers: Readonly<Record<string, string>>;
511
+ }) => boolean;
512
+ /**
513
+ * The sidecar registers the proxy's hook here. Without one, no turn can
514
+ * adopt a spare: nothing would put the turn's headers on its requests.
515
+ */
516
+ declare function setHeldSpareTurnSink(next: HeldSpareTurnSink | undefined): void;
517
+ /**
518
+ * A spare is launched under the native session id its turn will run as, and
519
+ * names the model upstream its requests reach through the key proxy.
520
+ */
521
+ type ClaudeSpareLaunch = {
522
+ readonly nativeSessionId: string;
523
+ readonly upstream: string;
524
+ };
525
+ declare const claudeHeldSpares: _$_tangle_network_sdk_cli_runner0.HeldSpareRegistry<ClaudeCodeEvent, ClaudeSpareLaunch>;
526
+ //#endregion
527
+ export { type ClaudeCodeAuthMode, type ClaudeCodeConfig, type ClaudeCodeContentBlockDelta, type ClaudeCodeContentBlockStart, type ClaudeCodeContentBlockStop, type ClaudeCodeErrorEvent, type ClaudeCodeEvent, type ClaudeCodeInitEvent, ClaudeCodeProviderAdapter, type ClaudeCodeResultEvent, type ClaudeCodeSystemEvent, type ClaudeCodeToolResultEvent, type ClaudeCodeToolUseEvent, type ContentBlockState, type HeldSpareTurnSink, claudeHeldSpares, normalizeExplicitClaudeModel, resolveClaudeCodeBaseUrl, setHeldSpareTurnSink };
528
+ //# sourceMappingURL=index.d.mts.map