{"version":3,"file":"loader.mjs","names":[],"sources":["../src/loader.ts"],"sourcesContent":["/**\n * Permission policy loader — walk-up discovery and merge.\n *\n * Walks up from `cwd`, collecting canonical and native agent config files. Merge semantics:\n *\n * - With/without: unioned from all discovered canonical files\n * - Up: outermost canonical file wins (team controls walk-up depth)\n * - DefaultMode: last-defined wins (innermost/cwd overrides)\n * - Rules: collected from all sources, deduplicated deny-first\n *\n * Load order at each directory (innermost processed last):\n *\n * 1. `.agents/permissions.json` (team, committed)\n * 2. `.agents/permissions.local.json` (personal, gitignored)\n * 3. Native agent configs filtered by with/without\n */\n\nimport { readFile } from \"node:fs/promises\";\nimport { dirname, join, resolve } from \"node:path\";\nimport { existsSync, watch, type FSWatcher } from \"node:fs\";\n\nimport { type AgentPermissionPolicy, type Rule } from \"./schema.ts\";\nimport {\n  AGENT_FILES,\n  parseJson,\n  validatePolicy,\n  decodeNative,\n} from \"./agent-files.ts\";\nimport {\n  collectRules,\n  delegationLimits,\n  mapMode,\n  mostRestrictiveMode,\n  deduplicateRules,\n  type PermissionPolicy,\n} from \"./evaluate.ts\";\nimport { type AgentId, CODECS } from \"./compat/codecs.ts\";\nimport { isAgentId } from \"./guards.ts\";\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface PolicyLoadOptions {\n  /** Starting directory for walk-up discovery. */\n  cwd: string;\n}\n\ninterface DiscoveredFile {\n  /** Agent identifier (e.g. \"canonical\", \"claude-code\"). */\n  agent: AgentId | \"canonical\";\n  /** Absolute path to the config file. */\n  path: string;\n  /** Whether this is a local override (read-only in merge). */\n  local: boolean;\n}\n\ninterface DecodedLayer {\n  file: DiscoveredFile;\n  policy: AgentPermissionPolicy;\n}\n\n// ---------------------------------------------------------------------------\n// Walk-up discovery\n// ---------------------------------------------------------------------------\n\n/**\n * Resolve effective `up` and agent filter from all discovered canonical files.\n *\n * - `up`: outermost canonical file's value wins (team controls depth). Falls back to `\"all\"` if no\n *   canonical file specifies it.\n * - `with`/`without`: unioned across all canonical files.\n */\nfunction resolveDiscoveryConfig(canonicalLayers: DecodedLayer[]): {\n  up: number;\n  agentFilter: Set<string> | undefined;\n} {\n  let up = Infinity;\n  // Set<string>, not Set<AgentId>: the filters compare against Object.keys() output (plain strings) and carry \"canonical\" alongside agent ids.\n  const withAgents = new Set<string>();\n  const withoutAgents = new Set<string>();\n\n  // canonicalLayers are outermost-first after reverse.\n  for (const layer of canonicalLayers) {\n    const { with: w, without: wo, up: u } = layer.policy;\n    if (u !== undefined) {\n      const resolved = u === \"all\" ? Infinity : u;\n      // Outermost wins — take the first up value we see (outermost-first)\n      if (up === Infinity) {\n        up = resolved;\n      }\n    }\n    if (w !== undefined) {\n      for (const a of w) withAgents.add(a);\n    }\n    if (wo !== undefined) {\n      for (const a of wo) withoutAgents.add(a);\n    }\n  }\n\n  // Build agent filter\n  let agentFilter: Set<string> | undefined;\n  if (withAgents.size > 0 && withoutAgents.size > 0) {\n    // Invalid — a single file can't have both, and cross-file we\n    // treat the combination as: with takes precedence (most restrictive)\n    const allAgents = [...Object.keys(CODECS), \"canonical\"];\n    agentFilter = new Set([...withAgents, \"canonical\"]);\n    // Also include any agent NOT in withoutAgents\n    for (const a of allAgents) {\n      if (!withoutAgents.has(a)) {\n        agentFilter.add(a);\n      }\n    }\n  } else if (withAgents.size > 0) {\n    agentFilter = new Set([...withAgents, \"canonical\"]);\n  } else if (withoutAgents.size > 0) {\n    const allAgents = [...Object.keys(CODECS), \"canonical\"];\n    const excluded = new Set(withoutAgents);\n    agentFilter = new Set(allAgents.filter((a) => !excluded.has(a)));\n  }\n\n  // No with/without = canonical only (safe default)\n  // withAgents and withoutAgents are both empty, agentFilter stays undefined\n  // but discoverFiles still needs to know not to read native configs.\n  // We achieve this by passing a filter that only includes \"canonical\".\n  if (withAgents.size === 0 && withoutAgents.size === 0) {\n    agentFilter = new Set([\"canonical\"]);\n  }\n\n  return { up, agentFilter };\n}\n\n/**\n * Walk up from cwd, collecting agent config files. Returns files ordered outermost-first (outermost\n * layers first, innermost/cwd layers last) so that last-defined-wins merge gives cwd the highest\n * priority.\n *\n * Within each directory, committed files come before local files, so local overrides committed at\n * the same level.\n */\nfunction discoverFiles(\n  cwd: string,\n  up: number,\n  agentFilter: Set<string> | undefined,\n): DiscoveredFile[] {\n  // Collect per-directory buckets, cwd-first\n  const dirBuckets: DiscoveredFile[][] = [];\n  let current = resolve(cwd);\n  let remaining = up === Infinity ? Number.MAX_SAFE_INTEGER : up + 1;\n\n  while (remaining > 0) {\n    const bucket: DiscoveredFile[] = [];\n    for (const [key, def] of Object.entries(AGENT_FILES)) {\n      if (!isAgentId(key) && key !== \"canonical\") continue;\n      const agent: AgentId | \"canonical\" = key;\n      // Apply agent filter\n      if (agentFilter && !agentFilter.has(agent)) continue;\n\n      // Skip agents without extract (codex TOML, crush no file)\n      if (agent !== \"canonical\" && def.extract === undefined) continue;\n\n      const main = join(current, def.name);\n      if (existsSync(main)) {\n        bucket.push({ agent, path: main, local: false });\n      }\n\n      if (def.localName) {\n        const local = join(current, def.localName);\n        if (existsSync(local)) {\n          bucket.push({ agent, path: local, local: true });\n        }\n      }\n    }\n    dirBuckets.push(bucket);\n\n    remaining--;\n    const parent = dirname(current);\n    if (parent === current) break; // reached root\n    current = parent;\n  }\n\n  // Reverse directory order so outermost is first.\n  // Within each directory, committed comes before local.\n  dirBuckets.reverse();\n  return dirBuckets.flat();\n}\n\n// ---------------------------------------------------------------------------\n// Reading and decoding\n// ---------------------------------------------------------------------------\n\nasync function readFileContent(filePath: string): Promise<string | undefined> {\n  try {\n    return await readFile(filePath, \"utf-8\");\n  } catch {\n    return undefined;\n  }\n}\n\nfunction decodeFile(\n  file: DiscoveredFile,\n  raw: unknown,\n): AgentPermissionPolicy | undefined {\n  if (file.agent === \"canonical\") {\n    const result = validatePolicy(raw);\n    return result.ok ? result.value : undefined;\n  }\n\n  const result = decodeNative(file.agent, raw);\n  return result.ok ? result.value : undefined;\n}\n\n/** What reading one discovered file gave: its layer, nothing because it is gone, or why it failed. */\ntype ReadResult =\n  { layer: DecodedLayer } | { absent: true } | { failure: string };\n\nasync function readLayer(file: DiscoveredFile): Promise<ReadResult> {\n  const content = await readFileContent(file.path);\n  if (content === undefined) {\n    // A file deleted since discovery is a change, not a failure.\n    return existsSync(file.path)\n      ? { failure: `${file.path} could not be read` }\n      : { absent: true };\n  }\n\n  const parsed = parseJson(content, file.path);\n  if (!parsed.ok) return { failure: `${file.path}: ${parsed.error}` };\n\n  const policy = decodeFile(file, parsed.value);\n  if (policy === undefined) {\n    return { failure: `${file.path} is not a valid ${file.agent} policy` };\n  }\n\n  return { layer: { file, policy } };\n}\n\n/** The layers found from `cwd`, and the files that were there but could not be used. */\nasync function loadLayers(\n  cwd: string,\n): Promise<{ layers: DecodedLayer[]; failures: string[] }> {\n  const failures = new Set<string>();\n  const read = async (files: DiscoveredFile[]): Promise<DecodedLayer[]> => {\n    const layers: DecodedLayer[] = [];\n    for (const file of files) {\n      const result = await readLayer(file);\n      if (\"layer\" in result) layers.push(result.layer);\n      else if (\"failure\" in result) failures.add(result.failure);\n    }\n    return layers;\n  };\n\n  // Pass 1: discover canonical files with max walk-up to find all of them\n  const canonicalLayers = await read(\n    discoverFiles(cwd, Infinity, new Set([\"canonical\"])),\n  );\n  if (canonicalLayers.length === 0) {\n    return { layers: [], failures: [...failures] };\n  }\n\n  // Resolve discovery config from canonical files\n  const { up, agentFilter } = resolveDiscoveryConfig(canonicalLayers);\n\n  // Pass 2: discover all files using resolved config\n  const layers = await read(discoverFiles(cwd, up, agentFilter));\n  return { layers, failures: [...failures] };\n}\n\n// ---------------------------------------------------------------------------\n// Merging\n// ---------------------------------------------------------------------------\n\n/** One source of policy: a name for provenance, its policy, and whether it bounds deeper layers. */\nexport interface PolicyLayer {\n  /** What the layer came from, usually a file path; it is what `explain` reports for its rules. */\n  source: string;\n  policy: AgentPermissionPolicy;\n  /** The layer's allow rules bound what the layers after it can allow. */\n  ceiling?: boolean;\n}\n\n/**\n * Merge layers, outermost first, into one policy.\n *\n * - Rules from every layer are collected and deduplicated deny-first; each rule remembers its layer.\n * - The default mode is the innermost layer's, except after a ceiling layer, where a deeper layer can\n *   only make it stricter.\n * - Delegation limits tighten: the shallowest `maxDepth`, every `nonDelegable` rule.\n * - A ceiling layer that allows something bounds the allow rules of the layers after it (see\n *   {@link PermissionPolicy.layers}).\n */\nexport function mergeLayerPolicies(\n  layers: readonly PolicyLayer[],\n): PermissionPolicy {\n  if (layers.length === 0) {\n    return { defaultMode: \"standard\" };\n  }\n\n  let mode: PermissionPolicy[\"defaultMode\"] = \"standard\";\n  let ceilingAbove = false;\n  const allRules: Rule[] = [];\n  const provenance = new Map<Rule, string>();\n\n  for (const layer of layers) {\n    if (layer.policy.defaultMode) {\n      const layerMode = mapMode(layer.policy.defaultMode);\n      mode = ceilingAbove\n        ? mapMode(mostRestrictiveMode(mode, layerMode) ?? mode)\n        : layerMode;\n    }\n    for (const rule of collectRules(layer.policy)) {\n      allRules.push(rule);\n      provenance.set(rule, layer.source);\n    }\n    if (layer.ceiling === true) ceilingAbove = true;\n  }\n\n  const rules = deduplicateRules(allRules);\n  const delegation = delegationLimits(\n    ...layers.map((layer) => layer.policy.delegation),\n  );\n\n  return {\n    defaultMode: mode,\n    ...(rules.length > 0 ? { rules, provenance } : {}),\n    ...(layers.some((layer) => layer.ceiling === true)\n      ? {\n          layers: layers.map((layer) => ({\n            source: layer.source,\n            ceiling: layer.ceiling === true,\n          })),\n        }\n      : {}),\n    ...(delegation === undefined ? {} : { delegation }),\n  };\n}\n\nfunction mergeLayers(layers: DecodedLayer[]): PermissionPolicy {\n  return mergeLayerPolicies(\n    layers.map((layer) => ({\n      source: layer.file.path,\n      policy: layer.policy,\n      ceiling: layer.policy.ceiling === true,\n    })),\n  );\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/**\n * Load and merge permission policy from all sources.\n *\n * @throws PolicyLoadError if a layer file exists but cannot be read, parsed or validated. Skipping it\n *   would drop its rules, and the policy left could be looser than the one written.\n *\n * Two-pass process:\n *\n * 1. Discover canonical files, resolve `up`/`with`/`without` from them.\n * 2. Re-discover all files (canonical + native) using resolved config, decode, and merge.\n */\nexport async function loadPolicy(\n  options: PolicyLoadOptions,\n): Promise<PermissionPolicy> {\n  const { layers, failures } = await loadLayers(options.cwd);\n  // A file that is there but unusable must not be skipped: the policy without it can be looser.\n  if (failures.length > 0) throw new PolicyLoadError(failures);\n  return mergeLayers(layers);\n}\n\n/** Thrown by `loadPolicy`, and given to `watchPolicy`'s error callback, when a layer file is there but cannot be used. */\nexport class PolicyLoadError extends Error {\n  /** One line per file that could not be read, parsed or validated. */\n  readonly failures: readonly string[];\n\n  constructor(failures: readonly string[]) {\n    super(`policy files could not be used:\\n  ${failures.join(\"\\n  \")}`);\n    this.name = \"PolicyLoadError\";\n    this.failures = failures;\n  }\n}\n\n/** A running watch. */\nexport interface PolicyWatcher {\n  /** Stop watching; no callback runs after this returns. */\n  close(): void;\n}\n\n/** How long changes are collected before the policy is reloaded once. */\nconst RELOAD_DEBOUNCE_MS = 50;\n\n/**\n * How long after the watch starts, and after a directory starts being watched, the layers are read\n * once more. The operating system can establish a watch after `fs.watch` returns, and a change made\n * in that window is never delivered, which would leave the reported policy stale until the next\n * change.\n */\nconst SETTLE_RECHECK_MS = 250;\n\n/** The file and directory names that can hold a layer, so other changes are ignored. */\nconst RELEVANT_NAMES: ReadonlySet<string> = new Set(\n  Object.values(AGENT_FILES).flatMap((def) =>\n    [def.name, \"localName\" in def ? def.localName : undefined].flatMap(\n      (path) => (path === undefined ? [] : path.split(\"/\")),\n    ),\n  ),\n);\n\n/** The directories that hold, or could come to hold, a layer file for a walk up from `cwd`. */\nfunction directoriesToWatch(cwd: string): string[] {\n  const directories = new Set<string>();\n  let current = resolve(cwd);\n  for (;;) {\n    directories.add(current);\n    for (const def of Object.values(AGENT_FILES)) {\n      for (const name of [\n        def.name,\n        \"localName\" in def ? def.localName : undefined,\n      ]) {\n        if (name !== undefined) directories.add(dirname(join(current, name)));\n      }\n    }\n    const parent = dirname(current);\n    if (parent === current) break;\n    current = parent;\n  }\n  return [...directories].filter((directory) => existsSync(directory));\n}\n\n/** What identifies a policy for change detection: its decisions and where each rule came from. */\nfunction policyKey(policy: PermissionPolicy): string {\n  return JSON.stringify({\n    defaultMode: policy.defaultMode,\n    rules: policy.rules?.map((rule) => [rule, policy.provenance?.get(rule)]),\n    layers: policy.layers,\n    delegation: policy.delegation,\n  });\n}\n\n/**\n * Watch the layer files of a walk up from `options.cwd`. `onChange` is called with the policy as it\n * first loads, and again each time a reload gives a different one, so a host needs no separate\n * {@link loadPolicy} call: one that loaded the policy first could miss a change made while the\n * watch was starting.\n *\n * A layer file that is there but cannot be read, parsed or validated (an editor mid-write, say) is\n * reported to `onError` as a {@link PolicyLoadError}, and no policy is reported until every file\n * loads again: a policy missing that layer would be looser than the one in force.\n */\nexport function watchPolicy(\n  options: PolicyLoadOptions,\n  onChange: (policy: PermissionPolicy) => void,\n  onError: (error: Error) => void,\n): PolicyWatcher {\n  const { cwd } = options;\n  const watchers = new Map<string, FSWatcher>();\n  let timer: ReturnType<typeof setTimeout> | undefined;\n  let closed = false;\n  let lastKey: string | undefined;\n\n  /** Watch every directory that should be watched, returning whether any was new. */\n  const syncWatchers = (): boolean => {\n    let added = false;\n    const wanted = new Set(directoriesToWatch(cwd));\n    for (const [directory, watcher] of watchers) {\n      if (!wanted.has(directory)) {\n        watcher.close();\n        watchers.delete(directory);\n      }\n    }\n    for (const directory of wanted) {\n      if (watchers.has(directory)) continue;\n      try {\n        const watcher = watch(directory, (_event, filename) => {\n          if (filename === null || RELEVANT_NAMES.has(filename)) schedule();\n        });\n        watcher.on(\"error\", (error) => {\n          if (!closed) onError(error);\n        });\n        watchers.set(directory, watcher);\n        added = true;\n      } catch (error) {\n        // The directory went away between listing and watching; the next reload lists again.\n        if (!(\n          error instanceof Error &&\n          \"code\" in error &&\n          error.code === \"ENOENT\"\n        )) {\n          throw error;\n        }\n      }\n    }\n    return added;\n  };\n\n  const reload = async (): Promise<void> => {\n    const { layers, failures } = await loadLayers(cwd);\n    if (closed) return;\n    // A file created in a directory before it was watched raised no event, so read again once it is.\n    if (syncWatchers()) scheduleRecheck();\n    if (failures.length > 0) {\n      onError(new PolicyLoadError(failures));\n      return;\n    }\n    const policy = mergeLayers(layers);\n    const key = policyKey(policy);\n    if (key === lastKey) return;\n    lastKey = key;\n    onChange(policy);\n  };\n\n  // Reloads run one at a time, in the order the changes came; the first one reports the initial policy.\n  let running: Promise<void> = reload().catch((error: unknown) => {\n    if (!closed)\n      onError(error instanceof Error ? error : new Error(String(error)));\n  });\n  const schedule = (): void => {\n    if (closed) return;\n    clearTimeout(timer);\n    timer = setTimeout(() => {\n      running = running.then(reload).catch((error: unknown) => {\n        if (!closed)\n          onError(error instanceof Error ? error : new Error(String(error)));\n      });\n    }, RELOAD_DEBOUNCE_MS);\n  };\n\n  const scheduleRecheck = (): void => {\n    if (closed) return;\n    clearTimeout(recheckTimer);\n    recheckTimer = setTimeout(schedule, SETTLE_RECHECK_MS);\n  };\n  let recheckTimer: ReturnType<typeof setTimeout> | undefined;\n\n  syncWatchers();\n  scheduleRecheck();\n\n  return {\n    close() {\n      closed = true;\n      clearTimeout(timer);\n      clearTimeout(recheckTimer);\n      for (const watcher of watchers.values()) watcher.close();\n      watchers.clear();\n    },\n  };\n}\n"],"mappings":"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"}