import { type AgentTool, type ExecutionEnv } from "../../internal/harness.js";
import { type TaskRegistry } from "../../core/task-registry.js";
import { type CwdRef } from "./fs-shared.js";
import type { ReversibilityVerdict } from "../../core/types.js";
import type { ShellReadAdmission } from "./shell-read-check.js";
/**
 * The full shell face's SHAPE classifier for the `bash` tool, exposed as a `ToolSpec.reversibilityProbe`
 * (the "maybe" tier's probe, installed on every full shell). A command is reversible ONLY if every connected
 * segment is a bare command whose program is on the reversible allowlist (default
 * {@link bashClassifyDefaultAllow} — curated to commands with NO write/mutation mode under ANY args) and whose
 * SHAPE the compound classifier accepts (no redirects, substitutions, subshells, escapes or backgrounding; no
 * blocking stdin read, follow mode or device read; a guarded verb form in its safe spelling) — or a bounded
 * read-only poll loop of such commands ({@link classifyBoundedReadonlyPollLoop}). EVERYTHING else — a write
 * command, an egress command, an operator, a path-prefixed or env-assigned command, a backgrounded call, a
 * non-string arg — is NOT reversible → the gate tightens a surviving allow to an ordinary ask. Fail-closed by
 * construction: the allowlist is the only path to `reversible: true`.
 *
 * WHERE a command reads is not this probe's question. The read boundary — deny rows, containment, symlinks,
 * patterns, traversals, the working directory a `cd` moves — is the gate's shell READ STATION
 * (`shell-read-check.ts`), judged on every shell call under every mode, ahead of this probe; a call the
 * station refused never reaches it, and a call the station asks about is asked about whatever this probe
 * says. `boundary` supplies only the environment's declared home, so the `$HOME`/`~` spellings fold here the
 * way the station folds them; nothing else of it is read. A caller-supplied `allow` is honored verbatim, so a
 * narrowed deployment is never widened by the default superset.
 */
export declare function bashReversibilityProbe(allow?: readonly string[], boundary?: {
    readonly homeDir?: string;
} | (() => {
    readonly homeDir?: string;
} | undefined)): (args: unknown) => ReversibilityVerdict;
/**
 * The FULL shell's contract id, single-sourced: both shell faces share the wire
 * name "Bash", so this id is the ONE structural discriminator between the write-capable shell and
 * the read-only allowlist face (`core.bash_readonly@1`). Consumed by prepare-task's
 * fullShellReachable roster assertion (its first load-bearing consumer).
 */
export { FULL_SHELL_CONTRACT_ID } from "../../core/tool-catalog-entries.js";
/** The CC-verbatim exit-1 interpretation for `command`, or undefined when exit 1 means a real error.
 *  Conservative parse: last `;`/`&&`/`||`/newline statement → last `|` pipeline segment → leading
 *  command name (env-assignments skipped, path prefix stripped); `git grep`/`git diff` special-cased
 *  (CC `cLp`). Exported for its unit tests. */
export declare function bashExitOneInterpretation(command: string): string | undefined;
export declare function canAutoBackground(command: string, depth?: number): boolean;
/** One observation of a running command, handed to {@link runShell}'s caller once per
 *  {@link TOOL_PROGRESS_BOUND}.intervalMs. NO clock: how long the call has been running is the RUN's fact,
 *  not this leg's — the two producers of a progress frame do not start their clocks at the same instant, so
 *  the lane that mints the frame owns the origin. The output trio rides or stays away TOGETHER, and only
 *  when the environment has actually streamed something — see the frame's own absence law. */
export interface RunningShellTick {
    output?: string;
    totalLines?: number;
    totalBytes?: number;
}
/**
 * `bash` (effect:write) — a full shell. ⚠️ It runs with `rootCanonical` as the initial cwd but is NOT
 * sandboxed: a command can `cd` out, read/write/delete any path the process can reach, and use the
 * network. `rootPath` is a file-tool guard rail, NOT a bash sandbox — real isolation is the
 * deployment's job (inject a chroot/container `ExecutionEnv`). Every call still goes through the
 * tool-policy gate, which a multi-tenant deployment MUST wire to constrain it. The cwd
 * persists across calls: a per-task `cwdRef` starts at `rootCanonical` and is updated
 * from the shell's final pwd after each command.
 */
