@theokit/sdk 4.19.4 → 4.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/internal/runtime/lifecycle/env-policy.ts","../../src/sandbox/shell-escape.ts","../../src/sandbox/types.ts","../../src/sandbox/local-sandbox.ts","../../src/errors.ts","../../src/sandbox/provision.ts"],"names":["execFile","path","mkdir","dirname","fsWriteFile"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Child-process environment policy (#54).\n *\n * Every subprocess the SDK spawns previously inherited the FULL `process.env`,\n * so API keys, tokens and passwords leaked into hook scripts and shell tools.\n * `resolveChildEnv` computes the env a child receives under an explicit policy,\n * modeled on codex's `ShellEnvironmentPolicy`\n * (referencia: codex/codex-rs/protocol/src/shell_environment.rs).\n *\n * Modes:\n * - `inherit-scrubbed` (DEFAULT) — inherit all parent vars EXCEPT secret-like\n * names (`*KEY*`, `*SECRET*`, `*TOKEN*`, `*PASSWORD*`, `*_AUTH*`). Non-breaking:\n * existing spawns keep every non-secret var; only secrets stop leaking.\n * - `core` — inherit ONLY a safe base allowlist (PATH/HOME/…); strongest scrub.\n * - `all` — explicit opt-out: inherit everything, secrets included.\n *\n * Explicit `overrides` ALWAYS win (merged last), so a tool can re-inject a var\n * it genuinely needs even under a scrubbing policy.\n *\n * @internal\n */\n\nimport type { EnvPolicy } from \"../../../types/env-policy.js\";\n\n// The `EnvPolicy` contract now lives in the domain `types/` layer (SE46 DIP\n// direction). Re-exported here so existing importers of this module keep\n// resolving the same name.\nexport type { EnvPolicy } from \"../../../types/env-policy.js\";\n\nexport interface ResolveChildEnvOptions {\n /** Source env to derive from. Defaults to `process.env`. */\n parent?: Record<string, string | undefined>;\n /** Inherit/scrub policy. Defaults to `inherit-scrubbed`. */\n policy?: EnvPolicy;\n /** Explicit vars merged AFTER the policy — always win. */\n overrides?: Record<string, string>;\n}\n\n/**\n * Secret-like variable-name patterns (case-insensitive). A parent var whose\n * name matches any of these is dropped under `inherit-scrubbed`. Conservative\n * by design — see the EC-4 false-positive test. `[_-]PWD` (not bare `PWD`)\n * catches `DB_PWD` without dropping the shell's working-directory `PWD`.\n * `CREDENTIAL` catches `GOOGLE_APPLICATION_CREDENTIALS`. #54-a extends the list to\n * the highest-signal VALUE-embedded-secret conventions — connection strings that\n * carry `user:password@` (`DATABASE_URL`, `REDIS_URL`, `MONGODB_URI`, `DB_URL`, …),\n * `DSN`, `WEBHOOK`, `COOKIE`, and `CONNECTION_STRING` — while deliberately NOT\n * dropping generic non-secret URLs (`PUBLIC_BASE_URL`, `API_URL`, `PGHOST`). A\n * denylist still cannot catch EVERY value-embedded secret — for untrusted children\n * use policy `\"core\"` (allowlist), the only fail-closed mode.\n */\nconst SECRET_PATTERNS: readonly RegExp[] = [\n /KEY/i,\n /SECRET/i,\n /TOKEN/i,\n /PASSWORD/i,\n /PASSWD/i,\n /PASSPHRASE/i,\n /[_-]PWD/i,\n /CREDENTIAL/i,\n /PRIVATE/i,\n /_AUTH/i,\n // #54-a — value-embedded-secret conventions (no generic `*_URL` — see keep-list test).\n /DSN/i,\n /WEBHOOK/i,\n /COOKIE/i,\n /CONNECTION[_-]?STRING/i,\n // Known DB / message-broker connection-string vars (carry `user:pass@`).\n /(?:^|[_-])(?:DATABASE|DB|REDIS|MONGO(?:DB)?|POSTGRES(?:QL)?|MYSQL|MARIADB|AMQP|RABBITMQ|CLICKHOUSE|ELASTIC(?:SEARCH)?|CASSANDRA|COUCHDB|MEMCACHED|NATS|KAFKA)[_-]?(?:URL|URI|DSN|CONNECTION)/i,\n];\n\n/**\n * Safe base variables kept under the `core` policy. Process-hygiene vars a\n * child almost always needs; none are secret-bearing.\n */\nconst CORE_VARS: readonly string[] = [\n \"PATH\",\n \"HOME\",\n \"SHELL\",\n \"LANG\",\n \"LC_ALL\",\n \"LC_CTYPE\",\n \"TMPDIR\",\n \"TMP\",\n \"TEMP\",\n \"USER\",\n \"LOGNAME\",\n];\n\nfunction isSecretName(name: string): boolean {\n return SECRET_PATTERNS.some((re) => re.test(name));\n}\n\n/** Whether a parent var of the given name is inherited under `policy`. */\nfunction inheritsUnderPolicy(name: string, policy: EnvPolicy): boolean {\n if (policy === \"all\") return true;\n if (policy === \"core\") return CORE_VARS.includes(name);\n return !isSecretName(name); // inherit-scrubbed\n}\n\nexport function resolveChildEnv(options: ResolveChildEnvOptions = {}): Record<string, string> {\n const parent = options.parent ?? process.env;\n const policy = options.policy ?? \"inherit-scrubbed\";\n\n const base: Record<string, string> = {};\n for (const [name, value] of Object.entries(parent)) {\n if (value !== undefined && inheritsUnderPolicy(name, policy)) base[name] = value;\n }\n\n // Explicit overrides always win — even over a scrub.\n for (const [name, value] of Object.entries(options.overrides ?? {})) {\n base[name] = value;\n }\n return base;\n}\n","/**\n * POSIX shell escaping for values interpolated into a `SandboxBackend.execute`\n * command string. `execute` runs via `/bin/sh -c`, so any untrusted value\n * (repo URL, ref, path) MUST be quoted to prevent command injection.\n *\n * @internal\n */\n\n/** Wrap `arg` in single quotes, escaping embedded single quotes (`'\\''`). */\nexport function shellEscapePosix(arg: string): string {\n return `'${arg.replace(/'/g, \"'\\\\''\")}'`;\n}\n","/**\n * Sandbox backend protocol — pluggable execution environment for agent tools.\n *\n * Per ADR D1: only 2 abstract methods (`execute` + `uploadFile`). All\n * higher-level operations are derived on the base class. New backends\n * (Docker, Firecracker, E2B) only implement those 2 methods.\n *\n * @public\n */\n\nimport type { EnvPolicy } from \"../types/env-policy.js\";\nimport { shellEscapePosix } from \"./shell-escape.js\";\n\nexport interface ExecuteResult {\n stdout: string;\n stderr: string;\n exitCode: number;\n timedOut: boolean;\n}\n\nexport interface SandboxConfig {\n workDir?: string;\n timeoutMs?: number;\n maxOutputBytes?: number;\n /**\n * #54 — env inherit/scrub policy for the executed command's child process.\n * Defaults to `\"inherit-scrubbed\"` (drop secret-like vars: `*KEY*`, `*SECRET*`,\n * `*TOKEN*`, `*PASSWORD*`, `*_AUTH*`). Pass `\"all\"` to restore full inheritance\n * or `\"core\"` for a minimal safe allowlist.\n */\n env?: EnvPolicy;\n}\n\nexport class SandboxSecurityError extends Error {\n readonly code = \"sandbox_security\" as const;\n constructor(message: string) {\n super(message);\n this.name = \"SandboxSecurityError\";\n }\n}\n\nexport class SandboxNotAvailableError extends Error {\n readonly code = \"sandbox_not_available\" as const;\n constructor(message: string) {\n super(message);\n this.name = \"SandboxNotAvailableError\";\n }\n}\n\nexport abstract class SandboxBackend {\n protected config: SandboxConfig;\n\n constructor(config: SandboxConfig = {}) {\n this.config = {\n workDir: config.workDir ?? \"/tmp\",\n timeoutMs: config.timeoutMs ?? 30_000,\n maxOutputBytes: config.maxOutputBytes ?? 5 * 1024 * 1024,\n // #54 — preserve the env policy so backends can scrub secrets.\n env: config.env ?? \"inherit-scrubbed\",\n };\n }\n\n abstract execute(command: string, opts?: { timeoutMs?: number }): Promise<ExecuteResult>;\n\n abstract uploadFile(path: string, content: string | Buffer): Promise<void>;\n\n async readFile(path: string): Promise<string> {\n const result = await this.execute(`cat ${this.shellEscape(path)}`);\n if (result.exitCode !== 0) {\n throw new Error(`readFile failed: ${result.stderr}`);\n }\n return result.stdout;\n }\n\n async writeFile(path: string, content: string): Promise<void> {\n await this.uploadFile(path, content);\n }\n\n async glob(pattern: string, cwd?: string): Promise<string[]> {\n const dir = cwd ?? this.config.workDir ?? \".\";\n const result = await this.execute(\n `find ${this.shellEscape(dir)} -name ${this.shellEscape(pattern)} -type f 2>/dev/null`,\n );\n if (result.exitCode !== 0) return [];\n return result.stdout.trim().split(\"\\n\").filter(Boolean);\n }\n\n async grep(pattern: string, path?: string): Promise<string[]> {\n const target = path ?? \".\";\n const result = await this.execute(\n `grep -rn ${this.shellEscape(pattern)} ${this.shellEscape(target)} 2>/dev/null`,\n );\n if (result.exitCode !== 0) return [];\n return result.stdout.trim().split(\"\\n\").filter(Boolean);\n }\n\n async listDir(path: string): Promise<string[]> {\n const result = await this.execute(`ls -1 ${this.shellEscape(path)}`);\n if (result.exitCode !== 0) return [];\n return result.stdout.trim().split(\"\\n\").filter(Boolean);\n }\n\n protected truncateOutput(output: string): string {\n const max = this.config.maxOutputBytes ?? 5 * 1024 * 1024;\n if (Buffer.byteLength(output) > max) {\n return `${output.slice(0, max)}\\n...(truncated)`;\n }\n return output;\n }\n\n private shellEscape(arg: string): string {\n return shellEscapePosix(arg);\n }\n}\n\n/**\n * A backend OR a per-request resolver of one — mirrors `FilesystemProvider` / `InteractiveProvider`.\n * A resolver runs at tool-execution time (request scope), so a multi-tenant / multi-role agent gets a\n * distinct sandbox per request without a shared mutable one. This is how a tool takes execution as an\n * INJECTED capability: the same tool runs on a local sandbox, a container/E2B backend (cluster/web), or\n * any future backend, with no direct `child_process` import.\n *\n * @public\n */\nexport type SandboxProvider<Ctx = unknown> =\n | SandboxBackend\n | ((ctx: Ctx) => SandboxBackend | Promise<SandboxBackend>);\n\n/** Resolve a {@link SandboxProvider} to a concrete backend for `ctx`. */\nexport async function resolveSandbox<Ctx>(\n provider: SandboxProvider<Ctx>,\n ctx: Ctx,\n): Promise<SandboxBackend> {\n return provider instanceof SandboxBackend ? provider : provider(ctx);\n}\n","/**\n * LocalSandbox — subprocess-based execution. **This is NOT an isolation\n * boundary.** It runs the command via `/bin/sh -c` in the SAME OS as the host\n * with the host's filesystem and network fully reachable — it provides NO\n * process, filesystem, or network isolation. Its only safety affordances are:\n * - a wall-clock timeout (kills a runaway command),\n * - an output-size cap (bounds memory), and\n * - env scrubbing (#54): secret-like parent env vars (`*KEY*`/`*SECRET*`/\n * `*TOKEN*`/`*PASSWORD*`/`*_AUTH*`) are dropped from the child by default\n * (`SandboxConfig.env`), so a shell tool cannot exfiltrate host secrets via\n * the environment.\n *\n * For real isolation (untrusted code), use a container/VM backend — NOT this.\n *\n * @public\n */\n\nimport { execFile } from \"node:child_process\";\nimport { writeFile as fsWriteFile, mkdir } from \"node:fs/promises\";\nimport { dirname } from \"node:path\";\n\nimport { resolveChildEnv } from \"../internal/runtime/lifecycle/env-policy.js\";\nimport { type ExecuteResult, SandboxBackend, type SandboxConfig } from \"./types.js\";\n\nexport class LocalSandbox extends SandboxBackend {\n constructor(config: SandboxConfig = {}) {\n super(config);\n }\n\n async execute(command: string, opts?: { timeoutMs?: number }): Promise<ExecuteResult> {\n const timeout = opts?.timeoutMs ?? this.config.timeoutMs ?? 30_000;\n const max = this.config.maxOutputBytes ?? 5 * 1024 * 1024;\n\n return new Promise<ExecuteResult>((resolve) => {\n const child = execFile(\n \"/bin/sh\",\n [\"-c\", command],\n {\n cwd: this.config.workDir,\n timeout,\n maxBuffer: max,\n encoding: \"utf-8\",\n // #54 — scrub secret-like host env vars from the child by default.\n env: resolveChildEnv({ policy: this.config.env }),\n },\n (error, stdout, stderr) => {\n resolve(this.buildResult(error, stdout ?? \"\", stderr ?? \"\"));\n },\n );\n\n // Safety: if child somehow doesn't callback\n child.on(\"error\", () => {\n resolve({ stdout: \"\", stderr: \"spawn error\", exitCode: 1, timedOut: false });\n });\n });\n }\n\n private buildResult(error: Error | null, stdout: string, stderr: string): ExecuteResult {\n const timedOut = error !== null && \"killed\" in error && (error as { killed: boolean }).killed;\n return {\n stdout: this.truncateOutput(stdout),\n stderr: this.truncateOutput(stderr),\n exitCode: timedOut ? 124 : error ? 1 : 0,\n timedOut,\n };\n }\n\n async uploadFile(path: string, content: string | Buffer): Promise<void> {\n const fullPath = path.startsWith(\"/\") ? path : `${this.config.workDir}/${path}`;\n await mkdir(dirname(fullPath), { recursive: true });\n await fsWriteFile(fullPath, content, \"utf-8\");\n }\n}\n","import { defaultRetriableForCode } from \"./internal/runtime/retry/default-retriable.js\";\nimport { redactSecrets } from \"./internal/security/redact.js\";\nimport type { RunOperation } from \"./types/run.js\";\n\n/**\n * Finite, machine-readable error codes for provider-originated errors\n * (ADR D66). Consumers can `switch (err.metadata?.code)` exhaustively\n * — adding a new variant is an explicit decision + test coverage.\n *\n * @public\n */\nexport type ErrorCode =\n | \"rate_limit\"\n | \"auth_failed\"\n | \"invalid_request\"\n | \"timeout\"\n | \"server_error\"\n | \"context_too_long\"\n | \"content_filtered\"\n | \"model_unavailable\"\n | \"network\"\n | \"quota_exceeded\"\n | \"unknown\";\n\n/**\n * Codes used by {@link AgentRunError} (Production-Readiness #3, ADR D311).\n *\n * Superset of {@link ErrorCode} extended with codes that do NOT originate\n * from a provider HTTP response:\n *\n * - `quota_exceeded` — billing limit hit (provider 402 or signalled error)\n * - `tool_runtime_error` — custom tool handler threw inside dispatch\n * - `aborted` — caller's `AbortSignal` fired (Phase 4)\n * - `invalid_model` — model id rejected by provider (400 \"model not found\")\n * - `safety_blocked` — provider safety filter blocked req or resp\n * - `provider_unreachable` — DNS/TCP/timeout/5xx at transport boundary\n *\n * The `& {}` tail keeps the literal-union ergonomics (autocomplete) while\n * accepting any string for forward compatibility with constructor calls\n * that pass arbitrary code values (legacy callers).\n *\n * @public\n */\n/**\n * T1.1 — closed literal union for `AgentRunError.code`. The previous\n * `(string & {})` escape hatch let arbitrary strings slip into the type\n * surface and defeated exhaustive `switch (code)` discrimination. This is\n * the canonical closed form. `AgentRunErrorCode` is re-aliased below for\n * source-level back-compat.\n *\n * Adding a new code: append the literal here AND audit every `switch (err.code)`\n * in callers. Type-checker enforces the audit via the `default: assertNever(code)`\n * convention.\n *\n * @public\n */\nexport type KnownAgentRunErrorCode =\n | ErrorCode\n | \"quota_exceeded\"\n | \"tool_runtime_error\"\n | \"aborted\"\n | \"invalid_model\"\n | \"safety_blocked\"\n | \"provider_unreachable\";\n\n/**\n * Back-compat alias of {@link KnownAgentRunErrorCode}. Pre-T1.1 callers that\n * imported `AgentRunErrorCode` keep working; new code SHOULD prefer\n * `KnownAgentRunErrorCode` to make the closed-union intent explicit.\n *\n * @public\n */\nexport type AgentRunErrorCode = KnownAgentRunErrorCode;\n\n/** Snapshot of every known code at runtime — used by the boundary coercer. */\nconst KNOWN_AGENT_RUN_ERROR_CODES = new Set<string>([\n \"rate_limit\",\n \"auth_failed\",\n \"invalid_request\",\n \"timeout\",\n \"server_error\",\n \"context_too_long\",\n \"content_filtered\",\n \"model_unavailable\",\n \"network\",\n \"unknown\",\n \"quota_exceeded\",\n \"tool_runtime_error\",\n \"aborted\",\n \"invalid_model\",\n \"safety_blocked\",\n \"provider_unreachable\",\n]);\n\n/**\n * T1.1 boundary helper — coerce an arbitrary string (typically arriving from\n * a downstream `RunErrorDetail.code` or a deserialized cloud response) into a\n * `KnownAgentRunErrorCode`. Unknown strings collapse to `\"unknown\"` so the\n * closed type contract holds without forcing every caller to switch.\n *\n * @internal\n */\nexport function coerceToKnownAgentRunErrorCode(code: string | undefined): KnownAgentRunErrorCode {\n if (code !== undefined && KNOWN_AGENT_RUN_ERROR_CODES.has(code)) {\n return code as KnownAgentRunErrorCode;\n }\n return \"unknown\";\n}\n\n/**\n * Structured context for errors that originated from a provider HTTP\n * call (ADR D65). Lets callers retry with the right backoff (`retryAfter`),\n * surface actionable diagnostics (`provider`, `endpoint`), and inspect the\n * raw response body when needed (`raw`, capped at ~2KB by the mapper).\n *\n * @public\n */\nexport interface ErrorMetadata {\n /** Provider canonical name (e.g., `\"anthropic\"`, `\"openai\"`, `\"openrouter\"`, `\"gemini\"`). */\n provider: string;\n /** HTTP endpoint that failed (e.g., `\"/v1/messages\"`, `\"/v1/chat/completions\"`). */\n endpoint: string;\n /** Machine-readable error code (finite enum). */\n code: ErrorCode;\n /** HTTP status code if applicable. */\n statusCode?: number;\n /** Seconds to wait before retry, per provider's `retry-after` header (numeric form only). */\n retryAfter?: number;\n /** Raw response body for debugging (truncated to ~2KB by the mapper). */\n raw?: unknown;\n}\n\n/**\n * Base class for all errors thrown by `@theokit/sdk`.\n *\n * Use `isRetryable` to drive retry/backoff logic. `code` and `protoErrorCode`\n * are populated for server-originated errors when available. `metadata`\n * (ADR D65) carries structured `{ provider, endpoint, code, ... }` when\n * the error originated from a provider HTTP call.\n *\n * @public\n */\nexport class TheokitAgentError extends Error {\n override readonly name: string = \"TheokitAgentError\";\n readonly isRetryable: boolean;\n readonly code?: string;\n readonly protoErrorCode?: string;\n readonly metadata?: ErrorMetadata;\n\n constructor(\n message: string,\n options: {\n isRetryable?: boolean;\n code?: string;\n protoErrorCode?: string;\n cause?: unknown;\n metadata?: ErrorMetadata;\n } = {},\n ) {\n super(message, options.cause !== undefined ? { cause: options.cause } : undefined);\n this.isRetryable = options.isRetryable ?? false;\n if (options.code !== undefined) this.code = options.code;\n if (options.protoErrorCode !== undefined) this.protoErrorCode = options.protoErrorCode;\n if (options.metadata !== undefined) this.metadata = options.metadata;\n }\n}\n\n/**\n * Invalid API key, not logged in, insufficient permissions.\n *\n * @public\n */\nexport class AuthenticationError extends TheokitAgentError {\n override readonly name: string = \"AuthenticationError\";\n\n constructor(\n message: string,\n options: { code?: string; cause?: unknown; metadata?: ErrorMetadata } = {},\n ) {\n super(message, { ...options, isRetryable: false });\n }\n}\n\n/**\n * Too many requests or usage limits exceeded.\n *\n * @public\n */\nexport class RateLimitError extends TheokitAgentError {\n override readonly name: string = \"RateLimitError\";\n\n constructor(\n message: string,\n options: { code?: string; cause?: unknown; metadata?: ErrorMetadata } = {},\n ) {\n super(message, { ...options, isRetryable: true });\n }\n}\n\n/**\n * Invalid model, bad request parameters, malformed options.\n *\n * @public\n */\nexport class ConfigurationError extends TheokitAgentError {\n override readonly name: string = \"ConfigurationError\";\n\n constructor(\n message: string,\n options: { code?: string; cause?: unknown; metadata?: ErrorMetadata } = {},\n ) {\n super(message, { ...options, isRetryable: false });\n }\n}\n\n/**\n * Thrown when creating a cloud agent for a repo whose SCM provider is not\n * connected. Use `helpUrl` to point the user at the right reconnect flow.\n *\n * @public\n */\nexport class IntegrationNotConnectedError extends ConfigurationError {\n override readonly name: string = \"IntegrationNotConnectedError\";\n readonly provider: string;\n readonly helpUrl: string;\n\n constructor(\n message: string,\n options: {\n provider: string;\n helpUrl: string;\n code?: string;\n cause?: unknown;\n metadata?: ErrorMetadata;\n },\n ) {\n super(message, options);\n this.provider = options.provider;\n this.helpUrl = options.helpUrl;\n }\n}\n\n/**\n * Service unavailable, timeout, transport-level failure.\n *\n * @public\n */\nexport class NetworkError extends TheokitAgentError {\n override readonly name: string = \"NetworkError\";\n\n constructor(\n message: string,\n options: { code?: string; cause?: unknown; metadata?: ErrorMetadata } = {},\n ) {\n super(message, { ...options, isRetryable: true });\n }\n}\n\n/**\n * Catch-all for unclassified server or runtime errors.\n *\n * @public\n */\nexport class UnknownAgentError extends TheokitAgentError {\n override readonly name: string = \"UnknownAgentError\";\n\n constructor(\n message: string,\n options: { code?: string; cause?: unknown; metadata?: ErrorMetadata } = {},\n ) {\n super(message, { ...options, isRetryable: false });\n }\n}\n\n/**\n * Thrown by `Agent.prompt` (and helpers that go through `run.wait()`) when\n * the option `{ throwOnError: true }` is set and the run terminates with\n * `status: 'error'`. Carries the structured `RunResult.error` fields so\n * callers can `catch` once and branch on `code` / `provider` instead of\n * unwrapping the run.\n *\n * Extends {@link TheokitAgentError} per ADR D65 — no new hierarchy.\n *\n * @example\n * try {\n * await Agent.prompt(msg, { apiKey, model, throwOnError: true });\n * } catch (err) {\n * if (err instanceof AgentRunError && err.code === 'auth_failed') {\n * // bad key\n * }\n * }\n *\n * @public\n */\nexport class AgentRunError extends TheokitAgentError {\n override readonly name: string = \"AgentRunError\";\n readonly provider?: string;\n readonly raw?: string;\n /** Provider's request id (`x-request-id` / `request-id` header). Useful for support tickets. */\n readonly requestId?: string;\n /** SDK conversation id this error was raised inside. */\n readonly conversationId?: string;\n\n constructor(\n message: string,\n options: {\n code: AgentRunErrorCode;\n provider?: string;\n raw?: string;\n requestId?: string;\n conversationId?: string;\n retriable?: boolean;\n cause?: unknown;\n metadata?: ErrorMetadata;\n },\n ) {\n super(message, {\n code: options.code,\n cause: options.cause,\n metadata: options.metadata,\n // D311: most AgentRunErrors are not retriable (auth, validation, abort).\n // Provider mappers (D314) override per-status — explicit `retriable` wins\n // over the implicit default when supplied.\n isRetryable: options.retriable ?? defaultRetriableForCode(options.code),\n });\n if (options.provider !== undefined) this.provider = options.provider;\n if (options.raw !== undefined) this.raw = options.raw;\n if (options.requestId !== undefined) this.requestId = options.requestId;\n if (options.conversationId !== undefined) this.conversationId = options.conversationId;\n }\n\n /**\n * Production-Readiness #3 (ADR D311): alias for `isRetryable` exposed as\n * `retriable` to match the handoff contract. Future v2 will deprecate\n * `isRetryable` in favor of this.\n */\n get retriable(): boolean {\n return this.isRetryable;\n }\n\n /**\n * D312: provider's `Retry-After` header in **milliseconds**. Mappers store\n * the header value (seconds) in `metadata.retryAfter`; this getter\n * multiplies by 1000 so the result composes with `Date.now()`/`setTimeout`.\n *\n * Returns `undefined` when no hint was provided. `0` is a legitimate value\n * — use `=== undefined` check rather than truthy check.\n */\n get retryAfterMs(): number | undefined {\n if (this.metadata?.retryAfter === undefined) return undefined;\n return this.metadata.retryAfter * 1000;\n }\n\n /**\n * D313 + T1.5: alias for `metadata.raw`. Provider response body for\n * debugging. T1.5 wraps the value in `redactSecrets` at the getter\n * boundary so secret-shaped substrings (`sk-...`, Bearer JWTs, etc.) are\n * stripped before reaching the caller. Available but NEVER serialized\n * into `.message` (anti-leak invariant).\n */\n get providerError(): unknown {\n const raw = this.metadata?.raw;\n if (raw === undefined) return undefined;\n if (typeof raw === \"string\") return redactSecrets(raw);\n // Non-string raw (object/buffer) — stringify then redact.\n try {\n return redactSecrets(JSON.stringify(raw));\n } catch {\n return redactSecrets(String(raw));\n }\n }\n\n /**\n * T1.5 — sanitized JSON form. `metadata.raw` is OMITTED by default; opt\n * in via `THEOKIT_DEBUG_RAW_ERRORS=1` to surface the (redacted) raw\n * payload for diagnostics. Every other field stays accessible.\n *\n * The single env-var gate is read each call so operators can toggle at\n * runtime without restarting the process.\n */\n toJSON(): Record<string, unknown> {\n const json: Record<string, unknown> = {\n name: this.name,\n message: this.message,\n isRetryable: this.isRetryable,\n };\n addOptionalFields(json, this);\n const safeMeta = sanitizeMetadata(this.metadata);\n if (safeMeta !== undefined) json.metadata = safeMeta;\n return json;\n }\n}\n\nfunction addOptionalFields(json: Record<string, unknown>, err: AgentRunError): void {\n if (err.code !== undefined) json.code = err.code;\n if (err.provider !== undefined) json.provider = err.provider;\n if (err.requestId !== undefined) json.requestId = err.requestId;\n if (err.conversationId !== undefined) json.conversationId = err.conversationId;\n if (err.raw !== undefined) json.raw = redactSecrets(err.raw);\n}\n\nfunction sanitizeMetadata(meta: ErrorMetadata | undefined): ErrorMetadata | undefined {\n if (meta === undefined) return undefined;\n const { raw, ...rest } = meta;\n const debugRaw = process.env.THEOKIT_DEBUG_RAW_ERRORS === \"1\";\n if (debugRaw && raw !== undefined) {\n const redactedRaw =\n typeof raw === \"string\" ? redactSecrets(raw) : redactSecrets(safeStringify(raw));\n return { ...rest, raw: redactedRaw } as ErrorMetadata;\n }\n return rest as ErrorMetadata;\n}\n\nfunction safeStringify(value: unknown): string {\n try {\n return JSON.stringify(value);\n } catch {\n return String(value);\n }\n}\n\n/**\n * Is this error transient (worth retrying)?\n *\n * Returns the SDK's own retryability verdict: every {@link TheokitAgentError}\n * subclass computes `isRetryable` at construction (rate-limit / network /\n * credential-pool-exhausted are retryable; auth / configuration / unsupported\n * are not), so this predicate is a single source of truth rather than a\n * re-derivation. Non-SDK errors return `false` conservatively — wrap a foreign\n * error in the appropriate SDK error first if you want it considered transient.\n * It never inspects `err.message`.\n *\n * @example\n * try {\n * await agent.send(message, { throwOnError: true });\n * } catch (err) {\n * if (isTransientError(err)) return retryWithBackoff();\n * throw err;\n * }\n *\n * @public\n */\nexport function isTransientError(err: unknown): boolean {\n return err instanceof TheokitAgentError && err.isRetryable === true;\n}\n\n/**\n * Thrown when a {@link Run} or agent operation is not available on the current\n * runtime. Check first with `run.supports(operation)`.\n *\n * Extends {@link TheokitAgentError} (so error-catching code that branches on\n * `instanceof TheokitAgentError` continues to work) but is never retryable —\n * an unsupported operation will not become supported on retry.\n *\n * @public\n */\nexport class UnsupportedRunOperationError extends TheokitAgentError {\n override readonly name: string = \"UnsupportedRunOperationError\";\n readonly operation: RunOperation;\n\n constructor(\n message: string,\n operation: RunOperation,\n options: { code?: string; cause?: unknown } = {},\n ) {\n super(message, {\n ...options,\n isRetryable: false,\n code: options.code ?? \"unsupported_run_operation\",\n });\n this.operation = operation;\n }\n}\n\n/**\n * Thrown when every credential in a per-provider pool is in cooldown\n * and no healthy key is available (ADR D133). The caller's\n * {@link import(\"./internal/llm/fallback-client.js\").FallbackLlmClient}\n * catches this and tries the next provider in the fallback chain.\n *\n * `metadata.nextRetryAt` (epoch ms) tells callers when the soonest\n * pool entry resumes — useful for manual retry scheduling.\n *\n * @public\n */\nexport class CredentialPoolExhaustedError extends TheokitAgentError {\n override readonly name: string = \"CredentialPoolExhaustedError\";\n readonly provider: string;\n readonly nextRetryAt: number | undefined;\n\n constructor(\n message: string,\n options: {\n provider: string;\n nextRetryAt?: number;\n code?: string;\n cause?: unknown;\n metadata?: ErrorMetadata;\n },\n ) {\n super(message, {\n ...options,\n isRetryable: true,\n code: options.code ?? \"credential_pool_exhausted\",\n });\n this.provider = options.provider;\n this.nextRetryAt = options.nextRetryAt;\n }\n}\n\n/**\n * Finite error codes specific to memory adapter operations (ADR D141).\n *\n * @public\n */\nexport type MemoryAdapterErrorCode =\n | \"auth_failed\"\n | \"rate_limited\"\n | \"not_found\"\n | \"network\"\n | \"invalid_input\"\n | \"unknown\";\n\n/**\n * Error raised by `@theokit-memory-*` adapters. Carries `adapterId`\n * so callers can branch on which provider failed (ADR D141).\n *\n * @public\n */\nexport class MemoryAdapterError extends TheokitAgentError {\n override readonly name: string = \"MemoryAdapterError\";\n readonly adapterId: string;\n\n constructor(\n message: string,\n options: {\n adapterId: string;\n code: MemoryAdapterErrorCode;\n cause?: unknown;\n metadata?: ErrorMetadata;\n },\n ) {\n super(message, {\n isRetryable: options.code === \"rate_limited\" || options.code === \"network\",\n code: options.code,\n ...(options.cause !== undefined ? { cause: options.cause } : {}),\n ...(options.metadata !== undefined ? { metadata: options.metadata } : {}),\n });\n this.adapterId = options.adapterId;\n }\n}\n\n/**\n * Thrown when a user-supplied task ID violates the grammar\n * `^[a-z0-9][a-z0-9_-]*$` (D368) OR starts with a reserved adapter\n * prefix (`wf-` / `b-` / `cron-`, EC-5).\n *\n * @public\n */\nexport class InvalidTaskIdError extends TheokitAgentError {\n override readonly name: string = \"InvalidTaskIdError\";\n readonly taskId: string;\n\n constructor(message: string, taskId: string, options: { cause?: unknown } = {}) {\n super(message, {\n ...options,\n isRetryable: false,\n code: \"invalid_task_id\",\n });\n this.taskId = taskId;\n }\n}\n\n/**\n * Thrown when `Task.subscribe(id)` is called for a task that has been\n * evicted, never submitted, or evicted after retention (D373).\n *\n * @public\n */\nexport class TaskNotFoundError extends TheokitAgentError {\n override readonly name: string = \"TaskNotFoundError\";\n readonly taskId: string;\n\n constructor(taskId: string, options: { cause?: unknown } = {}) {\n super(`Task not found: ${taskId}`, {\n ...options,\n isRetryable: false,\n code: \"task_not_found\",\n });\n this.taskId = taskId;\n }\n}\n\n/**\n * Thrown when `CloudAgent` is asked to wrap a task (D370). Cloud\n * task observability is deferred until Theo PaaS GA.\n *\n * @public\n */\nexport class UnsupportedTaskOperationError extends TheokitAgentError {\n override readonly name: string = \"UnsupportedTaskOperationError\";\n readonly operation: string;\n\n constructor(operation: string, options: { cause?: unknown } = {}) {\n super(\n `Task operation \"${operation}\" is not supported on CloudAgent (pre-release; see ADR D370)`,\n {\n ...options,\n isRetryable: false,\n code: \"task_op_unsupported\",\n },\n );\n this.operation = operation;\n }\n}\n\n/**\n * Thrown by `Budget` enforcement (ADR D386) when a `mode: \"block\"`\n * budget would be exceeded by the upcoming LLM call. Caller pega\n * tipado para retry-after-window-reset or surface to the user.\n *\n * @public\n */\nexport class BudgetExceededError extends TheokitAgentError {\n override readonly name: string = \"BudgetExceededError\";\n readonly budgetName: string;\n readonly window: import(\"./types/budget.js\").BudgetWindow;\n readonly spentUsd: number;\n readonly limitUsd: number;\n readonly mode: import(\"./types/budget.js\").BudgetMode;\n\n constructor(args: {\n budgetName: string;\n window: import(\"./types/budget.js\").BudgetWindow;\n spentUsd: number;\n limitUsd: number;\n mode: import(\"./types/budget.js\").BudgetMode;\n cause?: unknown;\n }) {\n super(\n `Budget \"${args.budgetName}\" exceeded for window ${args.window}: spent $${args.spentUsd.toFixed(4)} > limit $${args.limitUsd.toFixed(4)}`,\n {\n ...(args.cause !== undefined ? { cause: args.cause } : {}),\n isRetryable: false,\n code: \"budget_exceeded\",\n },\n );\n this.budgetName = args.budgetName;\n this.window = args.window;\n this.spentUsd = args.spentUsd;\n this.limitUsd = args.limitUsd;\n this.mode = args.mode;\n }\n}\n\n/**\n * Thrown when `CloudAgent.send({ budget })` is invoked (D388). Cloud\n * budget surface waits for Theo PaaS GA.\n *\n * @public\n */\n/**\n * T1.6 — Thrown when a consumer calls `agent.send()` or any method\n * on an agent that has already been `dispose()`d. Pre-T1.6 this was\n * a generic `new Error(\"Agent has been disposed\")` — consumers\n * couldn't catch it without string-matching the message.\n *\n * @public\n */\nexport class AgentDisposedError extends TheokitAgentError {\n override readonly name: string = \"AgentDisposedError\";\n readonly agentId: string;\n\n constructor(agentId: string) {\n super(`Agent \"${agentId}\" has been disposed. Create a new agent or use Agent.resume().`, {\n isRetryable: false,\n code: \"agent_disposed\",\n });\n this.agentId = agentId;\n }\n}\n\nexport class UnsupportedBudgetOperationError extends TheokitAgentError {\n override readonly name: string = \"UnsupportedBudgetOperationError\";\n readonly operation: string;\n\n constructor(operation: string, options: { cause?: unknown } = {}) {\n super(\n `Budget operation \"${operation}\" is not supported on CloudAgent (pre-release; see ADR D388)`,\n {\n ...options,\n isRetryable: false,\n code: \"budget_op_unsupported\",\n },\n );\n this.operation = operation;\n }\n}\n","/**\n * M6-3 — portable repo provisioner for the eval harness.\n *\n * Clones a repository and checks out a ref into an isolated working dir, issuing\n * every git command through {@link SandboxBackend.execute} (ADR D2 — same code\n * runs on Local/Docker/E2B; never a direct `child_process` import). Promotes\n * theocode's `prepareRepo` (`swebench-provision.ts:37`) onto the SDK's sandbox\n * abstraction.\n *\n * referencia: knowledge-base/references/theocode-eval/lib/swebench-provision.ts:37\n * (clone+checkout), :13 (ProvisionError with instanceId).\n *\n * @public\n */\n\nimport { TheokitAgentError } from \"../errors.js\";\nimport { LocalSandbox } from \"./local-sandbox.js\";\nimport { shellEscapePosix } from \"./shell-escape.js\";\nimport type { SandboxBackend } from \"./types.js\";\n\n/**\n * Raised when cloning or checking out a repo fails. Carries the `instanceId`\n * so a batch run can attribute the failure to the offending dataset row.\n */\nexport class RepoProvisionError extends TheokitAgentError {\n override readonly name = \"RepoProvisionError\";\n\n constructor(\n readonly instanceId: string,\n message: string,\n options: { cause?: unknown } = {},\n ) {\n super(`[${instanceId}] ${message}`, {\n code: \"repo_provision_failed\",\n isRetryable: false,\n ...(options.cause !== undefined ? { cause: options.cause } : {}),\n });\n }\n}\n\n/** Options for {@link provisionRepo}. */\nexport interface ProvisionRepoOptions {\n /**\n * Clonable repo URL or local path. SECURITY: when this comes from an\n * untrusted dataset, the value is passed to `git clone` after a `--`\n * end-of-options terminator (no flag injection) and with the `ext::`\n * transport disabled (no arbitrary-command transport).\n */\n readonly repoUrl: string;\n /** Branch, tag, or commit SHA to check out. Rejected if it begins with `-`. */\n readonly ref: string;\n /**\n * Unique id for this row — names the target dir and any error. Validated to\n * `[A-Za-z0-9._-]` (no path traversal) since it becomes a directory name.\n */\n readonly instanceId: string;\n}\n\n/**\n * Reject ids that would escape the workdir or be parsed as a git flag. Must\n * start with an alphanumeric (blocks `.`, `..`, `-foo`, leading-dot names) and\n * thereafter allow only `[A-Za-z0-9._-]`.\n */\nconst SAFE_INSTANCE_ID = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;\n\n/**\n * Clone `repoUrl` into `<sandbox workdir>/<instanceId>` and check out `ref`.\n * Returns the absolute `repoDir` (resolved via `git rev-parse --show-toplevel`,\n * which is portable across backends). Throws {@link RepoProvisionError} naming\n * the `instanceId` when clone or checkout exits non-zero.\n *\n * The `sandbox` is optional (V3-5): when omitted, a default {@link LocalSandbox}\n * is used (clones into the process cwd's `<instanceId>`) — pass an explicit\n * sandbox (e.g. `LocalSandbox({ workDir })` / Docker / E2B) to control the workdir.\n */\nexport function provisionRepo(opts: ProvisionRepoOptions): Promise<{ repoDir: string }>;\nexport function provisionRepo(\n sandbox: SandboxBackend,\n opts: ProvisionRepoOptions,\n): Promise<{ repoDir: string }>;\nexport async function provisionRepo(\n sandboxOrOpts: SandboxBackend | ProvisionRepoOptions,\n maybeOpts?: ProvisionRepoOptions,\n): Promise<{ repoDir: string }> {\n const sandbox = maybeOpts !== undefined ? (sandboxOrOpts as SandboxBackend) : new LocalSandbox();\n const opts = maybeOpts ?? (sandboxOrOpts as ProvisionRepoOptions);\n const { repoUrl, ref, instanceId } = opts;\n\n // Validate untrusted-derivable inputs before they reach git/the shell.\n if (!SAFE_INSTANCE_ID.test(instanceId)) {\n throw new RepoProvisionError(\n instanceId,\n \"invalid instanceId: must match [A-Za-z0-9._-] (no path traversal)\",\n );\n }\n if (ref.startsWith(\"-\")) {\n throw new RepoProvisionError(instanceId, `invalid ref: must not begin with '-' (got ${ref})`);\n }\n\n // `--` terminates options (no `--upload-pack=` flag injection); `protocol.ext.allow=never`\n // blocks the `ext::` arbitrary-command transport. `file`/`https` stay allowed.\n const clone = await sandbox.execute(\n `git -c protocol.ext.allow=never clone --quiet -- ${shellEscapePosix(repoUrl)} ${shellEscapePosix(instanceId)}`,\n );\n if (clone.exitCode !== 0) {\n throw new RepoProvisionError(instanceId, `clone failed: ${clone.stderr.trim()}`);\n }\n\n const top = await sandbox.execute(\n `git -C ${shellEscapePosix(instanceId)} rev-parse --show-toplevel`,\n );\n if (top.exitCode !== 0) {\n throw new RepoProvisionError(instanceId, `resolve repoDir failed: ${top.stderr.trim()}`);\n }\n const repoDir = top.stdout.trim();\n\n // `ref` is validated above not to begin with `-`, so it cannot be parsed as a flag.\n const checkout = await sandbox.execute(\n `git -C ${shellEscapePosix(repoDir)} checkout --quiet ${shellEscapePosix(ref)}`,\n );\n if (checkout.exitCode !== 0) {\n throw new RepoProvisionError(instanceId, `checkout ${ref} failed: ${checkout.stderr.trim()}`);\n }\n\n return { repoDir };\n}\n"]}
1
+ {"version":3,"sources":["../../src/sandbox/bwrap.ts","../../src/internal/security/redact.ts","../../src/internal/runtime/lifecycle/env-policy.ts","../../src/sandbox/shell-escape.ts","../../src/sandbox/types.ts","../../src/sandbox/local-sandbox.ts","../../src/sandbox/seccomp.ts","../../src/sandbox/linux-sandbox.ts","../../src/errors.ts","../../src/sandbox/provision.ts"],"names":["path","existsSync","execFileSync","execFile","mkdir","dirname","fsWriteFile","mkdtempSync","join","tmpdir","writeFileSync","rmSync"],"mappings":"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","file":"index.cjs","sourcesContent":["// Promovido do agent-builder no M75 (plano m75-sandbox-kernel-no-framework, D1): confinamento de\n// kernel e infraestrutura do framework, nao do consumidor. Custo medido da promocao: ZERO\n// dependencias — so node:child_process, node:fs e node:path. O filtro cBPF e um Buffer em JS puro.\n\nimport { execFileSync } from \"node:child_process\";\nimport { existsSync } from \"node:fs\";\nimport path from \"node:path\";\n\n/**\n * M53 — bubblewrap argv + honest detection, faithful to Codex's Linux sandbox\n * (`codex-rs/linux-sandbox/src/bwrap.rs` + `codex-rs/sandboxing/src/bwrap.rs`).\n *\n * HONEST SCOPE: filesystem confinement + network isolation via bwrap, PLUS the second stage —\n * a cBPF seccomp syscall filter (`agents/sandbox/seccomp.ts`), wired in `agents/sandbox/backend.ts`\n * via `restrictedSeccompPath()`. Portado no M63; este bloco afirmava o contrário até o M67 e\n * SUBDECLARAVA a postura de segurança real. Limite honesto que permanece: o filtro é **x86_64**\n * (guarda de arquitetura recusa instalar em outra arch, com WARN, e o confinamento de FS/rede do\n * bwrap segue valendo) **e** só é instalado quando a rede está restrita (`backend.ts:87`, fiel a\n * `landlock.rs:96-117`): com rede ligada não há filtro de syscall, apenas o confinamento de FS do\n * bwrap. `danger-full-access` pula o bwrap por completo, espelhando `bwrap.rs:245-252`.\n * Deltas versus o Codex seguem documentados em docs/CODEX-PARITY.md.\n */\n\n/**\n * Os tres modos canonicos do Codex. Definidos AQUI porque sao vocabulario do sandbox, nao da\n * configuracao do consumidor: `danger-full-access` significa \"nao embrulhe\", e essa e uma decisao do\n * subsistema de confinamento.\n */\nexport type SandboxMode = \"read-only\" | \"workspace-write\" | \"danger-full-access\";\n\nexport interface BwrapArgvOptions {\n /** Workspace root — the single RW bind under `workspace-write` (protocol.rs:1189-1200). */\n cwd: string;\n /** `true` removes `--unshare-net` (policy `network_access`, default false). */\n network?: boolean;\n /** Injectable for tests; defaults to a real `existsSync` check on `<cwd>/.git`. */\n gitDirExists?: boolean;\n /**\n * When present, emit `--clearenv` and re-inject ONLY these vars (Codex env_clear model,\n * `exec_env.rs:25-31`). Closes the denylist gap: a secret in an oddly-named var never reaches the\n * sandboxed child. Omitted ⇒ inherit the parent env (backward-compatible; SDK scrub still applies).\n */\n env?: Record<string, string>;\n}\n\n/**\n * Pure argv builder. Returns the bwrap flags ending in `--` (caller appends `/bin/sh -c <cmd>`),\n * or `null` when the policy skips the sandbox entirely (`danger-full-access`).\n */\nexport function buildBwrapArgv(mode: SandboxMode, opts: BwrapArgvOptions): string[] | null {\n if (mode === \"danger-full-access\") return null; // bwrap skipped entirely (bwrap.rs:245-252)\n\n const cwd = path.resolve(opts.cwd);\n const gitDir = path.join(cwd, \".git\");\n const hasGit = opts.gitDirExists ?? existsSync(gitDir);\n\n const argv: string[] = [\n // core, always (bwrap.rs:318-332; user+pid namespaces explicit so it works as root in containers)\n \"--new-session\",\n \"--die-with-parent\",\n \"--unshare-user\",\n \"--unshare-pid\",\n // full-read filesystem base (bwrap.rs:446-452)\n \"--ro-bind\",\n \"/\",\n \"/\",\n \"--dev\",\n \"/dev\",\n \"--proc\",\n \"/proc\",\n ];\n\n if (!opts.network) argv.push(\"--unshare-net\"); // network off by default (bwrap.rs:325-327)\n\n // env confinement — `--clearenv` MUST precede every `--setenv` or the clear wipes them\n // (exec_env.rs:25-31 clears then rebuilds). Only when an explicit allowlist is provided.\n if (opts.env) argv.push(\"--clearenv\");\n const setenv: Record<string, string> = {\n ...(opts.env ?? {}),\n // the flag signals the child that network is unshared (spawn.rs:20,79)\n ...(opts.network ? {} : { CODEX_SANDBOX_NETWORK_DISABLED: \"1\" }),\n };\n for (const [k, v] of Object.entries(setenv)) argv.push(\"--setenv\", k, v);\n\n if (mode === \"workspace-write\") {\n // writable roots: cwd + /tmp (protocol.rs:1189-1214)\n argv.push(\"--bind\", cwd, cwd, \"--bind\", \"/tmp\", \"/tmp\");\n // metadata protection ON TOP of the RW bind — order matters (permissions.rs:22-31; bwrap.rs:571-597)\n if (hasGit) argv.push(\"--ro-bind\", gitDir, gitDir);\n }\n // read-only: zero writable roots (protocol.rs:1176) — nothing to add\n\n argv.push(\"--chdir\", cwd, \"--\");\n return argv;\n}\n\n/** Injectable probes — each mirrors one Codex availability check. */\nexport interface BwrapProbes {\n /** `which bwrap` outside the cwd (anti-hijack, sandboxing/src/bwrap.rs:168-191). */\n which: () => string | null;\n /** `bwrap --help` text — must advertise `--perms` (launcher.rs:108-124). */\n helpText: (bin: string) => string | null;\n /** Active user-namespace probe with timeout (sandboxing/src/bwrap.rs:74-136). */\n userns: (bin: string) => boolean;\n}\n\nexport type BwrapDetection = { ok: true; bin: string } | { ok: false; reason: string };\n\n/** Honest detection — fail-closed on every probe; NEVER throws (callers WARN + fall back). */\nexport function detectBwrap(probes: BwrapProbes = realProbes): BwrapDetection {\n try {\n const bin = probes.which();\n if (!bin) return { ok: false, reason: \"bwrap not found in PATH\" };\n const help = probes.helpText(bin);\n if (!help?.includes(\"--perms\")) {\n return { ok: false, reason: `bwrap at ${bin} lacks --perms support (too old)` };\n }\n if (!probes.userns(bin)) {\n return { ok: false, reason: \"user namespaces unavailable (container/kernel restriction)\" };\n }\n return { ok: true, bin };\n } catch (err) {\n return {\n ok: false,\n reason: `bwrap probe failed: ${err instanceof Error ? err.message : String(err)}`,\n };\n }\n}\n\n/**\n * Quantas vezes a sondagem REAL rodou neste processo.\n *\n * Instrumentado aqui, e não num wrapper, porque é aqui que o custo está: cada `which` dispara um\n * subprocesso (`which bwrap`), e a sondagem completa custava 22,2 ms. Um gate que conta probes\n * INJETADOS não vê a sondagem real — foi o primeiro erro do gate do M71, e um mutante o expôs.\n */\nlet sondagensReais = 0;\n\n/** Quantas sondagens reais rodaram. Seam de TESTE — o gate de performance conta isto. */\nexport function realProbeCount(): number {\n return sondagensReais;\n}\n\n/** Real probes used in production. */\nexport const realProbes: BwrapProbes = {\n which: () => {\n sondagensReais++;\n try {\n const out = execFileSync(\"which\", [\"bwrap\"], { encoding: \"utf8\", timeout: 2_000 }).trim();\n // anti-hijack: never accept a bwrap that lives inside the workspace (bwrap.rs:168-191)\n if (!out || out.startsWith(process.cwd() + path.sep)) return null;\n return out;\n } catch {\n return null;\n }\n },\n helpText: (bin) => {\n try {\n // bwrap --help exits 0/1 depending on version; capture output either way\n return execFileSync(bin, [\"--help\"], { encoding: \"utf8\", timeout: 2_000 });\n } catch (err) {\n const e = err as { stdout?: string; stderr?: string };\n return [e.stdout, e.stderr].filter(Boolean).join(\"\\n\") || null;\n }\n },\n userns: (bin) => {\n try {\n // active probe, 500ms budget like Codex (sandboxing/src/bwrap.rs:74-136)\n execFileSync(bin, [\"--unshare-user\", \"--unshare-net\", \"--ro-bind\", \"/\", \"/\", \"/bin/true\"], {\n timeout: 500,\n stdio: \"ignore\",\n });\n return true;\n } catch {\n return false;\n }\n },\n};\n\n/**\n * O resultado da sondagem, memoizado pelo tempo de vida do PROCESSO.\n *\n * Medido antes do M71: `detectBwrap()` custa **22,2 ms** e não era memoizada — a segunda chamada\n * custava 19,4 ms. `buildChatAgent` no caminho headless disparava **duas** (uma por\n * `createSandboxBackend`, outra por `resolveSandboxPosture`, que o M70 acrescentou), somando 46,4 ms\n * por construção — e a construção acontece por turno. Em `strace`, ~90% dos 182 syscalls de uma\n * construção já aquecida vinham daqui: `which` varrendo o PATH, `/proc/filesystems`, `/newroot`, e os\n * `.so` que os dois subprocessos de sonda carregam.\n *\n * ## Por que sem invalidação\n *\n * O milestone mandava invalidar no `SessionStart`. Não funciona: `agents/lib/hooks/hooks.ts:28-30`\n * documenta — como correção **medida** de uma suposição anterior — que esse evento dispara **uma vez\n * por TURNO**, não por sessão. Invalidar ali re-sondaria a cada turno, exatamente o comportamento que\n * a memoização existe para eliminar.\n *\n * A referência também não invalida: o único cache real do Codex é um `OnceLock` write-once\n * (`codex-rs/linux-sandbox/src/launcher.rs:52`), e sua sondagem cara roda uma vez por processo,\n * apenas para imprimir um aviso de UI (`sandboxing/src/bwrap.rs:40-72`).\n *\n * **O preço, dito na cara — nos DOIS sentidos.** O m71-custo-por-turn#ADR-1 original só declarou um deles; o review do\n * M71 (F-perf-9) mostrou que o omitido era justamente o que tem consequência de segurança:\n *\n * - **Negativo obsoleto** (`bwrap` instalado DEPOIS): não é detectado até reiniciar. O sistema falha\n * FECHADO — a postura reporta `enforced: false` e o veto do M70 **recusa**. Custo: irritação (a\n * mensagem manda instalar o bwrap que a pessoa acabou de instalar). Aceito.\n * - **Positivo obsoleto** (`bwrap` removido/renomeado DEPOIS): a postura continuaria afirmando\n * `enforced: true / \"kernel (bwrap)\"` e o veto **aprovaria** citando um confinamento que já não\n * existe. Isso é a reintrodução literal do defeito que o M70 corrigiu — *\"dizer ao operador que ele\n * está protegido quando não está é pior do que não dizer nada\"*. Antes do M71 a re-sondagem por\n * turno fechava essa janela no turno seguinte; a memoização a deixaria aberta pelo processo inteiro.\n * **Por isso o positivo é revalidado** abaixo, a 1 syscall — 3 ordens de grandeza abaixo dos 22,2 ms\n * da sondagem completa, que é o custo que a memoização existe para eliminar.\n */\nlet memo: BwrapDetection | undefined;\n\n/**\n * `detectBwrap` com memoização — o que a produção deve chamar.\n *\n * Note que `detectBwrap` em si **não** memoiza, de propósito: ele aceita probes injetados, e memoizar\n * ali faria um teste com probes falsos envenenar o cache do processo para todos os outros.\n *\n * A revalidação do positivo NÃO é uma re-sondagem: `detectBwrap` gasta três probes (subprocesso\n * `which` + `--help` + namespace de usuário). Aqui só se confirma que o binário validado continua no\n * lugar. Se sumiu, o memo é rebaixado a negativo com o motivo dito — nunca promovido a positivo, que\n * exigiria a sondagem cara de volta.\n */\nexport function detectBwrapMemoizado(probes: BwrapProbes = realProbes): BwrapDetection {\n memo ??= detectBwrap(probes);\n if (memo.ok && !existsSync(memo.bin)) {\n memo = { ok: false, reason: `bwrap disappeared from ${memo.bin} after detection` };\n }\n return memo;\n}\n\n/** Seam de TESTE — limpa o memo. Produção nunca chama (ver m71-custo-por-turn#ADR-1). */\nexport function resetBwrapMemo(): void {\n memo = undefined;\n}\n","/**\n * Canonical secret redaction module (ADRs D68-D73).\n *\n * Single source of truth for credential pattern masking across the SDK.\n * Wired at output boundaries: `ErrorMetadata.raw` (mappers/shared.ts),\n * telemetry span attributes (telemetry/tracer.ts), transcript JSONL\n * appends (agent-session-store.ts), migration logger output\n * (memory/migrate-sqlite-to-lance.ts).\n *\n * - D68: central module, single source of truth (replaces 2 duplicates)\n * - D69: env snapshot at module init (prompt-injection defense)\n * - D70: ON by default, warn on opt-out\n * - D71: two-bucket masking — short fully masked, long preserves prefix+suffix\n * - D72: `codeFile` opt-out for legitimate prefix-shaped content\n * - D73: redact at OUTPUT boundaries, not at storage\n *\n * @internal\n */\n\n// D69: env snapshot captured at module load. Subsequent mutations of\n// process.env.THEOKIT_REDACT_SECRETS are ignored — defends against\n// prompt injection that tries to disable redaction mid-run.\nlet REDACT_ENABLED: boolean = readEnvOnce();\n\nfunction readEnvOnce(): boolean {\n const raw = process.env.THEOKIT_REDACT_SECRETS;\n if (raw === undefined) return true; // D70: default ON\n return [\"1\", \"true\", \"yes\", \"on\"].includes(raw.toLowerCase());\n}\n\n// D70: warn once on opt-out so the user knows they're vulnerable.\nlet warnedOptOut = false;\nif (!REDACT_ENABLED && !warnedOptOut) {\n process.stderr.write(\n \"[theokit-sdk] Secret redaction is DISABLED via THEOKIT_REDACT_SECRETS. \" +\n \"Credentials may leak into errors, telemetry, logs, transcripts.\\n\",\n );\n warnedOptOut = true;\n}\n\n/**\n * Built-in credential patterns. Order matters — more specific prefixes\n * must come before generic ones (e.g., `sk-ant-` before `sk-`). Quantifiers\n * are all bounded `{n,m}` or applied to char classes — linear time, no ReDoS.\n *\n * @internal\n */\nconst BUILTIN_PATTERNS: readonly RegExp[] = [\n // T5.4: 30+ vendor prefixes (was 12 pre-T5.4). Order matters — more\n // specific prefixes precede generic ones (e.g., sk-ant-admin01 before\n // sk-ant-, sk-proj- before sk-). PEM block deliberately first so its\n // multi-line span runs before any per-line patterns can fire.\n /-----BEGIN[ ]+(?:RSA |EC |DSA |OPENSSH |ENCRYPTED |)PRIVATE KEY-----[\\s\\S]+?-----END[ ]+(?:RSA |EC |DSA |OPENSSH |ENCRYPTED |)PRIVATE KEY-----/g,\n // JWT — exact 3-segment base64url. Dotted; the body floor of 4 chars per\n // segment matches the minimum legal payload while skipping `a.b.c` noise.\n /eyJ[A-Za-z0-9_-]{4,}\\.eyJ[A-Za-z0-9_-]{4,}\\.[A-Za-z0-9_-]{4,}/g,\n // Azure Storage SAS — match the sig= component (URL-encoded base64).\n /(?<=[?&]sig=)[A-Za-z0-9%+/]{20,}/g,\n // Anthropic\n /sk-ant-admin01-[A-Za-z0-9_-]{10,}/g, // Anthropic admin keys (must precede sk-ant-)\n /sk-ant-[A-Za-z0-9_-]{10,}/g, // Anthropic regular\n // OpenAI family + clones (sk- generic must come AFTER all sk-foo- variants)\n /sk-proj-[A-Za-z0-9_-]{10,}/g, // OpenAI project key (must precede sk- generic)\n /sk-[A-Za-z0-9_-]{10,}/g, // OpenAI / OpenRouter / DeepInfra / Together / DeepSeek\n // Provider prefixes (alphabetized for maintainability)\n /AIza[A-Za-z0-9_-]{35}/g, // Google API key\n /AKIA[A-Z0-9]{16}/g, // AWS access key\n /fw_[A-Za-z0-9]{20,}/g, // Fireworks\n /glpat-[A-Za-z0-9_-]{20}/g, // GitLab PAT\n /ghp_[A-Za-z0-9]{36}/g, // GitHub PAT classic\n /github_pat_[A-Za-z0-9_]{82}/g, // GitHub PAT fine-grained\n /gsk_[A-Za-z0-9]{20,}/g, // Groq\n /hf_[A-Za-z0-9]{20,}/g, // HuggingFace\n /\\bpa-[A-Za-z0-9_-]{20,}/g, // Voyage AI (word-boundary to skip CSS / kebab IDs)\n /pcsk_[A-Za-z0-9_-]{20,}/g, // Pinecone\n /pplx-[A-Za-z0-9_-]{20,}/g, // Perplexity\n /r8_[A-Za-z0-9_-]{20,}/g, // Replicate\n /rk_live_[A-Za-z0-9]{20,}/g, // Stripe restricted\n /sk_live_[A-Za-z0-9]{20,}/g, // Stripe secret\n /sntrys_[A-Za-z0-9]{40,}/g, // Sentry user auth\n /xai-[A-Za-z0-9_-]{20,}/g, // xAI (Grok)\n /xox[bpasr]-[A-Za-z0-9-]{10,}/g, //Slack tokens\n // Additional unique-prefix tokens with low false-positive risk\n /npm_[A-Za-z0-9]{36}/g, // npm access token\n /SG\\.[A-Za-z0-9_-]{22}\\.[A-Za-z0-9_-]{43}/g, // SendGrid\n /\\bSK[A-Za-z0-9]{32}\\b/g, // Twilio API SID (word-boundary to skip CSS class noise)\n /\\bkey-[a-f0-9]{32}\\b/g, // Mailgun (hex-only narrows false positives)\n /MT[A-Za-z0-9_-]{23}\\.[A-Za-z0-9_-]{6}\\.[A-Za-z0-9_-]{27}/g, // Discord bot\n /\\b(?:sdk|mob)-[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}\\b/g, // LaunchDarkly\n];\n\n// `Bearer <token>` matched as its own first-class pattern so PARAM_PATTERN\n// doesn't have to handle the unusual `Authorization: Bearer xxx` shape\n// (no `:` or `=` between \"Bearer\" and the value — bare whitespace).\nconst BEARER_PATTERN = /\\b(Bearer\\s+)([A-Za-z0-9_\\-.+/=]{8,})/g;\n\n// Parametric: matches `key=value` and `key: value` (with optional quote\n// between the key and the separator, to handle JSON: `\"api_key\": \"...\"`)\n// in URLs, query strings, JSON-like bodies, HTTP headers. Captures the\n// prefix so we keep it visible while masking the value.\n//\n// `authorization` deliberately excluded — BEARER_PATTERN handles the\n// common `Authorization: Bearer xxx` shape. Including it here causes\n// double-masking (\"Authorization: *** ***\") after Bearer fires.\n// T5.4: keyword set expanded from 6 → 16 to cover the OAuth / JWT / generic\n// credential vocabulary surfaced by DR6 finding #4. `authorization`,\n// `auth`, `bearer` stay excluded — BEARER_PATTERN handles the\n// `Authorization: Bearer xxx` shape and including these here would\n// re-catch the post-BUILTIN-masked form (D71 prefix-preservation\n// contract) and double-mask to `***`.\n//\n// Value class includes `.` so JWT / `.env` / dotted base64url values\n// match; the callback skips already-masked values (containing the\n// `...` D71 separator) to preserve the BUILTIN prefix-mask result.\nconst PARAM_PATTERN =\n /(\\b(?:access_token|api_key|api-key|client_secret|credential|credentials|id_token|jwt|password|private_key|refresh_token|secret|service_account|session_token|token|x-api-key)\\b[\"']?\\s*[:=]\\s*[\"']?)([A-Za-z0-9_\\-.+/]+)/gi;\n\nconst _extraPatterns: RegExp[] = [];\n\n/**\n * Add a user-defined redaction pattern. Additive — never removes builtins.\n * Throws if the regex lacks the `/g` flag (without `/g`, `.replace` only\n * substitutes the first match and the rest leaks).\n *\n * @internal — exposed publicly via `Security.addPattern` in `src/security.ts`.\n */\nexport function addPattern(re: RegExp): void {\n if (!re.global) {\n throw new Error(\"Security.addPattern: regex must have /g flag for replace-all semantics\");\n }\n _extraPatterns.push(re);\n}\n\n/**\n * Two-bucket masking (D71):\n * - tokens shorter than 18 chars → fully masked as `***`\n * - tokens >= 18 chars → keep first 6 + `...` + last 4\n *\n * Rationale: long tokens are unique per-account; prefix+suffix preserves\n * debuggability without revealing the secret middle.\n *\n * @internal\n */\nexport function maskToken(token: string): string {\n if (token.length < 18) return \"***\";\n return `${token.slice(0, 6)}...${token.slice(-4)}`;\n}\n\n// issue #117 — the EXACT shape of a `maskToken` output (`slice(0,6)+\"...\"+slice(-4)`\n// = 6 chars, literal `...`, 4 chars). Used to detect a value PARAM_PATTERN would\n// otherwise re-mask, WITHOUT skipping a raw secret that merely contains `...`.\nconst MASK_SHAPE = /^.{6}\\.\\.\\..{4}$/s;\n\n/**\n * Redact known credential patterns from `text`. Default behavior masks\n * builtins + extras + parametric `key=value` sinks.\n *\n * With `{ codeFile: true }` (D72), skips PARAM_PATTERN to avoid mangling\n * `.env.example`, schema JSON, or test fixtures that legitimately contain\n * prefix-like strings.\n *\n * Returns the redacted string. Coerces non-strings via JSON.stringify;\n * EC-7 fix (edge-case review): wraps in try/catch so circular references\n * never propagate — returns sentinel `\"[unredactable: circular]\"`.\n *\n * @internal\n */\n// Coerce arbitrary input to a string for redaction. Returns `null`\n// sentinel when the value is null/undefined/non-stringifiable, so the\n// caller can short-circuit with `\"\"`. EC-7 fix: circular refs go through\n// the try/catch and produce the sentinel marker, never throwing.\nfunction coerceToString(value: unknown): string | null {\n if (typeof value === \"string\") return value;\n if (value === null || value === undefined) return null;\n if (typeof value === \"object\") {\n try {\n const s = JSON.stringify(value);\n return s === undefined ? null : s;\n } catch {\n return \"[unredactable: circular]\";\n }\n }\n return String(value);\n}\n\nexport function redactSecrets(text: unknown, opts?: { codeFile?: boolean }): string {\n const coerced = coerceToString(text);\n if (coerced === null) return \"\";\n if (!REDACT_ENABLED) return coerced;\n\n let s = coerced;\n for (const re of BUILTIN_PATTERNS) {\n s = s.replace(re, (m) => maskToken(m));\n }\n for (const re of _extraPatterns) {\n s = s.replace(re, (m) => maskToken(m));\n }\n if (!opts?.codeFile) {\n // Bearer first (preserves \"Bearer \" prefix, masks the token after).\n // Must run before PARAM_PATTERN so the bare-whitespace shape doesn't\n // get mis-handled as a value.\n s = s.replace(BEARER_PATTERN, (_, prefix: string) => `${prefix}***`);\n // T5.4: skip if value already contains the D71 bucket-mask separator\n // (`...`) — BUILTIN ran first and produced a prefix-preserved mask;\n // re-masking would lose the prefix and degrade debuggability.\n s = s.replace(PARAM_PATTERN, (whole, prefix: string, value: string) => {\n // issue #117 — skip ONLY when the value is already a mask that a BUILTIN\n // pattern produced (maskToken's exact `6chars...4chars` shape), so we don't\n // re-mask and lose the prefix. The old `value.includes(\"...\")` was too broad:\n // a REAL secret that happens to contain `...` (e.g. `L_-cxw-.2UI_..._`) was\n // skipped and LEAKED. The mask shape is exact (maskToken: slice(0,6)+\"...\"+\n // slice(-4)), so a raw secret with `...` elsewhere is now masked.\n if (MASK_SHAPE.test(value)) return whole;\n return `${prefix}***`;\n });\n }\n return s;\n}\n\n/**\n * Test-only helper exported for `_test-reset.ts`. NOT included in the\n * `index.ts` barrel — vitest setup imports the dedicated module via\n * explicit path to discourage production callers.\n *\n * @internal\n */\nexport function _resetForTests(opts: { enabled?: boolean; clearExtras?: boolean }): void {\n if (opts.enabled !== undefined) REDACT_ENABLED = opts.enabled;\n if (opts.clearExtras === true) _extraPatterns.length = 0;\n}\n\n/**\n * T5.4 — Test-only count of BUILTIN_PATTERNS. Exposed so the count-floor\n * assertion can run without re-deriving the array shape in test land.\n * NOT included in the public barrel.\n *\n * @internal\n */\nexport function __TESTING__BUILTIN_PATTERN_COUNT(): number {\n return BUILTIN_PATTERNS.length;\n}\n","/**\n * Child-process environment policy (#54).\n *\n * Every subprocess the SDK spawns previously inherited the FULL `process.env`,\n * so API keys, tokens and passwords leaked into hook scripts and shell tools.\n * `resolveChildEnv` computes the env a child receives under an explicit policy,\n * modeled on codex's `ShellEnvironmentPolicy`\n * (referencia: codex/codex-rs/protocol/src/shell_environment.rs).\n *\n * Modes:\n * - `inherit-scrubbed` (DEFAULT) — inherit all parent vars EXCEPT secret-like\n * names (`*KEY*`, `*SECRET*`, `*TOKEN*`, `*PASSWORD*`, `*_AUTH*`). Non-breaking:\n * existing spawns keep every non-secret var; only secrets stop leaking.\n * - `core` — inherit ONLY a safe base allowlist (PATH/HOME/…); strongest scrub.\n * - `all` — explicit opt-out: inherit everything, secrets included.\n *\n * Explicit `overrides` ALWAYS win (merged last), so a tool can re-inject a var\n * it genuinely needs even under a scrubbing policy.\n *\n * @internal\n */\n\nimport type { EnvPolicy } from \"../../../types/env-policy.js\";\n\n// The `EnvPolicy` contract now lives in the domain `types/` layer (SE46 DIP\n// direction). Re-exported here so existing importers of this module keep\n// resolving the same name.\nexport type { EnvPolicy } from \"../../../types/env-policy.js\";\n\nexport interface ResolveChildEnvOptions {\n /** Source env to derive from. Defaults to `process.env`. */\n parent?: Record<string, string | undefined>;\n /** Inherit/scrub policy. Defaults to `inherit-scrubbed`. */\n policy?: EnvPolicy;\n /** Explicit vars merged AFTER the policy — always win. */\n overrides?: Record<string, string>;\n}\n\n/**\n * Secret-like variable-name patterns (case-insensitive). A parent var whose\n * name matches any of these is dropped under `inherit-scrubbed`. Conservative\n * by design — see the EC-4 false-positive test. `[_-]PWD` (not bare `PWD`)\n * catches `DB_PWD` without dropping the shell's working-directory `PWD`.\n * `CREDENTIAL` catches `GOOGLE_APPLICATION_CREDENTIALS`. #54-a extends the list to\n * the highest-signal VALUE-embedded-secret conventions — connection strings that\n * carry `user:password@` (`DATABASE_URL`, `REDIS_URL`, `MONGODB_URI`, `DB_URL`, …),\n * `DSN`, `WEBHOOK`, `COOKIE`, and `CONNECTION_STRING` — while deliberately NOT\n * dropping generic non-secret URLs (`PUBLIC_BASE_URL`, `API_URL`, `PGHOST`). A\n * denylist still cannot catch EVERY value-embedded secret — for untrusted children\n * use policy `\"core\"` (allowlist), the only fail-closed mode.\n */\nconst SECRET_PATTERNS: readonly RegExp[] = [\n /KEY/i,\n /SECRET/i,\n /TOKEN/i,\n /PASSWORD/i,\n /PASSWD/i,\n /PASSPHRASE/i,\n /[_-]PWD/i,\n /CREDENTIAL/i,\n /PRIVATE/i,\n /_AUTH/i,\n // #54-a — value-embedded-secret conventions (no generic `*_URL` — see keep-list test).\n /DSN/i,\n /WEBHOOK/i,\n /COOKIE/i,\n /CONNECTION[_-]?STRING/i,\n // Known DB / message-broker connection-string vars (carry `user:pass@`).\n /(?:^|[_-])(?:DATABASE|DB|REDIS|MONGO(?:DB)?|POSTGRES(?:QL)?|MYSQL|MARIADB|AMQP|RABBITMQ|CLICKHOUSE|ELASTIC(?:SEARCH)?|CASSANDRA|COUCHDB|MEMCACHED|NATS|KAFKA)[_-]?(?:URL|URI|DSN|CONNECTION)/i,\n];\n\n/**\n * Safe base variables kept under the `core` policy. Process-hygiene vars a\n * child almost always needs; none are secret-bearing.\n */\nconst CORE_VARS: readonly string[] = [\n \"PATH\",\n \"HOME\",\n \"SHELL\",\n \"LANG\",\n \"LC_ALL\",\n \"LC_CTYPE\",\n \"TMPDIR\",\n \"TMP\",\n \"TEMP\",\n \"USER\",\n \"LOGNAME\",\n];\n\nfunction isSecretName(name: string): boolean {\n return SECRET_PATTERNS.some((re) => re.test(name));\n}\n\n/** Whether a parent var of the given name is inherited under `policy`. */\nfunction inheritsUnderPolicy(name: string, policy: EnvPolicy): boolean {\n if (policy === \"all\") return true;\n if (policy === \"core\") return CORE_VARS.includes(name);\n return !isSecretName(name); // inherit-scrubbed\n}\n\nexport function resolveChildEnv(options: ResolveChildEnvOptions = {}): Record<string, string> {\n const parent = options.parent ?? process.env;\n const policy = options.policy ?? \"inherit-scrubbed\";\n\n const base: Record<string, string> = {};\n for (const [name, value] of Object.entries(parent)) {\n if (value !== undefined && inheritsUnderPolicy(name, policy)) base[name] = value;\n }\n\n // Explicit overrides always win — even over a scrub.\n for (const [name, value] of Object.entries(options.overrides ?? {})) {\n base[name] = value;\n }\n return base;\n}\n","/**\n * POSIX shell escaping for values interpolated into a `SandboxBackend.execute`\n * command string. `execute` runs via `/bin/sh -c`, so any untrusted value\n * (repo URL, ref, path) MUST be quoted to prevent command injection.\n *\n * @internal\n */\n\n/** Wrap `arg` in single quotes, escaping embedded single quotes (`'\\''`). */\nexport function shellEscapePosix(arg: string): string {\n return `'${arg.replace(/'/g, \"'\\\\''\")}'`;\n}\n","/**\n * Sandbox backend protocol — pluggable execution environment for agent tools.\n *\n * Per ADR D1: only 2 abstract methods (`execute` + `uploadFile`). All\n * higher-level operations are derived on the base class. New backends\n * (Docker, Firecracker, E2B) only implement those 2 methods.\n *\n * @public\n */\n\nimport type { EnvPolicy } from \"../types/env-policy.js\";\nimport { shellEscapePosix } from \"./shell-escape.js\";\n\nexport interface ExecuteResult {\n stdout: string;\n stderr: string;\n exitCode: number;\n timedOut: boolean;\n}\n\nexport interface SandboxConfig {\n workDir?: string;\n timeoutMs?: number;\n maxOutputBytes?: number;\n /**\n * #54 — env inherit/scrub policy for the executed command's child process.\n * Defaults to `\"inherit-scrubbed\"` (drop secret-like vars: `*KEY*`, `*SECRET*`,\n * `*TOKEN*`, `*PASSWORD*`, `*_AUTH*`). Pass `\"all\"` to restore full inheritance\n * or `\"core\"` for a minimal safe allowlist.\n */\n env?: EnvPolicy;\n}\n\nexport class SandboxSecurityError extends Error {\n readonly code = \"sandbox_security\" as const;\n constructor(message: string) {\n super(message);\n this.name = \"SandboxSecurityError\";\n }\n}\n\nexport class SandboxNotAvailableError extends Error {\n readonly code = \"sandbox_not_available\" as const;\n constructor(message: string) {\n super(message);\n this.name = \"SandboxNotAvailableError\";\n }\n}\n\nexport abstract class SandboxBackend {\n protected config: SandboxConfig;\n\n constructor(config: SandboxConfig = {}) {\n this.config = {\n workDir: config.workDir ?? \"/tmp\",\n timeoutMs: config.timeoutMs ?? 30_000,\n maxOutputBytes: config.maxOutputBytes ?? 5 * 1024 * 1024,\n // #54 — preserve the env policy so backends can scrub secrets.\n env: config.env ?? \"inherit-scrubbed\",\n };\n }\n\n abstract execute(command: string, opts?: { timeoutMs?: number }): Promise<ExecuteResult>;\n\n abstract uploadFile(path: string, content: string | Buffer): Promise<void>;\n\n async readFile(path: string): Promise<string> {\n const result = await this.execute(`cat ${this.shellEscape(path)}`);\n if (result.exitCode !== 0) {\n throw new Error(`readFile failed: ${result.stderr}`);\n }\n return result.stdout;\n }\n\n async writeFile(path: string, content: string): Promise<void> {\n await this.uploadFile(path, content);\n }\n\n async glob(pattern: string, cwd?: string): Promise<string[]> {\n const dir = cwd ?? this.config.workDir ?? \".\";\n const result = await this.execute(\n `find ${this.shellEscape(dir)} -name ${this.shellEscape(pattern)} -type f 2>/dev/null`,\n );\n if (result.exitCode !== 0) return [];\n return result.stdout.trim().split(\"\\n\").filter(Boolean);\n }\n\n async grep(pattern: string, path?: string): Promise<string[]> {\n const target = path ?? \".\";\n const result = await this.execute(\n `grep -rn ${this.shellEscape(pattern)} ${this.shellEscape(target)} 2>/dev/null`,\n );\n if (result.exitCode !== 0) return [];\n return result.stdout.trim().split(\"\\n\").filter(Boolean);\n }\n\n async listDir(path: string): Promise<string[]> {\n const result = await this.execute(`ls -1 ${this.shellEscape(path)}`);\n if (result.exitCode !== 0) return [];\n return result.stdout.trim().split(\"\\n\").filter(Boolean);\n }\n\n protected truncateOutput(output: string): string {\n const max = this.config.maxOutputBytes ?? 5 * 1024 * 1024;\n if (Buffer.byteLength(output) > max) {\n return `${output.slice(0, max)}\\n...(truncated)`;\n }\n return output;\n }\n\n private shellEscape(arg: string): string {\n return shellEscapePosix(arg);\n }\n}\n\n/**\n * A backend OR a per-request resolver of one — mirrors `FilesystemProvider` / `InteractiveProvider`.\n * A resolver runs at tool-execution time (request scope), so a multi-tenant / multi-role agent gets a\n * distinct sandbox per request without a shared mutable one. This is how a tool takes execution as an\n * INJECTED capability: the same tool runs on a local sandbox, a container/E2B backend (cluster/web), or\n * any future backend, with no direct `child_process` import.\n *\n * @public\n */\nexport type SandboxProvider<Ctx = unknown> =\n | SandboxBackend\n | ((ctx: Ctx) => SandboxBackend | Promise<SandboxBackend>);\n\n/** Resolve a {@link SandboxProvider} to a concrete backend for `ctx`. */\nexport async function resolveSandbox<Ctx>(\n provider: SandboxProvider<Ctx>,\n ctx: Ctx,\n): Promise<SandboxBackend> {\n return provider instanceof SandboxBackend ? provider : provider(ctx);\n}\n","/**\n * LocalSandbox — subprocess-based execution. **This is NOT an isolation\n * boundary.** It runs the command via `/bin/sh -c` in the SAME OS as the host\n * with the host's filesystem and network fully reachable — it provides NO\n * process, filesystem, or network isolation. Its only safety affordances are:\n * - a wall-clock timeout (kills a runaway command),\n * - an output-size cap (bounds memory), and\n * - env scrubbing (#54): secret-like parent env vars (`*KEY*`/`*SECRET*`/\n * `*TOKEN*`/`*PASSWORD*`/`*_AUTH*`) are dropped from the child by default\n * (`SandboxConfig.env`), so a shell tool cannot exfiltrate host secrets via\n * the environment.\n *\n * For real isolation (untrusted code), use a container/VM backend — NOT this.\n *\n * @public\n */\n\nimport { execFile } from \"node:child_process\";\nimport { writeFile as fsWriteFile, mkdir } from \"node:fs/promises\";\nimport { dirname } from \"node:path\";\n\nimport { resolveChildEnv } from \"../internal/runtime/lifecycle/env-policy.js\";\nimport { type ExecuteResult, SandboxBackend, type SandboxConfig } from \"./types.js\";\n\nexport class LocalSandbox extends SandboxBackend {\n constructor(config: SandboxConfig = {}) {\n super(config);\n }\n\n async execute(command: string, opts?: { timeoutMs?: number }): Promise<ExecuteResult> {\n const timeout = opts?.timeoutMs ?? this.config.timeoutMs ?? 30_000;\n const max = this.config.maxOutputBytes ?? 5 * 1024 * 1024;\n\n return new Promise<ExecuteResult>((resolve) => {\n const child = execFile(\n \"/bin/sh\",\n [\"-c\", command],\n {\n cwd: this.config.workDir,\n timeout,\n maxBuffer: max,\n encoding: \"utf-8\",\n // #54 — scrub secret-like host env vars from the child by default.\n env: resolveChildEnv({ policy: this.config.env }),\n },\n (error, stdout, stderr) => {\n resolve(this.buildResult(error, stdout ?? \"\", stderr ?? \"\"));\n },\n );\n\n // Safety: if child somehow doesn't callback\n child.on(\"error\", () => {\n resolve({ stdout: \"\", stderr: \"spawn error\", exitCode: 1, timedOut: false });\n });\n });\n }\n\n private buildResult(error: Error | null, stdout: string, stderr: string): ExecuteResult {\n const timedOut = error !== null && \"killed\" in error && (error as { killed: boolean }).killed;\n return {\n stdout: this.truncateOutput(stdout),\n stderr: this.truncateOutput(stderr),\n exitCode: timedOut ? 124 : error ? 1 : 0,\n timedOut,\n };\n }\n\n async uploadFile(path: string, content: string | Buffer): Promise<void> {\n const fullPath = path.startsWith(\"/\") ? path : `${this.config.workDir}/${path}`;\n await mkdir(dirname(fullPath), { recursive: true });\n await fsWriteFile(fullPath, content, \"utf-8\");\n }\n}\n","// Promovido do agent-builder no M75 (plano m75-sandbox-kernel-no-framework, D1): confinamento de\n// kernel e infraestrutura do framework, nao do consumidor. Custo medido da promocao: ZERO\n// dependencias — so node:child_process, node:fs e node:path. O filtro cBPF e um Buffer em JS puro.\n\n/**\n * M63 — cBPF seccomp filter generator, byte-faithful to Codex's Linux sandbox\n * (`codex-rs/linux-sandbox/src/landlock.rs:179-216`). Produces a raw `sock_filter[]` program (the exact\n * shape `bwrap --seccomp <fd>` consumes) so agent-builder ports Codex's syscall confinement WITHOUT a\n * native helper — bwrap applies `PR_SET_NO_NEW_PRIVS` + the filter before `execve`.\n *\n * Semantics (landlock.rs:252-253): default action = ALLOW; per-syscall match = ERRNO(EPERM). KILL is\n * used ONLY by the architecture/x32 guard. x86_64 only in v1 (aarch64 is a documented delta).\n */\n\n// BPF opcodes (linux/bpf_common.h)\nconst BPF_LD = 0x00;\nconst BPF_W = 0x00;\nconst BPF_ABS = 0x20;\nconst BPF_JMP = 0x05;\nconst BPF_JEQ = 0x10;\nconst BPF_JGE = 0x30;\nconst BPF_K = 0x00;\nconst BPF_RET = 0x06;\n\nconst LD_ABS_W = BPF_LD | BPF_W | BPF_ABS; // 0x20\nconst JEQ_K = BPF_JMP | BPF_JEQ | BPF_K; // 0x15\nconst JGE_K = BPF_JMP | BPF_JGE | BPF_K; // 0x35\nconst RET_K = BPF_RET | BPF_K; // 0x06\n\n// seccomp_data offsets (little-endian): nr@0, arch@4, args[0] low dword @16\nconst OFF_NR = 0;\nconst OFF_ARCH = 4;\nconst OFF_ARG0 = 16;\n\nconst AUDIT_ARCH_X86_64 = 0xc000003e;\nconst X32_BIT = 0x40000000; // nr >= this ⇒ x32 ABI ⇒ reject\n\n// seccomp return actions (linux/seccomp.h)\nconst SECCOMP_RET_ALLOW = 0x7fff0000;\nconst SECCOMP_RET_ERRNO = 0x00050000;\nconst EPERM = 1;\nconst RET_EPERM = SECCOMP_RET_ERRNO | (EPERM & 0xffff); // 0x00050001\nconst SECCOMP_RET_KILL_PROCESS = 0x80000000;\n\nconst AF_UNIX = 1;\n\n/** Always-denied, network-independent (landlock.rs:179-184). */\nconst ALWAYS_DENIED = [101, 310, 311, 425, 426, 427]; // ptrace, process_vm_readv/writev, io_uring_setup/enter/register\n/** Denied only when the network is restricted (landlock.rs:188-204). recvfrom(45)/sendmsg(46) are NOT here. */\nconst NETWORK_DENIED = [42, 43, 288, 49, 50, 52, 51, 48, 44, 307, 299, 55, 54];\n/** socket(2) / socketpair(2) — conditional on domain != AF_UNIX (landlock.rs:206-216). */\nconst SOCKET_SYSCALLS = [41, 53];\n\n/** One `sock_filter` instruction: `{u16 code, u8 jt, u8 jf, u32 k}`. */\ninterface Insn {\n code: number;\n jt: number;\n jf: number;\n k: number;\n}\nconst stmt = (code: number, k: number): Insn => ({ code, jt: 0, jf: 0, k });\nconst jmp = (code: number, k: number, jt: number, jf: number): Insn => ({ code, jt, jf, k });\n\nexport interface SeccompOptions {\n /** When true (network off), also deny the socket set + non-AF_UNIX socket(). */\n networkRestricted: boolean;\n}\n\n/**\n * Build the cBPF seccomp program as a `Buffer` (each `sock_filter` = 8 bytes). Jump targets are\n * expressed against labels and back-patched to relative offsets, so the layout is deterministic and\n * unit-testable against the authoritative syscall list.\n */\nexport function buildSeccompFilter(opts: SeccompOptions): Buffer {\n // We assemble with symbolic targets, then resolve to relative jumps. To keep the classic\n // \"deny → jump to a single DENY return; else fall through\" shape, DENY and ALLOW live at the END and\n // every JEQ jumps FORWARD to them. jt/jf carry the DISTANCE (in instructions) to the target.\n const insns: Insn[] = [];\n\n // Placeholder labels resolved after we know total length.\n // Layout: [arch guard][x32 guard][LD nr][deny checks...][socket checks...][ALLOW][DENY][KILL]\n // We build the body first with jumps to ALLOW/DENY/KILL as sentinel indices, then patch.\n const ALLOW = Symbol(\"ALLOW\");\n const DENY = Symbol(\"DENY\");\n const KILL = Symbol(\"KILL\");\n type Target = typeof ALLOW | typeof DENY | typeof KILL | number;\n interface SInsn {\n code: number;\n k: number;\n jt: Target;\n jf: Target;\n }\n const body: SInsn[] = [];\n const push = (code: number, k: number, jt: Target = 0, jf: Target = 0): void => {\n body.push({ code, k, jt, jf });\n };\n\n // --- arch guard: arch == x86_64 ? continue : KILL ---\n push(LD_ABS_W, OFF_ARCH);\n push(JEQ_K, AUDIT_ARCH_X86_64, 0, KILL); // if != → KILL\n // --- x32 guard: nr >= 0x40000000 ? KILL : continue ---\n push(LD_ABS_W, OFF_NR);\n push(JGE_K, X32_BIT, KILL, 0); // if >= → KILL\n // nr already loaded; keep it loaded for the deny checks.\n\n // --- unconditional denials → DENY ---\n const denied = opts.networkRestricted\n ? [...ALWAYS_DENIED, ...NETWORK_DENIED]\n : [...ALWAYS_DENIED];\n for (const nr of denied) push(JEQ_K, nr, DENY, 0); // if nr == syscall → DENY\n\n // --- socket-family: socket(41)/socketpair(53) → allow only AF_UNIX (only when restricted) ---\n if (opts.networkRestricted) {\n for (const sysno of SOCKET_SYSCALLS) {\n // if nr == socket → check domain; else skip the 2 domain-check instructions\n push(JEQ_K, sysno, 0, 2); // match: fall through to the LD/JEQ; no-match: jump +2 (past them)\n push(LD_ABS_W, OFF_ARG0); // load domain (args[0] low dword)\n push(JEQ_K, AF_UNIX, ALLOW, DENY); // AF_UNIX → ALLOW, else DENY\n // NOTE: after these, nr is NO LONGER in the accumulator — but every remaining syscall check\n // reloads via a fresh LD? No: the remaining path is only ALLOW. socket checks are LAST before\n // the tail, so a fall-through (non-socket syscall that reached here) goes straight to ALLOW.\n }\n }\n\n // --- tail ---\n push(RET_K, SECCOMP_RET_ALLOW); // ALLOW label target\n const allowIdx = body.length - 1;\n push(RET_K, RET_EPERM); // DENY\n const denyIdx = body.length - 1;\n push(RET_K, SECCOMP_RET_KILL_PROCESS); // KILL\n const killIdx = body.length - 1;\n\n // --- resolve symbolic targets to relative offsets ---\n // A ramificacao E o programa cBPF: ALLOW/DENY/KILL sao alvos simbolicos resolvidos para\n // deslocamento RELATIVO a proxima instrucao. Quebrar em helpers nao reduz a complexidade real —\n // move o calculo de salto para outro arquivo e torna mais dificil auditar contra landlock.rs, a\n // fonte autoritativa.\n //\n // Nao refatorar AGORA e decisao de processo do M75: esta funcao esta sendo MIGRADA sem mudanca de\n // comportamento (plano m75, D4) e ainda nao existe oraculo de equivalencia byte-a-byte contra a\n // versao original. Refatorar seguranca sem esse oraculo e trocar a fechadura no escuro.\n // Revisitar quando o gate de paridade (T4.2) estiver verde — ai o oraculo existe.\n // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: ver a razao logo acima\n const resolve = (i: number, t: Target): number => {\n const abs = t === ALLOW ? allowIdx : t === DENY ? denyIdx : t === KILL ? killIdx : i + 1 + t;\n // BPF jump offset is relative to the NEXT instruction: target - (i + 1)\n const off = abs - (i + 1);\n if (off < 0 || off > 255) throw new RangeError(`seccomp jump out of range at ${i}: ${off}`);\n return off;\n };\n // `for...of` com entries em vez de indice cru: o SDK compila com `noUncheckedIndexedAccess`, que\n // (corretamente) tipa `body[i]` como possivelmente indefinido. Iterar da a garantia no tipo em vez\n // de exigir um `!` — o codigo ja nao podia sair do intervalo, e agora o compilador sabe disso.\n for (const [i, b] of body.entries()) {\n if (b.code === JEQ_K || b.code === JGE_K) {\n insns.push(jmp(b.code, b.k, resolve(i, b.jt), resolve(i, b.jf)));\n } else {\n insns.push(stmt(b.code, b.k));\n }\n }\n\n const buf = Buffer.alloc(insns.length * 8);\n insns.forEach((ins, i) => {\n buf.writeUInt16LE(ins.code, i * 8);\n buf.writeUInt8(ins.jt, i * 8 + 2);\n buf.writeUInt8(ins.jf, i * 8 + 3);\n buf.writeUInt32LE(ins.k >>> 0, i * 8 + 4);\n });\n return buf;\n}\n","// Promovido do agent-builder no M75 (plano m75-sandbox-kernel-no-framework, D1). Renomeado de\n// `BwrapSandbox` para `LinuxSandbox`: bwrap e a IMPLEMENTACAO, Linux e o contrato — trocar o\n// mecanismo (landlock, por exemplo) nao deveria mudar o nome que o consumidor importa.\n\nimport { mkdtempSync, rmSync, writeFileSync } from \"node:fs\";\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\n\nimport { redactSecrets } from \"../internal/security/redact.js\";\nimport type { BwrapDetection, SandboxMode } from \"./bwrap.js\";\nimport { buildBwrapArgv, detectBwrapMemoizado } from \"./bwrap.js\";\nimport { LocalSandbox } from \"./local-sandbox.js\";\nimport { buildSeccompFilter } from \"./seccomp.js\";\nimport type { SandboxBackend, SandboxConfig } from \"./types.js\";\n\n/**\n * M53 — kernel-enforced sandbox backend, injected into `createShellTool({ sandbox })`.\n *\n * `LinuxSandbox extends LocalSandbox` and only REWRITES the command: `<bwrap-bin> <policy flags> --\n * /bin/sh -c '<original>'`. Everything else (spawn, output caps, timeout, ExecuteResult shape, file\n * ops) is inherited — the SDK backend stays the single execution engine. Mirrors Codex's\n * `SandboxManager::transform` (argv prefixing before spawn, never in-process).\n */\n\n/** POSIX single-quote escaping — the inner command crosses ONE extra `/bin/sh -c` boundary. */\nfunction shellQuote(s: string): string {\n return `'${s.replaceAll(\"'\", `'\\\\''`)}'`;\n}\n\n/**\n * M57 — the single source of truth for the sandbox command wrap. Turns `command` into\n * `<bin> <bwrap flags> [--seccomp 3] -- /bin/sh -c '<command>' [3< <bpf>]`, or `null` when the policy\n * skips the sandbox (`danger-full-access`). Extracted from `LinuxSandbox.wrapCommand` so the interactive\n * PTY backend (M57) can reuse the EXACT wrap the one-shot `run_shell` already uses (DRY) — faithful to\n * Codex, where the sandbox transforms the argv before the PTY spawns it (`sandboxing/src/manager.rs:321`).\n */\nexport function wrapCommandForSandbox(\n mode: SandboxMode,\n opts: {\n cwd: string;\n network?: boolean;\n env?: Record<string, string>;\n bin?: string;\n seccompPath?: string;\n },\n command: string,\n): string | null {\n const argv = buildBwrapArgv(mode, { cwd: opts.cwd, network: opts.network, env: opts.env });\n if (argv === null) return null; // danger-full-access: bwrap skipped\n const bin = opts.bin ?? \"bwrap\";\n const seccompArgv = opts.seccompPath !== undefined ? [\"--seccomp\", \"3\"] : [];\n const base = `${shellQuote(bin)} ${[...argv.slice(0, -1), ...seccompArgv, \"--\"].map(shellQuote).join(\" \")} /bin/sh -c ${shellQuote(command)}`;\n return opts.seccompPath !== undefined ? `${base} 3< ${shellQuote(opts.seccompPath)}` : base;\n}\n\n/**\n * Env allowlist re-injected inside the sandbox after `--clearenv`. Codex env_clear model: the child\n * gets exactly what it needs to run a shell, never the parent's full env (which may hold oddly-named\n * secrets the SDK name-pattern scrub misses). `CODEX_SANDBOX_NETWORK_DISABLED` is added by the argv\n * builder when network is unshared.\n */\nconst ENV_ALLOWLIST = [\n \"PATH\",\n \"HOME\",\n \"LANG\",\n \"LC_ALL\",\n \"LC_CTYPE\",\n \"TERM\",\n \"USER\",\n \"TMPDIR\",\n \"SHELL\",\n];\n\nexport function allowlistedEnv(source: NodeJS.ProcessEnv = process.env): Record<string, string> {\n const out: Record<string, string> = {};\n for (const k of ENV_ALLOWLIST) {\n const v = source[k];\n if (v !== undefined) out[k] = v;\n }\n return out;\n}\n\nexport class LinuxSandbox extends LocalSandbox {\n private readonly mode: SandboxMode;\n private readonly network: boolean;\n private readonly cwd: string;\n private readonly bin: string;\n private readonly env: Record<string, string>;\n /** M63 — path to the cBPF seccomp program written host-side; passed to `bwrap --seccomp 3` via a\n * shell redirect. `undefined` when the network is unrestricted OR generation failed (honest fallback). */\n private readonly seccompPath: string | undefined;\n\n constructor(\n config: SandboxConfig,\n opts: { mode: SandboxMode; network?: boolean; bin?: string; env?: Record<string, string> },\n ) {\n super(config);\n this.mode = opts.mode;\n this.network = opts.network ?? false;\n this.cwd = config.workDir ?? process.cwd();\n // MEDIUM-1: run the VALIDATED absolute binary from detection (anti-hijack), never bare `bwrap`\n // which the outer shell would re-resolve via $PATH at spawn time (TOCTOU / hijack window).\n this.bin = opts.bin ?? \"bwrap\";\n this.env = opts.env ?? allowlistedEnv();\n // Codex installs seccomp only when the network is restricted (landlock.rs:96-117); network on ⇒ none.\n this.seccompPath = this.network ? undefined : restrictedSeccompPath();\n }\n\n /** Extracted for test visibility — delegates to the pure `wrapCommandForSandbox` (M57, single wrap SoT). */\n wrapCommand(command: string): string | null {\n return wrapCommandForSandbox(\n this.mode,\n {\n cwd: this.cwd,\n network: this.network,\n env: this.env,\n bin: this.bin,\n seccompPath: this.seccompPath,\n },\n command,\n );\n }\n\n override execute(command: string, opts?: { timeoutMs?: number }) {\n const wrapped = this.wrapCommand(command);\n if (wrapped === null) return super.execute(command, opts); // danger-full-access: plain local\n return super.execute(wrapped, opts);\n }\n}\n\nlet warnedNonX64 = false;\n\n/**\n * M63 — the restricted-network seccomp program is DETERMINISTIC, so write it ONCE per process and\n * reuse the path across every LinuxSandbox (no per-instance temp accumulation).\n *\n * ARCH GUARD (review HIGH): `buildSeccompFilter` emits an x86_64 program whose arch guard KILLs every\n * syscall whose `seccomp_data.arch != AUDIT_ARCH_X86_64`. On a non-x86_64 host that would brick EVERY\n * sandboxed command (the first execve is killed) — and silently, because generation succeeds and bwrap\n * accepts it. So we REFUSE to install on non-x64 and WARN through the honest-downgrade channel (bwrap\n * FS/network confinement still applies), exactly like the bwrap-missing fallback. `arch` is injectable\n * for tests. Cleaned on exit AND on SIGINT/SIGTERM (TUI Ctrl+C would otherwise leak the temp dir).\n */\nexport function seccompPathForArch(arch: string, warn: (m: string) => void): string | undefined {\n if (arch !== \"x64\") {\n if (!warnedNonX64) {\n warnedNonX64 = true;\n warn(\n `[sandbox] seccomp syscall filter unsupported on ${arch} (x86_64 only in v1) — running without ` +\n \"the filter; bwrap FS/network confinement still applies.\",\n );\n }\n return undefined;\n }\n try {\n const dir = mkdtempSync(join(tmpdir(), \"ab-seccomp-\"));\n const path = join(dir, \"filter.bpf\");\n writeFileSync(path, buildSeccompFilter({ networkRestricted: true }));\n const cleanup = (): void => rmSync(dir, { recursive: true, force: true });\n process.once(\"exit\", cleanup);\n process.once(\"SIGINT\", cleanup);\n process.once(\"SIGTERM\", cleanup);\n return path;\n } catch (err) {\n warn(\n `[sandbox] seccomp filter unavailable (${err instanceof Error ? err.message : String(err)}) — ` +\n \"running without syscall filter (bwrap FS/network confinement still applies).\",\n );\n return undefined;\n }\n}\n\nlet seccompFilterPath: string | undefined | null; // undefined = not tried; null = resolved absent\n/** M57 — exported so the interactive PTY backend reuses the SAME memoized x64-gated seccomp program. */\nexport function restrictedSeccompPath(): string | undefined {\n if (seccompFilterPath !== undefined) return seccompFilterPath ?? undefined;\n const path = seccompPathForArch(process.arch, (m) => console.warn(redactSecrets(m)));\n seccompFilterPath = path ?? null;\n return path;\n}\n\nlet warnedUnavailable = false;\n\n/** Test seam: reset the WARN-once latch. */\nexport function resetSandboxWarnLatch(): void {\n warnedUnavailable = false;\n}\n\n/** Durable sandbox posture for the UI — the honest answer to \"am I kernel-enforced right now?\". */\nexport interface SandboxPosture {\n mode: SandboxMode;\n enforced: boolean;\n detail: string;\n}\n\n/**\n * MEDIUM-2: compute the posture so a surface (TUI footer) can show enforcement DURABLY instead of a\n * one-shot warn. `danger-full-access` is honestly reported as unenforced; an unavailable bwrap reports\n * the downgrade reason so the user never believes they are confined when they are not.\n */\nexport function resolveSandboxPosture(opts: {\n mode: SandboxMode;\n detect?: () => BwrapDetection;\n}): SandboxPosture {\n if (opts.mode === \"danger-full-access\") {\n return { mode: opts.mode, enforced: false, detail: \"no confinement (danger-full-access)\" };\n }\n const detection = (opts.detect ?? detectBwrapMemoizado)();\n if (!detection.ok) {\n return { mode: opts.mode, enforced: false, detail: `tool-gating only — ${detection.reason}` };\n }\n return { mode: opts.mode, enforced: true, detail: \"kernel (bwrap)\" };\n}\n\nexport interface CreateSandboxBackendOptions {\n mode: SandboxMode;\n workDir?: string;\n network?: boolean;\n timeoutMs?: number;\n /** Injectable for tests; defaults to the real 3-probe detection. */\n detect?: () => BwrapDetection;\n /** Injectable for tests; defaults to console.warn. */\n warn?: (message: string) => void;\n}\n\n/**\n * Honest factory: bwrap available + mode wants confinement → `LinuxSandbox` (kernel enforcement,\n * running the VALIDATED absolute bin); `danger-full-access` → plain `LocalSandbox` silently (explicit\n * opt-out, `bwrap.rs:245-252`); bwrap unavailable → WARN once + `LocalSandbox` (the declarative M23\n * gating remains the guard). NEVER pretends to sandbox — the fallback is loud, mirroring Codex's\n * MISSING_BWRAP_WARNING. The durable posture lives in `resolveSandboxPosture` for the UI.\n */\nexport function createSandboxBackend(opts: CreateSandboxBackendOptions): SandboxBackend {\n const config: SandboxConfig = { workDir: opts.workDir, timeoutMs: opts.timeoutMs };\n if (opts.mode === \"danger-full-access\") return new LocalSandbox(config);\n\n const detection = (opts.detect ?? detectBwrapMemoizado)();\n if (!detection.ok) {\n if (!warnedUnavailable) {\n warnedUnavailable = true;\n const warn = opts.warn ?? ((m: string) => console.warn(redactSecrets(m)));\n warn(\n `[sandbox] OS-level enforcement unavailable (${detection.reason}) — ` +\n `falling back to tool-level gating only (sandbox_mode=${opts.mode}).`,\n );\n }\n return new LocalSandbox(config);\n }\n return new LinuxSandbox(config, { mode: opts.mode, network: opts.network, bin: detection.bin });\n}\n\n/**\n * M75 T3.2 — latch do aviso do caminho INTERATIVO.\n *\n * Separado do latch de `createSandboxBackend` de propósito: são duas decisões distintas, tomadas em\n * momentos distintos, e um usuário que só use shell interativo precisa ver o aviso mesmo que o\n * caminho não-interativo já o tenha emitido — senão a sessão em que ele realmente digita comandos\n * seria a única sem o alerta.\n */\nlet avisouInterativo = false;\n\n/** Reset para testes — o latch é estado de módulo e testes precisam de isolamento. */\nexport function resetInteractiveWarnLatch(): void {\n avisouInterativo = false;\n}\n\nexport interface InteractiveWrapOptions {\n mode: SandboxMode;\n /** `true` mantém a rede. Default `false`, igual ao `run_shell` não-interativo. */\n network?: boolean;\n /** Injetável para testes; default é a detecção real memoizada. */\n detect?: () => BwrapDetection;\n /** Injetável para testes; default é `console.warn` com redação. */\n warn?: (message: string) => void;\n}\n\n/**\n * A composição que o caminho interativo precisa — o par de `createSandboxBackend`.\n *\n * `createSandboxBackend` resolve isto para o caminho não-interativo devolvendo um BACKEND pronto. O\n * PTY não aceita um backend: ele é dono do spawn e só admite transformar o comando. Esta função\n * entrega a MESMA decisão na forma que o PTY aceita — `(command, cwd) => string | null` —, pronta\n * para `new PtyInteractiveBackend({ wrapCommand: interactiveWrapCommand({ mode }) })`.\n *\n * A detecção é consultada **a cada wrap**, não congelada na construção: uma sessão interativa vive\n * por horas, e uma detecção positiva obsoleta continuaria afirmando confinamento depois de o binário\n * sumir (a revalidação por `existsSync` vive dentro de `detectBwrapMemoizado`).\n *\n * As duas rotas que devolvem `null` são semanticamente diferentes e o código não as funde:\n * `danger-full-access` é opt-out explícito e NÃO avisa; bwrap indisponível é falha e avisa uma vez.\n */\nexport function interactiveWrapCommand(\n opts: InteractiveWrapOptions,\n): (command: string, cwd: string) => string | null {\n return (command: string, cwd: string): string | null => {\n if (opts.mode === \"danger-full-access\") return null;\n\n const detection = (opts.detect ?? detectBwrapMemoizado)();\n if (!detection.ok) {\n if (!avisouInterativo) {\n avisouInterativo = true;\n const warn = opts.warn ?? ((m: string) => console.warn(redactSecrets(m)));\n warn(\n `[sandbox] OS-level enforcement unavailable (${detection.reason}) — interactive session ` +\n `runs WITHOUT kernel confinement (sandbox_mode=${opts.mode}).`,\n );\n }\n return null;\n }\n\n return wrapCommandForSandbox(\n opts.mode,\n {\n cwd,\n network: opts.network ?? false,\n env: allowlistedEnv(),\n bin: detection.bin,\n seccompPath: restrictedSeccompPath(),\n },\n command,\n );\n };\n}\n","import { defaultRetriableForCode } from \"./internal/runtime/retry/default-retriable.js\";\nimport { redactSecrets } from \"./internal/security/redact.js\";\nimport type { RunOperation } from \"./types/run.js\";\n\n/**\n * Finite, machine-readable error codes for provider-originated errors\n * (ADR D66). Consumers can `switch (err.metadata?.code)` exhaustively\n * — adding a new variant is an explicit decision + test coverage.\n *\n * @public\n */\nexport type ErrorCode =\n | \"rate_limit\"\n | \"auth_failed\"\n | \"invalid_request\"\n | \"timeout\"\n | \"server_error\"\n | \"context_too_long\"\n | \"content_filtered\"\n | \"model_unavailable\"\n | \"network\"\n | \"quota_exceeded\"\n | \"unknown\";\n\n/**\n * Codes used by {@link AgentRunError} (Production-Readiness #3, ADR D311).\n *\n * Superset of {@link ErrorCode} extended with codes that do NOT originate\n * from a provider HTTP response:\n *\n * - `quota_exceeded` — billing limit hit (provider 402 or signalled error)\n * - `tool_runtime_error` — custom tool handler threw inside dispatch\n * - `aborted` — caller's `AbortSignal` fired (Phase 4)\n * - `invalid_model` — model id rejected by provider (400 \"model not found\")\n * - `safety_blocked` — provider safety filter blocked req or resp\n * - `provider_unreachable` — DNS/TCP/timeout/5xx at transport boundary\n *\n * The `& {}` tail keeps the literal-union ergonomics (autocomplete) while\n * accepting any string for forward compatibility with constructor calls\n * that pass arbitrary code values (legacy callers).\n *\n * @public\n */\n/**\n * T1.1 — closed literal union for `AgentRunError.code`. The previous\n * `(string & {})` escape hatch let arbitrary strings slip into the type\n * surface and defeated exhaustive `switch (code)` discrimination. This is\n * the canonical closed form. `AgentRunErrorCode` is re-aliased below for\n * source-level back-compat.\n *\n * Adding a new code: append the literal here AND audit every `switch (err.code)`\n * in callers. Type-checker enforces the audit via the `default: assertNever(code)`\n * convention.\n *\n * @public\n */\nexport type KnownAgentRunErrorCode =\n | ErrorCode\n | \"quota_exceeded\"\n | \"tool_runtime_error\"\n | \"aborted\"\n | \"invalid_model\"\n | \"safety_blocked\"\n | \"provider_unreachable\";\n\n/**\n * Back-compat alias of {@link KnownAgentRunErrorCode}. Pre-T1.1 callers that\n * imported `AgentRunErrorCode` keep working; new code SHOULD prefer\n * `KnownAgentRunErrorCode` to make the closed-union intent explicit.\n *\n * @public\n */\nexport type AgentRunErrorCode = KnownAgentRunErrorCode;\n\n/** Snapshot of every known code at runtime — used by the boundary coercer. */\nconst KNOWN_AGENT_RUN_ERROR_CODES = new Set<string>([\n \"rate_limit\",\n \"auth_failed\",\n \"invalid_request\",\n \"timeout\",\n \"server_error\",\n \"context_too_long\",\n \"content_filtered\",\n \"model_unavailable\",\n \"network\",\n \"unknown\",\n \"quota_exceeded\",\n \"tool_runtime_error\",\n \"aborted\",\n \"invalid_model\",\n \"safety_blocked\",\n \"provider_unreachable\",\n]);\n\n/**\n * T1.1 boundary helper — coerce an arbitrary string (typically arriving from\n * a downstream `RunErrorDetail.code` or a deserialized cloud response) into a\n * `KnownAgentRunErrorCode`. Unknown strings collapse to `\"unknown\"` so the\n * closed type contract holds without forcing every caller to switch.\n *\n * @internal\n */\nexport function coerceToKnownAgentRunErrorCode(code: string | undefined): KnownAgentRunErrorCode {\n if (code !== undefined && KNOWN_AGENT_RUN_ERROR_CODES.has(code)) {\n return code as KnownAgentRunErrorCode;\n }\n return \"unknown\";\n}\n\n/**\n * Structured context for errors that originated from a provider HTTP\n * call (ADR D65). Lets callers retry with the right backoff (`retryAfter`),\n * surface actionable diagnostics (`provider`, `endpoint`), and inspect the\n * raw response body when needed (`raw`, capped at ~2KB by the mapper).\n *\n * @public\n */\nexport interface ErrorMetadata {\n /** Provider canonical name (e.g., `\"anthropic\"`, `\"openai\"`, `\"openrouter\"`, `\"gemini\"`). */\n provider: string;\n /** HTTP endpoint that failed (e.g., `\"/v1/messages\"`, `\"/v1/chat/completions\"`). */\n endpoint: string;\n /** Machine-readable error code (finite enum). */\n code: ErrorCode;\n /** HTTP status code if applicable. */\n statusCode?: number;\n /** Seconds to wait before retry, per provider's `retry-after` header (numeric form only). */\n retryAfter?: number;\n /** Raw response body for debugging (truncated to ~2KB by the mapper). */\n raw?: unknown;\n}\n\n/**\n * Base class for all errors thrown by `@theokit/sdk`.\n *\n * Use `isRetryable` to drive retry/backoff logic. `code` and `protoErrorCode`\n * are populated for server-originated errors when available. `metadata`\n * (ADR D65) carries structured `{ provider, endpoint, code, ... }` when\n * the error originated from a provider HTTP call.\n *\n * @public\n */\nexport class TheokitAgentError extends Error {\n override readonly name: string = \"TheokitAgentError\";\n readonly isRetryable: boolean;\n readonly code?: string;\n readonly protoErrorCode?: string;\n readonly metadata?: ErrorMetadata;\n\n constructor(\n message: string,\n options: {\n isRetryable?: boolean;\n code?: string;\n protoErrorCode?: string;\n cause?: unknown;\n metadata?: ErrorMetadata;\n } = {},\n ) {\n super(message, options.cause !== undefined ? { cause: options.cause } : undefined);\n this.isRetryable = options.isRetryable ?? false;\n if (options.code !== undefined) this.code = options.code;\n if (options.protoErrorCode !== undefined) this.protoErrorCode = options.protoErrorCode;\n if (options.metadata !== undefined) this.metadata = options.metadata;\n }\n}\n\n/**\n * Invalid API key, not logged in, insufficient permissions.\n *\n * @public\n */\nexport class AuthenticationError extends TheokitAgentError {\n override readonly name: string = \"AuthenticationError\";\n\n constructor(\n message: string,\n options: { code?: string; cause?: unknown; metadata?: ErrorMetadata } = {},\n ) {\n super(message, { ...options, isRetryable: false });\n }\n}\n\n/**\n * Too many requests or usage limits exceeded.\n *\n * @public\n */\nexport class RateLimitError extends TheokitAgentError {\n override readonly name: string = \"RateLimitError\";\n\n constructor(\n message: string,\n options: { code?: string; cause?: unknown; metadata?: ErrorMetadata } = {},\n ) {\n super(message, { ...options, isRetryable: true });\n }\n}\n\n/**\n * Invalid model, bad request parameters, malformed options.\n *\n * @public\n */\nexport class ConfigurationError extends TheokitAgentError {\n override readonly name: string = \"ConfigurationError\";\n\n constructor(\n message: string,\n options: { code?: string; cause?: unknown; metadata?: ErrorMetadata } = {},\n ) {\n super(message, { ...options, isRetryable: false });\n }\n}\n\n/**\n * Thrown when creating a cloud agent for a repo whose SCM provider is not\n * connected. Use `helpUrl` to point the user at the right reconnect flow.\n *\n * @public\n */\nexport class IntegrationNotConnectedError extends ConfigurationError {\n override readonly name: string = \"IntegrationNotConnectedError\";\n readonly provider: string;\n readonly helpUrl: string;\n\n constructor(\n message: string,\n options: {\n provider: string;\n helpUrl: string;\n code?: string;\n cause?: unknown;\n metadata?: ErrorMetadata;\n },\n ) {\n super(message, options);\n this.provider = options.provider;\n this.helpUrl = options.helpUrl;\n }\n}\n\n/**\n * Service unavailable, timeout, transport-level failure.\n *\n * @public\n */\nexport class NetworkError extends TheokitAgentError {\n override readonly name: string = \"NetworkError\";\n\n constructor(\n message: string,\n options: { code?: string; cause?: unknown; metadata?: ErrorMetadata } = {},\n ) {\n super(message, { ...options, isRetryable: true });\n }\n}\n\n/**\n * Catch-all for unclassified server or runtime errors.\n *\n * @public\n */\nexport class UnknownAgentError extends TheokitAgentError {\n override readonly name: string = \"UnknownAgentError\";\n\n constructor(\n message: string,\n options: { code?: string; cause?: unknown; metadata?: ErrorMetadata } = {},\n ) {\n super(message, { ...options, isRetryable: false });\n }\n}\n\n/**\n * Thrown by `Agent.prompt` (and helpers that go through `run.wait()`) when\n * the option `{ throwOnError: true }` is set and the run terminates with\n * `status: 'error'`. Carries the structured `RunResult.error` fields so\n * callers can `catch` once and branch on `code` / `provider` instead of\n * unwrapping the run.\n *\n * Extends {@link TheokitAgentError} per ADR D65 — no new hierarchy.\n *\n * @example\n * try {\n * await Agent.prompt(msg, { apiKey, model, throwOnError: true });\n * } catch (err) {\n * if (err instanceof AgentRunError && err.code === 'auth_failed') {\n * // bad key\n * }\n * }\n *\n * @public\n */\nexport class AgentRunError extends TheokitAgentError {\n override readonly name: string = \"AgentRunError\";\n readonly provider?: string;\n readonly raw?: string;\n /** Provider's request id (`x-request-id` / `request-id` header). Useful for support tickets. */\n readonly requestId?: string;\n /** SDK conversation id this error was raised inside. */\n readonly conversationId?: string;\n\n constructor(\n message: string,\n options: {\n code: AgentRunErrorCode;\n provider?: string;\n raw?: string;\n requestId?: string;\n conversationId?: string;\n retriable?: boolean;\n cause?: unknown;\n metadata?: ErrorMetadata;\n },\n ) {\n super(message, {\n code: options.code,\n cause: options.cause,\n metadata: options.metadata,\n // D311: most AgentRunErrors are not retriable (auth, validation, abort).\n // Provider mappers (D314) override per-status — explicit `retriable` wins\n // over the implicit default when supplied.\n isRetryable: options.retriable ?? defaultRetriableForCode(options.code),\n });\n if (options.provider !== undefined) this.provider = options.provider;\n if (options.raw !== undefined) this.raw = options.raw;\n if (options.requestId !== undefined) this.requestId = options.requestId;\n if (options.conversationId !== undefined) this.conversationId = options.conversationId;\n }\n\n /**\n * Production-Readiness #3 (ADR D311): alias for `isRetryable` exposed as\n * `retriable` to match the handoff contract. Future v2 will deprecate\n * `isRetryable` in favor of this.\n */\n get retriable(): boolean {\n return this.isRetryable;\n }\n\n /**\n * D312: provider's `Retry-After` header in **milliseconds**. Mappers store\n * the header value (seconds) in `metadata.retryAfter`; this getter\n * multiplies by 1000 so the result composes with `Date.now()`/`setTimeout`.\n *\n * Returns `undefined` when no hint was provided. `0` is a legitimate value\n * — use `=== undefined` check rather than truthy check.\n */\n get retryAfterMs(): number | undefined {\n if (this.metadata?.retryAfter === undefined) return undefined;\n return this.metadata.retryAfter * 1000;\n }\n\n /**\n * D313 + T1.5: alias for `metadata.raw`. Provider response body for\n * debugging. T1.5 wraps the value in `redactSecrets` at the getter\n * boundary so secret-shaped substrings (`sk-...`, Bearer JWTs, etc.) are\n * stripped before reaching the caller. Available but NEVER serialized\n * into `.message` (anti-leak invariant).\n */\n get providerError(): unknown {\n const raw = this.metadata?.raw;\n if (raw === undefined) return undefined;\n if (typeof raw === \"string\") return redactSecrets(raw);\n // Non-string raw (object/buffer) — stringify then redact.\n try {\n return redactSecrets(JSON.stringify(raw));\n } catch {\n return redactSecrets(String(raw));\n }\n }\n\n /**\n * T1.5 — sanitized JSON form. `metadata.raw` is OMITTED by default; opt\n * in via `THEOKIT_DEBUG_RAW_ERRORS=1` to surface the (redacted) raw\n * payload for diagnostics. Every other field stays accessible.\n *\n * The single env-var gate is read each call so operators can toggle at\n * runtime without restarting the process.\n */\n toJSON(): Record<string, unknown> {\n const json: Record<string, unknown> = {\n name: this.name,\n message: this.message,\n isRetryable: this.isRetryable,\n };\n addOptionalFields(json, this);\n const safeMeta = sanitizeMetadata(this.metadata);\n if (safeMeta !== undefined) json.metadata = safeMeta;\n return json;\n }\n}\n\nfunction addOptionalFields(json: Record<string, unknown>, err: AgentRunError): void {\n if (err.code !== undefined) json.code = err.code;\n if (err.provider !== undefined) json.provider = err.provider;\n if (err.requestId !== undefined) json.requestId = err.requestId;\n if (err.conversationId !== undefined) json.conversationId = err.conversationId;\n if (err.raw !== undefined) json.raw = redactSecrets(err.raw);\n}\n\nfunction sanitizeMetadata(meta: ErrorMetadata | undefined): ErrorMetadata | undefined {\n if (meta === undefined) return undefined;\n const { raw, ...rest } = meta;\n const debugRaw = process.env.THEOKIT_DEBUG_RAW_ERRORS === \"1\";\n if (debugRaw && raw !== undefined) {\n const redactedRaw =\n typeof raw === \"string\" ? redactSecrets(raw) : redactSecrets(safeStringify(raw));\n return { ...rest, raw: redactedRaw } as ErrorMetadata;\n }\n return rest as ErrorMetadata;\n}\n\nfunction safeStringify(value: unknown): string {\n try {\n return JSON.stringify(value);\n } catch {\n return String(value);\n }\n}\n\n/**\n * Is this error transient (worth retrying)?\n *\n * Returns the SDK's own retryability verdict: every {@link TheokitAgentError}\n * subclass computes `isRetryable` at construction (rate-limit / network /\n * credential-pool-exhausted are retryable; auth / configuration / unsupported\n * are not), so this predicate is a single source of truth rather than a\n * re-derivation. Non-SDK errors return `false` conservatively — wrap a foreign\n * error in the appropriate SDK error first if you want it considered transient.\n * It never inspects `err.message`.\n *\n * @example\n * try {\n * await agent.send(message, { throwOnError: true });\n * } catch (err) {\n * if (isTransientError(err)) return retryWithBackoff();\n * throw err;\n * }\n *\n * @public\n */\nexport function isTransientError(err: unknown): boolean {\n return err instanceof TheokitAgentError && err.isRetryable === true;\n}\n\n/**\n * Thrown when a {@link Run} or agent operation is not available on the current\n * runtime. Check first with `run.supports(operation)`.\n *\n * Extends {@link TheokitAgentError} (so error-catching code that branches on\n * `instanceof TheokitAgentError` continues to work) but is never retryable —\n * an unsupported operation will not become supported on retry.\n *\n * @public\n */\nexport class UnsupportedRunOperationError extends TheokitAgentError {\n override readonly name: string = \"UnsupportedRunOperationError\";\n readonly operation: RunOperation;\n\n constructor(\n message: string,\n operation: RunOperation,\n options: { code?: string; cause?: unknown } = {},\n ) {\n super(message, {\n ...options,\n isRetryable: false,\n code: options.code ?? \"unsupported_run_operation\",\n });\n this.operation = operation;\n }\n}\n\n/**\n * Thrown when every credential in a per-provider pool is in cooldown\n * and no healthy key is available (ADR D133). The caller's\n * {@link import(\"./internal/llm/fallback-client.js\").FallbackLlmClient}\n * catches this and tries the next provider in the fallback chain.\n *\n * `metadata.nextRetryAt` (epoch ms) tells callers when the soonest\n * pool entry resumes — useful for manual retry scheduling.\n *\n * @public\n */\nexport class CredentialPoolExhaustedError extends TheokitAgentError {\n override readonly name: string = \"CredentialPoolExhaustedError\";\n readonly provider: string;\n readonly nextRetryAt: number | undefined;\n\n constructor(\n message: string,\n options: {\n provider: string;\n nextRetryAt?: number;\n code?: string;\n cause?: unknown;\n metadata?: ErrorMetadata;\n },\n ) {\n super(message, {\n ...options,\n isRetryable: true,\n code: options.code ?? \"credential_pool_exhausted\",\n });\n this.provider = options.provider;\n this.nextRetryAt = options.nextRetryAt;\n }\n}\n\n/**\n * Finite error codes specific to memory adapter operations (ADR D141).\n *\n * @public\n */\nexport type MemoryAdapterErrorCode =\n | \"auth_failed\"\n | \"rate_limited\"\n | \"not_found\"\n | \"network\"\n | \"invalid_input\"\n | \"unknown\";\n\n/**\n * Error raised by `@theokit-memory-*` adapters. Carries `adapterId`\n * so callers can branch on which provider failed (ADR D141).\n *\n * @public\n */\nexport class MemoryAdapterError extends TheokitAgentError {\n override readonly name: string = \"MemoryAdapterError\";\n readonly adapterId: string;\n\n constructor(\n message: string,\n options: {\n adapterId: string;\n code: MemoryAdapterErrorCode;\n cause?: unknown;\n metadata?: ErrorMetadata;\n },\n ) {\n super(message, {\n isRetryable: options.code === \"rate_limited\" || options.code === \"network\",\n code: options.code,\n ...(options.cause !== undefined ? { cause: options.cause } : {}),\n ...(options.metadata !== undefined ? { metadata: options.metadata } : {}),\n });\n this.adapterId = options.adapterId;\n }\n}\n\n/**\n * Thrown when a user-supplied task ID violates the grammar\n * `^[a-z0-9][a-z0-9_-]*$` (D368) OR starts with a reserved adapter\n * prefix (`wf-` / `b-` / `cron-`, EC-5).\n *\n * @public\n */\nexport class InvalidTaskIdError extends TheokitAgentError {\n override readonly name: string = \"InvalidTaskIdError\";\n readonly taskId: string;\n\n constructor(message: string, taskId: string, options: { cause?: unknown } = {}) {\n super(message, {\n ...options,\n isRetryable: false,\n code: \"invalid_task_id\",\n });\n this.taskId = taskId;\n }\n}\n\n/**\n * Thrown when `Task.subscribe(id)` is called for a task that has been\n * evicted, never submitted, or evicted after retention (D373).\n *\n * @public\n */\nexport class TaskNotFoundError extends TheokitAgentError {\n override readonly name: string = \"TaskNotFoundError\";\n readonly taskId: string;\n\n constructor(taskId: string, options: { cause?: unknown } = {}) {\n super(`Task not found: ${taskId}`, {\n ...options,\n isRetryable: false,\n code: \"task_not_found\",\n });\n this.taskId = taskId;\n }\n}\n\n/**\n * Thrown when `CloudAgent` is asked to wrap a task (D370). Cloud\n * task observability is deferred until Theo PaaS GA.\n *\n * @public\n */\nexport class UnsupportedTaskOperationError extends TheokitAgentError {\n override readonly name: string = \"UnsupportedTaskOperationError\";\n readonly operation: string;\n\n constructor(operation: string, options: { cause?: unknown } = {}) {\n super(\n `Task operation \"${operation}\" is not supported on CloudAgent (pre-release; see ADR D370)`,\n {\n ...options,\n isRetryable: false,\n code: \"task_op_unsupported\",\n },\n );\n this.operation = operation;\n }\n}\n\n/**\n * Thrown by `Budget` enforcement (ADR D386) when a `mode: \"block\"`\n * budget would be exceeded by the upcoming LLM call. Caller pega\n * tipado para retry-after-window-reset or surface to the user.\n *\n * @public\n */\nexport class BudgetExceededError extends TheokitAgentError {\n override readonly name: string = \"BudgetExceededError\";\n readonly budgetName: string;\n readonly window: import(\"./types/budget.js\").BudgetWindow;\n readonly spentUsd: number;\n readonly limitUsd: number;\n readonly mode: import(\"./types/budget.js\").BudgetMode;\n\n constructor(args: {\n budgetName: string;\n window: import(\"./types/budget.js\").BudgetWindow;\n spentUsd: number;\n limitUsd: number;\n mode: import(\"./types/budget.js\").BudgetMode;\n cause?: unknown;\n }) {\n super(\n `Budget \"${args.budgetName}\" exceeded for window ${args.window}: spent $${args.spentUsd.toFixed(4)} > limit $${args.limitUsd.toFixed(4)}`,\n {\n ...(args.cause !== undefined ? { cause: args.cause } : {}),\n isRetryable: false,\n code: \"budget_exceeded\",\n },\n );\n this.budgetName = args.budgetName;\n this.window = args.window;\n this.spentUsd = args.spentUsd;\n this.limitUsd = args.limitUsd;\n this.mode = args.mode;\n }\n}\n\n/**\n * Thrown when `CloudAgent.send({ budget })` is invoked (D388). Cloud\n * budget surface waits for Theo PaaS GA.\n *\n * @public\n */\n/**\n * T1.6 — Thrown when a consumer calls `agent.send()` or any method\n * on an agent that has already been `dispose()`d. Pre-T1.6 this was\n * a generic `new Error(\"Agent has been disposed\")` — consumers\n * couldn't catch it without string-matching the message.\n *\n * @public\n */\nexport class AgentDisposedError extends TheokitAgentError {\n override readonly name: string = \"AgentDisposedError\";\n readonly agentId: string;\n\n constructor(agentId: string) {\n super(`Agent \"${agentId}\" has been disposed. Create a new agent or use Agent.resume().`, {\n isRetryable: false,\n code: \"agent_disposed\",\n });\n this.agentId = agentId;\n }\n}\n\nexport class UnsupportedBudgetOperationError extends TheokitAgentError {\n override readonly name: string = \"UnsupportedBudgetOperationError\";\n readonly operation: string;\n\n constructor(operation: string, options: { cause?: unknown } = {}) {\n super(\n `Budget operation \"${operation}\" is not supported on CloudAgent (pre-release; see ADR D388)`,\n {\n ...options,\n isRetryable: false,\n code: \"budget_op_unsupported\",\n },\n );\n this.operation = operation;\n }\n}\n","/**\n * M6-3 — portable repo provisioner for the eval harness.\n *\n * Clones a repository and checks out a ref into an isolated working dir, issuing\n * every git command through {@link SandboxBackend.execute} (ADR D2 — same code\n * runs on Local/Docker/E2B; never a direct `child_process` import). Promotes\n * theocode's `prepareRepo` (`swebench-provision.ts:37`) onto the SDK's sandbox\n * abstraction.\n *\n * referencia: knowledge-base/references/theocode-eval/lib/swebench-provision.ts:37\n * (clone+checkout), :13 (ProvisionError with instanceId).\n *\n * @public\n */\n\nimport { TheokitAgentError } from \"../errors.js\";\nimport { LocalSandbox } from \"./local-sandbox.js\";\nimport { shellEscapePosix } from \"./shell-escape.js\";\nimport type { SandboxBackend } from \"./types.js\";\n\n/**\n * Raised when cloning or checking out a repo fails. Carries the `instanceId`\n * so a batch run can attribute the failure to the offending dataset row.\n */\nexport class RepoProvisionError extends TheokitAgentError {\n override readonly name = \"RepoProvisionError\";\n\n constructor(\n readonly instanceId: string,\n message: string,\n options: { cause?: unknown } = {},\n ) {\n super(`[${instanceId}] ${message}`, {\n code: \"repo_provision_failed\",\n isRetryable: false,\n ...(options.cause !== undefined ? { cause: options.cause } : {}),\n });\n }\n}\n\n/** Options for {@link provisionRepo}. */\nexport interface ProvisionRepoOptions {\n /**\n * Clonable repo URL or local path. SECURITY: when this comes from an\n * untrusted dataset, the value is passed to `git clone` after a `--`\n * end-of-options terminator (no flag injection) and with the `ext::`\n * transport disabled (no arbitrary-command transport).\n */\n readonly repoUrl: string;\n /** Branch, tag, or commit SHA to check out. Rejected if it begins with `-`. */\n readonly ref: string;\n /**\n * Unique id for this row — names the target dir and any error. Validated to\n * `[A-Za-z0-9._-]` (no path traversal) since it becomes a directory name.\n */\n readonly instanceId: string;\n}\n\n/**\n * Reject ids that would escape the workdir or be parsed as a git flag. Must\n * start with an alphanumeric (blocks `.`, `..`, `-foo`, leading-dot names) and\n * thereafter allow only `[A-Za-z0-9._-]`.\n */\nconst SAFE_INSTANCE_ID = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;\n\n/**\n * Clone `repoUrl` into `<sandbox workdir>/<instanceId>` and check out `ref`.\n * Returns the absolute `repoDir` (resolved via `git rev-parse --show-toplevel`,\n * which is portable across backends). Throws {@link RepoProvisionError} naming\n * the `instanceId` when clone or checkout exits non-zero.\n *\n * The `sandbox` is optional (V3-5): when omitted, a default {@link LocalSandbox}\n * is used (clones into the process cwd's `<instanceId>`) — pass an explicit\n * sandbox (e.g. `LocalSandbox({ workDir })` / Docker / E2B) to control the workdir.\n */\nexport function provisionRepo(opts: ProvisionRepoOptions): Promise<{ repoDir: string }>;\nexport function provisionRepo(\n sandbox: SandboxBackend,\n opts: ProvisionRepoOptions,\n): Promise<{ repoDir: string }>;\nexport async function provisionRepo(\n sandboxOrOpts: SandboxBackend | ProvisionRepoOptions,\n maybeOpts?: ProvisionRepoOptions,\n): Promise<{ repoDir: string }> {\n const sandbox = maybeOpts !== undefined ? (sandboxOrOpts as SandboxBackend) : new LocalSandbox();\n const opts = maybeOpts ?? (sandboxOrOpts as ProvisionRepoOptions);\n const { repoUrl, ref, instanceId } = opts;\n\n // Validate untrusted-derivable inputs before they reach git/the shell.\n if (!SAFE_INSTANCE_ID.test(instanceId)) {\n throw new RepoProvisionError(\n instanceId,\n \"invalid instanceId: must match [A-Za-z0-9._-] (no path traversal)\",\n );\n }\n if (ref.startsWith(\"-\")) {\n throw new RepoProvisionError(instanceId, `invalid ref: must not begin with '-' (got ${ref})`);\n }\n\n // `--` terminates options (no `--upload-pack=` flag injection); `protocol.ext.allow=never`\n // blocks the `ext::` arbitrary-command transport. `file`/`https` stay allowed.\n const clone = await sandbox.execute(\n `git -c protocol.ext.allow=never clone --quiet -- ${shellEscapePosix(repoUrl)} ${shellEscapePosix(instanceId)}`,\n );\n if (clone.exitCode !== 0) {\n throw new RepoProvisionError(instanceId, `clone failed: ${clone.stderr.trim()}`);\n }\n\n const top = await sandbox.execute(\n `git -C ${shellEscapePosix(instanceId)} rev-parse --show-toplevel`,\n );\n if (top.exitCode !== 0) {\n throw new RepoProvisionError(instanceId, `resolve repoDir failed: ${top.stderr.trim()}`);\n }\n const repoDir = top.stdout.trim();\n\n // `ref` is validated above not to begin with `-`, so it cannot be parsed as a flag.\n const checkout = await sandbox.execute(\n `git -C ${shellEscapePosix(repoDir)} checkout --quiet ${shellEscapePosix(ref)}`,\n );\n if (checkout.exitCode !== 0) {\n throw new RepoProvisionError(instanceId, `checkout ${ref} failed: ${checkout.stderr.trim()}`);\n }\n\n return { repoDir };\n}\n"]}
@@ -1,3 +1,6 @@
1
+ export { type BwrapArgvOptions, type BwrapDetection, type BwrapProbes, buildBwrapArgv, detectBwrap, detectBwrapMemoizado, realProbeCount, realProbes, resetBwrapMemo, type SandboxMode, } from "./bwrap.js";
2
+ export { allowlistedEnv, type CreateSandboxBackendOptions, createSandboxBackend, type InteractiveWrapOptions, interactiveWrapCommand, LinuxSandbox, resetInteractiveWarnLatch, resetSandboxWarnLatch, resolveSandboxPosture, restrictedSeccompPath, type SandboxPosture, seccompPathForArch, wrapCommandForSandbox, } from "./linux-sandbox.js";
1
3
  export { LocalSandbox } from "./local-sandbox.js";
