import { type ExecutionEnv, ExecutionError, FileError, type FileInfo, type Result } from "../harness/types.js"; import type { BackgroundShellCapability, BackgroundShellId, BackgroundPoll, BackgroundSpawnOptions } from "../../core/background-shell.js"; import { BackgroundShellError } from "../../core/background-shell.js"; import type { SchedulerCapability, ScheduledIntent, SchedulerContext, ScheduledTaskId, ScheduledTaskSummary } from "../../core/scheduler.js"; import { SchedulerError } from "../../core/scheduler.js"; /** Convert user-facing timeout seconds into a positive, timer-safe millisecond delay. */ export declare function resolveExecTimeoutMs(timeoutSeconds: unknown): number | undefined; /** service [377] review finding (win32): `where bash.exe` can resolve to `System32\bash.exe` — the * WSL LAUNCHER, not a native shell. Running it drops into a Linux subsystem where Windows cwd/paths * do not exist; silently adopting it is exactly the "wrong shell, false green" failure D1 forbids. * Filter it (and the WindowsApps alias) out of PATH discovery; Git-Bash candidates are tried first. */ export declare function isWslBashLauncher(p: string): boolean; /** Shell discovery for the platform (service [377] ask ①: exported as the single SDK source so a host * adapter does not mirror the platform logic). Explicit `customShellPath` wins (missing → err); * win32 = Git-Bash discovery (ProgramFiles → PATH, WSL launcher filtered) with fail-loud * `shell_unavailable` (never a silent cmd.exe fallback); POSIX = /bin/bash → PATH bash → sh. */ export declare function getShellConfig(customShellPath?: string): Promise>; /** design/128 T1-1 / codex 1.236 复审 R2: open the spool file pair ALL-OR-NOTHING — a failure opening the * second file must close the first fd before rethrowing (the caller's catch only clears its references, so * a half-open pair would leak fdOut for the env's lifetime). `wx` + 0600 (never follow / never reuse an * existing path). Exported for direct fault-injection tests (pre-create a path → EEXIST). */ export declare function openSpoolPair(base: string): { outPath: string; errPath: string; fds: [number, number]; }; export declare class NodeExecutionEnv implements ExecutionEnv, BackgroundShellCapability, SchedulerCapability { cwd: string; private shellPath?; private shellEnv?; private inheritEnv; private readonly scheduler?; private readonly bgShells; private bgCounter; private readonly retainBackgroundProcesses; /** design/128 T1-1: lazily-created env-owned spool dir (mkdtemp under os tmp — unpredictable, never the cwd). */ private bgSpoolDir?; readonly backgroundCapabilities: BackgroundShellCapability["backgroundCapabilities"]; constructor(options: { cwd: string; shellPath?: string; shellEnv?: NodeJS.ProcessEnv; /** VENDORED EDIT (D1, security): how much of `process.env` the shell child inherits. Default `"scrub"` = * fail-closed (drop secret-pattern keys, keep PATH/build/locale). `"all"` = full inherit (trusted env); * `string[]` = strict allowlist. `shellEnv`/per-exec `env` always pass through. */ inheritEnv?: "all" | "scrub" | string[]; /** design/105: inject a resident scheduler daemon backend (the shell daemon). Absent ⇒ scheduling INERT. */ scheduler?: SchedulerCapability; /** * design/128 T1-1 — deliver-a-living-service mode (default false). When true, background processes * OUTLIVE the run: `disposeBackgroundShells()` becomes a no-op (the runner's every-exit-path dispose * included) and background stdio is spooled to env-owned temp files (0600, `wx`, unpredictable path) * so the child never dies of EPIPE after the host exits. DEPLOYMENT-declared at env construction — * no TaskSpec/model-facing switch exists. The 2h bg-timeout reaper and `killBackground` still work * while the host lives; after host exit, cleanup is the deployment's responsibility (e.g. the TB * container teardown). v1 covers processes spawned via `execBackground` only (a detach-adopted * foreground exec keeps pipe stdio — best-effort survival). Incompatible with durable-suspend * deployments (their pre-suspend dispose becomes a no-op too — do not combine). */ retainBackgroundProcesses?: boolean; }); get schedulerCapabilities(): SchedulerCapability["schedulerCapabilities"]; schedule(intent: ScheduledIntent, ctx: SchedulerContext): Promise>; cancel(id: ScheduledTaskId, ctx: SchedulerContext): Promise>; list(ctx: SchedulerContext): Promise>; absolutePath(path: string): Promise>; joinPath(parts: string[]): Promise>; exec(command: string, options?: { cwd?: string; env?: Record; timeout?: number; abortSignal?: AbortSignal; onStdout?: (chunk: string) => void; onStderr?: (chunk: string) => void; detachSignal?: AbortSignal; }): Promise>; readTextFile(path: string, abortSignal?: AbortSignal): Promise>; readTextLines(path: string, options?: { maxLines?: number; abortSignal?: AbortSignal; }): Promise>; readBinaryFile(path: string, abortSignal?: AbortSignal): Promise>; writeFile(path: string, content: string | Uint8Array, abortSignal?: AbortSignal): Promise>; /** Atomic exclusive create ({@link FileSystem.writeFileExclusive}): Node `wx` flag = one * `open(O_CREAT|O_EXCL)` syscall — an existing file returns FileError `"already_exists"` and is left * untouched. The EEXIST→already_exists mapping lives HERE, on the exclusive-open step only — a parent * `mkdir` can also throw EEXIST (parent path component is a regular file) and that is NOT "the target * already exists" (fable review). Parent directories are created like writeFile. */ writeFileExclusive(path: string, content: string | Uint8Array, abortSignal?: AbortSignal): Promise>; appendFile(path: string, content: string | Uint8Array): Promise>; fileInfo(path: string): Promise>; listDir(path: string, abortSignal?: AbortSignal): Promise>; canonicalPath(path: string): Promise>; readLink(path: string): Promise>; exists(path: string): Promise>; createDir(path: string, options?: { recursive?: boolean; }): Promise>; remove(path: string, options?: { recursive?: boolean; force?: boolean; }): Promise>; createTempDir(prefix?: string): Promise>; createTempFile(options?: { prefix?: string; suffix?: string; }): Promise>; /** design/116 detach: adopt a RUNNING foreground child as a background shell. Pre-fills the bg tails with * the output captured so far (so TaskOutput's first read has the full history), attaches fresh data/close * handlers, and arms the default bg timeout. Returns undefined when the live-shell limit is hit (detach * refused; the exec keeps running in the foreground). */ private adoptRunningChild; spawnBackground(command: string, options?: BackgroundSpawnOptions): Promise>; pollBackground(shellId: BackgroundShellId): Promise>; killBackground(shellId: BackgroundShellId): Promise>; /** design/128 T1-1: incrementally read a retained shell's spool files into the in-memory tails, so * pollBackground serves the same cursor semantics whether stdio came over pipes or spool files. * Bounded single read per stream per poll (the tail keeps only its rolling window anyway). */ private syncSpool; disposeBackgroundShells(opts?: { except?: readonly BackgroundShellId[]; }): Promise; cleanup(): Promise; } //# sourceMappingURL=node-execution-env.d.ts.map