import { type Caller } from '../context/session_context.ts';
import { Limit, type PathSpec, type Refusal } from '../types.ts';
import type { VfsCall } from '../vfs/types.ts';
import type { SessionState } from '../workspace/session/session.ts';
import type { Policy } from './base.ts';
import { Decisions } from './decisions.ts';
import { PolicyDenied } from './errors.ts';
import type { RouteContext } from './types.ts';
import { type Ask, type Claimant, type CommandContext, type CommandResultContext, type Deny, type ExecuteResultContext, type NetworkContext, type NetworkResultContext, type Pending, type PolicyMethod, type Route, type SessionContext, type SessionResultContext, type VfsContext, type VfsResultContext, type WorkspaceContext } from './types.ts';
type MethodContext = CommandContext | RouteContext | VfsContext | VfsResultContext | ExecuteResultContext | SessionContext | WorkspaceContext | NetworkContext;
/**
 * The command plane's rendering of a refusal: stderr and exit code. The
 * one place the outcome table for that plane is written down, so a
 * document rule and a coded policy print alike, and the policy's reason
 * is never mixed into what the terminal says: a Deny, or an unanswered
 * ask, is bash's own `<subject>: Permission denied` at 126, so stderr
 * never tells an agent whether a retry might pass; a Deny about a path
 * is the command's own GNU line for that path and EACCES; each leaves
 * the reason (and an ask's id) on the result's `refusal` record. A Deny
 * carrying an error keeps `<subject>: <reason>`, because there the
 * reason is the diagnostic a built-in worded in POSIX's terms. A path or
 * an error exits at the command's operand-refusal code (1, tar 2).
 */
export declare function renderDeny(subject: string, deny: Deny | Pending): [Uint8Array, number];
/**
 * Opt in by assigning a debug sink, as Python's module logger is off until
 * configured.
 */
export declare const logger: {
    debug?: (message: string) => void;
};
/**
 * `renderDeny` for a refused command whose context is at hand. A Deny about
 * a cp or mv operand says what GNU says when the step that operand's role
 * takes is refused, which the bare path line does not: the context says
 * which operand is a source and which the target, and its file view whether
 * each is a directory. Every other refusal renders as `renderDeny` renders
 * it.
 */
export declare function renderCommandDeny(subject: string, deny: Deny | Pending, ctx: CommandContext): Promise<[Uint8Array, number]>;
/**
 * The record a refused result carries beside its bash-voiced stderr. null
 * for a Deny carrying an error: that is the filesystem's own failure (a
 * busy mount root, a name that exists), whose stderr line already says
 * everything, so no policy refusal is recorded.
 */
export declare function refusalOf(action: Deny | Pending): Refusal | null;
/**
 * One line saying why, for a surface that hands the agent text rather
 * than a record; the agent adapters append it after stderr.
 */
export declare function describeRefusal(refusal: Refusal): string;
/**
 * The placement the policies agree on: their one runtime, null when none
 * placed the line, and a Deny when two disagree. Mirrors the Python
 * `agreed`.
 */
export declare function agreed(routes: readonly Route[]): Deny | Route | null;
/**
 * What a stage's answers come to, by kind: the first Deny, else the first
 * Ask, else the Route every placing answer agrees on. Mirrors the Python
 * `settled`.
 */
export declare function settled(answers: readonly (Deny | Ask)[]): Deny | Ask | null;
export declare function settled(answers: readonly (Deny | Ask | Route)[]): Deny | Ask | Route | null;
/**
 * The error an entry point throws for a policy's Deny, or for a question the host
 * has not answered, its record noted for the line running it. The message
 * says what the terminal would (`Permission denied` unless the entry point words
 * its own); the reason (or the ask id the agent quotes) rides the record,
 * on the error for a caller that catches it and on the line's result for
 * one that only reads what a command printed. `caller` is who was refused,
 * whose line notes the record; without one, the async context's line.
 */
export declare function policyDenied(action: Deny | Pending, filename: string, message?: string, caller?: Caller): PolicyDenied;
export declare function preVfsGate(policies: Policies, call: VfsCall, path: PathSpec, write: boolean, prefix: string, sessionId?: string, issuer?: symbol, access?: Pick<VfsContext, 'mode' | 'access' | 'gate'> & {
    decisions?: Decisions | null;
    final?: boolean;
    caller?: Caller;
}): Promise<void>;
/**
 * Fire postVfs at the dispatcher; a Deny, or an Ask the host has not
 * approved, drops the result with EACCES. Nothing cuts what a call returns:
 * a call that asks for a range, as a kernel or protocol mount does, must get
 * it whole. Commands and runtimes pass the same gate; a policy method's own read is exempt.
 */
