UNPKG

@sema-agent/core

Version:

Stateless, task-oriented AI agent core

49 lines (48 loc) • 3.75 kB
/** * The tracked-cwd liveness probe and its diagnosis, shared by the three sites that spawn into the tracked * logical cwd: the shell's foreground and background legs, and the watch tool's background leg. A second * copy of either half would be a second answer to "is this directory usable?" and a second refusal * wording for the same fact, so both are minted here once and each leg passes only its own tool name. */ import type { ExecutionEnv } from "../../internal/harness-types.js"; /** * Is `dir` USABLE as a spawn cwd? "Dead" is the whole class, not just deletion: gone, replaced by a FILE * of the same name or standing under one, or a symlink that does not resolve to a directory. `fileInfo` * is lstat-semantics, so a symlink is judged by FOLLOWING it (`canonicalPath`, then one probe of the * target — a link retargeted at a file resolves perfectly well and is still not a cwd). * * The failure direction is deliberately asymmetric. Where a failure says nothing about the chain (the * initial lstat, the target's own), an error means death only when it SAYS so — refusing a command, or * resetting somebody's working directory, over one flaky stat would be worse than the failure being * diagnosed. The RESOLUTION step is the exception: a chain that will not resolve is no directory by any * reading; see {@link resolutionFailureMeansDead} for the one code that step reads as death on top. */ export declare function isDeadCwd(env: ExecutionEnv, dir: string, signal?: AbortSignal): Promise<boolean>; /** * Dead-cwd diagnosis for a never-started command (spawn_error / shell_unavailable): a command that * DELETED or REPLACED the tracked cwd (e.g. `opam clean` after `cd` into a build dir) leaves the * persistent session pinned to a dead directory — every later spawn fails ENOENT/ENOTDIR with a message * blaming the SHELL BINARY ("spawn /bin/bash ENOENT"), the model concludes bash is gone, and the run is * permanently disabled (TB compile-compcert, 14 contaminated calls). The env can't distinguish this (spawn * reports the same code either way), so probe here: * - tracked cwd dead + task root alive → SELF-HEAL: reset the tracked cwd to the root, tell the model * what happened and that a retry works; * - tracked cwd dead + root ALSO dead (never promise a retry that must fail) → honest * unrecoverable verdict; * - cwd IS the root and it's dead (`rm -rf "$PWD"` in place — a diverged-guard would * skip diagnosis entirely) → honest root-gone verdict (no reset target exists); * - the caller knows NO root (`root === undefined` — a direct mount that was never handed one) → say the * cwd is gone and that this tool has no reset target, and stop there. Calling that directory "the task * root" or declaring the tree unrecoverable would both be claims the caller cannot back: the root may * well be alive, and a `cd` to it recovers. Nothing is reset. * - cwd healthy → return undefined (the spawn failure has another cause; keep the original error). * Returns the model-facing message, or undefined when this is not a dead-cwd case. Uses only the public * env faces (`fileInfo`/`canonicalPath`) — works for any env that maps never-started failures to * spawn_error/shell_unavailable (contract note on ExecutionErrorCode). * * `root` is REQUIRED-but-nullable on purpose (not an optional parameter): a caller without a root has to * say so at the call site, so "this mount has no root" can never be spelled the same way as "I forgot". */ export declare function diagnoseDeadCwd(env: ExecutionEnv, toolName: string, effectiveCwd: string, root: string | undefined, cwdRef?: { current: string; }, signal?: AbortSignal): Promise<string | undefined>;