export declare function createBashTool(env: ExecutionEnv, rootCanonical: string, coAuthor?: string | false, cwdRef?: CwdRef, taskOpts?: {
    taskRegistry?: TaskRegistry;
    taskOwner?: string;
    taskScope?: string;
    /** (mirrors MonitorToolOptions.sessionId): when the task runs INSIDE a session,
     *  a background command registers session-resident (owner = sessionId, sessionScoped flag) — it
     *  survives the run teardown like CC's bg shells and is reaped at the session terminal. Absent ⇒
     *  run-scoped registration exactly as before (killed-with-receipt at teardown). */
    sessionId?: string;
    /** Completion-notification sink — a finished background command fires ONE
     *  task-notification (priority "next": boundary interrupt, CC LocalShellTask posture). */
    onTaskNotification?: (n: import("../../core/task-notification.js").TaskNotificationPayload, opts?: {
        priority?: "now" | "next" | "later";
    }) => void;
    /** Per-tool-call detach hub — a fired signal adopts the running command as background. */
    detachHub?: import("../../core/tool-detach.js").ToolDetachHub;
    /**
     * EXPLICIT deployment opt-in: on this command's own
     * timeout, an eligible foreground command (see `canAutoBackground`'s own docstring — a
     * DELIBERATELY simplified, narrower-than-CC classifier) is adopted as a background task instead
     * of being killed. Defaults to `false` (the pre-existing, unconditional kill-on-timeout behavior)
     * — this must NOT be inferred from `detachHub`/`taskRegistry` merely being present, because those
     * are wired UNCONDITIONALLY for every task (the ctrl+b manual-detach capability, `defaultTaskRegistry`
     * is a module-level singleton) — tying auto-eligibility to their mere presence would silently flip
     * the timeout outcome for every existing caller/test with no opt-in signal at all (caught by
     * `test/tool-cut-kill.test.ts`'s pre-existing "ordinary lane" self-timeout test: a
     * `canAutoBackground`-eligible command it never expected to survive its timeout started surviving
     * it). A deployment that wants the CC-parity behavior sets this explicitly; sema's own default
     * Runner wiring currently does NOT set it, so this feature ships INERT until a caller opts in.
     *
     * IT ARMS TWO TRIGGERS, not one — the name is older than the second. Both are the engine deciding
     * to adopt a running command instead of ending it, both take the same adoption chain, and both are
     * gated on the same eligibility read of this command's text (`canAutoBackground`): (1) the command's
     * OWN timeout fires, and (2) a person's input is waiting for the turn boundary while this command
     * still runs (see {@link queuedHumanInput}). A deployment that opted in for one has opted in for
     * both; there is deliberately no second knob, because "may this command be moved to the background
     * by the engine" is one question and answering it twice is how the two triggers would drift apart.
     */
    autoBackgroundOnTimeout?: boolean;
    /**
     * The run's tool-progress sink: one call per liveness tick of a running foreground command (about
     * once a second), minted into a `tool_progress` frame by whoever wired this. Runner-wired; a
     * standalone toolkit build leaves it absent, and the execute leg then opens no streaming callbacks
     * at all — its `env.exec` options are byte-identical to what they were before this seat existed.
     */
    onToolProgress?: (body: import("../../core/runner/contracts.js").ToolProgressBody) => void;
    /**
     * Is a PERSON's input waiting for this run's next turn boundary? Read on each liveness tick of a
     * running foreground command: `true` on an {@link autoBackgroundOnTimeout}-armed command moves that
     * command into the background (through the SAME detach verb ctrl+b fires) so the message is
     * delivered this turn instead of after the command. CC 2.1.259 `backgroundedToDeliverMessage`.
     *
     * The predicate is the HARNESS's own accepted-but-unserved account and deliberately counts only what
     * a PERSON sent: an engine-authored reminder is not somebody waiting, and stepping a build aside for
     * one would fire on nearly every long command. Absent ⇒ nothing is ever auto-backgrounded for a
     * message (the pre-seat behavior), which is also what a standalone toolkit build gets.
     */
    queuedHumanInput?: () => boolean;
    /**
     * Mirrors {@link import("../../core/types.js").TaskSpec.oneShot}: this run has no later
     * turn for an async background notification to land in (a headless `-p` process exits once the
     * turn ends). Branches the background-launch receipt's guidance toward an active block-wait
     * instruction instead of "you will be notified — do not poll", the same failure form
     * `run_workflow`'s launch note was fixed for (a model that follows "end your turn" advice in a
     * one-shot process loses the result — the process exits with nothing left alive to receive it).
     */
    oneShot?: boolean;
    /**
     * The EXTRA containment roots of the structured file tools (additionalDirectories,
     * canonical) — combined with `rootCanonical` and consulted ONLY for the post-`cd` disclosure
     * note (a committed cwd outside every root gets one trailer line saying the structured tools'
     * relative paths now resolve there and may be refused). Bash itself stays deliberately
     * unconfined; passing this never gates anything.
     */
    additionalRoots?: readonly string[];
    /**
     * The gate's shell read station's pre-spawn ADMISSION (`ShellReadAdmission`, shell-read-check.ts): what
     * this leg runs is what the station judged before approval, and the admission re-establishes the SAME
     * candidates right before the spawn — a symlink re-pointed or a pattern re-matched while the approver
     * was thinking refuses the call instead of running it. It parses nothing and judges no word the
     * station did not. Absent ⇒ no station judged this mount (a library-direct toolkit with no gate):
     * nothing is re-established, and the full shell runs unconfined as it always did.
     */
    shellReadAdmission?: ShellReadAdmission;
    /** Override of the `timeout` parameter's DEFAULT budget, in ms — see
     *  {@link import("./index.js").HandsToolkitOptions.bashDefaultTimeoutMs} for the resolution
     *  contract (options over env over constant; invalid values discarded). */
    bashDefaultTimeoutMs?: number;
    /** Override of the `timeout` parameter's engine CEILING, in ms — only-widen
     *  vs the resolved default; see {@link import("./index.js").HandsToolkitOptions.bashMaxTimeoutMs}. */
    bashMaxTimeoutMs?: number;
    /** Structured sink for this leg's timeout-cap discard announcements — consumed by
     *  {@link import("./fs-shared.js").resolveBashTimeoutCaps} at mount (see
     *  {@link import("./index.js").HandsToolkitOptions.onNotice} for the replace-vs-warn contract). */
    onNotice?: (n: import("../../core/types.js").EngineNotice) => void;
    /**
     * Whether the Monitor tool is on THIS run's roster (the Runner's own mount predicate is
     * `backgroundTaskToolsActive`; it, not this tool, mounts Monitor). Read by the SR-2 gh rate-limit
     * hint, whose closing clause teaches the Monitor tool: `false` ⇒ the clause is dropped (the sleep
     * advice stays), absent/`true` ⇒ historic full wording (a standalone toolkit consumer may well have
     * mounted Monitor itself — the omitted default must not silently rewrite its hint).
     */
    monitorToolActive?: boolean;
    /** The session's reminder provenance mark: stamped on the gh rate-limit
     *  hint's open tag by the mint home (see {@link import("./index.js").HandsToolkitOptions.reminderMark}).
     *  Absent ⇒ historic bare tag. */
    reminderMark?: string;
    /** The task lane of THE retain predicate (`TaskSpec.retainBackgroundProcesses` of the run this mount
     *  serves; see {@link import("./index.js").HandsToolkitOptions.retainBackgroundProcesses}). Read by the
     *  lifetime sentence (description + receipts) and stamped onto every background row this tool registers
     *  (passing it — true or false — states the lane on the row). Absent ⇒ the sentence reads not-retained
     *  and the rows leave the lane to the owning run's teardown. */
    retainBackgroundProcesses?: boolean;
}): AgentTool;
/**
 * `bash_readonly` (effect:read) — a restricted shell for the verifier read-only boundary: a single
 * allowlisted, bare command with no shell operators. effect:read lets it survive the verifier's
 * read-only filter, but it is NOT a policy circumvention — it still goes through the tool-policy gate,
 * because a read can still be a side channel (dumping a secret file). The allowlist is a coarse pre-filter
 * over the command's SHAPE; WHERE it reads is the gate's shell read station's judgment (`shell-read-check.ts`,
 * the `readonly` seat), which REFUSES a deny-listed read, an out-of-root read and a read it cannot establish
 * — this face has no approval channel to degrade to, so every finding is a refusal, before anything runs.
 * The execute leg judges nothing: it admits what the station established (`shellReadAdmission` re-establishes
 * the same candidates right before the spawn) and runs the command.
 */