export declare function postVfsGate(policies: Policies, call: VfsCall, path: PathSpec, write: boolean, prefix: string, result: unknown, sessionId?: string, issuer?: symbol, access?: Pick<VfsContext, 'mode' | 'access'> & {
    decisions?: Decisions | null;
    caller?: Caller;
}): Promise<void>;
/**
 * Fire postExecute at the workspace boundary. Returns what drops the
 * line's output (a Deny, or the ledger's answer to an Ask), else the
 * merged Limit bound for the boundary to enforce. Nothing the line did is
 * undone. A run killed while the host decides throws the abort.
 */
export declare function postExecuteGate(policies: Policies, ctx: ExecuteResultContext, claimant?: Claimant | null, signal?: AbortSignal): Promise<[Deny | Pending | null, Limit | null]>;
/**
 * Fire postCommand once a command or CLI ran and its output drained.
 * Returns what refuses it after the fact (a Deny, or the ledger's answer
 * to an Ask), which the caller turns into exit 126 and a refusal record.
 * Nothing the command did is undone. A run killed while the host decides
 * throws the abort. Mirrors the Python `post_command_gate`.
 */
export declare function postCommandGate(policies: Policies, ctx: CommandResultContext, claimant?: Claimant | null, signal?: AbortSignal): Promise<Deny | Pending | null>;
/**
 * Fire postSession once a session write landed; a Deny, or an Ask the
 * host has not approved, becomes a PolicyDenied, for the writer to put the
 * old value back before it reports. Mirrors the Python
 * `post_session_gate`.
 */
export declare function postSessionGate(policies: Policies | null, ctx: SessionContext, old: string | null): Promise<void>;
/**
 * Fire preSession on the session plane; a Deny, or an Ask the host has
 * not approved, becomes a PolicyDenied. The one seam helper the session
 * plane's writers call, so a refusal is identical however the state is
 * reached: shell builtin, command view, or a later tier. Null policies (a
 * view constructed outside a workspace) gate nothing. An Ask goes to the
 * workspace's ledger (`Policies.decisions`), inside a line too. A write a
 * method makes while it decides (`ctx.session`) throws EACCES.
 */
/**
 * Fire preNetwork as a connection is about to open; a Deny, or an Ask,
 * refuses it with EACCES, the host as the name refused. A connection opens
 * under a command that was admitted without the question, so an Ask refuses
 * like a deny. A dry run's policy deciding opens nothing to judge. Only the
 * policies that let the connection through hear how it ends, so a refusal,
 * or an abort while they decide, ends it as refused for those already
 * passed. Returns them, for `postNetworkGate` (null when none was asked, so
 * every policy hears), and the tightest Limit they answered. Mirrors
 * Python's `pre_network_gate`.
 */
export declare function preNetworkGate(policies: Policies, ctx: NetworkContext): Promise<[readonly Policy[] | null, Limit | null]>;
/**
 * Fire postNetwork once a connection is over, for every policy among
 * `passed` (null for every policy), each asked past another's answer.
 * Mirrors Python's `post_network_gate`.
 */
export declare function postNetworkGate(policies: Policies, ctx: NetworkResultContext, passed?: readonly Policy[] | null): Promise<void>;
export declare function preSessionGate(policies: Policies | null, ctx: SessionContext): Promise<void>;
/**
 * Ordered policies; at every method the first Deny wins, and every Ask is
 * put to the host.
 *
 * Built-ins are seeded first (MountRegistry registers
 * MountRootPolicy), then the document's deny rules compiled by the
 * workspace, then user policies in registration order
 * (`Workspace({policies})`, then anything added later through
 * `add`). There is no allow arm, so adding a policy can only tighten
 * the workspace, never loosen it; order decides which refusal message
 * is shown, never whether a refusal holds.
 *
 * A policy that throws fails closed: the command is refused with a
 * whole-command Deny naming the policy. A policy that returns something the method may
 * not return (VALIDITY) throws PolicyError: that is a programming
 * error, not a refusal.
 *
 * The chain holds the decision ledger an Ask is put to (`decisions`),
 * `views`, which the workspace sets to fill a method's read-only `session`
 * and `vfs`, and `account`, which a server sets to the account it holds the
 * workspace for, for every method's `caller`.
 */
