claude-web/node_modules/@instantlyeasy/claude-code-sdk-ts/dist/index.cjs

3585 lines
102 KiB
JavaScript

"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/index.ts
var index_exports = {};
__export(index_exports, {
APIError: () => APIError,
API_KEY_SAFETY_WARNING: () => API_KEY_SAFETY_WARNING,
AbortError: () => AbortError,
AuthenticationError: () => AuthenticationError,
BUILTIN_METRICS: () => BUILTIN_METRICS,
CLIConnectionError: () => CLIConnectionError,
CLIJSONDecodeError: () => CLIJSONDecodeError,
CLINotFoundError: () => CLINotFoundError,
CircuitOpenError: () => CircuitOpenError,
ClaudeRetryExecutor: () => ClaudeRetryExecutor,
ClaudeSDKError: () => ClaudeSDKError,
ClaudeTelemetryProvider: () => ClaudeTelemetryProvider,
ConfigValidationError: () => ConfigValidationError,
ConnectionRefusedError: () => ConnectionRefusedError,
ConnectionTimeoutError: () => ConnectionTimeoutError,
ConsoleLogger: () => ConsoleLogger,
ContextLengthExceededError: () => ContextLengthExceededError,
ERROR_PATTERNS: () => ERROR_PATTERNS,
ErrorDetectionPatterns: () => ErrorDetectionPatterns,
ExponentialBackoffStrategy: () => ExponentialBackoffStrategy,
FibonacciBackoffStrategy: () => FibonacciBackoffStrategy,
JSONLogger: () => JSONLogger,
LinearBackoffStrategy: () => LinearBackoffStrategy,
LogLevel: () => LogLevel,
MCPServerPermissionError: () => MCPServerPermissionError,
MaxRetriesExceededError: () => MaxRetriesExceededError,
ModelNotAvailableError: () => ModelNotAvailableError,
MultiLogger: () => MultiLogger,
NetworkError: () => NetworkError,
NullLogger: () => NullLogger,
PermissionError: () => PermissionError,
ProcessError: () => ProcessError,
QueryBuilder: () => QueryBuilder,
RateLimitError: () => RateLimitError,
ResponseParser: () => ResponseParser,
RetryUtils: () => RetryUtils,
SimpleRetryExecutor: () => SimpleRetryExecutor,
StreamAbortedError: () => StreamAbortedError,
StreamPausedError: () => StreamPausedError,
StreamingError: () => StreamingError,
TelemetryUtils: () => TelemetryUtils,
TimeoutError: () => TimeoutError,
TokenStreamImpl: () => TokenStreamImpl,
ToolPermissionError: () => ToolPermissionError,
ToolPermissionManager: () => ToolPermissionManager2,
ValidationError: () => ValidationError,
claude: () => claude,
createExponentialRetryExecutor: () => createExponentialRetryExecutor,
createFibonacciRetryExecutor: () => createFibonacciRetryExecutor,
createLinearRetryExecutor: () => createLinearRetryExecutor,
createPermissionManager: () => createPermissionManager,
createRetryExecutor: () => createRetryExecutor,
createTelemetryProvider: () => createTelemetryProvider,
createTokenStream: () => createTokenStream,
createTypedError: () => createTypedError,
detectErrorType: () => detectErrorType,
hasResolution: () => hasResolution,
isAPIError: () => isAPIError,
isAuthenticationError: () => isAuthenticationError,
isEnhancedError: () => isEnhancedError,
isNetworkError: () => isNetworkError,
isRateLimitError: () => isRateLimitError,
isRetryableError: () => isRetryableError,
isStreamAbortedError: () => isStreamAbortedError,
isTimeoutError: () => isTimeoutError,
isToolPermissionError: () => isToolPermissionError,
isValidationError: () => isValidationError,
query: () => query,
withRetry: () => withRetry
});
module.exports = __toCommonJS(index_exports);
// src/_internal/transport/subprocess-cli.ts
var import_execa = require("execa");
var import_which = __toESM(require("which"), 1);
var import_node_readline = require("readline");
var import_node_os = require("os");
var import_node_path = require("path");
var import_node_os2 = require("os");
var import_promises = require("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 = [
(0, import_node_path.join)((0, import_node_os2.homedir)(), ".claude", "local", "claude"),
(0, import_node_path.join)((0, import_node_os2.homedir)(), ".claude", "bin", "claude")
];
for (const path3 of localPaths) {
try {
await (0, import_promises.access)(path3, import_promises.constants.X_OK);
return path3;
} catch {
}
}
try {
return await (0, import_which.default)("claude");
} catch {
try {
return await (0, import_which.default)("claude-code");
} catch {
}
}
const paths = [];
const isWindows = (0, import_node_os.platform)() === "win32";
const home = (0, import_node_os2.homedir)();
if (isWindows) {
paths.push(
(0, import_node_path.join)(home, "AppData", "Local", "Programs", "claude", "claude.exe"),
(0, import_node_path.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",
(0, import_node_path.join)(home, ".local", "bin", "claude"),
(0, import_node_path.join)(home, ".local", "bin", "claude-code"),
(0, import_node_path.join)(home, "bin", "claude"),
(0, import_node_path.join)(home, "bin", "claude-code"),
(0, import_node_path.join)(home, ".claude", "local", "claude")
// Claude's custom installation path
);
}
try {
const { stdout: npmPrefix } = await (0, import_execa.execa)("npm", ["config", "get", "prefix"]);
if (npmPrefix) {
paths.push(
(0, import_node_path.join)(npmPrefix.trim(), "bin", "claude"),
(0, import_node_path.join)(npmPrefix.trim(), "bin", "claude-code")
);
}
} catch {
}
for (const path3 of paths) {
try {
await (0, import_execa.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 = (0, import_execa.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 = (0, import_node_readline.createInterface)({
input: this.process.stderr,
crlfDelay: Infinity
});
stderrRl.on("line", (line) => {
if (this.options.debug) {
console.error("DEBUG stderr:", line);
}
});
}
const rl = (0, import_node_readline.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
var import_node_fs = require("fs");
var import_node_path2 = __toESM(require("path"), 1);
var ConfigLoader = class {
loadedConfigs = /* @__PURE__ */ new Map();
/**
* Detect file format based on extension
*/
detectFormat(filePath) {
const ext = import_node_path2.default.extname(filePath).toLowerCase();
if (ext === ".yaml" || ext === ".yml") return "yaml";
return "json";
}
/**
* Load configuration from file
*/
async loadFromFile(filePath, options) {
const absolutePath = import_node_path2.default.resolve(filePath);
try {
await import_node_fs.promises.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 import_node_fs.promises.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 = import_node_path2.default.resolve(import_node_path2.default.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
var import_node_fs2 = require("fs");
var import_node_path3 = __toESM(require("path"), 1);
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 = import_node_path3.default.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 import_node_fs2.promises.access(filePath);
} catch (error) {
if (error.code === "ENOENT") {
throw new Error(`Failed to read roles file: ${filePath}`);
}
throw error;
}
const content = await import_node_fs2.promises.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();
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
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,
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.cjs.map