// src/_internal/transport/subprocess-cli.ts import { execa } from "execa"; import which from "which"; import { createInterface } from "readline"; import { platform } from "os"; import { join } from "path"; import { homedir } from "os"; import { access, constants } from "fs/promises"; // src/types/base-error.ts var BaseSDKError = class _BaseSDKError extends Error { constructor(message) { super(message); this.name = "BaseSDKError"; Object.setPrototypeOf(this, _BaseSDKError.prototype); } }; // src/types/enhanced-errors.ts var APIError = class _APIError extends BaseSDKError { constructor(message, statusCode, headers) { super(message); this.statusCode = statusCode; this.headers = headers; this.name = "APIError"; Object.setPrototypeOf(this, _APIError.prototype); } }; var RateLimitError = class _RateLimitError extends APIError { constructor(message, retryAfter, limit, remaining, resetAt) { super(message, 429); this.retryAfter = retryAfter; this.limit = limit; this.remaining = remaining; this.resetAt = resetAt; this.name = "RateLimitError"; Object.setPrototypeOf(this, _RateLimitError.prototype); } }; var AuthenticationError = class _AuthenticationError extends APIError { constructor(message, authMethod, requiredAction) { super(message, 401); this.authMethod = authMethod; this.requiredAction = requiredAction; this.name = "AuthenticationError"; Object.setPrototypeOf(this, _AuthenticationError.prototype); } }; var ModelNotAvailableError = class _ModelNotAvailableError extends APIError { constructor(model, availableModels, reason) { super(`Model not available: ${model}`, 404); this.model = model; this.availableModels = availableModels; this.reason = reason; this.name = "ModelNotAvailableError"; Object.setPrototypeOf(this, _ModelNotAvailableError.prototype); } }; var ContextLengthExceededError = class _ContextLengthExceededError extends APIError { constructor(currentTokens, maxTokens, truncationStrategy) { super(`Context length exceeded: ${currentTokens} > ${maxTokens} tokens`, 413); this.currentTokens = currentTokens; this.maxTokens = maxTokens; this.truncationStrategy = truncationStrategy; this.name = "ContextLengthExceededError"; Object.setPrototypeOf(this, _ContextLengthExceededError.prototype); } }; var PermissionError = class _PermissionError extends BaseSDKError { constructor(message, resource, action) { super(message); this.resource = resource; this.action = action; this.name = "PermissionError"; Object.setPrototypeOf(this, _PermissionError.prototype); } }; var ToolPermissionError = class _ToolPermissionError extends PermissionError { constructor(tool, permission, reason, context) { super(`Tool permission denied: ${tool}`, tool, "execute"); this.tool = tool; this.permission = permission; this.reason = reason; this.context = context; this.name = "ToolPermissionError"; Object.setPrototypeOf(this, _ToolPermissionError.prototype); } }; var MCPServerPermissionError = class _MCPServerPermissionError extends PermissionError { constructor(serverName, permission, requestedTools) { super(`MCP server permission denied: ${serverName}`, serverName, "connect"); this.serverName = serverName; this.permission = permission; this.requestedTools = requestedTools; this.name = "MCPServerPermissionError"; Object.setPrototypeOf(this, _MCPServerPermissionError.prototype); } }; var NetworkError = class _NetworkError extends BaseSDKError { constructor(message, code, syscall) { super(message); this.code = code; this.syscall = syscall; this.name = "NetworkError"; Object.setPrototypeOf(this, _NetworkError.prototype); } }; var ConnectionTimeoutError = class _ConnectionTimeoutError extends NetworkError { constructor(timeout, operation) { super(`Connection timeout after ${timeout}ms`, "ETIMEDOUT"); this.timeout = timeout; this.operation = operation; this.name = "ConnectionTimeoutError"; Object.setPrototypeOf(this, _ConnectionTimeoutError.prototype); } }; var ConnectionRefusedError = class _ConnectionRefusedError extends NetworkError { constructor(host, port) { super(`Connection refused${host ? ` to ${host}:${port}` : ""}`, "ECONNREFUSED"); this.host = host; this.port = port; this.name = "ConnectionRefusedError"; Object.setPrototypeOf(this, _ConnectionRefusedError.prototype); } }; var StreamingError = class _StreamingError extends BaseSDKError { constructor(message, partialData, bytesReceived) { super(message); this.partialData = partialData; this.bytesReceived = bytesReceived; this.name = "StreamingError"; Object.setPrototypeOf(this, _StreamingError.prototype); } }; var StreamAbortedError = class _StreamAbortedError extends StreamingError { constructor(reason, abortedAt, partialData) { super(`Stream aborted${reason ? `: ${reason}` : ""}`, partialData); this.reason = reason; this.abortedAt = abortedAt; this.name = "StreamAbortedError"; Object.setPrototypeOf(this, _StreamAbortedError.prototype); } }; var StreamPausedError = class _StreamPausedError extends StreamingError { constructor(pausedAt, canResume = true) { super("Stream is paused"); this.pausedAt = pausedAt; this.canResume = canResume; this.name = "StreamPausedError"; Object.setPrototypeOf(this, _StreamPausedError.prototype); } }; var MaxRetriesExceededError = class _MaxRetriesExceededError extends BaseSDKError { constructor(lastError, attempts, totalDelay) { super(`Max retries exceeded after ${attempts} attempts: ${lastError.message}`); this.lastError = lastError; this.attempts = attempts; this.totalDelay = totalDelay; this.name = "MaxRetriesExceededError"; Object.setPrototypeOf(this, _MaxRetriesExceededError.prototype); } }; var CircuitOpenError = class _CircuitOpenError extends BaseSDKError { constructor(openedAt, failureCount, nextRetryAt) { super("Circuit breaker is open"); this.openedAt = openedAt; this.failureCount = failureCount; this.nextRetryAt = nextRetryAt; this.name = "CircuitOpenError"; Object.setPrototypeOf(this, _CircuitOpenError.prototype); } }; function isRateLimitError(error) { return error instanceof RateLimitError; } function isAuthenticationError(error) { return error instanceof AuthenticationError; } function isToolPermissionError(error) { return error instanceof ToolPermissionError; } function isStreamAbortedError(error) { return error instanceof StreamAbortedError; } function isNetworkError(error) { return error instanceof NetworkError; } function isTimeoutError(error) { return error instanceof TimeoutError; } function isValidationError(error) { return error instanceof ValidationError; } function isAPIError(error) { return error instanceof APIError; } function isRetryableError(error) { return error instanceof RateLimitError || error instanceof NetworkError || error instanceof ConnectionTimeoutError || error instanceof APIError && error.statusCode !== void 0 && error.statusCode >= 500; } var TimeoutError = class _TimeoutError extends NetworkError { constructor(message, _timeout) { super(message, "ETIMEDOUT"); this.name = "TimeoutError"; Object.setPrototypeOf(this, _TimeoutError.prototype); } }; var ValidationError = class _ValidationError extends BaseSDKError { constructor(message, field, value) { super(message); this.field = field; this.value = value; this.name = "ValidationError"; Object.setPrototypeOf(this, _ValidationError.prototype); } }; var ErrorDetectionPatterns = { rate_limit_error: [ /rate[_\s]?limit[_\s]?exceeded/i, /exceeded.*rate[_\s]?limit/i, /429/, /too many requests/i ], authentication_error: [ /authentication[_\s]?failed/i, /401/, /unauthorized/i, /please[_\s]?login/i ], model_not_available_error: [ /model[_\s]?not[_\s]?found/i, /invalid[_\s]?model/i, /no such model/i ], context_length_exceeded_error: [ /context[_\s]?length[_\s]?exceeded/i, /maximum[_\s]?tokens/i, /token[_\s]?limit/i ], tool_permission_error: [ /tool[_\s]?permission[_\s]?denied/i, /tool[_\s]?not[_\s]?allowed/i, /permission[_\s]?denied[_\s]?for[_\s]?tool/i ], network_error: [ /network[_\s]?error/i, /ENETWORK/i, /EHOSTUNREACH/i ], timeout_error: [ /timeout/i, /timed[_\s]?out/i, /ETIMEDOUT/i ], connection_refused_error: [ /connection[_\s]?refused/i, /ECONNREFUSED/i ], stream_aborted_error: [ /stream[_\s]?aborted/i, /aborted/i ], validation_error: [ /validation[_\s]?error/i, /validation[_\s]?failed/i, /invalid[_\s]?parameter/i, /invalid[_\s]?argument/i, /invalid[_\s]?request/i ], api_error: [] // Catch-all, no specific patterns }; var ERROR_PATTERNS = [ { pattern: /rate[_\s]?limit[_\s]?exceeded|429|too many requests/i, errorFactory: (_match, output) => { const retryAfterMatch = output.match(/retry[_\s]?after[:\s]+(\d+)/i); const retryAfter = retryAfterMatch?.[1] ? parseInt(retryAfterMatch[1]) : 60; return new RateLimitError("Rate limit exceeded", retryAfter); } }, { pattern: /authentication[_\s]?failed|401|unauthorized|please[_\s]?login/i, errorFactory: () => new AuthenticationError("Authentication failed", "cli", "Please run: claude login") }, { pattern: /model[_\s]?not[_\s]?found|invalid[_\s]?model|no such model/i, errorFactory: (_match, output) => { const modelMatch = output.match(/model[:\s]+"?(\w+)"?/i); const model = modelMatch?.[1] || "unknown"; return new ModelNotAvailableError(model); } }, { pattern: /context[_\s]?length[_\s]?exceeded|maximum[_\s]?tokens|token[_\s]?limit/i, errorFactory: (_match, output) => { const currentMatch = output.match(/current[:\s]+(\d+)/i); const maxMatch = output.match(/max(?:imum)?[:\s]+(\d+)/i); const current = currentMatch?.[1] ? parseInt(currentMatch[1]) : 0; const max = maxMatch?.[1] ? parseInt(maxMatch[1]) : 0; return new ContextLengthExceededError(current, max); } }, { pattern: /tool[_\s]?permission[_\s]?denied|tool[_\s]?not[_\s]?allowed|permission[_\s]?denied[_\s]?for[_\s]?tool/i, errorFactory: (_match, output) => { const toolMatch = output.match(/tool[:\s]+"?(\w+)"?|for[_\s]?tool[:\s]+"?(\w+)"?/i); const tool = toolMatch?.[1] || toolMatch?.[2] || "unknown"; return new ToolPermissionError(tool, "deny"); } }, { pattern: /connection[_\s]?timeout|ETIMEDOUT|request[_\s]?timeout/i, errorFactory: (_match, output) => { const timeoutMatch = output.match(/timeout[:\s]+(\d+)|after[_\s]?(\d+)ms/i); const timeoutStr = timeoutMatch?.[1] || timeoutMatch?.[2]; const timeout = timeoutStr ? parseInt(timeoutStr) : 3e4; return new ConnectionTimeoutError(timeout); } }, { pattern: /connection[_\s]?refused|ECONNREFUSED/i, errorFactory: () => new ConnectionRefusedError() } ]; // src/errors.ts var ClaudeSDKError = class _ClaudeSDKError extends Error { constructor(message, code) { super(message); this.code = code; this.name = "ClaudeSDKError"; Object.setPrototypeOf(this, _ClaudeSDKError.prototype); } }; var CLIConnectionError = class _CLIConnectionError extends ClaudeSDKError { constructor(message) { super(message); this.name = "CLIConnectionError"; Object.setPrototypeOf(this, _CLIConnectionError.prototype); } }; var CLINotFoundError = class _CLINotFoundError extends ClaudeSDKError { constructor(message = "Claude Code CLI not found. Please install it from https://github.com/anthropics/claude-code") { super(message); this.name = "CLINotFoundError"; Object.setPrototypeOf(this, _CLINotFoundError.prototype); } }; var ProcessError = class _ProcessError extends ClaudeSDKError { constructor(message, exitCode, signal) { super(message); this.exitCode = exitCode; this.signal = signal; this.name = "ProcessError"; Object.setPrototypeOf(this, _ProcessError.prototype); } }; var AbortError = class _AbortError extends ClaudeSDKError { constructor(message = "Operation was aborted") { super(message, "ABORT_ERROR"); this.name = "AbortError"; Object.setPrototypeOf(this, _AbortError.prototype); } }; var CLIJSONDecodeError = class _CLIJSONDecodeError extends ClaudeSDKError { constructor(message, rawOutput) { super(message); this.rawOutput = rawOutput; this.name = "CLIJSONDecodeError"; Object.setPrototypeOf(this, _CLIJSONDecodeError.prototype); } }; var ConfigValidationError = class _ConfigValidationError extends ClaudeSDKError { constructor(message) { super(message); this.name = "ConfigValidationError"; Object.setPrototypeOf(this, _ConfigValidationError.prototype); } }; function detectErrorType(message) { for (const [errorType, patterns] of Object.entries(ErrorDetectionPatterns)) { for (const pattern of patterns) { if (pattern.test(message)) { return errorType; } } } return "api_error"; } function createTypedError(errorType, message, _originalError) { switch (errorType) { case "rate_limit_error": { const retryMatch = message.match(/retry.?after[:\s]+(\d+)/i); const retryAfter = retryMatch?.[1] ? parseInt(retryMatch[1]) : 60; return new RateLimitError(message, retryAfter); } case "authentication_error": return new AuthenticationError(message); case "tool_permission_error": { const toolMatch = message.match(/tool[:\s]+([\w]+)/i); const toolName = toolMatch?.[1] || "unknown"; return new ToolPermissionError(toolName, "deny", message); } case "network_error": return new NetworkError(message); case "timeout_error": return new TimeoutError(message); case "validation_error": return new ValidationError(message); case "stream_aborted_error": return new StreamAbortedError(message); case "api_error": default: { const statusMatch = message.match(/\b(4\d{2}|5\d{2})\b/); const statusCode = statusMatch?.[1] ? parseInt(statusMatch[1]) : void 0; return new APIError(message, statusCode); } } } // src/_internal/transport/subprocess-abort-handler.ts var SubprocessAbortHandler = class { constructor(process2, signal) { this.process = process2; this.signal = signal; } cleanupHandler; timeoutId; /** * Sets up abort handling with proper cleanup. * Returns a cleanup function that should be called in finally blocks. */ setup() { if (!this.signal) { return () => { }; } if (this.signal.aborted) { this.process.cancel(); throw new AbortError("Operation aborted before starting"); } this.cleanupHandler = () => { this.process.cancel(); this.timeoutId = setTimeout(() => { if (!this.process.killed) { this.process.kill("SIGKILL"); } }, 5e3); }; this.signal.addEventListener("abort", this.cleanupHandler, { once: true }); const errorHandler = (error) => { if (error.name === "CancelError" || this.signal?.aborted) { return; } throw error; }; this.process.on("error", errorHandler); return () => { if (this.cleanupHandler) { this.signal?.removeEventListener("abort", this.cleanupHandler); } if (this.timeoutId) { clearTimeout(this.timeoutId); } this.process.removeListener("error", errorHandler); }; } /** * Checks if the process was aborted */ wasAborted() { return this.signal?.aborted ?? false; } }; // src/_internal/transport/subprocess-cli.ts var SubprocessCLITransport = class { process; options; prompt; abortHandler; cleanupAbort; constructor(prompt, options = {}) { this.prompt = prompt; this.options = options; } async findCLI() { const localPaths = [ join(homedir(), ".claude", "local", "claude"), join(homedir(), ".claude", "bin", "claude") ]; for (const path3 of localPaths) { try { await access(path3, constants.X_OK); return path3; } catch { } } try { return await which("claude"); } catch { try { return await which("claude-code"); } catch { } } const paths = []; const isWindows = platform() === "win32"; const home = homedir(); if (isWindows) { paths.push( join(home, "AppData", "Local", "Programs", "claude", "claude.exe"), join(home, "AppData", "Local", "Programs", "claude-code", "claude-code.exe"), "C:\\Program Files\\claude\\claude.exe", "C:\\Program Files\\claude-code\\claude-code.exe" ); } else { paths.push( "/usr/local/bin/claude", "/usr/local/bin/claude-code", "/usr/bin/claude", "/usr/bin/claude-code", "/opt/homebrew/bin/claude", "/opt/homebrew/bin/claude-code", join(home, ".local", "bin", "claude"), join(home, ".local", "bin", "claude-code"), join(home, "bin", "claude"), join(home, "bin", "claude-code"), join(home, ".claude", "local", "claude") // Claude's custom installation path ); } try { const { stdout: npmPrefix } = await execa("npm", ["config", "get", "prefix"]); if (npmPrefix) { paths.push( join(npmPrefix.trim(), "bin", "claude"), join(npmPrefix.trim(), "bin", "claude-code") ); } } catch { } for (const path3 of paths) { try { await execa(path3, ["--version"]); return path3; } catch { } } throw new CLINotFoundError(); } buildCommand() { const args = ["--output-format", "stream-json", "--verbose"]; if (this.options.model) args.push("--model", this.options.model); if (this.options.sessionId) { args.push("--resume", this.options.sessionId); } if (this.options.allowedTools && this.options.allowedTools.length > 0) { args.push("--allowedTools", this.options.allowedTools.join(",")); } if (this.options.deniedTools && this.options.deniedTools.length > 0) { args.push("--disallowedTools", this.options.deniedTools.join(",")); } if (this.options.permissionMode === "bypassPermissions") { args.push("--dangerously-skip-permissions"); } if (this.options.mcpServers && this.options.mcpServers.length > 0) { const mcpConfig = { mcpServers: this.options.mcpServers }; args.push("--mcp-config", JSON.stringify(mcpConfig)); } if (this.options.mcpServerPermissions && Object.keys(this.options.mcpServerPermissions).length > 0) { args.push("--mcp-server-permissions", JSON.stringify(this.options.mcpServerPermissions)); } if (this.options.configFile) { args.push("--config-file", this.options.configFile); } if (this.options.role) { args.push("--role", this.options.role); } if (this.options.context && this.options.context.length > 0) { args.push("--context", ...this.options.context); } if (this.options.temperature !== void 0) { args.push("--temperature", this.options.temperature.toString()); } if (this.options.maxTokens !== void 0) { args.push("--max-tokens", this.options.maxTokens.toString()); } if (this.options.addDirectories && this.options.addDirectories.length > 0) { args.push("--add-dir", this.options.addDirectories.join(" ")); } args.push("--print"); return args; } async connect() { const cliPath = await this.findCLI(); const args = this.buildCommand(); const env = { ...process.env, ...this.options.env, CLAUDE_CODE_ENTRYPOINT: "sdk-ts" }; if (this.options.debug) { console.error("DEBUG: Running command:", cliPath, args.join(" ")); } try { this.process = execa(cliPath, args, { env, cwd: this.options.cwd, stdin: "pipe", stdout: "pipe", stderr: "pipe", buffer: false // Remove signal from here - we'll handle it manually }); this.abortHandler = new SubprocessAbortHandler(this.process, this.options.signal); this.cleanupAbort = this.abortHandler.setup(); if (this.process.stdin) { this.process.stdin.write(this.prompt); this.process.stdin.end(); } } catch (error) { throw new CLIConnectionError(`Failed to start Claude Code CLI: ${error}`); } } async *receiveMessages() { if (!this.process || !this.process.stdout) { throw new CLIConnectionError("Not connected to CLI"); } try { if (this.process.stderr) { const stderrRl = createInterface({ input: this.process.stderr, crlfDelay: Infinity }); stderrRl.on("line", (line) => { if (this.options.debug) { console.error("DEBUG stderr:", line); } }); } const rl = createInterface({ input: this.process.stdout, crlfDelay: Infinity }); for await (const line of rl) { const trimmedLine = line.trim(); if (!trimmedLine) continue; if (this.options.debug) { console.error("DEBUG stdout:", trimmedLine); } try { const parsed = JSON.parse(trimmedLine); yield parsed; } catch (error) { if (trimmedLine.startsWith("{") || trimmedLine.startsWith("[")) { throw new CLIJSONDecodeError( `Failed to parse CLI output: ${error}`, trimmedLine ); } continue; } } try { await this.process; } catch (error) { if (error.isCanceled || error.name === "CancelError" || this.abortHandler?.wasAborted()) { throw new AbortError("Query was aborted via AbortSignal"); } const execError = error; if (execError.exitCode !== 0) { throw new ProcessError( `Claude Code CLI exited with code ${execError.exitCode}`, execError.exitCode, execError.signal ); } } } finally { if (this.cleanupAbort) { this.cleanupAbort(); } } } async disconnect() { if (this.cleanupAbort) { this.cleanupAbort(); this.cleanupAbort = void 0; } if (this.process) { if (!this.process.killed) { this.process.kill(); } this.process = void 0; } this.abortHandler = void 0; } }; // src/environment.ts function parseBoolean(value) { if (value === void 0) return void 0; const normalized = value.toLowerCase().trim(); if (normalized === "true" || normalized === "1" || normalized === "yes" || normalized === "on") { return true; } if (normalized === "false" || normalized === "0" || normalized === "no" || normalized === "off") { return false; } return void 0; } function parseLogLevel(value) { if (value === void 0) return void 0; const level = parseInt(value, 10); if (isNaN(level) || level < 0 || level > 4) { return void 0; } return level; } function loadSafeEnvironmentOptions() { const options = {}; const debug = parseBoolean(process.env.DEBUG); if (debug !== void 0) { options.debug = debug; } const verbose = parseBoolean(process.env.VERBOSE); if (verbose !== void 0) { options.verbose = verbose; } const logLevel = parseLogLevel(process.env.LOG_LEVEL); if (logLevel !== void 0) { options.logLevel = logLevel; } if (process.env.NODE_ENV) { options.nodeEnv = process.env.NODE_ENV; } return options; } var API_KEY_SAFETY_WARNING = ` IMPORTANT: API keys are not automatically loaded from environment variables. This is a safety measure to prevent accidental billing charges. If you need to use an API key, you must explicitly provide it in your code: const result = await query('Your prompt', { apiKey: 'your-api-key' }); If you understand the risks and want to allow API key from environment: const result = await query('Your prompt', { apiKey: process.env.ANTHROPIC_API_KEY, allowApiKeyFromEnv: true // Explicit opt-in }); `.trim(); // src/_internal/options-merger.ts function applyEnvironmentOptions(userOptions, envOptions) { const merged = { ...userOptions }; if (merged.debug === void 0 && envOptions.debug !== void 0) { merged.debug = envOptions.debug; } if (!("verbose" in merged) && envOptions.verbose !== void 0) { merged.verbose = envOptions.verbose; } if (!("logLevel" in merged) && envOptions.logLevel !== void 0) { merged.logLevel = envOptions.logLevel; } return merged; } // src/_internal/client.ts var InternalClient = class { options; prompt; constructor(prompt, options = {}) { this.prompt = prompt; const envOptions = loadSafeEnvironmentOptions(); this.options = applyEnvironmentOptions(options, envOptions); } async *processQuery() { const transport = new SubprocessCLITransport(this.prompt, this.options); try { await transport.connect(); for await (const output of transport.receiveMessages()) { const message = this.parseMessage(output); if (message) { yield message; } } } finally { await transport.disconnect(); } } parseMessage(output) { switch (output.type) { case "assistant": { const assistantMsg = output; if (assistantMsg.message) { return { type: "assistant", content: assistantMsg.message.content, session_id: assistantMsg.session_id }; } return { type: "assistant", content: [], session_id: assistantMsg.session_id }; } case "system": return null; case "result": { const resultMsg = output; return { type: "result", subtype: resultMsg.subtype, content: resultMsg.content || "", session_id: resultMsg.session_id, usage: resultMsg.usage, cost: { total_cost: resultMsg.cost?.total_cost_usd } }; } case "error": { const errorOutput = output; const errorMessage = errorOutput.error?.message || "Unknown error"; const errorType = detectErrorType(errorMessage); throw createTypedError(errorType, errorMessage, errorOutput.error); } default: return null; } } }; // src/types/telemetry.ts var BUILTIN_METRICS = { queries: { name: "claude_sdk_queries_total", type: "counter", description: "Total number of queries", unit: "query" }, queryDuration: { name: "claude_sdk_query_duration", type: "histogram", description: "Query duration", unit: "ms", boundaries: [10, 50, 100, 500, 1e3, 5e3, 1e4, 3e4, 6e4] }, tokens: { name: "claude_sdk_tokens_total", type: "counter", description: "Total tokens used", unit: "token" }, toolExecutions: { name: "claude_sdk_tool_executions_total", type: "counter", description: "Total tool executions", unit: "execution" }, toolDuration: { name: "claude_sdk_tool_duration", type: "histogram", description: "Tool execution duration", unit: "ms", boundaries: [1, 5, 10, 50, 100, 500, 1e3, 5e3] }, errors: { name: "claude_sdk_errors_total", type: "counter", description: "Total errors", unit: "error" }, retries: { name: "claude_sdk_retries_total", type: "counter", description: "Total retry attempts", unit: "retry" }, activeStreams: { name: "claude_sdk_active_streams", type: "gauge", description: "Number of active streams", unit: "stream" } }; // src/types/retry.ts var ExponentialBackoffStrategy = class { constructor(options = {}) { this.options = options; } calculateDelay(attempt, baseDelay) { const multiplier = this.options.multiplier || 2; const base = this.options.base || multiplier; const maxDelay = this.options.maxDelay || 6e4; let delay = baseDelay * Math.pow(base, attempt - 1); delay = Math.min(delay, maxDelay); if (this.options.jitter) { const jitterFactor = this.options.jitterFactor || 0.1; const jitterRange = delay * jitterFactor; const jitter = (Math.random() - 0.5) * 2 * jitterRange; delay = Math.max(0, delay + jitter); } return Math.round(delay); } shouldRetry(_error, _attempt) { return true; } reset() { } }; var LinearBackoffStrategy = class { constructor(options = {}) { this.options = options; } calculateDelay(attempt, baseDelay) { const increment = this.options.increment || baseDelay; const maxDelay = this.options.maxDelay || 6e4; let delay = baseDelay + increment * (attempt - 1); delay = Math.min(delay, maxDelay); if (this.options.jitter) { const jitter = (Math.random() - 0.5) * 0.2 * delay; delay = Math.max(0, delay + jitter); } return Math.round(delay); } shouldRetry(_error, _attempt) { return true; } reset() { } }; var FibonacciBackoffStrategy = class { constructor(options = {}) { this.options = options; } sequence = [1, 1]; calculateDelay(attempt, baseDelay) { const maxDelay = this.options.maxDelay || 6e4; while (this.sequence.length < attempt) { const len = this.sequence.length; if (len >= 2) { const next = this.sequence[len - 1] + this.sequence[len - 2]; this.sequence.push(next); } } const fibValue = this.sequence[attempt - 1] ?? 1; let delay = baseDelay * fibValue; delay = Math.min(delay, maxDelay); if (this.options.jitter) { const jitter = (Math.random() - 0.5) * 0.2 * delay; delay = Math.max(0, delay + jitter); } return Math.round(delay); } shouldRetry(_error, _attempt) { return true; } reset() { this.sequence = [1, 1]; } }; var RetryUtils = class { /** Default retryable errors */ static DEFAULT_RETRYABLE_ERRORS = [ "NetworkError", "TimeoutError", "RateLimitError", "ServiceUnavailableError" ]; /** Check if error is retryable by default */ static isRetryableError(error) { if (this.DEFAULT_RETRYABLE_ERRORS.includes(error.name)) { return true; } const retryablePatterns = [ /timeout/i, /rate.?limit/i, /too.?many.?requests/i, /service.?unavailable/i, /gateway.?timeout/i, /ECONNREFUSED/, /ETIMEDOUT/, /ENOTFOUND/ ]; return retryablePatterns.some((pattern) => pattern.test(error.message)); } /** Sleep for specified milliseconds */ static sleep(ms) { return new Promise((resolve) => setTimeout(resolve, ms)); } /** Create retry function with defaults */ static withRetry(fn, options = {}) { return async () => { const executor = new SimpleRetryExecutor(); return executor.execute(fn, options); }; } }; var SimpleRetryExecutor = class { defaults = { maxAttempts: 3, initialDelay: 1e3, maxDelay: 3e4, multiplier: 2, jitter: true }; stats = { totalExecutions: 0, successfulFirstAttempts: 0, successfulRetries: 0, totalFailures: 0, totalRetryAttempts: 0, averageAttempts: 0, maxAttempts: 0 }; async execute(fn, options) { const result = await this.executeWithResult(fn, options); return result.value; } async executeWithResult(fn, options) { const opts = { ...this.defaults, ...options }; const errors = []; const startTime = Date.now(); this.stats.totalExecutions++; for (let attempt = 1; attempt <= (opts.maxAttempts || 3); attempt++) { try { const value = await fn(); if (attempt === 1) { this.stats.successfulFirstAttempts++; } else { this.stats.successfulRetries++; } this.updateStats(attempt); return { value, attempts: attempt, totalDuration: Date.now() - startTime, errors }; } catch (error) { errors.push(error); const shouldRetry = this.shouldRetry(error, attempt, opts); if (!shouldRetry || attempt === opts.maxAttempts) { this.stats.totalFailures++; this.updateStats(attempt); throw error; } const delay = this.calculateDelay(attempt, opts); if (opts.onRetry) { await opts.onRetry(attempt, error, delay); } await RetryUtils.sleep(delay); this.stats.totalRetryAttempts++; } } throw errors[errors.length - 1]; } setDefaults(options) { this.defaults = { ...this.defaults, ...options }; } getStats() { return { ...this.stats }; } resetStats() { this.stats = { totalExecutions: 0, successfulFirstAttempts: 0, successfulRetries: 0, totalFailures: 0, totalRetryAttempts: 0, averageAttempts: 0, maxAttempts: 0 }; } shouldRetry(error, attempt, options) { if (options.shouldRetry) { return options.shouldRetry(error, attempt); } if (options.retryableErrors) { return options.retryableErrors.some((ErrorClass) => error instanceof ErrorClass); } return RetryUtils.isRetryableError(error); } calculateDelay(attempt, options) { const strategy = new ExponentialBackoffStrategy({ multiplier: options.multiplier, maxDelay: options.maxDelay, jitter: options.jitter, jitterFactor: options.jitterFactor }); return strategy.calculateDelay(attempt, options.initialDelay || 1e3); } updateStats(attempts) { this.stats.maxAttempts = Math.max(this.stats.maxAttempts, attempts); const totalAttempts = this.stats.successfulFirstAttempts + this.stats.successfulRetries * 2 + // At least 2 attempts this.stats.totalFailures * (this.defaults.maxAttempts || 3); this.stats.averageAttempts = totalAttempts / this.stats.totalExecutions; } }; // src/types/environment.ts function isEnhancedError(error) { return error instanceof Error && "category" in error && typeof error.category === "string"; } function hasResolution(error) { return isEnhancedError(error) && !!error.resolution && typeof error.resolution === "string"; } // src/parser.ts var ResponseParser = class { constructor(generator, handlers = [], logger) { this.generator = generator; this.handlers = handlers; this.logger = logger; } messages = []; consumed = false; /** * Get all messages as an array (consumes the generator) */ async asArray() { await this.consume(); return this.messages; } /** * Get only the text content from assistant messages */ async asText() { await this.consume(); const texts = []; for (const msg of this.messages) { if (msg.type === "assistant") { for (const block of msg.content) { if (block.type === "text") { texts.push(block.text); } } } } return texts.join("\n"); } /** * Get the final result message content */ async asResult() { await this.consume(); const resultMsg = this.messages.findLast((msg) => msg.type === "result"); return resultMsg?.content ?? null; } /** * Get all tool uses with their results */ async asToolExecutions() { await this.consume(); const executions = []; const toolUses = /* @__PURE__ */ new Map(); for (const msg of this.messages) { if (msg.type === "assistant") { for (const block of msg.content) { if (block.type === "tool_use") { toolUses.set(block.id, block); } else if (block.type === "tool_result") { const toolUse = toolUses.get(block.tool_use_id); if (toolUse) { executions.push({ tool: toolUse.name, input: toolUse.input, result: block.content, isError: block.is_error ?? false }); } } } } } return executions; } /** * Find all tool results for a specific tool */ async findToolResults(toolName) { const executions = await this.asToolExecutions(); return executions.filter((exec) => exec.tool === toolName && !exec.isError).map((exec) => exec.result); } /** * Get first tool result for a specific tool */ async findToolResult(toolName) { const results = await this.findToolResults(toolName); return results[0] ?? null; } /** * Extract structured data from the response */ async asJSON() { const text = await this.asText(); const codeBlockMatch = text.match(/```(?:json)?\n([\s\S]*?)\n```/); if (codeBlockMatch) { try { return JSON.parse(codeBlockMatch[1] ?? ""); } catch (e) { this.logger?.warn("Failed to parse JSON from code block", { error: e }); } } try { return JSON.parse(text); } catch { const jsonMatch = text.match(/\{[\s\S]*\}|\[[\s\S]*\]/); if (jsonMatch) { try { return JSON.parse(jsonMatch[0]); } catch (e) { this.logger?.warn("Failed to parse JSON from text", { error: e }); } } } return null; } /** * Get usage statistics */ async getUsage() { await this.consume(); const resultMsg = this.messages.findLast((msg) => msg.type === "result"); if (!resultMsg?.usage) return null; return { inputTokens: resultMsg.usage.input_tokens ?? 0, outputTokens: resultMsg.usage.output_tokens ?? 0, cacheCreationTokens: resultMsg.usage.cache_creation_input_tokens ?? 0, cacheReadTokens: resultMsg.usage.cache_read_input_tokens ?? 0, totalTokens: (resultMsg.usage.input_tokens ?? 0) + (resultMsg.usage.output_tokens ?? 0), totalCost: resultMsg.cost?.total_cost ?? 0 }; } /** * Get the session ID if available */ async getSessionId() { await this.consume(); for (const msg of this.messages) { if ("session_id" in msg && msg.session_id) { return msg.session_id; } if (msg.type === "system" && msg.data && typeof msg.data === "object" && "session_id" in msg.data) { return String(msg.data.session_id); } } return null; } /** * Stream messages with a callback (doesn't consume for other methods) */ async stream(callback) { for await (const message of this.generator) { for (const handler of this.handlers) { try { handler(message); } catch (error) { this.logger?.error("Message handler error", { error }); } } this.messages.push(message); await callback(message); } this.consumed = true; } /** * Wait for completion and return success status */ async succeeded() { await this.consume(); const resultMsg = this.messages.findLast((msg) => msg.type === "result"); if (!resultMsg) return false; const executions = await this.asToolExecutions(); const hasErrors = executions.some((exec) => exec.isError); return !hasErrors; } /** * Get all error messages */ async getErrors() { await this.consume(); const errors = []; for (const msg of this.messages) { if (msg.type === "system" && msg.subtype === "error") { const errorMessage = msg.data && typeof msg.data === "object" && "message" in msg.data ? String(msg.data.message) : "Unknown error"; errors.push(errorMessage); } } const executions = await this.asToolExecutions(); for (const exec of executions) { if (exec.isError) { errors.push(`Tool ${exec.tool} failed: ${exec.result}`); } } return errors; } /** * Transform messages using a custom transformer */ async transform(transformer) { await this.consume(); return transformer(this.messages); } /** * Consume the generator if not already consumed */ async consume() { if (this.consumed) return; this.logger?.debug("Consuming message generator"); for await (const message of this.generator) { this.logger?.debug("Received message", { type: message.type }); for (const handler of this.handlers) { try { handler(message); } catch (error) { this.logger?.error("Message handler error", { error }); } } this.messages.push(message); } this.consumed = true; this.logger?.debug("Message generator consumed", { messageCount: this.messages.length }); } }; // src/permissions/manager.ts var PermissionManager = class _PermissionManager { mcpServerPermissions; constructor() { this.mcpServerPermissions = /* @__PURE__ */ new Map(); } /** * Set permission for an MCP server */ setMCPServerPermission(serverName, permission) { if (!serverName) { throw new Error("Server name cannot be empty"); } if (!["whitelist", "blacklist", "ask"].includes(permission)) { throw new Error(`Invalid permission value: ${permission}`); } this.mcpServerPermissions.set(serverName, permission); } /** * Get permission for an MCP server */ getMCPServerPermission(serverName) { return this.mcpServerPermissions.get(serverName); } /** * Set multiple MCP server permissions at once */ setMCPServerPermissions(permissions) { Object.entries(permissions).forEach(([serverName, permission]) => { this.setMCPServerPermission(serverName, permission); }); } /** * Clear all MCP server permissions */ clearMCPServerPermissions() { this.mcpServerPermissions.clear(); } /** * Export current configuration */ exportConfig() { const config = {}; this.mcpServerPermissions.forEach((permission, serverName) => { config[serverName] = permission; }); return config; } /** * Resolve tool permission based on MCP server permission * Maps MCP server permissions to tool-level permissions */ resolveToolPermission(toolName, serverName) { const serverPermission = this.getMCPServerPermission(serverName); if (!serverPermission) { return void 0; } const permissionMap = { "whitelist": "allow", "blacklist": "deny", "ask": "ask" }; return permissionMap[serverPermission]; } /** * Apply permissions to ClaudeCodeOptions */ applyToOptions(options, merge = true) { const exportedConfig = this.exportConfig(); if (Object.keys(exportedConfig).length === 0) { return options; } if (merge && options.mcpServerPermissions) { return { ...options, mcpServerPermissions: { ...options.mcpServerPermissions, ...exportedConfig } }; } return { ...options, mcpServerPermissions: exportedConfig }; } /** * Serialize to JSON string */ toJSON() { return JSON.stringify(this.exportConfig()); } /** * Deserialize from JSON string */ fromJSON(json) { try { const config = JSON.parse(json); this.clearMCPServerPermissions(); this.setMCPServerPermissions(config); } catch (error) { throw new Error("Invalid JSON"); } } /** * Clone the permission manager */ clone() { const cloned = new _PermissionManager(); cloned.setMCPServerPermissions(this.exportConfig()); return cloned; } /** * Check if a server has any permission set */ hasPermission(serverName) { return this.mcpServerPermissions.has(serverName); } /** * Get all server names with permissions */ getServerNames() { return Array.from(this.mcpServerPermissions.keys()); } /** * Get count of permissions */ get size() { return this.mcpServerPermissions.size; } /** * Check if empty */ get isEmpty() { return this.mcpServerPermissions.size === 0; } }; // src/config/loader.ts import { promises as fs } from "fs"; import path from "path"; var ConfigLoader = class { loadedConfigs = /* @__PURE__ */ new Map(); /** * Detect file format based on extension */ detectFormat(filePath) { const ext = path.extname(filePath).toLowerCase(); if (ext === ".yaml" || ext === ".yml") return "yaml"; return "json"; } /** * Load configuration from file */ async loadFromFile(filePath, options) { const absolutePath = path.resolve(filePath); try { await fs.access(absolutePath); } catch (error) { if (error.code === "ENOENT") { throw new Error(`Failed to read configuration file: ${filePath}`); } throw error; } if (this.loadedConfigs.has(absolutePath)) { const cached = this.loadedConfigs.get(absolutePath); if (Object.keys(cached).length === 0) { throw new Error("Circular inheritance detected"); } return cached; } this.loadedConfigs.set(absolutePath, {}); try { const content = await fs.readFile(absolutePath, "utf-8"); const format = options?.format || this.detectFormat(filePath); let config; if (format === "yaml") { config = await this.parseYAML(content, options); } else { config = this.parseJSON(content, filePath); } if (config && config.extends) { const baseConfigPath = path.resolve(path.dirname(absolutePath), config.extends); const baseConfig = await this.loadFromFile(baseConfigPath, options); delete config.extends; const merged = this.mergeConfigs(baseConfig, config); this.loadedConfigs.set(absolutePath, merged); return merged; } this.validateConfig(config); this.loadedConfigs.set(absolutePath, config); return config; } catch (error) { this.loadedConfigs.delete(absolutePath); throw error; } } /** * Parse JSON content */ parseJSON(content, filePath) { try { return JSON.parse(content); } catch (error) { if (error instanceof SyntaxError) { throw new Error(`Invalid JSON in configuration file: ${filePath}`); } throw error; } } /** * Parse YAML content */ async parseYAML(content, options) { try { const yaml = await import("js-yaml"); return yaml.load(content, { strict: options?.strict ?? true, schema: yaml.JSON_SCHEMA }); } catch (error) { throw new ConfigValidationError(`Invalid YAML: ${error.message}`); } } /** * Validate configuration against schema */ validateConfig(config) { if (!config || typeof config !== "object") { throw new Error("Configuration must be an object"); } const cfg = config; if (!cfg.version) { throw new Error("Configuration must have a version field"); } if (cfg.version !== "1.0") { throw new Error(`Unsupported configuration version: ${cfg.version}`); } if (cfg.mcpServers) { Object.entries(cfg.mcpServers).forEach(([serverName, serverConfig]) => { this.validateMCPServerConfig(serverName, serverConfig); }); } if (cfg.globalSettings) { this.validateGlobalSettings(cfg.globalSettings); } if (cfg.tools) { this.validateTools(cfg.tools); } return cfg; } /** * Validate MCP server configuration */ validateMCPServerConfig(serverName, config) { const validPermissions = ["allow", "deny", "ask"]; if (!validPermissions.includes(config.defaultPermission)) { throw new Error( `Invalid permission value '${config.defaultPermission}' at mcpServers.${serverName}.defaultPermission` ); } if (config.tools) { Object.entries(config.tools).forEach(([toolName, permission]) => { const permValue = typeof permission === "object" && permission !== null ? permission.permission : permission; if (permValue && !validPermissions.includes(permValue)) { throw new Error( `Invalid permission value '${permValue}' at mcpServers.${serverName}.tools.${toolName}` ); } }); } } /** * Validate global settings */ validateGlobalSettings(settings) { if (!settings || typeof settings !== "object") { throw new Error("Global settings must be an object"); } const gs = settings; if (gs.defaultToolPermission) { const validPermissions = ["allow", "deny", "ask"]; if (!validPermissions.includes(gs.defaultToolPermission)) { throw new Error(`Invalid defaultToolPermission: ${gs.defaultToolPermission}`); } } if (gs.permissionMode) { const validModes = ["default", "acceptEdits", "bypassPermissions", "ask"]; if (!validModes.includes(gs.permissionMode)) { throw new Error(`Invalid permissionMode: ${gs.permissionMode}`); } } if (gs.timeout && (typeof gs.timeout !== "number" || gs.timeout <= 0)) { throw new Error("Timeout must be a positive number"); } if (gs.temperature !== void 0) { if (typeof gs.temperature !== "number" || gs.temperature < 0 || gs.temperature > 1) { throw new Error("Temperature must be between 0 and 1"); } } if (gs.maxTokens !== void 0) { const maxTokens = typeof gs.maxTokens === "string" ? parseInt(gs.maxTokens, 10) : gs.maxTokens; if (typeof maxTokens !== "number" || isNaN(maxTokens) || maxTokens <= 0) { throw new Error("maxTokens must be a positive number"); } } } /** * Validate tools configuration */ validateTools(tools) { if (!tools || typeof tools !== "object") { throw new Error("Tools configuration must be an object"); } const toolsConfig = tools; if (toolsConfig.allowed && !Array.isArray(toolsConfig.allowed)) { throw new Error("tools.allowed must be an array"); } if (toolsConfig.denied && !Array.isArray(toolsConfig.denied)) { throw new Error("tools.denied must be an array"); } } /** * Merge configuration with options */ mergeWithOptions(config, options, mergeOptions) { const merged = { ...options }; const configPrecedence = mergeOptions?.configPrecedence ?? true; if (config.globalSettings) { const gs = config.globalSettings; if (configPrecedence) { if (gs.model !== void 0) merged.model = gs.model; if (gs.timeout !== void 0) merged.timeout = gs.timeout; if (gs.cwd !== void 0) merged.cwd = gs.cwd; if (gs.permissionMode !== void 0) merged.permissionMode = gs.permissionMode; if (gs.env !== void 0) merged.env = { ...merged.env, ...gs.env }; if (gs.temperature !== void 0) merged.temperature = gs.temperature; if (gs.maxTokens !== void 0) merged.maxTokens = gs.maxTokens; } else { merged.model = merged.model ?? gs.model; merged.timeout = merged.timeout ?? gs.timeout; merged.cwd = merged.cwd ?? gs.cwd; merged.permissionMode = merged.permissionMode ?? gs.permissionMode; merged.env = { ...gs.env, ...merged.env }; merged.temperature = merged.temperature ?? gs.temperature; merged.maxTokens = merged.maxTokens ?? gs.maxTokens; } } if (config.mcpServers) { const mcpServerPermissions = {}; Object.entries(config.mcpServers).forEach(([serverName, serverConfig]) => { const permissionMap = { "allow": "whitelist", "deny": "blacklist", "ask": "ask" }; mcpServerPermissions[serverName] = permissionMap[serverConfig.defaultPermission]; }); merged.mcpServerPermissions = { ...merged.mcpServerPermissions, ...mcpServerPermissions }; } if (config.tools) { if (config.tools.allowed) { merged.allowedTools = [ ...config.tools.allowed, ...merged.allowedTools || [] ]; } if (config.tools.denied) { merged.deniedTools = [ ...config.tools.denied, ...merged.deniedTools || [] ]; } } return merged; } /** * Expand environment variables in configuration */ expandEnvironmentVariables(config) { const expanded = JSON.parse(JSON.stringify(config)); const expandValue = (value) => { if (typeof value === "string") { return value.replace(/\$\{([^}]+)\}/g, (match, varName) => { const envValue = process.env[varName]; if (envValue === void 0) { throw new Error(`Environment variable ${varName} not found`); } return envValue; }); } else if (typeof value === "object" && value !== null) { Object.keys(value).forEach((key) => { value[key] = expandValue(value[key]); }); } return value; }; return expandValue(expanded); } /** * Merge two configurations */ mergeConfigs(base, override) { const merged = { version: override.version || base.version }; if (base.globalSettings || override.globalSettings) { merged.globalSettings = { ...base.globalSettings, ...override.globalSettings }; } if (base.mcpServers || override.mcpServers) { merged.mcpServers = { ...base.mcpServers, ...override.mcpServers }; } if (base.tools || override.tools) { merged.tools = { allowed: [ ...base.tools?.allowed || [], ...override.tools?.allowed || [] ], denied: [ ...base.tools?.denied || [], ...override.tools?.denied || [] ] }; } return merged; } /** * Clear loaded configurations cache */ clearCache() { this.loadedConfigs.clear(); } /** * Get a cached configuration */ getCached(filePath) { return this.loadedConfigs.get(filePath); } }; // src/roles/manager.ts import { promises as fs2 } from "fs"; import path2 from "path"; var RoleManager = class { roles = /* @__PURE__ */ new Map(); defaultRole; /** * Add a role definition */ addRole(role) { const validation = this.validateRole(role); if (!validation.valid) { throw new Error(`Invalid role definition: ${validation.errors?.join(", ")}`); } this.roles.set(role.name, role); return this; } /** * Get a role by name */ getRole(name) { return this.roles.get(name); } /** * Check if a role exists */ hasRole(name) { return this.roles.has(name); } /** * List all role names */ listRoles() { return Array.from(this.roles.keys()); } /** * Set the default role */ setDefaultRole(name) { if (!this.roles.has(name)) { throw new Error(`Role '${name}' not found`); } this.defaultRole = name; return this; } /** * Get the default role */ getDefaultRole() { return this.defaultRole; } /** * Detect file format based on extension */ detectFormat(filePath) { const ext = path2.extname(filePath).toLowerCase(); if (ext === ".yaml" || ext === ".yml") return "yaml"; return "json"; } /** * Parse JSON content */ parseJSON(content, filePath) { try { return JSON.parse(content); } catch (error) { if (error instanceof SyntaxError) { throw new Error(`Invalid JSON in roles file: ${filePath}`); } throw error; } } /** * Parse YAML content */ async parseYAML(content, options) { try { const yaml = await import("js-yaml"); return yaml.load(content, { strict: options?.strict ?? true, schema: yaml.JSON_SCHEMA }); } catch (error) { throw new ConfigValidationError(`Invalid YAML: ${error.message}`); } } /** * Load roles from a configuration file */ async loadFromFile(filePath, options) { try { await fs2.access(filePath); } catch (error) { if (error.code === "ENOENT") { throw new Error(`Failed to read roles file: ${filePath}`); } throw error; } const content = await fs2.readFile(filePath, "utf-8"); const format = options?.format || this.detectFormat(filePath); let config; if (format === "yaml") { config = await this.parseYAML(content, options); } else { config = this.parseJSON(content, filePath); } this.loadFromConfig(config); } /** * Load roles from configuration object */ loadFromConfig(config) { if (config.version !== "1.0") { throw new Error(`Unsupported roles configuration version: ${config.version}`); } this.roles.clear(); Object.entries(config.roles).forEach(([name, roleConfig]) => { const role = { name, ...roleConfig }; this.addRole(role); }); if (config.defaultRole) { this.setDefaultRole(config.defaultRole); } } /** * Apply a role to options */ applyRole(roleName, options, applicationOptions) { const role = this.getRole(roleName); if (!role) { throw new Error(`Role '${roleName}' not found`); } const resolvedRole = this.resolveInheritance(role); return this.applyRoleToOptions(resolvedRole, options, applicationOptions); } /** * Resolve role inheritance */ resolveInheritance(role) { const chain = this.getInheritanceChain(role); if (chain.hasCircularDependency) { throw new Error("Circular inheritance detected"); } let resolved = { name: role.name, model: role.model, permissions: {} }; for (let i = chain.chain.length - 1; i >= 0; i--) { const currentRole = this.getRole(chain.chain[i]); if (!currentRole) continue; resolved = this.mergeRoles(resolved, currentRole); } return resolved; } /** * Get inheritance chain for a role */ getInheritanceChain(role, visited = /* @__PURE__ */ new Set()) { const chain = [role.name]; if (visited.has(role.name)) { return { chain, hasCircularDependency: true }; } visited.add(role.name); if (role.extends) { const parent = this.getRole(role.extends); if (!parent) { throw new Error(`Parent role '${role.extends}' not found`); } const parentChain = this.getInheritanceChain(parent, visited); chain.push(...parentChain.chain); if (parentChain.hasCircularDependency) { return { chain, hasCircularDependency: true }; } } return { chain, hasCircularDependency: false }; } /** * Merge two roles (child overrides parent) */ mergeRoles(parent, child) { const merged = { name: child.name, model: child.model || parent.model, permissions: { ...parent.permissions || {}, mode: child.permissions?.mode || parent.permissions?.mode, mcpServers: { ...parent.permissions?.mcpServers || {}, ...child.permissions?.mcpServers || {} }, tools: { allowed: [ ...parent.permissions?.tools?.allowed || [], ...child.permissions?.tools?.allowed || [] ], denied: [ ...parent.permissions?.tools?.denied || [], ...child.permissions?.tools?.denied || [] ] } } }; if (parent.description || child.description) { merged.description = child.description || parent.description; } if (parent.promptingTemplate || child.promptingTemplate) { merged.promptingTemplate = child.promptingTemplate || parent.promptingTemplate; } if (parent.systemPrompt || child.systemPrompt) { merged.systemPrompt = child.systemPrompt || parent.systemPrompt; } if (parent.context || child.context) { merged.context = { ...parent.context, ...child.context }; } if (parent.metadata || child.metadata) { merged.metadata = { ...parent.metadata, ...child.metadata }; } return merged; } /** * Apply role definition to options */ applyRoleToOptions(role, options, applicationOptions) { const applied = { ...options }; const override = applicationOptions?.override ?? true; if (override || !applied.model) { applied.model = role.model; } if (role.permissions.mode && (override || !applied.permissionMode)) { applied.permissionMode = role.permissions.mode; } if (role.permissions.mcpServers && Object.keys(role.permissions.mcpServers).length > 0) { applied.mcpServerPermissions = { ...applied.mcpServerPermissions || {}, ...role.permissions.mcpServers }; } if (role.permissions.tools?.allowed) { if (applicationOptions?.mergeArrays) { applied.allowedTools = [ ...applied.allowedTools || [], ...role.permissions.tools.allowed ]; } else { applied.allowedTools = role.permissions.tools.allowed; } } if (role.permissions.tools?.denied) { if (applicationOptions?.mergeArrays) { applied.deniedTools = [ ...applied.deniedTools || [], ...role.permissions.tools.denied ]; } else { applied.deniedTools = role.permissions.tools.denied; } } if (role.context) { if (role.context.maxTokens && (override || !applied.maxTokens)) { applied.maxTokens = role.context.maxTokens; } if (role.context.temperature !== void 0 && (override || applied.temperature === void 0)) { applied.temperature = role.context.temperature; } if (role.context.additionalContext) { applied.context = [ ...applied.context || [], ...role.context.additionalContext ]; } } if (role.systemPrompt && (override || !applied.systemPrompt)) { applied.systemPrompt = role.systemPrompt; } return applied; } /** * Validate a role definition */ validateRole(role) { const errors = []; const warnings = []; if (!role.name) { errors.push("Role must have a name"); } if (!role.model) { errors.push('Role "' + role.name + '" must have a model'); } else { const validModels = ["opus", "sonnet", "haiku", "claude-3-opus", "claude-3-sonnet", "claude-3-haiku"]; if (!validModels.some((m) => role.model.includes(m))) { errors.push(`Invalid model '${role.model}'`); } } if (role.permissions?.mode) { const validModes = ["default", "acceptEdits", "bypassPermissions"]; if (!validModes.includes(role.permissions.mode)) { errors.push("Invalid permission mode"); } if (role.permissions.mode === "bypassPermissions") { warnings.push("bypassPermissions mode may pose security risks"); } } if (role.context) { if (role.context.temperature !== void 0) { if (role.context.temperature < 0 || role.context.temperature > 1) { errors.push("Temperature must be between 0 and 1"); } else if (role.context.temperature > 0.9) { warnings.push(`High temperature (${role.context.temperature}) may produce inconsistent results`); } } if (role.context.maxTokens !== void 0 && role.context.maxTokens <= 0) { errors.push("Max tokens must be positive"); } } return { valid: errors.length === 0, errors: errors.length > 0 ? errors : void 0, warnings: warnings.length > 0 ? warnings : void 0 }; } /** * Get prompting template with variable interpolation */ getPromptingTemplate(roleName, variables) { const role = this.getRole(roleName); if (!role || !role.promptingTemplate) { throw new Error(`No prompting template found for role '${roleName}'`); } return this.interpolateTemplate(role.promptingTemplate, variables); } /** * Get full prompt including system prompt and template */ getFullPrompt(roleName, variables, userPrompt) { const role = this.getRole(roleName); if (!role) { throw new Error(`Role '${roleName}' not found`); } const parts = []; if (role.systemPrompt) { parts.push(role.systemPrompt); } if (role.promptingTemplate) { parts.push(this.interpolateTemplate(role.promptingTemplate, variables)); } parts.push(userPrompt); return parts.join("\n\n"); } /** * Interpolate template variables */ interpolateTemplate(template, variables) { return template.replace(/\$\{([^}]+)\}/g, (match, varName) => { if (!(varName in variables)) { throw new Error(`Missing template variable: ${varName}`); } return variables[varName]; }); } /** * Export configuration */ exportConfig() { const config = { version: "1.0", roles: {} }; this.roles.forEach((role, name) => { const { name: _, ...roleConfig } = role; config.roles[name] = roleConfig; }); if (this.defaultRole) { config.defaultRole = this.defaultRole; } return config; } /** * Clear all roles */ clear() { this.roles.clear(); this.defaultRole = void 0; } /** * Get count of roles */ get size() { return this.roles.size; } }; // src/logger.ts var LogLevel = /* @__PURE__ */ ((LogLevel2) => { LogLevel2[LogLevel2["ERROR"] = 0] = "ERROR"; LogLevel2[LogLevel2["WARN"] = 1] = "WARN"; LogLevel2[LogLevel2["INFO"] = 2] = "INFO"; LogLevel2[LogLevel2["DEBUG"] = 3] = "DEBUG"; LogLevel2[LogLevel2["TRACE"] = 4] = "TRACE"; return LogLevel2; })(LogLevel || {}); var ConsoleLogger = class { constructor(minLevel = 2 /* INFO */, prefix = "[Claude SDK]") { this.minLevel = minLevel; this.prefix = prefix; } log(entry) { if (entry.level > this.minLevel) return; const timestamp = entry.timestamp.toISOString(); const level = LogLevel[entry.level]; const prefix = `${timestamp} ${this.prefix} ${level}`; const args = [`${prefix}: ${entry.message}`]; if (entry.context && Object.keys(entry.context).length > 0) { args.push(JSON.stringify(entry.context, null, 2)); } if (entry.error) { args.push(entry.error); } switch (entry.level) { case 0 /* ERROR */: console.error(...args); break; case 1 /* WARN */: console.warn(...args); break; case 2 /* INFO */: console.info(...args); break; case 3 /* DEBUG */: case 4 /* TRACE */: console.log(...args); break; } } error(message, context) { this.log({ level: 0 /* ERROR */, message, timestamp: /* @__PURE__ */ new Date(), context, error: context?.error instanceof Error ? context.error : void 0 }); } warn(message, context) { this.log({ level: 1 /* WARN */, message, timestamp: /* @__PURE__ */ new Date(), context }); } info(message, context) { this.log({ level: 2 /* INFO */, message, timestamp: /* @__PURE__ */ new Date(), context }); } debug(message, context) { this.log({ level: 3 /* DEBUG */, message, timestamp: /* @__PURE__ */ new Date(), context }); } trace(message, context) { this.log({ level: 4 /* TRACE */, message, timestamp: /* @__PURE__ */ new Date(), context }); } }; var JSONLogger = class { constructor(minLevel = 2 /* INFO */, output = console.log) { this.minLevel = minLevel; this.output = output; } log(entry) { if (entry.level > this.minLevel) return; const logObject = { level: LogLevel[entry.level], message: entry.message, timestamp: entry.timestamp.toISOString(), context: entry.context, ...entry.error && { error: { message: entry.error.message, stack: entry.error.stack, name: entry.error.name } } }; this.output(JSON.stringify(logObject)); } error(message, context) { this.log({ level: 0 /* ERROR */, message, timestamp: /* @__PURE__ */ new Date(), context, error: context?.error instanceof Error ? context.error : void 0 }); } warn(message, context) { this.log({ level: 1 /* WARN */, message, timestamp: /* @__PURE__ */ new Date(), context }); } info(message, context) { this.log({ level: 2 /* INFO */, message, timestamp: /* @__PURE__ */ new Date(), context }); } debug(message, context) { this.log({ level: 3 /* DEBUG */, message, timestamp: /* @__PURE__ */ new Date(), context }); } trace(message, context) { this.log({ level: 4 /* TRACE */, message, timestamp: /* @__PURE__ */ new Date(), context }); } }; var MultiLogger = class { constructor(loggers) { this.loggers = loggers; } log(entry) { for (const logger of this.loggers) { try { logger.log(entry); } catch { } } } error(message, context) { for (const logger of this.loggers) { try { logger.error(message, context); } catch { } } } warn(message, context) { for (const logger of this.loggers) { try { logger.warn(message, context); } catch { } } } info(message, context) { for (const logger of this.loggers) { try { logger.info(message, context); } catch { } } } debug(message, context) { for (const logger of this.loggers) { try { logger.debug(message, context); } catch { } } } trace(message, context) { for (const logger of this.loggers) { try { logger.trace(message, context); } catch { } } } }; var NullLogger = class { log(_entry) { } error(_message, _context) { } warn(_message, _context) { } info(_message, _context) { } debug(_message, _context) { } trace(_message, _context) { } }; // src/fluent.ts var QueryBuilder = class _QueryBuilder { options = {}; messageHandlers = []; logger; permissionManager; configLoader; roleManager; rolePromptingTemplate; roleTemplateVariables; constructor() { this.permissionManager = new PermissionManager(); this.configLoader = new ConfigLoader(); this.roleManager = new RoleManager(); } /** * Set the model to use */ withModel(model) { this.options.model = model; return this; } /** * Set allowed tools * Use allowTools() with no arguments to enforce read-only mode (denies all tools) */ allowTools(...tools) { if (tools.length === 0) { const allTools = [ "Read", "Write", "Edit", "Bash", "Grep", "Glob", "LS", "MultiEdit", "NotebookRead", "NotebookEdit", "WebFetch", "TodoRead", "TodoWrite", "WebSearch", "Task", "MCPTool" ]; this.options.deniedTools = allTools; this.options.allowedTools = []; } else { this.options.allowedTools = tools; } return this; } /** * Set denied tools */ denyTools(...tools) { this.options.deniedTools = tools; return this; } /** * Set permission mode */ withPermissions(mode) { this.options.permissionMode = mode; return this; } /** * Skip all permissions (shorthand for bypassPermissions) */ skipPermissions() { this.options.permissionMode = "bypassPermissions"; return this; } /** * Accept all edits automatically */ acceptEdits() { this.options.permissionMode = "acceptEdits"; return this; } /** * Set working directory */ inDirectory(cwd) { this.options.cwd = cwd; return this; } /** * Set environment variables */ withEnv(env) { this.options.env = { ...this.options.env, ...env }; return this; } /** * Set timeout in milliseconds */ withTimeout(ms) { this.options.timeout = ms; return this; } /** * Set AbortSignal for cancellation */ withSignal(signal) { this.options.signal = signal; return this; } /** * Set session ID for continuing an existing conversation */ withSessionId(sessionId) { this.options.sessionId = sessionId; return this; } /** * Enable debug mode */ debug(enabled = true) { this.options.debug = enabled; return this; } /** * Add MCP servers */ withMCP(...servers) { this.options.mcpServers = [...this.options.mcpServers || [], ...servers]; return this; } /** * Add directory(-ies) to include in the context */ addDirectory(directories) { if (!this.options.addDirectories) { this.options.addDirectories = []; } const dirsToAdd = Array.isArray(directories) ? directories : [directories]; this.options.addDirectories.push(...dirsToAdd); return this; } /** * Set logger */ withLogger(logger) { this.logger = logger; return this; } /** * Add message handler */ onMessage(handler) { this.messageHandlers.push(handler); return this; } /** * Add handler for specific message type */ onAssistant(handler) { this.messageHandlers.push((msg) => { if (msg.type === "assistant") { handler(msg.content); } }); return this; } /** * Add handler for tool usage */ onToolUse(handler) { this.messageHandlers.push((msg) => { if (msg.type === "assistant") { for (const block of msg.content) { if (block.type === "tool_use") { handler({ name: block.name, input: block.input }); } } } }); return this; } /** * Set MCP server permission */ withMCPServerPermission(serverName, permission) { this.permissionManager.setMCPServerPermission(serverName, permission); return this; } /** * Set multiple MCP server permissions */ withMCPServerPermissions(permissions) { this.permissionManager.setMCPServerPermissions(permissions); return this; } /** * Load configuration from file */ async withConfigFile(filePath) { const config = await this.configLoader.loadFromFile(filePath); this.applyConfig(config); return this; } /** * Apply configuration object */ withConfig(config) { this.configLoader.validateConfig(config); this.applyConfig(config); return this; } /** * Load roles from file */ async withRolesFile(filePath) { await this.roleManager.loadFromFile(filePath); return this; } withRole(roleOrName, templateVariables) { if (typeof roleOrName === "string") { const options = this.roleManager.applyRole(roleOrName, this.options); this.options = options; const role = this.roleManager.getRole(roleOrName); if (role?.promptingTemplate) { this.rolePromptingTemplate = role.promptingTemplate; } if (role?.systemPrompt) { this.options.systemPrompt = role.systemPrompt; } } else { this.roleManager.addRole(roleOrName); const options = this.roleManager.applyRole(roleOrName.name, this.options); this.options = options; if (roleOrName.promptingTemplate) { this.rolePromptingTemplate = roleOrName.promptingTemplate; this.roleTemplateVariables = templateVariables; } if (roleOrName.systemPrompt) { this.options.systemPrompt = roleOrName.systemPrompt; } } return this; } /** * Apply configuration to options */ applyConfig(config) { this.options = this.configLoader.mergeWithOptions(config, this.options); } /** * Execute query and return response parser */ query(prompt) { const finalOptions = this.permissionManager.applyToOptions(this.options); let finalPrompt = prompt; if (this.rolePromptingTemplate && this.roleTemplateVariables) { const templatedPrompt = this.rolePromptingTemplate.replace( /\$\{([^}]+)\}/g, (match, varName) => this.roleTemplateVariables[varName] || match ); if (finalOptions.systemPrompt) { finalPrompt = `${finalOptions.systemPrompt} ${templatedPrompt} ${prompt}`; } else { finalPrompt = `${templatedPrompt} ${prompt}`; } } else if (finalOptions.systemPrompt) { finalPrompt = `${finalOptions.systemPrompt} ${prompt}`; } const parser = new ResponseParser( query(finalPrompt, finalOptions), this.messageHandlers, this.logger ); return parser; } /** * Execute query and return raw async generator (for backward compatibility) */ async *queryRaw(prompt) { const finalOptions = this.permissionManager.applyToOptions(this.options); let finalPrompt = prompt; if (this.rolePromptingTemplate && this.roleTemplateVariables) { const templatedPrompt = this.rolePromptingTemplate.replace( /\$\{([^}]+)\}/g, (match, varName) => this.roleTemplateVariables[varName] || match ); if (finalOptions.systemPrompt) { finalPrompt = `${finalOptions.systemPrompt} ${templatedPrompt} ${prompt}`; } else { finalPrompt = `${templatedPrompt} ${prompt}`; } } else if (finalOptions.systemPrompt) { finalPrompt = `${finalOptions.systemPrompt} ${prompt}`; } this.logger?.info("Starting query", { prompt: finalPrompt, options: finalOptions }); for await (const message of query(finalPrompt, finalOptions)) { this.logger?.debug("Received message", { type: message.type }); for (const handler of this.messageHandlers) { try { handler(message); } catch (error) { this.logger?.error("Message handler error", { error }); } } yield message; } this.logger?.info("Query completed"); } /** * Static factory method for cleaner syntax */ static create() { return new _QueryBuilder(); } }; function claude() { return new QueryBuilder(); } // src/streaming/token-stream.ts var TokenStreamImpl = class { controller; snapshot = []; metrics; messageGenerator; tokenGenerator; completionPromise; completionResolve; completionReject; eventHandlers = /* @__PURE__ */ new Map(); startTime; constructor(messageGenerator) { this.messageGenerator = messageGenerator; this.controller = new StreamControllerImpl(); this.startTime = Date.now(); this.metrics = { tokensEmitted: 0, duration: 0, state: "active", averageTokensPerSecond: 0, bytesReceived: 0, lastTokenTime: void 0, pauseCount: 0, totalPauseDuration: 0 }; this.completionPromise = new Promise((resolve, reject) => { this.completionResolve = resolve; this.completionReject = reject; }); } async *tokens() { if (this.tokenGenerator) { yield* this.tokenGenerator; return; } this.tokenGenerator = this.createTokenGenerator(); yield* this.tokenGenerator; } async *createTokenGenerator() { try { let currentTextBlock = ""; for await (const message of this.messageGenerator) { await this.controller.checkPause(); if (this.controller.isAborted) { throw new Error("Stream aborted"); } if (message.type === "assistant") { const assistantMessage = message; for (const block of assistantMessage.content) { await this.controller.checkPause(); if (this.controller.isAborted) { throw new Error("Stream aborted"); } if (block.type === "text") { const textBlock = block; const text = textBlock.text; const tokens = this.tokenizeText(text, currentTextBlock); for (const token of tokens) { await this.controller.checkPause(); if (this.controller.isAborted) { throw new Error("Stream aborted"); } const chunk = { token, timestamp: Date.now(), metadata: { messageId: `msg-${Date.now()}`, blockIndex: 0, position: this.metrics.tokensEmitted } }; this.snapshot.push(chunk); this.metrics.tokensEmitted++; this.metrics.bytesReceived = (this.metrics.bytesReceived || 0) + new TextEncoder().encode(token).length; this.metrics.lastTokenTime = Date.now(); this.updateMetrics(); this.emit("token", chunk); yield chunk; } currentTextBlock = text; } } } } this.metrics.state = "completed"; this.updateMetrics(); this.emit("complete", this.metrics.state); if (this.completionResolve) this.completionResolve(); } catch (error) { this.metrics.state = "error"; this.updateMetrics(); this.emit("error", error); if (this.completionReject) this.completionReject(error); throw error; } } tokenizeText(text, previousText) { const tokens = []; if (previousText && text.startsWith(previousText)) { const newText = text.substring(previousText.length); if (newText) { const parts = newText.split(/(\s+|[.,!?;:])/); for (const part of parts) { if (part) { tokens.push(part); } } } } else { const parts = text.split(/(\s+|[.,!?;:])/); for (const part of parts) { if (part) { tokens.push(part); } } } return tokens; } updateMetrics() { this.metrics.duration = Date.now() - this.startTime; if (this.metrics.tokensEmitted > 0 && this.metrics.duration > 0) { this.metrics.averageTokensPerSecond = this.metrics.tokensEmitted / (this.metrics.duration / 1e3); } this.metrics.pauseCount = this.controller.getPauseCount(); this.metrics.totalPauseDuration = this.controller.getTotalPauseDuration(); } getController() { return this.controller; } getSnapshot() { return [...this.snapshot]; } getMetrics() { this.updateMetrics(); return { ...this.metrics }; } async waitForCompletion() { return this.completionPromise; } on(event, handler) { if (!this.eventHandlers.has(event)) { this.eventHandlers.set(event, /* @__PURE__ */ new Set()); } this.eventHandlers.get(event).add(handler); } off(event, handler) { this.eventHandlers.get(event)?.delete(handler); } emit(event, data) { const handlers = this.eventHandlers.get(event); if (handlers) { for (const handler of handlers) { try { handler(data); } catch (error) { } } } if (["token", "pause", "resume", "complete", "error"].includes(event)) { this.emit("metrics", this.getMetrics()); } } }; var StreamControllerImpl = class { state = "active"; pausePromise; pauseResolve; listeners = /* @__PURE__ */ new Map(); pauseStartTime; _abortReason; pauseCount = 0; totalPauseDuration = 0; pause() { if (this.state === "active") { this.state = "paused"; this.pauseStartTime = Date.now(); this.pauseCount++; this.pausePromise = new Promise((resolve) => { this.pauseResolve = resolve; }); this.emit("pause"); } } resume() { if (this.state === "paused" && this.pauseResolve) { this.state = "active"; this.pauseResolve(); this.pausePromise = void 0; this.pauseResolve = void 0; if (this.pauseStartTime) { const pauseDuration = Date.now() - this.pauseStartTime; this.totalPauseDuration += pauseDuration; this.pauseStartTime = void 0; this.emit("resume", { pauseDuration }); } else { this.emit("resume"); } } } abort(reason) { this.state = "aborted"; this._abortReason = reason; if (this.pauseResolve) { this.pauseResolve(); } this.emit("abort"); } getState() { return this.state; } get isPaused() { return this.state === "paused"; } get isAborted() { return this.state === "aborted"; } get abortReason() { return this._abortReason; } getPauseCount() { return this.pauseCount; } getTotalPauseDuration() { if (this.state === "paused" && this.pauseStartTime) { return this.totalPauseDuration + (Date.now() - this.pauseStartTime); } return this.totalPauseDuration; } async checkPause() { if (this.pausePromise) { await this.pausePromise; } } on(event, listener) { if (!this.listeners.has(event)) { this.listeners.set(event, /* @__PURE__ */ new Set()); } this.listeners.get(event).add(listener); } off(event, listener) { this.listeners.get(event)?.delete(listener); } emit(event, _data) { const listeners = this.listeners.get(event); if (listeners) { for (const listener of listeners) { try { listener(); } catch (error) { } } } } }; function createTokenStream(messageGenerator) { return new TokenStreamImpl(messageGenerator); } // src/permissions/tool-permissions.ts var ToolPermissionManager2 = class { globalPermissions; rolePermissions; resolutionLog = []; constructor(options, rolePermissions) { this.globalPermissions = this.initializeGlobalPermissions(options); this.rolePermissions = new Map( rolePermissions ? Object.entries(rolePermissions) : [] ); } initializeGlobalPermissions(options) { const permissions = /* @__PURE__ */ new Map(); if (options.allowedTools) { for (const tool of options.allowedTools) { permissions.set(tool, "allow"); } } if (options.deniedTools) { for (const tool of options.deniedTools) { permissions.set(tool, "deny"); } } if (options.tools) { for (const tool of options.tools) { if (!permissions.has(tool)) { permissions.set(tool, "allow"); } } } return permissions; } /** * Resolve permissions for a specific tool with optional overrides */ async resolvePermission(tool, context, overrides) { const resolution = { tool, permission: "allow", // Default to allow source: "default", context, timestamp: Date.now() }; if (overrides) { const overridePermission = await this.checkOverrides(tool, context, overrides); if (overridePermission !== void 0) { resolution.permission = overridePermission; resolution.source = "query"; resolution.override = overrides; this.resolutionLog.push(resolution); return resolution; } } if (overrides?.dynamicPermissions) { const dynamicPermission = await this.checkDynamicPermissions( tool, context, overrides.dynamicPermissions ); if (dynamicPermission !== void 0) { resolution.permission = dynamicPermission; resolution.source = "dynamic"; resolution.override = overrides; this.resolutionLog.push(resolution); return resolution; } } if (this.rolePermissions.has(tool)) { resolution.permission = this.rolePermissions.get(tool); resolution.source = "role"; this.resolutionLog.push(resolution); return resolution; } if (this.globalPermissions.has(tool)) { resolution.permission = this.globalPermissions.get(tool); resolution.source = "global"; this.resolutionLog.push(resolution); return resolution; } this.resolutionLog.push(resolution); return resolution; } /** * Check query-level overrides */ async checkOverrides(tool, _context, overrides) { if (overrides.deny?.includes(tool)) { return "deny"; } if (overrides.allow?.includes(tool)) { return "allow"; } if (overrides.permissions?.[tool]) { return overrides.permissions[tool]; } return void 0; } /** * Check dynamic permissions */ async checkDynamicPermissions(tool, context, dynamicPermissions) { const dynamicFn = dynamicPermissions[tool]; if (dynamicFn) { try { return await dynamicFn(context); } catch (error) { } } return void 0; } /** * Get permission resolution history */ getResolutionHistory() { return [...this.resolutionLog]; } /** * Clear resolution history */ clearHistory() { this.resolutionLog = []; } /** * Update role permissions */ updateRolePermissions(permissions) { this.rolePermissions = new Map(Object.entries(permissions)); } /** * Check if a tool is allowed with current configuration */ async isToolAllowed(tool, context, overrides) { const resolution = await this.resolvePermission(tool, context, overrides); return resolution.permission === "allow"; } /** * Get effective permissions for a context */ async getEffectivePermissions(context, overrides) { const allTools = [ "Read", "Write", "Edit", "Bash", "Grep", "Glob", "LS", "MultiEdit", "NotebookRead", "NotebookEdit", "WebFetch", "TodoRead", "TodoWrite", "WebSearch", "Task", "MCPTool" ]; const effectivePermissions = /* @__PURE__ */ new Map(); for (const tool of allTools) { const resolution = await this.resolvePermission(tool, context, overrides); effectivePermissions.set(tool, resolution); } return effectivePermissions; } }; function createPermissionManager(options, rolePermissions) { return new ToolPermissionManager2(options, rolePermissions); } // src/telemetry/provider-simple.ts var ClaudeTelemetryProvider = class { async initialize(_config) { } getLogger(_name) { throw new Error("Telemetry provider not fully implemented yet"); } async shutdown() { } async forceFlush() { } getQueryMetrics() { return { totalQueries: 0, successfulQueries: 0, failedQueries: 0, totalTokens: 0, inputTokens: 0, outputTokens: 0, cacheHits: 0, cacheMisses: 0, averageQueryDuration: 0, p95QueryDuration: 0, p99QueryDuration: 0 }; } getToolMetrics() { return /* @__PURE__ */ new Map(); } }; function createTelemetryProvider() { return new ClaudeTelemetryProvider(); } var TelemetryUtils = class { static extractTraceContext(_headers) { return {}; } static injectTraceContext(_context, _headers) { } static createNoOpProvider() { return new ClaudeTelemetryProvider(); } }; // src/retry/executor.ts var ClaudeRetryExecutor = class { defaults = { maxAttempts: 3, initialDelay: 1e3, maxDelay: 3e4, multiplier: 2, jitter: true, jitterFactor: 0.1 }; stats = { totalExecutions: 0, successfulFirstAttempts: 0, successfulRetries: 0, totalFailures: 0, totalRetryAttempts: 0, averageAttempts: 0, maxAttempts: 0 }; strategy; constructor(options, strategy) { if (options) { this.defaults = { ...this.defaults, ...options }; } this.strategy = strategy || new ExponentialBackoffStrategy({ multiplier: this.defaults.multiplier, maxDelay: this.defaults.maxDelay, jitter: this.defaults.jitter, jitterFactor: this.defaults.jitterFactor }); } async execute(fn, options) { const result = await this.executeWithResult(fn, options); return result.value; } async executeWithResult(fn, options) { const opts = { ...this.defaults, ...options }; const errors = []; const startTime = Date.now(); this.stats.totalExecutions++; if (opts.signal?.aborted) { throw new Error("Operation aborted before execution"); } let totalTimeoutId; let totalTimeoutPromise; if (opts.totalTimeout) { totalTimeoutPromise = new Promise((_, reject) => { totalTimeoutId = setTimeout(() => { reject(new Error(`Total timeout of ${opts.totalTimeout}ms exceeded`)); }, opts.totalTimeout); }); } try { for (let attempt = 1; attempt <= (opts.maxAttempts || 3); attempt++) { try { if (opts.signal?.aborted) { throw new Error("Operation aborted"); } let attemptPromise = fn(); if (opts.attemptTimeout) { const timeoutPromise = new Promise((_, reject) => { setTimeout(() => { reject(new Error(`Attempt timeout of ${opts.attemptTimeout}ms exceeded`)); }, opts.attemptTimeout); }); attemptPromise = Promise.race([attemptPromise, timeoutPromise]); } const value = await (totalTimeoutPromise ? Promise.race([attemptPromise, totalTimeoutPromise]) : attemptPromise); if (attempt === 1) { this.stats.successfulFirstAttempts++; } else { this.stats.successfulRetries++; } this.updateStats(attempt); return { value, attempts: attempt, totalDuration: Date.now() - startTime, errors }; } catch (error) { errors.push(error); const shouldRetry = await this.shouldRetry(error, attempt, opts); if (!shouldRetry || attempt === opts.maxAttempts) { this.stats.totalFailures++; this.updateStats(attempt); throw error; } const delay = this.strategy.calculateDelay(attempt, opts.initialDelay || 1e3); if (opts.onRetry) { await opts.onRetry(attempt, error, delay); } await this.sleep(delay, opts.signal); this.stats.totalRetryAttempts++; } } throw errors[errors.length - 1]; } finally { if (totalTimeoutId) { clearTimeout(totalTimeoutId); } } } setDefaults(options) { this.defaults = { ...this.defaults, ...options }; if (options.multiplier || options.maxDelay || options.jitter || options.jitterFactor) { this.strategy = new ExponentialBackoffStrategy({ multiplier: options.multiplier || this.defaults.multiplier, maxDelay: options.maxDelay || this.defaults.maxDelay, jitter: options.jitter ?? this.defaults.jitter, jitterFactor: options.jitterFactor || this.defaults.jitterFactor }); } } getStats() { return { ...this.stats }; } resetStats() { this.stats = { totalExecutions: 0, successfulFirstAttempts: 0, successfulRetries: 0, totalFailures: 0, totalRetryAttempts: 0, averageAttempts: 0, maxAttempts: 0 }; } async shouldRetry(error, attempt, options) { if (options.shouldRetry) { return options.shouldRetry(error, attempt); } if (!this.strategy.shouldRetry(error, attempt)) { return false; } if (options.retryableErrors) { return options.retryableErrors.some((ErrorClass) => error instanceof ErrorClass); } return RetryUtils.isRetryableError(error); } async sleep(ms, signal) { return new Promise((resolve, reject) => { const timeoutId = setTimeout(() => { cleanup(); resolve(); }, ms); const cleanup = () => { clearTimeout(timeoutId); signal?.removeEventListener("abort", onAbort); }; const onAbort = () => { cleanup(); reject(new Error("Sleep aborted")); }; if (signal?.aborted) { reject(new Error("Sleep aborted")); return; } signal?.addEventListener("abort", onAbort); }); } updateStats(attempts) { this.stats.maxAttempts = Math.max(this.stats.maxAttempts, attempts); const totalAttempts = this.stats.successfulFirstAttempts + this.stats.successfulRetries * 2 + // At least 2 attempts for retries this.stats.totalFailures * (this.defaults.maxAttempts || 3); this.stats.averageAttempts = totalAttempts / this.stats.totalExecutions; } }; function createRetryExecutor(options) { return new ClaudeRetryExecutor(options); } function createExponentialRetryExecutor(options) { return new ClaudeRetryExecutor(options, new ExponentialBackoffStrategy({ multiplier: options?.multiplier, maxDelay: options?.maxDelay, jitter: options?.jitter, jitterFactor: options?.jitterFactor })); } function createLinearRetryExecutor(options) { return new ClaudeRetryExecutor(options, new LinearBackoffStrategy({ increment: options?.increment, maxDelay: options?.maxDelay, jitter: options?.jitter })); } function createFibonacciRetryExecutor(options) { return new ClaudeRetryExecutor(options, new FibonacciBackoffStrategy({ maxDelay: options?.maxDelay, jitter: options?.jitter })); } function withRetry(fn, options) { const executor = createRetryExecutor(options); return () => executor.execute(fn); } // src/index.ts async function* query(prompt, options) { const client = new InternalClient(prompt, options); yield* client.processQuery(); } export { APIError, API_KEY_SAFETY_WARNING, AbortError, AuthenticationError, BUILTIN_METRICS, CLIConnectionError, CLIJSONDecodeError, CLINotFoundError, CircuitOpenError, ClaudeRetryExecutor, ClaudeSDKError, ClaudeTelemetryProvider, ConfigValidationError, ConnectionRefusedError, ConnectionTimeoutError, ConsoleLogger, ContextLengthExceededError, ERROR_PATTERNS, ErrorDetectionPatterns, ExponentialBackoffStrategy, FibonacciBackoffStrategy, JSONLogger, LinearBackoffStrategy, LogLevel, MCPServerPermissionError, MaxRetriesExceededError, ModelNotAvailableError, MultiLogger, NetworkError, NullLogger, PermissionError, ProcessError, QueryBuilder, RateLimitError, ResponseParser, RetryUtils, SimpleRetryExecutor, StreamAbortedError, StreamPausedError, StreamingError, TelemetryUtils, TimeoutError, TokenStreamImpl, ToolPermissionError, ToolPermissionManager2 as ToolPermissionManager, ValidationError, claude, createExponentialRetryExecutor, createFibonacciRetryExecutor, createLinearRetryExecutor, createPermissionManager, createRetryExecutor, createTelemetryProvider, createTokenStream, createTypedError, detectErrorType, hasResolution, isAPIError, isAuthenticationError, isEnhancedError, isNetworkError, isRateLimitError, isRetryableError, isStreamAbortedError, isTimeoutError, isToolPermissionError, isValidationError, query, withRetry }; //# sourceMappingURL=index.js.map