{"version":3,"file":"config-DYXARgk8.mjs","names":[],"sources":["../src/utils/model-window.ts","../src/workers/workers-config.ts","../src/workers/config.ts"],"sourcesContent":["/**\n * model-window.ts — facts derivable from a bare model id.\n *\n * Shared by the worker stack (provider registry) and the session hooks\n * (context-fill). Zero imports on purpose: this leaf is bundled into hooks\n * (scripts/build-hooks.mjs) and must never drag config or path machinery\n * into a hook process.\n */\n\n/** Last-resort window when nothing on hand reports one and the model id\n *  carries no window information. */\nexport const DEFAULT_CONTEXT_WINDOW = 200_000;\n\n/** Strip a bracketed variant suffix: \"glm-5.3[1m]\" → \"glm-5.3\". The suffix\n *  selects a variant of the same base model (a context-window tier, a\n *  quantization), so the prefix is the id's family. */\nexport function stripModelVariant(model: string): string {\n  const stripped = model.replace(/\\[[^\\]]*\\]\\s*$/, \"\").trim();\n  return stripped || model;\n}\n\n/**\n * The context window a model id itself declares, or null when the id carries\n * no window information. Only the bracketed variant suffix is read\n * (\"[1m]\" → 1,000,000); a bare id says nothing and stays null so callers can\n * fall back to whatever they measured themselves.\n */\nexport function contextWindowFromModelId(model: string | null | undefined): number | null {\n  if (typeof model !== \"string\" || model === \"\") return null;\n  const m = /\\[(\\d+)m\\]$/i.exec(model.trim());\n  if (!m) return null;\n  const millions = Number(m[1]);\n  if (!Number.isFinite(millions) || millions < 1) return null;\n  return millions * 1_000_000;\n}\n","/**\n * workers-config.ts — workers.yaml: providers, model roles, class routing,\n * mcp_sets.\n *\n * config.ts's readWorkersSection/writeWorkersSection are the only callers —\n * every other module keeps talking to the WorkersConfig shape from config.ts\n * and never touches this file. That is deliberate: adding a provider used to\n * mean editing JSON inside an unrelated config blob; this module makes\n * providers/classes/mcp_sets/active a single human-editable file, documented\n * in docs/workers-config.md, while everything downstream is unchanged.\n *\n * Writes go through the `yaml` package's Document API and only touch the\n * entries that actually changed, so hand-written comments elsewhere in the\n * file — including a comment directly above an untouched provider — survive\n * byte-for-byte across `add`, `use`, `disable`, and every other mutation.\n */\n\nimport { existsSync, readFileSync, writeFileSync, chmodSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\nimport { Document, Scalar, parseDocument, type Node } from \"yaml\";\nimport { readJsonStrict, writeJsonAtomic } from \"../config/json-store.js\";\nimport { writeYamlFileAtomic, YamlStoreError } from \"../config/yaml-store.js\";\nimport { paiHomePath, resolvePaiFile, migratePaiFile, type MigrateFileResult } from \"../config/pai-home.js\";\nimport {\n  ANTHROPIC_NATIVE,\n  NATIVE_ANTHROPIC_MODELS,\n  WorkersConfigError,\n  expandHome,\n  isModelCapability,\n  parseCapabilitiesValue,\n  parseClassesValue,\n  parseMcpSetsValue,\n  parseModelsBlock,\n  parseProvider,\n  parseWorkersConfig,\n  type ClassTarget,\n  type WorkerProvider,\n} from \"./config.js\";\n\nexport const WORKERS_YAML_FILENAME = \"workers.yaml\";\n\n/**\n * Where workers.yaml lives since 2026-09-19: under the PAI_HOME namespace\n * dir (~/.claude/pai by default) — this file is per-user state that can\n * carry API keys and must never be committed, same as the rest of PAI_HOME.\n */\nfunction defaultWorkersYamlPath(): string {\n  return paiHomePath(WORKERS_YAML_FILENAME);\n}\n\n/** Briefly the canonical location between 2026-09-19's two migrations —\n *  read during the transition, never written to again. */\nfunction oldWorkersYamlPath(): string {\n  return join(homedir(), \".claude\", WORKERS_YAML_FILENAME);\n}\n\n/** Where workers.yaml lived before 2026-09-19 — read during the transition,\n *  never written to (see `pai worker config migrate`). */\nfunction legacyWorkersYamlPath(): string {\n  return join(homedir(), \".config\", \"pai\", WORKERS_YAML_FILENAME);\n}\n\n/**\n * The path any read/write of workers.yaml actually uses: PAI_WORKERS_YAML\n * (tests, power users) first, else the new PAI_HOME location if it exists,\n * else the most recent old location that is actually on disk (printing a\n * one-time notice), else the new location (the target a first write creates).\n */\nexport function workersYamlPath(): string {\n  const override = process.env.PAI_WORKERS_YAML;\n  if (override) return override;\n  return resolvePaiFile(\n    defaultWorkersYamlPath(),\n    [oldWorkersYamlPath(), legacyWorkersYamlPath()],\n    \"pai worker config migrate\"\n  );\n}\n\n/** Where a fresh write (init, migrate, relocate's destination) always\n *  targets — the new location, or PAI_WORKERS_YAML for test isolation.\n *  Never an old path: nothing is ever written there again. */\nfunction writeTargetWorkersYamlPath(): string {\n  return process.env.PAI_WORKERS_YAML ?? defaultWorkersYamlPath();\n}\n\n/**\n * One-line notice for `pai worker config check` and `pai worker providers`\n * when workers.yaml is still sitting at an old location. Null once it has\n * moved (or PAI_WORKERS_YAML is set — that always wins, nothing to migrate).\n */\nexport function workersYamlLegacyNotice(): string | null {\n  if (process.env.PAI_WORKERS_YAML) return null;\n  if (existsSync(defaultWorkersYamlPath())) return null;\n  const found = [oldWorkersYamlPath(), legacyWorkersYamlPath()].find((p) => existsSync(p));\n  if (!found) return null;\n  return `workers.yaml is still at the old location (${found}) — run \\`pai worker config migrate\\` to move it to ${defaultWorkersYamlPath()}`;\n}\n\nexport interface WorkersYamlData {\n  active: string | null;\n  providers: Record<string, WorkerProvider>;\n  classes: Record<string, ClassTarget>;\n  capabilities: Record<string, string[]>;\n  mcpSets: Record<string, string[]>;\n  nativeModels: WorkerProvider[\"models\"];\n}\n\n// ---------------------------------------------------------------------------\n// Friendly (on-disk) provider shape ↔ internal WorkerProvider\n// ---------------------------------------------------------------------------\n\n/** snake_case on-disk keys → the camelCase raw shape parseProvider expects. */\nfunction yamlProviderToRaw(y: Record<string, unknown>): Record<string, unknown> {\n  const raw: Record<string, unknown> = {};\n  if (y.enabled !== undefined) raw.enabled = y.enabled;\n  if (y.url !== undefined) raw.baseUrl = y.url;\n  if (y.key_file !== undefined) raw.keyFile = y.key_file;\n  if (y.key !== undefined) raw.key = y.key;\n  if (y.tier !== undefined) raw.costTier = y.tier;\n  if (y.models !== undefined) raw.models = y.models;\n  if (y.protocol !== undefined) raw.protocol = y.protocol;\n  if (y.engine !== undefined) raw.engine = y.engine;\n  if (y.upstream_url !== undefined) raw.upstreamUrl = y.upstream_url;\n  if (y.env !== undefined) raw.env = y.env;\n  if (y.note !== undefined) raw.note = y.note;\n  if (y.quota_probe !== undefined) raw.quotaProbe = y.quota_probe;\n  if (y.quota_skip_at !== undefined) raw.quotaSkipAt = y.quota_skip_at;\n  if (y.context_window !== undefined) raw.contextWindow = y.context_window;\n  if (y.tags !== undefined) raw.tags = y.tags;\n  if (y.usage !== undefined) raw.usage = y.usage;\n  if (y.model_tiers !== undefined) raw.modelTiers = y.model_tiers;\n  return raw;\n}\n\n/** Internal WorkerProvider → the friendly on-disk plain object for writing. */\nfunction providerToYamlPlain(p: WorkerProvider): Record<string, unknown> {\n  const y: Record<string, unknown> = {};\n  if (!p.enabled) y.enabled = false;\n  if (p.baseUrl) y.url = p.baseUrl;\n  if (p.keyFile) y.key_file = p.keyFile;\n  if (p.key) y.key = p.key;\n  if (p.costTier !== undefined) y.tier = p.costTier;\n  y.models = { ...p.models };\n  if (p.protocol && p.protocol !== \"anthropic\") y.protocol = p.protocol;\n  if (p.engine && p.engine !== \"claude\") y.engine = p.engine;\n  if (p.upstreamUrl) y.upstream_url = p.upstreamUrl;\n  if (p.env && Object.keys(p.env).length) y.env = { ...p.env };\n  if (p.note) y.note = p.note;\n  if (p.quotaProbe) y.quota_probe = p.quotaProbe;\n  if (p.quotaSkipAt !== undefined) y.quota_skip_at = p.quotaSkipAt;\n  if (p.contextWindow !== undefined) y.context_window = p.contextWindow;\n  if (p.tags?.length) y.tags = [...p.tags];\n  if (p.usage) y.usage = p.usage;\n  if (p.modelTiers) y.model_tiers = { ...p.modelTiers };\n  return y;\n}\n\n/** The builtin `anthropic` block only ever carries `builtin: true` + `models`. */\nfunction parseBuiltinAnthropic(raw: unknown, pathPrefix: string): WorkerProvider[\"models\"] {\n  if (typeof raw !== \"object\" || raw === null || Array.isArray(raw)) {\n    throw new WorkersConfigError(`${pathPrefix}: must be an object`);\n  }\n  const p = raw as Record<string, unknown>;\n  if (p.builtin !== true) {\n    throw new WorkersConfigError(\n      `${pathPrefix}: \"${ANTHROPIC_NATIVE}\" is reserved for the built-in Claude Code login — ` +\n        `set \"builtin: true\" (optionally with a \"models\" override) or rename this provider`\n    );\n  }\n  const disallowed = [\"url\", \"key_file\", \"key\", \"engine\", \"protocol\", \"upstream_url\"].filter(\n    (k) => p[k] !== undefined\n  );\n  if (disallowed.length) {\n    throw new WorkersConfigError(\n      `${pathPrefix}: a builtin provider cannot set ${disallowed.join(\", \")} — it runs on Claude Code's own login`\n    );\n  }\n  if (p.models === undefined) return { ...NATIVE_ANTHROPIC_MODELS };\n  return parseModelsBlock(`${pathPrefix}.models`, p.models);\n}\n\n// ---------------------------------------------------------------------------\n// Line-numbered errors\n// ---------------------------------------------------------------------------\n\nfunction lineOf(doc: Document, path: (string | number)[]): number | null {\n  try {\n    const node = doc.getIn(path, true) as Node | undefined;\n    const range = node && typeof node === \"object\" && \"range\" in node ? node.range : undefined;\n    if (!range) return null;\n    const text = String(doc);\n    return text.slice(0, range[0]).split(\"\\n\").length;\n  } catch {\n    return null;\n  }\n}\n\nfunction withLine(doc: Document, path: (string | number)[], yamlPath: string, e: unknown): never {\n  const msg = e instanceof Error ? e.message : String(e);\n  const line = lineOf(doc, path);\n  throw new WorkersConfigError(line ? `${yamlPath}:${line}: ${msg}` : `${yamlPath}: ${msg}`);\n}\n\n// ---------------------------------------------------------------------------\n// Load + validate\n// ---------------------------------------------------------------------------\n\n/**\n * Parse and fully validate a workers.yaml Document. Throws WorkersConfigError\n * naming `<path>:<line>` for anything wrong — an unknown provider referenced\n * by a class is a load error here, not a spawn-time surprise.\n */\nexport function parseWorkersYamlDocument(doc: Document, yamlPath: string): WorkersYamlData {\n  const root = doc.toJS() ?? {};\n  if (typeof root !== \"object\" || Array.isArray(root)) {\n    throw new WorkersConfigError(`${yamlPath}: top level must be a mapping`);\n  }\n  const r = root as Record<string, unknown>;\n\n  const providers: Record<string, WorkerProvider> = {};\n  let nativeModels: WorkerProvider[\"models\"] = { ...NATIVE_ANTHROPIC_MODELS };\n  const providersRaw = r.providers;\n  if (providersRaw !== undefined) {\n    if (typeof providersRaw !== \"object\" || providersRaw === null || Array.isArray(providersRaw)) {\n      withLine(doc, [\"providers\"], yamlPath, new WorkersConfigError(\"providers: must be a mapping of name → provider\"));\n    }\n    for (const [name, raw] of Object.entries(providersRaw as Record<string, unknown>)) {\n      try {\n        if (name === ANTHROPIC_NATIVE) {\n          nativeModels = parseBuiltinAnthropic(raw, `providers.${name}`);\n        } else {\n          providers[name] = parseProvider(name, yamlProviderToRaw(raw as Record<string, unknown>));\n        }\n      } catch (e) {\n        withLine(doc, [\"providers\", name], yamlPath, e);\n      }\n    }\n  }\n\n  let classes: Record<string, ClassTarget> = {};\n  if (r.classes !== undefined) {\n    try {\n      classes = parseClassesValue(r.classes, \"classes\");\n    } catch (e) {\n      withLine(doc, [\"classes\"], yamlPath, e);\n    }\n    // Cross-validate: every class must name a known provider (or \"anthropic\")\n    // and, if it names a role, a capability that provider actually declares.\n    // Unlike the JSON path (where a provider can be removed out from under a\n    // class and the error surfaces at spawn time), workers.yaml catches this\n    // at load time.\n    for (const [cls, target] of Object.entries(classes)) {\n      const provider = typeof target === \"string\" ? target.split(\"/\")[0] : target.provider;\n      const alias = typeof target === \"string\" ? target.split(\"/\")[1] : undefined;\n      if (provider !== undefined) {\n        const native = provider === ANTHROPIC_NATIVE;\n        if (!native && !providers[provider]) {\n          withLine(\n            doc,\n            [\"classes\", cls],\n            yamlPath,\n            new WorkersConfigError(\n              `classes.${cls}: no provider named \"${provider}\" (configured: ${Object.keys(providers).join(\", \") || \"(none)\"})`\n            )\n          );\n        }\n        if (alias !== undefined) {\n          if (!isModelCapability(alias)) {\n            withLine(\n              doc,\n              [\"classes\", cls],\n              yamlPath,\n              new WorkersConfigError(\n                `classes.${cls}: \"${alias}\" is not a valid capability name (must match ^[a-z][a-z0-9-]*$)`\n              )\n            );\n          } else if (!native && providers[provider] && alias !== \"default\" && !providers[provider].models[alias]) {\n            // the native provider has no configurable model slots — any\n            // alias resolves through resolveModelCapability's own fallback\n            withLine(\n              doc,\n              [\"classes\", cls],\n              yamlPath,\n              new WorkersConfigError(`classes.${cls}: provider \"${provider}\" has no \"${alias}\" model configured`)\n            );\n          }\n        }\n      }\n    }\n  }\n\n  let capabilities: Record<string, string[]> = {};\n  if (r.capabilities !== undefined) {\n    try {\n      capabilities = parseCapabilitiesValue(r.capabilities, \"capabilities\");\n    } catch (e) {\n      withLine(doc, [\"capabilities\"], yamlPath, e);\n    }\n  }\n\n  let mcpSets: Record<string, string[]> = {};\n  if (r.mcp_sets !== undefined) {\n    try {\n      mcpSets = parseMcpSetsValue(r.mcp_sets, \"mcp_sets\");\n    } catch (e) {\n      withLine(doc, [\"mcp_sets\"], yamlPath, e);\n    }\n  } else {\n    mcpSets = parseMcpSetsValue(undefined, \"mcp_sets\");\n  }\n\n  const active = r.active === undefined || r.active === null ? null : String(r.active);\n  if (active !== null && active !== ANTHROPIC_NATIVE && active !== \"auto\" && !providers[active]) {\n    withLine(\n      doc,\n      [\"active\"],\n      yamlPath,\n      new WorkersConfigError(\n        `active: no provider named \"${active}\" (configured: ${Object.keys(providers).join(\", \") || \"(none)\"})`\n      )\n    );\n  }\n\n  return { active, providers, classes, capabilities, mcpSets, nativeModels };\n}\n\n/** Read + parse workers.yaml. Returns null if the file does not exist. */\nexport function readWorkersYaml(yamlPath: string): { doc: Document; data: WorkersYamlData } | null {\n  if (!existsSync(yamlPath)) return null;\n  let text: string;\n  try {\n    text = readFileSync(yamlPath, \"utf8\");\n  } catch (e) {\n    throw new WorkersConfigError(\n      `Could not read ${yamlPath}: ${e instanceof Error ? e.message : String(e)}`\n    );\n  }\n  const doc = parseDocument(text);\n  if (doc.errors.length) {\n    throw new WorkersConfigError(`${yamlPath}: ${doc.errors[0].message}`);\n  }\n  const data = parseWorkersYamlDocument(doc, yamlPath);\n  return { doc, data };\n}\n\n// ---------------------------------------------------------------------------\n// Write (diff-based, comment-preserving)\n// ---------------------------------------------------------------------------\n\nfunction shallowEqual(a: unknown, b: unknown): boolean {\n  return JSON.stringify(a) === JSON.stringify(b);\n}\n\n/**\n * A `key:` value as an explicit double-quoted YAML scalar. A key is an\n * opaque token, not YAML-authored text — plain-scalar auto-styling could\n * read one back as a number or boolean (an all-digit token, \"true\", \"no\", …)\n * if it were ever left unquoted, so every write forces the quoted form\n * regardless of what the plain style would otherwise pick.\n */\nfunction quotedKeyNode(value: string): Scalar {\n  const s = new Scalar(value);\n  s.type = Scalar.QUOTE_DOUBLE;\n  return s;\n}\n\n/**\n * Apply the changes between `before` and `after` onto `doc`, touching only\n * the providers/classes/mcp_sets/active entries that actually differ. This is\n * what makes comment preservation possible: an untouched provider's node\n * (and any comment above it) is never revisited.\n */\nfunction syncWorkersYamlDocument(doc: Document, before: WorkersYamlData, after: WorkersYamlData): void {\n  // providers: add/update changed, remove gone (never touch the builtin anthropic block)\n  for (const [name, p] of Object.entries(after.providers)) {\n    const beforeP = before.providers[name];\n    const changed = !beforeP || !shallowEqual(providerToYamlPlain(beforeP), providerToYamlPlain(p));\n    if (changed) {\n      // a fresh (or wholesale-replaced) provider entry is set in one shot as\n      // a plain object — the yaml lib only turns it into real Map/Scalar\n      // nodes lazily at stringify time, so a follow-up setIn/deleteIn into\n      // the same not-yet-a-collection value would fail. Embedding the `key`\n      // as an actual Scalar node here rides along: stringify leaves already-\n      // Node values alone (see stringifyPair.js), quoting only that field.\n      const y: Record<string, unknown> = providerToYamlPlain(p);\n      if (typeof y.key === \"string\") y.key = quotedKeyNode(y.key);\n      doc.setIn([\"providers\", name], y);\n    }\n  }\n  for (const name of Object.keys(before.providers)) {\n    if (!(name in after.providers)) doc.deleteIn([\"providers\", name]);\n  }\n\n  // classes: same add/update/remove diff\n  for (const [cls, target] of Object.entries(after.classes)) {\n    if (!shallowEqual(before.classes[cls], target)) {\n      doc.setIn([\"classes\", cls], target);\n    }\n  }\n  for (const cls of Object.keys(before.classes)) {\n    if (!(cls in after.classes)) doc.deleteIn([\"classes\", cls]);\n  }\n\n  // capabilities: same add/update/remove diff\n  for (const [cap, prefs] of Object.entries(after.capabilities)) {\n    if (!shallowEqual(before.capabilities[cap], prefs)) {\n      doc.setIn([\"capabilities\", cap], [...prefs]);\n    }\n  }\n  for (const cap of Object.keys(before.capabilities)) {\n    if (!(cap in after.capabilities)) doc.deleteIn([\"capabilities\", cap]);\n  }\n\n  // mcp_sets: same add/update/remove diff\n  for (const [set, servers] of Object.entries(after.mcpSets)) {\n    if (!shallowEqual(before.mcpSets[set], servers)) {\n      doc.setIn([\"mcp_sets\", set], [...servers]);\n    }\n  }\n  for (const set of Object.keys(before.mcpSets)) {\n    if (!(set in after.mcpSets)) doc.deleteIn([\"mcp_sets\", set]);\n  }\n\n  // active\n  if (before.active !== after.active) {\n    if (after.active === null) doc.deleteIn([\"active\"]);\n    else doc.setIn([\"active\"], after.active);\n  }\n}\n\n/**\n * Write `after` into workers.yaml, preserving comments on everything that did\n * not change. Re-reads the file fresh (so the diff is against what is really\n * on disk, not a stale in-memory copy) and re-validates the result before\n * committing; on failure the previous bytes are left untouched.\n */\nexport function writeWorkersYaml(yamlPath: string, after: WorkersYamlData): void {\n  const existing = readWorkersYaml(yamlPath);\n  const doc = existing ? existing.doc : new Document({});\n  const before: WorkersYamlData = existing\n    ? existing.data\n    : {\n        active: null,\n        providers: {},\n        classes: {},\n        capabilities: {},\n        mcpSets: {},\n        nativeModels: { ...NATIVE_ANTHROPIC_MODELS },\n      };\n  syncWorkersYamlDocument(doc, before, after);\n  writeWorkersYamlText(yamlPath, String(doc));\n}\n\n/** Atomic write with a .bak-pai backup and a re-validate-or-restore guard.\n *  The file-I/O tail (backup, temp write at 0600, rename, chmod) is shared\n *  with every other PAI YAML file via writeYamlFileAtomic; only the\n *  workers.yaml-specific validation (parseWorkersYamlDocument) lives here. */\nexport function writeWorkersYamlText(yamlPath: string, text: string): void {\n  // Validate before committing anything to disk.\n  const probe = parseDocument(text);\n  if (probe.errors.length) {\n    throw new WorkersConfigError(`refusing to write ${yamlPath}: ${probe.errors[0].message} (previous file left unchanged)`);\n  }\n  try {\n    parseWorkersYamlDocument(probe, yamlPath);\n  } catch (e) {\n    const msg = e instanceof Error ? e.message : String(e);\n    throw new WorkersConfigError(`refusing to write ${yamlPath}: ${msg} (previous file left unchanged)`);\n  }\n\n  try {\n    writeYamlFileAtomic(yamlPath, text, { label: yamlPath });\n  } catch (e) {\n    throw new WorkersConfigError(e instanceof YamlStoreError ? e.message : String(e instanceof Error ? e.message : e));\n  }\n}\n\n// ---------------------------------------------------------------------------\n// Starter template, init, migrate\n// ---------------------------------------------------------------------------\n\n/** The exact commented starter shipped as examples/workers.yaml and by `init`. */\nexport function starterWorkersYamlText(): string {\n  return `# PAI worker configuration.\n# Providers PAI can run workers on, the model each role uses, and which\n# provider every --class goes to. Edit by hand; \\`pai worker providers\\` shows\n# the effective result. Comments are preserved when PAI writes this file.\n#\n# Per-user state, kept 0600: this file can hold API keys (\\`key:\\`, below).\n# Never commit it or share it. \\`key_file: <path>\\` keeps a secret in its own\n# 0600 file instead, if you'd rather not put it here.\n\nactive: anthropic          # provider for \\`pai worker run\\` without --provider or --class\n\nproviders:\n  anthropic:\n    builtin: true          # Claude Code's own login: no url, no key file\n    models:\n      default: ${NATIVE_ANTHROPIC_MODELS.default}\n      fast: ${NATIVE_ANTHROPIC_MODELS.fast}\n  glm:\n    url: https://api.z.ai/api/anthropic\n    key: \"<your-api-key>\"   # or key_file: <path to a 0600 file>\n    tier: 3\n    models:\n      default: glm-5.3[1m]\n      fast: glm-5.3-flash\n      image: example-paint\n  kimi:\n    url: https://api.kimi.ai/coding/\n    key: \"<your-api-key>\"   # or key_file: <path to a 0600 file>\n    tier: 3\n    models:\n      default: k3[1m]\n      fast: kimi-for-coding[1m]\n\n# An \\`engine: image\\` provider does not spawn Claude — \\`pai worker run\n# --capability image\\` POSTs straight to its OpenAI-compatible images API and\n# writes the PNG it gets back. Uncomment and point it at a real provider\n# (still nested under providers:, above) to enable \\`--capability image\\`:\n#   pictures:\n#     engine: image\n#     url: https://api.example.com/v1\n#     key: \"<your-api-key>\"\n#     models:\n#       default: example-image-model\n#       image: example-image-model\n\n# A class names a provider, or provider/role to pick a non-default model.\n# Workers exist to parallelise and to save cost: the default is Sonnet,\n# Haiku for the mechanical classes, and nothing here inherits the\n# orchestrating session's model.\nclasses:\n  implement: anthropic\n  draft: anthropic\n  research: anthropic\n  complex: anthropic\n  plan: anthropic\n  review: anthropic\n  spotcheck: anthropic/fast\n  simple: anthropic/fast\n  image: glm/image\n\n# Cross-provider capability preference: which provider serves a --capability\n# request, in order, when more than one declares it. Unlisted capabilities\n# fall back to the active provider, then any provider that declares them.\n# capabilities:\n#   image: [pictures, glm]\n#   fast: [anthropic]\n\nmcp_sets:\n  desktop: [clickr]\n`;\n}\n\n/**\n * Build a workers.yaml document from real (migrated) data, keeping the same\n * header/section comments as the starter. Used by `pai worker config\n * migrate` — `init` writes the literal starter instead, since it has no data\n * to carry over.\n */\nexport function buildWorkersYamlText(data: WorkersYamlData): string {\n  const lines: string[] = [];\n  lines.push(\"# PAI worker configuration.\");\n  lines.push(\"# Providers PAI can run workers on, the model each role uses, and which\");\n  lines.push(\"# provider every --class goes to. Edit by hand; `pai worker providers` shows\");\n  lines.push(\"# the effective result. Comments are preserved when PAI writes this file.\");\n  lines.push(\"\");\n  lines.push(\n    `active: ${data.active ?? \"null\"}` +\n      \"          # provider for `pai worker run` without --provider or --class\"\n  );\n  lines.push(\"\");\n  lines.push(\"providers:\");\n  lines.push(\"  anthropic:\");\n  lines.push(\"    builtin: true          # Claude Code's own login: no url, no key file\");\n  lines.push(\"    models:\");\n  lines.push(`      default: ${data.nativeModels.default}`);\n  if (data.nativeModels.fast) lines.push(`      fast: ${data.nativeModels.fast}`);\n  if (data.nativeModels.image) lines.push(`      image: ${data.nativeModels.image}`);\n  for (const [name, p] of Object.entries(data.providers)) {\n    const y = providerToYamlPlain(p);\n    lines.push(`  ${name}:`);\n    for (const [k, v] of Object.entries(y)) {\n      if (k === \"models\") continue;\n      // a key is an opaque token, not YAML-authored text — always quoted so\n      // it never round-trips as a number or boolean (see quotedKeyNode).\n      lines.push(k === \"key\" ? `    key: ${JSON.stringify(String(v))}` : `    ${k}: ${yamlScalar(v)}`);\n    }\n    lines.push(\"    models:\");\n    for (const [k, v] of Object.entries(p.models)) lines.push(`      ${k}: ${yamlScalar(v)}`);\n  }\n  lines.push(\"\");\n  lines.push(\"# A class names a provider, or provider/role to pick a non-default model.\");\n  lines.push(\"# Workers exist to parallelise and to save cost: the default is Sonnet,\");\n  lines.push(\"# Haiku for the mechanical classes, and nothing here inherits the\");\n  lines.push(\"# orchestrating session's model.\");\n  const classEntries = Object.entries(data.classes);\n  lines.push(classEntries.length ? \"classes:\" : \"classes: {}\");\n  for (const [cls, target] of classEntries) {\n    lines.push(`  ${cls}: ${typeof target === \"string\" ? target : yamlScalar(target)}`);\n  }\n  lines.push(\"\");\n  const capEntries = Object.entries(data.capabilities);\n  if (capEntries.length) {\n    lines.push(\"capabilities:\");\n    for (const [cap, prefs] of capEntries) lines.push(`  ${cap}: [${prefs.join(\", \")}]`);\n    lines.push(\"\");\n  }\n  const mcpEntries = Object.entries(data.mcpSets);\n  lines.push(mcpEntries.length ? \"mcp_sets:\" : \"mcp_sets: {}\");\n  for (const [set, servers] of mcpEntries) {\n    lines.push(`  ${set}: [${servers.join(\", \")}]`);\n  }\n  lines.push(\"\");\n  return lines.join(\"\\n\");\n}\n\n/** Minimal scalar formatter for buildWorkersYamlText's flat key: value lines. */\nfunction yamlScalar(v: unknown): string {\n  if (typeof v === \"string\") {\n    // quote only when the plain form would be ambiguous YAML\n    return /^[\\w./~\\[\\]-]+$/.test(v) ? v : JSON.stringify(v);\n  }\n  if (Array.isArray(v)) return `[${v.map(yamlScalar).join(\", \")}]`;\n  if (v && typeof v === \"object\") return JSON.stringify(v);\n  return String(v);\n}\n\n// ---------------------------------------------------------------------------\n// Migration from the JSON `workers` section\n// ---------------------------------------------------------------------------\n\nexport interface MigrateResult {\n  yamlPath: string;\n  yamlText: string;\n  /** Path the pre-migration JSON `workers` section was backed up to; null on a dry run. */\n  backupPath: string | null;\n  dryRun: boolean;\n}\n\n/**\n * `pai worker config migrate`: reads the JSON `workers` section, writes\n * workers.yaml with the starter's comments, backs the JSON section up to\n * `workers.json.migrated-<date>` next to it, and strips providers/classes\n * (and the legacy `roles`)/mcpSets/active from the JSON. Idempotent: refuses\n * when workers.yaml already exists unless `force`. `dryRun` computes and\n * returns the would-be YAML text without touching either file.\n */\nexport function migrateWorkersToYaml(\n  jsonPath: string,\n  opts: { force?: boolean; dryRun?: boolean } = {}\n): MigrateResult {\n  const existing = workersYamlPath();\n  if (existsSync(existing) && !opts.force) {\n    throw new WorkersConfigError(\n      `${existing} already exists — refusing to overwrite without --force`\n    );\n  }\n  const yamlPath = writeTargetWorkersYamlPath();\n  const raw = readJsonStrict(jsonPath, jsonPath);\n  const workers = parseWorkersConfig(raw.workers);\n  const data: WorkersYamlData = {\n    active: workers.active,\n    providers: workers.providers,\n    classes: workers.classes,\n    capabilities: workers.capabilities,\n    mcpSets: workers.mcpSets,\n    nativeModels: workers.nativeModels,\n  };\n  const yamlText = buildWorkersYamlText(data);\n\n  if (opts.dryRun) {\n    return { yamlPath, yamlText, backupPath: null, dryRun: true };\n  }\n\n  writeWorkersYamlText(yamlPath, yamlText);\n\n  const stamp = new Date().toISOString().slice(0, 10);\n  const backupPath = join(dirname(jsonPath), `workers.json.migrated-${stamp}`);\n  writeFileSync(backupPath, JSON.stringify(raw.workers ?? {}, null, 2) + \"\\n\", \"utf8\");\n\n  const priorWorkers = (raw.workers as Record<string, unknown>) ?? {};\n  const { providers: _p, classes: _c, roles: _r, mcpSets: _m, active: _a, ...rest } = priorWorkers;\n  raw.workers = rest;\n  writeJsonAtomic(jsonPath, raw, { label: jsonPath });\n\n  return { yamlPath, yamlText, backupPath, dryRun: false };\n}\n\n/**\n * `pai worker config init`: write the literal commented starter (no data to\n * carry over — that is what `migrate` is for). Refuses if workers.yaml\n * already exists.\n */\nexport function initWorkersYaml(): string {\n  const existing = workersYamlPath();\n  if (existsSync(existing)) {\n    throw new WorkersConfigError(\n      `${existing} already exists — edit it directly, or run \\`pai worker config migrate --force\\` to regenerate it from the JSON config`\n    );\n  }\n  const yamlPath = writeTargetWorkersYamlPath();\n  writeWorkersYamlText(yamlPath, starterWorkersYamlText());\n  return yamlPath;\n}\n\n// ---------------------------------------------------------------------------\n// Relocating from an old location\n// ---------------------------------------------------------------------------\n\nexport type RelocateResult = MigrateFileResult;\n\n/** True when an old-location workers.yaml exists and nothing is at the new one yet. */\nexport function needsWorkersYamlRelocation(): boolean {\n  return (\n    !process.env.PAI_WORKERS_YAML &&\n    !existsSync(defaultWorkersYamlPath()) &&\n    [oldWorkersYamlPath(), legacyWorkersYamlPath()].some((p) => existsSync(p))\n  );\n}\n\n/**\n * `pai worker config migrate` when workers.yaml is still at an old location\n * (~/.claude/workers.yaml or, older still, ~/.config/pai/workers.yaml): a\n * byte-for-byte copy to the new path (comments, keys, everything — this only\n * changes where the file lives), verified, then the old file is renamed\n * aside as workers.yaml.migrated-<YYYYMMDD> (never deleted). No JSON\n * involved, and no secrets are read or transformed beyond copying bytes.\n */\nexport function relocateWorkersYaml(opts: { force?: boolean; dryRun?: boolean } = {}): RelocateResult {\n  const toPath = writeTargetWorkersYamlPath();\n  const result = migratePaiFile(toPath, [oldWorkersYamlPath(), legacyWorkersYamlPath()], opts);\n  if (!result.dryRun && result.fromPath) chmodSync(toPath, 0o600);\n  return result;\n}\n\n// ---------------------------------------------------------------------------\n// Inlining key_file contents as `key:`\n// ---------------------------------------------------------------------------\n\nexport interface InlineKeysResult {\n  yamlPath: string;\n  inlined: { provider: string; keyFilePath: string }[];\n  dryRun: boolean;\n}\n\n/**\n * `pai worker config inline-keys`: for every provider with a `key_file` and\n * no `key`, read the file, write its trimmed contents as a quoted `key:`,\n * and remove `key_file`. The key file itself is left on disk — this only\n * changes what workers.yaml reads from, never deletes a credential the\n * operator might still want. `dryRun` computes the plan (provider names and\n * key file paths only — never the key values) without writing anything.\n */\nexport function inlineWorkersYamlKeys(opts: { dryRun?: boolean } = {}): InlineKeysResult {\n  const yamlPath = workersYamlPath();\n  const existing = readWorkersYaml(yamlPath);\n  if (!existing) {\n    throw new WorkersConfigError(`${yamlPath} does not exist — run \\`pai worker config init\\` first`);\n  }\n  const { doc, data } = existing;\n  const inlined: { provider: string; keyFilePath: string }[] = [];\n  for (const [name, p] of Object.entries(data.providers)) {\n    if (p.key || !p.keyFile) continue;\n    const keyPath = expandHome(p.keyFile);\n    let content: string;\n    try {\n      content = readFileSync(keyPath, \"utf8\");\n    } catch (e) {\n      throw new WorkersConfigError(\n        `providers.${name}.key_file: could not read ${keyPath}: ${e instanceof Error ? e.message : String(e)}`\n      );\n    }\n    const token = content.trim();\n    if (!token) throw new WorkersConfigError(`providers.${name}.key_file: ${keyPath} is empty`);\n    inlined.push({ provider: name, keyFilePath: p.keyFile });\n    if (!opts.dryRun) {\n      doc.setIn([\"providers\", name, \"key\"], quotedKeyNode(token));\n      doc.deleteIn([\"providers\", name, \"key_file\"]);\n    }\n  }\n  if (!opts.dryRun && inlined.length) {\n    writeWorkersYamlText(yamlPath, String(doc));\n  }\n  return { yamlPath, inlined, dryRun: !!opts.dryRun };\n}\n","/**\n * config.ts — the `workers` section of the PAI config file (CONFIG_FILE,\n * see src/daemon/config.ts's paiConfigFilePath — ~/.claude/pai/config.yaml\n * today, config.json until `pai config yaml` runs).\n *\n * Everything that knows about worker providers reads this module: the CLI\n * (`pai worker …`), the MCP tools (worker_*), and the Agent-routing hook.\n * Keep it free of commander/MCP imports so all three layers stay thin over it.\n *\n * Keys are never stored here — only paths to 0600 files. A provider without a\n * keyFile is a local server and gets the placeholder token \"local\".\n *\n * `protocol: \"openai\"` providers run through the PAI proxy (src/workers/proxy):\n * `upstreamUrl` is their Chat Completions base, and `run` points\n * ANTHROPIC_BASE_URL at the local proxy with the provider name in the path.\n * `engine: \"codex\"` providers run through the Codex CLI instead of Claude\n * Code.\n */\n\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { CONFIG_FILE, readMainConfigRaw, writeMainConfigRaw } from \"../daemon/config.js\";\nimport { paiHomePath } from \"../config/pai-home.js\";\nimport { contextWindowFromModelId, DEFAULT_CONTEXT_WINDOW } from \"../utils/model-window.js\";\nimport { readWorkersYaml, workersYamlPath, writeWorkersYaml, type WorkersYamlData } from \"./workers-config.js\";\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/**\n * Wire protocol a provider speaks: \"anthropic\" natively, \"openai\" through the\n * PAI proxy (which translates the Anthropic Messages API to Chat Completions).\n */\nexport type WorkerProtocol = \"anthropic\" | \"openai\";\n\n/**\n * Runner executable behind a provider: Claude Code, the Codex CLI, or the\n * \"image\" engine (src/workers/engines/image.ts — an OpenAI-compatible\n * images API, not a claude/codex spawn).\n */\nexport type WorkerEngine = \"claude\" | \"codex\" | \"image\";\n\n/** One quota window the statusline renders for a provider (e.g. \"5h\", \"7d\"). */\nexport interface UsageWindow {\n  /** Window label shown in the statusline, e.g. \"5h\". */\n  name: string;\n  /** jq expression against the usage response yielding a percent 0–100. */\n  percent: string;\n  /** jq expression against the usage response yielding the reset time. */\n  resetAt?: string;\n  /** How resetAt is interpreted: epoch ms (default), epoch s, or ISO string. */\n  resetUnit?: \"ms\" | \"s\" | \"iso\";\n}\n\n/**\n * How the statusline fetches and renders a provider's plan quota. The block\n * names a JSON GET endpoint plus per-window jq expressions, so a new provider\n * is config, not code in statusline-command.sh.\n */\nexport interface ProviderUsage {\n  /** GET endpoint returning the usage JSON. */\n  url: string;\n  /**\n   * Auth header template, default \"Authorization: Bearer\"; the key from\n   * keyFile is appended after a space. A value without a space (e.g.\n   * \"x-api-key\") is sent as \"<authHeader>: <key>\".\n   */\n  authHeader?: string;\n  /** Display label for the usage segments, default = provider name. */\n  label?: string;\n  windows: UsageWindow[];\n  /** Statusline cache TTL in seconds, default 60. */\n  ttlSeconds?: number;\n}\n\nexport interface WorkerProvider {\n  enabled: boolean;\n  /** Wire protocol the baseUrl speaks. */\n  protocol: WorkerProtocol;\n  /** Anthropic-compatible Messages API base. */\n  baseUrl: string;\n  /** 0600 file holding the auth token; null for local servers (\"local\"). */\n  keyFile: string | null;\n  /**\n   * The auth token itself, inline in workers.yaml. Wins over keyFile when\n   * both are set (`pai worker config check` notices this). Keeping the key\n   * out of a separate file is the operator's explicit call — the file this\n   * lives in must be 0600 (writeWorkersYamlText enforces that) and is never\n   * committed. See resolveProviderKey for the one place this is read.\n   */\n  key?: string;\n  /** Model id per capability; see MODEL_CAPABILITIES. Only default is required. */\n  models: { default: string } & Partial<Record<ModelCapability, string>>;\n  /**\n   * Model id → tier alias, overriding the built-in mapping (models.fast →\n   * haiku tier, models.default → sonnet tier). Lets a provider pin an extra\n   * model id to a tier, e.g. a heavyweight default to the opus tier.\n   */\n  modelTiers?: Record<string, ModelTier>;\n  /** Extra environment variables for runs through this provider (string values). */\n  env: Record<string, string>;\n  note?: string;\n  /**\n   * OpenAI Chat Completions base (e.g. \"https://api.openai.com/v1\"). Required\n   * for protocol \"openai\"; read by the PAI proxy, never by the runner.\n   */\n  upstreamUrl?: string;\n  /** Runner for this provider; \"codex\" goes through the Codex CLI. */\n  engine?: WorkerEngine;\n  /** Optional shell command printing 0–100 (percent of quota used). */\n  quotaProbe?: string;\n  /** Auto-routing skips the provider at or above this percentage. Default 95. */\n  quotaSkipAt?: number;\n  /**\n   * Context window of the provider's model, for the context meter. No\n   * default: the meter only shows a window the init event announced (or\n   * this explicit value, for engines without one, e.g. codex).\n   */\n  contextWindow?: number;\n  /** Cost tier 1 (cheapest) … 5 (most expensive); classes cap it via maxCostTier. */\n  costTier?: number;\n  /** Capability tags; classes filter auto-routing via requireTags. */\n  tags?: ProviderTag[];\n  /** Statusline plan-quota block; see ProviderUsage. Absent = \"usage n/a\". */\n  usage?: ProviderUsage;\n  /**\n   * True only for the synthetic built-in \"anthropic\" provider (see\n   * ANTHROPIC_NATIVE): plain Claude Code, on its own OAuth/Max-plan login —\n   * no baseUrl, no key file, no config entry. Never set by parseProvider.\n   */\n  native?: boolean;\n}\n\n/**\n * Reserved provider name for plain Anthropic: Claude Code's own OAuth/Max-plan\n * login, no base URL override and no API key. It never needs (or accepts) a\n * `providers.anthropic` config entry — resolveTarget/mustExist synthesize it\n * on demand via `nativeAnthropicProvider()`.\n */\nexport const ANTHROPIC_NATIVE = \"anthropic\";\n\n/**\n * Models the built-in provider runs on. This is the only place a model id is\n * named for it: run.ts resolves the class capability against this table like\n * it does for any configured provider and passes `--model` explicitly.\n *\n * Workers exist to parallelise and to save cost, so they must never inherit\n * the orchestrator's model. A bare headless `claude` takes the interactive\n * session default, and one probe came up on the most expensive tier because\n * the chat session had been switched to it. Sonnet is the working tier;\n * haiku serves the fast classes (spotcheck, simple).\n */\nexport const NATIVE_ANTHROPIC_MODELS: WorkerProvider[\"models\"] = {\n  default: \"claude-sonnet-5\",\n  fast: \"claude-haiku-4-5-20251001\",\n};\n\n/**\n * The synthetic provider object for ANTHROPIC_NATIVE. `baseUrl` is empty and\n * there is no key file, so buildRunEnv strips every provider env override;\n * the models come from NATIVE_ANTHROPIC_MODELS so a run always names its\n * model on the command line.\n */\nexport function nativeAnthropicProvider(\n  models: WorkerProvider[\"models\"] = NATIVE_ANTHROPIC_MODELS\n): WorkerProvider {\n  return {\n    enabled: true,\n    protocol: \"anthropic\",\n    baseUrl: \"\",\n    keyFile: null,\n    models: { ...models },\n    env: {},\n    native: true,\n  };\n}\n\n/**\n * Provider by name, synthesizing ANTHROPIC_NATIVE when it is asked for. Reads\n * `config.nativeModels` (workers.yaml's documented `providers.anthropic.models`\n * override, if any) so a config that pins a different default/fast id for the\n * built-in provider is honored everywhere a provider is resolved.\n */\nexport function getProviderOrNative(\n  config: { providers: Record<string, WorkerProvider>; nativeModels?: WorkerProvider[\"models\"] },\n  name: string\n): WorkerProvider | undefined {\n  if (name === ANTHROPIC_NATIVE) return nativeAnthropicProvider(config.nativeModels);\n  return config.providers[name];\n}\n\nexport interface WorkersPaneConfig {\n  enabled: boolean;\n  /** Font size (points) of the follow-pane profile's font. */\n  fontSize: number;\n  /** Seconds a pane lingers after its worker goes quiet. */\n  autoExitSecs: number;\n}\n\nexport interface WorkersRoutingConfig {\n  /** Provider names in preference order; first usable one wins. */\n  order: string[];\n  /** Minutes a provider sits in cooldown after a quota/rate failure. */\n  cooldownMinutes: number;\n  /** Reroute a failed-before-first-tool run to the next provider. */\n  retryOnQuota: boolean;\n}\n\n/** Sub-worker caps: how deep the worker tree may grow, how wide per parent. */\nexport interface WorkersTreeConfig {\n  /** Maximum nesting depth of sub-workers (top-level = 0). */\n  maxDepth: number;\n  /** Maximum concurrently running children per parent. */\n  maxChildren: number;\n}\n\n/** Cost/quality tier of a provider's model, 1 (cheapest) … 5 (most expensive). */\nexport type CostTier = 1 | 2 | 3 | 4 | 5;\n\n/** The tier aliases the CLI and daemon tables understand — class proxies, not\n *  Anthropic model names: any provider's model maps onto one of these. */\nexport type ModelTier = \"haiku\" | \"sonnet\" | \"opus\";\n\nconst MODEL_TIERS: readonly ModelTier[] = [\"haiku\", \"sonnet\", \"opus\"];\n\nexport const DEFAULT_COST_TIER = 3;\n\n/** Tags a provider may carry; classes filter auto-routing on them. */\nexport const PROVIDER_TAGS = [\n  \"code\",\n  \"vision\",\n  \"image-gen\",\n  \"long-context\",\n  \"fast\",\n  \"reasoning\",\n] as const;\n\nexport type ProviderTag = (typeof PROVIDER_TAGS)[number];\n\n/** The standard task classes; `workers.classes` maps each to a target. */\nexport const WORKER_CLASSES = [\n  \"draft\",\n  \"plan\",\n  \"implement\",\n  \"review\",\n  \"research\",\n  \"spotcheck\",\n  \"simple\",\n  \"complex\",\n  \"image\",\n] as const;\n\nexport type WorkerClassName = (typeof WORKER_CLASSES)[number];\n\n/**\n * The well-known model capabilities — documented, and what the starter\n * workers.yaml and `pai worker model`'s listing show by name. The set is\n * open, though: a provider's `models` block may carry any capability name\n * matching CAPABILITY_NAME_RE (see isModelCapability), e.g. \"vision\" or\n * \"longcontext\" for a provider that serves them. \"default\" is the required\n * catch-all; the others name what a model is *for* — \"fast\" the cheap tier\n * (spotcheck, haiku-tier spawns), \"image\" the image class/capability.\n * Everything resolves through resolveModelCapability, falling back to\n * default; cross-provider preference for a capability is `capabilities:` in\n * workers.yaml (see resolveCapability).\n */\nexport const MODEL_CAPABILITIES = [\"default\", \"fast\", \"image\"] as const;\n\nexport type ModelCapability = string;\n\nexport const CAPABILITY_NAME_RE = /^[a-z][a-z0-9-]*$/;\n\n/** Is this string a syntactically valid capability name (open set)? */\nexport function isModelCapability(v: string): v is ModelCapability {\n  return CAPABILITY_NAME_RE.test(v);\n}\n\n/**\n * Which model capability a class runs on when its target names no alias: the\n * image class uses the image model, the cheap classes (spotcheck, simple) the\n * fast model, every other class the provider default. A provider without a\n * fast model falls back to its default (resolveModelCapability).\n */\nconst CLASS_MODEL_CAPABILITY: Record<WorkerClassName, ModelCapability> = {\n  draft: \"default\",\n  plan: \"default\",\n  implement: \"default\",\n  review: \"default\",\n  research: \"default\",\n  spotcheck: \"fast\",\n  simple: \"fast\",\n  complex: \"default\",\n  image: \"image\",\n};\n\n/** Capability for a run's class (default when unset or not a standard class). */\nexport function classModelCapability(className?: string): ModelCapability {\n  return (className && CLASS_MODEL_CAPABILITY[className as WorkerClassName]) || \"default\";\n}\n\n/**\n * A class target: \"<provider>\", \"<provider>/<modelAlias>\", or an object. The\n * object either pins a `provider` (plus optional `mcp` allowlist) or only\n * constrains auto-routing (`maxCostTier`, `requireTags`, per-class `order`).\n */\nexport type ClassTarget =\n  | string\n  | {\n      provider?: string;\n      mcp?: string[];\n      /** Auto-routing may only use providers at or below this cost tier. */\n      maxCostTier?: number;\n      /** Auto-routing may only use providers carrying all these tags. */\n      requireTags?: string[];\n      /** Provider order for this class; defaults to routing.order. */\n      order?: string[];\n    };\n\n/**\n * State of the machine-wide Claude Code fallback (`pai worker fallback on`):\n * every new Claude Code process runs on `provider` until `fallback off`.\n * `saved` holds what ~/.claude/settings.json carried before the switch so\n * `off` can restore it exactly.\n */\nexport interface WorkersFallback {\n  /** Provider every new Claude Code process is pointed at. */\n  provider: string;\n  /**\n   * settings.json before the switch. `env` records the previous value of\n   * every env key fallback touched (null = the key was absent), `model` the\n   * previous top-level model pin (null = none), `envExisted` whether an env\n   * block existed at all.\n   */\n  saved: {\n    env: Record<string, string | null>;\n    model: string | null;\n    envExisted: boolean;\n  };\n  /** ISO stamp of the switch (shown by `fallback status`). */\n  on: string;\n}\n\nexport interface WorkersConfig {\n  enabled: boolean;\n  /** Provider name, or \"auto\" for routing.order resolution. */\n  active: string | null;\n  providers: Record<string, WorkerProvider>;\n  /** Class → target; see ClassTarget. (Reads the legacy `roles` key.) */\n  classes: Record<string, ClassTarget>;\n  /** MCP set name → server names; `--mcp <set>` and class `mcp` expand these. */\n  mcpSets: Record<string, string[]>;\n  /**\n   * Capability → provider names in preference order (workers.yaml\n   * `capabilities:`), e.g. `{ image: [\"pictures\", \"glm\"] }`. Cross-provider,\n   * unlike a provider's own `models` table: this is what lets `--capability\n   * image` find the one provider configured to serve it. See resolveCapability.\n   */\n  capabilities: Record<string, string[]>;\n  pane: WorkersPaneConfig;\n  logDir: string;\n  routing: WorkersRoutingConfig;\n  /** Sub-worker caps (workers.tree). */\n  tree: WorkersTreeConfig;\n  /**\n   * Daemon cache-keepalive cadence in seconds: how often a trivial\n   * single-turn heartbeat worker re-arms the provider prompt cache\n   * (src/workers/keepalive.ts). 0 = off.\n   */\n  cacheKeepaliveSecs: number;\n  /** Machine-wide Claude Code fallback; null = off. */\n  fallback: WorkersFallback | null;\n  /**\n   * Model ids for the built-in `anthropic` provider, when workers.yaml\n   * documents an override under `providers.anthropic.models`. Defaults to\n   * NATIVE_ANTHROPIC_MODELS.\n   */\n  nativeModels: WorkerProvider[\"models\"];\n}\n\n// ---------------------------------------------------------------------------\n// Defaults\n// ---------------------------------------------------------------------------\n\nexport const DEFAULT_LOG_DIR = \"~/.claude/logs/workers\";\n\nexport const DEFAULT_PANE: WorkersPaneConfig = {\n  enabled: true,\n  fontSize: 13,\n  autoExitSecs: 60,\n};\n\nexport const DEFAULT_ROUTING: WorkersRoutingConfig = {\n  order: [],\n  cooldownMinutes: 30,\n  retryOnQuota: true,\n};\n\nexport const DEFAULT_TREE: WorkersTreeConfig = {\n  maxDepth: 2,\n  maxChildren: 4,\n};\n\n/**\n * Cache-keepalive cadence when the config names none. Measured 2026-09-18\n * (pair probes through the real worker spawn path, numbers in\n * docs/cache-keepalive.md): the implicit provider cache only serves a fresh\n * worker warm within roughly the first minute (positive back-to-back, gone\n * at 2 min), and it covers only ~2.6k of the ~18k-token prefix. Holding it\n * needs a beat every <2 min — a continuous bill for a small saving — so the\n * default is OFF and arming it is the operator's explicit call (set e.g.\n * \"cacheKeepaliveSecs\": 60).\n */\nexport const DEFAULT_CACHE_KEEPALIVE_SECS = 0;\n\n/**\n * The default MCP sets every config starts from. `desktop` names the clickr\n * server so `--mcp desktop` hands a worker the machine controls (read-only\n * tools always; actuating ones after the operator hands the controls over,\n * see `pai worker controls`). A user's mcpSets section is merged over this,\n * so `desktop: []` removes the set deliberately.\n */\nexport const DEFAULT_MCP_SETS: Record<string, string[]> = {\n  desktop: [\"clickr\"],\n};\n\nexport function defaultWorkersConfig(): WorkersConfig {\n  return {\n    enabled: false,\n    active: null,\n    providers: {},\n    classes: {},\n    mcpSets: { ...DEFAULT_MCP_SETS },\n    capabilities: {},\n    pane: { ...DEFAULT_PANE },\n    logDir: DEFAULT_LOG_DIR,\n    routing: { ...DEFAULT_ROUTING, order: [] },\n    tree: { ...DEFAULT_TREE },\n    cacheKeepaliveSecs: DEFAULT_CACHE_KEEPALIVE_SECS,\n    fallback: null,\n    nativeModels: { ...NATIVE_ANTHROPIC_MODELS },\n  };\n}\n\n// ---------------------------------------------------------------------------\n// Validation\n// ---------------------------------------------------------------------------\n\nexport class WorkersConfigError extends Error {}\n\nfunction bad(path: string, why: string): never {\n  throw new WorkersConfigError(`workers${path}: ${why}`);\n}\n\nfunction str(v: unknown): string {\n  return typeof v === \"string\" ? v : \"\";\n}\n\n/**\n * Parse a `models` block (capability → model id, \"default\" required). Shared\n * by parseProvider and the YAML loader's builtin-anthropic override, which\n * has no other provider fields to validate.\n */\nexport function parseModelsBlock(pathPrefix: string, modelsRaw: unknown): WorkerProvider[\"models\"] {\n  const raw = modelsRaw === undefined ? {} : modelsRaw;\n  if (typeof raw !== \"object\" || raw === null) bad(pathPrefix, \"must be an object\");\n  const m = raw as Record<string, unknown>;\n  const defaultModel = str(m.default);\n  if (!defaultModel) bad(`${pathPrefix}.default`, \"is required\");\n  const models: WorkerProvider[\"models\"] = { default: defaultModel };\n  for (const key of Object.keys(m)) {\n    if (key === \"default\") continue;\n    if (!isModelCapability(key)) {\n      bad(\n        `${pathPrefix}.${key}`,\n        `\"${key}\" is not a valid capability name (must match ^[a-z][a-z0-9-]*$; well-known: ${MODEL_CAPABILITIES.join(\", \")}, but any name in that shape is accepted)`\n      );\n    }\n    const id = str(m[key]);\n    if (!id) bad(`${pathPrefix}.${key}`, \"must be a non-empty model id\");\n    models[key] = id;\n  }\n  return models;\n}\n\n/** Parse and validate one provider entry (shared by JSON and YAML loading). */\nexport function parseProvider(name: string, raw: unknown): WorkerProvider {\n  if (name === ANTHROPIC_NATIVE) {\n    bad(\n      `.providers.${name}`,\n      `\"${ANTHROPIC_NATIVE}\" is reserved for plain Anthropic (Claude Code's own OAuth/Max-plan login) and cannot be configured here — remove this entry; use --provider ${ANTHROPIC_NATIVE} or \"pai worker providers use ${ANTHROPIC_NATIVE}\" instead`\n    );\n  }\n  if (typeof raw !== \"object\" || raw === null) bad(`.providers.${name}`, \"must be an object\");\n  const p = raw as Record<string, unknown>;\n\n  const protocol = p.protocol === undefined ? \"anthropic\" : str(p.protocol);\n  if (protocol !== \"anthropic\" && protocol !== \"openai\") {\n    bad(`.providers.${name}.protocol`, `\"${str(p.protocol)}\" is neither \"anthropic\" nor \"openai\"`);\n  }\n  const engine = p.engine === undefined ? \"claude\" : str(p.engine);\n  if (engine !== \"claude\" && engine !== \"codex\" && engine !== \"image\") {\n    bad(`.providers.${name}.engine`, `\"${str(p.engine)}\" is none of \"claude\", \"codex\", \"image\"`);\n  }\n\n  const baseUrl = str(p.baseUrl);\n  // openai providers reach the model through the PAI proxy; their baseUrl is\n  // the proxy URL, filled in by the runner — only anthropic needs one here.\n  if (!baseUrl && protocol !== \"openai\") bad(`.providers.${name}.baseUrl`, \"is required\");\n\n  const keyFile =\n    p.keyFile === undefined || p.keyFile === null || str(p.keyFile) === \"\"\n      ? null\n      : str(p.keyFile);\n  const key = str(p.key) || undefined;\n\n  const models = parseModelsBlock(`.providers.${name}.models`, p.models);\n\n  let modelTiers: Record<string, ModelTier> | undefined;\n  if (p.modelTiers !== undefined) {\n    if (typeof p.modelTiers !== \"object\" || p.modelTiers === null || Array.isArray(p.modelTiers)) {\n      bad(`.providers.${name}.modelTiers`, \"must be an object of model id → haiku | sonnet | opus\");\n    }\n    modelTiers = {};\n    for (const [id, tier] of Object.entries(p.modelTiers as Record<string, unknown>)) {\n      if (typeof tier !== \"string\" || !MODEL_TIERS.includes(tier as ModelTier)) {\n        bad(\n          `.providers.${name}.modelTiers.${id}`,\n          `must be \"haiku\", \"sonnet\" or \"opus\" (got ${JSON.stringify(tier)})`\n        );\n      }\n      modelTiers[id] = tier as ModelTier;\n    }\n  }\n\n  const env: Record<string, string> = {};\n  if (p.env !== undefined) {\n    if (typeof p.env !== \"object\" || p.env === null || Array.isArray(p.env)) {\n      bad(`.providers.${name}.env`, \"must be an object of string values\");\n    }\n    for (const [k, v] of Object.entries(p.env as Record<string, unknown>)) {\n      if (typeof v !== \"string\") bad(`.providers.${name}.env.${k}`, \"must be a string\");\n      env[k] = v;\n    }\n  }\n\n  const quotaSkipAt = p.quotaSkipAt === undefined ? undefined : p.quotaSkipAt;\n  if (quotaSkipAt !== undefined) {\n    if (typeof quotaSkipAt !== \"number\" || quotaSkipAt < 0 || quotaSkipAt > 100) {\n      bad(`.providers.${name}.quotaSkipAt`, \"must be a number between 0 and 100\");\n    }\n  }\n\n  const contextWindow = p.contextWindow === undefined ? undefined : p.contextWindow;\n  if (contextWindow !== undefined) {\n    if (typeof contextWindow !== \"number\" || contextWindow <= 0) {\n      bad(`.providers.${name}.contextWindow`, \"must be a positive number of tokens\");\n    }\n  }\n\n  const upstreamUrl = str(p.upstreamUrl);\n  if (protocol === \"openai\" && !upstreamUrl) {\n    bad(`.providers.${name}.upstreamUrl`, `is required for protocol \"openai\" (the Chat Completions base, e.g. \"https://api.openai.com/v1\")`);\n  }\n\n  const costTier = p.costTier === undefined ? undefined : p.costTier;\n  if (costTier !== undefined) {\n    if (typeof costTier !== \"number\" || !Number.isInteger(costTier) || costTier < 1 || costTier > 5) {\n      bad(`.providers.${name}.costTier`, \"must be an integer 1 (cheapest) … 5 (most expensive)\");\n    }\n  }\n\n  let tags: ProviderTag[] | undefined;\n  if (p.tags !== undefined) {\n    if (!Array.isArray(p.tags) || p.tags.some((x) => typeof x !== \"string\")) {\n      bad(`.providers.${name}.tags`, `must be an array of tags from: ${PROVIDER_TAGS.join(\", \")}`);\n    }\n    for (const t of p.tags as string[]) {\n      if (!(PROVIDER_TAGS as readonly string[]).includes(t)) {\n        bad(`.providers.${name}.tags`, `\"${t}\" is not a tag (from: ${PROVIDER_TAGS.join(\", \")})`);\n      }\n    }\n    tags = p.tags as ProviderTag[];\n  }\n\n  let usage: ProviderUsage | undefined;\n  if (p.usage !== undefined) {\n    if (typeof p.usage !== \"object\" || p.usage === null || Array.isArray(p.usage)) {\n      bad(`.providers.${name}.usage`, \"must be an object\");\n    }\n    const u = p.usage as Record<string, unknown>;\n    const usageUrl = str(u.url);\n    if (!usageUrl) bad(`.providers.${name}.usage.url`, \"is required\");\n    if (!Array.isArray(u.windows) || u.windows.length === 0) {\n      bad(`.providers.${name}.usage.windows`, \"must be a non-empty array\");\n    }\n    const windows: UsageWindow[] = [];\n    for (const [i, wRaw] of (u.windows as unknown[]).entries()) {\n      const wpath = `.providers.${name}.usage.windows[${i}]`;\n      if (typeof wRaw !== \"object\" || wRaw === null || Array.isArray(wRaw)) {\n        bad(wpath, \"must be an object\");\n      }\n      const w = wRaw as Record<string, unknown>;\n      const wname = str(w.name);\n      if (!wname) bad(`${wpath}.name`, \"is required\");\n      const percent = str(w.percent);\n      if (!percent) bad(`${wpath}.percent`, \"is required (a jq expression yielding 0–100)\");\n      const resetUnit = w.resetUnit === undefined ? undefined : str(w.resetUnit);\n      if (resetUnit !== undefined && resetUnit !== \"ms\" && resetUnit !== \"s\" && resetUnit !== \"iso\") {\n        bad(`${wpath}.resetUnit`, `must be \"ms\", \"s\" or \"iso\"`);\n      }\n      windows.push({\n        name: wname,\n        percent,\n        ...(str(w.resetAt) ? { resetAt: str(w.resetAt) } : {}),\n        ...(resetUnit ? { resetUnit } : {}),\n      });\n    }\n    const ttlSeconds = u.ttlSeconds === undefined ? undefined : u.ttlSeconds;\n    if (ttlSeconds !== undefined && (typeof ttlSeconds !== \"number\" || ttlSeconds <= 0)) {\n      bad(`.providers.${name}.usage.ttlSeconds`, \"must be a positive number of seconds\");\n    }\n    usage = {\n      url: usageUrl,\n      ...(str(u.authHeader) ? { authHeader: str(u.authHeader) } : {}),\n      ...(str(u.label) ? { label: str(u.label) } : {}),\n      windows,\n      ...(ttlSeconds !== undefined ? { ttlSeconds } : {}),\n    };\n  }\n\n  return {\n    enabled: p.enabled === undefined ? true : p.enabled === true,\n    protocol,\n    baseUrl,\n    keyFile,\n    ...(key ? { key } : {}),\n    models,\n    ...(modelTiers ? { modelTiers } : {}),\n    env,\n    ...(str(p.note) ? { note: str(p.note) } : {}),\n    ...(upstreamUrl ? { upstreamUrl } : {}),\n    ...(engine !== \"claude\" ? { engine } : {}),\n    ...(str(p.quotaProbe) ? { quotaProbe: str(p.quotaProbe) } : {}),\n    ...(quotaSkipAt !== undefined ? { quotaSkipAt } : {}),\n    ...(contextWindow !== undefined ? { contextWindow } : {}),\n    ...(costTier !== undefined ? { costTier } : {}),\n    ...(tags ? { tags } : {}),\n    ...(usage ? { usage } : {}),\n  };\n}\n\n/**\n * Parse a `classes` (or legacy `roles`) value shared by JSON and YAML\n * loading. `badPathPrefix` names the field in error messages, e.g. \".classes\".\n */\nexport function parseClassesValue(\n  classesRaw: unknown,\n  badPathPrefix: string\n): Record<string, ClassTarget> {\n  const classes: Record<string, ClassTarget> = {};\n  if (classesRaw === undefined) return classes;\n  if (typeof classesRaw !== \"object\" || classesRaw === null || Array.isArray(classesRaw)) {\n    bad(badPathPrefix, \"must be an object of class → provider[/alias] or {provider, mcp, maxCostTier, requireTags, order}\");\n  }\n  for (const [cls, target] of Object.entries(classesRaw as Record<string, unknown>)) {\n    if (typeof target === \"object\" && target !== null && !Array.isArray(target)) {\n      const o = target as Record<string, unknown>;\n      const provider = str(o.provider);\n      if (o.provider !== undefined && (!provider || provider.includes(\" \"))) {\n        bad(`${badPathPrefix}.${cls}.provider`, `invalid provider \"${provider}\"`);\n      }\n      let mcp: string[] | undefined;\n      if (o.mcp !== undefined) {\n        if (!Array.isArray(o.mcp) || o.mcp.some((x) => typeof x !== \"string\")) {\n          bad(`${badPathPrefix}.${cls}.mcp`, \"must be an array of MCP server or set names\");\n        }\n        mcp = o.mcp as string[];\n      }\n      let maxCostTier: number | undefined;\n      if (o.maxCostTier !== undefined) {\n        if (\n          typeof o.maxCostTier !== \"number\" ||\n          !Number.isInteger(o.maxCostTier) ||\n          o.maxCostTier < 1 ||\n          o.maxCostTier > 5\n        ) {\n          bad(`${badPathPrefix}.${cls}.maxCostTier`, \"must be an integer 1 … 5\");\n        }\n        maxCostTier = o.maxCostTier;\n      }\n      let requireTags: string[] | undefined;\n      if (o.requireTags !== undefined) {\n        if (!Array.isArray(o.requireTags) || o.requireTags.some((x) => typeof x !== \"string\")) {\n          bad(`${badPathPrefix}.${cls}.requireTags`, `must be an array of tags from: ${PROVIDER_TAGS.join(\", \")}`);\n        }\n        for (const t of o.requireTags as string[]) {\n          if (!(PROVIDER_TAGS as readonly string[]).includes(t)) {\n            bad(`${badPathPrefix}.${cls}.requireTags`, `\"${t}\" is not a tag (from: ${PROVIDER_TAGS.join(\", \")})`);\n          }\n        }\n        requireTags = o.requireTags as string[];\n      }\n      let order: string[] | undefined;\n      if (o.order !== undefined) {\n        if (!Array.isArray(o.order) || o.order.some((x) => typeof x !== \"string\")) {\n          bad(`${badPathPrefix}.${cls}.order`, \"must be an array of provider names\");\n        }\n        order = o.order as string[];\n      }\n      const obj: ClassTarget = {\n        ...(provider ? { provider } : {}),\n        ...(mcp ? { mcp } : {}),\n        ...(maxCostTier !== undefined ? { maxCostTier } : {}),\n        ...(requireTags ? { requireTags } : {}),\n        ...(order ? { order } : {}),\n      };\n      classes[cls] = Object.keys(obj).length ? obj : {};\n    } else {\n      const t = str(target);\n      if (!t || t.includes(\" \")) bad(`${badPathPrefix}.${cls}`, `invalid target \"${t}\"`);\n      classes[cls] = t;\n    }\n  }\n  return classes;\n}\n\n/**\n * Parse an `mcpSets` (or `mcp_sets`) value shared by JSON and YAML loading.\n * Always merged over DEFAULT_MCP_SETS, so an omitted `desktop` key keeps the\n * built-in clickr set (see DEFAULT_MCP_SETS).\n */\nexport function parseMcpSetsValue(raw: unknown, badPathPrefix: string): Record<string, string[]> {\n  const mcpSets: Record<string, string[]> = { ...DEFAULT_MCP_SETS };\n  if (raw === undefined) return mcpSets;\n  if (typeof raw !== \"object\" || raw === null || Array.isArray(raw)) {\n    bad(badPathPrefix, \"must be an object of set name → [server names]\");\n  }\n  for (const [setName, servers] of Object.entries(raw as Record<string, unknown>)) {\n    if (!Array.isArray(servers) || servers.some((x) => typeof x !== \"string\")) {\n      bad(`${badPathPrefix}.${setName}`, \"must be an array of MCP server names\");\n    }\n    mcpSets[setName] = servers as string[];\n  }\n  return mcpSets;\n}\n\n/**\n * Parse a `capabilities` value shared by JSON and YAML loading: capability\n * name (open set, see isModelCapability) → provider names in preference\n * order. Provider names are not cross-checked here — a name that stops\n * existing is simply skipped by resolveCapability at resolve time, the same\n * way routing.order tolerates a removed provider.\n */\nexport function parseCapabilitiesValue(raw: unknown, badPathPrefix: string): Record<string, string[]> {\n  const capabilities: Record<string, string[]> = {};\n  if (raw === undefined) return capabilities;\n  if (typeof raw !== \"object\" || raw === null || Array.isArray(raw)) {\n    bad(badPathPrefix, \"must be an object of capability name → [provider names]\");\n  }\n  for (const [name, order] of Object.entries(raw as Record<string, unknown>)) {\n    if (!isModelCapability(name)) {\n      bad(`${badPathPrefix}.${name}`, `\"${name}\" is not a valid capability name (must match ^[a-z][a-z0-9-]*$)`);\n    }\n    if (!Array.isArray(order) || order.length === 0 || order.some((x) => typeof x !== \"string\" || !x)) {\n      bad(`${badPathPrefix}.${name}`, \"must be a non-empty array of provider names\");\n    }\n    capabilities[name] = order as string[];\n  }\n  return capabilities;\n}\n\n/**\n * Parse and validate a raw `workers` value. Missing section → defaults.\n * Unknown-but-typed garbage → WorkersConfigError naming the offending field.\n */\nexport function parseWorkersConfig(raw: unknown): WorkersConfig {\n  const d = defaultWorkersConfig();\n  if (raw === undefined || raw === null) return d;\n  if (typeof raw !== \"object\" || Array.isArray(raw)) {\n    bad(\"\", \"section must be an object\");\n  }\n  const w = raw as Record<string, unknown>;\n\n  const providers: Record<string, WorkerProvider> = {};\n  if (w.providers !== undefined) {\n    if (typeof w.providers !== \"object\" || w.providers === null || Array.isArray(w.providers)) {\n      bad(\".providers\", \"must be an object keyed by provider name\");\n    }\n    for (const [name, p] of Object.entries(w.providers)) {\n      providers[name] = parseProvider(name, p);\n    }\n  }\n\n  // classes is canonical; a config that still carries the pre-classes `roles`\n  // key is migrated by reading it here — the next write stores only `classes`.\n  const classesRaw = w.classes !== undefined ? w.classes : w.roles;\n  const classes = parseClassesValue(classesRaw, w.classes !== undefined ? \".classes\" : \".roles\");\n\n  const mcpSets = parseMcpSetsValue(w.mcpSets, \".mcpSets\");\n  const capabilities = parseCapabilitiesValue(w.capabilities, \".capabilities\");\n\n  let pane = { ...DEFAULT_PANE };\n  if (w.pane !== undefined) {\n    if (typeof w.pane !== \"object\" || w.pane === null) bad(\".pane\", \"must be an object\");\n    const pc = w.pane as Record<string, unknown>;\n    if (pc.enabled !== undefined && typeof pc.enabled !== \"boolean\") bad(\".pane.enabled\", \"must be boolean\");\n    if (pc.fontSize !== undefined && (typeof pc.fontSize !== \"number\" || pc.fontSize <= 0)) {\n      bad(\".pane.fontSize\", \"must be a positive number of points\");\n    }\n    if (pc.autoExitSecs !== undefined && typeof pc.autoExitSecs !== \"number\") {\n      bad(\".pane.autoExitSecs\", \"must be a number\");\n    }\n    // legacy fontScale (a relative scale, superseded by fontSize) is tolerated and ignored\n    pane = {\n      enabled: pc.enabled === undefined ? DEFAULT_PANE.enabled : pc.enabled === true,\n      fontSize: pc.fontSize === undefined ? DEFAULT_PANE.fontSize : pc.fontSize,\n      autoExitSecs: pc.autoExitSecs === undefined ? DEFAULT_PANE.autoExitSecs : pc.autoExitSecs,\n    };\n  }\n\n  let routing = { ...DEFAULT_ROUTING, order: [] as string[] };\n  if (w.routing !== undefined) {\n    if (typeof w.routing !== \"object\" || w.routing === null) bad(\".routing\", \"must be an object\");\n    const r = w.routing as Record<string, unknown>;\n    if (r.order !== undefined) {\n      if (!Array.isArray(r.order) || r.order.some((x) => typeof x !== \"string\")) {\n        bad(\".routing.order\", \"must be an array of provider names\");\n      }\n      routing.order = r.order as string[];\n    }\n    if (r.cooldownMinutes !== undefined && typeof r.cooldownMinutes !== \"number\") {\n      bad(\".routing.cooldownMinutes\", \"must be a number\");\n    }\n    if (r.retryOnQuota !== undefined && typeof r.retryOnQuota !== \"boolean\") {\n      bad(\".routing.retryOnQuota\", \"must be boolean\");\n    }\n    routing = {\n      order: routing.order,\n      cooldownMinutes: r.cooldownMinutes === undefined ? DEFAULT_ROUTING.cooldownMinutes : r.cooldownMinutes,\n      retryOnQuota: r.retryOnQuota === undefined ? DEFAULT_ROUTING.retryOnQuota : r.retryOnQuota === true,\n    };\n  }\n\n  let tree = { ...DEFAULT_TREE };\n  if (w.tree !== undefined) {\n    if (typeof w.tree !== \"object\" || w.tree === null || Array.isArray(w.tree)) {\n      bad(\".tree\", \"must be an object\");\n    }\n    const t = w.tree as Record<string, unknown>;\n    if (t.maxDepth !== undefined) {\n      if (typeof t.maxDepth !== \"number\" || !Number.isInteger(t.maxDepth) || t.maxDepth < 0) {\n        bad(\".tree.maxDepth\", \"must be a non-negative integer\");\n      }\n    }\n    if (t.maxChildren !== undefined) {\n      if (typeof t.maxChildren !== \"number\" || !Number.isInteger(t.maxChildren) || t.maxChildren < 1) {\n        bad(\".tree.maxChildren\", \"must be a positive integer\");\n      }\n    }\n    tree = {\n      maxDepth: t.maxDepth === undefined ? DEFAULT_TREE.maxDepth : t.maxDepth,\n      maxChildren: t.maxChildren === undefined ? DEFAULT_TREE.maxChildren : t.maxChildren,\n    };\n  }\n\n  let cacheKeepaliveSecs = DEFAULT_CACHE_KEEPALIVE_SECS;\n  if (w.cacheKeepaliveSecs !== undefined) {\n    if (\n      typeof w.cacheKeepaliveSecs !== \"number\" ||\n      !Number.isInteger(w.cacheKeepaliveSecs) ||\n      w.cacheKeepaliveSecs < 0\n    ) {\n      bad(\".cacheKeepaliveSecs\", \"must be a non-negative integer (seconds, 0 = off)\");\n    }\n    cacheKeepaliveSecs = w.cacheKeepaliveSecs;\n  }\n\n  const active = w.active === undefined || w.active === null ? null : str(w.active);\n  if (active !== null && active !== \"auto\" && !(active in providers)) {\n    // Tolerated at parse time (a provider may have been removed while active\n    // still names it) but every consumer resolves it to a clear error.\n  }\n\n  let fallback: WorkersFallback | null = null;\n  if (w.fallback !== undefined && w.fallback !== null) {\n    if (typeof w.fallback !== \"object\" || Array.isArray(w.fallback)) {\n      bad(\".fallback\", \"must be an object (written by `pai worker fallback on`)\");\n    }\n    const f = w.fallback as Record<string, unknown>;\n    const provider = str(f.provider);\n    if (!provider) bad(\".fallback.provider\", \"is required\");\n    const savedRaw = f.saved;\n    if (typeof savedRaw !== \"object\" || savedRaw === null || Array.isArray(savedRaw)) {\n      bad(\".fallback.saved\", \"must be an object\");\n    }\n    const s = savedRaw as Record<string, unknown>;\n    if (typeof s.env !== \"object\" || s.env === null || Array.isArray(s.env)) {\n      bad(\".fallback.saved.env\", \"must be an object of env key → previous value or null\");\n    }\n    const env: Record<string, string | null> = {};\n    for (const [k, v] of Object.entries(s.env as Record<string, unknown>)) {\n      env[k] = v === null || typeof v === \"string\" ? (v as string | null) : null;\n    }\n    if (s.model !== null && s.model !== undefined && typeof s.model !== \"string\") {\n      bad(\".fallback.saved.model\", \"must be a string or null\");\n    }\n    fallback = {\n      provider,\n      saved: {\n        env,\n        model: typeof s.model === \"string\" ? s.model : null,\n        envExisted: s.envExisted === true,\n      },\n      on: str(f.on) || new Date(0).toISOString(),\n    };\n  }\n\n  return {\n    enabled: w.enabled === undefined ? d.enabled : w.enabled === true,\n    active,\n    providers,\n    classes,\n    mcpSets,\n    capabilities,\n    pane,\n    logDir: str(w.logDir) || d.logDir,\n    routing,\n    tree,\n    cacheKeepaliveSecs,\n    fallback,\n    nativeModels: { ...NATIVE_ANTHROPIC_MODELS },\n  };\n}\n\n// ---------------------------------------------------------------------------\n// Read / write\n// ---------------------------------------------------------------------------\n\nfunction workersYamlDataOf(workers: WorkersConfig): WorkersYamlData {\n  return {\n    active: workers.active,\n    providers: workers.providers,\n    classes: workers.classes,\n    mcpSets: workers.mcpSets,\n    capabilities: workers.capabilities,\n    nativeModels: workers.nativeModels,\n  };\n}\n\n/**\n * Read the whole config file and return (raw, workers) — the raw record so\n * callers can rewrite it preserving every other section, the parsed+validated\n * workers section. Unreadable config throws, missing is fine. `path`\n * overrides the config location (tests, CLAUDE_SETTINGS_PATH-style dry runs);\n * default CONFIG_FILE (see paiConfigFilePath). Reads via readMainConfigRaw,\n * so a config.yaml next to `path` is preferred over JSON, same as every\n * other main-config reader.\n *\n * Providers, classes, mcpSets and active load from workers.yaml (next to\n * `path`) when it exists; otherwise they fall back to the JSON `workers`\n * section, and then to built-in defaults — nothing breaks before migration\n * (`pai worker config migrate`). Everything else (pane, routing, tree,\n * cacheKeepaliveSecs, fallback, enabled, logDir) always comes from the main\n * config (JSON or YAML).\n */\nexport function readWorkersSection(path: string = CONFIG_FILE): {\n  raw: Record<string, unknown>;\n  workers: WorkersConfig;\n} {\n  const raw = readMainConfigRaw(path);\n  const workers = parseWorkersConfig(raw.workers);\n  const yaml = readWorkersYaml(workersYamlPath());\n  if (yaml) {\n    workers.active = yaml.data.active;\n    workers.providers = yaml.data.providers;\n    workers.classes = yaml.data.classes;\n    workers.mcpSets = yaml.data.mcpSets;\n    workers.capabilities = yaml.data.capabilities;\n    workers.nativeModels = yaml.data.nativeModels;\n  }\n  return { raw, workers };\n}\n\n/**\n * Write the workers section back, atomically. When workers.yaml exists, its\n * providers/classes/mcpSets/active are synced there (comment-preserving,\n * only the entries that changed are touched) and stripped from the JSON\n * `workers` section; everything else still writes to JSON as before.\n */\nexport function writeWorkersSection(\n  raw: Record<string, unknown>,\n  workers: WorkersConfig,\n  path: string = CONFIG_FILE\n): void {\n  const yamlPath = workersYamlPath();\n  const usingYaml = existsSync(yamlPath);\n  if (usingYaml) {\n    writeWorkersYaml(yamlPath, workersYamlDataOf(workers));\n  }\n  const jsonWorkers = usingYaml\n    ? {\n        enabled: workers.enabled,\n        pane: workers.pane,\n        logDir: workers.logDir,\n        routing: workers.routing,\n        tree: workers.tree,\n        cacheKeepaliveSecs: workers.cacheKeepaliveSecs,\n        ...(workers.fallback ? { fallback: workers.fallback } : {}),\n      }\n    : workers.fallback\n      ? workers\n      : { ...workers, fallback: undefined };\n  raw.workers = jsonWorkers;\n  writeMainConfigRaw(raw, path);\n}\n\n/** Expand a leading ~ (config values are written with `~` to stay portable). */\nexport function expandHome(p: string): string {\n  if (p === \"~\" || p.startsWith(\"~/\")) return join(homedir(), p.slice(1));\n  return p;\n}\n\n// ---------------------------------------------------------------------------\n// Runnability checks (proxy / codex providers included)\n// ---------------------------------------------------------------------------\n\nexport function assertProviderRunnable(name: string, p: WorkerProvider): void {\n  if (p.protocol === \"openai\" && !p.upstreamUrl) {\n    throw new WorkersConfigError(\n      `provider \"${name}\" uses protocol \"openai\" but has no upstreamUrl — ` +\n        `set its Chat Completions base (e.g. \"https://api.openai.com/v1\") ` +\n        `so the PAI proxy knows where to translate to.`\n    );\n  }\n}\n\n/** Where a provider's key file lives, or null. Shared by run + test + add. */\nexport function providerKeyPath(p: WorkerProvider): string | null {\n  return p.keyFile ? expandHome(p.keyFile) : null;\n}\n\n/**\n * The provider's auth token: inline `key` wins when set, else `key_file`\n * read and trimmed, else null (native/local providers use the \"local\"\n * placeholder). The one place a provider's key value is resolved — every\n * spawn path (buildRunEnv, the codex runner, the openai proxy, the\n * machine-wide fallback) reads through this instead of its own\n * readFileSync, so inline keys work everywhere a key file already did.\n */\nexport function resolveProviderKey(p: WorkerProvider): string | null {\n  if (p.key) return p.key;\n  const keyPath = providerKeyPath(p);\n  if (!keyPath) return null;\n  let content: string;\n  try {\n    content = readFileSync(keyPath, \"utf8\");\n  } catch {\n    throw new WorkersConfigError(`key file not readable: ${keyPath}`);\n  }\n  const token = content.trim();\n  if (!token) throw new WorkersConfigError(`key file is empty: ${keyPath}`);\n  return token;\n}\n\n/** `key: ****` + last 4 chars — never the full value. Used everywhere a\n *  provider's key would otherwise be echoed (`providers`, `config check`). */\nexport function maskKey(key: string): string {\n  return `****${key.slice(-4)}`;\n}\n\nexport { DEFAULT_CONTEXT_WINDOW } from \"../utils/model-window.js\";\n\n/** Cost tier of a provider for class filtering (unset = 3, the middle). */\nexport function providerCostTier(p: WorkerProvider): number {\n  return p.costTier ?? DEFAULT_COST_TIER;\n}\n\n/**\n * The model id for a capability: the provider's preference for it, else its\n * default model — the one resolution rule every consumer (image class, fast\n * tier spawns, env pins) goes through.\n */\nexport function resolveModelCapability(p: WorkerProvider, capability: ModelCapability): string {\n  return p.models[capability] ?? p.models.default;\n}\n\n/** Runner behind a provider, defaulting to the Claude Code harness. */\nfunction providerEngine(p: WorkerProvider): WorkerEngine {\n  return p.engine ?? \"claude\";\n}\n\n/** Does this provider name a model for the capability (\"default\" always counts)? */\nfunction providerDeclaresCapability(p: WorkerProvider, capability: string): boolean {\n  return capability === \"default\" || p.models[capability] !== undefined;\n}\n\n/** A provider usable for this capability: declares it, enabled, and passes assertProviderRunnable. */\nfunction providerUsableForCapability(p: WorkerProvider | undefined, capability: string): p is WorkerProvider {\n  if (!p || !p.enabled || !providerDeclaresCapability(p, capability)) return false;\n  try {\n    assertProviderRunnable(\"\", p);\n    return true;\n  } catch {\n    return false;\n  }\n}\n\nexport interface ResolvedCapability {\n  /** Provider name the capability resolved to (\"anthropic\" for the built-in). */\n  provider: string;\n  model: string;\n  engine: WorkerEngine;\n  /**\n   * True when nothing declared this capability anywhere and the result is\n   * just the active provider's default model — a caller should treat this as\n   * \"no real image/vision/… provider is configured\", not a genuine match.\n   */\n  fellBack: boolean;\n}\n\n/**\n * Cross-provider capability resolution (`workers.yaml`'s `capabilities:`\n * map): which provider+model serves a named capability (e.g. \"image\"),\n * independent of any one provider's own `models` table.\n *\n * Resolution order:\n *   1. `capabilities.<name>` (explicit preference list) — first provider\n *      that declares the capability, is enabled, and passes\n *      assertProviderRunnable.\n *   2. No preference list: the active provider, if it declares the\n *      capability.\n *   3. Still nothing: any enabled provider that declares the capability\n *      (stable order — provider names sorted, \"anthropic\" included).\n *   4. Nothing anywhere: the active provider's default model, `fellBack: true`.\n */\nexport function resolveCapability(\n  workers: Pick<WorkersConfig, \"providers\" | \"active\" | \"capabilities\" | \"nativeModels\">,\n  capability: string\n): ResolvedCapability {\n  const order = workers.capabilities[capability];\n  if (order?.length) {\n    for (const name of order) {\n      const p = getProviderOrNative(workers, name);\n      if (providerUsableForCapability(p, capability)) {\n        return { provider: name, model: resolveModelCapability(p, capability), engine: providerEngine(p), fellBack: false };\n      }\n    }\n    throw new WorkersConfigError(\n      `no configured provider for capability \"${capability}\" is usable right now ` +\n        `(checked, in order: ${order.join(\", \")}) — set one with: pai worker capability ${capability} <provider>`\n    );\n  }\n\n  const activeName = workers.active && workers.active !== \"auto\" ? workers.active : null;\n  if (activeName) {\n    const p = getProviderOrNative(workers, activeName);\n    if (providerUsableForCapability(p, capability)) {\n      return { provider: activeName, model: resolveModelCapability(p, capability), engine: providerEngine(p), fellBack: false };\n    }\n  }\n\n  const candidates: Record<string, WorkerProvider> = {\n    [ANTHROPIC_NATIVE]: nativeAnthropicProvider(workers.nativeModels),\n    ...workers.providers,\n  };\n  for (const name of Object.keys(candidates).sort()) {\n    const p = candidates[name];\n    if (providerUsableForCapability(p, capability)) {\n      return { provider: name, model: resolveModelCapability(p, capability), engine: providerEngine(p), fellBack: false };\n    }\n  }\n\n  const fallbackName = activeName ?? ANTHROPIC_NATIVE;\n  const fallback = getProviderOrNative(workers, fallbackName) ?? nativeAnthropicProvider(workers.nativeModels);\n  return {\n    provider: fallbackName,\n    model: fallback.models.default,\n    engine: providerEngine(fallback),\n    fellBack: true,\n  };\n}\n\n/**\n * Context window used by the meter when the run reports none: an explicit\n * `contextWindow` first, then whatever the default model's id declares\n * (\"[1m]\" → 1,000,000), then the last-resort default.\n */\nexport function providerContextWindow(p: WorkerProvider): number {\n  return (\n    p.contextWindow ??\n    contextWindowFromModelId(p.models.default) ??\n    DEFAULT_CONTEXT_WINDOW\n  );\n}\n\n/** Directory under which inline keys (MCP `key` field) are stored, 0600. */\nexport function keysDir(): string {\n  return paiHomePath(\"keys\");\n}\n"],"mappings":"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"}