/** * OpenKai tool set (P2 read trio + P4b gated mutation, scope §3 + §4). * * Read trio (`read_file`, `list_files`, `grep`) — unchanged since P2; enough for * the loop to exercise tool-calling end-to-end without mutation. * * Gated mutations (`write_file`, `edit_file`, `hashline_edit`, `bash`) — each * behind the * {@link PermissionGate} + the pure {@link evaluate} policy engine. The P2 block * ("no write/bash until the permission engine exists") is now satisfied. The * honest-posture rule (ADR §5.6) still applies: execution is not sandboxed, and * the gate is **consent, not a sandbox** — approving a `bash` call runs it * unsandboxed. Denial is a refusal result returned to the model, not a throw. * * Each tool is an {@link AgentTool} backed by a typebox parameter schema. The * `execute` callback returns an {@link AgentToolResult} whose `content` is * `TextContent[]` (the shape the model reads) and whose `details` carries the * structured payload for logs/UI. * * Hardening posture (ren's adversarial review): * - `read_file` stats first and reads at most `maxBytes` (+1 sentinel) off * disk — a multi-GB target is never buffered whole. * - `web_fetch` runs under a 30 s AbortSignal timeout and caps the response * read at 1 MiB before truncating to `maxBytes` for output. * - `grep` rejects patterns over 500 chars. ReDoS posture: patterns are * model-authored and run in-process on bounded file reads; the length cap * plus per-file/result caps keep a catastrophic-backtracking pattern a * latency problem, not a process-killer. No full ReDoS proof is attempted. * - `grep`/`glob` walkers carry a visited-realpath set, so an in-cwd symlink * cycle (a/sub -> a) terminates instead of recursing forever. * - `bash` honours the pi-agent-core AbortSignal (kills the child) and has a * 120 s default exec timeout, param-overridable. * - `write_file` re-canonicalises its target AFTER approval (TOCTOU window). */ import { Type } from "typebox"; import type { AgentTool } from "@earendil-works/pi-agent-core"; import type { PermissionGate } from "./permission-gate.js"; import type { CastConfig } from "../fusion/casts.js"; /** * Resolve + floor-check in one step, returning the refusal text when the * path is out of bounds (containment escape OR deny-floor hit). The floor * applies to every tool — read-only included; it is a boundary, not a * permission decision (E001 security findings 1–2). * * Exported for the sibling tools that need the identical boundary * (hashline_edit's pre-read guard, the LSP tool's file confinement) — one * implementation, no drift. */ export declare function guardPath(cwd: string, input: string): { target?: string; refusal?: string; }; declare const ReadFileParams: Type.TObject<{ path: Type.TString; maxBytes: Type.TOptional; }>; /** read_file: read a UTF-8 file and return its (truncated) text. */ export declare const readFileTool: (cwd: string) => AgentTool; declare const ListFilesParams: Type.TObject<{ path: Type.TOptional; }>; /** list_files: list direct children of a directory. */ export declare const listFilesTool: (cwd: string) => AgentTool; declare const GrepParams: Type.TObject<{ pattern: Type.TString; path: Type.TOptional; maxResults: Type.TOptional; }>; /** grep: search file contents for a RegExp pattern (no shell, pure JS). */ export declare const grepTool: (cwd: string) => AgentTool; declare const GlobParams: Type.TObject<{ pattern: Type.TString; path: Type.TOptional; maxResults: Type.TOptional; }>; /** glob: match files under a directory by glob pattern (no new deps). */ export declare const globTool: (cwd: string) => AgentTool; /** * True when a host LITERAL (already known to be an IP) is a non-public address. * A non-IP host returns false here — the caller resolves it via DNS first. * Exported so the security reproducer can assert the range table directly. */ export declare function isBlockedFetchAddress(host: string): boolean; declare const WebFetchParams: Type.TObject<{ url: Type.TString; maxBytes: Type.TOptional; }>; /** web_fetch: GET a URL and return the body as text (read-only). */ export declare const webFetchTool: (cwd: string) => AgentTool; declare const TodoParams: Type.TObject<{ op: Type.TUnion<[Type.TLiteral<"add">, Type.TLiteral<"done">, Type.TLiteral<"list">, Type.TLiteral<"clear">]>; text: Type.TOptional; }>; /** todo: a shared per-project task list in .openkai/memory/todo.md (multi-instance aware). */ export declare const todoTool: (cwd: string) => AgentTool; /** The read-only tool set, bound to a cwd (v1-compat path for `openkai chat`). */ export declare function readOnlyTools(cwd: string): AgentTool[]; /** * Hooks fired around gated mutations. `beforeMutation` runs AFTER approval, * BEFORE the mutation — the shadow-git snapshot seam (Inc 05). Hook failures * are swallowed by the caller: undo must never block an approved mutation. */ export interface MutationHooks { beforeMutation?: (tool: string, summary: string) => Promise; } declare const WriteFileParams: Type.TObject<{ path: Type.TString; content: Type.TString; }>; /** write_file: full-file write behind the permission gate; preview is a diff. */ export declare function writeFileTool(cwd: string, gate: PermissionGate, hooks?: MutationHooks): AgentTool; declare const EditFileParams: Type.TObject<{ path: Type.TString; oldString: Type.TString; newString: Type.TString; }>; /** edit_file: exact-match single replace behind the gate; preview is the diff. */ export declare function editFileTool(cwd: string, gate: PermissionGate, hooks?: MutationHooks): AgentTool; declare const BashParams: Type.TObject<{ command: Type.TString; cwd: Type.TOptional; timeoutSeconds: Type.TOptional; }>; /** bash: unsandboxed shell behind the gate (ADR §5.6 honest posture). */ export declare function bashTool(cwd: string, gate: PermissionGate, hooks?: MutationHooks): AgentTool; /** * The full tool set (E008: + glob/web_fetch/todo/hashline_edit/task, * E009: + lsp, E010: + mcp), bound to a cwd and a {@link PermissionGate}. * Used by the TUI; `openkai chat` keeps {@link readOnlyTools}. * `extraTools` is for dynamically discovered tools (MCP servers). * `castConfig` feeds the task tool's stage→model resolution (operator casts). */ export declare function gatedTools(cwd: string, gate: PermissionGate, hooks?: MutationHooks, modelId?: string, extraTools?: AgentTool[], castConfig?: CastConfig): AgentTool[]; export {}; //# sourceMappingURL=tools.d.ts.map