/** * The agent permission matrix -> v2's ordered `{action, resource, effect}` rules. * * The matrix expresses a whitelist as an object keyed by tool name, with two * tricks the v2 schema cannot hold: a value may be an OBJECT of * pattern->effect (the bash escalation that made the host's official dialog * fire for the R6/R2 faces), and `"tm_*"` is a literal wildcard KEY that * matches our whole tool family. v2 takes only flat triples, so: * * - a plain `tool: "allow"|"deny"|"ask"` becomes `{action: tool, resource:"*", effect}`; * - an escalation object becomes ONE `ask` triple for that action — the object * existed only to force a dialog, and `ask` is the effect that does it. The * per-pattern precision comes back in #94, where the `evaluate` hook can * classify the actual command line (probed: `action:"shell"` carries the * whole command in `resources[0]`). * * Anything whose effect is not one of the host's three literals is DROPPED * rather than guessed at: a rule the host cannot parse is worse than no rule, * because it may fail closed on the whole agent. */ export type PermissionEffect = "allow" | "deny" | "ask"; export interface PermissionTriple { action: string; resource: string; effect: PermissionEffect; } /** * The matrix names three built-in tools differently from the host's v2 tool * ids. Measured against the live v2 surface (probed `session.context.tools`: * edit glob grep question read shell skill subagent webfetch websearch write, * plus patch/browser_*): * * bash → shell · task → subagent · apply_patch → patch * * A name with no v2 counterpart (`list`, `todowrite`, `lsp`) is NOT emitted as * a phantom rule — the caller gets it back in `unmapped` so the boot log can * say "this part of the whitelist has no v2 equivalent yet", which is a * reportable fact, unlike a rule the host will never match. */ export declare const V2_ACTION_NAMES: Readonly>; /** * RETIRED TOOLS — names the v1 personality used to register and this package * no longer ships. v1 support was removed in 1.7.0, so these are historical * names; the set survives because it still has three live jobs: * * - `v2.ts` skips them when registering, so a stale build or a future re-add * cannot slip one back onto the tool surface; * - `triplesFromAgentPermission` drops any permission rule naming one, and * `mergeTriples` reclaims such a rule from an upgraded config — an `allow` * for an action the host has never heard of claims a capability that does * not exist; * - `scripts/gen-v2-config.mjs` drops their triples from the generated * markdown for the same reason. * * Why each left: `tm_ptc_run` because the host's own Code Mode does the job * (one program, N governed calls, zero round-trips, proved against a live * session: parallel governed calls, results still offloaded through handles). * `tm_read`/`tm_grep`/`tm_bash` because the NATIVE read/grep/shell are the * better tools (paged reads, image/PDF attachment, background shell, and — * since the offload layer — they are governed too, measured at 12,902 tokens * arriving as a 78-token preview). Retiring them was only safe in that order, * which is why the governance moved to `execute.after` FIRST and this list is * the step that follows it, not the one that precedes it. */ export declare const V1_ONLY_TOOLS: ReadonlySet; /** * The file/shell ladder runs through the host's own tools, so the triples that * DENY them must not be projected: v2-session.ts deletes every literal-`deny` * action from the request, and denying `read` while `tm_read` is unregistered * would leave a role with no way to open a file at all. This is a translation * decision, not an edit to src/agents.ts — the matrix keeps its denies and the * ladder is applied at translation time. * * Both halves have to agree, so the SAME set is consulted by `toolsToRemove()` in * v2-session.ts; this constant is the one source. Letting the native file tools * back in does not lower a red line: the P2 scope ("stay inside the project + * the store dirs") is the host's own `external_directory` permission action on v2, * observed live answering `effect:"ask"` with a `permission.asked` behind it — a * real dialog where our code used to hard-throw. The two red lines the host does * NOT know about (the address policy under `webfetch`, R6 under `shell`) are the * ones `v2-guard.ts` puts into `permission.hook("evaluate")`, and that happened * BEFORE this fork, which is the ordering AGENTS.md requires. */ export declare const V2_LADDER_ACTIONS: ReadonlySet; export interface TranslateOptions { /** * With R6 on, the matrix escalates `bash` to a pattern object so the host's * OFFICIAL dialog fires. A plugin cannot raise a dialog on v2 (probed) — but * the host does honor an `ask` EFFECT it evaluates itself, so escalating the * mapped `shell` action to `ask` is the closest honest equivalent: the human * is asked, just per command rather than per pattern. #94 refines the * per-pattern half through `permission.hook("evaluate")`. */ escalateShellAsk?: boolean; /** * Which role these triples are for. Needed for the ONE tool the matrix does * not name: `tm_ledger` is not in the permission map, so nothing would ever * name it, and an unruled action is the host's default rather than our stated * rule. The lead's list is the lead's: `allow` for it, `deny` for the five * specialists, which also makes the runtime gate (`onlyAgent: "Team"`) * visible in the config the user can read. */ agentName?: string; } /** The agent `permission` block, as loosely as the config hands it to us. */ export declare function triplesFromAgentPermission(permission: Record | undefined | null, options?: TranslateOptions): { triples: PermissionTriple[]; unmapped: string[]; }; /** * Union that keeps the user's unrelated rules and lets OUR matrix decide OUR * actions (the matrix is the whitelist — that is the product's tool-surface * promise, and it must not be silently widened by a config edit half-applying * it). Idempotent: running it twice changes nothing. * * `drop` is the reclaim path for an upgrade: a rule naming an action this * package never registers (a retired tool) can only have come from us, and * leaving it behind would keep claiming a capability the host does not have. */ export declare function mergeTriples(existing: ReadonlyArray | undefined | null, ours: ReadonlyArray, drop?: ReadonlySet): { triples: PermissionTriple[]; changed: boolean; }; //# sourceMappingURL=v2-permissions.d.ts.map