2
4
  export { type ProvisionRepoOptions, provisionRepo, RepoProvisionError, } from "./provision.js";
5
+ export { buildSeccompFilter, type SeccompOptions } from "./seccomp.js";
3
6
  export { type ExecuteResult, resolveSandbox, SandboxBackend, type SandboxConfig, SandboxNotAvailableError, type SandboxProvider, SandboxSecurityError, } from "./types.js";
@@ -1,3 +1,6 @@
1
+ export { type BwrapArgvOptions, type BwrapDetection, type BwrapProbes, buildBwrapArgv, detectBwrap, detectBwrapMemoizado, realProbeCount, realProbes, resetBwrapMemo, type SandboxMode, } from "./bwrap.js";
2
+ export { allowlistedEnv, type CreateSandboxBackendOptions, createSandboxBackend, type InteractiveWrapOptions, interactiveWrapCommand, LinuxSandbox, resetInteractiveWarnLatch, resetSandboxWarnLatch, resolveSandboxPosture, restrictedSeccompPath, type SandboxPosture, seccompPathForArch, wrapCommandForSandbox, } from "./linux-sandbox.js";
1
3
  export { LocalSandbox } from "./local-sandbox.js";
2
4
  export { type ProvisionRepoOptions, provisionRepo, RepoProvisionError, } from "./provision.js";
5
+ export { buildSeccompFilter, type SeccompOptions } from "./seccomp.js";
3
6
  export { type ExecuteResult, resolveSandbox, SandboxBackend, type SandboxConfig, SandboxNotAvailableError, type SandboxProvider, SandboxSecurityError, } from "./types.js";