export declare class Policies {
    private readonly policies;
    private readonly mode;
    private placement;
    private wanted;
    decisions: Decisions;
    views: ((sessionId: string, session?: SessionState) => (Required<Pick<RouteContext, 'session' | 'caller'>> & Pick<RouteContext, 'vfs'>) | null) | null;
    account: string | null;
    constructor(policies?: readonly Policy[]);
    /**
     * Install the built-in placement, the workspace's `routePolicy`
     * compiled as a policy, which answers `preExecute` ahead of every
     * registered one. It sits outside the fail-closed fold: a misconfigured
     * route policy throws `RouteError` to the caller rather than refusing
     * the line, since the mistake is the deployment's to fix.
     */
    place(placement: Policy | null): void;
    /**
     * True when any policy defines `method`. O(1); the op seam gates on it
     * so a workspace with no op policies pays nothing per VFS op.
     */
    wants(method: PolicyMethod): boolean;
    /**
     * True when some policy will speak at `method` for this session. The
     * per-session refinement of `wants`: a policy that defines the method
     * counts, unless it speaks per session (`SessionScopedMixin`) and says this
     * is not one of its. For a seam that pays ahead for a method rather than
     * gating on it: the secret fill drops its masks under a session-write
     * gate, and a profile's policy at that entry point is one profile's, not
     * every session's. `codedOnly` leaves the profile's rules out, for a
     * caller whose line's gate already answers for them.
     */
    wantsFor(method: PolicyMethod, sessionId: string, codedOnly?: boolean): Promise<boolean>;
    private rescan;
    /**
     * Register a policy after the existing ones. Code only: a
     * declarative rule belongs in the permissions document
     * (`commands.deny`), which the workspace compiles.
     */
    add(entry: Policy): void;
    /** Remove one registration by identity, preserving the other policies' order. Host-side only. */
    remove(entry: Policy): boolean;
    private evaluate;
    private fire;
    /**
     * The policies' answers at one stage, in the order the stage asks them,
     * each naming its policy: what `explain` shows, from the same loop the
     * entry point runs. With `every` no answer stops the loop, so a Deny does not
     * hide the answers after it; without it the answers end at the first
     * Deny, as the entry point's do. The built-in hides never answer here, since a
     * hide never surfaces; the built-in placement answers first at
     * `preExecute` and the built-in mount mode last at `preVfs`, as they do
     * at the entry point. `rulesOnly` asks the profile's rules alone, as
     * `chain` takes it. Mirrors the Python `answers`.
     */
    answers(method: PolicyMethod, ctx: MethodContext, every?: boolean, rulesOnly?: boolean): Promise<(Deny | Ask | Route)[]>;
    /** Fire preCommand across the policies; the first Deny wins, else the first Ask. */
    preCommand(ctx: CommandContext): Promise<Deny | Ask | null>;
    /** Fire postCommand across the policies; the first Deny wins, else the first Ask. */
    postCommand(ctx: CommandResultContext): Promise<Deny | Ask | null>;
    /**
     * Fire preExecute: a Deny wins, else the first Ask, which holds the
     * line until the host approves it; and the Route every placing policy
     * agrees on, two placing the line on different runtimes refusing it.
     * `placed` says the caller placed the line (the runtime argument), so
     * the built-in placement is not asked and a Route is moot; a Deny or an
     * Ask still holds the line.
     */
    preExecute(ctx: RouteContext, placed?: boolean): Promise<[Deny | Ask | null, Route | null]>;
    /**
     * Fire preVfs across the policies; the first Deny wins, else the first
     * Ask, which the entry point decides how to put. A hidden path never
     * gets here: the dispatcher's walk answers it as absent first (`sees`),
     * so a refusal never tells a session a hidden name exists. The built-in
     * mount mode answers after the policies, whether or not any policy
     * overrides the method; `rulesOnly` asks the profile's path rules alone,
     * for an op a running command makes.
     */
    preVfs(ctx: VfsContext, rulesOnly?: boolean): Promise<Deny | Ask | null>;
    /** Fire postVfs; a Deny or an Ask holds the result back. */
    postVfs(ctx: VfsResultContext): Promise<Deny | Ask | null>;
    /**
     * Fire preNetwork across the policies; the first Deny wins, else the first
     * Ask, and Limits merge to the tightest. `passed` fills, as they answer,
     * with the policies that let the connection through, and those with no
     * preNetwork.
     */
    preNetwork(ctx: NetworkContext, passed: Policy[]): Promise<[Deny | Ask | null, Limit | null]>;
    /**
     * Fire postNetwork across the policies among `among` (null for every one),
     * every one asked; none answers, since the connection is already over.
     */
    postNetwork(ctx: NetworkResultContext, among?: readonly Policy[] | null): Promise<void>;
    /** Fire postExecute; a Deny or an Ask holds the output back, Limits merge to the boundary bound. */
    postExecute(ctx: ExecuteResultContext): Promise<[Deny | Ask | null, Limit | null]>;
    /** Fire preSession across the policies; the first Deny wins, else the first Ask. */
    preSession(ctx: SessionContext): Promise<Deny | Ask | null>;
    /** Fire preWorkspace across the policies; the first Deny wins. */
    preWorkspace(ctx: WorkspaceContext): Promise<Deny | null>;
    /** Fire postSession across the policies; the first Deny wins, else the first Ask. */
    postSession(ctx: SessionResultContext): Promise<Deny | Ask | null>;
}
export {};
//# sourceMappingURL=policies.d.ts.map