export declare function createBashReadonlyTool(env: ExecutionEnv, rootCanonical: string, allow: ReadonlySet<string>, opts?: {
    /** Same timeout-cap overrides the full `bash` leg takes — see
     *  {@link import("./index.js").HandsToolkitOptions.bashDefaultTimeoutMs} /
     *  {@link import("./index.js").HandsToolkitOptions.bashMaxTimeoutMs} — both foreground legs share
     *  runShell's clamp, so both must share the configurable resolution. */
    bashDefaultTimeoutMs?: number;
    bashMaxTimeoutMs?: number;
    /** Structured sink for the timeout-cap discard announcements — same seat the full `bash` leg
     *  takes (both foreground legs share the resolver, so both must share the sink). */
    onNotice?: (n: import("../../core/types.js").EngineNotice) => void;
    /** The gate's shell read station's pre-spawn ADMISSION (`ShellReadAdmission`, shell-read-check.ts): what
     *  this leg runs is what the station judged, re-established right before the spawn. Absent ⇒ no station
     *  judged this mount (a library-direct toolkit with no gate): this face then confines NOTHING — its
     *  containment IS the station, and a consumer mounting it without one must run `runToolGate` with the
     *  station's `shellReadCheck` (the Runner does). */
    shellReadAdmission?: ShellReadAdmission;
    /** The run's tool-progress sink — the SAME seat the full shell leg takes, for the same reason its
     *  two neighbours above are shared: both foreground legs run through `runShell`, so a long command
     *  must breathe on both or a person watching one of them is told nothing. This face has no detach
     *  chain, so it ticks and never auto-backgrounds. Absent ⇒ no streaming callbacks, byte-unchanged. */
    onToolProgress?: (body: import("../../core/runner/contracts.js").ToolProgressBody) => void;
}): AgentTool;
/**
 * `TaskOutput` — read a background shell's NEW output
 * since the last call (cursor), by task_id. Optional legacy `filter` regex is applied BEFORE the per-poll truncation so a watched line survives even when it
 * falls in a high-throughput middle window. Untrusted process output is fenced (delimitUntrusted) — observe-only,
 * never re-fed as instructions.
 */
export declare function createEnvTaskOutputTool(env: ExecutionEnv): AgentTool;
/** `TaskStop` — terminate a background shell by task_id.
 *
 *  This band kills ENV-DIRECT (it mounts precisely when the toolkit has
 *  no registry — the createHandsToolkit ternary routes registry deployments to createTaskStopTool), so a
 *  row for the SAME shell in the process-local {@link defaultTaskRegistry} (a Runner-mounted run sharing
 *  this env) used to settle via the watcher's no-claimant floor as stoppedBy:"system". The tool now marks
 *  the initiation site ("parent") on `registry` (default: the process-local {@link defaultTaskRegistry})
 *  BEFORE the kill — attribution only; the kill path and the model-facing receipt text are unchanged. */
export declare function createEnvTaskStopTool(env: ExecutionEnv, registry?: TaskRegistry): AgentTool;
