import type { ExecutionEnv } from "../../internal/harness.js"; import type { SkillManifest, ToolEffect } from "../types.js"; import type { ToolPolicy } from "../tool-policy.js"; /** One active skill frame: either a resolved manifest, or a fail-closed marker that the manifest for a * loaded skill could not be resolved (→ DENY-ALL while this frame is active). */ export type ActiveSkillFrame = { kind: "manifest"; manifest: SkillManifest; } | { kind: "unresolved"; lineageId: string; reason: string; }; /** * The per-task LIFO stack of active skill frames (design/77 §3). Owned by `prepare-task`'s closure; * the injected `skill` tool pushes onto it on a successful load, and a deny-narrowing policy reads it * on every tool call. A simple array is the stack — `push` on load, and the policy reads ALL frames * currently on it (the intersection). v1 keeps lifetime heuristic (see module header). */ export declare class ActiveSkillScope { private readonly frames; /** Push a resolved manifest frame (skill loaded successfully WITH a manifest). */ push(frame: ActiveSkillFrame): void; /** Pop the most-recently-pushed frame (LIFO). Returns it, or undefined when empty. v1 surfaces this * for the "next-skill-load pops the previous sibling frame" lifetime — see prepare-task wiring. */ pop(): ActiveSkillFrame | undefined; /** Snapshot of the live frames (a copy — callers must not mutate the stack through it). */ active(): readonly ActiveSkillFrame[]; get size(): number; } /** Path-segment-aware containment, FAMILY-AWARE ([K-PLATFORM-SWEEP] MAJOR#2: canonical keys are * backslash-form on a win32 env — the "/"-hardcoded suffix rejected every legitimate write there). * Compare in "/" form with drive-letter case folded; never keyed on process.platform (the env may be * remote and of the OTHER family than the host). */ export declare function isWithin(root: string, p: string): boolean; /** * Build the Gate-3 deny-narrowing policy over a live {@link ActiveSkillScope} (design/77 §3). For each * tool call, WHILE any skill frame is active: * - DENY any tool not in the INTERSECTION of every active frame's `allowTools`. * - For a WRITE tool with an `allowPaths` constraint on ANY active frame, DENY a write whose * canonicalized target is outside every listed prefix (reuses {@link canonicalizeTarget}, so a * symlink can't smuggle a write outside the allowed paths). * - A frame whose manifest could not be resolved (`kind:"unresolved"`) → DENY-ALL (fail-closed: no * allowlist means nothing is allowed — NOT the bare task policy). * When NO frame is active, the policy returns `allow` for everything (it only ever subtracts), leaving * the task policy unmodified — so a skill WITHOUT a manifest, or a task before any skill load, behaves * exactly as before (backward-compatible). * * This policy must be composed via `combinePolicies(scopePolicy, taskPolicy)` so its `deny` * short-circuits the fold and a task-policy `allow` can never widen it. * * `env`/`rootPath` are the SAME execution env + tracked cwd the hand tools resolve against, so * `allowPaths` matching sees the task's real filesystem (a remote/E2B task resolves in its container). */ export declare function createActiveSkillScopePolicy(opts: { scope: ActiveSkillScope; env: ExecutionEnv; rootPath?: string; /** Per-tool side-effect class (the SAME `toolEffects` map prepare-task builds). Lets the scope policy * fail CLOSED on a mutating tool that `allowPaths` can NOT confine (e.g. `bash` — no parseable path): * while an `allowPaths` constraint is active, such a tool is DENIED, never allowed to write anywhere. */ toolEffects?: ReadonlyMap; }): ToolPolicy; //# sourceMappingURL=active-skill-scope.d.ts.map