{".demo":{"directory":{"pi-theme.js":{"file":{"contents":"// Turns the page's theme (~/.config/showcase/theme.json, written by the demo page) into a pi theme.\n// Runs as the recipe's onTheme command; pi reloads its active custom theme when the file changes.\nconst { mkdirSync, readFileSync, writeFileSync } = require(\"node:fs\");\nconst path = require(\"node:path\");\n\nconst home = path.join(__dirname, \"..\");\nconst theme = JSON.parse(readFileSync(path.join(home, \".config/showcase/theme.json\"), \"utf8\"));\nconst { palette: p } = theme;\n\n// A tint of the terminal background toward a color, for the tool panels.\nfunction mix(base, color, amount) {\n  const channel = (hex, at) => parseInt(hex.slice(at, at + 2), 16);\n  return `#${[1, 3, 5].map((at) => Math.round(channel(base, at) * (1 - amount) + channel(color, at) * amount).toString(16).padStart(2, \"0\")).join(\"\")}`;\n}\nconst tint = theme.mode === \"light\" ? 0.14 : 0.16;\n\nconst colors = {\n  accent: theme.accent,\n  border: theme.muted,\n  borderAccent: theme.accent,\n  borderMuted: theme.line,\n  success: p.green,\n  error: p.red,\n  warning: p.yellow,\n  muted: theme.muted,\n  dim: theme.muted,\n  text: \"\",\n  thinkingText: theme.muted,\n  selectedBg: theme.line,\n  userMessageBg: theme.surface,\n  userMessageText: \"\",\n  customMessageBg: theme.surface,\n  customMessageText: \"\",\n  customMessageLabel: theme.accent,\n  toolPendingBg: mix(theme.terminal, p.blue, tint),\n  toolSuccessBg: mix(theme.terminal, p.green, tint),\n  toolErrorBg: mix(theme.terminal, p.red, tint),\n  toolTitle: theme.inkStrong,\n  toolOutput: \"\",\n  mdHeading: theme.accent,\n  mdLink: p.blue,\n  mdLinkUrl: theme.muted,\n  mdCode: p.cyan,\n  mdCodeBlock: \"\",\n  mdCodeBlockBorder: theme.line,\n  mdQuote: theme.muted,\n  mdQuoteBorder: theme.line,\n  mdHr: theme.line,\n  mdListBullet: theme.accent,\n  toolDiffAdded: p.green,\n  toolDiffRemoved: p.red,\n  toolDiffContext: theme.muted,\n  syntaxComment: theme.muted,\n  syntaxKeyword: p.magenta,\n  syntaxFunction: p.blue,\n  syntaxVariable: theme.ink,\n  syntaxString: p.green,\n  syntaxNumber: p.yellow,\n  syntaxType: p.cyan,\n  syntaxOperator: theme.ink,\n  syntaxPunctuation: theme.muted,\n  thinkingOff: theme.line,\n  thinkingMinimal: theme.muted,\n  thinkingLow: p.blue,\n  thinkingMedium: p.cyan,\n  thinkingHigh: p.magenta,\n  thinkingXhigh: p.red,\n  thinkingMax: p.brightRed,\n  bashMode: p.yellow,\n};\n\nconst out = path.join(home, \".pi/agent/themes\");\nmkdirSync(out, { recursive: true });\nwriteFileSync(path.join(out, \"showcase.json\"), `${JSON.stringify({ name: \"showcase\", colors }, null, 2)}\\n`);\n"}},"setup.js":{"file":{"contents":"// Runs once when the sandbox starts: marks project/ as a git checkout on main and records its files,\n// so the git stand-in can tell when the agent changes something.\nconst { createHash } = require(\"node:crypto\");\nconst { mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } = require(\"node:fs\");\nconst path = require(\"node:path\");\n\nconst home = path.join(__dirname, \"..\");\nconst project = path.join(home, \"project\");\nmkdirSync(path.join(project, \".git\"), { recursive: true });\nwriteFileSync(path.join(project, \".git/HEAD\"), \"ref: refs/heads/main\\n\");\n\nfunction files(dir) {\n  return readdirSync(dir).flatMap((name) => {\n    if (name === \".git\") return [];\n    const file = path.join(dir, name);\n    return statSync(file).isDirectory() ? files(file) : [file];\n  });\n}\nconst baseline = Object.fromEntries(files(project).map((file) => [path.relative(project, file), createHash(\"sha1\").update(readFileSync(file)).digest(\"hex\")]));\nwriteFileSync(path.join(__dirname, \"baseline.json\"), JSON.stringify(baseline));\n"}}}},".pi":{"directory":{"agent":{"directory":{"extensions":{"directory":{"demo-model.ts":{"file":{"contents":"// A scripted model, so the demo runs real pi without an API key and nothing leaves the browser.\n// Each prompt below has a fixed run of replies; the tools they call (read, edit, bash) are real.\nimport type { ExtensionAPI } from \"@earendil-works/pi-coding-agent\";\nimport {\n  calculateCost,\n  createAssistantMessageEventStream,\n  createFauxCore,\n  fauxAssistantMessage,\n  fauxText,\n  fauxThinking,\n  fauxToolCall,\n} from \"@earendil-works/pi-ai\";\n\nconst model = {\n  id: \"scripted\",\n  name: \"Scripted\",\n  reasoning: true,\n  input: [\"text\" as const],\n  // Priced like a mid-size hosted model, so the cost in the status line moves the way it would.\n  cost: { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3.75 },\n  contextWindow: 200_000,\n  maxTokens: 32_000,\n};\n\nconst oldLine = 'console.log(`${city}: ${reading.sky}, ${reading.low}-${reading.high}°C, ${Math.round(reading.rain * 100)}% chance of rain`);';\nconst newLines = `if (process.argv.includes(\"--json\")) {\n  console.log(JSON.stringify({ city, ...reading }));\n} else {\n  ${oldLine}\n}`;\n\ntype Step = ReturnType<typeof fauxAssistantMessage>;\nconst toolUse = { stopReason: \"toolUse\" as const };\n\n// Matched against the latest prompt; each entry lists the replies in order, one per model request.\nconst scripts: { match: RegExp; steps: Step[] }[] = [\n  {\n    match: /what does|explain|about/i,\n    steps: [\n      fauxAssistantMessage([fauxThinking(\"Start with the README, then the entry point.\"), fauxToolCall(\"read\", { path: \"README.md\" }), fauxToolCall(\"read\", { path: \"src/cli.js\" })], toolUse),\n      fauxAssistantMessage([fauxText(\"It's **forecast**, a tiny offline weather CLI. `src/cli.js` takes a city, looks it up in the bundled sample in `src/readings.js`, and prints the sky, the temperature range and the chance of rain. Unknown cities get a short error listing the ones it knows.\")]),\n    ],\n  },\n  {\n    match: /json/i,\n    steps: [\n      fauxAssistantMessage([fauxThinking(\"A flag check around the final print is enough; keep the text output as it is.\"), fauxToolCall(\"edit\", { path: \"src/cli.js\", edits: [{ oldText: oldLine, newText: newLines }] })], toolUse),\n      fauxAssistantMessage([fauxThinking(\"Run it both ways.\"), fauxToolCall(\"bash\", { command: \"node src/cli.js Berlin --json && node src/cli.js Berlin\" })], toolUse),\n      fauxAssistantMessage([fauxText(\"Added `--json`: it prints the reading as one JSON object, and the plain output is unchanged. The working tree is dirty now, which is why the branch in the status line shows `main*`.\")]),\n    ],\n  },\n];\n\nconst fallback = fauxAssistantMessage([\n  fauxText(\"I'm a scripted stand-in for a model, so I only know a few prompts. Try **what does this project do?** or **add a --json flag**, and watch the status line below: context, cost, cache reads and the cache TTL all move with each turn.\"),\n]);\n\nfunction text(content: unknown): string {\n  return typeof content === \"string\" ? content : Array.isArray(content) ? content.map((part) => part?.text ?? \"\").join(\" \") : \"\";\n}\n\nfunction nextStep(context: { messages: { role: string; content: unknown }[] }): Step {\n  const lastUser = context.messages.findLastIndex((message) => message.role === \"user\");\n  const prompt = text(context.messages[lastUser]?.content);\n  const replies = context.messages.slice(lastUser + 1).filter((message) => message.role === \"assistant\").length;\n  const script = scripts.find((candidate) => candidate.match.test(prompt));\n  return script?.steps[replies] ?? (replies === 0 ? fallback : fauxAssistantMessage([fauxText(\"Done.\")]));\n}\n\nexport default function demoModel(pi: ExtensionAPI): void {\n  const core = createFauxCore({ provider: \"demo\", api: \"demo-scripted\", models: [model], tokensPerSecond: 90 });\n  pi.registerProvider(\"demo\", {\n    name: \"Demo\",\n    baseUrl: \"http://demo.invalid\",\n    apiKey: \"demo\",\n    api: \"demo-scripted\" as never,\n    models: [model],\n    streamSimple: (requestModel, context, options) => {\n      core.setResponses([nextStep(context as never)]);\n      const source = core.streamSimple(requestModel as never, context, options);\n      // The faux provider counts tokens but leaves cost at zero; price them like a real reply.\n      const priced = createAssistantMessageEventStream();\n      void (async () => {\n        for await (const event of source) {\n          if (event.type === \"done\") event.message.usage.cost = calculateCost(requestModel, event.message.usage);\n          priced.push(event);\n        }\n        priced.end();\n      })();\n      return priced;\n    },\n  });\n}\n"}},"pi-statusline":{"directory":{"index.ts":{"file":{"contents":"import type { ExtensionAPI, ExtensionCommandContext } from \"@earendil-works/pi-coding-agent\";\nimport {\n  DEFAULT_HIDDEN_STATUSES,\n  loadStatuslineConfig,\n  writeStatuslineConfig,\n  type StatuslineConfig,\n} from \"./src/config.js\";\nimport { registerStatusline } from \"./src/statusline.js\";\n\nexport default function piStatuslineExtension(pi: ExtensionAPI): void {\n  const loaded = loadStatuslineConfig();\n  let config = loaded.config;\n\n  registerStatusline(pi, config);\n\n  pi.on(\"session_start\", async (_event, ctx) => {\n    for (const warning of loaded.warnings) ctx.ui.notify(warning, \"warning\");\n  });\n\n  pi.registerCommand(\"statusline\", {\n    description: \"Show, toggle, or tune pi-statusline\",\n    handler: async (args, ctx) => {\n      await runStatuslineCommand(args.trim(), ctx, () => config, (next) => {\n        config = next;\n      });\n    },\n  });\n}\n\nasync function runStatuslineCommand(\n  args: string,\n  ctx: ExtensionCommandContext,\n  read: () => StatuslineConfig,\n  write: (next: StatuslineConfig) => void,\n): Promise<void> {\n  const command = args.toLowerCase();\n  const current = read();\n\n  if (command === \"\" || command === \"status\") {\n    const hidden = current.hiddenStatuses.length > 0 ? current.hiddenStatuses.join(\", \") : \"none\";\n    ctx.ui.notify(`pi-statusline is ${current.enabled ? \"on\" : \"off\"}. Hidden statuses: ${hidden}`, \"info\");\n    return;\n  }\n\n  if (command === \"on\" || command === \"off\") {\n    await persist(ctx, { ...current, enabled: command === \"on\" }, write);\n    return;\n  }\n\n  if (command === \"reset-hidden\") {\n    await persist(ctx, { ...current, hiddenStatuses: [...DEFAULT_HIDDEN_STATUSES] }, write);\n    return;\n  }\n\n  const [verb, ...rest] = command.split(/\\s+/);\n  const key = rest.join(\" \").trim();\n  if (!key) {\n    ctx.ui.notify(\"Usage: /statusline [status|on|off|hide <key>|unhide <key>|reset-hidden]\", \"warning\");\n    return;\n  }\n\n  if (verb === \"hide\") {\n    if (current.hiddenStatuses.includes(key)) {\n      ctx.ui.notify(`${key} is already hidden.`, \"info\");\n      return;\n    }\n    await persist(ctx, { ...current, hiddenStatuses: [...current.hiddenStatuses, key] }, write);\n    return;\n  }\n  if (verb === \"unhide\") {\n    if (!current.hiddenStatuses.includes(key)) {\n      ctx.ui.notify(`${key} is not hidden.`, \"info\");\n      return;\n    }\n    await persist(\n      ctx,\n      { ...current, hiddenStatuses: current.hiddenStatuses.filter((entry) => entry !== key) },\n      write,\n    );\n    return;\n  }\n\n  ctx.ui.notify(\"Usage: /statusline [status|on|off|hide <key>|unhide <key>|reset-hidden]\", \"warning\");\n}\n\nasync function persist(\n  ctx: ExtensionCommandContext,\n  next: StatuslineConfig,\n  write: (value: StatuslineConfig) => void,\n): Promise<void> {\n  try {\n    const target = writeStatuslineConfig(next);\n    write(next);\n    ctx.ui.notify(`Saved pi-statusline settings to ${target}; reloading.`, \"info\");\n  } catch (error: unknown) {\n    ctx.ui.notify(`Could not save pi-statusline settings: ${error instanceof Error ? error.message : String(error)}`, \"error\");\n    return;\n  }\n  await ctx.reload();\n}\n"}},"package.json":{"file":{"contents":"{\n  \"name\": \"pi-statusline\",\n  \"version\": \"0.1.0\",\n  \"description\": \"A session status line for pi: repo state, context, cost, cache TTL, and timing\",\n  \"type\": \"module\",\n  \"keywords\": [\n    \"pi\",\n    \"extension\",\n    \"pi-package\",\n    \"pi-coding-agent\",\n    \"tui\",\n    \"statusline\",\n    \"footer\"\n  ],\n  \"license\": \"MIT\",\n  \"engines\": {\n    \"node\": \">=22.19.0\"\n  },\n  \"pi\": {\n    \"extensions\": [\n      \"./index.ts\"\n    ]\n  },\n  \"peerDependencies\": {\n    \"@earendil-works/pi-ai\": \"*\",\n    \"@earendil-works/pi-coding-agent\": \"*\",\n    \"@earendil-works/pi-tui\": \"*\"\n  },\n  \"devDependencies\": {\n    \"@earendil-works/pi-ai\": \"0.84.2\",\n    \"@earendil-works/pi-coding-agent\": \"0.84.2\",\n    \"@earendil-works/pi-tui\": \"0.84.2\",\n    \"@soleone/showcase\": \"github:Soleone/showcase#73e18f9\",\n    \"@types/node\": \"24.12.4\",\n    \"esbuild\": \"0.25.10\",\n    \"typescript\": \"5.9.3\",\n    \"vitest\": \"4.1.9\"\n  },\n  \"scripts\": {\n    \"typecheck\": \"tsc --noEmit\",\n    \"test\": \"vitest run\",\n    \"validate\": \"npm pack --dry-run\",\n    \"demo:build\": \"node demo/browser/build.mjs && showcase terminal demo/browser --out dist/browser\",\n    \"demo\": \"node demo/browser/build.mjs && showcase terminal demo/browser --out dist/browser --serve\",\n    \"media:capture\": \"node demo/capture.mjs\"\n  },\n  \"files\": [\n    \"index.ts\",\n    \"src\",\n    \"README.md\"\n  ]\n}\n"}},"src":{"directory":{"config.ts":{"file":{"contents":"/**\n * pi-statusline settings.\n *\n * Stored at `$PI_CODING_AGENT_DIR/pi-statusline.json`, falling back to\n * `~/.pi/agent/pi-statusline.json`. A malformed or unreadable file degrades to\n * defaults with a warning rather than taking the footer down.\n */\nimport * as fs from \"node:fs\";\nimport * as os from \"node:os\";\nimport * as path from \"node:path\";\n\nexport const DEFAULT_ENABLED = true;\n\n/**\n * Status keys hidden from the footer. These extensions print a one-line\n * indicator that duplicates what the status line already shows, so rendering\n * them would stack a second bar under the first.\n */\nexport const DEFAULT_HIDDEN_STATUSES = [\"goosedump\", \"venice\"];\n\nexport interface StatuslineConfig {\n  readonly version: 1;\n  readonly enabled: boolean;\n  readonly hiddenStatuses: readonly string[];\n}\n\nexport interface LoadedStatuslineConfig {\n  readonly config: StatuslineConfig;\n  readonly warnings: string[];\n  readonly path: string;\n}\n\nexport function defaultConfig(): StatuslineConfig {\n  return { version: 1, enabled: DEFAULT_ENABLED, hiddenStatuses: [...DEFAULT_HIDDEN_STATUSES] };\n}\n\nexport function parseStatuslineConfig(raw: unknown): { readonly config: StatuslineConfig; readonly warnings: string[] } {\n  const warnings: string[] = [];\n  if (raw !== undefined && !isRecord(raw)) {\n    warnings.push(\"Configuration is not a JSON object; using pi-statusline defaults.\");\n    return { config: defaultConfig(), warnings };\n  }\n  const value: Partial<Record<keyof StatuslineConfig, unknown>> = isRecord(raw) ? raw : {};\n\n  if (value.version !== undefined && value.version !== 1) {\n    warnings.push(\"Only pi-statusline configuration version 1 is supported.\");\n  }\n\n  let enabled = DEFAULT_ENABLED;\n  if (value.enabled !== undefined) {\n    if (typeof value.enabled === \"boolean\") {\n      enabled = value.enabled;\n    } else {\n      warnings.push(\"The enabled field must be a boolean; using the default.\");\n    }\n  }\n\n  let hiddenStatuses: string[] = [...DEFAULT_HIDDEN_STATUSES];\n  if (value.hiddenStatuses !== undefined) {\n    if (Array.isArray(value.hiddenStatuses) && value.hiddenStatuses.every((entry) => typeof entry === \"string\")) {\n      hiddenStatuses = value.hiddenStatuses as string[];\n    } else {\n      warnings.push(\"The hiddenStatuses field must be an array of strings; using the default.\");\n    }\n  }\n\n  return { config: { version: 1, enabled, hiddenStatuses }, warnings };\n}\n\nexport function configPath(\n  env: NodeJS.ProcessEnv = process.env,\n  homeDirectory = os.homedir(),\n): { readonly primary: string; readonly fallback: string } {\n  const agentDir = env.PI_CODING_AGENT_DIR?.trim() || path.join(homeDirectory, \".pi\", \"agent\");\n  const fallback = path.join(homeDirectory, \".pi\", \"agent\", \"pi-statusline.json\");\n  return { primary: path.join(agentDir, \"pi-statusline.json\"), fallback };\n}\n\nexport function loadStatuslineConfig(\n  env: NodeJS.ProcessEnv = process.env,\n  homeDirectory = os.homedir(),\n): LoadedStatuslineConfig {\n  const { primary, fallback } = configPath(env, homeDirectory);\n  const candidates = primary === fallback ? [primary] : [primary, fallback];\n  const warnings: string[] = [];\n  let raw: unknown;\n\n  for (const candidate of candidates) {\n    try {\n      raw = JSON.parse(fs.readFileSync(candidate, \"utf8\")) as unknown;\n      break;\n    } catch (error: unknown) {\n      if (isFileNotFound(error)) continue;\n      warnings.push(`Could not read ${candidate}; using pi-statusline defaults.`);\n      break;\n    }\n  }\n\n  const parsed = parseStatuslineConfig(raw);\n  return { config: parsed.config, warnings: [...warnings, ...parsed.warnings], path: primary };\n}\n\n/** Writes atomically: temp file, fsync, rename. Mirrors how pi-git stores settings. */\nexport function writeStatuslineConfig(\n  config: StatuslineConfig,\n  env: NodeJS.ProcessEnv = process.env,\n  homeDirectory = os.homedir(),\n): string {\n  const { primary: target } = configPath(env, homeDirectory);\n  const directory = path.dirname(target);\n  fs.mkdirSync(directory, { recursive: true, mode: 0o700 });\n  const temporary = path.join(directory, `.pi-statusline.${process.pid}.${Date.now()}.tmp`);\n  const serializable = {\n    version: 1,\n    enabled: config.enabled,\n    hiddenStatuses: [...config.hiddenStatuses],\n  };\n\n  let descriptor: number | undefined;\n  try {\n    descriptor = fs.openSync(temporary, \"w\", 0o600);\n    fs.writeFileSync(descriptor, `${JSON.stringify(serializable, null, 2)}\\n`, \"utf8\");\n    fs.fsyncSync(descriptor);\n    fs.closeSync(descriptor);\n    descriptor = undefined;\n    fs.renameSync(temporary, target);\n    try {\n      fs.chmodSync(target, 0o600);\n    } catch {\n      // The rename already landed; chmod is best effort on platforms that ignore it.\n    }\n  } catch (error) {\n    if (descriptor !== undefined) fs.closeSync(descriptor);\n    try {\n      fs.unlinkSync(temporary);\n    } catch {\n      // Preserve the original write error.\n    }\n    throw error;\n  }\n  return target;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n  return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction isFileNotFound(error: unknown): boolean {\n  return Boolean(error && typeof error === \"object\" && \"code\" in error && (error as { code?: unknown }).code === \"ENOENT\");\n}\n"}},"statusline.ts":{"file":{"contents":"import type { AssistantMessage } from \"@earendil-works/pi-ai\";\nimport type { ExtensionAPI } from \"@earendil-works/pi-coding-agent\";\nimport { truncateToWidth } from \"@earendil-works/pi-tui\";\nimport type { StatuslineConfig } from \"./config.js\";\nimport { compactTokenCount } from \"./token-format.js\";\n\n/** How often the working-tree dirty flag is re-checked. */\nconst DIRTY_POLL_MS = 5_000;\n/** Cache entries older than this are worth an amber TTL. */\nconst CACHE_TTL_WARNING_MS = 5 * 60_000;\n\nexport function registerStatusline(pi: ExtensionAPI, config: StatuslineConfig): void {\n  if (!config.enabled) return;\n\n  let sessionStarted = Date.now();\n  let sessionElapsed = formatSessionDuration(0);\n  let sessionStartLabel = formatSessionStart(sessionStarted);\n  let dirty = false;\n  let inputTokens = 0;\n  let cacheReadTokens = 0;\n  let outputTokens = 0;\n  let cost = 0;\n  let lastCacheRefreshAt: number | undefined;\n  let cacheResetAt = 0;\n  let dirtyTimer: ReturnType<typeof setInterval> | undefined;\n  let ttlTimer: ReturnType<typeof setInterval> | undefined;\n  let sessionTimer: ReturnType<typeof setInterval> | undefined;\n  let requestFooterRender: (() => void) | undefined;\n  let disposed = false;\n\n  const refreshDirty = async (cwd: string, renderOnChange = true): Promise<void> => {\n    let nextDirty: boolean;\n    try {\n      const result = await pi.exec(\"git\", [\"status\", \"--porcelain=v1\", \"-z\", \"--\", \".\"], { cwd, timeout: 5_000 });\n      nextDirty = result.stdout.length > 0;\n    } catch {\n      nextDirty = false;\n    }\n    if (disposed || nextDirty === dirty) return;\n    dirty = nextDirty;\n    if (renderOnChange) requestFooterRender?.();\n  };\n\n  const refreshUsage = (ctx: { sessionManager: { getBranch: () => readonly unknown[] } }): void => {\n    inputTokens = 0;\n    cacheReadTokens = 0;\n    outputTokens = 0;\n    cost = 0;\n    lastCacheRefreshAt = undefined;\n    for (const entry of ctx.sessionManager.getBranch()) {\n      if (!isAssistantEntry(entry)) continue;\n      inputTokens += entry.message.usage.input;\n      cacheReadTokens += entry.message.usage.cacheRead;\n      outputTokens += entry.message.usage.output;\n      cost += entry.message.usage.cost.total;\n      if (entry.message.timestamp >= cacheResetAt && (entry.message.usage.cacheRead > 0 || entry.message.usage.cacheWrite > 0)) {\n        lastCacheRefreshAt = entry.message.timestamp;\n      }\n    }\n  };\n\n  pi.on(\"session_start\", async (_event, ctx) => {\n    disposed = false;\n    sessionStarted = Date.now();\n    const headerTimestamp = ctx.sessionManager.getHeader?.()?.timestamp;\n    const persistedStart = headerTimestamp === undefined ? NaN : Date.parse(headerTimestamp);\n    sessionStartLabel = formatSessionStart(Number.isFinite(persistedStart) ? persistedStart : sessionStarted);\n    cacheResetAt = 0;\n    requestFooterRender = undefined;\n    sessionElapsed = formatSessionDuration(0);\n    refreshUsage(ctx);\n    await refreshDirty(ctx.cwd);\n    if (dirtyTimer) clearInterval(dirtyTimer);\n    dirtyTimer = setInterval(() => void refreshDirty(ctx.cwd), DIRTY_POLL_MS);\n    if (ttlTimer) clearInterval(ttlTimer);\n    ttlTimer = setInterval(() => {\n      if (lastCacheRefreshAt !== undefined) requestFooterRender?.();\n    }, 1_000);\n    if (sessionTimer) clearInterval(sessionTimer);\n    sessionTimer = setInterval(() => {\n      sessionElapsed = formatSessionDuration(Date.now() - sessionStarted);\n      requestFooterRender?.();\n    }, 60_000);\n\n    ctx.ui.setFooter((tui, theme, footerData) => {\n      const requestRender = () => tui.requestRender();\n      requestFooterRender = requestRender;\n      const unsubscribe = footerData.onBranchChange(() => {\n        void refreshDirty(ctx.cwd, false).then(requestRender);\n      });\n      return {\n        dispose: () => {\n          unsubscribe();\n          if (requestFooterRender === requestRender) requestFooterRender = undefined;\n        },\n        invalidate: () => undefined,\n        render: (width: number): string[] => {\n          const home = process.env.HOME ?? \"\";\n          const directory = home && ctx.cwd.startsWith(home) ? `~${ctx.cwd.slice(home.length)}` : ctx.cwd;\n          const branch = footerData.getGitBranch();\n          const branchText = branch ? `⎇ ${branch}${dirty ? \"*\" : \"\"}` : \"no-git\";\n          const model = ctx.model?.name || ctx.model?.id || \"no-model\";\n          const provider = ctx.model?.provider || \"no-provider\";\n          const usage = ctx.getContextUsage();\n          const percent = usage ? Math.min(100, Math.max(0, Math.round(usage.percent ?? 0))) : 0;\n          // The bar carries the fraction, so the number next to it is absolute:\n          // a percentage means nothing once you switch between window sizes.\n          const tokens = usage?.tokens;\n          const contextTokens = typeof tokens === \"number\" ? compactTokenCount(tokens) : \"?\";\n          const cacheAge = lastCacheRefreshAt === undefined ? undefined : Date.now() - lastCacheRefreshAt;\n          const cacheTtl = cacheAge === undefined ? undefined : formatTtl(cacheAge);\n          const cacheTtlColor = cacheAge !== undefined && cacheAge >= CACHE_TTL_WARNING_MS ? \"warning\" : \"dim\";\n          const context = `  ${contextBar(percent)} ${contextTokens}`;\n          const line = [\n            theme.fg(\"muted\", directory),\n            theme.fg(dirty ? \"warning\" : \"success\", `  ${branchText}`),\n            theme.fg(\"accent\", `  ${model}`),\n            theme.fg(\"dim\", ` ${provider}`),\n            theme.fg(\"dim\", context),\n            theme.fg(\"dim\", \"  \") +\n              theme.fg(\"muted\", \"$\") +\n              theme.fg(\"dim\", cost.toFixed(2)) +\n              theme.fg(\"dim\", \" \") +\n              theme.fg(\"muted\", \"⚡\") +\n              theme.fg(\"dim\", compactTokenCount(cacheReadTokens)) +\n              theme.fg(\"dim\", \" \") +\n              theme.fg(\"muted\", \"↑\") +\n              theme.fg(\"dim\", compactTokenCount(inputTokens)) +\n              theme.fg(\"dim\", \" \") +\n              theme.fg(\"muted\", \"↓\") +\n              theme.fg(\"dim\", compactTokenCount(outputTokens)) +\n              (cacheTtl === undefined ? \"\" :\n                theme.fg(\"dim\", \" \") +\n                theme.fg(\"muted\", \"TTL\") +\n                theme.fg(\"dim\", \" \") +\n                theme.fg(cacheTtlColor, cacheTtl)),\n            theme.fg(\"dim\", \"  \") +\n              theme.fg(\"muted\", \"⏱\") +\n              theme.fg(\"dim\", ` ${sessionElapsed}`) +\n              theme.fg(\"dim\", \"  \") +\n              theme.fg(\"muted\", \"Started\") +\n              theme.fg(\"dim\", ` ${sessionStartLabel}`),\n          ].join(\"\");\n          return [\n            truncateToWidth(line, width),\n            ...renderExtensionStatuses(width, config, footerData, (text) => theme.fg(\"text\", text)),\n          ];\n        },\n      };\n    });\n  });\n\n  const usageHandler = async (event: unknown, ctx: { sessionManager: { getBranch: () => readonly unknown[] } }) => {\n    if (event && typeof event === \"object\" && \"type\" in event && event.type === \"session_compact\") {\n      cacheResetAt = Date.now();\n    }\n    refreshUsage(ctx);\n  };\n  // One shared handler covers every event that can move the totals, since each\n  // of them only needs a fresh read of the session branch.\n  for (const event of [\"turn_end\", \"session_switch\", \"session_fork\", \"session_tree\", \"session_compact\"] as const) {\n    pi.on(event as any, usageHandler as any);\n  }\n  pi.on(\"tool_result\", async (_event, ctx) => refreshDirty(ctx.cwd));\n  pi.on(\"session_shutdown\", async () => {\n    disposed = true;\n    requestFooterRender = undefined;\n    for (const timer of [dirtyTimer, ttlTimer, sessionTimer]) {\n      if (timer) clearInterval(timer);\n    }\n    dirtyTimer = undefined;\n    ttlTimer = undefined;\n    sessionTimer = undefined;\n  });\n}\n\n/**\n * Extension statuses live in the map pi maintains for ctx.ui.setStatus(). The\n * built-in footer would have drawn them; a replacement footer has to redraw\n * them itself or every status indicator in the session silently disappears.\n */\nfunction renderExtensionStatuses(\n  width: number,\n  config: StatuslineConfig,\n  footerData: { getExtensionStatuses: () => ReadonlyMap<string, string> },\n  colorize: (text: string) => string,\n): string[] {\n  const hidden = new Set(config.hiddenStatuses);\n  return Array.from(footerData.getExtensionStatuses().entries())\n    .filter(([key, text]) => !hidden.has(key) && text.trim().length > 0)\n    .map(([, text]) => truncateToWidth(colorize(text), width));\n}\n\nfunction isAssistantEntry(value: unknown): value is { message: AssistantMessage } {\n  if (!value || typeof value !== \"object\") return false;\n  const entry = value as { type?: unknown; message?: unknown };\n  if (entry.type !== \"message\" || !entry.message || typeof entry.message !== \"object\") return false;\n  return (entry.message as { role?: unknown }).role === \"assistant\";\n}\n\nfunction contextBar(percent: number): string {\n  const filled = Math.floor(percent / 10);\n  let bar = \"\";\n  for (let index = 0; index < 10; index += 1) {\n    if (index < filled) {\n      const red = index < 5 ? index * 51 : 255;\n      const green = index < 5 ? 255 : 255 - (index - 4) * 51;\n      bar += rgb(red, green, 0, \"▰\");\n    } else {\n      bar += rgb(100, 100, 100, \"▱\");\n    }\n  }\n  return bar;\n}\n\nfunction rgb(red: number, green: number, blue: number, text: string): string {\n  return `\\x1b[38;2;${red};${green};${blue}m${text}\\x1b[0m`;\n}\n\nfunction formatTtl(milliseconds: number): string {\n  const seconds = Math.max(0, Math.floor(milliseconds / 1_000));\n  return `${String(Math.floor(seconds / 60)).padStart(2, \"0\")}:${String(seconds % 60).padStart(2, \"0\")}`;\n}\n\nfunction formatSessionDuration(milliseconds: number): string {\n  const minutes = Math.max(0, Math.floor(milliseconds / 60_000));\n  if (minutes < 60) return `${minutes}m`;\n  return `${Math.floor(minutes / 60)}h ${minutes % 60}m`;\n}\n\nfunction formatSessionStart(timestamp: number): string {\n  const started = new Date(timestamp);\n  const now = new Date();\n  const startedDay = new Date(started.getFullYear(), started.getMonth(), started.getDate());\n  const currentDay = new Date(now.getFullYear(), now.getMonth(), now.getDate());\n  const dayDifference = Math.round((currentDay.getTime() - startedDay.getTime()) / 86_400_000);\n  const time = `${String(started.getHours()).padStart(2, \"0\")}:${String(started.getMinutes()).padStart(2, \"0\")}`;\n  if (dayDifference === 0) return time;\n  if (dayDifference === 1) return `${time} yesterday`;\n  return `${started.toLocaleString(\"en-US\", { month: \"short\" })} ${started.getDate()}`;\n}\n"}},"token-format.ts":{"file":{"contents":"/**\n * Number formatting for the token readout.\n *\n * pi-git renders the same `$0.42 ⚡19.0M ↑264k ↓86k` shape in its commit notices,\n * so the two extensions agree by convention. This copy is deliberately\n * independent: a status line should not depend on a git workflow package for a\n * number formatter, and six duplicated lines is cheaper than that coupling.\n * If the shape changes, change it here and in pi-git's src/usage-format.ts.\n */\nexport function compactTokenCount(value: number): string {\n  if (value >= 1_000_000) return `${(value / 1_000_000).toFixed(1)}M`;\n  // Keep one decimal below 10k, where rounding to whole kilo would hide a third\n  // of the spend on small requests.\n  if (value >= 10_000) return `${Math.round(value / 1_000)}k`;\n  if (value >= 1_000) return `${Math.round(value / 100) / 10}k`;\n  return String(value);\n}\n"}}}}}}}},"settings.json":{"file":{"contents":"{\n  \"defaultProvider\": \"demo\",\n  \"defaultModel\": \"scripted\",\n  \"defaultThinkingLevel\": \"medium\",\n  \"quietStartup\": true,\n  \"enableInstallTelemetry\": false,\n  \"theme\": \"showcase\"\n}\n"}}}}}},"bin":{"directory":{"fd":{"file":{"contents":"#!/usr/bin/env node\n// A placeholder for fd, which the sandbox lacks: pi checks for it at startup and warns when it is missing.\n// It reports a version and finds nothing, so @-file completion stays empty in the demo.\nif (process.argv.includes(\"--version\")) console.log(\"fd (demo placeholder)\");\n"}},"git":{"file":{"contents":"#!/usr/bin/env node\n// A stand-in for git: the sandbox has none. It answers the two questions pi and pi-statusline ask,\n// the branch and whether the working tree changed since the demo started (against .demo/baseline.json).\nconst { createHash } = require(\"node:crypto\");\nconst { readFileSync, readdirSync, statSync } = require(\"node:fs\");\nconst path = require(\"node:path\");\n\nconst args = process.argv.slice(2).filter((arg) => arg !== \"--no-optional-locks\");\nconst home = path.join(__dirname, \"..\");\nconst project = path.join(home, \"project\");\n\nfunction files(dir, base = dir) {\n  return readdirSync(dir).flatMap((name) => {\n    if (name === \".git\" || name === \"node_modules\") return [];\n    const file = path.join(dir, name);\n    return statSync(file).isDirectory() ? files(file, base) : [path.relative(base, file)];\n  });\n}\nconst hash = (file) => createHash(\"sha1\").update(readFileSync(path.join(project, file))).digest(\"hex\");\n\nif (args[0] === \"symbolic-ref\") {\n  process.stdout.write(\"main\\n\");\n} else if (args[0] === \"status\") {\n  const baseline = JSON.parse(readFileSync(path.join(home, \".demo/baseline.json\"), \"utf8\"));\n  const current = files(project);\n  const changes = [\n    ...current.filter((file) => !(file in baseline)).map((file) => `?? ${file}`),\n    ...current.filter((file) => file in baseline && baseline[file] !== hash(file)).map((file) => ` M ${file}`),\n    ...Object.keys(baseline).filter((file) => !current.includes(file)).map((file) => ` D ${file}`),\n  ];\n  const zero = args.includes(\"-z\");\n  process.stdout.write(changes.map((line) => line + (zero ? \"\\0\" : \"\\n\")).join(\"\"));\n} else {\n  process.stderr.write(`git ${args.join(\" \")}: only a stand-in for git runs in this demo.\\n`);\n  process.exit(1);\n}\n"}},"pi":{"file":{"contents":"#!/usr/bin/env node\n// pi, bundled for the browser sandbox by demo/browser/build.mjs.\nimport(\"../.pi-app/dist/cli.js\");\n"}},"rg":{"file":{"contents":"#!/usr/bin/env node\n// A placeholder for rg, which the sandbox lacks: pi checks for it at startup and warns when it is missing.\n// It reports a version and finds nothing, so @-file completion stays empty in the demo.\nif (process.argv.includes(\"--version\")) console.log(\"rg (demo placeholder)\");\n"}}}},"package.json":{"file":{"contents":"{\n  \"name\": \"pi-demo\",\n  \"private\": true,\n  \"description\": \"Dependencies of the bundled pi 0.84.2, written by demo/browser/build.mjs.\",\n  \"dependencies\": {\n    \"@silvia-odwyer/photon-node\": \"0.3.4\",\n    \"chalk\": \"5.6.2\",\n    \"cross-spawn\": \"7.0.6\",\n    \"diff\": \"8.0.4\",\n    \"get-east-asian-width\": \"1.6.0\",\n    \"glob\": \"13.0.6\",\n    \"grok-mermaid\": \"0.2.2\",\n    \"highlight.js\": \"10.7.3\",\n    \"hosted-git-info\": \"9.0.3\",\n    \"http-proxy-agent\": \"7.0.2\",\n    \"https-proxy-agent\": \"7.0.6\",\n    \"ignore\": \"7.0.5\",\n    \"jiti\": \"2.7.0\",\n    \"marked\": \"18.0.5\",\n    \"minimatch\": \"10.2.5\",\n    \"partial-json\": \"0.1.7\",\n    \"proper-lockfile\": \"4.1.2\",\n    \"semver\": \"7.8.0\",\n    \"typebox\": \"1.3.7\",\n    \"undici\": \"8.9.0\",\n    \"yaml\": \"2.9.0\"\n  }\n}\n"}},"project":{"directory":{"README.md":{"file":{"contents":"# forecast\n\nA tiny command-line weather lookup. `node src/cli.js Berlin` prints today's forecast for a city from a bundled sample of readings, so it works offline.\n\n## Usage\n\n```sh\nnode src/cli.js Berlin\nnode src/cli.js Lisbon\n```\n"}},"package.json":{"file":{"contents":"{\n  \"name\": \"forecast\",\n  \"version\": \"0.1.0\",\n  \"type\": \"module\",\n  \"bin\": { \"forecast\": \"src/cli.js\" }\n}\n"}},"src":{"directory":{"cli.js":{"file":{"contents":"#!/usr/bin/env node\nimport { readings } from \"./readings.js\";\n\nconst city = process.argv[2];\nif (!city) {\n  console.error(\"Usage: forecast <city>\");\n  process.exit(1);\n}\n\nconst reading = readings[city.toLowerCase()];\nif (!reading) {\n  console.error(`No forecast for ${city}. Try Berlin, Lisbon or Oslo.`);\n  process.exit(1);\n}\n\nconsole.log(`${city}: ${reading.sky}, ${reading.low}-${reading.high}°C, ${Math.round(reading.rain * 100)}% chance of rain`);\n"}},"readings.js":{"file":{"contents":"// Sample readings, so the CLI works without a network.\nexport const readings = {\n  berlin: { sky: \"overcast\", high: 14, low: 8, rain: 0.6 },\n  lisbon: { sky: \"sunny\", high: 23, low: 16, rain: 0.05 },\n  oslo: { sky: \"light rain\", high: 9, low: 4, rain: 0.8 },\n};\n"}}}}}},".pi-app":{"directory":{"dist":{"directory":{"cli.js":{"file":{"contents":"#!/usr/bin/env node\nimport { createRequire as __createRequire } from 'node:module'; const require = __createRequire(import.meta.url);\nvar __defProp = Object.defineProperty;\nvar __getOwnPropNames = Object.getOwnPropertyNames;\nvar __require = /* @__PURE__ */ ((x) => typeof require !== \"undefined\" ? require : typeof Proxy !== \"undefined\" ? new Proxy(x, {\n  get: (a, b) => (typeof require !== \"undefined\" ? require : a)[b]\n}) : x)(function(x) {\n  if (typeof require !== \"undefined\") return require.apply(this, arguments);\n  throw Error('Dynamic require of \"' + x + '\" is not supported');\n});\nvar __esm = (fn, res) => function __init() {\n  return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;\n};\nvar __export = (target, all) => {\n  for (var name in all)\n    __defProp(target, name, { get: all[name], enumerable: true });\n};\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/utils/event-stream.js\nfunction createAssistantMessageEventStream() {\n  return new AssistantMessageEventStream();\n}\nvar EventStream, AssistantMessageEventStream;\nvar init_event_stream = __esm({\n  \"node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/utils/event-stream.js\"() {\n    EventStream = class {\n      queue = [];\n      waiting = [];\n      done = false;\n      finalResultPromise;\n      resolveFinalResult;\n      isComplete;\n      extractResult;\n      constructor(isComplete, extractResult) {\n        this.isComplete = isComplete;\n        this.extractResult = extractResult;\n        this.finalResultPromise = new Promise((resolve15) => {\n          this.resolveFinalResult = resolve15;\n        });\n      }\n      push(event) {\n        if (this.done)\n          return;\n        if (this.isComplete(event)) {\n          this.done = true;\n          this.resolveFinalResult(this.extractResult(event));\n        }\n        const waiter = this.waiting.shift();\n        if (waiter) {\n          waiter({ value: event, done: false });\n        } else {\n          this.queue.push(event);\n        }\n      }\n      end(result) {\n        this.done = true;\n        if (result !== void 0) {\n          this.resolveFinalResult(result);\n        }\n        while (this.waiting.length > 0) {\n          const waiter = this.waiting.shift();\n          waiter({ value: void 0, done: true });\n        }\n      }\n      async *[Symbol.asyncIterator]() {\n        while (true) {\n          if (this.queue.length > 0) {\n            yield this.queue.shift();\n          } else if (this.done) {\n            return;\n          } else {\n            const result = await new Promise((resolve15) => this.waiting.push(resolve15));\n            if (result.done)\n              return;\n            yield result.value;\n          }\n        }\n      }\n      result() {\n        return this.finalResultPromise;\n      }\n    };\n    AssistantMessageEventStream = class extends EventStream {\n      constructor() {\n        super((event) => event.type === \"done\" || event.type === \"error\", (event) => {\n          if (event.type === \"done\") {\n            return event.message;\n          } else if (event.type === \"error\") {\n            return event.error;\n          }\n          throw new Error(\"Unexpected event type for final result\");\n        });\n      }\n    };\n  }\n});\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/api/lazy.js\nfunction createSetupErrorMessage(model, error) {\n  return {\n    role: \"assistant\",\n    content: [],\n    api: model.api,\n    provider: model.provider,\n    model: model.id,\n    usage: {\n      input: 0,\n      output: 0,\n      cacheRead: 0,\n      cacheWrite: 0,\n      totalTokens: 0,\n      cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 }\n    },\n    stopReason: \"error\",\n    errorMessage: error instanceof Error ? error.message : String(error),\n    timestamp: Date.now()\n  };\n}\nfunction hasResult(source) {\n  return typeof source.result === \"function\";\n}\nasync function forwardStream(target, source) {\n  for await (const event of source) {\n    target.push(event);\n  }\n  target.end(hasResult(source) ? await source.result() : void 0);\n}\nfunction lazyStream(model, setup) {\n  const outer = new AssistantMessageEventStream();\n  setup().then((inner) => forwardStream(outer, inner)).catch((error) => {\n    const message = createSetupErrorMessage(model, error);\n    outer.push({ type: \"error\", reason: \"error\", error: message });\n    outer.end(message);\n  });\n  return outer;\n}\nfunction lazyApi(load, capabilities) {\n  const api = {\n    stream: (model, context, options) => lazyStream(model, async () => (await load()).stream(model, context, options)),\n    streamSimple: (model, context, options) => lazyStream(model, async () => (await load()).streamSimple(model, context, options))\n  };\n  if (capabilities?.fetchDeferred) {\n    api.fetchDeferred = (model, handle, options) => lazyStream(model, async () => {\n      const implementation = await load();\n      if (!implementation.fetchDeferred)\n        throw new Error(\"API does not support deferred responses\");\n      return implementation.fetchDeferred(model, handle, options);\n    });\n  }\n  if (capabilities?.cancelDeferred) {\n    api.cancelDeferred = async (model, handle, options) => {\n      const implementation = await load();\n      if (!implementation.cancelDeferred)\n        throw new Error(\"API cannot cancel deferred responses\");\n      await implementation.cancelDeferred(model, handle, options);\n    };\n  }\n  return api;\n}\nvar init_lazy = __esm({\n  \"node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/api/lazy.js\"() {\n    init_event_stream();\n  }\n});\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/auth/context.js\nfunction getProcessEnv() {\n  const proc = globalThis.process;\n  return proc?.env;\n}\nfunction defaultProviderAuthContext() {\n  return {\n    async env(name) {\n      const value = getProcessEnv()?.[name];\n      return typeof value === \"string\" && value.trim().length > 0 ? value : void 0;\n    },\n    async fileExists(path12) {\n      try {\n        const fs8 = await importNodeModule(\"node:fs/promises\");\n        let resolved = path12;\n        if (resolved.startsWith(\"~\")) {\n          const os5 = await importNodeModule(\"node:os\");\n          resolved = os5.homedir() + resolved.slice(1);\n        }\n        await fs8.access(resolved);\n        return true;\n      } catch {\n        return false;\n      }\n    }\n  };\n}\nvar __rewriteRelativeImportExtension, importNodeModule;\nvar init_context = __esm({\n  \"node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/auth/context.js\"() {\n    __rewriteRelativeImportExtension = function(path12, preserveJsx) {\n      if (typeof path12 === \"string\" && /^\\.\\.?\\//.test(path12)) {\n        return path12.replace(/\\.(tsx)$|((?:\\.d)?)((?:\\.[^./]+?)?)\\.([cm]?)ts$/i, function(m, tsx, d, ext, cm) {\n          return tsx ? preserveJsx ? \".jsx\" : \".js\" : d && (!ext || !cm) ? m : d + ext + \".\" + cm.toLowerCase() + \"js\";\n        });\n      }\n      return path12;\n    };\n    importNodeModule = (specifier) => import(__rewriteRelativeImportExtension(specifier));\n  }\n});\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/utils/abort.js\nfunction abortReason(signal) {\n  if (signal.reason !== void 0)\n    return signal.reason;\n  const error = new Error(\"The operation was aborted\");\n  error.name = \"AbortError\";\n  return error;\n}\nfunction operationSignal(signal) {\n  return signal ?? new AbortController().signal;\n}\nfunction raceWithAbortSignal(operation, signal) {\n  if (signal.aborted) {\n    void operation.catch(() => {\n    });\n    return Promise.reject(abortReason(signal));\n  }\n  return new Promise((resolve15, reject) => {\n    let settled = false;\n    const cleanup = () => signal.removeEventListener(\"abort\", onAbort);\n    const onAbort = () => {\n      if (settled)\n        return;\n      settled = true;\n      cleanup();\n      reject(abortReason(signal));\n    };\n    signal.addEventListener(\"abort\", onAbort, { once: true });\n    void operation.then((value) => {\n      if (settled)\n        return;\n      settled = true;\n      cleanup();\n      resolve15(value);\n    }, (error) => {\n      if (settled)\n        return;\n      settled = true;\n      cleanup();\n      reject(error);\n    });\n    if (signal.aborted)\n      onAbort();\n  });\n}\nvar init_abort = __esm({\n  \"node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/utils/abort.js\"() {\n  }\n});\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/auth/credential-store.js\nvar InMemoryCredentialStore;\nvar init_credential_store = __esm({\n  \"node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/auth/credential-store.js\"() {\n    init_abort();\n    InMemoryCredentialStore = class {\n      credentials = /* @__PURE__ */ new Map();\n      chains = /* @__PURE__ */ new Map();\n      /** Serialize tasks per provider id without releasing the chain before active work settles. */\n      enqueue(providerId, task, options) {\n        const signal = operationSignal(options?.signal);\n        const previous = this.chains.get(providerId) ?? Promise.resolve();\n        const queued = (async () => {\n          await previous.catch(() => {\n          });\n          signal.throwIfAborted();\n          return task();\n        })();\n        const tail = queued.catch(() => {\n        });\n        this.chains.set(providerId, tail);\n        void tail.then(() => {\n          if (this.chains.get(providerId) === tail)\n            this.chains.delete(providerId);\n        });\n        return raceWithAbortSignal(queued, signal);\n      }\n      async read(providerId, options) {\n        options?.signal?.throwIfAborted();\n        return this.credentials.get(providerId);\n      }\n      async list(options) {\n        options?.signal?.throwIfAborted();\n        return [...this.credentials].map(([providerId, credential]) => ({ providerId, type: credential.type }));\n      }\n      modify(providerId, fn, options) {\n        return this.enqueue(providerId, async () => {\n          const current = this.credentials.get(providerId);\n          const next = await fn(current);\n          options?.signal?.throwIfAborted();\n          if (next !== void 0)\n            this.credentials.set(providerId, next);\n          return next ?? current;\n        }, options);\n      }\n      delete(providerId, options) {\n        return this.enqueue(providerId, async () => {\n          this.credentials.delete(providerId);\n        }, options);\n      }\n    };\n  }\n});\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/utils/diagnostics.js\nfunction formatThrownValue(value) {\n  if (value instanceof Error)\n    return value.message || value.name;\n  if (typeof value === \"string\")\n    return value;\n  return String(value);\n}\nfunction extractDiagnosticError(error) {\n  if (!(error instanceof Error))\n    return { name: \"ThrownValue\", message: formatThrownValue(error) };\n  const code = error.code;\n  return {\n    name: error.name || void 0,\n    message: error.message || error.name,\n    stack: error.stack,\n    code: typeof code === \"string\" || typeof code === \"number\" ? code : void 0\n  };\n}\nfunction createAssistantMessageDiagnostic(type, error, details) {\n  return { type, timestamp: Date.now(), error: extractDiagnosticError(error), details };\n}\nfunction appendAssistantMessageDiagnostic(message, diagnostic) {\n  message.diagnostics = [...message.diagnostics ?? [], diagnostic];\n}\nvar init_diagnostics = __esm({\n  \"node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/utils/diagnostics.js\"() {\n  }\n});\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/auth/resolve.js\nfunction withCauseDetail(message, cause) {\n  if (cause === void 0 || cause === null)\n    return message;\n  const detail = formatThrownValue(cause).trim();\n  if (!detail || message.includes(detail))\n    return message;\n  return `${message}: ${detail}`;\n}\nfunction resolveProviderAuth(provider, credentials, authContext, overrides) {\n  const signal = operationSignal(overrides?.signal);\n  return raceWithAbortSignal(resolveProviderAuthWithSignal(provider, credentials, authContext, overrides, signal), signal);\n}\nasync function resolveProviderAuthWithSignal(provider, credentials, authContext, overrides, signal) {\n  signal.throwIfAborted();\n  const requestAuthContext = overrides?.env ? overlayEnvAuthContext(authContext, overrides.env) : authContext;\n  if (overrides?.apiKey !== void 0 && provider.auth.apiKey) {\n    return resolveApiKey(requestAuthContext, provider.auth.apiKey, provider.id, {\n      type: \"api_key\",\n      key: overrides.apiKey,\n      env: overrides.env\n    }, signal);\n  }\n  const stored = await readCredential(credentials, provider.id, signal);\n  if (stored) {\n    if (stored.type === \"oauth\" && provider.auth.oauth) {\n      return resolveStoredOAuth(credentials, provider.id, provider.auth.oauth, stored, signal, overrides?.minOAuthValidityMs);\n    }\n    if (stored.type === \"api_key\" && provider.auth.apiKey) {\n      const credential = overrides?.env ? { ...stored, env: { ...stored.env, ...overrides.env } } : stored;\n      return resolveApiKey(requestAuthContext, provider.auth.apiKey, provider.id, credential, signal);\n    }\n    return void 0;\n  }\n  return provider.auth.apiKey ? resolveApiKey(requestAuthContext, provider.auth.apiKey, provider.id, void 0, signal) : void 0;\n}\nfunction overlayEnvAuthContext(base, env) {\n  return {\n    env: async (name) => env[name] || await base.env(name),\n    fileExists: (path12) => base.fileExists(path12)\n  };\n}\nasync function resolveStoredOAuth(credentials, providerId, oauth, stored, signal, minOAuthValidityMs) {\n  const minimumValidityMs = Math.max(DEFAULT_OAUTH_MINIMUM_VALIDITY_MS, minOAuthValidityMs ?? 0);\n  const expiresSoon = (credential2) => Date.now() + minimumValidityMs >= credential2.expires;\n  let credential = stored;\n  if (expiresSoon(credential)) {\n    let post;\n    try {\n      post = await credentials.modify(providerId, async (current) => {\n        if (current?.type !== \"oauth\")\n          return void 0;\n        if (!expiresSoon(current))\n          return void 0;\n        try {\n          const refreshSignal = AbortSignal.any([\n            signal,\n            AbortSignal.timeout(DEFAULT_OAUTH_REFRESH_TIMEOUT_MS)\n          ]);\n          return await oauth.refresh(current, refreshSignal);\n        } catch (error) {\n          throw new ModelsError(\"oauth\", `OAuth refresh failed for ${providerId}`, { cause: error });\n        }\n      }, { signal });\n    } catch (error) {\n      if (error instanceof ModelsError)\n        throw error;\n      throw new ModelsError(\"auth\", `Credential store modify failed for ${providerId}`, { cause: error });\n    }\n    if (post?.type !== \"oauth\")\n      return void 0;\n    credential = post;\n    if (minOAuthValidityMs !== void 0 && expiresSoon(credential)) {\n      throw new ModelsError(\"oauth\", `OAuth refresh returned a token that expires too soon for ${providerId}`);\n    }\n  }\n  try {\n    return { auth: await oauth.toAuth(credential), source: \"OAuth\" };\n  } catch (error) {\n    throw new ModelsError(\"oauth\", `OAuth auth derivation failed for ${providerId}`, { cause: error });\n  }\n}\nasync function resolveApiKey(authContext, apiKey, providerId, credential, signal) {\n  try {\n    return await apiKey.resolve({ ctx: authContext, credential, signal });\n  } catch (error) {\n    throw new ModelsError(\"auth\", `API key auth failed for provider ${providerId}`, { cause: error });\n  }\n}\nasync function readCredential(credentials, providerId, signal) {\n  try {\n    return await credentials.read(providerId, { signal });\n  } catch (error) {\n    throw new ModelsError(\"auth\", `Credential store read failed for ${providerId}`, { cause: error });\n  }\n}\nvar ModelsError, DEFAULT_OAUTH_MINIMUM_VALIDITY_MS, DEFAULT_OAUTH_REFRESH_TIMEOUT_MS;\nvar init_resolve = __esm({\n  \"node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/auth/resolve.js\"() {\n    init_abort();\n    init_diagnostics();\n    ModelsError = class extends Error {\n      code;\n      constructor(code, message, options) {\n        super(withCauseDetail(message, options?.cause), options);\n        this.name = \"ModelsError\";\n        this.code = code;\n      }\n    };\n    DEFAULT_OAUTH_MINIMUM_VALIDITY_MS = 5 * 60 * 1e3;\n    DEFAULT_OAUTH_REFRESH_TIMEOUT_MS = 15e3;\n  }\n});\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/models-store.js\nvar InMemoryModelsStore;\nvar init_models_store = __esm({\n  \"node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/models-store.js\"() {\n    InMemoryModelsStore = class {\n      entries = /* @__PURE__ */ new Map();\n      async read(providerId, options) {\n        options?.signal?.throwIfAborted();\n        const entry = this.entries.get(providerId);\n        return entry ? structuredClone(entry) : void 0;\n      }\n      async write(providerId, entry, options) {\n        options?.signal?.throwIfAborted();\n        this.entries.set(providerId, structuredClone(entry));\n      }\n      async delete(providerId, options) {\n        options?.signal?.throwIfAborted();\n        this.entries.delete(providerId);\n      }\n    };\n  }\n});\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/models.js\nfunction mergeHeaders(base, override) {\n  if (!base && !override)\n    return void 0;\n  const merged = { ...base };\n  for (const [name, value] of Object.entries(override ?? {})) {\n    const lowerName = name.toLowerCase();\n    for (const existingName of Object.keys(merged)) {\n      if (existingName.toLowerCase() === lowerName)\n        delete merged[existingName];\n    }\n    merged[name] = value;\n  }\n  return merged;\n}\nfunction createModels(options) {\n  return new ModelsImpl(options);\n}\nfunction createProvider(input) {\n  const baselineModels = input.models;\n  let dynamicModels = [];\n  const fetchModels = input.fetchModels;\n  const currentModels = () => {\n    const merged = [...baselineModels];\n    for (const model of dynamicModels) {\n      const index = merged.findIndex((entry) => entry.id === model.id);\n      if (index >= 0)\n        merged[index] = model;\n      else\n        merged.push(model);\n    }\n    return merged;\n  };\n  const single = typeof input.api.stream === \"function\" ? input.api : void 0;\n  const byApi = single ? void 0 : input.api;\n  const apiFor = (model) => single ?? byApi?.[model.api];\n  const dispatch = (model, run) => {\n    const streams2 = apiFor(model);\n    if (!streams2) {\n      return lazyStream(model, async () => {\n        throw new ModelsError(\"stream\", `Provider ${input.id} has no API implementation for \"${model.api}\"`);\n      });\n    }\n    return run(streams2);\n  };\n  const provider = {\n    id: input.id,\n    name: input.name ?? input.id,\n    baseUrl: input.baseUrl,\n    headers: input.headers,\n    auth: input.auth,\n    getModels: currentModels,\n    refreshModels: fetchModels ? async (context) => {\n      if (context.stored) {\n        const restored = context.stored.models.filter((model) => model.provider === input.id).map((model) => model);\n        if (!await context.publish({\n          update: () => {\n            dynamicModels = restored;\n          }\n        })) {\n          return;\n        }\n      }\n      if (!context.allowNetwork || context.signal.aborted)\n        return;\n      const refreshed = await fetchModels(context);\n      if (context.signal.aborted)\n        return;\n      await context.publish({\n        persist: { models: refreshed, checkedAt: Date.now() },\n        update: () => {\n          dynamicModels = refreshed;\n        }\n      });\n    } : void 0,\n    filterModels: input.filterModels,\n    stream: (model, context, options) => dispatch(model, (streams2) => streams2.stream(model, context, options)),\n    streamSimple: (model, context, options) => dispatch(model, (streams2) => streams2.streamSimple(model, context, options))\n  };\n  const streams = single ? [single] : Object.values(byApi ?? {}).filter((entry) => entry !== void 0);\n  if (streams.some((entry) => entry.fetchDeferred !== void 0)) {\n    provider.fetchDeferred = (model, handle, options) => lazyStream(model, async () => {\n      const implementation = apiFor(model);\n      if (!implementation?.fetchDeferred) {\n        throw new ModelsError(\"provider\", `Provider ${input.id} does not support deferred responses for \"${model.api}\"`);\n      }\n      return implementation.fetchDeferred(model, handle, options);\n    });\n  }\n  if (streams.some((entry) => entry.cancelDeferred !== void 0)) {\n    provider.cancelDeferred = async (model, handle, options) => {\n      const implementation = apiFor(model);\n      if (!implementation?.cancelDeferred) {\n        throw new ModelsError(\"provider\", `Provider ${input.id} cannot cancel deferred responses for \"${model.api}\"`);\n      }\n      await implementation.cancelDeferred(model, handle, options);\n    };\n  }\n  return provider;\n}\nfunction hasApi(model, api) {\n  return model.api === api;\n}\nfunction calculateCost(model, usage) {\n  const inputTokens = usage.input + usage.cacheRead + usage.cacheWrite;\n  let rates = model.cost;\n  let matchedThreshold = -1;\n  for (const tier of model.cost.tiers ?? []) {\n    if (inputTokens > tier.inputTokensAbove && tier.inputTokensAbove > matchedThreshold) {\n      rates = tier;\n      matchedThreshold = tier.inputTokensAbove;\n    }\n  }\n  const longWrite = usage.cacheWrite1h ?? 0;\n  const shortWrite = usage.cacheWrite - longWrite;\n  usage.cost.input = rates.input / 1e6 * usage.input;\n  usage.cost.output = rates.output / 1e6 * usage.output;\n  usage.cost.cacheRead = rates.cacheRead / 1e6 * usage.cacheRead;\n  usage.cost.cacheWrite = (rates.cacheWrite * shortWrite + rates.input * 2 * longWrite) / 1e6;\n  usage.cost.total = usage.cost.input + usage.cost.output + usage.cost.cacheRead + usage.cost.cacheWrite;\n  return usage.cost;\n}\nfunction getSupportedThinkingLevels(model) {\n  if (!model.reasoning)\n    return [\"off\"];\n  return EXTENDED_THINKING_LEVELS.filter((level) => {\n    const mapped = model.thinkingLevelMap?.[level];\n    if (mapped === null)\n      return false;\n    if (level === \"xhigh\" || level === \"max\")\n      return mapped !== void 0;\n    return true;\n  });\n}\nfunction clampThinkingLevel(model, level) {\n  const availableLevels = getSupportedThinkingLevels(model);\n  if (availableLevels.includes(level))\n    return level;\n  const requestedIndex = EXTENDED_THINKING_LEVELS.indexOf(level);\n  if (requestedIndex === -1)\n    return availableLevels[0] ?? \"off\";\n  for (let i = requestedIndex; i < EXTENDED_THINKING_LEVELS.length; i++) {\n    const candidate = EXTENDED_THINKING_LEVELS[i];\n    if (availableLevels.includes(candidate))\n      return candidate;\n  }\n  for (let i = requestedIndex - 1; i >= 0; i--) {\n    const candidate = EXTENDED_THINKING_LEVELS[i];\n    if (availableLevels.includes(candidate))\n      return candidate;\n  }\n  return availableLevels[0] ?? \"off\";\n}\nfunction modelsAreEqual(a, b) {\n  if (!a || !b)\n    return false;\n  return a.id === b.id && a.provider === b.provider;\n}\nvar ModelsImpl, EXTENDED_THINKING_LEVELS;\nvar init_models = __esm({\n  \"node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/models.js\"() {\n    init_lazy();\n    init_context();\n    init_credential_store();\n    init_resolve();\n    init_models_store();\n    init_abort();\n    init_resolve();\n    ModelsImpl = class {\n      providers = /* @__PURE__ */ new Map();\n      credentials;\n      modelsStore;\n      authContext;\n      refreshGenerations = /* @__PURE__ */ new Map();\n      refreshControllers = /* @__PURE__ */ new Map();\n      publicationChains = /* @__PURE__ */ new Map();\n      constructor(options) {\n        this.credentials = options?.credentials ?? new InMemoryCredentialStore();\n        this.modelsStore = options?.modelsStore ?? new InMemoryModelsStore();\n        this.authContext = options?.authContext ?? defaultProviderAuthContext();\n      }\n      setProvider(provider) {\n        this.supersedeProviderRefresh(provider.id);\n        this.providers.set(provider.id, provider);\n      }\n      deleteProvider(id) {\n        this.supersedeProviderRefresh(id);\n        this.providers.delete(id);\n      }\n      clearProviders() {\n        for (const id of /* @__PURE__ */ new Set([...this.providers.keys(), ...this.refreshControllers.keys()])) {\n          this.supersedeProviderRefresh(id);\n        }\n        this.providers.clear();\n      }\n      getProviders() {\n        return Array.from(this.providers.values());\n      }\n      getProvider(id) {\n        return this.providers.get(id);\n      }\n      getModels(provider) {\n        if (provider !== void 0) {\n          const entry = this.providers.get(provider);\n          if (!entry)\n            return [];\n          try {\n            return entry.getModels();\n          } catch {\n            return [];\n          }\n        }\n        const models = [];\n        for (const entry of this.providers.values()) {\n          try {\n            models.push(...entry.getModels());\n          } catch {\n          }\n        }\n        return models;\n      }\n      getModel(provider, id) {\n        return this.getModels(provider).find((model) => model.id === id);\n      }\n      supersedeProviderRefresh(providerId) {\n        const generation = (this.refreshGenerations.get(providerId) ?? 0) + 1;\n        this.refreshGenerations.set(providerId, generation);\n        const previous = this.refreshControllers.get(providerId);\n        if (previous) {\n          this.refreshControllers.delete(providerId);\n          previous.abort();\n        }\n        return generation;\n      }\n      beginProviderRefresh(providerId) {\n        const generation = this.supersedeProviderRefresh(providerId);\n        const controller = new AbortController();\n        this.refreshControllers.set(providerId, controller);\n        return { generation, controller };\n      }\n      publishProviderModels(providerId, generation, signal, publication) {\n        const previous = this.publicationChains.get(providerId) ?? Promise.resolve();\n        const queued = (async () => {\n          await previous.catch(() => {\n          });\n          if (signal.aborted || this.refreshGenerations.get(providerId) !== generation)\n            return false;\n          if (publication.persist === null) {\n            await this.modelsStore.delete(providerId, { signal });\n          } else if (publication.persist !== void 0) {\n            await this.modelsStore.write(providerId, structuredClone(publication.persist), { signal });\n          }\n          if (signal.aborted || this.refreshGenerations.get(providerId) !== generation)\n            return false;\n          publication.update?.();\n          return true;\n        })();\n        const tail = queued.catch(() => {\n        });\n        this.publicationChains.set(providerId, tail);\n        void tail.then(() => {\n          if (this.publicationChains.get(providerId) === tail)\n            this.publicationChains.delete(providerId);\n        });\n        return raceWithAbortSignal(queued, signal);\n      }\n      async runProviderRefreshPhase(provider, credential, allowNetwork, force, generation, signal) {\n        const stored = await this.modelsStore.read(provider.id, { signal });\n        await provider.refreshModels({\n          credential,\n          stored: stored ? structuredClone(stored) : void 0,\n          publish: (publication) => this.publishProviderModels(provider.id, generation, signal, publication),\n          allowNetwork,\n          force: allowNetwork ? force : void 0,\n          signal\n        });\n      }\n      async refresh(options = {}) {\n        const allowNetwork = options.allowNetwork ?? true;\n        const callerSignal = operationSignal(options.signal);\n        const errors = /* @__PURE__ */ new Map();\n        if (callerSignal.aborted)\n          return { aborted: true, errors };\n        const selected = options.providers ? new Set(options.providers) : void 0;\n        const refreshable = Array.from(this.providers.values()).filter((provider) => provider.refreshModels !== void 0 && (!selected || selected.has(provider.id)));\n        const refresh = Promise.all(refreshable.map(async (provider) => {\n          const { generation, controller } = this.beginProviderRefresh(provider.id);\n          const signal = AbortSignal.any([callerSignal, controller.signal]);\n          const operation = (async () => {\n            let storedCredential;\n            let credentialError;\n            try {\n              storedCredential = await this.readCredential(provider.id, signal);\n            } catch (error) {\n              credentialError = error;\n            }\n            await this.runProviderRefreshPhase(provider, storedCredential, false, void 0, generation, signal);\n            if (credentialError !== void 0)\n              throw credentialError;\n            if (!allowNetwork || signal.aborted)\n              return;\n            const credential = await this.resolveRefreshCredential(provider, storedCredential, signal);\n            if (!credential)\n              return;\n            await this.runProviderRefreshPhase(provider, credential, true, options.force, generation, signal);\n          })();\n          try {\n            await raceWithAbortSignal(operation, signal);\n          } catch (error) {\n            if (!signal.aborted) {\n              errors.set(provider.id, error instanceof Error ? error : new ModelsError(\"model_source\", `Model refresh failed for ${provider.id}`, { cause: error }));\n            }\n          } finally {\n            if (this.refreshControllers.get(provider.id) === controller) {\n              this.refreshControllers.delete(provider.id);\n            }\n          }\n        }));\n        try {\n          await raceWithAbortSignal(refresh, callerSignal);\n        } catch (error) {\n          if (!callerSignal.aborted)\n            throw error;\n        }\n        return { aborted: callerSignal.aborted, errors: new Map(errors) };\n      }\n      async resolveRefreshCredential(provider, stored, signal) {\n        if (stored?.type === \"oauth\") {\n          const oauth = provider.auth.oauth;\n          if (!oauth)\n            return void 0;\n          if (Date.now() < stored.expires)\n            return stored;\n          if (signal.aborted)\n            return void 0;\n          const post = await this.credentials.modify(provider.id, async (current) => {\n            if (current?.type !== \"oauth\" || Date.now() < current.expires)\n              return void 0;\n            return oauth.refresh(current, signal);\n          }, { signal });\n          return post?.type === \"oauth\" ? post : void 0;\n        }\n        const apiKey = provider.auth.apiKey;\n        if (!apiKey)\n          return void 0;\n        const credential = stored?.type === \"api_key\" ? stored : void 0;\n        const result = await apiKey.resolve({ ctx: this.authContext, credential, signal });\n        if (!result)\n          return void 0;\n        return { type: \"api_key\", key: result.auth.apiKey, env: result.env };\n      }\n      async readCredential(providerId, signal) {\n        try {\n          return await this.credentials.read(providerId, { signal });\n        } catch (error) {\n          throw new ModelsError(\"auth\", `Credential store read failed for ${providerId}`, { cause: error });\n        }\n      }\n      async checkProviderAuth(provider, credential, signal) {\n        if (credential?.type === \"oauth\") {\n          return provider.auth.oauth ? { source: \"OAuth\", type: \"oauth\" } : void 0;\n        }\n        const apiKey = provider.auth.apiKey;\n        if (!apiKey)\n          return void 0;\n        if (apiKey.check) {\n          try {\n            return await apiKey.check({\n              ctx: this.authContext,\n              credential: credential?.type === \"api_key\" ? credential : void 0,\n              signal\n            });\n          } catch (error) {\n            throw new ModelsError(\"auth\", `API key auth check failed for provider ${provider.id}`, { cause: error });\n          }\n        }\n        const resolution = await resolveProviderAuth(provider, this.credentials, this.authContext, { signal });\n        return resolution ? { source: resolution.source, type: \"api_key\" } : void 0;\n      }\n      checkAuth(providerId, options) {\n        const signal = operationSignal(options?.signal);\n        const check = (async () => {\n          signal.throwIfAborted();\n          const provider = this.providers.get(providerId);\n          if (!provider)\n            return void 0;\n          return this.checkProviderAuth(provider, await this.readCredential(providerId, signal), signal);\n        })();\n        return raceWithAbortSignal(check, signal);\n      }\n      getAvailable(providerId, options) {\n        const signal = operationSignal(options?.signal);\n        const available = (async () => {\n          signal.throwIfAborted();\n          const providers = providerId ? [this.providers.get(providerId)].filter((entry) => entry !== void 0) : this.getProviders();\n          const checks = await Promise.all(providers.map(async (provider) => {\n            const credential = await this.readCredential(provider.id, signal);\n            return { provider, credential, auth: await this.checkProviderAuth(provider, credential, signal) };\n          }));\n          return checks.flatMap(({ provider, credential, auth }) => {\n            if (!auth)\n              return [];\n            const models = provider.getModels();\n            return provider.filterModels?.(models, credential) ?? models;\n          });\n        })();\n        return raceWithAbortSignal(available, signal);\n      }\n      async getAuth(providerOrModel, overrides) {\n        const signal = operationSignal(overrides?.signal);\n        const providerId = typeof providerOrModel === \"string\" ? providerOrModel : providerOrModel.provider;\n        const provider = this.providers.get(providerId);\n        if (!provider)\n          return void 0;\n        const result = await resolveProviderAuth(provider, this.credentials, this.authContext, { ...overrides, signal });\n        if (!result || typeof providerOrModel === \"string\" || !providerOrModel.headers)\n          return result;\n        return {\n          ...result,\n          auth: {\n            ...result.auth,\n            headers: mergeHeaders(result.auth.headers, providerOrModel.headers)\n          }\n        };\n      }\n      async login(providerId, type, interaction) {\n        const signal = operationSignal(interaction.signal);\n        signal.throwIfAborted();\n        const provider = this.providers.get(providerId);\n        if (!provider)\n          throw new ModelsError(\"provider\", `Unknown provider: ${providerId}`);\n        const method = type === \"oauth\" ? provider.auth.oauth : provider.auth.apiKey;\n        if (!method?.login) {\n          throw new ModelsError(\"auth\", `${provider.name} does not support ${type} login`);\n        }\n        const loginOperation = method.login({ ...interaction, signal });\n        const credential = await raceWithAbortSignal(loginOperation, signal);\n        let mutationStarted = false;\n        let markMutationStarted;\n        const started = new Promise((resolve15) => {\n          markMutationStarted = resolve15;\n        });\n        const mutation = this.credentials.modify(providerId, async () => {\n          mutationStarted = true;\n          markMutationStarted?.();\n          return credential;\n        }, { signal });\n        void mutation.catch(() => {\n        });\n        try {\n          await new Promise((resolve15, reject) => {\n            const onAbort = () => {\n              if (!mutationStarted)\n                reject(signal.reason);\n            };\n            signal.addEventListener(\"abort\", onAbort, { once: true });\n            void Promise.race([started, mutation]).then(() => {\n              signal.removeEventListener(\"abort\", onAbort);\n              resolve15();\n            }, (error) => {\n              signal.removeEventListener(\"abort\", onAbort);\n              reject(error);\n            });\n            if (signal.aborted)\n              onAbort();\n          });\n          await mutation;\n        } catch (error) {\n          signal.throwIfAborted();\n          throw new ModelsError(\"auth\", `Credential store modify failed for ${providerId}`, { cause: error });\n        }\n        return credential;\n      }\n      async logout(providerId, options) {\n        const signal = operationSignal(options?.signal);\n        signal.throwIfAborted();\n        try {\n          await this.credentials.delete(providerId, { signal });\n        } catch (error) {\n          signal.throwIfAborted();\n          throw new ModelsError(\"auth\", `Credential store delete failed for ${providerId}`, { cause: error });\n        }\n      }\n      requireProvider(model) {\n        const provider = this.providers.get(model.provider);\n        if (!provider) {\n          throw new ModelsError(\"provider\", `Unknown provider: ${model.provider}`);\n        }\n        return provider;\n      }\n      async applyAuth(model, options) {\n        this.requireProvider(model);\n        const resolution = await this.getAuth(model, {\n          apiKey: options?.apiKey,\n          env: options?.env,\n          signal: options?.signal\n        });\n        if (!resolution) {\n          throw new ModelsError(\"auth\", `Provider is not configured: ${model.provider}`);\n        }\n        const auth = resolution.auth;\n        const apiKey = options?.apiKey ?? auth.apiKey;\n        let headers = mergeHeaders(auth.headers, options?.headers);\n        if (options?.transformHeaders)\n          headers = await options.transformHeaders(headers ?? {});\n        const env = resolution.env || options?.env ? { ...resolution.env ?? {}, ...options?.env ?? {} } : void 0;\n        const requestModel = auth.baseUrl ? { ...model, baseUrl: auth.baseUrl } : model;\n        const { transformHeaders: _transformHeaders, ...providerOptions } = options ?? {};\n        const requestOptions = { ...providerOptions, apiKey, headers, env };\n        return { requestModel, requestOptions };\n      }\n      stream(model, context, options) {\n        return lazyStream(model, async () => {\n          const provider = this.requireProvider(model);\n          const { requestModel, requestOptions } = await this.applyAuth(model, options);\n          return provider.stream(requestModel, context, requestOptions);\n        });\n      }\n      async complete(model, context, options) {\n        return this.stream(model, context, options).result();\n      }\n      streamSimple(model, context, options) {\n        return lazyStream(model, async () => {\n          const provider = this.requireProvider(model);\n          const { requestModel, requestOptions } = await this.applyAuth(model, options);\n          return provider.streamSimple(requestModel, context, requestOptions);\n        });\n      }\n      async completeSimple(model, context, options) {\n        return this.streamSimple(model, context, options).result();\n      }\n      async fetchDeferred(model, handle, options) {\n        return lazyStream(model, async () => {\n          const provider = this.requireProvider(model);\n          if (!provider.fetchDeferred) {\n            throw new ModelsError(\"provider\", `Provider ${model.provider} does not support deferred responses`);\n          }\n          const { requestModel, requestOptions } = await this.applyAuth(model, options);\n          return provider.fetchDeferred(requestModel, handle, requestOptions);\n        }).result();\n      }\n      async cancelDeferred(model, handle, options) {\n        const provider = this.requireProvider(model);\n        if (!provider.cancelDeferred) {\n          throw new ModelsError(\"provider\", `Provider ${model.provider} does not support deferred responses`);\n        }\n        const { requestModel, requestOptions } = await this.applyAuth(model, options);\n        await provider.cancelDeferred(requestModel, handle, requestOptions);\n      }\n    };\n    EXTENDED_THINKING_LEVELS = [\"off\", \"minimal\", \"low\", \"medium\", \"high\", \"xhigh\", \"max\"];\n  }\n});\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/session-resources.js\nfunction registerSessionResourceCleanup(cleanup) {\n  sessionResourceCleanups.add(cleanup);\n  return () => {\n    sessionResourceCleanups.delete(cleanup);\n  };\n}\nfunction cleanupSessionResources(sessionId) {\n  const errors = [];\n  for (const cleanup of sessionResourceCleanups) {\n    try {\n      cleanup(sessionId);\n    } catch (error) {\n      errors.push(error);\n    }\n  }\n  if (errors.length > 0) {\n    throw new AggregateError(errors, \"Failed to cleanup session resources\");\n  }\n}\nvar sessionResourceCleanups;\nvar init_session_resources = __esm({\n  \"node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/session-resources.js\"() {\n    sessionResourceCleanups = /* @__PURE__ */ new Set();\n  }\n});\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/utils/json-parse.js\nimport { parse as partialParse } from \"partial-json\";\nfunction isControlCharacter(char) {\n  const codePoint = char.codePointAt(0);\n  return codePoint !== void 0 && codePoint >= 0 && codePoint <= 31;\n}\nfunction escapeControlCharacter(char) {\n  switch (char) {\n    case \"\\b\":\n      return \"\\\\b\";\n    case \"\\f\":\n      return \"\\\\f\";\n    case \"\\n\":\n      return \"\\\\n\";\n    case \"\\r\":\n      return \"\\\\r\";\n    case \"\t\":\n      return \"\\\\t\";\n    default:\n      return `\\\\u${char.codePointAt(0)?.toString(16).padStart(4, \"0\") ?? \"0000\"}`;\n  }\n}\nfunction repairJson(json) {\n  let repaired = \"\";\n  let inString = false;\n  for (let index = 0; index < json.length; index++) {\n    const char = json[index];\n    if (!inString) {\n      repaired += char;\n      if (char === '\"') {\n        inString = true;\n      }\n      continue;\n    }\n    if (char === '\"') {\n      repaired += char;\n      inString = false;\n      continue;\n    }\n    if (char === \"\\\\\") {\n      const nextChar = json[index + 1];\n      if (nextChar === void 0) {\n        repaired += \"\\\\\\\\\";\n        continue;\n      }\n      if (nextChar === \"u\") {\n        const unicodeDigits = json.slice(index + 2, index + 6);\n        if (/^[0-9a-fA-F]{4}$/.test(unicodeDigits)) {\n          repaired += `\\\\u${unicodeDigits}`;\n          index += 5;\n          continue;\n        }\n      }\n      if (VALID_JSON_ESCAPES.has(nextChar)) {\n        repaired += `\\\\${nextChar}`;\n        index += 1;\n        continue;\n      }\n      repaired += \"\\\\\\\\\";\n      continue;\n    }\n    repaired += isControlCharacter(char) ? escapeControlCharacter(char) : char;\n  }\n  return repaired;\n}\nfunction parseJsonWithRepair(json) {\n  try {\n    return JSON.parse(json);\n  } catch (error) {\n    const repairedJson = repairJson(json);\n    if (repairedJson !== json) {\n      return JSON.parse(repairedJson);\n    }\n    throw error;\n  }\n}\nfunction parseStreamingJson(partialJson) {\n  if (!partialJson || partialJson.trim() === \"\") {\n    return {};\n  }\n  try {\n    return parseJsonWithRepair(partialJson);\n  } catch {\n    try {\n      const result = partialParse(partialJson);\n      return result ?? {};\n    } catch {\n      try {\n        const result = partialParse(repairJson(partialJson));\n        return result ?? {};\n      } catch {\n        return {};\n      }\n    }\n  }\n}\nvar VALID_JSON_ESCAPES;\nvar init_json_parse = __esm({\n  \"node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/utils/json-parse.js\"() {\n    VALID_JSON_ESCAPES = /* @__PURE__ */ new Set(['\"', \"\\\\\", \"/\", \"b\", \"f\", \"n\", \"r\", \"t\", \"u\"]);\n  }\n});\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/utils/uuid.js\nfunction fillRandomBytes(bytes) {\n  if (globalThis.crypto?.getRandomValues) {\n    globalThis.crypto.getRandomValues(bytes);\n    return;\n  }\n  for (let i = 0; i < bytes.length; i++) {\n    bytes[i] = Math.floor(Math.random() * 256);\n  }\n}\nfunction uuidv7() {\n  const random = new Uint8Array(16);\n  fillRandomBytes(random);\n  const timestamp = Date.now();\n  if (timestamp > lastTimestamp) {\n    sequence = random[6] * 16777216 + random[7] * 65536 + random[8] * 256 + random[9];\n    lastTimestamp = timestamp;\n  } else {\n    sequence = sequence + 1 >>> 0;\n    if (sequence === 0)\n      lastTimestamp++;\n  }\n  const bytes = new Uint8Array(16);\n  bytes[0] = lastTimestamp / 1099511627776 & 255;\n  bytes[1] = lastTimestamp / 4294967296 & 255;\n  bytes[2] = lastTimestamp / 16777216 & 255;\n  bytes[3] = lastTimestamp / 65536 & 255;\n  bytes[4] = lastTimestamp / 256 & 255;\n  bytes[5] = lastTimestamp & 255;\n  bytes[6] = 112 | sequence >>> 28 & 15;\n  bytes[7] = sequence >>> 20 & 255;\n  bytes[8] = 128 | sequence >>> 14 & 63;\n  bytes[9] = sequence >>> 6 & 255;\n  bytes[10] = (sequence & 63) << 2 | random[10] & 3;\n  bytes[11] = random[11];\n  bytes[12] = random[12];\n  bytes[13] = random[13];\n  bytes[14] = random[14];\n  bytes[15] = random[15];\n  const hex = Array.from(bytes, (byte) => byte.toString(16).padStart(2, \"0\"));\n  return `${hex.slice(0, 4).join(\"\")}-${hex.slice(4, 6).join(\"\")}-${hex.slice(6, 8).join(\"\")}-${hex.slice(8, 10).join(\"\")}-${hex.slice(10, 16).join(\"\")}`;\n}\nvar lastTimestamp, sequence;\nvar init_uuid = __esm({\n  \"node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/utils/uuid.js\"() {\n    lastTimestamp = -Infinity;\n    sequence = 0;\n  }\n});\n\n// demo/browser/stubs/openai.js\nvar offline, OpenAI, AzureOpenAI;\nvar init_openai = __esm({\n  \"demo/browser/stubs/openai.js\"() {\n    \"use strict\";\n    offline = () => {\n      throw new Error(\"Real model providers are not available in this demo.\");\n    };\n    OpenAI = class {\n      constructor() {\n        offline();\n      }\n    };\n    AzureOpenAI = class {\n      constructor() {\n        offline();\n      }\n    };\n  }\n});\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/utils/error-body.js\nfunction normalizeProviderError(error) {\n  if (!(error instanceof Error)) {\n    return { message: safeJsonStringify(error), messageCarriesBody: false };\n  }\n  const sdkError = error;\n  const status = extractStatus(sdkError);\n  const body = extractBody(sdkError);\n  const messageCarriesBody = body === void 0 || error.message.includes(body);\n  return {\n    status,\n    body,\n    message: error.message,\n    messageCarriesBody\n  };\n}\nfunction extractStatus(error) {\n  if (typeof error.statusCode === \"number\")\n    return error.statusCode;\n  if (typeof error.status === \"number\")\n    return error.status;\n  if (typeof error.$metadata?.httpStatusCode === \"number\")\n    return error.$metadata.httpStatusCode;\n  if (typeof error.$response?.statusCode === \"number\")\n    return error.$response.statusCode;\n  return void 0;\n}\nfunction extractBody(error) {\n  const bodyText = pickBodyText(error);\n  if (bodyText === void 0)\n    return void 0;\n  const trimmed = bodyText.trim();\n  if (trimmed.length === 0)\n    return void 0;\n  return truncateErrorText(trimmed, MAX_PROVIDER_ERROR_BODY_CHARS);\n}\nfunction pickBodyText(error) {\n  if (typeof error.body === \"string\")\n    return error.body;\n  if (isPlainNonEmptyObject(error.error))\n    return safeJsonStringify(error.error);\n  const responseBody = error.$response?.body;\n  if (typeof responseBody === \"string\")\n    return responseBody;\n  if (isReadableStreamLike(responseBody))\n    return void 0;\n  if (isPlainNonEmptyObject(responseBody))\n    return safeJsonStringify(responseBody);\n  return void 0;\n}\nfunction isReadableStreamLike(value) {\n  return typeof value === \"object\" && value !== null && \"pipe\" in value && typeof value.pipe === \"function\";\n}\nfunction isPlainNonEmptyObject(value) {\n  if (typeof value !== \"object\" || value === null)\n    return false;\n  const proto = Object.getPrototypeOf(value);\n  if (proto !== Object.prototype && proto !== null)\n    return false;\n  return Object.keys(value).length > 0;\n}\nfunction formatProviderError(norm, prefix) {\n  if (norm.messageCarriesBody || norm.status === void 0 || norm.body === void 0) {\n    return prefix !== void 0 && norm.status !== void 0 ? `${prefix} (${norm.status}): ${norm.message}` : norm.message;\n  }\n  return prefix !== void 0 ? `${prefix} (${norm.status}): ${norm.body}` : `${norm.status}: ${norm.body}`;\n}\nfunction truncateErrorText(text, maxChars) {\n  if (text.length <= maxChars)\n    return text;\n  return `${text.slice(0, maxChars)}... [truncated ${text.length - maxChars} chars]`;\n}\nfunction safeJsonStringify(value) {\n  try {\n    const serialized = JSON.stringify(value);\n    return serialized === void 0 ? String(value) : serialized;\n  } catch {\n    return String(value);\n  }\n}\nvar MAX_PROVIDER_ERROR_BODY_CHARS;\nvar init_error_body = __esm({\n  \"node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/utils/error-body.js\"() {\n    MAX_PROVIDER_ERROR_BODY_CHARS = 4e3;\n  }\n});\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/utils/hash.js\nfunction shortHash(str2) {\n  let h1 = 3735928559;\n  let h2 = 1103547991;\n  for (let i = 0; i < str2.length; i++) {\n    const ch = str2.charCodeAt(i);\n    h1 = Math.imul(h1 ^ ch, 2654435761);\n    h2 = Math.imul(h2 ^ ch, 1597334677);\n  }\n  h1 = Math.imul(h1 ^ h1 >>> 16, 2246822507) ^ Math.imul(h2 ^ h2 >>> 13, 3266489909);\n  h2 = Math.imul(h2 ^ h2 >>> 16, 2246822507) ^ Math.imul(h1 ^ h1 >>> 13, 3266489909);\n  return (h2 >>> 0).toString(36) + (h1 >>> 0).toString(36);\n}\nvar init_hash = __esm({\n  \"node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/utils/hash.js\"() {\n  }\n});\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/utils/headers.js\nfunction headersToRecord(headers) {\n  const result = {};\n  for (const [key, value] of headers.entries()) {\n    result[key] = value;\n  }\n  return result;\n}\nfunction providerHeadersToRecord(headers) {\n  if (!headers)\n    return void 0;\n  const result = {};\n  for (const [key, value] of Object.entries(headers)) {\n    if (value !== null)\n      result[key] = value;\n  }\n  return Object.keys(result).length > 0 ? result : void 0;\n}\nvar init_headers = __esm({\n  \"node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/utils/headers.js\"() {\n  }\n});\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/utils/provider-env.js\nfunction getBunSandboxEnvValue(name) {\n  if (typeof process === \"undefined\" || !process.versions?.bun || Object.keys(process.env).length > 0) {\n    return void 0;\n  }\n  if (procEnvCache === null) {\n    procEnvCache = /* @__PURE__ */ new Map();\n    try {\n      const { readFileSync: readFileSync20 } = __require(\"node:fs\");\n      const data = readFileSync20(\"/proc/self/environ\", \"utf-8\");\n      for (const entry of data.split(\"\\0\")) {\n        const idx = entry.indexOf(\"=\");\n        if (idx > 0) {\n          procEnvCache.set(entry.slice(0, idx), entry.slice(idx + 1));\n        }\n      }\n    } catch {\n    }\n  }\n  return procEnvCache.get(name);\n}\nfunction getProviderEnvValue(name, env) {\n  return env?.[name] || (typeof process !== \"undefined\" ? process.env[name] : void 0) || getBunSandboxEnvValue(name) || void 0;\n}\nvar procEnvCache;\nvar init_provider_env = __esm({\n  \"node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/utils/provider-env.js\"() {\n    procEnvCache = null;\n  }\n});\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/utils/provider-retry.js\nfunction isProviderError(error) {\n  if (!(error instanceof Error) || !(\"status\" in error) || !(\"headers\" in error))\n    return false;\n  return (error.status === void 0 || typeof error.status === \"number\") && (error.headers === void 0 || error.headers instanceof Headers);\n}\nfunction isRetryableProviderError(error) {\n  const shouldRetry = error.headers?.get(\"x-should-retry\");\n  if (shouldRetry === \"true\")\n    return true;\n  if (shouldRetry === \"false\")\n    return false;\n  if (error.status === void 0)\n    return true;\n  return error.status === 408 || error.status === 409 || error.status === 429 || typeof error.status === \"number\" && error.status >= 500;\n}\nfunction validateServerRetryDelayMs(delayMs, maxRetryDelayMs, providerErrorMessage) {\n  const maxDelayMs = maxRetryDelayMs ?? DEFAULT_MAX_RETRY_DELAY_MS;\n  if (maxDelayMs > 0 && delayMs > maxDelayMs) {\n    throw new Error(`Server requested ${Math.ceil(delayMs / 1e3)}s retry delay (max: ${Math.ceil(maxDelayMs / 1e3)}s). ${providerErrorMessage}`);\n  }\n  return delayMs;\n}\nfunction getRetryDelayMs(error, retryIndex, maxRetryDelayMs) {\n  const retryAfterMs = error.headers?.get(\"retry-after-ms\");\n  if (retryAfterMs) {\n    const value = Number.parseFloat(retryAfterMs);\n    if (!Number.isNaN(value))\n      return validateServerRetryDelayMs(value, maxRetryDelayMs, error.message);\n  }\n  const retryAfter = error.headers?.get(\"retry-after\");\n  if (retryAfter) {\n    const seconds = Number.parseFloat(retryAfter);\n    const delayMs = Number.isNaN(seconds) ? Date.parse(retryAfter) - Date.now() : seconds * 1e3;\n    return validateServerRetryDelayMs(delayMs, maxRetryDelayMs, error.message);\n  }\n  const exponentialDelay = Math.min(0.5 * 2 ** retryIndex, 8) * 1e3;\n  return exponentialDelay * (1 - Math.random() * 0.25);\n}\nfunction createAbortError() {\n  const error = new Error(\"Request aborted\");\n  error.name = \"AbortError\";\n  return error;\n}\nfunction abortableSleep(ms, signal) {\n  return new Promise((resolve15, reject) => {\n    if (signal?.aborted) {\n      reject(createAbortError());\n      return;\n    }\n    const onAbort = () => {\n      clearTimeout(timeout);\n      reject(createAbortError());\n    };\n    const timeout = setTimeout(() => {\n      signal?.removeEventListener(\"abort\", onAbort);\n      resolve15();\n    }, Math.max(0, ms));\n    signal?.addEventListener(\"abort\", onAbort, { once: true });\n  });\n}\nasync function retryProviderRequest(request, options = {}) {\n  const maxRetries = options.maxRetries ?? 0;\n  let retriesRemaining = maxRetries;\n  for (; ; ) {\n    try {\n      return await request();\n    } catch (error) {\n      if (options.signal?.aborted)\n        throw createAbortError();\n      if (retriesRemaining <= 0 || !isProviderError(error) || !isRetryableProviderError(error))\n        throw error;\n      const retryIndex = maxRetries - retriesRemaining;\n      retriesRemaining--;\n      await abortableSleep(getRetryDelayMs(error, retryIndex, options.maxRetryDelayMs), options.signal);\n    }\n  }\n}\nvar DEFAULT_MAX_RETRY_DELAY_MS;\nvar init_provider_retry = __esm({\n  \"node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/utils/provider-retry.js\"() {\n    DEFAULT_MAX_RETRY_DELAY_MS = 6e4;\n  }\n});\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/utils/sanitize-unicode.js\nfunction sanitizeSurrogates(text) {\n  return text.replace(/[\\uD800-\\uDBFF](?![\\uDC00-\\uDFFF])|(?<![\\uD800-\\uDBFF])[\\uDC00-\\uDFFF]/g, \"\");\n}\nvar init_sanitize_unicode = __esm({\n  \"node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/utils/sanitize-unicode.js\"() {\n  }\n});\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/api/constrained-sampling.js\nfunction isJsonSchemaObject(value) {\n  return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\nfunction isStructuredSchema(schema) {\n  if (!isJsonSchemaObject(schema))\n    return false;\n  const types = typeof schema.type === \"string\" ? [schema.type] : Array.isArray(schema.type) ? schema.type : [];\n  return types.includes(\"object\") || types.includes(\"array\") || schema.properties !== void 0 || schema.items !== void 0;\n}\nfunction schemaAllowsNull(schema) {\n  if (!isJsonSchemaObject(schema))\n    return false;\n  if (schema.type === \"null\" || Array.isArray(schema.type) && schema.type.includes(\"null\"))\n    return true;\n  if (schema.const === null || Array.isArray(schema.enum) && schema.enum.includes(null))\n    return true;\n  return Array.isArray(schema.anyOf) && schema.anyOf.some((variant) => schemaAllowsNull(variant));\n}\nfunction makeJsonSchemaNodeStrict(schema) {\n  if (!isJsonSchemaObject(schema)) {\n    throw new UnsupportedStrictJsonSchemaError(\"boolean schemas are unsupported\");\n  }\n  for (const key of UNSUPPORTED_STRICT_SCHEMA_KEYS) {\n    if (schema[key] !== void 0) {\n      throw new UnsupportedStrictJsonSchemaError(`${key} schemas are unsupported`);\n    }\n  }\n  if (schema.anyOf !== void 0) {\n    if (!Array.isArray(schema.anyOf) || schema.anyOf.length === 0) {\n      throw new UnsupportedStrictJsonSchemaError(\"anyOf must contain at least one schema\");\n    }\n    for (const variant of schema.anyOf) {\n      if (isStructuredSchema(variant)) {\n        throw new UnsupportedStrictJsonSchemaError(\"object and array unions are unsupported\");\n      }\n      makeJsonSchemaNodeStrict(variant);\n    }\n  }\n  if (schema.items !== void 0) {\n    if (Array.isArray(schema.items)) {\n      throw new UnsupportedStrictJsonSchemaError(\"tuple schemas are unsupported\");\n    }\n    makeJsonSchemaNodeStrict(schema.items);\n  }\n  const isObjectSchema = schema.type === \"object\";\n  if (schema.properties !== void 0 && !isObjectSchema) {\n    throw new UnsupportedStrictJsonSchemaError(\"properties require type object\");\n  }\n  if (!isObjectSchema)\n    return;\n  if (schema.additionalProperties !== void 0 && schema.additionalProperties !== false) {\n    throw new UnsupportedStrictJsonSchemaError(\"schema-valued or true additionalProperties is unsupported\");\n  }\n  if (schema.properties !== void 0 && !isJsonSchemaObject(schema.properties)) {\n    throw new UnsupportedStrictJsonSchemaError(\"object properties must be a schema map\");\n  }\n  if (schema.required !== void 0 && (!Array.isArray(schema.required) || schema.required.some((key) => typeof key !== \"string\"))) {\n    throw new UnsupportedStrictJsonSchemaError(\"object required must be a string array\");\n  }\n  const properties = schema.properties ?? {};\n  const propertyNames = Object.keys(properties);\n  const required = new Set(Array.isArray(schema.required) ? schema.required : []);\n  if ([...required].some((key) => !propertyNames.includes(key))) {\n    throw new UnsupportedStrictJsonSchemaError(\"required contains an unknown property\");\n  }\n  for (const [key, property] of Object.entries(properties)) {\n    makeJsonSchemaNodeStrict(property);\n    if (!required.has(key) && !schemaAllowsNull(property)) {\n      properties[key] = { anyOf: [property, { type: \"null\" }] };\n    }\n  }\n  schema.required = propertyNames;\n  schema.additionalProperties = false;\n}\nfunction makeStrictJsonSchema(schema) {\n  const cloned = structuredClone(schema);\n  if (!isJsonSchemaObject(cloned)) {\n    throw new UnsupportedStrictJsonSchemaError(\"root schema must have type object\");\n  }\n  makeJsonSchemaNodeStrict(cloned);\n  if (cloned.type !== \"object\") {\n    throw new UnsupportedStrictJsonSchemaError(\"root schema must have type object\");\n  }\n  return cloned;\n}\nfunction getJsonSchemaToolParameters(tool, strict) {\n  return strict === true ? makeStrictJsonSchema(tool.parameters) : tool.parameters;\n}\nfunction getGrammarToolInput(toolName, arguments_, inputProperty) {\n  const input = arguments_[inputProperty];\n  if (typeof input !== \"string\") {\n    throw new Error(`Grammar tool call \"${toolName}\" requires argument \"${inputProperty}\" to be a string.`);\n  }\n  return input;\n}\nfunction appendGrammarToolInputJsonDelta(buffer, inputProperty, nextInput, close) {\n  if (buffer.closed) {\n    if (close && nextInput === buffer.input)\n      return void 0;\n    throw new Error(`grammar tool input for property \"${inputProperty}\" changed after it was closed`);\n  }\n  if (!nextInput.startsWith(buffer.input)) {\n    throw new Error(`grammar tool input for property \"${inputProperty}\" changed non-monotonically`);\n  }\n  const inputDelta = nextInput.slice(buffer.input.length);\n  if (!close && inputDelta.length === 0)\n    return void 0;\n  let delta = \"\";\n  if (!buffer.started) {\n    delta += `{${JSON.stringify(inputProperty)}:\"`;\n    buffer.started = true;\n  }\n  delta += JSON.stringify(inputDelta).slice(1, -1);\n  buffer.input = nextInput;\n  if (close) {\n    delta += '\"}';\n    buffer.closed = true;\n  }\n  return delta;\n}\nfunction inferGrammarInputProperty(tool) {\n  const schema = tool.parameters;\n  if (schema.type !== \"object\") {\n    throw new Error(\"grammar constrained sampling requires an object parameter schema\");\n  }\n  if (!Array.isArray(schema.required) || schema.required.length !== 1 || typeof schema.required[0] !== \"string\") {\n    throw new Error(\"grammar constrained sampling requires exactly one required string property\");\n  }\n  const inputProperty = schema.required[0];\n  if (!schema.properties?.[inputProperty]) {\n    throw new Error(`grammar constrained sampling requires a properties entry for ${inputProperty}`);\n  }\n  if (schema.properties[inputProperty]?.type !== \"string\") {\n    throw new Error(`grammar constrained sampling property ${inputProperty} must have type string`);\n  }\n  return inputProperty;\n}\nfunction resolveJsonSchemaStrictSampling(tool, supportsStrictMode) {\n  const config = tool.constrainedSampling;\n  if (!config || config.type !== \"json_schema\")\n    return void 0;\n  if (supportsStrictMode) {\n    try {\n      makeStrictJsonSchema(tool.parameters);\n      return true;\n    } catch (error) {\n      if (!(error instanceof UnsupportedStrictJsonSchemaError))\n        throw error;\n      if (config.strict !== \"require\")\n        return void 0;\n      throw new Error(`Tool \"${tool.name}\" requires JSON-schema constrained sampling, but ${error.message}.`);\n    }\n  }\n  if (config.strict === \"require\") {\n    throw new Error(`Tool \"${tool.name}\" requires JSON-schema constrained sampling, but strict tools are unsupported.`);\n  }\n  return void 0;\n}\nfunction resolveGrammarConstrainedSampling(tool, supportsOpenAIGrammarTools) {\n  const config = tool.constrainedSampling;\n  if (!config || config.type !== \"grammar\") {\n    return void 0;\n  }\n  if (!supportsOpenAIGrammarTools) {\n    return void 0;\n  }\n  const larkDefinition = config.variants.openai_lark;\n  const regexDefinition = config.variants.openai_regex;\n  const hasLarkDefinition = typeof larkDefinition === \"string\" && larkDefinition.trim().length > 0;\n  const hasRegexDefinition = typeof regexDefinition === \"string\" && regexDefinition.trim().length > 0;\n  if (!hasLarkDefinition && !hasRegexDefinition) {\n    throw new Error(`Tool \"${tool.name}\" cannot use grammar constrained sampling: no supported grammar variant was provided.`);\n  }\n  try {\n    return {\n      format: hasLarkDefinition ? \"lark\" : \"regex\",\n      definition: hasLarkDefinition ? larkDefinition : regexDefinition,\n      inputProperty: inferGrammarInputProperty(tool)\n    };\n  } catch (error) {\n    const message = error instanceof Error ? error.message : String(error);\n    throw new Error(`Tool \"${tool.name}\" cannot use grammar constrained sampling: ${message}.`);\n  }\n}\nfunction createGrammarToolInputProperties(tools, supportsOpenAIGrammarTools) {\n  const properties = /* @__PURE__ */ new Map();\n  for (const tool of tools ?? []) {\n    const grammar = resolveGrammarConstrainedSampling(tool, supportsOpenAIGrammarTools);\n    if (grammar) {\n      properties.set(tool.name, grammar.inputProperty);\n    }\n  }\n  return properties;\n}\nvar UnsupportedStrictJsonSchemaError, UNSUPPORTED_STRICT_SCHEMA_KEYS;\nvar init_constrained_sampling = __esm({\n  \"node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/api/constrained-sampling.js\"() {\n    UnsupportedStrictJsonSchemaError = class extends Error {\n    };\n    UNSUPPORTED_STRICT_SCHEMA_KEYS = [\n      \"$ref\",\n      \"$defs\",\n      \"definitions\",\n      \"allOf\",\n      \"oneOf\",\n      \"patternProperties\",\n      \"dependentSchemas\",\n      \"dependencies\",\n      \"unevaluatedProperties\",\n      \"propertyNames\",\n      \"contains\",\n      \"prefixItems\",\n      \"not\",\n      \"if\",\n      \"then\",\n      \"else\"\n    ];\n  }\n});\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/api/github-copilot-headers.js\nfunction inferCopilotInitiator(messages) {\n  const last = messages[messages.length - 1];\n  return last && last.role !== \"user\" ? \"agent\" : \"user\";\n}\nfunction hasCopilotVisionInput(messages) {\n  return messages.some((msg) => {\n    if (msg.role === \"user\" && Array.isArray(msg.content)) {\n      return msg.content.some((c) => c.type === \"image\");\n    }\n    if (msg.role === \"toolResult\" && Array.isArray(msg.content)) {\n      return msg.content.some((c) => c.type === \"image\");\n    }\n    return false;\n  });\n}\nfunction buildCopilotDynamicHeaders(params) {\n  const headers = {\n    \"X-Initiator\": inferCopilotInitiator(params.messages),\n    \"Openai-Intent\": \"conversation-edits\"\n  };\n  if (params.hasImages) {\n    headers[\"Copilot-Vision-Request\"] = \"true\";\n  }\n  return headers;\n}\nvar init_github_copilot_headers = __esm({\n  \"node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/api/github-copilot-headers.js\"() {\n  }\n});\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/api/openai-prompt-cache.js\nfunction clampOpenAIPromptCacheKey(key) {\n  if (key === void 0)\n    return void 0;\n  const chars = Array.from(key);\n  if (chars.length <= OPENAI_PROMPT_CACHE_KEY_MAX_LENGTH)\n    return key;\n  return chars.slice(0, OPENAI_PROMPT_CACHE_KEY_MAX_LENGTH).join(\"\");\n}\nvar OPENAI_PROMPT_CACHE_KEY_MAX_LENGTH;\nvar init_openai_prompt_cache = __esm({\n  \"node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/api/openai-prompt-cache.js\"() {\n    OPENAI_PROMPT_CACHE_KEY_MAX_LENGTH = 64;\n  }\n});\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/utils/estimate.js\nfunction calculateContextTokens(usage) {\n  return usage.totalTokens || usage.input + usage.output + usage.cacheRead + usage.cacheWrite;\n}\nfunction safeJsonStringify2(value) {\n  try {\n    return JSON.stringify(value) ?? \"undefined\";\n  } catch {\n    return \"[unserializable]\";\n  }\n}\nfunction estimateTextAndImageContentChars(content) {\n  if (typeof content === \"string\")\n    return content.length;\n  let chars = 0;\n  for (const block of content)\n    chars += block.type === \"text\" ? block.text.length : ESTIMATED_IMAGE_CHARS;\n  return chars;\n}\nfunction estimateTextTokens(text) {\n  return Math.ceil(text.length / CHARS_PER_TOKEN);\n}\nfunction estimateTextAndImageContentTokens(content) {\n  return Math.ceil(estimateTextAndImageContentChars(content) / CHARS_PER_TOKEN);\n}\nfunction estimateMessageTokens(message) {\n  let chars = 0;\n  if (message.role === \"user\")\n    return estimateTextAndImageContentTokens(message.content);\n  if (message.role === \"toolResult\")\n    return estimateTextAndImageContentTokens(message.content);\n  for (const block of message.content) {\n    if (block.type === \"text\") {\n      chars += block.text.length;\n    } else if (block.type === \"thinking\") {\n      chars += block.thinking.length;\n    } else {\n      chars += block.name.length + safeJsonStringify2(block.arguments).length;\n    }\n  }\n  return Math.ceil(chars / CHARS_PER_TOKEN);\n}\nfunction getLastAssistantUsageInfo(messages) {\n  let latestPrefixTimestamp = Number.NEGATIVE_INFINITY;\n  let usageInfo;\n  for (let i = 0; i < messages.length; i++) {\n    const message = messages[i];\n    if (message.role === \"assistant\") {\n      const assistant = message;\n      const usageAppliesToPrefix = assistant.timestamp >= latestPrefixTimestamp;\n      if (usageAppliesToPrefix && assistant.stopReason !== \"aborted\" && assistant.stopReason !== \"error\" && calculateContextTokens(assistant.usage) > 0) {\n        usageInfo = { usage: assistant.usage, index: i };\n      }\n    }\n    latestPrefixTimestamp = Math.max(latestPrefixTimestamp, message.timestamp);\n  }\n  return usageInfo;\n}\nfunction estimateMessages(messages) {\n  const usageInfo = getLastAssistantUsageInfo(messages);\n  if (usageInfo) {\n    const usageTokens = calculateContextTokens(usageInfo.usage);\n    let trailingTokens = 0;\n    for (let i = usageInfo.index + 1; i < messages.length; i++) {\n      trailingTokens += estimateMessageTokens(messages[i]);\n    }\n    return { tokens: usageTokens + trailingTokens, usageTokens, trailingTokens, lastUsageIndex: usageInfo.index };\n  }\n  let tokens = 0;\n  for (const message of messages)\n    tokens += estimateMessageTokens(message);\n  return { tokens, usageTokens: 0, trailingTokens: tokens, lastUsageIndex: null };\n}\nfunction estimateToolsTokens(tools) {\n  if (!tools || tools.length === 0)\n    return 0;\n  return estimateTextTokens(safeJsonStringify2(tools));\n}\nfunction isMessageArray(value) {\n  return Array.isArray(value);\n}\nfunction estimateContextTokens(context) {\n  if (isMessageArray(context))\n    return estimateMessages(context);\n  const estimate = estimateMessages(context.messages);\n  if (estimate.lastUsageIndex !== null) {\n    const addedNames = new Set(context.messages.slice(estimate.lastUsageIndex + 1).filter((message) => message.role === \"toolResult\").flatMap((message) => message.addedToolNames ?? []));\n    const addedToolTokens = estimateToolsTokens(context.tools?.filter((tool) => addedNames.has(tool.name)));\n    return {\n      tokens: estimate.tokens + addedToolTokens,\n      usageTokens: estimate.usageTokens,\n      trailingTokens: estimate.trailingTokens + addedToolTokens,\n      lastUsageIndex: estimate.lastUsageIndex\n    };\n  }\n  const prefixTokens = (context.systemPrompt ? estimateTextTokens(context.systemPrompt) : 0) + estimateToolsTokens(context.tools);\n  return {\n    tokens: estimate.tokens + prefixTokens,\n    usageTokens: estimate.usageTokens,\n    trailingTokens: estimate.trailingTokens + prefixTokens,\n    lastUsageIndex: estimate.lastUsageIndex\n  };\n}\nvar CHARS_PER_TOKEN, ESTIMATED_IMAGE_CHARS;\nvar init_estimate = __esm({\n  \"node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/utils/estimate.js\"() {\n    CHARS_PER_TOKEN = 4;\n    ESTIMATED_IMAGE_CHARS = 4800;\n  }\n});\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/api/simple-options.js\nfunction clampMaxTokensToContext(model, context, maxTokens) {\n  if (model.contextWindow <= 0)\n    return Math.max(MIN_MAX_TOKENS, maxTokens);\n  const available = model.contextWindow - estimateContextTokens(context).tokens - CONTEXT_SAFETY_TOKENS;\n  return Math.min(maxTokens, Math.max(MIN_MAX_TOKENS, available));\n}\nfunction buildBaseOptions(model, context, options, apiKey) {\n  const samplingParams = model.samplingParams || options?.samplingParams ? { ...model.samplingParams, ...options?.samplingParams } : void 0;\n  return {\n    temperature: options?.temperature,\n    samplingParams,\n    maxTokens: clampMaxTokensToContext(model, context, options?.maxTokens ?? model.maxTokens),\n    signal: options?.signal,\n    telemetryContext: options?.telemetryContext,\n    apiKey: apiKey || options?.apiKey,\n    fetch: options?.fetch,\n    transport: options?.transport,\n    cacheRetention: options?.cacheRetention,\n    sessionId: options?.sessionId,\n    headers: options?.headers,\n    onPayload: options?.onPayload,\n    onResponse: options?.onResponse,\n    timeoutMs: options?.timeoutMs,\n    websocketConnectTimeoutMs: options?.websocketConnectTimeoutMs,\n    maxRetries: options?.maxRetries,\n    maxRetryDelayMs: options?.maxRetryDelayMs,\n    metadata: options?.metadata,\n    env: options?.env\n  };\n}\nfunction clampReasoning(effort) {\n  return effort === \"xhigh\" || effort === \"max\" ? \"high\" : effort;\n}\nfunction adjustMaxTokensForThinking(baseMaxTokens, modelMaxTokens, reasoningLevel, customBudgets) {\n  const defaultBudgets = {\n    minimal: 1024,\n    low: 2048,\n    medium: 8192,\n    high: 16384\n  };\n  const budgets = { ...defaultBudgets, ...customBudgets };\n  const level = clampReasoning(reasoningLevel);\n  let thinkingBudget = budgets[level];\n  const maxTokens = baseMaxTokens === void 0 ? modelMaxTokens : Math.min(baseMaxTokens + thinkingBudget, modelMaxTokens);\n  if (maxTokens <= thinkingBudget) {\n    thinkingBudget = Math.max(0, maxTokens - MIN_ANSWER_TOKENS);\n  }\n  return { maxTokens, thinkingBudget };\n}\nvar CONTEXT_SAFETY_TOKENS, MIN_MAX_TOKENS, MIN_ANSWER_TOKENS;\nvar init_simple_options = __esm({\n  \"node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/api/simple-options.js\"() {\n    init_estimate();\n    CONTEXT_SAFETY_TOKENS = 4096;\n    MIN_MAX_TOKENS = 1;\n    MIN_ANSWER_TOKENS = 1024;\n  }\n});\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/api/transform-messages.js\nfunction replaceImagesWithPlaceholder(content, placeholder) {\n  const result = [];\n  let previousWasPlaceholder = false;\n  for (const block of content) {\n    if (block.type === \"image\") {\n      if (!previousWasPlaceholder) {\n        result.push({ type: \"text\", text: placeholder });\n      }\n      previousWasPlaceholder = true;\n      continue;\n    }\n    result.push(block);\n    previousWasPlaceholder = block.text === placeholder;\n  }\n  return result;\n}\nfunction downgradeUnsupportedImages(messages, model) {\n  if (model.input.includes(\"image\")) {\n    return messages;\n  }\n  return messages.map((msg) => {\n    if (msg.role === \"user\" && Array.isArray(msg.content)) {\n      return {\n        ...msg,\n        content: replaceImagesWithPlaceholder(msg.content, NON_VISION_USER_IMAGE_PLACEHOLDER)\n      };\n    }\n    if (msg.role === \"toolResult\") {\n      return {\n        ...msg,\n        content: replaceImagesWithPlaceholder(msg.content, NON_VISION_TOOL_IMAGE_PLACEHOLDER)\n      };\n    }\n    return msg;\n  });\n}\nfunction transformMessages(messages, model, normalizeToolCallId2) {\n  const toolCallIdMap = /* @__PURE__ */ new Map();\n  const normalizedMessages = messages.map((msg) => msg.content == null ? { ...msg, content: [] } : msg);\n  const imageAwareMessages = downgradeUnsupportedImages(normalizedMessages, model);\n  const transformed = imageAwareMessages.map((msg) => {\n    if (msg.role === \"user\") {\n      return msg;\n    }\n    if (msg.role === \"toolResult\") {\n      const normalizedId = toolCallIdMap.get(msg.toolCallId);\n      if (normalizedId && normalizedId !== msg.toolCallId) {\n        return { ...msg, toolCallId: normalizedId };\n      }\n      return msg;\n    }\n    if (msg.role === \"assistant\") {\n      const assistantMsg = msg;\n      const isSameModel = assistantMsg.provider === model.provider && assistantMsg.api === model.api && assistantMsg.model === model.id;\n      const transformedContent = assistantMsg.content.flatMap((block) => {\n        if (block.type === \"thinking\") {\n          if (block.redacted) {\n            return isSameModel ? block : [];\n          }\n          if (isSameModel && block.thinkingSignature)\n            return block;\n          if (!block.thinking || block.thinking.trim() === \"\")\n            return [];\n          if (isSameModel)\n            return block;\n          return {\n            type: \"text\",\n            text: block.thinking\n          };\n        }\n        if (block.type === \"text\") {\n          if (isSameModel)\n            return block;\n          return {\n            type: \"text\",\n            text: block.text\n          };\n        }\n        if (block.type === \"toolCall\") {\n          const toolCall = block;\n          let normalizedToolCall = toolCall;\n          if (!isSameModel && toolCall.thoughtSignature) {\n            normalizedToolCall = { ...toolCall };\n            delete normalizedToolCall.thoughtSignature;\n          }\n          if (!isSameModel && normalizeToolCallId2) {\n            const normalizedId = normalizeToolCallId2(toolCall.id, model, assistantMsg);\n            if (normalizedId !== toolCall.id) {\n              toolCallIdMap.set(toolCall.id, normalizedId);\n              normalizedToolCall = { ...normalizedToolCall, id: normalizedId };\n            }\n          }\n          return normalizedToolCall;\n        }\n        return block;\n      });\n      return {\n        ...assistantMsg,\n        content: transformedContent\n      };\n    }\n    return msg;\n  });\n  const result = [];\n  let pendingToolCalls = [];\n  let existingToolResultIds = /* @__PURE__ */ new Set();\n  const insertSyntheticToolResults = () => {\n    if (pendingToolCalls.length > 0) {\n      for (const tc of pendingToolCalls) {\n        if (!existingToolResultIds.has(tc.id)) {\n          result.push({\n            role: \"toolResult\",\n            toolCallId: tc.id,\n            toolName: tc.name,\n            content: [{ type: \"text\", text: \"No result provided\" }],\n            isError: true,\n            timestamp: Date.now()\n          });\n        }\n      }\n      pendingToolCalls = [];\n      existingToolResultIds = /* @__PURE__ */ new Set();\n    }\n  };\n  for (let i = 0; i < transformed.length; i++) {\n    const msg = transformed[i];\n    if (msg.role === \"assistant\") {\n      insertSyntheticToolResults();\n      const assistantMsg = msg;\n      if (assistantMsg.stopReason === \"error\" || assistantMsg.stopReason === \"aborted\") {\n        continue;\n      }\n      const toolCalls = assistantMsg.content.filter((b) => b.type === \"toolCall\");\n      if (toolCalls.length > 0) {\n        pendingToolCalls = toolCalls;\n        existingToolResultIds = /* @__PURE__ */ new Set();\n      }\n      result.push(msg);\n    } else if (msg.role === \"toolResult\") {\n      existingToolResultIds.add(msg.toolCallId);\n      result.push(msg);\n    } else if (msg.role === \"user\") {\n      insertSyntheticToolResults();\n      result.push(msg);\n    } else {\n      result.push(msg);\n    }\n  }\n  insertSyntheticToolResults();\n  return result;\n}\nvar NON_VISION_USER_IMAGE_PLACEHOLDER, NON_VISION_TOOL_IMAGE_PLACEHOLDER;\nvar init_transform_messages = __esm({\n  \"node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/api/transform-messages.js\"() {\n    NON_VISION_USER_IMAGE_PLACEHOLDER = \"(image omitted: model does not support images)\";\n    NON_VISION_TOOL_IMAGE_PLACEHOLDER = \"(tool image omitted: model does not support images)\";\n  }\n});\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/api/openai-completions.js\nvar openai_completions_exports = {};\n__export(openai_completions_exports, {\n  convertMessages: () => convertMessages,\n  stream: () => stream,\n  streamSimple: () => streamSimple\n});\nfunction hasHeader(headers, name) {\n  if (!headers)\n    return false;\n  const expected = name.toLowerCase();\n  for (const [key, value] of Object.entries(headers)) {\n    if (key.toLowerCase() === expected && value !== null && value.trim().length > 0)\n      return true;\n  }\n  return false;\n}\nfunction getClientApiKey(provider, apiKey, headers) {\n  if (apiKey)\n    return apiKey;\n  if (hasHeader(headers, \"authorization\") || hasHeader(headers, \"cf-aig-authorization\"))\n    return \"unused\";\n  throw new Error(`No API key for provider: ${provider}`);\n}\nfunction hasToolHistory(messages) {\n  for (const msg of messages) {\n    if (msg.role === \"toolResult\") {\n      return true;\n    }\n    if (msg.role === \"assistant\") {\n      if (msg.content.some((block) => block.type === \"toolCall\")) {\n        return true;\n      }\n    }\n  }\n  return false;\n}\nfunction getDeferredToolNames(messages) {\n  const names = /* @__PURE__ */ new Set();\n  for (const message of messages) {\n    if (message.role === \"toolResult\") {\n      for (const name of message.addedToolNames ?? []) {\n        names.add(name);\n      }\n    }\n  }\n  return names;\n}\nfunction getToolsByName(tools, names) {\n  if (!tools)\n    return [];\n  const toolsByName = new Map(tools.map((tool) => [tool.name, tool]));\n  return Array.from(names).map((name) => toolsByName.get(name)).filter((tool) => tool !== void 0);\n}\nfunction isTextContentBlock(block) {\n  return block.type === \"text\";\n}\nfunction isThinkingContentBlock(block) {\n  return block.type === \"thinking\";\n}\nfunction isToolCallBlock(block) {\n  return block.type === \"toolCall\";\n}\nfunction isImageContentBlock(block) {\n  return block.type === \"image\";\n}\nfunction isEncryptedReasoningDetail(detail) {\n  if (typeof detail !== \"object\" || detail === null) {\n    return false;\n  }\n  const candidate = detail;\n  return candidate.type === \"reasoning.encrypted\" && typeof candidate.id === \"string\" && candidate.id.length > 0 && typeof candidate.data === \"string\" && candidate.data.length > 0;\n}\nfunction resolveCacheRetention(cacheRetention, env) {\n  if (cacheRetention) {\n    return cacheRetention;\n  }\n  if (getProviderEnvValue(\"PI_CACHE_RETENTION\", env) === \"long\") {\n    return \"long\";\n  }\n  return \"short\";\n}\nfunction createClient(model, context, apiKey, optionsHeaders, fetch2, sessionId, compat = getCompat(model)) {\n  const headers = { ...model.headers };\n  if (model.provider === \"github-copilot\") {\n    const hasImages = hasCopilotVisionInput(context.messages);\n    const copilotHeaders = buildCopilotDynamicHeaders({\n      messages: context.messages,\n      hasImages\n    });\n    Object.assign(headers, copilotHeaders);\n  }\n  if (sessionId && compat.sendSessionAffinityHeaders) {\n    if (compat.sessionAffinityFormat === \"openrouter\") {\n      headers[\"x-session-id\"] = sessionId;\n    } else {\n      if (compat.sessionAffinityFormat === \"openai\") {\n        headers.session_id = sessionId;\n      }\n      headers[\"x-client-request-id\"] = sessionId;\n      headers[\"x-session-affinity\"] = sessionId;\n    }\n  }\n  if (optionsHeaders) {\n    Object.assign(headers, optionsHeaders);\n  }\n  return new OpenAI({\n    apiKey,\n    baseURL: model.baseUrl,\n    dangerouslyAllowBrowser: true,\n    fetch: fetch2,\n    defaultHeaders: headers\n  });\n}\nfunction buildParams(model, context, options, compat = getCompat(model), cacheRetention = resolveCacheRetention(options?.cacheRetention, options?.env), grammarToolInputProperties = createGrammarToolInputProperties(context.tools, compat.supportsOpenAIGrammarTools)) {\n  const messages = convertMessages(model, context, compat, { grammarToolInputProperties });\n  const cacheControl = getCompatCacheControl(compat, cacheRetention);\n  const params = {\n    model: model.id,\n    messages,\n    stream: true,\n    prompt_cache_key: model.baseUrl.includes(\"api.openai.com\") && cacheRetention !== \"none\" || cacheRetention === \"long\" && compat.supportsLongCacheRetention ? clampOpenAIPromptCacheKey(options?.sessionId) : void 0,\n    prompt_cache_retention: cacheRetention === \"long\" && compat.supportsLongCacheRetention ? \"24h\" : void 0\n  };\n  if (compat.supportsUsageInStreaming !== false) {\n    params.stream_options = { include_usage: true };\n  }\n  if (compat.supportsStore) {\n    params.store = false;\n  }\n  if (options?.maxTokens) {\n    if (compat.maxTokensField === \"max_tokens\") {\n      params.max_tokens = options.maxTokens;\n    } else {\n      params.max_completion_tokens = options.maxTokens;\n    }\n  }\n  if (options?.temperature !== void 0) {\n    params.temperature = options.temperature;\n  }\n  const deferredToolNames = compat.deferredToolsMode === \"kimi\" ? getDeferredToolNames(context.messages) : /* @__PURE__ */ new Set();\n  const activeTools = context.tools?.filter((tool) => !deferredToolNames.has(tool.name));\n  if (activeTools && activeTools.length > 0) {\n    params.tools = convertTools(activeTools, compat);\n    if (compat.zaiToolStream) {\n      params.tool_stream = true;\n    }\n  } else if (hasToolHistory(context.messages)) {\n    params.tools = [];\n  }\n  if (cacheControl) {\n    applyAnthropicCacheControl(messages, params.tools, cacheControl);\n  }\n  if (options?.toolChoice) {\n    params.tool_choice = options.toolChoice;\n  }\n  if (compat.thinkingFormat === \"zai\" && model.reasoning) {\n    const zaiParams = params;\n    zaiParams.thinking = options?.reasoningEffort ? { type: \"enabled\", clear_thinking: false } : { type: \"disabled\" };\n    if (options?.reasoningEffort && compat.supportsReasoningEffort) {\n      const mappedEffort = model.thinkingLevelMap?.[options.reasoningEffort];\n      const effort = mappedEffort === void 0 ? options.reasoningEffort : mappedEffort;\n      if (typeof effort === \"string\") {\n        zaiParams.reasoning_effort = effort;\n      }\n    }\n  } else if (compat.thinkingFormat === \"qwen\" && model.reasoning) {\n    params.enable_thinking = !!options?.reasoningEffort;\n    if (options?.reasoningEffort && compat.supportsReasoningEffort) {\n      const effort = model.thinkingLevelMap?.[options.reasoningEffort] ?? options.reasoningEffort;\n      if (typeof effort === \"string\") {\n        params.reasoning_effort = effort;\n      }\n    }\n  } else if (compat.thinkingFormat === \"qwen-chat-template\" && model.reasoning) {\n    params.chat_template_kwargs = {\n      enable_thinking: !!options?.reasoningEffort,\n      preserve_thinking: true\n    };\n  } else if (compat.thinkingFormat === \"chat-template\" && model.reasoning) {\n    const chatTemplateKwargs = buildChatTemplateValues(model, options, compat.chatTemplateKwargs);\n    if (chatTemplateKwargs) {\n      params.chat_template_kwargs = chatTemplateKwargs;\n    }\n  } else if (compat.thinkingFormat === \"baseten\" && model.reasoning) {\n    const basetenParams = params;\n    const chatTemplateArgs = buildChatTemplateValues(model, options, compat.chatTemplateArgs);\n    if (chatTemplateArgs) {\n      basetenParams.chat_template_args = chatTemplateArgs;\n    }\n    if (compat.supportsReasoningEffort) {\n      const requestedEffort = options?.reasoningEffort;\n      const mappedEffort = requestedEffort ? model.thinkingLevelMap?.[requestedEffort] : model.thinkingLevelMap?.off;\n      const effort = mappedEffort === void 0 ? requestedEffort : mappedEffort;\n      if (typeof effort === \"string\") {\n        basetenParams.reasoning_effort = effort;\n      }\n    }\n  } else if (compat.thinkingFormat === \"deepseek\" && model.reasoning) {\n    if (options?.reasoningEffort) {\n      params.thinking = { type: \"enabled\" };\n    } else if (model.thinkingLevelMap?.off !== null) {\n      params.thinking = { type: \"disabled\" };\n    }\n    if (options?.reasoningEffort && compat.supportsReasoningEffort) {\n      params.reasoning_effort = model.thinkingLevelMap?.[options.reasoningEffort] ?? options.reasoningEffort;\n    }\n  } else if (compat.thinkingFormat === \"openrouter\" && model.reasoning) {\n    const openRouterParams = params;\n    if (options?.reasoningEffort) {\n      openRouterParams.reasoning = {\n        effort: model.thinkingLevelMap?.[options.reasoningEffort] ?? options.reasoningEffort\n      };\n    } else if (model.thinkingLevelMap?.off !== null) {\n      openRouterParams.reasoning = { effort: model.thinkingLevelMap?.off ?? \"none\" };\n    }\n  } else if (compat.thinkingFormat === \"ant-ling\" && model.reasoning && options?.reasoningEffort) {\n    const effort = model.thinkingLevelMap?.[options.reasoningEffort];\n    if (typeof effort === \"string\") {\n      params.reasoning = { effort };\n    }\n  } else if (compat.thinkingFormat === \"together\" && model.reasoning) {\n    const togetherParams = params;\n    togetherParams.reasoning = { enabled: !!options?.reasoningEffort };\n    if (options?.reasoningEffort && compat.supportsReasoningEffort) {\n      togetherParams.reasoning_effort = model.thinkingLevelMap?.[options.reasoningEffort] ?? options.reasoningEffort;\n    }\n  } else if (compat.thinkingFormat === \"string-thinking\" && model.reasoning) {\n    const stringThinkingParams = params;\n    if (options?.reasoningEffort) {\n      stringThinkingParams.thinking = model.thinkingLevelMap?.[options.reasoningEffort] ?? options.reasoningEffort;\n    } else if (model.thinkingLevelMap?.off !== null) {\n      stringThinkingParams.thinking = model.thinkingLevelMap?.off ?? \"none\";\n    }\n  } else if (options?.reasoningEffort && model.reasoning && compat.supportsReasoningEffort) {\n    params.reasoning_effort = model.thinkingLevelMap?.[options.reasoningEffort] ?? options.reasoningEffort;\n  } else if (!options?.reasoningEffort && model.reasoning && compat.supportsReasoningEffort) {\n    const offValue = model.thinkingLevelMap?.off;\n    if (typeof offValue === \"string\") {\n      params.reasoning_effort = offValue;\n    }\n  }\n  if (compat.supportsThinkingTokenBudget && options?.reasoningEffort && model.reasoning) {\n    const level = clampReasoning(options.reasoningEffort);\n    const budgets = {\n      minimal: 1024,\n      low: 2048,\n      medium: 8192,\n      high: 16384,\n      ...options.thinkingBudgets\n    };\n    const ceiling = params.max_tokens ?? params.max_completion_tokens ?? model.maxTokens;\n    const budget = Math.min(budgets[level], Math.max(0, ceiling - MIN_ANSWER_TOKENS));\n    if (budget > 0) {\n      params.thinking_token_budget = budget;\n    }\n  }\n  if (model.compat?.openRouterRouting) {\n    params.provider = model.compat.openRouterRouting;\n  }\n  if (model.compat?.vercelGatewayRouting) {\n    const routing = model.compat.vercelGatewayRouting;\n    if (routing.only || routing.order) {\n      const gatewayOptions = {};\n      if (routing.only)\n        gatewayOptions.only = routing.only;\n      if (routing.order)\n        gatewayOptions.order = routing.order;\n      params.providerOptions = { gateway: gatewayOptions };\n    }\n  }\n  if (options?.samplingParams) {\n    Object.assign(params, options.samplingParams);\n  }\n  return params;\n}\nfunction buildChatTemplateValues(model, options, values) {\n  const resolvedValues = {};\n  for (const [key, value] of Object.entries(values)) {\n    const resolved = resolveChatTemplateKwargValue(model, options, value);\n    if (resolved !== void 0) {\n      resolvedValues[key] = resolved;\n    }\n  }\n  return Object.keys(resolvedValues).length > 0 ? resolvedValues : void 0;\n}\nfunction resolveChatTemplateKwargValue(model, options, value) {\n  if (typeof value !== \"object\" || value === null) {\n    return value;\n  }\n  const reasoningEffort = options?.reasoningEffort;\n  if (!reasoningEffort && value.omitWhenOff) {\n    return void 0;\n  }\n  if (value.$var === \"thinking.enabled\") {\n    return !!reasoningEffort;\n  }\n  const mappedValue = reasoningEffort ? model.thinkingLevelMap?.[reasoningEffort] : model.thinkingLevelMap?.off;\n  return mappedValue === void 0 ? reasoningEffort : typeof mappedValue === \"string\" ? mappedValue : void 0;\n}\nfunction getCompatCacheControl(compat, cacheRetention) {\n  if (compat.cacheControlFormat !== \"anthropic\" || cacheRetention === \"none\") {\n    return void 0;\n  }\n  const ttl = cacheRetention === \"long\" && compat.supportsLongCacheRetention ? \"1h\" : void 0;\n  return { type: \"ephemeral\", ...ttl ? { ttl } : {} };\n}\nfunction applyAnthropicCacheControl(messages, tools, cacheControl) {\n  addCacheControlToSystemPrompt(messages, cacheControl);\n  addCacheControlToLastTool(tools, cacheControl);\n  addCacheControlToLastConversationMessage(messages, cacheControl);\n}\nfunction addCacheControlToSystemPrompt(messages, cacheControl) {\n  for (const message of messages) {\n    if (message.role === \"system\" || message.role === \"developer\") {\n      addCacheControlToInstructionMessage(message, cacheControl);\n      return;\n    }\n  }\n}\nfunction addCacheControlToLastConversationMessage(messages, cacheControl) {\n  for (let i = messages.length - 1; i >= 0; i--) {\n    const message = messages[i];\n    if (message.role === \"user\" || message.role === \"assistant\" || message.role === \"tool\") {\n      if (addCacheControlToMessage(message, cacheControl)) {\n        return;\n      }\n    }\n  }\n}\nfunction addCacheControlToLastTool(tools, cacheControl) {\n  if (!tools || tools.length === 0) {\n    return;\n  }\n  const lastTool = tools[tools.length - 1];\n  lastTool.cache_control = cacheControl;\n}\nfunction addCacheControlToInstructionMessage(message, cacheControl) {\n  return addCacheControlToTextContent(message, cacheControl);\n}\nfunction addCacheControlToMessage(message, cacheControl) {\n  if (message.role === \"user\" || message.role === \"assistant\" || message.role === \"tool\") {\n    return addCacheControlToTextContent(message, cacheControl);\n  }\n  return false;\n}\nfunction addCacheControlToTextContent(message, cacheControl) {\n  const content = message.content;\n  if (typeof content === \"string\") {\n    if (content.length === 0) {\n      return false;\n    }\n    message.content = [\n      {\n        type: \"text\",\n        text: content,\n        cache_control: cacheControl\n      }\n    ];\n    return true;\n  }\n  if (!Array.isArray(content)) {\n    return false;\n  }\n  for (let i = content.length - 1; i >= 0; i--) {\n    const part = content[i];\n    if (part?.type === \"text\") {\n      const textPart = part;\n      textPart.cache_control = cacheControl;\n      return true;\n    }\n  }\n  return false;\n}\nfunction convertMessages(model, context, compat, options) {\n  const params = [];\n  const normalizeToolCallId2 = (id) => {\n    if (id.includes(\"|\")) {\n      const separatorIndex = id.indexOf(\"|\");\n      const callId = id.slice(0, separatorIndex).replace(/[^a-zA-Z0-9_-]/g, \"_\");\n      const itemId = id.slice(separatorIndex + 1).replace(/[^a-zA-Z0-9_-]/g, \"_\");\n      const combinedId = itemId.length > 0 ? `${callId}_${itemId}` : callId;\n      if (combinedId.length <= 40) {\n        return combinedId;\n      }\n      const hash = shortHash(id).slice(0, 8);\n      const prefix = callId.slice(0, Math.max(1, 40 - hash.length - 1));\n      return `${prefix}_${hash}`;\n    }\n    if (model.provider === \"openai\")\n      return id.length > 40 ? id.slice(0, 40) : id;\n    return id;\n  };\n  const transformedMessages = transformMessages(context.messages, model, (id) => normalizeToolCallId2(id));\n  if (context.systemPrompt) {\n    const useDeveloperRole = model.reasoning && compat.supportsDeveloperRole;\n    const role = useDeveloperRole ? \"developer\" : \"system\";\n    params.push({ role, content: sanitizeSurrogates(context.systemPrompt) });\n  }\n  let lastRole = null;\n  for (let i = 0; i < transformedMessages.length; i++) {\n    const msg = transformedMessages[i];\n    if (compat.requiresAssistantAfterToolResult && lastRole === \"toolResult\" && msg.role === \"user\") {\n      params.push({\n        role: \"assistant\",\n        content: \"I have processed the tool results.\"\n      });\n    }\n    if (msg.role === \"user\") {\n      if (typeof msg.content === \"string\") {\n        params.push({\n          role: \"user\",\n          content: sanitizeSurrogates(msg.content)\n        });\n      } else {\n        const content = msg.content.map((item) => {\n          if (item.type === \"text\") {\n            return {\n              type: \"text\",\n              text: sanitizeSurrogates(item.text)\n            };\n          } else {\n            return {\n              type: \"image_url\",\n              image_url: {\n                url: `data:${item.mimeType};base64,${item.data}`\n              }\n            };\n          }\n        });\n        if (content.length === 0)\n          continue;\n        params.push({\n          role: \"user\",\n          content\n        });\n      }\n    } else if (msg.role === \"assistant\") {\n      const assistantMsg = {\n        role: \"assistant\",\n        content: compat.requiresAssistantAfterToolResult ? \"\" : null\n      };\n      const assistantTextParts = msg.content.filter(isTextContentBlock).filter((block) => block.text.trim().length > 0).map((block) => ({\n        type: \"text\",\n        text: sanitizeSurrogates(block.text)\n      }));\n      const assistantText = assistantTextParts.map((part) => part.text).join(\"\");\n      const nonEmptyThinkingBlocks = msg.content.filter(isThinkingContentBlock).filter((block) => block.thinking.trim().length > 0);\n      if (nonEmptyThinkingBlocks.length > 0) {\n        if (compat.requiresThinkingAsText) {\n          const thinkingText = nonEmptyThinkingBlocks.map((block) => sanitizeSurrogates(block.thinking)).join(\"\\n\\n\");\n          assistantMsg.content = [{ type: \"text\", text: thinkingText }, ...assistantTextParts];\n        } else {\n          if (assistantText.length > 0) {\n            assistantMsg.content = assistantText;\n          }\n          let signature = nonEmptyThinkingBlocks[0].thinkingSignature;\n          if (model.provider === \"opencode-go\" && signature === \"reasoning\") {\n            signature = \"reasoning_content\";\n          }\n          if (signature && signature.length > 0) {\n            assistantMsg[signature] = nonEmptyThinkingBlocks.map((block) => block.thinking).join(\"\\n\");\n          }\n        }\n      } else if (assistantText.length > 0) {\n        assistantMsg.content = assistantText;\n      }\n      const toolCalls = msg.content.filter(isToolCallBlock);\n      if (toolCalls.length > 0) {\n        assistantMsg.tool_calls = toolCalls.map((tc) => {\n          const customInputProperty = options?.grammarToolInputProperties?.get(tc.name);\n          if (customInputProperty !== void 0) {\n            return {\n              id: tc.id,\n              type: \"custom\",\n              custom: {\n                name: tc.name,\n                input: sanitizeSurrogates(getGrammarToolInput(tc.name, tc.arguments, customInputProperty))\n              }\n            };\n          }\n          return {\n            id: tc.id,\n            type: \"function\",\n            function: {\n              name: tc.name,\n              arguments: JSON.stringify(tc.arguments)\n            }\n          };\n        });\n        const reasoningDetails = toolCalls.filter((tc) => tc.thoughtSignature).map((tc) => {\n          try {\n            return JSON.parse(tc.thoughtSignature);\n          } catch {\n            return null;\n          }\n        }).filter(Boolean);\n        if (reasoningDetails.length > 0) {\n          assistantMsg.reasoning_details = reasoningDetails;\n        }\n      }\n      if (compat.requiresReasoningContentOnAssistantMessages && model.reasoning && assistantMsg.reasoning_content === void 0) {\n        assistantMsg.reasoning_content = \"\";\n      }\n      const content = assistantMsg.content;\n      const hasContent = content !== null && content !== void 0 && (typeof content === \"string\" ? content.length > 0 : content.length > 0);\n      if (!hasContent && !assistantMsg.tool_calls) {\n        continue;\n      }\n      params.push(assistantMsg);\n    } else if (msg.role === \"toolResult\") {\n      const imageBlocks = [];\n      const deferredToolNames = /* @__PURE__ */ new Set();\n      let j = i;\n      for (; j < transformedMessages.length && transformedMessages[j].role === \"toolResult\"; j++) {\n        const toolMsg = transformedMessages[j];\n        const textResult = toolMsg.content.filter(isTextContentBlock).map((block) => block.text).join(\"\\n\");\n        const hasImages = toolMsg.content.some((c) => c.type === \"image\");\n        const hasText = textResult.length > 0;\n        const toolResultText = hasText ? textResult : hasImages ? \"(see attached image)\" : \"(no tool output)\";\n        const toolResultMsg = {\n          role: \"tool\",\n          content: sanitizeSurrogates(toolResultText),\n          tool_call_id: toolMsg.toolCallId\n        };\n        if (compat.requiresToolResultName && toolMsg.toolName) {\n          toolResultMsg.name = toolMsg.toolName;\n        }\n        params.push(toolResultMsg);\n        if (compat.deferredToolsMode === \"kimi\") {\n          for (const name of toolMsg.addedToolNames ?? []) {\n            deferredToolNames.add(name);\n          }\n        }\n        if (hasImages && model.input.includes(\"image\")) {\n          for (const block of toolMsg.content) {\n            if (isImageContentBlock(block)) {\n              imageBlocks.push({\n                type: \"image_url\",\n                image_url: {\n                  url: `data:${block.mimeType};base64,${block.data}`\n                }\n              });\n            }\n          }\n        }\n      }\n      i = j - 1;\n      if (imageBlocks.length > 0) {\n        if (compat.requiresAssistantAfterToolResult) {\n          params.push({\n            role: \"assistant\",\n            content: \"I have processed the tool results.\"\n          });\n        }\n        params.push({\n          role: \"user\",\n          content: [\n            {\n              type: \"text\",\n              text: \"Attached image(s) from tool result:\"\n            },\n            ...imageBlocks\n          ]\n        });\n        lastRole = \"user\";\n      } else {\n        lastRole = \"toolResult\";\n      }\n      if (deferredToolNames.size > 0) {\n        const deferredTools = getToolsByName(context.tools, deferredToolNames);\n        if (deferredTools.length > 0) {\n          const kimiToolMessage = {\n            role: \"system\",\n            tools: convertTools(deferredTools, compat)\n          };\n          params.push(kimiToolMessage);\n        }\n      }\n      continue;\n    }\n    lastRole = msg.role;\n  }\n  return params;\n}\nfunction convertTools(tools, compat) {\n  return tools.map((tool) => {\n    const grammar = resolveGrammarConstrainedSampling(tool, compat.supportsOpenAIGrammarTools);\n    if (grammar) {\n      return {\n        type: \"custom\",\n        custom: {\n          name: tool.name,\n          description: tool.description,\n          format: {\n            type: \"grammar\",\n            grammar: {\n              syntax: grammar.format,\n              definition: grammar.definition\n            }\n          }\n        }\n      };\n    }\n    const strict = resolveJsonSchemaStrictSampling(tool, compat.supportsStrictMode !== false);\n    return {\n      type: \"function\",\n      function: {\n        name: tool.name,\n        description: tool.description,\n        parameters: getJsonSchemaToolParameters(tool, strict),\n        // Only include strict if provider supports it. Some reject unknown fields.\n        ...compat.supportsStrictMode !== false && { strict: strict ?? false }\n      }\n    };\n  });\n}\nfunction parseChunkUsage(rawUsage, model) {\n  const promptTokens = rawUsage.prompt_tokens || 0;\n  const cacheReadTokens = rawUsage.prompt_tokens_details?.cached_tokens ?? rawUsage.prompt_cache_hit_tokens ?? 0;\n  const cacheWriteTokens = rawUsage.prompt_tokens_details?.cache_write_tokens || 0;\n  const input = Math.max(0, promptTokens - cacheReadTokens - cacheWriteTokens);\n  const outputTokens = rawUsage.completion_tokens || 0;\n  const usage = {\n    input,\n    output: outputTokens,\n    cacheRead: cacheReadTokens,\n    cacheWrite: cacheWriteTokens,\n    reasoning: rawUsage.completion_tokens_details?.reasoning_tokens || 0,\n    totalTokens: input + outputTokens + cacheReadTokens + cacheWriteTokens,\n    cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 }\n  };\n  calculateCost(model, usage);\n  return usage;\n}\nfunction mapStopReason(reason) {\n  if (reason === null)\n    return { stopReason: \"stop\" };\n  switch (reason) {\n    case \"stop\":\n    case \"end\":\n      return { stopReason: \"stop\" };\n    case \"length\":\n      return { stopReason: \"length\" };\n    case \"function_call\":\n    case \"tool_calls\":\n      return { stopReason: \"toolUse\" };\n    case \"content_filter\":\n      return { stopReason: \"error\", errorMessage: \"Provider finish_reason: content_filter\" };\n    case \"network_error\":\n      return { stopReason: \"error\", errorMessage: \"Provider finish_reason: network_error\" };\n    default:\n      return {\n        stopReason: \"error\",\n        errorMessage: `Provider finish_reason: ${reason}`\n      };\n  }\n}\nfunction detectCompat(model) {\n  const provider = model.provider;\n  const baseUrl = model.baseUrl;\n  const isZai = provider === \"zai\" || provider === \"zai-coding-cn\" || baseUrl.includes(\"api.z.ai\") || baseUrl.includes(\"open.bigmodel.cn\");\n  const isTogether = provider === \"together\" || baseUrl.includes(\"api.together.ai\") || baseUrl.includes(\"api.together.xyz\");\n  const isMoonshot = provider === \"moonshotai\" || provider === \"moonshotai-cn\" || baseUrl.includes(\"api.moonshot.\");\n  const isOpenRouter = provider === \"openrouter\" || baseUrl.includes(\"openrouter.ai\");\n  const isCloudflareWorkersAI = provider === \"cloudflare-workers-ai\" || baseUrl.includes(\"api.cloudflare.com\");\n  const isCloudflareAiGateway = provider === \"cloudflare-ai-gateway\" || baseUrl.includes(\"gateway.ai.cloudflare.com\");\n  const isNvidia = provider === \"nvidia\" || baseUrl.includes(\"integrate.api.nvidia.com\");\n  const isAntLing = provider === \"ant-ling\" || baseUrl.includes(\"api.ant-ling.com\");\n  const isDeepSeek = provider === \"deepseek\" || baseUrl.toLowerCase().includes(\"deepseek.com\");\n  const isNonStandard = isNvidia || provider === \"cerebras\" || baseUrl.includes(\"cerebras.ai\") || provider === \"xai\" || baseUrl.includes(\"api.x.ai\") || isTogether || baseUrl.includes(\"chutes.ai\") || isDeepSeek || isZai || isMoonshot || provider === \"opencode\" || baseUrl.includes(\"opencode.ai\") || isCloudflareWorkersAI || isCloudflareAiGateway || isAntLing;\n  const useMaxTokens = baseUrl.includes(\"chutes.ai\") || isDeepSeek || isMoonshot || isCloudflareAiGateway || isTogether || isNvidia || isAntLing || isZai;\n  const isGrok = provider === \"xai\" || baseUrl.includes(\"api.x.ai\");\n  const isOpenRouterDeveloperRoleModel = isOpenRouter && (model.id.startsWith(\"anthropic/\") || model.id.startsWith(\"openai/\"));\n  const cacheControlFormat = provider === \"openrouter\" && model.id.startsWith(\"anthropic/\") ? \"anthropic\" : void 0;\n  return {\n    supportsStore: !isNonStandard,\n    supportsDeveloperRole: isOpenRouterDeveloperRoleModel || !isNonStandard && !isOpenRouter,\n    supportsReasoningEffort: !isGrok && !isZai && !isMoonshot && !isTogether && !isCloudflareAiGateway && !isNvidia && !isAntLing,\n    supportsUsageInStreaming: true,\n    supportsFinishReason: true,\n    maxTokensField: useMaxTokens ? \"max_tokens\" : \"max_completion_tokens\",\n    requiresToolResultName: false,\n    requiresAssistantAfterToolResult: false,\n    requiresThinkingAsText: false,\n    requiresReasoningContentOnAssistantMessages: isDeepSeek,\n    thinkingFormat: isDeepSeek ? \"deepseek\" : isZai ? \"zai\" : isTogether ? \"together\" : isAntLing ? \"ant-ling\" : isOpenRouter ? \"openrouter\" : \"openai\",\n    openRouterRouting: {},\n    vercelGatewayRouting: {},\n    chatTemplateKwargs: {},\n    chatTemplateArgs: {},\n    zaiToolStream: false,\n    supportsThinkingTokenBudget: false,\n    supportsStrictMode: !isMoonshot && !isTogether && !isCloudflareAiGateway && !isNvidia,\n    supportsOpenAIGrammarTools: false,\n    cacheControlFormat,\n    sendSessionAffinityHeaders: false,\n    deferredToolsMode: void 0,\n    sessionAffinityFormat: isOpenRouter ? \"openrouter\" : \"openai\",\n    supportsLongCacheRetention: !(isTogether || isCloudflareWorkersAI || isCloudflareAiGateway || isNvidia || isAntLing)\n  };\n}\nfunction getCompat(model) {\n  const detected = detectCompat(model);\n  if (!model.compat)\n    return detected;\n  return {\n    supportsStore: model.compat.supportsStore ?? detected.supportsStore,\n    supportsDeveloperRole: model.compat.supportsDeveloperRole ?? detected.supportsDeveloperRole,\n    supportsReasoningEffort: model.compat.supportsReasoningEffort ?? detected.supportsReasoningEffort,\n    supportsUsageInStreaming: model.compat.supportsUsageInStreaming ?? detected.supportsUsageInStreaming,\n    supportsFinishReason: model.compat.supportsFinishReason ?? detected.supportsFinishReason,\n    maxTokensField: model.compat.maxTokensField ?? detected.maxTokensField,\n    requiresToolResultName: model.compat.requiresToolResultName ?? detected.requiresToolResultName,\n    requiresAssistantAfterToolResult: model.compat.requiresAssistantAfterToolResult ?? detected.requiresAssistantAfterToolResult,\n    requiresThinkingAsText: model.compat.requiresThinkingAsText ?? detected.requiresThinkingAsText,\n    requiresReasoningContentOnAssistantMessages: model.compat.requiresReasoningContentOnAssistantMessages ?? detected.requiresReasoningContentOnAssistantMessages,\n    thinkingFormat: model.compat.thinkingFormat ?? detected.thinkingFormat,\n    openRouterRouting: model.compat.openRouterRouting ?? {},\n    vercelGatewayRouting: model.compat.vercelGatewayRouting ?? detected.vercelGatewayRouting,\n    chatTemplateKwargs: model.compat.chatTemplateKwargs ?? detected.chatTemplateKwargs,\n    chatTemplateArgs: model.compat.chatTemplateArgs ?? detected.chatTemplateArgs,\n    zaiToolStream: model.compat.zaiToolStream ?? detected.zaiToolStream,\n    supportsThinkingTokenBudget: model.compat.supportsThinkingTokenBudget ?? detected.supportsThinkingTokenBudget,\n    supportsStrictMode: model.compat.supportsStrictMode ?? detected.supportsStrictMode,\n    supportsOpenAIGrammarTools: model.compat.supportsOpenAIGrammarTools ?? detected.supportsOpenAIGrammarTools,\n    cacheControlFormat: model.compat.cacheControlFormat ?? detected.cacheControlFormat,\n    sendSessionAffinityHeaders: model.compat.sendSessionAffinityHeaders ?? detected.sendSessionAffinityHeaders,\n    deferredToolsMode: model.compat.deferredToolsMode ?? detected.deferredToolsMode,\n    sessionAffinityFormat: model.compat.sessionAffinityFormat ?? detected.sessionAffinityFormat,\n    supportsLongCacheRetention: model.compat.supportsLongCacheRetention ?? detected.supportsLongCacheRetention\n  };\n}\nvar stream, streamSimple;\nvar init_openai_completions = __esm({\n  \"node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/api/openai-completions.js\"() {\n    init_openai();\n    init_models();\n    init_error_body();\n    init_event_stream();\n    init_hash();\n    init_headers();\n    init_json_parse();\n    init_provider_env();\n    init_provider_retry();\n    init_sanitize_unicode();\n    init_constrained_sampling();\n    init_github_copilot_headers();\n    init_openai_prompt_cache();\n    init_simple_options();\n    init_transform_messages();\n    stream = (model, context, options) => {\n      const stream11 = new AssistantMessageEventStream();\n      (async () => {\n        const output = {\n          role: \"assistant\",\n          content: [],\n          api: model.api,\n          provider: model.provider,\n          model: model.id,\n          usage: {\n            input: 0,\n            output: 0,\n            cacheRead: 0,\n            cacheWrite: 0,\n            totalTokens: 0,\n            cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 }\n          },\n          stopReason: \"pending\",\n          timestamp: Date.now()\n        };\n        try {\n          const apiKey = getClientApiKey(model.provider, options?.apiKey, options?.headers);\n          const compat = getCompat(model);\n          const grammarToolInputProperties = createGrammarToolInputProperties(context.tools, compat.supportsOpenAIGrammarTools);\n          const cacheRetention = resolveCacheRetention(options?.cacheRetention, options?.env);\n          const cacheSessionId = cacheRetention === \"none\" ? void 0 : options?.sessionId;\n          const client = createClient(model, context, apiKey, options?.headers, options?.fetch, cacheSessionId, compat);\n          let params = buildParams(model, context, options, compat, cacheRetention, grammarToolInputProperties);\n          const nextParams = await options?.onPayload?.(params, model);\n          if (nextParams !== void 0) {\n            params = nextParams;\n          }\n          const requestOptions = {\n            ...options?.signal ? { signal: options.signal } : {},\n            ...options?.timeoutMs !== void 0 ? { timeout: options.timeoutMs } : {},\n            maxRetries: 0\n          };\n          const { data: openaiStream, response } = await retryProviderRequest(() => client.chat.completions.create(params, requestOptions).withResponse(), {\n            maxRetries: options?.maxRetries,\n            maxRetryDelayMs: options?.maxRetryDelayMs,\n            signal: options?.signal\n          });\n          await options?.onResponse?.({ status: response.status, headers: headersToRecord(response.headers) }, model);\n          stream11.push({ type: \"start\", partial: output });\n          let textBlock = null;\n          let thinkingBlock = null;\n          let hasFinishReason = false;\n          const toolCallBlocksByIndex = /* @__PURE__ */ new Map();\n          const toolCallBlocksById = /* @__PURE__ */ new Map();\n          const pendingReasoningDetailsByToolCallId = /* @__PURE__ */ new Map();\n          const blocks = output.content;\n          const getContentIndex = (block) => blocks.indexOf(block);\n          const getCustomToolCallInput2 = (block) => {\n            const property = block.customInput?.property;\n            if (property === void 0)\n              return \"\";\n            const value = block.arguments[property];\n            return typeof value === \"string\" ? value : \"\";\n          };\n          const appendCustomToolCallInput2 = (block, nextInput, close) => {\n            const customInput = block.customInput;\n            if (!customInput)\n              return void 0;\n            const delta = appendGrammarToolInputJsonDelta(customInput.jsonBuffer, customInput.property, nextInput, close);\n            block.arguments = { [customInput.property]: nextInput };\n            return delta;\n          };\n          const finishBlock = (block) => {\n            const contentIndex = getContentIndex(block);\n            if (contentIndex === -1) {\n              return;\n            }\n            if (block.type === \"text\") {\n              stream11.push({\n                type: \"text_end\",\n                contentIndex,\n                content: block.text,\n                partial: output\n              });\n            } else if (block.type === \"thinking\") {\n              stream11.push({\n                type: \"thinking_end\",\n                contentIndex,\n                content: block.thinking,\n                partial: output\n              });\n            } else if (block.type === \"toolCall\") {\n              if (block.customInput) {\n                const delta = appendCustomToolCallInput2(block, getCustomToolCallInput2(block), true);\n                if (delta !== void 0) {\n                  stream11.push({\n                    type: \"toolcall_delta\",\n                    contentIndex,\n                    delta,\n                    partial: output\n                  });\n                }\n              } else {\n                block.arguments = parseStreamingJson(block.partialArgs);\n              }\n              delete block.partialArgs;\n              delete block.customInput;\n              delete block.streamIndex;\n              stream11.push({\n                type: \"toolcall_end\",\n                contentIndex,\n                toolCall: block,\n                partial: output\n              });\n            }\n          };\n          const ensureTextBlock = () => {\n            if (!textBlock) {\n              textBlock = { type: \"text\", text: \"\" };\n              blocks.push(textBlock);\n              stream11.push({ type: \"text_start\", contentIndex: getContentIndex(textBlock), partial: output });\n            }\n            return textBlock;\n          };\n          const ensureThinkingBlock = (thinkingSignature) => {\n            if (!thinkingBlock) {\n              thinkingBlock = {\n                type: \"thinking\",\n                thinking: \"\",\n                thinkingSignature\n              };\n              blocks.push(thinkingBlock);\n              stream11.push({ type: \"thinking_start\", contentIndex: getContentIndex(thinkingBlock), partial: output });\n            }\n            return thinkingBlock;\n          };\n          const applyPendingReasoningDetail = (block) => {\n            if (!block.id) {\n              return;\n            }\n            const pendingReasoningDetail = pendingReasoningDetailsByToolCallId.get(block.id);\n            if (pendingReasoningDetail) {\n              block.thoughtSignature = pendingReasoningDetail;\n              pendingReasoningDetailsByToolCallId.delete(block.id);\n            }\n          };\n          const ensureToolCallBlock = (toolCall) => {\n            const streamIndex = typeof toolCall.index === \"number\" ? toolCall.index : void 0;\n            const name = toolCall.function?.name ?? toolCall.custom?.name ?? \"\";\n            let block = streamIndex !== void 0 ? toolCallBlocksByIndex.get(streamIndex) : void 0;\n            if (!block && toolCall.id) {\n              block = toolCallBlocksById.get(toolCall.id);\n            }\n            if (!block) {\n              const customInputProperty = toolCall.custom && !toolCall.function ? grammarToolInputProperties.get(name) ?? \"input\" : void 0;\n              const hasCustomInput = customInputProperty !== void 0;\n              block = {\n                type: \"toolCall\",\n                id: toolCall.id || \"\",\n                name,\n                arguments: hasCustomInput ? { [customInputProperty]: \"\" } : {},\n                partialArgs: hasCustomInput ? void 0 : \"\",\n                customInput: hasCustomInput ? { property: customInputProperty, jsonBuffer: { input: \"\", started: false, closed: false } } : void 0,\n                streamIndex\n              };\n              if (streamIndex !== void 0) {\n                toolCallBlocksByIndex.set(streamIndex, block);\n              }\n              if (toolCall.id) {\n                toolCallBlocksById.set(toolCall.id, block);\n              }\n              blocks.push(block);\n              stream11.push({\n                type: \"toolcall_start\",\n                contentIndex: getContentIndex(block),\n                partial: output\n              });\n            }\n            if (streamIndex !== void 0 && block.streamIndex === void 0) {\n              block.streamIndex = streamIndex;\n              toolCallBlocksByIndex.set(streamIndex, block);\n            }\n            if (toolCall.id) {\n              toolCallBlocksById.set(toolCall.id, block);\n            }\n            if (!block.name && name) {\n              block.name = name;\n            }\n            if (toolCall.custom && !toolCall.function && !block.customInput) {\n              const customInputProperty = grammarToolInputProperties.get(block.name) ?? \"input\";\n              block.arguments = { [customInputProperty]: \"\" };\n              block.customInput = {\n                property: customInputProperty,\n                jsonBuffer: { input: \"\", started: false, closed: false }\n              };\n              delete block.partialArgs;\n            }\n            applyPendingReasoningDetail(block);\n            return block;\n          };\n          for await (const chunk of openaiStream) {\n            if (!chunk || typeof chunk !== \"object\")\n              continue;\n            output.responseId ||= chunk.id;\n            if (typeof chunk.model === \"string\" && chunk.model.length > 0 && chunk.model !== model.id) {\n              output.responseModel ||= chunk.model;\n            }\n            if (chunk.usage) {\n              output.usage = parseChunkUsage(chunk.usage, model);\n            }\n            const choice = Array.isArray(chunk.choices) ? chunk.choices[0] : void 0;\n            if (!choice)\n              continue;\n            if (!chunk.usage && choice.usage) {\n              output.usage = parseChunkUsage(choice.usage, model);\n            }\n            if (choice.finish_reason) {\n              output.rawStopReason = choice.finish_reason;\n              const finishReasonResult = mapStopReason(choice.finish_reason);\n              output.stopReason = finishReasonResult.stopReason;\n              if (finishReasonResult.errorMessage) {\n                output.errorMessage = finishReasonResult.errorMessage;\n              }\n              hasFinishReason = true;\n            }\n            if (choice.delta) {\n              if (choice.delta.content !== null && choice.delta.content !== void 0 && choice.delta.content.length > 0) {\n                const block = ensureTextBlock();\n                block.text += choice.delta.content;\n                stream11.push({\n                  type: \"text_delta\",\n                  contentIndex: getContentIndex(block),\n                  delta: choice.delta.content,\n                  partial: output\n                });\n              }\n              const reasoningFields = [\"reasoning_content\", \"reasoning\", \"reasoning_text\"];\n              const deltaFields = choice.delta;\n              let foundReasoningField = null;\n              for (const field of reasoningFields) {\n                const value = deltaFields[field];\n                if (typeof value === \"string\" && value.length > 0) {\n                  foundReasoningField = field;\n                  break;\n                }\n              }\n              if (foundReasoningField) {\n                const delta = deltaFields[foundReasoningField];\n                if (typeof delta === \"string\" && delta.length > 0) {\n                  const thinkingSignature = model.provider === \"opencode-go\" && foundReasoningField === \"reasoning\" ? \"reasoning_content\" : foundReasoningField;\n                  const block = ensureThinkingBlock(thinkingSignature);\n                  block.thinking += delta;\n                  stream11.push({\n                    type: \"thinking_delta\",\n                    contentIndex: getContentIndex(block),\n                    delta,\n                    partial: output\n                  });\n                }\n              }\n              if (choice?.delta?.tool_calls) {\n                for (const toolCall of choice.delta.tool_calls) {\n                  const block = ensureToolCallBlock(toolCall);\n                  if (!block.id && toolCall.id) {\n                    block.id = toolCall.id;\n                    toolCallBlocksById.set(toolCall.id, block);\n                  }\n                  const name = toolCall.function?.name ?? toolCall.custom?.name;\n                  if (!block.name && name) {\n                    block.name = name;\n                  }\n                  let delta = \"\";\n                  if (toolCall.function?.arguments) {\n                    delta = toolCall.function.arguments;\n                    block.partialArgs = (block.partialArgs ?? \"\") + toolCall.function.arguments;\n                    block.arguments = parseStreamingJson(block.partialArgs);\n                  } else if (toolCall.custom?.input) {\n                    const nextInput = getCustomToolCallInput2(block) + toolCall.custom.input;\n                    delta = appendCustomToolCallInput2(block, nextInput, false) ?? \"\";\n                  }\n                  stream11.push({\n                    type: \"toolcall_delta\",\n                    contentIndex: getContentIndex(block),\n                    delta,\n                    partial: output\n                  });\n                }\n              }\n              const reasoningDetails = choice.delta.reasoning_details;\n              if (Array.isArray(reasoningDetails)) {\n                for (const detail of reasoningDetails) {\n                  if (isEncryptedReasoningDetail(detail)) {\n                    const serializedDetail = JSON.stringify(detail);\n                    const matchingToolCall = toolCallBlocksById.get(detail.id);\n                    if (matchingToolCall) {\n                      matchingToolCall.thoughtSignature = serializedDetail;\n                    } else {\n                      pendingReasoningDetailsByToolCallId.set(detail.id, serializedDetail);\n                    }\n                  }\n                }\n              }\n            }\n          }\n          for (const block of blocks) {\n            finishBlock(block);\n          }\n          if (options?.signal?.aborted) {\n            throw new Error(\"Request was aborted\");\n          }\n          if (output.stopReason === \"aborted\") {\n            throw new Error(\"Request was aborted\");\n          }\n          if (!hasFinishReason && !compat.supportsFinishReason) {\n            output.stopReason = output.content.some((block) => block.type === \"toolCall\") ? \"toolUse\" : \"stop\";\n          }\n          if (output.stopReason === \"error\") {\n            throw new Error(output.errorMessage || \"Provider returned an error stop reason\");\n          }\n          if (compat.supportsFinishReason && !hasFinishReason || output.stopReason === \"pending\") {\n            throw new Error(\"Stream ended without finish_reason\");\n          }\n          stream11.push({ type: \"done\", reason: output.stopReason, message: output });\n          stream11.end();\n        } catch (error) {\n          for (const block of output.content) {\n            delete block.index;\n            delete block.partialArgs;\n            delete block.customInput;\n            delete block.streamIndex;\n          }\n          output.stopReason = options?.signal?.aborted ? \"aborted\" : \"error\";\n          output.errorMessage = formatProviderError(normalizeProviderError(error));\n          const rawMetadata = error?.error?.metadata?.raw;\n          if (rawMetadata && !output.errorMessage.includes(String(rawMetadata))) {\n            output.errorMessage += `\n${rawMetadata}`;\n          }\n          stream11.push({ type: \"error\", reason: output.stopReason, error: output });\n          stream11.end();\n        }\n      })();\n      return stream11;\n    };\n    streamSimple = (model, context, options) => {\n      getClientApiKey(model.provider, options?.apiKey, options?.headers);\n      const base = buildBaseOptions(model, context, options, options?.apiKey);\n      const clampedReasoning = options?.reasoning ? clampThinkingLevel(model, options.reasoning) : void 0;\n      const reasoningEffort = clampedReasoning === \"off\" ? void 0 : clampedReasoning;\n      const toolChoice = options?.toolChoice;\n      return stream(model, context, {\n        ...base,\n        reasoningEffort,\n        toolChoice,\n        thinkingBudgets: options?.thinkingBudgets\n      });\n    };\n  }\n});\n\n// demo/browser/stubs/anthropic.js\nvar Anthropic;\nvar init_anthropic = __esm({\n  \"demo/browser/stubs/anthropic.js\"() {\n    \"use strict\";\n    Anthropic = class {\n      constructor() {\n        throw new Error(\"Real model providers are not available in this demo.\");\n      }\n    };\n  }\n});\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/utils/deferred-tools.js\nfunction splitDeferredTools(context, enabled, normalizeName = identityToolName) {\n  const uniqueTools = /* @__PURE__ */ new Map();\n  for (const tool of context.tools ?? [])\n    uniqueTools.set(normalizeName(tool.name), tool);\n  if (!enabled)\n    return { immediate: [...uniqueTools.values()], deferred: /* @__PURE__ */ new Map() };\n  const deferredNames = /* @__PURE__ */ new Set();\n  const usedNames = /* @__PURE__ */ new Set();\n  for (const message of context.messages) {\n    if (message.role === \"assistant\") {\n      for (const block of message.content) {\n        if (block.type === \"toolCall\")\n          usedNames.add(normalizeName(block.name));\n      }\n    } else if (message.role === \"toolResult\") {\n      for (const name of message.addedToolNames ?? []) {\n        const normalizedName = normalizeName(name);\n        if (!usedNames.has(normalizedName))\n          deferredNames.add(normalizedName);\n      }\n    }\n  }\n  const immediate = [];\n  const deferred = /* @__PURE__ */ new Map();\n  for (const [name, tool] of uniqueTools) {\n    if (deferredNames.has(name))\n      deferred.set(name, tool);\n    else\n      immediate.push(tool);\n  }\n  return { immediate, deferred };\n}\nvar identityToolName;\nvar init_deferred_tools = __esm({\n  \"node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/utils/deferred-tools.js\"() {\n    identityToolName = (name) => name;\n  }\n});\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/utils/pi-user-agent.js\nfunction loadNodeOs() {\n  if (typeof process === \"undefined\" || !(process.versions?.node || process.versions?.bun)) {\n    return null;\n  }\n  return process.getBuiltinModule?.(\"node:os\") ?? null;\n}\nfunction getPiUserAgent() {\n  return nodeOs ? `pi (${nodeOs.platform()} ${nodeOs.release()}; ${nodeOs.arch()})` : \"pi (browser)\";\n}\nvar nodeOs;\nvar init_pi_user_agent = __esm({\n  \"node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/utils/pi-user-agent.js\"() {\n    nodeOs = loadNodeOs();\n  }\n});\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/api/anthropic-messages.js\nvar anthropic_messages_exports = {};\n__export(anthropic_messages_exports, {\n  stream: () => stream2,\n  streamSimple: () => streamSimple2\n});\nfunction resolveCacheRetention2(cacheRetention, env) {\n  if (cacheRetention) {\n    return cacheRetention;\n  }\n  if (getProviderEnvValue(\"PI_CACHE_RETENTION\", env) === \"long\") {\n    return \"long\";\n  }\n  return \"short\";\n}\nfunction getCacheControl(model, cacheRetention, env) {\n  const retention = resolveCacheRetention2(cacheRetention, env);\n  if (retention === \"none\") {\n    return { retention };\n  }\n  const ttl = retention === \"long\" && getAnthropicCompat(model).supportsLongCacheRetention ? \"1h\" : void 0;\n  return {\n    retention,\n    cacheControl: { type: \"ephemeral\", ...ttl && { ttl } }\n  };\n}\nfunction convertContentBlocks(content) {\n  const hasImages = content.some((c) => c.type === \"image\");\n  if (!hasImages) {\n    return sanitizeSurrogates(content.map((c) => c.text).join(\"\\n\"));\n  }\n  const blocks = content.map((block) => {\n    if (block.type === \"text\") {\n      return {\n        type: \"text\",\n        text: sanitizeSurrogates(block.text)\n      };\n    }\n    return {\n      type: \"image\",\n      source: {\n        type: \"base64\",\n        media_type: block.mimeType,\n        data: block.data\n      }\n    };\n  });\n  const hasText = blocks.some((b) => b.type === \"text\");\n  if (!hasText) {\n    blocks.unshift({\n      type: \"text\",\n      text: \"(see attached image)\"\n    });\n  }\n  return blocks;\n}\nfunction getAnthropicCompat(model) {\n  return {\n    supportsEagerToolInputStreaming: model.compat?.supportsEagerToolInputStreaming ?? true,\n    supportsLongCacheRetention: model.compat?.supportsLongCacheRetention ?? true,\n    sendSessionAffinityHeaders: model.compat?.sendSessionAffinityHeaders ?? false,\n    supportsCacheControlOnTools: model.compat?.supportsCacheControlOnTools ?? true,\n    supportsTemperature: model.compat?.supportsTemperature ?? true,\n    allowEmptySignature: model.compat?.allowEmptySignature ?? false,\n    supportsStrictTools: model.compat?.supportsStrictTools ?? false,\n    supportsToolReferences: model.compat?.supportsToolReferences ?? defaultSupportsToolReferences(model)\n  };\n}\nfunction defaultSupportsToolReferences(model) {\n  if (model.provider !== \"anthropic\" || model.id.includes(\"haiku\"))\n    return false;\n  const version = model.id.match(/^claude-(?:opus|sonnet|fable)-(\\d+)(?:-(\\d+))?(?:-|$)/);\n  if (!version)\n    return false;\n  const major = Number(version[1]);\n  const minor = version[2] && version[2].length < 8 ? Number(version[2]) : 0;\n  return major > 4 || major === 4 && minor >= 5;\n}\nfunction mergeHeaders2(...headerSources) {\n  const merged = {};\n  for (const headers of headerSources) {\n    if (headers) {\n      Object.assign(merged, headers);\n    }\n  }\n  return merged;\n}\nfunction mergeClientHeaders(model, ...headerSources) {\n  const merged = mergeHeaders2(...headerSources);\n  if (model.provider === \"kimi-coding\") {\n    for (const name of Object.keys(merged)) {\n      if (name.toLowerCase() === \"user-agent\")\n        delete merged[name];\n    }\n    merged[\"User-Agent\"] = getPiUserAgent();\n  }\n  return merged;\n}\nfunction hasHeader2(headers, name) {\n  if (!headers)\n    return false;\n  const expected = name.toLowerCase();\n  for (const [key, value] of Object.entries(headers)) {\n    if (key.toLowerCase() === expected && value !== null && value.trim().length > 0)\n      return true;\n  }\n  return false;\n}\nfunction assertRequestAuth(provider, apiKey, headers) {\n  if (apiKey)\n    return;\n  if (hasHeader2(headers, \"authorization\") || hasHeader2(headers, \"x-api-key\") || hasHeader2(headers, \"cf-aig-authorization\")) {\n    return;\n  }\n  throw new Error(`No API key for provider: ${provider}`);\n}\nfunction flushSseEvent(state) {\n  if (!state.event && state.data.length === 0) {\n    return null;\n  }\n  const event = {\n    event: state.event,\n    data: state.data.join(\"\\n\"),\n    raw: [...state.raw]\n  };\n  state.event = null;\n  state.data = [];\n  state.raw = [];\n  return event;\n}\nfunction decodeSseLine(line, state) {\n  if (line === \"\") {\n    return flushSseEvent(state);\n  }\n  state.raw.push(line);\n  if (line.startsWith(\":\")) {\n    return null;\n  }\n  const delimiterIndex = line.indexOf(\":\");\n  const fieldName = delimiterIndex === -1 ? line : line.slice(0, delimiterIndex);\n  let value = delimiterIndex === -1 ? \"\" : line.slice(delimiterIndex + 1);\n  if (value.startsWith(\" \")) {\n    value = value.slice(1);\n  }\n  if (fieldName === \"event\") {\n    state.event = value;\n  } else if (fieldName === \"data\") {\n    state.data.push(value);\n  }\n  return null;\n}\nfunction nextLineBreakIndex(text) {\n  const carriageReturnIndex = text.indexOf(\"\\r\");\n  const newlineIndex = text.indexOf(\"\\n\");\n  if (carriageReturnIndex === -1) {\n    return newlineIndex;\n  }\n  if (newlineIndex === -1) {\n    return carriageReturnIndex;\n  }\n  return Math.min(carriageReturnIndex, newlineIndex);\n}\nfunction consumeLine(text) {\n  const lineBreakIndex = nextLineBreakIndex(text);\n  if (lineBreakIndex === -1) {\n    return null;\n  }\n  let nextIndex = lineBreakIndex + 1;\n  if (text[lineBreakIndex] === \"\\r\" && text[nextIndex] === \"\\n\") {\n    nextIndex += 1;\n  }\n  return {\n    line: text.slice(0, lineBreakIndex),\n    rest: text.slice(nextIndex)\n  };\n}\nasync function* iterateSseMessages(body, signal) {\n  const reader = body.getReader();\n  const decoder = new TextDecoder();\n  const state = { event: null, data: [], raw: [] };\n  let buffer = \"\";\n  try {\n    while (true) {\n      if (signal?.aborted) {\n        throw new Error(\"Request was aborted\");\n      }\n      const { value, done } = await reader.read();\n      if (done) {\n        break;\n      }\n      buffer += decoder.decode(value, { stream: true });\n      let consumed2 = consumeLine(buffer);\n      while (consumed2) {\n        buffer = consumed2.rest;\n        const event = decodeSseLine(consumed2.line, state);\n        if (event) {\n          yield event;\n        }\n        consumed2 = consumeLine(buffer);\n      }\n    }\n    buffer += decoder.decode();\n    let consumed = consumeLine(buffer);\n    while (consumed) {\n      buffer = consumed.rest;\n      const event = decodeSseLine(consumed.line, state);\n      if (event) {\n        yield event;\n      }\n      consumed = consumeLine(buffer);\n    }\n    if (buffer.length > 0) {\n      const event = decodeSseLine(buffer, state);\n      if (event) {\n        yield event;\n      }\n    }\n    const trailingEvent = flushSseEvent(state);\n    if (trailingEvent) {\n      yield trailingEvent;\n    }\n  } finally {\n    reader.releaseLock();\n  }\n}\nasync function* iterateAnthropicEvents(response, signal) {\n  if (!response.body) {\n    throw new Error(\"Attempted to iterate over an Anthropic response with no body\");\n  }\n  let sawMessageStart = false;\n  let sawMessageEnd = false;\n  for await (const sse of iterateSseMessages(response.body, signal)) {\n    if (sse.event === \"error\") {\n      throw new Error(sse.data);\n    }\n    if (!ANTHROPIC_MESSAGE_EVENTS.has(sse.event ?? \"\")) {\n      continue;\n    }\n    try {\n      const event = parseJsonWithRepair(sse.data);\n      if (event.type === \"message_start\") {\n        sawMessageStart = true;\n      } else if (event.type === \"message_stop\") {\n        sawMessageEnd = true;\n      }\n      yield event;\n    } catch (error) {\n      const message = error instanceof Error ? error.message : String(error);\n      throw new Error(`Could not parse Anthropic SSE event ${sse.event}: ${message}; data=${sse.data}; raw=${sse.raw.join(\"\\\\n\")}`);\n    }\n  }\n  if (sawMessageStart && !sawMessageEnd) {\n    throw new Error(\"Anthropic stream ended before message_stop\");\n  }\n}\nfunction mapThinkingLevelToEffort(model, level) {\n  const mapped = level ? model.thinkingLevelMap?.[level] : void 0;\n  if (typeof mapped === \"string\")\n    return mapped;\n  switch (level) {\n    case \"minimal\":\n    case \"low\":\n      return \"low\";\n    case \"medium\":\n      return \"medium\";\n    case \"high\":\n      return \"high\";\n    default:\n      return \"high\";\n  }\n}\nfunction isOAuthToken(apiKey) {\n  return apiKey.includes(\"sk-ant-oat\");\n}\nfunction createClient2(model, apiKey, interleavedThinking, useFineGrainedToolStreamingBeta, optionsHeaders, fetch2, dynamicHeaders, sessionId) {\n  const needsInterleavedBeta = interleavedThinking && model.compat?.forceAdaptiveThinking !== true;\n  const betaFeatures = [];\n  if (useFineGrainedToolStreamingBeta) {\n    betaFeatures.push(FINE_GRAINED_TOOL_STREAMING_BETA);\n  }\n  if (needsInterleavedBeta) {\n    betaFeatures.push(INTERLEAVED_THINKING_BETA);\n  }\n  if (model.provider === \"github-copilot\") {\n    const client2 = new Anthropic({\n      apiKey: null,\n      authToken: apiKey ?? null,\n      baseURL: model.baseUrl,\n      dangerouslyAllowBrowser: true,\n      fetch: fetch2,\n      defaultHeaders: mergeClientHeaders(model, {\n        accept: \"application/json\",\n        \"anthropic-dangerous-direct-browser-access\": \"true\",\n        ...betaFeatures.length > 0 ? { \"anthropic-beta\": betaFeatures.join(\",\") } : {}\n      }, model.headers, dynamicHeaders, optionsHeaders)\n    });\n    return { client: client2, isOAuthToken: false };\n  }\n  if (apiKey && isOAuthToken(apiKey)) {\n    const client2 = new Anthropic({\n      apiKey: null,\n      authToken: apiKey,\n      baseURL: model.baseUrl,\n      dangerouslyAllowBrowser: true,\n      fetch: fetch2,\n      defaultHeaders: mergeClientHeaders(model, {\n        accept: \"application/json\",\n        \"anthropic-dangerous-direct-browser-access\": \"true\",\n        \"anthropic-beta\": [\"claude-code-20250219\", \"oauth-2025-04-20\", ...betaFeatures].join(\",\"),\n        \"user-agent\": `claude-cli/${claudeCodeVersion}`,\n        \"x-app\": \"cli\"\n      }, model.headers, optionsHeaders)\n    });\n    return { client: client2, isOAuthToken: true };\n  }\n  const sessionAffinityHeaders = sessionId && getAnthropicCompat(model).sendSessionAffinityHeaders ? { \"x-session-affinity\": sessionId } : {};\n  const defaultHeaders = mergeClientHeaders(model, {\n    accept: \"application/json\",\n    \"anthropic-dangerous-direct-browser-access\": \"true\",\n    ...betaFeatures.length > 0 ? { \"anthropic-beta\": betaFeatures.join(\",\") } : {}\n  }, sessionAffinityHeaders, model.headers, optionsHeaders);\n  const client = new Anthropic({\n    apiKey: apiKey ?? null,\n    authToken: null,\n    baseURL: model.baseUrl,\n    dangerouslyAllowBrowser: true,\n    fetch: fetch2,\n    defaultHeaders\n  });\n  return { client, isOAuthToken: false };\n}\nfunction buildParams2(model, context, isOAuthToken2, options) {\n  const { cacheControl } = getCacheControl(model, options?.cacheRetention, options?.env);\n  const compat = getAnthropicCompat(model);\n  const transformedMessages = transformMessages(context.messages, model, normalizeToolCallId);\n  const normalizeToolName = isOAuthToken2 ? toClaudeCodeName : (name) => name;\n  const toolPlacement = splitDeferredTools({ ...context, messages: transformedMessages }, compat.supportsToolReferences, normalizeToolName);\n  let immediateTools = toolPlacement.immediate;\n  let deferredTools = [...toolPlacement.deferred.values()];\n  if (immediateTools.length === 0 && deferredTools.length > 0) {\n    immediateTools = deferredTools;\n    deferredTools = [];\n  }\n  const deferredToolNames = new Set(deferredTools.map((tool) => normalizeToolName(tool.name)));\n  const params = {\n    model: model.id,\n    messages: convertMessages2(transformedMessages, isOAuthToken2, cacheControl, compat.allowEmptySignature, deferredToolNames, normalizeToolName),\n    max_tokens: options?.maxTokens ?? model.maxTokens,\n    stream: true\n  };\n  if (isOAuthToken2) {\n    params.system = [\n      {\n        type: \"text\",\n        text: \"You are Claude Code, Anthropic's official CLI for Claude.\",\n        ...cacheControl ? { cache_control: cacheControl } : {}\n      }\n    ];\n    if (context.systemPrompt) {\n      params.system.push({\n        type: \"text\",\n        text: sanitizeSurrogates(context.systemPrompt),\n        ...cacheControl ? { cache_control: cacheControl } : {}\n      });\n    }\n  } else if (context.systemPrompt) {\n    params.system = [\n      {\n        type: \"text\",\n        text: sanitizeSurrogates(context.systemPrompt),\n        ...cacheControl ? { cache_control: cacheControl } : {}\n      }\n    ];\n  }\n  if (options?.temperature !== void 0 && !options?.thinkingEnabled && compat.supportsTemperature) {\n    params.temperature = options.temperature;\n  }\n  if (immediateTools.length > 0 || deferredTools.length > 0) {\n    params.tools = [\n      ...convertTools2(immediateTools, isOAuthToken2, compat.supportsEagerToolInputStreaming, compat.supportsStrictTools, compat.supportsCacheControlOnTools ? cacheControl : void 0),\n      ...convertTools2(deferredTools, isOAuthToken2, compat.supportsEagerToolInputStreaming, compat.supportsStrictTools, void 0, true)\n    ];\n  }\n  if (model.reasoning) {\n    if (options?.thinkingEnabled) {\n      const display = options.thinkingDisplay ?? \"summarized\";\n      if (model.compat?.forceAdaptiveThinking === true) {\n        params.thinking = { type: \"adaptive\", display };\n        if (options.effort) {\n          params.output_config = options.effort === \"xhigh\" ? { effort: options.effort } : { effort: options.effort };\n        }\n      } else {\n        params.thinking = {\n          type: \"enabled\",\n          budget_tokens: options.thinkingBudgetTokens || 1024,\n          display\n        };\n      }\n    } else if (options?.thinkingEnabled === false && model.thinkingLevelMap?.off !== null) {\n      params.thinking = { type: \"disabled\" };\n    }\n  }\n  if (options?.metadata) {\n    const userId = options.metadata.user_id;\n    if (typeof userId === \"string\") {\n      params.metadata = { user_id: userId };\n    }\n  }\n  if (options?.toolChoice) {\n    if (typeof options.toolChoice === \"string\") {\n      params.tool_choice = { type: options.toolChoice };\n    } else {\n      params.tool_choice = options.toolChoice;\n    }\n  }\n  return params;\n}\nfunction normalizeToolCallId(id) {\n  return id.replace(/[^a-zA-Z0-9_-]/g, \"_\").slice(0, 64);\n}\nfunction convertToolResult(msg, isOAuthToken2, deferredToolNames, loadedToolNames, normalizeToolName) {\n  const references = [];\n  for (const name of msg.addedToolNames ?? []) {\n    const normalizedName = normalizeToolName(name);\n    if (!deferredToolNames.has(normalizedName) || loadedToolNames.has(normalizedName))\n      continue;\n    loadedToolNames.add(normalizedName);\n    references.push({\n      type: \"tool_reference\",\n      tool_name: isOAuthToken2 ? toClaudeCodeName(name) : name\n    });\n  }\n  const convertedContent = convertContentBlocks(msg.content);\n  return {\n    toolResult: {\n      type: \"tool_result\",\n      tool_use_id: msg.toolCallId,\n      content: references.length > 0 ? references : convertedContent,\n      is_error: msg.isError\n    },\n    siblingContent: references.length === 0 ? [] : typeof convertedContent === \"string\" ? [{ type: \"text\", text: convertedContent }] : convertedContent\n  };\n}\nfunction convertMessages2(transformedMessages, isOAuthToken2, cacheControl, allowEmptySignature = false, deferredToolNames = /* @__PURE__ */ new Set(), normalizeToolName = (name) => name) {\n  const params = [];\n  const loadedToolNames = /* @__PURE__ */ new Set();\n  for (let i = 0; i < transformedMessages.length; i++) {\n    const msg = transformedMessages[i];\n    if (msg.role === \"user\") {\n      if (typeof msg.content === \"string\") {\n        if (msg.content.trim().length > 0) {\n          params.push({\n            role: \"user\",\n            content: sanitizeSurrogates(msg.content)\n          });\n        }\n      } else {\n        const blocks = msg.content.map((item) => {\n          if (item.type === \"text\") {\n            return {\n              type: \"text\",\n              text: sanitizeSurrogates(item.text)\n            };\n          } else {\n            return {\n              type: \"image\",\n              source: {\n                type: \"base64\",\n                media_type: item.mimeType,\n                data: item.data\n              }\n            };\n          }\n        });\n        const filteredBlocks = blocks.filter((b) => {\n          if (b.type === \"text\") {\n            return b.text.trim().length > 0;\n          }\n          return true;\n        });\n        if (filteredBlocks.length === 0)\n          continue;\n        params.push({\n          role: \"user\",\n          content: filteredBlocks\n        });\n      }\n    } else if (msg.role === \"assistant\") {\n      const blocks = [];\n      for (const block of msg.content) {\n        if (block.type === \"text\") {\n          if (block.text.trim().length === 0)\n            continue;\n          blocks.push({\n            type: \"text\",\n            text: sanitizeSurrogates(block.text)\n          });\n        } else if (block.type === \"thinking\") {\n          if (block.redacted) {\n            blocks.push({\n              type: \"redacted_thinking\",\n              data: block.thinkingSignature\n            });\n            continue;\n          }\n          const thinkingSignature = block.thinkingSignature;\n          const hasThinkingSignature = !!thinkingSignature && thinkingSignature.trim().length > 0;\n          if (block.thinking.trim().length === 0 && !hasThinkingSignature)\n            continue;\n          if (!hasThinkingSignature) {\n            blocks.push(allowEmptySignature ? {\n              type: \"thinking\",\n              thinking: sanitizeSurrogates(block.thinking),\n              signature: \"\"\n            } : {\n              type: \"text\",\n              text: sanitizeSurrogates(block.thinking)\n            });\n          } else {\n            blocks.push({\n              type: \"thinking\",\n              thinking: sanitizeSurrogates(block.thinking),\n              signature: thinkingSignature\n            });\n          }\n        } else if (block.type === \"toolCall\") {\n          blocks.push({\n            type: \"tool_use\",\n            id: block.id,\n            name: isOAuthToken2 ? toClaudeCodeName(block.name) : block.name,\n            input: block.arguments ?? {}\n          });\n        }\n      }\n      if (blocks.length === 0)\n        continue;\n      params.push({\n        role: \"assistant\",\n        content: blocks\n      });\n    } else if (msg.role === \"toolResult\") {\n      const toolResults = [];\n      const siblingContent = [];\n      let j = i;\n      while (j < transformedMessages.length && transformedMessages[j].role === \"toolResult\") {\n        const converted = convertToolResult(transformedMessages[j], isOAuthToken2, deferredToolNames, loadedToolNames, normalizeToolName);\n        toolResults.push(converted.toolResult);\n        siblingContent.push(...converted.siblingContent);\n        j++;\n      }\n      i = j - 1;\n      params.push({\n        role: \"user\",\n        content: [...toolResults, ...siblingContent]\n      });\n    }\n  }\n  if (cacheControl && params.length > 0) {\n    const lastMessage = params[params.length - 1];\n    if (lastMessage.role === \"user\") {\n      if (Array.isArray(lastMessage.content)) {\n        const lastBlock = lastMessage.content[lastMessage.content.length - 1];\n        if (lastBlock && (lastBlock.type === \"text\" || lastBlock.type === \"image\" || lastBlock.type === \"tool_result\")) {\n          lastBlock.cache_control = cacheControl;\n        }\n      } else if (typeof lastMessage.content === \"string\") {\n        lastMessage.content = [\n          {\n            type: \"text\",\n            text: lastMessage.content,\n            cache_control: cacheControl\n          }\n        ];\n      }\n    }\n  }\n  return params;\n}\nfunction shouldUseFineGrainedToolStreamingBeta(model, context) {\n  return !!context.tools?.length && !getAnthropicCompat(model).supportsEagerToolInputStreaming;\n}\nfunction convertTools2(tools, isOAuthToken2, supportsEagerToolInputStreaming, supportsStrictTools, cacheControl, deferLoading = false) {\n  if (!tools)\n    return [];\n  return tools.map((tool, index) => {\n    const strict = resolveJsonSchemaStrictSampling(tool, supportsStrictTools);\n    const parameters = getJsonSchemaToolParameters(tool, strict);\n    const schema = parameters;\n    const legacyInputSchema = {\n      type: \"object\",\n      properties: schema.properties ?? {},\n      required: schema.required ?? []\n    };\n    const inputSchema = strict === true ? {\n      ...parameters,\n      ...legacyInputSchema\n    } : legacyInputSchema;\n    return {\n      name: isOAuthToken2 ? toClaudeCodeName(tool.name) : tool.name,\n      description: tool.description,\n      ...supportsEagerToolInputStreaming ? { eager_input_streaming: true } : {},\n      ...strict === true ? { strict: true } : {},\n      input_schema: inputSchema,\n      ...deferLoading ? { defer_loading: true } : {},\n      ...cacheControl && index === tools.length - 1 ? { cache_control: cacheControl } : {}\n    };\n  });\n}\nfunction mapStopReason2(reason, stopDetails) {\n  switch (reason) {\n    case \"end_turn\":\n      return { stopReason: \"stop\" };\n    case \"max_tokens\":\n      return { stopReason: \"length\" };\n    case \"tool_use\":\n      return { stopReason: \"toolUse\" };\n    case \"refusal\":\n      return {\n        stopReason: \"error\",\n        errorMessage: stopDetails?.explanation || `The model refused to complete the request`\n      };\n    case \"pause_turn\":\n      return { stopReason: \"stop\" };\n    case \"stop_sequence\":\n      return { stopReason: \"stop\" };\n    // We don't supply stop sequences, so this should never happen\n    case \"sensitive\":\n      return { stopReason: \"error\", errorMessage: \"Provider stopped with: sensitive\" };\n    default:\n      throw new Error(`Unhandled stop reason: ${reason}`);\n  }\n}\nvar claudeCodeVersion, claudeCodeTools, ccToolLookup, toClaudeCodeName, fromClaudeCodeName, FINE_GRAINED_TOOL_STREAMING_BETA, INTERLEAVED_THINKING_BETA, ANTHROPIC_MESSAGE_EVENTS, stream2, streamSimple2;\nvar init_anthropic_messages = __esm({\n  \"node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/api/anthropic-messages.js\"() {\n    init_anthropic();\n    init_models();\n    init_deferred_tools();\n    init_event_stream();\n    init_headers();\n    init_json_parse();\n    init_pi_user_agent();\n    init_provider_env();\n    init_provider_retry();\n    init_sanitize_unicode();\n    init_constrained_sampling();\n    init_github_copilot_headers();\n    init_simple_options();\n    init_transform_messages();\n    claudeCodeVersion = \"2.1.75\";\n    claudeCodeTools = [\n      \"Read\",\n      \"Write\",\n      \"Edit\",\n      \"Bash\",\n      \"Grep\",\n      \"Glob\",\n      \"AskUserQuestion\",\n      \"EnterPlanMode\",\n      \"ExitPlanMode\",\n      \"KillShell\",\n      \"NotebookEdit\",\n      \"Skill\",\n      \"Task\",\n      \"TaskOutput\",\n      \"TodoWrite\",\n      \"WebFetch\",\n      \"WebSearch\"\n    ];\n    ccToolLookup = new Map(claudeCodeTools.map((t) => [t.toLowerCase(), t]));\n    toClaudeCodeName = (name) => ccToolLookup.get(name.toLowerCase()) ?? name;\n    fromClaudeCodeName = (name, tools) => {\n      if (tools && tools.length > 0) {\n        const lowerName = name.toLowerCase();\n        const matchedTool = tools.find((tool) => tool.name.toLowerCase() === lowerName);\n        if (matchedTool)\n          return matchedTool.name;\n      }\n      return name;\n    };\n    FINE_GRAINED_TOOL_STREAMING_BETA = \"fine-grained-tool-streaming-2025-05-14\";\n    INTERLEAVED_THINKING_BETA = \"interleaved-thinking-2025-05-14\";\n    ANTHROPIC_MESSAGE_EVENTS = /* @__PURE__ */ new Set([\n      \"message_start\",\n      \"message_delta\",\n      \"message_stop\",\n      \"content_block_start\",\n      \"content_block_delta\",\n      \"content_block_stop\"\n    ]);\n    stream2 = (model, context, options) => {\n      const stream11 = new AssistantMessageEventStream();\n      (async () => {\n        const output = {\n          role: \"assistant\",\n          content: [],\n          api: model.api,\n          provider: model.provider,\n          model: model.id,\n          usage: {\n            input: 0,\n            output: 0,\n            cacheRead: 0,\n            cacheWrite: 0,\n            totalTokens: 0,\n            cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 }\n          },\n          stopReason: \"pending\",\n          timestamp: Date.now()\n        };\n        try {\n          let client;\n          let isOAuth;\n          if (options?.client) {\n            client = options.client;\n            isOAuth = false;\n          } else {\n            const apiKey = options?.apiKey;\n            assertRequestAuth(model.provider, apiKey, options?.headers);\n            let copilotDynamicHeaders;\n            if (model.provider === \"github-copilot\") {\n              const hasImages = hasCopilotVisionInput(context.messages);\n              copilotDynamicHeaders = buildCopilotDynamicHeaders({\n                messages: context.messages,\n                hasImages\n              });\n            }\n            const cacheRetention = resolveCacheRetention2(options?.cacheRetention, options?.env);\n            const cacheSessionId = cacheRetention === \"none\" ? void 0 : options?.sessionId;\n            const created = createClient2(model, apiKey, options?.interleavedThinking ?? true, shouldUseFineGrainedToolStreamingBeta(model, context), options?.headers, options?.fetch, copilotDynamicHeaders, cacheSessionId);\n            client = created.client;\n            isOAuth = created.isOAuthToken;\n          }\n          let params = buildParams2(model, context, isOAuth, options);\n          const nextParams = await options?.onPayload?.(params, model);\n          if (nextParams !== void 0) {\n            params = nextParams;\n          }\n          const requestOptions = {\n            ...options?.signal ? { signal: options.signal } : {},\n            ...options?.timeoutMs !== void 0 ? { timeout: options.timeoutMs } : {},\n            maxRetries: 0\n          };\n          const response = await retryProviderRequest(() => client.messages.create({ ...params, stream: true }, requestOptions).asResponse(), {\n            maxRetries: options?.maxRetries,\n            maxRetryDelayMs: options?.maxRetryDelayMs,\n            signal: options?.signal\n          });\n          await options?.onResponse?.({ status: response.status, headers: headersToRecord(response.headers) }, model);\n          stream11.push({ type: \"start\", partial: output });\n          const blocks = output.content;\n          for await (const event of iterateAnthropicEvents(response, options?.signal)) {\n            if (event.type === \"message_start\") {\n              output.responseId = event.message.id;\n              output.usage.input = event.message.usage.input_tokens || 0;\n              output.usage.output = event.message.usage.output_tokens || 0;\n              output.usage.cacheRead = event.message.usage.cache_read_input_tokens || 0;\n              output.usage.cacheWrite = event.message.usage.cache_creation_input_tokens || 0;\n              output.usage.cacheWrite1h = event.message.usage.cache_creation?.ephemeral_1h_input_tokens || 0;\n              output.usage.totalTokens = output.usage.input + output.usage.output + output.usage.cacheRead + output.usage.cacheWrite;\n              calculateCost(model, output.usage);\n            } else if (event.type === \"content_block_start\") {\n              if (event.content_block.type === \"text\") {\n                const block = {\n                  type: \"text\",\n                  text: event.content_block.text ?? \"\",\n                  index: event.index\n                };\n                output.content.push(block);\n                stream11.push({ type: \"text_start\", contentIndex: output.content.length - 1, partial: output });\n              } else if (event.content_block.type === \"thinking\") {\n                const block = {\n                  type: \"thinking\",\n                  thinking: event.content_block.thinking ?? \"\",\n                  thinkingSignature: event.content_block.signature ?? \"\",\n                  index: event.index\n                };\n                output.content.push(block);\n                stream11.push({ type: \"thinking_start\", contentIndex: output.content.length - 1, partial: output });\n              } else if (event.content_block.type === \"redacted_thinking\") {\n                const block = {\n                  type: \"thinking\",\n                  thinking: \"[Reasoning redacted]\",\n                  thinkingSignature: event.content_block.data,\n                  redacted: true,\n                  index: event.index\n                };\n                output.content.push(block);\n                stream11.push({ type: \"thinking_start\", contentIndex: output.content.length - 1, partial: output });\n              } else if (event.content_block.type === \"tool_use\") {\n                const block = {\n                  type: \"toolCall\",\n                  id: event.content_block.id,\n                  name: isOAuth ? fromClaudeCodeName(event.content_block.name, context.tools) : event.content_block.name,\n                  arguments: event.content_block.input ?? {},\n                  partialJson: \"\",\n                  index: event.index\n                };\n                output.content.push(block);\n                stream11.push({ type: \"toolcall_start\", contentIndex: output.content.length - 1, partial: output });\n              }\n            } else if (event.type === \"content_block_delta\") {\n              if (event.delta.type === \"text_delta\") {\n                const index = blocks.findIndex((b) => b.index === event.index);\n                const block = blocks[index];\n                if (block && block.type === \"text\") {\n                  block.text += event.delta.text;\n                  stream11.push({\n                    type: \"text_delta\",\n                    contentIndex: index,\n                    delta: event.delta.text,\n                    partial: output\n                  });\n                }\n              } else if (event.delta.type === \"thinking_delta\") {\n                const index = blocks.findIndex((b) => b.index === event.index);\n                const block = blocks[index];\n                if (block && block.type === \"thinking\") {\n                  block.thinking += event.delta.thinking;\n                  stream11.push({\n                    type: \"thinking_delta\",\n                    contentIndex: index,\n                    delta: event.delta.thinking,\n                    partial: output\n                  });\n                }\n              } else if (event.delta.type === \"input_json_delta\") {\n                const index = blocks.findIndex((b) => b.index === event.index);\n                const block = blocks[index];\n                if (block && block.type === \"toolCall\") {\n                  block.partialJson += event.delta.partial_json;\n                  block.arguments = parseStreamingJson(block.partialJson);\n                  stream11.push({\n                    type: \"toolcall_delta\",\n                    contentIndex: index,\n                    delta: event.delta.partial_json,\n                    partial: output\n                  });\n                }\n              } else if (event.delta.type === \"signature_delta\") {\n                const index = blocks.findIndex((b) => b.index === event.index);\n                const block = blocks[index];\n                if (block && block.type === \"thinking\") {\n                  block.thinkingSignature = block.thinkingSignature || \"\";\n                  block.thinkingSignature += event.delta.signature;\n                }\n              }\n            } else if (event.type === \"content_block_stop\") {\n              const index = blocks.findIndex((b) => b.index === event.index);\n              const block = blocks[index];\n              if (block) {\n                delete block.index;\n                if (block.type === \"text\") {\n                  stream11.push({\n                    type: \"text_end\",\n                    contentIndex: index,\n                    content: block.text,\n                    partial: output\n                  });\n                } else if (block.type === \"thinking\") {\n                  stream11.push({\n                    type: \"thinking_end\",\n                    contentIndex: index,\n                    content: block.thinking,\n                    partial: output\n                  });\n                } else if (block.type === \"toolCall\") {\n                  block.arguments = parseStreamingJson(block.partialJson);\n                  delete block.partialJson;\n                  stream11.push({\n                    type: \"toolcall_end\",\n                    contentIndex: index,\n                    toolCall: block,\n                    partial: output\n                  });\n                }\n              }\n            } else if (event.type === \"message_delta\") {\n              if (event.delta.stop_reason) {\n                output.rawStopReason = event.delta.stop_reason;\n                const stopReasonResult = mapStopReason2(event.delta.stop_reason, event.delta.stop_details);\n                output.stopReason = stopReasonResult.stopReason;\n                if (stopReasonResult.errorMessage) {\n                  output.errorMessage = stopReasonResult.errorMessage;\n                }\n              }\n              if (event.usage) {\n                if (event.usage.input_tokens != null) {\n                  output.usage.input = event.usage.input_tokens;\n                }\n                if (event.usage.output_tokens != null) {\n                  output.usage.output = event.usage.output_tokens;\n                }\n                if (event.usage.cache_read_input_tokens != null) {\n                  output.usage.cacheRead = event.usage.cache_read_input_tokens;\n                }\n                if (event.usage.cache_creation_input_tokens != null) {\n                  output.usage.cacheWrite = event.usage.cache_creation_input_tokens;\n                }\n                const thinkingTokens = event.usage.output_tokens_details?.thinking_tokens;\n                if (thinkingTokens != null) {\n                  output.usage.reasoning = thinkingTokens;\n                }\n              }\n              output.usage.totalTokens = output.usage.input + output.usage.output + output.usage.cacheRead + output.usage.cacheWrite;\n              calculateCost(model, output.usage);\n            }\n          }\n          if (options?.signal?.aborted) {\n            throw new Error(\"Request was aborted\");\n          }\n          if (output.stopReason === \"pending\") {\n            throw new Error(\"Anthropic stream ended without a stop reason\");\n          }\n          if (output.stopReason === \"aborted\" || output.stopReason === \"error\") {\n            throw new Error(output.errorMessage || \"An unknown error occurred\");\n          }\n          stream11.push({ type: \"done\", reason: output.stopReason, message: output });\n          stream11.end();\n        } catch (error) {\n          for (const block of output.content) {\n            delete block.index;\n            delete block.partialJson;\n          }\n          output.stopReason = options?.signal?.aborted ? \"aborted\" : \"error\";\n          output.errorMessage = error instanceof Error ? error.message : JSON.stringify(error);\n          stream11.push({ type: \"error\", reason: output.stopReason, error: output });\n          stream11.end();\n        }\n      })();\n      return stream11;\n    };\n    streamSimple2 = (model, context, options) => {\n      assertRequestAuth(model.provider, options?.apiKey, options?.headers);\n      const base = buildBaseOptions(model, context, options, options?.apiKey);\n      if (!options?.reasoning) {\n        return stream2(model, context, { ...base, thinkingEnabled: false });\n      }\n      if (model.compat?.forceAdaptiveThinking === true) {\n        const effort = mapThinkingLevelToEffort(model, options.reasoning);\n        return stream2(model, context, {\n          ...base,\n          thinkingEnabled: true,\n          effort\n        });\n      }\n      const adjusted = adjustMaxTokensForThinking(base.maxTokens, model.maxTokens, options.reasoning, options.thinkingBudgets);\n      const maxTokens = clampMaxTokensToContext(model, context, adjusted.maxTokens);\n      return stream2(model, context, {\n        ...base,\n        maxTokens,\n        thinkingEnabled: true,\n        thinkingBudgetTokens: Math.min(adjusted.thinkingBudget, Math.max(0, maxTokens - 1024))\n      });\n    };\n  }\n});\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/api/openai-responses-shared.js\nfunction encodeTextSignatureV1(id, phase) {\n  const payload = { v: 1, id };\n  if (phase)\n    payload.phase = phase;\n  return JSON.stringify(payload);\n}\nfunction parseTextSignature(signature) {\n  if (!signature)\n    return void 0;\n  if (signature.startsWith(\"{\")) {\n    try {\n      const parsed = JSON.parse(signature);\n      if (parsed.v === 1 && typeof parsed.id === \"string\") {\n        if (parsed.phase === \"commentary\" || parsed.phase === \"final_answer\") {\n          return { id: parsed.id, phase: parsed.phase };\n        }\n        return { id: parsed.id };\n      }\n    } catch {\n    }\n  }\n  return { id: signature };\n}\nfunction convertToolResultOutput(model, content) {\n  const textResult = content.filter((c) => c.type === \"text\").map((c) => c.text).join(\"\\n\");\n  const images = content.filter((c) => c.type === \"image\");\n  const hasText = textResult.length > 0;\n  if (images.length === 0 || !model.input.includes(\"image\")) {\n    return sanitizeSurrogates(hasText ? textResult : images.length > 0 ? \"(see attached image)\" : \"(no tool output)\");\n  }\n  const output = [];\n  if (hasText) {\n    output.push({ type: \"input_text\", text: sanitizeSurrogates(textResult) });\n  }\n  for (const image of images) {\n    output.push({\n      type: \"input_image\",\n      detail: \"auto\",\n      image_url: `data:${image.mimeType};base64,${image.data}`\n    });\n  }\n  return output;\n}\nfunction convertResponsesMessages(model, context, allowedToolCallProviders, options) {\n  const messages = [];\n  const loadedToolNames = /* @__PURE__ */ new Set();\n  const normalizeIdPart = (part) => {\n    const sanitized = part.replace(/[^a-zA-Z0-9_-]/g, \"_\");\n    const normalized = sanitized.length > 64 ? sanitized.slice(0, 64) : sanitized;\n    return normalized.replace(/_+$/, \"\");\n  };\n  const buildForeignResponsesItemId = (itemId) => {\n    const normalized = `fc_${shortHash(itemId)}`;\n    return normalized.length > 64 ? normalized.slice(0, 64) : normalized;\n  };\n  const normalizeToolCallId2 = (id, _targetModel, source) => {\n    if (!allowedToolCallProviders.has(model.provider))\n      return normalizeIdPart(id);\n    if (!id.includes(\"|\"))\n      return normalizeIdPart(id);\n    const [callId, itemId] = id.split(\"|\");\n    const normalizedCallId = normalizeIdPart(callId);\n    const isForeignToolCall = source.provider !== model.provider || source.api !== model.api;\n    let normalizedItemId = isForeignToolCall ? buildForeignResponsesItemId(itemId) : normalizeIdPart(itemId);\n    if (!normalizedItemId.startsWith(\"fc_\")) {\n      normalizedItemId = normalizeIdPart(`fc_${normalizedItemId}`);\n    }\n    return `${normalizedCallId}|${normalizedItemId}`;\n  };\n  const transformedMessages = transformMessages(context.messages, model, normalizeToolCallId2);\n  const includeSystemPrompt = options?.includeSystemPrompt ?? true;\n  if (includeSystemPrompt && context.systemPrompt) {\n    const compat = model.compat;\n    const role = model.reasoning && compat?.supportsDeveloperRole !== false ? \"developer\" : \"system\";\n    messages.push({\n      role,\n      content: sanitizeSurrogates(context.systemPrompt)\n    });\n  }\n  let msgIndex = 0;\n  for (const msg of transformedMessages) {\n    if (msg.role === \"user\") {\n      if (typeof msg.content === \"string\") {\n        messages.push({\n          role: \"user\",\n          content: [{ type: \"input_text\", text: sanitizeSurrogates(msg.content) }]\n        });\n      } else {\n        const content = msg.content.map((item) => {\n          if (item.type === \"text\") {\n            return {\n              type: \"input_text\",\n              text: sanitizeSurrogates(item.text)\n            };\n          }\n          return {\n            type: \"input_image\",\n            detail: \"auto\",\n            image_url: `data:${item.mimeType};base64,${item.data}`\n          };\n        });\n        if (content.length === 0)\n          continue;\n        messages.push({\n          role: \"user\",\n          content\n        });\n      }\n    } else if (msg.role === \"assistant\") {\n      const output = [];\n      const assistantMsg = msg;\n      const isSameProviderAndApi = assistantMsg.provider === model.provider && assistantMsg.api === model.api;\n      const isSameModel = isSameProviderAndApi && assistantMsg.model === model.id;\n      const isDifferentModel = isSameProviderAndApi && assistantMsg.model !== model.id;\n      let textBlockIndex = 0;\n      for (const block of msg.content) {\n        if (block.type === \"thinking\") {\n          if (block.thinkingSignature) {\n            const reasoningItem = JSON.parse(block.thinkingSignature);\n            output.push(reasoningItem);\n          }\n        } else if (block.type === \"text\") {\n          const textBlock = block;\n          const parsedSignature = parseTextSignature(textBlock.textSignature);\n          const fallbackMessageId = textBlockIndex === 0 ? `msg_pi_${msgIndex}` : `msg_pi_${msgIndex}_${textBlockIndex}`;\n          textBlockIndex++;\n          let msgId = parsedSignature?.id;\n          if (!msgId) {\n            msgId = fallbackMessageId;\n          } else if (msgId.length > 64) {\n            msgId = `msg_${shortHash(msgId)}`;\n          }\n          output.push({\n            type: \"message\",\n            role: \"assistant\",\n            content: [{ type: \"output_text\", text: sanitizeSurrogates(textBlock.text), annotations: [] }],\n            status: \"completed\",\n            id: msgId,\n            phase: parsedSignature?.phase\n          });\n        } else if (block.type === \"toolCall\") {\n          const toolCall = block;\n          const [callId, itemIdRaw] = toolCall.id.split(\"|\");\n          const customInputProperty = options?.grammarToolInputProperties?.get(toolCall.name);\n          let itemId = itemIdRaw;\n          if (isDifferentModel && itemId?.startsWith(\"fc_\") || customInputProperty === void 0 && !itemId?.startsWith(\"fc_\")) {\n            itemId = void 0;\n          }\n          const canReplayNamespace = isSameModel || options?.deferredTools?.has(toolCall.name) === true;\n          if (customInputProperty !== void 0) {\n            output.push({\n              type: \"custom_tool_call\",\n              id: itemId,\n              call_id: callId,\n              name: toolCall.name,\n              input: sanitizeSurrogates(getGrammarToolInput(toolCall.name, toolCall.arguments, customInputProperty)),\n              ...canReplayNamespace && toolCall.namespace !== void 0 ? { namespace: toolCall.namespace } : {}\n            });\n          } else {\n            output.push({\n              type: \"function_call\",\n              id: itemId,\n              call_id: callId,\n              name: toolCall.name,\n              arguments: JSON.stringify(toolCall.arguments),\n              ...canReplayNamespace && toolCall.namespace !== void 0 ? { namespace: toolCall.namespace } : {}\n            });\n          }\n        }\n      }\n      if (output.length === 0)\n        continue;\n      messages.push(...output);\n    } else if (msg.role === \"toolResult\") {\n      const [callId] = msg.toolCallId.split(\"|\");\n      const output = convertToolResultOutput(model, msg.content);\n      if (options?.grammarToolInputProperties?.has(msg.toolName)) {\n        messages.push({\n          type: \"custom_tool_call_output\",\n          call_id: callId,\n          output\n        });\n      } else {\n        messages.push({\n          type: \"function_call_output\",\n          call_id: callId,\n          output\n        });\n      }\n      const deferredTools = [];\n      for (const name of msg.addedToolNames ?? []) {\n        const tool = options?.deferredTools?.get(name);\n        if (!tool || loadedToolNames.has(name))\n          continue;\n        loadedToolNames.add(name);\n        deferredTools.push(tool);\n      }\n      if (deferredTools.length > 0 && options?.deferredToolsMode === \"additional-tools\") {\n        messages.push({\n          type: \"additional_tools\",\n          role: \"developer\",\n          tools: convertResponsesTools(deferredTools, options.toolOptions)\n        });\n      } else if (deferredTools.length > 0 && options?.deferredToolsMode === \"tool-search\") {\n        const names = deferredTools.map((tool) => tool.name);\n        const searchCallId = `pi_tool_load_${shortHash(`${msg.toolCallId}:${names.join(\",\")}`)}`;\n        messages.push({\n          type: \"tool_search_call\",\n          call_id: searchCallId,\n          execution: \"client\",\n          status: \"completed\",\n          arguments: { query: names.join(\" \"), limit: names.length }\n        });\n        messages.push({\n          type: \"tool_search_output\",\n          call_id: searchCallId,\n          execution: \"client\",\n          status: \"completed\",\n          tools: convertResponsesTools(deferredTools, {\n            ...options.toolOptions,\n            deferLoading: true\n          })\n        });\n      }\n    }\n    msgIndex++;\n  }\n  return messages;\n}\nfunction convertResponsesTools(tools, options) {\n  const defaultStrict = options?.strict === void 0 ? false : options.strict;\n  const supportsStrictMode = options?.supportsStrictMode ?? true;\n  const supportsOpenAIGrammarTools = options?.supportsOpenAIGrammarTools ?? false;\n  return tools.map((tool) => {\n    const grammar = resolveGrammarConstrainedSampling(tool, supportsOpenAIGrammarTools);\n    if (grammar) {\n      return {\n        type: \"custom\",\n        name: tool.name,\n        description: tool.description,\n        format: {\n          type: \"grammar\",\n          syntax: grammar.format,\n          definition: grammar.definition\n        },\n        ...options?.deferLoading ? { defer_loading: true } : {}\n      };\n    }\n    const constrainedStrict = resolveJsonSchemaStrictSampling(tool, supportsStrictMode);\n    const strict = constrainedStrict ?? defaultStrict;\n    const functionTool = {\n      type: \"function\",\n      name: tool.name,\n      description: tool.description,\n      parameters: getJsonSchemaToolParameters(tool, strict === true),\n      ...options?.deferLoading ? { defer_loading: true } : {}\n    };\n    if (supportsStrictMode) {\n      functionTool.strict = strict;\n    }\n    return functionTool;\n  });\n}\nfunction getCustomToolCallInput(block) {\n  const property = block.customInput?.property;\n  if (property === void 0)\n    return \"\";\n  const value = block.arguments[property];\n  return typeof value === \"string\" ? value : \"\";\n}\nfunction appendCustomToolCallInput(block, nextInput, close) {\n  const customInput = block.customInput;\n  if (!customInput)\n    return void 0;\n  const delta = appendGrammarToolInputJsonDelta(customInput.jsonBuffer, customInput.property, nextInput, close);\n  block.arguments = { [customInput.property]: nextInput };\n  return delta;\n}\nasync function processResponsesStream(openaiStream, output, stream11, model, options) {\n  let sawTerminalResponseEvent = false;\n  const outputSlots = /* @__PURE__ */ new Map();\n  const reasoningBlocksById = /* @__PURE__ */ new Map();\n  const applyMessagePhaseStopReason = (item) => {\n    if (item.type === \"message\" && item.phase === \"final_answer\") {\n      output.stopReason = \"stop\";\n    }\n  };\n  const getSlot = (outputIndex, type) => {\n    const slot = outputSlots.get(outputIndex);\n    return slot?.type === type ? slot : void 0;\n  };\n  const pushToolCallDelta = (slot, delta) => {\n    if (delta === void 0)\n      return;\n    stream11.push({\n      type: \"toolcall_delta\",\n      contentIndex: slot.contentIndex,\n      delta,\n      partial: output\n    });\n  };\n  const createSlot = (outputIndex, item) => {\n    if (item.type === \"reasoning\") {\n      const block = { type: \"thinking\", thinking: \"\" };\n      output.content.push(block);\n      const slot = {\n        type: \"thinking\",\n        block,\n        contentIndex: output.content.length - 1\n      };\n      outputSlots.set(outputIndex, slot);\n      stream11.push({ type: \"thinking_start\", contentIndex: slot.contentIndex, partial: output });\n      return slot;\n    }\n    if (item.type === \"message\") {\n      applyMessagePhaseStopReason(item);\n      const block = { type: \"text\", text: \"\" };\n      output.content.push(block);\n      const slot = { type: \"text\", block, contentIndex: output.content.length - 1 };\n      outputSlots.set(outputIndex, slot);\n      stream11.push({ type: \"text_start\", contentIndex: slot.contentIndex, partial: output });\n      return slot;\n    }\n    if (item.type === \"function_call\") {\n      const block = {\n        type: \"toolCall\",\n        id: `${item.call_id}|${item.id}`,\n        name: item.name,\n        arguments: {},\n        ...item.namespace !== void 0 ? { namespace: item.namespace } : {},\n        partialJson: item.arguments || \"\"\n      };\n      output.content.push(block);\n      const slot = {\n        type: \"toolCall\",\n        block,\n        contentIndex: output.content.length - 1\n      };\n      outputSlots.set(outputIndex, slot);\n      stream11.push({ type: \"toolcall_start\", contentIndex: slot.contentIndex, partial: output });\n      return slot;\n    }\n    if (item.type === \"custom_tool_call\") {\n      const inputProperty = options?.grammarToolInputProperties?.get(item.name) ?? \"input\";\n      const input = item.input || \"\";\n      const block = {\n        type: \"toolCall\",\n        id: `${item.call_id}|${item.id}`,\n        name: item.name,\n        arguments: { [inputProperty]: input },\n        ...item.namespace !== void 0 ? { namespace: item.namespace } : {},\n        customInput: {\n          property: inputProperty,\n          jsonBuffer: { input: \"\", started: false, closed: false }\n        }\n      };\n      output.content.push(block);\n      const slot = {\n        type: \"toolCall\",\n        block,\n        contentIndex: output.content.length - 1\n      };\n      outputSlots.set(outputIndex, slot);\n      stream11.push({ type: \"toolcall_start\", contentIndex: slot.contentIndex, partial: output });\n      return slot;\n    }\n    return void 0;\n  };\n  const getOrCreateSlot = (outputIndex, item) => {\n    return outputSlots.get(outputIndex) ?? createSlot(outputIndex, item);\n  };\n  const backfillReasoningSignatures = (responseOutput) => {\n    for (const item of responseOutput) {\n      if (item.type !== \"reasoning\" || !item.encrypted_content)\n        continue;\n      const block = reasoningBlocksById.get(item.id);\n      if (!block?.thinkingSignature)\n        continue;\n      const storedItem = JSON.parse(block.thinkingSignature);\n      if (storedItem.encrypted_content)\n        continue;\n      block.thinkingSignature = JSON.stringify({\n        ...storedItem,\n        encrypted_content: item.encrypted_content\n      });\n    }\n  };\n  const finalizeResponse = (response) => {\n    sawTerminalResponseEvent = true;\n    backfillReasoningSignatures(response.output ?? []);\n    if (response?.id) {\n      output.responseId = response.id;\n    }\n    if (response?.usage) {\n      const inputDetails = response.usage.input_tokens_details;\n      const cachedTokens = inputDetails?.cached_tokens || 0;\n      const cacheWriteTokens = inputDetails?.cache_write_tokens || 0;\n      output.usage = {\n        // OpenAI includes cached and cache-write tokens in input_tokens, so subtract both.\n        input: Math.max(0, (response.usage.input_tokens || 0) - cachedTokens - cacheWriteTokens),\n        output: response.usage.output_tokens || 0,\n        cacheRead: cachedTokens,\n        cacheWrite: cacheWriteTokens,\n        reasoning: response.usage.output_tokens_details?.reasoning_tokens || 0,\n        totalTokens: response.usage.total_tokens || 0,\n        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 }\n      };\n    }\n    calculateCost(model, output.usage);\n    if (options?.applyServiceTierPricing) {\n      const serviceTier = options.resolveServiceTier ? options.resolveServiceTier(response?.service_tier, options.serviceTier) : response?.service_tier ?? options.serviceTier;\n      options.applyServiceTierPricing(output.usage, serviceTier);\n    }\n    const status = response?.status;\n    const incompleteDetails = response?.incomplete_details;\n    const incompleteReason = typeof incompleteDetails?.reason === \"string\" ? incompleteDetails.reason : void 0;\n    output.rawStopReason = incompleteReason ? `${status}.${incompleteReason}` : status;\n    const mappedStop = mapStopReason3(status, incompleteReason);\n    output.stopReason = mappedStop.stopReason;\n    output.errorMessage = mappedStop.errorMessage;\n    if (output.content.some((b) => b.type === \"toolCall\") && output.stopReason === \"stop\") {\n      output.stopReason = \"toolUse\";\n    }\n  };\n  for await (const event of openaiStream) {\n    if (event.type === \"response.created\") {\n      output.responseId = event.response.id;\n    } else if (event.type === \"response.output_item.added\") {\n      createSlot(event.output_index, event.item);\n    } else if (event.type === \"response.reasoning_summary_text.delta\") {\n      const slot = getSlot(event.output_index, \"thinking\");\n      if (!slot)\n        continue;\n      slot.block.thinking += event.delta;\n      stream11.push({\n        type: \"thinking_delta\",\n        contentIndex: slot.contentIndex,\n        delta: event.delta,\n        partial: output\n      });\n    } else if (event.type === \"response.reasoning_summary_part.done\") {\n      const slot = getSlot(event.output_index, \"thinking\");\n      if (!slot)\n        continue;\n      slot.block.thinking += \"\\n\\n\";\n      stream11.push({\n        type: \"thinking_delta\",\n        contentIndex: slot.contentIndex,\n        delta: \"\\n\\n\",\n        partial: output\n      });\n    } else if (event.type === \"response.reasoning_text.delta\") {\n      const slot = getSlot(event.output_index, \"thinking\");\n      if (!slot)\n        continue;\n      slot.block.thinking += event.delta;\n      stream11.push({\n        type: \"thinking_delta\",\n        contentIndex: slot.contentIndex,\n        delta: event.delta,\n        partial: output\n      });\n    } else if (event.type === \"response.output_text.delta\") {\n      const slot = getSlot(event.output_index, \"text\");\n      if (!slot)\n        continue;\n      slot.block.text += event.delta;\n      stream11.push({\n        type: \"text_delta\",\n        contentIndex: slot.contentIndex,\n        delta: event.delta,\n        partial: output\n      });\n    } else if (event.type === \"response.refusal.delta\") {\n      const slot = getSlot(event.output_index, \"text\");\n      if (!slot)\n        continue;\n      slot.block.text += event.delta;\n      stream11.push({\n        type: \"text_delta\",\n        contentIndex: slot.contentIndex,\n        delta: event.delta,\n        partial: output\n      });\n    } else if (event.type === \"response.function_call_arguments.delta\") {\n      const slot = getSlot(event.output_index, \"toolCall\");\n      if (!slot || slot.block.partialJson === void 0)\n        continue;\n      slot.block.partialJson += event.delta;\n      slot.block.arguments = parseStreamingJson(slot.block.partialJson);\n      pushToolCallDelta(slot, event.delta);\n    } else if (event.type === \"response.function_call_arguments.done\") {\n      const slot = getSlot(event.output_index, \"toolCall\");\n      if (!slot || slot.block.partialJson === void 0)\n        continue;\n      const previousPartialJson = slot.block.partialJson;\n      slot.block.partialJson = event.arguments;\n      slot.block.arguments = parseStreamingJson(slot.block.partialJson);\n      if (event.arguments.startsWith(previousPartialJson)) {\n        const delta = event.arguments.slice(previousPartialJson.length);\n        if (delta.length > 0)\n          pushToolCallDelta(slot, delta);\n      }\n    } else if (event.type === \"response.custom_tool_call_input.delta\") {\n      const slot = getSlot(event.output_index, \"toolCall\");\n      if (!slot || !slot.block.customInput)\n        continue;\n      pushToolCallDelta(slot, appendCustomToolCallInput(slot.block, getCustomToolCallInput(slot.block) + event.delta, false));\n    } else if (event.type === \"response.custom_tool_call_input.done\") {\n      const slot = getSlot(event.output_index, \"toolCall\");\n      if (!slot || !slot.block.customInput)\n        continue;\n      pushToolCallDelta(slot, appendCustomToolCallInput(slot.block, event.input, true));\n    } else if (event.type === \"response.output_item.done\") {\n      const item = event.item;\n      applyMessagePhaseStopReason(item);\n      const slot = getOrCreateSlot(event.output_index, item);\n      if (item.type === \"reasoning\" && slot?.type === \"thinking\") {\n        const summaryText = item.summary?.map((s) => s.text).join(\"\\n\\n\") || \"\";\n        const contentText3 = item.content?.map((c) => c.text).join(\"\\n\\n\") || \"\";\n        slot.block.thinking = summaryText || contentText3 || slot.block.thinking;\n        slot.block.thinkingSignature = JSON.stringify(item);\n        reasoningBlocksById.set(item.id, slot.block);\n        stream11.push({\n          type: \"thinking_end\",\n          contentIndex: slot.contentIndex,\n          content: slot.block.thinking,\n          partial: output\n        });\n        outputSlots.delete(event.output_index);\n      } else if (item.type === \"message\" && slot?.type === \"text\") {\n        slot.block.text = item.content?.map((c) => c.type === \"output_text\" ? c.text : c.refusal).join(\"\") || \"\";\n        slot.block.textSignature = encodeTextSignatureV1(item.id, item.phase ?? void 0);\n        stream11.push({\n          type: \"text_end\",\n          contentIndex: slot.contentIndex,\n          content: slot.block.text,\n          partial: output\n        });\n        outputSlots.delete(event.output_index);\n      } else if (item.type === \"function_call\" && slot?.type === \"toolCall\" && slot.block.partialJson !== void 0) {\n        slot.block.arguments = parseStreamingJson(item.arguments || slot.block.partialJson || \"{}\");\n        if (item.namespace !== void 0)\n          slot.block.namespace = item.namespace;\n        delete slot.block.partialJson;\n        stream11.push({\n          type: \"toolcall_end\",\n          contentIndex: slot.contentIndex,\n          toolCall: slot.block,\n          partial: output\n        });\n        outputSlots.delete(event.output_index);\n      } else if (item.type === \"custom_tool_call\" && slot?.type === \"toolCall\" && slot.block.customInput) {\n        pushToolCallDelta(slot, appendCustomToolCallInput(slot.block, item.input ?? getCustomToolCallInput(slot.block), true));\n        if (item.namespace !== void 0)\n          slot.block.namespace = item.namespace;\n        delete slot.block.customInput;\n        stream11.push({\n          type: \"toolcall_end\",\n          contentIndex: slot.contentIndex,\n          toolCall: slot.block,\n          partial: output\n        });\n        outputSlots.delete(event.output_index);\n      }\n    } else if (event.type === \"response.completed\" || event.type === \"response.incomplete\") {\n      finalizeResponse(event.response);\n    } else if (event.type === \"error\") {\n      throw new Error(`Error Code ${event.code}: ${event.message}` || \"Unknown error\");\n    } else if (event.type === \"response.failed\") {\n      sawTerminalResponseEvent = true;\n      output.rawStopReason = event.response?.status;\n      const error = event.response?.error;\n      const details = event.response?.incomplete_details;\n      const msg = error ? `${error.code || \"unknown\"}: ${error.message || \"no message\"}` : details?.reason ? `incomplete: ${details.reason}` : \"Unknown error (no error details in response)\";\n      throw new Error(msg);\n    }\n  }\n  if (!sawTerminalResponseEvent) {\n    throw new Error(\"OpenAI Responses stream ended before a terminal response event\");\n  }\n}\nfunction mapStopReason3(status, incompleteReason) {\n  if (!status)\n    return { stopReason: \"stop\" };\n  switch (status) {\n    case \"completed\":\n      return { stopReason: \"stop\" };\n    case \"incomplete\":\n      if (incompleteReason === \"max_output_tokens\") {\n        return { stopReason: \"length\" };\n      }\n      return {\n        stopReason: \"error\",\n        errorMessage: incompleteReason ? `Response incomplete: ${incompleteReason}` : \"Response incomplete without a provider reason\"\n      };\n    case \"failed\":\n    case \"cancelled\":\n      return { stopReason: \"error\" };\n    // These two are wonky ...\n    case \"in_progress\":\n    case \"queued\":\n      return { stopReason: \"stop\" };\n    default: {\n      const _exhaustive = status;\n      throw new Error(`Unhandled stop reason: ${_exhaustive}`);\n    }\n  }\n}\nvar init_openai_responses_shared = __esm({\n  \"node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/api/openai-responses-shared.js\"() {\n    init_models();\n    init_hash();\n    init_json_parse();\n    init_sanitize_unicode();\n    init_constrained_sampling();\n    init_transform_messages();\n  }\n});\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/api/azure-openai-responses.js\nvar azure_openai_responses_exports = {};\n__export(azure_openai_responses_exports, {\n  stream: () => stream3,\n  streamSimple: () => streamSimple3\n});\nfunction parseDeploymentNameMap(value) {\n  const map = /* @__PURE__ */ new Map();\n  if (!value)\n    return map;\n  for (const entry of value.split(\",\")) {\n    const trimmed = entry.trim();\n    if (!trimmed)\n      continue;\n    const [modelId, deploymentName] = trimmed.split(\"=\", 2);\n    if (!modelId || !deploymentName)\n      continue;\n    map.set(modelId.trim(), deploymentName.trim());\n  }\n  return map;\n}\nfunction resolveDeploymentName(model, options) {\n  if (options?.azureDeploymentName) {\n    return options.azureDeploymentName;\n  }\n  const mappedDeployment = parseDeploymentNameMap(getProviderEnvValue(\"AZURE_OPENAI_DEPLOYMENT_NAME_MAP\", options?.env)).get(model.id);\n  return mappedDeployment || model.id;\n}\nfunction formatAzureOpenAIError(error) {\n  return formatProviderError(normalizeProviderError(error), \"Azure OpenAI API error\");\n}\nfunction normalizeAzureBaseUrl(baseUrl) {\n  const trimmed = baseUrl.trim().replace(/\\/+$/, \"\");\n  let url;\n  try {\n    url = new URL(trimmed);\n  } catch {\n    throw new Error(`Invalid Azure OpenAI base URL: ${baseUrl}`);\n  }\n  const isAzureHost = url.hostname.endsWith(\".openai.azure.com\") || url.hostname.endsWith(\".cognitiveservices.azure.com\") || url.hostname.endsWith(\".ai.azure.com\");\n  const normalizedPath = url.pathname.replace(/\\/+$/, \"\");\n  if (isAzureHost && (normalizedPath === \"\" || normalizedPath === \"/\" || normalizedPath === \"/openai\" || normalizedPath === \"/openai/v1/responses\")) {\n    url.pathname = \"/openai/v1\";\n    url.search = \"\";\n  }\n  return url.toString().replace(/\\/+$/, \"\");\n}\nfunction buildDefaultBaseUrl(resourceName) {\n  return `https://${resourceName}.openai.azure.com/openai/v1`;\n}\nfunction resolveAzureConfig(model, options) {\n  const apiVersion = options?.azureApiVersion || getProviderEnvValue(\"AZURE_OPENAI_API_VERSION\", options?.env) || DEFAULT_AZURE_API_VERSION;\n  const baseUrl = options?.azureBaseUrl?.trim() || getProviderEnvValue(\"AZURE_OPENAI_BASE_URL\", options?.env)?.trim() || void 0;\n  const resourceName = options?.azureResourceName || getProviderEnvValue(\"AZURE_OPENAI_RESOURCE_NAME\", options?.env);\n  let resolvedBaseUrl = baseUrl;\n  if (!resolvedBaseUrl && resourceName) {\n    resolvedBaseUrl = buildDefaultBaseUrl(resourceName);\n  }\n  if (!resolvedBaseUrl && model.baseUrl) {\n    resolvedBaseUrl = model.baseUrl;\n  }\n  if (!resolvedBaseUrl) {\n    throw new Error(\"Azure OpenAI base URL is required. Set AZURE_OPENAI_BASE_URL or AZURE_OPENAI_RESOURCE_NAME, or pass azureBaseUrl, azureResourceName, or model.baseUrl.\");\n  }\n  return {\n    baseUrl: normalizeAzureBaseUrl(resolvedBaseUrl),\n    apiVersion\n  };\n}\nfunction createClient3(model, apiKey, options) {\n  const headers = { ...model.headers };\n  if (options?.headers) {\n    Object.assign(headers, options.headers);\n  }\n  const { baseUrl, apiVersion } = resolveAzureConfig(model, options);\n  return new AzureOpenAI({\n    apiKey,\n    apiVersion,\n    dangerouslyAllowBrowser: true,\n    fetch: options?.fetch,\n    defaultHeaders: headers,\n    baseURL: baseUrl\n  });\n}\nfunction buildParams3(model, context, options, deploymentName, grammarToolInputProperties = createGrammarToolInputProperties(context.tools, model.compat?.supportsOpenAIGrammarTools ?? false)) {\n  const messages = convertResponsesMessages(model, context, AZURE_TOOL_CALL_PROVIDERS, {\n    grammarToolInputProperties\n  });\n  const params = {\n    model: deploymentName,\n    input: messages,\n    stream: true,\n    prompt_cache_key: clampOpenAIPromptCacheKey(options?.sessionId),\n    store: false\n  };\n  if (options?.maxTokens) {\n    params.max_output_tokens = Math.max(options.maxTokens, OPENAI_RESPONSES_MIN_OUTPUT_TOKENS);\n  }\n  if (options?.temperature !== void 0) {\n    params.temperature = options?.temperature;\n  }\n  if (context.tools && context.tools.length > 0) {\n    params.tools = convertResponsesTools(context.tools, {\n      supportsStrictMode: model.compat?.supportsStrictMode ?? true,\n      supportsOpenAIGrammarTools: model.compat?.supportsOpenAIGrammarTools ?? false\n    });\n  }\n  if (model.reasoning) {\n    if (options?.reasoningEffort || options?.reasoningSummary) {\n      const effort = options?.reasoningEffort ? model.thinkingLevelMap?.[options.reasoningEffort] ?? options.reasoningEffort : \"medium\";\n      params.reasoning = {\n        effort,\n        summary: options?.reasoningSummary || \"auto\"\n      };\n      params.include = [\"reasoning.encrypted_content\"];\n    } else if (model.thinkingLevelMap?.off !== null) {\n      params.reasoning = {\n        effort: model.thinkingLevelMap?.off ?? \"none\"\n      };\n    }\n  }\n  if (options?.samplingParams) {\n    Object.assign(params, options.samplingParams);\n  }\n  return params;\n}\nvar DEFAULT_AZURE_API_VERSION, AZURE_TOOL_CALL_PROVIDERS, OPENAI_RESPONSES_MIN_OUTPUT_TOKENS, stream3, streamSimple3;\nvar init_azure_openai_responses = __esm({\n  \"node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/api/azure-openai-responses.js\"() {\n    init_openai();\n    init_models();\n    init_error_body();\n    init_event_stream();\n    init_headers();\n    init_provider_env();\n    init_provider_retry();\n    init_constrained_sampling();\n    init_openai_prompt_cache();\n    init_openai_responses_shared();\n    init_simple_options();\n    DEFAULT_AZURE_API_VERSION = \"v1\";\n    AZURE_TOOL_CALL_PROVIDERS = /* @__PURE__ */ new Set([\"openai\", \"openai-codex\", \"opencode\", \"azure-openai-responses\"]);\n    OPENAI_RESPONSES_MIN_OUTPUT_TOKENS = 16;\n    stream3 = (model, context, options) => {\n      const stream11 = new AssistantMessageEventStream();\n      (async () => {\n        const deploymentName = resolveDeploymentName(model, options);\n        const output = {\n          role: \"assistant\",\n          content: [],\n          api: \"azure-openai-responses\",\n          provider: model.provider,\n          model: model.id,\n          usage: {\n            input: 0,\n            output: 0,\n            cacheRead: 0,\n            cacheWrite: 0,\n            totalTokens: 0,\n            cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 }\n          },\n          stopReason: \"pending\",\n          timestamp: Date.now()\n        };\n        try {\n          const apiKey = options?.apiKey;\n          if (!apiKey) {\n            throw new Error(`No API key for provider: ${model.provider}`);\n          }\n          const client = createClient3(model, apiKey, options);\n          const grammarToolInputProperties = createGrammarToolInputProperties(context.tools, model.compat?.supportsOpenAIGrammarTools ?? false);\n          let params = buildParams3(model, context, options, deploymentName, grammarToolInputProperties);\n          const nextParams = await options?.onPayload?.(params, model);\n          if (nextParams !== void 0) {\n            params = nextParams;\n          }\n          const requestOptions = {\n            ...options?.signal ? { signal: options.signal } : {},\n            ...options?.timeoutMs !== void 0 ? { timeout: options.timeoutMs } : {},\n            maxRetries: 0\n          };\n          const { data: openaiStream, response } = await retryProviderRequest(() => client.responses.create(params, requestOptions).withResponse(), {\n            maxRetries: options?.maxRetries,\n            maxRetryDelayMs: options?.maxRetryDelayMs,\n            signal: options?.signal\n          });\n          await options?.onResponse?.({ status: response.status, headers: headersToRecord(response.headers) }, model);\n          stream11.push({ type: \"start\", partial: output });\n          await processResponsesStream(openaiStream, output, stream11, model, { grammarToolInputProperties });\n          if (options?.signal?.aborted) {\n            throw new Error(\"Request was aborted\");\n          }\n          if (output.stopReason === \"pending\") {\n            throw new Error(\"Azure OpenAI Responses stream ended without a stop reason\");\n          }\n          if (output.stopReason === \"aborted\" || output.stopReason === \"error\") {\n            throw new Error(output.errorMessage || \"An unknown error occurred\");\n          }\n          stream11.push({ type: \"done\", reason: output.stopReason, message: output });\n          stream11.end();\n        } catch (error) {\n          for (const block of output.content) {\n            delete block.index;\n            delete block.partialJson;\n            delete block.customInput;\n          }\n          output.stopReason = options?.signal?.aborted ? \"aborted\" : \"error\";\n          output.errorMessage = formatAzureOpenAIError(error);\n          stream11.push({ type: \"error\", reason: output.stopReason, error: output });\n          stream11.end();\n        }\n      })();\n      return stream11;\n    };\n    streamSimple3 = (model, context, options) => {\n      const apiKey = options?.apiKey;\n      if (!apiKey) {\n        throw new Error(`No API key for provider: ${model.provider}`);\n      }\n      const base = buildBaseOptions(model, context, options, apiKey);\n      const clampedReasoning = options?.reasoning ? clampThinkingLevel(model, options.reasoning) : void 0;\n      const reasoningEffort = clampedReasoning === \"off\" ? void 0 : clampedReasoning;\n      return stream3(model, context, {\n        ...base,\n        reasoningEffort\n      });\n    };\n  }\n});\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/api/openai-responses.js\nvar openai_responses_exports = {};\n__export(openai_responses_exports, {\n  stream: () => stream4,\n  streamSimple: () => streamSimple4\n});\nfunction hasHeader3(headers, name) {\n  if (!headers)\n    return false;\n  const expected = name.toLowerCase();\n  for (const [key, value] of Object.entries(headers)) {\n    if (key.toLowerCase() === expected && value !== null && value.trim().length > 0)\n      return true;\n  }\n  return false;\n}\nfunction getClientApiKey2(provider, apiKey, headers) {\n  if (apiKey)\n    return apiKey;\n  if (hasHeader3(headers, \"authorization\") || hasHeader3(headers, \"cf-aig-authorization\"))\n    return \"unused\";\n  throw new Error(`No API key for provider: ${provider}`);\n}\nfunction detectSessionAffinityFormat(model) {\n  return model.provider === \"openrouter\" || model.baseUrl.includes(\"openrouter.ai\") ? \"openrouter\" : \"openai\";\n}\nfunction resolveCacheRetention3(cacheRetention, env) {\n  if (cacheRetention) {\n    return cacheRetention;\n  }\n  if (getProviderEnvValue(\"PI_CACHE_RETENTION\", env) === \"long\") {\n    return \"long\";\n  }\n  return \"short\";\n}\nfunction getCompat2(model) {\n  return {\n    supportsDeveloperRole: model.compat?.supportsDeveloperRole ?? true,\n    sessionAffinityFormat: model.compat?.sessionAffinityFormat ?? detectSessionAffinityFormat(model),\n    supportsLongCacheRetention: model.compat?.supportsLongCacheRetention ?? true,\n    supportsStrictMode: model.compat?.supportsStrictMode ?? false,\n    supportsOpenAIGrammarTools: model.compat?.supportsOpenAIGrammarTools ?? false,\n    supportsAdditionalTools: model.compat?.supportsAdditionalTools ?? false,\n    supportsToolSearch: model.compat?.supportsToolSearch ?? false,\n    supportsExplicitPromptCacheMode: model.compat?.supportsExplicitPromptCacheMode ?? false\n  };\n}\nfunction getPromptCacheRetention(compat, cacheRetention) {\n  return cacheRetention === \"long\" && compat.supportsLongCacheRetention ? \"24h\" : void 0;\n}\nfunction formatOpenAIResponsesError(error) {\n  return formatProviderError(normalizeProviderError(error), \"OpenAI API error\");\n}\nfunction createClient4(model, context, apiKey, optionsHeaders, fetch2, sessionId) {\n  const compat = getCompat2(model);\n  const headers = { ...model.headers };\n  if (model.provider === \"github-copilot\") {\n    const hasImages = hasCopilotVisionInput(context.messages);\n    const copilotHeaders = buildCopilotDynamicHeaders({\n      messages: context.messages,\n      hasImages\n    });\n    Object.assign(headers, copilotHeaders);\n  }\n  if (sessionId) {\n    if (compat.sessionAffinityFormat === \"openrouter\") {\n      headers[\"x-session-id\"] = sessionId;\n    } else {\n      if (compat.sessionAffinityFormat === \"openai\") {\n        headers.session_id = sessionId;\n      }\n      headers[\"x-client-request-id\"] = sessionId;\n    }\n  }\n  if (optionsHeaders) {\n    Object.assign(headers, optionsHeaders);\n  }\n  return new OpenAI({\n    apiKey,\n    baseURL: model.baseUrl,\n    dangerouslyAllowBrowser: true,\n    fetch: fetch2,\n    defaultHeaders: headers\n  });\n}\nfunction buildParams4(model, context, options, compat = getCompat2(model), grammarToolInputProperties = createGrammarToolInputProperties(context.tools, compat.supportsOpenAIGrammarTools)) {\n  const deferredToolsMode = compat.supportsAdditionalTools ? \"additional-tools\" : compat.supportsToolSearch ? \"tool-search\" : void 0;\n  const toolPlacement = splitDeferredTools(context, deferredToolsMode !== void 0);\n  const messages = convertResponsesMessages(model, context, OPENAI_TOOL_CALL_PROVIDERS, {\n    grammarToolInputProperties,\n    deferredTools: toolPlacement.deferred,\n    deferredToolsMode,\n    toolOptions: {\n      supportsStrictMode: compat.supportsStrictMode,\n      supportsOpenAIGrammarTools: compat.supportsOpenAIGrammarTools\n    }\n  });\n  const cacheRetention = resolveCacheRetention3(options?.cacheRetention, options?.env);\n  const disableImplicitPromptCache = cacheRetention === \"none\" && compat.supportsExplicitPromptCacheMode;\n  const params = {\n    model: model.id,\n    input: messages,\n    stream: true,\n    prompt_cache_key: cacheRetention === \"none\" ? void 0 : clampOpenAIPromptCacheKey(options?.sessionId),\n    prompt_cache_retention: getPromptCacheRetention(compat, cacheRetention),\n    prompt_cache_options: disableImplicitPromptCache ? { mode: \"explicit\" } : void 0,\n    store: false\n  };\n  if (options?.maxTokens) {\n    params.max_output_tokens = Math.max(options.maxTokens, OPENAI_RESPONSES_MIN_OUTPUT_TOKENS2);\n  }\n  if (options?.temperature !== void 0) {\n    params.temperature = options?.temperature;\n  }\n  if (options?.serviceTier !== void 0) {\n    params.service_tier = options.serviceTier;\n  }\n  if (toolPlacement.immediate.length > 0) {\n    params.tools = convertResponsesTools(toolPlacement.immediate, {\n      supportsStrictMode: compat.supportsStrictMode,\n      supportsOpenAIGrammarTools: compat.supportsOpenAIGrammarTools\n    });\n  }\n  if (options?.toolChoice !== void 0) {\n    params.tool_choice = options.toolChoice;\n  }\n  if (model.reasoning) {\n    if (options?.reasoningEffort || options?.reasoningSummary) {\n      const effort = options?.reasoningEffort ? model.thinkingLevelMap?.[options.reasoningEffort] ?? options.reasoningEffort : \"medium\";\n      params.reasoning = {\n        effort,\n        summary: options?.reasoningSummary || \"auto\"\n      };\n      params.include = [\"reasoning.encrypted_content\"];\n    } else if (model.provider !== \"github-copilot\" && model.thinkingLevelMap?.off !== null) {\n      params.reasoning = {\n        effort: model.thinkingLevelMap?.off ?? \"none\"\n      };\n    }\n    if (model.provider === \"xai\")\n      params.include = [\"reasoning.encrypted_content\"];\n  }\n  if (options?.samplingParams) {\n    Object.assign(params, options.samplingParams);\n  }\n  return params;\n}\nfunction getServiceTierCostMultiplier(model, serviceTier) {\n  switch (serviceTier) {\n    case \"flex\":\n      return 0.5;\n    case \"priority\":\n      return model.id === \"gpt-5.5\" ? 2.5 : 2;\n    default:\n      return 1;\n  }\n}\nfunction applyServiceTierPricing(usage, serviceTier, model) {\n  const multiplier = getServiceTierCostMultiplier(model, serviceTier);\n  if (multiplier === 1)\n    return;\n  usage.cost.input *= multiplier;\n  usage.cost.output *= multiplier;\n  usage.cost.cacheRead *= multiplier;\n  usage.cost.cacheWrite *= multiplier;\n  usage.cost.total = usage.cost.input + usage.cost.output + usage.cost.cacheRead + usage.cost.cacheWrite;\n}\nvar OPENAI_TOOL_CALL_PROVIDERS, OPENAI_RESPONSES_MIN_OUTPUT_TOKENS2, stream4, streamSimple4;\nvar init_openai_responses = __esm({\n  \"node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/api/openai-responses.js\"() {\n    init_openai();\n    init_models();\n    init_deferred_tools();\n    init_error_body();\n    init_event_stream();\n    init_headers();\n    init_provider_env();\n    init_provider_retry();\n    init_constrained_sampling();\n    init_github_copilot_headers();\n    init_openai_prompt_cache();\n    init_openai_responses_shared();\n    init_simple_options();\n    OPENAI_TOOL_CALL_PROVIDERS = /* @__PURE__ */ new Set([\"openai\", \"openai-codex\", \"opencode\"]);\n    OPENAI_RESPONSES_MIN_OUTPUT_TOKENS2 = 16;\n    stream4 = (model, context, options) => {\n      const stream11 = new AssistantMessageEventStream();\n      (async () => {\n        const output = {\n          role: \"assistant\",\n          content: [],\n          api: model.api,\n          provider: model.provider,\n          model: model.id,\n          usage: {\n            input: 0,\n            output: 0,\n            cacheRead: 0,\n            cacheWrite: 0,\n            totalTokens: 0,\n            cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 }\n          },\n          stopReason: \"pending\",\n          timestamp: Date.now()\n        };\n        try {\n          const apiKey = getClientApiKey2(model.provider, options?.apiKey, options?.headers);\n          const cacheRetention = resolveCacheRetention3(options?.cacheRetention, options?.env);\n          const cacheSessionId = cacheRetention === \"none\" ? void 0 : options?.sessionId;\n          const compat = getCompat2(model);\n          const grammarToolInputProperties = createGrammarToolInputProperties(context.tools, compat.supportsOpenAIGrammarTools);\n          const client = createClient4(model, context, apiKey, options?.headers, options?.fetch, cacheSessionId);\n          let params = buildParams4(model, context, options, compat, grammarToolInputProperties);\n          const nextParams = await options?.onPayload?.(params, model);\n          if (nextParams !== void 0) {\n            params = nextParams;\n          }\n          const requestOptions = {\n            ...options?.signal ? { signal: options.signal } : {},\n            ...options?.timeoutMs !== void 0 ? { timeout: options.timeoutMs } : {},\n            maxRetries: 0\n          };\n          const { data: openaiStream, response } = await retryProviderRequest(() => client.responses.create(params, requestOptions).withResponse(), {\n            maxRetries: options?.maxRetries,\n            maxRetryDelayMs: options?.maxRetryDelayMs,\n            signal: options?.signal\n          });\n          await options?.onResponse?.({ status: response.status, headers: headersToRecord(response.headers) }, model);\n          stream11.push({ type: \"start\", partial: output });\n          await processResponsesStream(openaiStream, output, stream11, model, {\n            serviceTier: options?.serviceTier,\n            grammarToolInputProperties,\n            applyServiceTierPricing: (usage, serviceTier) => applyServiceTierPricing(usage, serviceTier, model)\n          });\n          if (options?.signal?.aborted) {\n            throw new Error(\"Request was aborted\");\n          }\n          if (output.stopReason === \"pending\") {\n            throw new Error(\"OpenAI Responses stream ended without a stop reason\");\n          }\n          if (output.stopReason === \"aborted\" || output.stopReason === \"error\") {\n            throw new Error(output.errorMessage || \"An unknown error occurred\");\n          }\n          stream11.push({ type: \"done\", reason: output.stopReason, message: output });\n          stream11.end();\n        } catch (error) {\n          for (const block of output.content) {\n            delete block.index;\n            delete block.partialJson;\n            delete block.customInput;\n          }\n          output.stopReason = options?.signal?.aborted ? \"aborted\" : \"error\";\n          output.errorMessage = formatOpenAIResponsesError(error);\n          stream11.push({ type: \"error\", reason: output.stopReason, error: output });\n          stream11.end();\n        }\n      })();\n      return stream11;\n    };\n    streamSimple4 = (model, context, options) => {\n      getClientApiKey2(model.provider, options?.apiKey, options?.headers);\n      const base = buildBaseOptions(model, context, options, options?.apiKey);\n      const clampedReasoning = options?.reasoning ? clampThinkingLevel(model, options.reasoning) : void 0;\n      const reasoningEffort = clampedReasoning === \"off\" ? void 0 : clampedReasoning;\n      return stream4(model, context, {\n        ...base,\n        reasoningEffort\n      });\n    };\n  }\n});\n\n// demo/browser/stubs/genai.js\nvar GoogleGenAI, FinishReason, FunctionCallingConfigMode, ResourceScope, ThinkingLevel;\nvar init_genai = __esm({\n  \"demo/browser/stubs/genai.js\"() {\n    \"use strict\";\n    GoogleGenAI = class {\n      constructor() {\n        throw new Error(\"Real model providers are not available in this demo.\");\n      }\n    };\n    FinishReason = {};\n    FunctionCallingConfigMode = {};\n    ResourceScope = {};\n    ThinkingLevel = {};\n  }\n});\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/api/google-shared.js\nfunction isThinkingPart(part) {\n  return part.thought === true;\n}\nfunction retainThoughtSignature(existing, incoming) {\n  if (typeof incoming === \"string\" && incoming.length > 0)\n    return incoming;\n  return existing;\n}\nfunction isValidThoughtSignature(signature) {\n  if (!signature)\n    return false;\n  if (signature.length % 4 !== 0)\n    return false;\n  return base64SignaturePattern.test(signature);\n}\nfunction resolveThoughtSignature(isSameProviderAndModel, signature) {\n  return isSameProviderAndModel && isValidThoughtSignature(signature) ? signature : void 0;\n}\nfunction requiresToolCallId(modelId) {\n  const geminiMajorVersion = getGeminiMajorVersion(modelId);\n  return modelId.startsWith(\"claude-\") || modelId.startsWith(\"gpt-oss-\") || geminiMajorVersion !== void 0 && geminiMajorVersion >= 3;\n}\nfunction getGeminiMajorVersion(modelId) {\n  const match = modelId.toLowerCase().match(/^gemini(?:-live)?-(\\d+)/);\n  if (!match)\n    return void 0;\n  return Number.parseInt(match[1], 10);\n}\nfunction supportsMultimodalFunctionResponse(modelId) {\n  const geminiMajorVersion = getGeminiMajorVersion(modelId);\n  if (geminiMajorVersion !== void 0) {\n    return geminiMajorVersion >= 3;\n  }\n  return true;\n}\nfunction convertMessages3(model, context) {\n  const contents = [];\n  const normalizeToolCallId2 = (id) => {\n    if (!requiresToolCallId(model.id))\n      return id;\n    return id.replace(/[^a-zA-Z0-9_-]/g, \"_\").slice(0, 64);\n  };\n  const transformedMessages = transformMessages(context.messages, model, normalizeToolCallId2);\n  for (const msg of transformedMessages) {\n    if (msg.role === \"user\") {\n      if (typeof msg.content === \"string\") {\n        contents.push({\n          role: \"user\",\n          parts: [{ text: sanitizeSurrogates(msg.content) }]\n        });\n      } else {\n        const parts = msg.content.map((item) => {\n          if (item.type === \"text\") {\n            return { text: sanitizeSurrogates(item.text) };\n          } else {\n            return {\n              inlineData: {\n                mimeType: item.mimeType,\n                data: item.data\n              }\n            };\n          }\n        });\n        if (parts.length === 0)\n          continue;\n        contents.push({\n          role: \"user\",\n          parts\n        });\n      }\n    } else if (msg.role === \"assistant\") {\n      const parts = [];\n      const isSameProviderAndModel = msg.provider === model.provider && msg.model === model.id;\n      for (const block of msg.content) {\n        if (block.type === \"text\") {\n          const thoughtSignature = resolveThoughtSignature(isSameProviderAndModel, block.textSignature);\n          if ((!block.text || block.text.trim() === \"\") && !thoughtSignature)\n            continue;\n          parts.push({\n            text: sanitizeSurrogates(block.text),\n            ...thoughtSignature && { thoughtSignature }\n          });\n        } else if (block.type === \"thinking\") {\n          if (isSameProviderAndModel) {\n            const thoughtSignature = resolveThoughtSignature(isSameProviderAndModel, block.thinkingSignature);\n            if ((!block.thinking || block.thinking.trim() === \"\") && !thoughtSignature)\n              continue;\n            parts.push({\n              thought: true,\n              text: sanitizeSurrogates(block.thinking),\n              ...thoughtSignature && { thoughtSignature }\n            });\n          } else {\n            if (!block.thinking || block.thinking.trim() === \"\")\n              continue;\n            parts.push({\n              text: sanitizeSurrogates(block.thinking)\n            });\n          }\n        } else if (block.type === \"toolCall\") {\n          const thoughtSignature = resolveThoughtSignature(isSameProviderAndModel, block.thoughtSignature);\n          const part = {\n            functionCall: {\n              name: block.name,\n              args: block.arguments ?? {},\n              ...requiresToolCallId(model.id) ? { id: block.id } : {}\n            },\n            ...thoughtSignature && { thoughtSignature }\n          };\n          parts.push(part);\n        }\n      }\n      if (parts.length === 0)\n        continue;\n      contents.push({\n        role: \"model\",\n        parts\n      });\n    } else if (msg.role === \"toolResult\") {\n      const textContent = msg.content.filter((c) => c.type === \"text\");\n      const textResult = textContent.map((c) => c.text).join(\"\\n\");\n      const imageContent = model.input.includes(\"image\") ? msg.content.filter((c) => c.type === \"image\") : [];\n      const hasText = textResult.length > 0;\n      const hasImages = imageContent.length > 0;\n      const modelSupportsMultimodalFunctionResponse = supportsMultimodalFunctionResponse(model.id);\n      const responseValue = hasText ? sanitizeSurrogates(textResult) : hasImages ? \"(see attached image)\" : \"\";\n      const imageParts = imageContent.map((imageBlock) => ({\n        inlineData: {\n          mimeType: imageBlock.mimeType,\n          data: imageBlock.data\n        }\n      }));\n      const includeId = requiresToolCallId(model.id);\n      const functionResponsePart = {\n        functionResponse: {\n          name: msg.toolName,\n          response: msg.isError ? { error: responseValue } : { output: responseValue },\n          ...hasImages && modelSupportsMultimodalFunctionResponse && { parts: imageParts },\n          ...includeId ? { id: msg.toolCallId } : {}\n        }\n      };\n      const lastContent = contents[contents.length - 1];\n      if (lastContent?.role === \"user\" && lastContent.parts?.some((p) => p.functionResponse)) {\n        lastContent.parts.push(functionResponsePart);\n      } else {\n        contents.push({\n          role: \"user\",\n          parts: [functionResponsePart]\n        });\n      }\n      if (hasImages && !modelSupportsMultimodalFunctionResponse) {\n        contents.push({\n          role: \"user\",\n          parts: [{ text: \"Tool result image:\" }, ...imageParts]\n        });\n      }\n    }\n  }\n  return contents;\n}\nfunction sanitizeForOpenApi(schema) {\n  if (typeof schema !== \"object\" || schema === null || Array.isArray(schema)) {\n    return schema;\n  }\n  const result = {};\n  for (const [key, value] of Object.entries(schema)) {\n    if (JSON_SCHEMA_META_DECLARATIONS.has(key))\n      continue;\n    result[key] = sanitizeForOpenApi(value);\n  }\n  return result;\n}\nfunction convertTools3(tools, useParameters = false, supportsStrictMode = true) {\n  if (tools.length === 0)\n    return void 0;\n  return [\n    {\n      functionDeclarations: tools.map((tool) => {\n        const strict = resolveJsonSchemaStrictSampling(tool, supportsStrictMode);\n        const parameters = getJsonSchemaToolParameters(tool, strict);\n        return {\n          name: tool.name,\n          description: tool.description,\n          ...useParameters ? { parameters: sanitizeForOpenApi(parameters) } : { parametersJsonSchema: parameters }\n        };\n      })\n    }\n  ];\n}\nfunction supportsGoogleStrictToolSampling(modelId) {\n  const majorVersion = getGeminiMajorVersion(modelId);\n  return majorVersion !== void 0 && majorVersion >= 3;\n}\nfunction mapToolChoice(choice) {\n  switch (choice) {\n    case \"auto\":\n      return FunctionCallingConfigMode.AUTO;\n    case \"none\":\n      return FunctionCallingConfigMode.NONE;\n    case \"any\":\n      return FunctionCallingConfigMode.ANY;\n    default:\n      return FunctionCallingConfigMode.AUTO;\n  }\n}\nfunction resolveGoogleFunctionCallingMode(tools, toolChoice, supportsStrictMode) {\n  const useStrictMode = tools.some((tool) => resolveJsonSchemaStrictSampling(tool, supportsStrictMode) === true);\n  if (toolChoice === \"none\" || toolChoice === \"any\") {\n    return mapToolChoice(toolChoice);\n  }\n  if (useStrictMode) {\n    return FunctionCallingConfigMode.VALIDATED;\n  }\n  return toolChoice ? mapToolChoice(toolChoice) : void 0;\n}\nfunction mapStopReason4(reason) {\n  switch (reason) {\n    case FinishReason.STOP:\n      return \"stop\";\n    case FinishReason.MAX_TOKENS:\n      return \"length\";\n    case FinishReason.BLOCKLIST:\n    case FinishReason.PROHIBITED_CONTENT:\n    case FinishReason.SPII:\n    case FinishReason.SAFETY:\n    case FinishReason.IMAGE_SAFETY:\n    case FinishReason.IMAGE_PROHIBITED_CONTENT:\n    case FinishReason.IMAGE_RECITATION:\n    case FinishReason.IMAGE_OTHER:\n    case FinishReason.RECITATION:\n    case FinishReason.FINISH_REASON_UNSPECIFIED:\n    case FinishReason.OTHER:\n    case FinishReason.LANGUAGE:\n    case FinishReason.MALFORMED_FUNCTION_CALL:\n    case FinishReason.UNEXPECTED_TOOL_CALL:\n    case FinishReason.NO_IMAGE:\n      return \"error\";\n    default: {\n      const _exhaustive = reason;\n      throw new Error(`Unhandled stop reason: ${_exhaustive}`);\n    }\n  }\n}\nfunction retryGoogleRequest(request, options) {\n  return retryProviderRequest(async () => {\n    try {\n      return await request();\n    } catch (error) {\n      if (error instanceof Error && \"status\" in error && !(\"headers\" in error)) {\n        error.headers = void 0;\n      }\n      throw error;\n    }\n  }, {\n    maxRetries: options?.maxRetries,\n    maxRetryDelayMs: options?.maxRetryDelayMs,\n    signal: options?.signal\n  });\n}\nvar base64SignaturePattern, JSON_SCHEMA_META_DECLARATIONS;\nvar init_google_shared = __esm({\n  \"node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/api/google-shared.js\"() {\n    init_genai();\n    init_provider_retry();\n    init_sanitize_unicode();\n    init_constrained_sampling();\n    init_transform_messages();\n    base64SignaturePattern = /^[A-Za-z0-9+/]+={0,2}$/;\n    JSON_SCHEMA_META_DECLARATIONS = /* @__PURE__ */ new Set([\n      \"$schema\",\n      \"$id\",\n      \"$anchor\",\n      \"$dynamicAnchor\",\n      \"$vocabulary\",\n      \"$comment\",\n      \"$defs\",\n      \"definitions\"\n      // pre-draft-2019-09 equivalent of $defs\n    ]);\n  }\n});\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/api/google-generative-ai.js\nvar google_generative_ai_exports = {};\n__export(google_generative_ai_exports, {\n  stream: () => stream5,\n  streamSimple: () => streamSimple5\n});\nfunction createClient5(model, apiKey, optionsHeaders) {\n  const httpOptions = {};\n  if (model.baseUrl) {\n    httpOptions.baseUrl = model.baseUrl;\n    httpOptions.apiVersion = \"\";\n  }\n  const headers = providerHeadersToRecord({ ...model.headers, ...optionsHeaders });\n  if (headers) {\n    httpOptions.headers = headers;\n  }\n  return new GoogleGenAI({\n    apiKey,\n    httpOptions: Object.keys(httpOptions).length > 0 ? httpOptions : void 0\n  });\n}\nfunction buildParams5(model, context, options = {}) {\n  const contents = convertMessages3(model, context);\n  const generationConfig = {};\n  if (options.temperature !== void 0) {\n    generationConfig.temperature = options.temperature;\n  }\n  if (options.maxTokens !== void 0) {\n    generationConfig.maxOutputTokens = options.maxTokens;\n  }\n  const supportsStrictMode = supportsGoogleStrictToolSampling(model.id);\n  const functionCallingMode = context.tools?.length ? resolveGoogleFunctionCallingMode(context.tools, options.toolChoice, supportsStrictMode) : void 0;\n  const config = {\n    ...Object.keys(generationConfig).length > 0 && generationConfig,\n    ...context.systemPrompt && { systemInstruction: sanitizeSurrogates(context.systemPrompt) },\n    ...context.tools && context.tools.length > 0 && {\n      tools: convertTools3(context.tools, false, supportsStrictMode)\n    },\n    ...functionCallingMode !== void 0 && {\n      toolConfig: { functionCallingConfig: { mode: functionCallingMode } }\n    }\n  };\n  if (options.thinking?.enabled && model.reasoning) {\n    const thinkingConfig = { includeThoughts: true };\n    if (options.thinking.level !== void 0) {\n      thinkingConfig.thinkingLevel = options.thinking.level;\n    } else if (options.thinking.budgetTokens !== void 0) {\n      thinkingConfig.thinkingBudget = options.thinking.budgetTokens;\n    }\n    config.thinkingConfig = thinkingConfig;\n  } else if (model.reasoning && options.thinking && !options.thinking.enabled) {\n    config.thinkingConfig = getDisabledThinkingConfig(model);\n  }\n  if (options.signal) {\n    if (options.signal.aborted) {\n      throw new Error(\"Request aborted\");\n    }\n    config.abortSignal = options.signal;\n  }\n  const params = {\n    model: model.id,\n    contents,\n    config\n  };\n  return params;\n}\nfunction isGemma4Model(model) {\n  return /gemma-?4/.test(model.id.toLowerCase());\n}\nfunction isGemini3ProModel(model) {\n  return /gemini-3(?:\\.\\d+)?-pro/.test(model.id.toLowerCase());\n}\nfunction isGemini3FlashModel(model) {\n  const id = model.id.toLowerCase();\n  return /gemini-3(?:\\.\\d+)?-flash/.test(id) || id === \"gemini-flash-latest\" || id === \"gemini-flash-lite-latest\";\n}\nfunction getDisabledThinkingConfig(model) {\n  if (isGemini3ProModel(model)) {\n    return { thinkingLevel: \"LOW\" };\n  }\n  if (isGemini3FlashModel(model)) {\n    return { thinkingLevel: \"MINIMAL\" };\n  }\n  if (isGemma4Model(model)) {\n    return { thinkingLevel: \"MINIMAL\" };\n  }\n  return { thinkingBudget: 0 };\n}\nfunction getThinkingLevel(effort, model) {\n  if (isGemini3ProModel(model)) {\n    switch (effort) {\n      case \"minimal\":\n      case \"low\":\n        return \"LOW\";\n      case \"medium\":\n      case \"high\":\n        return \"HIGH\";\n    }\n  }\n  if (isGemma4Model(model)) {\n    switch (effort) {\n      case \"minimal\":\n      case \"low\":\n        return \"MINIMAL\";\n      case \"medium\":\n      case \"high\":\n        return \"HIGH\";\n    }\n  }\n  switch (effort) {\n    case \"minimal\":\n      return \"MINIMAL\";\n    case \"low\":\n      return \"LOW\";\n    case \"medium\":\n      return \"MEDIUM\";\n    case \"high\":\n      return \"HIGH\";\n  }\n}\nfunction getGoogleBudget(model, effort, customBudgets) {\n  if (customBudgets?.[effort] !== void 0) {\n    return customBudgets[effort];\n  }\n  if (model.id.includes(\"2.5-pro\")) {\n    const budgets = {\n      minimal: 128,\n      low: 2048,\n      medium: 8192,\n      high: 32768\n    };\n    return budgets[effort];\n  }\n  if (model.id.includes(\"2.5-flash-lite\")) {\n    const budgets = {\n      minimal: 512,\n      low: 2048,\n      medium: 8192,\n      high: 24576\n    };\n    return budgets[effort];\n  }\n  if (model.id.includes(\"2.5-flash\")) {\n    const budgets = {\n      minimal: 128,\n      low: 2048,\n      medium: 8192,\n      high: 24576\n    };\n    return budgets[effort];\n  }\n  return -1;\n}\nvar toolCallCounter, stream5, streamSimple5;\nvar init_google_generative_ai = __esm({\n  \"node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/api/google-generative-ai.js\"() {\n    init_genai();\n    init_models();\n    init_error_body();\n    init_event_stream();\n    init_headers();\n    init_sanitize_unicode();\n    init_google_shared();\n    init_simple_options();\n    toolCallCounter = 0;\n    stream5 = (model, context, options) => {\n      const stream11 = new AssistantMessageEventStream();\n      (async () => {\n        const output = {\n          role: \"assistant\",\n          content: [],\n          api: \"google-generative-ai\",\n          provider: model.provider,\n          model: model.id,\n          usage: {\n            input: 0,\n            output: 0,\n            cacheRead: 0,\n            cacheWrite: 0,\n            totalTokens: 0,\n            cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 }\n          },\n          stopReason: \"pending\",\n          timestamp: Date.now()\n        };\n        try {\n          if (options?.fetch && options.fetch !== globalThis.fetch) {\n            throw new Error(\"Custom fetch is not supported by the Google Generative AI adapter\");\n          }\n          const apiKey = options?.apiKey;\n          if (!apiKey) {\n            throw new Error(`No API key for provider: ${model.provider}`);\n          }\n          const client = createClient5(model, apiKey, options?.headers);\n          let params = buildParams5(model, context, options);\n          const nextParams = await options?.onPayload?.(params, model);\n          if (nextParams !== void 0) {\n            params = nextParams;\n          }\n          const googleStream = await retryGoogleRequest(() => client.models.generateContentStream(params), options);\n          stream11.push({ type: \"start\", partial: output });\n          let currentBlock = null;\n          const blocks = output.content;\n          const blockIndex = () => blocks.length - 1;\n          for await (const chunk of googleStream) {\n            output.responseId ||= chunk.responseId;\n            const candidate = chunk.candidates?.[0];\n            if (candidate?.content?.parts) {\n              for (const part of candidate.content.parts) {\n                if (part.text !== void 0) {\n                  const isThinking = isThinkingPart(part);\n                  if (!currentBlock || isThinking && currentBlock.type !== \"thinking\" || !isThinking && currentBlock.type !== \"text\") {\n                    if (currentBlock) {\n                      if (currentBlock.type === \"text\") {\n                        stream11.push({\n                          type: \"text_end\",\n                          contentIndex: blocks.length - 1,\n                          content: currentBlock.text,\n                          partial: output\n                        });\n                      } else {\n                        stream11.push({\n                          type: \"thinking_end\",\n                          contentIndex: blockIndex(),\n                          content: currentBlock.thinking,\n                          partial: output\n                        });\n                      }\n                    }\n                    if (isThinking) {\n                      currentBlock = { type: \"thinking\", thinking: \"\", thinkingSignature: void 0 };\n                      output.content.push(currentBlock);\n                      stream11.push({ type: \"thinking_start\", contentIndex: blockIndex(), partial: output });\n                    } else {\n                      currentBlock = { type: \"text\", text: \"\" };\n                      output.content.push(currentBlock);\n                      stream11.push({ type: \"text_start\", contentIndex: blockIndex(), partial: output });\n                    }\n                  }\n                  if (currentBlock.type === \"thinking\") {\n                    currentBlock.thinking += part.text;\n                    currentBlock.thinkingSignature = retainThoughtSignature(currentBlock.thinkingSignature, part.thoughtSignature);\n                    stream11.push({\n                      type: \"thinking_delta\",\n                      contentIndex: blockIndex(),\n                      delta: part.text,\n                      partial: output\n                    });\n                  } else {\n                    currentBlock.text += part.text;\n                    currentBlock.textSignature = retainThoughtSignature(currentBlock.textSignature, part.thoughtSignature);\n                    stream11.push({\n                      type: \"text_delta\",\n                      contentIndex: blockIndex(),\n                      delta: part.text,\n                      partial: output\n                    });\n                  }\n                }\n                if (part.functionCall) {\n                  if (currentBlock) {\n                    if (currentBlock.type === \"text\") {\n                      stream11.push({\n                        type: \"text_end\",\n                        contentIndex: blockIndex(),\n                        content: currentBlock.text,\n                        partial: output\n                      });\n                    } else {\n                      stream11.push({\n                        type: \"thinking_end\",\n                        contentIndex: blockIndex(),\n                        content: currentBlock.thinking,\n                        partial: output\n                      });\n                    }\n                    currentBlock = null;\n                  }\n                  const providedId = part.functionCall.id;\n                  const needsNewId = !providedId || output.content.some((b) => b.type === \"toolCall\" && b.id === providedId);\n                  const toolCallId = needsNewId ? `${part.functionCall.name}_${Date.now()}_${++toolCallCounter}` : providedId;\n                  const toolCall = {\n                    type: \"toolCall\",\n                    id: toolCallId,\n                    name: part.functionCall.name || \"\",\n                    arguments: part.functionCall.args ?? {},\n                    ...part.thoughtSignature && { thoughtSignature: part.thoughtSignature }\n                  };\n                  output.content.push(toolCall);\n                  stream11.push({ type: \"toolcall_start\", contentIndex: blockIndex(), partial: output });\n                  stream11.push({\n                    type: \"toolcall_delta\",\n                    contentIndex: blockIndex(),\n                    delta: JSON.stringify(toolCall.arguments),\n                    partial: output\n                  });\n                  stream11.push({ type: \"toolcall_end\", contentIndex: blockIndex(), toolCall, partial: output });\n                }\n              }\n            }\n            if (candidate?.finishReason) {\n              output.rawStopReason = candidate.finishReason;\n              output.stopReason = mapStopReason4(candidate.finishReason);\n              if (output.content.some((b) => b.type === \"toolCall\") && output.stopReason === \"stop\") {\n                output.stopReason = \"toolUse\";\n              }\n            }\n            if (chunk.usageMetadata) {\n              output.usage = {\n                input: (chunk.usageMetadata.promptTokenCount || 0) - (chunk.usageMetadata.cachedContentTokenCount || 0),\n                output: (chunk.usageMetadata.candidatesTokenCount || 0) + (chunk.usageMetadata.thoughtsTokenCount || 0),\n                cacheRead: chunk.usageMetadata.cachedContentTokenCount || 0,\n                cacheWrite: 0,\n                reasoning: chunk.usageMetadata.thoughtsTokenCount || 0,\n                totalTokens: chunk.usageMetadata.totalTokenCount || 0,\n                cost: {\n                  input: 0,\n                  output: 0,\n                  cacheRead: 0,\n                  cacheWrite: 0,\n                  total: 0\n                }\n              };\n              calculateCost(model, output.usage);\n            }\n          }\n          if (currentBlock) {\n            if (currentBlock.type === \"text\") {\n              stream11.push({\n                type: \"text_end\",\n                contentIndex: blockIndex(),\n                content: currentBlock.text,\n                partial: output\n              });\n            } else {\n              stream11.push({\n                type: \"thinking_end\",\n                contentIndex: blockIndex(),\n                content: currentBlock.thinking,\n                partial: output\n              });\n            }\n          }\n          if (options?.signal?.aborted) {\n            throw new Error(\"Request was aborted\");\n          }\n          if (output.stopReason === \"pending\") {\n            throw new Error(\"Google stream ended without a finish reason\");\n          }\n          if (output.stopReason === \"aborted\" || output.stopReason === \"error\") {\n            const errorMessage2 = output.rawStopReason ? `Provider stopped with: ${output.rawStopReason}` : \"An unknown error occurred\";\n            throw new Error(errorMessage2);\n          }\n          stream11.push({ type: \"done\", reason: output.stopReason, message: output });\n          stream11.end();\n        } catch (error) {\n          for (const block of output.content) {\n            if (\"index\" in block) {\n              delete block.index;\n            }\n          }\n          output.stopReason = options?.signal?.aborted ? \"aborted\" : \"error\";\n          output.errorMessage = formatProviderError(normalizeProviderError(error));\n          stream11.push({ type: \"error\", reason: output.stopReason, error: output });\n          stream11.end();\n        }\n      })();\n      return stream11;\n    };\n    streamSimple5 = (model, context, options) => {\n      const apiKey = options?.apiKey;\n      if (!apiKey) {\n        throw new Error(`No API key for provider: ${model.provider}`);\n      }\n      const base = buildBaseOptions(model, context, options, apiKey);\n      if (!options?.reasoning) {\n        return stream5(model, context, { ...base, thinking: { enabled: false } });\n      }\n      const clampedReasoning = clampThinkingLevel(model, options.reasoning);\n      const effort = clampedReasoning === \"off\" ? \"high\" : clampedReasoning;\n      const googleModel = model;\n      if (isGemini3ProModel(googleModel) || isGemini3FlashModel(googleModel) || isGemma4Model(googleModel)) {\n        return stream5(model, context, {\n          ...base,\n          thinking: {\n            enabled: true,\n            level: getThinkingLevel(effort, googleModel)\n          }\n        });\n      }\n      return stream5(model, context, {\n        ...base,\n        thinking: {\n          enabled: true,\n          budgetTokens: getGoogleBudget(googleModel, effort, options.thinkingBudgets)\n        }\n      });\n    };\n  }\n});\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/api/google-vertex.js\nvar google_vertex_exports = {};\n__export(google_vertex_exports, {\n  stream: () => stream6,\n  streamSimple: () => streamSimple6\n});\nfunction createClient6(model, project, location, optionsHeaders, env) {\n  const googleAuthOptions = buildGoogleAuthOptions(env);\n  return new GoogleGenAI({\n    vertexai: true,\n    project,\n    location,\n    apiVersion: API_VERSION,\n    ...googleAuthOptions ? { googleAuthOptions } : {},\n    httpOptions: buildHttpOptions(model, optionsHeaders)\n  });\n}\nfunction createClientWithApiKey(model, apiKey, optionsHeaders) {\n  return new GoogleGenAI({\n    vertexai: true,\n    apiKey,\n    apiVersion: API_VERSION,\n    httpOptions: buildHttpOptions(model, optionsHeaders)\n  });\n}\nfunction buildHttpOptions(model, optionsHeaders) {\n  const httpOptions = {};\n  const baseUrl = resolveCustomBaseUrl(model.baseUrl);\n  if (baseUrl) {\n    httpOptions.baseUrl = baseUrl;\n    httpOptions.baseUrlResourceScope = ResourceScope.COLLECTION;\n    if (baseUrlIncludesApiVersion(baseUrl)) {\n      httpOptions.apiVersion = \"\";\n    }\n  }\n  const headers = providerHeadersToRecord({ ...model.headers, ...optionsHeaders });\n  if (headers) {\n    httpOptions.headers = headers;\n  }\n  return Object.keys(httpOptions).length > 0 ? httpOptions : void 0;\n}\nfunction resolveCustomBaseUrl(baseUrl) {\n  const trimmed = baseUrl.trim();\n  if (!trimmed || trimmed.includes(\"{location}\")) {\n    return void 0;\n  }\n  return trimmed;\n}\nfunction baseUrlIncludesApiVersion(baseUrl) {\n  try {\n    const url = new URL(baseUrl);\n    return url.pathname.split(\"/\").some((part) => /^v\\d+(?:beta\\d*)?$/.test(part));\n  } catch {\n    return /(?:^|\\/)v\\d+(?:beta\\d*)?(?:\\/|$)/.test(baseUrl);\n  }\n}\nfunction buildGoogleAuthOptions(env) {\n  const keyFilename = getProviderEnvValue(\"GOOGLE_APPLICATION_CREDENTIALS\", env);\n  return keyFilename ? { keyFilename } : void 0;\n}\nfunction resolveApiKey2(options) {\n  const apiKey = options?.apiKey?.trim();\n  if (!apiKey || apiKey === GCP_VERTEX_CREDENTIALS_MARKER || isPlaceholderApiKey(apiKey)) {\n    return void 0;\n  }\n  return apiKey;\n}\nfunction isPlaceholderApiKey(apiKey) {\n  return /^<[^>]+>$/.test(apiKey);\n}\nfunction resolveProject(options) {\n  const project = options?.project || getProviderEnvValue(\"GOOGLE_CLOUD_PROJECT\", options?.env) || getProviderEnvValue(\"GCLOUD_PROJECT\", options?.env);\n  if (!project) {\n    throw new Error(\"Vertex AI requires a project ID. Set GOOGLE_CLOUD_PROJECT/GCLOUD_PROJECT or pass project in options.\");\n  }\n  return project;\n}\nfunction resolveLocation(options) {\n  const location = options?.location || getProviderEnvValue(\"GOOGLE_CLOUD_LOCATION\", options?.env);\n  if (!location) {\n    throw new Error(\"Vertex AI requires a location. Set GOOGLE_CLOUD_LOCATION or pass location in options.\");\n  }\n  return location;\n}\nfunction buildParams6(model, context, options = {}) {\n  const contents = convertMessages3(model, context);\n  const generationConfig = {};\n  if (options.temperature !== void 0) {\n    generationConfig.temperature = options.temperature;\n  }\n  if (options.maxTokens !== void 0) {\n    generationConfig.maxOutputTokens = options.maxTokens;\n  }\n  const supportsStrictMode = supportsGoogleStrictToolSampling(model.id);\n  const functionCallingMode = context.tools?.length ? resolveGoogleFunctionCallingMode(context.tools, options.toolChoice, supportsStrictMode) : void 0;\n  const config = {\n    ...Object.keys(generationConfig).length > 0 && generationConfig,\n    ...context.systemPrompt && { systemInstruction: sanitizeSurrogates(context.systemPrompt) },\n    ...context.tools && context.tools.length > 0 && {\n      tools: convertTools3(context.tools, false, supportsStrictMode)\n    },\n    ...functionCallingMode !== void 0 && {\n      toolConfig: { functionCallingConfig: { mode: functionCallingMode } }\n    }\n  };\n  if (options.thinking?.enabled && model.reasoning) {\n    const thinkingConfig = { includeThoughts: true };\n    if (options.thinking.level !== void 0) {\n      thinkingConfig.thinkingLevel = THINKING_LEVEL_MAP[options.thinking.level];\n    } else if (options.thinking.budgetTokens !== void 0) {\n      thinkingConfig.thinkingBudget = options.thinking.budgetTokens;\n    }\n    config.thinkingConfig = thinkingConfig;\n  } else if (model.reasoning && options.thinking && !options.thinking.enabled) {\n    config.thinkingConfig = getDisabledThinkingConfig2(model);\n  }\n  if (options.signal) {\n    if (options.signal.aborted) {\n      throw new Error(\"Request aborted\");\n    }\n    config.abortSignal = options.signal;\n  }\n  const params = {\n    model: model.id,\n    contents,\n    config\n  };\n  return params;\n}\nfunction isGemini3ProModel2(model) {\n  return /gemini-3(?:\\.\\d+)?-pro/.test(model.id.toLowerCase());\n}\nfunction isGemini3FlashModel2(model) {\n  const id = model.id.toLowerCase();\n  return /gemini-3(?:\\.\\d+)?-flash/.test(id) || id === \"gemini-flash-latest\" || id === \"gemini-flash-lite-latest\";\n}\nfunction getDisabledThinkingConfig2(model) {\n  const geminiModel = model;\n  if (isGemini3ProModel2(geminiModel)) {\n    return { thinkingLevel: ThinkingLevel.LOW };\n  }\n  if (isGemini3FlashModel2(geminiModel)) {\n    return { thinkingLevel: ThinkingLevel.MINIMAL };\n  }\n  return { thinkingBudget: 0 };\n}\nfunction getGemini3ThinkingLevel(effort, model) {\n  if (isGemini3ProModel2(model)) {\n    switch (effort) {\n      case \"minimal\":\n      case \"low\":\n        return \"LOW\";\n      case \"medium\":\n      case \"high\":\n        return \"HIGH\";\n    }\n  }\n  switch (effort) {\n    case \"minimal\":\n      return \"MINIMAL\";\n    case \"low\":\n      return \"LOW\";\n    case \"medium\":\n      return \"MEDIUM\";\n    case \"high\":\n      return \"HIGH\";\n  }\n}\nfunction getGoogleBudget2(model, effort, customBudgets) {\n  if (customBudgets?.[effort] !== void 0) {\n    return customBudgets[effort];\n  }\n  if (model.id.includes(\"2.5-pro\")) {\n    const budgets = {\n      minimal: 128,\n      low: 2048,\n      medium: 8192,\n      high: 32768\n    };\n    return budgets[effort];\n  }\n  if (model.id.includes(\"2.5-flash\")) {\n    const budgets = {\n      minimal: 128,\n      low: 2048,\n      medium: 8192,\n      high: 24576\n    };\n    return budgets[effort];\n  }\n  return -1;\n}\nvar API_VERSION, GCP_VERTEX_CREDENTIALS_MARKER, THINKING_LEVEL_MAP, toolCallCounter2, stream6, streamSimple6;\nvar init_google_vertex = __esm({\n  \"node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/api/google-vertex.js\"() {\n    init_genai();\n    init_models();\n    init_error_body();\n    init_event_stream();\n    init_headers();\n    init_provider_env();\n    init_sanitize_unicode();\n    init_google_shared();\n    init_simple_options();\n    API_VERSION = \"v1\";\n    GCP_VERTEX_CREDENTIALS_MARKER = \"gcp-vertex-credentials\";\n    THINKING_LEVEL_MAP = {\n      THINKING_LEVEL_UNSPECIFIED: ThinkingLevel.THINKING_LEVEL_UNSPECIFIED,\n      MINIMAL: ThinkingLevel.MINIMAL,\n      LOW: ThinkingLevel.LOW,\n      MEDIUM: ThinkingLevel.MEDIUM,\n      HIGH: ThinkingLevel.HIGH\n    };\n    toolCallCounter2 = 0;\n    stream6 = (model, context, options) => {\n      const stream11 = new AssistantMessageEventStream();\n      (async () => {\n        const output = {\n          role: \"assistant\",\n          content: [],\n          api: \"google-vertex\",\n          provider: model.provider,\n          model: model.id,\n          usage: {\n            input: 0,\n            output: 0,\n            cacheRead: 0,\n            cacheWrite: 0,\n            totalTokens: 0,\n            cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 }\n          },\n          stopReason: \"pending\",\n          timestamp: Date.now()\n        };\n        try {\n          if (options?.fetch && options.fetch !== globalThis.fetch) {\n            throw new Error(\"Custom fetch is not supported by the Google Vertex adapter\");\n          }\n          const apiKey = resolveApiKey2(options);\n          const client = apiKey ? createClientWithApiKey(model, apiKey, options?.headers) : createClient6(model, resolveProject(options), resolveLocation(options), options?.headers, options?.env);\n          let params = buildParams6(model, context, options);\n          const nextParams = await options?.onPayload?.(params, model);\n          if (nextParams !== void 0) {\n            params = nextParams;\n          }\n          const googleStream = await retryGoogleRequest(() => client.models.generateContentStream(params), options);\n          stream11.push({ type: \"start\", partial: output });\n          let currentBlock = null;\n          const blocks = output.content;\n          const blockIndex = () => blocks.length - 1;\n          for await (const chunk of googleStream) {\n            output.responseId ||= chunk.responseId;\n            const candidate = chunk.candidates?.[0];\n            if (candidate?.content?.parts) {\n              for (const part of candidate.content.parts) {\n                if (part.text !== void 0) {\n                  const isThinking = isThinkingPart(part);\n                  if (!currentBlock || isThinking && currentBlock.type !== \"thinking\" || !isThinking && currentBlock.type !== \"text\") {\n                    if (currentBlock) {\n                      if (currentBlock.type === \"text\") {\n                        stream11.push({\n                          type: \"text_end\",\n                          contentIndex: blocks.length - 1,\n                          content: currentBlock.text,\n                          partial: output\n                        });\n                      } else {\n                        stream11.push({\n                          type: \"thinking_end\",\n                          contentIndex: blockIndex(),\n                          content: currentBlock.thinking,\n                          partial: output\n                        });\n                      }\n                    }\n                    if (isThinking) {\n                      currentBlock = { type: \"thinking\", thinking: \"\", thinkingSignature: void 0 };\n                      output.content.push(currentBlock);\n                      stream11.push({ type: \"thinking_start\", contentIndex: blockIndex(), partial: output });\n                    } else {\n                      currentBlock = { type: \"text\", text: \"\" };\n                      output.content.push(currentBlock);\n                      stream11.push({ type: \"text_start\", contentIndex: blockIndex(), partial: output });\n                    }\n                  }\n                  if (currentBlock.type === \"thinking\") {\n                    currentBlock.thinking += part.text;\n                    currentBlock.thinkingSignature = retainThoughtSignature(currentBlock.thinkingSignature, part.thoughtSignature);\n                    stream11.push({\n                      type: \"thinking_delta\",\n                      contentIndex: blockIndex(),\n                      delta: part.text,\n                      partial: output\n                    });\n                  } else {\n                    currentBlock.text += part.text;\n                    currentBlock.textSignature = retainThoughtSignature(currentBlock.textSignature, part.thoughtSignature);\n                    stream11.push({\n                      type: \"text_delta\",\n                      contentIndex: blockIndex(),\n                      delta: part.text,\n                      partial: output\n                    });\n                  }\n                }\n                if (part.functionCall) {\n                  if (currentBlock) {\n                    if (currentBlock.type === \"text\") {\n                      stream11.push({\n                        type: \"text_end\",\n                        contentIndex: blockIndex(),\n                        content: currentBlock.text,\n                        partial: output\n                      });\n                    } else {\n                      stream11.push({\n                        type: \"thinking_end\",\n                        contentIndex: blockIndex(),\n                        content: currentBlock.thinking,\n                        partial: output\n                      });\n                    }\n                    currentBlock = null;\n                  }\n                  const providedId = part.functionCall.id;\n                  const needsNewId = !providedId || output.content.some((b) => b.type === \"toolCall\" && b.id === providedId);\n                  const toolCallId = needsNewId ? `${part.functionCall.name}_${Date.now()}_${++toolCallCounter2}` : providedId;\n                  const toolCall = {\n                    type: \"toolCall\",\n                    id: toolCallId,\n                    name: part.functionCall.name || \"\",\n                    arguments: part.functionCall.args ?? {},\n                    ...part.thoughtSignature && { thoughtSignature: part.thoughtSignature }\n                  };\n                  output.content.push(toolCall);\n                  stream11.push({ type: \"toolcall_start\", contentIndex: blockIndex(), partial: output });\n                  stream11.push({\n                    type: \"toolcall_delta\",\n                    contentIndex: blockIndex(),\n                    delta: JSON.stringify(toolCall.arguments),\n                    partial: output\n                  });\n                  stream11.push({ type: \"toolcall_end\", contentIndex: blockIndex(), toolCall, partial: output });\n                }\n              }\n            }\n            if (candidate?.finishReason) {\n              output.rawStopReason = candidate.finishReason;\n              output.stopReason = mapStopReason4(candidate.finishReason);\n              if (output.content.some((b) => b.type === \"toolCall\") && output.stopReason === \"stop\") {\n                output.stopReason = \"toolUse\";\n              }\n            }\n            if (chunk.usageMetadata) {\n              output.usage = {\n                input: (chunk.usageMetadata.promptTokenCount || 0) - (chunk.usageMetadata.cachedContentTokenCount || 0),\n                output: (chunk.usageMetadata.candidatesTokenCount || 0) + (chunk.usageMetadata.thoughtsTokenCount || 0),\n                cacheRead: chunk.usageMetadata.cachedContentTokenCount || 0,\n                cacheWrite: 0,\n                reasoning: chunk.usageMetadata.thoughtsTokenCount || 0,\n                totalTokens: chunk.usageMetadata.totalTokenCount || 0,\n                cost: {\n                  input: 0,\n                  output: 0,\n                  cacheRead: 0,\n                  cacheWrite: 0,\n                  total: 0\n                }\n              };\n              calculateCost(model, output.usage);\n            }\n          }\n          if (currentBlock) {\n            if (currentBlock.type === \"text\") {\n              stream11.push({\n                type: \"text_end\",\n                contentIndex: blockIndex(),\n                content: currentBlock.text,\n                partial: output\n              });\n            } else {\n              stream11.push({\n                type: \"thinking_end\",\n                contentIndex: blockIndex(),\n                content: currentBlock.thinking,\n                partial: output\n              });\n            }\n          }\n          if (options?.signal?.aborted) {\n            throw new Error(\"Request was aborted\");\n          }\n          if (output.stopReason === \"pending\") {\n            throw new Error(\"Google Vertex stream ended without a finish reason\");\n          }\n          if (output.stopReason === \"aborted\" || output.stopReason === \"error\") {\n            const errorMessage2 = output.rawStopReason ? `Provider stopped with: ${output.rawStopReason}` : \"An unknown error occurred\";\n            throw new Error(errorMessage2);\n          }\n          stream11.push({ type: \"done\", reason: output.stopReason, message: output });\n          stream11.end();\n        } catch (error) {\n          for (const block of output.content) {\n            if (\"index\" in block) {\n              delete block.index;\n            }\n          }\n          output.stopReason = options?.signal?.aborted ? \"aborted\" : \"error\";\n          output.errorMessage = formatProviderError(normalizeProviderError(error));\n          stream11.push({ type: \"error\", reason: output.stopReason, error: output });\n          stream11.end();\n        }\n      })();\n      return stream11;\n    };\n    streamSimple6 = (model, context, options) => {\n      const base = buildBaseOptions(model, context, options, void 0);\n      if (!options?.reasoning) {\n        return stream6(model, context, {\n          ...base,\n          thinking: { enabled: false }\n        });\n      }\n      const clampedReasoning = clampThinkingLevel(model, options.reasoning);\n      const effort = clampedReasoning === \"off\" ? \"high\" : clampedReasoning;\n      const geminiModel = model;\n      if (isGemini3ProModel2(geminiModel) || isGemini3FlashModel2(geminiModel)) {\n        return stream6(model, context, {\n          ...base,\n          thinking: {\n            enabled: true,\n            level: getGemini3ThinkingLevel(effort, geminiModel)\n          }\n        });\n      }\n      return stream6(model, context, {\n        ...base,\n        thinking: {\n          enabled: true,\n          budgetTokens: getGoogleBudget2(geminiModel, effort, options.thinkingBudgets)\n        }\n      });\n    };\n  }\n});\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/api/mistral-conversations.js\nvar mistral_conversations_exports = {};\n__export(mistral_conversations_exports, {\n  stream: () => stream7,\n  streamSimple: () => streamSimple7\n});\nfunction createOutput(model) {\n  return {\n    role: \"assistant\",\n    content: [],\n    api: model.api,\n    provider: model.provider,\n    model: model.id,\n    usage: {\n      input: 0,\n      output: 0,\n      cacheRead: 0,\n      cacheWrite: 0,\n      totalTokens: 0,\n      cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 }\n    },\n    stopReason: \"pending\",\n    timestamp: Date.now()\n  };\n}\nfunction createMistralToolCallIdNormalizer() {\n  const idMap = /* @__PURE__ */ new Map();\n  const reverseMap = /* @__PURE__ */ new Map();\n  return (id) => {\n    const existing = idMap.get(id);\n    if (existing)\n      return existing;\n    let attempt = 0;\n    while (true) {\n      const candidate = deriveMistralToolCallId(id, attempt);\n      const owner = reverseMap.get(candidate);\n      if (!owner || owner === id) {\n        idMap.set(id, candidate);\n        reverseMap.set(candidate, id);\n        return candidate;\n      }\n      attempt++;\n    }\n  };\n}\nfunction deriveMistralToolCallId(id, attempt) {\n  const normalized = id.replace(/[^a-zA-Z0-9]/g, \"\");\n  if (attempt === 0 && normalized.length === MISTRAL_TOOL_CALL_ID_LENGTH)\n    return normalized;\n  const seedBase = normalized || id;\n  const seed = attempt === 0 ? seedBase : `${seedBase}:${attempt}`;\n  return shortHash(seed).replace(/[^a-zA-Z0-9]/g, \"\").slice(0, MISTRAL_TOOL_CALL_ID_LENGTH);\n}\nfunction formatMistralError(error) {\n  if (error instanceof Error) {\n    const httpError = error;\n    const statusCode = typeof httpError.statusCode === \"number\" ? httpError.statusCode : void 0;\n    const bodyText = typeof httpError.body === \"string\" ? httpError.body.trim() : void 0;\n    if (statusCode !== void 0 && bodyText) {\n      return `Mistral API error (${statusCode}): ${truncateErrorText2(bodyText, MAX_MISTRAL_ERROR_BODY_CHARS)}`;\n    }\n    if (statusCode !== void 0)\n      return `Mistral API error (${statusCode}): ${error.message}`;\n    return error.message;\n  }\n  return safeJsonStringify3(error);\n}\nfunction truncateErrorText2(text, maxChars) {\n  if (text.length <= maxChars)\n    return text;\n  return `${text.slice(0, maxChars)}... [truncated ${text.length - maxChars} chars]`;\n}\nfunction safeJsonStringify3(value) {\n  try {\n    const serialized = JSON.stringify(value);\n    return serialized === void 0 ? String(value) : serialized;\n  } catch {\n    return String(value);\n  }\n}\nasync function requestMistralStream(model, payload, apiKey, options) {\n  const baseUrl = new URL(model.baseUrl);\n  baseUrl.pathname = `${baseUrl.pathname.replace(/\\/+$/u, \"\")}/`;\n  const url = new URL(\"v1/chat/completions\", baseUrl);\n  const headers = buildMistralHeaders(model, apiKey, options);\n  const timeoutSignal = AbortSignal.timeout(options?.timeoutMs ?? 6e4);\n  const signal = options?.signal ? AbortSignal.any([options.signal, timeoutSignal]) : timeoutSignal;\n  const response = await (options?.fetch ?? globalThis.fetch)(url, {\n    method: \"POST\",\n    headers,\n    body: JSON.stringify(toMistralWirePayload(payload)),\n    signal\n  });\n  await options?.onResponse?.({ status: response.status, headers: headersToRecord(response.headers) }, model);\n  if (!response.ok) {\n    const body = await response.text();\n    throw new MistralHttpError(response.status, body, response.statusText);\n  }\n  if (!response.body) {\n    throw new Error(\"Mistral response has no body\");\n  }\n  return readMistralEvents(response.body, signal);\n}\nfunction buildMistralHeaders(model, apiKey, options) {\n  const headers = new Headers({\n    accept: \"text/event-stream\",\n    authorization: `Bearer ${apiKey}`,\n    \"content-type\": \"application/json\"\n  });\n  applyMistralHeaderOverrides(headers, model.headers);\n  applyMistralHeaderOverrides(headers, options?.headers);\n  const hasExplicitAffinity = hasMistralHeaderOverride(model.headers, \"x-affinity\") || hasMistralHeaderOverride(options?.headers, \"x-affinity\");\n  if (shouldUsePromptCaching(options) && !hasExplicitAffinity) {\n    headers.set(\"x-affinity\", options.sessionId);\n  }\n  return headers;\n}\nfunction applyMistralHeaderOverrides(headers, overrides) {\n  if (!overrides)\n    return;\n  for (const [name, value] of Object.entries(overrides)) {\n    if (value === null)\n      headers.delete(name);\n    else\n      headers.set(name, value);\n  }\n}\nfunction hasMistralHeaderOverride(overrides, target) {\n  return !!overrides && Object.keys(overrides).some((name) => name.toLowerCase() === target);\n}\nfunction toMistralWirePayload(payload) {\n  const wirePayload = { ...payload };\n  for (const [source, target] of [\n    [\"topP\", \"top_p\"],\n    [\"maxTokens\", \"max_tokens\"],\n    [\"randomSeed\", \"random_seed\"],\n    [\"responseFormat\", \"response_format\"],\n    [\"toolChoice\", \"tool_choice\"],\n    [\"presencePenalty\", \"presence_penalty\"],\n    [\"frequencyPenalty\", \"frequency_penalty\"],\n    [\"parallelToolCalls\", \"parallel_tool_calls\"],\n    [\"reasoningEffort\", \"reasoning_effort\"],\n    [\"promptMode\", \"prompt_mode\"],\n    [\"promptCacheKey\", \"prompt_cache_key\"],\n    [\"safePrompt\", \"safe_prompt\"]\n  ]) {\n    remapMistralProperty(wirePayload, source, target);\n  }\n  wirePayload.messages = payload.messages.map((message) => toMistralWireMessage(message));\n  const responseFormat = wirePayload.response_format;\n  if (isMistralRecord(responseFormat)) {\n    const wireResponseFormat = { ...responseFormat };\n    remapMistralProperty(wireResponseFormat, \"jsonSchema\", \"json_schema\");\n    const jsonSchema = wireResponseFormat.json_schema;\n    if (isMistralRecord(jsonSchema)) {\n      const wireJsonSchema = { ...jsonSchema };\n      remapMistralProperty(wireJsonSchema, \"schemaDefinition\", \"schema\");\n      wireResponseFormat.json_schema = wireJsonSchema;\n    }\n    wirePayload.response_format = wireResponseFormat;\n  }\n  return wirePayload;\n}\nfunction toMistralWireMessage(message) {\n  const wireMessage = { ...message };\n  remapMistralProperty(wireMessage, \"toolCalls\", \"tool_calls\");\n  remapMistralProperty(wireMessage, \"toolCallId\", \"tool_call_id\");\n  if (Array.isArray(message.content)) {\n    wireMessage.content = message.content.map((chunk) => toMistralWireContentChunk(chunk));\n  }\n  return wireMessage;\n}\nfunction toMistralWireContentChunk(chunk) {\n  const wireChunk = { ...chunk };\n  for (const [source, target] of [\n    [\"imageUrl\", \"image_url\"],\n    [\"documentUrl\", \"document_url\"],\n    [\"documentName\", \"document_name\"],\n    [\"fileId\", \"file_id\"],\n    [\"referenceIds\", \"reference_ids\"],\n    [\"inputAudio\", \"input_audio\"]\n  ]) {\n    remapMistralProperty(wireChunk, source, target);\n  }\n  return wireChunk;\n}\nfunction remapMistralProperty(record, source, target) {\n  if (!(source in record))\n    return;\n  record[target] = record[source];\n  delete record[source];\n}\nfunction isMistralRecord(value) {\n  return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\nasync function* readMistralEvents(body, signal) {\n  const reader = body.getReader();\n  const decoder = new TextDecoder();\n  let buffer = \"\";\n  const onAbort = () => {\n    void reader.cancel().catch(() => {\n    });\n  };\n  signal.addEventListener(\"abort\", onAbort, { once: true });\n  try {\n    while (true) {\n      if (signal.aborted)\n        throw signal.reason;\n      const { done, value } = await reader.read();\n      if (signal.aborted)\n        throw signal.reason;\n      buffer += done ? decoder.decode() : decoder.decode(value, { stream: true });\n      let boundary = findMistralEventBoundary(buffer);\n      while (boundary) {\n        const event = parseMistralEvent(buffer.slice(0, boundary.index));\n        buffer = buffer.slice(boundary.index + boundary.length);\n        if (event === MISTRAL_STREAM_DONE)\n          return;\n        if (event)\n          yield event;\n        boundary = findMistralEventBoundary(buffer);\n      }\n      if (done)\n        break;\n    }\n    if (buffer.trim()) {\n      const event = parseMistralEvent(buffer);\n      if (event !== MISTRAL_STREAM_DONE && event)\n        yield event;\n    }\n  } finally {\n    signal.removeEventListener(\"abort\", onAbort);\n    try {\n      await reader.cancel();\n    } catch {\n    }\n    try {\n      reader.releaseLock();\n    } catch {\n    }\n  }\n}\nfunction findMistralEventBoundary(buffer) {\n  const match = /\\r\\n\\r\\n|\\r\\n\\r|\\r\\n\\n|\\r\\r\\n|\\n\\r\\n|\\r\\r|\\n\\r|\\n\\n/u.exec(buffer);\n  return match?.index === void 0 ? void 0 : { index: match.index, length: match[0].length };\n}\nfunction parseMistralEvent(raw) {\n  const data = raw.split(/\\r\\n|\\r|\\n/u).filter((line) => line.startsWith(\"data:\")).map((line) => line.slice(5).trimStart()).join(\"\\n\").trim();\n  if (!data)\n    return void 0;\n  if (data === \"[DONE]\")\n    return MISTRAL_STREAM_DONE;\n  const parsed = JSON.parse(data);\n  if (!isMistralRecord(parsed) || !Array.isArray(parsed.choices)) {\n    throw new Error(\"Invalid Mistral streaming event\");\n  }\n  return { data: parsed };\n}\nfunction buildChatPayload(model, context, messages, options) {\n  const payload = {\n    model: model.id,\n    stream: true,\n    messages: toChatMessages(messages, model.input.includes(\"image\"))\n  };\n  if (context.tools?.length)\n    payload.tools = toFunctionTools(context.tools);\n  if (options?.temperature !== void 0)\n    payload.temperature = options.temperature;\n  if (options?.maxTokens !== void 0)\n    payload.maxTokens = options.maxTokens;\n  if (options?.toolChoice)\n    payload.toolChoice = mapToolChoice2(options.toolChoice);\n  if (options?.promptMode)\n    payload.promptMode = options.promptMode;\n  if (options?.reasoningEffort)\n    payload.reasoningEffort = options.reasoningEffort;\n  if (shouldUsePromptCaching(options))\n    payload.promptCacheKey = options.sessionId;\n  if (context.systemPrompt) {\n    payload.messages.unshift({\n      role: \"system\",\n      content: sanitizeSurrogates(context.systemPrompt)\n    });\n  }\n  return payload;\n}\nfunction shouldUsePromptCaching(options) {\n  return options?.cacheRetention !== \"none\" && !!options?.sessionId;\n}\nfunction getMistralCachedPromptTokens(usage, promptTokens) {\n  const rawUsage = usage;\n  const rawCachedTokens = rawUsage.promptTokensDetails?.cachedTokens ?? rawUsage.prompt_tokens_details?.cached_tokens ?? rawUsage.promptTokenDetails?.cachedTokens ?? rawUsage.prompt_token_details?.cached_tokens ?? rawUsage.numCachedTokens ?? rawUsage.num_cached_tokens ?? 0;\n  const cachedTokens = typeof rawCachedTokens === \"number\" && Number.isFinite(rawCachedTokens) ? rawCachedTokens : 0;\n  return Math.min(promptTokens, Math.max(0, cachedTokens));\n}\nasync function consumeChatStream(model, output, stream11, mistralStream) {\n  let currentBlock = null;\n  const blocks = output.content;\n  const blockIndex = () => blocks.length - 1;\n  const toolBlocksByKey = /* @__PURE__ */ new Map();\n  const finishCurrentBlock = (block) => {\n    if (!block)\n      return;\n    if (block.type === \"text\") {\n      stream11.push({\n        type: \"text_end\",\n        contentIndex: blockIndex(),\n        content: block.text,\n        partial: output\n      });\n      return;\n    }\n    if (block.type === \"thinking\") {\n      stream11.push({\n        type: \"thinking_end\",\n        contentIndex: blockIndex(),\n        content: block.thinking,\n        partial: output\n      });\n    }\n  };\n  for await (const event of mistralStream) {\n    const chunk = event.data;\n    output.responseId ||= chunk.id;\n    if (chunk.usage) {\n      const promptTokens = chunk.usage.prompt_tokens || 0;\n      const cachedPromptTokens = getMistralCachedPromptTokens(chunk.usage, promptTokens);\n      output.usage.input = Math.max(0, promptTokens - cachedPromptTokens);\n      output.usage.output = chunk.usage.completion_tokens || 0;\n      output.usage.cacheRead = cachedPromptTokens;\n      output.usage.cacheWrite = 0;\n      output.usage.totalTokens = chunk.usage.total_tokens || output.usage.input + output.usage.output + output.usage.cacheRead + output.usage.cacheWrite;\n      calculateCost(model, output.usage);\n    }\n    const choice = chunk.choices[0];\n    if (!choice)\n      continue;\n    if (choice.finish_reason) {\n      output.rawStopReason = choice.finish_reason;\n      const stopReasonResult = mapChatStopReason(choice.finish_reason);\n      output.stopReason = stopReasonResult.stopReason;\n      if (stopReasonResult.errorMessage) {\n        output.errorMessage = stopReasonResult.errorMessage;\n      }\n    }\n    const delta = choice.delta;\n    if (delta.content !== null && delta.content !== void 0) {\n      const contentItems = typeof delta.content === \"string\" ? [delta.content] : delta.content;\n      for (const item of contentItems) {\n        if (typeof item === \"string\") {\n          const textDelta = sanitizeSurrogates(item);\n          if (!currentBlock || currentBlock.type !== \"text\") {\n            finishCurrentBlock(currentBlock);\n            currentBlock = { type: \"text\", text: \"\" };\n            output.content.push(currentBlock);\n            stream11.push({ type: \"text_start\", contentIndex: blockIndex(), partial: output });\n          }\n          currentBlock.text += textDelta;\n          stream11.push({\n            type: \"text_delta\",\n            contentIndex: blockIndex(),\n            delta: textDelta,\n            partial: output\n          });\n          continue;\n        }\n        if (item.type === \"thinking\") {\n          const deltaText = (item.thinking ?? []).map((part) => part.text ?? \"\").filter((text) => text.length > 0).join(\"\");\n          const thinkingDelta = sanitizeSurrogates(deltaText);\n          if (!thinkingDelta)\n            continue;\n          if (!currentBlock || currentBlock.type !== \"thinking\") {\n            finishCurrentBlock(currentBlock);\n            currentBlock = { type: \"thinking\", thinking: \"\" };\n            output.content.push(currentBlock);\n            stream11.push({ type: \"thinking_start\", contentIndex: blockIndex(), partial: output });\n          }\n          currentBlock.thinking += thinkingDelta;\n          stream11.push({\n            type: \"thinking_delta\",\n            contentIndex: blockIndex(),\n            delta: thinkingDelta,\n            partial: output\n          });\n          continue;\n        }\n        if (item.type === \"text\") {\n          const textDelta = sanitizeSurrogates(item.text ?? \"\");\n          if (!currentBlock || currentBlock.type !== \"text\") {\n            finishCurrentBlock(currentBlock);\n            currentBlock = { type: \"text\", text: \"\" };\n            output.content.push(currentBlock);\n            stream11.push({ type: \"text_start\", contentIndex: blockIndex(), partial: output });\n          }\n          currentBlock.text += textDelta;\n          stream11.push({\n            type: \"text_delta\",\n            contentIndex: blockIndex(),\n            delta: textDelta,\n            partial: output\n          });\n        }\n      }\n    }\n    const toolCalls = delta.tool_calls || [];\n    for (const toolCall of toolCalls) {\n      if (currentBlock) {\n        finishCurrentBlock(currentBlock);\n        currentBlock = null;\n      }\n      const callId = toolCall.id && toolCall.id !== \"null\" ? toolCall.id : deriveMistralToolCallId(`toolcall:${toolCall.index ?? 0}`, 0);\n      const key = `${callId}:${toolCall.index || 0}`;\n      const existingIndex = toolBlocksByKey.get(key);\n      let block;\n      if (existingIndex !== void 0) {\n        const existing = output.content[existingIndex];\n        if (existing?.type === \"toolCall\") {\n          block = existing;\n        }\n      }\n      if (!block) {\n        block = {\n          type: \"toolCall\",\n          id: callId,\n          name: toolCall.function.name,\n          arguments: {},\n          partialArgs: \"\"\n        };\n        output.content.push(block);\n        toolBlocksByKey.set(key, output.content.length - 1);\n        stream11.push({ type: \"toolcall_start\", contentIndex: output.content.length - 1, partial: output });\n      }\n      const argsDelta = typeof toolCall.function.arguments === \"string\" ? toolCall.function.arguments : JSON.stringify(toolCall.function.arguments || {});\n      block.partialArgs = (block.partialArgs || \"\") + argsDelta;\n      block.arguments = parseStreamingJson(block.partialArgs);\n      stream11.push({\n        type: \"toolcall_delta\",\n        contentIndex: toolBlocksByKey.get(key),\n        delta: argsDelta,\n        partial: output\n      });\n    }\n  }\n  finishCurrentBlock(currentBlock);\n  for (const index of toolBlocksByKey.values()) {\n    const block = output.content[index];\n    if (block.type !== \"toolCall\")\n      continue;\n    const toolBlock = block;\n    toolBlock.arguments = parseStreamingJson(toolBlock.partialArgs);\n    delete toolBlock.partialArgs;\n    stream11.push({\n      type: \"toolcall_end\",\n      contentIndex: index,\n      toolCall: toolBlock,\n      partial: output\n    });\n  }\n}\nfunction toFunctionTools(tools) {\n  return tools.map((tool) => {\n    const strict = resolveJsonSchemaStrictSampling(tool, true);\n    return {\n      type: \"function\",\n      function: {\n        name: tool.name,\n        description: tool.description,\n        parameters: stripSymbolKeys(getJsonSchemaToolParameters(tool, strict)),\n        strict: strict ?? false\n      }\n    };\n  });\n}\nfunction stripSymbolKeys(value) {\n  if (Array.isArray(value)) {\n    return value.map((item) => stripSymbolKeys(item));\n  }\n  if (value && typeof value === \"object\") {\n    const result = {};\n    for (const [key, entry] of Object.entries(value)) {\n      result[key] = stripSymbolKeys(entry);\n    }\n    return result;\n  }\n  return value;\n}\nfunction toChatMessages(messages, supportsImages) {\n  const result = [];\n  for (const msg of messages) {\n    if (msg.role === \"user\") {\n      if (typeof msg.content === \"string\") {\n        result.push({ role: \"user\", content: sanitizeSurrogates(msg.content) });\n        continue;\n      }\n      const hadImages = msg.content.some((item) => item.type === \"image\");\n      const content = msg.content.filter((item) => item.type === \"text\" || supportsImages).map((item) => {\n        if (item.type === \"text\")\n          return { type: \"text\", text: sanitizeSurrogates(item.text) };\n        return { type: \"image_url\", imageUrl: `data:${item.mimeType};base64,${item.data}` };\n      });\n      if (content.length > 0) {\n        result.push({ role: \"user\", content });\n        continue;\n      }\n      if (hadImages && !supportsImages) {\n        result.push({ role: \"user\", content: \"(image omitted: model does not support images)\" });\n      }\n      continue;\n    }\n    if (msg.role === \"assistant\") {\n      const contentParts = [];\n      const toolCalls = [];\n      for (const block of msg.content) {\n        if (block.type === \"text\") {\n          if (block.text.trim().length > 0) {\n            contentParts.push({ type: \"text\", text: sanitizeSurrogates(block.text) });\n          }\n          continue;\n        }\n        if (block.type === \"thinking\") {\n          if (block.thinking.trim().length > 0) {\n            contentParts.push({\n              type: \"thinking\",\n              thinking: [{ type: \"text\", text: sanitizeSurrogates(block.thinking) }]\n            });\n          }\n          continue;\n        }\n        toolCalls.push({\n          id: block.id,\n          type: \"function\",\n          function: { name: block.name, arguments: JSON.stringify(block.arguments || {}) },\n          index: 0\n        });\n      }\n      const assistantMessage = { role: \"assistant\", prefix: false };\n      if (contentParts.length > 0)\n        assistantMessage.content = contentParts;\n      if (toolCalls.length > 0)\n        assistantMessage.toolCalls = toolCalls;\n      if (contentParts.length > 0 || toolCalls.length > 0)\n        result.push(assistantMessage);\n      continue;\n    }\n    const toolContent = [];\n    const textResult = msg.content.filter((part) => part.type === \"text\").map((part) => part.type === \"text\" ? sanitizeSurrogates(part.text) : \"\").join(\"\\n\");\n    const hasImages = msg.content.some((part) => part.type === \"image\");\n    const toolText = buildToolResultText(textResult, hasImages, supportsImages, msg.isError);\n    toolContent.push({ type: \"text\", text: toolText });\n    for (const part of msg.content) {\n      if (!supportsImages)\n        continue;\n      if (part.type !== \"image\")\n        continue;\n      toolContent.push({\n        type: \"image_url\",\n        imageUrl: `data:${part.mimeType};base64,${part.data}`\n      });\n    }\n    result.push({\n      role: \"tool\",\n      toolCallId: msg.toolCallId,\n      name: msg.toolName,\n      content: toolContent\n    });\n  }\n  return result;\n}\nfunction buildToolResultText(text, hasImages, supportsImages, isError) {\n  const trimmed = text.trim();\n  const errorPrefix = isError ? \"[tool error] \" : \"\";\n  if (trimmed.length > 0) {\n    const imageSuffix = hasImages && !supportsImages ? \"\\n[tool image omitted: model does not support images]\" : \"\";\n    return `${errorPrefix}${trimmed}${imageSuffix}`;\n  }\n  if (hasImages) {\n    if (supportsImages) {\n      return isError ? \"[tool error] (see attached image)\" : \"(see attached image)\";\n    }\n    return isError ? \"[tool error] (image omitted: model does not support images)\" : \"(image omitted: model does not support images)\";\n  }\n  return isError ? \"[tool error] (no tool output)\" : \"(no tool output)\";\n}\nfunction usesReasoningEffort(model) {\n  return model.id === \"mistral-small-2603\" || model.id === \"mistral-small-latest\" || model.id === \"mistral-medium-3.5\";\n}\nfunction usesPromptModeReasoning(model) {\n  return model.reasoning && !usesReasoningEffort(model);\n}\nfunction mapReasoningEffort(model, level) {\n  return model.thinkingLevelMap?.[level] ?? \"high\";\n}\nfunction mapToolChoice2(choice) {\n  if (!choice)\n    return void 0;\n  if (choice === \"auto\" || choice === \"none\" || choice === \"any\" || choice === \"required\") {\n    return choice;\n  }\n  return {\n    type: \"function\",\n    function: { name: choice.function.name }\n  };\n}\nfunction mapChatStopReason(reason) {\n  if (reason === null)\n    return { stopReason: \"stop\" };\n  switch (reason) {\n    case \"stop\":\n      return { stopReason: \"stop\" };\n    case \"length\":\n    case \"model_length\":\n      return { stopReason: \"length\" };\n    case \"tool_calls\":\n      return { stopReason: \"toolUse\" };\n    case \"error\":\n      return { stopReason: \"error\", errorMessage: \"Provider stopped with: error\" };\n    default:\n      return { stopReason: \"error\", errorMessage: `Provider stopped with: ${reason}` };\n  }\n}\nvar MISTRAL_TOOL_CALL_ID_LENGTH, MAX_MISTRAL_ERROR_BODY_CHARS, stream7, streamSimple7, MistralHttpError, MISTRAL_STREAM_DONE;\nvar init_mistral_conversations = __esm({\n  \"node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/api/mistral-conversations.js\"() {\n    init_models();\n    init_event_stream();\n    init_hash();\n    init_headers();\n    init_json_parse();\n    init_sanitize_unicode();\n    init_constrained_sampling();\n    init_simple_options();\n    init_transform_messages();\n    MISTRAL_TOOL_CALL_ID_LENGTH = 9;\n    MAX_MISTRAL_ERROR_BODY_CHARS = 4e3;\n    stream7 = (model, context, options) => {\n      const stream11 = new AssistantMessageEventStream();\n      (async () => {\n        const output = createOutput(model);\n        try {\n          const apiKey = options?.apiKey;\n          if (!apiKey) {\n            throw new Error(`No API key for provider: ${model.provider}`);\n          }\n          const normalizeMistralToolCallId = createMistralToolCallIdNormalizer();\n          const transformedMessages = transformMessages(context.messages, model, (id) => normalizeMistralToolCallId(id));\n          let payload = buildChatPayload(model, context, transformedMessages, options);\n          const nextPayload = await options?.onPayload?.(payload, model);\n          if (nextPayload !== void 0) {\n            payload = nextPayload;\n          }\n          const mistralStream = await requestMistralStream(model, payload, apiKey, options);\n          stream11.push({ type: \"start\", partial: output });\n          await consumeChatStream(model, output, stream11, mistralStream);\n          if (options?.signal?.aborted) {\n            throw new Error(\"Request was aborted\");\n          }\n          if (output.stopReason === \"pending\") {\n            throw new Error(\"Mistral stream ended without a finish reason\");\n          }\n          if (output.stopReason === \"aborted\" || output.stopReason === \"error\") {\n            throw new Error(output.errorMessage || \"An unknown error occurred\");\n          }\n          stream11.push({ type: \"done\", reason: output.stopReason, message: output });\n          stream11.end();\n        } catch (error) {\n          for (const block of output.content) {\n            delete block.partialArgs;\n          }\n          output.stopReason = options?.signal?.aborted ? \"aborted\" : \"error\";\n          output.errorMessage = formatMistralError(error);\n          stream11.push({ type: \"error\", reason: output.stopReason, error: output });\n          stream11.end();\n        }\n      })();\n      return stream11;\n    };\n    streamSimple7 = (model, context, options) => {\n      const apiKey = options?.apiKey;\n      if (!apiKey) {\n        throw new Error(`No API key for provider: ${model.provider}`);\n      }\n      const base = buildBaseOptions(model, context, options, apiKey);\n      const clampedReasoning = options?.reasoning ? clampThinkingLevel(model, options.reasoning) : void 0;\n      const reasoning = clampedReasoning === \"off\" ? void 0 : clampedReasoning;\n      const shouldUseReasoning = model.reasoning && reasoning !== void 0;\n      return stream7(model, context, {\n        ...base,\n        promptMode: shouldUseReasoning && usesPromptModeReasoning(model) ? \"reasoning\" : void 0,\n        reasoningEffort: shouldUseReasoning && usesReasoningEffort(model) ? mapReasoningEffort(model, reasoning) : void 0\n      });\n    };\n    MistralHttpError = class extends Error {\n      statusCode;\n      body;\n      constructor(statusCode, body, statusText) {\n        super(statusText || `Request failed with status ${statusCode}`);\n        this.name = \"MistralHttpError\";\n        this.statusCode = statusCode;\n        this.body = body;\n      }\n    };\n    MISTRAL_STREAM_DONE = Symbol(\"mistral-stream-done\");\n  }\n});\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/utils/abort-signals.js\nfunction combineAbortSignals(signals) {\n  const activeSignals = signals.filter((signal) => signal !== void 0);\n  if (activeSignals.length === 0) {\n    return { cleanup: () => {\n    } };\n  }\n  if (activeSignals.length === 1) {\n    return { signal: activeSignals[0], cleanup: () => {\n    } };\n  }\n  const controller = new AbortController();\n  const listeners = [];\n  const abort = (signal) => {\n    if (!controller.signal.aborted) {\n      controller.abort(signal.reason);\n    }\n  };\n  for (const signal of activeSignals) {\n    if (signal.aborted) {\n      abort(signal);\n      break;\n    }\n    const listener = () => abort(signal);\n    signal.addEventListener(\"abort\", listener, { once: true });\n    listeners.push({ signal, listener });\n  }\n  return {\n    signal: controller.signal,\n    cleanup: () => {\n      for (const { signal, listener } of listeners) {\n        signal.removeEventListener(\"abort\", listener);\n      }\n    }\n  };\n}\nvar init_abort_signals = __esm({\n  \"node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/utils/abort-signals.js\"() {\n  }\n});\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/utils/node-http-proxy.js\nfunction getProxyEnv(key, env) {\n  const lowercaseKey = key.toLowerCase();\n  const uppercaseKey = key.toUpperCase();\n  return env?.[lowercaseKey] || env?.[uppercaseKey] || getProviderEnvValue(lowercaseKey) || getProviderEnvValue(uppercaseKey) || \"\";\n}\nfunction parseProxyTargetUrl(targetUrl) {\n  if (targetUrl instanceof URL) {\n    return targetUrl;\n  }\n  try {\n    return new URL(targetUrl);\n  } catch {\n    return void 0;\n  }\n}\nfunction shouldProxyHostname(hostname, port, env) {\n  const noProxy = getProxyEnv(\"no_proxy\", env).toLowerCase();\n  if (!noProxy) {\n    return true;\n  }\n  if (noProxy === \"*\") {\n    return false;\n  }\n  return noProxy.split(/[,\\s]/).every((proxy) => {\n    if (!proxy) {\n      return true;\n    }\n    const parsedProxy = proxy.match(/^(.+):(\\d+)$/);\n    let proxyHostname = parsedProxy ? parsedProxy[1] : proxy;\n    const proxyPort = parsedProxy ? Number.parseInt(parsedProxy[2], 10) : 0;\n    if (proxyPort && proxyPort !== port) {\n      return true;\n    }\n    if (!/^[.*]/.test(proxyHostname)) {\n      return hostname !== proxyHostname;\n    }\n    if (proxyHostname.startsWith(\"*\")) {\n      proxyHostname = proxyHostname.slice(1);\n    }\n    return !hostname.endsWith(proxyHostname);\n  });\n}\nfunction getProxyForUrl(targetUrl, env) {\n  const parsedUrl = parseProxyTargetUrl(targetUrl);\n  if (!parsedUrl?.protocol || !parsedUrl.host) {\n    return \"\";\n  }\n  const protocol = parsedUrl.protocol.split(\":\", 1)[0];\n  const hostname = parsedUrl.host.replace(/:\\d*$/, \"\");\n  const port = Number.parseInt(parsedUrl.port, 10) || DEFAULT_PROXY_PORTS[protocol] || 0;\n  if (!shouldProxyHostname(hostname, port, env)) {\n    return \"\";\n  }\n  let proxy = getProxyEnv(`${protocol}_proxy`, env) || getProxyEnv(\"all_proxy\", env);\n  if (proxy && !proxy.includes(\"://\")) {\n    proxy = `${protocol}://${proxy}`;\n  }\n  return proxy;\n}\nfunction resolveHttpProxyUrlForTarget(targetUrl, env) {\n  const proxy = getProxyForUrl(targetUrl, env);\n  if (!proxy) {\n    return void 0;\n  }\n  let proxyUrl;\n  try {\n    proxyUrl = new URL(proxy);\n  } catch (error) {\n    throw new Error(`Invalid proxy URL ${JSON.stringify(proxy)}: ${error instanceof Error ? error.message : String(error)}`);\n  }\n  if (proxyUrl.protocol !== \"http:\" && proxyUrl.protocol !== \"https:\") {\n    throw new Error(`${UNSUPPORTED_PROXY_PROTOCOL_MESSAGE} Got ${proxyUrl.protocol}`);\n  }\n  return proxyUrl;\n}\nvar DEFAULT_PROXY_PORTS, UNSUPPORTED_PROXY_PROTOCOL_MESSAGE;\nvar init_node_http_proxy = __esm({\n  \"node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/utils/node-http-proxy.js\"() {\n    init_provider_env();\n    DEFAULT_PROXY_PORTS = {\n      ftp: 21,\n      gopher: 70,\n      http: 80,\n      https: 443,\n      ws: 80,\n      wss: 443\n    };\n    UNSUPPORTED_PROXY_PROTOCOL_MESSAGE = \"Unsupported proxy protocol. SOCKS and PAC proxy URLs are not supported; use an HTTP or HTTPS proxy URL.\";\n  }\n});\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/api/openai-codex-responses.js\nvar openai_codex_responses_exports = {};\n__export(openai_codex_responses_exports, {\n  closeOpenAICodexWebSocketSessions: () => closeOpenAICodexWebSocketSessions,\n  getOpenAICodexWebSocketDebugStats: () => getOpenAICodexWebSocketDebugStats,\n  resetOpenAICodexWebSocketDebugStats: () => resetOpenAICodexWebSocketDebugStats,\n  stream: () => stream8,\n  streamSimple: () => streamSimple8\n});\nfunction assertSuccessfulOutput(output) {\n  if (output.stopReason === \"pending\") {\n    throw new Error(\"Codex stream ended without a stop reason\");\n  }\n  if (output.stopReason === \"error\" || output.stopReason === \"aborted\") {\n    throw new Error(output.errorMessage || \"An unknown error occurred\");\n  }\n}\nfunction isTerminalRateLimitError(errorText) {\n  return /GoUsageLimitError|FreeUsageLimitError|Monthly usage limit reached|available balance|insufficient_quota|out of budget|quota exceeded|billing/i.test(errorText);\n}\nfunction isRetryableError(status, errorText) {\n  if (status === 429 && isTerminalRateLimitError(errorText)) {\n    return false;\n  }\n  if (status === 429 || status === 500 || status === 502 || status === 503 || status === 504) {\n    return true;\n  }\n  return /rate.?limit|overloaded|service.?unavailable|upstream.?connect|connection.?refused/i.test(errorText);\n}\nfunction getRetryAfterDelayMs(headers) {\n  const retryAfterMs = headers.get(\"retry-after-ms\");\n  if (retryAfterMs !== null) {\n    const millis = Number(retryAfterMs);\n    if (Number.isFinite(millis)) {\n      return Math.max(0, millis);\n    }\n  }\n  const retryAfter = headers.get(\"retry-after\");\n  if (!retryAfter) {\n    return void 0;\n  }\n  const seconds = Number(retryAfter);\n  if (Number.isFinite(seconds)) {\n    return Math.max(0, seconds * 1e3);\n  }\n  const date = Date.parse(retryAfter);\n  if (!Number.isNaN(date)) {\n    return Math.max(0, date - Date.now());\n  }\n  return void 0;\n}\nfunction validateRetryDelayMs(delayMs, options) {\n  const maxRetryDelayMs = options?.maxRetryDelayMs ?? DEFAULT_MAX_RETRY_DELAY_MS2;\n  if (maxRetryDelayMs > 0 && delayMs > maxRetryDelayMs) {\n    throw new RetryDelayExceededError(`Server requested ${Math.ceil(delayMs / 1e3)}s retry delay (max: ${Math.ceil(maxRetryDelayMs / 1e3)}s)`);\n  }\n  return delayMs;\n}\nfunction sleep2(ms, signal) {\n  return new Promise((resolve15, reject) => {\n    if (signal?.aborted) {\n      reject(new Error(\"Request was aborted\"));\n      return;\n    }\n    const timeout = setTimeout(resolve15, ms);\n    signal?.addEventListener(\"abort\", () => {\n      clearTimeout(timeout);\n      reject(new Error(\"Request was aborted\"));\n    });\n  });\n}\nfunction normalizeTimeoutMs(value) {\n  if (value === void 0)\n    return void 0;\n  if (!Number.isFinite(value) || value < 0) {\n    throw new Error(`Invalid timeoutMs: ${String(value)}`);\n  }\n  return Math.floor(value);\n}\nfunction loadNodeZlib() {\n  if (typeof process === \"undefined\" || !(process.versions?.node || process.versions?.bun)) {\n    return null;\n  }\n  return process.getBuiltinModule?.(\"node:zlib\") ?? null;\n}\nfunction compressRequestBodyZstd(bodyJson) {\n  const zlib = loadNodeZlib();\n  if (!zlib || typeof zlib.zstdCompressSync !== \"function\") {\n    return null;\n  }\n  try {\n    const compressed = zlib.zstdCompressSync(bodyJson, {\n      params: { [zlib.constants.ZSTD_c_compressionLevel]: REQUEST_COMPRESSION_ZSTD_LEVEL }\n    });\n    return new Uint8Array(compressed.buffer, compressed.byteOffset, compressed.byteLength);\n  } catch {\n    return null;\n  }\n}\nfunction buildRequestBody(model, context, options, cacheSessionId, grammarToolInputProperties = createGrammarToolInputProperties(context.tools, model.compat?.supportsOpenAIGrammarTools ?? false)) {\n  const supportsStrictMode = model.compat?.supportsStrictMode ?? true;\n  const supportsOpenAIGrammarTools = model.compat?.supportsOpenAIGrammarTools ?? false;\n  const deferredToolsMode = model.compat?.supportsAdditionalTools ? \"additional-tools\" : model.compat?.supportsToolSearch ? \"tool-search\" : void 0;\n  const toolPlacement = splitDeferredTools(context, deferredToolsMode !== void 0);\n  const messages = convertResponsesMessages(model, context, CODEX_TOOL_CALL_PROVIDERS, {\n    includeSystemPrompt: false,\n    grammarToolInputProperties,\n    deferredTools: toolPlacement.deferred,\n    deferredToolsMode,\n    toolOptions: {\n      strict: null,\n      supportsStrictMode,\n      supportsOpenAIGrammarTools\n    }\n  });\n  const body = {\n    model: model.id,\n    store: false,\n    stream: true,\n    instructions: context.systemPrompt || \"You are a helpful assistant.\",\n    input: messages,\n    text: { verbosity: options?.textVerbosity || \"low\" },\n    include: [\"reasoning.encrypted_content\"],\n    prompt_cache_key: cacheSessionId,\n    tool_choice: options?.toolChoice ?? \"auto\",\n    parallel_tool_calls: true\n  };\n  if (options?.temperature !== void 0) {\n    body.temperature = options.temperature;\n  }\n  if (options?.serviceTier !== void 0) {\n    body.service_tier = options.serviceTier;\n  }\n  if (toolPlacement.immediate.length > 0) {\n    body.tools = convertResponsesTools(toolPlacement.immediate, {\n      strict: null,\n      supportsStrictMode,\n      supportsOpenAIGrammarTools\n    });\n  }\n  if (options?.reasoningEffort !== void 0) {\n    const effort = options.reasoningEffort === \"none\" ? model.thinkingLevelMap?.off ?? \"none\" : model.thinkingLevelMap?.[options.reasoningEffort] ?? options.reasoningEffort;\n    if (effort !== null) {\n      body.reasoning = {\n        effort,\n        summary: options.reasoningSummary ?? \"auto\"\n      };\n    }\n  }\n  return body;\n}\nfunction getServiceTierCostMultiplier2(model, serviceTier) {\n  switch (serviceTier) {\n    case \"flex\":\n      return 0.5;\n    case \"priority\":\n      return model.id === \"gpt-5.5\" ? 2.5 : 2;\n    default:\n      return 1;\n  }\n}\nfunction applyServiceTierPricing2(usage, serviceTier, model) {\n  const multiplier = getServiceTierCostMultiplier2(model, serviceTier);\n  if (multiplier === 1)\n    return;\n  usage.cost.input *= multiplier;\n  usage.cost.output *= multiplier;\n  usage.cost.cacheRead *= multiplier;\n  usage.cost.cacheWrite *= multiplier;\n  usage.cost.total = usage.cost.input + usage.cost.output + usage.cost.cacheRead + usage.cost.cacheWrite;\n}\nfunction resolveCodexServiceTier(responseServiceTier, requestServiceTier) {\n  if (responseServiceTier === \"default\" && (requestServiceTier === \"flex\" || requestServiceTier === \"priority\")) {\n    return requestServiceTier;\n  }\n  return responseServiceTier ?? requestServiceTier;\n}\nfunction resolveCodexUrl(baseUrl) {\n  const raw = baseUrl && baseUrl.trim().length > 0 ? baseUrl : DEFAULT_CODEX_BASE_URL;\n  const normalized = raw.replace(/\\/+$/, \"\");\n  if (normalized.endsWith(\"/codex/responses\"))\n    return normalized;\n  if (normalized.endsWith(\"/codex\"))\n    return `${normalized}/responses`;\n  return `${normalized}/codex/responses`;\n}\nfunction resolveCodexWebSocketUrl(baseUrl) {\n  const url = new URL(resolveCodexUrl(baseUrl));\n  if (url.protocol === \"https:\")\n    url.protocol = \"wss:\";\n  if (url.protocol === \"http:\")\n    url.protocol = \"ws:\";\n  return url.toString();\n}\nasync function processStream(response, output, stream11, model, grammarToolInputProperties, options) {\n  await processResponsesStream(mapCodexEvents(parseSSE(response, options?.signal), output), output, stream11, model, {\n    serviceTier: options?.serviceTier,\n    grammarToolInputProperties,\n    resolveServiceTier: resolveCodexServiceTier,\n    applyServiceTierPricing: (usage, serviceTier) => applyServiceTierPricing2(usage, serviceTier, model)\n  });\n}\nfunction isCodexNonTransportError(error) {\n  return error instanceof CodexApiError || error instanceof CodexProtocolError;\n}\nfunction isWebSocketConnectionLimitReachedError(error) {\n  return error instanceof CodexApiError && error.code === WEBSOCKET_CONNECTION_LIMIT_REACHED_CODE;\n}\nfunction isPreviousResponseNotFoundError(error) {\n  return error instanceof CodexApiError && error.code === PREVIOUS_RESPONSE_NOT_FOUND_CODE;\n}\nfunction extractCodexEventError(event) {\n  const nested = event.error && typeof event.error === \"object\" ? event.error : void 0;\n  return {\n    code: typeof event.code === \"string\" ? event.code : typeof nested?.code === \"string\" ? nested.code : void 0,\n    message: typeof event.message === \"string\" ? event.message : typeof nested?.message === \"string\" ? nested.message : void 0\n  };\n}\nasync function* mapCodexEvents(events, output) {\n  for await (const event of events) {\n    const type = typeof event.type === \"string\" ? event.type : void 0;\n    if (!type)\n      continue;\n    if (type === \"error\") {\n      const { code, message } = extractCodexEventError(event);\n      throw new CodexApiError(`Codex error: ${message || code || JSON.stringify(event)}`, {\n        code,\n        payload: event\n      });\n    }\n    if (type === \"response.failed\") {\n      const response = event.response;\n      const code = response?.error?.code;\n      const message = response?.error?.message;\n      throw new CodexApiError(message || \"Codex response failed\", { code, payload: event });\n    }\n    if (type === \"response.done\" || type === \"response.completed\" || type === \"response.incomplete\") {\n      const response = event.response;\n      if (typeof response?.end_turn === \"boolean\") {\n        output.endTurn = response.end_turn;\n      }\n      const normalizedResponse = response ? { ...response, status: normalizeCodexStatus(response.status) } : response;\n      yield { ...event, type: \"response.completed\", response: normalizedResponse };\n      return;\n    }\n    yield event;\n  }\n}\nfunction normalizeCodexStatus(status) {\n  if (typeof status !== \"string\")\n    return void 0;\n  return CODEX_RESPONSE_STATUSES.has(status) ? status : void 0;\n}\nasync function* parseSSE(response, signal) {\n  if (!response.body)\n    return;\n  const reader = response.body.getReader();\n  const decoder = new TextDecoder();\n  let buffer = \"\";\n  const onAbort = () => {\n    void reader.cancel().catch(() => {\n    });\n  };\n  signal?.addEventListener(\"abort\", onAbort, { once: true });\n  try {\n    while (true) {\n      if (signal?.aborted) {\n        throw new Error(\"Request was aborted\");\n      }\n      const { done, value } = await reader.read();\n      if (signal?.aborted) {\n        throw new Error(\"Request was aborted\");\n      }\n      if (done)\n        break;\n      buffer += decoder.decode(value, { stream: true });\n      let idx = buffer.indexOf(\"\\n\\n\");\n      while (idx !== -1) {\n        const chunk = buffer.slice(0, idx);\n        buffer = buffer.slice(idx + 2);\n        const dataLines = chunk.split(\"\\n\").filter((l) => l.startsWith(\"data:\")).map((l) => l.slice(5).trim());\n        if (dataLines.length > 0) {\n          const data = dataLines.join(\"\\n\").trim();\n          if (data && data !== \"[DONE]\") {\n            try {\n              yield JSON.parse(data);\n            } catch (cause) {\n              throw new CodexProtocolError(`Invalid Codex SSE JSON: ${formatThrownValue(cause)}`, {\n                cause,\n                payload: data\n              });\n            }\n          }\n        }\n        idx = buffer.indexOf(\"\\n\\n\");\n      }\n    }\n  } finally {\n    signal?.removeEventListener(\"abort\", onAbort);\n    try {\n      await reader.cancel();\n    } catch {\n    }\n    try {\n      reader.releaseLock();\n    } catch {\n    }\n  }\n}\nfunction getOrCreateWebSocketDebugStats(sessionId) {\n  let stats = websocketDebugStats.get(sessionId);\n  if (!stats) {\n    stats = {\n      requests: 0,\n      connectionsCreated: 0,\n      connectionsReused: 0,\n      cachedContextRequests: 0,\n      storeTrueRequests: 0,\n      fullContextRequests: 0,\n      deltaRequests: 0,\n      lastInputItems: 0,\n      websocketFailures: 0,\n      sseFallbacks: 0\n    };\n    websocketDebugStats.set(sessionId, stats);\n  }\n  return stats;\n}\nfunction getOpenAICodexWebSocketDebugStats(sessionId) {\n  const stats = websocketDebugStats.get(sessionId);\n  return stats ? { ...stats } : void 0;\n}\nfunction resetOpenAICodexWebSocketDebugStats(sessionId) {\n  if (sessionId) {\n    websocketDebugStats.delete(sessionId);\n    websocketSseFallbackSessions.delete(sessionId);\n    return;\n  }\n  websocketDebugStats.clear();\n  websocketSseFallbackSessions.clear();\n}\nfunction closeOpenAICodexWebSocketSessions(sessionId) {\n  const closeEntry = (entry) => {\n    if (entry.idleTimer)\n      clearTimeout(entry.idleTimer);\n    closeWebSocketSilently(entry.socket, 1e3, \"debug_close\");\n  };\n  if (sessionId) {\n    for (const entry of websocketSessionCache.get(sessionId)?.values() ?? [])\n      closeEntry(entry);\n    websocketSessionCache.delete(sessionId);\n    return;\n  }\n  for (const accountEntries of websocketSessionCache.values()) {\n    for (const entry of accountEntries.values())\n      closeEntry(entry);\n  }\n  websocketSessionCache.clear();\n}\nfunction isWebSocketSseFallbackActive(sessionId) {\n  return sessionId ? websocketSseFallbackSessions.has(sessionId) : false;\n}\nfunction recordWebSocketSseFallback(sessionId) {\n  if (!sessionId)\n    return;\n  const stats = getOrCreateWebSocketDebugStats(sessionId);\n  stats.sseFallbacks++;\n  stats.websocketFallbackActive = isWebSocketSseFallbackActive(sessionId);\n}\nfunction recordWebSocketFailure(sessionId, error) {\n  if (!sessionId)\n    return;\n  websocketSseFallbackSessions.add(sessionId);\n  const stats = getOrCreateWebSocketDebugStats(sessionId);\n  stats.websocketFailures++;\n  stats.lastWebSocketError = formatThrownValue(error);\n  stats.websocketFallbackActive = true;\n}\nasync function getWebSocketConstructor(env) {\n  if (!env && _cachedWebsocket)\n    return _cachedWebsocket;\n  if (typeof process !== \"undefined\" && process.versions?.bun) {\n    const WebSocketWithProxy = class extends WebSocket {\n      constructor(url, options) {\n        let _opts = {};\n        if (Array.isArray(options) || typeof options === \"string\") {\n          _opts = { protocols: options };\n        } else {\n          _opts = { ...options };\n        }\n        const proxyUrl = resolveHttpProxyUrlForTarget(url.toString().replace(/^wss:/, \"https:\").replace(/^ws:/, \"http:\"), env);\n        super(url, { ..._opts, ...proxyUrl ? { proxy: proxyUrl.toString() } : {} });\n      }\n    };\n    if (!env) {\n      _cachedWebsocket = WebSocketWithProxy;\n    }\n    return WebSocketWithProxy;\n  }\n  const ctor = globalThis.WebSocket;\n  if (typeof ctor !== \"function\")\n    return null;\n  return ctor;\n}\nfunction getWebSocketReadyState(socket) {\n  const readyState = socket.readyState;\n  return typeof readyState === \"number\" ? readyState : void 0;\n}\nfunction isWebSocketReusable(socket) {\n  const readyState = getWebSocketReadyState(socket);\n  return readyState === void 0 || readyState === 1;\n}\nfunction isWebSocketSessionExpired(entry) {\n  return Date.now() - entry.createdAt >= SESSION_WEBSOCKET_MAX_AGE_MS;\n}\nfunction closeWebSocketSilently(socket, code = 1e3, reason = \"done\") {\n  try {\n    socket.close(code, reason);\n  } catch {\n  }\n}\nfunction scheduleSessionWebSocketExpiry(sessionId, accountId, entry) {\n  if (entry.idleTimer) {\n    clearTimeout(entry.idleTimer);\n  }\n  entry.idleTimer = setTimeout(() => {\n    if (entry.busy)\n      return;\n    closeWebSocketSilently(entry.socket, 1e3, \"idle_timeout\");\n    const accountEntries = websocketSessionCache.get(sessionId);\n    if (accountEntries?.get(accountId) === entry)\n      accountEntries.delete(accountId);\n    if (accountEntries?.size === 0)\n      websocketSessionCache.delete(sessionId);\n  }, SESSION_WEBSOCKET_CACHE_TTL_MS);\n}\nasync function connectWebSocket(url, headers, signal, connectTimeoutMs = DEFAULT_WEBSOCKET_CONNECT_TIMEOUT_MS, env) {\n  const WebSocketCtor = await getWebSocketConstructor(env);\n  if (!WebSocketCtor) {\n    throw new Error(\"WebSocket transport is not available in this runtime\");\n  }\n  const wsHeaders = headersToRecord(headers);\n  delete wsHeaders[\"OpenAI-Beta\"];\n  return new Promise((resolve15, reject) => {\n    let settled = false;\n    let timeout;\n    let socket;\n    try {\n      socket = new WebSocketCtor(url, { headers: wsHeaders });\n    } catch (error) {\n      reject(error instanceof Error ? error : new Error(String(error)));\n      return;\n    }\n    const cleanup = () => {\n      if (timeout) {\n        clearTimeout(timeout);\n        timeout = void 0;\n      }\n      socket.removeEventListener(\"open\", onOpen);\n      socket.removeEventListener(\"error\", onError);\n      socket.removeEventListener(\"close\", onClose);\n      signal?.removeEventListener(\"abort\", onAbort);\n    };\n    const fail = (error, closeReason) => {\n      if (settled)\n        return;\n      settled = true;\n      cleanup();\n      if (closeReason) {\n        closeWebSocketSilently(socket, 1e3, closeReason);\n      }\n      reject(error);\n    };\n    const onOpen = () => {\n      if (settled)\n        return;\n      settled = true;\n      cleanup();\n      resolve15(socket);\n    };\n    const onError = (event) => {\n      fail(extractWebSocketError(event));\n    };\n    const onClose = (event) => {\n      fail(extractWebSocketCloseError(event));\n    };\n    const onAbort = () => {\n      fail(new Error(\"Request was aborted\"), \"aborted\");\n    };\n    socket.addEventListener(\"open\", onOpen);\n    socket.addEventListener(\"error\", onError);\n    socket.addEventListener(\"close\", onClose);\n    signal?.addEventListener(\"abort\", onAbort);\n    if (connectTimeoutMs > 0) {\n      timeout = setTimeout(() => {\n        fail(new Error(`WebSocket connect timeout after ${connectTimeoutMs}ms`), \"connect_timeout\");\n      }, connectTimeoutMs);\n    }\n    if (signal?.aborted) {\n      onAbort();\n    }\n  });\n}\nasync function acquireWebSocket(url, headers, sessionId, accountId, signal, connectTimeoutMs, env) {\n  if (!sessionId) {\n    const socket2 = await connectWebSocket(url, headers, signal, connectTimeoutMs, env);\n    return {\n      socket: socket2,\n      reused: false,\n      release: () => closeWebSocketSilently(socket2)\n    };\n  }\n  let accountEntries = websocketSessionCache.get(sessionId);\n  const cached = accountEntries?.get(accountId);\n  if (cached) {\n    if (cached.idleTimer) {\n      clearTimeout(cached.idleTimer);\n      cached.idleTimer = void 0;\n    }\n    if (!cached.busy && isWebSocketSessionExpired(cached)) {\n      closeWebSocketSilently(cached.socket, 1e3, \"connection_age_limit\");\n      accountEntries?.delete(accountId);\n      if (accountEntries?.size === 0)\n        websocketSessionCache.delete(sessionId);\n    } else if (!cached.busy && isWebSocketReusable(cached.socket)) {\n      cached.busy = true;\n      return {\n        socket: cached.socket,\n        entry: cached,\n        reused: true,\n        release: ({ keep } = {}) => {\n          if (!keep || !isWebSocketReusable(cached.socket)) {\n            closeWebSocketSilently(cached.socket);\n            const currentEntries = websocketSessionCache.get(sessionId);\n            if (currentEntries?.get(accountId) === cached)\n              currentEntries.delete(accountId);\n            if (currentEntries?.size === 0)\n              websocketSessionCache.delete(sessionId);\n            return;\n          }\n          cached.busy = false;\n          scheduleSessionWebSocketExpiry(sessionId, accountId, cached);\n        }\n      };\n    }\n    if (cached.busy) {\n      const socket2 = await connectWebSocket(url, headers, signal, connectTimeoutMs, env);\n      return {\n        socket: socket2,\n        reused: false,\n        release: () => {\n          closeWebSocketSilently(socket2);\n        }\n      };\n    }\n    if (!isWebSocketReusable(cached.socket)) {\n      closeWebSocketSilently(cached.socket);\n      accountEntries?.delete(accountId);\n      if (accountEntries?.size === 0)\n        websocketSessionCache.delete(sessionId);\n    }\n  }\n  const socket = await connectWebSocket(url, headers, signal, connectTimeoutMs, env);\n  const entry = { socket, busy: true, createdAt: Date.now() };\n  accountEntries = websocketSessionCache.get(sessionId);\n  if (!accountEntries) {\n    accountEntries = /* @__PURE__ */ new Map();\n    websocketSessionCache.set(sessionId, accountEntries);\n  }\n  accountEntries.set(accountId, entry);\n  return {\n    socket,\n    entry,\n    reused: false,\n    release: ({ keep } = {}) => {\n      if (!keep || !isWebSocketReusable(entry.socket)) {\n        closeWebSocketSilently(entry.socket);\n        if (entry.idleTimer)\n          clearTimeout(entry.idleTimer);\n        const currentEntries = websocketSessionCache.get(sessionId);\n        if (currentEntries?.get(accountId) === entry)\n          currentEntries.delete(accountId);\n        if (currentEntries?.size === 0)\n          websocketSessionCache.delete(sessionId);\n        return;\n      }\n      entry.busy = false;\n      scheduleSessionWebSocketExpiry(sessionId, accountId, entry);\n    }\n  };\n}\nfunction extractWebSocketError(event) {\n  if (event && typeof event === \"object\") {\n    const message = \"message\" in event ? event.message : void 0;\n    if (typeof message === \"string\" && message.length > 0) {\n      return new Error(message);\n    }\n    const nestedError = \"error\" in event ? event.error : void 0;\n    if (nestedError instanceof Error && nestedError.message.length > 0) {\n      return nestedError;\n    }\n    if (nestedError && typeof nestedError === \"object\" && \"message\" in nestedError) {\n      const nestedMessage = nestedError.message;\n      if (typeof nestedMessage === \"string\" && nestedMessage.length > 0) {\n        return new Error(nestedMessage);\n      }\n    }\n  }\n  return new Error(\"WebSocket error\");\n}\nfunction extractWebSocketCloseError(event) {\n  if (event && typeof event === \"object\") {\n    const code = \"code\" in event ? event.code : void 0;\n    const reason = \"reason\" in event ? event.reason : void 0;\n    const wasClean = \"wasClean\" in event ? event.wasClean : void 0;\n    const codeText = typeof code === \"number\" ? ` ${code}` : \"\";\n    let reasonText = typeof reason === \"string\" && reason.length > 0 ? ` ${reason}` : \"\";\n    if (!reasonText && code === WEBSOCKET_MESSAGE_TOO_BIG_CLOSE_CODE) {\n      reasonText = \" message too big\";\n    }\n    return new WebSocketCloseError(`WebSocket closed${codeText}${reasonText}`.trim(), {\n      code: typeof code === \"number\" ? code : void 0,\n      reason: typeof reason === \"string\" && reason.length > 0 ? reason : void 0,\n      wasClean: typeof wasClean === \"boolean\" ? wasClean : void 0\n    });\n  }\n  return new Error(\"WebSocket closed\");\n}\nasync function decodeWebSocketData(data) {\n  if (typeof data === \"string\")\n    return data;\n  if (data instanceof ArrayBuffer) {\n    return new TextDecoder().decode(new Uint8Array(data));\n  }\n  if (ArrayBuffer.isView(data)) {\n    const view = data;\n    return new TextDecoder().decode(new Uint8Array(view.buffer, view.byteOffset, view.byteLength));\n  }\n  if (data && typeof data === \"object\" && \"arrayBuffer\" in data) {\n    const blobLike = data;\n    const arrayBuffer = await blobLike.arrayBuffer();\n    return new TextDecoder().decode(new Uint8Array(arrayBuffer));\n  }\n  return null;\n}\nasync function* parseWebSocket(socket, signal, idleTimeoutMs) {\n  const queue = [];\n  let pending = null;\n  let done = false;\n  let failed = null;\n  let sawCompletion = false;\n  const wake = () => {\n    if (!pending)\n      return;\n    const resolve15 = pending;\n    pending = null;\n    resolve15();\n  };\n  const onMessage = (event) => {\n    void (async () => {\n      let text = null;\n      try {\n        if (!event || typeof event !== \"object\" || !(\"data\" in event))\n          return;\n        text = await decodeWebSocketData(event.data);\n        if (!text)\n          return;\n        const parsed = JSON.parse(text);\n        const type = typeof parsed.type === \"string\" ? parsed.type : \"\";\n        if (type === \"response.completed\" || type === \"response.done\" || type === \"response.incomplete\") {\n          sawCompletion = true;\n          done = true;\n        }\n        queue.push(parsed);\n        wake();\n      } catch (cause) {\n        failed = new CodexProtocolError(`Invalid Codex WebSocket JSON: ${formatThrownValue(cause)}`, {\n          cause,\n          payload: text\n        });\n        done = true;\n        wake();\n      }\n    })();\n  };\n  const onError = (event) => {\n    failed = extractWebSocketError(event);\n    done = true;\n    wake();\n  };\n  const onClose = (event) => {\n    if (sawCompletion) {\n      done = true;\n      wake();\n      return;\n    }\n    if (!failed) {\n      failed = extractWebSocketCloseError(event);\n    }\n    done = true;\n    wake();\n  };\n  const onAbort = () => {\n    failed = new Error(\"Request was aborted\");\n    done = true;\n    wake();\n  };\n  socket.addEventListener(\"message\", onMessage);\n  socket.addEventListener(\"error\", onError);\n  socket.addEventListener(\"close\", onClose);\n  signal?.addEventListener(\"abort\", onAbort);\n  try {\n    while (true) {\n      if (signal?.aborted) {\n        throw new Error(\"Request was aborted\");\n      }\n      if (queue.length > 0) {\n        yield queue.shift();\n        continue;\n      }\n      if (done)\n        break;\n      let timeout;\n      await new Promise((resolve15, reject) => {\n        pending = resolve15;\n        if (idleTimeoutMs !== void 0 && idleTimeoutMs > 0) {\n          timeout = setTimeout(() => {\n            const error = new Error(`WebSocket idle timeout after ${idleTimeoutMs}ms`);\n            failed = error;\n            done = true;\n            pending = null;\n            closeWebSocketSilently(socket, 1e3, \"idle_timeout\");\n            reject(error);\n          }, idleTimeoutMs);\n        }\n      }).finally(() => {\n        if (timeout) {\n          clearTimeout(timeout);\n        }\n      });\n    }\n    if (failed) {\n      throw failed;\n    }\n    if (!sawCompletion) {\n      throw new Error(\"WebSocket stream closed before response.completed\");\n    }\n  } finally {\n    socket.removeEventListener(\"message\", onMessage);\n    socket.removeEventListener(\"error\", onError);\n    socket.removeEventListener(\"close\", onClose);\n    signal?.removeEventListener(\"abort\", onAbort);\n  }\n}\nfunction requestBodyWithoutInput(body) {\n  const { input: _input, previous_response_id: _previousResponseId, ...rest } = body;\n  return rest;\n}\nfunction responseInputsEqual(a, b) {\n  return JSON.stringify(a ?? []) === JSON.stringify(b ?? []);\n}\nfunction requestBodiesMatchExceptInput(a, b) {\n  return JSON.stringify(requestBodyWithoutInput(a)) === JSON.stringify(requestBodyWithoutInput(b));\n}\nfunction getCachedWebSocketInputDelta(body, continuation) {\n  if (!requestBodiesMatchExceptInput(body, continuation.lastRequestBody)) {\n    return void 0;\n  }\n  const currentInput = body.input ?? [];\n  const baseline = [...continuation.lastRequestBody.input ?? [], ...continuation.lastResponseItems];\n  if (currentInput.length < baseline.length) {\n    return void 0;\n  }\n  const prefix = currentInput.slice(0, baseline.length);\n  if (!responseInputsEqual(prefix, baseline)) {\n    return void 0;\n  }\n  return currentInput.slice(baseline.length);\n}\nfunction buildCachedWebSocketRequestBody(entry, body) {\n  const continuation = entry.continuation;\n  if (!continuation) {\n    return body;\n  }\n  const delta = getCachedWebSocketInputDelta(body, continuation);\n  if (!delta || !continuation.lastResponseId) {\n    entry.continuation = void 0;\n    return body;\n  }\n  return {\n    ...body,\n    previous_response_id: continuation.lastResponseId,\n    input: delta\n  };\n}\nasync function* startWebSocketOutputOnFirstEvent(events, onStart) {\n  let started = false;\n  for await (const event of events) {\n    if (!started) {\n      started = true;\n      onStart();\n    }\n    yield event;\n  }\n}\nasync function processWebSocketStream(url, body, headers, output, stream11, model, onStart, idleTimeoutMs, websocketConnectTimeoutMs, cacheSessionId, accountId, grammarToolInputProperties, options) {\n  const { socket, entry, reused, release } = await acquireWebSocket(url, headers, cacheSessionId, accountId, options?.signal, websocketConnectTimeoutMs, options?.env);\n  let keepConnection = true;\n  const useCachedContext = options?.transport === \"websocket-cached\" || options?.transport === \"auto\";\n  const fullBody = body;\n  const requestBody = useCachedContext && entry ? buildCachedWebSocketRequestBody(entry, fullBody) : fullBody;\n  const stats = cacheSessionId ? getOrCreateWebSocketDebugStats(cacheSessionId) : void 0;\n  if (stats) {\n    stats.requests++;\n    if (reused)\n      stats.connectionsReused++;\n    else\n      stats.connectionsCreated++;\n    if (useCachedContext)\n      stats.cachedContextRequests++;\n    if (requestBody.store === true)\n      stats.storeTrueRequests++;\n    stats.lastInputItems = requestBody.input?.length ?? 0;\n    if (requestBody.previous_response_id) {\n      stats.deltaRequests++;\n      stats.lastDeltaInputItems = requestBody.input?.length ?? 0;\n      stats.lastPreviousResponseId = requestBody.previous_response_id;\n    } else {\n      stats.fullContextRequests++;\n      stats.lastDeltaInputItems = void 0;\n      stats.lastPreviousResponseId = void 0;\n    }\n  }\n  try {\n    socket.send(JSON.stringify({ type: \"response.create\", ...requestBody }));\n    await processResponsesStream(startWebSocketOutputOnFirstEvent(mapCodexEvents(parseWebSocket(socket, options?.signal, idleTimeoutMs), output), onStart), output, stream11, model, {\n      serviceTier: options?.serviceTier,\n      grammarToolInputProperties,\n      resolveServiceTier: resolveCodexServiceTier,\n      applyServiceTierPricing: (usage, serviceTier) => applyServiceTierPricing2(usage, serviceTier, model)\n    });\n    if (options?.signal?.aborted) {\n      keepConnection = false;\n    } else if (useCachedContext && entry && output.responseId) {\n      const responseItems = convertResponsesMessages(model, { messages: [output] }, CODEX_TOOL_CALL_PROVIDERS, {\n        includeSystemPrompt: false,\n        grammarToolInputProperties\n      }).filter((item) => item.type !== \"function_call_output\" && item.type !== \"custom_tool_call_output\");\n      entry.continuation = {\n        lastRequestBody: fullBody,\n        lastResponseId: output.responseId,\n        lastResponseItems: responseItems\n      };\n    }\n  } catch (error) {\n    if (entry) {\n      entry.continuation = void 0;\n    }\n    keepConnection = false;\n    throw error;\n  } finally {\n    release({ keep: keepConnection });\n  }\n}\nasync function parseErrorResponse(response) {\n  const raw = await response.text();\n  let message = raw || response.statusText || \"Request failed\";\n  let friendlyMessage;\n  try {\n    const parsed = JSON.parse(raw);\n    const err2 = parsed?.error;\n    if (err2) {\n      const code = err2.code || err2.type || \"\";\n      if (/usage_limit_reached|usage_not_included|rate_limit_exceeded/i.test(code) || response.status === 429) {\n        const plan = err2.plan_type ? ` (${err2.plan_type.toLowerCase()} plan)` : \"\";\n        const mins = err2.resets_at ? Math.max(0, Math.round((err2.resets_at * 1e3 - Date.now()) / 6e4)) : void 0;\n        const when = mins !== void 0 ? ` Try again in ~${mins} min.` : \"\";\n        friendlyMessage = `You have hit your ChatGPT usage limit${plan}.${when}`.trim();\n      }\n      message = err2.message || friendlyMessage || message;\n    }\n  } catch {\n  }\n  return { message, friendlyMessage };\n}\nfunction extractAccountId(token) {\n  try {\n    const parts = token.split(\".\");\n    if (parts.length !== 3)\n      throw new Error(\"Invalid token\");\n    const payload = JSON.parse(atob(parts[1]));\n    const accountId = payload?.[JWT_CLAIM_PATH]?.chatgpt_account_id;\n    if (!accountId)\n      throw new Error(\"No account ID in token\");\n    return accountId;\n  } catch {\n    throw new Error(\"Failed to extract accountId from token\");\n  }\n}\nfunction buildBaseCodexHeaders(initHeaders, additionalHeaders, accountId, token) {\n  const headers = new Headers(initHeaders);\n  for (const [key, value] of Object.entries(additionalHeaders || {})) {\n    if (value === null) {\n      headers.delete(key);\n    } else {\n      headers.set(key, value);\n    }\n  }\n  headers.set(\"Authorization\", `Bearer ${token}`);\n  headers.set(\"chatgpt-account-id\", accountId);\n  headers.set(\"originator\", \"pi\");\n  headers.set(\"User-Agent\", getPiUserAgent());\n  return headers;\n}\nfunction buildSSEHeaders(initHeaders, additionalHeaders, accountId, token, sessionId) {\n  const headers = buildBaseCodexHeaders(initHeaders, additionalHeaders, accountId, token);\n  headers.set(\"OpenAI-Beta\", \"responses=experimental\");\n  headers.set(\"accept\", \"text/event-stream\");\n  headers.set(\"content-type\", \"application/json\");\n  if (sessionId) {\n    headers.set(\"session-id\", sessionId);\n    headers.set(\"x-client-request-id\", sessionId);\n  }\n  return headers;\n}\nfunction buildWebSocketHeaders(initHeaders, additionalHeaders, accountId, token, requestId) {\n  const headers = buildBaseCodexHeaders(initHeaders, additionalHeaders, accountId, token);\n  headers.delete(\"accept\");\n  headers.delete(\"content-type\");\n  headers.delete(\"OpenAI-Beta\");\n  headers.delete(\"openai-beta\");\n  headers.set(\"OpenAI-Beta\", OPENAI_BETA_RESPONSES_WEBSOCKETS);\n  headers.set(\"x-client-request-id\", requestId);\n  headers.set(\"session-id\", requestId);\n  return headers;\n}\nvar DEFAULT_CODEX_BASE_URL, JWT_CLAIM_PATH, DEFAULT_MAX_RETRIES, BASE_DELAY_MS, DEFAULT_MAX_RETRY_DELAY_MS2, DEFAULT_WEBSOCKET_CONNECT_TIMEOUT_MS, REQUEST_COMPRESSION_ZSTD_LEVEL, CODEX_TOOL_CALL_PROVIDERS, WEBSOCKET_MESSAGE_TOO_BIG_CLOSE_CODE, WEBSOCKET_CONNECTION_LIMIT_REACHED_CODE, PREVIOUS_RESPONSE_NOT_FOUND_CODE, CODEX_RESPONSE_STATUSES, RetryDelayExceededError, stream8, streamSimple8, CodexApiError, CodexProtocolError, OPENAI_BETA_RESPONSES_WEBSOCKETS, SESSION_WEBSOCKET_CACHE_TTL_MS, SESSION_WEBSOCKET_MAX_AGE_MS, websocketSessionCache, websocketDebugStats, websocketSseFallbackSessions, _cachedWebsocket, WebSocketCloseError;\nvar init_openai_codex_responses = __esm({\n  \"node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/api/openai-codex-responses.js\"() {\n    init_models();\n    init_session_resources();\n    init_abort_signals();\n    init_deferred_tools();\n    init_diagnostics();\n    init_error_body();\n    init_event_stream();\n    init_headers();\n    init_node_http_proxy();\n    init_pi_user_agent();\n    init_uuid();\n    init_constrained_sampling();\n    init_openai_prompt_cache();\n    init_openai_responses_shared();\n    init_simple_options();\n    DEFAULT_CODEX_BASE_URL = \"https://chatgpt.com/backend-api\";\n    JWT_CLAIM_PATH = \"https://api.openai.com/auth\";\n    DEFAULT_MAX_RETRIES = 0;\n    BASE_DELAY_MS = 1e3;\n    DEFAULT_MAX_RETRY_DELAY_MS2 = 6e4;\n    DEFAULT_WEBSOCKET_CONNECT_TIMEOUT_MS = 15e3;\n    REQUEST_COMPRESSION_ZSTD_LEVEL = 3;\n    CODEX_TOOL_CALL_PROVIDERS = /* @__PURE__ */ new Set([\"openai\", \"openai-codex\", \"opencode\"]);\n    WEBSOCKET_MESSAGE_TOO_BIG_CLOSE_CODE = 1009;\n    WEBSOCKET_CONNECTION_LIMIT_REACHED_CODE = \"websocket_connection_limit_reached\";\n    PREVIOUS_RESPONSE_NOT_FOUND_CODE = \"previous_response_not_found\";\n    CODEX_RESPONSE_STATUSES = /* @__PURE__ */ new Set([\n      \"completed\",\n      \"incomplete\",\n      \"failed\",\n      \"cancelled\",\n      \"queued\",\n      \"in_progress\"\n    ]);\n    RetryDelayExceededError = class extends Error {\n    };\n    stream8 = (model, context, options) => {\n      const stream11 = new AssistantMessageEventStream();\n      (async () => {\n        const output = {\n          role: \"assistant\",\n          content: [],\n          api: \"openai-codex-responses\",\n          provider: model.provider,\n          model: model.id,\n          usage: {\n            input: 0,\n            output: 0,\n            cacheRead: 0,\n            cacheWrite: 0,\n            totalTokens: 0,\n            cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 }\n          },\n          stopReason: \"pending\",\n          timestamp: Date.now()\n        };\n        try {\n          const apiKey = options?.apiKey;\n          if (!apiKey) {\n            throw new Error(`No API key for provider: ${model.provider}`);\n          }\n          const accountId = extractAccountId(apiKey);\n          const grammarToolInputProperties = createGrammarToolInputProperties(context.tools, model.compat?.supportsOpenAIGrammarTools ?? false);\n          const cacheSessionId = options?.cacheRetention === \"none\" ? void 0 : options?.sessionId;\n          const codexSessionId = clampOpenAIPromptCacheKey(cacheSessionId);\n          let body = buildRequestBody(model, context, options, codexSessionId, grammarToolInputProperties);\n          const nextBody = await options?.onPayload?.(body, model);\n          if (nextBody !== void 0) {\n            body = nextBody;\n          }\n          const websocketRequestId = codexSessionId || uuidv7();\n          const sseHeaders = buildSSEHeaders(model.headers, options?.headers, accountId, apiKey, codexSessionId);\n          const websocketHeaders = buildWebSocketHeaders(model.headers, options?.headers, accountId, apiKey, websocketRequestId);\n          const bodyJson = JSON.stringify(body);\n          const httpTimeoutMs = normalizeTimeoutMs(options?.timeoutMs);\n          const websocketConnectTimeoutMs = normalizeTimeoutMs(options?.websocketConnectTimeoutMs);\n          const transport = options?.transport || \"auto\";\n          let startEmitted = false;\n          const websocketDisabledForSession = transport !== \"sse\" && isWebSocketSseFallbackActive(cacheSessionId);\n          if (websocketDisabledForSession) {\n            recordWebSocketSseFallback(cacheSessionId);\n          }\n          if (transport !== \"sse\" && !websocketDisabledForSession) {\n            let websocketStarted = false;\n            let retriedWebSocketConnectionLimit = false;\n            let retriedMissingWebSocketContinuation = false;\n            while (true) {\n              websocketStarted = false;\n              try {\n                await processWebSocketStream(resolveCodexWebSocketUrl(model.baseUrl), body, websocketHeaders, output, stream11, model, () => {\n                  websocketStarted = true;\n                  if (!startEmitted) {\n                    startEmitted = true;\n                    stream11.push({ type: \"start\", partial: output });\n                  }\n                }, httpTimeoutMs, websocketConnectTimeoutMs, cacheSessionId, accountId, grammarToolInputProperties, options);\n                if (options?.signal?.aborted) {\n                  throw new Error(\"Request was aborted\");\n                }\n                assertSuccessfulOutput(output);\n                stream11.push({\n                  type: \"done\",\n                  reason: output.stopReason,\n                  message: output\n                });\n                stream11.end();\n                return;\n              } catch (error) {\n                const aborted = options?.signal?.aborted;\n                const connectionLimitBeforeStart = !websocketStarted && isWebSocketConnectionLimitReachedError(error);\n                const previousResponseNotFound = isPreviousResponseNotFoundError(error);\n                if (!aborted && previousResponseNotFound && !retriedMissingWebSocketContinuation) {\n                  retriedMissingWebSocketContinuation = true;\n                  continue;\n                }\n                if (!aborted && connectionLimitBeforeStart && !retriedWebSocketConnectionLimit) {\n                  retriedWebSocketConnectionLimit = true;\n                  continue;\n                }\n                if (aborted || isCodexNonTransportError(error) && !connectionLimitBeforeStart) {\n                  throw error;\n                }\n                appendAssistantMessageDiagnostic(output, createAssistantMessageDiagnostic(\"provider_transport_failure\", error, {\n                  configuredTransport: transport,\n                  fallbackTransport: websocketStarted ? void 0 : \"sse\",\n                  eventsEmitted: websocketStarted,\n                  phase: websocketStarted ? \"after_message_stream_start\" : \"before_message_stream_start\",\n                  requestBytes: new TextEncoder().encode(bodyJson).byteLength\n                }));\n                recordWebSocketFailure(cacheSessionId, error);\n                if (websocketStarted) {\n                  throw error;\n                }\n                recordWebSocketSseFallback(cacheSessionId);\n                break;\n              }\n            }\n          }\n          const compressedBody = compressRequestBodyZstd(bodyJson);\n          if (compressedBody) {\n            sseHeaders.set(\"content-encoding\", \"zstd\");\n          }\n          const sseBody = compressedBody ?? bodyJson;\n          let response;\n          let lastError;\n          const maxRetries = options?.maxRetries ?? DEFAULT_MAX_RETRIES;\n          for (let attempt = 0; attempt <= maxRetries; attempt++) {\n            if (options?.signal?.aborted) {\n              throw new Error(\"Request was aborted\");\n            }\n            try {\n              const headerTimeoutSignal = httpTimeoutMs !== void 0 && httpTimeoutMs > 0 ? AbortSignal.timeout(httpTimeoutMs) : void 0;\n              const combinedSignal = combineAbortSignals([options?.signal, headerTimeoutSignal]);\n              try {\n                response = await (options?.fetch ?? globalThis.fetch)(resolveCodexUrl(model.baseUrl), {\n                  method: \"POST\",\n                  headers: sseHeaders,\n                  body: sseBody,\n                  signal: combinedSignal.signal\n                });\n              } catch (error) {\n                if (headerTimeoutSignal?.aborted && !options?.signal?.aborted) {\n                  throw new Error(`Codex SSE response headers timed out after ${httpTimeoutMs}ms`);\n                }\n                throw error;\n              } finally {\n                combinedSignal.cleanup();\n              }\n              await options?.onResponse?.({ status: response.status, headers: headersToRecord(response.headers) }, model);\n              if (response.ok) {\n                break;\n              }\n              const errorText = await response.text();\n              if (attempt < maxRetries && isRetryableError(response.status, errorText)) {\n                const retryAfterDelayMs = getRetryAfterDelayMs(response.headers);\n                const delayMs = retryAfterDelayMs === void 0 ? BASE_DELAY_MS * 2 ** attempt : validateRetryDelayMs(retryAfterDelayMs, options);\n                await sleep2(delayMs, options?.signal);\n                continue;\n              }\n              const fakeResponse = new Response(errorText, {\n                status: response.status,\n                statusText: response.statusText\n              });\n              const info = await parseErrorResponse(fakeResponse);\n              throw new Error(info.friendlyMessage || info.message);\n            } catch (error) {\n              if (error instanceof Error) {\n                if (error.name === \"AbortError\" || error.message === \"Request was aborted\") {\n                  throw new Error(\"Request was aborted\");\n                }\n              }\n              lastError = error instanceof Error ? error : new Error(String(error));\n              if (attempt < maxRetries && !(lastError instanceof RetryDelayExceededError) && !lastError.message.includes(\"usage limit\")) {\n                const delayMs = BASE_DELAY_MS * 2 ** attempt;\n                await sleep2(delayMs, options?.signal);\n                continue;\n              }\n              throw lastError;\n            }\n          }\n          if (!response?.ok) {\n            throw lastError ?? new Error(\"Failed after retries\");\n          }\n          if (!response.body) {\n            throw new Error(\"No response body\");\n          }\n          if (!startEmitted) {\n            startEmitted = true;\n            stream11.push({ type: \"start\", partial: output });\n          }\n          await processStream(response, output, stream11, model, grammarToolInputProperties, options);\n          if (options?.signal?.aborted) {\n            throw new Error(\"Request was aborted\");\n          }\n          assertSuccessfulOutput(output);\n          stream11.push({ type: \"done\", reason: output.stopReason, message: output });\n          stream11.end();\n        } catch (error) {\n          for (const block of output.content) {\n            delete block.partialJson;\n            delete block.customInput;\n          }\n          output.stopReason = options?.signal?.aborted ? \"aborted\" : \"error\";\n          output.errorMessage = formatProviderError(normalizeProviderError(error));\n          stream11.push({ type: \"error\", reason: output.stopReason, error: output });\n          stream11.end();\n        }\n      })();\n      return stream11;\n    };\n    streamSimple8 = (model, context, options) => {\n      const apiKey = options?.apiKey;\n      if (!apiKey) {\n        throw new Error(`No API key for provider: ${model.provider}`);\n      }\n      const base = buildBaseOptions(model, context, options, apiKey);\n      const clampedReasoning = options?.reasoning ? clampThinkingLevel(model, options.reasoning) : void 0;\n      const reasoningEffort = clampedReasoning === \"off\" ? void 0 : clampedReasoning;\n      return stream8(model, context, {\n        ...base,\n        reasoningEffort\n      });\n    };\n    CodexApiError = class extends Error {\n      code;\n      payload;\n      constructor(message, options) {\n        super(message);\n        this.name = \"CodexApiError\";\n        this.code = options?.code;\n        this.payload = options?.payload;\n        this.cause = options?.cause;\n      }\n    };\n    CodexProtocolError = class extends Error {\n      payload;\n      constructor(message, options) {\n        super(message);\n        this.name = \"CodexProtocolError\";\n        this.payload = options?.payload;\n        this.cause = options?.cause;\n      }\n    };\n    OPENAI_BETA_RESPONSES_WEBSOCKETS = \"responses_websockets=2026-02-06\";\n    SESSION_WEBSOCKET_CACHE_TTL_MS = 5 * 60 * 1e3;\n    SESSION_WEBSOCKET_MAX_AGE_MS = 55 * 60 * 1e3;\n    websocketSessionCache = /* @__PURE__ */ new Map();\n    websocketDebugStats = /* @__PURE__ */ new Map();\n    websocketSseFallbackSessions = /* @__PURE__ */ new Set();\n    registerSessionResourceCleanup(closeOpenAICodexWebSocketSessions);\n    _cachedWebsocket = null;\n    WebSocketCloseError = class extends Error {\n      code;\n      reason;\n      wasClean;\n      constructor(message, options) {\n        super(message);\n        this.name = \"WebSocketCloseError\";\n        this.code = options?.code;\n        this.reason = options?.reason;\n        this.wasClean = options?.wasClean;\n      }\n    };\n  }\n});\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/api/openrouter-images.js\nvar openrouter_images_exports = {};\n__export(openrouter_images_exports, {\n  generateImages: () => generateImages\n});\nfunction createClient7(model, apiKey, optionsHeaders, fetch2) {\n  return new OpenAI({\n    apiKey,\n    baseURL: model.baseUrl,\n    dangerouslyAllowBrowser: true,\n    fetch: fetch2,\n    defaultHeaders: providerHeadersToRecord({ ...model.headers, ...optionsHeaders })\n  });\n}\nfunction buildParams7(model, context) {\n  const content = context.input.map((item) => {\n    if (item.type === \"text\") {\n      return {\n        type: \"text\",\n        text: sanitizeSurrogates(item.text)\n      };\n    }\n    return {\n      type: \"image_url\",\n      image_url: {\n        url: `data:${item.mimeType};base64,${item.data}`\n      }\n    };\n  });\n  return {\n    model: model.id,\n    messages: [\n      {\n        role: \"user\",\n        content\n      }\n    ],\n    stream: false,\n    modalities: model.output.includes(\"text\") ? [\"image\", \"text\"] : [\"image\"]\n  };\n}\nfunction parseUsage(rawUsage, model) {\n  const promptTokens = rawUsage.prompt_tokens || 0;\n  const reportedCachedTokens = rawUsage.prompt_tokens_details?.cached_tokens || 0;\n  const cacheWriteTokens = rawUsage.prompt_tokens_details?.cache_write_tokens || 0;\n  const cacheReadTokens = cacheWriteTokens > 0 ? Math.max(0, reportedCachedTokens - cacheWriteTokens) : reportedCachedTokens;\n  const input = Math.max(0, promptTokens - cacheReadTokens - cacheWriteTokens);\n  const output = rawUsage.completion_tokens || 0;\n  const usage = {\n    input,\n    output,\n    cacheRead: cacheReadTokens,\n    cacheWrite: cacheWriteTokens,\n    totalTokens: input + output + cacheReadTokens + cacheWriteTokens,\n    cost: {\n      input: model.cost.input / 1e6 * input,\n      output: model.cost.output / 1e6 * output,\n      cacheRead: model.cost.cacheRead / 1e6 * cacheReadTokens,\n      cacheWrite: model.cost.cacheWrite / 1e6 * cacheWriteTokens,\n      total: 0\n    }\n  };\n  usage.cost.total = usage.cost.input + usage.cost.output + usage.cost.cacheRead + usage.cost.cacheWrite;\n  return usage;\n}\nvar generateImages;\nvar init_openrouter_images = __esm({\n  \"node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/api/openrouter-images.js\"() {\n    init_openai();\n    init_error_body();\n    init_headers();\n    init_provider_retry();\n    init_sanitize_unicode();\n    generateImages = async (model, context, options) => {\n      const output = {\n        api: model.api,\n        provider: model.provider,\n        model: model.id,\n        output: [],\n        stopReason: \"stop\",\n        timestamp: Date.now()\n      };\n      try {\n        const apiKey = options?.apiKey;\n        if (!apiKey) {\n          throw new Error(`No API key for provider: ${model.provider}`);\n        }\n        const client = createClient7(model, apiKey, options?.headers, options?.fetch);\n        let params = buildParams7(model, context);\n        const nextParams = await options?.onPayload?.(params, model);\n        if (nextParams !== void 0) {\n          params = nextParams;\n        }\n        const requestOptions = {\n          ...options?.signal ? { signal: options.signal } : {},\n          ...options?.timeoutMs !== void 0 ? { timeout: options.timeoutMs } : {},\n          maxRetries: 0\n        };\n        const { data: response, response: rawResponse } = await retryProviderRequest(() => client.chat.completions.create(params, requestOptions).withResponse(), {\n          maxRetries: options?.maxRetries,\n          maxRetryDelayMs: options?.maxRetryDelayMs,\n          signal: options?.signal\n        });\n        await options?.onResponse?.({ status: rawResponse.status, headers: headersToRecord(rawResponse.headers) }, model);\n        const imageResponse = response;\n        output.responseId = imageResponse.id;\n        if (imageResponse.usage) {\n          output.usage = parseUsage(imageResponse.usage, model);\n        }\n        const choice = imageResponse.choices[0];\n        if (choice) {\n          const content = choice.message.content;\n          if (typeof content === \"string\" && content.length > 0) {\n            output.output.push({ type: \"text\", text: content });\n          }\n          for (const image of choice.message.images ?? []) {\n            const imageUrl = typeof image.image_url === \"string\" ? image.image_url : image.image_url?.url;\n            if (!imageUrl?.startsWith(\"data:\"))\n              continue;\n            const matches = imageUrl.match(/^data:([^;]+);base64,(.+)$/);\n            if (!matches)\n              continue;\n            output.output.push({\n              type: \"image\",\n              mimeType: matches[1],\n              data: matches[2]\n            });\n          }\n        }\n        return output;\n      } catch (error) {\n        output.stopReason = options?.signal?.aborted ? \"aborted\" : \"error\";\n        output.errorMessage = formatProviderError(normalizeProviderError(error));\n        return output;\n      }\n    };\n  }\n});\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/api/pi-messages.js\nvar pi_messages_exports = {};\n__export(pi_messages_exports, {\n  PiMessagesResponseError: () => PiMessagesResponseError,\n  stream: () => stream9,\n  streamSimple: () => streamSimple9\n});\nfunction parsePiMessagesErrorBody(body) {\n  try {\n    const parsed = JSON.parse(body);\n    const error = parsed?.error;\n    return parsed && typeof error === \"object\" && error !== null && !Array.isArray(error) ? parsed : void 0;\n  } catch {\n    return void 0;\n  }\n}\nfunction truncateDiagnosticString(value) {\n  const maxLength = 8192;\n  return value.length > maxLength ? `${value.slice(0, maxLength)}\\u2026` : value;\n}\nfunction formatPiMessagesResponseError(response, body, errorBody) {\n  const message = typeof errorBody?.error?.message === \"string\" ? errorBody.error.message : void 0;\n  const code = typeof errorBody?.error?.code === \"string\" ? errorBody.error.code : void 0;\n  const suffix = message ?? body;\n  const codeSuffix = code ? ` (${code})` : \"\";\n  return `${response.status} ${response.statusText}: ${suffix}${codeSuffix}`;\n}\nfunction createPiMessagesResponseError(model, url, response, body) {\n  const errorBody = parsePiMessagesErrorBody(body);\n  const code = typeof errorBody?.error?.code === \"string\" ? errorBody.error.code : void 0;\n  return new PiMessagesResponseError(formatPiMessagesResponseError(response, body, errorBody), code, {\n    version: 1,\n    provider: model.provider,\n    model: model.id,\n    url: url.toString(),\n    status: response.status,\n    statusText: response.statusText,\n    error: errorBody?.error,\n    body: errorBody ? void 0 : truncateDiagnosticString(body),\n    timestampMs: Date.now()\n  });\n}\nfunction createEmptyUsage() {\n  return {\n    input: 0,\n    output: 0,\n    cacheRead: 0,\n    cacheWrite: 0,\n    totalTokens: 0,\n    cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 }\n  };\n}\nfunction appendRewriteDiagnostic(message, rewrite) {\n  if (!rewrite) {\n    return;\n  }\n  appendAssistantMessageDiagnostic(message, {\n    type: \"pi_messages_rewrite\",\n    timestamp: Date.now(),\n    details: { ...rewrite }\n  });\n}\nfunction createEventConverter(model) {\n  const partial = {\n    role: \"assistant\",\n    content: [],\n    api: model.api,\n    provider: model.provider,\n    model: model.id,\n    usage: createEmptyUsage(),\n    stopReason: \"pending\",\n    timestamp: Date.now()\n  };\n  const toolJson = /* @__PURE__ */ new Map();\n  return (event) => {\n    switch (event.type) {\n      case \"done\":\n        Object.assign(partial, {\n          stopReason: event.reason,\n          usage: event.usage,\n          responseId: event.responseId\n        });\n        appendRewriteDiagnostic(partial, event.rewrite);\n        return { type: \"done\", reason: event.reason, message: partial };\n      case \"error\":\n        Object.assign(partial, {\n          stopReason: event.reason,\n          usage: event.usage,\n          errorMessage: event.errorMessage,\n          responseId: event.responseId\n        });\n        appendRewriteDiagnostic(partial, event.rewrite);\n        return { type: \"error\", reason: event.reason, error: partial };\n      case \"start\":\n        break;\n      case \"text_start\":\n        partial.content[event.contentIndex] = { type: \"text\", text: \"\" };\n        break;\n      case \"text_delta\":\n        partial.content[event.contentIndex].text += event.delta;\n        break;\n      case \"text_end\":\n        Object.assign(partial.content[event.contentIndex], {\n          text: event.content,\n          textSignature: event.contentSignature\n        });\n        break;\n      case \"thinking_start\":\n        partial.content[event.contentIndex] = { type: \"thinking\", thinking: \"\" };\n        break;\n      case \"thinking_delta\":\n        partial.content[event.contentIndex].thinking += event.delta;\n        break;\n      case \"thinking_end\":\n        Object.assign(partial.content[event.contentIndex], {\n          thinking: event.content,\n          thinkingSignature: event.contentSignature,\n          redacted: event.redacted\n        });\n        break;\n      case \"toolcall_start\":\n        partial.content[event.contentIndex] = {\n          type: \"toolCall\",\n          id: event.id,\n          name: event.toolName,\n          arguments: {}\n        };\n        toolJson.set(event.contentIndex, \"\");\n        break;\n      case \"toolcall_delta\": {\n        const json = `${toolJson.get(event.contentIndex) ?? \"\"}${event.delta}`;\n        toolJson.set(event.contentIndex, json);\n        partial.content[event.contentIndex].arguments = parseStreamingJson(json);\n        break;\n      }\n      case \"toolcall_end\":\n        Object.assign(partial.content[event.contentIndex], event.toolCall);\n        toolJson.delete(event.contentIndex);\n        return {\n          type: \"toolcall_end\",\n          contentIndex: event.contentIndex,\n          toolCall: partial.content[event.contentIndex],\n          partial\n        };\n    }\n    return { ...event, partial };\n  };\n}\nasync function* readPiMessagesEvents(stream11) {\n  const decoder = new TextDecoder();\n  const reader = stream11.getReader();\n  let buffer = \"\";\n  try {\n    while (true) {\n      const { done, value } = await reader.read();\n      buffer += done ? decoder.decode() : decoder.decode(value, { stream: true });\n      buffer = buffer.replace(/\\r\\n/g, \"\\n\");\n      let split = buffer.indexOf(\"\\n\\n\");\n      while (split !== -1) {\n        const event = parsePiMessagesEvent(buffer.slice(0, split));\n        if (event) {\n          yield event;\n        }\n        buffer = buffer.slice(split + 2);\n        split = buffer.indexOf(\"\\n\\n\");\n      }\n      if (done) {\n        break;\n      }\n    }\n    if (buffer.trim()) {\n      const event = parsePiMessagesEvent(buffer);\n      if (event) {\n        yield event;\n      }\n    }\n  } finally {\n    reader.releaseLock();\n  }\n}\nfunction parsePiMessagesEvent(raw) {\n  const data = raw.split(\"\\n\").find((line) => line.startsWith(\"data:\"))?.slice(5).trim();\n  return data && data !== \"[DONE]\" ? JSON.parse(data) : void 0;\n}\nfunction createErrorEvent(model, error, aborted) {\n  const reason = aborted ? \"aborted\" : \"error\";\n  const assistantMessage = {\n    role: \"assistant\",\n    content: [],\n    api: model.api,\n    provider: model.provider,\n    model: model.id,\n    usage: createEmptyUsage(),\n    stopReason: reason,\n    errorMessage: error instanceof Error ? error.message : String(error),\n    timestamp: Date.now()\n  };\n  if (!aborted && error instanceof PiMessagesResponseError) {\n    appendAssistantMessageDiagnostic(assistantMessage, createAssistantMessageDiagnostic(\"pi_messages_response_failure\", error, error.diagnosticDetails));\n  }\n  return { type: \"error\", reason, error: assistantMessage };\n}\nfunction resolveCacheRetention4(cacheRetention, env) {\n  if (cacheRetention) {\n    return cacheRetention;\n  }\n  return getProviderEnvValue(\"PI_CACHE_RETENTION\", env) === \"long\" ? \"long\" : void 0;\n}\nvar PiMessagesResponseError, stream9, streamSimple9;\nvar init_pi_messages = __esm({\n  \"node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/api/pi-messages.js\"() {\n    init_diagnostics();\n    init_event_stream();\n    init_headers();\n    init_json_parse();\n    init_provider_env();\n    PiMessagesResponseError = class extends Error {\n      code;\n      diagnosticDetails;\n      constructor(message, code, diagnosticDetails) {\n        super(message);\n        this.name = \"PiMessagesResponseError\";\n        this.code = code;\n        this.diagnosticDetails = diagnosticDetails;\n      }\n    };\n    stream9 = (model, context, options) => {\n      const eventStream = new AssistantMessageEventStream();\n      const convertEvent = createEventConverter(model);\n      void (async () => {\n        try {\n          const apiKey = options?.apiKey;\n          if (!apiKey) {\n            throw new Error(`No API key provided for provider \"${model.provider}\"`);\n          }\n          const url = new URL(`${model.baseUrl.replace(/\\/+$/u, \"\")}/messages`);\n          if (options?.debug) {\n            url.searchParams.set(\"debug\", \"1\");\n          }\n          let payload = {\n            model: model.id,\n            context,\n            options: {\n              temperature: options?.temperature,\n              maxTokens: options?.maxTokens,\n              reasoning: options?.reasoning,\n              cacheRetention: resolveCacheRetention4(options?.cacheRetention, options?.env),\n              sessionId: options?.sessionId,\n              toolChoice: options?.toolChoice\n            }\n          };\n          const nextPayload = await options?.onPayload?.(payload, model);\n          if (nextPayload !== void 0) {\n            payload = nextPayload;\n          }\n          const response = await (options?.fetch ?? globalThis.fetch)(url, {\n            method: \"POST\",\n            headers: {\n              authorization: `Bearer ${apiKey}`,\n              accept: \"text/event-stream\",\n              \"content-type\": \"application/json\",\n              ...providerHeadersToRecord(options?.headers)\n            },\n            body: JSON.stringify(payload),\n            signal: options?.signal\n          });\n          await options?.onResponse?.({ status: response.status, headers: headersToRecord(response.headers) }, model);\n          if (!response.ok) {\n            const body = await response.text();\n            throw createPiMessagesResponseError(model, url, response, body);\n          }\n          if (!response.body) {\n            throw new Error(`${model.provider} response has no body`);\n          }\n          for await (const piEvent of readPiMessagesEvents(response.body)) {\n            const event = convertEvent(piEvent);\n            eventStream.push(event);\n            if (event.type === \"done\" || event.type === \"error\") {\n              return;\n            }\n          }\n          throw new Error(`${model.provider} stream ended without a terminal event`);\n        } catch (error) {\n          eventStream.push(createErrorEvent(model, error, options?.signal?.aborted ?? false));\n        }\n      })();\n      return eventStream;\n    };\n    streamSimple9 = (model, context, options) => {\n      const extra = options;\n      return stream9(model, context, {\n        ...options,\n        reasoning: options?.reasoning,\n        toolChoice: extra?.toolChoice,\n        debug: extra?.debug\n      });\n    };\n  }\n});\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/config.js\nimport { accessSync, constants, existsSync, readFileSync, realpathSync as realpathSync2 } from \"fs\";\nimport { homedir as homedir2 } from \"os\";\nimport { basename, dirname, join as join2, resolve, sep as sep2, win32 } from \"path\";\nimport { fileURLToPath as fileURLToPath2 } from \"url\";\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/utils/child-process.js\nimport { spawn as nodeSpawn, spawnSync as nodeSpawnSync } from \"node:child_process\";\nimport crossSpawn from \"cross-spawn\";\nvar EXIT_STDIO_GRACE_MS = 100;\nfunction spawnProcess(command, args, options) {\n  return process.platform === \"win32\" ? crossSpawn(command, args, options) : nodeSpawn(command, args, options);\n}\nfunction spawnProcessSync(command, args, options) {\n  return process.platform === \"win32\" ? crossSpawn.sync(command, args, options) : nodeSpawnSync(command, args, options);\n}\nfunction waitForChildProcess(child) {\n  return new Promise((resolve15, reject) => {\n    let settled = false;\n    let exited = false;\n    let exitCode = null;\n    let postExitTimer;\n    let stdoutEnded = child.stdout === null;\n    let stderrEnded = child.stderr === null;\n    const cleanup = () => {\n      if (postExitTimer) {\n        clearTimeout(postExitTimer);\n        postExitTimer = void 0;\n      }\n      child.removeListener(\"error\", onError);\n      child.removeListener(\"exit\", onExit);\n      child.removeListener(\"close\", onClose);\n      child.stdout?.removeListener(\"end\", onStdoutEnd);\n      child.stderr?.removeListener(\"end\", onStderrEnd);\n      child.stdout?.removeListener(\"data\", onData);\n      child.stderr?.removeListener(\"data\", onData);\n    };\n    const finalize = (code) => {\n      if (settled)\n        return;\n      settled = true;\n      cleanup();\n      child.stdout?.destroy();\n      child.stderr?.destroy();\n      resolve15(code);\n    };\n    const maybeFinalizeAfterExit = () => {\n      if (!exited || settled)\n        return;\n      if (stdoutEnded && stderrEnded) {\n        finalize(exitCode);\n      }\n    };\n    const armIdleTimer = () => {\n      if (postExitTimer)\n        clearTimeout(postExitTimer);\n      postExitTimer = setTimeout(() => finalize(exitCode), EXIT_STDIO_GRACE_MS);\n    };\n    const onData = () => {\n      if (exited && !settled)\n        armIdleTimer();\n    };\n    const onStdoutEnd = () => {\n      stdoutEnded = true;\n      maybeFinalizeAfterExit();\n    };\n    const onStderrEnd = () => {\n      stderrEnded = true;\n      maybeFinalizeAfterExit();\n    };\n    const onError = (err2) => {\n      if (settled)\n        return;\n      settled = true;\n      cleanup();\n      reject(err2);\n    };\n    const onExit = (code) => {\n      exited = true;\n      exitCode = code;\n      maybeFinalizeAfterExit();\n      if (!settled) {\n        armIdleTimer();\n      }\n    };\n    const onClose = (code) => {\n      finalize(code);\n    };\n    child.stdout?.once(\"end\", onStdoutEnd);\n    child.stderr?.once(\"end\", onStderrEnd);\n    child.stdout?.on(\"data\", onData);\n    child.stderr?.on(\"data\", onData);\n    child.once(\"error\", onError);\n    child.once(\"exit\", onExit);\n    child.once(\"close\", onClose);\n  });\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/utils/paths.js\nimport { realpathSync, statSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { isAbsolute, join, resolve as nodeResolvePath, relative, sep } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nvar UNICODE_SPACES = /[\\u00A0\\u2000-\\u200A\\u202F\\u205F\\u3000]/g;\nfunction canonicalizePath(path12) {\n  try {\n    return realpathSync(path12);\n  } catch {\n    return path12;\n  }\n}\nfunction getFileRevision(path12) {\n  try {\n    const stats = statSync(path12, { bigint: true });\n    return `${stats.dev}:${stats.ino}:${stats.size}:${stats.mtimeNs}:${stats.ctimeNs}`;\n  } catch {\n    return void 0;\n  }\n}\nfunction isLocalPath(value) {\n  const trimmed = value.trim();\n  if (trimmed.startsWith(\"npm:\") || trimmed.startsWith(\"git:\") || trimmed.startsWith(\"github:\") || trimmed.startsWith(\"http:\") || trimmed.startsWith(\"https:\") || trimmed.startsWith(\"ssh:\")) {\n    return false;\n  }\n  return true;\n}\nfunction normalizeWindowsShellPath(filePath) {\n  if (!filePath.startsWith(\"/\") || filePath.startsWith(\"//\") || filePath.includes(\"\\\\\"))\n    return filePath;\n  const match = filePath.match(/^\\/(?:mnt\\/|cygdrive\\/)?([a-z])(?:\\/(.*))?$/i);\n  if (!match)\n    return filePath;\n  const suffix = match[2]?.replaceAll(\"/\", \"\\\\\");\n  return `${match[1].toUpperCase()}:\\\\${suffix ?? \"\"}`;\n}\nfunction normalizePath(input, options = {}) {\n  let normalized = options.trim ? input.trim() : input;\n  if (options.normalizeUnicodeSpaces) {\n    normalized = normalized.replace(UNICODE_SPACES, \" \");\n  }\n  if (options.stripAtPrefix && normalized.startsWith(\"@\")) {\n    normalized = normalized.slice(1);\n  }\n  if (process.platform === \"win32\") {\n    normalized = normalizeWindowsShellPath(normalized);\n  }\n  if (options.expandTilde ?? true) {\n    const home = options.homeDir ?? homedir();\n    if (normalized === \"~\")\n      return home;\n    if (normalized.startsWith(\"~/\") || process.platform === \"win32\" && normalized.startsWith(\"~\\\\\")) {\n      return join(home, normalized.slice(2));\n    }\n  }\n  if (/^file:\\/\\//.test(normalized)) {\n    return fileURLToPath(normalized);\n  }\n  return normalized;\n}\nfunction resolvePath(input, baseDir = process.cwd(), options = {}) {\n  const normalized = normalizePath(input, options);\n  const normalizedBaseDir = normalizePath(baseDir);\n  return isAbsolute(normalized) ? nodeResolvePath(normalized) : nodeResolvePath(normalizedBaseDir, normalized);\n}\nfunction getCwdRelativePath(filePath, cwd) {\n  const resolvedCwd = resolvePath(cwd);\n  const resolvedPath = resolvePath(filePath, resolvedCwd);\n  const relativePath = relative(resolvedCwd, resolvedPath);\n  const isInsideCwd = relativePath === \"\" || relativePath !== \"..\" && !relativePath.startsWith(`..${sep}`) && !isAbsolute(relativePath);\n  return isInsideCwd ? relativePath || \".\" : void 0;\n}\nfunction formatPathRelativeToCwdOrAbsolute(filePath, cwd) {\n  const absolutePath = resolvePath(filePath, cwd);\n  return (getCwdRelativePath(absolutePath, cwd) ?? absolutePath).split(sep).join(\"/\");\n}\nfunction markPathIgnoredByCloudSync(path12) {\n  const attrs = process.platform === \"darwin\" ? [\"com.dropbox.ignored\", \"com.apple.fileprovider.ignore#P\"] : process.platform === \"linux\" ? [\"user.com.dropbox.ignored\"] : [];\n  for (const attr of attrs) {\n    if (process.platform === \"darwin\") {\n      spawnProcessSync(\"xattr\", [\"-w\", attr, \"1\", path12], { encoding: \"utf-8\", stdio: \"ignore\" });\n    } else {\n      spawnProcessSync(\"setfattr\", [\"-n\", attr, \"-v\", \"1\", path12], { encoding: \"utf-8\", stdio: \"ignore\" });\n    }\n  }\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/config.js\nvar __filename = fileURLToPath2(import.meta.url);\nvar __dirname = dirname(__filename);\nvar isBunBinary = import.meta.url.includes(\"$bunfs\") || import.meta.url.includes(\"~BUN\") || import.meta.url.includes(\"%7EBUN\");\nvar isBunRuntime = !!process.versions.bun;\nfunction normalizeSelfUpdatePackageTarget(target) {\n  if (typeof target === \"string\") {\n    return { packageName: target, installSpec: target };\n  }\n  return { packageName: target.packageName, installSpec: target.installSpec ?? target.packageName };\n}\nfunction makeSelfUpdateCommand(installStep, uninstallStep) {\n  if (!uninstallStep)\n    return installStep;\n  return {\n    ...installStep,\n    display: `${uninstallStep.display} && ${installStep.display}`,\n    steps: [uninstallStep, installStep]\n  };\n}\nfunction makeSelfUpdateCommandStep(command, args) {\n  return {\n    command,\n    args,\n    display: [command, ...args].map((arg) => /\\s/.test(arg) ? `\"${arg}\"` : arg).join(\" \")\n  };\n}\nfunction detectInstallMethod() {\n  if (isBunBinary) {\n    return \"bun-binary\";\n  }\n  const resolvedPath = `${__dirname}\\0${process.execPath || \"\"}`.toLowerCase().replace(/\\\\/g, \"/\");\n  if (resolvedPath.includes(\"/pnpm/\") || resolvedPath.includes(\"/.pnpm/\")) {\n    return \"pnpm\";\n  }\n  if (resolvedPath.includes(\"/yarn/\") || resolvedPath.includes(\"/.yarn/\")) {\n    return \"yarn\";\n  }\n  if (isBunRuntime || resolvedPath.includes(\"/install/global/node_modules/\")) {\n    return \"bun\";\n  }\n  if (resolvedPath.includes(\"/npm/\") || resolvedPath.includes(\"/node_modules/\")) {\n    return \"npm\";\n  }\n  return \"unknown\";\n}\nfunction getInferredNpmInstall() {\n  const packageDir = getPackageDir();\n  const path12 = process.platform === \"win32\" || packageDir.includes(\"\\\\\") ? win32 : { basename, dirname };\n  const parent = path12.dirname(packageDir);\n  let root;\n  if (path12.basename(parent).startsWith(\"@\") && path12.basename(path12.dirname(parent)) === \"node_modules\") {\n    root = path12.dirname(parent);\n  } else if (path12.basename(parent) === \"node_modules\") {\n    root = parent;\n  }\n  if (!root)\n    return void 0;\n  const rootParent = path12.dirname(root);\n  if (path12.basename(rootParent) === \"lib\")\n    return { root, prefix: path12.dirname(rootParent) };\n  return void 0;\n}\nfunction getSelfUpdateCommandForMethod(method, installedPackageName, updatePackageTarget = installedPackageName, npmCommand) {\n  const target = normalizeSelfUpdatePackageTarget(updatePackageTarget);\n  switch (method) {\n    case \"bun-binary\":\n      return void 0;\n    case \"pnpm\": {\n      const match = readCommandOutput(\"pnpm\", [\"root\", \"-g\"]) ? void 0 : /^(.*[\\\\/]global[\\\\/][^\\\\/]+)[\\\\/]\\.pnpm[\\\\/]/.exec(getPackageDir());\n      const binDirArgs = match ? [`--config.global-bin-dir=${process.env.PNPM_HOME || dirname(dirname(match[1]))}`] : [];\n      return makeSelfUpdateCommand(makeSelfUpdateCommandStep(\"pnpm\", [\n        \"install\",\n        \"-g\",\n        \"--ignore-scripts\",\n        \"--config.minimumReleaseAge=0\",\n        ...binDirArgs,\n        target.installSpec\n      ]), target.packageName === installedPackageName ? void 0 : makeSelfUpdateCommandStep(\"pnpm\", [\"remove\", \"-g\", ...binDirArgs, installedPackageName]));\n    }\n    case \"yarn\":\n      return makeSelfUpdateCommand(makeSelfUpdateCommandStep(\"yarn\", [\"global\", \"add\", \"--ignore-scripts\", target.installSpec]), target.packageName === installedPackageName ? void 0 : makeSelfUpdateCommandStep(\"yarn\", [\"global\", \"remove\", installedPackageName]));\n    case \"bun\":\n      return makeSelfUpdateCommand(makeSelfUpdateCommandStep(\"bun\", [\n        \"install\",\n        \"-g\",\n        \"--ignore-scripts\",\n        \"--minimum-release-age=0\",\n        target.installSpec\n      ]), target.packageName === installedPackageName ? void 0 : makeSelfUpdateCommandStep(\"bun\", [\"uninstall\", \"-g\", installedPackageName]));\n    case \"npm\": {\n      const [command = \"npm\", ...npmArgs] = npmCommand ?? [];\n      const inferred = npmCommand?.length ? void 0 : getInferredNpmInstall();\n      const prefixArgs = [...npmArgs, ...inferred ? [\"--prefix\", inferred.prefix] : []];\n      const installStep = makeSelfUpdateCommandStep(command, [\n        ...prefixArgs,\n        \"install\",\n        \"-g\",\n        \"--ignore-scripts\",\n        \"--min-release-age=0\",\n        target.installSpec\n      ]);\n      const uninstallStep = target.packageName === installedPackageName ? void 0 : makeSelfUpdateCommandStep(command, [...prefixArgs, \"uninstall\", \"-g\", installedPackageName]);\n      return makeSelfUpdateCommand(installStep, uninstallStep);\n    }\n    case \"unknown\":\n      return void 0;\n  }\n}\nfunction readCommandOutput(command, args, options = {}) {\n  const result = spawnProcessSync(command, args, {\n    encoding: \"utf-8\",\n    stdio: [\"ignore\", \"pipe\", \"pipe\"]\n  });\n  if (result.status === 0)\n    return result.stdout.trim() || void 0;\n  if (options.requireSuccess) {\n    const reason = result.error?.message || result.stderr.trim() || `exit code ${result.status ?? \"unknown\"}`;\n    throw new Error(`Failed to run ${[command, ...args].join(\" \")}: ${reason}`);\n  }\n  return void 0;\n}\nfunction getGlobalPackageRoots(method, _packageName, npmCommand) {\n  switch (method) {\n    case \"npm\": {\n      const configured = !!npmCommand?.length;\n      const [command = \"npm\", ...npmArgs] = npmCommand ?? [];\n      if (configured && command === \"bun\") {\n        const bunBin = readCommandOutput(command, [...npmArgs, \"pm\", \"bin\", \"-g\"], {\n          requireSuccess: true\n        });\n        const roots = [join2(homedir2(), \".bun\", \"install\", \"global\", \"node_modules\")];\n        if (bunBin) {\n          roots.push(join2(dirname(bunBin), \"install\", \"global\", \"node_modules\"));\n        }\n        return roots;\n      }\n      const root = readCommandOutput(command, [...npmArgs, \"root\", \"-g\"], {\n        requireSuccess: configured\n      });\n      const inferred = configured ? void 0 : getInferredNpmInstall();\n      return [root, inferred?.root].filter((x) => !!x);\n    }\n    case \"pnpm\": {\n      const root = readCommandOutput(\"pnpm\", [\"root\", \"-g\"]);\n      if (root)\n        return [root, dirname(root)];\n      const match = /^(.*[\\\\/]global[\\\\/][^\\\\/]+)[\\\\/]\\.pnpm[\\\\/]/.exec(getPackageDir());\n      return match ? [match[1]] : [];\n    }\n    case \"yarn\": {\n      const dir = readCommandOutput(\"yarn\", [\"global\", \"dir\"]);\n      return dir ? [dir, join2(dir, \"node_modules\")] : [];\n    }\n    case \"bun\": {\n      const bunBin = readCommandOutput(\"bun\", [\"pm\", \"bin\", \"-g\"]);\n      const roots = [join2(homedir2(), \".bun\", \"install\", \"global\", \"node_modules\")];\n      if (bunBin) {\n        roots.push(join2(dirname(bunBin), \"install\", \"global\", \"node_modules\"));\n      }\n      return roots;\n    }\n    case \"bun-binary\":\n    case \"unknown\":\n      return [];\n  }\n}\nfunction normalizeExistingPathForComparison(path12, resolveSymlinks) {\n  const resolvedPath = resolve(path12);\n  if (!existsSync(resolvedPath)) {\n    return void 0;\n  }\n  let normalizedPath = resolvedPath;\n  if (resolveSymlinks) {\n    try {\n      normalizedPath = realpathSync2(resolvedPath);\n    } catch {\n      return void 0;\n    }\n  }\n  if (process.platform === \"win32\") {\n    normalizedPath = normalizedPath.toLowerCase();\n  }\n  return normalizedPath;\n}\nfunction getPathComparisonCandidates(path12) {\n  return Array.from(new Set([normalizeExistingPathForComparison(path12, false), normalizeExistingPathForComparison(path12, true)].filter((candidate) => !!candidate)));\n}\nfunction getEntrypointPackageDir() {\n  const entrypoint = process.argv[1];\n  if (!entrypoint)\n    return void 0;\n  let dir = dirname(entrypoint);\n  while (dir !== dirname(dir)) {\n    if (existsSync(join2(dir, \"package.json\"))) {\n      return dir;\n    }\n    dir = dirname(dir);\n  }\n  return void 0;\n}\nfunction isSelfUpdatePathWritable() {\n  const packageDir = getPackageDir();\n  try {\n    accessSync(packageDir, constants.W_OK);\n    accessSync(dirname(packageDir), constants.W_OK);\n    return true;\n  } catch {\n    return false;\n  }\n}\nfunction isManagedByGlobalPackageManager(method, packageName, npmCommand) {\n  const packageDirs = [getPackageDir(), getEntrypointPackageDir()].filter((dir) => !!dir);\n  const packageDirCandidates = packageDirs.flatMap((dir) => getPathComparisonCandidates(dir));\n  return getGlobalPackageRoots(method, packageName, npmCommand).some((root) => {\n    return getPathComparisonCandidates(root).some((normalizedRoot) => {\n      const rootPrefix = normalizedRoot.endsWith(sep2) ? normalizedRoot : `${normalizedRoot}${sep2}`;\n      return packageDirCandidates.some((packageDir) => packageDir.startsWith(rootPrefix));\n    });\n  });\n}\nfunction getSelfUpdateCommand(packageName, npmCommand, updatePackageTarget = packageName) {\n  const method = detectInstallMethod();\n  const command = getSelfUpdateCommandForMethod(method, packageName, updatePackageTarget, npmCommand);\n  if (!command || !isManagedByGlobalPackageManager(method, packageName, npmCommand) || !isSelfUpdatePathWritable()) {\n    return void 0;\n  }\n  return command;\n}\nfunction getSelfUpdateUnavailableInstruction(packageName, npmCommand, updatePackageTarget = packageName) {\n  const method = detectInstallMethod();\n  const target = normalizeSelfUpdatePackageTarget(updatePackageTarget);\n  if (method === \"bun-binary\") {\n    return `Download from: https://github.com/earendil-works/pi-mono/releases/latest`;\n  }\n  const command = getSelfUpdateCommandForMethod(method, packageName, target, npmCommand);\n  if (command) {\n    if (isManagedByGlobalPackageManager(method, packageName, npmCommand) && !isSelfUpdatePathWritable()) {\n      return `This installation is managed by a global ${method} install, but the install path is not writable. Update it yourself with: ${command.display}`;\n    }\n    return `This installation is not managed by a global ${method} install. Update it with the package manager, wrapper, or source checkout that provides it.`;\n  }\n  return `Update ${target.installSpec} using the package manager, wrapper, or source checkout that provides this installation.`;\n}\nfunction getPackageDir() {\n  const envDir = process.env.PI_PACKAGE_DIR;\n  if (envDir) {\n    return normalizePath(envDir);\n  }\n  if (isBunBinary) {\n    return dirname(process.execPath);\n  }\n  let dir = __dirname;\n  while (dir !== dirname(dir)) {\n    if (existsSync(join2(dir, \"package.json\"))) {\n      return dir;\n    }\n    dir = dirname(dir);\n  }\n  return __dirname;\n}\nfunction getThemesDir() {\n  if (isBunBinary) {\n    return join2(getPackageDir(), \"theme\");\n  }\n  const packageDir = getPackageDir();\n  const srcOrDist = existsSync(join2(packageDir, \"src\")) ? \"src\" : \"dist\";\n  return join2(packageDir, srcOrDist, \"modes\", \"interactive\", \"theme\");\n}\nfunction getExportTemplateDir() {\n  if (isBunBinary) {\n    return join2(getPackageDir(), \"export-html\");\n  }\n  const packageDir = getPackageDir();\n  const srcOrDist = existsSync(join2(packageDir, \"src\")) ? \"src\" : \"dist\";\n  return join2(packageDir, srcOrDist, \"core\", \"export-html\");\n}\nfunction getPackageJsonPath() {\n  return join2(getPackageDir(), \"package.json\");\n}\nfunction getReadmePath() {\n  return resolve(join2(getPackageDir(), \"README.md\"));\n}\nfunction getDocsPath() {\n  return resolve(join2(getPackageDir(), \"docs\"));\n}\nfunction getExamplesPath() {\n  return resolve(join2(getPackageDir(), \"examples\"));\n}\nfunction getChangelogPath() {\n  return resolve(join2(getPackageDir(), \"CHANGELOG.md\"));\n}\nfunction getInteractiveAssetsDir() {\n  if (isBunBinary) {\n    return join2(getPackageDir(), \"assets\");\n  }\n  const packageDir = getPackageDir();\n  const srcOrDist = existsSync(join2(packageDir, \"src\")) ? \"src\" : \"dist\";\n  return join2(packageDir, srcOrDist, \"modes\", \"interactive\", \"assets\");\n}\nfunction getBundledInteractiveAssetPath(name) {\n  return join2(getInteractiveAssetsDir(), name);\n}\nvar pkg = {};\ntry {\n  pkg = JSON.parse(readFileSync(getPackageJsonPath(), \"utf-8\"));\n} catch (e) {\n  const err2 = e;\n  if (err2.code !== \"ENOENT\")\n    throw e;\n}\nvar piConfigName = pkg.piConfig?.name;\nvar PACKAGE_NAME = pkg.name || \"@earendil-works/pi-coding-agent\";\nvar APP_NAME = piConfigName || \"pi\";\nvar APP_TITLE = piConfigName ? APP_NAME : \"\\u03C0\";\nvar CONFIG_DIR_NAME = pkg.piConfig?.configDir || \".pi\";\nvar VERSION = pkg.version || \"0.0.0\";\nvar ENV_AGENT_DIR = `${APP_NAME.toUpperCase()}_CODING_AGENT_DIR`;\nvar ENV_SESSION_DIR = `${APP_NAME.toUpperCase()}_CODING_AGENT_SESSION_DIR`;\nfunction expandTildePath(path12) {\n  return normalizePath(path12);\n}\nvar DEFAULT_SHARE_VIEWER_URL = \"https://pi.dev/session/\";\nfunction getShareViewerUrl(gistId) {\n  const baseUrl = process.env.PI_SHARE_VIEWER_URL || DEFAULT_SHARE_VIEWER_URL;\n  return `${baseUrl}#${gistId}`;\n}\nfunction getAgentDir() {\n  const envDir = process.env[ENV_AGENT_DIR];\n  if (envDir) {\n    return expandTildePath(envDir);\n  }\n  return join2(homedir2(), CONFIG_DIR_NAME, \"agent\");\n}\nfunction getCustomThemesDir() {\n  return join2(getAgentDir(), \"themes\");\n}\nfunction getAuthPath() {\n  return join2(getAgentDir(), \"auth.json\");\n}\nfunction getSettingsPath() {\n  return join2(getAgentDir(), \"settings.json\");\n}\nfunction getBinDir() {\n  return join2(getAgentDir(), \"bin\");\n}\nfunction getSessionsDir() {\n  return join2(getAgentDir(), \"sessions\");\n}\nfunction getDebugLogPath() {\n  return join2(getAgentDir(), `${APP_NAME}-debug.log`);\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/core/http-dispatcher.js\nimport { EventEmitter } from \"node:events\";\nimport * as undici from \"undici\";\nvar DEFAULT_HTTP_IDLE_TIMEOUT_MS = 3e5;\nvar DEFAULT_AUTO_SELECT_FAMILY_ATTEMPT_TIMEOUT_MS = 2e3;\nvar HTTP_IDLE_TIMEOUT_CHOICES = [\n  { label: \"30 sec\", timeoutMs: 3e4 },\n  { label: \"1 min\", timeoutMs: 6e4 },\n  { label: \"2 min\", timeoutMs: 12e4 },\n  { label: \"5 min\", timeoutMs: 3e5 },\n  { label: \"disabled\", timeoutMs: 0 }\n];\nvar originalGlobalFetch = globalThis.fetch;\nvar installedGlobalFetch;\nfunction parseHttpIdleTimeoutMs(value) {\n  if (typeof value === \"string\") {\n    const trimmed = value.trim();\n    if (trimmed.toLowerCase() === \"disabled\") {\n      return 0;\n    }\n    if (trimmed.length === 0) {\n      return void 0;\n    }\n    return parseHttpIdleTimeoutMs(Number(trimmed));\n  }\n  if (typeof value !== \"number\" || !Number.isFinite(value) || value < 0) {\n    return void 0;\n  }\n  return Math.floor(value);\n}\nfunction formatHttpIdleTimeoutMs(timeoutMs) {\n  const choice = HTTP_IDLE_TIMEOUT_CHOICES.find((item) => item.timeoutMs === timeoutMs);\n  if (choice) {\n    return choice.label;\n  }\n  return `${timeoutMs / 1e3} sec`;\n}\nfunction applyHttpProxySettings(httpProxy) {\n  const proxy = httpProxy?.trim();\n  if (!proxy)\n    return;\n  process.env.HTTP_PROXY ??= proxy;\n  process.env.HTTPS_PROXY ??= proxy;\n}\nvar ignoreUndiciDispatcherError = (_error) => {\n};\nfunction withUndiciErrorListener(dispatcher) {\n  if (dispatcher instanceof EventEmitter) {\n    EventEmitter.prototype.on.call(dispatcher, \"error\", ignoreUndiciDispatcherError);\n  }\n  return dispatcher;\n}\nfunction createUndiciClient(origin, options) {\n  return withUndiciErrorListener(new undici.Client(origin, options));\n}\nfunction createUndiciOriginDispatcher(origin, options) {\n  const dispatcherOptions = options;\n  if (dispatcherOptions.connections === 1) {\n    return createUndiciClient(origin, dispatcherOptions);\n  }\n  return withUndiciErrorListener(new undici.Pool(origin, {\n    ...dispatcherOptions,\n    factory: createUndiciClient\n  }));\n}\nfunction configureHttpDispatcher(timeoutMs = DEFAULT_HTTP_IDLE_TIMEOUT_MS) {\n  const normalizedTimeoutMs = parseHttpIdleTimeoutMs(timeoutMs);\n  if (normalizedTimeoutMs === void 0) {\n    throw new Error(`Invalid HTTP idle timeout: ${String(timeoutMs)}`);\n  }\n  const dispatcher = withUndiciErrorListener(new undici.EnvHttpProxyAgent({\n    allowH2: false,\n    bodyTimeout: normalizedTimeoutMs,\n    connect: {\n      autoSelectFamilyAttemptTimeout: DEFAULT_AUTO_SELECT_FAMILY_ATTEMPT_TIMEOUT_MS\n    },\n    headersTimeout: normalizedTimeoutMs,\n    clientFactory: createUndiciClient,\n    factory: createUndiciOriginDispatcher\n  }));\n  undici.setGlobalDispatcher(dispatcher);\n  const shouldInstallGlobals = installedGlobalFetch === void 0 ? globalThis.fetch === originalGlobalFetch : globalThis.fetch === installedGlobalFetch;\n  if (shouldInstallGlobals) {\n    undici.install?.();\n    installedGlobalFetch = globalThis.fetch;\n  }\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/main.js\nimport { createInterface as createInterface4 } from \"node:readline\";\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/index.js\ninit_lazy();\ninit_context();\ninit_credential_store();\nimport { Type as Type2 } from \"typebox\";\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/auth/helpers.js\nfunction envApiKeyAuth(name, envVars) {\n  return {\n    name,\n    login: async (interaction) => {\n      interaction.signal.throwIfAborted();\n      const key = await interaction.prompt({ type: \"secret\", message: `Enter ${name}` });\n      interaction.signal.throwIfAborted();\n      return { type: \"api_key\", key };\n    },\n    resolve: async ({ ctx, credential, signal }) => {\n      signal.throwIfAborted();\n      if (credential?.key) {\n        return { auth: { apiKey: credential.key }, env: credential.env, source: \"stored credential\" };\n      }\n      for (const envVar of envVars) {\n        const value = await ctx.env(envVar);\n        signal.throwIfAborted();\n        if (value)\n          return { auth: { apiKey: value }, source: envVar };\n      }\n      return void 0;\n    }\n  };\n}\nfunction lazyOAuth(input) {\n  let promise;\n  const loaded = () => {\n    promise ??= input.load();\n    return promise;\n  };\n  return {\n    name: input.name,\n    isSubscription: input.isSubscription,\n    loginLabel: input.loginLabel,\n    login: async (interaction) => (await loaded()).login(interaction),\n    refresh: async (credential, signal) => (await loaded()).refresh(credential, signal),\n    toAuth: async (credential) => (await loaded()).toAuth(credential)\n  };\n}\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/images-models.js\ninit_context();\ninit_credential_store();\ninit_resolve();\nvar ImagesModelsImpl = class {\n  providers = /* @__PURE__ */ new Map();\n  credentials;\n  authContext;\n  constructor(options) {\n    this.credentials = options?.credentials ?? new InMemoryCredentialStore();\n    this.authContext = options?.authContext ?? defaultProviderAuthContext();\n  }\n  setProvider(provider) {\n    this.providers.set(provider.id, provider);\n  }\n  deleteProvider(id) {\n    this.providers.delete(id);\n  }\n  clearProviders() {\n    this.providers.clear();\n  }\n  getProviders() {\n    return Array.from(this.providers.values());\n  }\n  getProvider(id) {\n    return this.providers.get(id);\n  }\n  getModels(provider) {\n    if (provider !== void 0) {\n      const entry = this.providers.get(provider);\n      if (!entry)\n        return [];\n      try {\n        return entry.getModels();\n      } catch {\n        return [];\n      }\n    }\n    const models = [];\n    for (const entry of this.providers.values()) {\n      try {\n        models.push(...entry.getModels());\n      } catch {\n      }\n    }\n    return models;\n  }\n  getModel(provider, id) {\n    return this.getModels(provider).find((model) => model.id === id);\n  }\n  async refresh(provider) {\n    if (provider !== void 0) {\n      const entry = this.providers.get(provider);\n      if (!entry?.refreshModels)\n        return;\n      try {\n        await entry.refreshModels();\n      } catch (error) {\n        if (error instanceof ModelsError)\n          throw error;\n        throw new ModelsError(\"model_source\", `Model refresh failed for ${provider}`, { cause: error });\n      }\n      return;\n    }\n    await Promise.allSettled(Array.from(this.providers.values(), async (entry) => entry.refreshModels?.()));\n  }\n  async getAuth(providerOrModel, overrides) {\n    const providerId = typeof providerOrModel === \"string\" ? providerOrModel : providerOrModel.provider;\n    const provider = this.providers.get(providerId);\n    if (!provider)\n      return void 0;\n    return resolveProviderAuth(provider, this.credentials, this.authContext, overrides);\n  }\n  async generateImages(model, context, options) {\n    try {\n      const provider = this.providers.get(model.provider);\n      if (!provider) {\n        throw new ModelsError(\"provider\", `Unknown provider: ${model.provider}`);\n      }\n      const resolution = await this.getAuth(model, {\n        apiKey: options?.apiKey,\n        env: options?.env,\n        signal: options?.signal\n      });\n      const auth = resolution?.auth;\n      if (!auth) {\n        return provider.generateImages(model, context, options);\n      }\n      const requestModel = auth.baseUrl ? { ...model, baseUrl: auth.baseUrl } : model;\n      const apiKey = options?.apiKey ?? auth.apiKey;\n      const headers = auth.headers || options?.headers ? { ...auth.headers, ...options?.headers } : void 0;\n      const env = resolution.env || options?.env ? { ...resolution.env ?? {}, ...options?.env ?? {} } : void 0;\n      return await provider.generateImages(requestModel, context, { ...options, apiKey, headers, env });\n    } catch (error) {\n      return {\n        api: model.api,\n        provider: model.provider,\n        model: model.id,\n        output: [],\n        stopReason: \"error\",\n        errorMessage: error instanceof Error ? error.message : String(error),\n        timestamp: Date.now()\n      };\n    }\n  }\n};\nfunction createImagesModels(options) {\n  return new ImagesModelsImpl(options);\n}\nfunction createImagesProvider(input) {\n  let models = input.models;\n  let inflightRefresh;\n  const refreshModels = input.refreshModels;\n  return {\n    id: input.id,\n    name: input.name ?? input.id,\n    auth: input.auth,\n    getModels: () => models,\n    refreshModels: refreshModels ? () => {\n      inflightRefresh ??= (async () => {\n        try {\n          models = await refreshModels();\n        } finally {\n          inflightRefresh = void 0;\n        }\n      })();\n      return inflightRefresh;\n    } : void 0,\n    generateImages: (model, context, options) => input.api.generateImages(model, context, options)\n  };\n}\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/index.js\ninit_models();\ninit_models_store();\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/faux.js\ninit_models();\ninit_event_stream();\nvar DEFAULT_API = \"faux\";\nvar DEFAULT_PROVIDER = \"faux\";\nvar DEFAULT_MODEL_ID = \"faux-1\";\nvar DEFAULT_MODEL_NAME = \"Faux Model\";\nvar DEFAULT_BASE_URL = \"http://localhost:0\";\nvar DEFAULT_MIN_TOKEN_SIZE = 3;\nvar DEFAULT_MAX_TOKEN_SIZE = 5;\nvar DEFAULT_USAGE = {\n  input: 0,\n  output: 0,\n  cacheRead: 0,\n  cacheWrite: 0,\n  totalTokens: 0,\n  cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 }\n};\nfunction fauxText(text) {\n  return { type: \"text\", text };\n}\nfunction fauxThinking(thinking) {\n  return { type: \"thinking\", thinking };\n}\nfunction fauxToolCall(name, arguments_, options = {}) {\n  return {\n    type: \"toolCall\",\n    id: options.id ?? randomId(\"tool\"),\n    name,\n    arguments: arguments_\n  };\n}\nfunction normalizeFauxAssistantContent(content) {\n  if (typeof content === \"string\") {\n    return [fauxText(content)];\n  }\n  return Array.isArray(content) ? content : [content];\n}\nfunction fauxAssistantMessage(content, options = {}) {\n  return {\n    role: \"assistant\",\n    content: normalizeFauxAssistantContent(content),\n    api: DEFAULT_API,\n    provider: DEFAULT_PROVIDER,\n    model: DEFAULT_MODEL_ID,\n    usage: DEFAULT_USAGE,\n    stopReason: options.stopReason ?? \"stop\",\n    deferred: options.deferred,\n    errorMessage: options.errorMessage,\n    responseId: options.responseId,\n    timestamp: options.timestamp ?? Date.now()\n  };\n}\nfunction estimateTokens(text) {\n  return Math.ceil(text.length / 4);\n}\nfunction randomId(prefix) {\n  return `${prefix}:${Date.now()}:${Math.random().toString(36).slice(2)}`;\n}\nfunction contentToText(content) {\n  if (typeof content === \"string\") {\n    return content;\n  }\n  return content.map((block) => {\n    if (block.type === \"text\") {\n      return block.text;\n    }\n    return `[image:${block.mimeType}:${block.data.length}]`;\n  }).join(\"\\n\");\n}\nfunction assistantContentToText(content) {\n  return content.map((block) => {\n    if (block.type === \"text\") {\n      return block.text;\n    }\n    if (block.type === \"thinking\") {\n      return block.thinking;\n    }\n    return `${block.name}:${JSON.stringify(block.arguments)}`;\n  }).join(\"\\n\");\n}\nfunction toolResultToText(message) {\n  return [message.toolName, ...message.content.map((block) => contentToText([block]))].join(\"\\n\");\n}\nfunction messageToText(message) {\n  if (message.role === \"user\") {\n    return contentToText(message.content);\n  }\n  if (message.role === \"assistant\") {\n    return assistantContentToText(message.content);\n  }\n  return toolResultToText(message);\n}\nfunction serializeContext(context) {\n  const parts = [];\n  if (context.systemPrompt) {\n    parts.push(`system:${context.systemPrompt}`);\n  }\n  for (const message of context.messages) {\n    parts.push(`${message.role}:${messageToText(message)}`);\n  }\n  if (context.tools?.length) {\n    parts.push(`tools:${JSON.stringify(context.tools)}`);\n  }\n  return parts.join(\"\\n\\n\");\n}\nfunction commonPrefixLength(a, b) {\n  const length = Math.min(a.length, b.length);\n  let index = 0;\n  while (index < length && a[index] === b[index]) {\n    index++;\n  }\n  return index;\n}\nfunction withUsageEstimate(message, context, options, promptCache) {\n  const promptText = serializeContext(context);\n  const promptTokens = estimateTokens(promptText);\n  const outputTokens = estimateTokens(assistantContentToText(message.content));\n  let input = promptTokens;\n  let cacheRead = 0;\n  let cacheWrite = 0;\n  const sessionId = options?.sessionId;\n  if (sessionId && options?.cacheRetention !== \"none\") {\n    const previousPrompt = promptCache.get(sessionId);\n    if (previousPrompt) {\n      const cachedChars = commonPrefixLength(previousPrompt, promptText);\n      cacheRead = estimateTokens(previousPrompt.slice(0, cachedChars));\n      cacheWrite = estimateTokens(promptText.slice(cachedChars));\n      input = Math.max(0, promptTokens - cacheRead);\n    } else {\n      cacheWrite = promptTokens;\n    }\n    promptCache.set(sessionId, promptText);\n  }\n  return {\n    ...message,\n    usage: {\n      input,\n      output: outputTokens,\n      cacheRead,\n      cacheWrite,\n      totalTokens: input + outputTokens + cacheRead + cacheWrite,\n      cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 }\n    }\n  };\n}\nfunction splitStringByTokenSize(text, minTokenSize, maxTokenSize) {\n  const chunks = [];\n  let index = 0;\n  while (index < text.length) {\n    const tokenSize = minTokenSize + Math.floor(Math.random() * (maxTokenSize - minTokenSize + 1));\n    const charSize = Math.max(1, tokenSize * 4);\n    chunks.push(text.slice(index, index + charSize));\n    index += charSize;\n  }\n  return chunks.length > 0 ? chunks : [\"\"];\n}\nfunction cloneMessage(message, api, provider, modelId) {\n  const cloned = structuredClone(message);\n  return {\n    ...cloned,\n    api,\n    provider,\n    model: modelId,\n    timestamp: cloned.timestamp ?? Date.now(),\n    usage: cloned.usage ?? DEFAULT_USAGE\n  };\n}\nfunction createDeferredMessage(model, handle) {\n  return {\n    role: \"assistant\",\n    content: [],\n    api: model.api,\n    provider: model.provider,\n    model: model.id,\n    usage: DEFAULT_USAGE,\n    stopReason: \"deferred\",\n    deferred: handle,\n    timestamp: Date.now()\n  };\n}\nfunction createErrorMessage(error, api, provider, modelId) {\n  return {\n    role: \"assistant\",\n    content: [],\n    api,\n    provider,\n    model: modelId,\n    usage: DEFAULT_USAGE,\n    stopReason: \"error\",\n    errorMessage: error instanceof Error ? error.message : String(error),\n    timestamp: Date.now()\n  };\n}\nfunction createAbortedMessage(partial) {\n  return {\n    ...partial,\n    stopReason: \"aborted\",\n    errorMessage: \"Request was aborted\",\n    timestamp: Date.now()\n  };\n}\nfunction scheduleChunk(chunk, tokensPerSecond) {\n  if (!tokensPerSecond || tokensPerSecond <= 0) {\n    return new Promise((resolve15) => queueMicrotask(resolve15));\n  }\n  const delayMs = estimateTokens(chunk) / tokensPerSecond * 1e3;\n  return new Promise((resolve15) => setTimeout(resolve15, delayMs));\n}\nasync function streamWithDeltas(stream11, message, minTokenSize, maxTokenSize, tokensPerSecond, signal) {\n  const partial = { ...message, content: [], stopReason: \"pending\" };\n  if (signal?.aborted) {\n    const aborted = createAbortedMessage(partial);\n    stream11.push({ type: \"error\", reason: \"aborted\", error: aborted });\n    stream11.end(aborted);\n    return;\n  }\n  stream11.push({ type: \"start\", partial: { ...partial } });\n  for (let index = 0; index < message.content.length; index++) {\n    if (signal?.aborted) {\n      const aborted = createAbortedMessage(partial);\n      stream11.push({ type: \"error\", reason: \"aborted\", error: aborted });\n      stream11.end(aborted);\n      return;\n    }\n    const block = message.content[index];\n    if (block.type === \"thinking\") {\n      partial.content = [...partial.content, { type: \"thinking\", thinking: \"\" }];\n      stream11.push({ type: \"thinking_start\", contentIndex: index, partial: { ...partial } });\n      for (const chunk of splitStringByTokenSize(block.thinking, minTokenSize, maxTokenSize)) {\n        await scheduleChunk(chunk, tokensPerSecond);\n        if (signal?.aborted) {\n          const aborted = createAbortedMessage(partial);\n          stream11.push({ type: \"error\", reason: \"aborted\", error: aborted });\n          stream11.end(aborted);\n          return;\n        }\n        partial.content[index].thinking += chunk;\n        stream11.push({ type: \"thinking_delta\", contentIndex: index, delta: chunk, partial: { ...partial } });\n      }\n      stream11.push({\n        type: \"thinking_end\",\n        contentIndex: index,\n        content: block.thinking,\n        partial: { ...partial }\n      });\n      continue;\n    }\n    if (block.type === \"text\") {\n      partial.content = [...partial.content, { type: \"text\", text: \"\" }];\n      stream11.push({ type: \"text_start\", contentIndex: index, partial: { ...partial } });\n      for (const chunk of splitStringByTokenSize(block.text, minTokenSize, maxTokenSize)) {\n        await scheduleChunk(chunk, tokensPerSecond);\n        if (signal?.aborted) {\n          const aborted = createAbortedMessage(partial);\n          stream11.push({ type: \"error\", reason: \"aborted\", error: aborted });\n          stream11.end(aborted);\n          return;\n        }\n        partial.content[index].text += chunk;\n        stream11.push({ type: \"text_delta\", contentIndex: index, delta: chunk, partial: { ...partial } });\n      }\n      stream11.push({ type: \"text_end\", contentIndex: index, content: block.text, partial: { ...partial } });\n      continue;\n    }\n    partial.content = [...partial.content, { type: \"toolCall\", id: block.id, name: block.name, arguments: {} }];\n    stream11.push({ type: \"toolcall_start\", contentIndex: index, partial: { ...partial } });\n    for (const chunk of splitStringByTokenSize(JSON.stringify(block.arguments), minTokenSize, maxTokenSize)) {\n      await scheduleChunk(chunk, tokensPerSecond);\n      if (signal?.aborted) {\n        const aborted = createAbortedMessage(partial);\n        stream11.push({ type: \"error\", reason: \"aborted\", error: aborted });\n        stream11.end(aborted);\n        return;\n      }\n      stream11.push({ type: \"toolcall_delta\", contentIndex: index, delta: chunk, partial: { ...partial } });\n    }\n    partial.content[index].arguments = block.arguments;\n    stream11.push({ type: \"toolcall_end\", contentIndex: index, toolCall: block, partial: { ...partial } });\n  }\n  if (message.stopReason === \"pending\") {\n    throw new Error(\"Faux response ended without a stop reason\");\n  }\n  if (message.stopReason === \"error\" || message.stopReason === \"aborted\") {\n    stream11.push({ type: \"error\", reason: message.stopReason, error: message });\n    stream11.end(message);\n    return;\n  }\n  stream11.push({ type: \"done\", reason: message.stopReason, message });\n  stream11.end(message);\n}\nfunction createFauxCore(options) {\n  const api = options.api ?? randomId(DEFAULT_API);\n  const provider = options.provider ?? DEFAULT_PROVIDER;\n  const minTokenSize = Math.max(1, Math.min(options.tokenSize?.min ?? DEFAULT_MIN_TOKEN_SIZE, options.tokenSize?.max ?? DEFAULT_MAX_TOKEN_SIZE));\n  const maxTokenSize = Math.max(minTokenSize, options.tokenSize?.max ?? DEFAULT_MAX_TOKEN_SIZE);\n  let pendingResponses = [];\n  const tokensPerSecond = options.tokensPerSecond;\n  const state = { callCount: 0, deferredFetchCount: 0, cancelledDeferred: [] };\n  const promptCache = /* @__PURE__ */ new Map();\n  const deferredResponses = /* @__PURE__ */ new Map();\n  const modelDefinitions = options.models?.length ? options.models : [\n    {\n      id: DEFAULT_MODEL_ID,\n      name: DEFAULT_MODEL_NAME,\n      reasoning: false,\n      input: [\"text\", \"image\"],\n      cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },\n      contextWindow: 128e3,\n      maxTokens: 16384\n    }\n  ];\n  const models = modelDefinitions.map((definition) => ({\n    id: definition.id,\n    name: definition.name ?? definition.id,\n    api,\n    provider,\n    baseUrl: DEFAULT_BASE_URL,\n    reasoning: definition.reasoning ?? false,\n    input: definition.input ?? [\"text\", \"image\"],\n    cost: definition.cost ?? { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },\n    contextWindow: definition.contextWindow ?? 128e3,\n    maxTokens: definition.maxTokens ?? 16384\n  }));\n  const resolveResponse = async (step, context, streamOptions, requestModel) => {\n    const resolved = typeof step === \"function\" ? await step(context, streamOptions, state, requestModel) : step;\n    return withUsageEstimate(cloneMessage(resolved, api, provider, requestModel.id), context, streamOptions, promptCache);\n  };\n  const stream11 = (requestModel, context, streamOptions) => {\n    const outer = createAssistantMessageEventStream();\n    const step = pendingResponses.shift();\n    state.callCount++;\n    queueMicrotask(async () => {\n      try {\n        await streamOptions?.onResponse?.({ status: 200, headers: {} }, requestModel);\n        if (!step) {\n          let message2 = createErrorMessage(new Error(\"No more faux responses queued\"), api, provider, requestModel.id);\n          message2 = withUsageEstimate(message2, context, streamOptions, promptCache);\n          outer.push({ type: \"error\", reason: \"error\", error: message2 });\n          outer.end(message2);\n          return;\n        }\n        if (streamOptions?.deferred) {\n          const handle = {\n            provider: requestModel.provider,\n            modelId: requestModel.id,\n            api: requestModel.api,\n            id: randomId(\"deferred\"),\n            ...options.deferred?.pollAfterMs !== void 0 ? { pollAfterMs: options.deferred.pollAfterMs } : {}\n          };\n          deferredResponses.set(handle.id, {\n            handle,\n            step,\n            context,\n            options: streamOptions,\n            model: requestModel,\n            pendingFetches: Math.max(0, Math.floor(options.deferred?.pendingFetches ?? 0)),\n            cancelled: false\n          });\n          await streamWithDeltas(outer, createDeferredMessage(requestModel, handle), minTokenSize, maxTokenSize, tokensPerSecond, streamOptions.signal);\n          return;\n        }\n        const message = await resolveResponse(step, context, streamOptions, requestModel);\n        await streamWithDeltas(outer, message, minTokenSize, maxTokenSize, tokensPerSecond, streamOptions?.signal);\n      } catch (error) {\n        const message = createErrorMessage(error, api, provider, requestModel.id);\n        outer.push({ type: \"error\", reason: \"error\", error: message });\n        outer.end(message);\n      }\n    });\n    return outer;\n  };\n  const streamSimple11 = (streamModel, context, streamOptions) => stream11(streamModel, context, streamOptions);\n  const fetchDeferred = (requestModel, handle, fetchOptions) => {\n    const outer = createAssistantMessageEventStream();\n    state.deferredFetchCount++;\n    queueMicrotask(async () => {\n      try {\n        await fetchOptions?.onResponse?.({ status: 200, headers: {} }, requestModel);\n        const entry = deferredResponses.get(handle.id);\n        if (!entry || entry.handle.provider !== handle.provider || entry.handle.modelId !== handle.modelId || entry.handle.api !== handle.api) {\n          throw new Error(`Unknown faux deferred response: ${handle.id}`);\n        }\n        if (entry.cancelled)\n          throw new Error(`Faux deferred response was cancelled: ${handle.id}`);\n        if (entry.pendingFetches > 0) {\n          entry.pendingFetches--;\n          await streamWithDeltas(outer, createDeferredMessage(requestModel, entry.handle), minTokenSize, maxTokenSize, tokensPerSecond, fetchOptions?.signal);\n          return;\n        }\n        if (!entry.final) {\n          const { deferred: _deferred, signal: _submissionSignal, onResponse: _submissionOnResponse, ...submissionOptions } = entry.options ?? {};\n          try {\n            entry.final = await resolveResponse(entry.step, entry.context, submissionOptions, entry.model);\n          } catch (error) {\n            entry.final = createErrorMessage(error, api, provider, entry.model.id);\n          }\n        }\n        await streamWithDeltas(outer, entry.final, minTokenSize, maxTokenSize, tokensPerSecond, fetchOptions?.signal);\n      } catch (error) {\n        const message = createErrorMessage(error, api, provider, requestModel.id);\n        outer.push({ type: \"error\", reason: \"error\", error: message });\n        outer.end(message);\n      }\n    });\n    return outer;\n  };\n  const cancelDeferred = async (requestModel, handle, cancelOptions) => {\n    state.cancelledDeferred.push(structuredClone(handle));\n    const entry = deferredResponses.get(handle.id);\n    if (entry)\n      entry.cancelled = true;\n    await cancelOptions?.onResponse?.({ status: 200, headers: {} }, requestModel);\n  };\n  function getModel2(requestedModelId) {\n    if (!requestedModelId) {\n      return models[0];\n    }\n    return models.find((candidate) => candidate.id === requestedModelId);\n  }\n  return {\n    api,\n    provider,\n    models,\n    stream: stream11,\n    streamSimple: streamSimple11,\n    fetchDeferred,\n    cancelDeferred,\n    getModel: getModel2,\n    state,\n    setResponses(responses) {\n      pendingResponses = [...responses];\n    },\n    appendResponses(responses) {\n      pendingResponses.push(...responses);\n    },\n    getPendingResponseCount() {\n      return pendingResponses.length;\n    }\n  };\n}\nfunction fauxProvider(options = {}) {\n  const core = createFauxCore(options);\n  const provider = createProvider({\n    id: core.provider,\n    auth: { apiKey: { name: \"Faux\", resolve: async () => ({ auth: {} }) } },\n    models: core.models,\n    api: {\n      stream: core.stream,\n      streamSimple: core.streamSimple,\n      fetchDeferred: core.fetchDeferred,\n      cancelDeferred: core.cancelDeferred\n    }\n  });\n  return {\n    provider,\n    api: core.api,\n    models: core.models,\n    getModel: core.getModel,\n    state: core.state,\n    setResponses: core.setResponses,\n    appendResponses: core.appendResponses,\n    getPendingResponseCount: core.getPendingResponseCount\n  };\n}\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/index.js\ninit_session_resources();\ninit_diagnostics();\ninit_event_stream();\ninit_json_parse();\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/utils/overflow.js\nvar OVERFLOW_PATTERNS = [\n  /prompt is too long/i,\n  // Anthropic token overflow\n  /request_too_large/i,\n  // Anthropic request byte-size overflow (HTTP 413)\n  /input is too long for requested model/i,\n  // Amazon Bedrock\n  /exceeds the context window/i,\n  // OpenAI (Completions & Responses API)\n  /exceeds (?:the )?(?:model'?s )?maximum context length(?: of [\\d,]+ tokens?|\\s*\\([\\d,]+\\))/i,\n  // OpenAI-compatible proxies (LiteLLM)\n  /input token count.*exceeds the maximum/i,\n  // Google (Gemini)\n  /maximum prompt length is \\d+/i,\n  // xAI (Grok)\n  /reduce the length of the messages/i,\n  // Groq\n  /maximum context length is \\d+ tokens/i,\n  // OpenRouter (most backends)\n  /exceeds (?:the )?maximum allowed input length of [\\d,]+ tokens?/i,\n  // OpenRouter/Poolside\n  /input \\(\\d+ tokens\\) is longer than the model'?s context length \\(\\d+ tokens\\)/i,\n  // Together AI\n  /exceeds the limit of \\d+/i,\n  // GitHub Copilot\n  /exceeds the available context size/i,\n  // llama.cpp server\n  /greater than the context length/i,\n  // LM Studio\n  /context window exceeds limit/i,\n  // MiniMax\n  /exceeded model token limit/i,\n  // Kimi For Coding\n  /too large for model with \\d+ maximum context length/i,\n  // Mistral\n  /prompt has [\\d,]+ tokens?, but the configured context size is [\\d,]+ tokens?/i,\n  // DS4 server\n  /model_context_window_exceeded/i,\n  // z.ai non-standard finish_reason surfaced as error text\n  /prompt too long; exceeded (?:max )?context length/i,\n  // Ollama explicit overflow error\n  /range of input length should be/i,\n  // DashScope / Qwen Token Plan\n  /context[_ ]length[_ ]exceeded/i,\n  // Generic fallback\n  /too many tokens/i,\n  // Generic fallback\n  /token limit exceeded/i,\n  // Generic fallback\n  /^4(?:00|13)\\s*(?:status code)?\\s*\\(no body\\)/i\n  // Cerebras: 400/413 with no body\n];\nvar NON_OVERFLOW_PATTERNS = [\n  /^(Throttling error|Service unavailable):/i,\n  // AWS Bedrock non-overflow errors (human-readable prefixes from formatBedrockError)\n  /rate limit/i,\n  // Generic rate limiting\n  /too many requests/i\n  // Generic HTTP 429 style\n];\nfunction isContextOverflow(message, contextWindow) {\n  if (message.stopReason === \"error\" && message.errorMessage) {\n    const isNonOverflow = NON_OVERFLOW_PATTERNS.some((p) => p.test(message.errorMessage));\n    if (!isNonOverflow && OVERFLOW_PATTERNS.some((p) => p.test(message.errorMessage))) {\n      return true;\n    }\n  }\n  if (contextWindow && message.stopReason === \"stop\") {\n    const inputTokens = message.usage.input + message.usage.cacheRead;\n    if (inputTokens > contextWindow) {\n      return true;\n    }\n  }\n  if (contextWindow && message.stopReason === \"length\" && message.usage.output === 0) {\n    const inputTokens = message.usage.input + message.usage.cacheRead;\n    if (inputTokens >= contextWindow * 0.99) {\n      return true;\n    }\n  }\n  return false;\n}\nfunction isRecoverableLength(message, desiredMaxOutput) {\n  return message.stopReason === \"length\" && desiredMaxOutput > 0 && message.usage.output < desiredMaxOutput;\n}\nfunction getOverflowPatterns() {\n  return [...OVERFLOW_PATTERNS];\n}\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/utils/retry.js\nfunction buildProviderErrorPattern(patterns) {\n  return new RegExp(patterns.join(\"|\"), \"i\");\n}\nvar NON_RETRYABLE_PROVIDER_LIMIT_ERROR_PATTERN = buildProviderErrorPattern([\n  // OpenCode Go/free-tier limits returned as 429 JSON error types by OpenCode's\n  // Zen API. These are subscription/account limits, not transient throttles.\n  \"GoUsageLimitError\",\n  \"FreeUsageLimitError\",\n  // OpenCode Go subscription-limit text asks users to enable available-balance\n  // usage after rolling/weekly/monthly limits are reached.\n  \"Monthly usage limit reached\",\n  \"available balance\",\n  // Generic quota/budget/billing exhaustion. `insufficient_quota` is OpenAI's\n  // quota/billing error code; the other strings cover common gateway wording.\n  \"insufficient_quota\",\n  \"out of budget\",\n  \"quota exceeded\",\n  \"billing\"\n]);\nvar RETRYABLE_PROVIDER_ERROR_PATTERN = buildProviderErrorPattern([\n  // Generic provider load, HTTP status, and server-side transient failures.\n  \"overloaded\",\n  \"rate.?limit\",\n  \"too many requests\",\n  \"429\",\n  \"500\",\n  \"502\",\n  \"503\",\n  \"504\",\n  \"524\",\n  \"service.?unavailable\",\n  \"server.?error\",\n  \"internal.?error\",\n  // Wrapper/provider text for transient upstream failures, including OpenRouter\n  // \"Provider returned error\" responses (#2264).\n  \"provider.?returned.?error\",\n  \"exceeded request buffer limit while retrying upstream\",\n  // Network, proxy, and fetch transport failures. This includes OpenAI Codex\n  // raw-fetch failures such as \"upstream connect\", \"connection refused\", and\n  // \"reset before headers\" (#733), plus OpenRouter connection drops (#3317).\n  \"network.?error\",\n  \"connection.?error\",\n  \"connection.?refused\",\n  \"connection.?lost\",\n  \"other side closed\",\n  \"fetch failed\",\n  \"getaddrinfo\",\n  \"ENOTFOUND\",\n  \"EAI_AGAIN\",\n  \"upstream.?connect\",\n  \"reset before headers\",\n  \"socket hang up\",\n  \"socket connection was closed\",\n  \"timed? out\",\n  \"timeout\",\n  \"terminated\",\n  // WebSocket transports can report close/error text instead of HTTP/fetch text.\n  \"websocket.?closed\",\n  \"websocket.?error\",\n  // Premature stream endings from SDKs and transports. Anthropic can throw\n  // \"stream ended without ...\" and \"Anthropic stream ended before message_stop\"\n  // (#4433); Bedrock/Smithy can throw an HTTP/2 no-response error (#3594).\n  \"ended without\",\n  \"stream ended before message_stop\",\n  \"stream ended before a terminal response event\",\n  \"http2 request did not get a response\",\n  // Provider-requested retry delay cap failures should flow through the outer\n  // retry policy so callers can surface/abort the backoff (#1123).\n  \"retry delay\",\n  // Explicit retry guidance emitted mid-stream by OpenAI Responses and Bedrock\n  // stream exceptions (#6019).\n  \"you can retry your request\",\n  \"try your request again\",\n  \"please retry your request\",\n  // gRPC based providers (e.g. NVIDIA NIM)\n  \"ResourceExhausted\"\n]);\nvar RetrySleepAbortError = class extends Error {\n  constructor() {\n    super(\"Aborted\");\n  }\n};\nfunction sleep(ms, signal) {\n  return new Promise((resolve15, reject) => {\n    if (signal?.aborted) {\n      reject(new RetrySleepAbortError());\n      return;\n    }\n    const timeout = setTimeout(resolve15, ms);\n    signal?.addEventListener(\"abort\", () => {\n      clearTimeout(timeout);\n      reject(new RetrySleepAbortError());\n    }, { once: true });\n  });\n}\nasync function retryAssistantCall(produce, policy, signal, callbacks) {\n  const maxAttempts = policy?.enabled ? policy.maxRetries : 0;\n  let attempt = 0;\n  let lastRetry;\n  for (; ; ) {\n    const response = await produce();\n    if (response.stopReason === \"aborted\") {\n      if (lastRetry)\n        await callbacks?.onRetryFinished?.(false, lastRetry.attempt);\n      return response;\n    }\n    if (response.stopReason !== \"error\") {\n      if (lastRetry)\n        await callbacks?.onRetryFinished?.(true, lastRetry.attempt);\n      return response;\n    }\n    if (attempt >= maxAttempts || !isRetryableAssistantError(response)) {\n      if (lastRetry)\n        await callbacks?.onRetryFinished?.(false, lastRetry.attempt, response.errorMessage);\n      return response;\n    }\n    attempt++;\n    lastRetry = { attempt, errorMessage: response.errorMessage || \"Unknown error\" };\n    const delayMs = policy.baseDelayMs * 2 ** (attempt - 1);\n    await callbacks?.onRetryScheduled?.(attempt, maxAttempts, delayMs, lastRetry.errorMessage);\n    try {\n      await sleep(delayMs, signal);\n    } catch (error) {\n      await callbacks?.onRetryFinished?.(false, attempt, lastRetry.errorMessage);\n      if (error instanceof RetrySleepAbortError) {\n        return { ...response, stopReason: \"aborted\", errorMessage: void 0 };\n      }\n      throw error;\n    }\n    await callbacks?.onRetryAttemptStart?.();\n  }\n}\nfunction isRetryableAssistantError(message) {\n  if (message.stopReason !== \"error\" || !message.errorMessage)\n    return false;\n  const errorMessage2 = message.errorMessage;\n  if (NON_RETRYABLE_PROVIDER_LIMIT_ERROR_PATTERN.test(errorMessage2))\n    return false;\n  return RETRYABLE_PROVIDER_ERROR_PATTERN.test(errorMessage2);\n}\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/utils/text.js\nfunction contentText(content, separator = \"\\n\") {\n  if (typeof content === \"string\")\n    return content;\n  return content.filter((block) => block.type === \"text\").map((block) => block.text).join(separator);\n}\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/utils/typebox-helpers.js\nimport { Type } from \"typebox\";\nfunction StringEnum(values, options) {\n  return Type.Unsafe({\n    type: \"string\",\n    enum: values,\n    ...options?.description && { description: options.description },\n    ...options?.default && { default: options.default }\n  });\n}\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/index.js\ninit_uuid();\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/utils/validation.js\nimport { Compile } from \"typebox/compile\";\nimport { Value } from \"typebox/value\";\nvar validatorCache = /* @__PURE__ */ new WeakMap();\nvar TYPEBOX_KIND = Symbol.for(\"TypeBox.Kind\");\nfunction getSchemaTypes(schema) {\n  if (typeof schema.type === \"string\") {\n    return [schema.type];\n  }\n  if (Array.isArray(schema.type)) {\n    return schema.type.filter((type) => typeof type === \"string\");\n  }\n  return [];\n}\nfunction matchesJsonType(value, type) {\n  switch (type) {\n    case \"number\":\n      return typeof value === \"number\";\n    case \"integer\":\n      return typeof value === \"number\" && Number.isInteger(value);\n    case \"boolean\":\n      return typeof value === \"boolean\";\n    case \"string\":\n      return typeof value === \"string\";\n    case \"null\":\n      return value === null;\n    case \"array\":\n      return Array.isArray(value);\n    case \"object\":\n      return typeof value === \"object\" && value !== null && !Array.isArray(value);\n    default:\n      return false;\n  }\n}\nfunction getSubSchemaValidator(schema) {\n  try {\n    return getValidator(schema);\n  } catch {\n    return void 0;\n  }\n}\nfunction coercePrimitiveByType(value, type) {\n  switch (type) {\n    case \"number\": {\n      if (value === null) {\n        return 0;\n      }\n      if (typeof value === \"string\" && value.trim() !== \"\") {\n        const parsed = Number(value);\n        if (Number.isFinite(parsed)) {\n          return parsed;\n        }\n      }\n      if (typeof value === \"boolean\") {\n        return value ? 1 : 0;\n      }\n      return value;\n    }\n    case \"integer\": {\n      if (value === null) {\n        return 0;\n      }\n      if (typeof value === \"string\" && value.trim() !== \"\") {\n        const parsed = Number(value);\n        if (Number.isInteger(parsed)) {\n          return parsed;\n        }\n      }\n      if (typeof value === \"boolean\") {\n        return value ? 1 : 0;\n      }\n      return value;\n    }\n    case \"boolean\": {\n      if (value === null) {\n        return false;\n      }\n      if (typeof value === \"string\") {\n        if (value === \"true\") {\n          return true;\n        }\n        if (value === \"false\") {\n          return false;\n        }\n      }\n      if (typeof value === \"number\") {\n        if (value === 1) {\n          return true;\n        }\n        if (value === 0) {\n          return false;\n        }\n      }\n      return value;\n    }\n    case \"string\": {\n      if (value === null) {\n        return \"\";\n      }\n      if (typeof value === \"number\" || typeof value === \"boolean\") {\n        return String(value);\n      }\n      return value;\n    }\n    case \"null\": {\n      if (value === \"\" || value === 0 || value === false) {\n        return null;\n      }\n      return value;\n    }\n    default:\n      return value;\n  }\n}\nfunction applySchemaObjectCoercion(value, schema) {\n  const properties = schema.properties;\n  const definedKeys = new Set(properties ? Object.keys(properties) : []);\n  if (properties) {\n    for (const [key, propertySchema] of Object.entries(properties)) {\n      if (!(key in value)) {\n        continue;\n      }\n      value[key] = coerceWithJsonSchema(value[key], propertySchema);\n    }\n  }\n  if (schema.additionalProperties && typeof schema.additionalProperties === \"object\") {\n    for (const [key, propertyValue] of Object.entries(value)) {\n      if (definedKeys.has(key)) {\n        continue;\n      }\n      value[key] = coerceWithJsonSchema(propertyValue, schema.additionalProperties);\n    }\n  }\n}\nfunction applySchemaArrayCoercion(value, schema) {\n  if (Array.isArray(schema.items)) {\n    for (let index = 0; index < value.length; index++) {\n      const itemSchema = schema.items[index];\n      if (!itemSchema) {\n        continue;\n      }\n      value[index] = coerceWithJsonSchema(value[index], itemSchema);\n    }\n    return;\n  }\n  if (schema.items && typeof schema.items === \"object\") {\n    for (let index = 0; index < value.length; index++) {\n      value[index] = coerceWithJsonSchema(value[index], schema.items);\n    }\n  }\n}\nfunction coerceWithUnionSchema(value, schemas) {\n  for (const schema of schemas) {\n    const validator = getSubSchemaValidator(schema);\n    if (validator?.Check(value)) {\n      return value;\n    }\n  }\n  for (const schema of schemas) {\n    const candidate = structuredClone(value);\n    const coerced = coerceWithJsonSchema(candidate, schema);\n    const validator = getSubSchemaValidator(schema);\n    if (validator?.Check(coerced)) {\n      return coerced;\n    }\n  }\n  return value;\n}\nfunction coerceWithJsonSchema(value, schema) {\n  let nextValue = value;\n  if (Array.isArray(schema.allOf)) {\n    for (const nested of schema.allOf) {\n      nextValue = coerceWithJsonSchema(nextValue, nested);\n    }\n  }\n  if (Array.isArray(schema.anyOf)) {\n    nextValue = coerceWithUnionSchema(nextValue, schema.anyOf);\n  }\n  if (Array.isArray(schema.oneOf)) {\n    nextValue = coerceWithUnionSchema(nextValue, schema.oneOf);\n  }\n  const schemaTypes = getSchemaTypes(schema);\n  const matchesUnionMember = schemaTypes.length > 1 && schemaTypes.some((schemaType) => matchesJsonType(nextValue, schemaType));\n  if (schemaTypes.length > 0 && !matchesUnionMember) {\n    for (const schemaType of schemaTypes) {\n      const candidate = coercePrimitiveByType(nextValue, schemaType);\n      if (candidate !== nextValue) {\n        nextValue = candidate;\n        break;\n      }\n    }\n  }\n  if (schemaTypes.includes(\"object\") && typeof nextValue === \"object\" && nextValue !== null && !Array.isArray(nextValue)) {\n    applySchemaObjectCoercion(nextValue, schema);\n  }\n  if (schemaTypes.includes(\"array\") && Array.isArray(nextValue)) {\n    applySchemaArrayCoercion(nextValue, schema);\n  }\n  return nextValue;\n}\nfunction normalizeOptionalNulls(value, schema) {\n  if (Array.isArray(value)) {\n    if (Array.isArray(schema.items)) {\n      for (let index = 0; index < value.length; index++) {\n        const itemSchema = schema.items[index];\n        if (itemSchema)\n          normalizeOptionalNulls(value[index], itemSchema);\n      }\n    } else if (schema.items) {\n      for (const item of value)\n        normalizeOptionalNulls(item, schema.items);\n    }\n    return;\n  }\n  if (typeof value !== \"object\" || value === null || !schema.properties)\n    return;\n  const object = value;\n  const required = new Set(schema.required ?? []);\n  for (const [key, propertySchema] of Object.entries(schema.properties)) {\n    if (!(key in object))\n      continue;\n    if (object[key] === null && !required.has(key) && typeof propertySchema.$ref !== \"string\" && getSubSchemaValidator(propertySchema)?.Check(null) === false) {\n      delete object[key];\n    } else {\n      normalizeOptionalNulls(object[key], propertySchema);\n    }\n  }\n}\nfunction getValidator(schema) {\n  const key = schema;\n  const cached = validatorCache.get(key);\n  if (cached) {\n    return cached;\n  }\n  const validator = Compile(schema);\n  validatorCache.set(key, validator);\n  return validator;\n}\nfunction formatValidationPath(error) {\n  if (error.keyword === \"required\") {\n    const requiredProperties = error.params.requiredProperties;\n    const requiredProperty = requiredProperties?.[0];\n    if (requiredProperty) {\n      const basePath = error.instancePath.replace(/^\\//, \"\").replace(/\\//g, \".\");\n      return basePath ? `${basePath}.${requiredProperty}` : requiredProperty;\n    }\n  }\n  const path12 = error.instancePath.replace(/^\\//, \"\").replace(/\\//g, \".\");\n  return path12 || \"root\";\n}\nfunction validateToolCall(tools, toolCall) {\n  const tool = tools.find((t) => t.name === toolCall.name);\n  if (!tool) {\n    throw new Error(`Tool \"${toolCall.name}\" not found`);\n  }\n  return validateToolArguments(tool, toolCall);\n}\nfunction validateToolArguments(tool, toolCall) {\n  const args = structuredClone(toolCall.arguments);\n  normalizeOptionalNulls(args, tool.parameters);\n  Value.Convert(tool.parameters, args);\n  const validator = getValidator(tool.parameters);\n  if (!Object.getOwnPropertySymbols(tool.parameters).includes(TYPEBOX_KIND)) {\n    const coerced = coerceWithJsonSchema(args, tool.parameters);\n    if (coerced !== args) {\n      if (typeof args === \"object\" && args !== null && typeof coerced === \"object\" && coerced !== null) {\n        for (const key of Object.keys(args)) {\n          delete args[key];\n        }\n        Object.assign(args, coerced);\n      } else {\n        return validator.Check(coerced) ? coerced : args;\n      }\n    }\n  }\n  if (validator.Check(args)) {\n    return args;\n  }\n  const errors = validator.Errors(args).map((error) => `  - ${formatValidationPath(error)}: ${error.message}`).join(\"\\n\") || \"Unknown validation error\";\n  const errorMessage2 = `Validation failed for tool \"${toolCall.name}\":\n${errors}\n\nReceived arguments:\n${JSON.stringify(toolCall.arguments, null, 2)}`;\n  throw new Error(errorMessage2);\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/main.js\nimport chalk11 from \"chalk\";\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/cli/args.js\nimport chalk from \"chalk\";\nvar VALID_THINKING_LEVELS = [\"off\", \"minimal\", \"low\", \"medium\", \"high\", \"xhigh\", \"max\"];\nfunction isValidThinkingLevel(level) {\n  return VALID_THINKING_LEVELS.includes(level);\n}\nfunction parseArgs(args) {\n  const result = {\n    messages: [],\n    fileArgs: [],\n    unknownFlags: /* @__PURE__ */ new Map(),\n    diagnostics: []\n  };\n  for (let i = 0; i < args.length; i++) {\n    const arg = args[i];\n    if (arg === \"--help\" || arg === \"-h\") {\n      result.help = true;\n    } else if (arg === \"--version\" || arg === \"-v\") {\n      result.version = true;\n    } else if (arg === \"--mode\" && i + 1 < args.length) {\n      const mode = args[++i];\n      if (mode === \"text\" || mode === \"json\" || mode === \"rpc\") {\n        result.mode = mode;\n      }\n    } else if (arg === \"--continue\" || arg === \"-c\") {\n      result.continue = true;\n    } else if (arg === \"--resume\" || arg === \"-r\") {\n      result.resume = true;\n    } else if (arg === \"--provider\" && i + 1 < args.length) {\n      result.provider = args[++i];\n    } else if (arg === \"--model\" && i + 1 < args.length) {\n      result.model = args[++i];\n    } else if (arg === \"--api-key\" && i + 1 < args.length) {\n      result.apiKey = args[++i];\n    } else if (arg === \"--system-prompt\" && i + 1 < args.length) {\n      result.systemPrompt = args[++i];\n    } else if (arg === \"--append-system-prompt\" && i + 1 < args.length) {\n      result.appendSystemPrompt = result.appendSystemPrompt ?? [];\n      result.appendSystemPrompt.push(args[++i]);\n    } else if (arg === \"--name\" || arg === \"-n\") {\n      if (i + 1 < args.length) {\n        result.name = args[++i];\n      } else {\n        result.diagnostics.push({ type: \"error\", message: \"--name requires a value\" });\n      }\n    } else if (arg === \"--no-session\") {\n      result.noSession = true;\n    } else if (arg === \"--session\" && i + 1 < args.length) {\n      result.session = args[++i];\n    } else if (arg === \"--session-id\" && i + 1 < args.length) {\n      result.sessionId = args[++i];\n    } else if (arg === \"--fork\" && i + 1 < args.length) {\n      result.fork = args[++i];\n    } else if (arg === \"--session-dir\" && i + 1 < args.length) {\n      result.sessionDir = args[++i];\n    } else if (arg === \"--models\" && i + 1 < args.length) {\n      result.models = args[++i].split(\",\").map((s) => s.trim());\n    } else if (arg === \"--no-tools\" || arg === \"-nt\") {\n      result.noTools = true;\n    } else if (arg === \"--no-builtin-tools\" || arg === \"-nbt\") {\n      result.noBuiltinTools = true;\n    } else if ((arg === \"--tools\" || arg === \"-t\") && i + 1 < args.length) {\n      result.tools = args[++i].split(\",\").map((s) => s.trim()).filter((name) => name.length > 0);\n    } else if ((arg === \"--exclude-tools\" || arg === \"-xt\") && i + 1 < args.length) {\n      result.excludeTools = args[++i].split(\",\").map((s) => s.trim()).filter((name) => name.length > 0);\n    } else if (arg === \"--thinking\" && i + 1 < args.length) {\n      const level = args[++i];\n      if (isValidThinkingLevel(level)) {\n        result.thinking = level;\n      } else {\n        result.diagnostics.push({\n          type: \"warning\",\n          message: `Invalid thinking level \"${level}\". Valid values: ${VALID_THINKING_LEVELS.join(\", \")}`\n        });\n      }\n    } else if (arg === \"--print\" || arg === \"-p\") {\n      result.print = true;\n      const next = args[i + 1];\n      if (next !== void 0 && !next.startsWith(\"@\") && (!next.startsWith(\"-\") || next.startsWith(\"---\"))) {\n        result.messages.push(next);\n        i++;\n      }\n    } else if (arg === \"--export\" && i + 1 < args.length) {\n      result.export = args[++i];\n    } else if ((arg === \"--extension\" || arg === \"-e\") && i + 1 < args.length) {\n      result.extensions = result.extensions ?? [];\n      result.extensions.push(args[++i]);\n    } else if (arg === \"--no-extensions\" || arg === \"-ne\") {\n      result.noExtensions = true;\n    } else if (arg === \"--skill\" && i + 1 < args.length) {\n      result.skills = result.skills ?? [];\n      result.skills.push(args[++i]);\n    } else if (arg === \"--prompt-template\" && i + 1 < args.length) {\n      result.promptTemplates = result.promptTemplates ?? [];\n      result.promptTemplates.push(args[++i]);\n    } else if (arg === \"--theme\" && i + 1 < args.length) {\n      result.themes = result.themes ?? [];\n      result.themes.push(args[++i]);\n    } else if (arg === \"--use-theme\") {\n      const themeName = args[i + 1];\n      if (themeName === void 0 || themeName.startsWith(\"-\")) {\n        result.diagnostics.push({ type: \"error\", message: \"--use-theme requires a theme name\" });\n      } else {\n        result.useTheme = themeName;\n        i++;\n      }\n    } else if (arg === \"--no-skills\" || arg === \"-ns\") {\n      result.noSkills = true;\n    } else if (arg === \"--no-prompt-templates\" || arg === \"-np\") {\n      result.noPromptTemplates = true;\n    } else if (arg === \"--no-themes\") {\n      result.noThemes = true;\n    } else if (arg === \"--no-context-files\" || arg === \"-nc\") {\n      result.noContextFiles = true;\n    } else if (arg === \"--list-models\") {\n      if (i + 1 < args.length && !args[i + 1].startsWith(\"-\") && !args[i + 1].startsWith(\"@\")) {\n        result.listModels = args[++i];\n      } else {\n        result.listModels = true;\n      }\n    } else if (arg === \"--tui-mode\") {\n      const mode = args[i + 1];\n      if (mode === \"regular\" || mode === \"fullscreen\") {\n        result.tuiMode = mode;\n        i++;\n      } else if (mode === void 0 || mode.startsWith(\"-\")) {\n        result.diagnostics.push({ type: \"error\", message: \"--tui-mode requires regular or fullscreen\" });\n      } else {\n        i++;\n        result.diagnostics.push({\n          type: \"error\",\n          message: `Invalid TUI mode \"${mode}\". Valid values: regular, fullscreen`\n        });\n      }\n    } else if (arg === \"--verbose\") {\n      result.verbose = true;\n    } else if (arg === \"--approve\" || arg === \"-a\") {\n      result.projectTrustOverride = true;\n    } else if (arg === \"--no-approve\" || arg === \"-na\") {\n      result.projectTrustOverride = false;\n    } else if (arg === \"--offline\") {\n      result.offline = true;\n    } else if (arg.startsWith(\"@\")) {\n      result.fileArgs.push(arg.slice(1));\n    } else if (arg.startsWith(\"--\")) {\n      const eqIndex = arg.indexOf(\"=\");\n      if (eqIndex !== -1) {\n        result.unknownFlags.set(arg.slice(2, eqIndex), arg.slice(eqIndex + 1));\n      } else {\n        const flagName = arg.slice(2);\n        const next = args[i + 1];\n        if (next !== void 0 && !next.startsWith(\"-\") && !next.startsWith(\"@\")) {\n          result.unknownFlags.set(flagName, next);\n          i++;\n        } else {\n          result.unknownFlags.set(flagName, true);\n        }\n      }\n    } else if (arg.startsWith(\"-\") && !arg.startsWith(\"--\")) {\n      result.diagnostics.push({ type: \"error\", message: `Unknown option: ${arg}` });\n    } else if (!arg.startsWith(\"-\")) {\n      result.messages.push(arg);\n    }\n  }\n  return result;\n}\nfunction printHelp(extensionFlags) {\n  const extensionFlagsText = extensionFlags && extensionFlags.length > 0 ? `\n${chalk.bold(\"Extension CLI Flags:\")}\n${extensionFlags.map((flag) => {\n    const value = flag.type === \"string\" ? \" <value>\" : \"\";\n    const description = flag.description ?? `Registered by ${flag.extensionPath}`;\n    return `  --${flag.name}${value}`.padEnd(30) + description;\n  }).join(\"\\n\")}\n` : \"\";\n  console.log(`${chalk.bold(APP_NAME)} - AI coding assistant with read, bash, edit, write tools\n\n${chalk.bold(\"Usage:\")}\n  ${APP_NAME} [options] [@files...] [messages...]\n\n${chalk.bold(\"Commands:\")}\n  ${APP_NAME} install <source> [-l]     Install extension source and add to settings\n  ${APP_NAME} remove <source> [-l]      Remove extension source from settings\n  ${APP_NAME} uninstall <source> [-l]   Alias for remove\n  ${APP_NAME} update [source|self|pi]   Update pi, extensions, or model catalogs\n  ${APP_NAME} list                      List installed extensions from settings\n  ${APP_NAME} config [-l]               Open TUI to enable/disable package resources (Tab switches scope)\n  ${APP_NAME} auth <command>            Print credentials or check provider readiness\n  ${APP_NAME} <command> --help          Show help for install/remove/uninstall/update/list/config/auth\n\n${chalk.bold(\"Options:\")}\n  --provider <name>              Provider name (default: google)\n  --model <pattern>              Model pattern or ID (supports \"provider/id\" and optional \":<thinking>\")\n  --api-key <key>                API key (defaults to env vars)\n  --system-prompt <text>         System prompt (default: coding assistant prompt)\n  --append-system-prompt <text>  Append text or file contents to the system prompt (can be used multiple times)\n  --mode <mode>                  Output mode: text (default), json, or rpc\n  --print, -p                    Non-interactive mode: process prompt and exit\n  --continue, -c                 Continue previous session\n  --resume, -r                   Select a session to resume\n  --session <path|id>            Use specific session file or partial UUID\n  --session-id <id>              Use exact project session ID, creating it if missing\n  --fork <path|id>               Fork specific session file or partial UUID into a new session\n  --session-dir <dir>            Directory for session storage and lookup\n  --no-session                   Don't save session (ephemeral)\n  --name, -n <name>              Set session display name\n  --models <patterns>            Comma-separated model patterns for Ctrl+P cycling\n                                 Supports globs (anthropic/*, *sonnet*) and fuzzy matching\n  --no-tools, -nt                Disable all tools by default (built-in and extension)\n  --no-builtin-tools, -nbt       Disable built-in tools by default but keep extension/custom tools enabled\n  --tools, -t <tools>            Comma-separated allowlist of tool names to enable\n                                 Applies to built-in, extension, and custom tools\n  --exclude-tools, -xt <tools>   Comma-separated denylist of tool names to disable\n                                 Applies to built-in, extension, and custom tools\n  --thinking <level>             Set thinking level: off, minimal, low, medium, high, xhigh, max\n  --extension, -e <path>         Load an extension file (can be used multiple times)\n  --no-extensions, -ne           Disable extension discovery (explicit -e paths still work)\n  --skill <path>                 Load a skill file or directory (can be used multiple times)\n  --no-skills, -ns               Disable skills discovery and loading\n  --prompt-template <path>       Load a prompt template file or directory (can be used multiple times)\n  --no-prompt-templates, -np     Disable prompt template discovery and loading\n  --theme <path>                 Load a theme file or directory (can be used multiple times)\n  --use-theme <name[/name]>      Set the initial interactive theme for this run\n  --no-themes                    Disable theme discovery and loading\n  --no-context-files, -nc        Disable AGENTS.md and CLAUDE.md discovery and loading\n  --export <file>                Export session file to HTML and exit\n  --list-models [search]         List available models (with optional fuzzy search)\n  --verbose                      Force verbose startup (overrides quietStartup setting)\n  --tui-mode <mode>              TUI mode: regular (default) or fullscreen\n  --approve, -a                  Trust project-local files for this run\n  --no-approve, -na              Ignore project-local files for this run\n  --offline                      Disable startup network operations (same as PI_OFFLINE=1)\n  --help, -h                     Show this help\n  --version, -v                  Show version number\n\nExtensions can register additional flags (e.g., --plan from plan-mode extension).${extensionFlagsText}\n\n${chalk.bold(\"Examples:\")}\n  # Print a provider API key for an external client\n  ${APP_NAME} auth print-api-key --provider openai\n\n  # Print an OAuth bearer token for an external client (refreshes if expired)\n  ${APP_NAME} auth print-bearer-token --provider openai-codex\n\n  # Interactive mode\n  ${APP_NAME}\n\n  # Interactive mode with initial prompt\n  ${APP_NAME} \"List all .ts files in src/\"\n\n  # Include files in initial message\n  ${APP_NAME} @prompt.md @image.png \"What color is the sky?\"\n\n  # Non-interactive mode (process and exit)\n  ${APP_NAME} -p \"List all .ts files in src/\"\n\n  # Multiple messages (interactive)\n  ${APP_NAME} \"Read package.json\" \"What dependencies do we have?\"\n\n  # Continue previous session\n  ${APP_NAME} --continue \"What did we discuss?\"\n\n  # Start a named session\n  ${APP_NAME} --name \"Refactor auth module\"\n\n  # Use different model\n  ${APP_NAME} --provider openai --model gpt-4o-mini \"Help me refactor this code\"\n\n  # Use model with provider prefix (no --provider needed)\n  ${APP_NAME} --model openai/gpt-4o \"Help me refactor this code\"\n\n  # Use model with thinking level shorthand\n  ${APP_NAME} --model sonnet:high \"Solve this complex problem\"\n\n  # Limit model cycling to specific models\n  ${APP_NAME} --models claude-sonnet,claude-haiku,gpt-4o\n\n  # Limit to a specific provider with glob pattern\n  ${APP_NAME} --models \"github-copilot/*\"\n\n  # Cycle models with fixed thinking levels\n  ${APP_NAME} --models sonnet:high,haiku:low\n\n  # Start with a specific thinking level\n  ${APP_NAME} --thinking high \"Solve this complex problem\"\n\n  # Read-only mode (no file modifications possible)\n  ${APP_NAME} --tools read,grep,find,ls -p \"Review the code in src/\"\n\n  # Disable one tool while keeping the rest available\n  ${APP_NAME} --exclude-tools ask_question\n\n  # Export a session file to HTML\n  ${APP_NAME} --export ~/${CONFIG_DIR_NAME}/agent/sessions/--path--/session.jsonl\n  ${APP_NAME} --export session.jsonl output.html\n\n${chalk.bold(\"Environment Variables:\")}\n  ANTHROPIC_AUTH_TOKEN             - Anthropic bearer auth token\n  ANTHROPIC_API_KEY                - Anthropic Claude API key\n  ANTHROPIC_OAUTH_TOKEN            - Anthropic OAuth token (alternative to API key)\n  ANT_LING_API_KEY                 - Ant Ling API key\n  OPENAI_API_KEY                   - OpenAI GPT API key\n  AZURE_OPENAI_API_KEY             - Azure OpenAI API key\n  AZURE_OPENAI_BASE_URL            - Azure OpenAI/Cognitive Services base URL (e.g. https://{resource}.openai.azure.com)\n  AZURE_OPENAI_RESOURCE_NAME       - Azure OpenAI resource name (alternative to base URL)\n  AZURE_OPENAI_API_VERSION         - Azure OpenAI API version (default: v1)\n  AZURE_OPENAI_DEPLOYMENT_NAME_MAP - Azure OpenAI model=deployment map (comma-separated)\n  DEEPSEEK_API_KEY                 - DeepSeek API key\n  NVIDIA_API_KEY                   - NVIDIA NIM API key\n  GEMINI_API_KEY                   - Google Gemini API key\n  GROQ_API_KEY                     - Groq API key\n  CEREBRAS_API_KEY                 - Cerebras API key\n  XAI_API_KEY                      - xAI Grok API key\n  FIREWORKS_API_KEY                - Fireworks API key\n  TOGETHER_API_KEY                 - Together AI API key\n  BASETEN_API_KEY                  - Baseten API key\n  OPENROUTER_API_KEY               - OpenRouter API key\n  AI_GATEWAY_API_KEY               - Vercel AI Gateway API key\n  ZAI_API_KEY                      - ZAI Coding Plan API key (Global)\n  ZAI_CODING_CN_API_KEY            - ZAI Coding Plan API key (China)\n  MISTRAL_API_KEY                  - Mistral API key\n  MINIMAX_API_KEY                  - MiniMax API key\n  MOONSHOT_API_KEY                 - Moonshot AI API key\n  OPENCODE_API_KEY                 - OpenCode Zen/OpenCode Go API key\n  KIMI_API_KEY                     - Kimi For Coding API key\n  CLOUDFLARE_API_KEY               - Cloudflare API token (Workers AI and AI Gateway)\n  CLOUDFLARE_ACCOUNT_ID            - Cloudflare account id (required for both)\n  CLOUDFLARE_GATEWAY_ID            - Cloudflare AI Gateway slug (required for AI Gateway)\n  QWEN_TOKEN_PLAN_API_KEY          - Qwen Token Plan API key (international region)\n  QWEN_TOKEN_PLAN_CN_API_KEY       - Qwen Token Plan API key (China region)\n  XIAOMI_API_KEY                   - Xiaomi MiMo API key (api.xiaomimimo.com billing)\n  XIAOMI_TOKEN_PLAN_CN_API_KEY     - Xiaomi MiMo Token Plan API key (China region)\n  XIAOMI_TOKEN_PLAN_AMS_API_KEY    - Xiaomi MiMo Token Plan API key (Amsterdam region)\n  XIAOMI_TOKEN_PLAN_SGP_API_KEY    - Xiaomi MiMo Token Plan API key (Singapore region)\n  AWS_PROFILE                      - AWS profile for Amazon Bedrock\n  AWS_ACCESS_KEY_ID                - AWS access key for Amazon Bedrock\n  AWS_SECRET_ACCESS_KEY            - AWS secret key for Amazon Bedrock\n  AWS_BEARER_TOKEN_BEDROCK         - Bedrock API key (bearer token)\n  AWS_REGION                       - AWS region for Amazon Bedrock (e.g., us-east-1)\n  ${ENV_AGENT_DIR.padEnd(32)} - Config directory (default: ~/${CONFIG_DIR_NAME}/agent)\n  ${ENV_SESSION_DIR.padEnd(32)} - Session storage directory (overridden by --session-dir)\n  PI_PACKAGE_DIR                   - Override package directory (for Nix/Guix store paths)\n  PI_OFFLINE                       - Disable startup network operations when set to 1/true/yes\n  PI_TELEMETRY                     - Override install telemetry when set to 1/true/yes or 0/false/no\n  PI_SHARE_VIEWER_URL              - Base URL for /share command (default: https://pi.dev/session/)\n\n${chalk.bold(\"Built-in Tool Names:\")}\n  read   - Read file contents\n  bash   - Execute bash commands\n  edit   - Edit files with find/replace\n  write  - Write files (creates/overwrites)\n  grep   - Search file contents (read-only, off by default)\n  find   - Find files by glob pattern (read-only, off by default)\n  ls     - List directory contents (read-only, off by default)\n`);\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/core/model-resolver.js\nimport chalk2 from \"chalk\";\nimport { minimatch } from \"minimatch\";\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/core/defaults.js\nvar DEFAULT_THINKING_LEVEL = \"medium\";\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/core/model-resolver.js\nvar defaultModelPerProvider = {\n  \"amazon-bedrock\": \"us.anthropic.claude-opus-4-6-v1\",\n  \"ant-ling\": \"Ring-2.6-1T\",\n  anthropic: \"claude-opus-4-8\",\n  openai: \"gpt-5.5\",\n  \"azure-openai-responses\": \"gpt-5.4\",\n  \"openai-codex\": \"gpt-5.5\",\n  radius: \"auto\",\n  nvidia: \"nvidia/nemotron-3-super-120b-a12b\",\n  deepseek: \"deepseek-v4-pro\",\n  google: \"gemini-3.1-pro-preview\",\n  \"google-vertex\": \"gemini-3.1-pro-preview\",\n  \"github-copilot\": \"gpt-5.4\",\n  openrouter: \"moonshotai/kimi-k2.6\",\n  \"vercel-ai-gateway\": \"zai/glm-5.1\",\n  xai: \"grok-4.5\",\n  groq: \"openai/gpt-oss-120b\",\n  cerebras: \"zai-glm-4.7\",\n  zai: \"glm-5.1\",\n  \"zai-coding-cn\": \"glm-5.1\",\n  mistral: \"devstral-medium-latest\",\n  minimax: \"MiniMax-M2.7\",\n  \"minimax-cn\": \"MiniMax-M2.7\",\n  moonshotai: \"kimi-k2.6\",\n  \"moonshotai-cn\": \"kimi-k2.6\",\n  huggingface: \"moonshotai/Kimi-K2.6\",\n  fireworks: \"accounts/fireworks/models/kimi-k2p6\",\n  together: \"moonshotai/Kimi-K2.6\",\n  baseten: \"zai-org/GLM-5.2\",\n  opencode: \"kimi-k2.6\",\n  \"opencode-go\": \"kimi-k2.6\",\n  \"kimi-coding\": \"kimi-for-coding\",\n  \"cloudflare-workers-ai\": \"@cf/moonshotai/kimi-k2.6\",\n  \"cloudflare-ai-gateway\": \"workers-ai/@cf/moonshotai/kimi-k2.6\",\n  \"qwen-token-plan\": \"qwen3.7-max\",\n  \"qwen-token-plan-cn\": \"qwen3.7-max\",\n  \"qwen-token-plan-individual\": \"qwen3.8-max\",\n  xiaomi: \"mimo-v2.5-pro\",\n  \"xiaomi-token-plan-cn\": \"mimo-v2.5-pro\",\n  \"xiaomi-token-plan-ams\": \"mimo-v2.5-pro\",\n  \"xiaomi-token-plan-sgp\": \"mimo-v2.5-pro\"\n};\nfunction isAlias(id) {\n  if (id.endsWith(\"-latest\"))\n    return true;\n  const datePattern = /-\\d{8}$/;\n  return !datePattern.test(id);\n}\nfunction findExactModelReferenceMatch(modelReference, availableModels) {\n  const trimmedReference = modelReference.trim();\n  if (!trimmedReference) {\n    return void 0;\n  }\n  const normalizedReference = trimmedReference.toLowerCase();\n  const canonicalMatches = availableModels.filter((model) => `${model.provider}/${model.id}`.toLowerCase() === normalizedReference);\n  if (canonicalMatches.length === 1) {\n    return canonicalMatches[0];\n  }\n  if (canonicalMatches.length > 1) {\n    return void 0;\n  }\n  const slashIndex = trimmedReference.indexOf(\"/\");\n  if (slashIndex !== -1) {\n    const provider = trimmedReference.substring(0, slashIndex).trim();\n    const modelId = trimmedReference.substring(slashIndex + 1).trim();\n    if (provider && modelId) {\n      const providerMatches = availableModels.filter((model) => model.provider.toLowerCase() === provider.toLowerCase() && model.id.toLowerCase() === modelId.toLowerCase());\n      if (providerMatches.length === 1) {\n        return providerMatches[0];\n      }\n      if (providerMatches.length > 1) {\n        return void 0;\n      }\n    }\n  }\n  const idMatches = availableModels.filter((model) => model.id.toLowerCase() === normalizedReference);\n  return idMatches.length === 1 ? idMatches[0] : void 0;\n}\nfunction tryMatchModel(modelPattern, availableModels) {\n  const exactMatch = findExactModelReferenceMatch(modelPattern, availableModels);\n  if (exactMatch) {\n    return exactMatch;\n  }\n  const matches = availableModels.filter((m) => m.id.toLowerCase().includes(modelPattern.toLowerCase()) || m.name?.toLowerCase().includes(modelPattern.toLowerCase()));\n  if (matches.length === 0) {\n    return void 0;\n  }\n  const aliases = matches.filter((m) => isAlias(m.id));\n  const datedVersions = matches.filter((m) => !isAlias(m.id));\n  if (aliases.length > 0) {\n    aliases.sort((a, b) => b.id.localeCompare(a.id));\n    return aliases[0];\n  } else {\n    datedVersions.sort((a, b) => b.id.localeCompare(a.id));\n    return datedVersions[0];\n  }\n}\nfunction buildFallbackModel(provider, modelId, availableModels) {\n  const providerModels = availableModels.filter((m) => m.provider === provider);\n  if (providerModels.length === 0)\n    return void 0;\n  const defaultId = defaultModelPerProvider[provider];\n  const baseModel = defaultId ? providerModels.find((m) => m.id === defaultId) ?? providerModels[0] : providerModels[0];\n  return {\n    ...baseModel,\n    id: modelId,\n    name: modelId\n  };\n}\nfunction parseModelPattern(pattern, availableModels, options) {\n  const exactMatch = tryMatchModel(pattern, availableModels);\n  if (exactMatch) {\n    return { model: exactMatch, thinkingLevel: void 0, warning: void 0 };\n  }\n  const lastColonIndex = pattern.lastIndexOf(\":\");\n  if (lastColonIndex === -1) {\n    return { model: void 0, thinkingLevel: void 0, warning: void 0 };\n  }\n  const prefix = pattern.substring(0, lastColonIndex);\n  const suffix = pattern.substring(lastColonIndex + 1);\n  if (isValidThinkingLevel(suffix)) {\n    const result = parseModelPattern(prefix, availableModels, options);\n    if (result.model) {\n      return {\n        model: result.model,\n        thinkingLevel: result.warning ? void 0 : suffix,\n        warning: result.warning\n      };\n    }\n    return result;\n  } else {\n    const allowFallback = options?.allowInvalidThinkingLevelFallback ?? true;\n    if (!allowFallback) {\n      return { model: void 0, thinkingLevel: void 0, warning: void 0 };\n    }\n    const result = parseModelPattern(prefix, availableModels, options);\n    if (result.model) {\n      return {\n        model: result.model,\n        thinkingLevel: void 0,\n        warning: `Invalid thinking level \"${suffix}\" in pattern \"${pattern}\". Using default instead.`\n      };\n    }\n    return result;\n  }\n}\nfunction resolveModelScopeFromModels(patterns, models) {\n  const availableModels = [...models];\n  const scopedModels = [];\n  const diagnostics = [];\n  for (const pattern of patterns) {\n    if (pattern.includes(\"*\") || pattern.includes(\"?\") || pattern.includes(\"[\")) {\n      const colonIdx = pattern.lastIndexOf(\":\");\n      let globPattern = pattern;\n      let thinkingLevel2;\n      if (colonIdx !== -1) {\n        const suffix = pattern.substring(colonIdx + 1);\n        if (isValidThinkingLevel(suffix)) {\n          thinkingLevel2 = suffix;\n          globPattern = pattern.substring(0, colonIdx);\n        }\n      }\n      const exactMatch = findExactModelReferenceMatch(globPattern, availableModels);\n      if (exactMatch) {\n        if (!scopedModels.find((sm) => modelsAreEqual(sm.model, exactMatch))) {\n          scopedModels.push({ model: exactMatch, thinkingLevel: thinkingLevel2 });\n        }\n        continue;\n      }\n      const matchingModels = availableModels.filter((m) => {\n        const fullId = `${m.provider}/${m.id}`;\n        return minimatch(fullId, globPattern, { nocase: true }) || minimatch(m.id, globPattern, { nocase: true });\n      });\n      if (matchingModels.length === 0) {\n        diagnostics.push({\n          type: \"warning\",\n          code: \"no-match\",\n          message: `No models match pattern \"${pattern}\"`,\n          pattern\n        });\n        continue;\n      }\n      for (const model2 of matchingModels) {\n        if (!scopedModels.find((sm) => modelsAreEqual(sm.model, model2))) {\n          scopedModels.push({ model: model2, thinkingLevel: thinkingLevel2 });\n        }\n      }\n      continue;\n    }\n    const { model, thinkingLevel, warning } = parseModelPattern(pattern, availableModels);\n    if (warning) {\n      diagnostics.push({ type: \"warning\", code: \"invalid-thinking-level\", message: warning, pattern });\n    }\n    if (!model) {\n      diagnostics.push({\n        type: \"warning\",\n        code: \"no-match\",\n        message: `No models match pattern \"${pattern}\"`,\n        pattern\n      });\n      continue;\n    }\n    if (!scopedModels.find((sm) => modelsAreEqual(sm.model, model))) {\n      scopedModels.push({ model, thinkingLevel });\n    }\n  }\n  return { scopedModels, diagnostics };\n}\nasync function resolveModelScopeWithDiagnostics(patterns, modelRuntime, options) {\n  return resolveModelScopeFromModels(patterns, await modelRuntime.getAvailable(void 0, options));\n}\nasync function resolveModelScope(patterns, modelRuntime, options) {\n  const { scopedModels, diagnostics } = await resolveModelScopeWithDiagnostics(patterns, modelRuntime, options);\n  for (const diagnostic of diagnostics) {\n    console.warn(chalk2.yellow(`Warning: ${diagnostic.message}`));\n  }\n  return scopedModels;\n}\nfunction resolveCliModel(options) {\n  const { cliProvider, cliModel, cliThinking, modelRuntime } = options;\n  if (!cliModel) {\n    return { model: void 0, warning: void 0, error: void 0 };\n  }\n  const availableModels = [...modelRuntime.getModels()];\n  if (availableModels.length === 0) {\n    return {\n      model: void 0,\n      warning: void 0,\n      error: \"No models available. Check your installation or add models to models.json.\"\n    };\n  }\n  const providerMap = /* @__PURE__ */ new Map();\n  for (const m of availableModels) {\n    providerMap.set(m.provider.toLowerCase(), m.provider);\n  }\n  let provider = cliProvider ? providerMap.get(cliProvider.toLowerCase()) : void 0;\n  if (cliProvider && !provider) {\n    return {\n      model: void 0,\n      warning: void 0,\n      error: `Unknown provider \"${cliProvider}\". Use --list-models to see available providers/models.`\n    };\n  }\n  let pattern = cliModel;\n  let inferredProvider = false;\n  if (!provider) {\n    const slashIndex = cliModel.indexOf(\"/\");\n    if (slashIndex !== -1) {\n      const maybeProvider = cliModel.substring(0, slashIndex);\n      const canonical = providerMap.get(maybeProvider.toLowerCase());\n      if (canonical) {\n        provider = canonical;\n        pattern = cliModel.substring(slashIndex + 1);\n        inferredProvider = true;\n      }\n    }\n  }\n  if (!provider) {\n    const lower = cliModel.toLowerCase();\n    const exactMatches = availableModels.filter((m) => m.id.toLowerCase() === lower || `${m.provider}/${m.id}`.toLowerCase() === lower);\n    if (exactMatches.length === 1) {\n      return { model: exactMatches[0], warning: void 0, thinkingLevel: void 0, error: void 0 };\n    }\n    if (exactMatches.length > 1) {\n      const authenticatedExactMatches = exactMatches.filter((m) => modelRuntime.hasConfiguredAuth(m.provider));\n      if (authenticatedExactMatches.length === 1) {\n        return {\n          model: authenticatedExactMatches[0],\n          warning: void 0,\n          thinkingLevel: void 0,\n          error: void 0\n        };\n      }\n      const matches = exactMatches.map((m) => `${m.provider}/${m.id}`).sort((a, b) => a.localeCompare(b)).join(\", \");\n      const authHint = authenticatedExactMatches.length === 0 ? \"No matching provider is authenticated.\" : \"More than one matching provider is authenticated.\";\n      return {\n        model: void 0,\n        warning: void 0,\n        thinkingLevel: void 0,\n        error: `Model \"${cliModel}\" is ambiguous across providers: ${matches}. ${authHint} Use --provider or provider/model.`\n      };\n    }\n  }\n  if (cliProvider && provider) {\n    const prefix = `${provider}/`;\n    if (cliModel.toLowerCase().startsWith(prefix.toLowerCase())) {\n      pattern = cliModel.substring(prefix.length);\n    }\n  }\n  const candidates = provider ? availableModels.filter((m) => m.provider === provider) : availableModels;\n  const { model, thinkingLevel, warning } = parseModelPattern(pattern, candidates, {\n    allowInvalidThinkingLevelFallback: false\n  });\n  if (model) {\n    if (inferredProvider) {\n      const rawExactMatches = availableModels.filter((m) => m.id.toLowerCase() === cliModel.toLowerCase() && !modelsAreEqual(m, model));\n      if (rawExactMatches.length > 0 && !modelRuntime.hasConfiguredAuth(model.provider)) {\n        const authenticatedRawMatches = rawExactMatches.filter((m) => modelRuntime.hasConfiguredAuth(m.provider));\n        if (authenticatedRawMatches.length === 1) {\n          return {\n            model: authenticatedRawMatches[0],\n            thinkingLevel: void 0,\n            warning: void 0,\n            error: void 0\n          };\n        }\n      }\n    }\n    return { model, thinkingLevel, warning, error: void 0 };\n  }\n  if (inferredProvider) {\n    const lower = cliModel.toLowerCase();\n    const exact = availableModels.find((m) => m.id.toLowerCase() === lower || `${m.provider}/${m.id}`.toLowerCase() === lower);\n    if (exact) {\n      return { model: exact, warning: void 0, thinkingLevel: void 0, error: void 0 };\n    }\n    const fallback = parseModelPattern(cliModel, availableModels, {\n      allowInvalidThinkingLevelFallback: false\n    });\n    if (fallback.model) {\n      return {\n        model: fallback.model,\n        thinkingLevel: fallback.thinkingLevel,\n        warning: fallback.warning,\n        error: void 0\n      };\n    }\n  }\n  if (provider) {\n    let fallbackPattern = pattern;\n    let fallbackThinking;\n    if (!cliThinking) {\n      const lastColon = pattern.lastIndexOf(\":\");\n      if (lastColon !== -1) {\n        const suffix = pattern.substring(lastColon + 1);\n        if (isValidThinkingLevel(suffix)) {\n          fallbackPattern = pattern.substring(0, lastColon);\n          fallbackThinking = suffix;\n        }\n      }\n    }\n    const fallbackModel = buildFallbackModel(provider, fallbackPattern, availableModels);\n    if (fallbackModel) {\n      const requestedThinking = cliThinking ?? fallbackThinking;\n      const model2 = requestedThinking && requestedThinking !== \"off\" ? { ...fallbackModel, reasoning: true } : fallbackModel;\n      const fallbackWarning = warning ? `${warning} Model \"${fallbackPattern}\" not found for provider \"${provider}\". Using custom model id.` : `Model \"${fallbackPattern}\" not found for provider \"${provider}\". Using custom model id.`;\n      return { model: model2, thinkingLevel: fallbackThinking, warning: fallbackWarning, error: void 0 };\n    }\n  }\n  const display = provider ? `${provider}/${pattern}` : cliModel;\n  return {\n    model: void 0,\n    thinkingLevel: void 0,\n    warning,\n    error: `Model \"${display}\" not found. Use --list-models to see available models.`\n  };\n}\nasync function findInitialModel(options) {\n  const { cliProvider, cliModel, scopedModels, isContinuing, defaultProvider, defaultModelId, defaultThinkingLevel, modelRuntime } = options;\n  let model;\n  let thinkingLevel = DEFAULT_THINKING_LEVEL;\n  if (cliProvider && cliModel) {\n    const resolved = resolveCliModel({\n      cliProvider,\n      cliModel,\n      modelRuntime\n    });\n    if (resolved.error) {\n      console.error(chalk2.red(resolved.error));\n      process.exit(1);\n    }\n    if (resolved.model) {\n      return { model: resolved.model, thinkingLevel: DEFAULT_THINKING_LEVEL, fallbackMessage: void 0 };\n    }\n  }\n  if (scopedModels.length > 0 && !isContinuing) {\n    return {\n      model: scopedModels[0].model,\n      thinkingLevel: scopedModels[0].thinkingLevel ?? defaultThinkingLevel ?? DEFAULT_THINKING_LEVEL,\n      fallbackMessage: void 0\n    };\n  }\n  if (defaultProvider && defaultModelId) {\n    const found = modelRuntime.getModel(defaultProvider, defaultModelId);\n    if (found && modelRuntime.hasConfiguredAuth(found.provider)) {\n      model = found;\n      if (defaultThinkingLevel) {\n        thinkingLevel = defaultThinkingLevel;\n      }\n      return { model, thinkingLevel, fallbackMessage: void 0 };\n    }\n  }\n  const availableModels = [...modelRuntime.getAvailableSnapshot()];\n  if (availableModels.length > 0) {\n    for (const provider of Object.keys(defaultModelPerProvider)) {\n      const defaultId = defaultModelPerProvider[provider];\n      const match = availableModels.find((m) => m.provider === provider && m.id === defaultId);\n      if (match) {\n        return { model: match, thinkingLevel: DEFAULT_THINKING_LEVEL, fallbackMessage: void 0 };\n      }\n    }\n    return { model: availableModels[0], thinkingLevel: DEFAULT_THINKING_LEVEL, fallbackMessage: void 0 };\n  }\n  return { model: void 0, thinkingLevel: DEFAULT_THINKING_LEVEL, fallbackMessage: void 0 };\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/core/model-runtime.js\nimport { dirname as dirname3, join as join5 } from \"node:path\";\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/all.js\nvar all_exports = {};\n__export(all_exports, {\n  builtinImagesModels: () => builtinImagesModels,\n  builtinImagesProviders: () => builtinImagesProviders,\n  builtinModels: () => builtinModels,\n  builtinProviders: () => builtinProviders,\n  getBuiltinModel: () => getBuiltinModel,\n  getBuiltinModelDataGeneratedAt: () => getBuiltinModelDataGeneratedAt,\n  getBuiltinModels: () => getBuiltinModels,\n  getBuiltinProviders: () => getBuiltinProviders,\n  radiusProvider: () => radiusProvider\n});\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/data/amazon-bedrock.json\nvar amazon_bedrock_default = { \"bedrock-converse-stream\": { \"amazon.nova-2-lite-v1:0\": { id: \"amazon.nova-2-lite-v1:0\", name: \"Nova 2 Lite\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.33, output: 2.75, cacheRead: 0, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 4096 }, \"amazon.nova-lite-v1:0\": { id: \"amazon.nova-lite-v1:0\", name: \"Nova Lite\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 0.06, output: 0.24, cacheRead: 0.015, cacheWrite: 0 }, contextWindow: 3e5, maxTokens: 8192 }, \"amazon.nova-micro-v1:0\": { id: \"amazon.nova-micro-v1:0\", name: \"Nova Micro\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: false, input: [\"text\"], cost: { input: 0.035, output: 0.14, cacheRead: 875e-5, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 8192 }, \"amazon.nova-pro-v1:0\": { id: \"amazon.nova-pro-v1:0\", name: \"Nova Pro\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 0.8, output: 3.2, cacheRead: 0.2, cacheWrite: 0 }, contextWindow: 3e5, maxTokens: 8192 }, \"anthropic.claude-fable-5\": { id: \"anthropic.claude-fable-5\", name: \"Claude Fable 5\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 10, output: 50, cacheRead: 1, cacheWrite: 12.5 }, contextWindow: 1e6, maxTokens: 128e3, thinkingLevelMap: { off: null, xhigh: \"xhigh\", max: \"max\" } }, \"anthropic.claude-haiku-4-5-20251001-v1:0\": { id: \"anthropic.claude-haiku-4-5-20251001-v1:0\", name: \"Claude Haiku 4.5\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1, output: 5, cacheRead: 0.1, cacheWrite: 1.25 }, contextWindow: 2e5, maxTokens: 64e3, compat: { supportsStrictMode: true } }, \"anthropic.claude-opus-4-1-20250805-v1:0\": { id: \"anthropic.claude-opus-4-1-20250805-v1:0\", name: \"Claude Opus 4.1\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 15, output: 75, cacheRead: 1.5, cacheWrite: 18.75 }, contextWindow: 2e5, maxTokens: 32e3 }, \"anthropic.claude-opus-4-5-20251101-v1:0\": { id: \"anthropic.claude-opus-4-5-20251101-v1:0\", name: \"Claude Opus 4.5\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 }, contextWindow: 2e5, maxTokens: 64e3, compat: { supportsStrictMode: true } }, \"anthropic.claude-opus-4-6-v1\": { id: \"anthropic.claude-opus-4-6-v1\", name: \"Claude Opus 4.6\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 }, contextWindow: 1e6, maxTokens: 128e3, compat: { supportsStrictMode: true }, thinkingLevelMap: { max: \"max\" } }, \"anthropic.claude-opus-4-7\": { id: \"anthropic.claude-opus-4-7\", name: \"Claude Opus 4.7\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 }, contextWindow: 1e6, maxTokens: 128e3, thinkingLevelMap: { xhigh: \"xhigh\", max: \"max\" } }, \"anthropic.claude-opus-4-8\": { id: \"anthropic.claude-opus-4-8\", name: \"Claude Opus 4.8\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 }, contextWindow: 1e6, maxTokens: 128e3, thinkingLevelMap: { xhigh: \"xhigh\", max: \"max\" } }, \"anthropic.claude-sonnet-4-5-20250929-v1:0\": { id: \"anthropic.claude-sonnet-4-5-20250929-v1:0\", name: \"Claude Sonnet 4.5\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3.75 }, contextWindow: 2e5, maxTokens: 64e3, compat: { supportsStrictMode: true } }, \"anthropic.claude-sonnet-4-6\": { id: \"anthropic.claude-sonnet-4-6\", name: \"Claude Sonnet 4.6\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3.75 }, contextWindow: 1e6, maxTokens: 64e3, compat: { supportsStrictMode: true }, thinkingLevelMap: { max: \"max\" } }, \"anthropic.claude-sonnet-5\": { id: \"anthropic.claude-sonnet-5\", name: \"Claude Sonnet 5\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 2, output: 10, cacheRead: 0.2, cacheWrite: 2.5 }, contextWindow: 1e6, maxTokens: 128e3, compat: { supportsStrictMode: true }, thinkingLevelMap: { xhigh: \"xhigh\", max: \"max\" } }, \"au.anthropic.claude-haiku-4-5-20251001-v1:0\": { id: \"au.anthropic.claude-haiku-4-5-20251001-v1:0\", name: \"Claude Haiku 4.5 (AU)\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1, output: 5, cacheRead: 0.1, cacheWrite: 1.25 }, contextWindow: 2e5, maxTokens: 64e3, compat: { supportsStrictMode: true } }, \"au.anthropic.claude-opus-4-6-v1\": { id: \"au.anthropic.claude-opus-4-6-v1\", name: \"AU Anthropic Claude Opus 4.6\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 16.5, output: 82.5, cacheRead: 1.65, cacheWrite: 20.625 }, contextWindow: 1e6, maxTokens: 128e3, compat: { supportsStrictMode: true }, thinkingLevelMap: { max: \"max\" } }, \"au.anthropic.claude-opus-4-8\": { id: \"au.anthropic.claude-opus-4-8\", name: \"Claude Opus 4.8 (AU)\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 }, contextWindow: 1e6, maxTokens: 128e3, thinkingLevelMap: { xhigh: \"xhigh\", max: \"max\" } }, \"au.anthropic.claude-opus-5\": { id: \"au.anthropic.claude-opus-5\", name: \"Claude Opus 5 (AU)\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 }, contextWindow: 1e6, maxTokens: 128e3, thinkingLevelMap: { xhigh: \"xhigh\", max: \"max\" } }, \"au.anthropic.claude-sonnet-4-5-20250929-v1:0\": { id: \"au.anthropic.claude-sonnet-4-5-20250929-v1:0\", name: \"Claude Sonnet 4.5 (AU)\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3.75 }, contextWindow: 2e5, maxTokens: 64e3, compat: { supportsStrictMode: true } }, \"au.anthropic.claude-sonnet-4-6\": { id: \"au.anthropic.claude-sonnet-4-6\", name: \"AU Anthropic Claude Sonnet 4.6\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 3.3, output: 16.5, cacheRead: 0.33, cacheWrite: 4.125 }, contextWindow: 1e6, maxTokens: 128e3, compat: { supportsStrictMode: true }, thinkingLevelMap: { max: \"max\" } }, \"au.anthropic.claude-sonnet-5\": { id: \"au.anthropic.claude-sonnet-5\", name: \"Claude Sonnet 5 (AU)\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 2, output: 10, cacheRead: 0.2, cacheWrite: 2.5 }, contextWindow: 1e6, maxTokens: 128e3, compat: { supportsStrictMode: true }, thinkingLevelMap: { xhigh: \"xhigh\", max: \"max\" } }, \"deepseek.r1-v1:0\": { id: \"deepseek.r1-v1:0\", name: \"DeepSeek-R1\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: true, input: [\"text\"], cost: { input: 1.35, output: 5.4, cacheRead: 0, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 32768 }, \"deepseek.v3-v1:0\": { id: \"deepseek.v3-v1:0\", name: \"DeepSeek-V3.1\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: true, input: [\"text\"], cost: { input: 0.58, output: 1.68, cacheRead: 0, cacheWrite: 0 }, contextWindow: 163840, maxTokens: 81920, compat: { supportsStrictMode: true } }, \"deepseek.v3.2\": { id: \"deepseek.v3.2\", name: \"DeepSeek-V3.2\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: true, input: [\"text\"], cost: { input: 0.62, output: 1.85, cacheRead: 0, cacheWrite: 0 }, contextWindow: 163840, maxTokens: 81920, compat: { supportsStrictMode: true } }, \"eu.anthropic.claude-fable-5\": { id: \"eu.anthropic.claude-fable-5\", name: \"Claude Fable 5 (EU)\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.eu-central-1.amazonaws.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 11, output: 55, cacheRead: 1.1, cacheWrite: 13.75 }, contextWindow: 1e6, maxTokens: 128e3, thinkingLevelMap: { off: null, xhigh: \"xhigh\", max: \"max\" } }, \"eu.anthropic.claude-haiku-4-5-20251001-v1:0\": { id: \"eu.anthropic.claude-haiku-4-5-20251001-v1:0\", name: \"Claude Haiku 4.5 (EU)\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.eu-central-1.amazonaws.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.1, output: 5.5, cacheRead: 0.11, cacheWrite: 1.375 }, contextWindow: 2e5, maxTokens: 64e3, compat: { supportsStrictMode: true } }, \"eu.anthropic.claude-opus-4-5-20251101-v1:0\": { id: \"eu.anthropic.claude-opus-4-5-20251101-v1:0\", name: \"Claude Opus 4.5 (EU)\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.eu-central-1.amazonaws.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 5.5, output: 27.5, cacheRead: 0.55, cacheWrite: 6.875 }, contextWindow: 2e5, maxTokens: 64e3, compat: { supportsStrictMode: true } }, \"eu.anthropic.claude-opus-4-6-v1\": { id: \"eu.anthropic.claude-opus-4-6-v1\", name: \"Claude Opus 4.6 (EU)\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.eu-central-1.amazonaws.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 5.5, output: 27.5, cacheRead: 0.55, cacheWrite: 6.875 }, contextWindow: 1e6, maxTokens: 128e3, compat: { supportsStrictMode: true }, thinkingLevelMap: { max: \"max\" } }, \"eu.anthropic.claude-opus-4-7\": { id: \"eu.anthropic.claude-opus-4-7\", name: \"Claude Opus 4.7 (EU)\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.eu-central-1.amazonaws.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 5.5, output: 27.5, cacheRead: 0.55, cacheWrite: 6.875 }, contextWindow: 1e6, maxTokens: 128e3, thinkingLevelMap: { xhigh: \"xhigh\", max: \"max\" } }, \"eu.anthropic.claude-opus-4-8\": { id: \"eu.anthropic.claude-opus-4-8\", name: \"Claude Opus 4.8 (EU)\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.eu-central-1.amazonaws.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 5.5, output: 27.5, cacheRead: 0.55, cacheWrite: 6.875 }, contextWindow: 1e6, maxTokens: 128e3, thinkingLevelMap: { xhigh: \"xhigh\", max: \"max\" } }, \"eu.anthropic.claude-opus-5\": { id: \"eu.anthropic.claude-opus-5\", name: \"Claude Opus 5 (EU)\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.eu-central-1.amazonaws.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 5.5, output: 27.5, cacheRead: 0.55, cacheWrite: 6.875 }, contextWindow: 1e6, maxTokens: 128e3, thinkingLevelMap: { xhigh: \"xhigh\", max: \"max\" } }, \"eu.anthropic.claude-sonnet-4-5-20250929-v1:0\": { id: \"eu.anthropic.claude-sonnet-4-5-20250929-v1:0\", name: \"Claude Sonnet 4.5 (EU)\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.eu-central-1.amazonaws.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 3.3, output: 16.5, cacheRead: 0.33, cacheWrite: 4.125 }, contextWindow: 2e5, maxTokens: 64e3, compat: { supportsStrictMode: true } }, \"eu.anthropic.claude-sonnet-4-6\": { id: \"eu.anthropic.claude-sonnet-4-6\", name: \"Claude Sonnet 4.6 (EU)\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.eu-central-1.amazonaws.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 3.3, output: 16.5, cacheRead: 0.33, cacheWrite: 4.125 }, contextWindow: 1e6, maxTokens: 64e3, compat: { supportsStrictMode: true }, thinkingLevelMap: { max: \"max\" } }, \"eu.anthropic.claude-sonnet-5\": { id: \"eu.anthropic.claude-sonnet-5\", name: \"Claude Sonnet 5 (EU)\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.eu-central-1.amazonaws.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 2.2, output: 11, cacheRead: 0.22, cacheWrite: 2.75 }, contextWindow: 1e6, maxTokens: 128e3, compat: { supportsStrictMode: true }, thinkingLevelMap: { xhigh: \"xhigh\", max: \"max\" } }, \"global.anthropic.claude-fable-5\": { id: \"global.anthropic.claude-fable-5\", name: \"Claude Fable 5 (Global)\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 10, output: 50, cacheRead: 1, cacheWrite: 12.5 }, contextWindow: 1e6, maxTokens: 128e3, thinkingLevelMap: { off: null, xhigh: \"xhigh\", max: \"max\" } }, \"global.anthropic.claude-haiku-4-5-20251001-v1:0\": { id: \"global.anthropic.claude-haiku-4-5-20251001-v1:0\", name: \"Claude Haiku 4.5 (Global)\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1, output: 5, cacheRead: 0.1, cacheWrite: 1.25 }, contextWindow: 2e5, maxTokens: 64e3, compat: { supportsStrictMode: true } }, \"global.anthropic.claude-opus-4-5-20251101-v1:0\": { id: \"global.anthropic.claude-opus-4-5-20251101-v1:0\", name: \"Claude Opus 4.5 (Global)\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 }, contextWindow: 2e5, maxTokens: 64e3, compat: { supportsStrictMode: true } }, \"global.anthropic.claude-opus-4-6-v1\": { id: \"global.anthropic.claude-opus-4-6-v1\", name: \"Claude Opus 4.6 (Global)\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 }, contextWindow: 1e6, maxTokens: 128e3, compat: { supportsStrictMode: true }, thinkingLevelMap: { max: \"max\" } }, \"global.anthropic.claude-opus-4-7\": { id: \"global.anthropic.claude-opus-4-7\", name: \"Claude Opus 4.7 (Global)\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 }, contextWindow: 1e6, maxTokens: 128e3, thinkingLevelMap: { xhigh: \"xhigh\", max: \"max\" } }, \"global.anthropic.claude-opus-4-8\": { id: \"global.anthropic.claude-opus-4-8\", name: \"Claude Opus 4.8 (Global)\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 }, contextWindow: 1e6, maxTokens: 128e3, thinkingLevelMap: { xhigh: \"xhigh\", max: \"max\" } }, \"global.anthropic.claude-opus-5\": { id: \"global.anthropic.claude-opus-5\", name: \"Claude Opus 5 (Global)\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 }, contextWindow: 1e6, maxTokens: 128e3, thinkingLevelMap: { xhigh: \"xhigh\", max: \"max\" } }, \"global.anthropic.claude-sonnet-4-5-20250929-v1:0\": { id: \"global.anthropic.claude-sonnet-4-5-20250929-v1:0\", name: \"Claude Sonnet 4.5 (Global)\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3.75 }, contextWindow: 2e5, maxTokens: 64e3, compat: { supportsStrictMode: true } }, \"global.anthropic.claude-sonnet-4-6\": { id: \"global.anthropic.claude-sonnet-4-6\", name: \"Claude Sonnet 4.6 (Global)\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3.75 }, contextWindow: 1e6, maxTokens: 64e3, compat: { supportsStrictMode: true }, thinkingLevelMap: { max: \"max\" } }, \"global.anthropic.claude-sonnet-5\": { id: \"global.anthropic.claude-sonnet-5\", name: \"Claude Sonnet 5 (Global)\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 2, output: 10, cacheRead: 0.2, cacheWrite: 2.5 }, contextWindow: 1e6, maxTokens: 128e3, compat: { supportsStrictMode: true }, thinkingLevelMap: { xhigh: \"xhigh\", max: \"max\" } }, \"google.gemma-3-27b-it\": { id: \"google.gemma-3-27b-it\", name: \"Google Gemma 3 27B Instruct\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 0.12, output: 0.2, cacheRead: 0, cacheWrite: 0 }, contextWindow: 202752, maxTokens: 8192, compat: { supportsStrictMode: true } }, \"google.gemma-3-4b-it\": { id: \"google.gemma-3-4b-it\", name: \"Gemma 3 4B IT\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 0.04, output: 0.08, cacheRead: 0, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 4096 }, \"jp.anthropic.claude-haiku-4-5-20251001-v1:0\": { id: \"jp.anthropic.claude-haiku-4-5-20251001-v1:0\", name: \"Claude Haiku 4.5 (JP)\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1, output: 5, cacheRead: 0.1, cacheWrite: 1.25 }, contextWindow: 2e5, maxTokens: 64e3, compat: { supportsStrictMode: true } }, \"jp.anthropic.claude-opus-4-7\": { id: \"jp.anthropic.claude-opus-4-7\", name: \"Claude Opus 4.7 (JP)\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 }, contextWindow: 1e6, maxTokens: 128e3, thinkingLevelMap: { xhigh: \"xhigh\", max: \"max\" } }, \"jp.anthropic.claude-opus-4-8\": { id: \"jp.anthropic.claude-opus-4-8\", name: \"Claude Opus 4.8 (JP)\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 }, contextWindow: 1e6, maxTokens: 128e3, thinkingLevelMap: { xhigh: \"xhigh\", max: \"max\" } }, \"jp.anthropic.claude-opus-5\": { id: \"jp.anthropic.claude-opus-5\", name: \"Claude Opus 5 (JP)\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 }, contextWindow: 1e6, maxTokens: 128e3, thinkingLevelMap: { xhigh: \"xhigh\", max: \"max\" } }, \"jp.anthropic.claude-sonnet-4-5-20250929-v1:0\": { id: \"jp.anthropic.claude-sonnet-4-5-20250929-v1:0\", name: \"Claude Sonnet 4.5 (JP)\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3.75 }, contextWindow: 2e5, maxTokens: 64e3, compat: { supportsStrictMode: true } }, \"jp.anthropic.claude-sonnet-4-6\": { id: \"jp.anthropic.claude-sonnet-4-6\", name: \"Claude Sonnet 4.6 (JP)\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3.75 }, contextWindow: 1e6, maxTokens: 64e3, compat: { supportsStrictMode: true }, thinkingLevelMap: { max: \"max\" } }, \"jp.anthropic.claude-sonnet-5\": { id: \"jp.anthropic.claude-sonnet-5\", name: \"Claude Sonnet 5 (JP)\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 2, output: 10, cacheRead: 0.2, cacheWrite: 2.5 }, contextWindow: 1e6, maxTokens: 128e3, compat: { supportsStrictMode: true }, thinkingLevelMap: { xhigh: \"xhigh\", max: \"max\" } }, \"meta.llama3-1-70b-instruct-v1:0\": { id: \"meta.llama3-1-70b-instruct-v1:0\", name: \"Llama 3.1 70B Instruct\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: false, input: [\"text\"], cost: { input: 0.72, output: 0.72, cacheRead: 0, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 4096 }, \"meta.llama3-1-8b-instruct-v1:0\": { id: \"meta.llama3-1-8b-instruct-v1:0\", name: \"Llama 3.1 8B Instruct\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: false, input: [\"text\"], cost: { input: 0.22, output: 0.22, cacheRead: 0, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 4096 }, \"meta.llama3-3-70b-instruct-v1:0\": { id: \"meta.llama3-3-70b-instruct-v1:0\", name: \"Llama 3.3 70B Instruct\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: false, input: [\"text\"], cost: { input: 0.72, output: 0.72, cacheRead: 0, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 4096 }, \"meta.llama4-maverick-17b-instruct-v1:0\": { id: \"meta.llama4-maverick-17b-instruct-v1:0\", name: \"Llama 4 Maverick 17B Instruct\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 0.24, output: 0.97, cacheRead: 0, cacheWrite: 0 }, contextWindow: 1e6, maxTokens: 16384 }, \"meta.llama4-scout-17b-instruct-v1:0\": { id: \"meta.llama4-scout-17b-instruct-v1:0\", name: \"Llama 4 Scout 17B Instruct\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 0.17, output: 0.66, cacheRead: 0, cacheWrite: 0 }, contextWindow: 35e5, maxTokens: 16384 }, \"minimax.minimax-m2\": { id: \"minimax.minimax-m2\", name: \"MiniMax M2\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: true, input: [\"text\"], cost: { input: 0.3, output: 1.2, cacheRead: 0, cacheWrite: 0 }, contextWindow: 204608, maxTokens: 128e3 }, \"minimax.minimax-m2.1\": { id: \"minimax.minimax-m2.1\", name: \"MiniMax M2.1\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: true, input: [\"text\"], cost: { input: 0.3, output: 1.2, cacheRead: 0, cacheWrite: 0 }, contextWindow: 204800, maxTokens: 131072 }, \"minimax.minimax-m2.5\": { id: \"minimax.minimax-m2.5\", name: \"MiniMax M2.5\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: true, input: [\"text\"], cost: { input: 0.3, output: 1.2, cacheRead: 0, cacheWrite: 0 }, contextWindow: 196608, maxTokens: 98304 }, \"mistral.devstral-2-123b\": { id: \"mistral.devstral-2-123b\", name: \"Devstral 2 123B\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: false, input: [\"text\"], cost: { input: 0.4, output: 2, cacheRead: 0, cacheWrite: 0 }, contextWindow: 256e3, maxTokens: 8192, compat: { supportsStrictMode: true } }, \"mistral.magistral-small-2509\": { id: \"mistral.magistral-small-2509\", name: \"Magistral Small 1.2\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.5, output: 1.5, cacheRead: 0, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 4e4, compat: { supportsStrictMode: true } }, \"mistral.ministral-3-14b-instruct\": { id: \"mistral.ministral-3-14b-instruct\", name: \"Ministral 14B 3.0\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: false, input: [\"text\"], cost: { input: 0.2, output: 0.2, cacheRead: 0, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 4096, compat: { supportsStrictMode: true } }, \"mistral.ministral-3-3b-instruct\": { id: \"mistral.ministral-3-3b-instruct\", name: \"Ministral 3 3B\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 0.1, output: 0.1, cacheRead: 0, cacheWrite: 0 }, contextWindow: 256e3, maxTokens: 8192, compat: { supportsStrictMode: true } }, \"mistral.ministral-3-8b-instruct\": { id: \"mistral.ministral-3-8b-instruct\", name: \"Ministral 3 8B\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: false, input: [\"text\"], cost: { input: 0.15, output: 0.15, cacheRead: 0, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 4096, compat: { supportsStrictMode: true } }, \"mistral.mistral-large-3-675b-instruct\": { id: \"mistral.mistral-large-3-675b-instruct\", name: \"Mistral Large 3\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 0.5, output: 1.5, cacheRead: 0, cacheWrite: 0 }, contextWindow: 256e3, maxTokens: 8192, compat: { supportsStrictMode: true } }, \"mistral.pixtral-large-2502-v1:0\": { id: \"mistral.pixtral-large-2502-v1:0\", name: \"Pixtral Large (25.02)\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 2, output: 6, cacheRead: 0, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 8192 }, \"mistral.voxtral-mini-3b-2507\": { id: \"mistral.voxtral-mini-3b-2507\", name: \"Voxtral Mini 3B 2507\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: false, input: [\"text\"], cost: { input: 0.04, output: 0.04, cacheRead: 0, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 4096, compat: { supportsStrictMode: true } }, \"mistral.voxtral-small-24b-2507\": { id: \"mistral.voxtral-small-24b-2507\", name: \"Voxtral Small 24B 2507\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: false, input: [\"text\"], cost: { input: 0.15, output: 0.35, cacheRead: 0, cacheWrite: 0 }, contextWindow: 32e3, maxTokens: 8192, compat: { supportsStrictMode: true } }, \"moonshot.kimi-k2-thinking\": { id: \"moonshot.kimi-k2-thinking\", name: \"Kimi K2 Thinking\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: true, input: [\"text\"], cost: { input: 0.6, output: 2.5, cacheRead: 0, cacheWrite: 0 }, contextWindow: 262143, maxTokens: 16e3, compat: { supportsStrictMode: true } }, \"moonshotai.kimi-k2.5\": { id: \"moonshotai.kimi-k2.5\", name: \"Kimi K2.5\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.6, output: 3, cacheRead: 0, cacheWrite: 0 }, contextWindow: 262143, maxTokens: 16e3, compat: { supportsStrictMode: true } }, \"nvidia.nemotron-nano-12b-v2\": { id: \"nvidia.nemotron-nano-12b-v2\", name: \"NVIDIA Nemotron Nano 12B v2 VL BF16\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 0.2, output: 0.6, cacheRead: 0, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 4096, compat: { supportsStrictMode: true } }, \"nvidia.nemotron-nano-3-30b\": { id: \"nvidia.nemotron-nano-3-30b\", name: \"NVIDIA Nemotron Nano 3 30B\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: true, input: [\"text\"], cost: { input: 0.06, output: 0.24, cacheRead: 0, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 4096, compat: { supportsStrictMode: true } }, \"nvidia.nemotron-nano-9b-v2\": { id: \"nvidia.nemotron-nano-9b-v2\", name: \"NVIDIA Nemotron Nano 9B v2\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: false, input: [\"text\"], cost: { input: 0.06, output: 0.23, cacheRead: 0, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 4096, compat: { supportsStrictMode: true } }, \"nvidia.nemotron-super-3-120b\": { id: \"nvidia.nemotron-super-3-120b\", name: \"NVIDIA Nemotron 3 Super 120B A12B\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: true, input: [\"text\"], cost: { input: 0.15, output: 0.65, cacheRead: 0, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 131072, compat: { supportsStrictMode: true } }, \"openai.gpt-5.4\": { id: \"openai.gpt-5.4\", name: \"GPT-5.4\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 2.75, output: 16.5, cacheRead: 0.275, cacheWrite: 0 }, contextWindow: 272e3, maxTokens: 128e3, compat: { supportsStrictMode: true }, thinkingLevelMap: { xhigh: \"xhigh\" } }, \"openai.gpt-5.5\": { id: \"openai.gpt-5.5\", name: \"GPT-5.5\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 5.5, output: 33, cacheRead: 0.55, cacheWrite: 0 }, contextWindow: 272e3, maxTokens: 128e3, compat: { supportsStrictMode: true }, thinkingLevelMap: { xhigh: \"xhigh\" } }, \"openai.gpt-5.6-luna\": { id: \"openai.gpt-5.6-luna\", name: \"GPT-5.6 Luna\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.22, output: 1.32, cacheRead: 0.022, cacheWrite: 0.275 }, contextWindow: 105e4, maxTokens: 128e3, compat: { supportsStrictMode: true }, thinkingLevelMap: { xhigh: \"xhigh\" } }, \"openai.gpt-5.6-sol\": { id: \"openai.gpt-5.6-sol\", name: \"GPT-5.6 Sol\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 5.5, output: 33, cacheRead: 0.55, cacheWrite: 6.875 }, contextWindow: 105e4, maxTokens: 128e3, compat: { supportsStrictMode: true }, thinkingLevelMap: { xhigh: \"xhigh\" } }, \"openai.gpt-5.6-terra\": { id: \"openai.gpt-5.6-terra\", name: \"GPT-5.6 Terra\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 2.2, output: 13.2, cacheRead: 0.22, cacheWrite: 2.75 }, contextWindow: 105e4, maxTokens: 128e3, compat: { supportsStrictMode: true }, thinkingLevelMap: { xhigh: \"xhigh\" } }, \"openai.gpt-oss-120b\": { id: \"openai.gpt-oss-120b\", name: \"gpt-oss-120b\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: true, input: [\"text\"], cost: { input: 0.15, output: 0.6, cacheRead: 0, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 16384, compat: { supportsStrictMode: true } }, \"openai.gpt-oss-120b-1:0\": { id: \"openai.gpt-oss-120b-1:0\", name: \"gpt-oss-120b\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: true, input: [\"text\"], cost: { input: 0.15, output: 0.6, cacheRead: 0, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 16384, compat: { supportsStrictMode: true } }, \"openai.gpt-oss-20b\": { id: \"openai.gpt-oss-20b\", name: \"gpt-oss-20b\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: true, input: [\"text\"], cost: { input: 0.07, output: 0.3, cacheRead: 0, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 16384, compat: { supportsStrictMode: true } }, \"openai.gpt-oss-20b-1:0\": { id: \"openai.gpt-oss-20b-1:0\", name: \"gpt-oss-20b\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: true, input: [\"text\"], cost: { input: 0.07, output: 0.3, cacheRead: 0, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 16384, compat: { supportsStrictMode: true } }, \"openai.gpt-oss-safeguard-120b\": { id: \"openai.gpt-oss-safeguard-120b\", name: \"GPT OSS Safeguard 120B\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: false, input: [\"text\"], cost: { input: 0.15, output: 0.6, cacheRead: 0, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 16384, compat: { supportsStrictMode: true } }, \"openai.gpt-oss-safeguard-20b\": { id: \"openai.gpt-oss-safeguard-20b\", name: \"GPT OSS Safeguard 20B\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: false, input: [\"text\"], cost: { input: 0.07, output: 0.2, cacheRead: 0, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 16384, compat: { supportsStrictMode: true } }, \"qwen.qwen3-235b-a22b-2507-v1:0\": { id: \"qwen.qwen3-235b-a22b-2507-v1:0\", name: \"Qwen3 235B A22B 2507\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: false, input: [\"text\"], cost: { input: 0.22, output: 0.88, cacheRead: 0, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 131072, compat: { supportsStrictMode: true } }, \"qwen.qwen3-32b-v1:0\": { id: \"qwen.qwen3-32b-v1:0\", name: \"Qwen3 32B (dense)\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: true, input: [\"text\"], cost: { input: 0.15, output: 0.6, cacheRead: 0, cacheWrite: 0 }, contextWindow: 16384, maxTokens: 16384, compat: { supportsStrictMode: true } }, \"qwen.qwen3-coder-30b-a3b-v1:0\": { id: \"qwen.qwen3-coder-30b-a3b-v1:0\", name: \"Qwen3 Coder 30B A3B Instruct\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: false, input: [\"text\"], cost: { input: 0.15, output: 0.6, cacheRead: 0, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 131072, compat: { supportsStrictMode: true } }, \"qwen.qwen3-coder-480b-a35b-v1:0\": { id: \"qwen.qwen3-coder-480b-a35b-v1:0\", name: \"Qwen3 Coder 480B A35B Instruct\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: false, input: [\"text\"], cost: { input: 0.22, output: 1.8, cacheRead: 0, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 65536, compat: { supportsStrictMode: true } }, \"qwen.qwen3-coder-next\": { id: \"qwen.qwen3-coder-next\", name: \"Qwen3 Coder Next\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: true, input: [\"text\"], cost: { input: 0.22, output: 1.8, cacheRead: 0, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 65536, compat: { supportsStrictMode: true } }, \"qwen.qwen3-next-80b-a3b\": { id: \"qwen.qwen3-next-80b-a3b\", name: \"Qwen/Qwen3-Next-80B-A3B-Instruct\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: false, input: [\"text\"], cost: { input: 0.14, output: 1.4, cacheRead: 0, cacheWrite: 0 }, contextWindow: 262e3, maxTokens: 262e3, compat: { supportsStrictMode: true } }, \"qwen.qwen3-vl-235b-a22b\": { id: \"qwen.qwen3-vl-235b-a22b\", name: \"Qwen/Qwen3-VL-235B-A22B-Instruct\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 0.3, output: 1.5, cacheRead: 0, cacheWrite: 0 }, contextWindow: 262e3, maxTokens: 262e3, compat: { supportsStrictMode: true } }, \"us.anthropic.claude-fable-5\": { id: \"us.anthropic.claude-fable-5\", name: \"Claude Fable 5 (US)\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 10, output: 50, cacheRead: 1, cacheWrite: 12.5 }, contextWindow: 1e6, maxTokens: 128e3, thinkingLevelMap: { off: null, xhigh: \"xhigh\", max: \"max\" } }, \"us.anthropic.claude-haiku-4-5-20251001-v1:0\": { id: \"us.anthropic.claude-haiku-4-5-20251001-v1:0\", name: \"Claude Haiku 4.5 (US)\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1, output: 5, cacheRead: 0.1, cacheWrite: 1.25 }, contextWindow: 2e5, maxTokens: 64e3, compat: { supportsStrictMode: true } }, \"us.anthropic.claude-opus-4-1-20250805-v1:0\": { id: \"us.anthropic.claude-opus-4-1-20250805-v1:0\", name: \"Claude Opus 4.1 (US)\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 15, output: 75, cacheRead: 1.5, cacheWrite: 18.75 }, contextWindow: 2e5, maxTokens: 32e3 }, \"us.anthropic.claude-opus-4-5-20251101-v1:0\": { id: \"us.anthropic.claude-opus-4-5-20251101-v1:0\", name: \"Claude Opus 4.5 (US)\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 }, contextWindow: 2e5, maxTokens: 64e3, compat: { supportsStrictMode: true } }, \"us.anthropic.claude-opus-4-6-v1\": { id: \"us.anthropic.claude-opus-4-6-v1\", name: \"Claude Opus 4.6 (US)\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 }, contextWindow: 1e6, maxTokens: 128e3, compat: { supportsStrictMode: true }, thinkingLevelMap: { max: \"max\" } }, \"us.anthropic.claude-opus-4-7\": { id: \"us.anthropic.claude-opus-4-7\", name: \"Claude Opus 4.7 (US)\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 }, contextWindow: 1e6, maxTokens: 128e3, thinkingLevelMap: { xhigh: \"xhigh\", max: \"max\" } }, \"us.anthropic.claude-opus-4-8\": { id: \"us.anthropic.claude-opus-4-8\", name: \"Claude Opus 4.8 (US)\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 }, contextWindow: 1e6, maxTokens: 128e3, thinkingLevelMap: { xhigh: \"xhigh\", max: \"max\" } }, \"us.anthropic.claude-opus-5\": { id: \"us.anthropic.claude-opus-5\", name: \"Claude Opus 5 (US)\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 }, contextWindow: 1e6, maxTokens: 128e3, thinkingLevelMap: { xhigh: \"xhigh\", max: \"max\" } }, \"us.anthropic.claude-sonnet-4-5-20250929-v1:0\": { id: \"us.anthropic.claude-sonnet-4-5-20250929-v1:0\", name: \"Claude Sonnet 4.5 (US)\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3.75 }, contextWindow: 2e5, maxTokens: 64e3, compat: { supportsStrictMode: true } }, \"us.anthropic.claude-sonnet-4-6\": { id: \"us.anthropic.claude-sonnet-4-6\", name: \"Claude Sonnet 4.6 (US)\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3.75 }, contextWindow: 1e6, maxTokens: 64e3, compat: { supportsStrictMode: true }, thinkingLevelMap: { max: \"max\" } }, \"us.anthropic.claude-sonnet-5\": { id: \"us.anthropic.claude-sonnet-5\", name: \"Claude Sonnet 5 (US)\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 2, output: 10, cacheRead: 0.2, cacheWrite: 2.5 }, contextWindow: 1e6, maxTokens: 128e3, compat: { supportsStrictMode: true }, thinkingLevelMap: { xhigh: \"xhigh\", max: \"max\" } }, \"us.deepseek.r1-v1:0\": { id: \"us.deepseek.r1-v1:0\", name: \"DeepSeek-R1 (US)\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: true, input: [\"text\"], cost: { input: 1.35, output: 5.4, cacheRead: 0, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 32768 }, \"us.meta.llama4-maverick-17b-instruct-v1:0\": { id: \"us.meta.llama4-maverick-17b-instruct-v1:0\", name: \"Llama 4 Maverick 17B Instruct (US)\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 0.24, output: 0.97, cacheRead: 0, cacheWrite: 0 }, contextWindow: 1e6, maxTokens: 16384 }, \"us.meta.llama4-scout-17b-instruct-v1:0\": { id: \"us.meta.llama4-scout-17b-instruct-v1:0\", name: \"Llama 4 Scout 17B Instruct (US)\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 0.17, output: 0.66, cacheRead: 0, cacheWrite: 0 }, contextWindow: 35e5, maxTokens: 16384 }, \"writer.palmyra-x4-v1:0\": { id: \"writer.palmyra-x4-v1:0\", name: \"Palmyra X4\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: true, input: [\"text\"], cost: { input: 2.5, output: 10, cacheRead: 0, cacheWrite: 0 }, contextWindow: 122880, maxTokens: 8192 }, \"writer.palmyra-x5-v1:0\": { id: \"writer.palmyra-x5-v1:0\", name: \"Palmyra X5\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: true, input: [\"text\"], cost: { input: 0.6, output: 6, cacheRead: 0, cacheWrite: 0 }, contextWindow: 104e4, maxTokens: 8192 }, \"xai.grok-4.3\": { id: \"xai.grok-4.3\", name: \"Grok 4.3\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.25, output: 2.5, cacheRead: 0.2, cacheWrite: 0 }, contextWindow: 1e6, maxTokens: 131072, compat: { supportsStrictMode: true } }, \"zai.glm-4.7\": { id: \"zai.glm-4.7\", name: \"GLM-4.7\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: true, input: [\"text\"], cost: { input: 0.6, output: 2.2, cacheRead: 0, cacheWrite: 0 }, contextWindow: 204800, maxTokens: 131072, compat: { supportsStrictMode: true } }, \"zai.glm-4.7-flash\": { id: \"zai.glm-4.7-flash\", name: \"GLM-4.7-Flash\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: true, input: [\"text\"], cost: { input: 0.07, output: 0.4, cacheRead: 0, cacheWrite: 0 }, contextWindow: 2e5, maxTokens: 131072, compat: { supportsStrictMode: true } }, \"zai.glm-5\": { id: \"zai.glm-5\", name: \"GLM-5\", api: \"bedrock-converse-stream\", provider: \"amazon-bedrock\", baseUrl: \"https://bedrock-runtime.us-east-1.amazonaws.com\", reasoning: true, input: [\"text\"], cost: { input: 1, output: 3.2, cacheRead: 0, cacheWrite: 0 }, contextWindow: 202752, maxTokens: 101376, compat: { supportsStrictMode: true } } } };\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/model-catalog.js\nfunction flattenModelCatalog(_provider, groups) {\n  return Object.assign({}, ...Object.values(groups));\n}\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/amazon-bedrock.models.js\nvar AMAZON_BEDROCK_MODELS = flattenModelCatalog(\"amazon-bedrock\", amazon_bedrock_default);\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/data/ant-ling.json\nvar ant_ling_default = { \"openai-completions\": { \"Ling-2.6-1T\": { id: \"Ling-2.6-1T\", name: \"Ling 2.6 1T\", api: \"openai-completions\", baseUrl: \"https://api.ant-ling.com/v1\", provider: \"ant-ling\", reasoning: false, input: [\"text\"], cost: { input: 0.06, output: 0.25, cacheRead: 0, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 65536, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false, maxTokensField: \"max_tokens\", thinkingFormat: \"ant-ling\", supportsLongCacheRetention: false } }, \"Ling-2.6-flash\": { id: \"Ling-2.6-flash\", name: \"Ling 2.6 Flash\", api: \"openai-completions\", baseUrl: \"https://api.ant-ling.com/v1\", provider: \"ant-ling\", reasoning: false, input: [\"text\"], cost: { input: 0.01, output: 0.02, cacheRead: 0, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 65536, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false, maxTokensField: \"max_tokens\", thinkingFormat: \"ant-ling\", supportsLongCacheRetention: false } }, \"Ring-2.6-1T\": { id: \"Ring-2.6-1T\", name: \"Ring 2.6 1T\", api: \"openai-completions\", baseUrl: \"https://api.ant-ling.com/v1\", provider: \"ant-ling\", reasoning: true, input: [\"text\"], cost: { input: 0.06, output: 0.25, cacheRead: 0, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 65536, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false, maxTokensField: \"max_tokens\", thinkingFormat: \"ant-ling\", supportsLongCacheRetention: false }, thinkingLevelMap: { off: null, minimal: null, low: null, medium: null, high: \"high\", xhigh: \"xhigh\" } } } };\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/ant-ling.models.js\nvar ANT_LING_MODELS = flattenModelCatalog(\"ant-ling\", ant_ling_default);\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/data/anthropic.json\nvar anthropic_default = { \"anthropic-messages\": { \"claude-fable-5\": { id: \"claude-fable-5\", name: \"Claude Fable 5\", api: \"anthropic-messages\", provider: \"anthropic\", baseUrl: \"https://api.anthropic.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 10, output: 50, cacheRead: 1, cacheWrite: 12.5 }, contextWindow: 1e6, maxTokens: 128e3, thinkingLevelMap: { off: null, xhigh: \"xhigh\", max: \"max\" }, compat: { forceAdaptiveThinking: true, supportsStrictTools: true } }, \"claude-haiku-4-5\": { id: \"claude-haiku-4-5\", name: \"Claude Haiku 4.5 (latest)\", api: \"anthropic-messages\", provider: \"anthropic\", baseUrl: \"https://api.anthropic.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1, output: 5, cacheRead: 0.1, cacheWrite: 1.25 }, contextWindow: 2e5, maxTokens: 64e3, compat: { supportsStrictTools: true } }, \"claude-haiku-4-5-20251001\": { id: \"claude-haiku-4-5-20251001\", name: \"Claude Haiku 4.5\", api: \"anthropic-messages\", provider: \"anthropic\", baseUrl: \"https://api.anthropic.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1, output: 5, cacheRead: 0.1, cacheWrite: 1.25 }, contextWindow: 2e5, maxTokens: 64e3, compat: { supportsStrictTools: true } }, \"claude-opus-4-5\": { id: \"claude-opus-4-5\", name: \"Claude Opus 4.5 (latest)\", api: \"anthropic-messages\", provider: \"anthropic\", baseUrl: \"https://api.anthropic.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 }, contextWindow: 2e5, maxTokens: 64e3, compat: { supportsStrictTools: true } }, \"claude-opus-4-5-20251101\": { id: \"claude-opus-4-5-20251101\", name: \"Claude Opus 4.5\", api: \"anthropic-messages\", provider: \"anthropic\", baseUrl: \"https://api.anthropic.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 }, contextWindow: 2e5, maxTokens: 64e3, compat: { supportsStrictTools: true } }, \"claude-opus-4-6\": { id: \"claude-opus-4-6\", name: \"Claude Opus 4.6\", api: \"anthropic-messages\", provider: \"anthropic\", baseUrl: \"https://api.anthropic.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 }, contextWindow: 1e6, maxTokens: 128e3, thinkingLevelMap: { max: \"max\" }, compat: { forceAdaptiveThinking: true, supportsStrictTools: true } }, \"claude-opus-4-7\": { id: \"claude-opus-4-7\", name: \"Claude Opus 4.7\", api: \"anthropic-messages\", provider: \"anthropic\", baseUrl: \"https://api.anthropic.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 }, contextWindow: 1e6, maxTokens: 128e3, thinkingLevelMap: { xhigh: \"xhigh\", max: \"max\" }, compat: { forceAdaptiveThinking: true, supportsTemperature: false, supportsStrictTools: true } }, \"claude-opus-4-8\": { id: \"claude-opus-4-8\", name: \"Claude Opus 4.8\", api: \"anthropic-messages\", provider: \"anthropic\", baseUrl: \"https://api.anthropic.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 }, contextWindow: 1e6, maxTokens: 128e3, thinkingLevelMap: { xhigh: \"xhigh\", max: \"max\" }, compat: { forceAdaptiveThinking: true, supportsTemperature: false, supportsStrictTools: true } }, \"claude-opus-5\": { id: \"claude-opus-5\", name: \"Claude Opus 5\", api: \"anthropic-messages\", provider: \"anthropic\", baseUrl: \"https://api.anthropic.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 }, contextWindow: 1e6, maxTokens: 128e3, thinkingLevelMap: { xhigh: \"xhigh\", max: \"max\" }, compat: { forceAdaptiveThinking: true, supportsTemperature: false, supportsStrictTools: true } }, \"claude-sonnet-4-5\": { id: \"claude-sonnet-4-5\", name: \"Claude Sonnet 4.5 (latest)\", api: \"anthropic-messages\", provider: \"anthropic\", baseUrl: \"https://api.anthropic.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3.75 }, contextWindow: 1e6, maxTokens: 64e3, compat: { supportsStrictTools: true } }, \"claude-sonnet-4-5-20250929\": { id: \"claude-sonnet-4-5-20250929\", name: \"Claude Sonnet 4.5\", api: \"anthropic-messages\", provider: \"anthropic\", baseUrl: \"https://api.anthropic.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3.75 }, contextWindow: 1e6, maxTokens: 64e3, compat: { supportsStrictTools: true } }, \"claude-sonnet-4-6\": { id: \"claude-sonnet-4-6\", name: \"Claude Sonnet 4.6\", api: \"anthropic-messages\", provider: \"anthropic\", baseUrl: \"https://api.anthropic.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3.75 }, contextWindow: 1e6, maxTokens: 128e3, thinkingLevelMap: { max: \"max\" }, compat: { forceAdaptiveThinking: true, supportsStrictTools: true } }, \"claude-sonnet-5\": { id: \"claude-sonnet-5\", name: \"Claude Sonnet 5\", api: \"anthropic-messages\", provider: \"anthropic\", baseUrl: \"https://api.anthropic.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 2, output: 10, cacheRead: 0.2, cacheWrite: 2.5 }, contextWindow: 1e6, maxTokens: 128e3, thinkingLevelMap: { xhigh: \"xhigh\", max: \"max\" }, compat: { forceAdaptiveThinking: true, supportsStrictTools: true } } } };\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/anthropic.models.js\nvar ANTHROPIC_MODELS = flattenModelCatalog(\"anthropic\", anthropic_default);\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/data/azure-openai-responses.json\nvar azure_openai_responses_default = { \"azure-openai-responses\": { \"gpt-4\": { id: \"gpt-4\", name: \"GPT-4\", api: \"azure-openai-responses\", provider: \"azure-openai-responses\", baseUrl: \"\", reasoning: false, input: [\"text\"], cost: { input: 30, output: 60, cacheRead: 0, cacheWrite: 0 }, contextWindow: 8192, maxTokens: 8192 }, \"gpt-4-turbo\": { id: \"gpt-4-turbo\", name: \"GPT-4 Turbo\", api: \"azure-openai-responses\", provider: \"azure-openai-responses\", baseUrl: \"\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 10, output: 30, cacheRead: 0, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 4096 }, \"gpt-4.1\": { id: \"gpt-4.1\", name: \"GPT-4.1\", api: \"azure-openai-responses\", provider: \"azure-openai-responses\", baseUrl: \"\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 2, output: 8, cacheRead: 0.5, cacheWrite: 0 }, contextWindow: 1047576, maxTokens: 32768 }, \"gpt-4.1-mini\": { id: \"gpt-4.1-mini\", name: \"GPT-4.1 mini\", api: \"azure-openai-responses\", provider: \"azure-openai-responses\", baseUrl: \"\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 0.4, output: 1.6, cacheRead: 0.1, cacheWrite: 0 }, contextWindow: 1047576, maxTokens: 32768 }, \"gpt-4.1-nano\": { id: \"gpt-4.1-nano\", name: \"GPT-4.1 nano\", api: \"azure-openai-responses\", provider: \"azure-openai-responses\", baseUrl: \"\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 0.1, output: 0.4, cacheRead: 0.025, cacheWrite: 0 }, contextWindow: 1047576, maxTokens: 32768 }, \"gpt-4o\": { id: \"gpt-4o\", name: \"GPT-4o\", api: \"azure-openai-responses\", provider: \"azure-openai-responses\", baseUrl: \"\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 2.5, output: 10, cacheRead: 1.25, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 16384 }, \"gpt-4o-2024-05-13\": { id: \"gpt-4o-2024-05-13\", name: \"GPT-4o (2024-05-13)\", api: \"azure-openai-responses\", provider: \"azure-openai-responses\", baseUrl: \"\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 5, output: 15, cacheRead: 0, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 4096 }, \"gpt-4o-2024-08-06\": { id: \"gpt-4o-2024-08-06\", name: \"GPT-4o (2024-08-06)\", api: \"azure-openai-responses\", provider: \"azure-openai-responses\", baseUrl: \"\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 2.5, output: 10, cacheRead: 1.25, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 16384 }, \"gpt-4o-2024-11-20\": { id: \"gpt-4o-2024-11-20\", name: \"GPT-4o (2024-11-20)\", api: \"azure-openai-responses\", provider: \"azure-openai-responses\", baseUrl: \"\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 2.5, output: 10, cacheRead: 1.25, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 16384 }, \"gpt-4o-mini\": { id: \"gpt-4o-mini\", name: \"GPT-4o mini\", api: \"azure-openai-responses\", provider: \"azure-openai-responses\", baseUrl: \"\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 0.15, output: 0.6, cacheRead: 0.075, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 16384 }, \"gpt-5\": { id: \"gpt-5\", name: \"GPT-5\", api: \"azure-openai-responses\", provider: \"azure-openai-responses\", baseUrl: \"\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.25, output: 10, cacheRead: 0.125, cacheWrite: 0 }, contextWindow: 4e5, maxTokens: 128e3, thinkingLevelMap: { off: null }, compat: { supportsOpenAIGrammarTools: true } }, \"gpt-5-chat-latest\": { id: \"gpt-5-chat-latest\", name: \"GPT-5 Chat Latest\", api: \"azure-openai-responses\", baseUrl: \"\", provider: \"azure-openai-responses\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 1.25, output: 10, cacheRead: 0.125, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 16384, thinkingLevelMap: { off: null }, compat: { supportsOpenAIGrammarTools: true } }, \"gpt-5-mini\": { id: \"gpt-5-mini\", name: \"GPT-5 Mini\", api: \"azure-openai-responses\", provider: \"azure-openai-responses\", baseUrl: \"\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.25, output: 2, cacheRead: 0.025, cacheWrite: 0 }, contextWindow: 4e5, maxTokens: 128e3, thinkingLevelMap: { off: null }, compat: { supportsOpenAIGrammarTools: true } }, \"gpt-5-nano\": { id: \"gpt-5-nano\", name: \"GPT-5 Nano\", api: \"azure-openai-responses\", provider: \"azure-openai-responses\", baseUrl: \"\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.05, output: 0.4, cacheRead: 5e-3, cacheWrite: 0 }, contextWindow: 4e5, maxTokens: 128e3, thinkingLevelMap: { off: null }, compat: { supportsOpenAIGrammarTools: true } }, \"gpt-5-pro\": { id: \"gpt-5-pro\", name: \"GPT-5 Pro\", api: \"azure-openai-responses\", provider: \"azure-openai-responses\", baseUrl: \"\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 15, output: 120, cacheRead: 0, cacheWrite: 0 }, contextWindow: 4e5, maxTokens: 128e3, thinkingLevelMap: { off: null }, compat: { supportsOpenAIGrammarTools: true } }, \"gpt-5.1\": { id: \"gpt-5.1\", name: \"GPT-5.1\", api: \"azure-openai-responses\", provider: \"azure-openai-responses\", baseUrl: \"\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.25, output: 10, cacheRead: 0.125, cacheWrite: 0 }, contextWindow: 4e5, maxTokens: 128e3, thinkingLevelMap: { off: null }, compat: { supportsOpenAIGrammarTools: true } }, \"gpt-5.2\": { id: \"gpt-5.2\", name: \"GPT-5.2\", api: \"azure-openai-responses\", provider: \"azure-openai-responses\", baseUrl: \"\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.75, output: 14, cacheRead: 0.175, cacheWrite: 0 }, contextWindow: 4e5, maxTokens: 128e3, thinkingLevelMap: { off: null, xhigh: \"xhigh\" }, compat: { supportsOpenAIGrammarTools: true } }, \"gpt-5.2-chat-latest\": { id: \"gpt-5.2-chat-latest\", name: \"GPT-5.2 Chat\", api: \"azure-openai-responses\", provider: \"azure-openai-responses\", baseUrl: \"\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.75, output: 14, cacheRead: 0.175, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 16384, thinkingLevelMap: { off: null, xhigh: \"xhigh\" }, compat: { supportsOpenAIGrammarTools: true } }, \"gpt-5.2-pro\": { id: \"gpt-5.2-pro\", name: \"GPT-5.2 Pro\", api: \"azure-openai-responses\", provider: \"azure-openai-responses\", baseUrl: \"\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 21, output: 168, cacheRead: 0, cacheWrite: 0 }, contextWindow: 4e5, maxTokens: 128e3, thinkingLevelMap: { off: null, xhigh: \"xhigh\" }, compat: { supportsOpenAIGrammarTools: true } }, \"gpt-5.3-chat-latest\": { id: \"gpt-5.3-chat-latest\", name: \"GPT-5.3 Chat (latest)\", api: \"azure-openai-responses\", provider: \"azure-openai-responses\", baseUrl: \"\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 1.75, output: 14, cacheRead: 0.175, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 16384, thinkingLevelMap: { off: null, xhigh: \"xhigh\" }, compat: { supportsOpenAIGrammarTools: true } }, \"gpt-5.3-codex\": { id: \"gpt-5.3-codex\", name: \"GPT-5.3 Codex\", api: \"azure-openai-responses\", provider: \"azure-openai-responses\", baseUrl: \"\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.75, output: 14, cacheRead: 0.175, cacheWrite: 0 }, contextWindow: 4e5, maxTokens: 128e3, thinkingLevelMap: { off: null, xhigh: \"xhigh\" }, compat: { supportsOpenAIGrammarTools: true } }, \"gpt-5.3-codex-spark\": { id: \"gpt-5.3-codex-spark\", name: \"GPT-5.3 Codex Spark\", api: \"azure-openai-responses\", provider: \"azure-openai-responses\", baseUrl: \"\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.75, output: 14, cacheRead: 0.175, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 32e3, thinkingLevelMap: { off: null, xhigh: \"xhigh\" }, compat: { supportsOpenAIGrammarTools: true } }, \"gpt-5.4\": { id: \"gpt-5.4\", name: \"GPT-5.4\", api: \"azure-openai-responses\", provider: \"azure-openai-responses\", baseUrl: \"\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 2.5, output: 15, cacheRead: 0.25, cacheWrite: 0 }, contextWindow: 105e4, maxTokens: 128e3, thinkingLevelMap: { off: null, xhigh: \"xhigh\" }, compat: { supportsOpenAIGrammarTools: true } }, \"gpt-5.4-mini\": { id: \"gpt-5.4-mini\", name: \"GPT-5.4 mini\", api: \"azure-openai-responses\", provider: \"azure-openai-responses\", baseUrl: \"\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.75, output: 4.5, cacheRead: 0.075, cacheWrite: 0 }, contextWindow: 4e5, maxTokens: 128e3, thinkingLevelMap: { off: null, xhigh: \"xhigh\" }, compat: { supportsOpenAIGrammarTools: true } }, \"gpt-5.4-nano\": { id: \"gpt-5.4-nano\", name: \"GPT-5.4 nano\", api: \"azure-openai-responses\", provider: \"azure-openai-responses\", baseUrl: \"\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.2, output: 1.25, cacheRead: 0.02, cacheWrite: 0 }, contextWindow: 4e5, maxTokens: 128e3, thinkingLevelMap: { off: null, xhigh: \"xhigh\" }, compat: { supportsOpenAIGrammarTools: true } }, \"gpt-5.4-pro\": { id: \"gpt-5.4-pro\", name: \"GPT-5.4 Pro\", api: \"azure-openai-responses\", provider: \"azure-openai-responses\", baseUrl: \"\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 30, output: 180, cacheRead: 0, cacheWrite: 0 }, contextWindow: 105e4, maxTokens: 128e3, thinkingLevelMap: { off: null, xhigh: \"xhigh\" }, compat: { supportsOpenAIGrammarTools: true } }, \"gpt-5.5\": { id: \"gpt-5.5\", name: \"GPT-5.5\", api: \"azure-openai-responses\", provider: \"azure-openai-responses\", baseUrl: \"\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 5, output: 30, cacheRead: 0.5, cacheWrite: 0 }, contextWindow: 105e4, maxTokens: 128e3, thinkingLevelMap: { off: null, xhigh: \"xhigh\" }, compat: { supportsOpenAIGrammarTools: true } }, \"gpt-5.5-pro\": { id: \"gpt-5.5-pro\", name: \"GPT-5.5 Pro\", api: \"azure-openai-responses\", provider: \"azure-openai-responses\", baseUrl: \"\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 30, output: 180, cacheRead: 0, cacheWrite: 0 }, contextWindow: 105e4, maxTokens: 128e3, thinkingLevelMap: { off: null, xhigh: \"xhigh\", minimal: null, low: null }, compat: { supportsOpenAIGrammarTools: true } }, \"gpt-5.6-luna\": { id: \"gpt-5.6-luna\", name: \"GPT-5.6 Luna\", api: \"azure-openai-responses\", provider: \"azure-openai-responses\", baseUrl: \"\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.2, output: 1.2, cacheRead: 0.02, cacheWrite: 0.25 }, contextWindow: 105e4, maxTokens: 128e3, thinkingLevelMap: { off: null, xhigh: \"xhigh\", max: \"max\" }, compat: { supportsOpenAIGrammarTools: true } }, \"gpt-5.6-sol\": { id: \"gpt-5.6-sol\", name: \"GPT-5.6 Sol\", api: \"azure-openai-responses\", provider: \"azure-openai-responses\", baseUrl: \"\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 5, output: 30, cacheRead: 0.5, cacheWrite: 6.25 }, contextWindow: 105e4, maxTokens: 128e3, thinkingLevelMap: { off: null, xhigh: \"xhigh\", max: \"max\" }, compat: { supportsOpenAIGrammarTools: true } }, \"gpt-5.6-terra\": { id: \"gpt-5.6-terra\", name: \"GPT-5.6 Terra\", api: \"azure-openai-responses\", provider: \"azure-openai-responses\", baseUrl: \"\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 2, output: 12, cacheRead: 0.2, cacheWrite: 2.5 }, contextWindow: 105e4, maxTokens: 128e3, thinkingLevelMap: { off: null, xhigh: \"xhigh\", max: \"max\" }, compat: { supportsOpenAIGrammarTools: true } }, \"gpt-realtime-2.1\": { id: \"gpt-realtime-2.1\", name: \"GPT-Realtime-2.1\", api: \"azure-openai-responses\", provider: \"azure-openai-responses\", baseUrl: \"\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 4, output: 24, cacheRead: 0.4, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 32e3 }, o1: { id: \"o1\", name: \"o1\", api: \"azure-openai-responses\", provider: \"azure-openai-responses\", baseUrl: \"\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 15, output: 60, cacheRead: 7.5, cacheWrite: 0 }, contextWindow: 2e5, maxTokens: 1e5 }, \"o1-pro\": { id: \"o1-pro\", name: \"o1-pro\", api: \"azure-openai-responses\", provider: \"azure-openai-responses\", baseUrl: \"\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 150, output: 600, cacheRead: 0, cacheWrite: 0 }, contextWindow: 2e5, maxTokens: 1e5 }, o3: { id: \"o3\", name: \"o3\", api: \"azure-openai-responses\", provider: \"azure-openai-responses\", baseUrl: \"\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 2, output: 8, cacheRead: 0.5, cacheWrite: 0 }, contextWindow: 2e5, maxTokens: 1e5 }, \"o3-mini\": { id: \"o3-mini\", name: \"o3-mini\", api: \"azure-openai-responses\", provider: \"azure-openai-responses\", baseUrl: \"\", reasoning: true, input: [\"text\"], cost: { input: 1.1, output: 4.4, cacheRead: 0.55, cacheWrite: 0 }, contextWindow: 2e5, maxTokens: 1e5 }, \"o3-pro\": { id: \"o3-pro\", name: \"o3-pro\", api: \"azure-openai-responses\", provider: \"azure-openai-responses\", baseUrl: \"\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 20, output: 80, cacheRead: 0, cacheWrite: 0 }, contextWindow: 2e5, maxTokens: 1e5 }, \"o4-mini\": { id: \"o4-mini\", name: \"o4-mini\", api: \"azure-openai-responses\", provider: \"azure-openai-responses\", baseUrl: \"\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.1, output: 4.4, cacheRead: 0.275, cacheWrite: 0 }, contextWindow: 2e5, maxTokens: 1e5 } } };\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/azure-openai-responses.models.js\nvar AZURE_OPENAI_RESPONSES_MODELS = flattenModelCatalog(\"azure-openai-responses\", azure_openai_responses_default);\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/data/baseten.json\nvar baseten_default = { \"openai-completions\": { \"deepseek-ai/DeepSeek-V4-Flash-0731\": { id: \"deepseek-ai/DeepSeek-V4-Flash-0731\", name: \"Deepseek V4 Flash 0731\", api: \"openai-completions\", provider: \"baseten\", baseUrl: \"https://inference.baseten.co/v1\", reasoning: true, input: [\"text\"], cost: { input: 0.13, output: 0.26, cacheRead: 0.028, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false, supportsUsageInStreaming: true, maxTokensField: \"max_tokens\", supportsStrictMode: true, supportsLongCacheRetention: false }, contextWindow: 1048576, maxTokens: 1048576 }, \"deepseek-ai/DeepSeek-V4-Pro\": { id: \"deepseek-ai/DeepSeek-V4-Pro\", name: \"Deepseek V4 Pro\", api: \"openai-completions\", provider: \"baseten\", baseUrl: \"https://inference.baseten.co/v1\", reasoning: true, thinkingLevelMap: { off: \"none\", minimal: \"minimal\", low: \"low\", medium: \"medium\", high: \"high\", xhigh: \"xhigh\", max: \"max\" }, input: [\"text\"], cost: { input: 1.74, output: 3.48, cacheRead: 0.145, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: true, supportsUsageInStreaming: true, maxTokensField: \"max_tokens\", supportsStrictMode: true, supportsLongCacheRetention: false, thinkingFormat: \"openai\" }, contextWindow: 262144, maxTokens: 262144 }, \"deepseek-ai/DeepSeek-V4-Pro-0813\": { id: \"deepseek-ai/DeepSeek-V4-Pro-0813\", name: \"Deepseek V4 Pro 0813\", api: \"openai-completions\", provider: \"baseten\", baseUrl: \"https://inference.baseten.co/v1\", reasoning: true, thinkingLevelMap: { off: \"none\", minimal: \"minimal\", low: \"low\", medium: \"medium\", high: \"high\", xhigh: \"xhigh\", max: \"max\" }, input: [\"text\"], cost: { input: 1.32, output: 3.96, cacheRead: 0, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: true, supportsUsageInStreaming: true, maxTokensField: \"max_tokens\", supportsStrictMode: true, supportsLongCacheRetention: false, thinkingFormat: \"openai\" }, contextWindow: 1e6, maxTokens: 262144 }, \"moonshotai/Kimi-K2.5\": { id: \"moonshotai/Kimi-K2.5\", name: \"Kimi K2.5\", api: \"openai-completions\", provider: \"baseten\", baseUrl: \"https://inference.baseten.co/v1\", reasoning: true, thinkingLevelMap: { off: \"off\", minimal: null, low: null, medium: null, high: \"high\", xhigh: null, max: null }, input: [\"text\", \"image\"], cost: { input: 0.6, output: 3, cacheRead: 0.12, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false, supportsUsageInStreaming: true, maxTokensField: \"max_tokens\", supportsStrictMode: true, supportsLongCacheRetention: false, thinkingFormat: \"baseten\", chatTemplateArgs: { enable_thinking: { $var: \"thinking.enabled\" } } }, contextWindow: 262e3, maxTokens: 262e3 }, \"moonshotai/Kimi-K2.6\": { id: \"moonshotai/Kimi-K2.6\", name: \"Kimi K2.6\", api: \"openai-completions\", provider: \"baseten\", baseUrl: \"https://inference.baseten.co/v1\", reasoning: true, thinkingLevelMap: { off: \"off\", minimal: null, low: null, medium: null, high: \"high\", xhigh: null, max: null }, input: [\"text\", \"image\"], cost: { input: 0.95, output: 4, cacheRead: 0.16, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false, supportsUsageInStreaming: true, maxTokensField: \"max_tokens\", supportsStrictMode: true, supportsLongCacheRetention: false, thinkingFormat: \"baseten\", chatTemplateArgs: { enable_thinking: { $var: \"thinking.enabled\" } } }, contextWindow: 262e3, maxTokens: 262e3 }, \"moonshotai/Kimi-K2.7-Code\": { id: \"moonshotai/Kimi-K2.7-Code\", name: \"Kimi K2.7 Code\", api: \"openai-completions\", provider: \"baseten\", baseUrl: \"https://inference.baseten.co/v1\", reasoning: true, thinkingLevelMap: { off: \"off\", minimal: null, low: null, medium: null, high: \"high\", xhigh: null, max: null }, input: [\"text\", \"image\"], cost: { input: 0.95, output: 4, cacheRead: 0.16, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false, supportsUsageInStreaming: true, maxTokensField: \"max_tokens\", supportsStrictMode: true, supportsLongCacheRetention: false, thinkingFormat: \"baseten\", chatTemplateArgs: { enable_thinking: { $var: \"thinking.enabled\" } } }, contextWindow: 262e3, maxTokens: 262e3 }, \"moonshotai/Kimi-K3\": { id: \"moonshotai/Kimi-K3\", name: \"Kimi K3\", api: \"openai-completions\", provider: \"baseten\", baseUrl: \"https://inference.baseten.co/v1\", reasoning: true, thinkingLevelMap: { off: \"none\", minimal: null, low: \"low\", medium: null, high: \"high\", xhigh: null, max: \"max\" }, input: [\"text\", \"image\"], cost: { input: 3, output: 15, cacheRead: 0, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: true, supportsUsageInStreaming: true, maxTokensField: \"max_tokens\", supportsStrictMode: true, supportsLongCacheRetention: false, thinkingFormat: \"openai\" }, contextWindow: 1048576, maxTokens: 262144 }, \"nvidia/NVIDIA-Nemotron-3-Ultra-550B-A55B\": { id: \"nvidia/NVIDIA-Nemotron-3-Ultra-550B-A55B\", name: \"Nemotron Ultra\", api: \"openai-completions\", provider: \"baseten\", baseUrl: \"https://inference.baseten.co/v1\", reasoning: true, thinkingLevelMap: { off: \"off\", minimal: null, low: null, medium: null, high: \"high\", xhigh: null, max: null }, input: [\"text\"], cost: { input: 0.6, output: 2.4, cacheRead: 0.12, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false, supportsUsageInStreaming: true, maxTokensField: \"max_tokens\", supportsStrictMode: true, supportsLongCacheRetention: false, thinkingFormat: \"baseten\", chatTemplateArgs: { enable_thinking: { $var: \"thinking.enabled\" } } }, contextWindow: 202800, maxTokens: 202800 }, \"nvidia/Nemotron-120B-A12B\": { id: \"nvidia/Nemotron-120B-A12B\", name: \"Nemotron Super\", api: \"openai-completions\", provider: \"baseten\", baseUrl: \"https://inference.baseten.co/v1\", reasoning: true, thinkingLevelMap: { off: \"off\", minimal: null, low: null, medium: null, high: \"high\", xhigh: null, max: null }, input: [\"text\"], cost: { input: 0.3, output: 0.75, cacheRead: 0.06, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false, supportsUsageInStreaming: true, maxTokensField: \"max_tokens\", supportsStrictMode: true, supportsLongCacheRetention: false, thinkingFormat: \"baseten\", chatTemplateArgs: { enable_thinking: { $var: \"thinking.enabled\" } } }, contextWindow: 202800, maxTokens: 202800 }, \"openai/gpt-oss-120b\": { id: \"openai/gpt-oss-120b\", name: \"OpenAI GPT 120B\", api: \"openai-completions\", provider: \"baseten\", baseUrl: \"https://inference.baseten.co/v1\", reasoning: true, thinkingLevelMap: { off: \"none\", minimal: \"minimal\", low: \"low\", medium: \"medium\", high: \"high\", xhigh: \"xhigh\", max: \"max\" }, input: [\"text\"], cost: { input: 0.1, output: 0.5, cacheRead: 0, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: true, supportsUsageInStreaming: true, maxTokensField: \"max_tokens\", supportsStrictMode: true, supportsLongCacheRetention: false, thinkingFormat: \"openai\" }, contextWindow: 128072, maxTokens: 128072 }, \"thinkingmachines/inkling\": { id: \"thinkingmachines/inkling\", name: \"Inkling\", api: \"openai-completions\", provider: \"baseten\", baseUrl: \"https://inference.baseten.co/v1\", reasoning: true, thinkingLevelMap: { off: \"none\", minimal: \"minimal\", low: \"low\", medium: \"medium\", high: \"high\", xhigh: \"xhigh\", max: \"max\" }, input: [\"text\", \"image\"], cost: { input: 1, output: 4.05, cacheRead: 0, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: true, supportsUsageInStreaming: true, maxTokensField: \"max_tokens\", supportsStrictMode: true, supportsLongCacheRetention: false, thinkingFormat: \"openai\" }, contextWindow: 1048576, maxTokens: 32768 }, \"thinkingmachines/inkling-small\": { id: \"thinkingmachines/inkling-small\", name: \"Inkling Small\", api: \"openai-completions\", provider: \"baseten\", baseUrl: \"https://inference.baseten.co/v1\", reasoning: true, thinkingLevelMap: { off: \"none\", minimal: \"minimal\", low: \"low\", medium: \"medium\", high: \"high\", xhigh: \"xhigh\", max: \"max\" }, input: [\"text\", \"image\"], cost: { input: 0.5, output: 1.2, cacheRead: 0.1, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: true, supportsUsageInStreaming: true, maxTokensField: \"max_tokens\", supportsStrictMode: true, supportsLongCacheRetention: false, thinkingFormat: \"openai\" }, contextWindow: 1048576, maxTokens: 32768 }, \"zai-org/GLM-4.7\": { id: \"zai-org/GLM-4.7\", name: \"GLM 4.7\", api: \"openai-completions\", provider: \"baseten\", baseUrl: \"https://inference.baseten.co/v1\", reasoning: true, thinkingLevelMap: { off: \"off\", minimal: null, low: null, medium: null, high: \"high\", xhigh: null, max: null }, input: [\"text\"], cost: { input: 0.6, output: 2.2, cacheRead: 0.12, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false, supportsUsageInStreaming: true, maxTokensField: \"max_tokens\", supportsStrictMode: true, supportsLongCacheRetention: false, thinkingFormat: \"baseten\", chatTemplateArgs: { enable_thinking: { $var: \"thinking.enabled\" } } }, contextWindow: 2e5, maxTokens: 2e5 }, \"zai-org/GLM-5\": { id: \"zai-org/GLM-5\", name: \"GLM 5\", api: \"openai-completions\", provider: \"baseten\", baseUrl: \"https://inference.baseten.co/v1\", reasoning: true, thinkingLevelMap: { off: \"off\", minimal: null, low: null, medium: null, high: \"high\", xhigh: null, max: null }, input: [\"text\"], cost: { input: 0.95, output: 3.15, cacheRead: 0.2, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false, supportsUsageInStreaming: true, maxTokensField: \"max_tokens\", supportsStrictMode: true, supportsLongCacheRetention: false, thinkingFormat: \"baseten\", chatTemplateArgs: { enable_thinking: { $var: \"thinking.enabled\" } } }, contextWindow: 202800, maxTokens: 202800 }, \"zai-org/GLM-5.1\": { id: \"zai-org/GLM-5.1\", name: \"GLM 5.1\", api: \"openai-completions\", provider: \"baseten\", baseUrl: \"https://inference.baseten.co/v1\", reasoning: true, thinkingLevelMap: { off: \"off\", minimal: null, low: null, medium: null, high: \"high\", xhigh: null, max: null }, input: [\"text\"], cost: { input: 1.3, output: 4.3, cacheRead: 0.26, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false, supportsUsageInStreaming: true, maxTokensField: \"max_tokens\", supportsStrictMode: true, supportsLongCacheRetention: false, thinkingFormat: \"baseten\", chatTemplateArgs: { enable_thinking: { $var: \"thinking.enabled\" } } }, contextWindow: 202800, maxTokens: 202800 }, \"zai-org/GLM-5.2\": { id: \"zai-org/GLM-5.2\", name: \"GLM 5.2\", api: \"openai-completions\", provider: \"baseten\", baseUrl: \"https://inference.baseten.co/v1\", reasoning: true, thinkingLevelMap: { off: \"none\", minimal: null, low: null, medium: null, high: \"high\", xhigh: null, max: \"max\" }, input: [\"text\"], cost: { input: 1.4, output: 4.4, cacheRead: 0.3, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: true, supportsUsageInStreaming: true, maxTokensField: \"max_tokens\", supportsStrictMode: true, supportsLongCacheRetention: false, thinkingFormat: \"baseten\", chatTemplateArgs: { enable_thinking: { $var: \"thinking.enabled\" } } }, contextWindow: 1048576, maxTokens: 262144 }, \"zai-org/GLM-5.2-Fast\": { id: \"zai-org/GLM-5.2-Fast\", name: \"GLM 5.2 Fast\", api: \"openai-completions\", provider: \"baseten\", baseUrl: \"https://inference.baseten.co/v1\", reasoning: true, thinkingLevelMap: { off: \"none\", minimal: null, low: null, medium: null, high: \"high\", xhigh: null, max: \"max\" }, input: [\"text\"], cost: { input: 2.1, output: 6.6, cacheRead: 0.21, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: true, supportsUsageInStreaming: true, maxTokensField: \"max_tokens\", supportsStrictMode: true, supportsLongCacheRetention: false, thinkingFormat: \"baseten\", chatTemplateArgs: { enable_thinking: { $var: \"thinking.enabled\" } } }, contextWindow: 1048576, maxTokens: 262144 } } };\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/baseten.models.js\nvar BASETEN_MODELS = flattenModelCatalog(\"baseten\", baseten_default);\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/data/cerebras.json\nvar cerebras_default = { \"openai-completions\": { \"gemma-4-31b\": { id: \"gemma-4-31b\", name: \"Gemma 4 31B IT\", api: \"openai-completions\", provider: \"cerebras\", baseUrl: \"https://api.cerebras.ai/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.99, output: 1.49, cacheRead: 0, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 40960, compat: { supportsStore: false, supportsDeveloperRole: false }, thinkingLevelMap: { off: \"none\", minimal: null, low: \"low\", medium: \"medium\", high: \"high\", xhigh: null, max: null } }, \"gpt-oss-120b\": { id: \"gpt-oss-120b\", name: \"GPT OSS 120B\", api: \"openai-completions\", provider: \"cerebras\", baseUrl: \"https://api.cerebras.ai/v1\", reasoning: true, input: [\"text\"], cost: { input: 0.35, output: 0.75, cacheRead: 0, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 40960, compat: { supportsStore: false, supportsDeveloperRole: false }, thinkingLevelMap: { off: null, minimal: null, low: \"low\", medium: \"medium\", high: \"high\", xhigh: null, max: null } }, \"zai-glm-4.7\": { id: \"zai-glm-4.7\", name: \"Z.AI GLM-4.7\", api: \"openai-completions\", provider: \"cerebras\", baseUrl: \"https://api.cerebras.ai/v1\", reasoning: true, input: [\"text\"], cost: { input: 2.25, output: 2.75, cacheRead: 2.25, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 40960, compat: { supportsStore: false, supportsDeveloperRole: false }, thinkingLevelMap: { off: \"none\", minimal: null, low: null, medium: null, high: null, xhigh: null, max: null } } } };\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/cerebras.models.js\nvar CEREBRAS_MODELS = flattenModelCatalog(\"cerebras\", cerebras_default);\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/data/cloudflare-ai-gateway.json\nvar cloudflare_ai_gateway_default = { \"anthropic-messages\": { \"claude-fable-5\": { id: \"claude-fable-5\", name: \"Claude Fable 5\", api: \"anthropic-messages\", provider: \"cloudflare-ai-gateway\", baseUrl: \"https://gateway.ai.cloudflare.com/v1/{CLOUDFLARE_ACCOUNT_ID}/{CLOUDFLARE_GATEWAY_ID}/anthropic\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 10, output: 50, cacheRead: 1, cacheWrite: 12.5 }, contextWindow: 1e6, maxTokens: 128e3, compat: { sendSessionAffinityHeaders: true, forceAdaptiveThinking: true }, thinkingLevelMap: { off: null, xhigh: \"xhigh\", max: \"max\" } }, \"claude-haiku-4-5\": { id: \"claude-haiku-4-5\", name: \"Claude Haiku 4.5 (latest)\", api: \"anthropic-messages\", provider: \"cloudflare-ai-gateway\", baseUrl: \"https://gateway.ai.cloudflare.com/v1/{CLOUDFLARE_ACCOUNT_ID}/{CLOUDFLARE_GATEWAY_ID}/anthropic\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1, output: 5, cacheRead: 0.1, cacheWrite: 1.25 }, contextWindow: 2e5, maxTokens: 64e3, compat: { sendSessionAffinityHeaders: true } }, \"claude-opus-4-5\": { id: \"claude-opus-4-5\", name: \"Claude Opus 4.5 (latest)\", api: \"anthropic-messages\", provider: \"cloudflare-ai-gateway\", baseUrl: \"https://gateway.ai.cloudflare.com/v1/{CLOUDFLARE_ACCOUNT_ID}/{CLOUDFLARE_GATEWAY_ID}/anthropic\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 }, contextWindow: 2e5, maxTokens: 64e3, compat: { sendSessionAffinityHeaders: true } }, \"claude-opus-4-6\": { id: \"claude-opus-4-6\", name: \"Claude Opus 4.6\", api: \"anthropic-messages\", provider: \"cloudflare-ai-gateway\", baseUrl: \"https://gateway.ai.cloudflare.com/v1/{CLOUDFLARE_ACCOUNT_ID}/{CLOUDFLARE_GATEWAY_ID}/anthropic\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 }, contextWindow: 1e6, maxTokens: 128e3, compat: { sendSessionAffinityHeaders: true, forceAdaptiveThinking: true }, thinkingLevelMap: { max: \"max\" } }, \"claude-opus-4-7\": { id: \"claude-opus-4-7\", name: \"Claude Opus 4.7\", api: \"anthropic-messages\", provider: \"cloudflare-ai-gateway\", baseUrl: \"https://gateway.ai.cloudflare.com/v1/{CLOUDFLARE_ACCOUNT_ID}/{CLOUDFLARE_GATEWAY_ID}/anthropic\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 }, contextWindow: 1e6, maxTokens: 128e3, compat: { sendSessionAffinityHeaders: true, forceAdaptiveThinking: true, supportsTemperature: false }, thinkingLevelMap: { xhigh: \"xhigh\", max: \"max\" } }, \"claude-opus-4-8\": { id: \"claude-opus-4-8\", name: \"Claude Opus 4.8\", api: \"anthropic-messages\", provider: \"cloudflare-ai-gateway\", baseUrl: \"https://gateway.ai.cloudflare.com/v1/{CLOUDFLARE_ACCOUNT_ID}/{CLOUDFLARE_GATEWAY_ID}/anthropic\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 }, contextWindow: 1e6, maxTokens: 128e3, compat: { sendSessionAffinityHeaders: true, forceAdaptiveThinking: true, supportsTemperature: false }, thinkingLevelMap: { xhigh: \"xhigh\", max: \"max\" } }, \"claude-opus-5\": { id: \"claude-opus-5\", name: \"Claude Opus 5\", api: \"anthropic-messages\", provider: \"cloudflare-ai-gateway\", baseUrl: \"https://gateway.ai.cloudflare.com/v1/{CLOUDFLARE_ACCOUNT_ID}/{CLOUDFLARE_GATEWAY_ID}/anthropic\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 }, contextWindow: 1e6, maxTokens: 128e3, compat: { sendSessionAffinityHeaders: true, forceAdaptiveThinking: true, supportsTemperature: false }, thinkingLevelMap: { xhigh: \"xhigh\", max: \"max\" } }, \"claude-sonnet-4-5\": { id: \"claude-sonnet-4-5\", name: \"Claude Sonnet 4.5 (latest)\", api: \"anthropic-messages\", provider: \"cloudflare-ai-gateway\", baseUrl: \"https://gateway.ai.cloudflare.com/v1/{CLOUDFLARE_ACCOUNT_ID}/{CLOUDFLARE_GATEWAY_ID}/anthropic\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3.75 }, contextWindow: 1e6, maxTokens: 64e3, compat: { sendSessionAffinityHeaders: true } }, \"claude-sonnet-4-6\": { id: \"claude-sonnet-4-6\", name: \"Claude Sonnet 4.6\", api: \"anthropic-messages\", provider: \"cloudflare-ai-gateway\", baseUrl: \"https://gateway.ai.cloudflare.com/v1/{CLOUDFLARE_ACCOUNT_ID}/{CLOUDFLARE_GATEWAY_ID}/anthropic\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3.75 }, contextWindow: 1e6, maxTokens: 128e3, compat: { sendSessionAffinityHeaders: true, forceAdaptiveThinking: true }, thinkingLevelMap: { max: \"max\" } }, \"claude-sonnet-5\": { id: \"claude-sonnet-5\", name: \"Claude Sonnet 5\", api: \"anthropic-messages\", provider: \"cloudflare-ai-gateway\", baseUrl: \"https://gateway.ai.cloudflare.com/v1/{CLOUDFLARE_ACCOUNT_ID}/{CLOUDFLARE_GATEWAY_ID}/anthropic\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 2, output: 10, cacheRead: 0.2, cacheWrite: 2.5 }, contextWindow: 1e6, maxTokens: 128e3, compat: { sendSessionAffinityHeaders: true, forceAdaptiveThinking: true }, thinkingLevelMap: { xhigh: \"xhigh\", max: \"max\" } } }, \"openai-completions\": { \"workers-ai/@cf/google/gemma-4-26b-a4b-it\": { id: \"workers-ai/@cf/google/gemma-4-26b-a4b-it\", name: \"Gemma 4 26B A4B IT\", api: \"openai-completions\", provider: \"cloudflare-ai-gateway\", baseUrl: \"https://gateway.ai.cloudflare.com/v1/{CLOUDFLARE_ACCOUNT_ID}/{CLOUDFLARE_GATEWAY_ID}/compat\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.1, output: 0.3, cacheRead: 0, cacheWrite: 0 }, contextWindow: 256e3, maxTokens: 16384, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false, maxTokensField: \"max_tokens\", supportsStrictMode: false, supportsLongCacheRetention: false, sendSessionAffinityHeaders: true } }, \"workers-ai/@cf/ibm-granite/granite-4.0-h-micro\": { id: \"workers-ai/@cf/ibm-granite/granite-4.0-h-micro\", name: \"Granite 4.0 H Micro\", api: \"openai-completions\", provider: \"cloudflare-ai-gateway\", baseUrl: \"https://gateway.ai.cloudflare.com/v1/{CLOUDFLARE_ACCOUNT_ID}/{CLOUDFLARE_GATEWAY_ID}/compat\", reasoning: false, input: [\"text\"], cost: { input: 0.017, output: 0.112, cacheRead: 0, cacheWrite: 0 }, contextWindow: 131e3, maxTokens: 131e3, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false, maxTokensField: \"max_tokens\", supportsStrictMode: false, supportsLongCacheRetention: false, sendSessionAffinityHeaders: true } }, \"workers-ai/@cf/meta/llama-3.3-70b-instruct-fp8-fast\": { id: \"workers-ai/@cf/meta/llama-3.3-70b-instruct-fp8-fast\", name: \"Llama 3.3 70B Instruct fp8 Fast\", api: \"openai-completions\", provider: \"cloudflare-ai-gateway\", baseUrl: \"https://gateway.ai.cloudflare.com/v1/{CLOUDFLARE_ACCOUNT_ID}/{CLOUDFLARE_GATEWAY_ID}/compat\", reasoning: false, input: [\"text\"], cost: { input: 0.293, output: 2.253, cacheRead: 0, cacheWrite: 0 }, contextWindow: 24e3, maxTokens: 24e3, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false, maxTokensField: \"max_tokens\", supportsStrictMode: false, supportsLongCacheRetention: false, sendSessionAffinityHeaders: true } }, \"workers-ai/@cf/meta/llama-4-scout-17b-16e-instruct\": { id: \"workers-ai/@cf/meta/llama-4-scout-17b-16e-instruct\", name: \"Llama 4 Scout 17B 16E Instruct\", api: \"openai-completions\", provider: \"cloudflare-ai-gateway\", baseUrl: \"https://gateway.ai.cloudflare.com/v1/{CLOUDFLARE_ACCOUNT_ID}/{CLOUDFLARE_GATEWAY_ID}/compat\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 0.27, output: 0.85, cacheRead: 0, cacheWrite: 0 }, contextWindow: 131e3, maxTokens: 16384, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false, maxTokensField: \"max_tokens\", supportsStrictMode: false, supportsLongCacheRetention: false, sendSessionAffinityHeaders: true } }, \"workers-ai/@cf/mistralai/mistral-small-3.1-24b-instruct\": { id: \"workers-ai/@cf/mistralai/mistral-small-3.1-24b-instruct\", name: \"Mistral Small 3.1 24B Instruct\", api: \"openai-completions\", provider: \"cloudflare-ai-gateway\", baseUrl: \"https://gateway.ai.cloudflare.com/v1/{CLOUDFLARE_ACCOUNT_ID}/{CLOUDFLARE_GATEWAY_ID}/compat\", reasoning: false, input: [\"text\"], cost: { input: 0.351, output: 0.555, cacheRead: 0, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 128e3, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false, maxTokensField: \"max_tokens\", supportsStrictMode: false, supportsLongCacheRetention: false, sendSessionAffinityHeaders: true } }, \"workers-ai/@cf/moonshotai/kimi-k2.6\": { id: \"workers-ai/@cf/moonshotai/kimi-k2.6\", name: \"Kimi K2.6\", api: \"openai-completions\", provider: \"cloudflare-ai-gateway\", baseUrl: \"https://gateway.ai.cloudflare.com/v1/{CLOUDFLARE_ACCOUNT_ID}/{CLOUDFLARE_GATEWAY_ID}/compat\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.95, output: 4, cacheRead: 0.16, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 256e3, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false, maxTokensField: \"max_tokens\", supportsStrictMode: false, supportsLongCacheRetention: false, sendSessionAffinityHeaders: true } }, \"workers-ai/@cf/moonshotai/kimi-k2.7-code\": { id: \"workers-ai/@cf/moonshotai/kimi-k2.7-code\", name: \"Kimi K2.7 Code\", api: \"openai-completions\", provider: \"cloudflare-ai-gateway\", baseUrl: \"https://gateway.ai.cloudflare.com/v1/{CLOUDFLARE_ACCOUNT_ID}/{CLOUDFLARE_GATEWAY_ID}/compat\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.95, output: 4, cacheRead: 0.19, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 262144, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false, maxTokensField: \"max_tokens\", supportsStrictMode: false, supportsLongCacheRetention: false, sendSessionAffinityHeaders: true } }, \"workers-ai/@cf/nvidia/nemotron-3-120b-a12b\": { id: \"workers-ai/@cf/nvidia/nemotron-3-120b-a12b\", name: \"Nemotron 3 Super 120B\", api: \"openai-completions\", provider: \"cloudflare-ai-gateway\", baseUrl: \"https://gateway.ai.cloudflare.com/v1/{CLOUDFLARE_ACCOUNT_ID}/{CLOUDFLARE_GATEWAY_ID}/compat\", reasoning: true, input: [\"text\"], cost: { input: 0.5, output: 1.5, cacheRead: 0, cacheWrite: 0 }, contextWindow: 256e3, maxTokens: 256e3, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false, maxTokensField: \"max_tokens\", supportsStrictMode: false, supportsLongCacheRetention: false, sendSessionAffinityHeaders: true } }, \"workers-ai/@cf/openai/gpt-oss-120b\": { id: \"workers-ai/@cf/openai/gpt-oss-120b\", name: \"GPT OSS 120B\", api: \"openai-completions\", provider: \"cloudflare-ai-gateway\", baseUrl: \"https://gateway.ai.cloudflare.com/v1/{CLOUDFLARE_ACCOUNT_ID}/{CLOUDFLARE_GATEWAY_ID}/compat\", reasoning: true, input: [\"text\"], cost: { input: 0.35, output: 0.75, cacheRead: 0, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 16384, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false, maxTokensField: \"max_tokens\", supportsStrictMode: false, supportsLongCacheRetention: false, sendSessionAffinityHeaders: true } }, \"workers-ai/@cf/openai/gpt-oss-20b\": { id: \"workers-ai/@cf/openai/gpt-oss-20b\", name: \"GPT OSS 20B\", api: \"openai-completions\", provider: \"cloudflare-ai-gateway\", baseUrl: \"https://gateway.ai.cloudflare.com/v1/{CLOUDFLARE_ACCOUNT_ID}/{CLOUDFLARE_GATEWAY_ID}/compat\", reasoning: true, input: [\"text\"], cost: { input: 0.2, output: 0.3, cacheRead: 0, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 16384, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false, maxTokensField: \"max_tokens\", supportsStrictMode: false, supportsLongCacheRetention: false, sendSessionAffinityHeaders: true } }, \"workers-ai/@cf/qwen/qwen3-30b-a3b-fp8\": { id: \"workers-ai/@cf/qwen/qwen3-30b-a3b-fp8\", name: \"Qwen3 30B A3b fp8\", api: \"openai-completions\", provider: \"cloudflare-ai-gateway\", baseUrl: \"https://gateway.ai.cloudflare.com/v1/{CLOUDFLARE_ACCOUNT_ID}/{CLOUDFLARE_GATEWAY_ID}/compat\", reasoning: true, input: [\"text\"], cost: { input: 0.0509, output: 0.335, cacheRead: 0, cacheWrite: 0 }, contextWindow: 32768, maxTokens: 32768, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false, maxTokensField: \"max_tokens\", supportsStrictMode: false, supportsLongCacheRetention: false, sendSessionAffinityHeaders: true } }, \"workers-ai/@cf/zai-org/glm-4.7-flash\": { id: \"workers-ai/@cf/zai-org/glm-4.7-flash\", name: \"GLM-4.7-Flash\", api: \"openai-completions\", provider: \"cloudflare-ai-gateway\", baseUrl: \"https://gateway.ai.cloudflare.com/v1/{CLOUDFLARE_ACCOUNT_ID}/{CLOUDFLARE_GATEWAY_ID}/compat\", reasoning: true, input: [\"text\"], cost: { input: 0.0605, output: 0.4, cacheRead: 0, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 131072, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false, maxTokensField: \"max_tokens\", supportsStrictMode: false, supportsLongCacheRetention: false, sendSessionAffinityHeaders: true } }, \"workers-ai/@cf/zai-org/glm-5.2\": { id: \"workers-ai/@cf/zai-org/glm-5.2\", name: \"Glm 5.2\", api: \"openai-completions\", provider: \"cloudflare-ai-gateway\", baseUrl: \"https://gateway.ai.cloudflare.com/v1/{CLOUDFLARE_ACCOUNT_ID}/{CLOUDFLARE_GATEWAY_ID}/compat\", reasoning: true, input: [\"text\"], cost: { input: 1.4, output: 4.4, cacheRead: 0.26, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 256e3, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false, maxTokensField: \"max_tokens\", supportsStrictMode: false, supportsLongCacheRetention: false, sendSessionAffinityHeaders: true } } }, \"openai-responses\": { \"gpt-4\": { id: \"gpt-4\", name: \"GPT-4\", api: \"openai-responses\", provider: \"cloudflare-ai-gateway\", baseUrl: \"https://gateway.ai.cloudflare.com/v1/{CLOUDFLARE_ACCOUNT_ID}/{CLOUDFLARE_GATEWAY_ID}/openai\", reasoning: false, input: [\"text\"], cost: { input: 30, output: 60, cacheRead: 0, cacheWrite: 0 }, contextWindow: 8192, maxTokens: 8192, compat: { supportsStrictMode: true } }, \"gpt-4-turbo\": { id: \"gpt-4-turbo\", name: \"GPT-4 Turbo\", api: \"openai-responses\", provider: \"cloudflare-ai-gateway\", baseUrl: \"https://gateway.ai.cloudflare.com/v1/{CLOUDFLARE_ACCOUNT_ID}/{CLOUDFLARE_GATEWAY_ID}/openai\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 10, output: 30, cacheRead: 0, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 4096, compat: { supportsStrictMode: true } }, \"gpt-4.1\": { id: \"gpt-4.1\", name: \"GPT-4.1\", api: \"openai-responses\", provider: \"cloudflare-ai-gateway\", baseUrl: \"https://gateway.ai.cloudflare.com/v1/{CLOUDFLARE_ACCOUNT_ID}/{CLOUDFLARE_GATEWAY_ID}/openai\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 2, output: 8, cacheRead: 0.5, cacheWrite: 0 }, contextWindow: 1047576, maxTokens: 32768, compat: { supportsStrictMode: true } }, \"gpt-4.1-mini\": { id: \"gpt-4.1-mini\", name: \"GPT-4.1 mini\", api: \"openai-responses\", provider: \"cloudflare-ai-gateway\", baseUrl: \"https://gateway.ai.cloudflare.com/v1/{CLOUDFLARE_ACCOUNT_ID}/{CLOUDFLARE_GATEWAY_ID}/openai\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 0.4, output: 1.6, cacheRead: 0.1, cacheWrite: 0 }, contextWindow: 1047576, maxTokens: 32768, compat: { supportsStrictMode: true } }, \"gpt-4.1-nano\": { id: \"gpt-4.1-nano\", name: \"GPT-4.1 nano\", api: \"openai-responses\", provider: \"cloudflare-ai-gateway\", baseUrl: \"https://gateway.ai.cloudflare.com/v1/{CLOUDFLARE_ACCOUNT_ID}/{CLOUDFLARE_GATEWAY_ID}/openai\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 0.1, output: 0.4, cacheRead: 0.025, cacheWrite: 0 }, contextWindow: 1047576, maxTokens: 32768, compat: { supportsStrictMode: true } }, \"gpt-4o\": { id: \"gpt-4o\", name: \"GPT-4o\", api: \"openai-responses\", provider: \"cloudflare-ai-gateway\", baseUrl: \"https://gateway.ai.cloudflare.com/v1/{CLOUDFLARE_ACCOUNT_ID}/{CLOUDFLARE_GATEWAY_ID}/openai\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 2.5, output: 10, cacheRead: 1.25, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 16384, compat: { supportsStrictMode: true } }, \"gpt-4o-mini\": { id: \"gpt-4o-mini\", name: \"GPT-4o mini\", api: \"openai-responses\", provider: \"cloudflare-ai-gateway\", baseUrl: \"https://gateway.ai.cloudflare.com/v1/{CLOUDFLARE_ACCOUNT_ID}/{CLOUDFLARE_GATEWAY_ID}/openai\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 0.15, output: 0.6, cacheRead: 0.075, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 16384, compat: { supportsStrictMode: true } }, \"gpt-5\": { id: \"gpt-5\", name: \"GPT-5\", api: \"openai-responses\", provider: \"cloudflare-ai-gateway\", baseUrl: \"https://gateway.ai.cloudflare.com/v1/{CLOUDFLARE_ACCOUNT_ID}/{CLOUDFLARE_GATEWAY_ID}/openai\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.25, output: 10, cacheRead: 0.125, cacheWrite: 0 }, contextWindow: 4e5, maxTokens: 128e3, thinkingLevelMap: { off: null, minimal: \"minimal\", low: \"low\", medium: \"medium\", high: \"high\", xhigh: null, max: null }, compat: { supportsStrictMode: true, supportsOpenAIGrammarTools: true } }, \"gpt-5-mini\": { id: \"gpt-5-mini\", name: \"GPT-5 Mini\", api: \"openai-responses\", provider: \"cloudflare-ai-gateway\", baseUrl: \"https://gateway.ai.cloudflare.com/v1/{CLOUDFLARE_ACCOUNT_ID}/{CLOUDFLARE_GATEWAY_ID}/openai\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.25, output: 2, cacheRead: 0.025, cacheWrite: 0 }, contextWindow: 4e5, maxTokens: 128e3, thinkingLevelMap: { off: null, minimal: \"minimal\", low: \"low\", medium: \"medium\", high: \"high\", xhigh: null, max: null }, compat: { supportsStrictMode: true, supportsOpenAIGrammarTools: true } }, \"gpt-5-nano\": { id: \"gpt-5-nano\", name: \"GPT-5 Nano\", api: \"openai-responses\", provider: \"cloudflare-ai-gateway\", baseUrl: \"https://gateway.ai.cloudflare.com/v1/{CLOUDFLARE_ACCOUNT_ID}/{CLOUDFLARE_GATEWAY_ID}/openai\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.05, output: 0.4, cacheRead: 5e-3, cacheWrite: 0 }, contextWindow: 4e5, maxTokens: 128e3, thinkingLevelMap: { off: null, minimal: \"minimal\", low: \"low\", medium: \"medium\", high: \"high\", xhigh: null, max: null }, compat: { supportsStrictMode: true, supportsOpenAIGrammarTools: true } }, \"gpt-5-pro\": { id: \"gpt-5-pro\", name: \"GPT-5 Pro\", api: \"openai-responses\", provider: \"cloudflare-ai-gateway\", baseUrl: \"https://gateway.ai.cloudflare.com/v1/{CLOUDFLARE_ACCOUNT_ID}/{CLOUDFLARE_GATEWAY_ID}/openai\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 15, output: 120, cacheRead: 0, cacheWrite: 0 }, contextWindow: 4e5, maxTokens: 272e3, thinkingLevelMap: { off: null, minimal: null, low: null, medium: null, high: \"high\", xhigh: null, max: null }, compat: { supportsStrictMode: true, supportsOpenAIGrammarTools: true } }, \"gpt-5.1\": { id: \"gpt-5.1\", name: \"GPT-5.1\", api: \"openai-responses\", provider: \"cloudflare-ai-gateway\", baseUrl: \"https://gateway.ai.cloudflare.com/v1/{CLOUDFLARE_ACCOUNT_ID}/{CLOUDFLARE_GATEWAY_ID}/openai\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.25, output: 10, cacheRead: 0.125, cacheWrite: 0 }, contextWindow: 4e5, maxTokens: 128e3, thinkingLevelMap: { off: null, minimal: null, low: \"low\", medium: \"medium\", high: \"high\", xhigh: null, max: null }, compat: { supportsStrictMode: true, supportsOpenAIGrammarTools: true } }, \"gpt-5.2\": { id: \"gpt-5.2\", name: \"GPT-5.2\", api: \"openai-responses\", provider: \"cloudflare-ai-gateway\", baseUrl: \"https://gateway.ai.cloudflare.com/v1/{CLOUDFLARE_ACCOUNT_ID}/{CLOUDFLARE_GATEWAY_ID}/openai\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.75, output: 14, cacheRead: 0.175, cacheWrite: 0 }, contextWindow: 4e5, maxTokens: 128e3, thinkingLevelMap: { off: null, minimal: null, low: \"low\", medium: \"medium\", high: \"high\", xhigh: \"xhigh\", max: null }, compat: { supportsStrictMode: true, supportsOpenAIGrammarTools: true } }, \"gpt-5.2-chat-latest\": { id: \"gpt-5.2-chat-latest\", name: \"GPT-5.2 Chat\", api: \"openai-responses\", provider: \"cloudflare-ai-gateway\", baseUrl: \"https://gateway.ai.cloudflare.com/v1/{CLOUDFLARE_ACCOUNT_ID}/{CLOUDFLARE_GATEWAY_ID}/openai\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.75, output: 14, cacheRead: 0.175, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 16384, thinkingLevelMap: { off: null, minimal: null, low: null, medium: \"medium\", high: null, xhigh: \"xhigh\", max: null }, compat: { supportsStrictMode: true, supportsOpenAIGrammarTools: true } }, \"gpt-5.2-pro\": { id: \"gpt-5.2-pro\", name: \"GPT-5.2 Pro\", api: \"openai-responses\", provider: \"cloudflare-ai-gateway\", baseUrl: \"https://gateway.ai.cloudflare.com/v1/{CLOUDFLARE_ACCOUNT_ID}/{CLOUDFLARE_GATEWAY_ID}/openai\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 21, output: 168, cacheRead: 0, cacheWrite: 0 }, contextWindow: 4e5, maxTokens: 128e3, thinkingLevelMap: { off: null, minimal: null, low: null, medium: \"medium\", high: \"high\", xhigh: \"xhigh\", max: null }, compat: { supportsStrictMode: true, supportsOpenAIGrammarTools: true } }, \"gpt-5.3-chat-latest\": { id: \"gpt-5.3-chat-latest\", name: \"GPT-5.3 Chat (latest)\", api: \"openai-responses\", provider: \"cloudflare-ai-gateway\", baseUrl: \"https://gateway.ai.cloudflare.com/v1/{CLOUDFLARE_ACCOUNT_ID}/{CLOUDFLARE_GATEWAY_ID}/openai\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 1.75, output: 14, cacheRead: 0.175, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 16384, thinkingLevelMap: { off: null, xhigh: \"xhigh\" }, compat: { supportsStrictMode: true, supportsOpenAIGrammarTools: true } }, \"gpt-5.3-codex\": { id: \"gpt-5.3-codex\", name: \"GPT-5.3 Codex\", api: \"openai-responses\", provider: \"cloudflare-ai-gateway\", baseUrl: \"https://gateway.ai.cloudflare.com/v1/{CLOUDFLARE_ACCOUNT_ID}/{CLOUDFLARE_GATEWAY_ID}/openai\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.75, output: 14, cacheRead: 0.175, cacheWrite: 0 }, contextWindow: 4e5, maxTokens: 128e3, thinkingLevelMap: { off: null, minimal: null, low: \"low\", medium: \"medium\", high: \"high\", xhigh: \"xhigh\", max: null }, compat: { supportsStrictMode: true, supportsOpenAIGrammarTools: true } }, \"gpt-5.3-codex-spark\": { id: \"gpt-5.3-codex-spark\", name: \"GPT-5.3 Codex Spark\", api: \"openai-responses\", provider: \"cloudflare-ai-gateway\", baseUrl: \"https://gateway.ai.cloudflare.com/v1/{CLOUDFLARE_ACCOUNT_ID}/{CLOUDFLARE_GATEWAY_ID}/openai\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.75, output: 14, cacheRead: 0.175, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 32e3, thinkingLevelMap: { off: null, minimal: null, low: \"low\", medium: \"medium\", high: \"high\", xhigh: \"xhigh\", max: null }, compat: { supportsStrictMode: true, supportsOpenAIGrammarTools: true } }, \"gpt-5.4\": { id: \"gpt-5.4\", name: \"GPT-5.4\", api: \"openai-responses\", provider: \"cloudflare-ai-gateway\", baseUrl: \"https://gateway.ai.cloudflare.com/v1/{CLOUDFLARE_ACCOUNT_ID}/{CLOUDFLARE_GATEWAY_ID}/openai\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 2.5, output: 15, cacheRead: 0.25, cacheWrite: 0 }, contextWindow: 105e4, maxTokens: 128e3, thinkingLevelMap: { off: null, minimal: null, low: \"low\", medium: \"medium\", high: \"high\", xhigh: \"xhigh\", max: null }, compat: { supportsStrictMode: true, supportsOpenAIGrammarTools: true } }, \"gpt-5.4-mini\": { id: \"gpt-5.4-mini\", name: \"GPT-5.4 mini\", api: \"openai-responses\", provider: \"cloudflare-ai-gateway\", baseUrl: \"https://gateway.ai.cloudflare.com/v1/{CLOUDFLARE_ACCOUNT_ID}/{CLOUDFLARE_GATEWAY_ID}/openai\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.75, output: 4.5, cacheRead: 0.075, cacheWrite: 0 }, contextWindow: 4e5, maxTokens: 128e3, thinkingLevelMap: { off: null, minimal: null, low: \"low\", medium: \"medium\", high: \"high\", xhigh: \"xhigh\", max: null }, compat: { supportsStrictMode: true, supportsOpenAIGrammarTools: true } }, \"gpt-5.4-nano\": { id: \"gpt-5.4-nano\", name: \"GPT-5.4 nano\", api: \"openai-responses\", provider: \"cloudflare-ai-gateway\", baseUrl: \"https://gateway.ai.cloudflare.com/v1/{CLOUDFLARE_ACCOUNT_ID}/{CLOUDFLARE_GATEWAY_ID}/openai\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.2, output: 1.25, cacheRead: 0.02, cacheWrite: 0 }, contextWindow: 4e5, maxTokens: 128e3, thinkingLevelMap: { off: null, minimal: null, low: \"low\", medium: \"medium\", high: \"high\", xhigh: \"xhigh\", max: null }, compat: { supportsStrictMode: true, supportsOpenAIGrammarTools: true } }, \"gpt-5.4-pro\": { id: \"gpt-5.4-pro\", name: \"GPT-5.4 Pro\", api: \"openai-responses\", provider: \"cloudflare-ai-gateway\", baseUrl: \"https://gateway.ai.cloudflare.com/v1/{CLOUDFLARE_ACCOUNT_ID}/{CLOUDFLARE_GATEWAY_ID}/openai\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 30, output: 180, cacheRead: 0, cacheWrite: 0 }, contextWindow: 105e4, maxTokens: 128e3, thinkingLevelMap: { off: null, minimal: null, low: null, medium: \"medium\", high: \"high\", xhigh: \"xhigh\", max: null }, compat: { supportsStrictMode: true, supportsOpenAIGrammarTools: true } }, \"gpt-5.5\": { id: \"gpt-5.5\", name: \"GPT-5.5\", api: \"openai-responses\", provider: \"cloudflare-ai-gateway\", baseUrl: \"https://gateway.ai.cloudflare.com/v1/{CLOUDFLARE_ACCOUNT_ID}/{CLOUDFLARE_GATEWAY_ID}/openai\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 5, output: 30, cacheRead: 0.5, cacheWrite: 0 }, contextWindow: 105e4, maxTokens: 128e3, thinkingLevelMap: { off: null, minimal: null, low: \"low\", medium: \"medium\", high: \"high\", xhigh: \"xhigh\", max: null }, compat: { supportsStrictMode: true, supportsOpenAIGrammarTools: true } }, \"gpt-5.5-pro\": { id: \"gpt-5.5-pro\", name: \"GPT-5.5 Pro\", api: \"openai-responses\", provider: \"cloudflare-ai-gateway\", baseUrl: \"https://gateway.ai.cloudflare.com/v1/{CLOUDFLARE_ACCOUNT_ID}/{CLOUDFLARE_GATEWAY_ID}/openai\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 30, output: 180, cacheRead: 0, cacheWrite: 0 }, contextWindow: 105e4, maxTokens: 128e3, thinkingLevelMap: { off: null, minimal: null, low: null, medium: \"medium\", high: \"high\", xhigh: \"xhigh\", max: null }, compat: { supportsStrictMode: true, supportsOpenAIGrammarTools: true } }, \"gpt-5.6\": { id: \"gpt-5.6\", name: \"GPT-5.6\", api: \"openai-responses\", provider: \"cloudflare-ai-gateway\", baseUrl: \"https://gateway.ai.cloudflare.com/v1/{CLOUDFLARE_ACCOUNT_ID}/{CLOUDFLARE_GATEWAY_ID}/openai\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 5, output: 30, cacheRead: 0.5, cacheWrite: 6.25 }, contextWindow: 105e4, maxTokens: 128e3, thinkingLevelMap: { off: null, minimal: null, low: \"low\", medium: \"medium\", high: \"high\", xhigh: \"xhigh\", max: \"max\" }, compat: { supportsStrictMode: true, supportsOpenAIGrammarTools: true } }, \"gpt-5.6-luna\": { id: \"gpt-5.6-luna\", name: \"GPT-5.6 Luna\", api: \"openai-responses\", provider: \"cloudflare-ai-gateway\", baseUrl: \"https://gateway.ai.cloudflare.com/v1/{CLOUDFLARE_ACCOUNT_ID}/{CLOUDFLARE_GATEWAY_ID}/openai\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.2, output: 1.2, cacheRead: 0.02, cacheWrite: 0.25, tiers: [{ inputTokensAbove: 272e3, input: 0.4, output: 1.8, cacheRead: 0.04, cacheWrite: 0.5 }] }, contextWindow: 105e4, maxTokens: 128e3, thinkingLevelMap: { off: null, minimal: null, low: \"low\", medium: \"medium\", high: \"high\", xhigh: \"xhigh\", max: \"max\" }, compat: { supportsStrictMode: true, supportsOpenAIGrammarTools: true } }, \"gpt-5.6-sol\": { id: \"gpt-5.6-sol\", name: \"GPT-5.6 Sol\", api: \"openai-responses\", provider: \"cloudflare-ai-gateway\", baseUrl: \"https://gateway.ai.cloudflare.com/v1/{CLOUDFLARE_ACCOUNT_ID}/{CLOUDFLARE_GATEWAY_ID}/openai\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 5, output: 30, cacheRead: 0.5, cacheWrite: 6.25 }, contextWindow: 105e4, maxTokens: 128e3, thinkingLevelMap: { off: null, minimal: null, low: \"low\", medium: \"medium\", high: \"high\", xhigh: \"xhigh\", max: \"max\" }, compat: { supportsStrictMode: true, supportsOpenAIGrammarTools: true } }, \"gpt-5.6-terra\": { id: \"gpt-5.6-terra\", name: \"GPT-5.6 Terra\", api: \"openai-responses\", provider: \"cloudflare-ai-gateway\", baseUrl: \"https://gateway.ai.cloudflare.com/v1/{CLOUDFLARE_ACCOUNT_ID}/{CLOUDFLARE_GATEWAY_ID}/openai\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 2, output: 12, cacheRead: 0.2, cacheWrite: 2.5, tiers: [{ inputTokensAbove: 272e3, input: 4, output: 18, cacheRead: 0.4, cacheWrite: 5 }] }, contextWindow: 105e4, maxTokens: 128e3, thinkingLevelMap: { off: null, minimal: null, low: \"low\", medium: \"medium\", high: \"high\", xhigh: \"xhigh\", max: \"max\" }, compat: { supportsStrictMode: true, supportsOpenAIGrammarTools: true } }, o1: { id: \"o1\", name: \"o1\", api: \"openai-responses\", provider: \"cloudflare-ai-gateway\", baseUrl: \"https://gateway.ai.cloudflare.com/v1/{CLOUDFLARE_ACCOUNT_ID}/{CLOUDFLARE_GATEWAY_ID}/openai\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 15, output: 60, cacheRead: 7.5, cacheWrite: 0 }, contextWindow: 2e5, maxTokens: 1e5, thinkingLevelMap: { off: null, minimal: null, low: \"low\", medium: \"medium\", high: \"high\", xhigh: null, max: null }, compat: { supportsStrictMode: true } }, \"o1-pro\": { id: \"o1-pro\", name: \"o1-pro\", api: \"openai-responses\", provider: \"cloudflare-ai-gateway\", baseUrl: \"https://gateway.ai.cloudflare.com/v1/{CLOUDFLARE_ACCOUNT_ID}/{CLOUDFLARE_GATEWAY_ID}/openai\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 150, output: 600, cacheRead: 0, cacheWrite: 0 }, contextWindow: 2e5, maxTokens: 1e5, thinkingLevelMap: { off: null, minimal: null, low: \"low\", medium: \"medium\", high: \"high\", xhigh: null, max: null }, compat: { supportsStrictMode: true } }, o3: { id: \"o3\", name: \"o3\", api: \"openai-responses\", provider: \"cloudflare-ai-gateway\", baseUrl: \"https://gateway.ai.cloudflare.com/v1/{CLOUDFLARE_ACCOUNT_ID}/{CLOUDFLARE_GATEWAY_ID}/openai\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 2, output: 8, cacheRead: 0.5, cacheWrite: 0 }, contextWindow: 2e5, maxTokens: 1e5, thinkingLevelMap: { off: null, minimal: null, low: \"low\", medium: \"medium\", high: \"high\", xhigh: null, max: null }, compat: { supportsStrictMode: true } }, \"o3-mini\": { id: \"o3-mini\", name: \"o3-mini\", api: \"openai-responses\", provider: \"cloudflare-ai-gateway\", baseUrl: \"https://gateway.ai.cloudflare.com/v1/{CLOUDFLARE_ACCOUNT_ID}/{CLOUDFLARE_GATEWAY_ID}/openai\", reasoning: true, input: [\"text\"], cost: { input: 1.1, output: 4.4, cacheRead: 0.55, cacheWrite: 0 }, contextWindow: 2e5, maxTokens: 1e5, thinkingLevelMap: { off: null, minimal: null, low: \"low\", medium: \"medium\", high: \"high\", xhigh: null, max: null }, compat: { supportsStrictMode: true } }, \"o3-pro\": { id: \"o3-pro\", name: \"o3-pro\", api: \"openai-responses\", provider: \"cloudflare-ai-gateway\", baseUrl: \"https://gateway.ai.cloudflare.com/v1/{CLOUDFLARE_ACCOUNT_ID}/{CLOUDFLARE_GATEWAY_ID}/openai\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 20, output: 80, cacheRead: 0, cacheWrite: 0 }, contextWindow: 2e5, maxTokens: 1e5, thinkingLevelMap: { off: null, minimal: null, low: \"low\", medium: \"medium\", high: \"high\", xhigh: null, max: null }, compat: { supportsStrictMode: true } }, \"o4-mini\": { id: \"o4-mini\", name: \"o4-mini\", api: \"openai-responses\", provider: \"cloudflare-ai-gateway\", baseUrl: \"https://gateway.ai.cloudflare.com/v1/{CLOUDFLARE_ACCOUNT_ID}/{CLOUDFLARE_GATEWAY_ID}/openai\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.1, output: 4.4, cacheRead: 0.275, cacheWrite: 0 }, contextWindow: 2e5, maxTokens: 1e5, thinkingLevelMap: { off: null, minimal: null, low: \"low\", medium: \"medium\", high: \"high\", xhigh: null, max: null }, compat: { supportsStrictMode: true } } } };\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/cloudflare-ai-gateway.models.js\nvar CLOUDFLARE_AI_GATEWAY_MODELS = flattenModelCatalog(\"cloudflare-ai-gateway\", cloudflare_ai_gateway_default);\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/data/cloudflare-workers-ai.json\nvar cloudflare_workers_ai_default = { \"openai-completions\": { \"@cf/google/gemma-4-26b-a4b-it\": { id: \"@cf/google/gemma-4-26b-a4b-it\", name: \"Gemma 4 26B A4B IT\", api: \"openai-completions\", provider: \"cloudflare-workers-ai\", baseUrl: \"https://api.cloudflare.com/client/v4/accounts/{CLOUDFLARE_ACCOUNT_ID}/ai/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.1, output: 0.3, cacheRead: 0, cacheWrite: 0 }, contextWindow: 256e3, maxTokens: 16384, compat: { supportsStore: false, supportsDeveloperRole: false, supportsLongCacheRetention: false, sendSessionAffinityHeaders: true }, thinkingLevelMap: { off: null, minimal: null, low: \"low\", medium: \"medium\", high: \"high\", xhigh: null, max: null } }, \"@cf/ibm-granite/granite-4.0-h-micro\": { id: \"@cf/ibm-granite/granite-4.0-h-micro\", name: \"Granite 4.0 H Micro\", api: \"openai-completions\", provider: \"cloudflare-workers-ai\", baseUrl: \"https://api.cloudflare.com/client/v4/accounts/{CLOUDFLARE_ACCOUNT_ID}/ai/v1\", reasoning: false, input: [\"text\"], cost: { input: 0.017, output: 0.112, cacheRead: 0, cacheWrite: 0 }, contextWindow: 131e3, maxTokens: 131e3, compat: { supportsStore: false, supportsDeveloperRole: false, supportsLongCacheRetention: false, sendSessionAffinityHeaders: true } }, \"@cf/meta/llama-3.3-70b-instruct-fp8-fast\": { id: \"@cf/meta/llama-3.3-70b-instruct-fp8-fast\", name: \"Llama 3.3 70B Instruct fp8 Fast\", api: \"openai-completions\", provider: \"cloudflare-workers-ai\", baseUrl: \"https://api.cloudflare.com/client/v4/accounts/{CLOUDFLARE_ACCOUNT_ID}/ai/v1\", reasoning: false, input: [\"text\"], cost: { input: 0.293, output: 2.253, cacheRead: 0, cacheWrite: 0 }, contextWindow: 24e3, maxTokens: 24e3, compat: { supportsStore: false, supportsDeveloperRole: false, supportsLongCacheRetention: false, sendSessionAffinityHeaders: true } }, \"@cf/meta/llama-4-scout-17b-16e-instruct\": { id: \"@cf/meta/llama-4-scout-17b-16e-instruct\", name: \"Llama 4 Scout 17B 16E Instruct\", api: \"openai-completions\", provider: \"cloudflare-workers-ai\", baseUrl: \"https://api.cloudflare.com/client/v4/accounts/{CLOUDFLARE_ACCOUNT_ID}/ai/v1\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 0.27, output: 0.85, cacheRead: 0, cacheWrite: 0 }, contextWindow: 131e3, maxTokens: 16384, compat: { supportsStore: false, supportsDeveloperRole: false, supportsLongCacheRetention: false, sendSessionAffinityHeaders: true } }, \"@cf/mistralai/mistral-small-3.1-24b-instruct\": { id: \"@cf/mistralai/mistral-small-3.1-24b-instruct\", name: \"Mistral Small 3.1 24B Instruct\", api: \"openai-completions\", provider: \"cloudflare-workers-ai\", baseUrl: \"https://api.cloudflare.com/client/v4/accounts/{CLOUDFLARE_ACCOUNT_ID}/ai/v1\", reasoning: false, input: [\"text\"], cost: { input: 0.351, output: 0.555, cacheRead: 0, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 128e3, compat: { supportsStore: false, supportsDeveloperRole: false, supportsLongCacheRetention: false, sendSessionAffinityHeaders: true } }, \"@cf/moonshotai/kimi-k2.6\": { id: \"@cf/moonshotai/kimi-k2.6\", name: \"Kimi K2.6\", api: \"openai-completions\", provider: \"cloudflare-workers-ai\", baseUrl: \"https://api.cloudflare.com/client/v4/accounts/{CLOUDFLARE_ACCOUNT_ID}/ai/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.95, output: 4, cacheRead: 0.16, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 256e3, compat: { supportsStore: false, supportsDeveloperRole: false, supportsLongCacheRetention: false, sendSessionAffinityHeaders: true }, thinkingLevelMap: { off: null, minimal: null, low: \"low\", medium: \"medium\", high: \"high\", xhigh: null, max: null } }, \"@cf/moonshotai/kimi-k2.7-code\": { id: \"@cf/moonshotai/kimi-k2.7-code\", name: \"Kimi K2.7 Code\", api: \"openai-completions\", provider: \"cloudflare-workers-ai\", baseUrl: \"https://api.cloudflare.com/client/v4/accounts/{CLOUDFLARE_ACCOUNT_ID}/ai/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.95, output: 4, cacheRead: 0.19, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 262144, compat: { supportsStore: false, supportsDeveloperRole: false, supportsLongCacheRetention: false, sendSessionAffinityHeaders: true }, thinkingLevelMap: { off: null, minimal: null, low: \"low\", medium: \"medium\", high: \"high\", xhigh: null, max: null } }, \"@cf/nvidia/nemotron-3-120b-a12b\": { id: \"@cf/nvidia/nemotron-3-120b-a12b\", name: \"Nemotron 3 Super 120B\", api: \"openai-completions\", provider: \"cloudflare-workers-ai\", baseUrl: \"https://api.cloudflare.com/client/v4/accounts/{CLOUDFLARE_ACCOUNT_ID}/ai/v1\", reasoning: true, input: [\"text\"], cost: { input: 0.5, output: 1.5, cacheRead: 0, cacheWrite: 0 }, contextWindow: 256e3, maxTokens: 256e3, compat: { supportsStore: false, supportsDeveloperRole: false, supportsLongCacheRetention: false, sendSessionAffinityHeaders: true }, thinkingLevelMap: { off: null, minimal: null, low: \"low\", medium: \"medium\", high: \"high\", xhigh: null, max: null } }, \"@cf/openai/gpt-oss-120b\": { id: \"@cf/openai/gpt-oss-120b\", name: \"GPT OSS 120B\", api: \"openai-completions\", provider: \"cloudflare-workers-ai\", baseUrl: \"https://api.cloudflare.com/client/v4/accounts/{CLOUDFLARE_ACCOUNT_ID}/ai/v1\", reasoning: true, input: [\"text\"], cost: { input: 0.35, output: 0.75, cacheRead: 0, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 16384, compat: { supportsStore: false, supportsDeveloperRole: false, supportsLongCacheRetention: false, sendSessionAffinityHeaders: true }, thinkingLevelMap: { off: null, minimal: null, low: \"low\", medium: \"medium\", high: \"high\", xhigh: null, max: null } }, \"@cf/openai/gpt-oss-20b\": { id: \"@cf/openai/gpt-oss-20b\", name: \"GPT OSS 20B\", api: \"openai-completions\", provider: \"cloudflare-workers-ai\", baseUrl: \"https://api.cloudflare.com/client/v4/accounts/{CLOUDFLARE_ACCOUNT_ID}/ai/v1\", reasoning: true, input: [\"text\"], cost: { input: 0.2, output: 0.3, cacheRead: 0, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 16384, compat: { supportsStore: false, supportsDeveloperRole: false, supportsLongCacheRetention: false, sendSessionAffinityHeaders: true } }, \"@cf/qwen/qwen3-30b-a3b-fp8\": { id: \"@cf/qwen/qwen3-30b-a3b-fp8\", name: \"Qwen3 30B A3b fp8\", api: \"openai-completions\", provider: \"cloudflare-workers-ai\", baseUrl: \"https://api.cloudflare.com/client/v4/accounts/{CLOUDFLARE_ACCOUNT_ID}/ai/v1\", reasoning: true, input: [\"text\"], cost: { input: 0.0509, output: 0.335, cacheRead: 0, cacheWrite: 0 }, contextWindow: 32768, maxTokens: 32768, compat: { supportsStore: false, supportsDeveloperRole: false, supportsLongCacheRetention: false, sendSessionAffinityHeaders: true } }, \"@cf/zai-org/glm-4.7-flash\": { id: \"@cf/zai-org/glm-4.7-flash\", name: \"GLM-4.7-Flash\", api: \"openai-completions\", provider: \"cloudflare-workers-ai\", baseUrl: \"https://api.cloudflare.com/client/v4/accounts/{CLOUDFLARE_ACCOUNT_ID}/ai/v1\", reasoning: true, input: [\"text\"], cost: { input: 0.0605, output: 0.4, cacheRead: 0, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 131072, compat: { supportsStore: false, supportsDeveloperRole: false, supportsLongCacheRetention: false, sendSessionAffinityHeaders: true }, thinkingLevelMap: { off: null, minimal: null, low: \"low\", medium: \"medium\", high: \"high\", xhigh: null, max: null } }, \"@cf/zai-org/glm-5.2\": { id: \"@cf/zai-org/glm-5.2\", name: \"Glm 5.2\", api: \"openai-completions\", provider: \"cloudflare-workers-ai\", baseUrl: \"https://api.cloudflare.com/client/v4/accounts/{CLOUDFLARE_ACCOUNT_ID}/ai/v1\", reasoning: true, input: [\"text\"], cost: { input: 1.4, output: 4.4, cacheRead: 0.26, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 256e3, compat: { supportsStore: false, supportsDeveloperRole: false, supportsLongCacheRetention: false, sendSessionAffinityHeaders: true }, thinkingLevelMap: { off: null, minimal: null, low: \"low\", medium: \"medium\", high: \"high\", xhigh: null, max: null } } } };\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/cloudflare-workers-ai.models.js\nvar CLOUDFLARE_WORKERS_AI_MODELS = flattenModelCatalog(\"cloudflare-workers-ai\", cloudflare_workers_ai_default);\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/data/deepseek.json\nvar deepseek_default = { \"openai-completions\": { \"deepseek-v4-flash\": { id: \"deepseek-v4-flash\", name: \"DeepSeek V4 Flash\", api: \"openai-completions\", baseUrl: \"https://api.deepseek.com\", provider: \"deepseek\", reasoning: true, input: [\"text\"], cost: { input: 0.14, output: 0.28, cacheRead: 28e-4, cacheWrite: 0 }, contextWindow: 1e6, maxTokens: 384e3, compat: { supportsStore: false, supportsDeveloperRole: false, maxTokensField: \"max_tokens\", requiresReasoningContentOnAssistantMessages: true, thinkingFormat: \"deepseek\" }, thinkingLevelMap: { minimal: null, low: \"low\", medium: null, high: \"high\", max: \"max\" } }, \"deepseek-v4-pro\": { id: \"deepseek-v4-pro\", name: \"DeepSeek V4 Pro\", api: \"openai-completions\", baseUrl: \"https://api.deepseek.com\", provider: \"deepseek\", reasoning: true, input: [\"text\"], cost: { input: 0.435, output: 0.87, cacheRead: 3625e-6, cacheWrite: 0 }, contextWindow: 1e6, maxTokens: 384e3, compat: { supportsStore: false, supportsDeveloperRole: false, maxTokensField: \"max_tokens\", requiresReasoningContentOnAssistantMessages: true, thinkingFormat: \"deepseek\" }, thinkingLevelMap: { minimal: null, low: null, medium: null, high: \"high\", max: \"max\" } } } };\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/deepseek.models.js\nvar DEEPSEEK_MODELS = flattenModelCatalog(\"deepseek\", deepseek_default);\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/data/fireworks.json\nvar fireworks_default = { \"anthropic-messages\": { \"accounts/fireworks/models/deepseek-v4-flash\": { id: \"accounts/fireworks/models/deepseek-v4-flash\", name: \"DeepSeek V4 Flash\", provider: \"fireworks\", reasoning: true, input: [\"text\"], cost: { input: 0.14, output: 0.28, cacheRead: 0.028, cacheWrite: 0 }, contextWindow: 1e6, maxTokens: 384e3, api: \"anthropic-messages\", baseUrl: \"https://api.fireworks.ai/inference\", compat: { sendSessionAffinityHeaders: true, supportsEagerToolInputStreaming: false, supportsCacheControlOnTools: false, supportsLongCacheRetention: false } }, \"accounts/fireworks/models/deepseek-v4-flash-0731\": { id: \"accounts/fireworks/models/deepseek-v4-flash-0731\", name: \"DeepSeek V4 Flash 0731\", provider: \"fireworks\", reasoning: true, input: [\"text\"], cost: { input: 0.14, output: 0.28, cacheRead: 0.028, cacheWrite: 0 }, contextWindow: 1e6, maxTokens: 384e3, api: \"anthropic-messages\", baseUrl: \"https://api.fireworks.ai/inference\", compat: { sendSessionAffinityHeaders: true, supportsEagerToolInputStreaming: false, supportsCacheControlOnTools: false, supportsLongCacheRetention: false } }, \"accounts/fireworks/models/deepseek-v4-pro\": { id: \"accounts/fireworks/models/deepseek-v4-pro\", name: \"DeepSeek V4 Pro\", provider: \"fireworks\", reasoning: true, input: [\"text\"], cost: { input: 1.74, output: 3.48, cacheRead: 0.145, cacheWrite: 0 }, contextWindow: 1e6, maxTokens: 384e3, api: \"anthropic-messages\", baseUrl: \"https://api.fireworks.ai/inference\", compat: { sendSessionAffinityHeaders: true, supportsEagerToolInputStreaming: false, supportsCacheControlOnTools: false, supportsLongCacheRetention: false } }, \"accounts/fireworks/models/deepseek-v4-pro-0813\": { id: \"accounts/fireworks/models/deepseek-v4-pro-0813\", name: \"DeepSeek V4 Pro 0813\", provider: \"fireworks\", reasoning: true, input: [\"text\"], cost: { input: 1.32, output: 3.96, cacheRead: 0.044, cacheWrite: 0 }, contextWindow: 1e6, maxTokens: 384e3, api: \"anthropic-messages\", baseUrl: \"https://api.fireworks.ai/inference\", compat: { sendSessionAffinityHeaders: true, supportsEagerToolInputStreaming: false, supportsCacheControlOnTools: false, supportsLongCacheRetention: false } }, \"accounts/fireworks/models/gpt-oss-120b\": { id: \"accounts/fireworks/models/gpt-oss-120b\", name: \"GPT OSS 120B\", provider: \"fireworks\", reasoning: true, input: [\"text\"], cost: { input: 0.15, output: 0.6, cacheRead: 0.015, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 32768, api: \"anthropic-messages\", baseUrl: \"https://api.fireworks.ai/inference\", compat: { sendSessionAffinityHeaders: true, supportsEagerToolInputStreaming: false, supportsCacheControlOnTools: false, supportsLongCacheRetention: false } }, \"accounts/fireworks/models/gpt-oss-20b\": { id: \"accounts/fireworks/models/gpt-oss-20b\", name: \"GPT OSS 20B\", provider: \"fireworks\", reasoning: true, input: [\"text\"], cost: { input: 0.07, output: 0.3, cacheRead: 0.035, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 32768, api: \"anthropic-messages\", baseUrl: \"https://api.fireworks.ai/inference\", compat: { sendSessionAffinityHeaders: true, supportsEagerToolInputStreaming: false, supportsCacheControlOnTools: false, supportsLongCacheRetention: false } }, \"accounts/fireworks/models/inkling\": { id: \"accounts/fireworks/models/inkling\", name: \"Inkling\", provider: \"fireworks\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1, output: 4.05, cacheRead: 0.17, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 1048576, api: \"anthropic-messages\", baseUrl: \"https://api.fireworks.ai/inference\", compat: { sendSessionAffinityHeaders: true, supportsEagerToolInputStreaming: false, supportsCacheControlOnTools: false, supportsLongCacheRetention: false } }, \"accounts/fireworks/models/kimi-k2p6\": { id: \"accounts/fireworks/models/kimi-k2p6\", name: \"Kimi K2.6\", provider: \"fireworks\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.95, output: 4, cacheRead: 0.16, cacheWrite: 0 }, contextWindow: 262e3, maxTokens: 262e3, api: \"anthropic-messages\", baseUrl: \"https://api.fireworks.ai/inference\", compat: { sendSessionAffinityHeaders: true, supportsEagerToolInputStreaming: false, supportsCacheControlOnTools: false, supportsLongCacheRetention: false } }, \"accounts/fireworks/models/kimi-k2p7-code\": { id: \"accounts/fireworks/models/kimi-k2p7-code\", name: \"Kimi K2.7 Code\", provider: \"fireworks\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.95, output: 4, cacheRead: 0.19, cacheWrite: 0 }, contextWindow: 262e3, maxTokens: 262e3, api: \"anthropic-messages\", baseUrl: \"https://api.fireworks.ai/inference\", compat: { sendSessionAffinityHeaders: true, supportsEagerToolInputStreaming: false, supportsCacheControlOnTools: false, supportsLongCacheRetention: false } }, \"accounts/fireworks/models/minimax-m2p7\": { id: \"accounts/fireworks/models/minimax-m2p7\", name: \"MiniMax-M2.7\", provider: \"fireworks\", reasoning: true, input: [\"text\"], cost: { input: 0.3, output: 1.2, cacheRead: 0.06, cacheWrite: 0 }, contextWindow: 196608, maxTokens: 196608, api: \"anthropic-messages\", baseUrl: \"https://api.fireworks.ai/inference\", compat: { sendSessionAffinityHeaders: true, supportsEagerToolInputStreaming: false, supportsCacheControlOnTools: false, supportsLongCacheRetention: false } }, \"accounts/fireworks/models/minimax-m3\": { id: \"accounts/fireworks/models/minimax-m3\", name: \"MiniMax-M3\", provider: \"fireworks\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.3, output: 1.2, cacheRead: 0.06, cacheWrite: 0 }, contextWindow: 512e3, maxTokens: 512e3, api: \"anthropic-messages\", baseUrl: \"https://api.fireworks.ai/inference\", compat: { sendSessionAffinityHeaders: true, supportsEagerToolInputStreaming: false, supportsCacheControlOnTools: false, supportsLongCacheRetention: false } }, \"accounts/fireworks/models/muse-glimmer-30b\": { id: \"accounts/fireworks/models/muse-glimmer-30b\", name: \"Muse Glimmer 30B\", provider: \"fireworks\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.35, output: 1.5, cacheRead: 0.04, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 131072, api: \"anthropic-messages\", baseUrl: \"https://api.fireworks.ai/inference\", compat: { sendSessionAffinityHeaders: true, supportsEagerToolInputStreaming: false, supportsCacheControlOnTools: false, supportsLongCacheRetention: false } }, \"accounts/fireworks/models/nemotron-3-ultra-nvfp4\": { id: \"accounts/fireworks/models/nemotron-3-ultra-nvfp4\", name: \"Nemotron 3 Ultra 550B A55B\", provider: \"fireworks\", reasoning: true, input: [\"text\"], cost: { input: 0.6, output: 2.4, cacheRead: 0.119, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 128e3, api: \"anthropic-messages\", baseUrl: \"https://api.fireworks.ai/inference\", compat: { sendSessionAffinityHeaders: true, supportsEagerToolInputStreaming: false, supportsCacheControlOnTools: false, supportsLongCacheRetention: false } }, \"accounts/fireworks/models/nemotron-lightning-3p5-30b-a3b\": { id: \"accounts/fireworks/models/nemotron-lightning-3p5-30b-a3b\", name: \"Nemotron 3.5 Lightning 30B A3B\", provider: \"fireworks\", reasoning: true, input: [\"text\"], cost: { input: 0.05, output: 0.2, cacheRead: 0.01, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 262144, api: \"anthropic-messages\", baseUrl: \"https://api.fireworks.ai/inference\", compat: { sendSessionAffinityHeaders: true, supportsEagerToolInputStreaming: false, supportsCacheControlOnTools: false, supportsLongCacheRetention: false } }, \"accounts/fireworks/models/qwen3p7-plus\": { id: \"accounts/fireworks/models/qwen3p7-plus\", name: \"Qwen 3.7 Plus\", provider: \"fireworks\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.4, output: 1.6, cacheRead: 0.08, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 65536, api: \"anthropic-messages\", baseUrl: \"https://api.fireworks.ai/inference\", compat: { sendSessionAffinityHeaders: true, supportsEagerToolInputStreaming: false, supportsCacheControlOnTools: false, supportsLongCacheRetention: false } }, \"accounts/fireworks/models/qwen3p8-max\": { id: \"accounts/fireworks/models/qwen3p8-max\", name: \"Qwen3.8 Max\", provider: \"fireworks\", reasoning: true, input: [\"text\"], cost: { input: 2, output: 6, cacheRead: 0.25, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 131072, api: \"anthropic-messages\", baseUrl: \"https://api.fireworks.ai/inference\", compat: { sendSessionAffinityHeaders: true, supportsEagerToolInputStreaming: false, supportsCacheControlOnTools: false, supportsLongCacheRetention: false } }, \"accounts/fireworks/routers/kimi-k2p6-fast\": { id: \"accounts/fireworks/routers/kimi-k2p6-fast\", name: \"Kimi K2.6 Fast\", provider: \"fireworks\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 2, output: 8, cacheRead: 0.3, cacheWrite: 0 }, contextWindow: 262e3, maxTokens: 262e3, api: \"anthropic-messages\", baseUrl: \"https://api.fireworks.ai/inference\", compat: { sendSessionAffinityHeaders: true, supportsEagerToolInputStreaming: false, supportsCacheControlOnTools: false, supportsLongCacheRetention: false } }, \"accounts/fireworks/routers/kimi-k2p6-turbo\": { id: \"accounts/fireworks/routers/kimi-k2p6-turbo\", name: \"Kimi K2.6 Turbo\", provider: \"fireworks\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 2, output: 8, cacheRead: 0.3, cacheWrite: 0 }, contextWindow: 262e3, maxTokens: 262e3, api: \"anthropic-messages\", baseUrl: \"https://api.fireworks.ai/inference\", compat: { sendSessionAffinityHeaders: true, supportsEagerToolInputStreaming: false, supportsCacheControlOnTools: false, supportsLongCacheRetention: false } }, \"accounts/fireworks/routers/kimi-k2p7-code-fast\": { id: \"accounts/fireworks/routers/kimi-k2p7-code-fast\", name: \"Kimi K2.7 Code Fast\", provider: \"fireworks\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.9, output: 8, cacheRead: 0.38, cacheWrite: 0 }, contextWindow: 262e3, maxTokens: 262e3, api: \"anthropic-messages\", baseUrl: \"https://api.fireworks.ai/inference\", compat: { sendSessionAffinityHeaders: true, supportsEagerToolInputStreaming: false, supportsCacheControlOnTools: false, supportsLongCacheRetention: false } } }, \"openai-completions\": { \"accounts/fireworks/models/glm-5p2\": { id: \"accounts/fireworks/models/glm-5p2\", name: \"GLM 5.2\", provider: \"fireworks\", reasoning: true, input: [\"text\"], cost: { input: 1.4, output: 4.4, cacheRead: 0.14, cacheWrite: 0 }, contextWindow: 1048575, maxTokens: 131072, api: \"openai-completions\", baseUrl: \"https://api.fireworks.ai/inference/v1\", compat: { supportsStore: false, supportsDeveloperRole: false, sendSessionAffinityHeaders: true, supportsLongCacheRetention: false }, thinkingLevelMap: { off: \"none\", minimal: null, low: \"high\", medium: \"high\", high: \"high\", xhigh: null, max: \"max\" } }, \"accounts/fireworks/models/kimi-k3\": { id: \"accounts/fireworks/models/kimi-k3\", name: \"Kimi K3\", provider: \"fireworks\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 131072, api: \"openai-completions\", baseUrl: \"https://api.fireworks.ai/inference/v1\", compat: { supportsStore: false, supportsDeveloperRole: false, sendSessionAffinityHeaders: true, supportsLongCacheRetention: false, requiresReasoningContentOnAssistantMessages: true, thinkingFormat: \"openai\", deferredToolsMode: \"kimi\" }, thinkingLevelMap: { off: null, minimal: null, low: \"low\", medium: \"medium\", high: \"high\", xhigh: null, max: \"max\" } }, \"accounts/fireworks/routers/glm-5p2-fast\": { id: \"accounts/fireworks/routers/glm-5p2-fast\", name: \"GLM 5.2 Fast\", provider: \"fireworks\", reasoning: true, input: [\"text\"], cost: { input: 2.1, output: 6.6, cacheRead: 0.21, cacheWrite: 0 }, contextWindow: 1048575, maxTokens: 131072, api: \"openai-completions\", baseUrl: \"https://api.fireworks.ai/inference/v1\", compat: { supportsStore: false, supportsDeveloperRole: false, sendSessionAffinityHeaders: true, supportsLongCacheRetention: false }, thinkingLevelMap: { off: \"none\", minimal: null, low: \"high\", medium: \"high\", high: \"high\", xhigh: null, max: \"max\" } }, \"accounts/fireworks/routers/kimi-k3-fast\": { id: \"accounts/fireworks/routers/kimi-k3-fast\", name: \"Kimi K3 Fast\", provider: \"fireworks\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 4.5, output: 22.5, cacheRead: 0.45, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 131072, api: \"openai-completions\", baseUrl: \"https://api.fireworks.ai/inference/v1\", compat: { supportsStore: false, supportsDeveloperRole: false, sendSessionAffinityHeaders: true, supportsLongCacheRetention: false, requiresReasoningContentOnAssistantMessages: true, thinkingFormat: \"openai\", deferredToolsMode: \"kimi\" }, thinkingLevelMap: { off: null, minimal: null, low: \"low\", medium: \"medium\", high: \"high\", xhigh: null, max: \"max\" } } } };\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/fireworks.models.js\nvar FIREWORKS_MODELS = flattenModelCatalog(\"fireworks\", fireworks_default);\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/data/github-copilot.json\nvar github_copilot_default = { \"anthropic-messages\": { \"claude-haiku-4.5\": { id: \"claude-haiku-4.5\", name: \"Claude Haiku 4.5 (latest)\", api: \"anthropic-messages\", provider: \"github-copilot\", baseUrl: \"https://api.individual.githubcopilot.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1, output: 5, cacheRead: 0.1, cacheWrite: 1.25 }, contextWindow: 2e5, maxTokens: 64e3, headers: { \"User-Agent\": \"GitHubCopilotChat/0.35.0\", \"Editor-Version\": \"vscode/1.107.0\", \"Editor-Plugin-Version\": \"copilot-chat/0.35.0\", \"Copilot-Integration-Id\": \"vscode-chat\" }, compat: { supportsEagerToolInputStreaming: false } }, \"claude-opus-4.5\": { id: \"claude-opus-4.5\", name: \"Claude Opus 4.5 (latest)\", api: \"anthropic-messages\", provider: \"github-copilot\", baseUrl: \"https://api.individual.githubcopilot.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 }, contextWindow: 2e5, maxTokens: 32e3, headers: { \"User-Agent\": \"GitHubCopilotChat/0.35.0\", \"Editor-Version\": \"vscode/1.107.0\", \"Editor-Plugin-Version\": \"copilot-chat/0.35.0\", \"Copilot-Integration-Id\": \"vscode-chat\" } }, \"claude-opus-4.6\": { id: \"claude-opus-4.6\", name: \"Claude Opus 4.6\", api: \"anthropic-messages\", provider: \"github-copilot\", baseUrl: \"https://api.individual.githubcopilot.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 }, contextWindow: 1e6, maxTokens: 32e3, headers: { \"User-Agent\": \"GitHubCopilotChat/0.35.0\", \"Editor-Version\": \"vscode/1.107.0\", \"Editor-Plugin-Version\": \"copilot-chat/0.35.0\", \"Copilot-Integration-Id\": \"vscode-chat\" }, thinkingLevelMap: { max: \"max\" }, compat: { forceAdaptiveThinking: true } }, \"claude-opus-4.7\": { id: \"claude-opus-4.7\", name: \"Claude Opus 4.7\", api: \"anthropic-messages\", provider: \"github-copilot\", baseUrl: \"https://api.individual.githubcopilot.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 }, contextWindow: 1e6, maxTokens: 32e3, headers: { \"User-Agent\": \"GitHubCopilotChat/0.35.0\", \"Editor-Version\": \"vscode/1.107.0\", \"Editor-Plugin-Version\": \"copilot-chat/0.35.0\", \"Copilot-Integration-Id\": \"vscode-chat\" }, thinkingLevelMap: { xhigh: \"xhigh\", max: \"max\", minimal: \"low\" }, compat: { forceAdaptiveThinking: true, supportsTemperature: false } }, \"claude-opus-4.8\": { id: \"claude-opus-4.8\", name: \"Claude Opus 4.8\", api: \"anthropic-messages\", provider: \"github-copilot\", baseUrl: \"https://api.individual.githubcopilot.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 }, contextWindow: 1e6, maxTokens: 64e3, headers: { \"User-Agent\": \"GitHubCopilotChat/0.35.0\", \"Editor-Version\": \"vscode/1.107.0\", \"Editor-Plugin-Version\": \"copilot-chat/0.35.0\", \"Copilot-Integration-Id\": \"vscode-chat\" }, thinkingLevelMap: { xhigh: \"xhigh\", max: \"max\", minimal: \"low\" }, compat: { forceAdaptiveThinking: true, supportsTemperature: false } }, \"claude-opus-5\": { id: \"claude-opus-5\", name: \"Claude Opus 5\", api: \"anthropic-messages\", provider: \"github-copilot\", baseUrl: \"https://api.individual.githubcopilot.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 }, contextWindow: 1e6, maxTokens: 64e3, headers: { \"User-Agent\": \"GitHubCopilotChat/0.35.0\", \"Editor-Version\": \"vscode/1.107.0\", \"Editor-Plugin-Version\": \"copilot-chat/0.35.0\", \"Copilot-Integration-Id\": \"vscode-chat\" }, thinkingLevelMap: { xhigh: \"xhigh\", max: \"max\", minimal: \"low\" }, compat: { forceAdaptiveThinking: true, supportsTemperature: false } }, \"claude-sonnet-4\": { id: \"claude-sonnet-4\", name: \"Claude Sonnet 4 (latest)\", api: \"anthropic-messages\", provider: \"github-copilot\", baseUrl: \"https://api.individual.githubcopilot.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3.75 }, contextWindow: 216e3, maxTokens: 16e3, headers: { \"User-Agent\": \"GitHubCopilotChat/0.35.0\", \"Editor-Version\": \"vscode/1.107.0\", \"Editor-Plugin-Version\": \"copilot-chat/0.35.0\", \"Copilot-Integration-Id\": \"vscode-chat\" }, compat: { supportsEagerToolInputStreaming: false } }, \"claude-sonnet-4.5\": { id: \"claude-sonnet-4.5\", name: \"Claude Sonnet 4.5 (latest)\", api: \"anthropic-messages\", provider: \"github-copilot\", baseUrl: \"https://api.individual.githubcopilot.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3.75 }, contextWindow: 2e5, maxTokens: 32e3, headers: { \"User-Agent\": \"GitHubCopilotChat/0.35.0\", \"Editor-Version\": \"vscode/1.107.0\", \"Editor-Plugin-Version\": \"copilot-chat/0.35.0\", \"Copilot-Integration-Id\": \"vscode-chat\" }, compat: { supportsEagerToolInputStreaming: false } }, \"claude-sonnet-4.6\": { id: \"claude-sonnet-4.6\", name: \"Claude Sonnet 4.6\", api: \"anthropic-messages\", provider: \"github-copilot\", baseUrl: \"https://api.individual.githubcopilot.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3.75 }, contextWindow: 1e6, maxTokens: 32e3, headers: { \"User-Agent\": \"GitHubCopilotChat/0.35.0\", \"Editor-Version\": \"vscode/1.107.0\", \"Editor-Plugin-Version\": \"copilot-chat/0.35.0\", \"Copilot-Integration-Id\": \"vscode-chat\" }, thinkingLevelMap: { max: \"max\", minimal: \"low\" }, compat: { forceAdaptiveThinking: true } }, \"claude-sonnet-5\": { id: \"claude-sonnet-5\", name: \"Claude Sonnet 5\", api: \"anthropic-messages\", provider: \"github-copilot\", baseUrl: \"https://api.individual.githubcopilot.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 2, output: 10, cacheRead: 0.2, cacheWrite: 2.5 }, contextWindow: 1e6, maxTokens: 128e3, headers: { \"User-Agent\": \"GitHubCopilotChat/0.35.0\", \"Editor-Version\": \"vscode/1.107.0\", \"Editor-Plugin-Version\": \"copilot-chat/0.35.0\", \"Copilot-Integration-Id\": \"vscode-chat\" }, thinkingLevelMap: { xhigh: \"xhigh\", max: \"max\" }, compat: { forceAdaptiveThinking: true } } }, \"openai-completions\": { \"claude-fable-5\": { id: \"claude-fable-5\", name: \"Claude Fable 5\", api: \"openai-completions\", provider: \"github-copilot\", baseUrl: \"https://api.individual.githubcopilot.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 10, output: 50, cacheRead: 1, cacheWrite: 12.5 }, contextWindow: 1e6, maxTokens: 128e3, headers: { \"User-Agent\": \"GitHubCopilotChat/0.35.0\", \"Editor-Version\": \"vscode/1.107.0\", \"Editor-Plugin-Version\": \"copilot-chat/0.35.0\", \"Copilot-Integration-Id\": \"vscode-chat\" }, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false }, thinkingLevelMap: { off: null, xhigh: \"xhigh\", max: \"max\" } }, \"gemini-3.1-pro-preview\": { id: \"gemini-3.1-pro-preview\", name: \"Gemini 3.1 Pro Preview\", api: \"openai-completions\", provider: \"github-copilot\", baseUrl: \"https://api.individual.githubcopilot.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 2, output: 12, cacheRead: 0.2, cacheWrite: 0, tiers: [{ inputTokensAbove: 2e5, input: 4, output: 18, cacheRead: 0.4, cacheWrite: 0 }] }, contextWindow: 1e6, maxTokens: 64e3, headers: { \"User-Agent\": \"GitHubCopilotChat/0.35.0\", \"Editor-Version\": \"vscode/1.107.0\", \"Editor-Plugin-Version\": \"copilot-chat/0.35.0\", \"Copilot-Integration-Id\": \"vscode-chat\" }, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false } }, \"gemini-3.5-flash\": { id: \"gemini-3.5-flash\", name: \"Gemini 3.5 Flash\", api: \"openai-completions\", provider: \"github-copilot\", baseUrl: \"https://api.individual.githubcopilot.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.5, output: 9, cacheRead: 0.15, cacheWrite: 0 }, contextWindow: 2e5, maxTokens: 64e3, headers: { \"User-Agent\": \"GitHubCopilotChat/0.35.0\", \"Editor-Version\": \"vscode/1.107.0\", \"Editor-Plugin-Version\": \"copilot-chat/0.35.0\", \"Copilot-Integration-Id\": \"vscode-chat\" }, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false } }, \"gemini-3.6-flash\": { id: \"gemini-3.6-flash\", name: \"Gemini 3.6 Flash\", api: \"openai-completions\", provider: \"github-copilot\", baseUrl: \"https://api.individual.githubcopilot.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.5, output: 7.5, cacheRead: 0.15, cacheWrite: 0 }, contextWindow: 1e6, maxTokens: 64e3, headers: { \"User-Agent\": \"GitHubCopilotChat/0.35.0\", \"Editor-Version\": \"vscode/1.107.0\", \"Editor-Plugin-Version\": \"copilot-chat/0.35.0\", \"Copilot-Integration-Id\": \"vscode-chat\" }, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false } }, \"gemini-3.7-flash\": { id: \"gemini-3.7-flash\", name: \"Gemini 3.7 Flash\", api: \"openai-completions\", provider: \"github-copilot\", baseUrl: \"https://api.individual.githubcopilot.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.75, output: 3.75, cacheRead: 0.075, cacheWrite: 0 }, contextWindow: 1e6, maxTokens: 64e3, headers: { \"User-Agent\": \"GitHubCopilotChat/0.35.0\", \"Editor-Version\": \"vscode/1.107.0\", \"Editor-Plugin-Version\": \"copilot-chat/0.35.0\", \"Copilot-Integration-Id\": \"vscode-chat\" }, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false } }, \"gpt-4.1\": { id: \"gpt-4.1\", name: \"GPT-4.1\", api: \"openai-completions\", provider: \"github-copilot\", baseUrl: \"https://api.individual.githubcopilot.com\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 2, output: 8, cacheRead: 0.5, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 16384, headers: { \"User-Agent\": \"GitHubCopilotChat/0.35.0\", \"Editor-Version\": \"vscode/1.107.0\", \"Editor-Plugin-Version\": \"copilot-chat/0.35.0\", \"Copilot-Integration-Id\": \"vscode-chat\" }, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false } }, \"kimi-k2.7-code\": { id: \"kimi-k2.7-code\", name: \"Kimi K2.7 Code\", api: \"openai-completions\", provider: \"github-copilot\", baseUrl: \"https://api.individual.githubcopilot.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.95, output: 4, cacheRead: 0.19, cacheWrite: 0 }, contextWindow: 256e3, maxTokens: 32e3, headers: { \"User-Agent\": \"GitHubCopilotChat/0.35.0\", \"Editor-Version\": \"vscode/1.107.0\", \"Editor-Plugin-Version\": \"copilot-chat/0.35.0\", \"Copilot-Integration-Id\": \"vscode-chat\" }, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false } }, \"kimi-k3\": { id: \"kimi-k3\", name: \"Kimi K3\", api: \"openai-completions\", provider: \"github-copilot\", baseUrl: \"https://api.individual.githubcopilot.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 131072, headers: { \"User-Agent\": \"GitHubCopilotChat/0.35.0\", \"Editor-Version\": \"vscode/1.107.0\", \"Editor-Plugin-Version\": \"copilot-chat/0.35.0\", \"Copilot-Integration-Id\": \"vscode-chat\" }, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false } } }, \"openai-responses\": { \"gpt-5-mini\": { id: \"gpt-5-mini\", name: \"GPT-5 Mini\", api: \"openai-responses\", provider: \"github-copilot\", baseUrl: \"https://api.individual.githubcopilot.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.25, output: 2, cacheRead: 0.025, cacheWrite: 0 }, contextWindow: 264e3, maxTokens: 64e3, headers: { \"User-Agent\": \"GitHubCopilotChat/0.35.0\", \"Editor-Version\": \"vscode/1.107.0\", \"Editor-Plugin-Version\": \"copilot-chat/0.35.0\", \"Copilot-Integration-Id\": \"vscode-chat\" }, thinkingLevelMap: { off: null, minimal: \"low\", low: \"low\", medium: \"medium\", high: \"high\", xhigh: null, max: null }, compat: { supportsOpenAIGrammarTools: true } }, \"gpt-5.2\": { id: \"gpt-5.2\", name: \"GPT-5.2\", api: \"openai-responses\", provider: \"github-copilot\", baseUrl: \"https://api.individual.githubcopilot.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.75, output: 14, cacheRead: 0.175, cacheWrite: 0 }, contextWindow: 4e5, maxTokens: 128e3, headers: { \"User-Agent\": \"GitHubCopilotChat/0.35.0\", \"Editor-Version\": \"vscode/1.107.0\", \"Editor-Plugin-Version\": \"copilot-chat/0.35.0\", \"Copilot-Integration-Id\": \"vscode-chat\" }, thinkingLevelMap: { off: null, minimal: \"low\", xhigh: \"xhigh\" }, compat: { supportsOpenAIGrammarTools: true } }, \"gpt-5.2-codex\": { id: \"gpt-5.2-codex\", name: \"GPT-5.2 Codex\", api: \"openai-responses\", provider: \"github-copilot\", baseUrl: \"https://api.individual.githubcopilot.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.75, output: 14, cacheRead: 0.175, cacheWrite: 0 }, contextWindow: 4e5, maxTokens: 128e3, headers: { \"User-Agent\": \"GitHubCopilotChat/0.35.0\", \"Editor-Version\": \"vscode/1.107.0\", \"Editor-Plugin-Version\": \"copilot-chat/0.35.0\", \"Copilot-Integration-Id\": \"vscode-chat\" }, thinkingLevelMap: { off: null, minimal: \"low\", xhigh: \"xhigh\" }, compat: { supportsOpenAIGrammarTools: true } }, \"gpt-5.3-codex\": { id: \"gpt-5.3-codex\", name: \"GPT-5.3 Codex\", api: \"openai-responses\", provider: \"github-copilot\", baseUrl: \"https://api.individual.githubcopilot.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.75, output: 14, cacheRead: 0.175, cacheWrite: 0 }, contextWindow: 1e6, maxTokens: 128e3, headers: { \"User-Agent\": \"GitHubCopilotChat/0.35.0\", \"Editor-Version\": \"vscode/1.107.0\", \"Editor-Plugin-Version\": \"copilot-chat/0.35.0\", \"Copilot-Integration-Id\": \"vscode-chat\" }, thinkingLevelMap: { off: null, minimal: \"low\", low: \"low\", medium: \"medium\", high: \"high\", xhigh: \"xhigh\", max: null }, compat: { supportsOpenAIGrammarTools: true } }, \"gpt-5.4\": { id: \"gpt-5.4\", name: \"GPT-5.4\", api: \"openai-responses\", provider: \"github-copilot\", baseUrl: \"https://api.individual.githubcopilot.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 2.5, output: 15, cacheRead: 0.25, cacheWrite: 0, tiers: [{ inputTokensAbove: 272e3, input: 5, output: 22.5, cacheRead: 0.5, cacheWrite: 0 }] }, contextWindow: 1e6, maxTokens: 128e3, headers: { \"User-Agent\": \"GitHubCopilotChat/0.35.0\", \"Editor-Version\": \"vscode/1.107.0\", \"Editor-Plugin-Version\": \"copilot-chat/0.35.0\", \"Copilot-Integration-Id\": \"vscode-chat\" }, thinkingLevelMap: { off: null, minimal: \"low\", low: \"low\", medium: \"medium\", high: \"high\", xhigh: \"xhigh\", max: null }, compat: { supportsOpenAIGrammarTools: true } }, \"gpt-5.4-mini\": { id: \"gpt-5.4-mini\", name: \"GPT-5.4 mini\", api: \"openai-responses\", provider: \"github-copilot\", baseUrl: \"https://api.individual.githubcopilot.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.75, output: 4.5, cacheRead: 0.075, cacheWrite: 0 }, contextWindow: 4e5, maxTokens: 128e3, headers: { \"User-Agent\": \"GitHubCopilotChat/0.35.0\", \"Editor-Version\": \"vscode/1.107.0\", \"Editor-Plugin-Version\": \"copilot-chat/0.35.0\", \"Copilot-Integration-Id\": \"vscode-chat\" }, thinkingLevelMap: { off: null, minimal: \"low\", low: \"low\", medium: \"medium\", high: \"high\", xhigh: \"xhigh\", max: null }, compat: { supportsOpenAIGrammarTools: true } }, \"gpt-5.4-nano\": { id: \"gpt-5.4-nano\", name: \"GPT-5.4 nano\", api: \"openai-responses\", provider: \"github-copilot\", baseUrl: \"https://api.individual.githubcopilot.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.2, output: 1.25, cacheRead: 0.02, cacheWrite: 0 }, contextWindow: 4e5, maxTokens: 128e3, headers: { \"User-Agent\": \"GitHubCopilotChat/0.35.0\", \"Editor-Version\": \"vscode/1.107.0\", \"Editor-Plugin-Version\": \"copilot-chat/0.35.0\", \"Copilot-Integration-Id\": \"vscode-chat\" }, thinkingLevelMap: { off: null, minimal: \"low\", xhigh: \"xhigh\" }, compat: { supportsOpenAIGrammarTools: true } }, \"gpt-5.5\": { id: \"gpt-5.5\", name: \"GPT-5.5\", api: \"openai-responses\", provider: \"github-copilot\", baseUrl: \"https://api.individual.githubcopilot.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 5, output: 30, cacheRead: 0.5, cacheWrite: 0, tiers: [{ inputTokensAbove: 272e3, input: 10, output: 45, cacheRead: 1, cacheWrite: 0 }] }, contextWindow: 1e6, maxTokens: 128e3, headers: { \"User-Agent\": \"GitHubCopilotChat/0.35.0\", \"Editor-Version\": \"vscode/1.107.0\", \"Editor-Plugin-Version\": \"copilot-chat/0.35.0\", \"Copilot-Integration-Id\": \"vscode-chat\" }, thinkingLevelMap: { off: null, minimal: \"low\", low: \"low\", medium: \"medium\", high: \"high\", xhigh: \"xhigh\", max: null }, compat: { supportsOpenAIGrammarTools: true } }, \"gpt-5.6-luna\": { id: \"gpt-5.6-luna\", name: \"GPT-5.6 Luna\", api: \"openai-responses\", provider: \"github-copilot\", baseUrl: \"https://api.individual.githubcopilot.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.2, output: 1.2, cacheRead: 0.02, cacheWrite: 0, tiers: [{ inputTokensAbove: 2e5, input: 0.4, output: 1.8, cacheRead: 0.04, cacheWrite: 0 }] }, contextWindow: 105e4, maxTokens: 128e3, headers: { \"User-Agent\": \"GitHubCopilotChat/0.35.0\", \"Editor-Version\": \"vscode/1.107.0\", \"Editor-Plugin-Version\": \"copilot-chat/0.35.0\", \"Copilot-Integration-Id\": \"vscode-chat\" }, thinkingLevelMap: { off: null, minimal: \"low\", low: \"low\", medium: \"medium\", high: \"high\", xhigh: \"xhigh\", max: \"max\" }, compat: { supportsOpenAIGrammarTools: true } }, \"gpt-5.6-sol\": { id: \"gpt-5.6-sol\", name: \"GPT-5.6 Sol\", api: \"openai-responses\", provider: \"github-copilot\", baseUrl: \"https://api.individual.githubcopilot.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 5, output: 30, cacheRead: 0.5, cacheWrite: 6.25, tiers: [{ inputTokensAbove: 272e3, input: 10, output: 45, cacheRead: 1, cacheWrite: 12.5 }] }, contextWindow: 105e4, maxTokens: 128e3, headers: { \"User-Agent\": \"GitHubCopilotChat/0.35.0\", \"Editor-Version\": \"vscode/1.107.0\", \"Editor-Plugin-Version\": \"copilot-chat/0.35.0\", \"Copilot-Integration-Id\": \"vscode-chat\" }, thinkingLevelMap: { off: null, minimal: \"low\", low: \"low\", medium: \"medium\", high: \"high\", xhigh: \"xhigh\", max: \"max\" }, compat: { supportsOpenAIGrammarTools: true } }, \"gpt-5.6-terra\": { id: \"gpt-5.6-terra\", name: \"GPT-5.6 Terra\", api: \"openai-responses\", provider: \"github-copilot\", baseUrl: \"https://api.individual.githubcopilot.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 2, output: 12, cacheRead: 0.2, cacheWrite: 0, tiers: [{ inputTokensAbove: 272e3, input: 4, output: 18, cacheRead: 0.4, cacheWrite: 0 }] }, contextWindow: 105e4, maxTokens: 128e3, headers: { \"User-Agent\": \"GitHubCopilotChat/0.35.0\", \"Editor-Version\": \"vscode/1.107.0\", \"Editor-Plugin-Version\": \"copilot-chat/0.35.0\", \"Copilot-Integration-Id\": \"vscode-chat\" }, thinkingLevelMap: { off: null, minimal: \"low\", low: \"low\", medium: \"medium\", high: \"high\", xhigh: \"xhigh\", max: \"max\" }, compat: { supportsOpenAIGrammarTools: true } }, \"grok-4.5\": { id: \"grok-4.5\", name: \"Grok 4.5\", api: \"openai-responses\", provider: \"github-copilot\", baseUrl: \"https://api.individual.githubcopilot.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 2, output: 6, cacheRead: 0.5, cacheWrite: 0, tiers: [{ inputTokensAbove: 2e5, input: 4, output: 12, cacheRead: 1, cacheWrite: 0 }] }, contextWindow: 5e5, maxTokens: 128e3, headers: { \"User-Agent\": \"GitHubCopilotChat/0.35.0\", \"Editor-Version\": \"vscode/1.107.0\", \"Editor-Plugin-Version\": \"copilot-chat/0.35.0\", \"Copilot-Integration-Id\": \"vscode-chat\" }, thinkingLevelMap: { off: null, minimal: null, low: \"low\", medium: \"medium\", high: \"high\", xhigh: null, max: null } }, \"mai-code-1-flash-picker\": { id: \"mai-code-1-flash-picker\", name: \"MAI-Code-1-Flash\", api: \"openai-responses\", provider: \"github-copilot\", baseUrl: \"https://api.individual.githubcopilot.com\", reasoning: true, input: [\"text\"], cost: { input: 0.75, output: 4.5, cacheRead: 0.075, cacheWrite: 0 }, contextWindow: 256e3, maxTokens: 128e3, headers: { \"User-Agent\": \"GitHubCopilotChat/0.35.0\", \"Editor-Version\": \"vscode/1.107.0\", \"Editor-Plugin-Version\": \"copilot-chat/0.35.0\", \"Copilot-Integration-Id\": \"vscode-chat\" }, thinkingLevelMap: { off: null, minimal: null, low: \"low\", medium: \"medium\", high: \"high\", xhigh: null, max: null } }, \"mai-code-1.1-flash\": { id: \"mai-code-1.1-flash\", name: \"MAI-Code-1.1-Flash\", api: \"openai-responses\", provider: \"github-copilot\", baseUrl: \"https://api.individual.githubcopilot.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.2, output: 1.2, cacheRead: 0.02, cacheWrite: 0 }, contextWindow: 256e3, maxTokens: 128e3, headers: { \"User-Agent\": \"GitHubCopilotChat/0.35.0\", \"Editor-Version\": \"vscode/1.107.0\", \"Editor-Plugin-Version\": \"copilot-chat/0.35.0\", \"Copilot-Integration-Id\": \"vscode-chat\" }, thinkingLevelMap: { off: null, minimal: null, low: \"low\", medium: \"medium\", high: \"high\", xhigh: null, max: null } } } };\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/github-copilot.models.js\nvar GITHUB_COPILOT_MODELS = flattenModelCatalog(\"github-copilot\", github_copilot_default);\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/data/google.json\nvar google_default = { \"google-generative-ai\": { \"deep-research-max-preview-04-2026\": { id: \"deep-research-max-preview-04-2026\", name: \"Deep Research Max Preview (Apr-21-2026)\", api: \"google-generative-ai\", provider: \"google\", baseUrl: \"https://generativelanguage.googleapis.com/v1beta\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 2, output: 12, cacheRead: 0.2, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 65536 }, \"deep-research-preview-04-2026\": { id: \"deep-research-preview-04-2026\", name: \"Deep Research Preview (Apr-21-2026)\", api: \"google-generative-ai\", provider: \"google\", baseUrl: \"https://generativelanguage.googleapis.com/v1beta\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 2, output: 12, cacheRead: 0.2, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 65536 }, \"gemini-2.5-computer-use-preview-10-2025\": { id: \"gemini-2.5-computer-use-preview-10-2025\", name: \"Gemini 2.5 Computer Use Preview 10-2025\", api: \"google-generative-ai\", provider: \"google\", baseUrl: \"https://generativelanguage.googleapis.com/v1beta\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.25, output: 10, cacheRead: 0, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 65536 }, \"gemini-2.5-flash\": { id: \"gemini-2.5-flash\", name: \"Gemini 2.5 Flash\", api: \"google-generative-ai\", provider: \"google\", baseUrl: \"https://generativelanguage.googleapis.com/v1beta\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.3, output: 2.5, cacheRead: 0.03, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536 }, \"gemini-2.5-flash-lite\": { id: \"gemini-2.5-flash-lite\", name: \"Gemini 2.5 Flash-Lite\", api: \"google-generative-ai\", provider: \"google\", baseUrl: \"https://generativelanguage.googleapis.com/v1beta\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.1, output: 0.4, cacheRead: 0.01, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536 }, \"gemini-2.5-pro\": { id: \"gemini-2.5-pro\", name: \"Gemini 2.5 Pro\", api: \"google-generative-ai\", provider: \"google\", baseUrl: \"https://generativelanguage.googleapis.com/v1beta\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.25, output: 10, cacheRead: 0.125, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536 }, \"gemini-3-flash-preview\": { id: \"gemini-3-flash-preview\", name: \"Gemini 3 Flash Preview\", api: \"google-generative-ai\", provider: \"google\", baseUrl: \"https://generativelanguage.googleapis.com/v1beta\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.5, output: 3, cacheRead: 0.05, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536, thinkingLevelMap: { off: null } }, \"gemini-3.1-flash-lite\": { id: \"gemini-3.1-flash-lite\", name: \"Gemini 3.1 Flash Lite\", api: \"google-generative-ai\", provider: \"google\", baseUrl: \"https://generativelanguage.googleapis.com/v1beta\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.25, output: 1.5, cacheRead: 0.025, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536, thinkingLevelMap: { off: null } }, \"gemini-3.1-flash-lite-image\": { id: \"gemini-3.1-flash-lite-image\", name: \"Nano Banana 2 Lite\", api: \"google-generative-ai\", provider: \"google\", baseUrl: \"https://generativelanguage.googleapis.com/v1beta\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.25, output: 30, cacheRead: 0, cacheWrite: 0 }, contextWindow: 65536, maxTokens: 65536, thinkingLevelMap: { off: null } }, \"gemini-3.1-flash-lite-preview\": { id: \"gemini-3.1-flash-lite-preview\", name: \"Gemini 3.1 Flash Lite Preview\", api: \"google-generative-ai\", provider: \"google\", baseUrl: \"https://generativelanguage.googleapis.com/v1beta\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.25, output: 1.5, cacheRead: 0.025, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536, thinkingLevelMap: { off: null } }, \"gemini-3.1-flash-live-preview\": { id: \"gemini-3.1-flash-live-preview\", name: \"Gemini 3.1 Flash Live Preview\", api: \"google-generative-ai\", provider: \"google\", baseUrl: \"https://generativelanguage.googleapis.com/v1beta\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.75, output: 4.5, cacheRead: 0, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 65536, thinkingLevelMap: { off: null } }, \"gemini-3.1-pro-preview\": { id: \"gemini-3.1-pro-preview\", name: \"Gemini 3.1 Pro Preview\", api: \"google-generative-ai\", provider: \"google\", baseUrl: \"https://generativelanguage.googleapis.com/v1beta\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 2, output: 12, cacheRead: 0.2, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536, thinkingLevelMap: { off: null, minimal: null, low: \"LOW\", medium: null, high: \"HIGH\" } }, \"gemini-3.1-pro-preview-customtools\": { id: \"gemini-3.1-pro-preview-customtools\", name: \"Gemini 3.1 Pro Preview Custom Tools\", api: \"google-generative-ai\", provider: \"google\", baseUrl: \"https://generativelanguage.googleapis.com/v1beta\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 2, output: 12, cacheRead: 0.2, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536, thinkingLevelMap: { off: null, minimal: null, low: \"LOW\", medium: null, high: \"HIGH\" } }, \"gemini-3.5-flash\": { id: \"gemini-3.5-flash\", name: \"Gemini 3.5 Flash\", api: \"google-generative-ai\", provider: \"google\", baseUrl: \"https://generativelanguage.googleapis.com/v1beta\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.5, output: 9, cacheRead: 0.15, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536, thinkingLevelMap: { off: null } }, \"gemini-3.5-flash-lite\": { id: \"gemini-3.5-flash-lite\", name: \"Gemini 3.5 Flash Lite\", api: \"google-generative-ai\", provider: \"google\", baseUrl: \"https://generativelanguage.googleapis.com/v1beta\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.3, output: 2.5, cacheRead: 0.03, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536, thinkingLevelMap: { off: null } }, \"gemini-3.6-flash\": { id: \"gemini-3.6-flash\", name: \"Gemini 3.6 Flash\", api: \"google-generative-ai\", provider: \"google\", baseUrl: \"https://generativelanguage.googleapis.com/v1beta\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.5, output: 7.5, cacheRead: 0.15, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536, thinkingLevelMap: { off: null } }, \"gemini-3.7-flash\": { id: \"gemini-3.7-flash\", name: \"Gemini 3.7 Flash\", api: \"google-generative-ai\", provider: \"google\", baseUrl: \"https://generativelanguage.googleapis.com/v1beta\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.75, output: 3.75, cacheRead: 0.075, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536, thinkingLevelMap: { off: null } }, \"gemini-flash-latest\": { id: \"gemini-flash-latest\", name: \"Gemini Flash Latest\", api: \"google-generative-ai\", provider: \"google\", baseUrl: \"https://generativelanguage.googleapis.com/v1beta\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.5, output: 9, cacheRead: 0.15, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536, thinkingLevelMap: { off: null } }, \"gemini-flash-lite-latest\": { id: \"gemini-flash-lite-latest\", name: \"Gemini Flash-Lite Latest\", api: \"google-generative-ai\", provider: \"google\", baseUrl: \"https://generativelanguage.googleapis.com/v1beta\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.25, output: 1.5, cacheRead: 0.025, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536, thinkingLevelMap: { off: null } }, \"gemini-robotics-er-1.6-preview\": { id: \"gemini-robotics-er-1.6-preview\", name: \"Gemini Robotics-ER 1.6 Preview\", api: \"google-generative-ai\", provider: \"google\", baseUrl: \"https://generativelanguage.googleapis.com/v1beta\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1, output: 5, cacheRead: 0, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 65536 }, \"gemma-4-26b-a4b-it\": { id: \"gemma-4-26b-a4b-it\", name: \"Gemma 4 26B A4B IT\", api: \"google-generative-ai\", provider: \"google\", baseUrl: \"https://generativelanguage.googleapis.com/v1beta\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 32768, thinkingLevelMap: { off: null, minimal: \"MINIMAL\", low: null, medium: null, high: \"HIGH\" } }, \"gemma-4-31b-it\": { id: \"gemma-4-31b-it\", name: \"Gemma 4 31B IT\", api: \"google-generative-ai\", provider: \"google\", baseUrl: \"https://generativelanguage.googleapis.com/v1beta\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 32768, thinkingLevelMap: { off: null, minimal: \"MINIMAL\", low: null, medium: null, high: \"HIGH\" } } } };\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/google.models.js\nvar GOOGLE_MODELS = flattenModelCatalog(\"google\", google_default);\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/data/google-vertex.json\nvar google_vertex_default = { \"google-vertex\": { \"gemini-2.5-flash\": { id: \"gemini-2.5-flash\", name: \"Gemini 2.5 Flash\", api: \"google-vertex\", provider: \"google-vertex\", baseUrl: \"https://{location}-aiplatform.googleapis.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.3, output: 2.5, cacheRead: 0.03, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536 }, \"gemini-2.5-flash-lite\": { id: \"gemini-2.5-flash-lite\", name: \"Gemini 2.5 Flash-Lite\", api: \"google-vertex\", provider: \"google-vertex\", baseUrl: \"https://{location}-aiplatform.googleapis.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.1, output: 0.4, cacheRead: 0.01, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536 }, \"gemini-2.5-pro\": { id: \"gemini-2.5-pro\", name: \"Gemini 2.5 Pro\", api: \"google-vertex\", provider: \"google-vertex\", baseUrl: \"https://{location}-aiplatform.googleapis.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.25, output: 10, cacheRead: 0.125, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536 }, \"gemini-3-flash-preview\": { id: \"gemini-3-flash-preview\", name: \"Gemini 3 Flash Preview\", api: \"google-vertex\", provider: \"google-vertex\", baseUrl: \"https://{location}-aiplatform.googleapis.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.5, output: 3, cacheRead: 0.05, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536, thinkingLevelMap: { off: null } }, \"gemini-3.1-flash-lite\": { id: \"gemini-3.1-flash-lite\", name: \"Gemini 3.1 Flash Lite\", api: \"google-vertex\", provider: \"google-vertex\", baseUrl: \"https://{location}-aiplatform.googleapis.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.25, output: 1.5, cacheRead: 0.025, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536, thinkingLevelMap: { off: null } }, \"gemini-3.1-pro-preview\": { id: \"gemini-3.1-pro-preview\", name: \"Gemini 3.1 Pro Preview\", api: \"google-vertex\", provider: \"google-vertex\", baseUrl: \"https://{location}-aiplatform.googleapis.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 2, output: 12, cacheRead: 0.2, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536, thinkingLevelMap: { off: null, minimal: null, low: \"LOW\", medium: null, high: \"HIGH\" } }, \"gemini-3.1-pro-preview-customtools\": { id: \"gemini-3.1-pro-preview-customtools\", name: \"Gemini 3.1 Pro Preview Custom Tools\", api: \"google-vertex\", provider: \"google-vertex\", baseUrl: \"https://{location}-aiplatform.googleapis.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 2, output: 12, cacheRead: 0.2, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536, thinkingLevelMap: { off: null, minimal: null, low: \"LOW\", medium: null, high: \"HIGH\" } }, \"gemini-3.5-flash\": { id: \"gemini-3.5-flash\", name: \"Gemini 3.5 Flash\", api: \"google-vertex\", provider: \"google-vertex\", baseUrl: \"https://{location}-aiplatform.googleapis.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.5, output: 9, cacheRead: 0.15, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536, thinkingLevelMap: { off: null } }, \"gemini-3.5-flash-lite\": { id: \"gemini-3.5-flash-lite\", name: \"Gemini 3.5 Flash Lite\", api: \"google-vertex\", provider: \"google-vertex\", baseUrl: \"https://{location}-aiplatform.googleapis.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.3, output: 2.5, cacheRead: 0.03, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536, thinkingLevelMap: { off: null } }, \"gemini-3.6-flash\": { id: \"gemini-3.6-flash\", name: \"Gemini 3.6 Flash\", api: \"google-vertex\", provider: \"google-vertex\", baseUrl: \"https://{location}-aiplatform.googleapis.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.5, output: 7.5, cacheRead: 0.15, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536, thinkingLevelMap: { off: null } }, \"gemini-3.7-flash\": { id: \"gemini-3.7-flash\", name: \"Gemini 3.7 Flash\", api: \"google-vertex\", provider: \"google-vertex\", baseUrl: \"https://{location}-aiplatform.googleapis.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.75, output: 3.75, cacheRead: 0.075, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536, thinkingLevelMap: { off: null } }, \"gemini-flash-latest\": { id: \"gemini-flash-latest\", name: \"Gemini Flash Latest\", api: \"google-vertex\", provider: \"google-vertex\", baseUrl: \"https://{location}-aiplatform.googleapis.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.5, output: 9, cacheRead: 0.15, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536, thinkingLevelMap: { off: null } }, \"gemini-flash-lite-latest\": { id: \"gemini-flash-lite-latest\", name: \"Gemini Flash-Lite Latest\", api: \"google-vertex\", provider: \"google-vertex\", baseUrl: \"https://{location}-aiplatform.googleapis.com\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.25, output: 1.5, cacheRead: 0.025, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536, thinkingLevelMap: { off: null } } } };\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/google-vertex.models.js\nvar GOOGLE_VERTEX_MODELS = flattenModelCatalog(\"google-vertex\", google_vertex_default);\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/data/groq.json\nvar groq_default = { \"openai-completions\": { \"llama-3.1-8b-instant\": { id: \"llama-3.1-8b-instant\", name: \"Llama 3.1 8B\", api: \"openai-completions\", provider: \"groq\", baseUrl: \"https://api.groq.com/openai/v1\", reasoning: false, input: [\"text\"], cost: { input: 0.05, output: 0.08, cacheRead: 0, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 131072 }, \"llama-3.3-70b-versatile\": { id: \"llama-3.3-70b-versatile\", name: \"Llama 3.3 70B\", api: \"openai-completions\", provider: \"groq\", baseUrl: \"https://api.groq.com/openai/v1\", reasoning: false, input: [\"text\"], cost: { input: 0.59, output: 0.79, cacheRead: 0, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 32768 }, \"openai/gpt-oss-120b\": { id: \"openai/gpt-oss-120b\", name: \"GPT OSS 120B\", api: \"openai-completions\", provider: \"groq\", baseUrl: \"https://api.groq.com/openai/v1\", reasoning: true, input: [\"text\"], cost: { input: 0.15, output: 0.6, cacheRead: 0.075, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 65536, thinkingLevelMap: { off: null, minimal: null, low: \"low\", medium: \"medium\", high: \"high\", xhigh: null, max: null } }, \"openai/gpt-oss-20b\": { id: \"openai/gpt-oss-20b\", name: \"GPT OSS 20B\", api: \"openai-completions\", provider: \"groq\", baseUrl: \"https://api.groq.com/openai/v1\", reasoning: true, input: [\"text\"], cost: { input: 0.075, output: 0.3, cacheRead: 0.0375, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 65536, thinkingLevelMap: { off: null, minimal: null, low: \"low\", medium: \"medium\", high: \"high\", xhigh: null, max: null } }, \"openai/gpt-oss-safeguard-20b\": { id: \"openai/gpt-oss-safeguard-20b\", name: \"Safety GPT OSS 20B\", api: \"openai-completions\", provider: \"groq\", baseUrl: \"https://api.groq.com/openai/v1\", reasoning: true, input: [\"text\"], cost: { input: 0.075, output: 0.3, cacheRead: 0, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 65536, thinkingLevelMap: { off: null, minimal: null, low: \"low\", medium: \"medium\", high: \"high\", xhigh: null, max: null } }, \"qwen/qwen3.6-27b\": { id: \"qwen/qwen3.6-27b\", name: \"Qwen3.6 27B\", api: \"openai-completions\", provider: \"groq\", baseUrl: \"https://api.groq.com/openai/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.6, output: 3, cacheRead: 0.3, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 16384, thinkingLevelMap: { off: \"none\", minimal: null, low: null, medium: null, high: \"default\", xhigh: null, max: null } } } };\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/groq.models.js\nvar GROQ_MODELS = flattenModelCatalog(\"groq\", groq_default);\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/data/huggingface.json\nvar huggingface_default = { \"openai-completions\": { \"MiniMaxAI/MiniMax-M2\": { id: \"MiniMaxAI/MiniMax-M2\", name: \"MiniMax-M2\", api: \"openai-completions\", provider: \"huggingface\", baseUrl: \"https://router.huggingface.co/v1\", reasoning: true, input: [\"text\"], cost: { input: 0.3, output: 1.2, cacheRead: 0, cacheWrite: 0 }, compat: { supportsDeveloperRole: false }, contextWindow: 204800, maxTokens: 128e3 }, \"MiniMaxAI/MiniMax-M2.1\": { id: \"MiniMaxAI/MiniMax-M2.1\", name: \"MiniMax-M2.1\", api: \"openai-completions\", provider: \"huggingface\", baseUrl: \"https://router.huggingface.co/v1\", reasoning: true, input: [\"text\"], cost: { input: 0.3, output: 1.2, cacheRead: 0, cacheWrite: 0 }, compat: { supportsDeveloperRole: false }, contextWindow: 204800, maxTokens: 131072 }, \"MiniMaxAI/MiniMax-M2.5\": { id: \"MiniMaxAI/MiniMax-M2.5\", name: \"MiniMax-M2.5\", api: \"openai-completions\", provider: \"huggingface\", baseUrl: \"https://router.huggingface.co/v1\", reasoning: true, input: [\"text\"], cost: { input: 0.3, output: 1.2, cacheRead: 0.03, cacheWrite: 0 }, compat: { supportsDeveloperRole: false }, contextWindow: 204800, maxTokens: 131072 }, \"MiniMaxAI/MiniMax-M2.7\": { id: \"MiniMaxAI/MiniMax-M2.7\", name: \"MiniMax-M2.7\", api: \"openai-completions\", provider: \"huggingface\", baseUrl: \"https://router.huggingface.co/v1\", reasoning: true, input: [\"text\"], cost: { input: 0.3, output: 1.2, cacheRead: 0.06, cacheWrite: 0 }, compat: { supportsDeveloperRole: false }, contextWindow: 204800, maxTokens: 131072 }, \"MiniMaxAI/MiniMax-M3\": { id: \"MiniMaxAI/MiniMax-M3\", name: \"MiniMax-M3\", api: \"openai-completions\", provider: \"huggingface\", baseUrl: \"https://router.huggingface.co/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.3, output: 1.2, cacheRead: 0, cacheWrite: 0 }, compat: { supportsDeveloperRole: false }, contextWindow: 524288, maxTokens: 128e3 }, \"Qwen/Qwen2.5-Coder-32B-Instruct\": { id: \"Qwen/Qwen2.5-Coder-32B-Instruct\", name: \"Qwen2.5-Coder-32B-Instruct\", api: \"openai-completions\", provider: \"huggingface\", baseUrl: \"https://router.huggingface.co/v1\", reasoning: false, input: [\"text\"], cost: { input: 0.06, output: 0.2, cacheRead: 0, cacheWrite: 0 }, compat: { supportsDeveloperRole: false }, contextWindow: 131072, maxTokens: 8192 }, \"Qwen/Qwen3-235B-A22B\": { id: \"Qwen/Qwen3-235B-A22B\", name: \"Qwen3 235B-A22B\", api: \"openai-completions\", provider: \"huggingface\", baseUrl: \"https://router.huggingface.co/v1\", reasoning: true, input: [\"text\"], cost: { input: 0.2, output: 0.8, cacheRead: 0, cacheWrite: 0 }, compat: { supportsDeveloperRole: false }, contextWindow: 40960, maxTokens: 16384 }, \"Qwen/Qwen3-235B-A22B-Instruct-2507\": { id: \"Qwen/Qwen3-235B-A22B-Instruct-2507\", name: \"Qwen3 235B-A22B Instruct 2507\", api: \"openai-completions\", provider: \"huggingface\", baseUrl: \"https://router.huggingface.co/v1\", reasoning: false, input: [\"text\"], cost: { input: 0.855, output: 2.565, cacheRead: 0, cacheWrite: 0 }, compat: { supportsDeveloperRole: false }, contextWindow: 262144, maxTokens: 16384 }, \"Qwen/Qwen3-235B-A22B-Thinking-2507\": { id: \"Qwen/Qwen3-235B-A22B-Thinking-2507\", name: \"Qwen3-235B-A22B-Thinking-2507\", api: \"openai-completions\", provider: \"huggingface\", baseUrl: \"https://router.huggingface.co/v1\", reasoning: true, input: [\"text\"], cost: { input: 0.3, output: 3, cacheRead: 0, cacheWrite: 0 }, compat: { supportsDeveloperRole: false }, contextWindow: 262144, maxTokens: 131072 }, \"Qwen/Qwen3-30B-A3B\": { id: \"Qwen/Qwen3-30B-A3B\", name: \"Qwen3 30B A3B\", api: \"openai-completions\", provider: \"huggingface\", baseUrl: \"https://router.huggingface.co/v1\", reasoning: true, input: [\"text\"], cost: { input: 0.12, output: 0.5, cacheRead: 0, cacheWrite: 0 }, compat: { supportsDeveloperRole: false }, contextWindow: 40960, maxTokens: 16384 }, \"Qwen/Qwen3-32B\": { id: \"Qwen/Qwen3-32B\", name: \"Qwen3 32B\", api: \"openai-completions\", provider: \"huggingface\", baseUrl: \"https://router.huggingface.co/v1\", reasoning: true, input: [\"text\"], cost: { input: 0.29, output: 0.59, cacheRead: 0, cacheWrite: 0 }, compat: { supportsDeveloperRole: false }, contextWindow: 131072, maxTokens: 16384 }, \"Qwen/Qwen3-Coder-30B-A3B-Instruct\": { id: \"Qwen/Qwen3-Coder-30B-A3B-Instruct\", name: \"Qwen3-Coder 30B-A3B Instruct\", api: \"openai-completions\", provider: \"huggingface\", baseUrl: \"https://router.huggingface.co/v1\", reasoning: false, input: [\"text\"], cost: { input: 0.07, output: 0.26, cacheRead: 0, cacheWrite: 0 }, compat: { supportsDeveloperRole: false }, contextWindow: 262144, maxTokens: 65536 }, \"Qwen/Qwen3-Coder-480B-A35B-Instruct\": { id: \"Qwen/Qwen3-Coder-480B-A35B-Instruct\", name: \"Qwen3-Coder-480B-A35B-Instruct\", api: \"openai-completions\", provider: \"huggingface\", baseUrl: \"https://router.huggingface.co/v1\", reasoning: false, input: [\"text\"], cost: { input: 2, output: 2, cacheRead: 0, cacheWrite: 0 }, compat: { supportsDeveloperRole: false }, contextWindow: 262144, maxTokens: 66536 }, \"Qwen/Qwen3-Coder-Next\": { id: \"Qwen/Qwen3-Coder-Next\", name: \"Qwen3-Coder-Next\", api: \"openai-completions\", provider: \"huggingface\", baseUrl: \"https://router.huggingface.co/v1\", reasoning: false, input: [\"text\"], cost: { input: 0.2, output: 1.5, cacheRead: 0, cacheWrite: 0 }, compat: { supportsDeveloperRole: false }, contextWindow: 262144, maxTokens: 65536 }, \"Qwen/Qwen3-Next-80B-A3B-Instruct\": { id: \"Qwen/Qwen3-Next-80B-A3B-Instruct\", name: \"Qwen3-Next-80B-A3B-Instruct\", api: \"openai-completions\", provider: \"huggingface\", baseUrl: \"https://router.huggingface.co/v1\", reasoning: false, input: [\"text\"], cost: { input: 0.25, output: 1, cacheRead: 0, cacheWrite: 0 }, compat: { supportsDeveloperRole: false }, contextWindow: 262144, maxTokens: 66536 }, \"Qwen/Qwen3-Next-80B-A3B-Thinking\": { id: \"Qwen/Qwen3-Next-80B-A3B-Thinking\", name: \"Qwen3-Next-80B-A3B-Thinking\", api: \"openai-completions\", provider: \"huggingface\", baseUrl: \"https://router.huggingface.co/v1\", reasoning: false, input: [\"text\"], cost: { input: 0.3, output: 2, cacheRead: 0, cacheWrite: 0 }, compat: { supportsDeveloperRole: false }, contextWindow: 262144, maxTokens: 131072 }, \"Qwen/Qwen3.5-122B-A10B\": { id: \"Qwen/Qwen3.5-122B-A10B\", name: \"Qwen3.5 122B-A10B\", api: \"openai-completions\", provider: \"huggingface\", baseUrl: \"https://router.huggingface.co/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.4, output: 3.2, cacheRead: 0, cacheWrite: 0 }, compat: { supportsDeveloperRole: false }, contextWindow: 262144, maxTokens: 65536 }, \"Qwen/Qwen3.5-27B\": { id: \"Qwen/Qwen3.5-27B\", name: \"Qwen3.5 27B\", api: \"openai-completions\", provider: \"huggingface\", baseUrl: \"https://router.huggingface.co/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.3, output: 2.4, cacheRead: 0, cacheWrite: 0 }, compat: { supportsDeveloperRole: false }, contextWindow: 262144, maxTokens: 65536 }, \"Qwen/Qwen3.5-35B-A3B\": { id: \"Qwen/Qwen3.5-35B-A3B\", name: \"Qwen3.5 35B-A3B\", api: \"openai-completions\", provider: \"huggingface\", baseUrl: \"https://router.huggingface.co/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.25, output: 2, cacheRead: 0, cacheWrite: 0 }, compat: { supportsDeveloperRole: false }, contextWindow: 262144, maxTokens: 65536 }, \"Qwen/Qwen3.5-397B-A17B\": { id: \"Qwen/Qwen3.5-397B-A17B\", name: \"Qwen3.5-397B-A17B\", api: \"openai-completions\", provider: \"huggingface\", baseUrl: \"https://router.huggingface.co/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.6, output: 3.6, cacheRead: 0, cacheWrite: 0 }, compat: { supportsDeveloperRole: false }, contextWindow: 262144, maxTokens: 32768, thinkingLevelMap: { off: \"none\", minimal: null, low: \"low\", medium: \"medium\", high: \"high\", xhigh: null, max: null } }, \"Qwen/Qwen3.5-9B\": { id: \"Qwen/Qwen3.5-9B\", name: \"Qwen3.5 9B\", api: \"openai-completions\", provider: \"huggingface\", baseUrl: \"https://router.huggingface.co/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.17, output: 0.25, cacheRead: 0, cacheWrite: 0 }, compat: { supportsDeveloperRole: false }, contextWindow: 262144, maxTokens: 65536 }, \"Qwen/Qwen3.6-27B\": { id: \"Qwen/Qwen3.6-27B\", name: \"Qwen3.6 27B\", api: \"openai-completions\", provider: \"huggingface\", baseUrl: \"https://router.huggingface.co/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.47, output: 3.19, cacheRead: 0, cacheWrite: 0 }, compat: { supportsDeveloperRole: false }, contextWindow: 262144, maxTokens: 65536 }, \"Qwen/Qwen3.6-35B-A3B\": { id: \"Qwen/Qwen3.6-35B-A3B\", name: \"Qwen3.6 35B-A3B\", api: \"openai-completions\", provider: \"huggingface\", baseUrl: \"https://router.huggingface.co/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.15, output: 0.95, cacheRead: 0, cacheWrite: 0 }, compat: { supportsDeveloperRole: false }, contextWindow: 262144, maxTokens: 65536 }, \"XiaomiMiMo/MiMo-V2-Flash\": { id: \"XiaomiMiMo/MiMo-V2-Flash\", name: \"MiMo-V2-Flash\", api: \"openai-completions\", provider: \"huggingface\", baseUrl: \"https://router.huggingface.co/v1\", reasoning: true, input: [\"text\"], cost: { input: 0.1, output: 0.3, cacheRead: 0, cacheWrite: 0 }, compat: { supportsDeveloperRole: false }, contextWindow: 262144, maxTokens: 4096 }, \"XiaomiMiMo/MiMo-V2.5\": { id: \"XiaomiMiMo/MiMo-V2.5\", name: \"MiMo-V2.5\", api: \"openai-completions\", provider: \"huggingface\", baseUrl: \"https://router.huggingface.co/v1\", reasoning: true, input: [\"text\"], cost: { input: 0.4, output: 2, cacheRead: 0, cacheWrite: 0 }, compat: { supportsDeveloperRole: false }, contextWindow: 262144, maxTokens: 131072, thinkingLevelMap: { off: \"none\", minimal: null, low: \"low\", medium: \"medium\", high: \"high\", xhigh: \"xhigh\", max: null } }, \"XiaomiMiMo/MiMo-V2.5-Pro\": { id: \"XiaomiMiMo/MiMo-V2.5-Pro\", name: \"MiMo-V2.5-Pro\", api: \"openai-completions\", provider: \"huggingface\", baseUrl: \"https://router.huggingface.co/v1\", reasoning: true, input: [\"text\"], cost: { input: 1, output: 3, cacheRead: 0, cacheWrite: 0 }, compat: { supportsDeveloperRole: false }, contextWindow: 1048576, maxTokens: 131072, thinkingLevelMap: { off: \"none\", minimal: null, low: \"low\", medium: \"medium\", high: \"high\", xhigh: \"xhigh\", max: null } }, \"deepseek-ai/DeepSeek-R1\": { id: \"deepseek-ai/DeepSeek-R1\", name: \"DeepSeek-R1\", api: \"openai-completions\", provider: \"huggingface\", baseUrl: \"https://router.huggingface.co/v1\", reasoning: true, input: [\"text\"], cost: { input: 0.7, output: 2.5, cacheRead: 0, cacheWrite: 0 }, compat: { supportsDeveloperRole: false }, contextWindow: 64e3, maxTokens: 32768 }, \"deepseek-ai/DeepSeek-R1-0528\": { id: \"deepseek-ai/DeepSeek-R1-0528\", name: \"DeepSeek-R1-0528\", api: \"openai-completions\", provider: \"huggingface\", baseUrl: \"https://router.huggingface.co/v1\", reasoning: true, input: [\"text\"], cost: { input: 3, output: 5, cacheRead: 0, cacheWrite: 0 }, compat: { supportsDeveloperRole: false }, contextWindow: 163840, maxTokens: 163840 }, \"deepseek-ai/DeepSeek-V3\": { id: \"deepseek-ai/DeepSeek-V3\", name: \"DeepSeek-V3\", api: \"openai-completions\", provider: \"huggingface\", baseUrl: \"https://router.huggingface.co/v1\", reasoning: false, input: [\"text\"], cost: { input: 0.4, output: 1.3, cacheRead: 0, cacheWrite: 0 }, compat: { supportsDeveloperRole: false }, contextWindow: 64e3, maxTokens: 8192 }, \"deepseek-ai/DeepSeek-V3-0324\": { id: \"deepseek-ai/DeepSeek-V3-0324\", name: \"DeepSeek V3 0324\", api: \"openai-completions\", provider: \"huggingface\", baseUrl: \"https://router.huggingface.co/v1\", reasoning: false, input: [\"text\"], cost: { input: 0.27, output: 1.12, cacheRead: 0, cacheWrite: 0 }, compat: { supportsDeveloperRole: false }, contextWindow: 163840, maxTokens: 163840 }, \"deepseek-ai/DeepSeek-V3.1\": { id: \"deepseek-ai/DeepSeek-V3.1\", name: \"DeepSeek-V3.1\", api: \"openai-completions\", provider: \"huggingface\", baseUrl: \"https://router.huggingface.co/v1\", reasoning: true, input: [\"text\"], cost: { input: 0.27, output: 1, cacheRead: 0, cacheWrite: 0 }, compat: { supportsDeveloperRole: false }, contextWindow: 131072, maxTokens: 8192 }, \"deepseek-ai/DeepSeek-V3.2\": { id: \"deepseek-ai/DeepSeek-V3.2\", name: \"DeepSeek-V3.2\", api: \"openai-completions\", provider: \"huggingface\", baseUrl: \"https://router.huggingface.co/v1\", reasoning: true, input: [\"text\"], cost: { input: 0.28, output: 0.4, cacheRead: 0, cacheWrite: 0 }, compat: { supportsDeveloperRole: false }, contextWindow: 163840, maxTokens: 65536 }, \"deepseek-ai/DeepSeek-V4-Flash\": { id: \"deepseek-ai/DeepSeek-V4-Flash\", name: \"DeepSeek V4 Flash\", api: \"openai-completions\", provider: \"huggingface\", baseUrl: \"https://router.huggingface.co/v1\", reasoning: true, input: [\"text\"], cost: { input: 0.14, output: 0.28, cacheRead: 0, cacheWrite: 0 }, compat: { supportsDeveloperRole: false }, contextWindow: 1048576, maxTokens: 384e3 }, \"deepseek-ai/DeepSeek-V4-Flash-0731\": { id: \"deepseek-ai/DeepSeek-V4-Flash-0731\", name: \"DeepSeek V4 Flash 0731\", api: \"openai-completions\", provider: \"huggingface\", baseUrl: \"https://router.huggingface.co/v1\", reasoning: true, input: [\"text\"], cost: { input: 0.14, output: 0.28, cacheRead: 0, cacheWrite: 0 }, compat: { supportsDeveloperRole: false }, contextWindow: 1048576, maxTokens: 384e3, thinkingLevelMap: { off: null, minimal: null, low: null, medium: null, high: \"high\", xhigh: null, max: \"max\" } }, \"deepseek-ai/DeepSeek-V4-Pro\": { id: \"deepseek-ai/DeepSeek-V4-Pro\", name: \"DeepSeek V4 Pro\", api: \"openai-completions\", provider: \"huggingface\", baseUrl: \"https://router.huggingface.co/v1\", reasoning: true, input: [\"text\"], cost: { input: 0.435, output: 0.87, cacheRead: 3625e-6, cacheWrite: 0 }, compat: { supportsDeveloperRole: false }, contextWindow: 1048576, maxTokens: 393216, thinkingLevelMap: { off: null, minimal: null, low: null, medium: null, high: \"high\", xhigh: null, max: null } }, \"google/gemma-4-26B-A4B-it\": { id: \"google/gemma-4-26B-A4B-it\", name: \"Gemma 4 26B A4B IT\", api: \"openai-completions\", provider: \"huggingface\", baseUrl: \"https://router.huggingface.co/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.13, output: 0.4, cacheRead: 0, cacheWrite: 0 }, compat: { supportsDeveloperRole: false }, contextWindow: 262144, maxTokens: 32768 }, \"google/gemma-4-31B-it\": { id: \"google/gemma-4-31B-it\", name: \"Gemma 4 31B IT\", api: \"openai-completions\", provider: \"huggingface\", baseUrl: \"https://router.huggingface.co/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.14, output: 0.4, cacheRead: 0, cacheWrite: 0 }, compat: { supportsDeveloperRole: false }, contextWindow: 262144, maxTokens: 32768 }, \"meta-llama/Llama-3.1-8B-Instruct\": { id: \"meta-llama/Llama-3.1-8B-Instruct\", name: \"Llama-3.1-8B-Instruct\", api: \"openai-completions\", provider: \"huggingface\", baseUrl: \"https://router.huggingface.co/v1\", reasoning: false, input: [\"text\"], cost: { input: 0.06, output: 0.06, cacheRead: 0, cacheWrite: 0 }, compat: { supportsDeveloperRole: false }, contextWindow: 131072, maxTokens: 4096 }, \"meta-llama/Llama-3.3-70B-Instruct\": { id: \"meta-llama/Llama-3.3-70B-Instruct\", name: \"Llama-3.3-70B-Instruct\", api: \"openai-completions\", provider: \"huggingface\", baseUrl: \"https://router.huggingface.co/v1\", reasoning: false, input: [\"text\"], cost: { input: 0.59, output: 0.79, cacheRead: 0, cacheWrite: 0 }, compat: { supportsDeveloperRole: false }, contextWindow: 131072, maxTokens: 4096 }, \"moonshotai/Kimi-K2-Instruct\": { id: \"moonshotai/Kimi-K2-Instruct\", name: \"Kimi-K2-Instruct\", api: \"openai-completions\", provider: \"huggingface\", baseUrl: \"https://router.huggingface.co/v1\", reasoning: false, input: [\"text\"], cost: { input: 1, output: 3, cacheRead: 0, cacheWrite: 0 }, compat: { supportsDeveloperRole: false }, contextWindow: 131072, maxTokens: 16384 }, \"moonshotai/Kimi-K2-Instruct-0905\": { id: \"moonshotai/Kimi-K2-Instruct-0905\", name: \"Kimi-K2-Instruct-0905\", api: \"openai-completions\", provider: \"huggingface\", baseUrl: \"https://router.huggingface.co/v1\", reasoning: false, input: [\"text\"], cost: { input: 1, output: 3, cacheRead: 0, cacheWrite: 0 }, compat: { supportsDeveloperRole: false }, contextWindow: 262144, maxTokens: 16384 }, \"moonshotai/Kimi-K2-Thinking\": { id: \"moonshotai/Kimi-K2-Thinking\", name: \"Kimi-K2-Thinking\", api: \"openai-completions\", provider: \"huggingface\", baseUrl: \"https://router.huggingface.co/v1\", reasoning: true, input: [\"text\"], cost: { input: 0.6, output: 2.5, cacheRead: 0.15, cacheWrite: 0 }, compat: { supportsDeveloperRole: false }, contextWindow: 262144, maxTokens: 262144 }, \"moonshotai/Kimi-K2.5\": { id: \"moonshotai/Kimi-K2.5\", name: \"Kimi-K2.5\", api: \"openai-completions\", provider: \"huggingface\", baseUrl: \"https://router.huggingface.co/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.6, output: 3, cacheRead: 0.1, cacheWrite: 0 }, compat: { supportsDeveloperRole: false }, contextWindow: 262144, maxTokens: 262144 }, \"moonshotai/Kimi-K2.6\": { id: \"moonshotai/Kimi-K2.6\", name: \"Kimi-K2.6\", api: \"openai-completions\", provider: \"huggingface\", baseUrl: \"https://router.huggingface.co/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.95, output: 4, cacheRead: 0.16, cacheWrite: 0 }, compat: { supportsDeveloperRole: false }, contextWindow: 262144, maxTokens: 262144 }, \"moonshotai/Kimi-K2.7-Code\": { id: \"moonshotai/Kimi-K2.7-Code\", name: \"Kimi K2.7 Code\", api: \"openai-completions\", provider: \"huggingface\", baseUrl: \"https://router.huggingface.co/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.95, output: 4, cacheRead: 0, cacheWrite: 0 }, compat: { supportsDeveloperRole: false }, contextWindow: 262144, maxTokens: 262144 }, \"moonshotai/Kimi-K3\": { id: \"moonshotai/Kimi-K3\", name: \"Kimi K3\", api: \"openai-completions\", provider: \"huggingface\", baseUrl: \"https://router.huggingface.co/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 3, output: 15, cacheRead: 0, cacheWrite: 0 }, compat: { supportsDeveloperRole: false }, contextWindow: 1e6, maxTokens: 131072, thinkingLevelMap: { off: null, minimal: null, low: \"low\", medium: null, high: \"high\", xhigh: null, max: \"max\" } }, \"openai/gpt-oss-120b\": { id: \"openai/gpt-oss-120b\", name: \"GPT OSS 120B\", api: \"openai-completions\", provider: \"huggingface\", baseUrl: \"https://router.huggingface.co/v1\", reasoning: true, input: [\"text\"], cost: { input: 0.25, output: 0.69, cacheRead: 0, cacheWrite: 0 }, compat: { supportsDeveloperRole: false }, contextWindow: 131072, maxTokens: 32768, thinkingLevelMap: { off: null, minimal: null, low: \"low\", medium: \"medium\", high: \"high\", xhigh: null, max: null } }, \"openai/gpt-oss-20b\": { id: \"openai/gpt-oss-20b\", name: \"GPT OSS 20B\", api: \"openai-completions\", provider: \"huggingface\", baseUrl: \"https://router.huggingface.co/v1\", reasoning: true, input: [\"text\"], cost: { input: 0.1, output: 0.5, cacheRead: 0, cacheWrite: 0 }, compat: { supportsDeveloperRole: false }, contextWindow: 131072, maxTokens: 32768, thinkingLevelMap: { off: null, minimal: null, low: \"low\", medium: \"medium\", high: \"high\", xhigh: null, max: null } }, \"stepfun-ai/Step-3.5-Flash\": { id: \"stepfun-ai/Step-3.5-Flash\", name: \"Step 3.5 Flash\", api: \"openai-completions\", provider: \"huggingface\", baseUrl: \"https://router.huggingface.co/v1\", reasoning: true, input: [\"text\"], cost: { input: 0.1, output: 0.3, cacheRead: 0, cacheWrite: 0 }, compat: { supportsDeveloperRole: false }, contextWindow: 262144, maxTokens: 256e3 }, \"stepfun-ai/Step-3.7-Flash\": { id: \"stepfun-ai/Step-3.7-Flash\", name: \"Step 3.7 Flash\", api: \"openai-completions\", provider: \"huggingface\", baseUrl: \"https://router.huggingface.co/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.2, output: 1.15, cacheRead: 0, cacheWrite: 0 }, compat: { supportsDeveloperRole: false }, contextWindow: 262144, maxTokens: 256e3, thinkingLevelMap: { off: null, minimal: null, low: \"low\", medium: \"medium\", high: \"high\", xhigh: null, max: null } }, \"tencent/Hy3\": { id: \"tencent/Hy3\", name: \"Hy3\", api: \"openai-completions\", provider: \"huggingface\", baseUrl: \"https://router.huggingface.co/v1\", reasoning: true, input: [\"text\"], cost: { input: 0.14, output: 0.58, cacheRead: 0, cacheWrite: 0 }, compat: { supportsDeveloperRole: false }, contextWindow: 262144, maxTokens: 64e3, thinkingLevelMap: { off: \"none\", minimal: null, low: \"low\", medium: null, high: \"high\", xhigh: null, max: null } }, \"thinkingmachines/Inkling\": { id: \"thinkingmachines/Inkling\", name: \"Inkling\", api: \"openai-completions\", provider: \"huggingface\", baseUrl: \"https://router.huggingface.co/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1, output: 4.05, cacheRead: 0, cacheWrite: 0 }, compat: { supportsDeveloperRole: false }, contextWindow: 1048576, maxTokens: 1048576, thinkingLevelMap: { off: null, minimal: null, low: \"low\", medium: \"medium\", high: \"high\", xhigh: null, max: null } }, \"thinkingmachines/Inkling-Small\": { id: \"thinkingmachines/Inkling-Small\", name: \"Inkling Small\", api: \"openai-completions\", provider: \"huggingface\", baseUrl: \"https://router.huggingface.co/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.5, output: 1.2, cacheRead: 0, cacheWrite: 0 }, compat: { supportsDeveloperRole: false }, contextWindow: 524288, maxTokens: 1048576 }, \"zai-org/GLM-4.5\": { id: \"zai-org/GLM-4.5\", name: \"GLM-4.5\", api: \"openai-completions\", provider: \"huggingface\", baseUrl: \"https://router.huggingface.co/v1\", reasoning: true, input: [\"text\"], cost: { input: 0.6, output: 2.2, cacheRead: 0, cacheWrite: 0 }, compat: { supportsDeveloperRole: false }, contextWindow: 131072, maxTokens: 98304 }, \"zai-org/GLM-4.5-Air\": { id: \"zai-org/GLM-4.5-Air\", name: \"GLM-4.5-Air\", api: \"openai-completions\", provider: \"huggingface\", baseUrl: \"https://router.huggingface.co/v1\", reasoning: true, input: [\"text\"], cost: { input: 0.13, output: 0.85, cacheRead: 0, cacheWrite: 0 }, compat: { supportsDeveloperRole: false }, contextWindow: 131072, maxTokens: 98304 }, \"zai-org/GLM-4.5V\": { id: \"zai-org/GLM-4.5V\", name: \"GLM-4.5V\", api: \"openai-completions\", provider: \"huggingface\", baseUrl: \"https://router.huggingface.co/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.6, output: 1.8, cacheRead: 0, cacheWrite: 0 }, compat: { supportsDeveloperRole: false }, contextWindow: 65536, maxTokens: 16384 }, \"zai-org/GLM-4.6\": { id: \"zai-org/GLM-4.6\", name: \"GLM-4.6\", api: \"openai-completions\", provider: \"huggingface\", baseUrl: \"https://router.huggingface.co/v1\", reasoning: true, input: [\"text\"], cost: { input: 0.55, output: 2.2, cacheRead: 0, cacheWrite: 0 }, compat: { supportsDeveloperRole: false }, contextWindow: 204800, maxTokens: 131072 }, \"zai-org/GLM-4.7\": { id: \"zai-org/GLM-4.7\", name: \"GLM-4.7\", api: \"openai-completions\", provider: \"huggingface\", baseUrl: \"https://router.huggingface.co/v1\", reasoning: true, input: [\"text\"], cost: { input: 0.6, output: 2.2, cacheRead: 0.11, cacheWrite: 0 }, compat: { supportsDeveloperRole: false }, contextWindow: 204800, maxTokens: 131072 }, \"zai-org/GLM-4.7-Flash\": { id: \"zai-org/GLM-4.7-Flash\", name: \"GLM-4.7-Flash\", api: \"openai-completions\", provider: \"huggingface\", baseUrl: \"https://router.huggingface.co/v1\", reasoning: true, input: [\"text\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, compat: { supportsDeveloperRole: false }, contextWindow: 2e5, maxTokens: 128e3 }, \"zai-org/GLM-5\": { id: \"zai-org/GLM-5\", name: \"GLM-5\", api: \"openai-completions\", provider: \"huggingface\", baseUrl: \"https://router.huggingface.co/v1\", reasoning: true, input: [\"text\"], cost: { input: 1, output: 3.2, cacheRead: 0.2, cacheWrite: 0 }, compat: { supportsDeveloperRole: false }, contextWindow: 202752, maxTokens: 131072 }, \"zai-org/GLM-5.1\": { id: \"zai-org/GLM-5.1\", name: \"GLM-5.1\", api: \"openai-completions\", provider: \"huggingface\", baseUrl: \"https://router.huggingface.co/v1\", reasoning: true, input: [\"text\"], cost: { input: 1, output: 3.2, cacheRead: 0.2, cacheWrite: 0 }, compat: { supportsDeveloperRole: false }, contextWindow: 202752, maxTokens: 131072 }, \"zai-org/GLM-5.2\": { id: \"zai-org/GLM-5.2\", name: \"GLM-5.2\", api: \"openai-completions\", provider: \"huggingface\", baseUrl: \"https://router.huggingface.co/v1\", reasoning: true, input: [\"text\"], cost: { input: 1.4, output: 4.4, cacheRead: 0, cacheWrite: 0 }, compat: { supportsDeveloperRole: false }, contextWindow: 262144, maxTokens: 131072 } } };\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/huggingface.models.js\nvar HUGGINGFACE_MODELS = flattenModelCatalog(\"huggingface\", huggingface_default);\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/data/kimi-coding.json\nvar kimi_coding_default = { \"anthropic-messages\": { k3: { id: \"k3\", name: \"Kimi K3\", api: \"anthropic-messages\", provider: \"kimi-coding\", baseUrl: \"https://api.kimi.com/coding\", compat: { allowEmptySignature: true, forceAdaptiveThinking: true }, reasoning: true, input: [\"text\", \"image\"], cost: { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 131072, thinkingLevelMap: { off: null, minimal: null, low: \"low\", medium: null, high: \"high\", xhigh: null, max: \"max\" } }, \"k3-256k\": { id: \"k3-256k\", name: \"Kimi K3-256K\", api: \"anthropic-messages\", provider: \"kimi-coding\", baseUrl: \"https://api.kimi.com/coding\", compat: { forceAdaptiveThinking: true }, reasoning: true, input: [\"text\", \"image\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 131072, thinkingLevelMap: { off: null, minimal: null, low: \"low\", medium: null, high: \"high\", xhigh: null, max: \"max\" } }, \"kimi-for-coding\": { id: \"kimi-for-coding\", name: \"Kimi K2.7 Code\", api: \"anthropic-messages\", provider: \"kimi-coding\", baseUrl: \"https://api.kimi.com/coding\", compat: { allowEmptySignature: true, forceAdaptiveThinking: true }, reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.95, output: 4, cacheRead: 0.19, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 32768 }, \"kimi-for-coding-highspeed\": { id: \"kimi-for-coding-highspeed\", name: \"Kimi For Coding HighSpeed\", api: \"anthropic-messages\", provider: \"kimi-coding\", baseUrl: \"https://api.kimi.com/coding\", compat: { forceAdaptiveThinking: true }, reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.9, output: 8, cacheRead: 0.38, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 32768 } } };\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/kimi-coding.models.js\nvar KIMI_CODING_MODELS = flattenModelCatalog(\"kimi-coding\", kimi_coding_default);\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/data/minimax.json\nvar minimax_default = { \"anthropic-messages\": { \"MiniMax-M2.7\": { id: \"MiniMax-M2.7\", name: \"MiniMax-M2.7\", api: \"anthropic-messages\", provider: \"minimax\", baseUrl: \"https://api.minimax.io/anthropic\", reasoning: true, input: [\"text\"], cost: { input: 0.3, output: 1.2, cacheRead: 0.06, cacheWrite: 0.375 }, contextWindow: 204800, maxTokens: 131072 }, \"MiniMax-M2.7-highspeed\": { id: \"MiniMax-M2.7-highspeed\", name: \"MiniMax-M2.7-highspeed\", api: \"anthropic-messages\", provider: \"minimax\", baseUrl: \"https://api.minimax.io/anthropic\", reasoning: true, input: [\"text\"], cost: { input: 0.6, output: 2.4, cacheRead: 0.06, cacheWrite: 0.375 }, contextWindow: 204800, maxTokens: 131072 }, \"MiniMax-M3\": { id: \"MiniMax-M3\", name: \"MiniMax-M3\", api: \"anthropic-messages\", provider: \"minimax\", baseUrl: \"https://api.minimax.io/anthropic\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.3, output: 1.2, cacheRead: 0.06, cacheWrite: 0 }, contextWindow: 1e6, maxTokens: 128e3 } } };\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/minimax.models.js\nvar MINIMAX_MODELS = flattenModelCatalog(\"minimax\", minimax_default);\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/data/minimax-cn.json\nvar minimax_cn_default = { \"anthropic-messages\": { \"MiniMax-M2.7\": { id: \"MiniMax-M2.7\", name: \"MiniMax-M2.7\", api: \"anthropic-messages\", provider: \"minimax-cn\", baseUrl: \"https://api.minimaxi.com/anthropic\", reasoning: true, input: [\"text\"], cost: { input: 0.3, output: 1.2, cacheRead: 0.06, cacheWrite: 0.375 }, contextWindow: 204800, maxTokens: 131072 }, \"MiniMax-M2.7-highspeed\": { id: \"MiniMax-M2.7-highspeed\", name: \"MiniMax-M2.7-highspeed\", api: \"anthropic-messages\", provider: \"minimax-cn\", baseUrl: \"https://api.minimaxi.com/anthropic\", reasoning: true, input: [\"text\"], cost: { input: 0.6, output: 2.4, cacheRead: 0.06, cacheWrite: 0.375 }, contextWindow: 204800, maxTokens: 131072 }, \"MiniMax-M3\": { id: \"MiniMax-M3\", name: \"MiniMax-M3\", api: \"anthropic-messages\", provider: \"minimax-cn\", baseUrl: \"https://api.minimaxi.com/anthropic\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.3, output: 1.2, cacheRead: 0.06, cacheWrite: 0 }, contextWindow: 1e6, maxTokens: 128e3 } } };\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/minimax-cn.models.js\nvar MINIMAX_CN_MODELS = flattenModelCatalog(\"minimax-cn\", minimax_cn_default);\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/data/mistral.json\nvar mistral_default = { \"mistral-conversations\": { \"codestral-latest\": { id: \"codestral-latest\", name: \"Codestral (latest)\", api: \"mistral-conversations\", provider: \"mistral\", baseUrl: \"https://api.mistral.ai\", reasoning: false, input: [\"text\"], cost: { input: 0.3, output: 0.9, cacheRead: 0.03, cacheWrite: 0 }, contextWindow: 256e3, maxTokens: 4096 }, \"devstral-2512\": { id: \"devstral-2512\", name: \"Devstral 2\", api: \"mistral-conversations\", provider: \"mistral\", baseUrl: \"https://api.mistral.ai\", reasoning: false, input: [\"text\"], cost: { input: 0.4, output: 2, cacheRead: 0.04, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 262144 }, \"devstral-latest\": { id: \"devstral-latest\", name: \"Devstral 2\", api: \"mistral-conversations\", provider: \"mistral\", baseUrl: \"https://api.mistral.ai\", reasoning: false, input: [\"text\"], cost: { input: 0.4, output: 2, cacheRead: 0.04, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 262144 }, \"devstral-medium-2507\": { id: \"devstral-medium-2507\", name: \"Devstral Medium\", api: \"mistral-conversations\", provider: \"mistral\", baseUrl: \"https://api.mistral.ai\", reasoning: false, input: [\"text\"], cost: { input: 0.4, output: 2, cacheRead: 0.04, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 128e3 }, \"devstral-medium-latest\": { id: \"devstral-medium-latest\", name: \"Devstral 2 (latest)\", api: \"mistral-conversations\", provider: \"mistral\", baseUrl: \"https://api.mistral.ai\", reasoning: false, input: [\"text\"], cost: { input: 0.4, output: 2, cacheRead: 0.04, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 262144 }, \"devstral-small-2505\": { id: \"devstral-small-2505\", name: \"Devstral Small 2505\", api: \"mistral-conversations\", provider: \"mistral\", baseUrl: \"https://api.mistral.ai\", reasoning: false, input: [\"text\"], cost: { input: 0.1, output: 0.3, cacheRead: 0.01, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 128e3 }, \"devstral-small-2507\": { id: \"devstral-small-2507\", name: \"Devstral Small\", api: \"mistral-conversations\", provider: \"mistral\", baseUrl: \"https://api.mistral.ai\", reasoning: false, input: [\"text\"], cost: { input: 0.1, output: 0.3, cacheRead: 0.01, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 128e3 }, \"labs-devstral-small-2512\": { id: \"labs-devstral-small-2512\", name: \"Devstral Small 2\", api: \"mistral-conversations\", provider: \"mistral\", baseUrl: \"https://api.mistral.ai\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 256e3, maxTokens: 256e3 }, \"magistral-medium-latest\": { id: \"magistral-medium-latest\", name: \"Magistral Medium (latest)\", api: \"mistral-conversations\", provider: \"mistral\", baseUrl: \"https://api.mistral.ai\", reasoning: true, input: [\"text\"], cost: { input: 2, output: 5, cacheRead: 0.2, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 16384 }, \"magistral-small\": { id: \"magistral-small\", name: \"Magistral Small\", api: \"mistral-conversations\", provider: \"mistral\", baseUrl: \"https://api.mistral.ai\", reasoning: true, input: [\"text\"], cost: { input: 0.5, output: 1.5, cacheRead: 0.05, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 128e3 }, \"ministral-3b-latest\": { id: \"ministral-3b-latest\", name: \"Ministral 3B (latest)\", api: \"mistral-conversations\", provider: \"mistral\", baseUrl: \"https://api.mistral.ai\", reasoning: false, input: [\"text\"], cost: { input: 0.04, output: 0.04, cacheRead: 4e-3, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 128e3 }, \"ministral-8b-latest\": { id: \"ministral-8b-latest\", name: \"Ministral 8B (latest)\", api: \"mistral-conversations\", provider: \"mistral\", baseUrl: \"https://api.mistral.ai\", reasoning: false, input: [\"text\"], cost: { input: 0.1, output: 0.1, cacheRead: 0.01, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 128e3 }, \"mistral-large-2411\": { id: \"mistral-large-2411\", name: \"Mistral Large 2.1\", api: \"mistral-conversations\", provider: \"mistral\", baseUrl: \"https://api.mistral.ai\", reasoning: false, input: [\"text\"], cost: { input: 2, output: 6, cacheRead: 0.2, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 16384 }, \"mistral-large-2512\": { id: \"mistral-large-2512\", name: \"Mistral Large 3\", api: \"mistral-conversations\", provider: \"mistral\", baseUrl: \"https://api.mistral.ai\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 0.5, output: 1.5, cacheRead: 0.05, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 262144 }, \"mistral-large-latest\": { id: \"mistral-large-latest\", name: \"Mistral Large (latest)\", api: \"mistral-conversations\", provider: \"mistral\", baseUrl: \"https://api.mistral.ai\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 0.5, output: 1.5, cacheRead: 0.05, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 262144 }, \"mistral-medium-2505\": { id: \"mistral-medium-2505\", name: \"Mistral Medium 3\", api: \"mistral-conversations\", provider: \"mistral\", baseUrl: \"https://api.mistral.ai\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 0.4, output: 2, cacheRead: 0.04, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 131072 }, \"mistral-medium-2508\": { id: \"mistral-medium-2508\", name: \"Mistral Medium 3.1\", api: \"mistral-conversations\", provider: \"mistral\", baseUrl: \"https://api.mistral.ai\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 0.4, output: 2, cacheRead: 0.04, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 262144 }, \"mistral-medium-2604\": { id: \"mistral-medium-2604\", name: \"Mistral Medium 3.5\", api: \"mistral-conversations\", provider: \"mistral\", baseUrl: \"https://api.mistral.ai\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.5, output: 7.5, cacheRead: 0.15, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 262144 }, \"mistral-medium-3.5\": { id: \"mistral-medium-3.5\", name: \"Mistral Medium 3.5\", api: \"mistral-conversations\", provider: \"mistral\", baseUrl: \"https://api.mistral.ai\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.5, output: 7.5, cacheRead: 0, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 262144 }, \"mistral-medium-latest\": { id: \"mistral-medium-latest\", name: \"Mistral Medium (latest)\", api: \"mistral-conversations\", provider: \"mistral\", baseUrl: \"https://api.mistral.ai\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.5, output: 7.5, cacheRead: 0.15, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 262144 }, \"mistral-nemo\": { id: \"mistral-nemo\", name: \"Mistral Nemo\", api: \"mistral-conversations\", provider: \"mistral\", baseUrl: \"https://api.mistral.ai\", reasoning: false, input: [\"text\"], cost: { input: 0.15, output: 0.15, cacheRead: 0.015, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 128e3 }, \"mistral-small-2506\": { id: \"mistral-small-2506\", name: \"Mistral Small 3.2\", api: \"mistral-conversations\", provider: \"mistral\", baseUrl: \"https://api.mistral.ai\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 0.1, output: 0.3, cacheRead: 0.01, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 16384 }, \"mistral-small-2603\": { id: \"mistral-small-2603\", name: \"Mistral Small 4\", api: \"mistral-conversations\", provider: \"mistral\", baseUrl: \"https://api.mistral.ai\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.15, output: 0.6, cacheRead: 0.015, cacheWrite: 0 }, contextWindow: 256e3, maxTokens: 256e3 }, \"mistral-small-latest\": { id: \"mistral-small-latest\", name: \"Mistral Small (latest)\", api: \"mistral-conversations\", provider: \"mistral\", baseUrl: \"https://api.mistral.ai\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.15, output: 0.6, cacheRead: 0.015, cacheWrite: 0 }, contextWindow: 256e3, maxTokens: 256e3 }, \"open-mistral-7b\": { id: \"open-mistral-7b\", name: \"Mistral 7B\", api: \"mistral-conversations\", provider: \"mistral\", baseUrl: \"https://api.mistral.ai\", reasoning: false, input: [\"text\"], cost: { input: 0.25, output: 0.25, cacheRead: 0.025, cacheWrite: 0 }, contextWindow: 8e3, maxTokens: 8e3 }, \"open-mistral-nemo\": { id: \"open-mistral-nemo\", name: \"Open Mistral Nemo\", api: \"mistral-conversations\", provider: \"mistral\", baseUrl: \"https://api.mistral.ai\", reasoning: false, input: [\"text\"], cost: { input: 0.15, output: 0.15, cacheRead: 0.015, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 128e3 }, \"open-mixtral-8x22b\": { id: \"open-mixtral-8x22b\", name: \"Mixtral 8x22B\", api: \"mistral-conversations\", provider: \"mistral\", baseUrl: \"https://api.mistral.ai\", reasoning: false, input: [\"text\"], cost: { input: 2, output: 6, cacheRead: 0.2, cacheWrite: 0 }, contextWindow: 64e3, maxTokens: 64e3 }, \"open-mixtral-8x7b\": { id: \"open-mixtral-8x7b\", name: \"Mixtral 8x7B\", api: \"mistral-conversations\", provider: \"mistral\", baseUrl: \"https://api.mistral.ai\", reasoning: false, input: [\"text\"], cost: { input: 0.7, output: 0.7, cacheRead: 0.07, cacheWrite: 0 }, contextWindow: 32e3, maxTokens: 32e3 }, \"pixtral-12b\": { id: \"pixtral-12b\", name: \"Pixtral 12B\", api: \"mistral-conversations\", provider: \"mistral\", baseUrl: \"https://api.mistral.ai\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 0.15, output: 0.15, cacheRead: 0.015, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 128e3 }, \"pixtral-large-latest\": { id: \"pixtral-large-latest\", name: \"Pixtral Large (latest)\", api: \"mistral-conversations\", provider: \"mistral\", baseUrl: \"https://api.mistral.ai\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 2, output: 6, cacheRead: 0.2, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 128e3 }, \"voxtral-small-latest\": { id: \"voxtral-small-latest\", name: \"Voxtral Small (latest)\", api: \"mistral-conversations\", provider: \"mistral\", baseUrl: \"https://api.mistral.ai\", reasoning: false, input: [\"text\"], cost: { input: 0.1, output: 0.3, cacheRead: 0.01, cacheWrite: 0 }, contextWindow: 32e3, maxTokens: 32e3 } } };\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/mistral.models.js\nvar MISTRAL_MODELS = flattenModelCatalog(\"mistral\", mistral_default);\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/data/moonshotai.json\nvar moonshotai_default = { \"openai-completions\": { \"kimi-k2-0711-preview\": { id: \"kimi-k2-0711-preview\", name: \"Kimi K2 0711\", api: \"openai-completions\", provider: \"moonshotai\", baseUrl: \"https://api.moonshot.ai/v1\", reasoning: false, input: [\"text\"], cost: { input: 0.6, output: 2.5, cacheRead: 0.15, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 16384, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false, maxTokensField: \"max_tokens\", supportsStrictMode: false, thinkingFormat: \"deepseek\" } }, \"kimi-k2-0905-preview\": { id: \"kimi-k2-0905-preview\", name: \"Kimi K2 0905\", api: \"openai-completions\", provider: \"moonshotai\", baseUrl: \"https://api.moonshot.ai/v1\", reasoning: false, input: [\"text\"], cost: { input: 0.6, output: 2.5, cacheRead: 0.15, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 262144, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false, maxTokensField: \"max_tokens\", supportsStrictMode: false, thinkingFormat: \"deepseek\" } }, \"kimi-k2-thinking\": { id: \"kimi-k2-thinking\", name: \"Kimi K2 Thinking\", api: \"openai-completions\", provider: \"moonshotai\", baseUrl: \"https://api.moonshot.ai/v1\", reasoning: true, input: [\"text\"], cost: { input: 0.6, output: 2.5, cacheRead: 0.15, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 262144, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false, maxTokensField: \"max_tokens\", supportsStrictMode: false, thinkingFormat: \"deepseek\" } }, \"kimi-k2-thinking-turbo\": { id: \"kimi-k2-thinking-turbo\", name: \"Kimi K2 Thinking Turbo\", api: \"openai-completions\", provider: \"moonshotai\", baseUrl: \"https://api.moonshot.ai/v1\", reasoning: true, input: [\"text\"], cost: { input: 1.15, output: 8, cacheRead: 0.15, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 262144, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false, maxTokensField: \"max_tokens\", supportsStrictMode: false, thinkingFormat: \"deepseek\" } }, \"kimi-k2-turbo-preview\": { id: \"kimi-k2-turbo-preview\", name: \"Kimi K2 Turbo\", api: \"openai-completions\", provider: \"moonshotai\", baseUrl: \"https://api.moonshot.ai/v1\", reasoning: false, input: [\"text\"], cost: { input: 2.4, output: 10, cacheRead: 0.6, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 262144, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false, maxTokensField: \"max_tokens\", supportsStrictMode: false, thinkingFormat: \"deepseek\" } }, \"kimi-k2.5\": { id: \"kimi-k2.5\", name: \"Kimi K2.5\", api: \"openai-completions\", provider: \"moonshotai\", baseUrl: \"https://api.moonshot.ai/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.6, output: 3, cacheRead: 0.1, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 262144, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false, maxTokensField: \"max_tokens\", supportsStrictMode: false, thinkingFormat: \"deepseek\" } }, \"kimi-k2.6\": { id: \"kimi-k2.6\", name: \"Kimi K2.6\", api: \"openai-completions\", provider: \"moonshotai\", baseUrl: \"https://api.moonshot.ai/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.95, output: 4, cacheRead: 0.16, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 262144, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false, maxTokensField: \"max_tokens\", supportsStrictMode: false, thinkingFormat: \"deepseek\" } }, \"kimi-k2.7-code\": { id: \"kimi-k2.7-code\", name: \"Kimi K2.7 Code\", api: \"openai-completions\", provider: \"moonshotai\", baseUrl: \"https://api.moonshot.ai/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.95, output: 4, cacheRead: 0.19, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 262144, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false, maxTokensField: \"max_tokens\", supportsStrictMode: false, thinkingFormat: \"deepseek\" }, thinkingLevelMap: { off: null } }, \"kimi-k2.7-code-highspeed\": { id: \"kimi-k2.7-code-highspeed\", name: \"Kimi K2.7 Code HighSpeed\", api: \"openai-completions\", provider: \"moonshotai\", baseUrl: \"https://api.moonshot.ai/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.9, output: 8, cacheRead: 0.38, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 262144, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false, maxTokensField: \"max_tokens\", supportsStrictMode: false, thinkingFormat: \"deepseek\" }, thinkingLevelMap: { off: null } }, \"kimi-k3\": { id: \"kimi-k3\", name: \"Kimi K3\", api: \"openai-completions\", provider: \"moonshotai\", baseUrl: \"https://api.moonshot.ai/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 131072, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: true, maxTokensField: \"max_tokens\", supportsStrictMode: false, thinkingFormat: \"openai\", requiresReasoningContentOnAssistantMessages: true, deferredToolsMode: \"kimi\" }, thinkingLevelMap: { off: null, minimal: null, low: \"low\", medium: null, high: \"high\", xhigh: null, max: \"max\" } } } };\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/moonshotai.models.js\nvar MOONSHOTAI_MODELS = flattenModelCatalog(\"moonshotai\", moonshotai_default);\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/data/moonshotai-cn.json\nvar moonshotai_cn_default = { \"openai-completions\": { \"kimi-k2-0711-preview\": { id: \"kimi-k2-0711-preview\", name: \"Kimi K2 0711\", api: \"openai-completions\", provider: \"moonshotai-cn\", baseUrl: \"https://api.moonshot.cn/v1\", reasoning: false, input: [\"text\"], cost: { input: 0.6, output: 2.5, cacheRead: 0.15, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 16384, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false, maxTokensField: \"max_tokens\", supportsStrictMode: false, thinkingFormat: \"deepseek\" } }, \"kimi-k2-0905-preview\": { id: \"kimi-k2-0905-preview\", name: \"Kimi K2 0905\", api: \"openai-completions\", provider: \"moonshotai-cn\", baseUrl: \"https://api.moonshot.cn/v1\", reasoning: false, input: [\"text\"], cost: { input: 0.6, output: 2.5, cacheRead: 0.15, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 262144, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false, maxTokensField: \"max_tokens\", supportsStrictMode: false, thinkingFormat: \"deepseek\" } }, \"kimi-k2-thinking\": { id: \"kimi-k2-thinking\", name: \"Kimi K2 Thinking\", api: \"openai-completions\", provider: \"moonshotai-cn\", baseUrl: \"https://api.moonshot.cn/v1\", reasoning: true, input: [\"text\"], cost: { input: 0.6, output: 2.5, cacheRead: 0.15, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 262144, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false, maxTokensField: \"max_tokens\", supportsStrictMode: false, thinkingFormat: \"deepseek\" } }, \"kimi-k2-thinking-turbo\": { id: \"kimi-k2-thinking-turbo\", name: \"Kimi K2 Thinking Turbo\", api: \"openai-completions\", provider: \"moonshotai-cn\", baseUrl: \"https://api.moonshot.cn/v1\", reasoning: true, input: [\"text\"], cost: { input: 1.15, output: 8, cacheRead: 0.15, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 262144, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false, maxTokensField: \"max_tokens\", supportsStrictMode: false, thinkingFormat: \"deepseek\" } }, \"kimi-k2-turbo-preview\": { id: \"kimi-k2-turbo-preview\", name: \"Kimi K2 Turbo\", api: \"openai-completions\", provider: \"moonshotai-cn\", baseUrl: \"https://api.moonshot.cn/v1\", reasoning: false, input: [\"text\"], cost: { input: 2.4, output: 10, cacheRead: 0.6, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 262144, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false, maxTokensField: \"max_tokens\", supportsStrictMode: false, thinkingFormat: \"deepseek\" } }, \"kimi-k2.5\": { id: \"kimi-k2.5\", name: \"Kimi K2.5\", api: \"openai-completions\", provider: \"moonshotai-cn\", baseUrl: \"https://api.moonshot.cn/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.6, output: 3, cacheRead: 0.1, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 262144, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false, maxTokensField: \"max_tokens\", supportsStrictMode: false, thinkingFormat: \"deepseek\" } }, \"kimi-k2.6\": { id: \"kimi-k2.6\", name: \"Kimi K2.6\", api: \"openai-completions\", provider: \"moonshotai-cn\", baseUrl: \"https://api.moonshot.cn/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.95, output: 4, cacheRead: 0.16, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 262144, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false, maxTokensField: \"max_tokens\", supportsStrictMode: false, thinkingFormat: \"deepseek\" } }, \"kimi-k2.7-code\": { id: \"kimi-k2.7-code\", name: \"Kimi K2.7 Code\", api: \"openai-completions\", provider: \"moonshotai-cn\", baseUrl: \"https://api.moonshot.cn/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.95, output: 4, cacheRead: 0.19, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 262144, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false, maxTokensField: \"max_tokens\", supportsStrictMode: false, thinkingFormat: \"deepseek\" }, thinkingLevelMap: { off: null } }, \"kimi-k2.7-code-highspeed\": { id: \"kimi-k2.7-code-highspeed\", name: \"Kimi K2.7 Code HighSpeed\", api: \"openai-completions\", provider: \"moonshotai-cn\", baseUrl: \"https://api.moonshot.cn/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.9, output: 8, cacheRead: 0.38, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 262144, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false, maxTokensField: \"max_tokens\", supportsStrictMode: false, thinkingFormat: \"deepseek\" }, thinkingLevelMap: { off: null } }, \"kimi-k3\": { id: \"kimi-k3\", name: \"Kimi K3\", api: \"openai-completions\", provider: \"moonshotai-cn\", baseUrl: \"https://api.moonshot.cn/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 131072, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: true, maxTokensField: \"max_tokens\", supportsStrictMode: false, thinkingFormat: \"openai\", requiresReasoningContentOnAssistantMessages: true, deferredToolsMode: \"kimi\" }, thinkingLevelMap: { off: null, minimal: null, low: \"low\", medium: null, high: \"high\", xhigh: null, max: \"max\" } } } };\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/moonshotai-cn.models.js\nvar MOONSHOTAI_CN_MODELS = flattenModelCatalog(\"moonshotai-cn\", moonshotai_cn_default);\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/data/nvidia.json\nvar nvidia_default = { \"openai-completions\": { \"google/gemma-3-12b-it\": { id: \"google/gemma-3-12b-it\", name: \"Gemma 3 12B IT\", api: \"openai-completions\", provider: \"nvidia\", baseUrl: \"https://integrate.api.nvidia.com/v1\", headers: { \"NVCF-POLL-SECONDS\": \"3600\" }, reasoning: false, input: [\"text\", \"image\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false, maxTokensField: \"max_tokens\", supportsStrictMode: false, supportsLongCacheRetention: false }, contextWindow: 131072, maxTokens: 16384 }, \"google/gemma-3-4b-it\": { id: \"google/gemma-3-4b-it\", name: \"Gemma 3 4B IT\", api: \"openai-completions\", provider: \"nvidia\", baseUrl: \"https://integrate.api.nvidia.com/v1\", headers: { \"NVCF-POLL-SECONDS\": \"3600\" }, reasoning: false, input: [\"text\", \"image\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false, maxTokensField: \"max_tokens\", supportsStrictMode: false, supportsLongCacheRetention: false }, contextWindow: 131072, maxTokens: 16384 }, \"meta/llama-3.1-70b-instruct\": { id: \"meta/llama-3.1-70b-instruct\", name: \"Llama 3.1 70b Instruct\", api: \"openai-completions\", provider: \"nvidia\", baseUrl: \"https://integrate.api.nvidia.com/v1\", headers: { \"NVCF-POLL-SECONDS\": \"3600\" }, reasoning: false, input: [\"text\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false, maxTokensField: \"max_tokens\", supportsStrictMode: false, supportsLongCacheRetention: false }, contextWindow: 128e3, maxTokens: 4096 }, \"meta/llama-3.1-8b-instruct\": { id: \"meta/llama-3.1-8b-instruct\", name: \"Llama 3.1 8B Instruct\", api: \"openai-completions\", provider: \"nvidia\", baseUrl: \"https://integrate.api.nvidia.com/v1\", headers: { \"NVCF-POLL-SECONDS\": \"3600\" }, reasoning: false, input: [\"text\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false, maxTokensField: \"max_tokens\", supportsStrictMode: false, supportsLongCacheRetention: false }, contextWindow: 16e3, maxTokens: 4096 }, \"meta/llama-3.2-11b-vision-instruct\": { id: \"meta/llama-3.2-11b-vision-instruct\", name: \"Llama 3.2 11b Vision Instruct\", api: \"openai-completions\", provider: \"nvidia\", baseUrl: \"https://integrate.api.nvidia.com/v1\", headers: { \"NVCF-POLL-SECONDS\": \"3600\" }, reasoning: false, input: [\"text\", \"image\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false, maxTokensField: \"max_tokens\", supportsStrictMode: false, supportsLongCacheRetention: false }, contextWindow: 128e3, maxTokens: 4096 }, \"meta/llama-3.2-90b-vision-instruct\": { id: \"meta/llama-3.2-90b-vision-instruct\", name: \"Llama-3.2-90B-Vision-Instruct\", api: \"openai-completions\", provider: \"nvidia\", baseUrl: \"https://integrate.api.nvidia.com/v1\", headers: { \"NVCF-POLL-SECONDS\": \"3600\" }, reasoning: false, input: [\"text\", \"image\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false, maxTokensField: \"max_tokens\", supportsStrictMode: false, supportsLongCacheRetention: false }, contextWindow: 128e3, maxTokens: 8192 }, \"meta/llama-3.3-70b-instruct\": { id: \"meta/llama-3.3-70b-instruct\", name: \"Llama 3.3 70b Instruct\", api: \"openai-completions\", provider: \"nvidia\", baseUrl: \"https://integrate.api.nvidia.com/v1\", headers: { \"NVCF-POLL-SECONDS\": \"3600\" }, reasoning: false, input: [\"text\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false, maxTokensField: \"max_tokens\", supportsStrictMode: false, supportsLongCacheRetention: false }, contextWindow: 128e3, maxTokens: 4096 }, \"minimaxai/minimax-m3\": { id: \"minimaxai/minimax-m3\", name: \"MiniMax-M3\", api: \"openai-completions\", provider: \"nvidia\", baseUrl: \"https://integrate.api.nvidia.com/v1\", headers: { \"NVCF-POLL-SECONDS\": \"3600\" }, reasoning: true, input: [\"text\", \"image\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false, maxTokensField: \"max_tokens\", supportsStrictMode: false, supportsLongCacheRetention: false }, contextWindow: 1e6, maxTokens: 16384 }, \"mistralai/mistral-7b-instruct-v0.3\": { id: \"mistralai/mistral-7b-instruct-v0.3\", name: \"Mistral-7B-Instruct-v0.3\", api: \"openai-completions\", provider: \"nvidia\", baseUrl: \"https://integrate.api.nvidia.com/v1\", headers: { \"NVCF-POLL-SECONDS\": \"3600\" }, reasoning: false, input: [\"text\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false, maxTokensField: \"max_tokens\", supportsStrictMode: false, supportsLongCacheRetention: false }, contextWindow: 65536, maxTokens: 65536 }, \"moonshotai/kimi-k2.6\": { id: \"moonshotai/kimi-k2.6\", name: \"Kimi K2.6\", api: \"openai-completions\", provider: \"nvidia\", baseUrl: \"https://integrate.api.nvidia.com/v1\", headers: { \"NVCF-POLL-SECONDS\": \"3600\" }, reasoning: true, input: [\"text\", \"image\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false, maxTokensField: \"max_tokens\", supportsStrictMode: false, supportsLongCacheRetention: false }, contextWindow: 262144, maxTokens: 262144 }, \"nvidia/cosmos-reason2-8b\": { id: \"nvidia/cosmos-reason2-8b\", name: \"Cosmos Reason2 8B\", api: \"openai-completions\", provider: \"nvidia\", baseUrl: \"https://integrate.api.nvidia.com/v1\", headers: { \"NVCF-POLL-SECONDS\": \"3600\" }, reasoning: true, input: [\"text\", \"image\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false, maxTokensField: \"max_tokens\", supportsStrictMode: false, supportsLongCacheRetention: false }, contextWindow: 131072, maxTokens: 16384 }, \"nvidia/llama-3.1-nemotron-70b-instruct\": { id: \"nvidia/llama-3.1-nemotron-70b-instruct\", name: \"Llama 3.1 Nemotron 70B Instruct\", api: \"openai-completions\", provider: \"nvidia\", baseUrl: \"https://integrate.api.nvidia.com/v1\", headers: { \"NVCF-POLL-SECONDS\": \"3600\" }, reasoning: false, input: [\"text\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false, maxTokensField: \"max_tokens\", supportsStrictMode: false, supportsLongCacheRetention: false }, contextWindow: 128e3, maxTokens: 8192 }, \"nvidia/llama-3.1-nemotron-nano-8b-v1\": { id: \"nvidia/llama-3.1-nemotron-nano-8b-v1\", name: \"Llama 3.1 Nemotron Nano 8B v1\", api: \"openai-completions\", provider: \"nvidia\", baseUrl: \"https://integrate.api.nvidia.com/v1\", headers: { \"NVCF-POLL-SECONDS\": \"3600\" }, reasoning: true, input: [\"text\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false, maxTokensField: \"max_tokens\", supportsStrictMode: false, supportsLongCacheRetention: false }, contextWindow: 131072, maxTokens: 16384 }, \"nvidia/llama-3.1-nemotron-nano-vl-8b-v1\": { id: \"nvidia/llama-3.1-nemotron-nano-vl-8b-v1\", name: \"Llama 3.1 Nemotron Nano VL 8B v1\", api: \"openai-completions\", provider: \"nvidia\", baseUrl: \"https://integrate.api.nvidia.com/v1\", headers: { \"NVCF-POLL-SECONDS\": \"3600\" }, reasoning: true, input: [\"text\", \"image\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false, maxTokensField: \"max_tokens\", supportsStrictMode: false, supportsLongCacheRetention: false }, contextWindow: 32768, maxTokens: 16384 }, \"nvidia/llama-3.1-nemotron-ultra-253b-v1\": { id: \"nvidia/llama-3.1-nemotron-ultra-253b-v1\", name: \"Llama 3.1 Nemotron Ultra 253B\", api: \"openai-completions\", provider: \"nvidia\", baseUrl: \"https://integrate.api.nvidia.com/v1\", headers: { \"NVCF-POLL-SECONDS\": \"3600\" }, reasoning: true, input: [\"text\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false, maxTokensField: \"max_tokens\", supportsStrictMode: false, supportsLongCacheRetention: false }, contextWindow: 128e3, maxTokens: 16384 }, \"nvidia/llama-3.3-nemotron-super-49b-v1\": { id: \"nvidia/llama-3.3-nemotron-super-49b-v1\", name: \"Llama 3.3 Nemotron Super 49B v1\", api: \"openai-completions\", provider: \"nvidia\", baseUrl: \"https://integrate.api.nvidia.com/v1\", headers: { \"NVCF-POLL-SECONDS\": \"3600\" }, reasoning: true, input: [\"text\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false, maxTokensField: \"max_tokens\", supportsStrictMode: false, supportsLongCacheRetention: false }, contextWindow: 131072, maxTokens: 65536 }, \"nvidia/llama-3.3-nemotron-super-49b-v1.5\": { id: \"nvidia/llama-3.3-nemotron-super-49b-v1.5\", name: \"Llama 3.3 Nemotron Super 49B v1.5\", api: \"openai-completions\", provider: \"nvidia\", baseUrl: \"https://integrate.api.nvidia.com/v1\", headers: { \"NVCF-POLL-SECONDS\": \"3600\" }, reasoning: true, input: [\"text\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false, maxTokensField: \"max_tokens\", supportsStrictMode: false, supportsLongCacheRetention: false }, contextWindow: 131072, maxTokens: 65536 }, \"nvidia/nemotron-3-nano-30b-a3b\": { id: \"nvidia/nemotron-3-nano-30b-a3b\", name: \"nemotron-3-nano-30b-a3b\", api: \"openai-completions\", provider: \"nvidia\", baseUrl: \"https://integrate.api.nvidia.com/v1\", headers: { \"NVCF-POLL-SECONDS\": \"3600\" }, reasoning: true, input: [\"text\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false, maxTokensField: \"max_tokens\", supportsStrictMode: false, supportsLongCacheRetention: false }, contextWindow: 131072, maxTokens: 131072 }, \"nvidia/nemotron-3-nano-omni-30b-a3b-reasoning\": { id: \"nvidia/nemotron-3-nano-omni-30b-a3b-reasoning\", name: \"Nemotron 3 Nano Omni\", api: \"openai-completions\", provider: \"nvidia\", baseUrl: \"https://integrate.api.nvidia.com/v1\", headers: { \"NVCF-POLL-SECONDS\": \"3600\" }, reasoning: true, input: [\"text\", \"image\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false, maxTokensField: \"max_tokens\", supportsStrictMode: false, supportsLongCacheRetention: false }, contextWindow: 256e3, maxTokens: 65536 }, \"nvidia/nemotron-3-super-120b-a12b\": { id: \"nvidia/nemotron-3-super-120b-a12b\", name: \"Nemotron 3 Super\", api: \"openai-completions\", provider: \"nvidia\", baseUrl: \"https://integrate.api.nvidia.com/v1\", headers: { \"NVCF-POLL-SECONDS\": \"3600\" }, reasoning: true, input: [\"text\"], cost: { input: 0.2, output: 0.8, cacheRead: 0, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false, maxTokensField: \"max_tokens\", supportsStrictMode: false, supportsLongCacheRetention: false }, contextWindow: 262144, maxTokens: 262144 }, \"nvidia/nemotron-3-ultra-550b-a55b\": { id: \"nvidia/nemotron-3-ultra-550b-a55b\", name: \"Nemotron 3 Ultra 550B A55B\", api: \"openai-completions\", provider: \"nvidia\", baseUrl: \"https://integrate.api.nvidia.com/v1\", headers: { \"NVCF-POLL-SECONDS\": \"3600\" }, reasoning: true, input: [\"text\"], cost: { input: 0.5, output: 2.5, cacheRead: 0.15, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false, maxTokensField: \"max_tokens\", supportsStrictMode: false, supportsLongCacheRetention: false }, contextWindow: 1e6, maxTokens: 65536 }, \"nvidia/nemotron-3.5-lightning-30b-a3b\": { id: \"nvidia/nemotron-3.5-lightning-30b-a3b\", name: \"Nemotron 3.5 Lightning 30B A3B\", api: \"openai-completions\", provider: \"nvidia\", baseUrl: \"https://integrate.api.nvidia.com/v1\", headers: { \"NVCF-POLL-SECONDS\": \"3600\" }, reasoning: true, input: [\"text\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false, maxTokensField: \"max_tokens\", supportsStrictMode: false, supportsLongCacheRetention: false }, contextWindow: 262144, maxTokens: 262144 }, \"nvidia/nemotron-nano-12b-v2-vl\": { id: \"nvidia/nemotron-nano-12b-v2-vl\", name: \"Nemotron Nano 12B v2 VL\", api: \"openai-completions\", provider: \"nvidia\", baseUrl: \"https://integrate.api.nvidia.com/v1\", headers: { \"NVCF-POLL-SECONDS\": \"3600\" }, reasoning: true, input: [\"text\", \"image\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false, maxTokensField: \"max_tokens\", supportsStrictMode: false, supportsLongCacheRetention: false }, contextWindow: 128e3, maxTokens: 128e3 }, \"nvidia/nvidia-nemotron-nano-9b-v2\": { id: \"nvidia/nvidia-nemotron-nano-9b-v2\", name: \"nvidia-nemotron-nano-9b-v2\", api: \"openai-completions\", provider: \"nvidia\", baseUrl: \"https://integrate.api.nvidia.com/v1\", headers: { \"NVCF-POLL-SECONDS\": \"3600\" }, reasoning: true, input: [\"text\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false, maxTokensField: \"max_tokens\", supportsStrictMode: false, supportsLongCacheRetention: false }, contextWindow: 131072, maxTokens: 131072 }, \"openai/gpt-oss-120b\": { id: \"openai/gpt-oss-120b\", name: \"GPT-OSS-120B\", api: \"openai-completions\", provider: \"nvidia\", baseUrl: \"https://integrate.api.nvidia.com/v1\", headers: { \"NVCF-POLL-SECONDS\": \"3600\" }, reasoning: true, input: [\"text\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false, maxTokensField: \"max_tokens\", supportsStrictMode: false, supportsLongCacheRetention: false }, contextWindow: 128e3, maxTokens: 8192 }, \"openai/gpt-oss-20b\": { id: \"openai/gpt-oss-20b\", name: \"GPT OSS 20B\", api: \"openai-completions\", provider: \"nvidia\", baseUrl: \"https://integrate.api.nvidia.com/v1\", headers: { \"NVCF-POLL-SECONDS\": \"3600\" }, reasoning: true, input: [\"text\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false, maxTokensField: \"max_tokens\", supportsStrictMode: false, supportsLongCacheRetention: false }, contextWindow: 131072, maxTokens: 32768 }, \"poolside/laguna-xs-2.1\": { id: \"poolside/laguna-xs-2.1\", name: \"Laguna XS 2.1\", api: \"openai-completions\", provider: \"nvidia\", baseUrl: \"https://integrate.api.nvidia.com/v1\", headers: { \"NVCF-POLL-SECONDS\": \"3600\" }, reasoning: true, input: [\"text\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false, maxTokensField: \"max_tokens\", supportsStrictMode: false, supportsLongCacheRetention: false }, contextWindow: 262144, maxTokens: 16384 }, \"stepfun-ai/step-3.7-flash\": { id: \"stepfun-ai/step-3.7-flash\", name: \"Step 3.7 Flash\", api: \"openai-completions\", provider: \"nvidia\", baseUrl: \"https://integrate.api.nvidia.com/v1\", headers: { \"NVCF-POLL-SECONDS\": \"3600\" }, reasoning: true, input: [\"text\", \"image\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false, maxTokensField: \"max_tokens\", supportsStrictMode: false, supportsLongCacheRetention: false }, contextWindow: 256e3, maxTokens: 16384 }, \"thinkingmachines/inkling\": { id: \"thinkingmachines/inkling\", name: \"Inkling\", api: \"openai-completions\", provider: \"nvidia\", baseUrl: \"https://integrate.api.nvidia.com/v1\", headers: { \"NVCF-POLL-SECONDS\": \"3600\" }, reasoning: true, input: [\"text\", \"image\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false, maxTokensField: \"max_tokens\", supportsStrictMode: false, supportsLongCacheRetention: false }, contextWindow: 1048576, maxTokens: 16384 }, \"z-ai/glm-5.2\": { id: \"z-ai/glm-5.2\", name: \"GLM-5.2\", api: \"openai-completions\", provider: \"nvidia\", baseUrl: \"https://integrate.api.nvidia.com/v1\", headers: { \"NVCF-POLL-SECONDS\": \"3600\" }, reasoning: true, input: [\"text\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false, maxTokensField: \"max_tokens\", supportsStrictMode: false, supportsLongCacheRetention: false }, contextWindow: 1e6, maxTokens: 131072 } } };\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/nvidia.models.js\nvar NVIDIA_MODELS = flattenModelCatalog(\"nvidia\", nvidia_default);\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/data/openai.json\nvar openai_default = { \"openai-responses\": { \"gpt-4\": { id: \"gpt-4\", name: \"GPT-4\", api: \"openai-responses\", provider: \"openai\", baseUrl: \"https://api.openai.com/v1\", reasoning: false, input: [\"text\"], cost: { input: 30, output: 60, cacheRead: 0, cacheWrite: 0 }, contextWindow: 8192, maxTokens: 8192, compat: { supportsStrictMode: true } }, \"gpt-4-turbo\": { id: \"gpt-4-turbo\", name: \"GPT-4 Turbo\", api: \"openai-responses\", provider: \"openai\", baseUrl: \"https://api.openai.com/v1\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 10, output: 30, cacheRead: 0, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 4096, compat: { supportsStrictMode: true } }, \"gpt-4.1\": { id: \"gpt-4.1\", name: \"GPT-4.1\", api: \"openai-responses\", provider: \"openai\", baseUrl: \"https://api.openai.com/v1\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 2, output: 8, cacheRead: 0.5, cacheWrite: 0 }, contextWindow: 1047576, maxTokens: 32768, compat: { supportsStrictMode: true } }, \"gpt-4.1-mini\": { id: \"gpt-4.1-mini\", name: \"GPT-4.1 mini\", api: \"openai-responses\", provider: \"openai\", baseUrl: \"https://api.openai.com/v1\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 0.4, output: 1.6, cacheRead: 0.1, cacheWrite: 0 }, contextWindow: 1047576, maxTokens: 32768, compat: { supportsStrictMode: true } }, \"gpt-4.1-nano\": { id: \"gpt-4.1-nano\", name: \"GPT-4.1 nano\", api: \"openai-responses\", provider: \"openai\", baseUrl: \"https://api.openai.com/v1\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 0.1, output: 0.4, cacheRead: 0.025, cacheWrite: 0 }, contextWindow: 1047576, maxTokens: 32768, compat: { supportsStrictMode: true } }, \"gpt-4o\": { id: \"gpt-4o\", name: \"GPT-4o\", api: \"openai-responses\", provider: \"openai\", baseUrl: \"https://api.openai.com/v1\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 2.5, output: 10, cacheRead: 1.25, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 16384, compat: { supportsStrictMode: true } }, \"gpt-4o-2024-05-13\": { id: \"gpt-4o-2024-05-13\", name: \"GPT-4o (2024-05-13)\", api: \"openai-responses\", provider: \"openai\", baseUrl: \"https://api.openai.com/v1\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 5, output: 15, cacheRead: 0, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 4096, compat: { supportsStrictMode: true } }, \"gpt-4o-2024-08-06\": { id: \"gpt-4o-2024-08-06\", name: \"GPT-4o (2024-08-06)\", api: \"openai-responses\", provider: \"openai\", baseUrl: \"https://api.openai.com/v1\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 2.5, output: 10, cacheRead: 1.25, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 16384, compat: { supportsStrictMode: true } }, \"gpt-4o-2024-11-20\": { id: \"gpt-4o-2024-11-20\", name: \"GPT-4o (2024-11-20)\", api: \"openai-responses\", provider: \"openai\", baseUrl: \"https://api.openai.com/v1\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 2.5, output: 10, cacheRead: 1.25, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 16384, compat: { supportsStrictMode: true } }, \"gpt-4o-mini\": { id: \"gpt-4o-mini\", name: \"GPT-4o mini\", api: \"openai-responses\", provider: \"openai\", baseUrl: \"https://api.openai.com/v1\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 0.15, output: 0.6, cacheRead: 0.075, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 16384, compat: { supportsStrictMode: true } }, \"gpt-5\": { id: \"gpt-5\", name: \"GPT-5\", api: \"openai-responses\", provider: \"openai\", baseUrl: \"https://api.openai.com/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.25, output: 10, cacheRead: 0.125, cacheWrite: 0 }, contextWindow: 4e5, maxTokens: 128e3, thinkingLevelMap: { off: null, minimal: \"minimal\", low: \"low\", medium: \"medium\", high: \"high\", xhigh: null, max: null }, compat: { supportsStrictMode: true, supportsOpenAIGrammarTools: true } }, \"gpt-5-chat-latest\": { id: \"gpt-5-chat-latest\", name: \"GPT-5 Chat Latest\", api: \"openai-responses\", baseUrl: \"https://api.openai.com/v1\", provider: \"openai\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 1.25, output: 10, cacheRead: 0.125, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 16384, thinkingLevelMap: { off: null }, compat: { supportsStrictMode: true, supportsOpenAIGrammarTools: true } }, \"gpt-5-mini\": { id: \"gpt-5-mini\", name: \"GPT-5 Mini\", api: \"openai-responses\", provider: \"openai\", baseUrl: \"https://api.openai.com/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.25, output: 2, cacheRead: 0.025, cacheWrite: 0 }, contextWindow: 4e5, maxTokens: 128e3, thinkingLevelMap: { off: null, minimal: \"minimal\", low: \"low\", medium: \"medium\", high: \"high\", xhigh: null, max: null }, compat: { supportsStrictMode: true, supportsOpenAIGrammarTools: true } }, \"gpt-5-nano\": { id: \"gpt-5-nano\", name: \"GPT-5 Nano\", api: \"openai-responses\", provider: \"openai\", baseUrl: \"https://api.openai.com/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.05, output: 0.4, cacheRead: 5e-3, cacheWrite: 0 }, contextWindow: 4e5, maxTokens: 128e3, thinkingLevelMap: { off: null, minimal: \"minimal\", low: \"low\", medium: \"medium\", high: \"high\", xhigh: null, max: null }, compat: { supportsStrictMode: true, supportsOpenAIGrammarTools: true } }, \"gpt-5-pro\": { id: \"gpt-5-pro\", name: \"GPT-5 Pro\", api: \"openai-responses\", provider: \"openai\", baseUrl: \"https://api.openai.com/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 15, output: 120, cacheRead: 0, cacheWrite: 0 }, contextWindow: 4e5, maxTokens: 128e3, thinkingLevelMap: { off: null, minimal: null, low: null, medium: null, high: \"high\", xhigh: null, max: null }, compat: { supportsStrictMode: true, supportsOpenAIGrammarTools: true } }, \"gpt-5.1\": { id: \"gpt-5.1\", name: \"GPT-5.1\", api: \"openai-responses\", provider: \"openai\", baseUrl: \"https://api.openai.com/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.25, output: 10, cacheRead: 0.125, cacheWrite: 0 }, contextWindow: 4e5, maxTokens: 128e3, thinkingLevelMap: { off: \"none\", minimal: null, low: \"low\", medium: \"medium\", high: \"high\", xhigh: null, max: null }, compat: { supportsStrictMode: true, supportsOpenAIGrammarTools: true } }, \"gpt-5.2\": { id: \"gpt-5.2\", name: \"GPT-5.2\", api: \"openai-responses\", provider: \"openai\", baseUrl: \"https://api.openai.com/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.75, output: 14, cacheRead: 0.175, cacheWrite: 0 }, contextWindow: 4e5, maxTokens: 128e3, thinkingLevelMap: { off: \"none\", minimal: null, low: \"low\", medium: \"medium\", high: \"high\", xhigh: \"xhigh\", max: null }, compat: { supportsStrictMode: true, supportsOpenAIGrammarTools: true } }, \"gpt-5.2-chat-latest\": { id: \"gpt-5.2-chat-latest\", name: \"GPT-5.2 Chat\", api: \"openai-responses\", provider: \"openai\", baseUrl: \"https://api.openai.com/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.75, output: 14, cacheRead: 0.175, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 16384, thinkingLevelMap: { off: null, minimal: null, low: null, medium: \"medium\", high: null, xhigh: \"xhigh\", max: null }, compat: { supportsStrictMode: true, supportsOpenAIGrammarTools: true } }, \"gpt-5.2-pro\": { id: \"gpt-5.2-pro\", name: \"GPT-5.2 Pro\", api: \"openai-responses\", provider: \"openai\", baseUrl: \"https://api.openai.com/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 21, output: 168, cacheRead: 0, cacheWrite: 0 }, contextWindow: 4e5, maxTokens: 128e3, thinkingLevelMap: { off: null, minimal: null, low: null, medium: \"medium\", high: \"high\", xhigh: \"xhigh\", max: null }, compat: { supportsStrictMode: true, supportsOpenAIGrammarTools: true } }, \"gpt-5.3-chat-latest\": { id: \"gpt-5.3-chat-latest\", name: \"GPT-5.3 Chat (latest)\", api: \"openai-responses\", provider: \"openai\", baseUrl: \"https://api.openai.com/v1\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 1.75, output: 14, cacheRead: 0.175, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 16384, thinkingLevelMap: { off: null, xhigh: \"xhigh\" }, compat: { supportsStrictMode: true, supportsOpenAIGrammarTools: true } }, \"gpt-5.3-codex\": { id: \"gpt-5.3-codex\", name: \"GPT-5.3 Codex\", api: \"openai-responses\", provider: \"openai\", baseUrl: \"https://api.openai.com/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.75, output: 14, cacheRead: 0.175, cacheWrite: 0 }, contextWindow: 4e5, maxTokens: 128e3, thinkingLevelMap: { off: \"none\", minimal: null, low: \"low\", medium: \"medium\", high: \"high\", xhigh: \"xhigh\", max: null }, compat: { supportsStrictMode: true, supportsOpenAIGrammarTools: true } }, \"gpt-5.3-codex-spark\": { id: \"gpt-5.3-codex-spark\", name: \"GPT-5.3 Codex Spark\", api: \"openai-responses\", provider: \"openai\", baseUrl: \"https://api.openai.com/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.75, output: 14, cacheRead: 0.175, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 32e3, thinkingLevelMap: { off: null, minimal: null, low: \"low\", medium: \"medium\", high: \"high\", xhigh: \"xhigh\", max: null }, compat: { supportsStrictMode: true, supportsOpenAIGrammarTools: true } }, \"gpt-5.4\": { id: \"gpt-5.4\", name: \"GPT-5.4\", api: \"openai-responses\", provider: \"openai\", baseUrl: \"https://api.openai.com/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 2.5, output: 15, cacheRead: 0.25, cacheWrite: 0, tiers: [{ inputTokensAbove: 272e3, input: 5, output: 22.5, cacheRead: 0.5, cacheWrite: 0 }] }, contextWindow: 272e3, maxTokens: 128e3, thinkingLevelMap: { off: \"none\", minimal: null, low: \"low\", medium: \"medium\", high: \"high\", xhigh: \"xhigh\", max: null }, compat: { supportsStrictMode: true, supportsOpenAIGrammarTools: true, supportsAdditionalTools: true, supportsToolSearch: true } }, \"gpt-5.4-mini\": { id: \"gpt-5.4-mini\", name: \"GPT-5.4 mini\", api: \"openai-responses\", provider: \"openai\", baseUrl: \"https://api.openai.com/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.75, output: 4.5, cacheRead: 0.075, cacheWrite: 0 }, contextWindow: 4e5, maxTokens: 128e3, thinkingLevelMap: { off: \"none\", minimal: null, low: \"low\", medium: \"medium\", high: \"high\", xhigh: \"xhigh\", max: null }, compat: { supportsStrictMode: true, supportsOpenAIGrammarTools: true, supportsAdditionalTools: true, supportsToolSearch: true } }, \"gpt-5.4-nano\": { id: \"gpt-5.4-nano\", name: \"GPT-5.4 nano\", api: \"openai-responses\", provider: \"openai\", baseUrl: \"https://api.openai.com/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.2, output: 1.25, cacheRead: 0.02, cacheWrite: 0 }, contextWindow: 4e5, maxTokens: 128e3, thinkingLevelMap: { off: \"none\", minimal: null, low: \"low\", medium: \"medium\", high: \"high\", xhigh: \"xhigh\", max: null }, compat: { supportsStrictMode: true, supportsOpenAIGrammarTools: true } }, \"gpt-5.4-pro\": { id: \"gpt-5.4-pro\", name: \"GPT-5.4 Pro\", api: \"openai-responses\", provider: \"openai\", baseUrl: \"https://api.openai.com/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 30, output: 180, cacheRead: 0, cacheWrite: 0, tiers: [{ inputTokensAbove: 272e3, input: 60, output: 270, cacheRead: 0, cacheWrite: 0 }] }, contextWindow: 105e4, maxTokens: 128e3, thinkingLevelMap: { off: null, minimal: null, low: null, medium: \"medium\", high: \"high\", xhigh: \"xhigh\", max: null }, compat: { supportsStrictMode: true, supportsOpenAIGrammarTools: true, supportsAdditionalTools: true, supportsToolSearch: true } }, \"gpt-5.5\": { id: \"gpt-5.5\", name: \"GPT-5.5\", api: \"openai-responses\", provider: \"openai\", baseUrl: \"https://api.openai.com/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 5, output: 30, cacheRead: 0.5, cacheWrite: 0, tiers: [{ inputTokensAbove: 272e3, input: 10, output: 45, cacheRead: 1, cacheWrite: 0 }] }, contextWindow: 272e3, maxTokens: 128e3, thinkingLevelMap: { off: \"none\", minimal: null, low: \"low\", medium: \"medium\", high: \"high\", xhigh: \"xhigh\", max: null }, compat: { supportsStrictMode: true, supportsOpenAIGrammarTools: true, supportsAdditionalTools: true, supportsToolSearch: true } }, \"gpt-5.5-pro\": { id: \"gpt-5.5-pro\", name: \"GPT-5.5 Pro\", api: \"openai-responses\", provider: \"openai\", baseUrl: \"https://api.openai.com/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 30, output: 180, cacheRead: 0, cacheWrite: 0, tiers: [{ inputTokensAbove: 272e3, input: 60, output: 270, cacheRead: 0, cacheWrite: 0 }] }, contextWindow: 105e4, maxTokens: 128e3, thinkingLevelMap: { off: null, minimal: null, low: null, medium: \"medium\", high: \"high\", xhigh: \"xhigh\", max: null }, compat: { supportsStrictMode: true, supportsOpenAIGrammarTools: true } }, \"gpt-5.6-luna\": { id: \"gpt-5.6-luna\", name: \"GPT-5.6 Luna\", api: \"openai-responses\", provider: \"openai\", baseUrl: \"https://api.openai.com/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.2, output: 1.2, cacheRead: 0.02, cacheWrite: 0.25, tiers: [{ inputTokensAbove: 272e3, input: 0.4, output: 1.8, cacheRead: 0.04, cacheWrite: 0.5 }] }, contextWindow: 272e3, maxTokens: 128e3, thinkingLevelMap: { off: \"none\", minimal: null, low: \"low\", medium: \"medium\", high: \"high\", xhigh: \"xhigh\", max: \"max\" }, compat: { supportsStrictMode: true, supportsOpenAIGrammarTools: true, supportsAdditionalTools: true, supportsToolSearch: true, supportsExplicitPromptCacheMode: true } }, \"gpt-5.6-sol\": { id: \"gpt-5.6-sol\", name: \"GPT-5.6 Sol\", api: \"openai-responses\", provider: \"openai\", baseUrl: \"https://api.openai.com/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 5, output: 30, cacheRead: 0.5, cacheWrite: 6.25, tiers: [{ inputTokensAbove: 272e3, input: 10, output: 45, cacheRead: 1, cacheWrite: 12.5 }] }, contextWindow: 272e3, maxTokens: 128e3, thinkingLevelMap: { off: \"none\", minimal: null, low: \"low\", medium: \"medium\", high: \"high\", xhigh: \"xhigh\", max: \"max\" }, compat: { supportsStrictMode: true, supportsOpenAIGrammarTools: true, supportsAdditionalTools: true, supportsToolSearch: true, supportsExplicitPromptCacheMode: true } }, \"gpt-5.6-terra\": { id: \"gpt-5.6-terra\", name: \"GPT-5.6 Terra\", api: \"openai-responses\", provider: \"openai\", baseUrl: \"https://api.openai.com/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 2, output: 12, cacheRead: 0.2, cacheWrite: 2.5, tiers: [{ inputTokensAbove: 272e3, input: 4, output: 18, cacheRead: 0.4, cacheWrite: 5 }] }, contextWindow: 272e3, maxTokens: 128e3, thinkingLevelMap: { off: \"none\", minimal: null, low: \"low\", medium: \"medium\", high: \"high\", xhigh: \"xhigh\", max: \"max\" }, compat: { supportsStrictMode: true, supportsOpenAIGrammarTools: true, supportsAdditionalTools: true, supportsToolSearch: true, supportsExplicitPromptCacheMode: true } }, \"gpt-realtime-2.1\": { id: \"gpt-realtime-2.1\", name: \"GPT-Realtime-2.1\", api: \"openai-responses\", provider: \"openai\", baseUrl: \"https://api.openai.com/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 4, output: 24, cacheRead: 0.4, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 32e3, thinkingLevelMap: { off: null, minimal: \"minimal\", low: \"low\", medium: \"medium\", high: \"high\", xhigh: \"xhigh\", max: null }, compat: { supportsStrictMode: true } }, o1: { id: \"o1\", name: \"o1\", api: \"openai-responses\", provider: \"openai\", baseUrl: \"https://api.openai.com/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 15, output: 60, cacheRead: 7.5, cacheWrite: 0 }, contextWindow: 2e5, maxTokens: 1e5, thinkingLevelMap: { off: null, minimal: null, low: \"low\", medium: \"medium\", high: \"high\", xhigh: null, max: null }, compat: { supportsStrictMode: true } }, \"o1-pro\": { id: \"o1-pro\", name: \"o1-pro\", api: \"openai-responses\", provider: \"openai\", baseUrl: \"https://api.openai.com/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 150, output: 600, cacheRead: 0, cacheWrite: 0 }, contextWindow: 2e5, maxTokens: 1e5, thinkingLevelMap: { off: null, minimal: null, low: \"low\", medium: \"medium\", high: \"high\", xhigh: null, max: null }, compat: { supportsStrictMode: true } }, o3: { id: \"o3\", name: \"o3\", api: \"openai-responses\", provider: \"openai\", baseUrl: \"https://api.openai.com/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 2, output: 8, cacheRead: 0.5, cacheWrite: 0 }, contextWindow: 2e5, maxTokens: 1e5, thinkingLevelMap: { off: null, minimal: null, low: \"low\", medium: \"medium\", high: \"high\", xhigh: null, max: null }, compat: { supportsStrictMode: true } }, \"o3-mini\": { id: \"o3-mini\", name: \"o3-mini\", api: \"openai-responses\", provider: \"openai\", baseUrl: \"https://api.openai.com/v1\", reasoning: true, input: [\"text\"], cost: { input: 1.1, output: 4.4, cacheRead: 0.55, cacheWrite: 0 }, contextWindow: 2e5, maxTokens: 1e5, thinkingLevelMap: { off: null, minimal: null, low: \"low\", medium: \"medium\", high: \"high\", xhigh: null, max: null }, compat: { supportsStrictMode: true } }, \"o3-pro\": { id: \"o3-pro\", name: \"o3-pro\", api: \"openai-responses\", provider: \"openai\", baseUrl: \"https://api.openai.com/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 20, output: 80, cacheRead: 0, cacheWrite: 0 }, contextWindow: 2e5, maxTokens: 1e5, thinkingLevelMap: { off: null, minimal: null, low: \"low\", medium: \"medium\", high: \"high\", xhigh: null, max: null }, compat: { supportsStrictMode: true } }, \"o4-mini\": { id: \"o4-mini\", name: \"o4-mini\", api: \"openai-responses\", provider: \"openai\", baseUrl: \"https://api.openai.com/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.1, output: 4.4, cacheRead: 0.275, cacheWrite: 0 }, contextWindow: 2e5, maxTokens: 1e5, thinkingLevelMap: { off: null, minimal: null, low: \"low\", medium: \"medium\", high: \"high\", xhigh: null, max: null }, compat: { supportsStrictMode: true } } } };\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/openai.models.js\nvar OPENAI_MODELS = flattenModelCatalog(\"openai\", openai_default);\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/data/openai-codex.json\nvar openai_codex_default = { \"openai-codex-responses\": { \"gpt-5.3-codex-spark\": { id: \"gpt-5.3-codex-spark\", name: \"GPT-5.3 Codex Spark\", api: \"openai-codex-responses\", provider: \"openai-codex\", baseUrl: \"https://chatgpt.com/backend-api\", reasoning: true, input: [\"text\"], cost: { input: 1.75, output: 14, cacheRead: 0.175, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 128e3, thinkingLevelMap: { xhigh: \"xhigh\", minimal: \"low\" }, compat: { supportsOpenAIGrammarTools: true } }, \"gpt-5.4\": { id: \"gpt-5.4\", name: \"GPT-5.4\", api: \"openai-codex-responses\", provider: \"openai-codex\", baseUrl: \"https://chatgpt.com/backend-api\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 2.5, output: 15, cacheRead: 0.25, cacheWrite: 0, tiers: [{ inputTokensAbove: 272e3, input: 5, output: 22.5, cacheRead: 0.5, cacheWrite: 0 }] }, contextWindow: 272e3, maxTokens: 128e3, thinkingLevelMap: { xhigh: \"xhigh\", minimal: \"low\" }, compat: { supportsOpenAIGrammarTools: true, supportsToolSearch: true } }, \"gpt-5.4-mini\": { id: \"gpt-5.4-mini\", name: \"GPT-5.4 mini\", api: \"openai-codex-responses\", provider: \"openai-codex\", baseUrl: \"https://chatgpt.com/backend-api\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.75, output: 4.5, cacheRead: 0.075, cacheWrite: 0 }, contextWindow: 272e3, maxTokens: 128e3, thinkingLevelMap: { xhigh: \"xhigh\", minimal: \"low\" }, compat: { supportsOpenAIGrammarTools: true, supportsToolSearch: true } }, \"gpt-5.5\": { id: \"gpt-5.5\", name: \"GPT-5.5\", api: \"openai-codex-responses\", provider: \"openai-codex\", baseUrl: \"https://chatgpt.com/backend-api\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 5, output: 30, cacheRead: 0.5, cacheWrite: 0, tiers: [{ inputTokensAbove: 272e3, input: 10, output: 45, cacheRead: 1, cacheWrite: 0 }] }, contextWindow: 272e3, maxTokens: 128e3, thinkingLevelMap: { xhigh: \"xhigh\", minimal: \"low\" }, compat: { supportsOpenAIGrammarTools: true, supportsToolSearch: true } }, \"gpt-5.6-luna\": { id: \"gpt-5.6-luna\", name: \"GPT-5.6 Luna\", api: \"openai-codex-responses\", provider: \"openai-codex\", baseUrl: \"https://chatgpt.com/backend-api\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.2, output: 1.2, cacheRead: 0.02, cacheWrite: 0.25, tiers: [{ inputTokensAbove: 272e3, input: 0.4, output: 1.8, cacheRead: 0.04, cacheWrite: 0.5 }] }, contextWindow: 272e3, maxTokens: 128e3, thinkingLevelMap: { xhigh: \"xhigh\", max: \"max\", minimal: \"low\" }, compat: { supportsOpenAIGrammarTools: true, supportsAdditionalTools: true, supportsToolSearch: true } }, \"gpt-5.6-sol\": { id: \"gpt-5.6-sol\", name: \"GPT-5.6 Sol\", api: \"openai-codex-responses\", provider: \"openai-codex\", baseUrl: \"https://chatgpt.com/backend-api\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 5, output: 30, cacheRead: 0.5, cacheWrite: 6.25, tiers: [{ inputTokensAbove: 272e3, input: 10, output: 45, cacheRead: 1, cacheWrite: 12.5 }] }, contextWindow: 272e3, maxTokens: 128e3, thinkingLevelMap: { xhigh: \"xhigh\", max: \"max\", minimal: \"low\" }, compat: { supportsOpenAIGrammarTools: true, supportsAdditionalTools: true, supportsToolSearch: true } }, \"gpt-5.6-terra\": { id: \"gpt-5.6-terra\", name: \"GPT-5.6 Terra\", api: \"openai-codex-responses\", provider: \"openai-codex\", baseUrl: \"https://chatgpt.com/backend-api\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 2, output: 12, cacheRead: 0.2, cacheWrite: 2.5, tiers: [{ inputTokensAbove: 272e3, input: 4, output: 18, cacheRead: 0.4, cacheWrite: 5 }] }, contextWindow: 272e3, maxTokens: 128e3, thinkingLevelMap: { xhigh: \"xhigh\", max: \"max\", minimal: \"low\" }, compat: { supportsOpenAIGrammarTools: true, supportsAdditionalTools: true, supportsToolSearch: true } } } };\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/openai-codex.models.js\nvar OPENAI_CODEX_MODELS = flattenModelCatalog(\"openai-codex\", openai_codex_default);\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/data/opencode.json\nvar opencode_default = { \"anthropic-messages\": { \"claude-fable-5\": { id: \"claude-fable-5\", name: \"Claude Fable 5\", api: \"anthropic-messages\", provider: \"opencode\", baseUrl: \"https://opencode.ai/zen\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 10, output: 50, cacheRead: 1, cacheWrite: 12.5 }, contextWindow: 1e6, maxTokens: 128e3, thinkingLevelMap: { off: null, xhigh: \"xhigh\", max: \"max\" }, compat: { forceAdaptiveThinking: true } }, \"claude-haiku-4-5\": { id: \"claude-haiku-4-5\", name: \"Claude Haiku 4.5\", api: \"anthropic-messages\", provider: \"opencode\", baseUrl: \"https://opencode.ai/zen\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1, output: 5, cacheRead: 0.1, cacheWrite: 1.25 }, contextWindow: 2e5, maxTokens: 64e3 }, \"claude-opus-4-5\": { id: \"claude-opus-4-5\", name: \"Claude Opus 4.5\", api: \"anthropic-messages\", provider: \"opencode\", baseUrl: \"https://opencode.ai/zen\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 }, contextWindow: 2e5, maxTokens: 64e3 }, \"claude-opus-4-6\": { id: \"claude-opus-4-6\", name: \"Claude Opus 4.6\", api: \"anthropic-messages\", provider: \"opencode\", baseUrl: \"https://opencode.ai/zen\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 }, contextWindow: 1e6, maxTokens: 128e3, thinkingLevelMap: { max: \"max\" }, compat: { forceAdaptiveThinking: true } }, \"claude-opus-4-7\": { id: \"claude-opus-4-7\", name: \"Claude Opus 4.7\", api: \"anthropic-messages\", provider: \"opencode\", baseUrl: \"https://opencode.ai/zen\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 }, contextWindow: 1e6, maxTokens: 128e3, thinkingLevelMap: { xhigh: \"xhigh\", max: \"max\" }, compat: { forceAdaptiveThinking: true, supportsTemperature: false } }, \"claude-opus-4-8\": { id: \"claude-opus-4-8\", name: \"Claude Opus 4.8\", api: \"anthropic-messages\", provider: \"opencode\", baseUrl: \"https://opencode.ai/zen\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 }, contextWindow: 1e6, maxTokens: 128e3, thinkingLevelMap: { xhigh: \"xhigh\", max: \"max\" }, compat: { forceAdaptiveThinking: true, supportsTemperature: false } }, \"claude-opus-5\": { id: \"claude-opus-5\", name: \"Claude Opus 5\", api: \"anthropic-messages\", provider: \"opencode\", baseUrl: \"https://opencode.ai/zen\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 }, contextWindow: 1e6, maxTokens: 128e3, thinkingLevelMap: { xhigh: \"xhigh\", max: \"max\" }, compat: { forceAdaptiveThinking: true, supportsTemperature: false } }, \"claude-sonnet-4\": { id: \"claude-sonnet-4\", name: \"Claude Sonnet 4\", api: \"anthropic-messages\", provider: \"opencode\", baseUrl: \"https://opencode.ai/zen\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3.75 }, contextWindow: 2e5, maxTokens: 64e3 }, \"claude-sonnet-4-5\": { id: \"claude-sonnet-4-5\", name: \"Claude Sonnet 4.5\", api: \"anthropic-messages\", provider: \"opencode\", baseUrl: \"https://opencode.ai/zen\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3.75 }, contextWindow: 2e5, maxTokens: 64e3 }, \"claude-sonnet-4-6\": { id: \"claude-sonnet-4-6\", name: \"Claude Sonnet 4.6\", api: \"anthropic-messages\", provider: \"opencode\", baseUrl: \"https://opencode.ai/zen\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3.75 }, contextWindow: 1e6, maxTokens: 64e3, thinkingLevelMap: { max: \"max\" }, compat: { forceAdaptiveThinking: true } }, \"claude-sonnet-5\": { id: \"claude-sonnet-5\", name: \"Claude Sonnet 5\", api: \"anthropic-messages\", provider: \"opencode\", baseUrl: \"https://opencode.ai/zen\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 2, output: 10, cacheRead: 0.2, cacheWrite: 2.5 }, contextWindow: 1e6, maxTokens: 128e3, thinkingLevelMap: { xhigh: \"xhigh\", max: \"max\" }, compat: { forceAdaptiveThinking: true } }, \"qwen3.5-plus\": { id: \"qwen3.5-plus\", name: \"Qwen3.5 Plus\", api: \"anthropic-messages\", provider: \"opencode\", baseUrl: \"https://opencode.ai/zen\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.2, output: 1.2, cacheRead: 0.02, cacheWrite: 0.25 }, contextWindow: 262144, maxTokens: 65536 }, \"qwen3.6-plus\": { id: \"qwen3.6-plus\", name: \"Qwen3.6 Plus\", api: \"anthropic-messages\", provider: \"opencode\", baseUrl: \"https://opencode.ai/zen\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.5, output: 3, cacheRead: 0.05, cacheWrite: 0.625 }, contextWindow: 262144, maxTokens: 65536 } }, \"google-generative-ai\": { \"gemini-3-flash\": { id: \"gemini-3-flash\", name: \"Gemini 3 Flash\", api: \"google-generative-ai\", provider: \"opencode\", baseUrl: \"https://opencode.ai/zen/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.5, output: 3, cacheRead: 0.05, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536, thinkingLevelMap: { off: null } }, \"gemini-3.1-pro\": { id: \"gemini-3.1-pro\", name: \"Gemini 3.1 Pro Preview\", api: \"google-generative-ai\", provider: \"opencode\", baseUrl: \"https://opencode.ai/zen/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 2, output: 12, cacheRead: 0.2, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536, thinkingLevelMap: { off: null, minimal: null, low: \"LOW\", medium: null, high: \"HIGH\" } }, \"gemini-3.5-flash\": { id: \"gemini-3.5-flash\", name: \"Gemini 3.5 Flash\", api: \"google-generative-ai\", provider: \"opencode\", baseUrl: \"https://opencode.ai/zen/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.5, output: 9, cacheRead: 0.15, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536, thinkingLevelMap: { off: null } }, \"gemini-3.5-flash-lite\": { id: \"gemini-3.5-flash-lite\", name: \"Gemini 3.5 Flash Lite\", api: \"google-generative-ai\", provider: \"opencode\", baseUrl: \"https://opencode.ai/zen/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.3, output: 2.5, cacheRead: 0.03, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536, thinkingLevelMap: { off: null } }, \"gemini-3.6-flash\": { id: \"gemini-3.6-flash\", name: \"Gemini 3.6 Flash\", api: \"google-generative-ai\", provider: \"opencode\", baseUrl: \"https://opencode.ai/zen/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.5, output: 7.5, cacheRead: 0.15, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536, thinkingLevelMap: { off: null } }, \"gemini-3.7-flash\": { id: \"gemini-3.7-flash\", name: \"Gemini 3.7 Flash\", api: \"google-generative-ai\", provider: \"opencode\", baseUrl: \"https://opencode.ai/zen/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.5, output: 7.5, cacheRead: 0.15, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536, thinkingLevelMap: { off: null } } }, \"openai-completions\": { \"big-pickle\": { id: \"big-pickle\", name: \"Big Pickle\", api: \"openai-completions\", provider: \"opencode\", baseUrl: \"https://opencode.ai/zen/v1\", reasoning: true, input: [\"text\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, maxTokensField: \"max_tokens\" }, contextWindow: 2e5, maxTokens: 32e3 }, \"deepseek-v4-flash\": { id: \"deepseek-v4-flash\", name: \"DeepSeek V4 Flash\", api: \"openai-completions\", provider: \"opencode\", baseUrl: \"https://opencode.ai/zen/v1\", reasoning: true, input: [\"text\"], cost: { input: 0.14, output: 0.28, cacheRead: 0.028, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, maxTokensField: \"max_tokens\", supportsLongCacheRetention: false, requiresReasoningContentOnAssistantMessages: true }, contextWindow: 1e6, maxTokens: 384e3, thinkingLevelMap: { off: null, minimal: null, low: null, medium: null, high: \"high\", xhigh: null, max: \"max\" } }, \"deepseek-v4-flash-free\": { id: \"deepseek-v4-flash-free\", name: \"DeepSeek V4 Flash Free\", api: \"openai-completions\", provider: \"opencode\", baseUrl: \"https://opencode.ai/zen/v1\", reasoning: true, input: [\"text\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, maxTokensField: \"max_tokens\", requiresReasoningContentOnAssistantMessages: true }, contextWindow: 2e5, maxTokens: 128e3, thinkingLevelMap: { off: null, minimal: null, low: null, medium: null, high: \"high\", xhigh: null, max: \"max\" } }, \"deepseek-v4-pro\": { id: \"deepseek-v4-pro\", name: \"DeepSeek V4 Pro\", api: \"openai-completions\", provider: \"opencode\", baseUrl: \"https://opencode.ai/zen/v1\", reasoning: true, input: [\"text\"], cost: { input: 1.74, output: 3.84, cacheRead: 0.145, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, maxTokensField: \"max_tokens\", supportsLongCacheRetention: false, requiresReasoningContentOnAssistantMessages: true }, contextWindow: 1e6, maxTokens: 384e3, thinkingLevelMap: { off: null, minimal: null, low: null, medium: null, high: \"high\", xhigh: null, max: \"max\" } }, \"glm-5\": { id: \"glm-5\", name: \"GLM-5\", api: \"openai-completions\", provider: \"opencode\", baseUrl: \"https://opencode.ai/zen/v1\", reasoning: true, input: [\"text\"], cost: { input: 1, output: 3.2, cacheRead: 0.2, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, maxTokensField: \"max_tokens\" }, contextWindow: 204800, maxTokens: 131072 }, \"glm-5.1\": { id: \"glm-5.1\", name: \"GLM-5.1\", api: \"openai-completions\", provider: \"opencode\", baseUrl: \"https://opencode.ai/zen/v1\", reasoning: true, input: [\"text\"], cost: { input: 1.4, output: 4.4, cacheRead: 0.26, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, maxTokensField: \"max_tokens\" }, contextWindow: 204800, maxTokens: 131072 }, \"glm-5.2\": { id: \"glm-5.2\", name: \"GLM-5.2\", api: \"openai-completions\", provider: \"opencode\", baseUrl: \"https://opencode.ai/zen/v1\", reasoning: true, input: [\"text\"], cost: { input: 1.4, output: 4.4, cacheRead: 0.26, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, maxTokensField: \"max_tokens\" }, contextWindow: 1e6, maxTokens: 131072, thinkingLevelMap: { off: null, minimal: null, low: null, medium: null, high: \"high\", xhigh: null, max: \"max\" } }, \"hy3-free\": { id: \"hy3-free\", name: \"Hy3 Free\", api: \"openai-completions\", provider: \"opencode\", baseUrl: \"https://opencode.ai/zen/v1\", reasoning: true, input: [\"text\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, maxTokensField: \"max_tokens\" }, contextWindow: 19e4, maxTokens: 64e3, thinkingLevelMap: { off: null, minimal: null, low: \"low\", medium: \"medium\", high: \"high\", xhigh: null, max: null } }, \"kimi-k2.5\": { id: \"kimi-k2.5\", name: \"Kimi K2.5\", api: \"openai-completions\", provider: \"opencode\", baseUrl: \"https://opencode.ai/zen/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.6, output: 3, cacheRead: 0.08, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, maxTokensField: \"max_tokens\", supportsLongCacheRetention: false }, contextWindow: 262144, maxTokens: 65536 }, \"kimi-k2.6\": { id: \"kimi-k2.6\", name: \"Kimi K2.6\", api: \"openai-completions\", provider: \"opencode\", baseUrl: \"https://opencode.ai/zen/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.95, output: 4, cacheRead: 0.16, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, thinkingFormat: \"deepseek\", supportsReasoningEffort: false, maxTokensField: \"max_tokens\", supportsLongCacheRetention: false }, contextWindow: 262144, maxTokens: 65536 }, \"kimi-k2.7-code\": { id: \"kimi-k2.7-code\", name: \"Kimi K2.7 Code\", api: \"openai-completions\", provider: \"opencode\", baseUrl: \"https://opencode.ai/zen/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.95, output: 4, cacheRead: 0.19, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, maxTokensField: \"max_tokens\" }, contextWindow: 262144, maxTokens: 262144 }, \"kimi-k3\": { id: \"kimi-k3\", name: \"Kimi K3\", api: \"openai-completions\", provider: \"opencode\", baseUrl: \"https://opencode.ai/zen/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, maxTokensField: \"max_tokens\" }, contextWindow: 1048576, maxTokens: 131072, thinkingLevelMap: { off: null, minimal: null, low: null, medium: null, high: null, xhigh: null, max: \"max\" } }, \"laguna-s-2.1-free\": { id: \"laguna-s-2.1-free\", name: \"Laguna S 2.1 Free\", api: \"openai-completions\", provider: \"opencode\", baseUrl: \"https://opencode.ai/zen/v1\", reasoning: true, input: [\"text\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, maxTokensField: \"max_tokens\" }, contextWindow: 256e3, maxTokens: 32e3, thinkingLevelMap: { off: null, minimal: null, low: \"low\", medium: \"medium\", high: \"high\", xhigh: null, max: null } }, \"mimo-v2.5-free\": { id: \"mimo-v2.5-free\", name: \"MiMo V2.5 Free\", api: \"openai-completions\", provider: \"opencode\", baseUrl: \"https://opencode.ai/zen/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, maxTokensField: \"max_tokens\" }, contextWindow: 2e5, maxTokens: 32e3 }, \"minimax-m2.5\": { id: \"minimax-m2.5\", name: \"MiniMax-M2.5\", api: \"openai-completions\", provider: \"opencode\", baseUrl: \"https://opencode.ai/zen/v1\", reasoning: true, input: [\"text\"], cost: { input: 0.3, output: 1.2, cacheRead: 0.06, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, maxTokensField: \"max_tokens\" }, contextWindow: 204800, maxTokens: 131072 }, \"minimax-m2.7\": { id: \"minimax-m2.7\", name: \"MiniMax-M2.7\", api: \"openai-completions\", provider: \"opencode\", baseUrl: \"https://opencode.ai/zen/v1\", reasoning: true, input: [\"text\"], cost: { input: 0.3, output: 1.2, cacheRead: 0.06, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, maxTokensField: \"max_tokens\", supportsLongCacheRetention: false }, contextWindow: 204800, maxTokens: 131072 }, \"minimax-m3\": { id: \"minimax-m3\", name: \"MiniMax-M3\", api: \"openai-completions\", provider: \"opencode\", baseUrl: \"https://opencode.ai/zen/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.3, output: 1.2, cacheRead: 0.06, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, maxTokensField: \"max_tokens\" }, contextWindow: 512e3, maxTokens: 128e3 }, \"nemotron-3-ultra-free\": { id: \"nemotron-3-ultra-free\", name: \"Nemotron 3 Ultra Free\", api: \"openai-completions\", provider: \"opencode\", baseUrl: \"https://opencode.ai/zen/v1\", reasoning: true, input: [\"text\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, maxTokensField: \"max_tokens\" }, contextWindow: 1e6, maxTokens: 128e3 }, \"nemotron-3.5-lightning-free\": { id: \"nemotron-3.5-lightning-free\", name: \"Nemotron 3.5 Lightning Free\", api: \"openai-completions\", provider: \"opencode\", baseUrl: \"https://opencode.ai/zen/v1\", reasoning: true, input: [\"text\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, maxTokensField: \"max_tokens\" }, contextWindow: 262144, maxTokens: 262144 } }, \"openai-responses\": { \"gpt-5\": { id: \"gpt-5\", name: \"GPT-5\", api: \"openai-responses\", provider: \"opencode\", baseUrl: \"https://opencode.ai/zen/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.07, output: 8.5, cacheRead: 0.107, cacheWrite: 0 }, compat: { sessionAffinityFormat: \"openai-nosession\", supportsOpenAIGrammarTools: true }, contextWindow: 4e5, maxTokens: 128e3, thinkingLevelMap: { off: null, minimal: \"minimal\", low: \"low\", medium: \"medium\", high: \"high\", xhigh: null, max: null } }, \"gpt-5-codex\": { id: \"gpt-5-codex\", name: \"GPT-5 Codex\", api: \"openai-responses\", provider: \"opencode\", baseUrl: \"https://opencode.ai/zen/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.07, output: 8.5, cacheRead: 0.107, cacheWrite: 0 }, compat: { sessionAffinityFormat: \"openai-nosession\", supportsOpenAIGrammarTools: true }, contextWindow: 4e5, maxTokens: 128e3, thinkingLevelMap: { off: null, minimal: null, low: \"low\", medium: \"medium\", high: \"high\", xhigh: null, max: null } }, \"gpt-5-nano\": { id: \"gpt-5-nano\", name: \"GPT-5 Nano\", api: \"openai-responses\", provider: \"opencode\", baseUrl: \"https://opencode.ai/zen/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.05, output: 0.4, cacheRead: 5e-3, cacheWrite: 0 }, compat: { sessionAffinityFormat: \"openai-nosession\", supportsOpenAIGrammarTools: true }, contextWindow: 4e5, maxTokens: 128e3, thinkingLevelMap: { off: null, minimal: \"minimal\", low: \"low\", medium: \"medium\", high: \"high\", xhigh: null, max: null } }, \"gpt-5.1\": { id: \"gpt-5.1\", name: \"GPT-5.1\", api: \"openai-responses\", provider: \"opencode\", baseUrl: \"https://opencode.ai/zen/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.07, output: 8.5, cacheRead: 0.107, cacheWrite: 0 }, compat: { sessionAffinityFormat: \"openai-nosession\", supportsOpenAIGrammarTools: true }, contextWindow: 4e5, maxTokens: 128e3, thinkingLevelMap: { off: null, minimal: null, low: \"low\", medium: \"medium\", high: \"high\", xhigh: null, max: null } }, \"gpt-5.1-codex\": { id: \"gpt-5.1-codex\", name: \"GPT-5.1 Codex\", api: \"openai-responses\", provider: \"opencode\", baseUrl: \"https://opencode.ai/zen/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.07, output: 8.5, cacheRead: 0.107, cacheWrite: 0 }, compat: { sessionAffinityFormat: \"openai-nosession\", supportsOpenAIGrammarTools: true }, contextWindow: 4e5, maxTokens: 128e3, thinkingLevelMap: { off: null, minimal: null, low: \"low\", medium: \"medium\", high: \"high\", xhigh: null, max: null } }, \"gpt-5.1-codex-max\": { id: \"gpt-5.1-codex-max\", name: \"GPT-5.1 Codex Max\", api: \"openai-responses\", provider: \"opencode\", baseUrl: \"https://opencode.ai/zen/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.25, output: 10, cacheRead: 0.125, cacheWrite: 0 }, compat: { sessionAffinityFormat: \"openai-nosession\", supportsOpenAIGrammarTools: true }, contextWindow: 4e5, maxTokens: 128e3, thinkingLevelMap: { off: null, minimal: null, low: \"low\", medium: \"medium\", high: \"high\", xhigh: \"xhigh\", max: null } }, \"gpt-5.1-codex-mini\": { id: \"gpt-5.1-codex-mini\", name: \"GPT-5.1 Codex Mini\", api: \"openai-responses\", provider: \"opencode\", baseUrl: \"https://opencode.ai/zen/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.25, output: 2, cacheRead: 0.025, cacheWrite: 0 }, compat: { sessionAffinityFormat: \"openai-nosession\", supportsOpenAIGrammarTools: true }, contextWindow: 4e5, maxTokens: 128e3, thinkingLevelMap: { off: null, minimal: null, low: \"low\", medium: \"medium\", high: \"high\", xhigh: null, max: null } }, \"gpt-5.2\": { id: \"gpt-5.2\", name: \"GPT-5.2\", api: \"openai-responses\", provider: \"opencode\", baseUrl: \"https://opencode.ai/zen/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.75, output: 14, cacheRead: 0.175, cacheWrite: 0 }, compat: { sessionAffinityFormat: \"openai-nosession\", supportsOpenAIGrammarTools: true }, contextWindow: 4e5, maxTokens: 128e3, thinkingLevelMap: { off: null, minimal: null, low: \"low\", medium: \"medium\", high: \"high\", xhigh: \"xhigh\", max: null } }, \"gpt-5.2-codex\": { id: \"gpt-5.2-codex\", name: \"GPT-5.2 Codex\", api: \"openai-responses\", provider: \"opencode\", baseUrl: \"https://opencode.ai/zen/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.75, output: 14, cacheRead: 0.175, cacheWrite: 0 }, compat: { sessionAffinityFormat: \"openai-nosession\", supportsOpenAIGrammarTools: true }, contextWindow: 4e5, maxTokens: 128e3, thinkingLevelMap: { off: null, minimal: null, low: \"low\", medium: \"medium\", high: \"high\", xhigh: \"xhigh\", max: null } }, \"gpt-5.3-codex\": { id: \"gpt-5.3-codex\", name: \"GPT-5.3 Codex\", api: \"openai-responses\", provider: \"opencode\", baseUrl: \"https://opencode.ai/zen/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.75, output: 14, cacheRead: 0.175, cacheWrite: 0 }, compat: { sessionAffinityFormat: \"openai-nosession\", supportsOpenAIGrammarTools: true }, contextWindow: 4e5, maxTokens: 128e3, thinkingLevelMap: { off: null, minimal: null, low: \"low\", medium: \"medium\", high: \"high\", xhigh: \"xhigh\", max: null } }, \"gpt-5.4\": { id: \"gpt-5.4\", name: \"GPT-5.4\", api: \"openai-responses\", provider: \"opencode\", baseUrl: \"https://opencode.ai/zen/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 2.5, output: 15, cacheRead: 0.25, cacheWrite: 0 }, compat: { sessionAffinityFormat: \"openai-nosession\", supportsOpenAIGrammarTools: true }, contextWindow: 272e3, maxTokens: 128e3, thinkingLevelMap: { off: null, minimal: null, low: \"low\", medium: \"medium\", high: \"high\", xhigh: \"xhigh\", max: null } }, \"gpt-5.4-mini\": { id: \"gpt-5.4-mini\", name: \"GPT-5.4 Mini\", api: \"openai-responses\", provider: \"opencode\", baseUrl: \"https://opencode.ai/zen/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.75, output: 4.5, cacheRead: 0.075, cacheWrite: 0 }, compat: { sessionAffinityFormat: \"openai-nosession\", supportsOpenAIGrammarTools: true }, contextWindow: 4e5, maxTokens: 128e3, thinkingLevelMap: { off: null, minimal: null, low: \"low\", medium: \"medium\", high: \"high\", xhigh: \"xhigh\", max: null } }, \"gpt-5.4-nano\": { id: \"gpt-5.4-nano\", name: \"GPT-5.4 Nano\", api: \"openai-responses\", provider: \"opencode\", baseUrl: \"https://opencode.ai/zen/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.2, output: 1.25, cacheRead: 0.02, cacheWrite: 0 }, compat: { sessionAffinityFormat: \"openai-nosession\", supportsOpenAIGrammarTools: true }, contextWindow: 4e5, maxTokens: 128e3, thinkingLevelMap: { off: null, minimal: null, low: \"low\", medium: \"medium\", high: \"high\", xhigh: \"xhigh\", max: null } }, \"gpt-5.4-pro\": { id: \"gpt-5.4-pro\", name: \"GPT-5.4 Pro\", api: \"openai-responses\", provider: \"opencode\", baseUrl: \"https://opencode.ai/zen/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 30, output: 180, cacheRead: 30, cacheWrite: 0 }, compat: { sessionAffinityFormat: \"openai-nosession\", supportsOpenAIGrammarTools: true }, contextWindow: 105e4, maxTokens: 128e3, thinkingLevelMap: { off: null, minimal: null, low: null, medium: \"medium\", high: \"high\", xhigh: \"xhigh\", max: null } }, \"gpt-5.5\": { id: \"gpt-5.5\", name: \"GPT-5.5\", api: \"openai-responses\", provider: \"opencode\", baseUrl: \"https://opencode.ai/zen/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 5, output: 30, cacheRead: 0.5, cacheWrite: 0 }, compat: { sessionAffinityFormat: \"openai-nosession\", supportsOpenAIGrammarTools: true }, contextWindow: 105e4, maxTokens: 128e3, thinkingLevelMap: { off: null, minimal: null, low: \"low\", medium: \"medium\", high: \"high\", xhigh: \"xhigh\", max: null } }, \"gpt-5.5-pro\": { id: \"gpt-5.5-pro\", name: \"GPT-5.5 Pro\", api: \"openai-responses\", provider: \"opencode\", baseUrl: \"https://opencode.ai/zen/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 30, output: 180, cacheRead: 30, cacheWrite: 0 }, compat: { sessionAffinityFormat: \"openai-nosession\", supportsOpenAIGrammarTools: true }, contextWindow: 105e4, maxTokens: 128e3, thinkingLevelMap: { off: null, minimal: null, low: null, medium: \"medium\", high: \"high\", xhigh: \"xhigh\", max: null } }, \"gpt-5.6-luna\": { id: \"gpt-5.6-luna\", name: \"GPT-5.6 Luna\", api: \"openai-responses\", provider: \"opencode\", baseUrl: \"https://opencode.ai/zen/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.2, output: 1.2, cacheRead: 0.02, cacheWrite: 0.25 }, compat: { sessionAffinityFormat: \"openai-nosession\", supportsOpenAIGrammarTools: true }, contextWindow: 105e4, maxTokens: 128e3, thinkingLevelMap: { off: null, minimal: null, low: \"low\", medium: \"medium\", high: \"high\", xhigh: \"xhigh\", max: \"max\" } }, \"gpt-5.6-sol\": { id: \"gpt-5.6-sol\", name: \"GPT-5.6 Sol\", api: \"openai-responses\", provider: \"opencode\", baseUrl: \"https://opencode.ai/zen/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 5, output: 30, cacheRead: 0.5, cacheWrite: 6.25 }, compat: { sessionAffinityFormat: \"openai-nosession\", supportsOpenAIGrammarTools: true }, contextWindow: 105e4, maxTokens: 128e3, thinkingLevelMap: { off: null, minimal: null, low: \"low\", medium: \"medium\", high: \"high\", xhigh: \"xhigh\", max: \"max\" } }, \"gpt-5.6-terra\": { id: \"gpt-5.6-terra\", name: \"GPT-5.6 Terra\", api: \"openai-responses\", provider: \"opencode\", baseUrl: \"https://opencode.ai/zen/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 2.5, output: 15, cacheRead: 0.25, cacheWrite: 3.125 }, compat: { sessionAffinityFormat: \"openai-nosession\", supportsOpenAIGrammarTools: true }, contextWindow: 105e4, maxTokens: 128e3, thinkingLevelMap: { off: null, minimal: null, low: \"low\", medium: \"medium\", high: \"high\", xhigh: \"xhigh\", max: \"max\" } }, \"grok-4.5\": { id: \"grok-4.5\", name: \"Grok 4.5\", api: \"openai-responses\", provider: \"opencode\", baseUrl: \"https://opencode.ai/zen/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 2, output: 6, cacheRead: 0.5, cacheWrite: 0 }, compat: { sessionAffinityFormat: \"openai-nosession\" }, contextWindow: 5e5, maxTokens: 5e5, thinkingLevelMap: { off: null, minimal: null, low: \"low\", medium: \"medium\", high: \"high\", xhigh: null, max: null } }, \"grok-4.6\": { id: \"grok-4.6\", name: \"Grok 4.6\", api: \"openai-responses\", provider: \"opencode\", baseUrl: \"https://opencode.ai/zen/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 2, output: 6, cacheRead: 0.5, cacheWrite: 0 }, compat: { sessionAffinityFormat: \"openai-nosession\" }, contextWindow: 5e5, maxTokens: 5e5, thinkingLevelMap: { off: null, minimal: null, low: \"low\", medium: \"medium\", high: \"high\", xhigh: \"xhigh\", max: null } }, \"grok-build-0.1\": { id: \"grok-build-0.1\", name: \"Grok Build 0.1\", api: \"openai-responses\", provider: \"opencode\", baseUrl: \"https://opencode.ai/zen/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1, output: 2, cacheRead: 0.2, cacheWrite: 0 }, compat: { sessionAffinityFormat: \"openai-nosession\", supportsReasoningEffort: false }, contextWindow: 256e3, maxTokens: 256e3, thinkingLevelMap: { off: null, minimal: null, low: null, medium: null } }, \"muse-spark-1.2\": { id: \"muse-spark-1.2\", name: \"Muse Spark 1.2\", api: \"openai-responses\", provider: \"opencode\", baseUrl: \"https://opencode.ai/zen/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.25, output: 4.25, cacheRead: 0.15, cacheWrite: 0 }, compat: { sessionAffinityFormat: \"openai-nosession\" }, contextWindow: 1048576, maxTokens: 131072, thinkingLevelMap: { off: null, minimal: \"minimal\", low: \"low\", medium: \"medium\", high: \"high\", xhigh: \"xhigh\", max: null } } } };\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/opencode.models.js\nvar OPENCODE_MODELS = flattenModelCatalog(\"opencode\", opencode_default);\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/data/opencode-go.json\nvar opencode_go_default = { \"anthropic-messages\": { \"minimax-m3\": { id: \"minimax-m3\", name: \"MiniMax-M3\", api: \"anthropic-messages\", provider: \"opencode-go\", baseUrl: \"https://opencode.ai/zen/go\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.3, output: 1.2, cacheRead: 0.06, cacheWrite: 0 }, contextWindow: 1e6, maxTokens: 131072 }, \"qwen3.7-max\": { id: \"qwen3.7-max\", name: \"Qwen3.7 Max\", api: \"anthropic-messages\", provider: \"opencode-go\", baseUrl: \"https://opencode.ai/zen/go\", reasoning: true, input: [\"text\"], cost: { input: 2.5, output: 7.5, cacheRead: 0.5, cacheWrite: 3.125 }, contextWindow: 1e6, maxTokens: 65536 }, \"qwen3.7-plus\": { id: \"qwen3.7-plus\", name: \"Qwen3.7 Plus\", api: \"anthropic-messages\", provider: \"opencode-go\", baseUrl: \"https://opencode.ai/zen/go\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.4, output: 1.6, cacheRead: 0.04, cacheWrite: 0.5 }, contextWindow: 1e6, maxTokens: 65536 }, \"qwen3.8-max\": { id: \"qwen3.8-max\", name: \"Qwen3.8 Max\", api: \"anthropic-messages\", provider: \"opencode-go\", baseUrl: \"https://opencode.ai/zen/go\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 2, output: 6, cacheRead: 0.25, cacheWrite: 2.5 }, contextWindow: 1e6, maxTokens: 131072 } }, \"openai-completions\": { \"deepseek-v4-flash\": { id: \"deepseek-v4-flash\", name: \"DeepSeek V4 Flash (2x usage)\", api: \"openai-completions\", provider: \"opencode-go\", baseUrl: \"https://opencode.ai/zen/go/v1\", reasoning: true, input: [\"text\"], cost: { input: 0.07, output: 0.14, cacheRead: 14e-4, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, maxTokensField: \"max_tokens\", requiresReasoningContentOnAssistantMessages: true, thinkingFormat: \"deepseek\" }, contextWindow: 1e6, maxTokens: 384e3, thinkingLevelMap: { minimal: null, low: null, medium: null, high: \"high\", max: \"max\" } }, \"deepseek-v4-pro\": { id: \"deepseek-v4-pro\", name: \"DeepSeek V4 Pro (New)\", api: \"openai-completions\", provider: \"opencode-go\", baseUrl: \"https://opencode.ai/zen/go/v1\", reasoning: true, input: [\"text\"], cost: { input: 0.435, output: 0.87, cacheRead: 3625e-6, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, maxTokensField: \"max_tokens\", requiresReasoningContentOnAssistantMessages: true, thinkingFormat: \"deepseek\" }, contextWindow: 1e6, maxTokens: 384e3, thinkingLevelMap: { minimal: null, low: null, medium: null, high: \"high\", max: \"max\" } }, \"glm-5.1\": { id: \"glm-5.1\", name: \"GLM-5.1\", api: \"openai-completions\", provider: \"opencode-go\", baseUrl: \"https://opencode.ai/zen/go/v1\", reasoning: true, input: [\"text\"], cost: { input: 1.4, output: 4.4, cacheRead: 0.26, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, maxTokensField: \"max_tokens\" }, contextWindow: 202752, maxTokens: 32768 }, \"glm-5.2\": { id: \"glm-5.2\", name: \"GLM-5.2\", api: \"openai-completions\", provider: \"opencode-go\", baseUrl: \"https://opencode.ai/zen/go/v1\", reasoning: true, input: [\"text\"], cost: { input: 1.4, output: 4.4, cacheRead: 0.26, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, maxTokensField: \"max_tokens\" }, contextWindow: 1e6, maxTokens: 131072, thinkingLevelMap: { off: null, minimal: null, low: null, medium: null, high: \"high\", xhigh: null, max: \"max\" } }, \"glm-5.3\": { id: \"glm-5.3\", name: \"GLM-5.3\", api: \"openai-completions\", provider: \"opencode-go\", baseUrl: \"https://opencode.ai/zen/go/v1\", reasoning: true, input: [\"text\"], cost: { input: 1.4, output: 4.4, cacheRead: 0.26, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, maxTokensField: \"max_tokens\" }, contextWindow: 1e6, maxTokens: 131072, thinkingLevelMap: { off: null, minimal: null, low: \"low\", medium: null, high: \"high\", xhigh: null, max: \"max\" } }, hy3: { id: \"hy3\", name: \"Hy3\", api: \"openai-completions\", provider: \"opencode-go\", baseUrl: \"https://opencode.ai/zen/go/v1\", reasoning: true, input: [\"text\"], cost: { input: 0.14, output: 0.58, cacheRead: 0.035, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, maxTokensField: \"max_tokens\" }, contextWindow: 256e3, maxTokens: 64e3, thinkingLevelMap: { off: \"none\", minimal: null, low: \"low\", medium: null, high: \"high\", xhigh: null, max: null } }, \"kimi-k2.6\": { id: \"kimi-k2.6\", name: \"Kimi K2.6\", api: \"openai-completions\", provider: \"opencode-go\", baseUrl: \"https://opencode.ai/zen/go/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.95, output: 4, cacheRead: 0.16, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, thinkingFormat: \"deepseek\", supportsReasoningEffort: false, maxTokensField: \"max_tokens\", supportsLongCacheRetention: false }, contextWindow: 262144, maxTokens: 65536, thinkingLevelMap: { minimal: null, low: null, medium: null } }, \"kimi-k2.7-code\": { id: \"kimi-k2.7-code\", name: \"Kimi K2.7 Code\", api: \"openai-completions\", provider: \"opencode-go\", baseUrl: \"https://opencode.ai/zen/go/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.95, output: 4, cacheRead: 0.19, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, maxTokensField: \"max_tokens\" }, contextWindow: 262144, maxTokens: 262144 }, \"kimi-k3\": { id: \"kimi-k3\", name: \"Kimi K3\", api: \"openai-completions\", provider: \"opencode-go\", baseUrl: \"https://opencode.ai/zen/go/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, maxTokensField: \"max_tokens\" }, contextWindow: 1048576, maxTokens: 131072, thinkingLevelMap: { off: null, minimal: null, low: null, medium: null, high: null, xhigh: null, max: \"max\" } }, \"mimo-v2.5\": { id: \"mimo-v2.5\", name: \"MiMo V2.5\", api: \"openai-completions\", provider: \"opencode-go\", baseUrl: \"https://opencode.ai/zen/go/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.14, output: 0.28, cacheRead: 28e-4, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, maxTokensField: \"max_tokens\" }, contextWindow: 1e6, maxTokens: 128e3 }, \"mimo-v2.5-pro\": { id: \"mimo-v2.5-pro\", name: \"MiMo V2.5 Pro\", api: \"openai-completions\", provider: \"opencode-go\", baseUrl: \"https://opencode.ai/zen/go/v1\", reasoning: true, input: [\"text\"], cost: { input: 0.435, output: 0.87, cacheRead: 3625e-6, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, maxTokensField: \"max_tokens\" }, contextWindow: 1048576, maxTokens: 128e3 }, \"minimax-m2.7\": { id: \"minimax-m2.7\", name: \"MiniMax-M2.7\", api: \"openai-completions\", provider: \"opencode-go\", baseUrl: \"https://opencode.ai/zen/go/v1\", reasoning: true, input: [\"text\"], cost: { input: 0.3, output: 1.2, cacheRead: 0.06, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, maxTokensField: \"max_tokens\" }, contextWindow: 204800, maxTokens: 131072 }, \"qwen3.6-plus\": { id: \"qwen3.6-plus\", name: \"Qwen3.6 Plus\", api: \"openai-completions\", provider: \"opencode-go\", baseUrl: \"https://opencode.ai/zen/go/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.5, output: 3, cacheRead: 0.05, cacheWrite: 0.625 }, compat: { supportsStore: false, supportsDeveloperRole: false, thinkingFormat: \"qwen\", maxTokensField: \"max_tokens\" }, contextWindow: 1e6, maxTokens: 65536 } }, \"openai-responses\": { \"gpt-5.6-luna\": { id: \"gpt-5.6-luna\", name: \"GPT-5.6 Luna (2x usage)\", api: \"openai-responses\", provider: \"opencode-go\", baseUrl: \"https://opencode.ai/zen/go/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.1, output: 0.6, cacheRead: 0.01, cacheWrite: 0.125 }, compat: { sessionAffinityFormat: \"openai-nosession\" }, contextWindow: 105e4, maxTokens: 128e3, thinkingLevelMap: { off: null, minimal: null, low: \"low\", medium: \"medium\", high: \"high\", xhigh: \"xhigh\", max: \"max\" } }, \"grok-4.5\": { id: \"grok-4.5\", name: \"Grok 4.5\", api: \"openai-responses\", provider: \"opencode-go\", baseUrl: \"https://opencode.ai/zen/go/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 2, output: 6, cacheRead: 0.5, cacheWrite: 0 }, compat: { sessionAffinityFormat: \"openai-nosession\" }, contextWindow: 5e5, maxTokens: 5e5, thinkingLevelMap: { off: null, minimal: null, low: \"low\", medium: \"medium\", high: \"high\", xhigh: null, max: null } } } };\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/opencode-go.models.js\nvar OPENCODE_GO_MODELS = flattenModelCatalog(\"opencode-go\", opencode_go_default);\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/data/openrouter.json\nvar openrouter_default = { \"openai-completions\": { \"ai21/jamba-large-1.7\": { id: \"ai21/jamba-large-1.7\", name: \"AI21: Jamba Large 1.7\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: false, input: [\"text\"], cost: { input: 2, output: 8, cacheRead: 0, cacheWrite: 0 }, contextWindow: 256e3, maxTokens: 4096, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"aion-labs/aion-2.0\": { id: \"aion-labs/aion-2.0\", name: \"AionLabs: Aion-2.0\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\"], cost: { input: 0.8, output: 1.6, cacheRead: 0.2, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 32768, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"aion-labs/aion-3.0\": { id: \"aion-labs/aion-3.0\", name: \"AionLabs: Aion-3.0\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\"], cost: { input: 3, output: 6, cacheRead: 0.75, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 32768, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"aion-labs/aion-3.0-mini\": { id: \"aion-labs/aion-3.0-mini\", name: \"AionLabs: Aion-3.0-Mini\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\"], cost: { input: 0.7, output: 1.4, cacheRead: 0.18, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 32768, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"amazon/nova-2-lite-v1\": { id: \"amazon/nova-2-lite-v1\", name: \"Amazon: Nova 2 Lite\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.3, output: 2.5, cacheRead: 0, cacheWrite: 0 }, contextWindow: 1e6, maxTokens: 65535, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"amazon/nova-lite-v1\": { id: \"amazon/nova-lite-v1\", name: \"Amazon: Nova Lite 1.0\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 0.06, output: 0.24, cacheRead: 0, cacheWrite: 0 }, contextWindow: 3e5, maxTokens: 5120, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"amazon/nova-micro-v1\": { id: \"amazon/nova-micro-v1\", name: \"Amazon: Nova Micro 1.0\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: false, input: [\"text\"], cost: { input: 0.035, output: 0.14, cacheRead: 0, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 5120, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"amazon/nova-premier-v1\": { id: \"amazon/nova-premier-v1\", name: \"Amazon: Nova Premier 1.0\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 2.5, output: 12.5, cacheRead: 0.625, cacheWrite: 0 }, contextWindow: 1e6, maxTokens: 32e3, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"amazon/nova-pro-v1\": { id: \"amazon/nova-pro-v1\", name: \"Amazon: Nova Pro 1.0\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 0.8, output: 3.2, cacheRead: 0, cacheWrite: 0 }, contextWindow: 3e5, maxTokens: 5120, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"anthropic/claude-3-haiku\": { id: \"anthropic/claude-3-haiku\", name: \"Anthropic: Claude 3 Haiku\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 0.25, output: 1.25, cacheRead: 0.03, cacheWrite: 0.3 }, contextWindow: 2e5, maxTokens: 4096, compat: { thinkingFormat: \"openrouter\", cacheControlFormat: \"anthropic\" } }, \"anthropic/claude-fable-5\": { id: \"anthropic/claude-fable-5\", name: \"Anthropic: Claude Fable 5\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 10, output: 50, cacheRead: 1, cacheWrite: 12.5 }, contextWindow: 1e6, maxTokens: 128e3, compat: { thinkingFormat: \"openrouter\", cacheControlFormat: \"anthropic\" }, thinkingLevelMap: { off: null, xhigh: \"xhigh\", max: \"max\" } }, \"anthropic/claude-fable-5:batch\": { id: \"anthropic/claude-fable-5:batch\", name: \"Anthropic: Claude Fable 5 (batch)\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 }, contextWindow: 1e6, maxTokens: 128e3, compat: { thinkingFormat: \"openrouter\", cacheControlFormat: \"anthropic\" }, thinkingLevelMap: { off: null, xhigh: \"xhigh\", max: \"max\" } }, \"anthropic/claude-haiku-4.5\": { id: \"anthropic/claude-haiku-4.5\", name: \"Anthropic: Claude Haiku 4.5\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1, output: 5, cacheRead: 0.1, cacheWrite: 1.25 }, contextWindow: 2e5, maxTokens: 64e3, compat: { thinkingFormat: \"openrouter\", cacheControlFormat: \"anthropic\" } }, \"anthropic/claude-haiku-4.5:batch\": { id: \"anthropic/claude-haiku-4.5:batch\", name: \"Anthropic: Claude Haiku 4.5 (batch)\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.5, output: 2.5, cacheRead: 0.05, cacheWrite: 0.625 }, contextWindow: 2e5, maxTokens: 64e3, compat: { thinkingFormat: \"openrouter\", cacheControlFormat: \"anthropic\" } }, \"anthropic/claude-opus-4\": { id: \"anthropic/claude-opus-4\", name: \"Anthropic: Claude Opus 4\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 15, output: 75, cacheRead: 1.5, cacheWrite: 18.75 }, contextWindow: 2e5, maxTokens: 32e3, compat: { thinkingFormat: \"openrouter\", cacheControlFormat: \"anthropic\" } }, \"anthropic/claude-opus-4.1\": { id: \"anthropic/claude-opus-4.1\", name: \"Anthropic: Claude Opus 4.1\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 15, output: 75, cacheRead: 1.5, cacheWrite: 18.75 }, contextWindow: 2e5, maxTokens: 32e3, compat: { thinkingFormat: \"openrouter\", cacheControlFormat: \"anthropic\" } }, \"anthropic/claude-opus-4.1:batch\": { id: \"anthropic/claude-opus-4.1:batch\", name: \"Anthropic: Claude Opus 4.1 (batch)\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 7.5, output: 37.5, cacheRead: 0.75, cacheWrite: 9.375 }, contextWindow: 2e5, maxTokens: 32e3, compat: { thinkingFormat: \"openrouter\", cacheControlFormat: \"anthropic\" } }, \"anthropic/claude-opus-4.5\": { id: \"anthropic/claude-opus-4.5\", name: \"Anthropic: Claude Opus 4.5\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 }, contextWindow: 2e5, maxTokens: 64e3, compat: { thinkingFormat: \"openrouter\", cacheControlFormat: \"anthropic\" } }, \"anthropic/claude-opus-4.5:batch\": { id: \"anthropic/claude-opus-4.5:batch\", name: \"Anthropic: Claude Opus 4.5 (batch)\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 2.5, output: 12.5, cacheRead: 0.25, cacheWrite: 3.125 }, contextWindow: 2e5, maxTokens: 64e3, compat: { thinkingFormat: \"openrouter\", cacheControlFormat: \"anthropic\" } }, \"anthropic/claude-opus-4.6\": { id: \"anthropic/claude-opus-4.6\", name: \"Anthropic: Claude Opus 4.6\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 }, contextWindow: 1e6, maxTokens: 128e3, compat: { thinkingFormat: \"openrouter\", cacheControlFormat: \"anthropic\" }, thinkingLevelMap: { max: \"max\" } }, \"anthropic/claude-opus-4.6:batch\": { id: \"anthropic/claude-opus-4.6:batch\", name: \"Anthropic: Claude Opus 4.6 (batch)\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 2.5, output: 12.5, cacheRead: 0.25, cacheWrite: 3.125 }, contextWindow: 1e6, maxTokens: 128e3, compat: { thinkingFormat: \"openrouter\", cacheControlFormat: \"anthropic\" }, thinkingLevelMap: { max: \"max\" } }, \"anthropic/claude-opus-4.7\": { id: \"anthropic/claude-opus-4.7\", name: \"Anthropic: Claude Opus 4.7\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 }, contextWindow: 1e6, maxTokens: 128e3, compat: { thinkingFormat: \"openrouter\", cacheControlFormat: \"anthropic\" }, thinkingLevelMap: { xhigh: \"xhigh\", max: \"max\" } }, \"anthropic/claude-opus-4.7-fast\": { id: \"anthropic/claude-opus-4.7-fast\", name: \"Anthropic: Claude Opus 4.7 (Fast)\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 30, output: 150, cacheRead: 3, cacheWrite: 37.5 }, contextWindow: 1e6, maxTokens: 128e3, compat: { thinkingFormat: \"openrouter\", cacheControlFormat: \"anthropic\" }, thinkingLevelMap: { xhigh: \"xhigh\", max: \"max\" } }, \"anthropic/claude-opus-4.7:batch\": { id: \"anthropic/claude-opus-4.7:batch\", name: \"Anthropic: Claude Opus 4.7 (batch)\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 2.5, output: 12.5, cacheRead: 0.25, cacheWrite: 3.125 }, contextWindow: 1e6, maxTokens: 128e3, compat: { thinkingFormat: \"openrouter\", cacheControlFormat: \"anthropic\" }, thinkingLevelMap: { xhigh: \"xhigh\", max: \"max\" } }, \"anthropic/claude-opus-4.8\": { id: \"anthropic/claude-opus-4.8\", name: \"Anthropic: Claude Opus 4.8\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 }, contextWindow: 1e6, maxTokens: 128e3, compat: { thinkingFormat: \"openrouter\", cacheControlFormat: \"anthropic\" }, thinkingLevelMap: { xhigh: \"xhigh\", max: \"max\" } }, \"anthropic/claude-opus-4.8-fast\": { id: \"anthropic/claude-opus-4.8-fast\", name: \"Anthropic: Claude Opus 4.8 (Fast)\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 10, output: 50, cacheRead: 1, cacheWrite: 12.5 }, contextWindow: 1e6, maxTokens: 128e3, compat: { thinkingFormat: \"openrouter\", cacheControlFormat: \"anthropic\" }, thinkingLevelMap: { xhigh: \"xhigh\", max: \"max\" } }, \"anthropic/claude-opus-4.8:batch\": { id: \"anthropic/claude-opus-4.8:batch\", name: \"Anthropic: Claude Opus 4.8 (batch)\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 2.5, output: 12.5, cacheRead: 0.25, cacheWrite: 3.125 }, contextWindow: 1e6, maxTokens: 128e3, compat: { thinkingFormat: \"openrouter\", cacheControlFormat: \"anthropic\" }, thinkingLevelMap: { xhigh: \"xhigh\", max: \"max\" } }, \"anthropic/claude-opus-5\": { id: \"anthropic/claude-opus-5\", name: \"Claude Opus 5\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 }, contextWindow: 1e6, maxTokens: 128e3, compat: { thinkingFormat: \"openrouter\", cacheControlFormat: \"anthropic\" }, thinkingLevelMap: { xhigh: \"xhigh\", max: \"max\" } }, \"anthropic/claude-opus-5-fast\": { id: \"anthropic/claude-opus-5-fast\", name: \"Claude Opus 5 (Fast)\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 10, output: 50, cacheRead: 1, cacheWrite: 12.5 }, contextWindow: 1e6, maxTokens: 128e3, compat: { thinkingFormat: \"openrouter\", cacheControlFormat: \"anthropic\" }, thinkingLevelMap: { xhigh: \"xhigh\", max: \"max\" } }, \"anthropic/claude-opus-5:batch\": { id: \"anthropic/claude-opus-5:batch\", name: \"Claude Opus 5 (batch)\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 2.5, output: 12.5, cacheRead: 0.25, cacheWrite: 3.125 }, contextWindow: 1e6, maxTokens: 128e3, compat: { thinkingFormat: \"openrouter\", cacheControlFormat: \"anthropic\" }, thinkingLevelMap: { xhigh: \"xhigh\", max: \"max\" } }, \"anthropic/claude-sonnet-4\": { id: \"anthropic/claude-sonnet-4\", name: \"Anthropic: Claude Sonnet 4\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3.75 }, contextWindow: 2e5, maxTokens: 64e3, compat: { thinkingFormat: \"openrouter\", cacheControlFormat: \"anthropic\" } }, \"anthropic/claude-sonnet-4.5\": { id: \"anthropic/claude-sonnet-4.5\", name: \"Anthropic: Claude Sonnet 4.5\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3.75 }, contextWindow: 1e6, maxTokens: 64e3, compat: { thinkingFormat: \"openrouter\", cacheControlFormat: \"anthropic\" } }, \"anthropic/claude-sonnet-4.5:batch\": { id: \"anthropic/claude-sonnet-4.5:batch\", name: \"Anthropic: Claude Sonnet 4.5 (batch)\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.5, output: 7.5, cacheRead: 0.15, cacheWrite: 1.875 }, contextWindow: 1e6, maxTokens: 64e3, compat: { thinkingFormat: \"openrouter\", cacheControlFormat: \"anthropic\" } }, \"anthropic/claude-sonnet-4.6\": { id: \"anthropic/claude-sonnet-4.6\", name: \"Anthropic: Claude Sonnet 4.6\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3.75 }, contextWindow: 1e6, maxTokens: 128e3, compat: { thinkingFormat: \"openrouter\", cacheControlFormat: \"anthropic\" }, thinkingLevelMap: { max: \"max\" } }, \"anthropic/claude-sonnet-4.6:batch\": { id: \"anthropic/claude-sonnet-4.6:batch\", name: \"Anthropic: Claude Sonnet 4.6 (batch)\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.5, output: 7.5, cacheRead: 0.15, cacheWrite: 1.875 }, contextWindow: 1e6, maxTokens: 128e3, compat: { thinkingFormat: \"openrouter\", cacheControlFormat: \"anthropic\" }, thinkingLevelMap: { max: \"max\" } }, \"anthropic/claude-sonnet-5\": { id: \"anthropic/claude-sonnet-5\", name: \"Anthropic: Claude Sonnet 5\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 2, output: 10, cacheRead: 0.2, cacheWrite: 2.5 }, contextWindow: 1e6, maxTokens: 128e3, compat: { thinkingFormat: \"openrouter\", cacheControlFormat: \"anthropic\" }, thinkingLevelMap: { xhigh: \"xhigh\", max: \"max\" } }, \"anthropic/claude-sonnet-5:batch\": { id: \"anthropic/claude-sonnet-5:batch\", name: \"Anthropic: Claude Sonnet 5 (batch)\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1, output: 5, cacheRead: 0.1, cacheWrite: 1.25 }, contextWindow: 1e6, maxTokens: 128e3, compat: { thinkingFormat: \"openrouter\", cacheControlFormat: \"anthropic\" }, thinkingLevelMap: { xhigh: \"xhigh\", max: \"max\" } }, \"arcee-ai/trinity-large-thinking\": { id: \"arcee-ai/trinity-large-thinking\", name: \"Arcee AI: Trinity Large Thinking\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\"], cost: { input: 0.22, output: 0.85, cacheRead: 0.06, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 262144, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"arcee-ai/virtuoso-large\": { id: \"arcee-ai/virtuoso-large\", name: \"Arcee AI: Virtuoso Large\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: false, input: [\"text\"], cost: { input: 0.75, output: 1.2, cacheRead: 0, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 64e3, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, auto: { id: \"auto\", name: \"Auto\", api: \"openai-completions\", provider: \"openrouter\", baseUrl: \"https://openrouter.ai/api/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 2e6, maxTokens: 3e4, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"bytedance-seed/seed-1.6\": { id: \"bytedance-seed/seed-1.6\", name: \"ByteDance Seed: Seed 1.6\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.25, output: 2, cacheRead: 0, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 32768, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"bytedance-seed/seed-1.6-flash\": { id: \"bytedance-seed/seed-1.6-flash\", name: \"ByteDance Seed: Seed 1.6 Flash\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.075, output: 0.3, cacheRead: 0, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 32768, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"bytedance-seed/seed-2-1-turbo\": { id: \"bytedance-seed/seed-2-1-turbo\", name: \"ByteDance Seed: Seed 2.1 Turbo\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.5, output: 2.5, cacheRead: 0, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 262144, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"bytedance-seed/seed-2.0-code\": { id: \"bytedance-seed/seed-2.0-code\", name: \"ByteDance Seed: Seed-2.0-Code\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.5, output: 3, cacheRead: 0, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 131072, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"bytedance-seed/seed-2.0-lite\": { id: \"bytedance-seed/seed-2.0-lite\", name: \"ByteDance Seed: Seed-2.0-Lite\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.25, output: 2, cacheRead: 0, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 131072, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"bytedance-seed/seed-2.0-mini\": { id: \"bytedance-seed/seed-2.0-mini\", name: \"ByteDance Seed: Seed-2.0-Mini\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.1, output: 0.4, cacheRead: 0, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 131072, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"cohere/command-r-08-2024\": { id: \"cohere/command-r-08-2024\", name: \"Cohere: Command R (08-2024)\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: false, input: [\"text\"], cost: { input: 0.15, output: 0.6, cacheRead: 0, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 4e3, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"cohere/command-r-plus-08-2024\": { id: \"cohere/command-r-plus-08-2024\", name: \"Cohere: Command R+ (08-2024)\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: false, input: [\"text\"], cost: { input: 2.5, output: 10, cacheRead: 0, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 4e3, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"cohere/north-mini-code:free\": { id: \"cohere/north-mini-code:free\", name: \"Cohere: North Mini Code (free)\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 256e3, maxTokens: 64e3, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"deepseek/deepseek-chat\": { id: \"deepseek/deepseek-chat\", name: \"DeepSeek: DeepSeek V3\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: false, input: [\"text\"], cost: { input: 0.2574, output: 1.0287, cacheRead: 0, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 16e3, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"deepseek/deepseek-chat-v3-0324\": { id: \"deepseek/deepseek-chat-v3-0324\", name: \"DeepSeek: DeepSeek V3 0324\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: false, input: [\"text\"], cost: { input: 0.27, output: 1.12, cacheRead: 0.135, cacheWrite: 0 }, contextWindow: 163840, maxTokens: 65536, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"deepseek/deepseek-chat-v3.1\": { id: \"deepseek/deepseek-chat-v3.1\", name: \"DeepSeek: DeepSeek V3.1\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\"], cost: { input: 0.25, output: 0.95, cacheRead: 0.13, cacheWrite: 0 }, contextWindow: 163840, maxTokens: 32768, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"deepseek/deepseek-r1\": { id: \"deepseek/deepseek-r1\", name: \"DeepSeek: R1\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\"], cost: { input: 0.7, output: 2.5, cacheRead: 0, cacheWrite: 0 }, contextWindow: 64e3, maxTokens: 16e3, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"deepseek/deepseek-r1-0528\": { id: \"deepseek/deepseek-r1-0528\", name: \"DeepSeek: R1 0528\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\"], cost: { input: 0.5, output: 2.15, cacheRead: 0.35, cacheWrite: 0 }, contextWindow: 163840, maxTokens: 32768, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"deepseek/deepseek-v3.1-terminus\": { id: \"deepseek/deepseek-v3.1-terminus\", name: \"DeepSeek: DeepSeek V3.1 Terminus\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\"], cost: { input: 0.27, output: 0.95, cacheRead: 0.13, cacheWrite: 0 }, contextWindow: 163840, maxTokens: 32768, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"deepseek/deepseek-v3.2\": { id: \"deepseek/deepseek-v3.2\", name: \"DeepSeek: DeepSeek V3.2\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\"], cost: { input: 0.269, output: 0.4, cacheRead: 0.1345, cacheWrite: 0 }, contextWindow: 163840, maxTokens: 65536, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"deepseek/deepseek-v3.2-exp\": { id: \"deepseek/deepseek-v3.2-exp\", name: \"DeepSeek: DeepSeek V3.2 Exp\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\"], cost: { input: 0.27, output: 0.41, cacheRead: 0, cacheWrite: 0 }, contextWindow: 163840, maxTokens: 65536, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"deepseek/deepseek-v4-flash\": { id: \"deepseek/deepseek-v4-flash\", name: \"DeepSeek: DeepSeek V4 Flash 0423\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\"], cost: { input: 0.14, output: 0.28, cacheRead: 0.028, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 393216, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\", requiresReasoningContentOnAssistantMessages: true }, thinkingLevelMap: { minimal: null, low: null, medium: null, high: \"high\", max: null, xhigh: \"xhigh\" } }, \"deepseek/deepseek-v4-flash-0731\": { id: \"deepseek/deepseek-v4-flash-0731\", name: \"DeepSeek: DeepSeek V4 Flash 0731\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\"], cost: { input: 0.14, output: 0.28, cacheRead: 0.028, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 393216, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\", requiresReasoningContentOnAssistantMessages: true }, thinkingLevelMap: { minimal: null, low: null, medium: null, high: \"high\", max: null, xhigh: \"xhigh\" } }, \"deepseek/deepseek-v4-pro\": { id: \"deepseek/deepseek-v4-pro\", name: \"DeepSeek: DeepSeek V4 Pro\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\"], cost: { input: 1.168, output: 2.336, cacheRead: 0.09855, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 393216, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\", requiresReasoningContentOnAssistantMessages: true }, thinkingLevelMap: { minimal: null, low: null, medium: null, high: \"high\", max: null, xhigh: \"xhigh\" } }, \"deepseek/deepseek-v4-pro-0813\": { id: \"deepseek/deepseek-v4-pro-0813\", name: \"DeepSeek: DeepSeek V4 Pro 0813\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\"], cost: { input: 0.435, output: 0.87, cacheRead: 3625e-6, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 384e3, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\", requiresReasoningContentOnAssistantMessages: true }, thinkingLevelMap: { minimal: null, low: null, medium: null, high: \"high\", max: null, xhigh: \"xhigh\" } }, \"google/gemini-2.5-flash\": { id: \"google/gemini-2.5-flash\", name: \"Google: Gemini 2.5 Flash\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.3, output: 2.5, cacheRead: 0.03, cacheWrite: 0.083333 }, contextWindow: 1048576, maxTokens: 65535, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"google/gemini-2.5-flash-lite\": { id: \"google/gemini-2.5-flash-lite\", name: \"Google: Gemini 2.5 Flash Lite\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.1, output: 0.4, cacheRead: 0.01, cacheWrite: 0.083333 }, contextWindow: 1048576, maxTokens: 65535, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"google/gemini-2.5-flash-lite:batch\": { id: \"google/gemini-2.5-flash-lite:batch\", name: \"Google: Gemini 2.5 Flash Lite (batch)\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.05, output: 0.2, cacheRead: 0.01, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65535, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"google/gemini-2.5-flash:batch\": { id: \"google/gemini-2.5-flash:batch\", name: \"Google: Gemini 2.5 Flash (batch)\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.15, output: 1.25, cacheRead: 0.03, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65535, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"google/gemini-2.5-pro\": { id: \"google/gemini-2.5-pro\", name: \"Google: Gemini 2.5 Pro\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.25, output: 10, cacheRead: 0.125, cacheWrite: 0.375 }, contextWindow: 1048576, maxTokens: 65536, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"google/gemini-2.5-pro-preview\": { id: \"google/gemini-2.5-pro-preview\", name: \"Google: Gemini 2.5 Pro Preview 06-05\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.25, output: 10, cacheRead: 0.125, cacheWrite: 0.375 }, contextWindow: 1048576, maxTokens: 65536, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"google/gemini-2.5-pro-preview-05-06\": { id: \"google/gemini-2.5-pro-preview-05-06\", name: \"Google: Gemini 2.5 Pro Preview 05-06\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.25, output: 10, cacheRead: 0.125, cacheWrite: 0.375 }, contextWindow: 1048576, maxTokens: 65535, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"google/gemini-2.5-pro:batch\": { id: \"google/gemini-2.5-pro:batch\", name: \"Google: Gemini 2.5 Pro (batch)\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.625, output: 5, cacheRead: 0.125, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"google/gemini-3-flash-preview\": { id: \"google/gemini-3-flash-preview\", name: \"Google: Gemini 3 Flash Preview\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.5, output: 3, cacheRead: 0.05, cacheWrite: 0.083333 }, contextWindow: 1048576, maxTokens: 65536, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"google/gemini-3-flash-preview:batch\": { id: \"google/gemini-3-flash-preview:batch\", name: \"Google: Gemini 3 Flash Preview (batch)\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.25, output: 1.5, cacheRead: 0, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"google/gemini-3-pro-image\": { id: \"google/gemini-3-pro-image\", name: \"Google: Nano Banana Pro (Gemini 3 Pro Image)\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 2, output: 12, cacheRead: 0.2, cacheWrite: 0.375 }, contextWindow: 65536, maxTokens: 32768, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"google/gemini-3.1-flash-lite\": { id: \"google/gemini-3.1-flash-lite\", name: \"Google: Gemini 3.1 Flash Lite\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.25, output: 1.5, cacheRead: 0.025, cacheWrite: 0.083333 }, contextWindow: 1048576, maxTokens: 65536, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"google/gemini-3.1-flash-lite-preview\": { id: \"google/gemini-3.1-flash-lite-preview\", name: \"Google: Gemini 3.1 Flash Lite Preview\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.25, output: 1.5, cacheRead: 0.025, cacheWrite: 0.083333 }, contextWindow: 1048576, maxTokens: 65536, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"google/gemini-3.1-flash-lite:batch\": { id: \"google/gemini-3.1-flash-lite:batch\", name: \"Google: Gemini 3.1 Flash Lite (batch)\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.125, output: 0.75, cacheRead: 0.0125, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"google/gemini-3.1-pro-preview\": { id: \"google/gemini-3.1-pro-preview\", name: \"Google: Gemini 3.1 Pro Preview\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 2, output: 12, cacheRead: 0.2, cacheWrite: 0.375 }, contextWindow: 1048576, maxTokens: 65536, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"google/gemini-3.1-pro-preview-customtools\": { id: \"google/gemini-3.1-pro-preview-customtools\", name: \"Google: Gemini 3.1 Pro Preview Custom Tools\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 2, output: 12, cacheRead: 0.2, cacheWrite: 0.375 }, contextWindow: 1048576, maxTokens: 65536, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"google/gemini-3.1-pro-preview:batch\": { id: \"google/gemini-3.1-pro-preview:batch\", name: \"Google: Gemini 3.1 Pro Preview (batch)\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1, output: 6, cacheRead: 0, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"google/gemini-3.5-flash\": { id: \"google/gemini-3.5-flash\", name: \"Google: Gemini 3.5 Flash\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.5, output: 9, cacheRead: 0.15, cacheWrite: 0.083333 }, contextWindow: 1048576, maxTokens: 65536, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"google/gemini-3.5-flash-lite\": { id: \"google/gemini-3.5-flash-lite\", name: \"Google: Gemini 3.5 Flash Lite\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.3, output: 2.5, cacheRead: 0.03, cacheWrite: 0.083333 }, contextWindow: 1048576, maxTokens: 65536, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"google/gemini-3.5-flash-lite:batch\": { id: \"google/gemini-3.5-flash-lite:batch\", name: \"Google: Gemini 3.5 Flash Lite (batch)\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.15, output: 1.25, cacheRead: 0.015, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"google/gemini-3.5-flash:batch\": { id: \"google/gemini-3.5-flash:batch\", name: \"Google: Gemini 3.5 Flash (batch)\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.75, output: 4.5, cacheRead: 0.075, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"google/gemini-3.6-flash\": { id: \"google/gemini-3.6-flash\", name: \"Google: Gemini 3.6 Flash\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.75, output: 3.75, cacheRead: 0.075, cacheWrite: 0.041667 }, contextWindow: 1048576, maxTokens: 65536, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"google/gemini-3.6-flash:batch\": { id: \"google/gemini-3.6-flash:batch\", name: \"Google: Gemini 3.6 Flash (batch)\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.375, output: 1.875, cacheRead: 0.0375, cacheWrite: 0.041667 }, contextWindow: 1048576, maxTokens: 65536, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"google/gemini-3.7-flash\": { id: \"google/gemini-3.7-flash\", name: \"Google: Gemini 3.7 Flash\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.375, output: 1.875, cacheRead: 0.0375, cacheWrite: 0.020833 }, contextWindow: 1048576, maxTokens: 65536, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"google/gemini-3.7-flash:batch\": { id: \"google/gemini-3.7-flash:batch\", name: \"Google: Gemini 3.7 Flash (batch)\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.1875, output: 0.9375, cacheRead: 0.01875, cacheWrite: 0.020833 }, contextWindow: 1048576, maxTokens: 65536, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"google/gemma-3-12b-it\": { id: \"google/gemma-3-12b-it\", name: \"Google: Gemma 3 12B\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 0.05, output: 0.15, cacheRead: 0, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 16384, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"google/gemma-3-27b-it\": { id: \"google/gemma-3-27b-it\", name: \"Google: Gemma 3 27B\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 0.08, output: 0.45, cacheRead: 0.04, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 131072, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"google/gemma-4-26b-a4b-it\": { id: \"google/gemma-4-26b-a4b-it\", name: \"Google: Gemma 4 26B A4B \", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.12, output: 0.4, cacheRead: 0.05, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 262144, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"google/gemma-4-26b-a4b-it:free\": { id: \"google/gemma-4-26b-a4b-it:free\", name: \"Google: Gemma 4 26B A4B  (free)\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 32768, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"google/gemma-4-31b-it\": { id: \"google/gemma-4-31b-it\", name: \"Google: Gemma 4 31B\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.1, output: 0.34, cacheRead: 0.1, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 262144, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"google/gemma-4-31b-it:free\": { id: \"google/gemma-4-31b-it:free\", name: \"Google: Gemma 4 31B (free)\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 32768, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"ibm-granite/granite-4.1-8b\": { id: \"ibm-granite/granite-4.1-8b\", name: \"IBM: Granite 4.1 8B\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: false, input: [\"text\"], cost: { input: 0.05, output: 0.1, cacheRead: 0.05, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 131072, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"inception/mercury-2\": { id: \"inception/mercury-2\", name: \"Inception: Mercury 2\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\"], cost: { input: 0.25, output: 0.75, cacheRead: 0.025, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 5e4, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" }, thinkingLevelMap: { off: null } }, \"inclusionai/ling-2.6-1t\": { id: \"inclusionai/ling-2.6-1t\", name: \"inclusionAI: Ling-2.6-1T\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: false, input: [\"text\"], cost: { input: 0.075, output: 0.625, cacheRead: 0.015, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 32768, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"inclusionai/ling-2.6-flash\": { id: \"inclusionai/ling-2.6-flash\", name: \"inclusionAI: Ling-2.6-flash\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: false, input: [\"text\"], cost: { input: 0.01, output: 0.03, cacheRead: 2e-3, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 32768, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"inclusionai/ling-3.0-flash\": { id: \"inclusionai/ling-3.0-flash\", name: \"Ling-3.0-flash\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\"], cost: { input: 0.021, output: 0.063, cacheRead: 42e-4, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 32768, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"inclusionai/ring-2.6-1t\": { id: \"inclusionai/ring-2.6-1t\", name: \"inclusionAI: Ring-2.6-1T\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\"], cost: { input: 0.075, output: 0.625, cacheRead: 0.015, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 65536, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"kwaipilot/kat-coder-air-v2.5\": { id: \"kwaipilot/kat-coder-air-v2.5\", name: \"Kwaipilot: KAT-Coder-Air V2.5\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: false, input: [\"text\"], cost: { input: 0.15, output: 0.6, cacheRead: 0.03, cacheWrite: 0 }, contextWindow: 256e3, maxTokens: 8e4, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"kwaipilot/kat-coder-pro-v2\": { id: \"kwaipilot/kat-coder-pro-v2\", name: \"Kwaipilot: KAT-Coder-Pro V2\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: false, input: [\"text\"], cost: { input: 0.3, output: 1.2, cacheRead: 0.06, cacheWrite: 0 }, contextWindow: 256e3, maxTokens: 8e4, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"kwaipilot/kat-coder-pro-v2.5\": { id: \"kwaipilot/kat-coder-pro-v2.5\", name: \"Kwaipilot: KAT-Coder-Pro V2.5\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: false, input: [\"text\"], cost: { input: 0.74, output: 2.96, cacheRead: 0.15, cacheWrite: 0 }, contextWindow: 256e3, maxTokens: 8e4, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"liquid/lfm-2.5-2.6b:free\": { id: \"liquid/lfm-2.5-2.6b:free\", name: \"LiquidAI: LFM2.5-2.6B (free)\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 8192, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"meituan/longcat-2.0\": { id: \"meituan/longcat-2.0\", name: \"Meituan: LongCat 2.0\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\"], cost: { input: 0.3, output: 1.2, cacheRead: 6e-3, cacheWrite: 0 }, contextWindow: 1048756, maxTokens: 262144, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"meta-llama/llama-3.1-70b-instruct\": { id: \"meta-llama/llama-3.1-70b-instruct\", name: \"Meta: Llama 3.1 70B Instruct\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: false, input: [\"text\"], cost: { input: 0.4, output: 0.4, cacheRead: 0, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 16384, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"meta-llama/llama-3.1-8b-instruct\": { id: \"meta-llama/llama-3.1-8b-instruct\", name: \"Meta: Llama 3.1 8B Instruct\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: false, input: [\"text\"], cost: { input: 0.05, output: 0.08, cacheRead: 0.025, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 131072, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"meta-llama/llama-3.3-70b-instruct\": { id: \"meta-llama/llama-3.3-70b-instruct\", name: \"Meta: Llama 3.3 70B Instruct\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: false, input: [\"text\"], cost: { input: 0.1, output: 0.32, cacheRead: 0, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 16384, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"meta-llama/llama-4-maverick\": { id: \"meta-llama/llama-4-maverick\", name: \"Meta: Llama 4 Maverick\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 0.2, output: 0.8, cacheRead: 0, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 16384, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"meta-llama/llama-4-scout\": { id: \"meta-llama/llama-4-scout\", name: \"Meta: Llama 4 Scout\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 0.1, output: 0.3, cacheRead: 0, cacheWrite: 0 }, contextWindow: 327680, maxTokens: 16384, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"meta/muse-glimmer-30b\": { id: \"meta/muse-glimmer-30b\", name: \"Meta: Muse Glimmer 30B\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.35, output: 1.5, cacheRead: 0.04, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 4096, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"meta/muse-spark-1.1\": { id: \"meta/muse-spark-1.1\", name: \"Meta: Muse Spark 1.1\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.25, output: 4.25, cacheRead: 0.15, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 4096, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"meta/muse-spark-1.2\": { id: \"meta/muse-spark-1.2\", name: \"Meta: Muse Spark 1.2\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.25, output: 4.25, cacheRead: 0.15, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 4096, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"minimax/minimax-m1\": { id: \"minimax/minimax-m1\", name: \"MiniMax: MiniMax M1\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\"], cost: { input: 0.55, output: 2.2, cacheRead: 0, cacheWrite: 0 }, contextWindow: 1e6, maxTokens: 4e4, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"minimax/minimax-m2\": { id: \"minimax/minimax-m2\", name: \"MiniMax: MiniMax M2\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\"], cost: { input: 0.255, output: 1.02, cacheRead: 0, cacheWrite: 0 }, contextWindow: 204800, maxTokens: 131072, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"minimax/minimax-m2.1\": { id: \"minimax/minimax-m2.1\", name: \"MiniMax: MiniMax M2.1\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\"], cost: { input: 0.3, output: 1.2, cacheRead: 0.03, cacheWrite: 0 }, contextWindow: 204800, maxTokens: 131072, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"minimax/minimax-m2.5\": { id: \"minimax/minimax-m2.5\", name: \"MiniMax: MiniMax M2.5\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\"], cost: { input: 0.22, output: 0.9, cacheRead: 0.05, cacheWrite: 0 }, contextWindow: 196608, maxTokens: 196608, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"minimax/minimax-m2.7\": { id: \"minimax/minimax-m2.7\", name: \"MiniMax: MiniMax M2.7\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\"], cost: { input: 0.3, output: 1.2, cacheRead: 0.06, cacheWrite: 0 }, contextWindow: 204800, maxTokens: 131072, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"minimax/minimax-m3\": { id: \"minimax/minimax-m3\", name: \"MiniMax: MiniMax M3\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.3, output: 1.2, cacheRead: 0.06, cacheWrite: 0 }, contextWindow: 524288, maxTokens: 512e3, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"minimax/minimax-m3:batch\": { id: \"minimax/minimax-m3:batch\", name: \"MiniMax: MiniMax M3 (batch)\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.15, output: 0.6, cacheRead: 0.03, cacheWrite: 0 }, contextWindow: 524288, maxTokens: 4096, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"mistralai/codestral-2508\": { id: \"mistralai/codestral-2508\", name: \"Mistral: Codestral 2508\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: false, input: [\"text\"], cost: { input: 0.3, output: 0.9, cacheRead: 0.03, cacheWrite: 0 }, contextWindow: 256e3, maxTokens: 4096, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"mistralai/ministral-14b-2512\": { id: \"mistralai/ministral-14b-2512\", name: \"Mistral: Ministral 3 14B 2512\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 0.2, output: 0.2, cacheRead: 0.02, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 4096, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"mistralai/ministral-3b-2512\": { id: \"mistralai/ministral-3b-2512\", name: \"Mistral: Ministral 3 3B 2512\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 0.1, output: 0.1, cacheRead: 0.01, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 4096, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"mistralai/ministral-8b-2512\": { id: \"mistralai/ministral-8b-2512\", name: \"Mistral: Ministral 3 8B 2512\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 0.15, output: 0.15, cacheRead: 0.015, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 4096, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"mistralai/mistral-large\": { id: \"mistralai/mistral-large\", name: \"Mistral Large\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: false, input: [\"text\"], cost: { input: 2, output: 6, cacheRead: 0.2, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 4096, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"mistralai/mistral-large-2407\": { id: \"mistralai/mistral-large-2407\", name: \"Mistral Large 2407\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: false, input: [\"text\"], cost: { input: 2, output: 6, cacheRead: 0.2, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 4096, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"mistralai/mistral-large-2512\": { id: \"mistralai/mistral-large-2512\", name: \"Mistral: Mistral Large 3 2512\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 0.5, output: 1.5, cacheRead: 0.05, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 4096, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"mistralai/mistral-medium-3\": { id: \"mistralai/mistral-medium-3\", name: \"Mistral: Mistral Medium 3\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 0.4, output: 2, cacheRead: 0.04, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 4096, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"mistralai/mistral-medium-3-5\": { id: \"mistralai/mistral-medium-3-5\", name: \"Mistral: Mistral Medium 3.5\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.5, output: 7.5, cacheRead: 0, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 4096, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"mistralai/mistral-medium-3.1\": { id: \"mistralai/mistral-medium-3.1\", name: \"Mistral: Mistral Medium 3.1\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 0.4, output: 2, cacheRead: 0.04, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 4096, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"mistralai/mistral-nemo\": { id: \"mistralai/mistral-nemo\", name: \"Mistral: Mistral Nemo\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: false, input: [\"text\"], cost: { input: 0.019, output: 0.03, cacheRead: 0, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 16384, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"mistralai/mistral-saba\": { id: \"mistralai/mistral-saba\", name: \"Mistral: Saba\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: false, input: [\"text\"], cost: { input: 0.2, output: 0.6, cacheRead: 0.02, cacheWrite: 0 }, contextWindow: 32768, maxTokens: 4096, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"mistralai/mistral-small-2603\": { id: \"mistralai/mistral-small-2603\", name: \"Mistral: Mistral Small 4\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.15, output: 0.6, cacheRead: 0.015, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 4096, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"mistralai/mistral-small-3.2-24b-instruct\": { id: \"mistralai/mistral-small-3.2-24b-instruct\", name: \"Mistral: Mistral Small 3.2 24B\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 0.09375, output: 0.25, cacheRead: 0, cacheWrite: 0 }, contextWindow: 256e3, maxTokens: 16384, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"mistralai/mixtral-8x22b-instruct\": { id: \"mistralai/mixtral-8x22b-instruct\", name: \"Mistral: Mixtral 8x22B Instruct\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: false, input: [\"text\"], cost: { input: 2, output: 6, cacheRead: 0.2, cacheWrite: 0 }, contextWindow: 65536, maxTokens: 4096, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"mistralai/voxtral-small-24b-2507\": { id: \"mistralai/voxtral-small-24b-2507\", name: \"Mistral: Voxtral Small 24B 2507\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: false, input: [\"text\"], cost: { input: 0.1, output: 0.3, cacheRead: 0.01, cacheWrite: 0 }, contextWindow: 32e3, maxTokens: 4096, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"moonshotai/kimi-k2\": { id: \"moonshotai/kimi-k2\", name: \"MoonshotAI: Kimi K2 0711\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: false, input: [\"text\"], cost: { input: 0.57, output: 2.3, cacheRead: 0, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 100352, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"moonshotai/kimi-k2-0905\": { id: \"moonshotai/kimi-k2-0905\", name: \"MoonshotAI: Kimi K2 0905\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: false, input: [\"text\"], cost: { input: 0.6, output: 2.5, cacheRead: 0, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 100352, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"moonshotai/kimi-k2-thinking\": { id: \"moonshotai/kimi-k2-thinking\", name: \"MoonshotAI: Kimi K2 Thinking\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\"], cost: { input: 0.6, output: 2.5, cacheRead: 0.15, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 100352, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"moonshotai/kimi-k2.5\": { id: \"moonshotai/kimi-k2.5\", name: \"MoonshotAI: Kimi K2.5\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.41, output: 2.06, cacheRead: 0.07, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 4096, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"moonshotai/kimi-k2.6\": { id: \"moonshotai/kimi-k2.6\", name: \"MoonshotAI: Kimi K2.6\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.95, output: 4, cacheRead: 0.16, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 262144, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\", requiresReasoningContentOnAssistantMessages: true } }, \"moonshotai/kimi-k2.7-code\": { id: \"moonshotai/kimi-k2.7-code\", name: \"MoonshotAI: Kimi K2.7 Code\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.67, output: 3.4, cacheRead: 0.15, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 262144, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"moonshotai/kimi-k2.7-code:batch\": { id: \"moonshotai/kimi-k2.7-code:batch\", name: \"MoonshotAI: Kimi K2.7 Code (batch)\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.475, output: 2, cacheRead: 0.095, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 4096, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"moonshotai/kimi-k3\": { id: \"moonshotai/kimi-k3\", name: \"MoonshotAI: Kimi K3\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 131072, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"nex-agi/nex-n2-mini\": { id: \"nex-agi/nex-n2-mini\", name: \"Nex AGI: Nex-N2-Mini\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.025, output: 0.1, cacheRead: 25e-4, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 262144, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"nex-agi/nex-n2-pro\": { id: \"nex-agi/nex-n2-pro\", name: \"Nex AGI: Nex-N2-Pro\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.25, output: 1, cacheRead: 0.025, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 262144, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"nvidia/nemotron-3-nano-30b-a3b\": { id: \"nvidia/nemotron-3-nano-30b-a3b\", name: \"NVIDIA: Nemotron 3 Nano 30B A3B\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\"], cost: { input: 0.05, output: 0.2, cacheRead: 0.025, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 228e3, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"nvidia/nemotron-3-nano-30b-a3b:free\": { id: \"nvidia/nemotron-3-nano-30b-a3b:free\", name: \"NVIDIA: Nemotron 3 Nano 30B A3B (free)\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 256e3, maxTokens: 4096, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"nvidia/nemotron-3-nano-omni-30b-a3b-reasoning:free\": { id: \"nvidia/nemotron-3-nano-omni-30b-a3b-reasoning:free\", name: \"NVIDIA: Nemotron 3 Nano Omni (free)\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 256e3, maxTokens: 65536, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"nvidia/nemotron-3-super-120b-a12b\": { id: \"nvidia/nemotron-3-super-120b-a12b\", name: \"NVIDIA: Nemotron 3 Super\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\"], cost: { input: 0.085, output: 0.4, cacheRead: 0, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 16384, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"nvidia/nemotron-3-super-120b-a12b:free\": { id: \"nvidia/nemotron-3-super-120b-a12b:free\", name: \"NVIDIA: Nemotron 3 Super (free)\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 262144, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"nvidia/nemotron-3-ultra-550b-a55b\": { id: \"nvidia/nemotron-3-ultra-550b-a55b\", name: \"NVIDIA: Nemotron 3 Ultra\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\"], cost: { input: 0.6, output: 3.6, cacheRead: 0.2, cacheWrite: 0 }, contextWindow: 512288, maxTokens: 4096, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"nvidia/nemotron-3-ultra-550b-a55b:batch\": { id: \"nvidia/nemotron-3-ultra-550b-a55b:batch\", name: \"NVIDIA: Nemotron 3 Ultra (batch)\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\"], cost: { input: 0.3, output: 1.8, cacheRead: 0.1, cacheWrite: 0 }, contextWindow: 512288, maxTokens: 4096, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"nvidia/nemotron-3-ultra-550b-a55b:free\": { id: \"nvidia/nemotron-3-ultra-550b-a55b:free\", name: \"NVIDIA: Nemotron 3 Ultra (free)\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 1e6, maxTokens: 65536, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"nvidia/nemotron-3.5-lightning\": { id: \"nvidia/nemotron-3.5-lightning\", name: \"NVIDIA: Nemotron 3.5 Lightning\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\"], cost: { input: 0.1, output: 0.25, cacheRead: 0.05, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 262144, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"nvidia/nemotron-3.5-lightning:free\": { id: \"nvidia/nemotron-3.5-lightning:free\", name: \"NVIDIA: Nemotron 3.5 Lightning (free)\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 1e6, maxTokens: 65536, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"nvidia/nemotron-nano-12b-v2-vl:free\": { id: \"nvidia/nemotron-nano-12b-v2-vl:free\", name: \"NVIDIA: Nemotron Nano 12B 2 VL (free)\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 128e3, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"nvidia/nemotron-nano-9b-v2:free\": { id: \"nvidia/nemotron-nano-9b-v2:free\", name: \"NVIDIA: Nemotron Nano 9B V2 (free)\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 4096, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"openai/gpt-3.5-turbo\": { id: \"openai/gpt-3.5-turbo\", name: \"OpenAI: GPT-3.5 Turbo\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: false, input: [\"text\"], cost: { input: 0.5, output: 1.5, cacheRead: 0, cacheWrite: 0 }, contextWindow: 16385, maxTokens: 4096, compat: { thinkingFormat: \"openrouter\" } }, \"openai/gpt-3.5-turbo-0613\": { id: \"openai/gpt-3.5-turbo-0613\", name: \"OpenAI: GPT-3.5 Turbo (older v0613)\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: false, input: [\"text\"], cost: { input: 1, output: 2, cacheRead: 0, cacheWrite: 0 }, contextWindow: 4095, maxTokens: 4096, compat: { thinkingFormat: \"openrouter\" } }, \"openai/gpt-3.5-turbo-16k\": { id: \"openai/gpt-3.5-turbo-16k\", name: \"OpenAI: GPT-3.5 Turbo 16k\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: false, input: [\"text\"], cost: { input: 3, output: 4, cacheRead: 0, cacheWrite: 0 }, contextWindow: 16385, maxTokens: 4096, compat: { thinkingFormat: \"openrouter\" } }, \"openai/gpt-3.5-turbo:batch\": { id: \"openai/gpt-3.5-turbo:batch\", name: \"OpenAI: GPT-3.5 Turbo (batch)\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: false, input: [\"text\"], cost: { input: 0.25, output: 0.75, cacheRead: 0, cacheWrite: 0 }, contextWindow: 16385, maxTokens: 4096, compat: { thinkingFormat: \"openrouter\" } }, \"openai/gpt-4\": { id: \"openai/gpt-4\", name: \"OpenAI: GPT-4\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: false, input: [\"text\"], cost: { input: 30, output: 60, cacheRead: 0, cacheWrite: 0 }, contextWindow: 8191, maxTokens: 4096, compat: { thinkingFormat: \"openrouter\" } }, \"openai/gpt-4-turbo\": { id: \"openai/gpt-4-turbo\", name: \"OpenAI: GPT-4 Turbo\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 10, output: 30, cacheRead: 0, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 4096, compat: { thinkingFormat: \"openrouter\" } }, \"openai/gpt-4-turbo-preview\": { id: \"openai/gpt-4-turbo-preview\", name: \"OpenAI: GPT-4 Turbo Preview\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: false, input: [\"text\"], cost: { input: 10, output: 30, cacheRead: 0, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 4096, compat: { thinkingFormat: \"openrouter\" } }, \"openai/gpt-4-turbo:batch\": { id: \"openai/gpt-4-turbo:batch\", name: \"OpenAI: GPT-4 Turbo (batch)\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 5, output: 15, cacheRead: 0, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 4096, compat: { thinkingFormat: \"openrouter\" } }, \"openai/gpt-4.1\": { id: \"openai/gpt-4.1\", name: \"OpenAI: GPT-4.1\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 2, output: 8, cacheRead: 0.5, cacheWrite: 0 }, contextWindow: 1047576, maxTokens: 32768, compat: { thinkingFormat: \"openrouter\" } }, \"openai/gpt-4.1-mini\": { id: \"openai/gpt-4.1-mini\", name: \"OpenAI: GPT-4.1 Mini\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 0.4, output: 1.6, cacheRead: 0.1, cacheWrite: 0 }, contextWindow: 1047576, maxTokens: 32768, compat: { thinkingFormat: \"openrouter\" } }, \"openai/gpt-4.1-mini:batch\": { id: \"openai/gpt-4.1-mini:batch\", name: \"OpenAI: GPT-4.1 Mini (batch)\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 0.2, output: 0.8, cacheRead: 0.05, cacheWrite: 0 }, contextWindow: 1047576, maxTokens: 32768, compat: { thinkingFormat: \"openrouter\" } }, \"openai/gpt-4.1-nano\": { id: \"openai/gpt-4.1-nano\", name: \"OpenAI: GPT-4.1 Nano\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 0.1, output: 0.4, cacheRead: 0.025, cacheWrite: 0 }, contextWindow: 1047576, maxTokens: 32768, compat: { thinkingFormat: \"openrouter\" } }, \"openai/gpt-4.1-nano:batch\": { id: \"openai/gpt-4.1-nano:batch\", name: \"OpenAI: GPT-4.1 Nano (batch)\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 0.05, output: 0.2, cacheRead: 0.0125, cacheWrite: 0 }, contextWindow: 1047576, maxTokens: 32768, compat: { thinkingFormat: \"openrouter\" } }, \"openai/gpt-4.1:batch\": { id: \"openai/gpt-4.1:batch\", name: \"OpenAI: GPT-4.1 (batch)\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 1, output: 4, cacheRead: 0.25, cacheWrite: 0 }, contextWindow: 1047576, maxTokens: 32768, compat: { thinkingFormat: \"openrouter\" } }, \"openai/gpt-4o\": { id: \"openai/gpt-4o\", name: \"OpenAI: GPT-4o\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 2.5, output: 10, cacheRead: 1.25, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 16384, compat: { thinkingFormat: \"openrouter\" } }, \"openai/gpt-4o-2024-05-13\": { id: \"openai/gpt-4o-2024-05-13\", name: \"OpenAI: GPT-4o (2024-05-13)\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 5, output: 15, cacheRead: 0, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 4096, compat: { thinkingFormat: \"openrouter\" } }, \"openai/gpt-4o-2024-08-06\": { id: \"openai/gpt-4o-2024-08-06\", name: \"OpenAI: GPT-4o (2024-08-06)\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 2.5, output: 10, cacheRead: 1.25, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 16384, compat: { thinkingFormat: \"openrouter\" } }, \"openai/gpt-4o-2024-11-20\": { id: \"openai/gpt-4o-2024-11-20\", name: \"OpenAI: GPT-4o (2024-11-20)\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 2.5, output: 10, cacheRead: 1.25, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 16384, compat: { thinkingFormat: \"openrouter\" } }, \"openai/gpt-4o-mini\": { id: \"openai/gpt-4o-mini\", name: \"OpenAI: GPT-4o-mini\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 0.15, output: 0.6, cacheRead: 0.075, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 16384, compat: { thinkingFormat: \"openrouter\" } }, \"openai/gpt-4o-mini-2024-07-18\": { id: \"openai/gpt-4o-mini-2024-07-18\", name: \"OpenAI: GPT-4o-mini (2024-07-18)\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 0.15, output: 0.6, cacheRead: 0.075, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 16384, compat: { thinkingFormat: \"openrouter\" } }, \"openai/gpt-4o-mini:batch\": { id: \"openai/gpt-4o-mini:batch\", name: \"OpenAI: GPT-4o-mini (batch)\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 0.075, output: 0.3, cacheRead: 0.0375, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 16384, compat: { thinkingFormat: \"openrouter\" } }, \"openai/gpt-4o:batch\": { id: \"openai/gpt-4o:batch\", name: \"OpenAI: GPT-4o (batch)\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 1.25, output: 5, cacheRead: 0.625, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 16384, compat: { thinkingFormat: \"openrouter\" } }, \"openai/gpt-5\": { id: \"openai/gpt-5\", name: \"OpenAI: GPT-5\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.25, output: 10, cacheRead: 0.125, cacheWrite: 0 }, contextWindow: 4e5, maxTokens: 128e3, compat: { thinkingFormat: \"openrouter\" } }, \"openai/gpt-5-codex:batch\": { id: \"openai/gpt-5-codex:batch\", name: \"OpenAI: GPT-5 Codex (batch)\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.625, output: 5, cacheRead: 0.0625, cacheWrite: 0 }, contextWindow: 4e5, maxTokens: 128e3, compat: { thinkingFormat: \"openrouter\" } }, \"openai/gpt-5-mini\": { id: \"openai/gpt-5-mini\", name: \"OpenAI: GPT-5 Mini\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.25, output: 2, cacheRead: 0.025, cacheWrite: 0 }, contextWindow: 4e5, maxTokens: 128e3, compat: { thinkingFormat: \"openrouter\" } }, \"openai/gpt-5-mini:batch\": { id: \"openai/gpt-5-mini:batch\", name: \"OpenAI: GPT-5 Mini (batch)\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.125, output: 1, cacheRead: 0.0125, cacheWrite: 0 }, contextWindow: 4e5, maxTokens: 128e3, compat: { thinkingFormat: \"openrouter\" } }, \"openai/gpt-5-nano\": { id: \"openai/gpt-5-nano\", name: \"OpenAI: GPT-5 Nano\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.05, output: 0.4, cacheRead: 5e-3, cacheWrite: 0 }, contextWindow: 4e5, maxTokens: 128e3, compat: { thinkingFormat: \"openrouter\" } }, \"openai/gpt-5-nano:batch\": { id: \"openai/gpt-5-nano:batch\", name: \"OpenAI: GPT-5 Nano (batch)\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.025, output: 0.2, cacheRead: 25e-4, cacheWrite: 0 }, contextWindow: 4e5, maxTokens: 128e3, compat: { thinkingFormat: \"openrouter\" } }, \"openai/gpt-5-pro\": { id: \"openai/gpt-5-pro\", name: \"OpenAI: GPT-5 Pro\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 15, output: 120, cacheRead: 0, cacheWrite: 0 }, contextWindow: 4e5, maxTokens: 128e3, compat: { thinkingFormat: \"openrouter\" } }, \"openai/gpt-5-pro:batch\": { id: \"openai/gpt-5-pro:batch\", name: \"OpenAI: GPT-5 Pro (batch)\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 7.5, output: 60, cacheRead: 0, cacheWrite: 0 }, contextWindow: 4e5, maxTokens: 128e3, compat: { thinkingFormat: \"openrouter\" } }, \"openai/gpt-5.1\": { id: \"openai/gpt-5.1\", name: \"OpenAI: GPT-5.1\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.25, output: 10, cacheRead: 0.125, cacheWrite: 0 }, contextWindow: 4e5, maxTokens: 128e3, compat: { thinkingFormat: \"openrouter\" } }, \"openai/gpt-5.1-codex\": { id: \"openai/gpt-5.1-codex\", name: \"OpenAI: GPT-5.1-Codex\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.25, output: 10, cacheRead: 0.13, cacheWrite: 0 }, contextWindow: 4e5, maxTokens: 128e3, compat: { thinkingFormat: \"openrouter\" } }, \"openai/gpt-5.1-codex-max\": { id: \"openai/gpt-5.1-codex-max\", name: \"OpenAI: GPT-5.1-Codex-Max\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.25, output: 10, cacheRead: 0.125, cacheWrite: 0 }, contextWindow: 4e5, maxTokens: 128e3, compat: { thinkingFormat: \"openrouter\" } }, \"openai/gpt-5.1-codex-mini\": { id: \"openai/gpt-5.1-codex-mini\", name: \"OpenAI: GPT-5.1-Codex-Mini\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.25, output: 2, cacheRead: 0.03, cacheWrite: 0 }, contextWindow: 4e5, maxTokens: 128e3, compat: { thinkingFormat: \"openrouter\" } }, \"openai/gpt-5.1:batch\": { id: \"openai/gpt-5.1:batch\", name: \"OpenAI: GPT-5.1 (batch)\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.625, output: 5, cacheRead: 0.0625, cacheWrite: 0 }, contextWindow: 4e5, maxTokens: 128e3, compat: { thinkingFormat: \"openrouter\" } }, \"openai/gpt-5.2\": { id: \"openai/gpt-5.2\", name: \"OpenAI: GPT-5.2\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.75, output: 14, cacheRead: 0.175, cacheWrite: 0 }, contextWindow: 4e5, maxTokens: 128e3, compat: { thinkingFormat: \"openrouter\" }, thinkingLevelMap: { xhigh: \"xhigh\" } }, \"openai/gpt-5.2-chat\": { id: \"openai/gpt-5.2-chat\", name: \"OpenAI: GPT-5.2 Chat\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 1.75, output: 14, cacheRead: 0.175, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 32e3, compat: { thinkingFormat: \"openrouter\" }, thinkingLevelMap: { xhigh: \"xhigh\" } }, \"openai/gpt-5.2-codex\": { id: \"openai/gpt-5.2-codex\", name: \"OpenAI: GPT-5.2-Codex\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.75, output: 14, cacheRead: 0.175, cacheWrite: 0 }, contextWindow: 4e5, maxTokens: 128e3, compat: { thinkingFormat: \"openrouter\" }, thinkingLevelMap: { xhigh: \"xhigh\" } }, \"openai/gpt-5.2-pro\": { id: \"openai/gpt-5.2-pro\", name: \"OpenAI: GPT-5.2 Pro\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 21, output: 168, cacheRead: 0, cacheWrite: 0 }, contextWindow: 4e5, maxTokens: 128e3, compat: { thinkingFormat: \"openrouter\" }, thinkingLevelMap: { xhigh: \"xhigh\" } }, \"openai/gpt-5.2-pro:batch\": { id: \"openai/gpt-5.2-pro:batch\", name: \"OpenAI: GPT-5.2 Pro (batch)\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 10.5, output: 84, cacheRead: 0, cacheWrite: 0 }, contextWindow: 4e5, maxTokens: 128e3, compat: { thinkingFormat: \"openrouter\" }, thinkingLevelMap: { xhigh: \"xhigh\" } }, \"openai/gpt-5.2:batch\": { id: \"openai/gpt-5.2:batch\", name: \"OpenAI: GPT-5.2 (batch)\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.875, output: 7, cacheRead: 0.0875, cacheWrite: 0 }, contextWindow: 4e5, maxTokens: 128e3, compat: { thinkingFormat: \"openrouter\" }, thinkingLevelMap: { xhigh: \"xhigh\" } }, \"openai/gpt-5.3-codex\": { id: \"openai/gpt-5.3-codex\", name: \"OpenAI: GPT-5.3-Codex\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.75, output: 14, cacheRead: 0.175, cacheWrite: 0 }, contextWindow: 4e5, maxTokens: 128e3, compat: { thinkingFormat: \"openrouter\" }, thinkingLevelMap: { xhigh: \"xhigh\" } }, \"openai/gpt-5.4\": { id: \"openai/gpt-5.4\", name: \"OpenAI: GPT-5.4\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 2.5, output: 15, cacheRead: 0.25, cacheWrite: 0 }, contextWindow: 105e4, maxTokens: 128e3, compat: { thinkingFormat: \"openrouter\" }, thinkingLevelMap: { xhigh: \"xhigh\" } }, \"openai/gpt-5.4-mini\": { id: \"openai/gpt-5.4-mini\", name: \"OpenAI: GPT-5.4 Mini\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.75, output: 4.5, cacheRead: 0.075, cacheWrite: 0 }, contextWindow: 4e5, maxTokens: 128e3, compat: { thinkingFormat: \"openrouter\" }, thinkingLevelMap: { xhigh: \"xhigh\" } }, \"openai/gpt-5.4-mini:batch\": { id: \"openai/gpt-5.4-mini:batch\", name: \"OpenAI: GPT-5.4 Mini (batch)\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.375, output: 2.25, cacheRead: 0.0375, cacheWrite: 0 }, contextWindow: 4e5, maxTokens: 128e3, compat: { thinkingFormat: \"openrouter\" }, thinkingLevelMap: { xhigh: \"xhigh\" } }, \"openai/gpt-5.4-nano\": { id: \"openai/gpt-5.4-nano\", name: \"OpenAI: GPT-5.4 Nano\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.2, output: 1.25, cacheRead: 0.02, cacheWrite: 0 }, contextWindow: 4e5, maxTokens: 128e3, compat: { thinkingFormat: \"openrouter\" }, thinkingLevelMap: { xhigh: \"xhigh\" } }, \"openai/gpt-5.4-nano:batch\": { id: \"openai/gpt-5.4-nano:batch\", name: \"OpenAI: GPT-5.4 Nano (batch)\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.1, output: 0.625, cacheRead: 0.01, cacheWrite: 0 }, contextWindow: 4e5, maxTokens: 128e3, compat: { thinkingFormat: \"openrouter\" }, thinkingLevelMap: { xhigh: \"xhigh\" } }, \"openai/gpt-5.4-pro\": { id: \"openai/gpt-5.4-pro\", name: \"OpenAI: GPT-5.4 Pro\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 30, output: 180, cacheRead: 0, cacheWrite: 0 }, contextWindow: 105e4, maxTokens: 128e3, compat: { thinkingFormat: \"openrouter\" }, thinkingLevelMap: { xhigh: \"xhigh\" } }, \"openai/gpt-5.4-pro:batch\": { id: \"openai/gpt-5.4-pro:batch\", name: \"OpenAI: GPT-5.4 Pro (batch)\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 15, output: 90, cacheRead: 0, cacheWrite: 0 }, contextWindow: 105e4, maxTokens: 128e3, compat: { thinkingFormat: \"openrouter\" }, thinkingLevelMap: { xhigh: \"xhigh\" } }, \"openai/gpt-5.4:batch\": { id: \"openai/gpt-5.4:batch\", name: \"OpenAI: GPT-5.4 (batch)\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.25, output: 7.5, cacheRead: 0.125, cacheWrite: 0 }, contextWindow: 105e4, maxTokens: 128e3, compat: { thinkingFormat: \"openrouter\" }, thinkingLevelMap: { xhigh: \"xhigh\" } }, \"openai/gpt-5.5\": { id: \"openai/gpt-5.5\", name: \"OpenAI: GPT-5.5\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 5, output: 30, cacheRead: 0.5, cacheWrite: 0 }, contextWindow: 105e4, maxTokens: 128e3, compat: { thinkingFormat: \"openrouter\" }, thinkingLevelMap: { xhigh: \"xhigh\" } }, \"openai/gpt-5.5-pro\": { id: \"openai/gpt-5.5-pro\", name: \"OpenAI: GPT-5.5 Pro\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 30, output: 180, cacheRead: 0, cacheWrite: 0 }, contextWindow: 105e4, maxTokens: 128e3, compat: { thinkingFormat: \"openrouter\" }, thinkingLevelMap: { xhigh: \"xhigh\", off: null, minimal: null, low: null } }, \"openai/gpt-5.5-pro:batch\": { id: \"openai/gpt-5.5-pro:batch\", name: \"OpenAI: GPT-5.5 Pro (batch)\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 15, output: 90, cacheRead: 0, cacheWrite: 0 }, contextWindow: 105e4, maxTokens: 128e3, compat: { thinkingFormat: \"openrouter\" }, thinkingLevelMap: { xhigh: \"xhigh\" } }, \"openai/gpt-5.5:batch\": { id: \"openai/gpt-5.5:batch\", name: \"OpenAI: GPT-5.5 (batch)\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 2.5, output: 15, cacheRead: 0.25, cacheWrite: 0 }, contextWindow: 105e4, maxTokens: 128e3, compat: { thinkingFormat: \"openrouter\" }, thinkingLevelMap: { xhigh: \"xhigh\" } }, \"openai/gpt-5.6-luna\": { id: \"openai/gpt-5.6-luna\", name: \"OpenAI: GPT-5.6 Luna\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.1, output: 0.6, cacheRead: 0.01, cacheWrite: 0.125 }, contextWindow: 105e4, maxTokens: 128e3, compat: { thinkingFormat: \"openrouter\" }, thinkingLevelMap: { xhigh: \"xhigh\", max: \"max\" } }, \"openai/gpt-5.6-luna-pro\": { id: \"openai/gpt-5.6-luna-pro\", name: \"OpenAI: GPT-5.6 Luna Pro\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.1, output: 0.6, cacheRead: 0.01, cacheWrite: 0.125 }, contextWindow: 105e4, maxTokens: 128e3, compat: { thinkingFormat: \"openrouter\" }, thinkingLevelMap: { xhigh: \"xhigh\", max: \"max\" } }, \"openai/gpt-5.6-luna-pro:batch\": { id: \"openai/gpt-5.6-luna-pro:batch\", name: \"OpenAI: GPT-5.6 Luna Pro (batch)\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.1, output: 0.6, cacheRead: 0.01, cacheWrite: 0 }, contextWindow: 105e4, maxTokens: 128e3, compat: { thinkingFormat: \"openrouter\" }, thinkingLevelMap: { xhigh: \"xhigh\", max: \"max\" } }, \"openai/gpt-5.6-luna:batch\": { id: \"openai/gpt-5.6-luna:batch\", name: \"OpenAI: GPT-5.6 Luna (batch)\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.1, output: 0.6, cacheRead: 0.01, cacheWrite: 0 }, contextWindow: 105e4, maxTokens: 128e3, compat: { thinkingFormat: \"openrouter\" }, thinkingLevelMap: { xhigh: \"xhigh\", max: \"max\" } }, \"openai/gpt-5.6-sol\": { id: \"openai/gpt-5.6-sol\", name: \"OpenAI: GPT-5.6 Sol\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 5, output: 30, cacheRead: 0.5, cacheWrite: 6.25 }, contextWindow: 105e4, maxTokens: 128e3, compat: { thinkingFormat: \"openrouter\" }, thinkingLevelMap: { xhigh: \"xhigh\", max: \"max\" } }, \"openai/gpt-5.6-sol-pro\": { id: \"openai/gpt-5.6-sol-pro\", name: \"OpenAI: GPT-5.6 Sol Pro\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 5, output: 30, cacheRead: 0.5, cacheWrite: 6.25 }, contextWindow: 105e4, maxTokens: 128e3, compat: { thinkingFormat: \"openrouter\" }, thinkingLevelMap: { xhigh: \"xhigh\", max: \"max\" } }, \"openai/gpt-5.6-sol-pro:batch\": { id: \"openai/gpt-5.6-sol-pro:batch\", name: \"OpenAI: GPT-5.6 Sol Pro (batch)\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 2.5, output: 15, cacheRead: 0.25, cacheWrite: 0 }, contextWindow: 105e4, maxTokens: 128e3, compat: { thinkingFormat: \"openrouter\" }, thinkingLevelMap: { xhigh: \"xhigh\", max: \"max\" } }, \"openai/gpt-5.6-sol:batch\": { id: \"openai/gpt-5.6-sol:batch\", name: \"OpenAI: GPT-5.6 Sol (batch)\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 2.5, output: 15, cacheRead: 0.25, cacheWrite: 0 }, contextWindow: 105e4, maxTokens: 128e3, compat: { thinkingFormat: \"openrouter\" }, thinkingLevelMap: { xhigh: \"xhigh\", max: \"max\" } }, \"openai/gpt-5.6-terra\": { id: \"openai/gpt-5.6-terra\", name: \"OpenAI: GPT-5.6 Terra\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1, output: 6, cacheRead: 0.1, cacheWrite: 1.25 }, contextWindow: 105e4, maxTokens: 128e3, compat: { thinkingFormat: \"openrouter\" }, thinkingLevelMap: { xhigh: \"xhigh\", max: \"max\" } }, \"openai/gpt-5.6-terra-pro\": { id: \"openai/gpt-5.6-terra-pro\", name: \"OpenAI: GPT-5.6 Terra Pro\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1, output: 6, cacheRead: 0.1, cacheWrite: 1.25 }, contextWindow: 105e4, maxTokens: 128e3, compat: { thinkingFormat: \"openrouter\" }, thinkingLevelMap: { xhigh: \"xhigh\", max: \"max\" } }, \"openai/gpt-5.6-terra-pro:batch\": { id: \"openai/gpt-5.6-terra-pro:batch\", name: \"OpenAI: GPT-5.6 Terra Pro (batch)\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1, output: 6, cacheRead: 0.1, cacheWrite: 0 }, contextWindow: 105e4, maxTokens: 128e3, compat: { thinkingFormat: \"openrouter\" }, thinkingLevelMap: { xhigh: \"xhigh\", max: \"max\" } }, \"openai/gpt-5.6-terra:batch\": { id: \"openai/gpt-5.6-terra:batch\", name: \"OpenAI: GPT-5.6 Terra (batch)\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1, output: 6, cacheRead: 0.1, cacheWrite: 0 }, contextWindow: 105e4, maxTokens: 128e3, compat: { thinkingFormat: \"openrouter\" }, thinkingLevelMap: { xhigh: \"xhigh\", max: \"max\" } }, \"openai/gpt-5:batch\": { id: \"openai/gpt-5:batch\", name: \"OpenAI: GPT-5 (batch)\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.625, output: 5, cacheRead: 0.0625, cacheWrite: 0 }, contextWindow: 4e5, maxTokens: 128e3, compat: { thinkingFormat: \"openrouter\" } }, \"openai/gpt-audio\": { id: \"openai/gpt-audio\", name: \"OpenAI: GPT Audio\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: false, input: [\"text\"], cost: { input: 2.5, output: 10, cacheRead: 0, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 16384, compat: { thinkingFormat: \"openrouter\" } }, \"openai/gpt-audio-mini\": { id: \"openai/gpt-audio-mini\", name: \"OpenAI: GPT Audio Mini\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: false, input: [\"text\"], cost: { input: 0.6, output: 2.4, cacheRead: 0, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 16384, compat: { thinkingFormat: \"openrouter\" } }, \"openai/gpt-chat-latest\": { id: \"openai/gpt-chat-latest\", name: \"OpenAI: GPT Chat Latest\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 5, output: 30, cacheRead: 0.5, cacheWrite: 0 }, contextWindow: 4e5, maxTokens: 128e3, compat: { thinkingFormat: \"openrouter\" } }, \"openai/gpt-oss-120b\": { id: \"openai/gpt-oss-120b\", name: \"OpenAI: gpt-oss-120b\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\"], cost: { input: 0.03, output: 0.17, cacheRead: 0.03, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 131072, compat: { thinkingFormat: \"openrouter\" } }, \"openai/gpt-oss-20b\": { id: \"openai/gpt-oss-20b\", name: \"OpenAI: gpt-oss-20b\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\"], cost: { input: 0.03, output: 0.13, cacheRead: 0.03, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 131072, compat: { thinkingFormat: \"openrouter\" } }, \"openai/gpt-oss-20b:free\": { id: \"openai/gpt-oss-20b:free\", name: \"OpenAI: gpt-oss-20b (free)\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 32768, compat: { thinkingFormat: \"openrouter\" } }, \"openai/gpt-oss-safeguard-20b\": { id: \"openai/gpt-oss-safeguard-20b\", name: \"OpenAI: gpt-oss-safeguard-20b\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\"], cost: { input: 0.075, output: 0.3, cacheRead: 0.0375, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 65536, compat: { thinkingFormat: \"openrouter\" } }, \"openai/o1\": { id: \"openai/o1\", name: \"OpenAI: o1\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 15, output: 60, cacheRead: 7.5, cacheWrite: 0 }, contextWindow: 2e5, maxTokens: 1e5, compat: { thinkingFormat: \"openrouter\" } }, \"openai/o1:batch\": { id: \"openai/o1:batch\", name: \"OpenAI: o1 (batch)\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 7.5, output: 30, cacheRead: 3.75, cacheWrite: 0 }, contextWindow: 2e5, maxTokens: 1e5, compat: { thinkingFormat: \"openrouter\" } }, \"openai/o3\": { id: \"openai/o3\", name: \"OpenAI: o3\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 2, output: 8, cacheRead: 0.5, cacheWrite: 0 }, contextWindow: 2e5, maxTokens: 1e5, compat: { thinkingFormat: \"openrouter\" } }, \"openai/o3-mini\": { id: \"openai/o3-mini\", name: \"OpenAI: o3 Mini\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\"], cost: { input: 1.1, output: 4.4, cacheRead: 0.55, cacheWrite: 0 }, contextWindow: 2e5, maxTokens: 1e5, compat: { thinkingFormat: \"openrouter\" } }, \"openai/o3-mini-high\": { id: \"openai/o3-mini-high\", name: \"OpenAI: o3 Mini High\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\"], cost: { input: 1.1, output: 4.4, cacheRead: 0.55, cacheWrite: 0 }, contextWindow: 2e5, maxTokens: 1e5, compat: { thinkingFormat: \"openrouter\" } }, \"openai/o3-mini-high:batch\": { id: \"openai/o3-mini-high:batch\", name: \"OpenAI: o3 Mini High (batch)\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\"], cost: { input: 0.55, output: 2.2, cacheRead: 0.275, cacheWrite: 0 }, contextWindow: 2e5, maxTokens: 1e5, compat: { thinkingFormat: \"openrouter\" } }, \"openai/o3-mini:batch\": { id: \"openai/o3-mini:batch\", name: \"OpenAI: o3 Mini (batch)\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\"], cost: { input: 0.55, output: 2.2, cacheRead: 0.275, cacheWrite: 0 }, contextWindow: 2e5, maxTokens: 1e5, compat: { thinkingFormat: \"openrouter\" } }, \"openai/o3-pro\": { id: \"openai/o3-pro\", name: \"OpenAI: o3 Pro\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 20, output: 80, cacheRead: 0, cacheWrite: 0 }, contextWindow: 2e5, maxTokens: 1e5, compat: { thinkingFormat: \"openrouter\" } }, \"openai/o3-pro:batch\": { id: \"openai/o3-pro:batch\", name: \"OpenAI: o3 Pro (batch)\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 10, output: 40, cacheRead: 0, cacheWrite: 0 }, contextWindow: 2e5, maxTokens: 1e5, compat: { thinkingFormat: \"openrouter\" } }, \"openai/o3:batch\": { id: \"openai/o3:batch\", name: \"OpenAI: o3 (batch)\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1, output: 4, cacheRead: 0.25, cacheWrite: 0 }, contextWindow: 2e5, maxTokens: 1e5, compat: { thinkingFormat: \"openrouter\" } }, \"openai/o4-mini\": { id: \"openai/o4-mini\", name: \"OpenAI: o4 Mini\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.1, output: 4.4, cacheRead: 0.275, cacheWrite: 0 }, contextWindow: 2e5, maxTokens: 1e5, compat: { thinkingFormat: \"openrouter\" } }, \"openai/o4-mini-high\": { id: \"openai/o4-mini-high\", name: \"OpenAI: o4 Mini High\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.1, output: 4.4, cacheRead: 0.275, cacheWrite: 0 }, contextWindow: 2e5, maxTokens: 1e5, compat: { thinkingFormat: \"openrouter\" } }, \"openai/o4-mini-high:batch\": { id: \"openai/o4-mini-high:batch\", name: \"OpenAI: o4 Mini High (batch)\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.55, output: 2.2, cacheRead: 0.1375, cacheWrite: 0 }, contextWindow: 2e5, maxTokens: 1e5, compat: { thinkingFormat: \"openrouter\" } }, \"openai/o4-mini:batch\": { id: \"openai/o4-mini:batch\", name: \"OpenAI: o4 Mini (batch)\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.55, output: 2.2, cacheRead: 0.1375, cacheWrite: 0 }, contextWindow: 2e5, maxTokens: 1e5, compat: { thinkingFormat: \"openrouter\" } }, \"openrouter/auto\": { id: \"openrouter/auto\", name: \"Auto Router\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: -1e6, output: -1e6, cacheRead: 0, cacheWrite: 0 }, contextWindow: 2e6, maxTokens: 4096, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"openrouter/auto-beta\": { id: \"openrouter/auto-beta\", name: \"Auto Router (Beta)\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: -1e6, output: -1e6, cacheRead: 0, cacheWrite: 0 }, contextWindow: 2e6, maxTokens: 4096, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"openrouter/free\": { id: \"openrouter/free\", name: \"Free Models Router\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 2e5, maxTokens: 4096, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"openrouter/fusion\": { id: \"openrouter/fusion\", name: \"OpenRouter: Fusion\", api: \"openai-completions\", provider: \"openrouter\", baseUrl: \"https://openrouter.ai/api/v1\", reasoning: true, input: [\"text\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 1e6, maxTokens: 3e4, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"poolside/laguna-s-2.1\": { id: \"poolside/laguna-s-2.1\", name: \"Poolside: Laguna S 2.1\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\"], cost: { input: 0.09, output: 0.18, cacheRead: 9e-3, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 131072, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"poolside/laguna-s-2.1:free\": { id: \"poolside/laguna-s-2.1:free\", name: \"Poolside: Laguna S 2.1 (free)\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 32768, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"poolside/laguna-xs-2.1\": { id: \"poolside/laguna-xs-2.1\", name: \"Poolside: Laguna XS 2.1\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\"], cost: { input: 0.06, output: 0.12, cacheRead: 0.03, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 32768, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"poolside/laguna-xs-2.1:free\": { id: \"poolside/laguna-xs-2.1:free\", name: \"Poolside: Laguna XS 2.1 (free)\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 32768, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"qwen/qwen-2.5-72b-instruct\": { id: \"qwen/qwen-2.5-72b-instruct\", name: \"Qwen2.5 72B Instruct\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: false, input: [\"text\"], cost: { input: 0.36, output: 0.4, cacheRead: 0, cacheWrite: 0 }, contextWindow: 32768, maxTokens: 16384, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"qwen/qwen-2.5-7b-instruct\": { id: \"qwen/qwen-2.5-7b-instruct\", name: \"Qwen: Qwen2.5 7B Instruct\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: false, input: [\"text\"], cost: { input: 0.1, output: 0.2, cacheRead: 0, cacheWrite: 0 }, contextWindow: 32768, maxTokens: 32768, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"qwen/qwen-plus\": { id: \"qwen/qwen-plus\", name: \"Qwen: Qwen-Plus\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: false, input: [\"text\"], cost: { input: 0.26, output: 0.78, cacheRead: 0.052, cacheWrite: 0.325 }, contextWindow: 1e6, maxTokens: 32768, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"qwen/qwen-plus-2025-07-28\": { id: \"qwen/qwen-plus-2025-07-28\", name: \"Qwen: Qwen Plus 0728\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: false, input: [\"text\"], cost: { input: 0.26, output: 0.78, cacheRead: 0, cacheWrite: 0 }, contextWindow: 1e6, maxTokens: 32768, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"qwen/qwen-plus-2025-07-28:thinking\": { id: \"qwen/qwen-plus-2025-07-28:thinking\", name: \"Qwen: Qwen Plus 0728 (thinking)\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\"], cost: { input: 0.4, output: 1.2, cacheRead: 0, cacheWrite: 0.5 }, contextWindow: 1e6, maxTokens: 32768, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"qwen/qwen3-14b\": { id: \"qwen/qwen3-14b\", name: \"Qwen: Qwen3 14B\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\"], cost: { input: 0.12, output: 0.24, cacheRead: 0, cacheWrite: 0 }, contextWindow: 40960, maxTokens: 16384, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"qwen/qwen3-235b-a22b\": { id: \"qwen/qwen3-235b-a22b\", name: \"Qwen: Qwen3 235B A22B\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\"], cost: { input: 0.455, output: 1.82, cacheRead: 0, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 8192, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"qwen/qwen3-235b-a22b-2507\": { id: \"qwen/qwen3-235b-a22b-2507\", name: \"Qwen: Qwen3 235B A22B Instruct 2507\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: false, input: [\"text\"], cost: { input: 0.09, output: 0.55, cacheRead: 0, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 16384, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"qwen/qwen3-235b-a22b-thinking-2507\": { id: \"qwen/qwen3-235b-a22b-thinking-2507\", name: \"Qwen: Qwen3 235B A22B Thinking 2507\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\"], cost: { input: 0.23, output: 2.3, cacheRead: 0, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 4096, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"qwen/qwen3-30b-a3b\": { id: \"qwen/qwen3-30b-a3b\", name: \"Qwen: Qwen3 30B A3B\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\"], cost: { input: 0.12, output: 0.5, cacheRead: 0, cacheWrite: 0 }, contextWindow: 40960, maxTokens: 16384, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"qwen/qwen3-30b-a3b-instruct-2507\": { id: \"qwen/qwen3-30b-a3b-instruct-2507\", name: \"Qwen: Qwen3 30B A3B Instruct 2507\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: false, input: [\"text\"], cost: { input: 0.04815, output: 0.19305, cacheRead: 0, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 32e3, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"qwen/qwen3-30b-a3b-thinking-2507\": { id: \"qwen/qwen3-30b-a3b-thinking-2507\", name: \"Qwen: Qwen3 30B A3B Thinking 2507\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\"], cost: { input: 0.2, output: 2.4, cacheRead: 0, cacheWrite: 0 }, contextWindow: 81920, maxTokens: 32768, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"qwen/qwen3-32b\": { id: \"qwen/qwen3-32b\", name: \"Qwen: Qwen3 32B\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\"], cost: { input: 0.08, output: 0.28, cacheRead: 0, cacheWrite: 0 }, contextWindow: 40960, maxTokens: 16384, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"qwen/qwen3-8b\": { id: \"qwen/qwen3-8b\", name: \"Qwen: Qwen3 8B\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\"], cost: { input: 0.117, output: 0.455, cacheRead: 0, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 8192, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"qwen/qwen3-coder\": { id: \"qwen/qwen3-coder\", name: \"Qwen: Qwen3 Coder 480B A35B\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: false, input: [\"text\"], cost: { input: 0.3, output: 1, cacheRead: 0.1, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 65536, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"qwen/qwen3-coder-30b-a3b-instruct\": { id: \"qwen/qwen3-coder-30b-a3b-instruct\", name: \"Qwen: Qwen3 Coder 30B A3B Instruct\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: false, input: [\"text\"], cost: { input: 0.07, output: 0.28, cacheRead: 0, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 262144, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"qwen/qwen3-coder-flash\": { id: \"qwen/qwen3-coder-flash\", name: \"Qwen: Qwen3 Coder Flash\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: false, input: [\"text\"], cost: { input: 0.195, output: 0.975, cacheRead: 0.039, cacheWrite: 0.24375 }, contextWindow: 1e6, maxTokens: 65536, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"qwen/qwen3-coder-next\": { id: \"qwen/qwen3-coder-next\", name: \"Qwen: Qwen3 Coder Next\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: false, input: [\"text\"], cost: { input: 0.12, output: 0.8, cacheRead: 0.07, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 262144, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"qwen/qwen3-coder-plus\": { id: \"qwen/qwen3-coder-plus\", name: \"Qwen: Qwen3 Coder Plus\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: false, input: [\"text\"], cost: { input: 0.65, output: 3.25, cacheRead: 0.13, cacheWrite: 0.8125 }, contextWindow: 1e6, maxTokens: 65536, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"qwen/qwen3-max\": { id: \"qwen/qwen3-max\", name: \"Qwen: Qwen3 Max\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: false, input: [\"text\"], cost: { input: 0.78, output: 3.9, cacheRead: 0.156, cacheWrite: 0.975 }, contextWindow: 262144, maxTokens: 65536, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"qwen/qwen3-max-thinking\": { id: \"qwen/qwen3-max-thinking\", name: \"Qwen: Qwen3 Max Thinking\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\"], cost: { input: 0.78, output: 3.9, cacheRead: 0, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 65536, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"qwen/qwen3-next-80b-a3b-instruct\": { id: \"qwen/qwen3-next-80b-a3b-instruct\", name: \"Qwen: Qwen3 Next 80B A3B Instruct\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: false, input: [\"text\"], cost: { input: 0.1, output: 1.1, cacheRead: 0.07, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 262144, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"qwen/qwen3-next-80b-a3b-thinking\": { id: \"qwen/qwen3-next-80b-a3b-thinking\", name: \"Qwen: Qwen3 Next 80B A3B Thinking\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\"], cost: { input: 0.15, output: 1.2, cacheRead: 0, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 32768, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"qwen/qwen3-vl-235b-a22b-instruct\": { id: \"qwen/qwen3-vl-235b-a22b-instruct\", name: \"Qwen: Qwen3 VL 235B A22B Instruct\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 0.26, output: 1.04, cacheRead: 0, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 32768, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"qwen/qwen3-vl-235b-a22b-thinking\": { id: \"qwen/qwen3-vl-235b-a22b-thinking\", name: \"Qwen: Qwen3 VL 235B A22B Thinking\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.4, output: 4, cacheRead: 0, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 32768, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"qwen/qwen3-vl-30b-a3b-instruct\": { id: \"qwen/qwen3-vl-30b-a3b-instruct\", name: \"Qwen: Qwen3 VL 30B A3B Instruct\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 0.13, output: 0.52, cacheRead: 0, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 32768, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"qwen/qwen3-vl-30b-a3b-thinking\": { id: \"qwen/qwen3-vl-30b-a3b-thinking\", name: \"Qwen: Qwen3 VL 30B A3B Thinking\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.2, output: 2.4, cacheRead: 0, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 32768, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"qwen/qwen3-vl-32b-instruct\": { id: \"qwen/qwen3-vl-32b-instruct\", name: \"Qwen: Qwen3 VL 32B Instruct\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 0.104, output: 0.416, cacheRead: 0, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 32768, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"qwen/qwen3-vl-8b-instruct\": { id: \"qwen/qwen3-vl-8b-instruct\", name: \"Qwen: Qwen3 VL 8B Instruct\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 0.117, output: 0.455, cacheRead: 0, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 32768, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"qwen/qwen3-vl-8b-thinking\": { id: \"qwen/qwen3-vl-8b-thinking\", name: \"Qwen: Qwen3 VL 8B Thinking\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.18, output: 2.1, cacheRead: 0, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 32768, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"qwen/qwen3.5-122b-a10b\": { id: \"qwen/qwen3.5-122b-a10b\", name: \"Qwen: Qwen3.5-122B-A10B\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.29, output: 2.4, cacheRead: 0, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 81920, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"qwen/qwen3.5-27b\": { id: \"qwen/qwen3.5-27b\", name: \"Qwen: Qwen3.5-27B\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.195, output: 1.56, cacheRead: 0, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 65536, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"qwen/qwen3.5-35b-a3b\": { id: \"qwen/qwen3.5-35b-a3b\", name: \"Qwen: Qwen3.5-35B-A3B\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.25, output: 1.25, cacheRead: 0.25, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 262144, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"qwen/qwen3.5-397b-a17b\": { id: \"qwen/qwen3.5-397b-a17b\", name: \"Qwen: Qwen3.5 397B A17B\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.5, output: 3.6, cacheRead: 0.3, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 262144, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"qwen/qwen3.5-9b\": { id: \"qwen/qwen3.5-9b\", name: \"Qwen: Qwen3.5-9B\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.1, output: 0.15, cacheRead: 0, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 262144, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"qwen/qwen3.5-flash-02-23\": { id: \"qwen/qwen3.5-flash-02-23\", name: \"Qwen: Qwen3.5-Flash\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.065, output: 0.26, cacheRead: 0, cacheWrite: 0 }, contextWindow: 1e6, maxTokens: 65536, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"qwen/qwen3.5-plus-02-15\": { id: \"qwen/qwen3.5-plus-02-15\", name: \"Qwen: Qwen3.5 Plus 2026-02-15\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.26, output: 1.56, cacheRead: 0, cacheWrite: 0 }, contextWindow: 1e6, maxTokens: 65536, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"qwen/qwen3.5-plus-20260420\": { id: \"qwen/qwen3.5-plus-20260420\", name: \"Qwen: Qwen3.5 Plus 2026-04-20\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.3, output: 1.8, cacheRead: 0, cacheWrite: 0.375 }, contextWindow: 1e6, maxTokens: 65536, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"qwen/qwen3.6-27b\": { id: \"qwen/qwen3.6-27b\", name: \"Qwen: Qwen3.6 27B\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.6, output: 3.6, cacheRead: 0.12, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 262144, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"qwen/qwen3.6-35b-a3b\": { id: \"qwen/qwen3.6-35b-a3b\", name: \"Qwen: Qwen3.6 35B A3B\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.15, output: 1, cacheRead: 0.05, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 262144, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"qwen/qwen3.6-flash\": { id: \"qwen/qwen3.6-flash\", name: \"Qwen: Qwen3.6 Flash\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.1875, output: 1.125, cacheRead: 0, cacheWrite: 0.234375 }, contextWindow: 1e6, maxTokens: 65536, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"qwen/qwen3.6-max-preview\": { id: \"qwen/qwen3.6-max-preview\", name: \"Qwen: Qwen3.6 Max Preview\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\"], cost: { input: 1.027, output: 6.162, cacheRead: 0, cacheWrite: 1.28375 }, contextWindow: 262144, maxTokens: 65536, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"qwen/qwen3.6-plus\": { id: \"qwen/qwen3.6-plus\", name: \"Qwen: Qwen3.6 Plus\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.325, output: 1.95, cacheRead: 0, cacheWrite: 0.40625 }, contextWindow: 1e6, maxTokens: 65536, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"qwen/qwen3.7-flash\": { id: \"qwen/qwen3.7-flash\", name: \"Qwen: Qwen3.7 Flash\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.03, output: 0.13, cacheRead: 6e-3, cacheWrite: 0.038 }, contextWindow: 1e6, maxTokens: 65536, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"qwen/qwen3.7-max\": { id: \"qwen/qwen3.7-max\", name: \"Qwen: Qwen3.7 Max\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\"], cost: { input: 1.475, output: 4.425, cacheRead: 0.295, cacheWrite: 1.84375 }, contextWindow: 1e6, maxTokens: 131072, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"qwen/qwen3.7-plus\": { id: \"qwen/qwen3.7-plus\", name: \"Qwen: Qwen3.7 Plus\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.32, output: 1.28, cacheRead: 0.064, cacheWrite: 0.4 }, contextWindow: 1e6, maxTokens: 131072, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"qwen/qwen3.8-2.4t-a95b\": { id: \"qwen/qwen3.8-2.4t-a95b\", name: \"Qwen: Qwen3.8 2.4T A95B\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\"], cost: { input: 2, output: 6, cacheRead: 0.25, cacheWrite: 0 }, contextWindow: 1e6, maxTokens: 262144, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"qwen/qwen3.8-max\": { id: \"qwen/qwen3.8-max\", name: \"Qwen: Qwen3.8 Max\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 2, output: 6, cacheRead: 0.25, cacheWrite: 2.5 }, contextWindow: 1e6, maxTokens: 131072, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"rekaai/reka-edge\": { id: \"rekaai/reka-edge\", name: \"Reka Edge\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 0.1, output: 0.1, cacheRead: 0, cacheWrite: 0 }, contextWindow: 16384, maxTokens: 16384, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"relace/relace-search\": { id: \"relace/relace-search\", name: \"Relace: Relace Search\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: false, input: [\"text\"], cost: { input: 1, output: 3, cacheRead: 0, cacheWrite: 0 }, contextWindow: 256e3, maxTokens: 128e3, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"sakana/fugu-ultra\": { id: \"sakana/fugu-ultra\", name: \"Sakana: Fugu Ultra\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 5, output: 30, cacheRead: 0.5, cacheWrite: 0 }, contextWindow: 1e6, maxTokens: 128e3, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"sakana/sakana-namazu\": { id: \"sakana/sakana-namazu\", name: \"Sakana: Sakana Namazu\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.95, output: 4, cacheRead: 0.15, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 65536, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"sao10k/l3.1-euryale-70b\": { id: \"sao10k/l3.1-euryale-70b\", name: \"Sao10K: Llama 3.1 Euryale 70B v2.2\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: false, input: [\"text\"], cost: { input: 0.85, output: 0.85, cacheRead: 0, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 16384, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"stepfun/step-3.5-flash\": { id: \"stepfun/step-3.5-flash\", name: \"StepFun: Step 3.5 Flash\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\"], cost: { input: 0.1, output: 0.3, cacheRead: 0, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 65536, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"stepfun/step-3.7-flash\": { id: \"stepfun/step-3.7-flash\", name: \"StepFun: Step 3.7 Flash\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.2, output: 1.15, cacheRead: 0.04, cacheWrite: 0 }, contextWindow: 256e3, maxTokens: 256e3, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"tencent/hy3\": { id: \"tencent/hy3\", name: \"Tencent: Hy3\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\"], cost: { input: 0.132, output: 0.528, cacheRead: 0.033, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 128e3, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"tencent/hy3-preview\": { id: \"tencent/hy3-preview\", name: \"Tencent: Hy3 preview\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\"], cost: { input: 0.063, output: 0.21, cacheRead: 0.021, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 4096, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"thedrummer/unslopnemo-12b\": { id: \"thedrummer/unslopnemo-12b\", name: \"TheDrummer: UnslopNemo 12B\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: false, input: [\"text\"], cost: { input: 0.4, output: 0.4, cacheRead: 0, cacheWrite: 0 }, contextWindow: 1024e3, maxTokens: 1024e3, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"thinkingmachines/inkling\": { id: \"thinkingmachines/inkling\", name: \"Thinking Machines: Inkling\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.95, output: 4.05, cacheRead: 0.16, cacheWrite: 0 }, contextWindow: 524288, maxTokens: 262144, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"thinkingmachines/inkling-small\": { id: \"thinkingmachines/inkling-small\", name: \"Thinking Machines: Inkling Small\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.45, output: 1.2, cacheRead: 0.1, cacheWrite: 0 }, contextWindow: 524288, maxTokens: 262144, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"thinkingmachines/inkling:batch\": { id: \"thinkingmachines/inkling:batch\", name: \"Thinking Machines: Inkling (batch)\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.5, output: 2.025, cacheRead: 0.085, cacheWrite: 0 }, contextWindow: 524288, maxTokens: 4096, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"upstage/solar-pro-3\": { id: \"upstage/solar-pro-3\", name: \"Upstage: Solar Pro 3\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\"], cost: { input: 0.15, output: 0.6, cacheRead: 0.015, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 131072, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"upstage/solar-pro4\": { id: \"upstage/solar-pro4\", name: \"Upstage: Solar Pro 4\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\"], cost: { input: 0.03, output: 0.12, cacheRead: 6e-3, cacheWrite: 0 }, contextWindow: 524288, maxTokens: 131072, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"x-ai/grok-4.20\": { id: \"x-ai/grok-4.20\", name: \"SpaceXAI: Grok 4.20\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.25, output: 2.5, cacheRead: 0.2, cacheWrite: 0 }, contextWindow: 2e6, maxTokens: 4096, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"x-ai/grok-4.3\": { id: \"x-ai/grok-4.3\", name: \"SpaceXAI: Grok 4.3\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.25, output: 2.5, cacheRead: 0.2, cacheWrite: 0 }, contextWindow: 1e6, maxTokens: 4096, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"x-ai/grok-4.5\": { id: \"x-ai/grok-4.5\", name: \"SpaceXAI: Grok 4.5\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 2, output: 6, cacheRead: 0.3, cacheWrite: 0 }, contextWindow: 5e5, maxTokens: 4096, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"x-ai/grok-4.6\": { id: \"x-ai/grok-4.6\", name: \"SpaceXAI: Grok 4.6\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 2, output: 6, cacheRead: 0.5, cacheWrite: 0 }, contextWindow: 5e5, maxTokens: 4096, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"x-ai/grok-build-0.1\": { id: \"x-ai/grok-build-0.1\", name: \"SpaceXAI: Grok Build 0.1\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1, output: 2, cacheRead: 0.2, cacheWrite: 0 }, contextWindow: 256e3, maxTokens: 4096, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"xiaomi/mimo-v2.5\": { id: \"xiaomi/mimo-v2.5\", name: \"Xiaomi: MiMo-V2.5\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.14, output: 0.28, cacheRead: 28e-4, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 131072, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"xiaomi/mimo-v2.5-pro\": { id: \"xiaomi/mimo-v2.5-pro\", name: \"Xiaomi: MiMo-V2.5-Pro\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\"], cost: { input: 0.435, output: 0.87, cacheRead: 36e-4, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 131072, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"z-ai/glm-4.5\": { id: \"z-ai/glm-4.5\", name: \"Z.ai: GLM 4.5\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\"], cost: { input: 0.6, output: 2.2, cacheRead: 0.11, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 98304, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"z-ai/glm-4.5-air\": { id: \"z-ai/glm-4.5-air\", name: \"Z.ai: GLM 4.5 Air\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\"], cost: { input: 0.13, output: 0.85, cacheRead: 0.025, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 98304, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"z-ai/glm-4.5v\": { id: \"z-ai/glm-4.5v\", name: \"Z.ai: GLM 4.5V\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.6, output: 1.8, cacheRead: 0.11, cacheWrite: 0 }, contextWindow: 65536, maxTokens: 16384, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"z-ai/glm-4.6\": { id: \"z-ai/glm-4.6\", name: \"Z.ai: GLM 4.6\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\"], cost: { input: 0.5, output: 2, cacheRead: 0.1, cacheWrite: 0 }, contextWindow: 202752, maxTokens: 131072, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"z-ai/glm-4.6v\": { id: \"z-ai/glm-4.6v\", name: \"Z.ai: GLM 4.6V\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.3, output: 0.9, cacheRead: 0.055, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 32768, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"z-ai/glm-4.7\": { id: \"z-ai/glm-4.7\", name: \"Z.ai: GLM 4.7\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\"], cost: { input: 0.4, output: 1.75, cacheRead: 0.08, cacheWrite: 0 }, contextWindow: 202752, maxTokens: 131072, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"z-ai/glm-4.7-flash\": { id: \"z-ai/glm-4.7-flash\", name: \"Z.ai: GLM 4.7 Flash\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\"], cost: { input: 0.06, output: 0.4, cacheRead: 0.01, cacheWrite: 0 }, contextWindow: 202752, maxTokens: 16384, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"z-ai/glm-5\": { id: \"z-ai/glm-5\", name: \"Z.ai: GLM 5\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\"], cost: { input: 0.6, output: 1.9, cacheRead: 0.119, cacheWrite: 0 }, contextWindow: 204800, maxTokens: 131072, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"z-ai/glm-5-turbo\": { id: \"z-ai/glm-5-turbo\", name: \"Z.ai: GLM 5 Turbo\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\"], cost: { input: 1.2, output: 4, cacheRead: 0.24, cacheWrite: 0 }, contextWindow: 202752, maxTokens: 131072, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"z-ai/glm-5.1\": { id: \"z-ai/glm-5.1\", name: \"Z.ai: GLM 5.1\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\"], cost: { input: 1.4, output: 4.4, cacheRead: 0.26, cacheWrite: 0 }, contextWindow: 202752, maxTokens: 131072, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"z-ai/glm-5.2\": { id: \"z-ai/glm-5.2\", name: \"Z.ai: GLM 5.2\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\"], cost: { input: 0.63, output: 1.98, cacheRead: 0.0945, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 4096, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" }, thinkingLevelMap: { xhigh: \"xhigh\" } }, \"z-ai/glm-5.2:batch\": { id: \"z-ai/glm-5.2:batch\", name: \"Z.ai: GLM 5.2 (batch)\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\"], cost: { input: 0.7, output: 2.2, cacheRead: 0.13, cacheWrite: 0 }, contextWindow: 512e3, maxTokens: 4096, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"z-ai/glm-5v-turbo\": { id: \"z-ai/glm-5v-turbo\", name: \"Z.ai: GLM 5V Turbo\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.2, output: 4, cacheRead: 0.24, cacheWrite: 0 }, contextWindow: 202752, maxTokens: 131072, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"~anthropic/claude-fable-latest\": { id: \"~anthropic/claude-fable-latest\", name: \"Anthropic: Claude Fable Latest\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 10, output: 50, cacheRead: 1, cacheWrite: 12.5 }, contextWindow: 1e6, maxTokens: 128e3, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\", cacheControlFormat: \"anthropic\" } }, \"~anthropic/claude-haiku-latest\": { id: \"~anthropic/claude-haiku-latest\", name: \"Anthropic Claude Haiku Latest\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1, output: 5, cacheRead: 0.1, cacheWrite: 1.25 }, contextWindow: 2e5, maxTokens: 64e3, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\", cacheControlFormat: \"anthropic\" } }, \"~anthropic/claude-opus-latest\": { id: \"~anthropic/claude-opus-latest\", name: \"Anthropic: Claude Opus Latest\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 }, contextWindow: 1e6, maxTokens: 128e3, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\", cacheControlFormat: \"anthropic\" } }, \"~anthropic/claude-sonnet-latest\": { id: \"~anthropic/claude-sonnet-latest\", name: \"Anthropic Claude Sonnet Latest\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 2, output: 10, cacheRead: 0.2, cacheWrite: 2.5 }, contextWindow: 1e6, maxTokens: 128e3, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\", cacheControlFormat: \"anthropic\" } }, \"~deepseek/deepseek-v4-flash-latest\": { id: \"~deepseek/deepseek-v4-flash-latest\", name: \"DeepSeek V4 Flash Latest\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\"], cost: { input: 0.079996, output: 0.252, cacheRead: 0.0252, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 4096, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\", requiresReasoningContentOnAssistantMessages: true }, thinkingLevelMap: { minimal: null, low: null, medium: null, high: \"high\", max: null, xhigh: \"xhigh\" } }, \"~google/gemini-flash-latest\": { id: \"~google/gemini-flash-latest\", name: \"Google Gemini Flash Latest\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.375, output: 1.875, cacheRead: 0.0375, cacheWrite: 0.020833 }, contextWindow: 1048576, maxTokens: 65536, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"~google/gemini-pro-latest\": { id: \"~google/gemini-pro-latest\", name: \"Google Gemini Pro Latest\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 2, output: 12, cacheRead: 0.2, cacheWrite: 0.375 }, contextWindow: 1048576, maxTokens: 65536, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"~moonshotai/kimi-latest\": { id: \"~moonshotai/kimi-latest\", name: \"MoonshotAI Kimi Latest\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 2.8, output: 14, cacheRead: 0.29, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 131072, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"~openai/gpt-latest\": { id: \"~openai/gpt-latest\", name: \"OpenAI GPT Latest\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 5, output: 30, cacheRead: 0.5, cacheWrite: 6.25 }, contextWindow: 105e4, maxTokens: 128e3, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"~openai/gpt-mini-latest\": { id: \"~openai/gpt-mini-latest\", name: \"OpenAI GPT Mini Latest\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.75, output: 4.5, cacheRead: 0.075, cacheWrite: 0 }, contextWindow: 4e5, maxTokens: 128e3, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } }, \"~x-ai/grok-latest\": { id: \"~x-ai/grok-latest\", name: \"xAI: Grok Latest\", api: \"openai-completions\", baseUrl: \"https://openrouter.ai/api/v1\", provider: \"openrouter\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 2, output: 6, cacheRead: 0.5, cacheWrite: 0 }, contextWindow: 5e5, maxTokens: 4096, compat: { supportsDeveloperRole: false, thinkingFormat: \"openrouter\" } } } };\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/openrouter.models.js\nvar OPENROUTER_MODELS = flattenModelCatalog(\"openrouter\", openrouter_default);\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/data/qwen-token-plan.json\nvar qwen_token_plan_default = { \"openai-completions\": { \"MiniMax-M2.5\": { id: \"MiniMax-M2.5\", name: \"MiniMax-M2.5\", api: \"openai-completions\", provider: \"qwen-token-plan\", baseUrl: \"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1\", compat: { thinkingFormat: \"qwen\", supportsDeveloperRole: false, supportsStore: false, supportsReasoningEffort: false }, reasoning: true, input: [\"text\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 196608, maxTokens: 32768 }, \"deepseek-v3.2\": { id: \"deepseek-v3.2\", name: \"DeepSeek V3.2\", api: \"openai-completions\", provider: \"qwen-token-plan\", baseUrl: \"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1\", compat: { thinkingFormat: \"qwen\", supportsDeveloperRole: false, supportsStore: false, supportsReasoningEffort: false }, reasoning: true, input: [\"text\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 65536 }, \"deepseek-v4-flash\": { id: \"deepseek-v4-flash\", name: \"DeepSeek V4 Flash\", api: \"openai-completions\", provider: \"qwen-token-plan\", baseUrl: \"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1\", compat: { thinkingFormat: \"qwen\", supportsDeveloperRole: false, supportsStore: false, supportsReasoningEffort: true }, thinkingLevelMap: { minimal: null, low: null, medium: null, high: \"high\", xhigh: null, max: \"max\" }, reasoning: true, input: [\"text\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 1e6, maxTokens: 384e3 }, \"deepseek-v4-flash-0731\": { id: \"deepseek-v4-flash-0731\", name: \"DeepSeek V4 Flash 0731\", api: \"openai-completions\", provider: \"qwen-token-plan\", baseUrl: \"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1\", compat: { thinkingFormat: \"qwen\", supportsDeveloperRole: false, supportsStore: false, supportsReasoningEffort: true }, thinkingLevelMap: { minimal: null, low: null, medium: null, high: \"high\", xhigh: null, max: \"max\" }, reasoning: true, input: [\"text\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 1e6, maxTokens: 384e3 }, \"deepseek-v4-pro\": { id: \"deepseek-v4-pro\", name: \"DeepSeek V4 Pro\", api: \"openai-completions\", provider: \"qwen-token-plan\", baseUrl: \"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1\", compat: { thinkingFormat: \"qwen\", supportsDeveloperRole: false, supportsStore: false, supportsReasoningEffort: true }, thinkingLevelMap: { minimal: null, low: null, medium: null, high: \"high\", xhigh: null, max: \"max\" }, reasoning: true, input: [\"text\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 1e6, maxTokens: 384e3 }, \"glm-5\": { id: \"glm-5\", name: \"GLM-5\", api: \"openai-completions\", provider: \"qwen-token-plan\", baseUrl: \"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1\", compat: { thinkingFormat: \"qwen\", supportsDeveloperRole: false, supportsStore: false, supportsReasoningEffort: true }, thinkingLevelMap: { minimal: null, low: null, medium: null, high: \"high\", xhigh: null, max: \"max\" }, reasoning: true, input: [\"text\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 202752, maxTokens: 16384 }, \"glm-5.1\": { id: \"glm-5.1\", name: \"GLM-5.1\", api: \"openai-completions\", provider: \"qwen-token-plan\", baseUrl: \"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1\", compat: { thinkingFormat: \"qwen\", supportsDeveloperRole: false, supportsStore: false, supportsReasoningEffort: true }, thinkingLevelMap: { minimal: null, low: null, medium: null, high: \"high\", xhigh: null, max: \"max\" }, reasoning: true, input: [\"text\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 202752, maxTokens: 128e3 }, \"glm-5.2\": { id: \"glm-5.2\", name: \"GLM-5.2\", api: \"openai-completions\", provider: \"qwen-token-plan\", baseUrl: \"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1\", compat: { thinkingFormat: \"qwen\", supportsDeveloperRole: false, supportsStore: false, supportsReasoningEffort: true }, thinkingLevelMap: { minimal: null, low: null, medium: null, high: \"high\", xhigh: null, max: \"max\" }, reasoning: true, input: [\"text\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 1e6, maxTokens: 131072 }, \"kimi-k2.5\": { id: \"kimi-k2.5\", name: \"Kimi K2.5\", api: \"openai-completions\", provider: \"qwen-token-plan\", baseUrl: \"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1\", compat: { thinkingFormat: \"qwen\", supportsDeveloperRole: false, supportsStore: false, supportsReasoningEffort: false }, reasoning: true, input: [\"text\", \"image\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 98304 }, \"kimi-k2.6\": { id: \"kimi-k2.6\", name: \"Kimi K2.6\", api: \"openai-completions\", provider: \"qwen-token-plan\", baseUrl: \"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1\", compat: { thinkingFormat: \"qwen\", supportsDeveloperRole: false, supportsStore: false, supportsReasoningEffort: false }, reasoning: true, input: [\"text\", \"image\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 262144 }, \"kimi-k2.7-code\": { id: \"kimi-k2.7-code\", name: \"Kimi K2.7 Code\", api: \"openai-completions\", provider: \"qwen-token-plan\", baseUrl: \"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1\", compat: { thinkingFormat: \"qwen\", supportsDeveloperRole: false, supportsStore: false, supportsReasoningEffort: false }, reasoning: true, input: [\"text\", \"image\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 262144 }, \"qwen3.6-flash\": { id: \"qwen3.6-flash\", name: \"Qwen3.6 Flash\", api: \"openai-completions\", provider: \"qwen-token-plan\", baseUrl: \"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1\", compat: { thinkingFormat: \"qwen\", supportsDeveloperRole: false, supportsStore: false, supportsReasoningEffort: false }, reasoning: true, input: [\"text\", \"image\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 1e6, maxTokens: 65536 }, \"qwen3.6-plus\": { id: \"qwen3.6-plus\", name: \"Qwen3.6 Plus\", api: \"openai-completions\", provider: \"qwen-token-plan\", baseUrl: \"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1\", compat: { thinkingFormat: \"qwen\", supportsDeveloperRole: false, supportsStore: false, supportsReasoningEffort: false }, reasoning: true, input: [\"text\", \"image\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 1e6, maxTokens: 65536 }, \"qwen3.7-max\": { id: \"qwen3.7-max\", name: \"Qwen3.7 Max\", api: \"openai-completions\", provider: \"qwen-token-plan\", baseUrl: \"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1\", compat: { thinkingFormat: \"qwen\", supportsDeveloperRole: false, supportsStore: false, supportsReasoningEffort: false }, reasoning: true, input: [\"text\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 1e6, maxTokens: 131072 }, \"qwen3.7-plus\": { id: \"qwen3.7-plus\", name: \"Qwen3.7 Plus\", api: \"openai-completions\", provider: \"qwen-token-plan\", baseUrl: \"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1\", compat: { thinkingFormat: \"qwen\", supportsDeveloperRole: false, supportsStore: false, supportsReasoningEffort: false }, reasoning: true, input: [\"text\", \"image\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 1e6, maxTokens: 65536 }, \"qwen3.8-max\": { id: \"qwen3.8-max\", name: \"Qwen3.8 Max\", api: \"openai-completions\", provider: \"qwen-token-plan\", baseUrl: \"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1\", compat: { thinkingFormat: \"qwen\", supportsDeveloperRole: false, supportsStore: false, supportsReasoningEffort: true }, thinkingLevelMap: { minimal: null, low: \"low\", medium: \"medium\", high: null, xhigh: \"xhigh\", max: null }, reasoning: true, input: [\"text\", \"image\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 1e6, maxTokens: 131072 } } };\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/qwen-token-plan.models.js\nvar QWEN_TOKEN_PLAN_MODELS = flattenModelCatalog(\"qwen-token-plan\", qwen_token_plan_default);\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/data/qwen-token-plan-cn.json\nvar qwen_token_plan_cn_default = { \"openai-completions\": { \"MiniMax-M2.5\": { id: \"MiniMax-M2.5\", name: \"MiniMax-M2.5\", api: \"openai-completions\", provider: \"qwen-token-plan-cn\", baseUrl: \"https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1\", compat: { thinkingFormat: \"qwen\", supportsDeveloperRole: false, supportsStore: false, supportsReasoningEffort: false }, reasoning: true, input: [\"text\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 196608, maxTokens: 32768 }, \"deepseek-v3.2\": { id: \"deepseek-v3.2\", name: \"DeepSeek V3.2\", api: \"openai-completions\", provider: \"qwen-token-plan-cn\", baseUrl: \"https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1\", compat: { thinkingFormat: \"qwen\", supportsDeveloperRole: false, supportsStore: false, supportsReasoningEffort: false }, reasoning: true, input: [\"text\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 65536 }, \"deepseek-v4-flash\": { id: \"deepseek-v4-flash\", name: \"DeepSeek V4 Flash\", api: \"openai-completions\", provider: \"qwen-token-plan-cn\", baseUrl: \"https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1\", compat: { thinkingFormat: \"qwen\", supportsDeveloperRole: false, supportsStore: false, supportsReasoningEffort: true }, thinkingLevelMap: { minimal: null, low: null, medium: null, high: \"high\", xhigh: null, max: \"max\" }, reasoning: true, input: [\"text\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 1e6, maxTokens: 384e3 }, \"deepseek-v4-flash-0731\": { id: \"deepseek-v4-flash-0731\", name: \"DeepSeek V4 Flash 0731\", api: \"openai-completions\", provider: \"qwen-token-plan-cn\", baseUrl: \"https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1\", compat: { thinkingFormat: \"qwen\", supportsDeveloperRole: false, supportsStore: false, supportsReasoningEffort: true }, thinkingLevelMap: { minimal: null, low: null, medium: null, high: \"high\", xhigh: null, max: \"max\" }, reasoning: true, input: [\"text\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 1e6, maxTokens: 384e3 }, \"deepseek-v4-pro\": { id: \"deepseek-v4-pro\", name: \"DeepSeek V4 Pro\", api: \"openai-completions\", provider: \"qwen-token-plan-cn\", baseUrl: \"https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1\", compat: { thinkingFormat: \"qwen\", supportsDeveloperRole: false, supportsStore: false, supportsReasoningEffort: true }, thinkingLevelMap: { minimal: null, low: null, medium: null, high: \"high\", xhigh: null, max: \"max\" }, reasoning: true, input: [\"text\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 1e6, maxTokens: 384e3 }, \"glm-5\": { id: \"glm-5\", name: \"GLM-5\", api: \"openai-completions\", provider: \"qwen-token-plan-cn\", baseUrl: \"https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1\", compat: { thinkingFormat: \"qwen\", supportsDeveloperRole: false, supportsStore: false, supportsReasoningEffort: true }, thinkingLevelMap: { minimal: null, low: null, medium: null, high: \"high\", xhigh: null, max: \"max\" }, reasoning: true, input: [\"text\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 202752, maxTokens: 16384 }, \"glm-5.1\": { id: \"glm-5.1\", name: \"GLM-5.1\", api: \"openai-completions\", provider: \"qwen-token-plan-cn\", baseUrl: \"https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1\", compat: { thinkingFormat: \"qwen\", supportsDeveloperRole: false, supportsStore: false, supportsReasoningEffort: true }, thinkingLevelMap: { minimal: null, low: null, medium: null, high: \"high\", xhigh: null, max: \"max\" }, reasoning: true, input: [\"text\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 202752, maxTokens: 128e3 }, \"glm-5.2\": { id: \"glm-5.2\", name: \"GLM-5.2\", api: \"openai-completions\", provider: \"qwen-token-plan-cn\", baseUrl: \"https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1\", compat: { thinkingFormat: \"qwen\", supportsDeveloperRole: false, supportsStore: false, supportsReasoningEffort: true }, thinkingLevelMap: { minimal: null, low: null, medium: null, high: \"high\", xhigh: null, max: \"max\" }, reasoning: true, input: [\"text\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 1e6, maxTokens: 131072 }, \"kimi-k2.5\": { id: \"kimi-k2.5\", name: \"Kimi K2.5\", api: \"openai-completions\", provider: \"qwen-token-plan-cn\", baseUrl: \"https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1\", compat: { thinkingFormat: \"qwen\", supportsDeveloperRole: false, supportsStore: false, supportsReasoningEffort: false }, reasoning: true, input: [\"text\", \"image\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 98304 }, \"kimi-k2.6\": { id: \"kimi-k2.6\", name: \"Kimi K2.6\", api: \"openai-completions\", provider: \"qwen-token-plan-cn\", baseUrl: \"https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1\", compat: { thinkingFormat: \"qwen\", supportsDeveloperRole: false, supportsStore: false, supportsReasoningEffort: false }, reasoning: true, input: [\"text\", \"image\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 262144 }, \"kimi-k2.7-code\": { id: \"kimi-k2.7-code\", name: \"Kimi K2.7 Code\", api: \"openai-completions\", provider: \"qwen-token-plan-cn\", baseUrl: \"https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1\", compat: { thinkingFormat: \"qwen\", supportsDeveloperRole: false, supportsStore: false, supportsReasoningEffort: false }, reasoning: true, input: [\"text\", \"image\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 262144 }, \"qwen3.6-flash\": { id: \"qwen3.6-flash\", name: \"Qwen3.6 Flash\", api: \"openai-completions\", provider: \"qwen-token-plan-cn\", baseUrl: \"https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1\", compat: { thinkingFormat: \"qwen\", supportsDeveloperRole: false, supportsStore: false, supportsReasoningEffort: false }, reasoning: true, input: [\"text\", \"image\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 1e6, maxTokens: 65536 }, \"qwen3.6-plus\": { id: \"qwen3.6-plus\", name: \"Qwen3.6 Plus\", api: \"openai-completions\", provider: \"qwen-token-plan-cn\", baseUrl: \"https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1\", compat: { thinkingFormat: \"qwen\", supportsDeveloperRole: false, supportsStore: false, supportsReasoningEffort: false }, reasoning: true, input: [\"text\", \"image\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 1e6, maxTokens: 65536 }, \"qwen3.7-max\": { id: \"qwen3.7-max\", name: \"Qwen3.7 Max\", api: \"openai-completions\", provider: \"qwen-token-plan-cn\", baseUrl: \"https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1\", compat: { thinkingFormat: \"qwen\", supportsDeveloperRole: false, supportsStore: false, supportsReasoningEffort: false }, reasoning: true, input: [\"text\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 1e6, maxTokens: 131072 }, \"qwen3.7-plus\": { id: \"qwen3.7-plus\", name: \"Qwen3.7 Plus\", api: \"openai-completions\", provider: \"qwen-token-plan-cn\", baseUrl: \"https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1\", compat: { thinkingFormat: \"qwen\", supportsDeveloperRole: false, supportsStore: false, supportsReasoningEffort: false }, reasoning: true, input: [\"text\", \"image\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 1e6, maxTokens: 65536 }, \"qwen3.8-max\": { id: \"qwen3.8-max\", name: \"Qwen3.8 Max\", api: \"openai-completions\", provider: \"qwen-token-plan-cn\", baseUrl: \"https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1\", compat: { thinkingFormat: \"qwen\", supportsDeveloperRole: false, supportsStore: false, supportsReasoningEffort: true }, thinkingLevelMap: { minimal: null, low: \"low\", medium: \"medium\", high: null, xhigh: \"xhigh\", max: null }, reasoning: true, input: [\"text\", \"image\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 1e6, maxTokens: 131072 } } };\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/qwen-token-plan-cn.models.js\nvar QWEN_TOKEN_PLAN_CN_MODELS = flattenModelCatalog(\"qwen-token-plan-cn\", qwen_token_plan_cn_default);\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/data/qwen-token-plan-individual.json\nvar qwen_token_plan_individual_default = { \"openai-completions\": { \"deepseek-v4-flash-0731\": { id: \"deepseek-v4-flash-0731\", name: \"DeepSeek V4 Flash 0731\", api: \"openai-completions\", provider: \"qwen-token-plan-individual\", baseUrl: \"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1\", compat: { thinkingFormat: \"qwen\", supportsDeveloperRole: false, supportsStore: false, supportsReasoningEffort: true }, thinkingLevelMap: { minimal: null, low: null, medium: null, high: \"high\", xhigh: null, max: \"max\" }, reasoning: true, input: [\"text\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 1e6, maxTokens: 384e3 }, \"deepseek-v4-pro\": { id: \"deepseek-v4-pro\", name: \"DeepSeek V4 Pro\", api: \"openai-completions\", provider: \"qwen-token-plan-individual\", baseUrl: \"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1\", compat: { thinkingFormat: \"qwen\", supportsDeveloperRole: false, supportsStore: false, supportsReasoningEffort: true }, thinkingLevelMap: { minimal: null, low: null, medium: null, high: \"high\", xhigh: null, max: \"max\" }, reasoning: true, input: [\"text\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 1e6, maxTokens: 384e3 }, \"glm-5.2\": { id: \"glm-5.2\", name: \"GLM-5.2\", api: \"openai-completions\", provider: \"qwen-token-plan-individual\", baseUrl: \"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1\", compat: { thinkingFormat: \"qwen\", supportsDeveloperRole: false, supportsStore: false, supportsReasoningEffort: true }, thinkingLevelMap: { minimal: null, low: null, medium: null, high: \"high\", xhigh: null, max: \"max\" }, reasoning: true, input: [\"text\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 1e6, maxTokens: 131072 }, \"qwen3.6-flash\": { id: \"qwen3.6-flash\", name: \"Qwen3.6 Flash\", api: \"openai-completions\", provider: \"qwen-token-plan-individual\", baseUrl: \"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1\", compat: { thinkingFormat: \"qwen\", supportsDeveloperRole: false, supportsStore: false, supportsReasoningEffort: false }, reasoning: true, input: [\"text\", \"image\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 1e6, maxTokens: 65536 }, \"qwen3.7-max\": { id: \"qwen3.7-max\", name: \"Qwen3.7 Max\", api: \"openai-completions\", provider: \"qwen-token-plan-individual\", baseUrl: \"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1\", compat: { thinkingFormat: \"qwen\", supportsDeveloperRole: false, supportsStore: false, supportsReasoningEffort: false }, reasoning: true, input: [\"text\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 1e6, maxTokens: 131072 }, \"qwen3.7-plus\": { id: \"qwen3.7-plus\", name: \"Qwen3.7 Plus\", api: \"openai-completions\", provider: \"qwen-token-plan-individual\", baseUrl: \"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1\", compat: { thinkingFormat: \"qwen\", supportsDeveloperRole: false, supportsStore: false, supportsReasoningEffort: false }, reasoning: true, input: [\"text\", \"image\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 1e6, maxTokens: 65536 }, \"qwen3.8-max\": { id: \"qwen3.8-max\", name: \"Qwen3.8 Max\", api: \"openai-completions\", provider: \"qwen-token-plan-individual\", baseUrl: \"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1\", compat: { thinkingFormat: \"qwen\", supportsDeveloperRole: false, supportsStore: false, supportsReasoningEffort: true }, thinkingLevelMap: { minimal: null, low: \"low\", medium: \"medium\", high: null, xhigh: \"xhigh\", max: null }, reasoning: true, input: [\"text\", \"image\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 1e6, maxTokens: 131072 } } };\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/qwen-token-plan-individual.models.js\nvar QWEN_TOKEN_PLAN_INDIVIDUAL_MODELS = flattenModelCatalog(\"qwen-token-plan-individual\", qwen_token_plan_individual_default);\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/data/together.json\nvar together_default = { \"openai-completions\": { \"MiniMaxAI/MiniMax-M2.7\": { id: \"MiniMaxAI/MiniMax-M2.7\", name: \"MiniMax-M2.7\", api: \"openai-completions\", provider: \"together\", baseUrl: \"https://api.together.ai/v1\", reasoning: true, thinkingLevelMap: { off: null, minimal: null, low: null, medium: null }, input: [\"text\"], cost: { input: 0.3, output: 1.2, cacheRead: 0.06, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false, maxTokensField: \"max_tokens\", supportsStrictMode: false, supportsLongCacheRetention: false }, contextWindow: 202752, maxTokens: 131072 }, \"MiniMaxAI/MiniMax-M3\": { id: \"MiniMaxAI/MiniMax-M3\", name: \"MiniMax-M3\", api: \"openai-completions\", provider: \"together\", baseUrl: \"https://api.together.ai/v1\", reasoning: true, thinkingLevelMap: { minimal: null, low: null, medium: null }, input: [\"text\", \"image\"], cost: { input: 0.3, output: 1.2, cacheRead: 0.06, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false, maxTokensField: \"max_tokens\", thinkingFormat: \"together\", supportsStrictMode: false, supportsLongCacheRetention: false }, contextWindow: 524288, maxTokens: 25e4 }, \"Qwen/Qwen2.5-7B-Instruct-Turbo\": { id: \"Qwen/Qwen2.5-7B-Instruct-Turbo\", name: \"Qwen 2.5 7B Instruct Turbo\", api: \"openai-completions\", provider: \"together\", baseUrl: \"https://api.together.ai/v1\", reasoning: false, input: [\"text\"], cost: { input: 0.3, output: 0.3, cacheRead: 0, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false, maxTokensField: \"max_tokens\", thinkingFormat: \"together\", supportsStrictMode: false, supportsLongCacheRetention: false }, contextWindow: 32768, maxTokens: 32768 }, \"Qwen/Qwen3.5-9B\": { id: \"Qwen/Qwen3.5-9B\", name: \"Qwen3.5 9B\", api: \"openai-completions\", provider: \"together\", baseUrl: \"https://api.together.ai/v1\", reasoning: true, thinkingLevelMap: { minimal: null, low: null, medium: null }, input: [\"text\", \"image\"], cost: { input: 0.17, output: 0.25, cacheRead: 0, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false, maxTokensField: \"max_tokens\", thinkingFormat: \"together\", supportsStrictMode: false, supportsLongCacheRetention: false }, contextWindow: 262144, maxTokens: 65536 }, \"Qwen/Qwen3.6-Plus\": { id: \"Qwen/Qwen3.6-Plus\", name: \"Qwen3.6 Plus\", api: \"openai-completions\", provider: \"together\", baseUrl: \"https://api.together.ai/v1\", reasoning: true, thinkingLevelMap: { minimal: null, low: null, medium: null }, input: [\"text\"], cost: { input: 0.5, output: 3, cacheRead: 0, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false, maxTokensField: \"max_tokens\", thinkingFormat: \"together\", supportsStrictMode: false, supportsLongCacheRetention: false }, contextWindow: 1e6, maxTokens: 5e5 }, \"Qwen/Qwen3.7-Max\": { id: \"Qwen/Qwen3.7-Max\", name: \"Qwen3.7 Max\", api: \"openai-completions\", provider: \"together\", baseUrl: \"https://api.together.ai/v1\", reasoning: false, input: [\"text\"], cost: { input: 1.25, output: 3.75, cacheRead: 0.125, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false, maxTokensField: \"max_tokens\", thinkingFormat: \"together\", supportsStrictMode: false, supportsLongCacheRetention: false }, contextWindow: 1e6, maxTokens: 5e5 }, \"deepseek-ai/DeepSeek-V4-Flash-0731\": { id: \"deepseek-ai/DeepSeek-V4-Flash-0731\", name: \"DeepSeek V4 Flash 0731\", api: \"openai-completions\", provider: \"together\", baseUrl: \"https://api.together.ai/v1\", reasoning: true, thinkingLevelMap: { minimal: null, low: null, medium: null }, input: [\"text\"], cost: { input: 0.14, output: 0.28, cacheRead: 0.03, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false, maxTokensField: \"max_tokens\", thinkingFormat: \"together\", supportsStrictMode: false, supportsLongCacheRetention: false }, contextWindow: 1e6, maxTokens: 384e3 }, \"deepseek-ai/DeepSeek-V4-Pro\": { id: \"deepseek-ai/DeepSeek-V4-Pro\", name: \"DeepSeek V4 Pro\", api: \"openai-completions\", provider: \"together\", baseUrl: \"https://api.together.ai/v1\", reasoning: true, thinkingLevelMap: { minimal: null, low: null, medium: null, high: \"high\", xhigh: null }, input: [\"text\"], cost: { input: 1.74, output: 3.48, cacheRead: 0.2, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: true, maxTokensField: \"max_tokens\", thinkingFormat: \"together\", supportsStrictMode: false, supportsLongCacheRetention: false }, contextWindow: 512e3, maxTokens: 384e3 }, \"google/gemma-4-31B-it\": { id: \"google/gemma-4-31B-it\", name: \"Gemma 4 31B Instruct\", api: \"openai-completions\", provider: \"together\", baseUrl: \"https://api.together.ai/v1\", reasoning: true, thinkingLevelMap: { minimal: null, low: null, medium: null }, input: [\"text\", \"image\"], cost: { input: 0.39, output: 0.97, cacheRead: 0, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false, maxTokensField: \"max_tokens\", thinkingFormat: \"together\", supportsStrictMode: false, supportsLongCacheRetention: false }, contextWindow: 262144, maxTokens: 131072 }, \"meta-llama/Llama-3.3-70B-Instruct-Turbo\": { id: \"meta-llama/Llama-3.3-70B-Instruct-Turbo\", name: \"Llama 3.3 70B\", api: \"openai-completions\", provider: \"together\", baseUrl: \"https://api.together.ai/v1\", reasoning: false, input: [\"text\"], cost: { input: 1.04, output: 1.04, cacheRead: 0, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false, maxTokensField: \"max_tokens\", thinkingFormat: \"together\", supportsStrictMode: false, supportsLongCacheRetention: false }, contextWindow: 131072, maxTokens: 131072 }, \"moonshotai/Kimi-K2.6\": { id: \"moonshotai/Kimi-K2.6\", name: \"Kimi K2.6\", api: \"openai-completions\", provider: \"together\", baseUrl: \"https://api.together.ai/v1\", reasoning: true, thinkingLevelMap: { minimal: null, low: null, medium: null }, input: [\"text\", \"image\"], cost: { input: 1.2, output: 4.5, cacheRead: 0.2, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false, maxTokensField: \"max_tokens\", thinkingFormat: \"together\", supportsStrictMode: false, supportsLongCacheRetention: false }, contextWindow: 262144, maxTokens: 131e3 }, \"moonshotai/Kimi-K2.7-Code\": { id: \"moonshotai/Kimi-K2.7-Code\", name: \"Kimi K2.7 Code\", api: \"openai-completions\", provider: \"together\", baseUrl: \"https://api.together.ai/v1\", reasoning: true, thinkingLevelMap: { minimal: null, low: null, medium: null }, input: [\"text\"], cost: { input: 0.95, output: 4, cacheRead: 0.19, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false, maxTokensField: \"max_tokens\", thinkingFormat: \"together\", supportsStrictMode: false, supportsLongCacheRetention: false }, contextWindow: 262144, maxTokens: 131072 }, \"moonshotai/Kimi-K3\": { id: \"moonshotai/Kimi-K3\", name: \"Kimi K3\", api: \"openai-completions\", provider: \"together\", baseUrl: \"https://api.together.ai/v1\", reasoning: true, thinkingLevelMap: { minimal: null, low: null, medium: null }, input: [\"text\", \"image\"], cost: { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false, maxTokensField: \"max_tokens\", thinkingFormat: \"together\", supportsStrictMode: false, supportsLongCacheRetention: false }, contextWindow: 1048576, maxTokens: 131072 }, \"nvidia/nemotron-3-ultra-550b-a55b\": { id: \"nvidia/nemotron-3-ultra-550b-a55b\", name: \"Nemotron 3 Ultra 550B A55B\", api: \"openai-completions\", provider: \"together\", baseUrl: \"https://api.together.ai/v1\", reasoning: true, thinkingLevelMap: { minimal: null, low: null, medium: null }, input: [\"text\"], cost: { input: 0.6, output: 3.6, cacheRead: 0.2, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false, maxTokensField: \"max_tokens\", thinkingFormat: \"together\", supportsStrictMode: false, supportsLongCacheRetention: false }, contextWindow: 512300, maxTokens: 512300 }, \"openai/gpt-oss-120b\": { id: \"openai/gpt-oss-120b\", name: \"GPT OSS 120B\", api: \"openai-completions\", provider: \"together\", baseUrl: \"https://api.together.ai/v1\", reasoning: true, thinkingLevelMap: { off: null, minimal: null, low: \"low\", medium: \"medium\", high: \"high\", xhigh: null, max: null }, input: [\"text\"], cost: { input: 0.15, output: 0.6, cacheRead: 0, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: true, maxTokensField: \"max_tokens\", thinkingFormat: \"openai\", supportsStrictMode: false, supportsLongCacheRetention: false }, contextWindow: 131072, maxTokens: 131072 }, \"openai/gpt-oss-20b\": { id: \"openai/gpt-oss-20b\", name: \"GPT OSS 20B\", api: \"openai-completions\", provider: \"together\", baseUrl: \"https://api.together.ai/v1\", reasoning: true, thinkingLevelMap: { off: null, minimal: null, low: \"low\", medium: \"medium\", high: \"high\", xhigh: null, max: null }, input: [\"text\"], cost: { input: 0.05, output: 0.2, cacheRead: 0, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: true, maxTokensField: \"max_tokens\", thinkingFormat: \"openai\", supportsStrictMode: false, supportsLongCacheRetention: false }, contextWindow: 131072, maxTokens: 131072 }, \"thinkingmachines/Inkling\": { id: \"thinkingmachines/Inkling\", name: \"Inkling\", api: \"openai-completions\", provider: \"together\", baseUrl: \"https://api.together.ai/v1\", reasoning: true, thinkingLevelMap: { minimal: null, low: null, medium: null }, input: [\"text\", \"image\"], cost: { input: 1, output: 4.05, cacheRead: 0.17, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false, maxTokensField: \"max_tokens\", thinkingFormat: \"together\", supportsStrictMode: false, supportsLongCacheRetention: false }, contextWindow: 524288, maxTokens: 131072 }, \"zai-org/GLM-5.2\": { id: \"zai-org/GLM-5.2\", name: \"GLM-5.2\", api: \"openai-completions\", provider: \"together\", baseUrl: \"https://api.together.ai/v1\", reasoning: true, thinkingLevelMap: { minimal: null, low: null, medium: null }, input: [\"text\"], cost: { input: 1.4, output: 4.4, cacheRead: 0.26, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false, maxTokensField: \"max_tokens\", thinkingFormat: \"together\", supportsStrictMode: false, supportsLongCacheRetention: false }, contextWindow: 512e3, maxTokens: 164e3 } } };\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/together.models.js\nvar TOGETHER_MODELS = flattenModelCatalog(\"together\", together_default);\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/data/vercel-ai-gateway.json\nvar vercel_ai_gateway_default = { \"anthropic-messages\": { \"alibaba/qwen-3-14b\": { id: \"alibaba/qwen-3-14b\", name: \"Qwen3-14B\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\"], cost: { input: 0.12, output: 0.24, cacheRead: 0, cacheWrite: 0 }, contextWindow: 40960, maxTokens: 16384 }, \"alibaba/qwen-3-235b\": { id: \"alibaba/qwen-3-235b\", name: \"Qwen3 235B A22B\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\"], cost: { input: 0.22, output: 0.88, cacheRead: 0, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 16384 }, \"alibaba/qwen-3-30b\": { id: \"alibaba/qwen-3-30b\", name: \"Qwen3-30B-A3B\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\"], cost: { input: 0.12, output: 0.5, cacheRead: 0, cacheWrite: 0 }, contextWindow: 40960, maxTokens: 16384 }, \"alibaba/qwen-3-32b\": { id: \"alibaba/qwen-3-32b\", name: \"Qwen 3 32B\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\"], cost: { input: 0.16, output: 0.64, cacheRead: 0, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 8192 }, \"alibaba/qwen-3.6-max-preview\": { id: \"alibaba/qwen-3.6-max-preview\", name: \"Qwen 3.6 Max Preview\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\"], cost: { input: 1.3, output: 7.8, cacheRead: 0.26, cacheWrite: 1.625 }, contextWindow: 24e4, maxTokens: 64e3 }, \"alibaba/qwen3-235b-a22b-thinking\": { id: \"alibaba/qwen3-235b-a22b-thinking\", name: \"Qwen3 VL 235B A22B Thinking\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.4, output: 4, cacheRead: 0, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 32768 }, \"alibaba/qwen3-coder\": { id: \"alibaba/qwen3-coder\", name: \"Qwen3 Coder 480B A35B Instruct\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: false, input: [\"text\"], cost: { input: 1.5, output: 7.5, cacheRead: 0.3, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 65536 }, \"alibaba/qwen3-coder-30b-a3b\": { id: \"alibaba/qwen3-coder-30b-a3b\", name: \"Qwen 3 Coder 30B A3B Instruct\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: false, input: [\"text\"], cost: { input: 0.15, output: 0.6, cacheRead: 0, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 8192 }, \"alibaba/qwen3-coder-next\": { id: \"alibaba/qwen3-coder-next\", name: \"Qwen3 Coder Next\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: false, input: [\"text\"], cost: { input: 0.5, output: 1.2, cacheRead: 0, cacheWrite: 0 }, contextWindow: 256e3, maxTokens: 256e3 }, \"alibaba/qwen3-coder-plus\": { id: \"alibaba/qwen3-coder-plus\", name: \"Qwen3 Coder Plus\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: false, input: [\"text\"], cost: { input: 1, output: 5, cacheRead: 0.2, cacheWrite: 0 }, contextWindow: 1e6, maxTokens: 65536 }, \"alibaba/qwen3-max\": { id: \"alibaba/qwen3-max\", name: \"Qwen3 Max\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: false, input: [\"text\"], cost: { input: 1.2, output: 6, cacheRead: 0.24, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 32768 }, \"alibaba/qwen3-max-preview\": { id: \"alibaba/qwen3-max-preview\", name: \"Qwen3 Max Preview\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: false, input: [\"text\"], cost: { input: 1.2, output: 6, cacheRead: 0.24, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 32768 }, \"alibaba/qwen3-max-thinking\": { id: \"alibaba/qwen3-max-thinking\", name: \"Qwen 3 Max Thinking\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\"], cost: { input: 1.2, output: 6, cacheRead: 0.24, cacheWrite: 0 }, contextWindow: 256e3, maxTokens: 65536 }, \"alibaba/qwen3-next-80b-a3b-instruct\": { id: \"alibaba/qwen3-next-80b-a3b-instruct\", name: \"Qwen3 Next 80B A3B Instruct\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: false, input: [\"text\"], cost: { input: 0.15, output: 1.2, cacheRead: 0, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 32768 }, \"alibaba/qwen3-next-80b-a3b-thinking\": { id: \"alibaba/qwen3-next-80b-a3b-thinking\", name: \"Qwen3 Next 80B A3B Thinking\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\"], cost: { input: 0.15, output: 1.2, cacheRead: 0, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 32768 }, \"alibaba/qwen3-vl-235b-a22b-instruct\": { id: \"alibaba/qwen3-vl-235b-a22b-instruct\", name: \"Qwen3 VL 235B A22B Instruct\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 0.4, output: 1.6, cacheRead: 0, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 129024 }, \"alibaba/qwen3-vl-instruct\": { id: \"alibaba/qwen3-vl-instruct\", name: \"Qwen3 VL 235B A22B Instruct\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 0.4, output: 1.6, cacheRead: 0, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 129024 }, \"alibaba/qwen3-vl-thinking\": { id: \"alibaba/qwen3-vl-thinking\", name: \"Qwen3 VL 235B A22B Thinking\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.4, output: 4, cacheRead: 0, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 32768 }, \"alibaba/qwen3.5-flash\": { id: \"alibaba/qwen3.5-flash\", name: \"Qwen 3.5 Flash\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.1, output: 0.4, cacheRead: 1e-3, cacheWrite: 0.125 }, contextWindow: 1e6, maxTokens: 64e3 }, \"alibaba/qwen3.5-plus\": { id: \"alibaba/qwen3.5-plus\", name: \"Qwen 3.5 Plus\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.4, output: 2.4, cacheRead: 0.04, cacheWrite: 0.5 }, contextWindow: 1e6, maxTokens: 64e3 }, \"alibaba/qwen3.6-27b\": { id: \"alibaba/qwen3.6-27b\", name: \"Qwen 3.6 27B\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.6, output: 3.6, cacheRead: 0, cacheWrite: 0 }, contextWindow: 256e3, maxTokens: 256e3 }, \"alibaba/qwen3.6-plus\": { id: \"alibaba/qwen3.6-plus\", name: \"Qwen 3.6 Plus\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.5, output: 3, cacheRead: 0.1, cacheWrite: 0.625 }, contextWindow: 1e6, maxTokens: 64e3 }, \"alibaba/qwen3.7-flash\": { id: \"alibaba/qwen3.7-flash\", name: \"Qwen 3.7 Flash\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.03, output: 0.13, cacheRead: 6e-3, cacheWrite: 0.038 }, contextWindow: 991e3, maxTokens: 64e3 }, \"alibaba/qwen3.7-max\": { id: \"alibaba/qwen3.7-max\", name: \"Qwen 3.7 Max\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\"], cost: { input: 2.5, output: 7.5, cacheRead: 0.5, cacheWrite: 3.125 }, contextWindow: 991e3, maxTokens: 64e3 }, \"alibaba/qwen3.7-plus\": { id: \"alibaba/qwen3.7-plus\", name: \"Qwen 3.7 Plus\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.4, output: 1.6, cacheRead: 0.08, cacheWrite: 0.5 }, contextWindow: 1e6, maxTokens: 64e3 }, \"alibaba/qwen3.8-2.4t-a95b\": { id: \"alibaba/qwen3.8-2.4t-a95b\", name: \"Qwen3.8 2.4T A95B\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\"], cost: { input: 2, output: 6, cacheRead: 0.25, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 131072 }, \"alibaba/qwen3.8-max\": { id: \"alibaba/qwen3.8-max\", name: \"Qwen 3.8 Max\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 2, output: 6, cacheRead: 0.25, cacheWrite: 2.5 }, contextWindow: 1e6, maxTokens: 128e3 }, \"amazon/nova-2-lite\": { id: \"amazon/nova-2-lite\", name: \"Nova 2 Lite\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.3, output: 2.5, cacheRead: 0.075, cacheWrite: 0 }, contextWindow: 1e6, maxTokens: 1e6 }, \"amazon/nova-lite\": { id: \"amazon/nova-lite\", name: \"Nova Lite\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 0.06, output: 0.24, cacheRead: 0, cacheWrite: 0 }, contextWindow: 3e5, maxTokens: 8192 }, \"amazon/nova-micro\": { id: \"amazon/nova-micro\", name: \"Nova Micro\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: false, input: [\"text\"], cost: { input: 0.035, output: 0.14, cacheRead: 0, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 8192 }, \"amazon/nova-pro\": { id: \"amazon/nova-pro\", name: \"Nova Pro\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 0.8, output: 3.2, cacheRead: 0, cacheWrite: 0 }, contextWindow: 3e5, maxTokens: 8192 }, \"anthropic/claude-3-haiku\": { id: \"anthropic/claude-3-haiku\", name: \"Claude 3 Haiku\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 0.25, output: 1.25, cacheRead: 0.03, cacheWrite: 0.3 }, contextWindow: 2e5, maxTokens: 4096 }, \"anthropic/claude-fable-5\": { id: \"anthropic/claude-fable-5\", name: \"Claude Fable 5\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 10, output: 50, cacheRead: 1, cacheWrite: 12.5 }, contextWindow: 1e6, maxTokens: 128e3, thinkingLevelMap: { off: null, xhigh: \"xhigh\", max: \"max\" }, compat: { forceAdaptiveThinking: true } }, \"anthropic/claude-haiku-4.5\": { id: \"anthropic/claude-haiku-4.5\", name: \"Claude Haiku 4.5\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1, output: 5, cacheRead: 0.1, cacheWrite: 1.25 }, contextWindow: 2e5, maxTokens: 64e3 }, \"anthropic/claude-opus-4\": { id: \"anthropic/claude-opus-4\", name: \"Claude Opus 4\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 15, output: 75, cacheRead: 1.5, cacheWrite: 18.75 }, contextWindow: 2e5, maxTokens: 8192 }, \"anthropic/claude-opus-4.5\": { id: \"anthropic/claude-opus-4.5\", name: \"Claude Opus 4.5\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 }, contextWindow: 2e5, maxTokens: 64e3 }, \"anthropic/claude-opus-4.6\": { id: \"anthropic/claude-opus-4.6\", name: \"Claude Opus 4.6\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 }, contextWindow: 1e6, maxTokens: 128e3, thinkingLevelMap: { max: \"max\" }, compat: { forceAdaptiveThinking: true } }, \"anthropic/claude-opus-4.7\": { id: \"anthropic/claude-opus-4.7\", name: \"Claude Opus 4.7\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 }, contextWindow: 1e6, maxTokens: 128e3, thinkingLevelMap: { xhigh: \"xhigh\", max: \"max\" }, compat: { forceAdaptiveThinking: true, supportsTemperature: false } }, \"anthropic/claude-opus-4.8\": { id: \"anthropic/claude-opus-4.8\", name: \"Claude Opus 4.8\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 }, contextWindow: 1e6, maxTokens: 128e3, thinkingLevelMap: { xhigh: \"xhigh\", max: \"max\" }, compat: { forceAdaptiveThinking: true, supportsTemperature: false } }, \"anthropic/claude-opus-4.8-fast\": { id: \"anthropic/claude-opus-4.8-fast\", name: \"Claude Opus 4.8 (Fast)\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 10, output: 50, cacheRead: 1, cacheWrite: 12.5 }, contextWindow: 1e6, maxTokens: 128e3, thinkingLevelMap: { xhigh: \"xhigh\", max: \"max\" }, compat: { forceAdaptiveThinking: true, supportsTemperature: false } }, \"anthropic/claude-opus-5\": { id: \"anthropic/claude-opus-5\", name: \"Claude Opus 5\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 }, contextWindow: 1e6, maxTokens: 128e3, thinkingLevelMap: { xhigh: \"xhigh\", max: \"max\" }, compat: { forceAdaptiveThinking: true, supportsTemperature: false } }, \"anthropic/claude-opus-5-fast\": { id: \"anthropic/claude-opus-5-fast\", name: \"Claude Opus 5 (Fast)\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 10, output: 50, cacheRead: 1, cacheWrite: 12.5 }, contextWindow: 1e6, maxTokens: 128e3, thinkingLevelMap: { xhigh: \"xhigh\", max: \"max\" }, compat: { forceAdaptiveThinking: true, supportsTemperature: false } }, \"anthropic/claude-sonnet-4\": { id: \"anthropic/claude-sonnet-4\", name: \"Claude Sonnet 4\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3.75 }, contextWindow: 1e6, maxTokens: 8192 }, \"anthropic/claude-sonnet-4.5\": { id: \"anthropic/claude-sonnet-4.5\", name: \"Claude Sonnet 4.5\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3.75 }, contextWindow: 1e6, maxTokens: 64e3 }, \"anthropic/claude-sonnet-4.6\": { id: \"anthropic/claude-sonnet-4.6\", name: \"Claude Sonnet 4.6\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3.75 }, contextWindow: 1e6, maxTokens: 128e3, thinkingLevelMap: { max: \"max\" }, compat: { forceAdaptiveThinking: true } }, \"anthropic/claude-sonnet-5\": { id: \"anthropic/claude-sonnet-5\", name: \"Claude Sonnet 5\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 2, output: 10, cacheRead: 0.2, cacheWrite: 2.5 }, contextWindow: 1e6, maxTokens: 128e3, thinkingLevelMap: { xhigh: \"xhigh\", max: \"max\" }, compat: { forceAdaptiveThinking: true } }, \"arcee-ai/trinity-large-thinking\": { id: \"arcee-ai/trinity-large-thinking\", name: \"Trinity Large Thinking\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\"], cost: { input: 0.25, output: 0.9, cacheRead: 0, cacheWrite: 0 }, contextWindow: 262100, maxTokens: 8e4 }, \"arcee-ai/trinity-mini\": { id: \"arcee-ai/trinity-mini\", name: \"Trinity Mini\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: false, input: [\"text\"], cost: { input: 0.045, output: 0.15, cacheRead: 0, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 131072 }, \"bytedance/seed-1.6\": { id: \"bytedance/seed-1.6\", name: \"Seed 1.6\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.25, output: 2, cacheRead: 0.05, cacheWrite: 0 }, contextWindow: 256e3, maxTokens: 32e3 }, \"bytedance/seed-1.8\": { id: \"bytedance/seed-1.8\", name: \"Bytedance Seed 1.8\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.25, output: 2, cacheRead: 0.05, cacheWrite: 0 }, contextWindow: 256e3, maxTokens: 64e3 }, \"cohere/command-a\": { id: \"cohere/command-a\", name: \"Command A\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: false, input: [\"text\"], cost: { input: 2.5, output: 10, cacheRead: 0, cacheWrite: 0 }, contextWindow: 256e3, maxTokens: 8e3 }, \"deepseek/deepseek-r1\": { id: \"deepseek/deepseek-r1\", name: \"DeepSeek-R1\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\"], cost: { input: 1.35, output: 5.4, cacheRead: 0, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 8192 }, \"deepseek/deepseek-v3\": { id: \"deepseek/deepseek-v3\", name: \"DeepSeek V3 0324\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: false, input: [\"text\"], cost: { input: 0.27, output: 1.12, cacheRead: 0.135, cacheWrite: 0 }, contextWindow: 163840, maxTokens: 163840 }, \"deepseek/deepseek-v3.1\": { id: \"deepseek/deepseek-v3.1\", name: \"DeepSeek V3.1\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\"], cost: { input: 0.25, output: 0.95, cacheRead: 0.13, cacheWrite: 0 }, contextWindow: 163840, maxTokens: 128e3 }, \"deepseek/deepseek-v3.1-terminus\": { id: \"deepseek/deepseek-v3.1-terminus\", name: \"DeepSeek V3.1 Terminus\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\"], cost: { input: 0.27, output: 1, cacheRead: 0.135, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 65536 }, \"deepseek/deepseek-v3.2\": { id: \"deepseek/deepseek-v3.2\", name: \"DeepSeek V3.2\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: false, input: [\"text\"], cost: { input: 0.28, output: 0.42, cacheRead: 0.028, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 8e3 }, \"deepseek/deepseek-v3.2-thinking\": { id: \"deepseek/deepseek-v3.2-thinking\", name: \"DeepSeek V3.2 Thinking\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: false, input: [\"text\"], cost: { input: 0.62, output: 1.85, cacheRead: 0, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 8e3 }, \"deepseek/deepseek-v4-flash\": { id: \"deepseek/deepseek-v4-flash\", name: \"DeepSeek V4 Flash\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\"], cost: { input: 0.2, output: 0.4, cacheRead: 0.04, cacheWrite: 0 }, contextWindow: 1e6, maxTokens: 384e3 }, \"deepseek/deepseek-v4-flash-0731\": { id: \"deepseek/deepseek-v4-flash-0731\", name: \"DeepSeek V4 Flash 0731\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\"], cost: { input: 0.2, output: 0.4, cacheRead: 0.04, cacheWrite: 0 }, contextWindow: 1e6, maxTokens: 384e3 }, \"deepseek/deepseek-v4-pro\": { id: \"deepseek/deepseek-v4-pro\", name: \"DeepSeek V4 Pro\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\"], cost: { input: 1.74, output: 3.48, cacheRead: 0.14, cacheWrite: 0 }, contextWindow: 1048600, maxTokens: 1048600 }, \"deepseek/deepseek-v4-pro-0813\": { id: \"deepseek/deepseek-v4-pro-0813\", name: \"DeepSeek V4 Pro 0813\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\"], cost: { input: 1.32, output: 3.96, cacheRead: 0.132, cacheWrite: 0 }, contextWindow: 1e6, maxTokens: 384e3 }, \"google/gemini-2.5-flash\": { id: \"google/gemini-2.5-flash\", name: \"Gemini 2.5 Flash\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.3, output: 2.5, cacheRead: 0.03, cacheWrite: 0 }, contextWindow: 1e6, maxTokens: 65536 }, \"google/gemini-2.5-flash-lite\": { id: \"google/gemini-2.5-flash-lite\", name: \"Gemini 2.5 Flash Lite\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.1, output: 0.4, cacheRead: 0.01, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536 }, \"google/gemini-2.5-pro\": { id: \"google/gemini-2.5-pro\", name: \"Gemini 2.5 Pro\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.25, output: 10, cacheRead: 0.125, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536 }, \"google/gemini-3-flash\": { id: \"google/gemini-3-flash\", name: \"Gemini 3 Flash\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.5, output: 3, cacheRead: 0.05, cacheWrite: 0 }, contextWindow: 1e6, maxTokens: 65e3 }, \"google/gemini-3.1-flash-lite\": { id: \"google/gemini-3.1-flash-lite\", name: \"Gemini 3.1 Flash Lite\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.25, output: 1.5, cacheRead: 0.03, cacheWrite: 0 }, contextWindow: 1e6, maxTokens: 65e3 }, \"google/gemini-3.1-pro-preview\": { id: \"google/gemini-3.1-pro-preview\", name: \"Gemini 3.1 Pro Preview\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 2, output: 12, cacheRead: 0.2, cacheWrite: 0 }, contextWindow: 1e6, maxTokens: 64e3 }, \"google/gemini-3.5-flash\": { id: \"google/gemini-3.5-flash\", name: \"Gemini 3.5 Flash\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.5, output: 9, cacheRead: 0.15, cacheWrite: 0 }, contextWindow: 1e6, maxTokens: 64e3 }, \"google/gemini-3.5-flash-lite\": { id: \"google/gemini-3.5-flash-lite\", name: \"Gemini 3.5 Flash Lite\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.3, output: 2.5, cacheRead: 0.03, cacheWrite: 0 }, contextWindow: 1e6, maxTokens: 65e3 }, \"google/gemini-3.6-flash\": { id: \"google/gemini-3.6-flash\", name: \"Gemini 3.6 Flash\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.5, output: 7.5, cacheRead: 0.15, cacheWrite: 0 }, contextWindow: 1e6, maxTokens: 64e3 }, \"google/gemini-3.7-flash\": { id: \"google/gemini-3.7-flash\", name: \"Gemini 3.7 Flash\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.75, output: 3.75, cacheRead: 0.075, cacheWrite: 0 }, contextWindow: 1e6, maxTokens: 65536 }, \"google/gemma-4-26b-a4b-it\": { id: \"google/gemma-4-26b-a4b-it\", name: \"Google Gemma 4 26B A4B\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.15, output: 0.6, cacheRead: 0.015, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 131072 }, \"google/gemma-4-31b-it\": { id: \"google/gemma-4-31b-it\", name: \"Gemma 4 31B IT\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.14, output: 0.4, cacheRead: 0, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 131072 }, \"inception/mercury-2\": { id: \"inception/mercury-2\", name: \"Mercury 2\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\"], cost: { input: 0.25, output: 0.75, cacheRead: 0.025, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 128e3 }, \"inception/mercury-coder-small\": { id: \"inception/mercury-coder-small\", name: \"Mercury Coder Small Beta\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: false, input: [\"text\"], cost: { input: 0.25, output: 1, cacheRead: 0, cacheWrite: 0 }, contextWindow: 32e3, maxTokens: 16384 }, \"inclusionai/ling-3.0-flash\": { id: \"inclusionai/ling-3.0-flash\", name: \"Ling 3.0 Flash\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\"], cost: { input: 0.06, output: 0.18, cacheRead: 0.012, cacheWrite: 0 }, contextWindow: 256e3, maxTokens: 32e3 }, \"interfaze/interfaze-beta\": { id: \"interfaze/interfaze-beta\", name: \"Interfaze Beta\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.5, output: 3.5, cacheRead: 0, cacheWrite: 0 }, contextWindow: 1e6, maxTokens: 32e3 }, \"kwaipilot/kat-coder-air-v2.5\": { id: \"kwaipilot/kat-coder-air-v2.5\", name: \"Kat Coder Air V2.5\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.15, output: 0.6, cacheRead: 0.03, cacheWrite: 0 }, contextWindow: 256e3, maxTokens: 8e4 }, \"kwaipilot/kat-coder-pro-v1\": { id: \"kwaipilot/kat-coder-pro-v1\", name: \"KAT-Coder-Pro V1\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: false, input: [\"text\"], cost: { input: 0.3, output: 1.2, cacheRead: 0.06, cacheWrite: 0 }, contextWindow: 256e3, maxTokens: 32e3 }, \"kwaipilot/kat-coder-pro-v2\": { id: \"kwaipilot/kat-coder-pro-v2\", name: \"Kat Coder Pro V2\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\"], cost: { input: 0.3, output: 1.2, cacheRead: 0.06, cacheWrite: 0 }, contextWindow: 256e3, maxTokens: 256e3 }, \"kwaipilot/kat-coder-pro-v2.5\": { id: \"kwaipilot/kat-coder-pro-v2.5\", name: \"Kat Coder Pro V2.5\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.74, output: 2.96, cacheRead: 0.15, cacheWrite: 0 }, contextWindow: 256e3, maxTokens: 8e4 }, \"meta/llama-3.1-70b\": { id: \"meta/llama-3.1-70b\", name: \"Llama 3.1 70B Instruct\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: false, input: [\"text\"], cost: { input: 0.72, output: 0.72, cacheRead: 0, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 8192 }, \"meta/llama-3.1-8b\": { id: \"meta/llama-3.1-8b\", name: \"Llama 3.1 8B Instruct\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: false, input: [\"text\"], cost: { input: 0.22, output: 0.22, cacheRead: 0, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 8192 }, \"meta/llama-3.3-70b\": { id: \"meta/llama-3.3-70b\", name: \"Llama 3.3 70B Instruct\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: false, input: [\"text\"], cost: { input: 0.72, output: 0.72, cacheRead: 0, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 8192 }, \"meta/llama-4-maverick\": { id: \"meta/llama-4-maverick\", name: \"Llama 4 Maverick 17B Instruct\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 0.24, output: 0.97, cacheRead: 0, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 8192 }, \"meta/llama-4-scout\": { id: \"meta/llama-4-scout\", name: \"Llama 4 Scout 17B Instruct\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 0.17, output: 0.66, cacheRead: 0, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 8192 }, \"meta/muse-glimmer-30b\": { id: \"meta/muse-glimmer-30b\", name: \"Muse Glimmer 30B\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.35, output: 1.5, cacheRead: 0.04, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 131072 }, \"meta/muse-spark-1.1\": { id: \"meta/muse-spark-1.1\", name: \"Muse Spark 1.1\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.25, output: 4.25, cacheRead: 0.15, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 1048576 }, \"meta/muse-spark-1.2\": { id: \"meta/muse-spark-1.2\", name: \"Muse Spark 1.2\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.25, output: 4.25, cacheRead: 0.15, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 1048576 }, \"meta/muse-spark-1.2-contributor\": { id: \"meta/muse-spark-1.2-contributor\", name: \"Muse Spark 1.2 Contributor\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.1, output: 0.2, cacheRead: 2e-3, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 1048576 }, \"minimax/minimax-m2\": { id: \"minimax/minimax-m2\", name: \"MiniMax M2\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\"], cost: { input: 0.3, output: 1.2, cacheRead: 0.03, cacheWrite: 0.375 }, contextWindow: 205e3, maxTokens: 205e3 }, \"minimax/minimax-m2.1\": { id: \"minimax/minimax-m2.1\", name: \"MiniMax M2.1\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\"], cost: { input: 0.3, output: 1.2, cacheRead: 0.03, cacheWrite: 0.375 }, contextWindow: 204800, maxTokens: 131072 }, \"minimax/minimax-m2.1-lightning\": { id: \"minimax/minimax-m2.1-lightning\", name: \"MiniMax M2.1 Lightning\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\"], cost: { input: 0.3, output: 2.4, cacheRead: 0.03, cacheWrite: 0.375 }, contextWindow: 204800, maxTokens: 131072 }, \"minimax/minimax-m2.5\": { id: \"minimax/minimax-m2.5\", name: \"MiniMax M2.5\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\"], cost: { input: 0.3, output: 1.2, cacheRead: 0.03, cacheWrite: 0.375 }, contextWindow: 204800, maxTokens: 131e3 }, \"minimax/minimax-m2.5-highspeed\": { id: \"minimax/minimax-m2.5-highspeed\", name: \"MiniMax M2.5 High Speed\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\"], cost: { input: 0.6, output: 2.4, cacheRead: 0.03, cacheWrite: 0.375 }, contextWindow: 204800, maxTokens: 131e3 }, \"minimax/minimax-m2.7\": { id: \"minimax/minimax-m2.7\", name: \"Minimax M2.7\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\"], cost: { input: 0.3, output: 1.2, cacheRead: 0.06, cacheWrite: 0.375 }, contextWindow: 204800, maxTokens: 131e3 }, \"minimax/minimax-m2.7-highspeed\": { id: \"minimax/minimax-m2.7-highspeed\", name: \"MiniMax M2.7 High Speed\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\"], cost: { input: 0.6, output: 2.4, cacheRead: 0.06, cacheWrite: 0.375 }, contextWindow: 204800, maxTokens: 131100 }, \"minimax/minimax-m3\": { id: \"minimax/minimax-m3\", name: \"MiniMax M3\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.3, output: 1.2, cacheRead: 0.06, cacheWrite: 0 }, contextWindow: 1e6, maxTokens: 1e6 }, \"mistral/codestral\": { id: \"mistral/codestral\", name: \"Mistral Codestral\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: false, input: [\"text\"], cost: { input: 0.3, output: 0.9, cacheRead: 0, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 4e3 }, \"mistral/devstral-2\": { id: \"mistral/devstral-2\", name: \"Devstral 2\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: false, input: [\"text\"], cost: { input: 0.4, output: 2, cacheRead: 0, cacheWrite: 0 }, contextWindow: 256e3, maxTokens: 256e3 }, \"mistral/devstral-small-2\": { id: \"mistral/devstral-small-2\", name: \"Devstral Small 2\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 0.1, output: 0.3, cacheRead: 0, cacheWrite: 0 }, contextWindow: 256e3, maxTokens: 256e3 }, \"mistral/magistral-medium\": { id: \"mistral/magistral-medium\", name: \"Magistral Medium 2509\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 2, output: 5, cacheRead: 0, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 64e3 }, \"mistral/magistral-small\": { id: \"mistral/magistral-small\", name: \"Magistral Small 2509\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.5, output: 1.5, cacheRead: 0, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 64e3 }, \"mistral/ministral-14b\": { id: \"mistral/ministral-14b\", name: \"Ministral 14B\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 0.2, output: 0.2, cacheRead: 0, cacheWrite: 0 }, contextWindow: 256e3, maxTokens: 256e3 }, \"mistral/ministral-3b\": { id: \"mistral/ministral-3b\", name: \"Ministral 3B\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 0.1, output: 0.1, cacheRead: 0, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 4e3 }, \"mistral/ministral-8b\": { id: \"mistral/ministral-8b\", name: \"Ministral 8B\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 0.15, output: 0.15, cacheRead: 0, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 4e3 }, \"mistral/mistral-large-3\": { id: \"mistral/mistral-large-3\", name: \"Mistral Large 3\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 0.5, output: 1.5, cacheRead: 0, cacheWrite: 0 }, contextWindow: 256e3, maxTokens: 256e3 }, \"mistral/mistral-medium\": { id: \"mistral/mistral-medium\", name: \"Mistral Medium 3.1\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 0.4, output: 2, cacheRead: 0, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 64e3 }, \"mistral/mistral-medium-3.5\": { id: \"mistral/mistral-medium-3.5\", name: \"Mistral Medium Latest\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.5, output: 7.5, cacheRead: 0, cacheWrite: 0 }, contextWindow: 256e3, maxTokens: 256e3 }, \"mistral/mistral-nemo\": { id: \"mistral/mistral-nemo\", name: \"Mistral Nemo 12B\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 0.15, output: 0.15, cacheRead: 0, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 128e3 }, \"mistral/mistral-small\": { id: \"mistral/mistral-small\", name: \"Mistral Small\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 0.1, output: 0.3, cacheRead: 0, cacheWrite: 0 }, contextWindow: 32e3, maxTokens: 4e3 }, \"mistral/pixtral-12b\": { id: \"mistral/pixtral-12b\", name: \"Pixtral 12B 2409\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 0.15, output: 0.15, cacheRead: 0, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 4e3 }, \"moonshotai/kimi-k2\": { id: \"moonshotai/kimi-k2\", name: \"Kimi K2 Instruct\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: false, input: [\"text\"], cost: { input: 0.57, output: 2.3, cacheRead: 0, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 131072 }, \"moonshotai/kimi-k2-thinking\": { id: \"moonshotai/kimi-k2-thinking\", name: \"Kimi K2 Thinking\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\"], cost: { input: 0.47, output: 2, cacheRead: 0.141, cacheWrite: 0 }, contextWindow: 216144, maxTokens: 216144 }, \"moonshotai/kimi-k2.5\": { id: \"moonshotai/kimi-k2.5\", name: \"Kimi K2.5\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.6, output: 3, cacheRead: 0.1, cacheWrite: 0 }, contextWindow: 262114, maxTokens: 262114 }, \"moonshotai/kimi-k2.6\": { id: \"moonshotai/kimi-k2.6\", name: \"Kimi K2.6\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.95, output: 4, cacheRead: 0.16, cacheWrite: 0 }, contextWindow: 262e3, maxTokens: 262e3 }, \"moonshotai/kimi-k2.7-code\": { id: \"moonshotai/kimi-k2.7-code\", name: \"Kimi K2.7 Code\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.95, output: 4, cacheRead: 0.19, cacheWrite: 0 }, contextWindow: 256e3, maxTokens: 32768 }, \"moonshotai/kimi-k2.7-code-highspeed\": { id: \"moonshotai/kimi-k2.7-code-highspeed\", name: \"Kimi K2.7 Code High Speed\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.9, output: 8, cacheRead: 0.38, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 32768 }, \"moonshotai/kimi-k3\": { id: \"moonshotai/kimi-k3\", name: \"Kimi K3\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 0 }, contextWindow: 1e6, maxTokens: 131072 }, \"moonshotai/kimi-k3-fast\": { id: \"moonshotai/kimi-k3-fast\", name: \"Kimi K3 Fast\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 4.5, output: 22.5, cacheRead: 0.45, cacheWrite: 0 }, contextWindow: 1e6, maxTokens: 131072 }, \"nvidia/nemotron-3-nano-30b-a3b\": { id: \"nvidia/nemotron-3-nano-30b-a3b\", name: \"Nemotron 3 Nano 30B A3B\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\"], cost: { input: 0.05, output: 0.24, cacheRead: 0, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 262144 }, \"nvidia/nemotron-3-super-120b-a12b\": { id: \"nvidia/nemotron-3-super-120b-a12b\", name: \"NVIDIA Nemotron 3 Super 120B A12B\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\"], cost: { input: 0.15, output: 0.65, cacheRead: 0, cacheWrite: 0 }, contextWindow: 256e3, maxTokens: 32e3 }, \"nvidia/nemotron-3-ultra-550b-a55b\": { id: \"nvidia/nemotron-3-ultra-550b-a55b\", name: \"Nemotron 3 Ultra\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\"], cost: { input: 0.6, output: 2.4, cacheRead: 0.12, cacheWrite: 0 }, contextWindow: 1e6, maxTokens: 65e3 }, \"nvidia/nemotron-nano-12b-v2-vl\": { id: \"nvidia/nemotron-nano-12b-v2-vl\", name: \"Nvidia Nemotron Nano 12B V2 VL\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.2, output: 0.6, cacheRead: 0, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 131072 }, \"nvidia/nemotron-nano-9b-v2\": { id: \"nvidia/nemotron-nano-9b-v2\", name: \"Nvidia Nemotron Nano 9B V2\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\"], cost: { input: 0.06, output: 0.23, cacheRead: 0, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 131072 }, \"openai/gpt-3.5-turbo\": { id: \"openai/gpt-3.5-turbo\", name: \"GPT-3.5 Turbo\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: false, input: [\"text\"], cost: { input: 0.5, output: 1.5, cacheRead: 0, cacheWrite: 0 }, contextWindow: 16385, maxTokens: 4096 }, \"openai/gpt-4-turbo\": { id: \"openai/gpt-4-turbo\", name: \"GPT-4 Turbo\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 10, output: 30, cacheRead: 0, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 4096 }, \"openai/gpt-4.1\": { id: \"openai/gpt-4.1\", name: \"GPT-4.1\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 2, output: 8, cacheRead: 0.5, cacheWrite: 0 }, contextWindow: 1047576, maxTokens: 32768 }, \"openai/gpt-4.1-mini\": { id: \"openai/gpt-4.1-mini\", name: \"GPT-4.1 mini\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 0.4, output: 1.6, cacheRead: 0.1, cacheWrite: 0 }, contextWindow: 1047576, maxTokens: 32768 }, \"openai/gpt-4.1-nano\": { id: \"openai/gpt-4.1-nano\", name: \"GPT-4.1 nano\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 0.1, output: 0.4, cacheRead: 0.025, cacheWrite: 0 }, contextWindow: 1047576, maxTokens: 32768 }, \"openai/gpt-4o\": { id: \"openai/gpt-4o\", name: \"GPT-4o\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 2.5, output: 10, cacheRead: 1.25, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 16384 }, \"openai/gpt-4o-mini\": { id: \"openai/gpt-4o-mini\", name: \"GPT-4o mini\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 0.15, output: 0.6, cacheRead: 0.075, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 16384 }, \"openai/gpt-5\": { id: \"openai/gpt-5\", name: \"GPT-5\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.25, output: 10, cacheRead: 0.125, cacheWrite: 0 }, contextWindow: 4e5, maxTokens: 128e3 }, \"openai/gpt-5-codex\": { id: \"openai/gpt-5-codex\", name: \"GPT-5-Codex\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.25, output: 10, cacheRead: 0.13, cacheWrite: 0 }, contextWindow: 4e5, maxTokens: 128e3 }, \"openai/gpt-5-mini\": { id: \"openai/gpt-5-mini\", name: \"GPT-5 mini\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.25, output: 2, cacheRead: 0.025, cacheWrite: 0 }, contextWindow: 4e5, maxTokens: 128e3 }, \"openai/gpt-5-nano\": { id: \"openai/gpt-5-nano\", name: \"GPT-5 nano\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.05, output: 0.4, cacheRead: 5e-3, cacheWrite: 0 }, contextWindow: 4e5, maxTokens: 128e3 }, \"openai/gpt-5-pro\": { id: \"openai/gpt-5-pro\", name: \"GPT-5 pro\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 15, output: 120, cacheRead: 0, cacheWrite: 0 }, contextWindow: 4e5, maxTokens: 272e3 }, \"openai/gpt-5.1-codex\": { id: \"openai/gpt-5.1-codex\", name: \"GPT-5.1-Codex\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.25, output: 10, cacheRead: 0.13, cacheWrite: 0 }, contextWindow: 4e5, maxTokens: 128e3 }, \"openai/gpt-5.1-codex-max\": { id: \"openai/gpt-5.1-codex-max\", name: \"GPT 5.1 Codex Max\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.25, output: 10, cacheRead: 0.125, cacheWrite: 0 }, contextWindow: 4e5, maxTokens: 128e3 }, \"openai/gpt-5.1-codex-mini\": { id: \"openai/gpt-5.1-codex-mini\", name: \"GPT 5.1 Codex Mini\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.25, output: 2, cacheRead: 0.03, cacheWrite: 0 }, contextWindow: 4e5, maxTokens: 128e3 }, \"openai/gpt-5.1-thinking\": { id: \"openai/gpt-5.1-thinking\", name: \"GPT 5.1 Thinking\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.25, output: 10, cacheRead: 0.125, cacheWrite: 0 }, contextWindow: 4e5, maxTokens: 128e3 }, \"openai/gpt-5.2\": { id: \"openai/gpt-5.2\", name: \"GPT 5.2\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.75, output: 14, cacheRead: 0.175, cacheWrite: 0 }, contextWindow: 4e5, maxTokens: 128e3, thinkingLevelMap: { xhigh: \"xhigh\" } }, \"openai/gpt-5.2-codex\": { id: \"openai/gpt-5.2-codex\", name: \"GPT 5.2 Codex\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.75, output: 14, cacheRead: 0.175, cacheWrite: 0 }, contextWindow: 4e5, maxTokens: 128e3, thinkingLevelMap: { xhigh: \"xhigh\" } }, \"openai/gpt-5.2-pro\": { id: \"openai/gpt-5.2-pro\", name: \"GPT 5.2 \", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 21, output: 168, cacheRead: 0, cacheWrite: 0 }, contextWindow: 4e5, maxTokens: 128e3, thinkingLevelMap: { xhigh: \"xhigh\" } }, \"openai/gpt-5.3-codex\": { id: \"openai/gpt-5.3-codex\", name: \"GPT 5.3 Codex\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.75, output: 14, cacheRead: 0.175, cacheWrite: 0 }, contextWindow: 4e5, maxTokens: 128e3, thinkingLevelMap: { xhigh: \"xhigh\" } }, \"openai/gpt-5.4\": { id: \"openai/gpt-5.4\", name: \"GPT 5.4\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 2.5, output: 15, cacheRead: 0.25, cacheWrite: 0 }, contextWindow: 105e4, maxTokens: 128e3, thinkingLevelMap: { xhigh: \"xhigh\" } }, \"openai/gpt-5.4-mini\": { id: \"openai/gpt-5.4-mini\", name: \"GPT 5.4 Mini\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.75, output: 4.5, cacheRead: 0.075, cacheWrite: 0 }, contextWindow: 4e5, maxTokens: 128e3, thinkingLevelMap: { xhigh: \"xhigh\" } }, \"openai/gpt-5.4-nano\": { id: \"openai/gpt-5.4-nano\", name: \"GPT 5.4 Nano\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.2, output: 1.25, cacheRead: 0.02, cacheWrite: 0 }, contextWindow: 4e5, maxTokens: 128e3, thinkingLevelMap: { xhigh: \"xhigh\" } }, \"openai/gpt-5.4-pro\": { id: \"openai/gpt-5.4-pro\", name: \"GPT 5.4 Pro\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 30, output: 180, cacheRead: 0, cacheWrite: 0 }, contextWindow: 105e4, maxTokens: 128e3, thinkingLevelMap: { xhigh: \"xhigh\" } }, \"openai/gpt-5.5\": { id: \"openai/gpt-5.5\", name: \"GPT 5.5\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 5, output: 30, cacheRead: 0.5, cacheWrite: 0 }, contextWindow: 1e6, maxTokens: 128e3, thinkingLevelMap: { xhigh: \"xhigh\" } }, \"openai/gpt-5.5-pro\": { id: \"openai/gpt-5.5-pro\", name: \"GPT 5.5 Pro\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 30, output: 180, cacheRead: 0, cacheWrite: 0 }, contextWindow: 1e6, maxTokens: 128e3, thinkingLevelMap: { xhigh: \"xhigh\", off: null, minimal: null, low: null } }, \"openai/gpt-5.6-luna\": { id: \"openai/gpt-5.6-luna\", name: \"GPT 5.6 Luna\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.2, output: 1.2, cacheRead: 0.02, cacheWrite: 0.25 }, contextWindow: 105e4, maxTokens: 128e3, thinkingLevelMap: { xhigh: \"xhigh\" } }, \"openai/gpt-5.6-sol\": { id: \"openai/gpt-5.6-sol\", name: \"GPT 5.6 Sol\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 5, output: 30, cacheRead: 0.5, cacheWrite: 6.25 }, contextWindow: 105e4, maxTokens: 128e3, thinkingLevelMap: { xhigh: \"xhigh\" } }, \"openai/gpt-5.6-terra\": { id: \"openai/gpt-5.6-terra\", name: \"GPT 5.6 Terra\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 2, output: 12, cacheRead: 0.2, cacheWrite: 2.5 }, contextWindow: 105e4, maxTokens: 128e3, thinkingLevelMap: { xhigh: \"xhigh\" } }, \"openai/gpt-oss-120b\": { id: \"openai/gpt-oss-120b\", name: \"GPT OSS 120B\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\"], cost: { input: 0.1, output: 0.5, cacheRead: 0, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 131072 }, \"openai/gpt-oss-20b\": { id: \"openai/gpt-oss-20b\", name: \"GPT OSS 20B\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\"], cost: { input: 0.05, output: 0.2, cacheRead: 0, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 8192 }, \"openai/gpt-oss-safeguard-20b\": { id: \"openai/gpt-oss-safeguard-20b\", name: \"GPT OSS Safeguard 20B\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\"], cost: { input: 0.075, output: 0.3, cacheRead: 0.037, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 65536 }, \"openai/o1\": { id: \"openai/o1\", name: \"o1\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 15, output: 60, cacheRead: 7.5, cacheWrite: 0 }, contextWindow: 2e5, maxTokens: 1e5 }, \"openai/o3\": { id: \"openai/o3\", name: \"o3\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 2, output: 8, cacheRead: 0.5, cacheWrite: 0 }, contextWindow: 2e5, maxTokens: 1e5 }, \"openai/o3-deep-research\": { id: \"openai/o3-deep-research\", name: \"o3-deep-research\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 10, output: 40, cacheRead: 2.5, cacheWrite: 0 }, contextWindow: 2e5, maxTokens: 1e5 }, \"openai/o3-mini\": { id: \"openai/o3-mini\", name: \"o3-mini\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\"], cost: { input: 1.1, output: 4.4, cacheRead: 0.55, cacheWrite: 0 }, contextWindow: 2e5, maxTokens: 1e5 }, \"openai/o3-pro\": { id: \"openai/o3-pro\", name: \"o3 Pro\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 20, output: 80, cacheRead: 0, cacheWrite: 0 }, contextWindow: 2e5, maxTokens: 1e5 }, \"openai/o4-mini\": { id: \"openai/o4-mini\", name: \"o4-mini\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.1, output: 4.4, cacheRead: 0.275, cacheWrite: 0 }, contextWindow: 2e5, maxTokens: 1e5 }, \"poolside/laguna-s-2.1\": { id: \"poolside/laguna-s-2.1\", name: \"Laguna S 2.1\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\"], cost: { input: 0.1, output: 0.2, cacheRead: 0.01, cacheWrite: 0 }, contextWindow: 1e6, maxTokens: 131072 }, \"poolside/laguna-s-2.1-free\": { id: \"poolside/laguna-s-2.1-free\", name: \"Laguna S 2.1 Free\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 256e3, maxTokens: 32768 }, \"sakana/fugu-ultra\": { id: \"sakana/fugu-ultra\", name: \"Fugu Ultra\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 5, output: 30, cacheRead: 0.5, cacheWrite: 0 }, contextWindow: 1e6, maxTokens: 1e6 }, \"sakana/namazu\": { id: \"sakana/namazu\", name: \"Sakana Namazu\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.95, output: 4, cacheRead: 0.15, cacheWrite: 0 }, contextWindow: 256e3, maxTokens: 256e3 }, \"stepfun/step-3.5-flash\": { id: \"stepfun/step-3.5-flash\", name: \"StepFun 3.5 Flash\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.09, output: 0.3, cacheRead: 0.02, cacheWrite: 0 }, contextWindow: 262114, maxTokens: 262114 }, \"stepfun/step-3.7-flash\": { id: \"stepfun/step-3.7-flash\", name: \"Step 3.7 Flash\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.2, output: 1.15, cacheRead: 0.04, cacheWrite: 0 }, contextWindow: 256e3, maxTokens: 256e3 }, \"tencent/hy3\": { id: \"tencent/hy3\", name: \"Hy3\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\"], cost: { input: 0.14, output: 0.58, cacheRead: 0.035, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 262144 }, \"thinkingmachines/inkling\": { id: \"thinkingmachines/inkling\", name: \"Inkling\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1, output: 4.05, cacheRead: 0.17, cacheWrite: 0 }, contextWindow: 256e3, maxTokens: 256e3 }, \"thinkingmachines/inkling-small\": { id: \"thinkingmachines/inkling-small\", name: \"Inkling Small\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.5, output: 1.2, cacheRead: 0.1, cacheWrite: 0 }, contextWindow: 1e6, maxTokens: 1e6 }, \"xai/grok-4.1-fast-non-reasoning\": { id: \"xai/grok-4.1-fast-non-reasoning\", name: \"Grok 4.1 Fast Non-Reasoning\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 0.2, output: 0.5, cacheRead: 0.05, cacheWrite: 0 }, contextWindow: 1e6, maxTokens: 1e6 }, \"xai/grok-4.1-fast-reasoning\": { id: \"xai/grok-4.1-fast-reasoning\", name: \"Grok 4.1 Fast Reasoning\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.2, output: 0.5, cacheRead: 0.05, cacheWrite: 0 }, contextWindow: 1e6, maxTokens: 1e6 }, \"xai/grok-4.20-multi-agent\": { id: \"xai/grok-4.20-multi-agent\", name: \"Grok 4.20 Multi-Agent\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.25, output: 2.5, cacheRead: 0.2, cacheWrite: 0 }, contextWindow: 2e6, maxTokens: 2e6 }, \"xai/grok-4.20-multi-agent-beta\": { id: \"xai/grok-4.20-multi-agent-beta\", name: \"Grok 4.20 Multi Agent Beta\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.25, output: 2.5, cacheRead: 0.2, cacheWrite: 0 }, contextWindow: 2e6, maxTokens: 2e6 }, \"xai/grok-4.20-non-reasoning\": { id: \"xai/grok-4.20-non-reasoning\", name: \"Grok 4.20 Non-Reasoning\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 1.25, output: 2.5, cacheRead: 0.2, cacheWrite: 0 }, contextWindow: 2e6, maxTokens: 2e6 }, \"xai/grok-4.20-non-reasoning-beta\": { id: \"xai/grok-4.20-non-reasoning-beta\", name: \"Grok 4.20 Beta Non-Reasoning\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: false, input: [\"text\", \"image\"], cost: { input: 1.25, output: 2.5, cacheRead: 0.2, cacheWrite: 0 }, contextWindow: 2e6, maxTokens: 2e6 }, \"xai/grok-4.20-reasoning\": { id: \"xai/grok-4.20-reasoning\", name: \"Grok 4.20 Reasoning\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.25, output: 2.5, cacheRead: 0.2, cacheWrite: 0 }, contextWindow: 2e6, maxTokens: 2e6 }, \"xai/grok-4.20-reasoning-beta\": { id: \"xai/grok-4.20-reasoning-beta\", name: \"Grok 4.20 Beta Reasoning\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.25, output: 2.5, cacheRead: 0.2, cacheWrite: 0 }, contextWindow: 2e6, maxTokens: 2e6 }, \"xai/grok-4.3\": { id: \"xai/grok-4.3\", name: \"Grok 4.3\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.25, output: 2.5, cacheRead: 0.2, cacheWrite: 0 }, contextWindow: 1e6, maxTokens: 1e6 }, \"xai/grok-4.5\": { id: \"xai/grok-4.5\", name: \"Grok 4.5\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 2, output: 6, cacheRead: 0.3, cacheWrite: 0 }, contextWindow: 5e5, maxTokens: 5e5 }, \"xai/grok-4.6\": { id: \"xai/grok-4.6\", name: \"Grok 4.6\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\"], cost: { input: 2, output: 6, cacheRead: 0.5, cacheWrite: 0 }, contextWindow: 5e5, maxTokens: 5e5 }, \"xai/grok-build-0.1\": { id: \"xai/grok-build-0.1\", name: \"Grok Build 0.1\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1, output: 2, cacheRead: 0.2, cacheWrite: 0 }, contextWindow: 256e3, maxTokens: 256e3 }, \"xiaomi/mimo-v2.5\": { id: \"xiaomi/mimo-v2.5\", name: \"MiMo M2.5\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.14, output: 0.28, cacheRead: 28e-4, cacheWrite: 0 }, contextWindow: 105e4, maxTokens: 131100 }, \"xiaomi/mimo-v2.5-pro\": { id: \"xiaomi/mimo-v2.5-pro\", name: \"MiMo V2.5 Pro\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\"], cost: { input: 0.435, output: 0.87, cacheRead: 36e-4, cacheWrite: 0 }, contextWindow: 105e4, maxTokens: 131e3 }, \"zai/glm-4.5\": { id: \"zai/glm-4.5\", name: \"GLM 4.5\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\"], cost: { input: 0.6, output: 2.2, cacheRead: 0.11, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 96e3 }, \"zai/glm-4.5-air\": { id: \"zai/glm-4.5-air\", name: \"GLM 4.5 Air\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\"], cost: { input: 0.2, output: 1.1, cacheRead: 0.03, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 96e3 }, \"zai/glm-4.5v\": { id: \"zai/glm-4.5v\", name: \"GLM 4.5V\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.6, output: 1.8, cacheRead: 0.11, cacheWrite: 0 }, contextWindow: 66e3, maxTokens: 16e3 }, \"zai/glm-4.6\": { id: \"zai/glm-4.6\", name: \"GLM 4.6\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\"], cost: { input: 0.6, output: 2.2, cacheRead: 0.11, cacheWrite: 0 }, contextWindow: 2e5, maxTokens: 96e3 }, \"zai/glm-4.6v\": { id: \"zai/glm-4.6v\", name: \"GLM-4.6V\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.3, output: 0.9, cacheRead: 0.05, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 24e3 }, \"zai/glm-4.6v-flash\": { id: \"zai/glm-4.6v-flash\", name: \"GLM-4.6V-Flash\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 24e3 }, \"zai/glm-4.7\": { id: \"zai/glm-4.7\", name: \"GLM 4.7\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\"], cost: { input: 0.6, output: 2.2, cacheRead: 0.12, cacheWrite: 0 }, contextWindow: 2e5, maxTokens: 12e4 }, \"zai/glm-4.7-flash\": { id: \"zai/glm-4.7-flash\", name: \"GLM 4.7 Flash\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\"], cost: { input: 0.07, output: 0.4, cacheRead: 0, cacheWrite: 0 }, contextWindow: 2e5, maxTokens: 131e3 }, \"zai/glm-4.7-flashx\": { id: \"zai/glm-4.7-flashx\", name: \"GLM 4.7 FlashX\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\"], cost: { input: 0.06, output: 0.4, cacheRead: 0.01, cacheWrite: 0 }, contextWindow: 2e5, maxTokens: 128e3 }, \"zai/glm-5\": { id: \"zai/glm-5\", name: \"GLM 5\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\"], cost: { input: 1, output: 3.2, cacheRead: 0, cacheWrite: 0 }, contextWindow: 202800, maxTokens: 131100 }, \"zai/glm-5-turbo\": { id: \"zai/glm-5-turbo\", name: \"GLM 5 Turbo\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\"], cost: { input: 1.2, output: 4, cacheRead: 0.24, cacheWrite: 0 }, contextWindow: 202800, maxTokens: 131100 }, \"zai/glm-5.1\": { id: \"zai/glm-5.1\", name: \"GLM 5.1\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\"], cost: { input: 1.4, output: 4.4, cacheRead: 0.26, cacheWrite: 0 }, contextWindow: 202800, maxTokens: 64e3 }, \"zai/glm-5.2\": { id: \"zai/glm-5.2\", name: \"GLM 5.2\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\"], cost: { input: 1.1, output: 3.851, cacheRead: 0.275, cacheWrite: 0 }, contextWindow: 1e6, maxTokens: 128e3 }, \"zai/glm-5.2-fast\": { id: \"zai/glm-5.2-fast\", name: \"GLM 5.2 Fast\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\"], cost: { input: 2.1, output: 6.6, cacheRead: 0.21, cacheWrite: 0 }, contextWindow: 1e6, maxTokens: 128e3 }, \"zai/glm-5v-turbo\": { id: \"zai/glm-5v-turbo\", name: \"GLM 5V Turbo\", api: \"anthropic-messages\", baseUrl: \"https://ai-gateway.vercel.sh\", provider: \"vercel-ai-gateway\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.2, output: 4, cacheRead: 0.24, cacheWrite: 0 }, contextWindow: 2e5, maxTokens: 128e3 } } };\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/vercel-ai-gateway.models.js\nvar VERCEL_AI_GATEWAY_MODELS = flattenModelCatalog(\"vercel-ai-gateway\", vercel_ai_gateway_default);\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/data/xai.json\nvar xai_default = { \"openai-completions\": { \"grok-4.3\": { id: \"grok-4.3\", name: \"Grok 4.3\", api: \"openai-completions\", provider: \"xai\", baseUrl: \"https://api.x.ai/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1.25, output: 2.5, cacheRead: 0.2, cacheWrite: 0 }, contextWindow: 1e6, maxTokens: 3e4, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false } }, \"grok-4.6\": { id: \"grok-4.6\", name: \"Grok 4.6\", api: \"openai-completions\", provider: \"xai\", baseUrl: \"https://api.x.ai/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 2, output: 6, cacheRead: 0.5, cacheWrite: 0 }, contextWindow: 5e5, maxTokens: 5e5, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false } }, \"grok-build-0.1\": { id: \"grok-build-0.1\", name: \"Grok Build 0.1\", api: \"openai-completions\", provider: \"xai\", baseUrl: \"https://api.x.ai/v1\", reasoning: true, input: [\"text\", \"image\"], cost: { input: 1, output: 2, cacheRead: 0.2, cacheWrite: 0 }, contextWindow: 256e3, maxTokens: 256e3, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false } } }, \"openai-responses\": { \"grok-4.5\": { id: \"grok-4.5\", name: \"Grok 4.5\", api: \"openai-responses\", provider: \"xai\", baseUrl: \"https://api.x.ai/v1\", compat: { supportsLongCacheRetention: false }, reasoning: true, input: [\"text\", \"image\"], cost: { input: 2, output: 6, cacheRead: 0.3, cacheWrite: 0 }, contextWindow: 5e5, maxTokens: 5e5, thinkingLevelMap: { off: null, minimal: null, low: \"low\", medium: \"medium\", high: \"high\", xhigh: null, max: null } } } };\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/xai.models.js\nvar XAI_MODELS = flattenModelCatalog(\"xai\", xai_default);\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/data/xiaomi.json\nvar xiaomi_default = { \"openai-completions\": { \"mimo-v2-flash\": { id: \"mimo-v2-flash\", name: \"MiMo-V2-Flash\", api: \"openai-completions\", provider: \"xiaomi\", baseUrl: \"https://api.xiaomimimo.com/v1\", compat: { requiresReasoningContentOnAssistantMessages: true, thinkingFormat: \"deepseek\" }, reasoning: true, input: [\"text\"], cost: { input: 0.14, output: 0.28, cacheRead: 28e-4, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 65536 }, \"mimo-v2-omni\": { id: \"mimo-v2-omni\", name: \"MiMo-V2-Omni\", api: \"openai-completions\", provider: \"xiaomi\", baseUrl: \"https://api.xiaomimimo.com/v1\", compat: { requiresReasoningContentOnAssistantMessages: true, thinkingFormat: \"deepseek\" }, reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.14, output: 0.28, cacheRead: 28e-4, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 131072 }, \"mimo-v2-pro\": { id: \"mimo-v2-pro\", name: \"MiMo-V2-Pro\", api: \"openai-completions\", provider: \"xiaomi\", baseUrl: \"https://api.xiaomimimo.com/v1\", compat: { requiresReasoningContentOnAssistantMessages: true, thinkingFormat: \"deepseek\" }, reasoning: true, input: [\"text\"], cost: { input: 0.435, output: 0.87, cacheRead: 36e-4, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 131072 }, \"mimo-v2.5\": { id: \"mimo-v2.5\", name: \"MiMo-V2.5\", api: \"openai-completions\", provider: \"xiaomi\", baseUrl: \"https://api.xiaomimimo.com/v1\", compat: { requiresReasoningContentOnAssistantMessages: true, thinkingFormat: \"deepseek\" }, reasoning: true, input: [\"text\", \"image\"], cost: { input: 0.14, output: 0.28, cacheRead: 28e-4, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 131072 }, \"mimo-v2.5-pro\": { id: \"mimo-v2.5-pro\", name: \"MiMo-V2.5-Pro\", api: \"openai-completions\", provider: \"xiaomi\", baseUrl: \"https://api.xiaomimimo.com/v1\", compat: { requiresReasoningContentOnAssistantMessages: true, thinkingFormat: \"deepseek\" }, reasoning: true, input: [\"text\"], cost: { input: 0.435, output: 0.87, cacheRead: 36e-4, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 131072 }, \"mimo-v2.5-pro-ultraspeed\": { id: \"mimo-v2.5-pro-ultraspeed\", name: \"MiMo-V2.5-Pro-UltraSpeed\", api: \"openai-completions\", provider: \"xiaomi\", baseUrl: \"https://api.xiaomimimo.com/v1\", compat: { requiresReasoningContentOnAssistantMessages: true, thinkingFormat: \"deepseek\" }, reasoning: true, input: [\"text\"], cost: { input: 1.305, output: 2.61, cacheRead: 0.0108, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 131072 } } };\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/xiaomi.models.js\nvar XIAOMI_MODELS = flattenModelCatalog(\"xiaomi\", xiaomi_default);\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/data/xiaomi-token-plan-ams.json\nvar xiaomi_token_plan_ams_default = { \"openai-completions\": { \"mimo-v2-pro\": { id: \"mimo-v2-pro\", name: \"MiMo-V2-Pro\", api: \"openai-completions\", provider: \"xiaomi-token-plan-ams\", baseUrl: \"https://token-plan-ams.xiaomimimo.com/v1\", compat: { requiresReasoningContentOnAssistantMessages: true, thinkingFormat: \"deepseek\" }, reasoning: true, input: [\"text\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 131072 }, \"mimo-v2.5\": { id: \"mimo-v2.5\", name: \"MiMo-V2.5\", api: \"openai-completions\", provider: \"xiaomi-token-plan-ams\", baseUrl: \"https://token-plan-ams.xiaomimimo.com/v1\", compat: { requiresReasoningContentOnAssistantMessages: true, thinkingFormat: \"deepseek\" }, reasoning: true, input: [\"text\", \"image\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 131072 }, \"mimo-v2.5-pro\": { id: \"mimo-v2.5-pro\", name: \"MiMo-V2.5-Pro\", api: \"openai-completions\", provider: \"xiaomi-token-plan-ams\", baseUrl: \"https://token-plan-ams.xiaomimimo.com/v1\", compat: { requiresReasoningContentOnAssistantMessages: true, thinkingFormat: \"deepseek\" }, reasoning: true, input: [\"text\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 131072 } } };\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/xiaomi-token-plan-ams.models.js\nvar XIAOMI_TOKEN_PLAN_AMS_MODELS = flattenModelCatalog(\"xiaomi-token-plan-ams\", xiaomi_token_plan_ams_default);\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/data/xiaomi-token-plan-cn.json\nvar xiaomi_token_plan_cn_default = { \"openai-completions\": { \"mimo-v2-pro\": { id: \"mimo-v2-pro\", name: \"MiMo-V2-Pro\", api: \"openai-completions\", provider: \"xiaomi-token-plan-cn\", baseUrl: \"https://token-plan-cn.xiaomimimo.com/v1\", compat: { requiresReasoningContentOnAssistantMessages: true, thinkingFormat: \"deepseek\" }, reasoning: true, input: [\"text\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 131072 }, \"mimo-v2.5\": { id: \"mimo-v2.5\", name: \"MiMo-V2.5\", api: \"openai-completions\", provider: \"xiaomi-token-plan-cn\", baseUrl: \"https://token-plan-cn.xiaomimimo.com/v1\", compat: { requiresReasoningContentOnAssistantMessages: true, thinkingFormat: \"deepseek\" }, reasoning: true, input: [\"text\", \"image\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 131072 }, \"mimo-v2.5-pro\": { id: \"mimo-v2.5-pro\", name: \"MiMo-V2.5-Pro\", api: \"openai-completions\", provider: \"xiaomi-token-plan-cn\", baseUrl: \"https://token-plan-cn.xiaomimimo.com/v1\", compat: { requiresReasoningContentOnAssistantMessages: true, thinkingFormat: \"deepseek\" }, reasoning: true, input: [\"text\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 131072 } } };\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/xiaomi-token-plan-cn.models.js\nvar XIAOMI_TOKEN_PLAN_CN_MODELS = flattenModelCatalog(\"xiaomi-token-plan-cn\", xiaomi_token_plan_cn_default);\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/data/xiaomi-token-plan-sgp.json\nvar xiaomi_token_plan_sgp_default = { \"openai-completions\": { \"mimo-v2-pro\": { id: \"mimo-v2-pro\", name: \"MiMo-V2-Pro\", api: \"openai-completions\", provider: \"xiaomi-token-plan-sgp\", baseUrl: \"https://token-plan-sgp.xiaomimimo.com/v1\", compat: { requiresReasoningContentOnAssistantMessages: true, thinkingFormat: \"deepseek\" }, reasoning: true, input: [\"text\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 131072 }, \"mimo-v2.5\": { id: \"mimo-v2.5\", name: \"MiMo-V2.5\", api: \"openai-completions\", provider: \"xiaomi-token-plan-sgp\", baseUrl: \"https://token-plan-sgp.xiaomimimo.com/v1\", compat: { requiresReasoningContentOnAssistantMessages: true, thinkingFormat: \"deepseek\" }, reasoning: true, input: [\"text\", \"image\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 131072 }, \"mimo-v2.5-pro\": { id: \"mimo-v2.5-pro\", name: \"MiMo-V2.5-Pro\", api: \"openai-completions\", provider: \"xiaomi-token-plan-sgp\", baseUrl: \"https://token-plan-sgp.xiaomimimo.com/v1\", compat: { requiresReasoningContentOnAssistantMessages: true, thinkingFormat: \"deepseek\" }, reasoning: true, input: [\"text\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 131072 } } };\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/xiaomi-token-plan-sgp.models.js\nvar XIAOMI_TOKEN_PLAN_SGP_MODELS = flattenModelCatalog(\"xiaomi-token-plan-sgp\", xiaomi_token_plan_sgp_default);\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/data/zai.json\nvar zai_default = { \"openai-completions\": { \"glm-4.7\": { id: \"glm-4.7\", name: \"GLM-4.7\", api: \"openai-completions\", provider: \"zai\", baseUrl: \"https://api.z.ai/api/coding/paas/v4\", reasoning: true, input: [\"text\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false, maxTokensField: \"max_tokens\", thinkingFormat: \"zai\", zaiToolStream: true }, contextWindow: 204800, maxTokens: 131072 }, \"glm-5-turbo\": { id: \"glm-5-turbo\", name: \"GLM-5-Turbo\", api: \"openai-completions\", provider: \"zai\", baseUrl: \"https://api.z.ai/api/coding/paas/v4\", reasoning: true, input: [\"text\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false, maxTokensField: \"max_tokens\", thinkingFormat: \"zai\", zaiToolStream: true }, contextWindow: 2e5, maxTokens: 131072 }, \"glm-5.2\": { id: \"glm-5.2\", name: \"GLM-5.2\", api: \"openai-completions\", provider: \"zai\", baseUrl: \"https://api.z.ai/api/coding/paas/v4\", reasoning: true, thinkingLevelMap: { minimal: null, low: \"high\", medium: \"high\", high: \"high\", max: \"max\" }, input: [\"text\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: true, maxTokensField: \"max_tokens\", thinkingFormat: \"zai\", zaiToolStream: true }, contextWindow: 1e6, maxTokens: 131072 }, \"glm-5.2-highspeed\": { id: \"glm-5.2-highspeed\", name: \"GLM-5.2 Highspeed\", api: \"openai-completions\", provider: \"zai\", baseUrl: \"https://api.z.ai/api/coding/paas/v4\", reasoning: true, input: [\"text\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false, maxTokensField: \"max_tokens\", thinkingFormat: \"zai\", zaiToolStream: true }, contextWindow: 1e6, maxTokens: 131072 }, \"glm-5.3\": { id: \"glm-5.3\", name: \"GLM-5.3\", api: \"openai-completions\", provider: \"zai\", baseUrl: \"https://api.z.ai/api/coding/paas/v4\", reasoning: true, input: [\"text\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false, maxTokensField: \"max_tokens\", thinkingFormat: \"zai\", zaiToolStream: true }, contextWindow: 1e6, maxTokens: 131072 } } };\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/zai.models.js\nvar ZAI_MODELS = flattenModelCatalog(\"zai\", zai_default);\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/data/zai-coding-cn.json\nvar zai_coding_cn_default = { \"openai-completions\": { \"glm-4.7\": { id: \"glm-4.7\", name: \"GLM-4.7\", api: \"openai-completions\", provider: \"zai-coding-cn\", baseUrl: \"https://open.bigmodel.cn/api/coding/paas/v4\", reasoning: true, input: [\"text\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false, maxTokensField: \"max_tokens\", thinkingFormat: \"zai\", zaiToolStream: true }, contextWindow: 204800, maxTokens: 131072 }, \"glm-5-turbo\": { id: \"glm-5-turbo\", name: \"GLM-5-Turbo\", api: \"openai-completions\", provider: \"zai-coding-cn\", baseUrl: \"https://open.bigmodel.cn/api/coding/paas/v4\", reasoning: true, input: [\"text\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false, maxTokensField: \"max_tokens\", thinkingFormat: \"zai\", zaiToolStream: true }, contextWindow: 2e5, maxTokens: 131072 }, \"glm-5.2\": { id: \"glm-5.2\", name: \"GLM-5.2\", api: \"openai-completions\", provider: \"zai-coding-cn\", baseUrl: \"https://open.bigmodel.cn/api/coding/paas/v4\", reasoning: true, thinkingLevelMap: { minimal: null, low: \"high\", medium: \"high\", high: \"high\", max: \"max\" }, input: [\"text\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: true, maxTokensField: \"max_tokens\", thinkingFormat: \"zai\", zaiToolStream: true }, contextWindow: 1e6, maxTokens: 131072 }, \"glm-5.2-highspeed\": { id: \"glm-5.2-highspeed\", name: \"GLM-5.2 Highspeed\", api: \"openai-completions\", provider: \"zai-coding-cn\", baseUrl: \"https://open.bigmodel.cn/api/coding/paas/v4\", reasoning: true, input: [\"text\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false, maxTokensField: \"max_tokens\", thinkingFormat: \"zai\", zaiToolStream: true }, contextWindow: 1e6, maxTokens: 131072 }, \"glm-5.3\": { id: \"glm-5.3\", name: \"GLM-5.3\", api: \"openai-completions\", provider: \"zai-coding-cn\", baseUrl: \"https://open.bigmodel.cn/api/coding/paas/v4\", reasoning: true, input: [\"text\"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false, maxTokensField: \"max_tokens\", thinkingFormat: \"zai\", zaiToolStream: true }, contextWindow: 1e6, maxTokens: 131072 } } };\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/zai-coding-cn.models.js\nvar ZAI_CODING_CN_MODELS = flattenModelCatalog(\"zai-coding-cn\", zai_coding_cn_default);\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/models.generated.js\nvar MODELS = {\n  \"amazon-bedrock\": AMAZON_BEDROCK_MODELS,\n  \"ant-ling\": ANT_LING_MODELS,\n  \"anthropic\": ANTHROPIC_MODELS,\n  \"azure-openai-responses\": AZURE_OPENAI_RESPONSES_MODELS,\n  \"baseten\": BASETEN_MODELS,\n  \"cerebras\": CEREBRAS_MODELS,\n  \"cloudflare-ai-gateway\": CLOUDFLARE_AI_GATEWAY_MODELS,\n  \"cloudflare-workers-ai\": CLOUDFLARE_WORKERS_AI_MODELS,\n  \"deepseek\": DEEPSEEK_MODELS,\n  \"fireworks\": FIREWORKS_MODELS,\n  \"github-copilot\": GITHUB_COPILOT_MODELS,\n  \"google\": GOOGLE_MODELS,\n  \"google-vertex\": GOOGLE_VERTEX_MODELS,\n  \"groq\": GROQ_MODELS,\n  \"huggingface\": HUGGINGFACE_MODELS,\n  \"kimi-coding\": KIMI_CODING_MODELS,\n  \"minimax\": MINIMAX_MODELS,\n  \"minimax-cn\": MINIMAX_CN_MODELS,\n  \"mistral\": MISTRAL_MODELS,\n  \"moonshotai\": MOONSHOTAI_MODELS,\n  \"moonshotai-cn\": MOONSHOTAI_CN_MODELS,\n  \"nvidia\": NVIDIA_MODELS,\n  \"openai\": OPENAI_MODELS,\n  \"openai-codex\": OPENAI_CODEX_MODELS,\n  \"opencode\": OPENCODE_MODELS,\n  \"opencode-go\": OPENCODE_GO_MODELS,\n  \"openrouter\": OPENROUTER_MODELS,\n  \"qwen-token-plan\": QWEN_TOKEN_PLAN_MODELS,\n  \"qwen-token-plan-cn\": QWEN_TOKEN_PLAN_CN_MODELS,\n  \"qwen-token-plan-individual\": QWEN_TOKEN_PLAN_INDIVIDUAL_MODELS,\n  \"together\": TOGETHER_MODELS,\n  \"vercel-ai-gateway\": VERCEL_AI_GATEWAY_MODELS,\n  \"xai\": XAI_MODELS,\n  \"xiaomi\": XIAOMI_MODELS,\n  \"xiaomi-token-plan-ams\": XIAOMI_TOKEN_PLAN_AMS_MODELS,\n  \"xiaomi-token-plan-cn\": XIAOMI_TOKEN_PLAN_CN_MODELS,\n  \"xiaomi-token-plan-sgp\": XIAOMI_TOKEN_PLAN_SGP_MODELS,\n  \"zai\": ZAI_MODELS,\n  \"zai-coding-cn\": ZAI_CODING_CN_MODELS\n};\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/all.js\ninit_models();\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/api/bedrock-converse-stream.lazy.js\ninit_lazy();\nvar __rewriteRelativeImportExtension2 = function(path12, preserveJsx) {\n  if (typeof path12 === \"string\" && /^\\.\\.?\\//.test(path12)) {\n    return path12.replace(/\\.(tsx)$|((?:\\.d)?)((?:\\.[^./]+?)?)\\.([cm]?)ts$/i, function(m, tsx, d, ext, cm) {\n      return tsx ? preserveJsx ? \".jsx\" : \".js\" : d && (!ext || !cm) ? m : d + ext + \".\" + cm.toLowerCase() + \"js\";\n    });\n  }\n  return path12;\n};\nvar importNodeOnlyApi = (specifier) => {\n  const runtimeSpecifier = import.meta.url.endsWith(\".js\") ? specifier.replace(/\\.ts$/, \".js\") : specifier;\n  return import(__rewriteRelativeImportExtension2(runtimeSpecifier));\n};\nvar bedrockModuleOverride;\nfunction setBedrockProviderModule(module) {\n  bedrockModuleOverride = module;\n}\nvar bedrockConverseStreamApi = () => lazyApi(async () => bedrockModuleOverride ?? await importNodeOnlyApi(\"./bedrock-converse-stream.ts\"));\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/amazon-bedrock.js\ninit_models();\nvar bedrockAuth = {\n  name: \"AWS credentials or bearer token\",\n  login: async (interaction) => {\n    interaction.signal.throwIfAborted();\n    const method = await interaction.prompt({\n      type: \"select\",\n      message: \"Select Amazon Bedrock authentication method:\",\n      options: [\n        { id: \"bearer-token\", label: \"Bearer token\" },\n        { id: \"aws-profile\", label: \"AWS profile\" },\n        { id: \"credential-chain\", label: \"Existing AWS credential chain\" }\n      ]\n    });\n    interaction.signal.throwIfAborted();\n    if (method === \"bearer-token\") {\n      return {\n        type: \"api_key\",\n        key: await interaction.prompt({ type: \"secret\", message: \"Enter Amazon Bedrock bearer token\" })\n      };\n    }\n    interaction.notify({\n      type: \"info\",\n      message: \"Amazon Bedrock supports AWS profiles, IAM credentials, and role-based credentials.\",\n      links: [\n        {\n          label: \"AWS credential provider chain\",\n          url: \"https://docs.aws.amazon.com/sdkref/latest/guide/standardized-credentials.html\"\n        }\n      ]\n    });\n    if (method === \"aws-profile\") {\n      return {\n        type: \"api_key\",\n        env: { AWS_PROFILE: await interaction.prompt({ type: \"text\", message: \"Enter AWS profile name\" }) }\n      };\n    }\n    if (method !== \"credential-chain\")\n      throw new Error(`Unknown Amazon Bedrock auth method: ${method}`);\n    await interaction.prompt({\n      type: \"text\",\n      message: \"Configure AWS credentials, then press Enter to continue\"\n    });\n    return { type: \"api_key\" };\n  },\n  resolve: async ({ ctx, credential, signal }) => {\n    const env = async (name) => {\n      signal.throwIfAborted();\n      const value = await ctx.env(name);\n      signal.throwIfAborted();\n      return value;\n    };\n    if (credential?.key) {\n      return { auth: { apiKey: credential.key }, env: credential.env, source: \"stored credential\" };\n    }\n    if (await env(\"AWS_BEARER_TOKEN_BEDROCK\"))\n      return { auth: {}, source: \"AWS_BEARER_TOKEN_BEDROCK\" };\n    if (credential?.env?.AWS_PROFILE ?? await env(\"AWS_PROFILE\")) {\n      return {\n        auth: {},\n        env: credential?.env,\n        source: credential?.env?.AWS_PROFILE ? \"stored credential\" : \"AWS_PROFILE\"\n      };\n    }\n    if (await env(\"AWS_ACCESS_KEY_ID\") && await env(\"AWS_SECRET_ACCESS_KEY\")) {\n      return { auth: {}, source: \"AWS access keys\" };\n    }\n    if (await env(\"AWS_CONTAINER_CREDENTIALS_RELATIVE_URI\"))\n      return { auth: {}, source: \"ECS task role\" };\n    if (await env(\"AWS_CONTAINER_CREDENTIALS_FULL_URI\"))\n      return { auth: {}, source: \"ECS task role\" };\n    if (await env(\"AWS_WEB_IDENTITY_TOKEN_FILE\"))\n      return { auth: {}, source: \"web identity token\" };\n    return void 0;\n  }\n};\nfunction amazonBedrockProvider() {\n  return createProvider({\n    id: \"amazon-bedrock\",\n    name: \"Amazon Bedrock\",\n    auth: { apiKey: bedrockAuth },\n    models: Object.values(AMAZON_BEDROCK_MODELS),\n    api: bedrockConverseStreamApi()\n  });\n}\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/api/openai-completions.lazy.js\ninit_lazy();\nvar openAICompletionsApi = () => lazyApi(() => Promise.resolve().then(() => (init_openai_completions(), openai_completions_exports)));\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/ant-ling.js\ninit_models();\nfunction antLingProvider() {\n  return createProvider({\n    id: \"ant-ling\",\n    name: \"Ant Ling\",\n    baseUrl: \"https://api.ant-ling.com/v1\",\n    auth: { apiKey: envApiKeyAuth(\"Ant Ling API key\", [\"ANT_LING_API_KEY\"]) },\n    models: Object.values(ANT_LING_MODELS),\n    api: openAICompletionsApi()\n  });\n}\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/api/anthropic-messages.lazy.js\ninit_lazy();\nvar anthropicMessagesApi = () => lazyApi(() => Promise.resolve().then(() => (init_anthropic_messages(), anthropic_messages_exports)));\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/auth/oauth/load.js\nvar __rewriteRelativeImportExtension3 = function(path12, preserveJsx) {\n  if (typeof path12 === \"string\" && /^\\.\\.?\\//.test(path12)) {\n    return path12.replace(/\\.(tsx)$|((?:\\.d)?)((?:\\.[^./]+?)?)\\.([cm]?)ts$/i, function(m, tsx, d, ext, cm) {\n      return tsx ? preserveJsx ? \".jsx\" : \".js\" : d && (!ext || !cm) ? m : d + ext + \".\" + cm.toLowerCase() + \"js\";\n    });\n  }\n  return path12;\n};\nvar importOAuthModule = (specifier) => {\n  const runtimeSpecifier = import.meta.url.endsWith(\".js\") ? specifier.replace(/\\.ts$/, \".js\") : specifier;\n  return import(__rewriteRelativeImportExtension3(runtimeSpecifier));\n};\nvar bundledLoaders;\nvar loadAnthropicOAuth = async () => {\n  if (bundledLoaders)\n    return bundledLoaders.anthropic();\n  return (await importOAuthModule(\"./anthropic.ts\")).anthropicOAuth;\n};\nvar loadOpenAICodexOAuth = async () => {\n  if (bundledLoaders)\n    return bundledLoaders.openaiCodex();\n  return (await importOAuthModule(\"./openai-codex.ts\")).openaiCodexOAuth;\n};\nvar loadGitHubCopilotOAuth = async () => {\n  if (bundledLoaders)\n    return bundledLoaders.githubCopilot();\n  return (await importOAuthModule(\"./github-copilot.ts\")).githubCopilotOAuth;\n};\nvar loadOpenRouterOAuth = async () => {\n  if (bundledLoaders)\n    return bundledLoaders.openrouter();\n  return (await importOAuthModule(\"./openrouter.ts\")).openRouterOAuth;\n};\nvar loadKimiCodingOAuth = async () => {\n  if (bundledLoaders)\n    return bundledLoaders.kimiCoding();\n  return (await importOAuthModule(\"./kimi-coding.ts\")).kimiCodingOAuth;\n};\nvar loadXaiOAuth = async () => {\n  if (bundledLoaders)\n    return bundledLoaders.xai();\n  return (await importOAuthModule(\"./xai.ts\")).xaiOAuth;\n};\nvar loadRadiusOAuth = async (options) => {\n  if (bundledLoaders)\n    return bundledLoaders.radius(options);\n  return (await importOAuthModule(\"./radius.ts\")).createRadiusOAuth(options);\n};\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/env-api-keys.js\ninit_provider_env();\nvar __rewriteRelativeImportExtension4 = function(path12, preserveJsx) {\n  if (typeof path12 === \"string\" && /^\\.\\.?\\//.test(path12)) {\n    return path12.replace(/\\.(tsx)$|((?:\\.d)?)((?:\\.[^./]+?)?)\\.([cm]?)ts$/i, function(m, tsx, d, ext, cm) {\n      return tsx ? preserveJsx ? \".jsx\" : \".js\" : d && (!ext || !cm) ? m : d + ext + \".\" + cm.toLowerCase() + \"js\";\n    });\n  }\n  return path12;\n};\nvar _existsSync = null;\nvar _homedir = null;\nvar _join = null;\nvar dynamicImport = (specifier) => import(__rewriteRelativeImportExtension4(specifier));\nvar NODE_FS_SPECIFIER = \"node:fs\";\nvar NODE_OS_SPECIFIER = \"node:os\";\nvar NODE_PATH_SPECIFIER = \"node:path\";\nif (typeof process !== \"undefined\" && (process.versions?.node || process.versions?.bun)) {\n  dynamicImport(NODE_FS_SPECIFIER).then((m) => {\n    _existsSync = m.existsSync;\n  });\n  dynamicImport(NODE_OS_SPECIFIER).then((m) => {\n    _homedir = m.homedir;\n  });\n  dynamicImport(NODE_PATH_SPECIFIER).then((m) => {\n    _join = m.join;\n  });\n}\nvar ANTHROPIC_AUTH_TOKEN_ENV = \"ANTHROPIC_AUTH_TOKEN\";\nvar ANTHROPIC_OAUTH_TOKEN_ENV = \"ANTHROPIC_OAUTH_TOKEN\";\nvar ANTHROPIC_API_KEY_ENV = \"ANTHROPIC_API_KEY\";\nvar cachedVertexAdcCredentialsExists = null;\nfunction hasVertexAdcCredentials(env) {\n  const explicitCredentialsPath = env?.GOOGLE_APPLICATION_CREDENTIALS;\n  if (explicitCredentialsPath) {\n    return _existsSync ? _existsSync(explicitCredentialsPath) : false;\n  }\n  if (cachedVertexAdcCredentialsExists === null) {\n    if (!_existsSync || !_homedir || !_join) {\n      const isNode = typeof process !== \"undefined\" && (process.versions?.node || process.versions?.bun);\n      if (!isNode) {\n        cachedVertexAdcCredentialsExists = false;\n      }\n      return false;\n    }\n    const gacPath = getProviderEnvValue(\"GOOGLE_APPLICATION_CREDENTIALS\", env);\n    if (gacPath) {\n      cachedVertexAdcCredentialsExists = _existsSync(gacPath);\n    } else {\n      cachedVertexAdcCredentialsExists = _existsSync(_join(_homedir(), \".config\", \"gcloud\", \"application_default_credentials.json\"));\n    }\n  }\n  return cachedVertexAdcCredentialsExists;\n}\nfunction getApiKeyEnvVars(provider) {\n  if (provider === \"github-copilot\") {\n    return [\"COPILOT_GITHUB_TOKEN\"];\n  }\n  if (provider === \"anthropic\") {\n    return [ANTHROPIC_AUTH_TOKEN_ENV, ANTHROPIC_OAUTH_TOKEN_ENV, ANTHROPIC_API_KEY_ENV];\n  }\n  const envMap = {\n    \"ant-ling\": \"ANT_LING_API_KEY\",\n    \"qwen-token-plan\": \"QWEN_TOKEN_PLAN_API_KEY\",\n    \"qwen-token-plan-cn\": \"QWEN_TOKEN_PLAN_CN_API_KEY\",\n    \"qwen-token-plan-individual\": \"QWEN_TOKEN_PLAN_API_KEY\",\n    openai: \"OPENAI_API_KEY\",\n    \"azure-openai-responses\": \"AZURE_OPENAI_API_KEY\",\n    nvidia: \"NVIDIA_API_KEY\",\n    deepseek: \"DEEPSEEK_API_KEY\",\n    google: \"GEMINI_API_KEY\",\n    \"google-vertex\": \"GOOGLE_CLOUD_API_KEY\",\n    groq: \"GROQ_API_KEY\",\n    cerebras: \"CEREBRAS_API_KEY\",\n    xai: \"XAI_API_KEY\",\n    radius: \"RADIUS_API_KEY\",\n    openrouter: \"OPENROUTER_API_KEY\",\n    \"vercel-ai-gateway\": \"AI_GATEWAY_API_KEY\",\n    zai: \"ZAI_API_KEY\",\n    \"zai-coding-cn\": \"ZAI_CODING_CN_API_KEY\",\n    mistral: \"MISTRAL_API_KEY\",\n    minimax: \"MINIMAX_API_KEY\",\n    \"minimax-cn\": \"MINIMAX_CN_API_KEY\",\n    moonshotai: \"MOONSHOT_API_KEY\",\n    \"moonshotai-cn\": \"MOONSHOT_API_KEY\",\n    huggingface: \"HF_TOKEN\",\n    fireworks: \"FIREWORKS_API_KEY\",\n    together: \"TOGETHER_API_KEY\",\n    baseten: \"BASETEN_API_KEY\",\n    opencode: \"OPENCODE_API_KEY\",\n    \"opencode-go\": \"OPENCODE_API_KEY\",\n    \"kimi-coding\": \"KIMI_API_KEY\",\n    \"cloudflare-workers-ai\": \"CLOUDFLARE_API_KEY\",\n    \"cloudflare-ai-gateway\": \"CLOUDFLARE_API_KEY\",\n    xiaomi: \"XIAOMI_API_KEY\",\n    \"xiaomi-token-plan-cn\": \"XIAOMI_TOKEN_PLAN_CN_API_KEY\",\n    \"xiaomi-token-plan-ams\": \"XIAOMI_TOKEN_PLAN_AMS_API_KEY\",\n    \"xiaomi-token-plan-sgp\": \"XIAOMI_TOKEN_PLAN_SGP_API_KEY\"\n  };\n  const envVar = envMap[provider];\n  return envVar ? [envVar] : void 0;\n}\nfunction findEnvKeys(provider, env) {\n  const envVars = getApiKeyEnvVars(provider);\n  if (!envVars)\n    return void 0;\n  const found = envVars.filter((envVar) => !!getProviderEnvValue(envVar, env));\n  return found.length > 0 ? found : void 0;\n}\nfunction getEnvApiKey(provider, env) {\n  const envKeys = findEnvKeys(provider, env);\n  if (envKeys?.[0]) {\n    const apiKeyEnv = provider === \"anthropic\" ? envKeys.find((key) => key !== ANTHROPIC_AUTH_TOKEN_ENV) : envKeys[0];\n    if (apiKeyEnv)\n      return getProviderEnvValue(apiKeyEnv, env);\n  }\n  if (provider === \"google-vertex\") {\n    const hasCredentials = hasVertexAdcCredentials(env);\n    const hasProject = !!(getProviderEnvValue(\"GOOGLE_CLOUD_PROJECT\", env) || getProviderEnvValue(\"GCLOUD_PROJECT\", env));\n    const hasLocation = !!getProviderEnvValue(\"GOOGLE_CLOUD_LOCATION\", env);\n    if (hasCredentials && hasProject && hasLocation) {\n      return \"<authenticated>\";\n    }\n  }\n  if (provider === \"amazon-bedrock\") {\n    if (getProviderEnvValue(\"AWS_PROFILE\", env) || getProviderEnvValue(\"AWS_ACCESS_KEY_ID\", env) && getProviderEnvValue(\"AWS_SECRET_ACCESS_KEY\", env) || getProviderEnvValue(\"AWS_BEARER_TOKEN_BEDROCK\", env) || getProviderEnvValue(\"AWS_CONTAINER_CREDENTIALS_RELATIVE_URI\", env) || getProviderEnvValue(\"AWS_CONTAINER_CREDENTIALS_FULL_URI\", env) || getProviderEnvValue(\"AWS_WEB_IDENTITY_TOKEN_FILE\", env)) {\n      return \"<authenticated>\";\n    }\n  }\n  return void 0;\n}\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/anthropic.js\ninit_models();\nfunction anthropicApiKeyAuth() {\n  return {\n    name: \"Anthropic API key\",\n    login: async (interaction) => {\n      interaction.signal.throwIfAborted();\n      const key = await interaction.prompt({ type: \"secret\", message: \"Enter Anthropic API key\" });\n      interaction.signal.throwIfAborted();\n      return { type: \"api_key\", key };\n    },\n    resolve: async ({ ctx, credential, signal }) => {\n      signal.throwIfAborted();\n      if (credential?.key) {\n        return { auth: { apiKey: credential.key }, env: credential.env, source: \"stored credential\" };\n      }\n      const authToken = await ctx.env(ANTHROPIC_AUTH_TOKEN_ENV);\n      signal.throwIfAborted();\n      if (authToken) {\n        return {\n          auth: { headers: { Authorization: `Bearer ${authToken}` } },\n          source: ANTHROPIC_AUTH_TOKEN_ENV\n        };\n      }\n      for (const envVar of [ANTHROPIC_OAUTH_TOKEN_ENV, ANTHROPIC_API_KEY_ENV]) {\n        const apiKey = await ctx.env(envVar);\n        signal.throwIfAborted();\n        if (apiKey)\n          return { auth: { apiKey }, source: envVar };\n      }\n      return void 0;\n    }\n  };\n}\nfunction anthropicProvider() {\n  return createProvider({\n    id: \"anthropic\",\n    name: \"Anthropic\",\n    baseUrl: \"https://api.anthropic.com\",\n    auth: {\n      apiKey: anthropicApiKeyAuth(),\n      oauth: lazyOAuth({\n        name: \"Anthropic (Claude Pro/Max)\",\n        isSubscription: true,\n        load: loadAnthropicOAuth\n      })\n    },\n    models: Object.values(ANTHROPIC_MODELS),\n    api: anthropicMessagesApi()\n  });\n}\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/api/azure-openai-responses.lazy.js\ninit_lazy();\nvar azureOpenAIResponsesApi = () => lazyApi(() => Promise.resolve().then(() => (init_azure_openai_responses(), azure_openai_responses_exports)));\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/azure-openai-responses.js\ninit_models();\nfunction azureOpenAIResponsesProvider() {\n  return createProvider({\n    id: \"azure-openai-responses\",\n    name: \"Azure OpenAI\",\n    auth: { apiKey: envApiKeyAuth(\"Azure OpenAI API key\", [\"AZURE_OPENAI_API_KEY\"]) },\n    models: Object.values(AZURE_OPENAI_RESPONSES_MODELS),\n    api: azureOpenAIResponsesApi()\n  });\n}\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/baseten.js\ninit_models();\nfunction basetenProvider() {\n  return createProvider({\n    id: \"baseten\",\n    name: \"Baseten\",\n    baseUrl: \"https://inference.baseten.co/v1\",\n    auth: { apiKey: envApiKeyAuth(\"Baseten API key\", [\"BASETEN_API_KEY\"]) },\n    models: Object.values(BASETEN_MODELS),\n    api: openAICompletionsApi()\n  });\n}\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/cerebras.js\ninit_models();\nfunction cerebrasProvider() {\n  return createProvider({\n    id: \"cerebras\",\n    name: \"Cerebras\",\n    baseUrl: \"https://api.cerebras.ai/v1\",\n    auth: { apiKey: envApiKeyAuth(\"Cerebras API key\", [\"CEREBRAS_API_KEY\"]) },\n    models: Object.values(CEREBRAS_MODELS),\n    api: openAICompletionsApi()\n  });\n}\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/api/openai-responses.lazy.js\ninit_lazy();\nvar openAIResponsesApi = () => lazyApi(() => Promise.resolve().then(() => (init_openai_responses(), openai_responses_exports)));\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/cloudflare-ai-gateway.js\ninit_models();\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/cloudflare-auth.js\nvar CLOUDFLARE_API_KEY = \"CLOUDFLARE_API_KEY\";\nvar CLOUDFLARE_ACCOUNT_ID = \"CLOUDFLARE_ACCOUNT_ID\";\nvar CLOUDFLARE_GATEWAY_ID = \"CLOUDFLARE_GATEWAY_ID\";\nasync function resolveValue(name, ctx, credential, signal) {\n  const fromCredential = credential ? name === CLOUDFLARE_API_KEY ? credential.key : credential.env?.[name] : void 0;\n  if (fromCredential !== void 0)\n    return fromCredential;\n  signal.throwIfAborted();\n  const value = await ctx.env(name);\n  signal.throwIfAborted();\n  return value;\n}\nasync function resolveCloudflareEnv(kind, ctx, credential, signal) {\n  const apiKey = await resolveValue(CLOUDFLARE_API_KEY, ctx, credential, signal);\n  const accountId = await resolveValue(CLOUDFLARE_ACCOUNT_ID, ctx, credential, signal);\n  const gatewayId = kind === \"ai-gateway\" ? await resolveValue(CLOUDFLARE_GATEWAY_ID, ctx, credential, signal) : void 0;\n  if (!apiKey || !accountId || kind === \"ai-gateway\" && !gatewayId)\n    return void 0;\n  return {\n    apiKey,\n    env: {\n      CLOUDFLARE_ACCOUNT_ID: accountId,\n      ...gatewayId ? { CLOUDFLARE_GATEWAY_ID: gatewayId } : {}\n    },\n    source: credential ? \"stored credential\" : CLOUDFLARE_API_KEY\n  };\n}\nfunction cloudflareWorkersAIAuth() {\n  return {\n    name: \"Cloudflare API key\",\n    login: async (interaction) => {\n      const key = await interaction.prompt({ type: \"secret\", message: \"Enter Cloudflare API key\" });\n      const accountId = await interaction.prompt({ type: \"text\", message: \"Enter Cloudflare account ID\" });\n      return { type: \"api_key\", key, env: { CLOUDFLARE_ACCOUNT_ID: accountId } };\n    },\n    resolve: async ({ ctx, credential, signal }) => {\n      const resolved = await resolveCloudflareEnv(\"workers-ai\", ctx, credential, signal);\n      if (!resolved)\n        return void 0;\n      return {\n        auth: { apiKey: resolved.apiKey },\n        env: resolved.env,\n        source: resolved.source\n      };\n    }\n  };\n}\nfunction cloudflareAIGatewayAuth() {\n  return {\n    name: \"Cloudflare API key\",\n    login: async (interaction) => {\n      const key = await interaction.prompt({ type: \"secret\", message: \"Enter Cloudflare API key\" });\n      const accountId = await interaction.prompt({ type: \"text\", message: \"Enter Cloudflare account ID\" });\n      const gatewayId = await interaction.prompt({ type: \"text\", message: \"Enter Cloudflare AI Gateway ID\" });\n      return {\n        type: \"api_key\",\n        key,\n        env: { CLOUDFLARE_ACCOUNT_ID: accountId, CLOUDFLARE_GATEWAY_ID: gatewayId }\n      };\n    },\n    resolve: async ({ ctx, credential, signal }) => {\n      const resolved = await resolveCloudflareEnv(\"ai-gateway\", ctx, credential, signal);\n      if (!resolved)\n        return void 0;\n      return {\n        auth: {\n          headers: {\n            \"cf-aig-authorization\": `Bearer ${resolved.apiKey}`,\n            Authorization: null,\n            \"x-api-key\": null\n          }\n        },\n        env: resolved.env,\n        source: resolved.source\n      };\n    }\n  };\n}\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/cloudflare-stream.js\nvar CLOUDFLARE_ACCOUNT_ID2 = \"CLOUDFLARE_ACCOUNT_ID\";\nvar CLOUDFLARE_GATEWAY_ID2 = \"CLOUDFLARE_GATEWAY_ID\";\nfunction resolveCloudflareModel(model, env) {\n  if (!env)\n    return model;\n  const baseUrl = model.baseUrl.replaceAll(`{${CLOUDFLARE_ACCOUNT_ID2}}`, env[CLOUDFLARE_ACCOUNT_ID2] ?? `{${CLOUDFLARE_ACCOUNT_ID2}}`).replaceAll(`{${CLOUDFLARE_GATEWAY_ID2}}`, env[CLOUDFLARE_GATEWAY_ID2] ?? `{${CLOUDFLARE_GATEWAY_ID2}}`);\n  return baseUrl === model.baseUrl ? model : { ...model, baseUrl };\n}\nfunction cloudflareStreams(streams) {\n  return {\n    stream: (model, context, options) => streams.stream(resolveCloudflareModel(model, options?.env), context, options),\n    streamSimple: (model, context, options) => streams.streamSimple(resolveCloudflareModel(model, options?.env), context, options)\n  };\n}\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/cloudflare-ai-gateway.js\nfunction cloudflareAIGatewayProvider() {\n  return createProvider({\n    id: \"cloudflare-ai-gateway\",\n    name: \"Cloudflare AI Gateway\",\n    auth: { apiKey: cloudflareAIGatewayAuth() },\n    models: Object.values(CLOUDFLARE_AI_GATEWAY_MODELS),\n    api: {\n      \"anthropic-messages\": cloudflareStreams(anthropicMessagesApi()),\n      \"openai-completions\": cloudflareStreams(openAICompletionsApi()),\n      \"openai-responses\": cloudflareStreams(openAIResponsesApi())\n    }\n  });\n}\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/cloudflare-workers-ai.js\ninit_models();\nfunction cloudflareWorkersAIProvider() {\n  return createProvider({\n    id: \"cloudflare-workers-ai\",\n    name: \"Cloudflare Workers AI\",\n    auth: { apiKey: cloudflareWorkersAIAuth() },\n    models: Object.values(CLOUDFLARE_WORKERS_AI_MODELS),\n    api: cloudflareStreams(openAICompletionsApi())\n  });\n}\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/data/.manifest.json\nvar manifest_default = { schemaVersion: 3, generatedAt: \"2026-08-14T10:02:30.583Z\", structureHash: \"012f19b2e2c92706bc700f4c9dd80a21f1f43d68959bc90c78d2cdb51374d5cc\", files: { \"amazon-bedrock.json\": \"7285f05ca2975d20342ce76957c4d7faf226f6a9ebda4625998c9aa59d5d0855\", \"ant-ling.json\": \"4979fe79d99ed97382d7ce40170c6132e932e77906de1eb54464c042e7d63633\", \"anthropic.json\": \"e22c277e3a1ffddc3d2701b72787c9e0bd67b835de6b4cb806677b6b6a89a2f7\", \"azure-openai-responses.json\": \"5315b6a2299fefbdbb6cc13a720544077c9498132ad5e3a7d76a8c1daa8e9335\", \"baseten.json\": \"cbf1233893814cf4bd6d874ec854e5f6a6d531c251f916f2b2e5744d771ef48b\", \"cerebras.json\": \"3fd3e19b83ab4be07d27817e25e5be0ffe4158b1394f0311d6a22d9f03847728\", \"cloudflare-ai-gateway.json\": \"84923bf578efeff444187ec557dd17c79328b60d72d302e05f104799b31a48f8\", \"cloudflare-workers-ai.json\": \"e3dd801884fc61e99b2148aa456974335fe25c040c6428f569b83738a594e4b4\", \"deepseek.json\": \"e3106724723fd82d48a3ff685da9908a3a7b7b4fd84cc3cfe97a6a23067b6029\", \"fireworks.json\": \"2c85d89cd04288b15ff8a23af5eba72779cae9221f4bcfed1720ce6d41629fcc\", \"github-copilot.json\": \"ccaac3191493c147327fbc7dafe801d921574e855f53073a27b5e7d113575b5e\", \"google-vertex.json\": \"1f2fb67e61815616f5a243912622b373cb61fe1310c63e620c17b8e86899ce18\", \"google.json\": \"c6d9822f7eda23cfeb7d29caee0baa7d2fa7bf3561252734a17428937fbcbfd1\", \"groq.json\": \"f1eb899453e70b5e4479fe6eb78869ee99121fa6d4a019a5a05ab42d2ada8992\", \"huggingface.json\": \"83202359ede3656fd7c956dab0a6742087bc2cc1ebc0cfd4d52b7ed1569237d7\", \"kimi-coding.json\": \"5e28e32e5b16df506a3a1c620ed7870fa7e5e57d8ede4a2aa44dbb24ecf1ba2f\", \"minimax-cn.json\": \"8ccd71ff838f4b78bb88809babb0dc32a4fcfaec2bc4f4083841000428df4f77\", \"minimax.json\": \"253edd4c910a41c8bb252400ba099f3a4de0a8900ce154319288ab091b372987\", \"mistral.json\": \"4f9d84bf1ba10cb14ff2c9e23e77d63441756ef3500375dd4ad10094614b215b\", \"moonshotai-cn.json\": \"1e6146ff3477883636448c0f44222f0a52b3c4562ef8f4eecf7e941cdd59d12e\", \"moonshotai.json\": \"d8d5209873058ddccd37c1f026833e2ea3f9476c3dc9628b4a940d407acc0b2e\", \"nvidia.json\": \"602427f41bc6c23853e329f2eb62c3b054452819115d56db687e559d8938f0ac\", \"openai-codex.json\": \"2712c2924a4a75213dddc743c0e5f08d50a781fe807f16d5afb5fb65b41c64c7\", \"openai.json\": \"47746dfe79d92a7da58d7fae2c02a5d481b2eba2f5a914a42792552940b78b78\", \"opencode-go.json\": \"2981aef88765e8c03d242ccd3f86c6241b0fd1d78cfd27fea17d65eb5b4e5bee\", \"opencode.json\": \"929a6e4c8f71b7f7b59146e1cfd722380f3394f225cacd1344a0fd495b29a11c\", \"openrouter.json\": \"ace0ac8ca6bac4b6f98cf92288e9d0f95dad90ea1e69745b72c57354141c7093\", \"qwen-token-plan-cn.json\": \"bc478981a0786a2c43acffc44846596a8df9c78e583a2348348f6cbf09738b9b\", \"qwen-token-plan-individual.json\": \"0e1578a5c0e11d65644bb42d1d6efee5af97a55a4881d0421ab68bd970d4d4ef\", \"qwen-token-plan.json\": \"3fa3afccf5577c73abeb2e4eccd19f07ad4c59c34299b6d6fc284b77da24cd21\", \"together.json\": \"f8f3f9c49c8ffeb27b57ba547238ffb143a05d727962d016569ff71054314fe1\", \"vercel-ai-gateway.json\": \"b7ded15530dd619677cc34133d6bb725bb3766650a149b42fa43f583aa0c5db3\", \"xai.json\": \"282838b0546d63106c81f1703cdf5ed31ebfe0c5f13a4bec0d590472cbbe03f2\", \"xiaomi-token-plan-ams.json\": \"7ce8ed244672c45737d286ff3ca9c3a2686a5d4b2f0c5f71ab9348c14b14daf3\", \"xiaomi-token-plan-cn.json\": \"684892b5fe6fa371d6040d2011c0fa33facd650d2eaf19f5dbee8efb33016200\", \"xiaomi-token-plan-sgp.json\": \"b19e79b82ac4fdcb080e6d220106797504c885ed70b27fc2b3c1aa4810f32963\", \"xiaomi.json\": \"810368d3828c8bb9498012a0d48639030c0c216b8c13e79da02daa515aa23448\", \"zai-coding-cn.json\": \"663466fef5cca84909b9929671a48fefb3721c0990c61bbec05d8b1692247310\", \"zai.json\": \"fd81b25003c3e653ee319c2ba0ce353a4f02df1a409246c8d0f96d13dd0ec592\" } };\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/deepseek.js\ninit_models();\nfunction deepseekProvider() {\n  return createProvider({\n    id: \"deepseek\",\n    name: \"DeepSeek\",\n    baseUrl: \"https://api.deepseek.com\",\n    auth: { apiKey: envApiKeyAuth(\"DeepSeek API key\", [\"DEEPSEEK_API_KEY\"]) },\n    models: Object.values(DEEPSEEK_MODELS),\n    api: openAICompletionsApi()\n  });\n}\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/fireworks.js\ninit_models();\nfunction fireworksProvider() {\n  return createProvider({\n    id: \"fireworks\",\n    name: \"Fireworks\",\n    baseUrl: \"https://api.fireworks.ai/inference\",\n    auth: { apiKey: envApiKeyAuth(\"Fireworks API key\", [\"FIREWORKS_API_KEY\"]) },\n    models: Object.values(FIREWORKS_MODELS),\n    api: {\n      \"anthropic-messages\": anthropicMessagesApi(),\n      \"openai-completions\": openAICompletionsApi()\n    }\n  });\n}\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/github-copilot.js\ninit_models();\nfunction githubCopilotProvider() {\n  return createProvider({\n    id: \"github-copilot\",\n    name: \"GitHub Copilot\",\n    baseUrl: \"https://api.individual.githubcopilot.com\",\n    auth: {\n      apiKey: envApiKeyAuth(\"GitHub Copilot token\", [\"COPILOT_GITHUB_TOKEN\"]),\n      oauth: lazyOAuth({ name: \"GitHub Copilot\", isSubscription: true, load: loadGitHubCopilotOAuth })\n    },\n    models: Object.values(GITHUB_COPILOT_MODELS),\n    filterModels: (models, credential) => {\n      if (credential?.type !== \"oauth\")\n        return models;\n      const availableModelIds = credential.availableModelIds;\n      if (!Array.isArray(availableModelIds) || !availableModelIds.every((id) => typeof id === \"string\")) {\n        return models;\n      }\n      const available = new Set(availableModelIds);\n      return models.filter((model) => available.has(model.id));\n    },\n    api: {\n      \"anthropic-messages\": anthropicMessagesApi(),\n      \"openai-completions\": openAICompletionsApi(),\n      \"openai-responses\": openAIResponsesApi()\n    }\n  });\n}\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/api/google-generative-ai.lazy.js\ninit_lazy();\nvar googleGenerativeAIApi = () => lazyApi(() => Promise.resolve().then(() => (init_google_generative_ai(), google_generative_ai_exports)));\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/google.js\ninit_models();\nfunction googleProvider() {\n  return createProvider({\n    id: \"google\",\n    name: \"Google\",\n    baseUrl: \"https://generativelanguage.googleapis.com/v1beta\",\n    auth: { apiKey: envApiKeyAuth(\"Gemini API key\", [\"GEMINI_API_KEY\"]) },\n    models: Object.values(GOOGLE_MODELS),\n    api: googleGenerativeAIApi()\n  });\n}\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/api/google-vertex.lazy.js\ninit_lazy();\nvar googleVertexApi = () => lazyApi(() => Promise.resolve().then(() => (init_google_vertex(), google_vertex_exports)));\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/google-vertex.js\ninit_models();\nvar VERTEX_ADC_PATH = \"~/.config/gcloud/application_default_credentials.json\";\nvar vertexAuth = {\n  name: \"Google Cloud credentials\",\n  login: async (interaction) => {\n    interaction.signal.throwIfAborted();\n    const method = await interaction.prompt({\n      type: \"select\",\n      message: \"Select Google Vertex AI authentication method:\",\n      options: [\n        { id: \"api-key\", label: \"Google Cloud API key\" },\n        { id: \"adc\", label: \"Application Default Credentials\" },\n        { id: \"service-account\", label: \"Service account credentials file\" }\n      ]\n    });\n    interaction.signal.throwIfAborted();\n    if (method === \"api-key\") {\n      return {\n        type: \"api_key\",\n        key: await interaction.prompt({ type: \"secret\", message: \"Enter Google Cloud API key\" })\n      };\n    }\n    if (method !== \"adc\" && method !== \"service-account\") {\n      throw new Error(`Unknown Google Vertex AI auth method: ${method}`);\n    }\n    interaction.notify({\n      type: \"info\",\n      message: method === \"adc\" ? \"Run `gcloud auth application-default login`, then provide the project and location.\" : \"Provide a service account credentials file, project, and location.\",\n      links: [\n        {\n          label: \"Application Default Credentials\",\n          url: \"https://cloud.google.com/docs/authentication/provide-credentials-adc\"\n        }\n      ]\n    });\n    const project = await interaction.prompt({ type: \"text\", message: \"Enter Google Cloud project ID\" });\n    const location = await interaction.prompt({ type: \"text\", message: \"Enter Google Cloud location\" });\n    const credentialsPath = method === \"service-account\" ? await interaction.prompt({ type: \"text\", message: \"Enter service account credentials file path\" }) : void 0;\n    return {\n      type: \"api_key\",\n      env: {\n        GOOGLE_CLOUD_PROJECT: project,\n        GOOGLE_CLOUD_LOCATION: location,\n        ...credentialsPath ? { GOOGLE_APPLICATION_CREDENTIALS: credentialsPath } : {}\n      }\n    };\n  },\n  resolve: async ({ ctx, credential, signal }) => {\n    const env = async (name) => {\n      signal.throwIfAborted();\n      const value = await ctx.env(name);\n      signal.throwIfAborted();\n      return value;\n    };\n    const key = credential?.key ?? await env(\"GOOGLE_CLOUD_API_KEY\");\n    if (key)\n      return { auth: { apiKey: key }, source: credential?.key ? \"stored credential\" : \"GOOGLE_CLOUD_API_KEY\" };\n    const adcPath = credential?.env?.GOOGLE_APPLICATION_CREDENTIALS ?? await env(\"GOOGLE_APPLICATION_CREDENTIALS\");\n    signal.throwIfAborted();\n    const hasCredentials = await ctx.fileExists(adcPath ?? VERTEX_ADC_PATH);\n    signal.throwIfAborted();\n    const project = credential?.env?.GOOGLE_CLOUD_PROJECT ?? await env(\"GOOGLE_CLOUD_PROJECT\") ?? await env(\"GCLOUD_PROJECT\");\n    const location = credential?.env?.GOOGLE_CLOUD_LOCATION ?? await env(\"GOOGLE_CLOUD_LOCATION\");\n    if (hasCredentials && project && location) {\n      return {\n        auth: {},\n        env: credential?.env,\n        source: credential ? \"stored credential\" : \"gcloud application default credentials\"\n      };\n    }\n    return void 0;\n  }\n};\nfunction googleVertexProvider() {\n  return createProvider({\n    id: \"google-vertex\",\n    name: \"Google Vertex AI\",\n    auth: { apiKey: vertexAuth },\n    models: Object.values(GOOGLE_VERTEX_MODELS),\n    api: googleVertexApi()\n  });\n}\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/groq.js\ninit_models();\nfunction groqProvider() {\n  return createProvider({\n    id: \"groq\",\n    name: \"Groq\",\n    baseUrl: \"https://api.groq.com/openai/v1\",\n    auth: { apiKey: envApiKeyAuth(\"Groq API key\", [\"GROQ_API_KEY\"]) },\n    models: Object.values(GROQ_MODELS),\n    api: openAICompletionsApi()\n  });\n}\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/huggingface.js\ninit_models();\nfunction huggingfaceProvider() {\n  return createProvider({\n    id: \"huggingface\",\n    name: \"Hugging Face\",\n    baseUrl: \"https://router.huggingface.co/v1\",\n    auth: { apiKey: envApiKeyAuth(\"Hugging Face token\", [\"HF_TOKEN\"]) },\n    models: Object.values(HUGGINGFACE_MODELS),\n    api: openAICompletionsApi()\n  });\n}\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/kimi-coding.js\ninit_models();\nfunction kimiCodingProvider() {\n  return createProvider({\n    id: \"kimi-coding\",\n    name: \"Kimi For Coding\",\n    baseUrl: \"https://api.kimi.com/coding\",\n    auth: {\n      apiKey: envApiKeyAuth(\"Kimi API key\", [\"KIMI_API_KEY\"]),\n      oauth: lazyOAuth({\n        name: \"Kimi Code (subscription)\",\n        isSubscription: true,\n        loginLabel: \"Sign in with Kimi Code\",\n        load: loadKimiCodingOAuth\n      })\n    },\n    models: Object.values(KIMI_CODING_MODELS),\n    api: anthropicMessagesApi()\n  });\n}\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/minimax.js\ninit_models();\nfunction minimaxProvider() {\n  return createProvider({\n    id: \"minimax\",\n    name: \"MiniMax\",\n    baseUrl: \"https://api.minimax.io/anthropic\",\n    auth: { apiKey: envApiKeyAuth(\"MiniMax API key\", [\"MINIMAX_API_KEY\"]) },\n    models: Object.values(MINIMAX_MODELS),\n    api: anthropicMessagesApi()\n  });\n}\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/minimax-cn.js\ninit_models();\nfunction minimaxCnProvider() {\n  return createProvider({\n    id: \"minimax-cn\",\n    name: \"MiniMax CN\",\n    baseUrl: \"https://api.minimaxi.com/anthropic\",\n    auth: { apiKey: envApiKeyAuth(\"MiniMax CN API key\", [\"MINIMAX_CN_API_KEY\"]) },\n    models: Object.values(MINIMAX_CN_MODELS),\n    api: anthropicMessagesApi()\n  });\n}\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/api/mistral-conversations.lazy.js\ninit_lazy();\nvar mistralConversationsApi = () => lazyApi(() => Promise.resolve().then(() => (init_mistral_conversations(), mistral_conversations_exports)));\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/mistral.js\ninit_models();\nfunction mistralProvider() {\n  return createProvider({\n    id: \"mistral\",\n    name: \"Mistral\",\n    baseUrl: \"https://api.mistral.ai\",\n    auth: { apiKey: envApiKeyAuth(\"Mistral API key\", [\"MISTRAL_API_KEY\"]) },\n    models: Object.values(MISTRAL_MODELS),\n    api: mistralConversationsApi()\n  });\n}\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/moonshotai.js\ninit_models();\nfunction moonshotaiProvider() {\n  return createProvider({\n    id: \"moonshotai\",\n    name: \"Moonshot AI\",\n    baseUrl: \"https://api.moonshot.ai/v1\",\n    auth: { apiKey: envApiKeyAuth(\"Moonshot AI API key\", [\"MOONSHOT_API_KEY\"]) },\n    models: Object.values(MOONSHOTAI_MODELS),\n    api: openAICompletionsApi()\n  });\n}\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/moonshotai-cn.js\ninit_models();\nfunction moonshotaiCnProvider() {\n  return createProvider({\n    id: \"moonshotai-cn\",\n    name: \"Moonshot AI CN\",\n    baseUrl: \"https://api.moonshot.cn/v1\",\n    auth: { apiKey: envApiKeyAuth(\"Moonshot AI API key\", [\"MOONSHOT_API_KEY\"]) },\n    models: Object.values(MOONSHOTAI_CN_MODELS),\n    api: openAICompletionsApi()\n  });\n}\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/nvidia.js\ninit_models();\nfunction nvidiaProvider() {\n  return createProvider({\n    id: \"nvidia\",\n    name: \"NVIDIA\",\n    baseUrl: \"https://integrate.api.nvidia.com/v1\",\n    auth: { apiKey: envApiKeyAuth(\"NVIDIA API key\", [\"NVIDIA_API_KEY\"]) },\n    models: Object.values(NVIDIA_MODELS),\n    api: openAICompletionsApi()\n  });\n}\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/openai.js\ninit_models();\nfunction openaiProvider() {\n  return createProvider({\n    id: \"openai\",\n    name: \"OpenAI\",\n    baseUrl: \"https://api.openai.com/v1\",\n    auth: { apiKey: envApiKeyAuth(\"OpenAI API key\", [\"OPENAI_API_KEY\"]) },\n    models: Object.values(OPENAI_MODELS),\n    api: openAIResponsesApi()\n  });\n}\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/api/openai-codex-responses.lazy.js\ninit_lazy();\nvar openAICodexResponsesApi = () => lazyApi(() => Promise.resolve().then(() => (init_openai_codex_responses(), openai_codex_responses_exports)));\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/openai-codex.js\ninit_models();\nfunction openaiCodexProvider() {\n  return createProvider({\n    id: \"openai-codex\",\n    name: \"OpenAI Codex\",\n    baseUrl: \"https://chatgpt.com/backend-api\",\n    auth: {\n      oauth: lazyOAuth({\n        name: \"OpenAI (ChatGPT Plus/Pro)\",\n        isSubscription: true,\n        load: loadOpenAICodexOAuth\n      })\n    },\n    models: Object.values(OPENAI_CODEX_MODELS),\n    api: openAICodexResponsesApi()\n  });\n}\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/opencode.js\ninit_models();\nfunction opencodeProvider() {\n  return createProvider({\n    id: \"opencode\",\n    name: \"OpenCode Zen\",\n    auth: { apiKey: envApiKeyAuth(\"OpenCode API key\", [\"OPENCODE_API_KEY\"]) },\n    models: Object.values(OPENCODE_MODELS),\n    api: {\n      \"anthropic-messages\": anthropicMessagesApi(),\n      \"google-generative-ai\": googleGenerativeAIApi(),\n      \"openai-completions\": openAICompletionsApi(),\n      \"openai-responses\": openAIResponsesApi()\n    }\n  });\n}\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/opencode-go.js\ninit_models();\nfunction opencodeGoProvider() {\n  return createProvider({\n    id: \"opencode-go\",\n    name: \"OpenCode Go\",\n    auth: { apiKey: envApiKeyAuth(\"OpenCode API key\", [\"OPENCODE_API_KEY\"]) },\n    models: Object.values(OPENCODE_GO_MODELS),\n    api: {\n      \"anthropic-messages\": anthropicMessagesApi(),\n      \"openai-completions\": openAICompletionsApi(),\n      \"openai-responses\": openAIResponsesApi()\n    }\n  });\n}\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/openrouter.js\ninit_models();\nfunction openrouterProvider() {\n  return createProvider({\n    id: \"openrouter\",\n    name: \"OpenRouter\",\n    baseUrl: \"https://openrouter.ai/api/v1\",\n    auth: {\n      apiKey: envApiKeyAuth(\"OpenRouter API key\", [\"OPENROUTER_API_KEY\"]),\n      oauth: lazyOAuth({\n        name: \"OpenRouter OAuth\",\n        loginLabel: \"Sign in with OpenRouter\",\n        load: loadOpenRouterOAuth\n      })\n    },\n    models: Object.values(OPENROUTER_MODELS),\n    api: openAICompletionsApi()\n  });\n}\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/api/openrouter-images.lazy.js\nvar openrouterImagesApi = () => ({\n  generateImages: async (model, context, options) => (await Promise.resolve().then(() => (init_openrouter_images(), openrouter_images_exports))).generateImages(model, context, options)\n});\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/image-models.generated.js\nvar IMAGE_MODELS = {\n  openrouter: {\n    \"black-forest-labs/flux.2-flex\": {\n      id: \"black-forest-labs/flux.2-flex\",\n      name: \"Black Forest Labs: FLUX.2 Flex\",\n      api: \"openrouter-images\",\n      provider: \"openrouter\",\n      baseUrl: \"https://openrouter.ai/api/v1\",\n      input: [\"text\", \"image\"],\n      output: [\"image\"],\n      cost: {\n        input: 0,\n        output: 0,\n        cacheRead: 0,\n        cacheWrite: 0\n      }\n    },\n    \"black-forest-labs/flux.2-klein-4b\": {\n      id: \"black-forest-labs/flux.2-klein-4b\",\n      name: \"Black Forest Labs: FLUX.2 Klein 4B\",\n      api: \"openrouter-images\",\n      provider: \"openrouter\",\n      baseUrl: \"https://openrouter.ai/api/v1\",\n      input: [\"text\", \"image\"],\n      output: [\"image\"],\n      cost: {\n        input: 0,\n        output: 0,\n        cacheRead: 0,\n        cacheWrite: 0\n      }\n    },\n    \"black-forest-labs/flux.2-max\": {\n      id: \"black-forest-labs/flux.2-max\",\n      name: \"Black Forest Labs: FLUX.2 Max\",\n      api: \"openrouter-images\",\n      provider: \"openrouter\",\n      baseUrl: \"https://openrouter.ai/api/v1\",\n      input: [\"text\", \"image\"],\n      output: [\"image\"],\n      cost: {\n        input: 0,\n        output: 0,\n        cacheRead: 0,\n        cacheWrite: 0\n      }\n    },\n    \"black-forest-labs/flux.2-pro\": {\n      id: \"black-forest-labs/flux.2-pro\",\n      name: \"Black Forest Labs: FLUX.2 Pro\",\n      api: \"openrouter-images\",\n      provider: \"openrouter\",\n      baseUrl: \"https://openrouter.ai/api/v1\",\n      input: [\"text\", \"image\"],\n      output: [\"image\"],\n      cost: {\n        input: 0,\n        output: 0,\n        cacheRead: 0,\n        cacheWrite: 0\n      }\n    },\n    \"bytedance-seed/seedream-4.5\": {\n      id: \"bytedance-seed/seedream-4.5\",\n      name: \"ByteDance Seed: Seedream 4.5\",\n      api: \"openrouter-images\",\n      provider: \"openrouter\",\n      baseUrl: \"https://openrouter.ai/api/v1\",\n      input: [\"image\", \"text\"],\n      output: [\"image\"],\n      cost: {\n        input: 0,\n        output: 0,\n        cacheRead: 0,\n        cacheWrite: 0\n      }\n    },\n    \"bytedance-seed/seedream-5-0-lite\": {\n      id: \"bytedance-seed/seedream-5-0-lite\",\n      name: \"ByteDance Seed: Seedream 5.0 Lite\",\n      api: \"openrouter-images\",\n      provider: \"openrouter\",\n      baseUrl: \"https://openrouter.ai/api/v1\",\n      input: [\"text\", \"image\"],\n      output: [\"image\"],\n      cost: {\n        input: 0,\n        output: 0,\n        cacheRead: 0,\n        cacheWrite: 0\n      }\n    },\n    \"bytedance-seed/seedream-5-0-pro\": {\n      id: \"bytedance-seed/seedream-5-0-pro\",\n      name: \"ByteDance Seed: Seedream 5.0 Pro\",\n      api: \"openrouter-images\",\n      provider: \"openrouter\",\n      baseUrl: \"https://openrouter.ai/api/v1\",\n      input: [\"text\", \"image\"],\n      output: [\"image\"],\n      cost: {\n        input: 0,\n        output: 0,\n        cacheRead: 0,\n        cacheWrite: 0\n      }\n    },\n    \"google/gemini-2.5-flash-image\": {\n      id: \"google/gemini-2.5-flash-image\",\n      name: \"Google: Nano Banana (Gemini 2.5 Flash Image)\",\n      api: \"openrouter-images\",\n      provider: \"openrouter\",\n      baseUrl: \"https://openrouter.ai/api/v1\",\n      input: [\"image\", \"text\"],\n      output: [\"image\", \"text\"],\n      cost: {\n        input: 0.3,\n        output: 2.5,\n        cacheRead: 0.03,\n        cacheWrite: 0.0833333333333333\n      }\n    },\n    \"google/gemini-3-pro-image\": {\n      id: \"google/gemini-3-pro-image\",\n      name: \"Google: Nano Banana Pro (Gemini 3 Pro Image)\",\n      api: \"openrouter-images\",\n      provider: \"openrouter\",\n      baseUrl: \"https://openrouter.ai/api/v1\",\n      input: [\"image\", \"text\"],\n      output: [\"image\", \"text\"],\n      cost: {\n        input: 2,\n        output: 12,\n        cacheRead: 0.19999999999999998,\n        cacheWrite: 0.375\n      }\n    },\n    \"google/gemini-3-pro-image-preview\": {\n      id: \"google/gemini-3-pro-image-preview\",\n      name: \"Google: Nano Banana Pro (Gemini 3 Pro Image Preview)\",\n      api: \"openrouter-images\",\n      provider: \"openrouter\",\n      baseUrl: \"https://openrouter.ai/api/v1\",\n      input: [\"image\", \"text\"],\n      output: [\"image\", \"text\"],\n      cost: {\n        input: 2,\n        output: 12,\n        cacheRead: 0.19999999999999998,\n        cacheWrite: 0.375\n      }\n    },\n    \"google/gemini-3.1-flash-image\": {\n      id: \"google/gemini-3.1-flash-image\",\n      name: \"Google: Nano Banana 2 (Gemini 3.1 Flash Image)\",\n      api: \"openrouter-images\",\n      provider: \"openrouter\",\n      baseUrl: \"https://openrouter.ai/api/v1\",\n      input: [\"image\", \"text\"],\n      output: [\"image\", \"text\"],\n      cost: {\n        input: 0.5,\n        output: 3,\n        cacheRead: 0,\n        cacheWrite: 0\n      }\n    },\n    \"google/gemini-3.1-flash-image-preview\": {\n      id: \"google/gemini-3.1-flash-image-preview\",\n      name: \"Google: Nano Banana 2 (Gemini 3.1 Flash Image Preview)\",\n      api: \"openrouter-images\",\n      provider: \"openrouter\",\n      baseUrl: \"https://openrouter.ai/api/v1\",\n      input: [\"image\", \"text\"],\n      output: [\"image\", \"text\"],\n      cost: {\n        input: 0.5,\n        output: 3,\n        cacheRead: 0,\n        cacheWrite: 0\n      }\n    },\n    \"google/gemini-3.1-flash-lite-image\": {\n      id: \"google/gemini-3.1-flash-lite-image\",\n      name: \"Google: Nano Banana 2 Lite (Gemini 3.1 Flash Lite Image)\",\n      api: \"openrouter-images\",\n      provider: \"openrouter\",\n      baseUrl: \"https://openrouter.ai/api/v1\",\n      input: [\"image\", \"text\"],\n      output: [\"image\", \"text\"],\n      cost: {\n        input: 0.25,\n        output: 1.5,\n        cacheRead: 0,\n        cacheWrite: 0\n      }\n    },\n    \"krea/krea-2-large\": {\n      id: \"krea/krea-2-large\",\n      name: \"Krea: Krea 2 Large\",\n      api: \"openrouter-images\",\n      provider: \"openrouter\",\n      baseUrl: \"https://openrouter.ai/api/v1\",\n      input: [\"text\", \"image\"],\n      output: [\"image\"],\n      cost: {\n        input: 0,\n        output: 0,\n        cacheRead: 0,\n        cacheWrite: 0\n      }\n    },\n    \"krea/krea-2-medium\": {\n      id: \"krea/krea-2-medium\",\n      name: \"Krea: Krea 2 Medium\",\n      api: \"openrouter-images\",\n      provider: \"openrouter\",\n      baseUrl: \"https://openrouter.ai/api/v1\",\n      input: [\"text\", \"image\"],\n      output: [\"image\"],\n      cost: {\n        input: 0,\n        output: 0,\n        cacheRead: 0,\n        cacheWrite: 0\n      }\n    },\n    \"krea/krea-2-medium-turbo\": {\n      id: \"krea/krea-2-medium-turbo\",\n      name: \"Krea: Krea 2 Medium Turbo\",\n      api: \"openrouter-images\",\n      provider: \"openrouter\",\n      baseUrl: \"https://openrouter.ai/api/v1\",\n      input: [\"text\", \"image\"],\n      output: [\"image\"],\n      cost: {\n        input: 0,\n        output: 0,\n        cacheRead: 0,\n        cacheWrite: 0\n      }\n    },\n    \"microsoft/mai-image-2.5\": {\n      id: \"microsoft/mai-image-2.5\",\n      name: \"Microsoft: MAI-Image-2.5\",\n      api: \"openrouter-images\",\n      provider: \"openrouter\",\n      baseUrl: \"https://openrouter.ai/api/v1\",\n      input: [\"text\", \"image\"],\n      output: [\"image\"],\n      cost: {\n        input: 5,\n        output: 0,\n        cacheRead: 0,\n        cacheWrite: 0\n      }\n    },\n    \"microsoft/mai-image-2.5-pro\": {\n      id: \"microsoft/mai-image-2.5-pro\",\n      name: \"Microsoft: MAI-Image-2.5 Pro\",\n      api: \"openrouter-images\",\n      provider: \"openrouter\",\n      baseUrl: \"https://openrouter.ai/api/v1\",\n      input: [\"text\", \"image\"],\n      output: [\"image\"],\n      cost: {\n        input: 5,\n        output: 0,\n        cacheRead: 0,\n        cacheWrite: 0\n      }\n    },\n    \"openai/gpt-5-image\": {\n      id: \"openai/gpt-5-image\",\n      name: \"OpenAI: GPT-5 Image\",\n      api: \"openrouter-images\",\n      provider: \"openrouter\",\n      baseUrl: \"https://openrouter.ai/api/v1\",\n      input: [\"image\", \"text\"],\n      output: [\"image\", \"text\"],\n      cost: {\n        input: 10,\n        output: 10,\n        cacheRead: 1.25,\n        cacheWrite: 0\n      }\n    },\n    \"openai/gpt-5-image-mini\": {\n      id: \"openai/gpt-5-image-mini\",\n      name: \"OpenAI: GPT-5 Image Mini\",\n      api: \"openrouter-images\",\n      provider: \"openrouter\",\n      baseUrl: \"https://openrouter.ai/api/v1\",\n      input: [\"image\", \"text\"],\n      output: [\"image\", \"text\"],\n      cost: {\n        input: 2.5,\n        output: 2,\n        cacheRead: 0.25,\n        cacheWrite: 0\n      }\n    },\n    \"openai/gpt-5.4-image-2\": {\n      id: \"openai/gpt-5.4-image-2\",\n      name: \"OpenAI: GPT-5.4 Image 2\",\n      api: \"openrouter-images\",\n      provider: \"openrouter\",\n      baseUrl: \"https://openrouter.ai/api/v1\",\n      input: [\"image\", \"text\"],\n      output: [\"image\", \"text\"],\n      cost: {\n        input: 8,\n        output: 15,\n        cacheRead: 2,\n        cacheWrite: 0\n      }\n    },\n    \"openai/gpt-image-1\": {\n      id: \"openai/gpt-image-1\",\n      name: \"OpenAI: GPT Image 1\",\n      api: \"openrouter-images\",\n      provider: \"openrouter\",\n      baseUrl: \"https://openrouter.ai/api/v1\",\n      input: [\"text\", \"image\"],\n      output: [\"image\"],\n      cost: {\n        input: 10,\n        output: 10,\n        cacheRead: 1.25,\n        cacheWrite: 0\n      }\n    },\n    \"openai/gpt-image-1-mini\": {\n      id: \"openai/gpt-image-1-mini\",\n      name: \"OpenAI: GPT Image 1 Mini\",\n      api: \"openrouter-images\",\n      provider: \"openrouter\",\n      baseUrl: \"https://openrouter.ai/api/v1\",\n      input: [\"text\", \"image\"],\n      output: [\"image\"],\n      cost: {\n        input: 2.5,\n        output: 2.5,\n        cacheRead: 0.25,\n        cacheWrite: 0\n      }\n    },\n    \"openai/gpt-image-2\": {\n      id: \"openai/gpt-image-2\",\n      name: \"OpenAI: GPT Image 2\",\n      api: \"openrouter-images\",\n      provider: \"openrouter\",\n      baseUrl: \"https://openrouter.ai/api/v1\",\n      input: [\"text\", \"image\"],\n      output: [\"image\"],\n      cost: {\n        input: 8,\n        output: 8,\n        cacheRead: 2,\n        cacheWrite: 0\n      }\n    },\n    \"openrouter/auto\": {\n      id: \"openrouter/auto\",\n      name: \"Auto Router\",\n      api: \"openrouter-images\",\n      provider: \"openrouter\",\n      baseUrl: \"https://openrouter.ai/api/v1\",\n      input: [\"text\", \"image\"],\n      output: [\"text\", \"image\"],\n      cost: {\n        input: -1e6,\n        output: -1e6,\n        cacheRead: 0,\n        cacheWrite: 0\n      }\n    },\n    \"openrouter/auto-beta\": {\n      id: \"openrouter/auto-beta\",\n      name: \"Auto Router (Beta)\",\n      api: \"openrouter-images\",\n      provider: \"openrouter\",\n      baseUrl: \"https://openrouter.ai/api/v1\",\n      input: [\"text\", \"image\"],\n      output: [\"text\", \"image\"],\n      cost: {\n        input: -1e6,\n        output: -1e6,\n        cacheRead: 0,\n        cacheWrite: 0\n      }\n    },\n    \"qwen/qwen-image-3\": {\n      id: \"qwen/qwen-image-3\",\n      name: \"Qwen: Qwen Image 3\",\n      api: \"openrouter-images\",\n      provider: \"openrouter\",\n      baseUrl: \"https://openrouter.ai/api/v1\",\n      input: [\"text\", \"image\"],\n      output: [\"image\"],\n      cost: {\n        input: 0,\n        output: 0,\n        cacheRead: 0,\n        cacheWrite: 0\n      }\n    },\n    \"qwen/qwen-image-3-pro\": {\n      id: \"qwen/qwen-image-3-pro\",\n      name: \"Qwen: Qwen Image 3 Pro\",\n      api: \"openrouter-images\",\n      provider: \"openrouter\",\n      baseUrl: \"https://openrouter.ai/api/v1\",\n      input: [\"text\", \"image\"],\n      output: [\"image\"],\n      cost: {\n        input: 0,\n        output: 0,\n        cacheRead: 0,\n        cacheWrite: 0\n      }\n    },\n    \"recraft/recraft-v3\": {\n      id: \"recraft/recraft-v3\",\n      name: \"Recraft: Recraft V3\",\n      api: \"openrouter-images\",\n      provider: \"openrouter\",\n      baseUrl: \"https://openrouter.ai/api/v1\",\n      input: [\"text\", \"image\"],\n      output: [\"image\"],\n      cost: {\n        input: 0,\n        output: 0,\n        cacheRead: 0,\n        cacheWrite: 0\n      }\n    },\n    \"recraft/recraft-v4\": {\n      id: \"recraft/recraft-v4\",\n      name: \"Recraft: Recraft V4\",\n      api: \"openrouter-images\",\n      provider: \"openrouter\",\n      baseUrl: \"https://openrouter.ai/api/v1\",\n      input: [\"text\", \"image\"],\n      output: [\"image\"],\n      cost: {\n        input: 0,\n        output: 0,\n        cacheRead: 0,\n        cacheWrite: 0\n      }\n    },\n    \"recraft/recraft-v4-pro\": {\n      id: \"recraft/recraft-v4-pro\",\n      name: \"Recraft: Recraft V4 Pro\",\n      api: \"openrouter-images\",\n      provider: \"openrouter\",\n      baseUrl: \"https://openrouter.ai/api/v1\",\n      input: [\"text\", \"image\"],\n      output: [\"image\"],\n      cost: {\n        input: 0,\n        output: 0,\n        cacheRead: 0,\n        cacheWrite: 0\n      }\n    },\n    \"recraft/recraft-v4-pro-vector\": {\n      id: \"recraft/recraft-v4-pro-vector\",\n      name: \"Recraft: Recraft V4 Pro Vector\",\n      api: \"openrouter-images\",\n      provider: \"openrouter\",\n      baseUrl: \"https://openrouter.ai/api/v1\",\n      input: [\"text\", \"image\"],\n      output: [\"image\"],\n      cost: {\n        input: 0,\n        output: 0,\n        cacheRead: 0,\n        cacheWrite: 0\n      }\n    },\n    \"recraft/recraft-v4-vector\": {\n      id: \"recraft/recraft-v4-vector\",\n      name: \"Recraft: Recraft V4 Vector\",\n      api: \"openrouter-images\",\n      provider: \"openrouter\",\n      baseUrl: \"https://openrouter.ai/api/v1\",\n      input: [\"text\", \"image\"],\n      output: [\"image\"],\n      cost: {\n        input: 0,\n        output: 0,\n        cacheRead: 0,\n        cacheWrite: 0\n      }\n    },\n    \"recraft/recraft-v4.1\": {\n      id: \"recraft/recraft-v4.1\",\n      name: \"Recraft: Recraft V4.1\",\n      api: \"openrouter-images\",\n      provider: \"openrouter\",\n      baseUrl: \"https://openrouter.ai/api/v1\",\n      input: [\"text\", \"image\"],\n      output: [\"image\"],\n      cost: {\n        input: 0,\n        output: 0,\n        cacheRead: 0,\n        cacheWrite: 0\n      }\n    },\n    \"recraft/recraft-v4.1-pro\": {\n      id: \"recraft/recraft-v4.1-pro\",\n      name: \"Recraft: Recraft V4.1 Pro\",\n      api: \"openrouter-images\",\n      provider: \"openrouter\",\n      baseUrl: \"https://openrouter.ai/api/v1\",\n      input: [\"text\", \"image\"],\n      output: [\"image\"],\n      cost: {\n        input: 0,\n        output: 0,\n        cacheRead: 0,\n        cacheWrite: 0\n      }\n    },\n    \"recraft/recraft-v4.1-pro-vector\": {\n      id: \"recraft/recraft-v4.1-pro-vector\",\n      name: \"Recraft: Recraft V4.1 Pro Vector\",\n      api: \"openrouter-images\",\n      provider: \"openrouter\",\n      baseUrl: \"https://openrouter.ai/api/v1\",\n      input: [\"text\", \"image\"],\n      output: [\"image\"],\n      cost: {\n        input: 0,\n        output: 0,\n        cacheRead: 0,\n        cacheWrite: 0\n      }\n    },\n    \"recraft/recraft-v4.1-utility\": {\n      id: \"recraft/recraft-v4.1-utility\",\n      name: \"Recraft: Recraft V4.1 Utility\",\n      api: \"openrouter-images\",\n      provider: \"openrouter\",\n      baseUrl: \"https://openrouter.ai/api/v1\",\n      input: [\"text\", \"image\"],\n      output: [\"image\"],\n      cost: {\n        input: 0,\n        output: 0,\n        cacheRead: 0,\n        cacheWrite: 0\n      }\n    },\n    \"recraft/recraft-v4.1-utility-pro\": {\n      id: \"recraft/recraft-v4.1-utility-pro\",\n      name: \"Recraft: Recraft V4.1 Utility Pro\",\n      api: \"openrouter-images\",\n      provider: \"openrouter\",\n      baseUrl: \"https://openrouter.ai/api/v1\",\n      input: [\"text\", \"image\"],\n      output: [\"image\"],\n      cost: {\n        input: 0,\n        output: 0,\n        cacheRead: 0,\n        cacheWrite: 0\n      }\n    },\n    \"recraft/recraft-v4.1-vector\": {\n      id: \"recraft/recraft-v4.1-vector\",\n      name: \"Recraft: Recraft V4.1 Vector\",\n      api: \"openrouter-images\",\n      provider: \"openrouter\",\n      baseUrl: \"https://openrouter.ai/api/v1\",\n      input: [\"text\", \"image\"],\n      output: [\"image\"],\n      cost: {\n        input: 0,\n        output: 0,\n        cacheRead: 0,\n        cacheWrite: 0\n      }\n    },\n    \"sourceful/riverflow-v2-fast\": {\n      id: \"sourceful/riverflow-v2-fast\",\n      name: \"Sourceful: Riverflow V2 Fast\",\n      api: \"openrouter-images\",\n      provider: \"openrouter\",\n      baseUrl: \"https://openrouter.ai/api/v1\",\n      input: [\"text\", \"image\"],\n      output: [\"image\"],\n      cost: {\n        input: 0,\n        output: 0,\n        cacheRead: 0,\n        cacheWrite: 0\n      }\n    },\n    \"sourceful/riverflow-v2-pro\": {\n      id: \"sourceful/riverflow-v2-pro\",\n      name: \"Sourceful: Riverflow V2 Pro\",\n      api: \"openrouter-images\",\n      provider: \"openrouter\",\n      baseUrl: \"https://openrouter.ai/api/v1\",\n      input: [\"text\", \"image\"],\n      output: [\"image\"],\n      cost: {\n        input: 0,\n        output: 0,\n        cacheRead: 0,\n        cacheWrite: 0\n      }\n    },\n    \"sourceful/riverflow-v2.5-fast\": {\n      id: \"sourceful/riverflow-v2.5-fast\",\n      name: \"Sourceful: Riverflow V2.5 Fast\",\n      api: \"openrouter-images\",\n      provider: \"openrouter\",\n      baseUrl: \"https://openrouter.ai/api/v1\",\n      input: [\"text\", \"image\"],\n      output: [\"image\"],\n      cost: {\n        input: 0,\n        output: 0,\n        cacheRead: 0,\n        cacheWrite: 0\n      }\n    },\n    \"sourceful/riverflow-v2.5-pro\": {\n      id: \"sourceful/riverflow-v2.5-pro\",\n      name: \"Sourceful: Riverflow V2.5 Pro\",\n      api: \"openrouter-images\",\n      provider: \"openrouter\",\n      baseUrl: \"https://openrouter.ai/api/v1\",\n      input: [\"text\", \"image\"],\n      output: [\"image\"],\n      cost: {\n        input: 0,\n        output: 0,\n        cacheRead: 0,\n        cacheWrite: 0\n      }\n    },\n    \"x-ai/grok-imagine-image-2.0\": {\n      id: \"x-ai/grok-imagine-image-2.0\",\n      name: \"xAI: Grok Imagine Image 2.0\",\n      api: \"openrouter-images\",\n      provider: \"openrouter\",\n      baseUrl: \"https://openrouter.ai/api/v1\",\n      input: [\"text\", \"image\"],\n      output: [\"image\"],\n      cost: {\n        input: 0,\n        output: 0,\n        cacheRead: 0,\n        cacheWrite: 0\n      }\n    },\n    \"x-ai/grok-imagine-image-quality\": {\n      id: \"x-ai/grok-imagine-image-quality\",\n      name: \"SpaceXAI: Grok Imagine Image Quality\",\n      api: \"openrouter-images\",\n      provider: \"openrouter\",\n      baseUrl: \"https://openrouter.ai/api/v1\",\n      input: [\"text\", \"image\"],\n      output: [\"image\"],\n      cost: {\n        input: 0,\n        output: 0,\n        cacheRead: 0,\n        cacheWrite: 0\n      }\n    }\n  }\n};\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/openrouter-images.js\nfunction openrouterImagesProvider() {\n  return createImagesProvider({\n    id: \"openrouter\",\n    name: \"OpenRouter\",\n    auth: {\n      apiKey: envApiKeyAuth(\"OpenRouter API key\", [\"OPENROUTER_API_KEY\"]),\n      oauth: lazyOAuth({\n        name: \"OpenRouter OAuth\",\n        loginLabel: \"Sign in with OpenRouter\",\n        load: loadOpenRouterOAuth\n      })\n    },\n    models: Object.values(IMAGE_MODELS.openrouter),\n    api: openrouterImagesApi()\n  });\n}\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/qwen-token-plan.js\ninit_models();\nfunction qwenTokenPlanProvider() {\n  return createProvider({\n    id: \"qwen-token-plan\",\n    name: \"Qwen Token Plan\",\n    baseUrl: \"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1\",\n    auth: { apiKey: envApiKeyAuth(\"Qwen Token Plan API key\", [\"QWEN_TOKEN_PLAN_API_KEY\"]) },\n    models: Object.values(QWEN_TOKEN_PLAN_MODELS),\n    api: openAICompletionsApi()\n  });\n}\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/qwen-token-plan-cn.js\ninit_models();\nfunction qwenTokenPlanCnProvider() {\n  return createProvider({\n    id: \"qwen-token-plan-cn\",\n    name: \"Qwen Token Plan CN\",\n    baseUrl: \"https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1\",\n    auth: { apiKey: envApiKeyAuth(\"Qwen Token Plan CN API key\", [\"QWEN_TOKEN_PLAN_CN_API_KEY\"]) },\n    models: Object.values(QWEN_TOKEN_PLAN_CN_MODELS),\n    api: openAICompletionsApi()\n  });\n}\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/qwen-token-plan-individual.js\ninit_models();\nfunction qwenTokenPlanIndividualProvider() {\n  return createProvider({\n    id: \"qwen-token-plan-individual\",\n    name: \"Qwen Token Plan Individual\",\n    baseUrl: \"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1\",\n    auth: { apiKey: envApiKeyAuth(\"Qwen Token Plan Individual API key\", [\"QWEN_TOKEN_PLAN_API_KEY\"]) },\n    models: Object.values(QWEN_TOKEN_PLAN_INDIVIDUAL_MODELS),\n    api: openAICompletionsApi()\n  });\n}\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/api/pi-messages.lazy.js\ninit_lazy();\nvar piMessagesApi = () => lazyApi(() => Promise.resolve().then(() => (init_pi_messages(), pi_messages_exports)));\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/radius-config.js\nvar DEFAULT_RADIUS_GATEWAY = \"https://radius.pi.dev\";\nfunction isRadiusGatewayModel(value) {\n  if (typeof value !== \"object\" || value === null || Array.isArray(value))\n    return false;\n  const model = value;\n  return typeof model.id === \"string\" && typeof model.name === \"string\" && typeof model.reasoning === \"boolean\" && Array.isArray(model.input) && typeof model.cost === \"object\" && model.cost !== null && !Array.isArray(model.cost) && typeof model.contextWindow === \"number\" && typeof model.maxTokens === \"number\";\n}\nfunction sanitizeRadiusGatewayConfig(config) {\n  if (typeof config !== \"object\" || config === null || Array.isArray(config))\n    return void 0;\n  const { baseUrl, models } = config;\n  if (typeof baseUrl !== \"string\" || !Array.isArray(models))\n    return void 0;\n  return {\n    baseUrl,\n    models: models.filter(isRadiusGatewayModel).map((model) => ({ ...model }))\n  };\n}\nfunction normalizeRadiusGatewayUrl(value) {\n  const withScheme = /^https?:\\/\\//iu.test(value) ? value : `https://${value}`;\n  return withScheme.replace(/\\/+$/u, \"\");\n}\nfunction getRadiusCredentialConfig(credential) {\n  return sanitizeRadiusGatewayConfig(credential?.gatewayConfig);\n}\nfunction getRadiusModelsFromConfig(providerId, config) {\n  return config.models.map((model) => ({\n    ...model,\n    api: \"pi-messages\",\n    provider: providerId,\n    baseUrl: config.baseUrl\n  }));\n}\nfunction getRadiusModels(providerId, credential) {\n  const config = getRadiusCredentialConfig(credential);\n  return config ? getRadiusModelsFromConfig(providerId, config) : [];\n}\nfunction truncateHttpBody(body) {\n  const trimmed = body.trim();\n  return trimmed.length > 512 ? `${trimmed.slice(0, 512)}\\u2026` : trimmed;\n}\nasync function loadRadiusGatewayConfig(gateway, apiKey, signal) {\n  const headers = { accept: \"application/json\" };\n  if (apiKey)\n    headers.authorization = `Bearer ${apiKey}`;\n  const response = await fetch(new URL(\"/v1/config\", gateway), { headers, signal });\n  if (!response.ok) {\n    throw new Error(`Could not load Radius config from ${gateway}: ${response.status}: ${truncateHttpBody(await response.text())}`);\n  }\n  const config = sanitizeRadiusGatewayConfig(await response.json());\n  if (!config)\n    throw new Error(`Invalid Radius config from ${gateway}`);\n  return config;\n}\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/radius.js\nfunction radiusProvider(options = {}) {\n  const id = options.id ?? \"radius\";\n  const name = options.name ?? \"Radius\";\n  const gateway = normalizeRadiusGatewayUrl(options.gateway ?? DEFAULT_RADIUS_GATEWAY);\n  let models = getRadiusModels(id, void 0);\n  const streams = piMessagesApi();\n  return {\n    id,\n    name,\n    auth: {\n      apiKey: envApiKeyAuth(\"Radius API key\", [\"RADIUS_API_KEY\"]),\n      oauth: lazyOAuth({ name, load: () => loadRadiusOAuth({ name, gateway }) })\n    },\n    getModels: () => models,\n    refreshModels: async (context) => {\n      const stored = context.stored;\n      if (stored) {\n        const restored = stored.models.filter((model) => model.provider === id);\n        if (!await context.publish({\n          update: () => {\n            models = restored;\n          }\n        })) {\n          return;\n        }\n      }\n      if (!stored && context.credential?.type === \"oauth\") {\n        const legacy = getRadiusModels(id, context.credential);\n        if (legacy.length > 0) {\n          if (!await context.publish({\n            persist: { models: legacy, checkedAt: Date.now() },\n            update: () => {\n              models = legacy;\n            }\n          })) {\n            return;\n          }\n        }\n      }\n      if (!context.allowNetwork || context.signal.aborted)\n        return;\n      const apiKey = context.credential?.type === \"oauth\" ? context.credential.access : context.credential?.key;\n      const config = await loadRadiusGatewayConfig(gateway, apiKey, context.signal);\n      if (context.signal.aborted)\n        return;\n      const refreshed = getRadiusModelsFromConfig(id, config);\n      await context.publish({\n        persist: { models: refreshed, checkedAt: Date.now() },\n        update: () => {\n          models = refreshed;\n        }\n      });\n    },\n    stream: (model, context, streamOptions) => streams.stream(model, context, streamOptions),\n    streamSimple: (model, context, streamOptions) => streams.streamSimple(model, context, streamOptions)\n  };\n}\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/together.js\ninit_models();\nfunction togetherProvider() {\n  return createProvider({\n    id: \"together\",\n    name: \"Together\",\n    baseUrl: \"https://api.together.ai/v1\",\n    auth: { apiKey: envApiKeyAuth(\"Together API key\", [\"TOGETHER_API_KEY\"]) },\n    models: Object.values(TOGETHER_MODELS),\n    api: openAICompletionsApi()\n  });\n}\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/vercel-ai-gateway.js\ninit_models();\nfunction vercelAIGatewayProvider() {\n  return createProvider({\n    id: \"vercel-ai-gateway\",\n    name: \"Vercel AI Gateway\",\n    baseUrl: \"https://ai-gateway.vercel.sh\",\n    auth: { apiKey: envApiKeyAuth(\"Vercel AI Gateway API key\", [\"AI_GATEWAY_API_KEY\"]) },\n    models: Object.values(VERCEL_AI_GATEWAY_MODELS),\n    api: anthropicMessagesApi()\n  });\n}\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/xai.js\ninit_models();\nfunction xaiProvider() {\n  return createProvider({\n    id: \"xai\",\n    name: \"xAI\",\n    baseUrl: \"https://api.x.ai/v1\",\n    auth: {\n      apiKey: envApiKeyAuth(\"xAI API key\", [\"XAI_API_KEY\"]),\n      oauth: lazyOAuth({\n        name: \"xAI (Grok/X subscription)\",\n        isSubscription: true,\n        loginLabel: \"Sign in with SuperGrok or X Premium\",\n        load: loadXaiOAuth\n      })\n    },\n    models: Object.values(XAI_MODELS),\n    api: {\n      \"openai-completions\": openAICompletionsApi(),\n      \"openai-responses\": openAIResponsesApi()\n    }\n  });\n}\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/xiaomi.js\ninit_models();\nfunction xiaomiProvider() {\n  return createProvider({\n    id: \"xiaomi\",\n    name: \"Xiaomi\",\n    baseUrl: \"https://api.xiaomimimo.com/v1\",\n    auth: { apiKey: envApiKeyAuth(\"Xiaomi API key\", [\"XIAOMI_API_KEY\"]) },\n    models: Object.values(XIAOMI_MODELS),\n    api: openAICompletionsApi()\n  });\n}\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/xiaomi-token-plan-ams.js\ninit_models();\nfunction xiaomiTokenPlanAmsProvider() {\n  return createProvider({\n    id: \"xiaomi-token-plan-ams\",\n    name: \"Xiaomi Token Plan AMS\",\n    baseUrl: \"https://token-plan-ams.xiaomimimo.com/v1\",\n    auth: { apiKey: envApiKeyAuth(\"Xiaomi Token Plan AMS API key\", [\"XIAOMI_TOKEN_PLAN_AMS_API_KEY\"]) },\n    models: Object.values(XIAOMI_TOKEN_PLAN_AMS_MODELS),\n    api: openAICompletionsApi()\n  });\n}\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/xiaomi-token-plan-cn.js\ninit_models();\nfunction xiaomiTokenPlanCnProvider() {\n  return createProvider({\n    id: \"xiaomi-token-plan-cn\",\n    name: \"Xiaomi Token Plan CN\",\n    baseUrl: \"https://token-plan-cn.xiaomimimo.com/v1\",\n    auth: { apiKey: envApiKeyAuth(\"Xiaomi Token Plan CN API key\", [\"XIAOMI_TOKEN_PLAN_CN_API_KEY\"]) },\n    models: Object.values(XIAOMI_TOKEN_PLAN_CN_MODELS),\n    api: openAICompletionsApi()\n  });\n}\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/xiaomi-token-plan-sgp.js\ninit_models();\nfunction xiaomiTokenPlanSgpProvider() {\n  return createProvider({\n    id: \"xiaomi-token-plan-sgp\",\n    name: \"Xiaomi Token Plan SGP\",\n    baseUrl: \"https://token-plan-sgp.xiaomimimo.com/v1\",\n    auth: { apiKey: envApiKeyAuth(\"Xiaomi Token Plan SGP API key\", [\"XIAOMI_TOKEN_PLAN_SGP_API_KEY\"]) },\n    models: Object.values(XIAOMI_TOKEN_PLAN_SGP_MODELS),\n    api: openAICompletionsApi()\n  });\n}\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/zai.js\ninit_models();\nfunction zaiProvider() {\n  return createProvider({\n    id: \"zai\",\n    name: \"Z.AI\",\n    baseUrl: \"https://api.z.ai/api/coding/paas/v4\",\n    auth: { apiKey: envApiKeyAuth(\"Z.AI API key\", [\"ZAI_API_KEY\"]) },\n    models: Object.values(ZAI_MODELS),\n    api: openAICompletionsApi()\n  });\n}\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/zai-coding-cn.js\ninit_models();\nfunction zaiCodingCnProvider() {\n  return createProvider({\n    id: \"zai-coding-cn\",\n    name: \"Z.AI Coding CN\",\n    baseUrl: \"https://open.bigmodel.cn/api/coding/paas/v4\",\n    auth: { apiKey: envApiKeyAuth(\"Z.AI Coding CN API key\", [\"ZAI_CODING_CN_API_KEY\"]) },\n    models: Object.values(ZAI_CODING_CN_MODELS),\n    api: openAICompletionsApi()\n  });\n}\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/all.js\nfunction getBuiltinModel(provider, modelId) {\n  const models = MODELS[provider];\n  return models?.[modelId];\n}\nfunction getBuiltinProviders() {\n  return Object.keys(MODELS);\n}\nfunction getBuiltinModelDataGeneratedAt() {\n  const generatedAt = Date.parse(manifest_default.generatedAt);\n  return Number.isNaN(generatedAt) ? void 0 : generatedAt;\n}\nfunction getBuiltinModels(provider) {\n  const models = MODELS[provider];\n  return models ? Object.values(models) : [];\n}\nfunction builtinProviders() {\n  return [\n    amazonBedrockProvider(),\n    antLingProvider(),\n    anthropicProvider(),\n    azureOpenAIResponsesProvider(),\n    basetenProvider(),\n    cerebrasProvider(),\n    cloudflareAIGatewayProvider(),\n    cloudflareWorkersAIProvider(),\n    deepseekProvider(),\n    fireworksProvider(),\n    githubCopilotProvider(),\n    googleProvider(),\n    googleVertexProvider(),\n    groqProvider(),\n    huggingfaceProvider(),\n    kimiCodingProvider(),\n    minimaxProvider(),\n    minimaxCnProvider(),\n    mistralProvider(),\n    moonshotaiProvider(),\n    moonshotaiCnProvider(),\n    nvidiaProvider(),\n    openaiProvider(),\n    openaiCodexProvider(),\n    opencodeProvider(),\n    opencodeGoProvider(),\n    openrouterProvider(),\n    qwenTokenPlanProvider(),\n    qwenTokenPlanCnProvider(),\n    qwenTokenPlanIndividualProvider(),\n    radiusProvider(),\n    togetherProvider(),\n    vercelAIGatewayProvider(),\n    xaiProvider(),\n    xiaomiProvider(),\n    xiaomiTokenPlanAmsProvider(),\n    xiaomiTokenPlanCnProvider(),\n    xiaomiTokenPlanSgpProvider(),\n    zaiProvider(),\n    zaiCodingCnProvider()\n  ];\n}\nfunction builtinModels(options) {\n  const models = createModels(options);\n  for (const provider of builtinProviders()) {\n    models.setProvider(provider);\n  }\n  return models;\n}\nfunction builtinImagesProviders() {\n  return [openrouterImagesProvider()];\n}\nfunction builtinImagesModels(options) {\n  const models = createImagesModels(options);\n  for (const provider of builtinImagesProviders()) {\n    models.setProvider(provider);\n  }\n  return models;\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/utils/abort.js\nfunction abortReason2(signal) {\n  if (signal.reason !== void 0)\n    return signal.reason;\n  const error = new Error(\"The operation was aborted\");\n  error.name = \"AbortError\";\n  return error;\n}\nfunction operationSignal2(signal) {\n  return signal ?? new AbortController().signal;\n}\nfunction raceWithAbortSignal2(operation, signal) {\n  if (!signal)\n    return operation;\n  if (signal.aborted) {\n    void operation.catch(() => {\n    });\n    return Promise.reject(abortReason2(signal));\n  }\n  return new Promise((resolve15, reject) => {\n    let settled = false;\n    const cleanup = () => signal.removeEventListener(\"abort\", onAbort);\n    const onAbort = () => {\n      if (settled)\n        return;\n      settled = true;\n      cleanup();\n      reject(abortReason2(signal));\n    };\n    signal.addEventListener(\"abort\", onAbort, { once: true });\n    void operation.then((value) => {\n      if (settled)\n        return;\n      settled = true;\n      cleanup();\n      resolve15(value);\n    }, (error) => {\n      if (settled)\n        return;\n      settled = true;\n      cleanup();\n      reject(error);\n    });\n    if (signal.aborted)\n      onAbort();\n  });\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/core/auth-storage.js\nimport { chmodSync, existsSync as existsSync3, mkdirSync, readFileSync as readFileSync2, writeFileSync } from \"fs\";\nimport { dirname as dirname2, join as join3 } from \"path\";\nimport lockfile from \"proper-lockfile\";\nimport { setTimeout as sleep3 } from \"timers/promises\";\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/core/resolve-config-value.js\nimport { execSync, spawnSync as spawnSync2 } from \"child_process\";\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/utils/shell.js\nimport { existsSync as existsSync2 } from \"node:fs\";\nimport { delimiter } from \"node:path\";\nimport { spawn, spawnSync } from \"child_process\";\nfunction isLegacyWslBashPath(path12) {\n  const normalized = path12.replace(/\\//g, \"\\\\\").toLowerCase();\n  return /^[a-z]:\\\\windows\\\\(?:system32|sysnative)\\\\bash\\.exe$/.test(normalized);\n}\nfunction getBashShellConfig(shell) {\n  return isLegacyWslBashPath(shell) ? { shell, args: [\"-s\"], commandTransport: \"stdin\" } : { shell, args: [\"-c\"] };\n}\nfunction findBashOnPath() {\n  if (process.platform === \"win32\") {\n    try {\n      const result = spawnSync(\"where\", [\"bash.exe\"], {\n        encoding: \"utf-8\",\n        timeout: 5e3,\n        windowsHide: true\n      });\n      if (result.status === 0 && result.stdout) {\n        const firstMatch = result.stdout.trim().split(/\\r?\\n/)[0];\n        if (firstMatch && existsSync2(firstMatch)) {\n          return firstMatch;\n        }\n      }\n    } catch {\n    }\n    return null;\n  }\n  try {\n    const result = spawnSync(\"which\", [\"bash\"], { encoding: \"utf-8\", timeout: 5e3 });\n    if (result.status === 0 && result.stdout) {\n      const firstMatch = result.stdout.trim().split(/\\r?\\n/)[0];\n      if (firstMatch) {\n        return firstMatch;\n      }\n    }\n  } catch {\n  }\n  return null;\n}\nfunction getShellConfig(customShellPath) {\n  if (customShellPath) {\n    if (existsSync2(customShellPath)) {\n      return getBashShellConfig(customShellPath);\n    }\n    throw new Error(`Custom shell path not found: ${customShellPath}`);\n  }\n  if (process.platform === \"win32\") {\n    const paths = [];\n    const programFiles = process.env.ProgramFiles;\n    if (programFiles) {\n      paths.push(`${programFiles}\\\\Git\\\\bin\\\\bash.exe`);\n    }\n    const programFilesX86 = process.env[\"ProgramFiles(x86)\"];\n    if (programFilesX86) {\n      paths.push(`${programFilesX86}\\\\Git\\\\bin\\\\bash.exe`);\n    }\n    for (const path12 of paths) {\n      if (existsSync2(path12)) {\n        return getBashShellConfig(path12);\n      }\n    }\n    const bashOnPath2 = findBashOnPath();\n    if (bashOnPath2) {\n      return getBashShellConfig(bashOnPath2);\n    }\n    throw new Error(`No bash shell found. Options:\n  1. Install Git for Windows: https://git-scm.com/download/win\n  2. Add your bash to PATH (Cygwin, MSYS2, etc.)\n  3. Set shellPath in settings.json\n\nSearched Git Bash in:\n${paths.map((p) => `  ${p}`).join(\"\\n\")}`);\n  }\n  if (existsSync2(\"/bin/bash\")) {\n    return getBashShellConfig(\"/bin/bash\");\n  }\n  const bashOnPath = findBashOnPath();\n  if (bashOnPath) {\n    return getBashShellConfig(bashOnPath);\n  }\n  return { shell: \"sh\", args: [\"-c\"] };\n}\nfunction getShellEnv() {\n  const binDir = getBinDir();\n  const pathKey = Object.keys(process.env).find((key) => key.toLowerCase() === \"path\") ?? \"PATH\";\n  const currentPath = process.env[pathKey] ?? \"\";\n  const pathEntries = currentPath.split(delimiter).filter(Boolean);\n  const hasBinDir = pathEntries.includes(binDir);\n  const updatedPath = hasBinDir ? currentPath : [binDir, currentPath].filter(Boolean).join(delimiter);\n  return {\n    ...process.env,\n    [pathKey]: updatedPath\n  };\n}\nfunction sanitizeBinaryOutput(str2) {\n  return Array.from(str2).filter((char) => {\n    const code = char.codePointAt(0);\n    if (code === void 0)\n      return false;\n    if (code === 9 || code === 10 || code === 13)\n      return true;\n    if (code <= 31)\n      return false;\n    if (code >= 65529 && code <= 65531)\n      return false;\n    return true;\n  }).join(\"\");\n}\nvar trackedDetachedChildPids = /* @__PURE__ */ new Set();\nfunction trackDetachedChildPid(pid) {\n  trackedDetachedChildPids.add(pid);\n}\nfunction untrackDetachedChildPid(pid) {\n  trackedDetachedChildPids.delete(pid);\n}\nfunction killTrackedDetachedChildren() {\n  for (const pid of trackedDetachedChildPids) {\n    killProcessTree(pid);\n  }\n  trackedDetachedChildPids.clear();\n}\nfunction killProcessTree(pid) {\n  if (process.platform === \"win32\") {\n    try {\n      spawn(\"taskkill\", [\"/F\", \"/T\", \"/PID\", String(pid)], {\n        stdio: \"ignore\",\n        detached: true,\n        windowsHide: true\n      });\n    } catch {\n    }\n  } else {\n    try {\n      process.kill(-pid, \"SIGKILL\");\n    } catch {\n      try {\n        process.kill(pid, \"SIGKILL\");\n      } catch {\n      }\n    }\n  }\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/core/resolve-config-value.js\nvar commandResultCache = /* @__PURE__ */ new Map();\nvar ENV_VAR_NAME_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;\nvar ENV_VAR_NAME_PREFIX_RE = /^[A-Za-z_][A-Za-z0-9_]*/;\nfunction appendLiteral(parts, value) {\n  if (!value)\n    return;\n  const previousPart = parts[parts.length - 1];\n  if (previousPart?.type === \"literal\") {\n    previousPart.value += value;\n    return;\n  }\n  parts.push({ type: \"literal\", value });\n}\nfunction parseConfigValueTemplate(config) {\n  const parts = [];\n  let index = 0;\n  while (index < config.length) {\n    const dollarIndex = config.indexOf(\"$\", index);\n    if (dollarIndex < 0) {\n      appendLiteral(parts, config.slice(index));\n      break;\n    }\n    appendLiteral(parts, config.slice(index, dollarIndex));\n    const nextChar = config[dollarIndex + 1];\n    if (nextChar === \"$\" || nextChar === \"!\") {\n      appendLiteral(parts, nextChar);\n      index = dollarIndex + 2;\n      continue;\n    }\n    if (nextChar === \"{\") {\n      const endIndex = config.indexOf(\"}\", dollarIndex + 2);\n      if (endIndex < 0) {\n        appendLiteral(parts, \"$\");\n        index = dollarIndex + 1;\n        continue;\n      }\n      const name = config.slice(dollarIndex + 2, endIndex);\n      if (ENV_VAR_NAME_RE.test(name)) {\n        parts.push({ type: \"env\", name });\n      } else {\n        appendLiteral(parts, config.slice(dollarIndex, endIndex + 1));\n      }\n      index = endIndex + 1;\n      continue;\n    }\n    const match = config.slice(dollarIndex + 1).match(ENV_VAR_NAME_PREFIX_RE);\n    if (match) {\n      parts.push({ type: \"env\", name: match[0] });\n      index = dollarIndex + 1 + match[0].length;\n      continue;\n    }\n    appendLiteral(parts, \"$\");\n    index = dollarIndex + 1;\n  }\n  return parts;\n}\nfunction parseConfigValueReference(config) {\n  if (config.startsWith(\"!\")) {\n    return { type: \"command\", config };\n  }\n  return { type: \"template\", parts: parseConfigValueTemplate(config) };\n}\nfunction resolveEnvConfigValue(name, env) {\n  return env?.[name] || process.env[name] || void 0;\n}\nfunction getTemplateEnvVarNames(parts) {\n  const names = [];\n  for (const part of parts) {\n    if (part.type !== \"env\" || names.includes(part.name))\n      continue;\n    names.push(part.name);\n  }\n  return names;\n}\nfunction resolveTemplate(parts, env) {\n  let resolved = \"\";\n  for (const part of parts) {\n    if (part.type === \"literal\") {\n      resolved += part.value;\n      continue;\n    }\n    const envValue = resolveEnvConfigValue(part.name, env);\n    if (envValue === void 0)\n      return void 0;\n    resolved += envValue;\n  }\n  return resolved;\n}\nfunction getConfigValueEnvVarNames(config) {\n  const reference = parseConfigValueReference(config);\n  return reference.type === \"template\" ? getTemplateEnvVarNames(reference.parts) : [];\n}\nfunction getMissingConfigValueEnvVarNames(config, env) {\n  return getConfigValueEnvVarNames(config).filter((name) => resolveEnvConfigValue(name, env) === void 0);\n}\nfunction isCommandConfigValue(config) {\n  return parseConfigValueReference(config).type === \"command\";\n}\nfunction isConfigValueConfigured(config, env) {\n  return getMissingConfigValueEnvVarNames(config, env).length === 0;\n}\nfunction resolveConfigValue(config, env) {\n  const reference = parseConfigValueReference(config);\n  if (reference.type === \"command\") {\n    return executeCommand(reference.config);\n  }\n  return resolveTemplate(reference.parts, env);\n}\nfunction executeWithConfiguredShell(command) {\n  try {\n    const { shell, args, commandTransport } = getShellConfig();\n    const commandFromStdin = commandTransport === \"stdin\";\n    const result = spawnSync2(shell, commandFromStdin ? args : [...args, command], {\n      encoding: \"utf-8\",\n      input: commandFromStdin ? command : void 0,\n      timeout: 1e4,\n      stdio: [commandFromStdin ? \"pipe\" : \"ignore\", \"pipe\", \"ignore\"],\n      shell: false,\n      windowsHide: true\n    });\n    if (result.error) {\n      const error = result.error;\n      if (error.code === \"ENOENT\") {\n        return { executed: false, value: void 0 };\n      }\n      return { executed: true, value: void 0 };\n    }\n    if (result.status !== 0) {\n      return { executed: true, value: void 0 };\n    }\n    const value = (result.stdout ?? \"\").trim();\n    return { executed: true, value: value || void 0 };\n  } catch {\n    return { executed: false, value: void 0 };\n  }\n}\nfunction executeWithDefaultShell(command) {\n  try {\n    const output = execSync(command, {\n      encoding: \"utf-8\",\n      timeout: 1e4,\n      stdio: [\"ignore\", \"pipe\", \"ignore\"]\n    });\n    return output.trim() || void 0;\n  } catch {\n    return void 0;\n  }\n}\nfunction executeCommandUncached(commandConfig) {\n  const command = commandConfig.slice(1);\n  return process.platform === \"win32\" ? (() => {\n    const configuredResult = executeWithConfiguredShell(command);\n    return configuredResult.executed ? configuredResult.value : executeWithDefaultShell(command);\n  })() : executeWithDefaultShell(command);\n}\nfunction executeCommand(commandConfig) {\n  if (commandResultCache.has(commandConfig)) {\n    return commandResultCache.get(commandConfig);\n  }\n  const result = executeCommandUncached(commandConfig);\n  commandResultCache.set(commandConfig, result);\n  return result;\n}\nfunction resolveConfigValueUncached(config, env) {\n  const reference = parseConfigValueReference(config);\n  if (reference.type === \"command\") {\n    return executeCommandUncached(reference.config);\n  }\n  return resolveTemplate(reference.parts, env);\n}\nfunction resolveConfigValueOrThrow(config, description, env) {\n  const resolvedValue = resolveConfigValueUncached(config, env);\n  if (resolvedValue !== void 0) {\n    return resolvedValue;\n  }\n  const reference = parseConfigValueReference(config);\n  if (reference.type === \"command\") {\n    throw new Error(`Failed to resolve ${description} from shell command: ${reference.config.slice(1)}`);\n  }\n  if (reference.type === \"template\") {\n    const missingEnvVars = getMissingConfigValueEnvVarNames(config, env);\n    if (missingEnvVars.length === 1) {\n      throw new Error(`Failed to resolve ${description} from environment variable: ${missingEnvVars[0]}`);\n    }\n    if (missingEnvVars.length > 1) {\n      throw new Error(`Failed to resolve ${description} from environment variables: ${missingEnvVars.join(\", \")}`);\n    }\n  }\n  throw new Error(`Failed to resolve ${description}`);\n}\nfunction resolveHeadersOrThrow(headers, description, env) {\n  if (!headers)\n    return void 0;\n  const resolved = {};\n  for (const [key, value] of Object.entries(headers)) {\n    resolved[key] = resolveConfigValueOrThrow(value, `${description} header \"${key}\"`, env);\n  }\n  return Object.keys(resolved).length > 0 ? resolved : void 0;\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/core/auth-storage.js\nvar AUTH_FILE_WRITE_OPTIONS = { encoding: \"utf-8\", mode: 384 };\nvar sharedAuthFileReadState;\nvar FileAuthStorageBackend = class {\n  authPath;\n  constructor(authPath = join3(getAgentDir(), \"auth.json\")) {\n    this.authPath = normalizePath(authPath);\n  }\n  ensureParentDir() {\n    const dir = dirname2(this.authPath);\n    if (!existsSync3(dir)) {\n      mkdirSync(dir, { recursive: true, mode: 448 });\n    }\n  }\n  ensureFileExists() {\n    if (!existsSync3(this.authPath)) {\n      writeFileSync(this.authPath, \"{}\", AUTH_FILE_WRITE_OPTIONS);\n      chmodSync(this.authPath, 384);\n    }\n  }\n  acquireLockSyncWithRetry(path12) {\n    const maxAttempts = 10;\n    const delayMs = 20;\n    let lastError;\n    for (let attempt = 1; attempt <= maxAttempts; attempt++) {\n      try {\n        return lockfile.lockSync(path12, { realpath: false });\n      } catch (error) {\n        const code = typeof error === \"object\" && error !== null && \"code\" in error ? String(error.code) : void 0;\n        if (code !== \"ELOCKED\" || attempt === maxAttempts) {\n          throw error;\n        }\n        lastError = error;\n        const start = Date.now();\n        while (Date.now() - start < delayMs) {\n        }\n      }\n    }\n    throw lastError ?? new Error(\"Failed to acquire auth storage lock\");\n  }\n  withLock(fn) {\n    this.ensureParentDir();\n    this.ensureFileExists();\n    let release;\n    try {\n      release = this.acquireLockSyncWithRetry(this.authPath);\n      const current = existsSync3(this.authPath) ? readFileSync2(this.authPath, \"utf-8\") : void 0;\n      const { result, next } = fn(current);\n      if (next !== void 0) {\n        writeFileSync(this.authPath, next, AUTH_FILE_WRITE_OPTIONS);\n        chmodSync(this.authPath, 384);\n      }\n      return result;\n    } finally {\n      if (release) {\n        release();\n      }\n    }\n  }\n  async acquireLockAsync(signal, onCompromised) {\n    const staleMs = 3e4;\n    const maxDelayMs = 2e3;\n    const deadline = Date.now() + staleMs;\n    let retry = 0;\n    while (true) {\n      signal?.throwIfAborted();\n      let release;\n      try {\n        release = await lockfile.lock(this.authPath, {\n          realpath: false,\n          retries: 0,\n          stale: staleMs,\n          onCompromised\n        });\n      } catch (error) {\n        signal?.throwIfAborted();\n        const code = typeof error === \"object\" && error !== null && \"code\" in error ? String(error.code) : void 0;\n        const remainingMs = deadline - Date.now();\n        if (code !== \"ELOCKED\" || remainingMs <= 0)\n          throw error;\n        const baseDelayMs = Math.min(10 * 2 ** retry, maxDelayMs / 2);\n        retry++;\n        const delayMs = Math.min(Math.round(baseDelayMs * (1 + Math.random())), remainingMs);\n        if (signal)\n          await sleep3(delayMs, void 0, { signal });\n        else\n          await sleep3(delayMs);\n        continue;\n      }\n      if (signal?.aborted) {\n        await release();\n        signal.throwIfAborted();\n      }\n      return release;\n    }\n  }\n  async withLockAsync(fn, options) {\n    options?.signal?.throwIfAborted();\n    this.ensureParentDir();\n    this.ensureFileExists();\n    let release;\n    let lockCompromised = false;\n    let lockCompromisedError;\n    const throwIfCompromised = () => {\n      if (lockCompromised) {\n        throw lockCompromisedError ?? new Error(\"Auth storage lock was compromised\");\n      }\n    };\n    try {\n      release = await this.acquireLockAsync(options?.signal, (error) => {\n        lockCompromised = true;\n        lockCompromisedError = error;\n      });\n      throwIfCompromised();\n      options?.signal?.throwIfAborted();\n      const current = existsSync3(this.authPath) ? readFileSync2(this.authPath, \"utf-8\") : void 0;\n      const { result, next } = await fn(current);\n      throwIfCompromised();\n      options?.signal?.throwIfAborted();\n      if (next !== void 0) {\n        writeFileSync(this.authPath, next, AUTH_FILE_WRITE_OPTIONS);\n        chmodSync(this.authPath, 384);\n      }\n      throwIfCompromised();\n      return result;\n    } finally {\n      if (release) {\n        try {\n          await release();\n        } catch {\n        }\n      }\n    }\n  }\n};\nvar ReadOnlyAuthStorage = class {\n  authPath;\n  data;\n  constructor(authPath = join3(getAgentDir(), \"auth.json\")) {\n    this.authPath = normalizePath(authPath);\n  }\n  load() {\n    if (this.data)\n      return this.data;\n    let parsed;\n    try {\n      parsed = JSON.parse(readFileSync2(this.authPath, \"utf-8\"));\n    } catch (error) {\n      if (error.code === \"ENOENT\") {\n        this.data = {};\n        return this.data;\n      }\n      throw new Error(`Failed to read auth.json: ${error instanceof Error ? error.message : String(error)}`);\n    }\n    if (typeof parsed !== \"object\" || parsed === null || Array.isArray(parsed)) {\n      throw new Error(\"Invalid auth.json: expected an object\");\n    }\n    for (const [providerId, credential] of Object.entries(parsed)) {\n      if (typeof credential !== \"object\" || credential === null || Array.isArray(credential)) {\n        throw new Error(`Invalid auth.json credential for provider \"${providerId}\"`);\n      }\n      const value = credential;\n      if (value.type === \"api_key\") {\n        const validKey = value.key === void 0 || typeof value.key === \"string\";\n        const validEnv = value.env === void 0 || typeof value.env === \"object\" && value.env !== null && !Array.isArray(value.env) && Object.values(value.env).every((entry) => typeof entry === \"string\");\n        if (validKey && validEnv)\n          continue;\n      } else if (value.type === \"oauth\" && typeof value.access === \"string\" && typeof value.refresh === \"string\" && typeof value.expires === \"number\" && Number.isFinite(value.expires)) {\n        continue;\n      }\n      throw new Error(`Invalid auth.json credential for provider \"${providerId}\"`);\n    }\n    this.data = parsed;\n    return this.data;\n  }\n  async read(providerId, options) {\n    options?.signal?.throwIfAborted();\n    const credential = this.load()[providerId];\n    options?.signal?.throwIfAborted();\n    if (!credential)\n      return void 0;\n    if (credential.type !== \"api_key\" || !credential.key || isCommandConfigValue(credential.key)) {\n      return structuredClone(credential);\n    }\n    return { ...credential, key: resolveConfigValue(credential.key, credential.env) };\n  }\n  async list(options) {\n    options?.signal?.throwIfAborted();\n    const credentials = Object.entries(this.load()).map(([providerId, credential]) => ({\n      providerId,\n      type: credential.type\n    }));\n    options?.signal?.throwIfAborted();\n    return credentials;\n  }\n  async modify(_providerId, _fn, _options) {\n    throw new Error(\"Read-only credential storage cannot modify auth.json\");\n  }\n  async delete(_providerId, _options) {\n    throw new Error(\"Read-only credential storage cannot modify auth.json\");\n  }\n};\nvar InMemoryAuthStorageBackend = class {\n  value;\n  asyncChain = Promise.resolve();\n  withLock(fn) {\n    const { result, next } = fn(this.value);\n    if (next !== void 0) {\n      this.value = next;\n    }\n    return result;\n  }\n  withLockAsync(fn, options) {\n    const previous = this.asyncChain;\n    const operation = (async () => {\n      await previous.catch(() => {\n      });\n      options?.signal?.throwIfAborted();\n      const { result, next } = await fn(this.value);\n      options?.signal?.throwIfAborted();\n      if (next !== void 0) {\n        this.value = next;\n      }\n      return result;\n    })();\n    this.asyncChain = operation.catch(() => {\n    });\n    return raceWithAbortSignal2(operation, options?.signal);\n  }\n};\nvar AuthStorage = class _AuthStorage {\n  storage;\n  authPath;\n  readState;\n  constructor(storage, authPath) {\n    this.storage = storage;\n    this.authPath = authPath;\n    this.readState = authPath && sharedAuthFileReadState?.authPath === authPath ? sharedAuthFileReadState.readState : { data: {} };\n    if (authPath && !sharedAuthFileReadState) {\n      sharedAuthFileReadState = { authPath, readState: this.readState };\n    }\n    if (authPath) {\n      const revision = getFileRevision(authPath);\n      if (revision !== void 0 && revision === this.readState.revision)\n        return;\n    }\n    this.reload();\n  }\n  static create(authPath = join3(getAgentDir(), \"auth.json\")) {\n    const normalizedAuthPath = normalizePath(authPath);\n    return new _AuthStorage(new FileAuthStorageBackend(normalizedAuthPath), normalizedAuthPath);\n  }\n  static fromStorage(storage) {\n    return new _AuthStorage(storage);\n  }\n  static inMemory(data = {}) {\n    const storage = new InMemoryAuthStorageBackend();\n    storage.withLock(() => ({ result: void 0, next: JSON.stringify(data, null, 2) }));\n    return _AuthStorage.fromStorage(storage);\n  }\n  parseStorageData(content) {\n    if (!content) {\n      return {};\n    }\n    return JSON.parse(content);\n  }\n  updateReadState(data, revision) {\n    this.readState.data = data;\n    this.readState.revision = revision;\n  }\n  /**\n   * Reload credentials from storage.\n   */\n  reload() {\n    let content;\n    let revision;\n    try {\n      this.storage.withLock((current) => {\n        content = current;\n        revision = this.authPath ? getFileRevision(this.authPath) : void 0;\n        return { result: void 0 };\n      });\n      this.updateReadState(this.parseStorageData(content), revision);\n    } catch {\n    }\n  }\n  async reloadFromStorageAsync(options) {\n    return this.storage.withLockAsync(async (content) => {\n      const currentData = this.parseStorageData(content);\n      const revision = this.authPath ? getFileRevision(this.authPath) : void 0;\n      this.updateReadState(currentData, revision);\n      return { result: currentData };\n    }, options);\n  }\n  async readLatestData(options) {\n    options?.signal?.throwIfAborted();\n    if (!this.authPath) {\n      const reload2 = this.reloadFromStorageAsync(options);\n      return options?.signal ? reload2 : reload2.catch(() => this.readState.data);\n    }\n    const revision = getFileRevision(this.authPath);\n    if (revision !== void 0 && revision === this.readState.revision)\n      return this.readState.data;\n    if (!this.readState.reload) {\n      const controller = new AbortController();\n      const reload2 = {\n        controller,\n        promise: this.reloadFromStorageAsync({ signal: controller.signal }),\n        readers: 0\n      };\n      this.readState.reload = reload2;\n      void reload2.promise.then(() => {\n        if (this.readState.reload === reload2)\n          this.readState.reload = void 0;\n      }, () => {\n        if (this.readState.reload === reload2)\n          this.readState.reload = void 0;\n      });\n    }\n    const reload = this.readState.reload;\n    reload.readers++;\n    try {\n      const result = raceWithAbortSignal2(reload.promise, options?.signal);\n      return options?.signal ? await result : await result.catch(() => this.readState.data);\n    } finally {\n      reload.readers--;\n      if (reload.readers === 0 && this.readState.reload === reload) {\n        this.readState.reload = void 0;\n        reload.controller.abort();\n      }\n    }\n  }\n  async read(provider, options) {\n    const credential = (await this.readLatestData(options))[provider];\n    options?.signal?.throwIfAborted();\n    if (credential?.type !== \"api_key\")\n      return credential;\n    if (credential.key === void 0)\n      return credential;\n    return { ...credential, key: resolveConfigValue(credential.key, credential.env) };\n  }\n  async modify(provider, fn, options) {\n    let latestData = this.readState.data;\n    let revision;\n    const result = await this.storage.withLockAsync(async (content) => {\n      const currentData = this.parseStorageData(content);\n      const next = await fn(currentData[provider]);\n      if (next === void 0) {\n        latestData = currentData;\n        revision = this.authPath ? getFileRevision(this.authPath) : void 0;\n        return { result: currentData[provider] };\n      }\n      const merged = { ...currentData, [provider]: next };\n      latestData = merged;\n      return { result: next, next: JSON.stringify(merged, null, 2) };\n    }, options);\n    this.updateReadState(latestData, revision);\n    return result;\n  }\n  async delete(provider, options) {\n    let latestData = this.readState.data;\n    await this.storage.withLockAsync(async (content) => {\n      const currentData = this.parseStorageData(content);\n      delete currentData[provider];\n      latestData = currentData;\n      return { result: void 0, next: JSON.stringify(currentData, null, 2) };\n    }, options);\n    this.updateReadState(latestData);\n  }\n  /** List credential metadata without resolving configured key values. */\n  async list(options) {\n    const entries = Object.entries(await this.readLatestData(options));\n    options?.signal?.throwIfAborted();\n    return entries.map(([providerId, credential]) => ({ providerId, type: credential.type }));\n  }\n};\nfunction readStoredCredential(providerId, authPath = join3(getAgentDir(), \"auth.json\")) {\n  try {\n    const data = JSON.parse(readFileSync2(normalizePath(authPath), \"utf-8\"));\n    return data[providerId];\n  } catch {\n    return void 0;\n  }\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/core/model-config.js\nimport { readFile } from \"node:fs/promises\";\nimport { Type as Type3 } from \"typebox\";\nimport { Compile as Compile2 } from \"typebox/compile\";\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/utils/json.js\nfunction stripJsonComments(input) {\n  return input.replace(/\"(?:\\\\.|[^\"\\\\])*\"|\\/\\/[^\\n]*/g, (m) => m[0] === '\"' ? m : \"\").replace(/\"(?:\\\\.|[^\"\\\\])*\"|,(\\s*[}\\]])/g, (m, tail) => tail ?? (m[0] === '\"' ? m : \"\"));\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/core/model-config.js\nvar PercentileCutoffsSchema = Type3.Object({\n  p50: Type3.Optional(Type3.Number()),\n  p75: Type3.Optional(Type3.Number()),\n  p90: Type3.Optional(Type3.Number()),\n  p99: Type3.Optional(Type3.Number())\n});\nvar OpenRouterRoutingSchema = Type3.Object({\n  allow_fallbacks: Type3.Optional(Type3.Boolean()),\n  require_parameters: Type3.Optional(Type3.Boolean()),\n  data_collection: Type3.Optional(Type3.Union([Type3.Literal(\"deny\"), Type3.Literal(\"allow\")])),\n  zdr: Type3.Optional(Type3.Boolean()),\n  enforce_distillable_text: Type3.Optional(Type3.Boolean()),\n  order: Type3.Optional(Type3.Array(Type3.String())),\n  only: Type3.Optional(Type3.Array(Type3.String())),\n  ignore: Type3.Optional(Type3.Array(Type3.String())),\n  quantizations: Type3.Optional(Type3.Array(Type3.String())),\n  sort: Type3.Optional(Type3.Union([\n    Type3.String(),\n    Type3.Object({\n      by: Type3.Optional(Type3.String()),\n      partition: Type3.Optional(Type3.Union([Type3.String(), Type3.Null()]))\n    })\n  ])),\n  max_price: Type3.Optional(Type3.Object({\n    prompt: Type3.Optional(Type3.Union([Type3.Number(), Type3.String()])),\n    completion: Type3.Optional(Type3.Union([Type3.Number(), Type3.String()])),\n    image: Type3.Optional(Type3.Union([Type3.Number(), Type3.String()])),\n    audio: Type3.Optional(Type3.Union([Type3.Number(), Type3.String()])),\n    request: Type3.Optional(Type3.Union([Type3.Number(), Type3.String()]))\n  })),\n  preferred_min_throughput: Type3.Optional(Type3.Union([Type3.Number(), PercentileCutoffsSchema])),\n  preferred_max_latency: Type3.Optional(Type3.Union([Type3.Number(), PercentileCutoffsSchema]))\n});\nvar VercelGatewayRoutingSchema = Type3.Object({\n  only: Type3.Optional(Type3.Array(Type3.String())),\n  order: Type3.Optional(Type3.Array(Type3.String()))\n});\nvar ThinkingLevelMapValueSchema = Type3.Union([Type3.String(), Type3.Null()]);\nvar ThinkingLevelMapSchema = Type3.Object({\n  off: Type3.Optional(ThinkingLevelMapValueSchema),\n  minimal: Type3.Optional(ThinkingLevelMapValueSchema),\n  low: Type3.Optional(ThinkingLevelMapValueSchema),\n  medium: Type3.Optional(ThinkingLevelMapValueSchema),\n  high: Type3.Optional(ThinkingLevelMapValueSchema),\n  xhigh: Type3.Optional(ThinkingLevelMapValueSchema),\n  max: Type3.Optional(ThinkingLevelMapValueSchema)\n});\nvar ChatTemplateKwargScalarSchema = Type3.Union([Type3.String(), Type3.Number(), Type3.Boolean(), Type3.Null()]);\nvar ChatTemplateKwargVariableSchema = Type3.Object({\n  $var: Type3.Union([Type3.Literal(\"thinking.enabled\"), Type3.Literal(\"thinking.effort\")]),\n  omitWhenOff: Type3.Optional(Type3.Boolean())\n});\nvar ChatTemplateKwargSchema = Type3.Union([ChatTemplateKwargScalarSchema, ChatTemplateKwargVariableSchema]);\nvar OpenAICompletionsCompatSchema = Type3.Object({\n  supportsStore: Type3.Optional(Type3.Boolean()),\n  supportsDeveloperRole: Type3.Optional(Type3.Boolean()),\n  supportsReasoningEffort: Type3.Optional(Type3.Boolean()),\n  supportsUsageInStreaming: Type3.Optional(Type3.Boolean()),\n  maxTokensField: Type3.Optional(Type3.Union([Type3.Literal(\"max_completion_tokens\"), Type3.Literal(\"max_tokens\")])),\n  requiresToolResultName: Type3.Optional(Type3.Boolean()),\n  requiresAssistantAfterToolResult: Type3.Optional(Type3.Boolean()),\n  requiresThinkingAsText: Type3.Optional(Type3.Boolean()),\n  requiresReasoningContentOnAssistantMessages: Type3.Optional(Type3.Boolean()),\n  thinkingFormat: Type3.Optional(Type3.Union([\n    Type3.Literal(\"openai\"),\n    Type3.Literal(\"openrouter\"),\n    Type3.Literal(\"together\"),\n    Type3.Literal(\"baseten\"),\n    Type3.Literal(\"deepseek\"),\n    Type3.Literal(\"zai\"),\n    Type3.Literal(\"qwen\"),\n    Type3.Literal(\"chat-template\"),\n    Type3.Literal(\"qwen-chat-template\"),\n    Type3.Literal(\"string-thinking\"),\n    Type3.Literal(\"ant-ling\")\n  ])),\n  chatTemplateKwargs: Type3.Optional(Type3.Record(Type3.String(), ChatTemplateKwargSchema)),\n  chatTemplateArgs: Type3.Optional(Type3.Record(Type3.String(), ChatTemplateKwargSchema)),\n  cacheControlFormat: Type3.Optional(Type3.Literal(\"anthropic\")),\n  openRouterRouting: Type3.Optional(OpenRouterRoutingSchema),\n  vercelGatewayRouting: Type3.Optional(VercelGatewayRoutingSchema),\n  supportsOpenAIGrammarTools: Type3.Optional(Type3.Boolean()),\n  supportsStrictMode: Type3.Optional(Type3.Boolean()),\n  sendSessionAffinityHeaders: Type3.Optional(Type3.Boolean()),\n  deferredToolsMode: Type3.Optional(Type3.Literal(\"kimi\")),\n  sessionAffinityFormat: Type3.Optional(Type3.Union([Type3.Literal(\"openai\"), Type3.Literal(\"openai-nosession\"), Type3.Literal(\"openrouter\")])),\n  supportsLongCacheRetention: Type3.Optional(Type3.Boolean())\n});\nvar OpenAIResponsesCompatSchema = Type3.Object({\n  supportsDeveloperRole: Type3.Optional(Type3.Boolean()),\n  sessionAffinityFormat: Type3.Optional(Type3.Union([Type3.Literal(\"openai\"), Type3.Literal(\"openai-nosession\"), Type3.Literal(\"openrouter\")])),\n  supportsLongCacheRetention: Type3.Optional(Type3.Boolean()),\n  supportsStrictMode: Type3.Optional(Type3.Boolean()),\n  supportsOpenAIGrammarTools: Type3.Optional(Type3.Boolean()),\n  supportsAdditionalTools: Type3.Optional(Type3.Boolean()),\n  supportsToolSearch: Type3.Optional(Type3.Boolean())\n});\nvar AnthropicMessagesCompatSchema = Type3.Object({\n  supportsEagerToolInputStreaming: Type3.Optional(Type3.Boolean()),\n  supportsLongCacheRetention: Type3.Optional(Type3.Boolean()),\n  sendSessionAffinityHeaders: Type3.Optional(Type3.Boolean()),\n  supportsCacheControlOnTools: Type3.Optional(Type3.Boolean()),\n  supportsTemperature: Type3.Optional(Type3.Boolean()),\n  forceAdaptiveThinking: Type3.Optional(Type3.Boolean()),\n  allowEmptySignature: Type3.Optional(Type3.Boolean()),\n  supportsStrictTools: Type3.Optional(Type3.Boolean()),\n  supportsToolReferences: Type3.Optional(Type3.Boolean())\n});\nvar ProviderCompatSchema = Type3.Union([\n  OpenAICompletionsCompatSchema,\n  OpenAIResponsesCompatSchema,\n  AnthropicMessagesCompatSchema\n]);\nvar ModelCostRatesSchema = {\n  input: Type3.Number(),\n  output: Type3.Number(),\n  cacheRead: Type3.Number(),\n  cacheWrite: Type3.Number()\n};\nvar ModelCostTierSchema = Type3.Object({\n  inputTokensAbove: Type3.Number(),\n  ...ModelCostRatesSchema\n});\nvar ModelCostSchema = Type3.Object({\n  ...ModelCostRatesSchema,\n  tiers: Type3.Optional(Type3.Array(ModelCostTierSchema))\n});\nvar ModelDefinitionSchema = Type3.Object({\n  id: Type3.String({ minLength: 1 }),\n  name: Type3.Optional(Type3.String({ minLength: 1 })),\n  api: Type3.Optional(Type3.String({ minLength: 1 })),\n  baseUrl: Type3.Optional(Type3.String({ minLength: 1 })),\n  reasoning: Type3.Optional(Type3.Boolean()),\n  thinkingLevelMap: Type3.Optional(ThinkingLevelMapSchema),\n  input: Type3.Optional(Type3.Array(Type3.Union([Type3.Literal(\"text\"), Type3.Literal(\"image\")]))),\n  cost: Type3.Optional(ModelCostSchema),\n  contextWindow: Type3.Optional(Type3.Number()),\n  maxTokens: Type3.Optional(Type3.Number()),\n  samplingParams: Type3.Optional(Type3.Record(Type3.String(), Type3.Unknown())),\n  headers: Type3.Optional(Type3.Record(Type3.String(), Type3.String())),\n  compat: Type3.Optional(ProviderCompatSchema)\n});\nvar ModelOverrideSchema = Type3.Object({\n  name: Type3.Optional(Type3.String({ minLength: 1 })),\n  reasoning: Type3.Optional(Type3.Boolean()),\n  thinkingLevelMap: Type3.Optional(ThinkingLevelMapSchema),\n  input: Type3.Optional(Type3.Array(Type3.Union([Type3.Literal(\"text\"), Type3.Literal(\"image\")]))),\n  cost: Type3.Optional(Type3.Object({\n    input: Type3.Optional(Type3.Number()),\n    output: Type3.Optional(Type3.Number()),\n    cacheRead: Type3.Optional(Type3.Number()),\n    cacheWrite: Type3.Optional(Type3.Number()),\n    tiers: Type3.Optional(Type3.Array(ModelCostTierSchema))\n  })),\n  contextWindow: Type3.Optional(Type3.Number()),\n  maxTokens: Type3.Optional(Type3.Number()),\n  samplingParams: Type3.Optional(Type3.Record(Type3.String(), Type3.Unknown())),\n  headers: Type3.Optional(Type3.Record(Type3.String(), Type3.String())),\n  compat: Type3.Optional(ProviderCompatSchema)\n});\nvar ProviderConfigSchema = Type3.Object({\n  name: Type3.Optional(Type3.String({ minLength: 1 })),\n  baseUrl: Type3.Optional(Type3.String({ minLength: 1 })),\n  apiKey: Type3.Optional(Type3.String({ minLength: 1 })),\n  api: Type3.Optional(Type3.String({ minLength: 1 })),\n  oauth: Type3.Optional(Type3.Literal(\"radius\")),\n  headers: Type3.Optional(Type3.Record(Type3.String(), Type3.String())),\n  compat: Type3.Optional(ProviderCompatSchema),\n  authHeader: Type3.Optional(Type3.Boolean()),\n  models: Type3.Optional(Type3.Array(ModelDefinitionSchema)),\n  modelOverrides: Type3.Optional(Type3.Record(Type3.String(), ModelOverrideSchema))\n});\nvar ModelsConfigSchema = Type3.Object({\n  providers: Type3.Record(Type3.String(), ProviderConfigSchema)\n});\nvar validateModelsConfig = Compile2(ModelsConfigSchema);\nfunction formatValidationPath2(error) {\n  if (error.keyword === \"required\") {\n    const requiredProperties = error.params.requiredProperties;\n    const requiredProperty = requiredProperties?.[0];\n    if (requiredProperty) {\n      const basePath = error.instancePath.replace(/^\\//, \"\").replace(/\\//g, \".\");\n      return basePath ? `${basePath}.${requiredProperty}` : requiredProperty;\n    }\n  }\n  const path12 = error.instancePath.replace(/^\\//, \"\").replace(/\\//g, \".\");\n  return path12 || \"root\";\n}\nfunction deepFreeze(value) {\n  if (typeof value !== \"object\" || value === null || Object.isFrozen(value))\n    return value;\n  for (const child of Object.values(value))\n    deepFreeze(child);\n  return Object.freeze(value);\n}\nvar ModelConfig = class _ModelConfig {\n  providers;\n  error;\n  constructor(providers, error) {\n    this.providers = providers;\n    this.error = error;\n  }\n  static async load(modelsJsonPath) {\n    if (!modelsJsonPath)\n      return new _ModelConfig(/* @__PURE__ */ new Map());\n    const path12 = normalizePath(modelsJsonPath);\n    let content;\n    try {\n      content = await readFile(path12, \"utf-8\");\n    } catch (error) {\n      if (error.code === \"ENOENT\")\n        return new _ModelConfig(/* @__PURE__ */ new Map());\n      return new _ModelConfig(/* @__PURE__ */ new Map(), `Failed to load models.json: ${error instanceof Error ? error.message : error}\n\nFile: ${path12}`);\n    }\n    let parsed;\n    try {\n      parsed = JSON.parse(stripJsonComments(content));\n    } catch (error) {\n      return new _ModelConfig(/* @__PURE__ */ new Map(), `Failed to parse models.json: ${error instanceof Error ? error.message : error}\n\nFile: ${path12}`);\n    }\n    if (!validateModelsConfig.Check(parsed)) {\n      const errors = validateModelsConfig.Errors(parsed).map((error) => `  - ${formatValidationPath2(error)}: ${error.message}`).join(\"\\n\") || \"Unknown schema error\";\n      return new _ModelConfig(/* @__PURE__ */ new Map(), `Invalid models.json schema:\n${errors}\n\nFile: ${path12}`);\n    }\n    const config = parsed;\n    const providers = /* @__PURE__ */ new Map();\n    for (const [providerId, provider] of Object.entries(config.providers)) {\n      providers.set(providerId, deepFreeze(structuredClone(provider)));\n    }\n    return new _ModelConfig(providers);\n  }\n  getProvider(providerId) {\n    return this.providers.get(providerId);\n  }\n  getProviderIds() {\n    return [...this.providers.keys()];\n  }\n  getError() {\n    return this.error;\n  }\n};\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/core/models-store.js\nimport { join as join4 } from \"node:path\";\nvar sharedModelsFileReadState;\nvar InMemoryCodingAgentModelsStore = class {\n  entries = /* @__PURE__ */ new Map();\n  async read(providerId, options) {\n    options?.signal?.throwIfAborted();\n    const entry = this.entries.get(providerId);\n    return entry ? structuredClone(entry) : void 0;\n  }\n  async write(providerId, entry, options) {\n    options?.signal?.throwIfAborted();\n    this.entries.set(providerId, structuredClone(entry));\n  }\n  async delete(providerId, options) {\n    options?.signal?.throwIfAborted();\n    this.entries.delete(providerId);\n  }\n};\nvar FileModelsStore = class {\n  storage;\n  path;\n  readState;\n  constructor(path12 = join4(getAgentDir(), \"models-store.json\")) {\n    this.path = normalizePath(path12);\n    this.storage = new FileAuthStorageBackend(this.path);\n    this.readState = sharedModelsFileReadState?.path === this.path ? sharedModelsFileReadState.readState : { data: {} };\n    if (!sharedModelsFileReadState) {\n      sharedModelsFileReadState = { path: this.path, readState: this.readState };\n    }\n  }\n  parse(content) {\n    return content ? JSON.parse(content) : {};\n  }\n  updateReadState(readState, data, revision) {\n    readState.data = data;\n    readState.revision = revision;\n  }\n  reloadFromStorage(readState, options) {\n    return this.storage.withLockAsync(async (content) => {\n      const data = this.parse(content);\n      this.updateReadState(readState, data, getFileRevision(this.path));\n      return { result: data };\n    }, options);\n  }\n  async readLatest(readState, options) {\n    options?.signal?.throwIfAborted();\n    const revision = getFileRevision(this.path);\n    if (revision !== void 0 && revision === readState.revision)\n      return readState.data;\n    if (!readState.reload) {\n      const controller = new AbortController();\n      const reload2 = {\n        controller,\n        promise: this.reloadFromStorage(readState, { signal: controller.signal }),\n        readers: 0\n      };\n      readState.reload = reload2;\n      void reload2.promise.then(() => {\n        if (readState.reload === reload2)\n          readState.reload = void 0;\n      }, () => {\n        if (readState.reload === reload2)\n          readState.reload = void 0;\n      });\n    }\n    const reload = readState.reload;\n    reload.readers++;\n    try {\n      return await raceWithAbortSignal2(reload.promise, options?.signal);\n    } finally {\n      reload.readers--;\n      if (reload.readers === 0 && readState.reload === reload) {\n        readState.reload = void 0;\n        reload.controller.abort();\n      }\n    }\n  }\n  async read(providerId, options) {\n    const entry = (await this.readLatest(this.readState, options))[providerId];\n    options?.signal?.throwIfAborted();\n    return entry ? structuredClone(entry) : void 0;\n  }\n  async write(providerId, entry, options) {\n    let latest;\n    await this.storage.withLockAsync(async (content) => {\n      const current = this.parse(content);\n      current[providerId] = structuredClone(entry);\n      latest = current;\n      return { result: void 0, next: JSON.stringify(current, null, 2) };\n    }, options);\n    if (latest)\n      this.updateReadState(this.readState, latest);\n  }\n  async delete(providerId, options) {\n    let latest;\n    await this.storage.withLockAsync(async (content) => {\n      const current = this.parse(content);\n      delete current[providerId];\n      latest = current;\n      return { result: void 0, next: JSON.stringify(current, null, 2) };\n    }, options);\n    if (latest)\n      this.updateReadState(this.readState, latest);\n  }\n};\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/compat.js\nvar compat_exports = {};\n__export(compat_exports, {\n  ANTHROPIC_API_KEY_ENV: () => ANTHROPIC_API_KEY_ENV,\n  ANTHROPIC_AUTH_TOKEN_ENV: () => ANTHROPIC_AUTH_TOKEN_ENV,\n  ANTHROPIC_OAUTH_TOKEN_ENV: () => ANTHROPIC_OAUTH_TOKEN_ENV,\n  AssistantMessageEventStream: () => AssistantMessageEventStream,\n  EventStream: () => EventStream,\n  InMemoryCredentialStore: () => InMemoryCredentialStore,\n  InMemoryModelsStore: () => InMemoryModelsStore,\n  ModelsError: () => ModelsError,\n  StringEnum: () => StringEnum,\n  Type: () => Type2,\n  anthropicMessagesApi: () => anthropicMessagesApi,\n  appendAssistantMessageDiagnostic: () => appendAssistantMessageDiagnostic,\n  azureOpenAIResponsesApi: () => azureOpenAIResponsesApi,\n  bedrockConverseStreamApi: () => bedrockConverseStreamApi,\n  calculateCost: () => calculateCost,\n  clampThinkingLevel: () => clampThinkingLevel,\n  cleanupSessionResources: () => cleanupSessionResources,\n  complete: () => complete,\n  completeSimple: () => completeSimple,\n  contentText: () => contentText,\n  createAssistantMessageDiagnostic: () => createAssistantMessageDiagnostic,\n  createAssistantMessageEventStream: () => createAssistantMessageEventStream,\n  createFauxCore: () => createFauxCore,\n  createImagesModels: () => createImagesModels,\n  createImagesProvider: () => createImagesProvider,\n  createModels: () => createModels,\n  createProvider: () => createProvider,\n  defaultProviderAuthContext: () => defaultProviderAuthContext,\n  envApiKeyAuth: () => envApiKeyAuth,\n  extractDiagnosticError: () => extractDiagnosticError,\n  fauxAssistantMessage: () => fauxAssistantMessage,\n  fauxProvider: () => fauxProvider,\n  fauxText: () => fauxText,\n  fauxThinking: () => fauxThinking,\n  fauxToolCall: () => fauxToolCall,\n  findEnvKeys: () => findEnvKeys,\n  formatThrownValue: () => formatThrownValue,\n  generateImages: () => generateImages2,\n  generateImagesOpenRouter: () => generateImagesOpenRouter,\n  getApiProvider: () => getApiProvider,\n  getApiProviders: () => getApiProviders,\n  getEnvApiKey: () => getEnvApiKey,\n  getImageModel: () => getImageModel,\n  getImageModels: () => getImageModels,\n  getImageProviders: () => getImageProviders,\n  getImagesApiProvider: () => getImagesApiProvider,\n  getModel: () => getModel,\n  getModels: () => getModels,\n  getOverflowPatterns: () => getOverflowPatterns,\n  getProviders: () => getProviders,\n  getSupportedThinkingLevels: () => getSupportedThinkingLevels,\n  googleGenerativeAIApi: () => googleGenerativeAIApi,\n  googleVertexApi: () => googleVertexApi,\n  hasApi: () => hasApi,\n  isContextOverflow: () => isContextOverflow,\n  isRecoverableLength: () => isRecoverableLength,\n  isRetryableAssistantError: () => isRetryableAssistantError,\n  lazyApi: () => lazyApi,\n  lazyOAuth: () => lazyOAuth,\n  lazyStream: () => lazyStream,\n  mistralConversationsApi: () => mistralConversationsApi,\n  modelsAreEqual: () => modelsAreEqual,\n  openAICodexResponsesApi: () => openAICodexResponsesApi,\n  openAICompletionsApi: () => openAICompletionsApi,\n  openAIResponsesApi: () => openAIResponsesApi,\n  parseJsonWithRepair: () => parseJsonWithRepair,\n  parseStreamingJson: () => parseStreamingJson,\n  piMessagesApi: () => piMessagesApi,\n  registerApiProvider: () => registerApiProvider,\n  registerBuiltInApiProviders: () => registerBuiltInApiProviders,\n  registerBuiltInImagesApiProviders: () => registerBuiltInImagesApiProviders,\n  registerFauxProvider: () => registerFauxProvider,\n  registerImagesApiProvider: () => registerImagesApiProvider,\n  registerSessionResourceCleanup: () => registerSessionResourceCleanup,\n  repairJson: () => repairJson,\n  resetApiProviders: () => resetApiProviders,\n  retryAssistantCall: () => retryAssistantCall,\n  setBedrockProviderModule: () => setBedrockProviderModule,\n  stream: () => stream10,\n  streamAnthropic: () => streamAnthropic,\n  streamAzureOpenAIResponses: () => streamAzureOpenAIResponses,\n  streamGoogle: () => streamGoogle,\n  streamGoogleVertex: () => streamGoogleVertex,\n  streamMistral: () => streamMistral,\n  streamOpenAICodexResponses: () => streamOpenAICodexResponses,\n  streamOpenAICompletions: () => streamOpenAICompletions,\n  streamOpenAIResponses: () => streamOpenAIResponses,\n  streamSimple: () => streamSimple10,\n  streamSimpleAnthropic: () => streamSimpleAnthropic,\n  streamSimpleAzureOpenAIResponses: () => streamSimpleAzureOpenAIResponses,\n  streamSimpleGoogle: () => streamSimpleGoogle,\n  streamSimpleGoogleVertex: () => streamSimpleGoogleVertex,\n  streamSimpleMistral: () => streamSimpleMistral,\n  streamSimpleOpenAICodexResponses: () => streamSimpleOpenAICodexResponses,\n  streamSimpleOpenAICompletions: () => streamSimpleOpenAICompletions,\n  streamSimpleOpenAIResponses: () => streamSimpleOpenAIResponses,\n  unregisterApiProviders: () => unregisterApiProviders,\n  uuidv7: () => uuidv7,\n  validateToolArguments: () => validateToolArguments,\n  validateToolCall: () => validateToolCall\n});\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/image-models.js\nvar imageModelRegistry = /* @__PURE__ */ new Map();\nfor (const [provider, models] of Object.entries(IMAGE_MODELS)) {\n  const providerModels = /* @__PURE__ */ new Map();\n  for (const [id, model] of Object.entries(models)) {\n    providerModels.set(id, model);\n  }\n  imageModelRegistry.set(provider, providerModels);\n}\nfunction getImageModel(provider, modelId) {\n  const providerModels = imageModelRegistry.get(provider);\n  return providerModels?.get(modelId);\n}\nfunction getImageProviders() {\n  return Array.from(imageModelRegistry.keys());\n}\nfunction getImageModels(provider) {\n  const models = imageModelRegistry.get(provider);\n  return models ? Array.from(models.values()) : [];\n}\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/images-api-registry.js\nvar imagesApiProviderRegistry = /* @__PURE__ */ new Map();\nfunction wrapGenerateImages(api, generateImages3) {\n  return (model, context, options) => {\n    if (model.api !== api) {\n      throw new Error(`Mismatched api: ${model.api} expected ${api}`);\n    }\n    return generateImages3(model, context, options);\n  };\n}\nfunction registerImagesApiProvider(provider, sourceId) {\n  imagesApiProviderRegistry.set(provider.api, {\n    provider: {\n      api: provider.api,\n      generateImages: wrapGenerateImages(provider.api, provider.generateImages)\n    },\n    sourceId\n  });\n}\nfunction getImagesApiProvider(api) {\n  return imagesApiProviderRegistry.get(api)?.provider;\n}\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/providers/images/register-builtins.js\nvar openRouterImagesProviderModulePromise;\nfunction createLazyLoadErrorImages(model, error) {\n  return {\n    api: model.api,\n    provider: model.provider,\n    model: model.id,\n    output: [],\n    stopReason: \"error\",\n    errorMessage: error instanceof Error ? error.message : String(error),\n    timestamp: Date.now()\n  };\n}\nfunction loadOpenRouterImagesProviderModule() {\n  openRouterImagesProviderModulePromise ||= Promise.resolve().then(() => (init_openrouter_images(), openrouter_images_exports)).then((module) => module);\n  return openRouterImagesProviderModulePromise;\n}\nvar generateImagesOpenRouter = async (model, context, options) => {\n  try {\n    const module = await loadOpenRouterImagesProviderModule();\n    return await module.generateImages(model, context, options);\n  } catch (error) {\n    return createLazyLoadErrorImages(model, error);\n  }\n};\nfunction registerBuiltInImagesApiProviders() {\n  registerImagesApiProvider({\n    api: \"openrouter-images\",\n    generateImages: generateImagesOpenRouter\n  });\n}\nregisterBuiltInImagesApiProviders();\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/images.js\nfunction resolveImagesApiProvider(api) {\n  const provider = getImagesApiProvider(api);\n  if (!provider) {\n    throw new Error(`No API provider registered for api: ${api}`);\n  }\n  return provider;\n}\nasync function generateImages2(model, context, options) {\n  const provider = resolveImagesApiProvider(model.api);\n  return provider.generateImages(model, context, options);\n}\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/legacy-api-aliases.js\nvar anthropicMessagesStreams = anthropicMessagesApi();\nvar azureOpenAIResponsesStreams = azureOpenAIResponsesApi();\nvar googleGenerativeAIStreams = googleGenerativeAIApi();\nvar googleVertexStreams = googleVertexApi();\nvar mistralConversationsStreams = mistralConversationsApi();\nvar openAICodexResponsesStreams = openAICodexResponsesApi();\nvar openAICompletionsStreams = openAICompletionsApi();\nvar openAIResponsesStreams = openAIResponsesApi();\nvar streamAnthropic = anthropicMessagesStreams.stream;\nvar streamSimpleAnthropic = anthropicMessagesStreams.streamSimple;\nvar streamAzureOpenAIResponses = azureOpenAIResponsesStreams.stream;\nvar streamSimpleAzureOpenAIResponses = azureOpenAIResponsesStreams.streamSimple;\nvar streamGoogle = googleGenerativeAIStreams.stream;\nvar streamSimpleGoogle = googleGenerativeAIStreams.streamSimple;\nvar streamGoogleVertex = googleVertexStreams.stream;\nvar streamSimpleGoogleVertex = googleVertexStreams.streamSimple;\nvar streamMistral = mistralConversationsStreams.stream;\nvar streamSimpleMistral = mistralConversationsStreams.streamSimple;\nvar streamOpenAICodexResponses = openAICodexResponsesStreams.stream;\nvar streamSimpleOpenAICodexResponses = openAICodexResponsesStreams.streamSimple;\nvar streamOpenAICompletions = openAICompletionsStreams.stream;\nvar streamSimpleOpenAICompletions = openAICompletionsStreams.streamSimple;\nvar streamOpenAIResponses = openAIResponsesStreams.stream;\nvar streamSimpleOpenAIResponses = openAIResponsesStreams.streamSimple;\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/compat.js\nvar getModel = getBuiltinModel;\nvar getModels = getBuiltinModels;\nvar getProviders = getBuiltinProviders;\nvar apiProviderRegistry = /* @__PURE__ */ new Map();\nfunction wrapStream(api, stream11) {\n  return (model, context, options) => {\n    if (model.api !== api) {\n      throw new Error(`Mismatched api: ${model.api} expected ${api}`);\n    }\n    return stream11(model, context, options);\n  };\n}\nfunction wrapStreamSimple(api, streamSimple11) {\n  return (model, context, options) => {\n    if (model.api !== api) {\n      throw new Error(`Mismatched api: ${model.api} expected ${api}`);\n    }\n    return streamSimple11(model, context, options);\n  };\n}\nfunction registerApiProvider(provider, sourceId) {\n  apiProviderRegistry.set(provider.api, {\n    provider: {\n      api: provider.api,\n      stream: wrapStream(provider.api, provider.stream),\n      streamSimple: wrapStreamSimple(provider.api, provider.streamSimple)\n    },\n    sourceId\n  });\n}\nfunction getApiProvider(api) {\n  return apiProviderRegistry.get(api)?.provider;\n}\nfunction getApiProviders() {\n  return Array.from(apiProviderRegistry.values(), (entry) => entry.provider);\n}\nfunction unregisterApiProviders(sourceId) {\n  for (const [api, entry] of apiProviderRegistry.entries()) {\n    if (entry.sourceId === sourceId) {\n      apiProviderRegistry.delete(api);\n    }\n  }\n}\nfunction clearApiProviders() {\n  apiProviderRegistry.clear();\n}\nfunction registerFauxProvider(options = {}) {\n  const core = createFauxCore(options);\n  const sourceId = `faux-provider-${Math.random().toString(36).slice(2, 10)}`;\n  registerApiProvider({ api: core.api, stream: core.stream, streamSimple: core.streamSimple }, sourceId);\n  return {\n    api: core.api,\n    models: core.models,\n    getModel: core.getModel,\n    state: core.state,\n    setResponses: core.setResponses,\n    appendResponses: core.appendResponses,\n    getPendingResponseCount: core.getPendingResponseCount,\n    unregister() {\n      unregisterApiProviders(sourceId);\n    }\n  };\n}\nvar BUILTIN_APIS = [\n  [\"anthropic-messages\", anthropicMessagesApi()],\n  [\"openai-completions\", openAICompletionsApi()],\n  [\"openai-responses\", openAIResponsesApi()],\n  [\"openai-codex-responses\", openAICodexResponsesApi()],\n  [\"azure-openai-responses\", azureOpenAIResponsesApi()],\n  [\"google-generative-ai\", googleGenerativeAIApi()],\n  [\"google-vertex\", googleVertexApi()],\n  [\"mistral-conversations\", mistralConversationsApi()],\n  [\"bedrock-converse-stream\", bedrockConverseStreamApi()],\n  [\"pi-messages\", piMessagesApi()]\n];\nvar builtinApiProviderInstances = /* @__PURE__ */ new Map();\nfunction registerBuiltInApiProviders() {\n  for (const [api, streams] of BUILTIN_APIS) {\n    if (!getApiProvider(api)) {\n      registerApiProvider({ api, stream: streams.stream, streamSimple: streams.streamSimple });\n    }\n    builtinApiProviderInstances.set(api, getApiProvider(api));\n  }\n}\nfunction resetApiProviders() {\n  clearApiProviders();\n  builtinApiProviderInstances.clear();\n  registerBuiltInApiProviders();\n}\nregisterBuiltInApiProviders();\nvar compatModels = builtinModels();\nvar AMBIENT_AUTH_MARKER = \"<authenticated>\";\nfunction hasExplicitApiKey(apiKey) {\n  return typeof apiKey === \"string\" && apiKey.trim().length > 0;\n}\nfunction withEnvApiKey(model, options) {\n  if (hasExplicitApiKey(options?.apiKey))\n    return options;\n  const apiKey = getEnvApiKey(model.provider, options?.env);\n  if (!apiKey || apiKey === AMBIENT_AUTH_MARKER)\n    return options;\n  return { ...options, apiKey };\n}\nfunction hasResolvedCloudflareAuth(options) {\n  return hasExplicitApiKey(options?.apiKey) || typeof options?.headers?.[\"cf-aig-authorization\"] === \"string\";\n}\nfunction getBuiltinProviderForModel(model) {\n  if (getApiProvider(model.api) !== builtinApiProviderInstances.get(model.api))\n    return void 0;\n  const provider = compatModels.getProvider(model.provider);\n  return provider?.getModels().some((candidate) => candidate.api === model.api) ? provider : void 0;\n}\nfunction resolveApiProvider(api) {\n  const provider = getApiProvider(api);\n  if (!provider) {\n    throw new Error(`No API provider registered for api: ${api}`);\n  }\n  return provider;\n}\nfunction stream10(model, context, options) {\n  const builtinProvider = getBuiltinProviderForModel(model);\n  if (builtinProvider) {\n    if (model.provider.startsWith(\"cloudflare-\") && !hasResolvedCloudflareAuth(options)) {\n      return compatModels.stream(model, context, options);\n    }\n    return builtinProvider.stream(model, context, withEnvApiKey(model, options));\n  }\n  const provider = resolveApiProvider(model.api);\n  return provider.stream(model, context, withEnvApiKey(model, options));\n}\nasync function complete(model, context, options) {\n  const s = stream10(model, context, options);\n  return s.result();\n}\nfunction streamSimple10(model, context, options) {\n  const builtinProvider = getBuiltinProviderForModel(model);\n  if (builtinProvider) {\n    if (model.provider.startsWith(\"cloudflare-\") && !hasResolvedCloudflareAuth(options)) {\n      return compatModels.streamSimple(model, context, options);\n    }\n    return builtinProvider.streamSimple(model, context, withEnvApiKey(model, options));\n  }\n  const provider = resolveApiProvider(model.api);\n  return provider.streamSimple(model, context, withEnvApiKey(model, options));\n}\nasync function completeSimple(model, context, options) {\n  const s = streamSimple10(model, context, options);\n  return s.result();\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/core/provider-composer.js\nfunction mergeCompat(base, override) {\n  if (!override)\n    return base;\n  const merged = { ...base, ...override };\n  const baseNested = base;\n  const overrideNested = override;\n  const mergedNested = merged;\n  for (const key of [\"openRouterRouting\", \"vercelGatewayRouting\", \"chatTemplateKwargs\", \"chatTemplateArgs\"]) {\n    const baseValue = baseNested?.[key];\n    const overrideValue = overrideNested[key];\n    if (typeof baseValue === \"object\" && baseValue !== null || typeof overrideValue === \"object\" && overrideValue !== null) {\n      mergedNested[key] = { ...baseValue, ...overrideValue };\n    }\n  }\n  return merged;\n}\nfunction applyModelOverride(model, override) {\n  return {\n    ...model,\n    name: override.name ?? model.name,\n    reasoning: override.reasoning ?? model.reasoning,\n    thinkingLevelMap: override.thinkingLevelMap ? { ...model.thinkingLevelMap, ...override.thinkingLevelMap } : model.thinkingLevelMap,\n    input: override.input ?? model.input,\n    cost: override.cost ? {\n      input: override.cost.input ?? model.cost.input,\n      output: override.cost.output ?? model.cost.output,\n      cacheRead: override.cost.cacheRead ?? model.cost.cacheRead,\n      cacheWrite: override.cost.cacheWrite ?? model.cost.cacheWrite,\n      tiers: override.cost.tiers ?? model.cost.tiers\n    } : model.cost,\n    contextWindow: override.contextWindow ?? model.contextWindow,\n    maxTokens: override.maxTokens ?? model.maxTokens,\n    samplingParams: override.samplingParams ? { ...model.samplingParams, ...override.samplingParams } : model.samplingParams,\n    compat: mergeCompat(model.compat, override.compat)\n  };\n}\nfunction modelFromJson(providerId, definition, providerConfig, defaults) {\n  const api = definition.api ?? providerConfig.api ?? defaults?.api;\n  if (!api) {\n    throw new Error(`Provider ${providerId}, model ${definition.id}: no \"api\" specified. Set at provider or model level.`);\n  }\n  const baseUrl = definition.baseUrl ?? providerConfig.baseUrl ?? defaults?.baseUrl;\n  if (!baseUrl)\n    throw new Error(`Provider ${providerId}: \"baseUrl\" is required when defining custom models.`);\n  if (definition.contextWindow !== void 0 && definition.contextWindow <= 0) {\n    throw new Error(`Provider ${providerId}, model ${definition.id}: invalid contextWindow`);\n  }\n  if (definition.maxTokens !== void 0 && definition.maxTokens <= 0) {\n    throw new Error(`Provider ${providerId}, model ${definition.id}: invalid maxTokens`);\n  }\n  return {\n    id: definition.id,\n    name: definition.name ?? definition.id,\n    api,\n    provider: providerId,\n    baseUrl,\n    reasoning: definition.reasoning ?? false,\n    thinkingLevelMap: definition.thinkingLevelMap,\n    input: definition.input ?? [\"text\"],\n    cost: definition.cost ?? { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },\n    contextWindow: definition.contextWindow ?? 128e3,\n    maxTokens: definition.maxTokens ?? 16384,\n    samplingParams: definition.samplingParams,\n    headers: void 0,\n    compat: mergeCompat(providerConfig.compat, definition.compat)\n  };\n}\nfunction applyModelsJson(providerId, baseModels, config) {\n  if (!config)\n    return [...baseModels];\n  if (config.oauth && !config.baseUrl) {\n    throw new Error(`Provider ${providerId}: \"baseUrl\" is required when \"oauth\" is set.`);\n  }\n  const hasOverrides = config.modelOverrides && Object.keys(config.modelOverrides).length > 0;\n  if (!config.models?.length && !config.baseUrl && !config.headers && !config.compat && !hasOverrides && !config.apiKey && !config.oauth && config.authHeader === void 0) {\n    throw new Error(`Provider ${providerId}: must specify \"baseUrl\", \"headers\", \"compat\", \"modelOverrides\", or \"models\".`);\n  }\n  const models = baseModels.map((model) => ({\n    ...model,\n    baseUrl: config.oauth === \"radius\" ? model.baseUrl : config.baseUrl ?? model.baseUrl,\n    compat: mergeCompat(model.compat, config.compat)\n  }));\n  for (const definition of config.models ?? []) {\n    const existingIndex = models.findIndex((model2) => model2.id === definition.id);\n    const defaults = existingIndex >= 0 ? models[existingIndex] : models[0];\n    const model = modelFromJson(providerId, definition, config, defaults);\n    if (existingIndex >= 0)\n      models[existingIndex] = model;\n    else\n      models.push(model);\n  }\n  return models;\n}\nfunction applyExtension(providerId, models, config) {\n  if (!config)\n    return [...models];\n  if (!config.models) {\n    return config.baseUrl ? models.map((model) => ({ ...model, baseUrl: config.baseUrl })) : [...models];\n  }\n  return config.models.map((definition) => {\n    const defaults = models.find((model) => model.id === definition.id) ?? models[0];\n    const api = definition.api ?? config.api ?? defaults?.api;\n    if (!api) {\n      throw new Error(`Provider ${providerId}, model ${definition.id}: no \"api\" specified. Set at provider or model level.`);\n    }\n    const baseUrl = definition.baseUrl ?? config.baseUrl ?? defaults?.baseUrl;\n    if (!baseUrl)\n      throw new Error(`Provider ${providerId}: \"baseUrl\" is required when defining custom models.`);\n    return {\n      ...definition,\n      api,\n      provider: providerId,\n      baseUrl,\n      headers: void 0\n    };\n  });\n}\nfunction adaptOAuth(config) {\n  return {\n    name: config.name,\n    isSubscription: config.isSubscription,\n    login: async (callbacks) => {\n      const credential = await config.login({\n        onAuth: (info) => callbacks.notify({ type: \"auth_url\", ...info }),\n        onDeviceCode: (info) => callbacks.notify({ type: \"device_code\", ...info }),\n        onPrompt: (prompt) => callbacks.prompt({ type: \"text\", ...prompt }),\n        onProgress: (message) => callbacks.notify({ type: \"progress\", message }),\n        onManualCodeInput: () => callbacks.prompt({ type: \"manual_code\", message: \"Paste the authorization code\" }),\n        onSelect: (prompt) => callbacks.prompt({ type: \"select\", ...prompt }),\n        signal: callbacks.signal\n      });\n      return { ...credential, type: \"oauth\" };\n    },\n    refresh: async (credential, signal) => ({ ...await config.refreshToken(credential, signal), type: \"oauth\" }),\n    toAuth: async (credential) => ({ apiKey: config.getApiKey(credential) })\n  };\n}\nfunction withConfiguredAuth(auth, headers, authHeader) {\n  let mergedHeaders = auth.headers || headers ? { ...auth.headers, ...headers } : void 0;\n  if (authHeader) {\n    if (!auth.apiKey)\n      throw new Error(\"authHeader requires a resolved API key\");\n    mergedHeaders = { ...mergedHeaders, Authorization: `Bearer ${auth.apiKey}` };\n  }\n  return { ...auth, headers: mergedHeaders };\n}\nfunction configuredApiKey(config, extension) {\n  return extension?.apiKey ?? config?.apiKey;\n}\nfunction configuredHeaders(config, extension) {\n  if (!config?.headers && !extension?.headers)\n    return void 0;\n  return { ...config?.headers, ...extension?.headers };\n}\nasync function configContextEnv(values, ctx, explicit) {\n  const env = { ...explicit };\n  for (const name of new Set(values.flatMap(getConfigValueEnvVarNames))) {\n    if (env[name] !== void 0)\n      continue;\n    const value = await ctx.env(name);\n    if (value !== void 0)\n      env[name] = value;\n  }\n  return Object.keys(env).length > 0 ? env : void 0;\n}\nfunction composeApiKeyAuth(providerId, base, config, extension) {\n  const inherited = base?.auth.apiKey;\n  const rawKey = configuredApiKey(config, extension);\n  const oauth = extension?.oauth ?? base?.auth.oauth;\n  if (!inherited && rawKey === void 0 && oauth)\n    return void 0;\n  const rawHeaders = configuredHeaders(config, extension);\n  const authHeader = extension?.authHeader ?? config?.authHeader ?? false;\n  return {\n    name: inherited?.name ?? \"API key\",\n    login: inherited?.login ?? (async (interaction) => ({\n      type: \"api_key\",\n      key: await interaction.prompt({ type: \"secret\", message: \"Enter API key\" })\n    })),\n    check: async (input) => {\n      if (input.credential) {\n        if (inherited?.check)\n          return inherited.check(input);\n        if (input.credential.key)\n          return { type: \"api_key\", source: \"stored credential\" };\n        const resolved2 = await inherited?.resolve(input);\n        return resolved2 ? { type: \"api_key\", source: resolved2.source } : void 0;\n      }\n      if (rawKey !== void 0) {\n        if (isCommandConfigValue(rawKey))\n          return { type: \"api_key\", source: \"configured API key\" };\n        const envNames = getConfigValueEnvVarNames(rawKey);\n        for (const name of envNames) {\n          if (await input.ctx.env(name) === void 0)\n            return void 0;\n        }\n        return { type: \"api_key\", source: \"configured API key\" };\n      }\n      if (inherited?.check)\n        return inherited.check(input);\n      const resolved = await inherited?.resolve(input);\n      return resolved ? { type: \"api_key\", source: resolved.source } : void 0;\n    },\n    resolve: async (input) => {\n      let result;\n      if (input.credential) {\n        result = inherited ? await inherited.resolve(input) : input.credential.key ? { auth: { apiKey: input.credential.key }, env: input.credential.env, source: \"stored credential\" } : void 0;\n      } else if (rawKey !== void 0) {\n        const env = await configContextEnv([rawKey], input.ctx);\n        const key = resolveConfigValueOrThrow(rawKey, `API key for provider \"${providerId}\"`, env);\n        result = inherited ? await inherited.resolve({ ...input, credential: { type: \"api_key\", key } }) : { auth: { apiKey: key }, source: \"configured API key\" };\n      } else {\n        result = await inherited?.resolve(input);\n      }\n      if (!result)\n        return void 0;\n      const explicitEnv = { ...input.credential?.env ?? {}, ...result.env ?? {} };\n      const headerEnv = await configContextEnv(Object.values(rawHeaders ?? {}), input.ctx, explicitEnv);\n      const headers = resolveHeadersOrThrow(rawHeaders, `provider \"${providerId}\"`, headerEnv);\n      return { ...result, auth: withConfiguredAuth(result.auth, headers, authHeader) };\n    }\n  };\n}\nfunction composeOAuthAuth(providerId, base, config, extension) {\n  const oauth = extension?.oauth ? adaptOAuth(extension.oauth) : base?.auth.oauth;\n  if (!oauth)\n    return void 0;\n  const rawHeaders = configuredHeaders(config, extension);\n  const authHeader = extension?.authHeader ?? config?.authHeader ?? false;\n  return {\n    ...oauth,\n    toAuth: async (credential) => {\n      const auth = await oauth.toAuth(credential);\n      const env = credential.env;\n      const headers = resolveHeadersOrThrow(rawHeaders, `provider \"${providerId}\"`, typeof env === \"object\" && env !== null ? env : void 0);\n      return withConfiguredAuth(auth, headers, authHeader);\n    }\n  };\n}\nfunction rawModelHeaders(model, config, extension) {\n  const definition = config?.models?.find((entry) => entry.id === model.id);\n  const extensionModel = extension?.models?.find((entry) => entry.id === model.id);\n  const headers = {\n    ...config?.modelOverrides?.[model.id]?.headers,\n    ...definition?.headers,\n    ...extensionModel?.headers\n  };\n  return Object.keys(headers).length > 0 ? headers : void 0;\n}\nfunction validateExtensionProvider(providerId, base, modelsConfig, extension) {\n  if (extension.streamSimple && !extension.api) {\n    throw new Error(`Provider ${providerId}: \"api\" is required when registering streamSimple.`);\n  }\n  applyExtension(providerId, applyModelsJson(providerId, base?.getModels() ?? [], modelsConfig), extension);\n}\nfunction composeModelProvider(providerId, base, modelConfig, extension) {\n  const config = modelConfig.getProvider(providerId);\n  let extensionOAuthCredential;\n  let refreshedExtensionModels;\n  const currentExtension = () => extension && refreshedExtensionModels ? { ...extension, models: refreshedExtensionModels } : extension;\n  const getModels2 = () => {\n    let models = applyExtension(providerId, applyModelsJson(providerId, base?.getModels() ?? [], config), currentExtension());\n    if (extensionOAuthCredential && extension?.oauth?.modifyModels) {\n      models = extension.oauth.modifyModels(models, extensionOAuthCredential);\n    }\n    return models.map((model) => {\n      const override = config?.modelOverrides?.[model.id];\n      return override ? applyModelOverride(model, override) : model;\n    });\n  };\n  getModels2();\n  const apiKey = composeApiKeyAuth(providerId, base, config, extension);\n  const oauth = composeOAuthAuth(providerId, base, config, extension);\n  if (!apiKey && !oauth)\n    throw new Error(`Provider ${providerId}: no authentication method configured.`);\n  const supportsBaseApi = (model) => base?.getModels().some((entry) => entry.api === model.api) ?? false;\n  const streamWith = (model, context, options, simple) => lazyStream(model, async () => {\n    if (extension?.streamSimple && model.api === extension.api) {\n      return extension.streamSimple(model, context, options);\n    }\n    if (base && supportsBaseApi(model)) {\n      return simple ? base.streamSimple(model, context, options) : base.stream(model, context, options);\n    }\n    const api = getApiProvider(model.api);\n    if (!api)\n      throw new Error(`No API provider registered for api: ${model.api}`);\n    return simple ? api.streamSimple(model, context, options) : api.stream(model, context, options);\n  });\n  const provider = {\n    id: providerId,\n    name: extension?.name ?? config?.name ?? base?.name ?? extension?.oauth?.name ?? providerId,\n    baseUrl: extension?.baseUrl ?? config?.baseUrl ?? base?.baseUrl,\n    headers: base?.headers,\n    auth: { ...apiKey ? { apiKey } : {}, ...oauth ? { oauth } : {} },\n    getModels: getModels2,\n    refreshModels: base?.refreshModels || extension?.refreshModels || extension?.oauth?.modifyModels ? async (context) => {\n      await base?.refreshModels?.(context);\n      let refreshed;\n      if (extension?.refreshModels)\n        refreshed = await extension.refreshModels(context);\n      if (context.signal.aborted)\n        return;\n      const oauthCredential = context.credential?.type === \"oauth\" ? context.credential : void 0;\n      await context.publish({\n        update: () => {\n          if (refreshed) {\n            applyExtension(providerId, applyModelsJson(providerId, base?.getModels() ?? [], config), {\n              ...extension,\n              models: refreshed\n            });\n            refreshedExtensionModels = refreshed;\n          }\n          extensionOAuthCredential = oauthCredential;\n        }\n      });\n    } : void 0,\n    filterModels: base?.filterModels ? (models, credential) => base.filterModels(models, credential) : void 0,\n    stream: (model, context, options) => streamWith(model, context, options, false),\n    streamSimple: (model, context, options) => streamWith(model, context, options, true)\n  };\n  const fetchDeferred = base?.fetchDeferred;\n  if (fetchDeferred) {\n    provider.fetchDeferred = (model, handle, options) => fetchDeferred(model, handle, options);\n  }\n  const cancelDeferred = base?.cancelDeferred;\n  if (cancelDeferred) {\n    provider.cancelDeferred = (model, handle, options) => cancelDeferred(model, handle, options);\n  }\n  return provider;\n}\nfunction resolveConfiguredModelHeaders(model, config, extension, env) {\n  return resolveHeadersOrThrow(rawModelHeaders(model, config, extension), `model \"${model.provider}/${model.id}\"`, env);\n}\nfunction resolveCompatibilityRequestConfig(model, config, extension) {\n  const configured = resolveHeadersOrThrow({ ...configuredHeaders(config, extension), ...rawModelHeaders(model, config, extension) }, `model \"${model.provider}/${model.id}\"`);\n  return {\n    headers: model.headers || configured ? { ...model.headers, ...configured } : void 0,\n    authHeader: extension?.authHeader ?? config?.authHeader ?? false\n  };\n}\nfunction configuredRequestAuthStatus(config, extension) {\n  const value = configuredApiKey(config, extension);\n  if (value === void 0)\n    return void 0;\n  if (isCommandConfigValue(value))\n    return { configured: true, source: \"models_json_command\" };\n  const names = getConfigValueEnvVarNames(value);\n  if (names.length > 0) {\n    return isConfigValueConfigured(value) ? { configured: true, source: \"environment\", label: names.join(\", \") } : { configured: false };\n  }\n  return { configured: true, source: extension?.apiKey !== void 0 ? \"fallback\" : \"models_json_key\" };\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/utils/management-http.js\nvar RETRYABLE_STATUS_CODES = /* @__PURE__ */ new Set([408, 425, 429, 500, 502, 503, 504]);\nasync function fetchWithRetry(input, init = void 0, options = {}) {\n  const maxRetries = options.maxRetries === void 0 || !Number.isFinite(options.maxRetries) ? 2 : Math.max(0, Math.floor(options.maxRetries));\n  const retryOnStatus = options.retryOnStatus ?? true;\n  const parentSignal = init?.signal;\n  const timeoutSignal = options.timeoutMs !== void 0 && options.timeoutMs > 0 ? AbortSignal.timeout(options.timeoutMs) : void 0;\n  const signal = timeoutSignal ? parentSignal ? AbortSignal.any([parentSignal, timeoutSignal]) : timeoutSignal : parentSignal;\n  for (let attempt = 0; ; attempt++) {\n    signal?.throwIfAborted();\n    try {\n      const response = await fetch(input, signal ? { ...init, signal } : init);\n      const shouldRetry = retryOnStatus && RETRYABLE_STATUS_CODES.has(response.status) && attempt < maxRetries;\n      if (!shouldRetry)\n        return response;\n      try {\n        await response.body?.cancel();\n      } catch {\n      }\n    } catch (error) {\n      if (parentSignal?.aborted || timeoutSignal?.aborted || error instanceof Error && error.name === \"AbortError\" && timeoutSignal === void 0 || attempt >= maxRetries) {\n        throw error;\n      }\n    }\n  }\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/utils/pi-user-agent.js\nfunction getPiUserAgent2(version) {\n  const runtime = process.versions.bun ? `bun/${process.versions.bun}` : `node/${process.version}`;\n  return `pi/${version} (${process.platform}; ${runtime}; ${process.arch})`;\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/core/remote-catalog-provider.js\nvar DEFAULT_CATALOG_BASE_URL = \"https://pi.dev\";\nvar REMOTE_CATALOG_REFRESH_INTERVAL_MS = 4 * 60 * 60 * 1e3;\nfunction mergeModels(baseline, dynamic) {\n  const merged = [...baseline];\n  for (const model of dynamic) {\n    const index = merged.findIndex((entry) => entry.id === model.id);\n    if (index >= 0)\n      merged[index] = model;\n    else\n      merged.push(model);\n  }\n  return merged;\n}\nfunction parseCatalog(providerId, value) {\n  const entries = Array.isArray(value) ? value : typeof value === \"object\" && value !== null && \"models\" in value && Array.isArray(value.models) ? value.models : typeof value === \"object\" && value !== null ? Object.values(value) : void 0;\n  if (!entries)\n    throw new Error(`Invalid model catalog for provider \"${providerId}\"`);\n  return entries.filter((entry) => typeof entry === \"object\" && entry !== null && \"id\" in entry).map((model) => ({ ...model, provider: providerId }));\n}\nfunction remoteModels(entry, localGeneratedAt) {\n  if (!entry)\n    return [];\n  if (localGeneratedAt !== void 0 && (entry.lastModified === void 0 || entry.lastModified <= localGeneratedAt)) {\n    return [];\n  }\n  return entry.models;\n}\nfunction withRemoteCatalog(provider, catalogBaseUrl = DEFAULT_CATALOG_BASE_URL, localGeneratedAt) {\n  let dynamicModels = [];\n  return {\n    ...provider,\n    getModels: () => mergeModels(provider.getModels(), dynamicModels),\n    refreshModels: async (context) => {\n      const stored = context.stored;\n      const restored = remoteModels(stored, localGeneratedAt).filter((model) => model.provider === provider.id);\n      if (!await context.publish({\n        update: () => {\n          dynamicModels = restored;\n        }\n      })) {\n        return;\n      }\n      if (!context.allowNetwork || context.signal.aborted)\n        return;\n      if (!context.force && stored?.checkedAt !== void 0 && stored.lastModified !== void 0 && Date.now() - stored.checkedAt < REMOTE_CATALOG_REFRESH_INTERVAL_MS) {\n        return;\n      }\n      const validator = stored?.models.length ? stored.etag : void 0;\n      const url = new URL(`/api/models/providers/${encodeURIComponent(provider.id)}`, catalogBaseUrl);\n      const response = await fetchWithRetry(url, {\n        headers: {\n          accept: \"application/json\",\n          \"User-Agent\": getPiUserAgent2(VERSION),\n          ...validator ? { \"if-none-match\": validator } : {}\n        },\n        signal: context.signal\n      });\n      if (context.signal.aborted)\n        return;\n      const checkedAt = Date.now();\n      if (response.status === 304 && stored) {\n        await context.publish({ persist: { ...stored, checkedAt } });\n        return;\n      }\n      if (response.status === 404 || response.status === 501) {\n        await context.publish({\n          persist: {\n            ...stored ?? { models: [] },\n            checkedAt,\n            lastModified: 0,\n            etag: void 0\n          }\n        });\n        return;\n      }\n      if (!response.ok) {\n        await context.publish({ persist: { ...stored ?? { models: [] }, checkedAt } });\n        throw new Error(`Model catalog request failed for ${provider.id}: ${response.status}`);\n      }\n      const refreshed = parseCatalog(provider.id, await response.json());\n      const lastModified = Date.parse(response.headers.get(\"last-modified\") ?? \"\");\n      if (context.signal.aborted)\n        return;\n      const entry = {\n        models: refreshed,\n        checkedAt,\n        lastModified: Number.isNaN(lastModified) ? 0 : lastModified,\n        etag: response.headers.get(\"etag\") ?? void 0\n      };\n      const published = remoteModels(entry, localGeneratedAt);\n      await context.publish({\n        persist: entry,\n        update: () => {\n          dynamicModels = published;\n        }\n      });\n    }\n  };\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/core/runtime-credentials.js\nvar RuntimeCredentials = class {\n  store;\n  overrides = /* @__PURE__ */ new Map();\n  constructor(store) {\n    this.store = store;\n  }\n  setRuntimeApiKey(providerId, apiKey) {\n    this.overrides.set(providerId, apiKey);\n  }\n  removeRuntimeApiKey(providerId) {\n    this.overrides.delete(providerId);\n  }\n  hasRuntimeApiKey(providerId) {\n    return this.overrides.has(providerId);\n  }\n  async read(providerId, options) {\n    options?.signal?.throwIfAborted();\n    const override = this.overrides.get(providerId);\n    return override ? { type: \"api_key\", key: override } : this.store.read(providerId, options);\n  }\n  async list(options) {\n    const entries = new Map((await this.store.list(options)).map((entry) => [entry.providerId, entry]));\n    options?.signal?.throwIfAborted();\n    for (const providerId of this.overrides.keys()) {\n      entries.set(providerId, { providerId, type: \"api_key\" });\n    }\n    return [...entries.values()];\n  }\n  modify(providerId, fn, options) {\n    return this.store.modify(providerId, fn, options);\n  }\n  async delete(providerId, options) {\n    options?.signal?.throwIfAborted();\n    await this.store.delete(providerId, options);\n    this.overrides.delete(providerId);\n  }\n};\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/core/model-runtime.js\nvar CredentialSynchronizationError = class extends Error {\n  providerId;\n  operation;\n  credential;\n  constructor(providerId, operation, credential, options) {\n    super(`Credential ${operation} committed for ${providerId}, but local synchronization failed`, options);\n    this.name = \"CredentialSynchronizationError\";\n    this.providerId = providerId;\n    this.operation = operation;\n    this.credential = credential;\n  }\n};\nfunction mergeHeaders3(base, override) {\n  if (!base && !override)\n    return void 0;\n  const merged = { ...base };\n  for (const [name, value] of Object.entries(override ?? {})) {\n    const lowerName = name.toLowerCase();\n    for (const existingName of Object.keys(merged)) {\n      if (existingName.toLowerCase() === lowerName)\n        delete merged[existingName];\n    }\n    merged[name] = value;\n  }\n  return merged;\n}\nvar ModelRuntime = class _ModelRuntime {\n  models;\n  credentials;\n  defaultBuiltins;\n  builtins = /* @__PURE__ */ new Map();\n  nativeExtensionProviders = /* @__PURE__ */ new Map();\n  extensionProviders = /* @__PURE__ */ new Map();\n  compositionErrors = /* @__PURE__ */ new Map();\n  modelsPath;\n  modelNetworkEnabled;\n  config;\n  snapshot = {\n    all: [],\n    available: [],\n    configuredProviders: /* @__PURE__ */ new Set(),\n    storedProviders: /* @__PURE__ */ new Set(),\n    auth: /* @__PURE__ */ new Map()\n  };\n  availabilityRefreshSeq = 0;\n  availabilityErrorSeq = 0;\n  providerAvailabilitySeq = /* @__PURE__ */ new Map();\n  availabilityError;\n  credentialOperations = /* @__PURE__ */ new Map();\n  constructor(credentials, config, modelsPath, modelsStore, providers, modelNetworkEnabled) {\n    this.credentials = credentials;\n    this.config = config;\n    this.modelsPath = modelsPath;\n    this.modelNetworkEnabled = modelNetworkEnabled;\n    this.defaultBuiltins = new Map(providers.map((provider) => [provider.id, provider]));\n    for (const [providerId, provider] of this.defaultBuiltins)\n      this.builtins.set(providerId, provider);\n    this.models = createModels({ credentials, modelsStore });\n    this.rebuildProviders();\n  }\n  static async create(options = {}) {\n    const credentials = new RuntimeCredentials(options.credentials ?? AuthStorage.create(options.authPath));\n    const modelsPath = options.modelsPath === null ? void 0 : options.modelsPath ?? join5(getAgentDir(), \"models.json\");\n    const config = await ModelConfig.load(modelsPath);\n    const modelsStore = options.modelsStore ?? (modelsPath ? new FileModelsStore(options.modelsStorePath ?? join5(dirname3(modelsPath), \"models-store.json\")) : new InMemoryCodingAgentModelsStore());\n    const builtinModelDataGeneratedAt = getBuiltinModelDataGeneratedAt();\n    const providers = builtinProviders().map((provider) => provider.id === \"radius\" ? provider : withRemoteCatalog(provider, options.catalogBaseUrl, builtinModelDataGeneratedAt));\n    const runtime = new _ModelRuntime(credentials, config, modelsPath, modelsStore, providers, process.env.PI_OFFLINE === void 0);\n    runtime.configureRadiusProviders();\n    runtime.rebuildProviders();\n    const refreshFromNetwork = runtime.modelNetworkEnabled && options.allowModelNetwork === true;\n    const controller = refreshFromNetwork && options.modelRefreshTimeoutMs !== void 0 ? new AbortController() : void 0;\n    const timeout = controller ? setTimeout(() => controller.abort(), options.modelRefreshTimeoutMs) : void 0;\n    const signal = controller ? options.signal ? AbortSignal.any([options.signal, controller.signal]) : controller.signal : options.signal;\n    try {\n      if (options.refreshOnCreate !== false) {\n        await runtime.refresh({ allowNetwork: refreshFromNetwork, signal });\n      }\n    } finally {\n      if (timeout)\n        clearTimeout(timeout);\n    }\n    return runtime;\n  }\n  configureRadiusProviders() {\n    this.builtins.clear();\n    for (const [providerId, provider] of this.defaultBuiltins)\n      this.builtins.set(providerId, provider);\n    for (const providerId of this.config.getProviderIds()) {\n      const config = this.config.getProvider(providerId);\n      if (config?.oauth !== \"radius\" || !config.baseUrl)\n        continue;\n      this.builtins.set(providerId, radiusProvider({\n        id: providerId,\n        name: config.name ?? providerId,\n        gateway: config.baseUrl.replace(/\\/v1\\/?$/u, \"\")\n      }));\n    }\n  }\n  providerIds() {\n    return /* @__PURE__ */ new Set([\n      ...this.builtins.keys(),\n      ...this.nativeExtensionProviders.keys(),\n      ...this.config.getProviderIds(),\n      ...this.extensionProviders.keys()\n    ]);\n  }\n  recomposeProvider(providerId) {\n    const base = this.nativeExtensionProviders.get(providerId) ?? this.builtins.get(providerId);\n    const extension = this.extensionProviders.get(providerId);\n    if (!base && !this.config.getProvider(providerId) && !extension) {\n      this.models.deleteProvider(providerId);\n      this.compositionErrors.delete(providerId);\n      return;\n    }\n    if (base && !this.config.getProvider(providerId) && !extension) {\n      this.models.setProvider(base);\n      this.compositionErrors.delete(providerId);\n      return;\n    }\n    try {\n      this.models.setProvider(composeModelProvider(providerId, base, this.config, extension));\n      this.compositionErrors.delete(providerId);\n    } catch (error) {\n      this.compositionErrors.set(providerId, error instanceof Error ? error.message : String(error));\n      if (base)\n        this.models.setProvider(base);\n      else\n        this.models.deleteProvider(providerId);\n    }\n  }\n  rebuildProviders() {\n    this.models.clearProviders();\n    this.compositionErrors.clear();\n    for (const providerId of this.providerIds())\n      this.recomposeProvider(providerId);\n    this.updateModelSnapshot();\n  }\n  updateModelSnapshot() {\n    const all = [...this.models.getModels()];\n    this.snapshot = {\n      ...this.snapshot,\n      all,\n      available: all.filter((model) => this.snapshot.configuredProviders.has(model.provider))\n    };\n  }\n  async runAvailabilityRefresh(seq, errorSeq, signal) {\n    const providers = this.models.getProviders();\n    const [available, checks, credentials] = await Promise.all([\n      this.models.getAvailable(void 0, { signal }),\n      Promise.all(providers.map(async (provider) => [\n        provider.id,\n        await this.models.checkAuth(provider.id, { signal })\n      ])),\n      this.credentials.list({ signal })\n    ]);\n    if (seq !== this.availabilityRefreshSeq)\n      return;\n    const auth = new Map(checks);\n    const configuredProviders = new Set(checks.filter((entry) => entry[1] !== void 0).map(([providerId]) => providerId));\n    this.snapshot = {\n      all: [...this.models.getModels()],\n      available: [...available],\n      configuredProviders,\n      storedProviders: new Set(credentials.map((entry) => entry.providerId)),\n      auth\n    };\n    if (errorSeq === this.availabilityErrorSeq)\n      this.availabilityError = void 0;\n  }\n  queueAvailabilityRefresh(signal) {\n    const seq = ++this.availabilityRefreshSeq;\n    for (const [providerId, providerSeq] of this.providerAvailabilitySeq) {\n      this.providerAvailabilitySeq.set(providerId, providerSeq + 1);\n    }\n    const errorSeq = ++this.availabilityErrorSeq;\n    const effectiveSignal = operationSignal2(signal);\n    return this.runAvailabilityRefresh(seq, errorSeq, effectiveSignal).catch((error) => {\n      if (errorSeq === this.availabilityErrorSeq && !effectiveSignal.aborted) {\n        this.availabilityError = error instanceof Error ? error.message : String(error);\n      }\n      throw error;\n    });\n  }\n  async refreshProviderAvailability(providerId, signal) {\n    ++this.availabilityRefreshSeq;\n    const providerSeq = (this.providerAvailabilitySeq.get(providerId) ?? 0) + 1;\n    this.providerAvailabilitySeq.set(providerId, providerSeq);\n    const errorSeq = ++this.availabilityErrorSeq;\n    try {\n      const [available, auth, credential] = await Promise.all([\n        this.models.getAvailable(providerId, { signal }),\n        this.models.checkAuth(providerId, { signal }),\n        this.credentials.read(providerId, { signal })\n      ]);\n      signal.throwIfAborted();\n      if (this.providerAvailabilitySeq.get(providerId) !== providerSeq)\n        return;\n      const configuredProviders = new Set(this.snapshot.configuredProviders);\n      const storedProviders = new Set(this.snapshot.storedProviders);\n      const authByProvider = new Map(this.snapshot.auth);\n      if (auth) {\n        configuredProviders.add(providerId);\n        authByProvider.set(providerId, auth);\n      } else {\n        configuredProviders.delete(providerId);\n        authByProvider.delete(providerId);\n      }\n      if (credential)\n        storedProviders.add(providerId);\n      else\n        storedProviders.delete(providerId);\n      const all = [...this.models.getModels()];\n      const availableById = new Map([...this.snapshot.available.filter((model) => model.provider !== providerId), ...available].map((model) => [\n        `${model.provider}\\0${model.id}`,\n        model\n      ]));\n      this.snapshot = {\n        all,\n        available: all.flatMap((model) => availableById.get(`${model.provider}\\0${model.id}`) ?? []),\n        configuredProviders,\n        storedProviders,\n        auth: authByProvider\n      };\n      if (errorSeq === this.availabilityErrorSeq)\n        this.availabilityError = void 0;\n    } catch (error) {\n      if (this.providerAvailabilitySeq.get(providerId) === providerSeq && errorSeq === this.availabilityErrorSeq && !signal.aborted) {\n        this.availabilityError = error instanceof Error ? error.message : String(error);\n      }\n      throw error;\n    }\n  }\n  getProviders() {\n    return this.models.getProviders();\n  }\n  getProvider(providerId) {\n    return this.models.getProvider(providerId);\n  }\n  getModels(providerId) {\n    return this.models.getModels(providerId);\n  }\n  getModel(providerId, modelId) {\n    return this.models.getModel(providerId, modelId);\n  }\n  async checkAuth(providerId, options) {\n    return this.models.checkAuth(providerId, options);\n  }\n  async getAvailable(providerId, options) {\n    if (providerId) {\n      const errorSeq = ++this.availabilityErrorSeq;\n      try {\n        const available = await this.models.getAvailable(providerId, options);\n        if (errorSeq === this.availabilityErrorSeq)\n          this.availabilityError = void 0;\n        return available;\n      } catch (error) {\n        if (errorSeq === this.availabilityErrorSeq && !options?.signal?.aborted) {\n          this.availabilityError = error instanceof Error ? error.message : String(error);\n        }\n        throw error;\n      }\n    }\n    await this.queueAvailabilityRefresh(options?.signal);\n    return this.snapshot.available;\n  }\n  getAvailableSnapshot() {\n    return this.snapshot.available;\n  }\n  getError() {\n    const errors = [];\n    const configError = this.config.getError();\n    if (configError)\n      errors.push(configError);\n    for (const [providerId, error] of this.compositionErrors) {\n      errors.push(`Provider \"${providerId}\": ${error}`);\n    }\n    if (this.availabilityError)\n      errors.push(`Availability refresh: ${this.availabilityError}`);\n    return errors.length > 0 ? errors.join(\"\\n\\n\") : void 0;\n  }\n  getRegisteredProviderConfig(providerId) {\n    return this.extensionProviders.get(providerId);\n  }\n  getRegisteredProviderIds() {\n    return [.../* @__PURE__ */ new Set([...this.extensionProviders.keys(), ...this.nativeExtensionProviders.keys()])];\n  }\n  getRegisteredNativeProvider(providerId) {\n    return this.nativeExtensionProviders.get(providerId);\n  }\n  /** @internal Compatibility fallback for ModelRegistry when provider auth is unconfigured. */\n  getCompatibilityRequestConfig(model) {\n    return resolveCompatibilityRequestConfig(model, this.config.getProvider(model.provider), this.extensionProviders.get(model.provider));\n  }\n  isUsingOAuth(providerId) {\n    return this.snapshot.auth.get(providerId)?.type === \"oauth\";\n  }\n  isUsingSubscription(providerId) {\n    return this.isUsingOAuth(providerId) && this.models.getProvider(providerId)?.auth.oauth?.isSubscription === true;\n  }\n  hasConfiguredAuth(providerId) {\n    return this.snapshot.configuredProviders.has(providerId);\n  }\n  async getAuth(providerOrModel, overrides = {}) {\n    if (typeof providerOrModel === \"string\")\n      return this.models.getAuth(providerOrModel, overrides);\n    const resolution = await this.models.getAuth(providerOrModel, overrides);\n    if (!resolution)\n      return void 0;\n    const configuredHeaders2 = resolveConfiguredModelHeaders(providerOrModel, this.config.getProvider(providerOrModel.provider), this.extensionProviders.get(providerOrModel.provider), { ...resolution.env ?? {}, ...overrides.env ?? {} });\n    return {\n      ...resolution,\n      auth: {\n        ...resolution.auth,\n        headers: mergeHeaders3(resolution.auth.headers, configuredHeaders2)\n      }\n    };\n  }\n  enqueueCredentialOperation(providerId, signal, task) {\n    const previous = this.credentialOperations.get(providerId) ?? Promise.resolve();\n    let markStarted;\n    const started = new Promise((resolve15) => {\n      markStarted = resolve15;\n    });\n    const operation = (async () => {\n      await previous.catch(() => {\n      });\n      signal.throwIfAborted();\n      markStarted?.();\n      return task();\n    })();\n    const tail = operation.catch(() => {\n    });\n    this.credentialOperations.set(providerId, tail);\n    void tail.then(() => {\n      if (this.credentialOperations.get(providerId) === tail)\n        this.credentialOperations.delete(providerId);\n    });\n    return raceWithAbortSignal2(started, signal).then(() => operation);\n  }\n  async synchronizeCredentialState(providerId, operation, credential, signal) {\n    try {\n      signal.throwIfAborted();\n      this.recomposeProvider(providerId);\n      const compositionError = this.compositionErrors.get(providerId);\n      if (compositionError)\n        throw new Error(compositionError);\n      const result = await this.models.refresh({ allowNetwork: false, providers: [providerId], signal });\n      if (result.aborted)\n        signal.throwIfAborted();\n      const refreshError = result.errors.get(providerId);\n      if (refreshError)\n        throw refreshError;\n      this.updateModelSnapshot();\n      await this.refreshProviderAvailability(providerId, signal);\n    } catch (cause) {\n      throw new CredentialSynchronizationError(providerId, operation, credential, { cause });\n    }\n  }\n  setRuntimeApiKey(providerId, apiKey, options = {}) {\n    const signal = operationSignal2(options.signal);\n    return this.enqueueCredentialOperation(providerId, signal, async () => {\n      this.credentials.setRuntimeApiKey(providerId, apiKey);\n      await this.synchronizeCredentialState(providerId, \"setRuntimeApiKey\", { type: \"api_key\", key: apiKey }, signal);\n    });\n  }\n  removeRuntimeApiKey(providerId, options = {}) {\n    const signal = operationSignal2(options.signal);\n    return this.enqueueCredentialOperation(providerId, signal, async () => {\n      this.credentials.removeRuntimeApiKey(providerId);\n      await this.synchronizeCredentialState(providerId, \"removeRuntimeApiKey\", void 0, signal);\n    });\n  }\n  listCredentials(options) {\n    return this.credentials.list(options);\n  }\n  getProviderAuthStatus(providerId) {\n    if (this.credentials.hasRuntimeApiKey(providerId))\n      return { configured: true, source: \"runtime\" };\n    if (this.snapshot.storedProviders.has(providerId))\n      return { configured: true, source: \"stored\" };\n    const configured = configuredRequestAuthStatus(this.config.getProvider(providerId), this.extensionProviders.get(providerId));\n    if (configured)\n      return configured;\n    const check = this.snapshot.auth.get(providerId);\n    return check ? { configured: true, source: \"environment\", label: check.source } : { configured: false };\n  }\n  async prepareRequest(model, options) {\n    const provider = this.models.getProvider(model.provider);\n    if (!provider)\n      throw new ModelsError(\"provider\", `Unknown provider: ${model.provider}`);\n    const resolution = await this.getAuth(model, {\n      apiKey: options?.apiKey,\n      env: options?.env,\n      signal: options?.signal\n    });\n    if (!resolution)\n      throw new ModelsError(\"auth\", `Provider is not configured: ${model.provider}`);\n    const { transformHeaders, ...rawProviderOptions } = options ?? {};\n    const providerOptions = rawProviderOptions;\n    let headers = mergeHeaders3(resolution.auth.headers, providerOptions.headers);\n    if (transformHeaders)\n      headers = await transformHeaders(headers ?? {});\n    const env = resolution.env || providerOptions.env ? { ...resolution.env ?? {}, ...providerOptions.env ?? {} } : void 0;\n    return {\n      provider,\n      model: resolution.auth.baseUrl ? { ...model, baseUrl: resolution.auth.baseUrl } : model,\n      options: {\n        ...providerOptions,\n        apiKey: providerOptions.apiKey ?? resolution.auth.apiKey,\n        headers,\n        env\n      }\n    };\n  }\n  stream(model, context, options) {\n    return lazyStream(model, async () => {\n      const prepared = await this.prepareRequest(model, options);\n      return prepared.provider.stream(prepared.model, context, prepared.options);\n    });\n  }\n  complete(model, context, options) {\n    return this.stream(model, context, options).result();\n  }\n  streamSimple(model, context, options) {\n    return lazyStream(model, async () => {\n      const prepared = await this.prepareRequest(model, options);\n      return prepared.provider.streamSimple(prepared.model, context, prepared.options);\n    });\n  }\n  completeSimple(model, context, options) {\n    return this.streamSimple(model, context, options).result();\n  }\n  async fetchDeferred(model, handle, options) {\n    return lazyStream(model, async () => {\n      const prepared = await this.prepareRequest(model, options);\n      if (!prepared.provider.fetchDeferred) {\n        throw new ModelsError(\"provider\", `Provider ${model.provider} does not support deferred responses`);\n      }\n      return prepared.provider.fetchDeferred(prepared.model, handle, prepared.options);\n    }).result();\n  }\n  async cancelDeferred(model, handle, options) {\n    const prepared = await this.prepareRequest(model, options);\n    if (!prepared.provider.cancelDeferred) {\n      throw new ModelsError(\"provider\", `Provider ${model.provider} does not support deferred responses`);\n    }\n    await prepared.provider.cancelDeferred(prepared.model, handle, prepared.options);\n  }\n  login(providerId, type, interaction) {\n    const signal = operationSignal2(interaction.signal);\n    return this.enqueueCredentialOperation(providerId, signal, async () => {\n      const credential = await this.models.login(providerId, type, { ...interaction, signal });\n      await this.synchronizeCredentialState(providerId, \"login\", credential, signal);\n      return credential;\n    });\n  }\n  logout(providerId, options = {}) {\n    const signal = operationSignal2(options.signal);\n    return this.enqueueCredentialOperation(providerId, signal, async () => {\n      await this.models.logout(providerId, { signal });\n      await this.synchronizeCredentialState(providerId, \"logout\", void 0, signal);\n    });\n  }\n  async refresh(options = {}) {\n    this.config = await ModelConfig.load(this.modelsPath);\n    this.configureRadiusProviders();\n    if (options.providers) {\n      for (const providerId of new Set(options.providers))\n        this.recomposeProvider(providerId);\n      this.updateModelSnapshot();\n    } else {\n      this.rebuildProviders();\n    }\n    const refreshOptions = {\n      ...options,\n      allowNetwork: options.allowNetwork ?? this.modelNetworkEnabled\n    };\n    const result = await this.models.refresh(refreshOptions) ?? {\n      aborted: refreshOptions.signal?.aborted ?? false,\n      errors: /* @__PURE__ */ new Map()\n    };\n    const errors = new Map(result.errors);\n    this.updateModelSnapshot();\n    if (options.providers) {\n      await Promise.all([...new Set(options.providers)].map(async (providerId) => {\n        try {\n          await this.refreshProviderAvailability(providerId, operationSignal2(options.signal));\n        } catch (error) {\n          if (!options.signal?.aborted) {\n            errors.set(providerId, error instanceof Error ? error : new Error(String(error)));\n          }\n        }\n      }));\n    } else {\n      try {\n        await this.queueAvailabilityRefresh(options.signal);\n      } catch {\n      }\n    }\n    return { aborted: result.aborted || (options.signal?.aborted ?? false), errors };\n  }\n  registerNativeProvider(provider) {\n    if (!provider.id.trim())\n      throw new Error(\"Provider id must not be empty.\");\n    this.extensionProviders.delete(provider.id);\n    this.nativeExtensionProviders.set(provider.id, provider);\n    this.recomposeProvider(provider.id);\n    this.updateModelSnapshot();\n    void this.refresh({ allowNetwork: false });\n  }\n  registerProvider(providerId, config) {\n    validateExtensionProvider(providerId, this.builtins.get(providerId), this.config.getProvider(providerId), config);\n    this.nativeExtensionProviders.delete(providerId);\n    const previous = this.extensionProviders.get(providerId);\n    const effective = { ...previous };\n    for (const [key, value] of Object.entries(config)) {\n      if (value !== void 0)\n        effective[key] = value;\n    }\n    this.extensionProviders.set(providerId, effective);\n    this.recomposeProvider(providerId);\n    this.updateModelSnapshot();\n    if (this.snapshot.storedProviders.has(providerId) || configuredRequestAuthStatus(this.config.getProvider(providerId), effective)?.configured) {\n      const configuredProviders = new Set(this.snapshot.configuredProviders).add(providerId);\n      const auth = new Map(this.snapshot.auth);\n      if (!auth.get(providerId)) {\n        auth.set(providerId, {\n          type: effective.oauth && !effective.apiKey ? \"oauth\" : \"api_key\",\n          source: \"configured provider\"\n        });\n      }\n      this.snapshot = {\n        ...this.snapshot,\n        auth,\n        configuredProviders,\n        available: this.snapshot.all.filter((model) => configuredProviders.has(model.provider))\n      };\n    }\n    void this.refresh({ allowNetwork: false });\n  }\n  unregisterProvider(providerId) {\n    this.extensionProviders.delete(providerId);\n    this.nativeExtensionProviders.delete(providerId);\n    this.recomposeProvider(providerId);\n    this.updateModelSnapshot();\n    void this.refresh({ allowNetwork: false });\n  }\n};\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/cli/auth-command.js\nvar AuthCommandError = class extends Error {\n};\nvar AUTH_COMMAND_USAGE = {\n  check: `${APP_NAME} auth check --provider <provider> [--json] [--credentials] [--no-refresh]`,\n  api_key: `${APP_NAME} auth print-api-key --provider <provider> [--model <model>]`,\n  bearer_token: `${APP_NAME} auth print-bearer-token --provider <provider> [--model <model>] [--min-expiry <duration>]`\n};\nfunction getAuthCommandName(kind) {\n  return kind === \"check\" ? \"auth check\" : kind === \"api_key\" ? \"auth print-api-key\" : \"auth print-bearer-token\";\n}\nfunction getAuthCommandUsage(kind) {\n  return AUTH_COMMAND_USAGE[kind];\n}\nfunction isAuthCommandHelp(args) {\n  return args[0] === \"auth\" && (args[1] === void 0 || args[1] === \"help\" || args.includes(\"--help\") || args.includes(\"-h\"));\n}\nfunction printAuthCommandHelp() {\n  console.log(`Usage:\n  pi auth print-api-key [--provider <provider>] [--model <model>]\n  pi auth print-bearer-token [--provider <provider>] [--model <model>] [--min-expiry <duration>]\n  pi auth check [--provider <provider>] [--model <model>] [--json] [--credentials] [--no-refresh]\n\nAuth commands require at least one of --provider or --model. Checks refresh expired OAuth credentials by default; --no-refresh prevents this. --credentials emits the credential, or includes it in JSON output.`);\n}\nfunction parseAuthCommand(args) {\n  if (args[0] !== \"auth\")\n    return void 0;\n  const kind = args[1] === \"check\" ? \"check\" : args[1] === \"print-api-key\" ? \"api_key\" : args[1] === \"print-bearer-token\" ? \"bearer_token\" : void 0;\n  if (!kind) {\n    throw new AuthCommandError(`Unknown auth command \"${args[1] ?? \"\"}\". Use \"${APP_NAME} auth print-api-key\", \"${APP_NAME} auth print-bearer-token\", or \"${APP_NAME} auth check\".`);\n  }\n  const commandArgs = [];\n  let json = false;\n  let credentials = false;\n  let noRefresh = false;\n  let minExpiryMs;\n  for (let index = 2; index < args.length; index++) {\n    const arg = args[index];\n    if (arg === \"--min-expiry\") {\n      if (kind !== \"bearer_token\")\n        throw new AuthCommandError(\"--min-expiry is only supported by print-bearer-token\");\n      const value = args[++index];\n      const match = value ? /^(\\d+)(ms|s|m|h)$/iu.exec(value) : void 0;\n      if (!match)\n        throw new AuthCommandError(\"--min-expiry must use a duration such as 30m or 1h\");\n      const amount = Number(match[1]);\n      const unit = match[2];\n      minExpiryMs = amount * (unit === \"ms\" ? 1 : unit === \"s\" ? 1e3 : unit === \"m\" ? 6e4 : 36e5);\n      continue;\n    }\n    if (arg === \"--json\" || arg === \"--credentials\" || arg === \"--no-refresh\") {\n      if (kind !== \"check\")\n        throw new AuthCommandError(`${arg} is only supported by auth check`);\n      if (arg === \"--json\")\n        json = true;\n      else if (arg === \"--credentials\")\n        credentials = true;\n      else\n        noRefresh = true;\n      continue;\n    }\n    commandArgs.push(arg);\n  }\n  return minExpiryMs === void 0 ? { kind, args: commandArgs, json, credentials, noRefresh } : { kind, args: commandArgs, json, credentials, noRefresh, minExpiryMs };\n}\nfunction validateAuthCommandArgs(args, kind) {\n  const provider = args.provider?.trim() || void 0;\n  const model = args.model?.trim() || void 0;\n  if (args.unknownFlags.size > 0) {\n    const option = args.unknownFlags.keys().next().value;\n    throw new AuthCommandError(`Unknown option --${option} for \"${getAuthCommandName(kind)}\".`);\n  }\n  if (args.apiKey !== void 0 || args.messages.length > 0 || args.fileArgs.length > 0) {\n    throw new AuthCommandError(\"Auth commands only accept --provider and --model\");\n  }\n  if (kind === \"check\") {\n    if (!provider && !model) {\n      throw new AuthCommandError(\"Auth checks require --provider <provider> or --model <model>\");\n    }\n    return { provider, model };\n  }\n  if (!provider && !model) {\n    throw new AuthCommandError(\"Credential printing requires --provider <provider> or --model <model>\");\n  }\n  return { provider, model };\n}\nfunction getAuthCredential(auth) {\n  if (auth?.auth.apiKey)\n    return auth.auth.apiKey;\n  const authorization = Object.entries(auth?.auth.headers ?? {}).find(([name]) => name.toLowerCase() === \"authorization\")?.[1];\n  return typeof authorization === \"string\" ? /^Bearer\\s+(.+)$/iu.exec(authorization)?.[1] : void 0;\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/cli/auth-check.js\nasync function checkProviderAuth(args, modelRuntime, options = { refresh: false }) {\n  const { provider: cliProvider, model: cliModel } = validateAuthCommandArgs(args, \"check\");\n  let provider = cliProvider;\n  if (cliModel) {\n    const resolved = resolveCliModel({ cliProvider, cliModel, modelRuntime });\n    if (resolved.error || !resolved.model) {\n      throw new AuthCommandError(resolved.error ?? `Unable to resolve model \"${cliModel}\"`);\n    }\n    provider = resolved.model.provider;\n  }\n  if (!provider)\n    throw new AuthCommandError(\"Unable to resolve an auth provider\");\n  if (modelRuntime.getError()) {\n    return { status: \"invalid\", provider, reason: \"invalid_state\" };\n  }\n  if (!modelRuntime.getProvider(provider)) {\n    return { status: \"not_ready\", provider, reason: \"provider_not_found\" };\n  }\n  try {\n    const auth = await modelRuntime.checkAuth(provider);\n    if (!auth)\n      return { status: \"not_ready\", provider, reason: \"credentials_not_configured\" };\n    if (options.refresh && !await modelRuntime.getAuth(provider)) {\n      return { status: \"not_ready\", provider, reason: \"credentials_not_configured\" };\n    }\n    return { status: \"ready\", provider, authType: auth.type };\n  } catch {\n    return { status: \"invalid\", provider, reason: \"invalid_state\" };\n  }\n}\nasync function getProviderCredential(providerId, modelRuntime, credentials, options) {\n  const credential = await credentials.read(providerId);\n  if (!options.refresh && credential?.type === \"oauth\")\n    return credential.access;\n  return getAuthCredential(await modelRuntime.getAuth(providerId));\n}\nasync function createAuthCheckModelRuntime(credentials) {\n  return ModelRuntime.create({\n    credentials,\n    modelsStore: new InMemoryCodingAgentModelsStore(),\n    allowModelNetwork: false,\n    refreshOnCreate: false\n  });\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/cli/credential-print.js\nvar DEFAULT_BEARER_TOKEN_MIN_EXPIRY_MS = 30 * 6e4;\nasync function resolveCredentialForPrint(args, modelRuntime, kind, minExpiryMs, signal) {\n  const { provider: cliProvider, model: cliModel } = validateAuthCommandArgs(args, kind);\n  const credentialTypes = new Map((await modelRuntime.listCredentials({ signal })).map((credential) => [credential.providerId, credential.type]));\n  const providers = [];\n  if (cliProvider) {\n    const provider = modelRuntime.getProvider(cliProvider);\n    if (!provider) {\n      throw new AuthCommandError(`Unknown provider \"${cliProvider}\". Use --list-models to see available providers.`);\n    }\n    if (cliModel) {\n      const resolved = resolveCliModel({ cliProvider: provider.id, cliModel, modelRuntime });\n      if (resolved.error || !resolved.model) {\n        throw new AuthCommandError(resolved.error ?? \"Unable to resolve the requested provider/model\");\n      }\n      providers.push({ id: provider.id, model: resolved.model });\n    } else {\n      providers.push({ id: provider.id });\n    }\n  } else {\n    for (const provider of modelRuntime.getProviders()) {\n      if (!credentialTypes.has(provider.id))\n        continue;\n      const resolved = resolveCliModel({ cliProvider: provider.id, cliModel, modelRuntime });\n      if (resolved.model && !resolved.error && !resolved.warning?.includes(\"Using custom model id\")) {\n        providers.push({ id: provider.id, model: resolved.model });\n      }\n    }\n    if (providers.length === 0) {\n      throw new AuthCommandError(`Model \"${cliModel}\" not found. Use --list-models to see available models.`);\n    }\n  }\n  const credentials = [];\n  for (const provider of providers) {\n    const type = credentialTypes.get(provider.id);\n    if (kind === \"api_key\" && type === \"oauth\")\n      continue;\n    if (kind === \"bearer_token\" && type !== \"oauth\")\n      continue;\n    const authOptions = {\n      ...kind === \"bearer_token\" ? { minOAuthValidityMs: minExpiryMs ?? DEFAULT_BEARER_TOKEN_MIN_EXPIRY_MS } : {},\n      signal\n    };\n    const auth = provider.model ? await modelRuntime.getAuth(provider.model, authOptions) : await modelRuntime.getAuth(provider.id, authOptions);\n    const value = getAuthCredential(auth);\n    if (value)\n      credentials.push({ providerId: provider.id, value });\n  }\n  if (credentials.length === 1)\n    return credentials[0].value;\n  if (credentials.length === 0) {\n    const providerId = providers[0]?.id;\n    const type = providerId ? credentialTypes.get(providerId) : void 0;\n    if (cliProvider && kind === \"api_key\" && type === \"oauth\") {\n      throw new AuthCommandError(`Provider \"${providerId}\" is configured with OAuth, not an API key`);\n    }\n    if (cliProvider && kind === \"bearer_token\" && type !== \"oauth\") {\n      throw new AuthCommandError(`Provider \"${providerId}\" is not configured with an OAuth bearer token`);\n    }\n    throw new AuthCommandError(`No usable ${kind === \"api_key\" ? \"API key\" : \"OAuth bearer token\"} is configured`);\n  }\n  throw new AuthCommandError(`Multiple configured providers matched (${credentials.map(({ providerId }) => providerId).join(\", \")}). Specify --provider.`);\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/cli/file-processor.js\nimport { access as access2, readFile as readFile2, stat } from \"node:fs/promises\";\nimport chalk3 from \"chalk\";\nimport { resolve as resolve2 } from \"path\";\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/path-utils.js\nimport { accessSync as accessSync2, constants as constants2 } from \"node:fs\";\nimport { access } from \"node:fs/promises\";\nvar NARROW_NO_BREAK_SPACE = \"\\u202F\";\nfunction tryMacOSScreenshotPath(filePath) {\n  return filePath.replace(/ (AM|PM)\\./gi, `${NARROW_NO_BREAK_SPACE}$1.`);\n}\nfunction tryNFDVariant(filePath) {\n  return filePath.normalize(\"NFD\");\n}\nfunction tryCurlyQuoteVariant(filePath) {\n  return filePath.replace(/'/g, \"\\u2019\");\n}\nfunction fileExists(filePath) {\n  try {\n    accessSync2(filePath, constants2.F_OK);\n    return true;\n  } catch {\n    return false;\n  }\n}\nasync function pathExists(filePath) {\n  try {\n    await access(filePath, constants2.F_OK);\n    return true;\n  } catch {\n    return false;\n  }\n}\nfunction resolveToCwd(filePath, cwd) {\n  return resolvePath(filePath, cwd, { normalizeUnicodeSpaces: true, stripAtPrefix: true });\n}\nfunction resolveReadPath(filePath, cwd) {\n  const resolved = resolveToCwd(filePath, cwd);\n  if (fileExists(resolved)) {\n    return resolved;\n  }\n  const amPmVariant = tryMacOSScreenshotPath(resolved);\n  if (amPmVariant !== resolved && fileExists(amPmVariant)) {\n    return amPmVariant;\n  }\n  const nfdVariant = tryNFDVariant(resolved);\n  if (nfdVariant !== resolved && fileExists(nfdVariant)) {\n    return nfdVariant;\n  }\n  const curlyVariant = tryCurlyQuoteVariant(resolved);\n  if (curlyVariant !== resolved && fileExists(curlyVariant)) {\n    return curlyVariant;\n  }\n  const nfdCurlyVariant = tryCurlyQuoteVariant(nfdVariant);\n  if (nfdCurlyVariant !== resolved && fileExists(nfdCurlyVariant)) {\n    return nfdCurlyVariant;\n  }\n  return resolved;\n}\nasync function resolveReadPathAsync(filePath, cwd) {\n  const resolved = resolveToCwd(filePath, cwd);\n  if (await pathExists(resolved)) {\n    return resolved;\n  }\n  const amPmVariant = tryMacOSScreenshotPath(resolved);\n  if (amPmVariant !== resolved && await pathExists(amPmVariant)) {\n    return amPmVariant;\n  }\n  const nfdVariant = tryNFDVariant(resolved);\n  if (nfdVariant !== resolved && await pathExists(nfdVariant)) {\n    return nfdVariant;\n  }\n  const curlyVariant = tryCurlyQuoteVariant(resolved);\n  if (curlyVariant !== resolved && await pathExists(curlyVariant)) {\n    return curlyVariant;\n  }\n  const nfdCurlyVariant = tryCurlyQuoteVariant(nfdVariant);\n  if (nfdCurlyVariant !== resolved && await pathExists(nfdCurlyVariant)) {\n    return nfdCurlyVariant;\n  }\n  return resolved;\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/utils/exif-orientation.js\nfunction readOrientationFromTiff(bytes, tiffStart) {\n  if (tiffStart + 8 > bytes.length)\n    return 1;\n  const byteOrder = bytes[tiffStart] << 8 | bytes[tiffStart + 1];\n  const le = byteOrder === 18761;\n  const read16 = (pos) => {\n    if (le)\n      return bytes[pos] | bytes[pos + 1] << 8;\n    return bytes[pos] << 8 | bytes[pos + 1];\n  };\n  const read32 = (pos) => {\n    if (le)\n      return bytes[pos] | bytes[pos + 1] << 8 | bytes[pos + 2] << 16 | bytes[pos + 3] << 24;\n    return (bytes[pos] << 24 | bytes[pos + 1] << 16 | bytes[pos + 2] << 8 | bytes[pos + 3]) >>> 0;\n  };\n  const ifdOffset = read32(tiffStart + 4);\n  const ifdStart = tiffStart + ifdOffset;\n  if (ifdStart + 2 > bytes.length)\n    return 1;\n  const entryCount = read16(ifdStart);\n  for (let i = 0; i < entryCount; i++) {\n    const entryPos = ifdStart + 2 + i * 12;\n    if (entryPos + 12 > bytes.length)\n      return 1;\n    if (read16(entryPos) === 274) {\n      const value = read16(entryPos + 8);\n      return value >= 1 && value <= 8 ? value : 1;\n    }\n  }\n  return 1;\n}\nfunction findJpegTiffOffset(bytes) {\n  let offset = 2;\n  while (offset < bytes.length - 1) {\n    if (bytes[offset] !== 255)\n      return -1;\n    const marker = bytes[offset + 1];\n    if (marker === 255) {\n      offset++;\n      continue;\n    }\n    if (marker === 225) {\n      if (offset + 4 >= bytes.length)\n        return -1;\n      const segmentStart = offset + 4;\n      if (segmentStart + 6 > bytes.length)\n        return -1;\n      if (!hasExifHeader(bytes, segmentStart))\n        return -1;\n      return segmentStart + 6;\n    }\n    if (offset + 4 > bytes.length)\n      return -1;\n    const length = bytes[offset + 2] << 8 | bytes[offset + 3];\n    offset += 2 + length;\n  }\n  return -1;\n}\nfunction findWebpTiffOffset(bytes) {\n  let offset = 12;\n  while (offset + 8 <= bytes.length) {\n    const chunkId = String.fromCharCode(bytes[offset], bytes[offset + 1], bytes[offset + 2], bytes[offset + 3]);\n    const chunkSize = bytes[offset + 4] | bytes[offset + 5] << 8 | bytes[offset + 6] << 16 | bytes[offset + 7] << 24;\n    const dataStart = offset + 8;\n    if (chunkId === \"EXIF\") {\n      if (dataStart + chunkSize > bytes.length)\n        return -1;\n      const tiffStart = chunkSize >= 6 && hasExifHeader(bytes, dataStart) ? dataStart + 6 : dataStart;\n      return tiffStart;\n    }\n    offset = dataStart + chunkSize + chunkSize % 2;\n  }\n  return -1;\n}\nfunction hasExifHeader(bytes, offset) {\n  return bytes[offset] === 69 && bytes[offset + 1] === 120 && bytes[offset + 2] === 105 && bytes[offset + 3] === 102 && bytes[offset + 4] === 0 && bytes[offset + 5] === 0;\n}\nfunction getExifOrientation(bytes) {\n  let tiffOffset = -1;\n  if (bytes.length >= 2 && bytes[0] === 255 && bytes[1] === 216) {\n    tiffOffset = findJpegTiffOffset(bytes);\n  } else if (bytes.length >= 12 && bytes[0] === 82 && bytes[1] === 73 && bytes[2] === 70 && bytes[3] === 70 && bytes[8] === 87 && bytes[9] === 69 && bytes[10] === 66 && bytes[11] === 80) {\n    tiffOffset = findWebpTiffOffset(bytes);\n  }\n  if (tiffOffset === -1)\n    return 1;\n  return readOrientationFromTiff(bytes, tiffOffset);\n}\nfunction rotate90(photon, image, dstIndex) {\n  const w = image.get_width();\n  const h = image.get_height();\n  const src = image.get_raw_pixels();\n  const dst = new Uint8Array(src.length);\n  for (let y = 0; y < h; y++) {\n    for (let x = 0; x < w; x++) {\n      const srcIdx = (y * w + x) * 4;\n      const dstIdx = dstIndex(x, y, w, h) * 4;\n      dst[dstIdx] = src[srcIdx];\n      dst[dstIdx + 1] = src[srcIdx + 1];\n      dst[dstIdx + 2] = src[srcIdx + 2];\n      dst[dstIdx + 3] = src[srcIdx + 3];\n    }\n  }\n  return new photon.PhotonImage(dst, h, w);\n}\nfunction applyExifOrientation(photon, image, originalBytes) {\n  const orientation = getExifOrientation(originalBytes);\n  if (orientation === 1)\n    return image;\n  switch (orientation) {\n    case 2:\n      photon.fliph(image);\n      return image;\n    case 3:\n      photon.fliph(image);\n      photon.flipv(image);\n      return image;\n    case 4:\n      photon.flipv(image);\n      return image;\n    case 5: {\n      const rotated = rotate90(photon, image, (x, y, _w, h) => x * h + (h - 1 - y));\n      photon.fliph(rotated);\n      return rotated;\n    }\n    case 6:\n      return rotate90(photon, image, (x, y, _w, h) => x * h + (h - 1 - y));\n    case 7: {\n      const rotated = rotate90(photon, image, (x, y, w, h) => (w - 1 - x) * h + y);\n      photon.fliph(rotated);\n      return rotated;\n    }\n    case 8:\n      return rotate90(photon, image, (x, y, w, h) => (w - 1 - x) * h + y);\n    default:\n      return image;\n  }\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/utils/photon.js\nimport { createRequire } from \"module\";\nimport * as path from \"path\";\nimport { fileURLToPath as fileURLToPath3 } from \"url\";\nvar require2 = createRequire(import.meta.url);\nvar fs = require2(\"fs\");\nvar WASM_FILENAME = \"photon_rs_bg.wasm\";\nvar photonModule = null;\nvar loadPromise = null;\nfunction pathOrNull(file) {\n  if (typeof file === \"string\") {\n    return file;\n  }\n  if (file instanceof URL) {\n    return fileURLToPath3(file);\n  }\n  return null;\n}\nfunction getFallbackWasmPaths() {\n  const execDir = path.dirname(process.execPath);\n  return [\n    path.join(execDir, WASM_FILENAME),\n    path.join(execDir, \"photon\", WASM_FILENAME),\n    path.join(process.cwd(), WASM_FILENAME)\n  ];\n}\nfunction patchPhotonWasmRead() {\n  const originalReadFileSync = fs.readFileSync.bind(fs);\n  const fallbackPaths = getFallbackWasmPaths();\n  const mutableFs = fs;\n  const patchedReadFileSync = ((...args) => {\n    const [file, options] = args;\n    const resolvedPath = pathOrNull(file);\n    if (resolvedPath?.endsWith(WASM_FILENAME)) {\n      try {\n        return originalReadFileSync(...args);\n      } catch (error) {\n        const err2 = error;\n        if (err2?.code && err2.code !== \"ENOENT\") {\n          throw error;\n        }\n        for (const fallbackPath of fallbackPaths) {\n          if (!fs.existsSync(fallbackPath)) {\n            continue;\n          }\n          if (options === void 0) {\n            return originalReadFileSync(fallbackPath);\n          }\n          return originalReadFileSync(fallbackPath, options);\n        }\n        throw error;\n      }\n    }\n    return originalReadFileSync(...args);\n  });\n  try {\n    mutableFs.readFileSync = patchedReadFileSync;\n  } catch {\n    Object.defineProperty(fs, \"readFileSync\", {\n      value: patchedReadFileSync,\n      writable: true,\n      configurable: true\n    });\n  }\n  return () => {\n    try {\n      mutableFs.readFileSync = originalReadFileSync;\n    } catch {\n      Object.defineProperty(fs, \"readFileSync\", {\n        value: originalReadFileSync,\n        writable: true,\n        configurable: true\n      });\n    }\n  };\n}\nasync function loadPhoton() {\n  if (photonModule) {\n    return photonModule;\n  }\n  if (loadPromise) {\n    return loadPromise;\n  }\n  loadPromise = (async () => {\n    const restoreReadFileSync = patchPhotonWasmRead();\n    try {\n      photonModule = await import(\"@silvia-odwyer/photon-node\");\n      return photonModule;\n    } catch {\n      photonModule = null;\n      return photonModule;\n    } finally {\n      restoreReadFileSync();\n    }\n  })();\n  return loadPromise;\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/utils/image-convert.js\nasync function convertImageBytesToPng(bytes) {\n  const photon = await loadPhoton();\n  if (!photon) {\n    return null;\n  }\n  try {\n    const rawImage = photon.PhotonImage.new_from_byteslice(bytes);\n    const image = applyExifOrientation(photon, rawImage, bytes);\n    if (image !== rawImage)\n      rawImage.free();\n    try {\n      return new Uint8Array(image.get_bytes());\n    } finally {\n      image.free();\n    }\n  } catch {\n    return null;\n  }\n}\nasync function convertToPng(base64Data, mimeType) {\n  if (mimeType === \"image/png\") {\n    return { data: base64Data, mimeType };\n  }\n  const bytes = new Uint8Array(Buffer.from(base64Data, \"base64\"));\n  const pngBytes = await convertImageBytesToPng(bytes);\n  if (!pngBytes) {\n    return null;\n  }\n  return {\n    data: Buffer.from(pngBytes).toString(\"base64\"),\n    mimeType: \"image/png\"\n  };\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/utils/image-resize.js\nimport { Worker } from \"node:worker_threads\";\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/utils/image-resize-core.js\nvar DEFAULT_MAX_BYTES = 4.5 * 1024 * 1024;\nvar DEFAULT_OPTIONS = {\n  maxWidth: 2e3,\n  maxHeight: 2e3,\n  maxBytes: DEFAULT_MAX_BYTES,\n  jpegQuality: 80\n};\nfunction encodeCandidate(buffer, mimeType) {\n  const data = Buffer.from(buffer).toString(\"base64\");\n  return {\n    data,\n    encodedSize: Buffer.byteLength(data, \"utf-8\"),\n    mimeType\n  };\n}\nasync function resizeImageInProcess(inputBytes, mimeType, options) {\n  const opts = { ...DEFAULT_OPTIONS, ...options };\n  const inputBase64Size = Math.ceil(inputBytes.byteLength / 3) * 4;\n  const photon = await loadPhoton();\n  if (!photon) {\n    return null;\n  }\n  let image;\n  try {\n    let tryEncodings = function(width, height, jpegQualities) {\n      const resized = photon.resize(image, width, height, photon.SamplingFilter.Lanczos3);\n      try {\n        const candidates = [encodeCandidate(resized.get_bytes(), \"image/png\")];\n        for (const quality of jpegQualities) {\n          candidates.push(encodeCandidate(resized.get_bytes_jpeg(quality), \"image/jpeg\"));\n        }\n        return candidates;\n      } finally {\n        resized.free();\n      }\n    };\n    const rawImage = photon.PhotonImage.new_from_byteslice(inputBytes);\n    image = applyExifOrientation(photon, rawImage, inputBytes);\n    if (image !== rawImage)\n      rawImage.free();\n    const originalWidth = image.get_width();\n    const originalHeight = image.get_height();\n    const format = mimeType.split(\"/\")[1] ?? \"png\";\n    if (originalWidth <= opts.maxWidth && originalHeight <= opts.maxHeight && inputBase64Size < opts.maxBytes) {\n      return {\n        data: Buffer.from(inputBytes).toString(\"base64\"),\n        mimeType: mimeType || `image/${format}`,\n        originalWidth,\n        originalHeight,\n        width: originalWidth,\n        height: originalHeight,\n        wasResized: false\n      };\n    }\n    let targetWidth = originalWidth;\n    let targetHeight = originalHeight;\n    if (targetWidth > opts.maxWidth) {\n      targetHeight = Math.round(targetHeight * opts.maxWidth / targetWidth);\n      targetWidth = opts.maxWidth;\n    }\n    if (targetHeight > opts.maxHeight) {\n      targetWidth = Math.round(targetWidth * opts.maxHeight / targetHeight);\n      targetHeight = opts.maxHeight;\n    }\n    const qualitySteps = Array.from(/* @__PURE__ */ new Set([opts.jpegQuality, 85, 70, 55, 40]));\n    let currentWidth = targetWidth;\n    let currentHeight = targetHeight;\n    while (true) {\n      const candidates = tryEncodings(currentWidth, currentHeight, qualitySteps);\n      for (const candidate of candidates) {\n        if (candidate.encodedSize < opts.maxBytes) {\n          return {\n            data: candidate.data,\n            mimeType: candidate.mimeType,\n            originalWidth,\n            originalHeight,\n            width: currentWidth,\n            height: currentHeight,\n            wasResized: true\n          };\n        }\n      }\n      if (currentWidth === 1 && currentHeight === 1) {\n        break;\n      }\n      const nextWidth = currentWidth === 1 ? 1 : Math.max(1, Math.floor(currentWidth * 0.75));\n      const nextHeight = currentHeight === 1 ? 1 : Math.max(1, Math.floor(currentHeight * 0.75));\n      if (nextWidth === currentWidth && nextHeight === currentHeight) {\n        break;\n      }\n      currentWidth = nextWidth;\n      currentHeight = nextHeight;\n    }\n    return null;\n  } catch {\n    return null;\n  } finally {\n    if (image) {\n      image.free();\n    }\n  }\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/utils/image-resize.js\nfunction toTransferableBytes(input) {\n  return new Uint8Array(input);\n}\nfunction isResizeImageWorkerResponse(value) {\n  return value !== null && typeof value === \"object\";\n}\nfunction createResizeWorker(workerSpecifier) {\n  return new Worker(workerSpecifier);\n}\nasync function resizeImageInWorker(workerSpecifier, inputBytes, mimeType, options) {\n  const worker = createResizeWorker(workerSpecifier);\n  try {\n    const inputBytesForWorker = toTransferableBytes(inputBytes);\n    return await new Promise((resolve15, reject) => {\n      let settled = false;\n      const settle = (result) => {\n        if (settled)\n          return;\n        settled = true;\n        resolve15(result);\n      };\n      const fail = (error) => {\n        if (settled)\n          return;\n        settled = true;\n        reject(error);\n      };\n      worker.once(\"message\", (message) => {\n        if (!isResizeImageWorkerResponse(message)) {\n          fail(new Error(\"Invalid image resize worker response\"));\n          return;\n        }\n        if (message.error) {\n          fail(new Error(message.error));\n          return;\n        }\n        settle(message.result ?? null);\n      });\n      worker.once(\"error\", fail);\n      worker.once(\"exit\", (code) => {\n        if (!settled) {\n          fail(new Error(`Image resize worker exited with code ${code}`));\n        }\n      });\n      worker.postMessage({\n        inputBytes: inputBytesForWorker,\n        mimeType,\n        options\n      }, [inputBytesForWorker.buffer]);\n    });\n  } finally {\n    void worker.terminate().catch(() => void 0);\n  }\n}\nasync function resizeImage(inputBytes, mimeType, options) {\n  const isTypeScriptRuntime = import.meta.url.endsWith(\".ts\");\n  const workerUrl = new URL(isTypeScriptRuntime ? \"./image-resize-worker.ts\" : \"./image-resize-worker.js\", import.meta.url);\n  if (typeof process.versions.bun === \"string\") {\n    try {\n      return await resizeImageInWorker(\"./src/utils/image-resize-worker.ts\", inputBytes, mimeType, options);\n    } catch {\n    }\n  }\n  try {\n    return await resizeImageInWorker(workerUrl, inputBytes, mimeType, options);\n  } catch {\n    return resizeImageInProcess(inputBytes, mimeType, options);\n  }\n}\nfunction formatDimensionNote(result) {\n  if (!result.wasResized) {\n    return void 0;\n  }\n  const scale = result.originalWidth / result.width;\n  return `[Image: original ${result.originalWidth}x${result.originalHeight}, displayed at ${result.width}x${result.height}. Multiply coordinates by ${scale.toFixed(2)} to map to original image.]`;\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/utils/image-process.js\nfunction baseMimeType(mimeType) {\n  return mimeType.split(\";\")[0]?.trim().toLowerCase() ?? mimeType.toLowerCase();\n}\nfunction normalizeSupportedImageMimeType(mimeType) {\n  switch (baseMimeType(mimeType)) {\n    case \"image/png\":\n      return \"image/png\";\n    case \"image/jpeg\":\n    case \"image/jpg\":\n      return \"image/jpeg\";\n    case \"image/gif\":\n      return \"image/gif\";\n    case \"image/webp\":\n      return \"image/webp\";\n    default:\n      return null;\n  }\n}\nasync function normalizeImage(bytes, mimeType) {\n  const normalizedMimeType = normalizeSupportedImageMimeType(mimeType);\n  if (normalizedMimeType) {\n    return { bytes, mimeType: normalizedMimeType };\n  }\n  const pngBytes = await convertImageBytesToPng(bytes);\n  if (!pngBytes) {\n    return null;\n  }\n  return {\n    bytes: pngBytes,\n    mimeType: \"image/png\",\n    convertedFrom: baseMimeType(mimeType)\n  };\n}\nfunction conversionHint(from, to) {\n  if (!from || from === to)\n    return void 0;\n  return `[Image converted from ${from} to ${to}.]`;\n}\nasync function processImage(bytes, mimeType, options) {\n  const autoResizeImages = options?.autoResizeImages ?? true;\n  const normalized = await normalizeImage(bytes, mimeType);\n  if (!normalized) {\n    return {\n      ok: false,\n      message: \"[Image omitted: could not be converted to a supported inline image format.]\"\n    };\n  }\n  if (autoResizeImages) {\n    const resized = await resizeImage(normalized.bytes, normalized.mimeType, options?.resizeOptions);\n    if (!resized) {\n      return {\n        ok: false,\n        message: \"[Image omitted: could not be resized below the inline image size limit.]\"\n      };\n    }\n    const hints2 = [];\n    const convertedHint2 = conversionHint(normalized.convertedFrom, resized.mimeType);\n    if (convertedHint2)\n      hints2.push(convertedHint2);\n    const dimensionNote = formatDimensionNote(resized);\n    if (dimensionNote)\n      hints2.push(dimensionNote);\n    return {\n      ok: true,\n      data: resized.data,\n      mimeType: resized.mimeType,\n      hints: hints2\n    };\n  }\n  const hints = [];\n  const convertedHint = conversionHint(normalized.convertedFrom, normalized.mimeType);\n  if (convertedHint)\n    hints.push(convertedHint);\n  return {\n    ok: true,\n    data: Buffer.from(normalized.bytes).toString(\"base64\"),\n    mimeType: normalized.mimeType,\n    hints\n  };\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/utils/mime.js\nimport { open } from \"node:fs/promises\";\nvar IMAGE_TYPE_SNIFF_BYTES = 4100;\nvar PNG_SIGNATURE = [137, 80, 78, 71, 13, 10, 26, 10];\nfunction detectSupportedImageMimeType(buffer) {\n  if (startsWith(buffer, [255, 216, 255])) {\n    return buffer[3] === 247 ? null : \"image/jpeg\";\n  }\n  if (startsWith(buffer, PNG_SIGNATURE)) {\n    return isPng(buffer) && !isAnimatedPng(buffer) ? \"image/png\" : null;\n  }\n  if (startsWithAscii(buffer, 0, \"GIF\")) {\n    return \"image/gif\";\n  }\n  if (startsWithAscii(buffer, 0, \"RIFF\") && startsWithAscii(buffer, 8, \"WEBP\")) {\n    return \"image/webp\";\n  }\n  if (startsWithAscii(buffer, 0, \"BM\") && isBmp(buffer)) {\n    return \"image/bmp\";\n  }\n  return null;\n}\nasync function detectSupportedImageMimeTypeFromFile(filePath) {\n  const fileHandle = await open(filePath, \"r\");\n  try {\n    const buffer = Buffer.alloc(IMAGE_TYPE_SNIFF_BYTES);\n    const { bytesRead } = await fileHandle.read(buffer, 0, IMAGE_TYPE_SNIFF_BYTES, 0);\n    return detectSupportedImageMimeType(buffer.subarray(0, bytesRead));\n  } finally {\n    await fileHandle.close();\n  }\n}\nfunction isPng(buffer) {\n  return buffer.length >= 16 && readUint32BE(buffer, PNG_SIGNATURE.length) === 13 && startsWithAscii(buffer, 12, \"IHDR\");\n}\nfunction isAnimatedPng(buffer) {\n  let offset = PNG_SIGNATURE.length;\n  while (offset + 8 <= buffer.length) {\n    const chunkLength = readUint32BE(buffer, offset);\n    const chunkTypeOffset = offset + 4;\n    if (startsWithAscii(buffer, chunkTypeOffset, \"acTL\"))\n      return true;\n    if (startsWithAscii(buffer, chunkTypeOffset, \"IDAT\"))\n      return false;\n    const nextOffset = offset + 8 + chunkLength + 4;\n    if (nextOffset <= offset || nextOffset > buffer.length)\n      return false;\n    offset = nextOffset;\n  }\n  return false;\n}\nfunction isBmp(buffer) {\n  if (buffer.length < 26)\n    return false;\n  const declaredFileSize = readUint32LE(buffer, 2);\n  const pixelDataOffset = readUint32LE(buffer, 10);\n  const dibHeaderSize = readUint32LE(buffer, 14);\n  if (declaredFileSize !== 0 && declaredFileSize < 26)\n    return false;\n  if (pixelDataOffset < 14 + dibHeaderSize)\n    return false;\n  if (declaredFileSize !== 0 && pixelDataOffset >= declaredFileSize)\n    return false;\n  let colorPlanes;\n  let bitsPerPixel;\n  if (dibHeaderSize === 12) {\n    colorPlanes = readUint16LE(buffer, 22);\n    bitsPerPixel = readUint16LE(buffer, 24);\n  } else if (dibHeaderSize >= 40 && dibHeaderSize <= 124) {\n    if (buffer.length < 30)\n      return false;\n    colorPlanes = readUint16LE(buffer, 26);\n    bitsPerPixel = readUint16LE(buffer, 28);\n  } else {\n    return false;\n  }\n  return colorPlanes === 1 && [1, 4, 8, 16, 24, 32].includes(bitsPerPixel);\n}\nfunction readUint16LE(buffer, offset) {\n  return (buffer[offset] ?? 0) + ((buffer[offset + 1] ?? 0) << 8);\n}\nfunction readUint32BE(buffer, offset) {\n  return (buffer[offset] ?? 0) * 16777216 + ((buffer[offset + 1] ?? 0) << 16) + ((buffer[offset + 2] ?? 0) << 8) + (buffer[offset + 3] ?? 0);\n}\nfunction readUint32LE(buffer, offset) {\n  return (buffer[offset] ?? 0) + ((buffer[offset + 1] ?? 0) << 8) + ((buffer[offset + 2] ?? 0) << 16) + (buffer[offset + 3] ?? 0) * 16777216;\n}\nfunction startsWith(buffer, bytes) {\n  if (buffer.length < bytes.length)\n    return false;\n  return bytes.every((byte, index) => buffer[index] === byte);\n}\nfunction startsWithAscii(buffer, offset, text) {\n  if (buffer.length < offset + text.length)\n    return false;\n  for (let index = 0; index < text.length; index++) {\n    if (buffer[offset + index] !== text.charCodeAt(index))\n      return false;\n  }\n  return true;\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/cli/file-processor.js\nasync function processFileArguments(fileArgs, options) {\n  const autoResizeImages = options?.autoResizeImages ?? true;\n  let text = \"\";\n  const images = [];\n  for (const fileArg of fileArgs) {\n    const absolutePath = resolve2(resolveReadPath(fileArg, process.cwd()));\n    try {\n      await access2(absolutePath);\n    } catch {\n      console.error(chalk3.red(`Error: File not found: ${absolutePath}`));\n      process.exit(1);\n    }\n    const stats = await stat(absolutePath);\n    if (stats.size === 0) {\n      continue;\n    }\n    const mimeType = await detectSupportedImageMimeTypeFromFile(absolutePath);\n    if (mimeType) {\n      const content = await readFile2(absolutePath);\n      const processed = await processImage(content, mimeType, { autoResizeImages });\n      if (!processed.ok) {\n        text += `<file name=\"${absolutePath}\">${processed.message}</file>\n`;\n        continue;\n      }\n      const attachment = {\n        type: \"image\",\n        mimeType: processed.mimeType,\n        data: processed.data\n      };\n      images.push(attachment);\n      if (processed.hints.length > 0) {\n        text += `<file name=\"${absolutePath}\">${processed.hints.join(\"\\n\")}</file>\n`;\n      } else {\n        text += `<file name=\"${absolutePath}\"></file>\n`;\n      }\n    } else {\n      try {\n        const content = await readFile2(absolutePath, \"utf-8\");\n        text += `<file name=\"${absolutePath}\">\n${content}\n</file>\n`;\n      } catch (error) {\n        const message = error instanceof Error ? error.message : String(error);\n        console.error(chalk3.red(`Error: Could not read file ${absolutePath}: ${message}`));\n        process.exit(1);\n      }\n    }\n  }\n  return { text, images };\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/cli/initial-message.js\nfunction buildInitialMessage({ parsed, fileText, fileImages, stdinContent }) {\n  const parts = [];\n  if (stdinContent !== void 0) {\n    parts.push(stdinContent);\n  }\n  if (fileText) {\n    parts.push(fileText);\n  }\n  if (parsed.messages.length > 0) {\n    parts.push(parsed.messages[0]);\n    parsed.messages.shift();\n  }\n  return {\n    initialMessage: parts.length > 0 ? parts.join(\"\") : void 0,\n    initialImages: fileImages && fileImages.length > 0 ? fileImages : void 0\n  };\n}\n\n// node_modules/.pnpm/@earendil-works+pi-tui@0.84.2/node_modules/@earendil-works/pi-tui/dist/index.js\nvar dist_exports = {};\n__export(dist_exports, {\n  Box: () => Box,\n  CURSOR_MARKER: () => CURSOR_MARKER,\n  CancellableLoader: () => CancellableLoader,\n  CombinedAutocompleteProvider: () => CombinedAutocompleteProvider,\n  Container: () => Container,\n  Editor: () => Editor,\n  HStack: () => HStack,\n  Image: () => Image,\n  Input: () => Input,\n  Key: () => Key,\n  KeybindingsManager: () => KeybindingsManager,\n  Loader: () => Loader,\n  Markdown: () => Markdown,\n  Marked: () => Marked2,\n  ProcessTerminal: () => ProcessTerminal,\n  ScrollView: () => ScrollView,\n  SelectList: () => SelectList,\n  SettingsList: () => SettingsList,\n  Spacer: () => Spacer,\n  StdinBuffer: () => StdinBuffer,\n  TUI_KEYBINDINGS: () => TUI_KEYBINDINGS,\n  Text: () => Text,\n  TruncatedText: () => TruncatedText,\n  TuiAltScreen: () => TuiAltScreen,\n  TuiMainScreen: () => TuiMainScreen,\n  VStack: () => VStack,\n  allocateImageId: () => allocateImageId,\n  calculateImageRows: () => calculateImageRows,\n  compositeTuiLine: () => compositeTuiLine,\n  decodeKittyPrintable: () => decodeKittyPrintable,\n  deleteAllKittyImages: () => deleteAllKittyImages,\n  deleteKittyImage: () => deleteKittyImage,\n  detectCapabilities: () => detectCapabilities,\n  encodeITerm2: () => encodeITerm2,\n  encodeKitty: () => encodeKitty,\n  fuzzyFilter: () => fuzzyFilter,\n  fuzzyMatch: () => fuzzyMatch,\n  getCapabilities: () => getCapabilities,\n  getCellDimensions: () => getCellDimensions,\n  getGifDimensions: () => getGifDimensions,\n  getImageDimensions: () => getImageDimensions,\n  getJpegDimensions: () => getJpegDimensions,\n  getKeybindings: () => getKeybindings,\n  getOsc8LinkAtColumn: () => getOsc8LinkAtColumn,\n  getPngDimensions: () => getPngDimensions,\n  getWebpDimensions: () => getWebpDimensions,\n  hyperlink: () => hyperlink,\n  imageFallback: () => imageFallback,\n  isFocusable: () => isFocusable,\n  isKeyRelease: () => isKeyRelease,\n  isKeyRepeat: () => isKeyRepeat,\n  isKittyProtocolActive: () => isKittyProtocolActive,\n  isViewportTUI: () => isViewportTUI,\n  matchesKey: () => matchesKey,\n  parseKey: () => parseKey,\n  parseOsc11BackgroundColor: () => parseOsc11BackgroundColor,\n  parseTerminalColorSchemeReport: () => parseTerminalColorSchemeReport,\n  renderImage: () => renderImage,\n  renderLatex: () => renderLatex,\n  resetCapabilitiesCache: () => resetCapabilitiesCache,\n  setCapabilities: () => setCapabilities,\n  setCellDimensions: () => setCellDimensions,\n  setKeybindings: () => setKeybindings,\n  setKittyProtocolActive: () => setKittyProtocolActive,\n  sliceByColumn: () => sliceByColumn,\n  stripTerminalSequences: () => stripTerminalSequences,\n  truncateToWidth: () => truncateToWidth,\n  visibleWidth: () => visibleWidth,\n  wrapTextWithAnsi: () => wrapTextWithAnsi\n});\nimport { Marked as Marked2 } from \"marked\";\n\n// node_modules/.pnpm/@earendil-works+pi-tui@0.84.2/node_modules/@earendil-works/pi-tui/dist/autocomplete.js\nimport { spawn as spawn2 } from \"child_process\";\nimport { readdirSync, statSync as statSync2 } from \"fs\";\nimport { homedir as homedir3 } from \"os\";\nimport { basename as basename2, dirname as dirname5, join as join7 } from \"path\";\n\n// node_modules/.pnpm/@earendil-works+pi-tui@0.84.2/node_modules/@earendil-works/pi-tui/dist/fuzzy.js\nfunction fuzzyMatch(query, text) {\n  const queryLower = query.toLowerCase();\n  const textLower = text.toLowerCase();\n  const matchQuery = (normalizedQuery) => {\n    if (normalizedQuery.length === 0) {\n      return { matches: true, score: 0 };\n    }\n    if (normalizedQuery.length > textLower.length) {\n      return { matches: false, score: 0 };\n    }\n    let queryIndex = 0;\n    let score = 0;\n    let lastMatchIndex = -1;\n    let consecutiveMatches = 0;\n    for (let i = 0; i < textLower.length && queryIndex < normalizedQuery.length; i++) {\n      if (textLower[i] === normalizedQuery[queryIndex]) {\n        const isWordBoundary = i === 0 || /[\\s\\-_./:]/.test(textLower[i - 1]);\n        if (lastMatchIndex === i - 1) {\n          consecutiveMatches++;\n          score -= consecutiveMatches * 5;\n        } else {\n          consecutiveMatches = 0;\n          if (lastMatchIndex >= 0) {\n            score += (i - lastMatchIndex - 1) * 2;\n          }\n        }\n        if (isWordBoundary) {\n          score -= 10;\n        }\n        score += i * 0.1;\n        lastMatchIndex = i;\n        queryIndex++;\n      }\n    }\n    if (queryIndex < normalizedQuery.length) {\n      return { matches: false, score: 0 };\n    }\n    if (normalizedQuery === textLower) {\n      score -= 100;\n    }\n    return { matches: true, score };\n  };\n  const primaryMatch = matchQuery(queryLower);\n  if (primaryMatch.matches) {\n    return primaryMatch;\n  }\n  const alphaNumericMatch = queryLower.match(/^(?<letters>[a-z]+)(?<digits>[0-9]+)$/);\n  const numericAlphaMatch = queryLower.match(/^(?<digits>[0-9]+)(?<letters>[a-z]+)$/);\n  const swappedQuery = alphaNumericMatch ? `${alphaNumericMatch.groups?.digits ?? \"\"}${alphaNumericMatch.groups?.letters ?? \"\"}` : numericAlphaMatch ? `${numericAlphaMatch.groups?.letters ?? \"\"}${numericAlphaMatch.groups?.digits ?? \"\"}` : \"\";\n  if (!swappedQuery) {\n    return primaryMatch;\n  }\n  const swappedMatch = matchQuery(swappedQuery);\n  if (!swappedMatch.matches) {\n    return primaryMatch;\n  }\n  return { matches: true, score: swappedMatch.score + 5 };\n}\nfunction fuzzyFilter(items, query, getText) {\n  if (!query.trim()) {\n    return items;\n  }\n  const tokens = query.trim().split(/[\\s/]+/).filter((t) => t.length > 0);\n  if (tokens.length === 0) {\n    return items;\n  }\n  const results = [];\n  for (const item of items) {\n    const text = getText(item);\n    let totalScore = 0;\n    let allMatch = true;\n    for (const token of tokens) {\n      const match = fuzzyMatch(token, text);\n      if (match.matches) {\n        totalScore += match.score;\n      } else {\n        allMatch = false;\n        break;\n      }\n    }\n    if (allMatch) {\n      results.push({ item, totalScore });\n    }\n  }\n  results.sort((a, b) => a.totalScore - b.totalScore);\n  return results.map((r) => r.item);\n}\n\n// node_modules/.pnpm/@earendil-works+pi-tui@0.84.2/node_modules/@earendil-works/pi-tui/dist/autocomplete.js\nvar PATH_DELIMITERS = /* @__PURE__ */ new Set([\" \", \"\t\", '\"', \"'\", \"=\"]);\nfunction toDisplayPath(value) {\n  return value.replace(/\\\\/g, \"/\");\n}\nfunction escapeRegex(value) {\n  return value.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\nfunction buildFdPathQuery(query) {\n  const normalized = toDisplayPath(query);\n  if (!normalized.includes(\"/\")) {\n    return normalized;\n  }\n  const hasTrailingSeparator = normalized.endsWith(\"/\");\n  const trimmed = normalized.replace(/^\\/+|\\/+$/g, \"\");\n  if (!trimmed) {\n    return normalized;\n  }\n  const separatorPattern = \"[\\\\\\\\/]\";\n  const segments = trimmed.split(\"/\").filter(Boolean).map((segment) => escapeRegex(segment));\n  if (segments.length === 0) {\n    return normalized;\n  }\n  let pattern = segments.join(separatorPattern);\n  if (hasTrailingSeparator) {\n    pattern += separatorPattern;\n  }\n  return pattern;\n}\nfunction findLastDelimiter(text) {\n  for (let i = text.length - 1; i >= 0; i -= 1) {\n    if (PATH_DELIMITERS.has(text[i] ?? \"\")) {\n      return i;\n    }\n  }\n  return -1;\n}\nfunction findUnclosedQuoteStart(text) {\n  let inQuotes = false;\n  let quoteStart = -1;\n  for (let i = 0; i < text.length; i += 1) {\n    if (text[i] === '\"') {\n      inQuotes = !inQuotes;\n      if (inQuotes) {\n        quoteStart = i;\n      }\n    }\n  }\n  return inQuotes ? quoteStart : null;\n}\nfunction isTokenStart(text, index) {\n  return index === 0 || PATH_DELIMITERS.has(text[index - 1] ?? \"\");\n}\nfunction extractQuotedPrefix(text) {\n  const quoteStart = findUnclosedQuoteStart(text);\n  if (quoteStart === null) {\n    return null;\n  }\n  if (quoteStart > 0 && text[quoteStart - 1] === \"@\") {\n    if (!isTokenStart(text, quoteStart - 1)) {\n      return null;\n    }\n    return text.slice(quoteStart - 1);\n  }\n  if (!isTokenStart(text, quoteStart)) {\n    return null;\n  }\n  return text.slice(quoteStart);\n}\nfunction parsePathPrefix(prefix) {\n  if (prefix.startsWith('@\"')) {\n    return { rawPrefix: prefix.slice(2), isAtPrefix: true, isQuotedPrefix: true };\n  }\n  if (prefix.startsWith('\"')) {\n    return { rawPrefix: prefix.slice(1), isAtPrefix: false, isQuotedPrefix: true };\n  }\n  if (prefix.startsWith(\"@\")) {\n    return { rawPrefix: prefix.slice(1), isAtPrefix: true, isQuotedPrefix: false };\n  }\n  return { rawPrefix: prefix, isAtPrefix: false, isQuotedPrefix: false };\n}\nfunction buildCompletionValue(path12, options) {\n  const needsQuotes = options.isQuotedPrefix || path12.includes(\" \");\n  const prefix = options.isAtPrefix ? \"@\" : \"\";\n  if (!needsQuotes) {\n    return `${prefix}${path12}`;\n  }\n  const openQuote = `${prefix}\"`;\n  const closeQuote = '\"';\n  return `${openQuote}${path12}${closeQuote}`;\n}\nasync function walkDirectoryWithFd(baseDir, fdPath, query, maxResults, signal) {\n  const args = [\n    \"--base-directory\",\n    baseDir,\n    \"--max-results\",\n    String(maxResults),\n    \"--type\",\n    \"f\",\n    \"--type\",\n    \"d\",\n    \"--follow\",\n    \"--hidden\",\n    \"--exclude\",\n    \".git\",\n    \"--exclude\",\n    \".git/*\",\n    \"--exclude\",\n    \".git/**\"\n  ];\n  if (toDisplayPath(query).includes(\"/\")) {\n    args.push(\"--full-path\");\n  }\n  if (query) {\n    args.push(buildFdPathQuery(query));\n  }\n  return await new Promise((resolve15) => {\n    if (signal.aborted) {\n      resolve15([]);\n      return;\n    }\n    const child = spawn2(fdPath, args, {\n      stdio: [\"ignore\", \"pipe\", \"pipe\"]\n    });\n    let stdout = \"\";\n    let resolved = false;\n    const finish = (results) => {\n      if (resolved)\n        return;\n      resolved = true;\n      signal.removeEventListener(\"abort\", onAbort);\n      resolve15(results);\n    };\n    const onAbort = () => {\n      if (child.exitCode === null) {\n        child.kill(\"SIGKILL\");\n      }\n    };\n    signal.addEventListener(\"abort\", onAbort, { once: true });\n    child.stdout.setEncoding(\"utf-8\");\n    child.stdout.on(\"data\", (chunk) => {\n      stdout += chunk;\n    });\n    child.on(\"error\", () => {\n      finish([]);\n    });\n    child.on(\"close\", (code) => {\n      if (signal.aborted || code !== 0 || !stdout) {\n        finish([]);\n        return;\n      }\n      const lines = stdout.trim().split(\"\\n\").filter(Boolean);\n      const results = [];\n      for (const line of lines) {\n        const displayLine = toDisplayPath(line);\n        const hasTrailingSeparator = displayLine.endsWith(\"/\");\n        const normalizedPath = hasTrailingSeparator ? displayLine.slice(0, -1) : displayLine;\n        if (normalizedPath === \".git\" || normalizedPath.startsWith(\".git/\") || normalizedPath.includes(\"/.git/\")) {\n          continue;\n        }\n        results.push({\n          path: displayLine,\n          isDirectory: hasTrailingSeparator\n        });\n      }\n      finish(results);\n    });\n  });\n}\nvar CombinedAutocompleteProvider = class {\n  commands;\n  basePath;\n  fdPath;\n  constructor(commands = [], basePath, fdPath = null) {\n    this.commands = commands;\n    this.basePath = basePath;\n    this.fdPath = fdPath;\n  }\n  async getSuggestions(lines, cursorLine, cursorCol, options) {\n    const currentLine = lines[cursorLine] || \"\";\n    const textBeforeCursor = currentLine.slice(0, cursorCol);\n    const atPrefix = this.extractAtPrefix(textBeforeCursor);\n    if (atPrefix) {\n      const { rawPrefix, isQuotedPrefix } = parsePathPrefix(atPrefix);\n      const suggestions2 = await this.getFuzzyFileSuggestions(rawPrefix, {\n        isQuotedPrefix,\n        signal: options.signal\n      });\n      if (suggestions2.length === 0)\n        return null;\n      return {\n        items: suggestions2,\n        prefix: atPrefix\n      };\n    }\n    if (!options.force && textBeforeCursor.startsWith(\"/\")) {\n      const spaceIndex = textBeforeCursor.indexOf(\" \");\n      if (spaceIndex === -1) {\n        const prefix = textBeforeCursor.slice(1);\n        const commandItems = this.commands.map((cmd) => {\n          const name = \"name\" in cmd ? cmd.name : cmd.value;\n          const hint = \"argumentHint\" in cmd && cmd.argumentHint ? cmd.argumentHint : void 0;\n          const desc = cmd.description ?? \"\";\n          const fullDesc = hint ? desc ? `${hint} \\u2014 ${desc}` : hint : desc;\n          return {\n            name,\n            label: name,\n            description: fullDesc || void 0\n          };\n        });\n        const filtered = fuzzyFilter(commandItems, prefix, (item) => item.name).map((item) => ({\n          value: item.name,\n          label: item.label,\n          ...item.description && { description: item.description }\n        }));\n        if (filtered.length === 0)\n          return null;\n        return {\n          items: filtered,\n          prefix: textBeforeCursor\n        };\n      }\n      const commandName = textBeforeCursor.slice(1, spaceIndex);\n      const argumentText = textBeforeCursor.slice(spaceIndex + 1);\n      const command = this.commands.find((cmd) => {\n        const name = \"name\" in cmd ? cmd.name : cmd.value;\n        return name === commandName;\n      });\n      if (!command || !(\"getArgumentCompletions\" in command) || !command.getArgumentCompletions) {\n        return null;\n      }\n      const argumentSuggestions = await command.getArgumentCompletions(argumentText);\n      if (!Array.isArray(argumentSuggestions) || argumentSuggestions.length === 0) {\n        return null;\n      }\n      return {\n        items: argumentSuggestions,\n        prefix: argumentText\n      };\n    }\n    const pathMatch = this.extractPathPrefix(textBeforeCursor, options.force ?? false);\n    if (pathMatch === null) {\n      return null;\n    }\n    const suggestions = this.getFileSuggestions(pathMatch);\n    if (suggestions.length === 0)\n      return null;\n    return {\n      items: suggestions,\n      prefix: pathMatch\n    };\n  }\n  applyCompletion(lines, cursorLine, cursorCol, item, prefix) {\n    const currentLine = lines[cursorLine] || \"\";\n    const beforePrefix = currentLine.slice(0, cursorCol - prefix.length);\n    const afterCursor = currentLine.slice(cursorCol);\n    const isQuotedPrefix = prefix.startsWith('\"') || prefix.startsWith('@\"');\n    const hasLeadingQuoteAfterCursor = afterCursor.startsWith('\"');\n    const hasTrailingQuoteInItem = item.value.endsWith('\"');\n    const adjustedAfterCursor = isQuotedPrefix && hasTrailingQuoteInItem && hasLeadingQuoteAfterCursor ? afterCursor.slice(1) : afterCursor;\n    const isSlashCommand = prefix.startsWith(\"/\") && beforePrefix.trim() === \"\" && !prefix.slice(1).includes(\"/\");\n    if (isSlashCommand) {\n      const newLine2 = `${beforePrefix}/${item.value} ${adjustedAfterCursor}`;\n      const newLines2 = [...lines];\n      newLines2[cursorLine] = newLine2;\n      return {\n        lines: newLines2,\n        cursorLine,\n        cursorCol: beforePrefix.length + item.value.length + 2\n        // +2 for \"/\" and space\n      };\n    }\n    if (prefix.startsWith(\"@\")) {\n      const isDirectory2 = item.label.endsWith(\"/\");\n      const suffix = isDirectory2 ? \"\" : \" \";\n      const newLine2 = `${beforePrefix + item.value}${suffix}${adjustedAfterCursor}`;\n      const newLines2 = [...lines];\n      newLines2[cursorLine] = newLine2;\n      const hasTrailingQuote2 = item.value.endsWith('\"');\n      const cursorOffset2 = isDirectory2 && hasTrailingQuote2 ? item.value.length - 1 : item.value.length;\n      return {\n        lines: newLines2,\n        cursorLine,\n        cursorCol: beforePrefix.length + cursorOffset2 + suffix.length\n      };\n    }\n    const textBeforeCursor = currentLine.slice(0, cursorCol);\n    if (textBeforeCursor.includes(\"/\") && textBeforeCursor.includes(\" \")) {\n      const newLine2 = beforePrefix + item.value + adjustedAfterCursor;\n      const newLines2 = [...lines];\n      newLines2[cursorLine] = newLine2;\n      const isDirectory2 = item.label.endsWith(\"/\");\n      const hasTrailingQuote2 = item.value.endsWith('\"');\n      const cursorOffset2 = isDirectory2 && hasTrailingQuote2 ? item.value.length - 1 : item.value.length;\n      return {\n        lines: newLines2,\n        cursorLine,\n        cursorCol: beforePrefix.length + cursorOffset2\n      };\n    }\n    const newLine = beforePrefix + item.value + adjustedAfterCursor;\n    const newLines = [...lines];\n    newLines[cursorLine] = newLine;\n    const isDirectory = item.label.endsWith(\"/\");\n    const hasTrailingQuote = item.value.endsWith('\"');\n    const cursorOffset = isDirectory && hasTrailingQuote ? item.value.length - 1 : item.value.length;\n    return {\n      lines: newLines,\n      cursorLine,\n      cursorCol: beforePrefix.length + cursorOffset\n    };\n  }\n  // Extract @ prefix for fuzzy file suggestions\n  extractAtPrefix(text) {\n    const quotedPrefix = extractQuotedPrefix(text);\n    if (quotedPrefix?.startsWith('@\"')) {\n      return quotedPrefix;\n    }\n    const lastDelimiterIndex = findLastDelimiter(text);\n    const tokenStart = lastDelimiterIndex === -1 ? 0 : lastDelimiterIndex + 1;\n    if (text[tokenStart] === \"@\") {\n      return text.slice(tokenStart);\n    }\n    return null;\n  }\n  // Extract a path-like prefix from the text before cursor\n  extractPathPrefix(text, forceExtract = false) {\n    const quotedPrefix = extractQuotedPrefix(text);\n    if (quotedPrefix) {\n      return quotedPrefix;\n    }\n    const lastDelimiterIndex = findLastDelimiter(text);\n    const pathPrefix = lastDelimiterIndex === -1 ? text : text.slice(lastDelimiterIndex + 1);\n    if (forceExtract) {\n      return pathPrefix;\n    }\n    if (pathPrefix.includes(\"/\") || pathPrefix.startsWith(\".\") || pathPrefix.startsWith(\"~/\")) {\n      return pathPrefix;\n    }\n    if (pathPrefix === \"\" && text.endsWith(\" \")) {\n      return pathPrefix;\n    }\n    return null;\n  }\n  // Expand home directory (~/) to actual home path\n  expandHomePath(path12) {\n    if (path12.startsWith(\"~/\")) {\n      const expandedPath = join7(homedir3(), path12.slice(2));\n      return path12.endsWith(\"/\") && !expandedPath.endsWith(\"/\") ? `${expandedPath}/` : expandedPath;\n    } else if (path12 === \"~\") {\n      return homedir3();\n    }\n    return path12;\n  }\n  resolveScopedFuzzyQuery(rawQuery) {\n    const normalizedQuery = toDisplayPath(rawQuery);\n    const slashIndex = normalizedQuery.lastIndexOf(\"/\");\n    if (slashIndex === -1) {\n      return null;\n    }\n    const displayBase = normalizedQuery.slice(0, slashIndex + 1);\n    const query = normalizedQuery.slice(slashIndex + 1);\n    let baseDir;\n    if (displayBase.startsWith(\"~/\")) {\n      baseDir = this.expandHomePath(displayBase);\n    } else if (displayBase.startsWith(\"/\")) {\n      baseDir = displayBase;\n    } else {\n      baseDir = join7(this.basePath, displayBase);\n    }\n    try {\n      if (!statSync2(baseDir).isDirectory()) {\n        return null;\n      }\n    } catch {\n      return null;\n    }\n    return { baseDir, query, displayBase };\n  }\n  scopedPathForDisplay(displayBase, relativePath) {\n    const normalizedRelativePath = toDisplayPath(relativePath);\n    if (displayBase === \"/\") {\n      return `/${normalizedRelativePath}`;\n    }\n    return `${toDisplayPath(displayBase)}${normalizedRelativePath}`;\n  }\n  // Get file/directory suggestions for a given path prefix\n  getFileSuggestions(prefix) {\n    try {\n      let searchDir;\n      let searchPrefix;\n      const { rawPrefix, isAtPrefix, isQuotedPrefix } = parsePathPrefix(prefix);\n      let expandedPrefix = rawPrefix;\n      if (expandedPrefix.startsWith(\"~\")) {\n        expandedPrefix = this.expandHomePath(expandedPrefix);\n      }\n      const isRootPrefix = rawPrefix === \"\" || rawPrefix === \"./\" || rawPrefix === \"../\" || rawPrefix === \"~\" || rawPrefix === \"~/\" || rawPrefix === \"/\" || isAtPrefix && rawPrefix === \"\";\n      if (isRootPrefix) {\n        if (rawPrefix.startsWith(\"~\") || expandedPrefix.startsWith(\"/\")) {\n          searchDir = expandedPrefix;\n        } else {\n          searchDir = join7(this.basePath, expandedPrefix);\n        }\n        searchPrefix = \"\";\n      } else if (rawPrefix.endsWith(\"/\")) {\n        if (rawPrefix.startsWith(\"~\") || expandedPrefix.startsWith(\"/\")) {\n          searchDir = expandedPrefix;\n        } else {\n          searchDir = join7(this.basePath, expandedPrefix);\n        }\n        searchPrefix = \"\";\n      } else {\n        const dir = dirname5(expandedPrefix);\n        const file = basename2(expandedPrefix);\n        if (rawPrefix.startsWith(\"~\") || expandedPrefix.startsWith(\"/\")) {\n          searchDir = dir;\n        } else {\n          searchDir = join7(this.basePath, dir);\n        }\n        searchPrefix = file;\n      }\n      const entries = readdirSync(searchDir, { withFileTypes: true });\n      const suggestions = [];\n      for (const entry of entries) {\n        if (!entry.name.toLowerCase().startsWith(searchPrefix.toLowerCase())) {\n          continue;\n        }\n        let isDirectory = entry.isDirectory();\n        if (!isDirectory && entry.isSymbolicLink()) {\n          try {\n            const fullPath = join7(searchDir, entry.name);\n            isDirectory = statSync2(fullPath).isDirectory();\n          } catch {\n          }\n        }\n        let relativePath;\n        const name = entry.name;\n        const displayPrefix = rawPrefix;\n        if (displayPrefix.endsWith(\"/\")) {\n          relativePath = displayPrefix + name;\n        } else if (displayPrefix.includes(\"/\") || displayPrefix.includes(\"\\\\\")) {\n          if (displayPrefix.startsWith(\"~/\")) {\n            const homeRelativeDir = displayPrefix.slice(2);\n            const dir = dirname5(homeRelativeDir);\n            relativePath = `~/${dir === \".\" ? name : join7(dir, name)}`;\n          } else if (displayPrefix.startsWith(\"/\")) {\n            const dir = dirname5(displayPrefix);\n            if (dir === \"/\") {\n              relativePath = `/${name}`;\n            } else {\n              relativePath = `${dir}/${name}`;\n            }\n          } else {\n            relativePath = join7(dirname5(displayPrefix), name);\n            if (displayPrefix.startsWith(\"./\") && !relativePath.startsWith(\"./\")) {\n              relativePath = `./${relativePath}`;\n            }\n          }\n        } else {\n          if (displayPrefix.startsWith(\"~\")) {\n            relativePath = `~/${name}`;\n          } else {\n            relativePath = name;\n          }\n        }\n        relativePath = toDisplayPath(relativePath);\n        const pathValue = isDirectory ? `${relativePath}/` : relativePath;\n        const value = buildCompletionValue(pathValue, {\n          isDirectory,\n          isAtPrefix,\n          isQuotedPrefix\n        });\n        suggestions.push({\n          value,\n          label: name + (isDirectory ? \"/\" : \"\")\n        });\n      }\n      suggestions.sort((a, b) => {\n        const aIsDir = a.value.endsWith(\"/\");\n        const bIsDir = b.value.endsWith(\"/\");\n        if (aIsDir && !bIsDir)\n          return -1;\n        if (!aIsDir && bIsDir)\n          return 1;\n        return a.label.localeCompare(b.label);\n      });\n      return suggestions;\n    } catch (_e) {\n      return [];\n    }\n  }\n  // Score an entry against the query (higher = better match)\n  // isDirectory adds bonus to prioritize folders\n  scoreEntry(filePath, query, isDirectory) {\n    const fileName = basename2(filePath);\n    const lowerFileName = fileName.toLowerCase();\n    const lowerQuery = query.toLowerCase();\n    let score = 0;\n    if (lowerFileName === lowerQuery)\n      score = 100;\n    else if (lowerFileName.startsWith(lowerQuery))\n      score = 80;\n    else if (lowerFileName.includes(lowerQuery))\n      score = 50;\n    else if (filePath.toLowerCase().includes(lowerQuery))\n      score = 30;\n    if (isDirectory && score > 0)\n      score += 10;\n    return score;\n  }\n  // Fuzzy file search using fd (fast, respects .gitignore)\n  async getFuzzyFileSuggestions(query, options) {\n    if (!this.fdPath || options.signal.aborted) {\n      return [];\n    }\n    try {\n      const scopedQuery = this.resolveScopedFuzzyQuery(query);\n      const fdBaseDir = scopedQuery?.baseDir ?? this.basePath;\n      const fdQuery = scopedQuery?.query ?? query;\n      const entries = await walkDirectoryWithFd(fdBaseDir, this.fdPath, fdQuery, 100, options.signal);\n      if (options.signal.aborted) {\n        return [];\n      }\n      const scoredEntries = entries.map((entry) => ({\n        ...entry,\n        score: fdQuery ? this.scoreEntry(entry.path, fdQuery, entry.isDirectory) : 1\n      })).filter((entry) => entry.score > 0);\n      scoredEntries.sort((a, b) => b.score - a.score);\n      const topEntries = scoredEntries.slice(0, 20);\n      const suggestions = [];\n      for (const { path: entryPath, isDirectory } of topEntries) {\n        const pathWithoutSlash = isDirectory ? entryPath.slice(0, -1) : entryPath;\n        const displayPath = scopedQuery ? this.scopedPathForDisplay(scopedQuery.displayBase, pathWithoutSlash) : pathWithoutSlash;\n        const entryName = basename2(pathWithoutSlash);\n        const completionPath = isDirectory ? `${displayPath}/` : displayPath;\n        const value = buildCompletionValue(completionPath, {\n          isDirectory,\n          isAtPrefix: true,\n          isQuotedPrefix: options.isQuotedPrefix\n        });\n        suggestions.push({\n          value,\n          label: entryName + (isDirectory ? \"/\" : \"\"),\n          description: displayPath\n        });\n      }\n      return suggestions;\n    } catch {\n      return [];\n    }\n  }\n  // Check if we should trigger file completion (called on Tab key)\n  shouldTriggerFileCompletion(lines, cursorLine, cursorCol) {\n    const currentLine = lines[cursorLine] || \"\";\n    const textBeforeCursor = currentLine.slice(0, cursorCol);\n    if (textBeforeCursor.trim().startsWith(\"/\") && !textBeforeCursor.trim().includes(\" \")) {\n      return false;\n    }\n    return true;\n  }\n};\n\n// node_modules/.pnpm/@earendil-works+pi-tui@0.84.2/node_modules/@earendil-works/pi-tui/dist/utils.js\nimport { eastAsianWidth } from \"get-east-asian-width\";\nvar graphemeSegmenter = new Intl.Segmenter(void 0, { granularity: \"grapheme\" });\nvar wordSegmenter = new Intl.Segmenter(void 0, { granularity: \"word\" });\nfunction getGraphemeSegmenter() {\n  return graphemeSegmenter;\n}\nfunction getWordSegmenter() {\n  return wordSegmenter;\n}\nfunction couldBeEmoji(segment) {\n  const cp = segment.codePointAt(0);\n  return cp >= 126976 && cp <= 130047 || // Emoji and Pictograph\n  cp >= 8960 && cp <= 9215 || // Misc technical\n  cp >= 9728 && cp <= 10175 || // Misc symbols, dingbats\n  cp >= 11088 && cp <= 11093 || // Specific stars/circles\n  segment.includes(\"\\uFE0F\") || // Contains VS16 (emoji presentation selector)\n  segment.length > 2;\n}\nvar zeroWidthRegex = new RegExp(\"^(?:\\\\p{Default_Ignorable_Code_Point}|\\\\p{Control}|\\\\p{Mark}|\\\\p{Surrogate})+$\", \"v\");\nvar leadingNonPrintingRegex = new RegExp(\"^[\\\\p{Default_Ignorable_Code_Point}\\\\p{Control}\\\\p{Format}\\\\p{Mark}\\\\p{Surrogate}]+\", \"v\");\nvar nonPrintingCharRegex = new RegExp(\"^(?:\\\\p{Default_Ignorable_Code_Point}|\\\\p{Control}|\\\\p{Format}|\\\\p{Mark}|\\\\p{Surrogate})$\", \"v\");\nvar markCharRegex = new RegExp(\"^\\\\p{Mark}$\", \"v\");\nvar terminalSpacingMarkRegex = new RegExp(\"^(?:[\\\\p{Spacing_Mark}--[\\\\u1734\\\\u302E\\\\u302F]]|[\\\\u065F\\\\u0F7F\\\\u102B\\\\u102C\\\\u1031\\\\u1033-\\\\u1035\\\\u1038\\\\u103A-\\\\u103E])+$\", \"v\");\nvar rgiEmojiRegex = new RegExp(\"^\\\\p{RGI_Emoji}$\", \"v\");\nvar WIDTH_CACHE_SIZE = 512;\nvar widthCache = /* @__PURE__ */ new Map();\nvar cjkBreakRegex = /[\\p{Script_Extensions=Han}\\p{Script_Extensions=Hiragana}\\p{Script_Extensions=Katakana}\\p{Script_Extensions=Hangul}\\p{Script_Extensions=Bopomofo}]/u;\nfunction isPrintableAscii(str2) {\n  for (let i = 0; i < str2.length; i++) {\n    const code = str2.charCodeAt(i);\n    if (code < 32 || code > 126) {\n      return false;\n    }\n  }\n  return true;\n}\nfunction truncateFragmentToWidth(text, maxWidth) {\n  if (maxWidth <= 0 || text.length === 0) {\n    return { text: \"\", width: 0 };\n  }\n  if (isPrintableAscii(text)) {\n    const clipped = text.slice(0, maxWidth);\n    return { text: clipped, width: clipped.length };\n  }\n  const hasAnsi = text.includes(\"\\x1B\");\n  const hasTabs = text.includes(\"\t\");\n  if (!hasAnsi && !hasTabs) {\n    let result2 = \"\";\n    let width2 = 0;\n    for (const { segment } of graphemeSegmenter.segment(text)) {\n      const w = graphemeWidth(segment);\n      if (width2 + w > maxWidth) {\n        break;\n      }\n      result2 += segment;\n      width2 += w;\n    }\n    return { text: result2, width: width2 };\n  }\n  let result = \"\";\n  let width = 0;\n  let i = 0;\n  let pendingAnsi = \"\";\n  while (i < text.length) {\n    const ansi = extractAnsiCode(text, i);\n    if (ansi) {\n      pendingAnsi += ansi.code;\n      i += ansi.length;\n      continue;\n    }\n    if (text[i] === \"\t\") {\n      if (width + 3 > maxWidth) {\n        break;\n      }\n      if (pendingAnsi) {\n        result += pendingAnsi;\n        pendingAnsi = \"\";\n      }\n      result += \"\t\";\n      width += 3;\n      i++;\n      continue;\n    }\n    let end = i;\n    while (end < text.length && text[end] !== \"\t\") {\n      const nextAnsi = extractAnsiCode(text, end);\n      if (nextAnsi) {\n        break;\n      }\n      end++;\n    }\n    for (const { segment } of graphemeSegmenter.segment(text.slice(i, end))) {\n      const w = graphemeWidth(segment);\n      if (width + w > maxWidth) {\n        return { text: result, width };\n      }\n      if (pendingAnsi) {\n        result += pendingAnsi;\n        pendingAnsi = \"\";\n      }\n      result += segment;\n      width += w;\n    }\n    i = end;\n  }\n  return { text: result, width };\n}\nfunction finalizeTruncatedResult(prefix, prefixWidth, ellipsis, ellipsisWidth, maxWidth, pad) {\n  const reset = \"\\x1B[0m\";\n  const hyperlinkClose = getActiveOsc8Close(prefix);\n  const visibleWidth2 = prefixWidth + ellipsisWidth;\n  let result;\n  if (ellipsis.length > 0) {\n    result = `${prefix}${hyperlinkClose}${reset}${ellipsis}${reset}`;\n  } else {\n    result = `${prefix}${hyperlinkClose}${reset}`;\n  }\n  return pad ? result + \" \".repeat(Math.max(0, maxWidth - visibleWidth2)) : result;\n}\nfunction graphemeWidth(segment) {\n  if (segment === \"\t\") {\n    return 3;\n  }\n  if (terminalSpacingMarkRegex.test(segment)) {\n    return [...segment].length;\n  }\n  if (zeroWidthRegex.test(segment)) {\n    return 0;\n  }\n  if (couldBeEmoji(segment) && rgiEmojiRegex.test(segment)) {\n    return 2;\n  }\n  const base = segment.replace(leadingNonPrintingRegex, \"\");\n  const cp = base.codePointAt(0);\n  if (cp === void 0) {\n    return 0;\n  }\n  if (cp >= 127462 && cp <= 127487) {\n    return 2;\n  }\n  let width = eastAsianWidth(cp);\n  let followsMark = false;\n  const chars = [...base];\n  for (const char of chars.slice(1)) {\n    if (terminalSpacingMarkRegex.test(char)) {\n      width += 1;\n      followsMark = false;\n    } else if (markCharRegex.test(char)) {\n      followsMark = true;\n    } else if (!nonPrintingCharRegex.test(char)) {\n      const c = char.codePointAt(0);\n      if (followsMark || c >= 65280 && c <= 65519) {\n        width += eastAsianWidth(c);\n      } else if (c === 3635 || c === 3763) {\n        width += 1;\n      }\n      followsMark = false;\n    }\n  }\n  return width;\n}\nfunction visibleWidth(str2) {\n  if (str2.length === 0) {\n    return 0;\n  }\n  if (isPrintableAscii(str2)) {\n    return str2.length;\n  }\n  const cached = widthCache.get(str2);\n  if (cached !== void 0) {\n    return cached;\n  }\n  let clean = str2;\n  if (str2.includes(\"\t\")) {\n    clean = clean.replace(/\\t/g, \"   \");\n  }\n  if (clean.includes(\"\\x1B\")) {\n    let stripped = \"\";\n    let i = 0;\n    while (i < clean.length) {\n      const ansi = extractAnsiCode(clean, i);\n      if (ansi) {\n        i += ansi.length;\n        continue;\n      }\n      stripped += clean[i];\n      i++;\n    }\n    clean = stripped;\n  }\n  let width = 0;\n  for (const { segment } of graphemeSegmenter.segment(clean)) {\n    width += graphemeWidth(segment);\n  }\n  if (widthCache.size >= WIDTH_CACHE_SIZE) {\n    const firstKey = widthCache.keys().next().value;\n    if (firstKey !== void 0) {\n      widthCache.delete(firstKey);\n    }\n  }\n  widthCache.set(str2, width);\n  return width;\n}\nfunction stripTerminalSequences(str2) {\n  if (!str2.includes(\"\\x1B\"))\n    return str2;\n  let result = \"\";\n  let i = 0;\n  while (i < str2.length) {\n    const ansi = extractAnsiCode(str2, i);\n    if (ansi) {\n      i += ansi.length;\n      continue;\n    }\n    result += str2[i];\n    i++;\n  }\n  return result;\n}\nfunction getGraphemeCellRange(line, column) {\n  let currentCol = 0;\n  let i = 0;\n  while (i < line.length) {\n    const ansi = extractAnsiCode(line, i);\n    if (ansi) {\n      i += ansi.length;\n      continue;\n    }\n    let textEnd = i;\n    while (textEnd < line.length && !extractAnsiCode(line, textEnd))\n      textEnd++;\n    for (const { segment } of graphemeSegmenter.segment(line.slice(i, textEnd))) {\n      const width = graphemeWidth(segment);\n      if (width > 0 && column >= currentCol && column < currentCol + width) {\n        return { start: currentCol, end: currentCol + width };\n      }\n      currentCol += width;\n    }\n    i = textEnd;\n  }\n  return void 0;\n}\nfunction getOsc8LinkAtColumn(line, column) {\n  let activeUrl;\n  let currentCol = 0;\n  let i = 0;\n  while (i < line.length) {\n    const ansi = extractAnsiCode(line, i);\n    if (ansi) {\n      const hyperlink2 = /^\\x1b\\]8;[^;]*;([^\\x07\\x1b]*)(?:\\x07|\\x1b\\\\)$/.exec(ansi.code);\n      if (hyperlink2)\n        activeUrl = hyperlink2[1] || void 0;\n      i += ansi.length;\n      continue;\n    }\n    let textEnd = i;\n    while (textEnd < line.length && !extractAnsiCode(line, textEnd))\n      textEnd++;\n    for (const { segment } of graphemeSegmenter.segment(line.slice(i, textEnd))) {\n      const width = segment === \"\t\" ? 3 : graphemeWidth(segment);\n      if (column >= currentCol && column < currentCol + width)\n        return activeUrl;\n      currentCol += width;\n    }\n    i = textEnd;\n  }\n  return void 0;\n}\nvar THAI_LAO_AM_REGEX = /[\\u0e33\\u0eb3]/;\nvar THAI_LAO_AM_GLOBAL_REGEX = /[\\u0e33\\u0eb3]/g;\nfunction normalizeTerminalOutput(str2) {\n  let normalized = str2;\n  if (THAI_LAO_AM_REGEX.test(normalized)) {\n    normalized = normalized.replace(THAI_LAO_AM_GLOBAL_REGEX, (char) => char === \"\\u0E33\" ? \"\\u0E4D\\u0E32\" : \"\\u0ECD\\u0EB2\");\n  }\n  if (!normalized.includes(\"\t\"))\n    return normalized;\n  let result = \"\";\n  let i = 0;\n  while (i < normalized.length) {\n    const ansi = extractAnsiCode(normalized, i);\n    if (ansi) {\n      result += ansi.code;\n      i += ansi.length;\n      continue;\n    }\n    result += normalized[i] === \"\t\" ? \"   \" : normalized[i];\n    i++;\n  }\n  return result;\n}\nfunction extractAnsiCode(str2, pos) {\n  if (pos >= str2.length || str2[pos] !== \"\\x1B\")\n    return null;\n  const next = str2[pos + 1];\n  if (next === \"[\") {\n    let j = pos + 2;\n    while (j < str2.length && !/[mGKHJ]/.test(str2[j]))\n      j++;\n    if (j < str2.length)\n      return { code: str2.substring(pos, j + 1), length: j + 1 - pos };\n    return null;\n  }\n  if (next === \"]\") {\n    let j = pos + 2;\n    while (j < str2.length) {\n      if (str2[j] === \"\\x07\")\n        return { code: str2.substring(pos, j + 1), length: j + 1 - pos };\n      if (str2[j] === \"\\x1B\" && str2[j + 1] === \"\\\\\")\n        return { code: str2.substring(pos, j + 2), length: j + 2 - pos };\n      j++;\n    }\n    return null;\n  }\n  if (next === \"_\") {\n    let j = pos + 2;\n    while (j < str2.length) {\n      if (str2[j] === \"\\x07\")\n        return { code: str2.substring(pos, j + 1), length: j + 1 - pos };\n      if (str2[j] === \"\\x1B\" && str2[j + 1] === \"\\\\\")\n        return { code: str2.substring(pos, j + 2), length: j + 2 - pos };\n      j++;\n    }\n    return null;\n  }\n  return null;\n}\nfunction parseOsc8Hyperlink(ansiCode) {\n  if (!ansiCode.startsWith(\"\\x1B]8;\")) {\n    return void 0;\n  }\n  const terminator = ansiCode.endsWith(\"\\x07\") ? \"\\x07\" : \"\\x1B\\\\\";\n  const body = ansiCode.slice(4, terminator === \"\\x07\" ? -1 : -2);\n  const separatorIndex = body.indexOf(\";\");\n  if (separatorIndex === -1) {\n    return void 0;\n  }\n  const params = body.slice(0, separatorIndex);\n  const url = body.slice(separatorIndex + 1);\n  if (!url) {\n    return null;\n  }\n  return { params, url, terminator };\n}\nfunction formatOsc8Hyperlink(hyperlink2) {\n  return `\\x1B]8;${hyperlink2.params};${hyperlink2.url}${hyperlink2.terminator}`;\n}\nfunction formatOsc8Close(terminator) {\n  return `\\x1B]8;;${terminator}`;\n}\nfunction getActiveOsc8Close(prefix) {\n  if (!prefix.includes(\"\\x1B]8;\")) {\n    return \"\";\n  }\n  let activeHyperlink = null;\n  let i = 0;\n  while (i < prefix.length) {\n    const ansi = extractAnsiCode(prefix, i);\n    if (ansi) {\n      const hyperlink2 = parseOsc8Hyperlink(ansi.code);\n      if (hyperlink2 !== void 0) {\n        activeHyperlink = hyperlink2;\n      }\n      i += ansi.length;\n    } else {\n      i++;\n    }\n  }\n  return activeHyperlink ? formatOsc8Close(activeHyperlink.terminator) : \"\";\n}\nvar AnsiCodeTracker = class {\n  // Track individual attributes separately so we can reset them specifically\n  bold = false;\n  dim = false;\n  italic = false;\n  underline = false;\n  blink = false;\n  inverse = false;\n  hidden = false;\n  strikethrough = false;\n  fgColor = null;\n  // Stores the full code like \"31\" or \"38;5;240\"\n  bgColor = null;\n  // Stores the full code like \"41\" or \"48;5;240\"\n  activeHyperlink = null;\n  process(ansiCode) {\n    const hyperlink2 = parseOsc8Hyperlink(ansiCode);\n    if (hyperlink2 !== void 0) {\n      this.activeHyperlink = hyperlink2;\n      return;\n    }\n    if (!ansiCode.endsWith(\"m\")) {\n      return;\n    }\n    const match = ansiCode.match(/\\x1b\\[([\\d;]*)m/);\n    if (!match)\n      return;\n    const params = match[1];\n    if (params === \"\" || params === \"0\") {\n      this.reset();\n      return;\n    }\n    const parts = params.split(\";\");\n    let i = 0;\n    while (i < parts.length) {\n      const code = Number.parseInt(parts[i], 10);\n      if (code === 38 || code === 48) {\n        if (parts[i + 1] === \"5\" && parts[i + 2] !== void 0) {\n          const colorCode = `${parts[i]};${parts[i + 1]};${parts[i + 2]}`;\n          if (code === 38) {\n            this.fgColor = colorCode;\n          } else {\n            this.bgColor = colorCode;\n          }\n          i += 3;\n          continue;\n        } else if (parts[i + 1] === \"2\" && parts[i + 4] !== void 0) {\n          const colorCode = `${parts[i]};${parts[i + 1]};${parts[i + 2]};${parts[i + 3]};${parts[i + 4]}`;\n          if (code === 38) {\n            this.fgColor = colorCode;\n          } else {\n            this.bgColor = colorCode;\n          }\n          i += 5;\n          continue;\n        }\n      }\n      switch (code) {\n        case 0:\n          this.reset();\n          break;\n        case 1:\n          this.bold = true;\n          break;\n        case 2:\n          this.dim = true;\n          break;\n        case 3:\n          this.italic = true;\n          break;\n        case 4:\n          this.underline = true;\n          break;\n        case 5:\n          this.blink = true;\n          break;\n        case 7:\n          this.inverse = true;\n          break;\n        case 8:\n          this.hidden = true;\n          break;\n        case 9:\n          this.strikethrough = true;\n          break;\n        case 21:\n          this.bold = false;\n          break;\n        // Some terminals\n        case 22:\n          this.bold = false;\n          this.dim = false;\n          break;\n        case 23:\n          this.italic = false;\n          break;\n        case 24:\n          this.underline = false;\n          break;\n        case 25:\n          this.blink = false;\n          break;\n        case 27:\n          this.inverse = false;\n          break;\n        case 28:\n          this.hidden = false;\n          break;\n        case 29:\n          this.strikethrough = false;\n          break;\n        case 39:\n          this.fgColor = null;\n          break;\n        // Default fg\n        case 49:\n          this.bgColor = null;\n          break;\n        // Default bg\n        default:\n          if (code >= 30 && code <= 37 || code >= 90 && code <= 97) {\n            this.fgColor = String(code);\n          } else if (code >= 40 && code <= 47 || code >= 100 && code <= 107) {\n            this.bgColor = String(code);\n          }\n          break;\n      }\n      i++;\n    }\n  }\n  reset() {\n    this.bold = false;\n    this.dim = false;\n    this.italic = false;\n    this.underline = false;\n    this.blink = false;\n    this.inverse = false;\n    this.hidden = false;\n    this.strikethrough = false;\n    this.fgColor = null;\n    this.bgColor = null;\n  }\n  /** Clear all state for reuse. */\n  clear() {\n    this.reset();\n    this.activeHyperlink = null;\n  }\n  getActiveCodes() {\n    const codes = [];\n    if (this.bold)\n      codes.push(\"1\");\n    if (this.dim)\n      codes.push(\"2\");\n    if (this.italic)\n      codes.push(\"3\");\n    if (this.underline)\n      codes.push(\"4\");\n    if (this.blink)\n      codes.push(\"5\");\n    if (this.inverse)\n      codes.push(\"7\");\n    if (this.hidden)\n      codes.push(\"8\");\n    if (this.strikethrough)\n      codes.push(\"9\");\n    if (this.fgColor)\n      codes.push(this.fgColor);\n    if (this.bgColor)\n      codes.push(this.bgColor);\n    let result = codes.length > 0 ? `\\x1B[${codes.join(\";\")}m` : \"\";\n    if (this.activeHyperlink) {\n      result += formatOsc8Hyperlink(this.activeHyperlink);\n    }\n    return result;\n  }\n  hasActiveCodes() {\n    return this.bold || this.dim || this.italic || this.underline || this.blink || this.inverse || this.hidden || this.strikethrough || this.fgColor !== null || this.bgColor !== null || this.activeHyperlink !== null;\n  }\n  /**\n   * Get reset codes for attributes that need to be turned off at line end.\n   * Underline must be closed to prevent bleeding into padding.\n   * Active OSC 8 hyperlinks must be closed and re-opened on the next line.\n   * Returns empty string if no attributes need closing.\n   */\n  getLineEndReset() {\n    let result = \"\";\n    if (this.underline) {\n      result += \"\\x1B[24m\";\n    }\n    if (this.activeHyperlink) {\n      result += formatOsc8Close(this.activeHyperlink.terminator);\n    }\n    return result;\n  }\n};\nfunction updateTrackerFromText(text, tracker) {\n  let i = 0;\n  while (i < text.length) {\n    const ansiResult = extractAnsiCode(text, i);\n    if (ansiResult) {\n      tracker.process(ansiResult.code);\n      i += ansiResult.length;\n    } else {\n      i++;\n    }\n  }\n}\nfunction splitIntoTokensWithAnsi(text) {\n  const tokens = [];\n  let current = \"\";\n  let pendingAnsi = \"\";\n  let currentKind = null;\n  let i = 0;\n  const flushCurrent = () => {\n    if (!current) {\n      return;\n    }\n    tokens.push(current);\n    current = \"\";\n    currentKind = null;\n  };\n  while (i < text.length) {\n    const ansiResult = extractAnsiCode(text, i);\n    if (ansiResult) {\n      pendingAnsi += ansiResult.code;\n      i += ansiResult.length;\n      continue;\n    }\n    let end = i;\n    while (end < text.length && !extractAnsiCode(text, end)) {\n      end++;\n    }\n    for (const { segment } of graphemeSegmenter.segment(text.slice(i, end))) {\n      const segmentIsSpace = segment === \" \";\n      if (!segmentIsSpace && cjkBreakRegex.test(segment)) {\n        flushCurrent();\n        const token = pendingAnsi + segment;\n        pendingAnsi = \"\";\n        tokens.push(token);\n        continue;\n      }\n      const segmentKind = segmentIsSpace ? \"space\" : \"word\";\n      if (current && currentKind !== segmentKind) {\n        flushCurrent();\n      }\n      if (pendingAnsi) {\n        current += pendingAnsi;\n        pendingAnsi = \"\";\n      }\n      currentKind = segmentKind;\n      current += segment;\n    }\n    i = end;\n  }\n  if (pendingAnsi) {\n    if (current) {\n      current += pendingAnsi;\n    } else if (tokens.length > 0) {\n      tokens[tokens.length - 1] += pendingAnsi;\n    } else {\n      current = pendingAnsi;\n    }\n  }\n  if (current) {\n    tokens.push(current);\n  }\n  return tokens;\n}\nfunction wrapTextWithAnsi(text, width) {\n  if (!text) {\n    return [\"\"];\n  }\n  const inputLines = text.split(/\\r\\n|\\r|\\n/);\n  const result = [];\n  const tracker = new AnsiCodeTracker();\n  for (const inputLine of inputLines) {\n    const prefix = result.length > 0 ? tracker.getActiveCodes() : \"\";\n    const wrappedLines = wrapSingleLine(prefix + inputLine, width);\n    for (const wrappedLine of wrappedLines) {\n      result.push(wrappedLine);\n    }\n    updateTrackerFromText(inputLine, tracker);\n  }\n  return result.length > 0 ? result : [\"\"];\n}\nfunction wrapSingleLine(line, width) {\n  if (!line) {\n    return [\"\"];\n  }\n  const visibleLength = visibleWidth(line);\n  if (visibleLength <= width) {\n    return [line];\n  }\n  const wrapped = [];\n  const tracker = new AnsiCodeTracker();\n  const tokens = splitIntoTokensWithAnsi(line);\n  let currentLine = \"\";\n  let currentVisibleLength = 0;\n  for (const token of tokens) {\n    const tokenVisibleLength = visibleWidth(token);\n    const isWhitespace = token.trim() === \"\";\n    if (tokenVisibleLength > width && !isWhitespace) {\n      if (currentLine) {\n        const lineEndReset = tracker.getLineEndReset();\n        if (lineEndReset) {\n          currentLine += lineEndReset;\n        }\n        wrapped.push(currentLine);\n        currentLine = \"\";\n        currentVisibleLength = 0;\n      }\n      const broken = breakLongWord(token, width, tracker);\n      for (let i = 0; i < broken.length - 1; i++) {\n        wrapped.push(broken[i]);\n      }\n      currentLine = broken[broken.length - 1];\n      currentVisibleLength = visibleWidth(currentLine);\n      continue;\n    }\n    const totalNeeded = currentVisibleLength + tokenVisibleLength;\n    if (totalNeeded > width && currentVisibleLength > 0) {\n      let lineToWrap = currentLine.trimEnd();\n      const lineEndReset = tracker.getLineEndReset();\n      if (lineEndReset) {\n        lineToWrap += lineEndReset;\n      }\n      wrapped.push(lineToWrap);\n      if (isWhitespace) {\n        currentLine = tracker.getActiveCodes();\n        currentVisibleLength = 0;\n      } else {\n        currentLine = tracker.getActiveCodes() + token;\n        currentVisibleLength = tokenVisibleLength;\n      }\n    } else {\n      currentLine += token;\n      currentVisibleLength += tokenVisibleLength;\n    }\n    updateTrackerFromText(token, tracker);\n  }\n  if (currentLine) {\n    wrapped.push(currentLine);\n  }\n  return wrapped.length > 0 ? wrapped.map((line2) => line2.trimEnd()) : [\"\"];\n}\nvar PUNCTUATION_REGEX = /[(){}[\\]<>.,;:'\"!?+\\-=*/\\\\|&%^$#@~`]/;\nfunction isWhitespaceChar(char) {\n  return /\\s/.test(char);\n}\nfunction breakLongWord(word, width, tracker) {\n  const lines = [];\n  let currentLine = tracker.getActiveCodes();\n  let currentWidth = 0;\n  let i = 0;\n  const segments = [];\n  while (i < word.length) {\n    const ansiResult = extractAnsiCode(word, i);\n    if (ansiResult) {\n      segments.push({ type: \"ansi\", value: ansiResult.code });\n      i += ansiResult.length;\n    } else {\n      let end = i;\n      while (end < word.length) {\n        const nextAnsi = extractAnsiCode(word, end);\n        if (nextAnsi)\n          break;\n        end++;\n      }\n      const textPortion = word.slice(i, end);\n      for (const seg of graphemeSegmenter.segment(textPortion)) {\n        segments.push({ type: \"grapheme\", value: seg.segment });\n      }\n      i = end;\n    }\n  }\n  for (const seg of segments) {\n    if (seg.type === \"ansi\") {\n      currentLine += seg.value;\n      tracker.process(seg.value);\n      continue;\n    }\n    const grapheme = seg.value;\n    if (!grapheme)\n      continue;\n    const graphemeWidth2 = visibleWidth(grapheme);\n    if (currentWidth + graphemeWidth2 > width) {\n      const lineEndReset = tracker.getLineEndReset();\n      if (lineEndReset) {\n        currentLine += lineEndReset;\n      }\n      lines.push(currentLine);\n      currentLine = tracker.getActiveCodes();\n      currentWidth = 0;\n    }\n    currentLine += grapheme;\n    currentWidth += graphemeWidth2;\n  }\n  if (currentLine) {\n    lines.push(currentLine);\n  }\n  return lines.length > 0 ? lines : [\"\"];\n}\nfunction applyBackgroundToLine(line, width, bgFn) {\n  const visibleLen = visibleWidth(line);\n  const paddingNeeded = Math.max(0, width - visibleLen);\n  const padding = \" \".repeat(paddingNeeded);\n  const withPadding = line + padding;\n  return bgFn(withPadding);\n}\nfunction truncateToWidth(text, maxWidth, ellipsis = \"...\", pad = false) {\n  if (maxWidth <= 0) {\n    return \"\";\n  }\n  if (text.length === 0) {\n    return pad ? \" \".repeat(maxWidth) : \"\";\n  }\n  const ellipsisWidth = visibleWidth(ellipsis);\n  if (ellipsisWidth >= maxWidth) {\n    const textWidth = visibleWidth(text);\n    if (textWidth <= maxWidth) {\n      return pad ? text + \" \".repeat(maxWidth - textWidth) : text;\n    }\n    const clippedEllipsis = truncateFragmentToWidth(ellipsis, maxWidth);\n    if (clippedEllipsis.width === 0) {\n      return pad ? \" \".repeat(maxWidth) : \"\";\n    }\n    return finalizeTruncatedResult(\"\", 0, clippedEllipsis.text, clippedEllipsis.width, maxWidth, pad);\n  }\n  if (isPrintableAscii(text)) {\n    if (text.length <= maxWidth) {\n      return pad ? text + \" \".repeat(maxWidth - text.length) : text;\n    }\n    const targetWidth2 = maxWidth - ellipsisWidth;\n    return finalizeTruncatedResult(text.slice(0, targetWidth2), targetWidth2, ellipsis, ellipsisWidth, maxWidth, pad);\n  }\n  const targetWidth = maxWidth - ellipsisWidth;\n  let result = \"\";\n  let pendingAnsi = \"\";\n  let visibleSoFar = 0;\n  let keptWidth = 0;\n  let keepContiguousPrefix = true;\n  let overflowed = false;\n  let exhaustedInput = false;\n  const hasAnsi = text.includes(\"\\x1B\");\n  const hasTabs = text.includes(\"\t\");\n  if (!hasAnsi && !hasTabs) {\n    for (const { segment } of graphemeSegmenter.segment(text)) {\n      const width = graphemeWidth(segment);\n      if (keepContiguousPrefix && keptWidth + width <= targetWidth) {\n        result += segment;\n        keptWidth += width;\n      } else {\n        keepContiguousPrefix = false;\n      }\n      visibleSoFar += width;\n      if (visibleSoFar > maxWidth) {\n        overflowed = true;\n        break;\n      }\n    }\n    exhaustedInput = !overflowed;\n  } else {\n    let i = 0;\n    while (i < text.length) {\n      const ansi = extractAnsiCode(text, i);\n      if (ansi) {\n        pendingAnsi += ansi.code;\n        i += ansi.length;\n        continue;\n      }\n      if (text[i] === \"\t\") {\n        if (keepContiguousPrefix && keptWidth + 3 <= targetWidth) {\n          if (pendingAnsi) {\n            result += pendingAnsi;\n            pendingAnsi = \"\";\n          }\n          result += \"\t\";\n          keptWidth += 3;\n        } else {\n          keepContiguousPrefix = false;\n          pendingAnsi = \"\";\n        }\n        visibleSoFar += 3;\n        if (visibleSoFar > maxWidth) {\n          overflowed = true;\n          break;\n        }\n        i++;\n        continue;\n      }\n      let end = i;\n      while (end < text.length && text[end] !== \"\t\") {\n        const nextAnsi = extractAnsiCode(text, end);\n        if (nextAnsi) {\n          break;\n        }\n        end++;\n      }\n      for (const { segment } of graphemeSegmenter.segment(text.slice(i, end))) {\n        const width = graphemeWidth(segment);\n        if (keepContiguousPrefix && keptWidth + width <= targetWidth) {\n          if (pendingAnsi) {\n            result += pendingAnsi;\n            pendingAnsi = \"\";\n          }\n          result += segment;\n          keptWidth += width;\n        } else {\n          keepContiguousPrefix = false;\n          pendingAnsi = \"\";\n        }\n        visibleSoFar += width;\n        if (visibleSoFar > maxWidth) {\n          overflowed = true;\n          break;\n        }\n      }\n      if (overflowed) {\n        break;\n      }\n      i = end;\n    }\n    exhaustedInput = i >= text.length;\n  }\n  if (!overflowed && exhaustedInput) {\n    return pad ? text + \" \".repeat(Math.max(0, maxWidth - visibleSoFar)) : text;\n  }\n  return finalizeTruncatedResult(result, keptWidth, ellipsis, ellipsisWidth, maxWidth, pad);\n}\nfunction sliceByColumn(line, startCol, length, strict = false) {\n  return sliceWithWidth(line, startCol, length, strict).text;\n}\nfunction sliceWithWidth(line, startCol, length, strict = false) {\n  if (length <= 0)\n    return { text: \"\", width: 0 };\n  const endCol = startCol + length;\n  let result = \"\", resultWidth = 0, currentCol = 0, i = 0, pendingAnsi = \"\";\n  while (i < line.length) {\n    const ansi = extractAnsiCode(line, i);\n    if (ansi) {\n      if (currentCol >= startCol && currentCol < endCol)\n        result += ansi.code;\n      else if (currentCol < startCol)\n        pendingAnsi += ansi.code;\n      i += ansi.length;\n      continue;\n    }\n    let textEnd = i;\n    while (textEnd < line.length && !extractAnsiCode(line, textEnd))\n      textEnd++;\n    for (const { segment } of graphemeSegmenter.segment(line.slice(i, textEnd))) {\n      const w = graphemeWidth(segment);\n      const inRange = currentCol >= startCol && currentCol < endCol;\n      const fits = !strict || currentCol + w <= endCol;\n      if (inRange && fits) {\n        if (pendingAnsi) {\n          result += pendingAnsi;\n          pendingAnsi = \"\";\n        }\n        result += segment;\n        resultWidth += w;\n      }\n      currentCol += w;\n      if (currentCol >= endCol)\n        break;\n    }\n    i = textEnd;\n    if (currentCol >= endCol)\n      break;\n  }\n  return { text: result, width: resultWidth };\n}\nvar pooledStyleTracker = new AnsiCodeTracker();\nfunction extractSegments(line, beforeEnd, afterStart, afterLen, strictAfter = false) {\n  let before = \"\", beforeWidth = 0, after = \"\", afterWidth = 0;\n  let currentCol = 0, i = 0;\n  let pendingAnsiBefore = \"\";\n  let afterStarted = false;\n  const afterEnd = afterStart + afterLen;\n  pooledStyleTracker.clear();\n  while (i < line.length) {\n    const ansi = extractAnsiCode(line, i);\n    if (ansi) {\n      pooledStyleTracker.process(ansi.code);\n      if (currentCol < beforeEnd) {\n        pendingAnsiBefore += ansi.code;\n      } else if (currentCol >= afterStart && currentCol < afterEnd && afterStarted) {\n        after += ansi.code;\n      }\n      i += ansi.length;\n      continue;\n    }\n    let textEnd = i;\n    while (textEnd < line.length && !extractAnsiCode(line, textEnd))\n      textEnd++;\n    for (const { segment } of graphemeSegmenter.segment(line.slice(i, textEnd))) {\n      const w = graphemeWidth(segment);\n      if (currentCol < beforeEnd && currentCol + w <= beforeEnd) {\n        if (pendingAnsiBefore) {\n          before += pendingAnsiBefore;\n          pendingAnsiBefore = \"\";\n        }\n        before += segment;\n        beforeWidth += w;\n      } else if (currentCol >= afterStart && currentCol < afterEnd) {\n        const fits = !strictAfter || currentCol + w <= afterEnd;\n        if (fits) {\n          if (!afterStarted) {\n            after += pooledStyleTracker.getActiveCodes();\n            afterStarted = true;\n          }\n          after += segment;\n          afterWidth += w;\n        }\n      }\n      currentCol += w;\n      if (afterLen <= 0 ? currentCol >= beforeEnd : currentCol >= afterEnd)\n        break;\n    }\n    i = textEnd;\n    if (afterLen <= 0 ? currentCol >= beforeEnd : currentCol >= afterEnd)\n      break;\n  }\n  return { before, beforeWidth, after, afterWidth };\n}\n\n// node_modules/.pnpm/@earendil-works+pi-tui@0.84.2/node_modules/@earendil-works/pi-tui/dist/components/box.js\nvar Box = class {\n  children = [];\n  paddingX;\n  paddingY;\n  bgFn;\n  // Cache for rendered output\n  cache;\n  constructor(paddingX = 1, paddingY = 1, bgFn) {\n    this.paddingX = paddingX;\n    this.paddingY = paddingY;\n    this.bgFn = bgFn;\n  }\n  addChild(component) {\n    this.children.push(component);\n    this.invalidateCache();\n  }\n  removeChild(component) {\n    const index = this.children.indexOf(component);\n    if (index !== -1) {\n      this.children.splice(index, 1);\n      this.invalidateCache();\n    }\n  }\n  clear() {\n    this.children = [];\n    this.invalidateCache();\n  }\n  setBgFn(bgFn) {\n    this.bgFn = bgFn;\n  }\n  invalidateCache() {\n    this.cache = void 0;\n  }\n  matchCache(width, childLines, bgSample) {\n    const cache = this.cache;\n    return !!cache && cache.width === width && cache.bgSample === bgSample && cache.childLines.length === childLines.length && cache.childLines.every((line, i) => line === childLines[i]);\n  }\n  invalidate() {\n    this.invalidateCache();\n    for (const child of this.children) {\n      child.invalidate?.();\n    }\n  }\n  render(width) {\n    if (this.children.length === 0) {\n      return [];\n    }\n    const contentWidth = Math.max(1, width - this.paddingX * 2);\n    const leftPad = \" \".repeat(this.paddingX);\n    const childLines = [];\n    for (const child of this.children) {\n      const lines = child.render(contentWidth);\n      for (const line of lines) {\n        childLines.push(leftPad + line);\n      }\n    }\n    if (childLines.length === 0) {\n      return [];\n    }\n    const bgSample = this.bgFn ? this.bgFn(\"test\") : void 0;\n    if (this.matchCache(width, childLines, bgSample)) {\n      return this.cache.lines;\n    }\n    const result = [];\n    for (let i = 0; i < this.paddingY; i++) {\n      result.push(this.applyBg(\"\", width));\n    }\n    for (const line of childLines) {\n      result.push(this.applyBg(line, width));\n    }\n    for (let i = 0; i < this.paddingY; i++) {\n      result.push(this.applyBg(\"\", width));\n    }\n    this.cache = { childLines, width, bgSample, lines: result };\n    return result;\n  }\n  applyBg(line, width) {\n    const visLen = visibleWidth(line);\n    const padNeeded = Math.max(0, width - visLen);\n    const padded = line + \" \".repeat(padNeeded);\n    if (this.bgFn) {\n      return applyBackgroundToLine(padded, width, this.bgFn);\n    }\n    return padded;\n  }\n};\n\n// node_modules/.pnpm/@earendil-works+pi-tui@0.84.2/node_modules/@earendil-works/pi-tui/dist/keys.js\nvar _kittyProtocolActive = false;\nfunction setKittyProtocolActive(active) {\n  _kittyProtocolActive = active;\n}\nfunction isKittyProtocolActive() {\n  return _kittyProtocolActive;\n}\nvar Key = {\n  // Special keys\n  escape: \"escape\",\n  esc: \"esc\",\n  enter: \"enter\",\n  return: \"return\",\n  tab: \"tab\",\n  space: \"space\",\n  backspace: \"backspace\",\n  delete: \"delete\",\n  insert: \"insert\",\n  clear: \"clear\",\n  home: \"home\",\n  end: \"end\",\n  pageUp: \"pageUp\",\n  pageDown: \"pageDown\",\n  up: \"up\",\n  down: \"down\",\n  left: \"left\",\n  right: \"right\",\n  f1: \"f1\",\n  f2: \"f2\",\n  f3: \"f3\",\n  f4: \"f4\",\n  f5: \"f5\",\n  f6: \"f6\",\n  f7: \"f7\",\n  f8: \"f8\",\n  f9: \"f9\",\n  f10: \"f10\",\n  f11: \"f11\",\n  f12: \"f12\",\n  // Symbol keys\n  backtick: \"`\",\n  hyphen: \"-\",\n  equals: \"=\",\n  leftbracket: \"[\",\n  rightbracket: \"]\",\n  backslash: \"\\\\\",\n  semicolon: \";\",\n  quote: \"'\",\n  comma: \",\",\n  period: \".\",\n  slash: \"/\",\n  exclamation: \"!\",\n  at: \"@\",\n  hash: \"#\",\n  dollar: \"$\",\n  percent: \"%\",\n  caret: \"^\",\n  ampersand: \"&\",\n  asterisk: \"*\",\n  leftparen: \"(\",\n  rightparen: \")\",\n  underscore: \"_\",\n  plus: \"+\",\n  pipe: \"|\",\n  tilde: \"~\",\n  leftbrace: \"{\",\n  rightbrace: \"}\",\n  colon: \":\",\n  lessthan: \"<\",\n  greaterthan: \">\",\n  question: \"?\",\n  // Single modifiers\n  ctrl: (key) => `ctrl+${key}`,\n  shift: (key) => `shift+${key}`,\n  alt: (key) => `alt+${key}`,\n  super: (key) => `super+${key}`,\n  // Combined modifiers\n  ctrlShift: (key) => `ctrl+shift+${key}`,\n  shiftCtrl: (key) => `shift+ctrl+${key}`,\n  ctrlAlt: (key) => `ctrl+alt+${key}`,\n  altCtrl: (key) => `alt+ctrl+${key}`,\n  shiftAlt: (key) => `shift+alt+${key}`,\n  altShift: (key) => `alt+shift+${key}`,\n  ctrlSuper: (key) => `ctrl+super+${key}`,\n  superCtrl: (key) => `super+ctrl+${key}`,\n  shiftSuper: (key) => `shift+super+${key}`,\n  superShift: (key) => `super+shift+${key}`,\n  altSuper: (key) => `alt+super+${key}`,\n  superAlt: (key) => `super+alt+${key}`,\n  // Triple modifiers\n  ctrlShiftAlt: (key) => `ctrl+shift+alt+${key}`,\n  ctrlShiftSuper: (key) => `ctrl+shift+super+${key}`\n};\nvar SYMBOL_KEYS = /* @__PURE__ */ new Set([\n  \"`\",\n  \"-\",\n  \"=\",\n  \"[\",\n  \"]\",\n  \"\\\\\",\n  \";\",\n  \"'\",\n  \",\",\n  \".\",\n  \"/\",\n  \"!\",\n  \"@\",\n  \"#\",\n  \"$\",\n  \"%\",\n  \"^\",\n  \"&\",\n  \"*\",\n  \"(\",\n  \")\",\n  \"_\",\n  \"+\",\n  \"|\",\n  \"~\",\n  \"{\",\n  \"}\",\n  \":\",\n  \"<\",\n  \">\",\n  \"?\"\n]);\nvar MODIFIERS = {\n  shift: 1,\n  alt: 2,\n  ctrl: 4,\n  super: 8\n};\nvar LOCK_MASK = 64 + 128;\nvar CODEPOINTS = {\n  escape: 27,\n  tab: 9,\n  enter: 13,\n  space: 32,\n  backspace: 127,\n  kpEnter: 57414\n  // Numpad Enter (Kitty protocol)\n};\nvar ARROW_CODEPOINTS = {\n  up: -1,\n  down: -2,\n  right: -3,\n  left: -4\n};\nvar FUNCTIONAL_CODEPOINTS = {\n  delete: -10,\n  insert: -11,\n  pageUp: -12,\n  pageDown: -13,\n  home: -14,\n  end: -15\n};\nvar KITTY_FUNCTIONAL_KEY_EQUIVALENTS = /* @__PURE__ */ new Map([\n  [57399, 48],\n  // KP_0 -> 0\n  [57400, 49],\n  // KP_1 -> 1\n  [57401, 50],\n  // KP_2 -> 2\n  [57402, 51],\n  // KP_3 -> 3\n  [57403, 52],\n  // KP_4 -> 4\n  [57404, 53],\n  // KP_5 -> 5\n  [57405, 54],\n  // KP_6 -> 6\n  [57406, 55],\n  // KP_7 -> 7\n  [57407, 56],\n  // KP_8 -> 8\n  [57408, 57],\n  // KP_9 -> 9\n  [57409, 46],\n  // KP_DECIMAL -> .\n  [57410, 47],\n  // KP_DIVIDE -> /\n  [57411, 42],\n  // KP_MULTIPLY -> *\n  [57412, 45],\n  // KP_SUBTRACT -> -\n  [57413, 43],\n  // KP_ADD -> +\n  [57415, 61],\n  // KP_EQUAL -> =\n  [57416, 44],\n  // KP_SEPARATOR -> ,\n  [57417, ARROW_CODEPOINTS.left],\n  [57418, ARROW_CODEPOINTS.right],\n  [57419, ARROW_CODEPOINTS.up],\n  [57420, ARROW_CODEPOINTS.down],\n  [57421, FUNCTIONAL_CODEPOINTS.pageUp],\n  [57422, FUNCTIONAL_CODEPOINTS.pageDown],\n  [57423, FUNCTIONAL_CODEPOINTS.home],\n  [57424, FUNCTIONAL_CODEPOINTS.end],\n  [57425, FUNCTIONAL_CODEPOINTS.insert],\n  [57426, FUNCTIONAL_CODEPOINTS.delete]\n]);\nfunction normalizeKittyFunctionalCodepoint(codepoint) {\n  return KITTY_FUNCTIONAL_KEY_EQUIVALENTS.get(codepoint) ?? codepoint;\n}\nfunction normalizeShiftedLetterIdentityCodepoint(codepoint, modifier) {\n  const effectiveModifier = modifier & ~LOCK_MASK;\n  if ((effectiveModifier & MODIFIERS.shift) !== 0 && codepoint >= 65 && codepoint <= 90) {\n    return codepoint + 32;\n  }\n  return codepoint;\n}\nvar LEGACY_KEY_SEQUENCES = {\n  up: [\"\\x1B[A\", \"\\x1BOA\"],\n  down: [\"\\x1B[B\", \"\\x1BOB\"],\n  right: [\"\\x1B[C\", \"\\x1BOC\"],\n  left: [\"\\x1B[D\", \"\\x1BOD\"],\n  home: [\"\\x1B[H\", \"\\x1BOH\", \"\\x1B[1~\", \"\\x1B[7~\"],\n  end: [\"\\x1B[F\", \"\\x1BOF\", \"\\x1B[4~\", \"\\x1B[8~\"],\n  insert: [\"\\x1B[2~\"],\n  delete: [\"\\x1B[3~\"],\n  pageUp: [\"\\x1B[5~\", \"\\x1B[[5~\"],\n  pageDown: [\"\\x1B[6~\", \"\\x1B[[6~\"],\n  clear: [\"\\x1B[E\", \"\\x1BOE\"],\n  f1: [\"\\x1BOP\", \"\\x1B[11~\", \"\\x1B[[A\"],\n  f2: [\"\\x1BOQ\", \"\\x1B[12~\", \"\\x1B[[B\"],\n  f3: [\"\\x1BOR\", \"\\x1B[13~\", \"\\x1B[[C\"],\n  f4: [\"\\x1BOS\", \"\\x1B[14~\", \"\\x1B[[D\"],\n  f5: [\"\\x1B[15~\", \"\\x1B[[E\"],\n  f6: [\"\\x1B[17~\"],\n  f7: [\"\\x1B[18~\"],\n  f8: [\"\\x1B[19~\"],\n  f9: [\"\\x1B[20~\"],\n  f10: [\"\\x1B[21~\"],\n  f11: [\"\\x1B[23~\"],\n  f12: [\"\\x1B[24~\"]\n};\nvar LEGACY_SHIFT_SEQUENCES = {\n  up: [\"\\x1B[a\"],\n  down: [\"\\x1B[b\"],\n  right: [\"\\x1B[c\"],\n  left: [\"\\x1B[d\"],\n  clear: [\"\\x1B[e\"],\n  insert: [\"\\x1B[2$\"],\n  delete: [\"\\x1B[3$\"],\n  pageUp: [\"\\x1B[5$\"],\n  pageDown: [\"\\x1B[6$\"],\n  home: [\"\\x1B[7$\"],\n  end: [\"\\x1B[8$\"]\n};\nvar LEGACY_CTRL_SEQUENCES = {\n  up: [\"\\x1BOa\"],\n  down: [\"\\x1BOb\"],\n  right: [\"\\x1BOc\"],\n  left: [\"\\x1BOd\"],\n  clear: [\"\\x1BOe\"],\n  insert: [\"\\x1B[2^\"],\n  delete: [\"\\x1B[3^\"],\n  pageUp: [\"\\x1B[5^\"],\n  pageDown: [\"\\x1B[6^\"],\n  home: [\"\\x1B[7^\"],\n  end: [\"\\x1B[8^\"]\n};\nvar LEGACY_SEQUENCE_KEY_IDS = {\n  \"\\x1BOA\": \"up\",\n  \"\\x1BOB\": \"down\",\n  \"\\x1BOC\": \"right\",\n  \"\\x1BOD\": \"left\",\n  \"\\x1BOH\": \"home\",\n  \"\\x1BOF\": \"end\",\n  \"\\x1B[E\": \"clear\",\n  \"\\x1BOE\": \"clear\",\n  \"\\x1BOe\": \"ctrl+clear\",\n  \"\\x1B[e\": \"shift+clear\",\n  \"\\x1B[2~\": \"insert\",\n  \"\\x1B[2$\": \"shift+insert\",\n  \"\\x1B[2^\": \"ctrl+insert\",\n  \"\\x1B[3$\": \"shift+delete\",\n  \"\\x1B[3^\": \"ctrl+delete\",\n  \"\\x1B[[5~\": \"pageUp\",\n  \"\\x1B[[6~\": \"pageDown\",\n  \"\\x1B[a\": \"shift+up\",\n  \"\\x1B[b\": \"shift+down\",\n  \"\\x1B[c\": \"shift+right\",\n  \"\\x1B[d\": \"shift+left\",\n  \"\\x1BOa\": \"ctrl+up\",\n  \"\\x1BOb\": \"ctrl+down\",\n  \"\\x1BOc\": \"ctrl+right\",\n  \"\\x1BOd\": \"ctrl+left\",\n  \"\\x1B[5$\": \"shift+pageUp\",\n  \"\\x1B[6$\": \"shift+pageDown\",\n  \"\\x1B[7$\": \"shift+home\",\n  \"\\x1B[8$\": \"shift+end\",\n  \"\\x1B[5^\": \"ctrl+pageUp\",\n  \"\\x1B[6^\": \"ctrl+pageDown\",\n  \"\\x1B[7^\": \"ctrl+home\",\n  \"\\x1B[8^\": \"ctrl+end\",\n  \"\\x1BOP\": \"f1\",\n  \"\\x1BOQ\": \"f2\",\n  \"\\x1BOR\": \"f3\",\n  \"\\x1BOS\": \"f4\",\n  \"\\x1B[11~\": \"f1\",\n  \"\\x1B[12~\": \"f2\",\n  \"\\x1B[13~\": \"f3\",\n  \"\\x1B[14~\": \"f4\",\n  \"\\x1B[[A\": \"f1\",\n  \"\\x1B[[B\": \"f2\",\n  \"\\x1B[[C\": \"f3\",\n  \"\\x1B[[D\": \"f4\",\n  \"\\x1B[[E\": \"f5\",\n  \"\\x1B[15~\": \"f5\",\n  \"\\x1B[17~\": \"f6\",\n  \"\\x1B[18~\": \"f7\",\n  \"\\x1B[19~\": \"f8\",\n  \"\\x1B[20~\": \"f9\",\n  \"\\x1B[21~\": \"f10\",\n  \"\\x1B[23~\": \"f11\",\n  \"\\x1B[24~\": \"f12\",\n  \"\\x1Bb\": \"alt+left\",\n  \"\\x1Bf\": \"alt+right\",\n  \"\\x1Bp\": \"alt+up\",\n  \"\\x1Bn\": \"alt+down\"\n};\nvar matchesLegacySequence = (data, sequences) => sequences.includes(data);\nvar matchesLegacyModifierSequence = (data, key, modifier) => {\n  if (modifier === MODIFIERS.shift) {\n    return matchesLegacySequence(data, LEGACY_SHIFT_SEQUENCES[key]);\n  }\n  if (modifier === MODIFIERS.ctrl) {\n    return matchesLegacySequence(data, LEGACY_CTRL_SEQUENCES[key]);\n  }\n  return false;\n};\nvar _lastEventType = \"press\";\nfunction isKeyRelease(data) {\n  if (data.includes(\"\\x1B[200~\")) {\n    return false;\n  }\n  if (data.includes(\":3u\") || data.includes(\":3~\") || data.includes(\":3A\") || data.includes(\":3B\") || data.includes(\":3C\") || data.includes(\":3D\") || data.includes(\":3H\") || data.includes(\":3F\")) {\n    return true;\n  }\n  return false;\n}\nfunction isKeyRepeat(data) {\n  if (data.includes(\"\\x1B[200~\")) {\n    return false;\n  }\n  if (data.includes(\":2u\") || data.includes(\":2~\") || data.includes(\":2A\") || data.includes(\":2B\") || data.includes(\":2C\") || data.includes(\":2D\") || data.includes(\":2H\") || data.includes(\":2F\")) {\n    return true;\n  }\n  return false;\n}\nfunction parseEventType(eventTypeStr) {\n  if (!eventTypeStr)\n    return \"press\";\n  const eventType = parseInt(eventTypeStr, 10);\n  if (eventType === 2)\n    return \"repeat\";\n  if (eventType === 3)\n    return \"release\";\n  return \"press\";\n}\nfunction parseKittySequence(data) {\n  const csiUMatch = data.match(/^\\x1b\\[(\\d+)(?::(\\d*))?(?::(\\d+))?(?:;(\\d+))?(?::(\\d+))?u$/);\n  if (csiUMatch) {\n    const codepoint = parseInt(csiUMatch[1], 10);\n    const shiftedKey = csiUMatch[2] && csiUMatch[2].length > 0 ? parseInt(csiUMatch[2], 10) : void 0;\n    const baseLayoutKey = csiUMatch[3] ? parseInt(csiUMatch[3], 10) : void 0;\n    const modValue = csiUMatch[4] ? parseInt(csiUMatch[4], 10) : 1;\n    const eventType = parseEventType(csiUMatch[5]);\n    _lastEventType = eventType;\n    return { codepoint, shiftedKey, baseLayoutKey, modifier: modValue - 1, eventType };\n  }\n  const arrowMatch = data.match(/^\\x1b\\[1;(\\d+)(?::(\\d+))?([ABCD])$/);\n  if (arrowMatch) {\n    const modValue = parseInt(arrowMatch[1], 10);\n    const eventType = parseEventType(arrowMatch[2]);\n    const arrowCodes = { A: -1, B: -2, C: -3, D: -4 };\n    _lastEventType = eventType;\n    return { codepoint: arrowCodes[arrowMatch[3]], modifier: modValue - 1, eventType };\n  }\n  const funcMatch = data.match(/^\\x1b\\[(\\d+)(?:;(\\d+))?(?::(\\d+))?~$/);\n  if (funcMatch) {\n    const keyNum = parseInt(funcMatch[1], 10);\n    const modValue = funcMatch[2] ? parseInt(funcMatch[2], 10) : 1;\n    const eventType = parseEventType(funcMatch[3]);\n    const funcCodes = {\n      2: FUNCTIONAL_CODEPOINTS.insert,\n      3: FUNCTIONAL_CODEPOINTS.delete,\n      5: FUNCTIONAL_CODEPOINTS.pageUp,\n      6: FUNCTIONAL_CODEPOINTS.pageDown,\n      7: FUNCTIONAL_CODEPOINTS.home,\n      8: FUNCTIONAL_CODEPOINTS.end\n    };\n    const codepoint = funcCodes[keyNum];\n    if (codepoint !== void 0) {\n      _lastEventType = eventType;\n      return { codepoint, modifier: modValue - 1, eventType };\n    }\n  }\n  const homeEndMatch = data.match(/^\\x1b\\[1;(\\d+)(?::(\\d+))?([HF])$/);\n  if (homeEndMatch) {\n    const modValue = parseInt(homeEndMatch[1], 10);\n    const eventType = parseEventType(homeEndMatch[2]);\n    const codepoint = homeEndMatch[3] === \"H\" ? FUNCTIONAL_CODEPOINTS.home : FUNCTIONAL_CODEPOINTS.end;\n    _lastEventType = eventType;\n    return { codepoint, modifier: modValue - 1, eventType };\n  }\n  return null;\n}\nfunction matchesKittySequence(data, expectedCodepoint, expectedModifier) {\n  const parsed = parseKittySequence(data);\n  if (!parsed)\n    return false;\n  const actualMod = parsed.modifier & ~LOCK_MASK;\n  const expectedMod = expectedModifier & ~LOCK_MASK;\n  if (actualMod !== expectedMod)\n    return false;\n  const normalizedCodepoint = normalizeShiftedLetterIdentityCodepoint(normalizeKittyFunctionalCodepoint(parsed.codepoint), parsed.modifier);\n  const normalizedExpectedCodepoint = normalizeShiftedLetterIdentityCodepoint(normalizeKittyFunctionalCodepoint(expectedCodepoint), expectedModifier);\n  if (normalizedCodepoint === normalizedExpectedCodepoint)\n    return true;\n  if (parsed.baseLayoutKey !== void 0 && parsed.baseLayoutKey === expectedCodepoint) {\n    const cp = normalizedCodepoint;\n    const isLatinLetter = cp >= 97 && cp <= 122;\n    const isKnownSymbol = SYMBOL_KEYS.has(String.fromCharCode(cp));\n    if (!isLatinLetter && !isKnownSymbol)\n      return true;\n  }\n  return false;\n}\nfunction parseModifyOtherKeysSequence(data) {\n  const match = data.match(/^\\x1b\\[27;(\\d+);(\\d+)~$/);\n  if (!match)\n    return null;\n  const modValue = parseInt(match[1], 10);\n  const codepoint = parseInt(match[2], 10);\n  return { codepoint, modifier: modValue - 1 };\n}\nfunction matchesModifyOtherKeys(data, expectedKeycode, expectedModifier) {\n  const parsed = parseModifyOtherKeysSequence(data);\n  if (!parsed)\n    return false;\n  return parsed.codepoint === expectedKeycode && parsed.modifier === expectedModifier;\n}\nfunction isWindowsTerminalSession() {\n  return Boolean(process.env.WT_SESSION) && !process.env.SSH_CONNECTION && !process.env.SSH_CLIENT && !process.env.SSH_TTY;\n}\nfunction matchesRawBackspace(data, expectedModifier) {\n  if (data === \"\\x7F\")\n    return expectedModifier === 0;\n  if (data !== \"\\b\")\n    return false;\n  return isWindowsTerminalSession() ? expectedModifier === MODIFIERS.ctrl : expectedModifier === 0;\n}\nfunction rawCtrlChar(key) {\n  const char = key.toLowerCase();\n  const code = char.charCodeAt(0);\n  if (code >= 97 && code <= 122 || char === \"[\" || char === \"\\\\\" || char === \"]\" || char === \"_\") {\n    return String.fromCharCode(code & 31);\n  }\n  if (char === \"-\") {\n    return String.fromCharCode(31);\n  }\n  return null;\n}\nfunction isDigitKey(key) {\n  return key >= \"0\" && key <= \"9\";\n}\nfunction matchesPrintableModifyOtherKeys(data, expectedKeycode, expectedModifier) {\n  if (expectedModifier === 0)\n    return false;\n  const parsed = parseModifyOtherKeysSequence(data);\n  if (!parsed || parsed.modifier !== expectedModifier)\n    return false;\n  return normalizeShiftedLetterIdentityCodepoint(parsed.codepoint, parsed.modifier) === normalizeShiftedLetterIdentityCodepoint(expectedKeycode, expectedModifier);\n}\nfunction formatKeyNameWithModifiers(keyName, modifier) {\n  const mods = [];\n  const effectiveMod = modifier & ~LOCK_MASK;\n  const supportedModifierMask = MODIFIERS.shift | MODIFIERS.ctrl | MODIFIERS.alt | MODIFIERS.super;\n  if ((effectiveMod & ~supportedModifierMask) !== 0)\n    return void 0;\n  if (effectiveMod & MODIFIERS.shift)\n    mods.push(\"shift\");\n  if (effectiveMod & MODIFIERS.ctrl)\n    mods.push(\"ctrl\");\n  if (effectiveMod & MODIFIERS.alt)\n    mods.push(\"alt\");\n  if (effectiveMod & MODIFIERS.super)\n    mods.push(\"super\");\n  return mods.length > 0 ? `${mods.join(\"+\")}+${keyName}` : keyName;\n}\nfunction parseKeyId(keyId) {\n  const parts = keyId.toLowerCase().split(\"+\");\n  const key = parts[parts.length - 1];\n  if (!key)\n    return null;\n  return {\n    key,\n    ctrl: parts.includes(\"ctrl\"),\n    shift: parts.includes(\"shift\"),\n    alt: parts.includes(\"alt\"),\n    super: parts.includes(\"super\")\n  };\n}\nfunction matchesKey(data, keyId) {\n  const parsed = parseKeyId(keyId);\n  if (!parsed)\n    return false;\n  const { key, ctrl, shift, alt, super: superModifier } = parsed;\n  let modifier = 0;\n  if (shift)\n    modifier |= MODIFIERS.shift;\n  if (alt)\n    modifier |= MODIFIERS.alt;\n  if (ctrl)\n    modifier |= MODIFIERS.ctrl;\n  if (superModifier)\n    modifier |= MODIFIERS.super;\n  switch (key) {\n    case \"escape\":\n    case \"esc\":\n      if (modifier !== 0)\n        return false;\n      return data === \"\\x1B\" || matchesKittySequence(data, CODEPOINTS.escape, 0) || matchesModifyOtherKeys(data, CODEPOINTS.escape, 0);\n    case \"space\":\n      if (!_kittyProtocolActive) {\n        if (modifier === MODIFIERS.ctrl && data === \"\\0\") {\n          return true;\n        }\n        if (modifier === MODIFIERS.alt && data === \"\\x1B \") {\n          return true;\n        }\n      }\n      if (modifier === 0) {\n        return data === \" \" || matchesKittySequence(data, CODEPOINTS.space, 0) || matchesModifyOtherKeys(data, CODEPOINTS.space, 0);\n      }\n      return matchesKittySequence(data, CODEPOINTS.space, modifier) || matchesModifyOtherKeys(data, CODEPOINTS.space, modifier);\n    case \"tab\":\n      if (modifier === MODIFIERS.shift) {\n        return data === \"\\x1B[Z\" || matchesKittySequence(data, CODEPOINTS.tab, MODIFIERS.shift) || matchesModifyOtherKeys(data, CODEPOINTS.tab, MODIFIERS.shift);\n      }\n      if (modifier === 0) {\n        return data === \"\t\" || matchesKittySequence(data, CODEPOINTS.tab, 0);\n      }\n      return matchesKittySequence(data, CODEPOINTS.tab, modifier) || matchesModifyOtherKeys(data, CODEPOINTS.tab, modifier);\n    case \"enter\":\n    case \"return\":\n      if (modifier === MODIFIERS.shift) {\n        if (matchesKittySequence(data, CODEPOINTS.enter, MODIFIERS.shift) || matchesKittySequence(data, CODEPOINTS.kpEnter, MODIFIERS.shift)) {\n          return true;\n        }\n        if (matchesModifyOtherKeys(data, CODEPOINTS.enter, MODIFIERS.shift)) {\n          return true;\n        }\n        if (_kittyProtocolActive) {\n          return data === \"\\x1B\\r\" || data === \"\\n\";\n        }\n        return false;\n      }\n      if (modifier === MODIFIERS.alt) {\n        if (matchesKittySequence(data, CODEPOINTS.enter, MODIFIERS.alt) || matchesKittySequence(data, CODEPOINTS.kpEnter, MODIFIERS.alt)) {\n          return true;\n        }\n        if (matchesModifyOtherKeys(data, CODEPOINTS.enter, MODIFIERS.alt)) {\n          return true;\n        }\n        if (!_kittyProtocolActive) {\n          return data === \"\\x1B\\r\";\n        }\n        return false;\n      }\n      if (modifier === 0) {\n        return data === \"\\r\" || !_kittyProtocolActive && data === \"\\n\" || data === \"\\x1BOM\" || // SS3 M (numpad enter in some terminals)\n        matchesKittySequence(data, CODEPOINTS.enter, 0) || matchesKittySequence(data, CODEPOINTS.kpEnter, 0);\n      }\n      return matchesKittySequence(data, CODEPOINTS.enter, modifier) || matchesKittySequence(data, CODEPOINTS.kpEnter, modifier) || matchesModifyOtherKeys(data, CODEPOINTS.enter, modifier);\n    case \"backspace\":\n      if (modifier === MODIFIERS.alt) {\n        if (data === \"\\x1B\\x7F\" || data === \"\\x1B\\b\") {\n          return true;\n        }\n        return matchesKittySequence(data, CODEPOINTS.backspace, MODIFIERS.alt) || matchesModifyOtherKeys(data, CODEPOINTS.backspace, MODIFIERS.alt);\n      }\n      if (modifier === MODIFIERS.ctrl) {\n        if (matchesRawBackspace(data, MODIFIERS.ctrl))\n          return true;\n        return matchesKittySequence(data, CODEPOINTS.backspace, MODIFIERS.ctrl) || matchesModifyOtherKeys(data, CODEPOINTS.backspace, MODIFIERS.ctrl);\n      }\n      if (modifier === 0) {\n        return matchesRawBackspace(data, 0) || matchesKittySequence(data, CODEPOINTS.backspace, 0) || matchesModifyOtherKeys(data, CODEPOINTS.backspace, 0);\n      }\n      return matchesKittySequence(data, CODEPOINTS.backspace, modifier) || matchesModifyOtherKeys(data, CODEPOINTS.backspace, modifier);\n    case \"insert\":\n      if (modifier === 0) {\n        return matchesLegacySequence(data, LEGACY_KEY_SEQUENCES.insert) || matchesKittySequence(data, FUNCTIONAL_CODEPOINTS.insert, 0);\n      }\n      if (matchesLegacyModifierSequence(data, \"insert\", modifier)) {\n        return true;\n      }\n      return matchesKittySequence(data, FUNCTIONAL_CODEPOINTS.insert, modifier);\n    case \"delete\":\n      if (modifier === 0) {\n        return matchesLegacySequence(data, LEGACY_KEY_SEQUENCES.delete) || matchesKittySequence(data, FUNCTIONAL_CODEPOINTS.delete, 0);\n      }\n      if (matchesLegacyModifierSequence(data, \"delete\", modifier)) {\n        return true;\n      }\n      return matchesKittySequence(data, FUNCTIONAL_CODEPOINTS.delete, modifier);\n    case \"clear\":\n      if (modifier === 0) {\n        return matchesLegacySequence(data, LEGACY_KEY_SEQUENCES.clear);\n      }\n      return matchesLegacyModifierSequence(data, \"clear\", modifier);\n    case \"home\":\n      if (modifier === 0) {\n        return matchesLegacySequence(data, LEGACY_KEY_SEQUENCES.home) || matchesKittySequence(data, FUNCTIONAL_CODEPOINTS.home, 0);\n      }\n      if (matchesLegacyModifierSequence(data, \"home\", modifier)) {\n        return true;\n      }\n      return matchesKittySequence(data, FUNCTIONAL_CODEPOINTS.home, modifier);\n    case \"end\":\n      if (modifier === 0) {\n        return matchesLegacySequence(data, LEGACY_KEY_SEQUENCES.end) || matchesKittySequence(data, FUNCTIONAL_CODEPOINTS.end, 0);\n      }\n      if (matchesLegacyModifierSequence(data, \"end\", modifier)) {\n        return true;\n      }\n      return matchesKittySequence(data, FUNCTIONAL_CODEPOINTS.end, modifier);\n    case \"pageup\":\n      if (modifier === 0) {\n        return matchesLegacySequence(data, LEGACY_KEY_SEQUENCES.pageUp) || matchesKittySequence(data, FUNCTIONAL_CODEPOINTS.pageUp, 0);\n      }\n      if (matchesLegacyModifierSequence(data, \"pageUp\", modifier)) {\n        return true;\n      }\n      return matchesKittySequence(data, FUNCTIONAL_CODEPOINTS.pageUp, modifier);\n    case \"pagedown\":\n      if (modifier === 0) {\n        return matchesLegacySequence(data, LEGACY_KEY_SEQUENCES.pageDown) || matchesKittySequence(data, FUNCTIONAL_CODEPOINTS.pageDown, 0);\n      }\n      if (matchesLegacyModifierSequence(data, \"pageDown\", modifier)) {\n        return true;\n      }\n      return matchesKittySequence(data, FUNCTIONAL_CODEPOINTS.pageDown, modifier);\n    case \"up\":\n      if (modifier === MODIFIERS.alt) {\n        return data === \"\\x1Bp\" || matchesKittySequence(data, ARROW_CODEPOINTS.up, MODIFIERS.alt);\n      }\n      if (modifier === 0) {\n        return matchesLegacySequence(data, LEGACY_KEY_SEQUENCES.up) || matchesKittySequence(data, ARROW_CODEPOINTS.up, 0);\n      }\n      if (matchesLegacyModifierSequence(data, \"up\", modifier)) {\n        return true;\n      }\n      return matchesKittySequence(data, ARROW_CODEPOINTS.up, modifier);\n    case \"down\":\n      if (modifier === MODIFIERS.alt) {\n        return data === \"\\x1Bn\" || matchesKittySequence(data, ARROW_CODEPOINTS.down, MODIFIERS.alt);\n      }\n      if (modifier === 0) {\n        return matchesLegacySequence(data, LEGACY_KEY_SEQUENCES.down) || matchesKittySequence(data, ARROW_CODEPOINTS.down, 0);\n      }\n      if (matchesLegacyModifierSequence(data, \"down\", modifier)) {\n        return true;\n      }\n      return matchesKittySequence(data, ARROW_CODEPOINTS.down, modifier);\n    case \"left\":\n      if (modifier === MODIFIERS.alt) {\n        return data === \"\\x1B[1;3D\" || !_kittyProtocolActive && data === \"\\x1BB\" || data === \"\\x1Bb\" || matchesKittySequence(data, ARROW_CODEPOINTS.left, MODIFIERS.alt);\n      }\n      if (modifier === MODIFIERS.ctrl) {\n        return data === \"\\x1B[1;5D\" || matchesLegacyModifierSequence(data, \"left\", MODIFIERS.ctrl) || matchesKittySequence(data, ARROW_CODEPOINTS.left, MODIFIERS.ctrl);\n      }\n      if (modifier === 0) {\n        return matchesLegacySequence(data, LEGACY_KEY_SEQUENCES.left) || matchesKittySequence(data, ARROW_CODEPOINTS.left, 0);\n      }\n      if (matchesLegacyModifierSequence(data, \"left\", modifier)) {\n        return true;\n      }\n      return matchesKittySequence(data, ARROW_CODEPOINTS.left, modifier);\n    case \"right\":\n      if (modifier === MODIFIERS.alt) {\n        return data === \"\\x1B[1;3C\" || !_kittyProtocolActive && data === \"\\x1BF\" || data === \"\\x1Bf\" || matchesKittySequence(data, ARROW_CODEPOINTS.right, MODIFIERS.alt);\n      }\n      if (modifier === MODIFIERS.ctrl) {\n        return data === \"\\x1B[1;5C\" || matchesLegacyModifierSequence(data, \"right\", MODIFIERS.ctrl) || matchesKittySequence(data, ARROW_CODEPOINTS.right, MODIFIERS.ctrl);\n      }\n      if (modifier === 0) {\n        return matchesLegacySequence(data, LEGACY_KEY_SEQUENCES.right) || matchesKittySequence(data, ARROW_CODEPOINTS.right, 0);\n      }\n      if (matchesLegacyModifierSequence(data, \"right\", modifier)) {\n        return true;\n      }\n      return matchesKittySequence(data, ARROW_CODEPOINTS.right, modifier);\n    case \"f1\":\n    case \"f2\":\n    case \"f3\":\n    case \"f4\":\n    case \"f5\":\n    case \"f6\":\n    case \"f7\":\n    case \"f8\":\n    case \"f9\":\n    case \"f10\":\n    case \"f11\":\n    case \"f12\": {\n      if (modifier !== 0) {\n        return false;\n      }\n      const functionKey = key;\n      return matchesLegacySequence(data, LEGACY_KEY_SEQUENCES[functionKey]);\n    }\n  }\n  if (key.length === 1 && (key >= \"a\" && key <= \"z\" || isDigitKey(key) || SYMBOL_KEYS.has(key))) {\n    const codepoint = key.charCodeAt(0);\n    const rawCtrl = rawCtrlChar(key);\n    const isLetter = key >= \"a\" && key <= \"z\";\n    const isDigit = isDigitKey(key);\n    if (modifier === MODIFIERS.ctrl + MODIFIERS.alt && !_kittyProtocolActive && rawCtrl) {\n      if (data === `\\x1B${rawCtrl}`)\n        return true;\n    }\n    if (modifier === MODIFIERS.alt && !_kittyProtocolActive && (isLetter || isDigit || SYMBOL_KEYS.has(key))) {\n      if (data === `\\x1B${key}`)\n        return true;\n    }\n    if (modifier === MODIFIERS.ctrl) {\n      if (rawCtrl && data === rawCtrl)\n        return true;\n      return matchesKittySequence(data, codepoint, MODIFIERS.ctrl) || matchesPrintableModifyOtherKeys(data, codepoint, MODIFIERS.ctrl);\n    }\n    if (modifier === MODIFIERS.shift + MODIFIERS.ctrl) {\n      return matchesKittySequence(data, codepoint, MODIFIERS.shift + MODIFIERS.ctrl) || matchesPrintableModifyOtherKeys(data, codepoint, MODIFIERS.shift + MODIFIERS.ctrl);\n    }\n    if (modifier === MODIFIERS.shift) {\n      if (isLetter && data === key.toUpperCase())\n        return true;\n      return matchesKittySequence(data, codepoint, MODIFIERS.shift) || matchesPrintableModifyOtherKeys(data, codepoint, MODIFIERS.shift);\n    }\n    if (modifier !== 0) {\n      return matchesKittySequence(data, codepoint, modifier) || matchesPrintableModifyOtherKeys(data, codepoint, modifier);\n    }\n    return data === key || matchesKittySequence(data, codepoint, 0);\n  }\n  return false;\n}\nfunction formatParsedKey(codepoint, modifier, baseLayoutKey) {\n  const normalizedCodepoint = normalizeKittyFunctionalCodepoint(codepoint);\n  const identityCodepoint = normalizeShiftedLetterIdentityCodepoint(normalizedCodepoint, modifier);\n  const isLatinLetter = identityCodepoint >= 97 && identityCodepoint <= 122;\n  const isDigit = identityCodepoint >= 48 && identityCodepoint <= 57;\n  const isKnownSymbol = SYMBOL_KEYS.has(String.fromCharCode(identityCodepoint));\n  const effectiveCodepoint = isLatinLetter || isDigit || isKnownSymbol ? identityCodepoint : baseLayoutKey ?? identityCodepoint;\n  let keyName;\n  if (effectiveCodepoint === CODEPOINTS.escape)\n    keyName = \"escape\";\n  else if (effectiveCodepoint === CODEPOINTS.tab)\n    keyName = \"tab\";\n  else if (effectiveCodepoint === CODEPOINTS.enter || effectiveCodepoint === CODEPOINTS.kpEnter)\n    keyName = \"enter\";\n  else if (effectiveCodepoint === CODEPOINTS.space)\n    keyName = \"space\";\n  else if (effectiveCodepoint === CODEPOINTS.backspace)\n    keyName = \"backspace\";\n  else if (effectiveCodepoint === FUNCTIONAL_CODEPOINTS.delete)\n    keyName = \"delete\";\n  else if (effectiveCodepoint === FUNCTIONAL_CODEPOINTS.insert)\n    keyName = \"insert\";\n  else if (effectiveCodepoint === FUNCTIONAL_CODEPOINTS.home)\n    keyName = \"home\";\n  else if (effectiveCodepoint === FUNCTIONAL_CODEPOINTS.end)\n    keyName = \"end\";\n  else if (effectiveCodepoint === FUNCTIONAL_CODEPOINTS.pageUp)\n    keyName = \"pageUp\";\n  else if (effectiveCodepoint === FUNCTIONAL_CODEPOINTS.pageDown)\n    keyName = \"pageDown\";\n  else if (effectiveCodepoint === ARROW_CODEPOINTS.up)\n    keyName = \"up\";\n  else if (effectiveCodepoint === ARROW_CODEPOINTS.down)\n    keyName = \"down\";\n  else if (effectiveCodepoint === ARROW_CODEPOINTS.left)\n    keyName = \"left\";\n  else if (effectiveCodepoint === ARROW_CODEPOINTS.right)\n    keyName = \"right\";\n  else if (effectiveCodepoint >= 48 && effectiveCodepoint <= 57)\n    keyName = String.fromCharCode(effectiveCodepoint);\n  else if (effectiveCodepoint >= 97 && effectiveCodepoint <= 122)\n    keyName = String.fromCharCode(effectiveCodepoint);\n  else if (SYMBOL_KEYS.has(String.fromCharCode(effectiveCodepoint)))\n    keyName = String.fromCharCode(effectiveCodepoint);\n  if (!keyName)\n    return void 0;\n  return formatKeyNameWithModifiers(keyName, modifier);\n}\nfunction parseKey(data) {\n  const kitty = parseKittySequence(data);\n  if (kitty) {\n    return formatParsedKey(kitty.codepoint, kitty.modifier, kitty.baseLayoutKey);\n  }\n  const modifyOtherKeys = parseModifyOtherKeysSequence(data);\n  if (modifyOtherKeys) {\n    return formatParsedKey(modifyOtherKeys.codepoint, modifyOtherKeys.modifier);\n  }\n  if (_kittyProtocolActive) {\n    if (data === \"\\x1B\\r\" || data === \"\\n\")\n      return \"shift+enter\";\n  }\n  const legacySequenceKeyId = LEGACY_SEQUENCE_KEY_IDS[data];\n  if (legacySequenceKeyId)\n    return legacySequenceKeyId;\n  if (data === \"\\x1B\")\n    return \"escape\";\n  if (data === \"\u001c\")\n    return \"ctrl+\\\\\";\n  if (data === \"\u001d\")\n    return \"ctrl+]\";\n  if (data === \"\u001f\")\n    return \"ctrl+-\";\n  if (data === \"\\x1B\\x1B\")\n    return \"ctrl+alt+[\";\n  if (data === \"\\x1B\u001c\")\n    return \"ctrl+alt+\\\\\";\n  if (data === \"\\x1B\u001d\")\n    return \"ctrl+alt+]\";\n  if (data === \"\\x1B\u001f\")\n    return \"ctrl+alt+-\";\n  if (data === \"\t\")\n    return \"tab\";\n  if (data === \"\\r\" || !_kittyProtocolActive && data === \"\\n\" || data === \"\\x1BOM\")\n    return \"enter\";\n  if (data === \"\\0\")\n    return \"ctrl+space\";\n  if (data === \" \")\n    return \"space\";\n  if (data === \"\\x7F\")\n    return \"backspace\";\n  if (data === \"\\b\")\n    return isWindowsTerminalSession() ? \"ctrl+backspace\" : \"backspace\";\n  if (data === \"\\x1B[Z\")\n    return \"shift+tab\";\n  if (!_kittyProtocolActive && data === \"\\x1B\\r\")\n    return \"alt+enter\";\n  if (!_kittyProtocolActive && data === \"\\x1B \")\n    return \"alt+space\";\n  if (data === \"\\x1B\\x7F\" || data === \"\\x1B\\b\")\n    return \"alt+backspace\";\n  if (!_kittyProtocolActive && data === \"\\x1BB\")\n    return \"alt+left\";\n  if (!_kittyProtocolActive && data === \"\\x1BF\")\n    return \"alt+right\";\n  if (!_kittyProtocolActive && data.length === 2 && data[0] === \"\\x1B\") {\n    const code = data.charCodeAt(1);\n    if (code >= 1 && code <= 26) {\n      return `ctrl+alt+${String.fromCharCode(code + 96)}`;\n    }\n    const key = String.fromCharCode(code);\n    if (code >= 97 && code <= 122 || code >= 48 && code <= 57 || SYMBOL_KEYS.has(key)) {\n      return `alt+${key}`;\n    }\n  }\n  if (data === \"\\x1B[A\")\n    return \"up\";\n  if (data === \"\\x1B[B\")\n    return \"down\";\n  if (data === \"\\x1B[C\")\n    return \"right\";\n  if (data === \"\\x1B[D\")\n    return \"left\";\n  if (data === \"\\x1B[H\" || data === \"\\x1BOH\")\n    return \"home\";\n  if (data === \"\\x1B[F\" || data === \"\\x1BOF\")\n    return \"end\";\n  if (data === \"\\x1B[3~\")\n    return \"delete\";\n  if (data === \"\\x1B[5~\")\n    return \"pageUp\";\n  if (data === \"\\x1B[6~\")\n    return \"pageDown\";\n  if (data.length === 1) {\n    const code = data.charCodeAt(0);\n    if (code >= 1 && code <= 26) {\n      return `ctrl+${String.fromCharCode(code + 96)}`;\n    }\n    if (code >= 32 && code <= 126) {\n      return data;\n    }\n  }\n  return void 0;\n}\nvar KITTY_CSI_U_REGEX = /^\\x1b\\[(\\d+)(?::(\\d*))?(?::(\\d+))?(?:;(\\d+))?(?::(\\d+))?u$/;\nvar KITTY_PRINTABLE_ALLOWED_MODIFIERS = MODIFIERS.shift | LOCK_MASK;\nfunction decodeKittyPrintable(data) {\n  const match = data.match(KITTY_CSI_U_REGEX);\n  if (!match)\n    return void 0;\n  const codepoint = Number.parseInt(match[1] ?? \"\", 10);\n  if (!Number.isFinite(codepoint))\n    return void 0;\n  const shiftedKey = match[2] && match[2].length > 0 ? Number.parseInt(match[2], 10) : void 0;\n  const modValue = match[4] ? Number.parseInt(match[4], 10) : 1;\n  const modifier = Number.isFinite(modValue) ? modValue - 1 : 0;\n  if ((modifier & ~KITTY_PRINTABLE_ALLOWED_MODIFIERS) !== 0)\n    return void 0;\n  if (modifier & (MODIFIERS.alt | MODIFIERS.ctrl))\n    return void 0;\n  let effectiveCodepoint = codepoint;\n  if (modifier & MODIFIERS.shift && typeof shiftedKey === \"number\") {\n    effectiveCodepoint = shiftedKey;\n  }\n  effectiveCodepoint = normalizeKittyFunctionalCodepoint(effectiveCodepoint);\n  if (!Number.isFinite(effectiveCodepoint) || effectiveCodepoint < 32)\n    return void 0;\n  try {\n    return String.fromCodePoint(effectiveCodepoint);\n  } catch {\n    return void 0;\n  }\n}\nfunction decodeModifyOtherKeysPrintable(data) {\n  const parsed = parseModifyOtherKeysSequence(data);\n  if (!parsed)\n    return void 0;\n  const modifier = parsed.modifier & ~LOCK_MASK;\n  if ((modifier & ~MODIFIERS.shift) !== 0)\n    return void 0;\n  if (!Number.isFinite(parsed.codepoint) || parsed.codepoint < 32)\n    return void 0;\n  try {\n    return String.fromCodePoint(parsed.codepoint);\n  } catch {\n    return void 0;\n  }\n}\nfunction decodePrintableKey(data) {\n  return decodeKittyPrintable(data) ?? decodeModifyOtherKeysPrintable(data);\n}\n\n// node_modules/.pnpm/@earendil-works+pi-tui@0.84.2/node_modules/@earendil-works/pi-tui/dist/keybindings.js\nvar TUI_KEYBINDINGS = {\n  \"tui.editor.cursorUp\": { defaultKeys: \"up\", description: \"Move cursor up\" },\n  \"tui.editor.cursorDown\": { defaultKeys: \"down\", description: \"Move cursor down\" },\n  \"tui.editor.historyPrevious\": {\n    defaultKeys: [],\n    description: \"Select previous prompt history entry\"\n  },\n  \"tui.editor.historyNext\": {\n    defaultKeys: [],\n    description: \"Select next prompt history entry\"\n  },\n  \"tui.editor.cursorLeft\": {\n    defaultKeys: [\"left\", \"ctrl+b\"],\n    description: \"Move cursor left\"\n  },\n  \"tui.editor.cursorRight\": {\n    defaultKeys: [\"right\", \"ctrl+f\"],\n    description: \"Move cursor right\"\n  },\n  \"tui.editor.cursorWordLeft\": {\n    defaultKeys: [\"alt+left\", \"ctrl+left\", \"alt+b\"],\n    description: \"Move cursor word left\"\n  },\n  \"tui.editor.cursorWordRight\": {\n    defaultKeys: [\"alt+right\", \"ctrl+right\", \"alt+f\"],\n    description: \"Move cursor word right\"\n  },\n  \"tui.editor.cursorLineStart\": {\n    defaultKeys: [\"home\", \"ctrl+home\", \"ctrl+a\"],\n    description: \"Move to line start\"\n  },\n  \"tui.editor.cursorLineEnd\": {\n    defaultKeys: [\"end\", \"ctrl+end\", \"ctrl+e\"],\n    description: \"Move to line end\"\n  },\n  \"tui.editor.jumpForward\": {\n    defaultKeys: \"ctrl+]\",\n    description: \"Jump forward to character\"\n  },\n  \"tui.editor.jumpBackward\": {\n    defaultKeys: \"ctrl+alt+]\",\n    description: \"Jump backward to character\"\n  },\n  \"tui.editor.pageUp\": { defaultKeys: [\"pageUp\", \"ctrl+pageUp\"], description: \"Page up\" },\n  \"tui.editor.pageDown\": { defaultKeys: [\"pageDown\", \"ctrl+pageDown\"], description: \"Page down\" },\n  \"tui.editor.deleteCharBackward\": {\n    defaultKeys: \"backspace\",\n    description: \"Delete character backward\"\n  },\n  \"tui.editor.deleteCharForward\": {\n    defaultKeys: [\"delete\", \"ctrl+d\"],\n    description: \"Delete character forward\"\n  },\n  \"tui.editor.deleteWordBackward\": {\n    defaultKeys: [\"ctrl+w\", \"alt+backspace\"],\n    description: \"Delete word backward\"\n  },\n  \"tui.editor.deleteWordForward\": {\n    defaultKeys: [\"alt+d\", \"alt+delete\"],\n    description: \"Delete word forward\"\n  },\n  \"tui.editor.deleteToLineStart\": {\n    defaultKeys: \"ctrl+u\",\n    description: \"Delete to line start\"\n  },\n  \"tui.editor.deleteToLineEnd\": {\n    defaultKeys: \"ctrl+k\",\n    description: \"Delete to line end\"\n  },\n  \"tui.editor.yank\": { defaultKeys: \"ctrl+y\", description: \"Yank\" },\n  \"tui.editor.yankPop\": { defaultKeys: \"alt+y\", description: \"Yank pop\" },\n  \"tui.editor.undo\": { defaultKeys: \"ctrl+-\", description: \"Undo\" },\n  \"tui.input.newLine\": { defaultKeys: [\"shift+enter\", \"ctrl+j\"], description: \"Insert newline\" },\n  \"tui.input.submit\": { defaultKeys: \"enter\", description: \"Submit input\" },\n  \"tui.input.tab\": { defaultKeys: \"tab\", description: \"Tab / autocomplete\" },\n  \"tui.input.copy\": { defaultKeys: \"ctrl+c\", description: \"Copy selection\" },\n  \"tui.select.up\": { defaultKeys: \"up\", description: \"Move selection up\" },\n  \"tui.select.down\": { defaultKeys: \"down\", description: \"Move selection down\" },\n  \"tui.select.pageUp\": { defaultKeys: \"pageUp\", description: \"Selection page up\" },\n  \"tui.select.pageDown\": {\n    defaultKeys: \"pageDown\",\n    description: \"Selection page down\"\n  },\n  \"tui.select.confirm\": { defaultKeys: \"enter\", description: \"Confirm selection\" },\n  \"tui.select.cancel\": {\n    defaultKeys: [\"escape\", \"ctrl+c\"],\n    description: \"Cancel selection\"\n  },\n  // These intentionally shadow the unmodified editor bindings in fullscreen mode.\n  \"tui.altScreen.pageUp\": {\n    defaultKeys: \"pageUp\",\n    description: \"Scroll viewport up one page\"\n  },\n  \"tui.altScreen.pageDown\": {\n    defaultKeys: \"pageDown\",\n    description: \"Scroll viewport down one page\"\n  },\n  \"tui.altScreen.halfPageUp\": {\n    defaultKeys: [],\n    description: \"Scroll viewport up half a page\"\n  },\n  \"tui.altScreen.halfPageDown\": {\n    defaultKeys: [],\n    description: \"Scroll viewport down half a page\"\n  },\n  \"tui.altScreen.lineUp\": {\n    defaultKeys: [],\n    description: \"Scroll viewport up one line\"\n  },\n  \"tui.altScreen.lineDown\": {\n    defaultKeys: [],\n    description: \"Scroll viewport down one line\"\n  },\n  \"tui.altScreen.previousPrompt\": {\n    defaultKeys: \"ctrl+shift+up\",\n    description: \"Jump to previous semantic prompt\"\n  },\n  \"tui.altScreen.nextPrompt\": {\n    defaultKeys: \"ctrl+shift+down\",\n    description: \"Jump to next semantic prompt\"\n  },\n  \"tui.altScreen.search\": {\n    defaultKeys: \"ctrl+shift+f\",\n    description: \"Search the primary scroll view\"\n  },\n  \"tui.altScreen.searchNext\": {\n    defaultKeys: [\"enter\", \"ctrl+g\"],\n    description: \"Select the next search match\"\n  },\n  \"tui.altScreen.searchPrevious\": {\n    defaultKeys: [\"shift+enter\", \"ctrl+shift+g\"],\n    description: \"Select the previous search match\"\n  },\n  \"tui.altScreen.searchClose\": {\n    defaultKeys: \"escape\",\n    description: \"Close transcript search\"\n  },\n  \"tui.altScreen.top\": { defaultKeys: \"home\", description: \"Scroll viewport to top\" },\n  \"tui.altScreen.bottom\": { defaultKeys: \"end\", description: \"Scroll viewport to bottom\" }\n};\nfunction normalizeKeys(keys) {\n  if (keys === void 0)\n    return [];\n  const keyList = Array.isArray(keys) ? keys : [keys];\n  const seen = /* @__PURE__ */ new Set();\n  const result = [];\n  for (const key of keyList) {\n    if (!seen.has(key)) {\n      seen.add(key);\n      result.push(key);\n    }\n  }\n  return result;\n}\nvar KeybindingsManager = class {\n  definitions;\n  userBindings;\n  keysById = /* @__PURE__ */ new Map();\n  conflicts = [];\n  constructor(definitions, userBindings = {}) {\n    this.definitions = definitions;\n    this.userBindings = userBindings;\n    this.rebuild();\n  }\n  rebuild() {\n    this.keysById.clear();\n    this.conflicts = [];\n    const userClaims = /* @__PURE__ */ new Map();\n    for (const [keybinding, keys] of Object.entries(this.userBindings)) {\n      if (!(keybinding in this.definitions))\n        continue;\n      for (const key of normalizeKeys(keys)) {\n        const claimants = userClaims.get(key) ?? /* @__PURE__ */ new Set();\n        claimants.add(keybinding);\n        userClaims.set(key, claimants);\n      }\n    }\n    for (const [key, keybindings] of userClaims) {\n      if (keybindings.size > 1) {\n        this.conflicts.push({ key, keybindings: [...keybindings] });\n      }\n    }\n    for (const [id, definition] of Object.entries(this.definitions)) {\n      const userKeys = this.userBindings[id];\n      const keys = userKeys === void 0 ? normalizeKeys(definition.defaultKeys) : normalizeKeys(userKeys);\n      this.keysById.set(id, keys);\n    }\n  }\n  matches(data, keybinding) {\n    const keys = this.keysById.get(keybinding) ?? [];\n    for (const key of keys) {\n      if (matchesKey(data, key))\n        return true;\n    }\n    return false;\n  }\n  getKeys(keybinding) {\n    return [...this.keysById.get(keybinding) ?? []];\n  }\n  getDefinition(keybinding) {\n    return this.definitions[keybinding];\n  }\n  getConflicts() {\n    return this.conflicts.map((conflict) => ({ ...conflict, keybindings: [...conflict.keybindings] }));\n  }\n  setUserBindings(userBindings) {\n    this.userBindings = userBindings;\n    this.rebuild();\n  }\n  getUserBindings() {\n    return { ...this.userBindings };\n  }\n  getResolvedBindings() {\n    const resolved = {};\n    for (const id of Object.keys(this.definitions)) {\n      const keys = this.keysById.get(id) ?? [];\n      resolved[id] = keys.length === 1 ? keys[0] : [...keys];\n    }\n    return resolved;\n  }\n};\nvar globalKeybindings = null;\nfunction setKeybindings(keybindings) {\n  globalKeybindings = keybindings;\n}\nfunction getKeybindings() {\n  if (!globalKeybindings) {\n    globalKeybindings = new KeybindingsManager(TUI_KEYBINDINGS);\n  }\n  return globalKeybindings;\n}\n\n// node_modules/.pnpm/@earendil-works+pi-tui@0.84.2/node_modules/@earendil-works/pi-tui/dist/components/text.js\nvar Text = class {\n  text;\n  paddingX;\n  // Left/right padding\n  paddingY;\n  // Top/bottom padding\n  customBgFn;\n  // Cache for rendered output\n  cachedText;\n  cachedWidth;\n  cachedLines;\n  constructor(text = \"\", paddingX = 1, paddingY = 1, customBgFn) {\n    this.text = text;\n    this.paddingX = paddingX;\n    this.paddingY = paddingY;\n    this.customBgFn = customBgFn;\n  }\n  setText(text) {\n    this.text = text;\n    this.cachedText = void 0;\n    this.cachedWidth = void 0;\n    this.cachedLines = void 0;\n  }\n  setCustomBgFn(customBgFn) {\n    this.customBgFn = customBgFn;\n    this.cachedText = void 0;\n    this.cachedWidth = void 0;\n    this.cachedLines = void 0;\n  }\n  invalidate() {\n    this.cachedText = void 0;\n    this.cachedWidth = void 0;\n    this.cachedLines = void 0;\n  }\n  render(width) {\n    if (this.cachedLines && this.cachedText === this.text && this.cachedWidth === width) {\n      return this.cachedLines;\n    }\n    if (!this.text || this.text.trim() === \"\") {\n      const result2 = [];\n      this.cachedText = this.text;\n      this.cachedWidth = width;\n      this.cachedLines = result2;\n      return result2;\n    }\n    const normalizedText = this.text.replace(/\\t/g, \"   \");\n    const contentWidth = Math.max(1, width - this.paddingX * 2);\n    const wrappedLines = wrapTextWithAnsi(normalizedText, contentWidth);\n    const leftMargin = \" \".repeat(this.paddingX);\n    const rightMargin = \" \".repeat(this.paddingX);\n    const contentLines = [];\n    for (const line of wrappedLines) {\n      const lineWithMargins = leftMargin + line + rightMargin;\n      if (this.customBgFn) {\n        contentLines.push(applyBackgroundToLine(lineWithMargins, width, this.customBgFn));\n      } else {\n        const visibleLen = visibleWidth(lineWithMargins);\n        const paddingNeeded = Math.max(0, width - visibleLen);\n        contentLines.push(lineWithMargins + \" \".repeat(paddingNeeded));\n      }\n    }\n    const emptyLine = \" \".repeat(width);\n    const emptyLines = [];\n    for (let i = 0; i < this.paddingY; i++) {\n      const line = this.customBgFn ? applyBackgroundToLine(emptyLine, width, this.customBgFn) : emptyLine;\n      emptyLines.push(line);\n    }\n    const result = [...emptyLines, ...contentLines, ...emptyLines];\n    this.cachedText = this.text;\n    this.cachedWidth = width;\n    this.cachedLines = result;\n    return result.length > 0 ? result : [\"\"];\n  }\n};\n\n// node_modules/.pnpm/@earendil-works+pi-tui@0.84.2/node_modules/@earendil-works/pi-tui/dist/components/loader.js\nvar DEFAULT_FRAMES = [\"\\u280B\", \"\\u2819\", \"\\u2839\", \"\\u2838\", \"\\u283C\", \"\\u2834\", \"\\u2826\", \"\\u2827\", \"\\u2807\", \"\\u280F\"];\nvar DEFAULT_INTERVAL_MS = 80;\nvar Loader = class extends Text {\n  frames = [...DEFAULT_FRAMES];\n  intervalMs = DEFAULT_INTERVAL_MS;\n  currentFrame = 0;\n  intervalId = null;\n  ui = null;\n  renderIndicatorVerbatim = false;\n  spinnerColorFn;\n  messageColorFn;\n  message = \"Loading...\";\n  constructor(ui, spinnerColorFn, messageColorFn, message = \"Loading...\", indicator) {\n    super(\"\", 1, 0);\n    this.ui = ui;\n    this.spinnerColorFn = spinnerColorFn;\n    this.messageColorFn = messageColorFn;\n    this.message = message;\n    this.setIndicator(indicator);\n  }\n  render(width) {\n    return [\"\", ...super.render(width)];\n  }\n  start() {\n    this.updateDisplay();\n    this.restartAnimation();\n  }\n  stop() {\n    if (this.intervalId) {\n      clearInterval(this.intervalId);\n      this.intervalId = null;\n    }\n  }\n  setMessage(message) {\n    this.message = message;\n    this.updateDisplay();\n  }\n  setIndicator(indicator) {\n    this.renderIndicatorVerbatim = indicator !== void 0;\n    this.frames = indicator?.frames !== void 0 ? [...indicator.frames] : [...DEFAULT_FRAMES];\n    this.intervalMs = indicator?.intervalMs && indicator.intervalMs > 0 ? indicator.intervalMs : DEFAULT_INTERVAL_MS;\n    this.currentFrame = 0;\n    this.start();\n  }\n  restartAnimation() {\n    this.stop();\n    if (this.frames.length <= 1) {\n      return;\n    }\n    this.intervalId = setInterval(() => {\n      this.currentFrame = (this.currentFrame + 1) % this.frames.length;\n      this.updateDisplay();\n    }, this.intervalMs);\n  }\n  updateDisplay() {\n    const frame2 = this.frames[this.currentFrame] ?? \"\";\n    const renderedFrame = this.renderIndicatorVerbatim ? frame2 : this.spinnerColorFn(frame2);\n    const indicator = frame2.length > 0 ? `${renderedFrame} ` : \"\";\n    this.setText(`${indicator}${this.messageColorFn(this.message)}`);\n    if (this.ui) {\n      this.ui.requestRender();\n    }\n  }\n};\n\n// node_modules/.pnpm/@earendil-works+pi-tui@0.84.2/node_modules/@earendil-works/pi-tui/dist/components/cancellable-loader.js\nvar CancellableLoader = class extends Loader {\n  abortController = new AbortController();\n  /** Called when user presses Escape */\n  onAbort;\n  /** AbortSignal that is aborted when user presses Escape */\n  get signal() {\n    return this.abortController.signal;\n  }\n  /** Whether the loader was aborted */\n  get aborted() {\n    return this.abortController.signal.aborted;\n  }\n  handleInput(data) {\n    const kb = getKeybindings();\n    if (kb.matches(data, \"tui.select.cancel\")) {\n      this.abortController.abort();\n      this.onAbort?.();\n    }\n  }\n  dispose() {\n    this.stop();\n  }\n};\n\n// node_modules/.pnpm/@earendil-works+pi-tui@0.84.2/node_modules/@earendil-works/pi-tui/dist/kill-ring.js\nvar KillRing = class {\n  ring = [];\n  /**\n   * Add text to the kill ring.\n   *\n   * @param text - The killed text to add\n   * @param opts - Push options\n   * @param opts.prepend - If accumulating, prepend (backward deletion) or append (forward deletion)\n   * @param opts.accumulate - Merge with the most recent entry instead of creating a new one\n   */\n  push(text, opts) {\n    if (!text)\n      return;\n    if (opts.accumulate && this.ring.length > 0) {\n      const last = this.ring.pop();\n      this.ring.push(opts.prepend ? text + last : last + text);\n    } else {\n      this.ring.push(text);\n    }\n  }\n  /** Get most recent entry without modifying the ring. */\n  peek() {\n    return this.ring.length > 0 ? this.ring[this.ring.length - 1] : void 0;\n  }\n  /** Move last entry to front (for yank-pop cycling). */\n  rotate() {\n    if (this.ring.length > 1) {\n      const last = this.ring.pop();\n      this.ring.unshift(last);\n    }\n  }\n  get length() {\n    return this.ring.length;\n  }\n};\n\n// node_modules/.pnpm/@earendil-works+pi-tui@0.84.2/node_modules/@earendil-works/pi-tui/dist/tui.js\nimport * as os from \"node:os\";\nimport * as path2 from \"node:path\";\nimport { performance } from \"node:perf_hooks\";\n\n// node_modules/.pnpm/@earendil-works+pi-tui@0.84.2/node_modules/@earendil-works/pi-tui/dist/terminal-colors.js\nfunction hexToRgb(hex) {\n  const normalized = hex.startsWith(\"#\") ? hex.slice(1) : hex;\n  const r = parseInt(normalized.slice(0, 2), 16);\n  const g = parseInt(normalized.slice(2, 4), 16);\n  const b = parseInt(normalized.slice(4, 6), 16);\n  return { r, g, b };\n}\nfunction parseOscHexChannel(channel) {\n  if (!/^[0-9a-f]+$/i.test(channel)) {\n    return void 0;\n  }\n  const max = 16 ** channel.length - 1;\n  if (max <= 0) {\n    return void 0;\n  }\n  return Math.round(parseInt(channel, 16) / max * 255);\n}\nvar OSC11_BACKGROUND_COLOR_RESPONSE_PATTERN = /^\\x1b\\]11;([^\\x07\\x1b]*)(?:\\x07|\\x1b\\\\)$/i;\nvar COLOR_SCHEME_REPORT_PATTERN = /^(?:\\x1b\\[\\?997;(1|2)n)+$/;\nfunction isOsc11BackgroundColorResponse(data) {\n  return OSC11_BACKGROUND_COLOR_RESPONSE_PATTERN.test(data);\n}\nfunction parseOsc11BackgroundColor(data) {\n  const match = data.match(OSC11_BACKGROUND_COLOR_RESPONSE_PATTERN);\n  if (!match) {\n    return void 0;\n  }\n  const value = match[1].trim();\n  if (value.startsWith(\"#\")) {\n    const hex = value.slice(1);\n    if (/^[0-9a-f]{6}$/i.test(hex)) {\n      return hexToRgb(value);\n    }\n    if (/^[0-9a-f]{12}$/i.test(hex)) {\n      const r2 = parseOscHexChannel(hex.slice(0, 4));\n      const g2 = parseOscHexChannel(hex.slice(4, 8));\n      const b2 = parseOscHexChannel(hex.slice(8, 12));\n      return r2 !== void 0 && g2 !== void 0 && b2 !== void 0 ? { r: r2, g: g2, b: b2 } : void 0;\n    }\n    return void 0;\n  }\n  const rgbValue = value.replace(/^rgba?:/i, \"\");\n  const [red, green, blue] = rgbValue.split(\"/\");\n  if (red === void 0 || green === void 0 || blue === void 0) {\n    return void 0;\n  }\n  const r = parseOscHexChannel(red);\n  const g = parseOscHexChannel(green);\n  const b = parseOscHexChannel(blue);\n  return r !== void 0 && g !== void 0 && b !== void 0 ? { r, g, b } : void 0;\n}\nfunction parseTerminalColorSchemeReport(data) {\n  const match = data.match(COLOR_SCHEME_REPORT_PATTERN);\n  if (!match) {\n    return void 0;\n  }\n  return match[1] === \"2\" ? \"light\" : \"dark\";\n}\n\n// node_modules/.pnpm/@earendil-works+pi-tui@0.84.2/node_modules/@earendil-works/pi-tui/dist/terminal-image.js\nimport { execSync as execSync2 } from \"node:child_process\";\nimport { homedir as homedir4 } from \"node:os\";\nimport { isAbsolute as isAbsolute2 } from \"node:path\";\nimport { pathToFileURL } from \"node:url\";\nvar cachedCapabilities = null;\nvar cellDimensions = { widthPx: 9, heightPx: 18 };\nfunction getCellDimensions() {\n  return cellDimensions;\n}\nfunction setCellDimensions(dims) {\n  cellDimensions = dims;\n}\nfunction probeTmuxHyperlinks() {\n  try {\n    const termfeatures = execSync2(\"tmux display-message -p '#{client_termfeatures}'\", {\n      encoding: \"utf8\",\n      timeout: 250,\n      stdio: [\"ignore\", \"pipe\", \"ignore\"]\n    });\n    return termfeatures.split(\",\").map((feature) => feature.trim()).includes(\"hyperlinks\");\n  } catch {\n    return false;\n  }\n}\nfunction detectCapabilities(tmuxForwardsHyperlink = probeTmuxHyperlinks) {\n  const termProgram = process.env.TERM_PROGRAM?.toLowerCase() || \"\";\n  const terminalEmulator = process.env.TERMINAL_EMULATOR?.toLowerCase() || \"\";\n  const term = process.env.TERM?.toLowerCase() || \"\";\n  const colorTerm = process.env.COLORTERM?.toLowerCase() || \"\";\n  const hasTrueColorHint = colorTerm === \"truecolor\" || colorTerm === \"24bit\";\n  const isWindowsConsole = process.platform === \"win32\";\n  if (process.env.TMUX || term.startsWith(\"tmux\")) {\n    return { images: null, trueColor: hasTrueColorHint, hyperlinks: tmuxForwardsHyperlink() };\n  }\n  if (term.startsWith(\"screen\")) {\n    return { images: null, trueColor: hasTrueColorHint, hyperlinks: false };\n  }\n  if (process.env.KITTY_WINDOW_ID || termProgram === \"kitty\") {\n    return { images: \"kitty\", trueColor: true, hyperlinks: true };\n  }\n  if (termProgram === \"ghostty\" || term.includes(\"ghostty\") || process.env.GHOSTTY_RESOURCES_DIR) {\n    return { images: \"kitty\", trueColor: true, hyperlinks: true };\n  }\n  if (process.env.WEZTERM_PANE || termProgram === \"wezterm\") {\n    return { images: \"kitty\", trueColor: true, hyperlinks: true };\n  }\n  if (termProgram === \"warpterminal\" || process.env.WARP_SESSION_ID || process.env.WARP_TERMINAL_SESSION_UUID) {\n    return { images: \"kitty\", trueColor: true, hyperlinks: true };\n  }\n  if (process.env.ITERM_SESSION_ID || termProgram === \"iterm.app\") {\n    return { images: \"iterm2\", trueColor: true, hyperlinks: true };\n  }\n  if (process.env.WT_SESSION) {\n    return { images: null, trueColor: true, hyperlinks: true };\n  }\n  if (termProgram === \"vscode\") {\n    return { images: null, trueColor: true, hyperlinks: true };\n  }\n  if (termProgram === \"alacritty\") {\n    return { images: null, trueColor: true, hyperlinks: true };\n  }\n  if (terminalEmulator === \"jetbrains-jediterm\") {\n    return { images: null, trueColor: true, hyperlinks: false };\n  }\n  if (isWindowsConsole) {\n    return { images: null, trueColor: true, hyperlinks: false };\n  }\n  return { images: null, trueColor: hasTrueColorHint, hyperlinks: false };\n}\nfunction getCapabilities() {\n  if (!cachedCapabilities) {\n    cachedCapabilities = detectCapabilities();\n  }\n  return cachedCapabilities;\n}\nfunction resetCapabilitiesCache() {\n  cachedCapabilities = null;\n}\nfunction setCapabilities(caps) {\n  cachedCapabilities = caps;\n}\nvar KITTY_PREFIX = \"\\x1B_G\";\nvar ITERM2_PREFIX = \"\\x1B]1337;File=\";\nfunction isImageLine(line) {\n  if (line.startsWith(KITTY_PREFIX) || line.startsWith(ITERM2_PREFIX)) {\n    return true;\n  }\n  return line.includes(KITTY_PREFIX) || line.includes(ITERM2_PREFIX);\n}\nfunction allocateImageId() {\n  return Math.floor(Math.random() * 4294967294) + 1;\n}\nfunction encodeKitty(base64Data, options = {}) {\n  const CHUNK_SIZE = 4096;\n  const params = [\"a=T\", \"f=100\", \"q=2\"];\n  if (options.moveCursor === false)\n    params.push(\"C=1\");\n  if (options.columns)\n    params.push(`c=${options.columns}`);\n  if (options.rows)\n    params.push(`r=${options.rows}`);\n  if (options.imageId)\n    params.push(`i=${options.imageId}`);\n  if (base64Data.length <= CHUNK_SIZE) {\n    return `\\x1B_G${params.join(\",\")};${base64Data}\\x1B\\\\`;\n  }\n  const chunks = [];\n  let offset = 0;\n  let isFirst = true;\n  while (offset < base64Data.length) {\n    const chunk = base64Data.slice(offset, offset + CHUNK_SIZE);\n    const isLast = offset + CHUNK_SIZE >= base64Data.length;\n    if (isFirst) {\n      chunks.push(`\\x1B_G${params.join(\",\")},m=1;${chunk}\\x1B\\\\`);\n      isFirst = false;\n    } else if (isLast) {\n      chunks.push(`\\x1B_Gm=0;${chunk}\\x1B\\\\`);\n    } else {\n      chunks.push(`\\x1B_Gm=1;${chunk}\\x1B\\\\`);\n    }\n    offset += CHUNK_SIZE;\n  }\n  return chunks.join(\"\");\n}\nfunction deleteKittyImage(imageId) {\n  return `\\x1B_Ga=d,d=I,i=${imageId},q=2\\x1B\\\\`;\n}\nfunction deleteAllKittyImages() {\n  return \"\\x1B_Ga=d,d=A,q=2\\x1B\\\\\";\n}\nfunction deleteAllKittyPlacements() {\n  return \"\\x1B_Ga=d,d=a,q=2\\x1B\\\\\";\n}\nfunction encodeITerm2(base64Data, options = {}) {\n  const params = [\n    `inline=${options.inline !== false ? 1 : 0}`,\n    `size=${Buffer.byteLength(base64Data, \"base64\")}`\n  ];\n  if (options.width !== void 0)\n    params.push(`width=${options.width}`);\n  if (options.height !== void 0)\n    params.push(`height=${options.height}`);\n  if (options.name) {\n    const nameBase64 = Buffer.from(options.name).toString(\"base64\");\n    params.push(`name=${nameBase64}`);\n  }\n  if (options.preserveAspectRatio === false) {\n    params.push(\"preserveAspectRatio=0\");\n  }\n  return `\\x1B]1337;File=${params.join(\";\")}:${base64Data}\\x07`;\n}\nvar kittyImageMetadata = /* @__PURE__ */ new Map();\nvar kittyTransmissionGeneration = 0;\nfunction registerKittyImageMetadata(metadata) {\n  kittyTransmissionGeneration += 1;\n  kittyImageMetadata.delete(metadata.imageId);\n  kittyImageMetadata.set(metadata.imageId, { ...metadata, transmissionGeneration: kittyTransmissionGeneration });\n  if (kittyImageMetadata.size > 1e3) {\n    const oldestImageId = kittyImageMetadata.keys().next().value;\n    if (oldestImageId !== void 0)\n      kittyImageMetadata.delete(oldestImageId);\n  }\n}\nfunction getRegisteredKittyImageMetadata(line) {\n  const controls = /\\x1b_G([^;]*);/.exec(line)?.[1];\n  if (!controls)\n    return void 0;\n  const imageId = /(?:^|,)i=(\\d+)(?:,|$)/.exec(controls)?.[1];\n  return imageId === void 0 ? void 0 : kittyImageMetadata.get(Number.parseInt(imageId, 10));\n}\nfunction getKittyImageMetadata(line) {\n  const metadata = getRegisteredKittyImageMetadata(line);\n  if (!metadata)\n    return void 0;\n  return {\n    imageId: metadata.imageId,\n    columns: metadata.columns,\n    rows: metadata.rows,\n    widthPx: metadata.widthPx,\n    heightPx: metadata.heightPx\n  };\n}\nvar KITTY_PLACEMENT_CONTROL_KEYS = /* @__PURE__ */ new Set([\n  \"i\",\n  \"p\",\n  \"x\",\n  \"y\",\n  \"w\",\n  \"h\",\n  \"X\",\n  \"Y\",\n  \"c\",\n  \"r\",\n  \"C\",\n  \"U\",\n  \"z\",\n  \"P\",\n  \"Q\",\n  \"H\",\n  \"V\"\n]);\nfunction getKittyImagePlacement(line) {\n  const match = /\\x1b_G([^;]*);/.exec(line);\n  const metadata = getRegisteredKittyImageMetadata(line);\n  if (!match || !metadata)\n    return void 0;\n  let commandStart = match.index;\n  let commandControls = match[1];\n  let transmissionEnd;\n  while (true) {\n    const terminator = line.indexOf(\"\\x1B\\\\\", commandStart + KITTY_PREFIX.length);\n    if (terminator === -1)\n      return void 0;\n    transmissionEnd = terminator + 2;\n    if (!/(?:^|,)m=1(?:,|$)/.test(commandControls))\n      break;\n    commandStart = transmissionEnd;\n    if (!line.startsWith(KITTY_PREFIX, commandStart))\n      return void 0;\n    const controlsEnd = line.indexOf(\";\", commandStart + KITTY_PREFIX.length);\n    if (controlsEnd === -1)\n      return void 0;\n    commandControls = line.slice(commandStart + KITTY_PREFIX.length, controlsEnd);\n  }\n  const controls = match[1].split(\",\").filter((control) => KITTY_PLACEMENT_CONTROL_KEYS.has(control.split(\"=\", 1)[0] ?? \"\"));\n  const sequence3 = `\\x1B_Ga=p,q=2,${controls.join(\",\")}\\x1B\\\\`;\n  return {\n    imageId: metadata.imageId,\n    transmissionGeneration: metadata.transmissionGeneration,\n    transmissionBytes: transmissionEnd - match.index,\n    estimatedDecodedBytes: metadata.widthPx * metadata.heightPx * 4,\n    sequence: sequence3,\n    replacementLine: `${line.slice(0, match.index)}${sequence3}${line.slice(transmissionEnd)}`\n  };\n}\nfunction cropKittyImageLine(line, hiddenRows, visibleRows) {\n  const metadata = getKittyImageMetadata(line);\n  const match = /\\x1b_G([^;]*);/.exec(line);\n  if (!metadata || !match || hiddenRows < 0 || hiddenRows >= metadata.rows || visibleRows <= 0)\n    return line;\n  const croppedRows = Math.min(visibleRows, metadata.rows - hiddenRows);\n  if (hiddenRows === 0 && croppedRows === metadata.rows)\n    return line;\n  const sourceY = Math.floor(metadata.heightPx * hiddenRows / metadata.rows);\n  const sourceEnd = Math.ceil(metadata.heightPx * (hiddenRows + croppedRows) / metadata.rows);\n  const sourceHeight = Math.max(1, Math.min(metadata.heightPx, sourceEnd) - sourceY);\n  const controls = match[1].split(\",\").filter((control) => !/^[yhr]=/.test(control));\n  controls.push(`y=${sourceY}`, `h=${sourceHeight}`, `r=${croppedRows}`);\n  return `${line.slice(0, match.index)}\\x1B_G${controls.join(\",\")};${line.slice(match.index + match[0].length)}`;\n}\nfunction calculateImageCellSize(imageDimensions, maxWidthCells, maxHeightCells, cellDimensions2 = { widthPx: 9, heightPx: 18 }) {\n  const maxWidth = Math.max(1, Math.floor(maxWidthCells));\n  const maxHeight = maxHeightCells === void 0 ? void 0 : Math.max(1, Math.floor(maxHeightCells));\n  const imageWidth = Math.max(1, imageDimensions.widthPx);\n  const imageHeight = Math.max(1, imageDimensions.heightPx);\n  const widthScale = maxWidth * cellDimensions2.widthPx / imageWidth;\n  const heightScale = maxHeight === void 0 ? widthScale : maxHeight * cellDimensions2.heightPx / imageHeight;\n  const scale = Math.min(widthScale, heightScale);\n  const scaledWidthPx = imageWidth * scale;\n  const scaledHeightPx = imageHeight * scale;\n  const columns = Math.ceil(scaledWidthPx / cellDimensions2.widthPx);\n  const rows = Math.ceil(scaledHeightPx / cellDimensions2.heightPx);\n  return {\n    columns: Math.max(1, Math.min(maxWidth, columns)),\n    rows: Math.max(1, maxHeight === void 0 ? rows : Math.min(maxHeight, rows))\n  };\n}\nfunction calculateImageRows(imageDimensions, targetWidthCells, cellDimensions2 = { widthPx: 9, heightPx: 18 }) {\n  return calculateImageCellSize(imageDimensions, targetWidthCells, void 0, cellDimensions2).rows;\n}\nfunction getPngDimensions(base64Data) {\n  try {\n    const buffer = Buffer.from(base64Data, \"base64\");\n    if (buffer.length < 24) {\n      return null;\n    }\n    if (buffer[0] !== 137 || buffer[1] !== 80 || buffer[2] !== 78 || buffer[3] !== 71) {\n      return null;\n    }\n    const width = buffer.readUInt32BE(16);\n    const height = buffer.readUInt32BE(20);\n    return { widthPx: width, heightPx: height };\n  } catch {\n    return null;\n  }\n}\nfunction getJpegDimensions(base64Data) {\n  try {\n    const buffer = Buffer.from(base64Data, \"base64\");\n    if (buffer.length < 2) {\n      return null;\n    }\n    if (buffer[0] !== 255 || buffer[1] !== 216) {\n      return null;\n    }\n    let offset = 2;\n    while (offset < buffer.length - 9) {\n      if (buffer[offset] !== 255) {\n        offset++;\n        continue;\n      }\n      const marker = buffer[offset + 1];\n      if (marker >= 192 && marker <= 194) {\n        const height = buffer.readUInt16BE(offset + 5);\n        const width = buffer.readUInt16BE(offset + 7);\n        return { widthPx: width, heightPx: height };\n      }\n      if (offset + 3 >= buffer.length) {\n        return null;\n      }\n      const length = buffer.readUInt16BE(offset + 2);\n      if (length < 2) {\n        return null;\n      }\n      offset += 2 + length;\n    }\n    return null;\n  } catch {\n    return null;\n  }\n}\nfunction getGifDimensions(base64Data) {\n  try {\n    const buffer = Buffer.from(base64Data, \"base64\");\n    if (buffer.length < 10) {\n      return null;\n    }\n    const sig = buffer.slice(0, 6).toString(\"ascii\");\n    if (sig !== \"GIF87a\" && sig !== \"GIF89a\") {\n      return null;\n    }\n    const width = buffer.readUInt16LE(6);\n    const height = buffer.readUInt16LE(8);\n    return { widthPx: width, heightPx: height };\n  } catch {\n    return null;\n  }\n}\nfunction getWebpDimensions(base64Data) {\n  try {\n    const buffer = Buffer.from(base64Data, \"base64\");\n    if (buffer.length < 30) {\n      return null;\n    }\n    const riff = buffer.slice(0, 4).toString(\"ascii\");\n    const webp = buffer.slice(8, 12).toString(\"ascii\");\n    if (riff !== \"RIFF\" || webp !== \"WEBP\") {\n      return null;\n    }\n    const chunk = buffer.slice(12, 16).toString(\"ascii\");\n    if (chunk === \"VP8 \") {\n      if (buffer.length < 30)\n        return null;\n      const width = buffer.readUInt16LE(26) & 16383;\n      const height = buffer.readUInt16LE(28) & 16383;\n      return { widthPx: width, heightPx: height };\n    } else if (chunk === \"VP8L\") {\n      if (buffer.length < 25)\n        return null;\n      const bits = buffer.readUInt32LE(21);\n      const width = (bits & 16383) + 1;\n      const height = (bits >> 14 & 16383) + 1;\n      return { widthPx: width, heightPx: height };\n    } else if (chunk === \"VP8X\") {\n      if (buffer.length < 30)\n        return null;\n      const width = (buffer[24] | buffer[25] << 8 | buffer[26] << 16) + 1;\n      const height = (buffer[27] | buffer[28] << 8 | buffer[29] << 16) + 1;\n      return { widthPx: width, heightPx: height };\n    }\n    return null;\n  } catch {\n    return null;\n  }\n}\nfunction getImageDimensions(base64Data, mimeType) {\n  if (mimeType === \"image/png\") {\n    return getPngDimensions(base64Data);\n  }\n  if (mimeType === \"image/jpeg\") {\n    return getJpegDimensions(base64Data);\n  }\n  if (mimeType === \"image/gif\") {\n    return getGifDimensions(base64Data);\n  }\n  if (mimeType === \"image/webp\") {\n    return getWebpDimensions(base64Data);\n  }\n  return null;\n}\nfunction renderImage(base64Data, imageDimensions, options = {}) {\n  const caps = getCapabilities();\n  if (!caps.images) {\n    return null;\n  }\n  const maxWidth = options.maxWidthCells ?? 80;\n  const size = calculateImageCellSize(imageDimensions, maxWidth, options.maxHeightCells, getCellDimensions());\n  if (caps.images === \"kitty\") {\n    if (options.imageId !== void 0) {\n      registerKittyImageMetadata({\n        imageId: options.imageId,\n        columns: size.columns,\n        rows: size.rows,\n        widthPx: imageDimensions.widthPx,\n        heightPx: imageDimensions.heightPx\n      });\n    }\n    const sequence3 = encodeKitty(base64Data, {\n      columns: size.columns,\n      rows: size.rows,\n      imageId: options.imageId,\n      moveCursor: options.moveCursor\n    });\n    return { sequence: sequence3, columns: size.columns, rows: size.rows, imageId: options.imageId };\n  }\n  if (caps.images === \"iterm2\") {\n    const sequence3 = encodeITerm2(base64Data, {\n      width: size.columns,\n      height: \"auto\",\n      preserveAspectRatio: options.preserveAspectRatio ?? true\n    });\n    return { sequence: sequence3, columns: size.columns, rows: size.rows };\n  }\n  return null;\n}\nfunction hyperlink(text, url) {\n  return `\\x1B]8;;${url}\\x1B\\\\${text}\\x1B]8;;\\x1B\\\\`;\n}\nfunction shortenImagePath(filename) {\n  const home = homedir4();\n  if (home && (filename === home || filename.startsWith(`${home}/`) || filename.startsWith(`${home}\\\\`))) {\n    return `~${filename.slice(home.length)}`;\n  }\n  return filename;\n}\nfunction imageFallback(mimeType, dimensions, filename) {\n  const parts = [];\n  if (filename) {\n    const display = shortenImagePath(filename);\n    if (getCapabilities().hyperlinks && isAbsolute2(filename)) {\n      parts.push(hyperlink(display, pathToFileURL(filename).href));\n    } else {\n      parts.push(display);\n    }\n  }\n  parts.push(`[${mimeType}]`);\n  if (dimensions)\n    parts.push(`${dimensions.widthPx}x${dimensions.heightPx}`);\n  return `[Image: ${parts.join(\" \")}]`;\n}\n\n// node_modules/.pnpm/@earendil-works+pi-tui@0.84.2/node_modules/@earendil-works/pi-tui/dist/tui.js\nfunction isFocusable(component) {\n  return component !== null && \"focused\" in component;\n}\nvar CURSOR_MARKER = \"\\x1B_pi:c\\x07\";\nfunction parseSizeValue(value, referenceSize) {\n  if (value === void 0)\n    return void 0;\n  if (typeof value === \"number\")\n    return value;\n  const match = value.match(/^(\\d+(?:\\.\\d+)?)%$/);\n  if (match) {\n    return Math.floor(referenceSize * parseFloat(match[1]) / 100);\n  }\n  return void 0;\n}\nvar Container = class {\n  children = [];\n  addChild(component) {\n    this.children.push(component);\n  }\n  removeChild(component) {\n    const index = this.children.indexOf(component);\n    if (index !== -1) {\n      this.children.splice(index, 1);\n    }\n  }\n  clear() {\n    this.children = [];\n  }\n  invalidate() {\n    for (const child of this.children) {\n      child.invalidate?.();\n    }\n  }\n  render(width) {\n    const lines = [];\n    for (const child of this.children) {\n      const childLines = child.render(width);\n      for (const line of childLines) {\n        lines.push(line);\n      }\n    }\n    return lines;\n  }\n};\nvar SEGMENT_RESET = \"\\x1B[0m\\x1B]8;;\\x07\";\nfunction compositeTuiLine(baseLine, overlayLine, startCol, overlayWidth, totalWidth) {\n  if (isImageLine(baseLine))\n    return baseLine;\n  const afterStart = startCol + overlayWidth;\n  const base = extractSegments(baseLine, startCol, afterStart, totalWidth - afterStart, true);\n  const overlay = sliceWithWidth(overlayLine, 0, overlayWidth, true);\n  const beforePad = Math.max(0, startCol - base.beforeWidth);\n  const overlayPad = Math.max(0, overlayWidth - overlay.width);\n  const actualBeforeWidth = Math.max(startCol, base.beforeWidth);\n  const actualOverlayWidth = Math.max(overlayWidth, overlay.width);\n  const afterTarget = Math.max(0, totalWidth - actualBeforeWidth - actualOverlayWidth);\n  const afterPad = Math.max(0, afterTarget - base.afterWidth);\n  const result = base.before + \" \".repeat(beforePad) + SEGMENT_RESET + overlay.text + \" \".repeat(overlayPad) + SEGMENT_RESET + base.after + \" \".repeat(afterPad);\n  return visibleWidth(result) <= totalWidth ? result : sliceByColumn(result, 0, totalWidth, true);\n}\nvar VIEWPORT_TUI = Symbol.for(\"@earendil-works/pi-tui/viewport\");\nfunction isViewportTUI(tui) {\n  return tui[VIEWPORT_TUI] === true;\n}\nvar TuiBase = class _TuiBase extends Container {\n  terminal;\n  focusedComponent = null;\n  inputListeners = /* @__PURE__ */ new Set();\n  /** Global callback for debug key (Shift+Ctrl+D). Called before input is forwarded to focused component. */\n  onDebug;\n  renderRequested = false;\n  immediateRenderScheduled = false;\n  renderTimer;\n  lastRenderAt = 0;\n  static MIN_RENDER_INTERVAL_MS = 16;\n  showHardwareCursor = process.env.PI_HARDWARE_CURSOR === \"1\";\n  clearOnShrink = process.env.PI_CLEAR_ON_SHRINK === \"1\";\n  fullRedrawCount = 0;\n  stopped = false;\n  pendingOsc11BackgroundReplies = 0;\n  pendingOsc11BackgroundQueries = [];\n  terminalColorSchemeListeners = /* @__PURE__ */ new Set();\n  terminalColorSchemeNotificationsEnabled = false;\n  logDirectory;\n  // Overlay stack for modal components rendered on top of base content\n  focusOrderCounter = 0;\n  overlayStack = [];\n  get hasOverlayEntries() {\n    return this.overlayStack.length > 0;\n  }\n  overlayFocusRestore = { status: \"inactive\" };\n  constructor(terminal, showHardwareCursor, logDirectory) {\n    super();\n    this.terminal = terminal;\n    this.logDirectory = logDirectory ?? process.env.PI_CODING_AGENT_DIR ?? path2.join(os.homedir(), \".pi\", \"agent\");\n    if (showHardwareCursor !== void 0) {\n      this.showHardwareCursor = showHardwareCursor;\n    }\n  }\n  resetRenderState() {\n  }\n  beforeTerminalStart() {\n  }\n  afterTerminalStart() {\n  }\n  beforeTerminalStop(_options) {\n  }\n  afterTerminalStop(_options) {\n  }\n  get fullRedraws() {\n    return this.fullRedrawCount;\n  }\n  getShowHardwareCursor() {\n    return this.showHardwareCursor;\n  }\n  setShowHardwareCursor(enabled) {\n    if (this.showHardwareCursor === enabled)\n      return;\n    this.showHardwareCursor = enabled;\n    if (!enabled) {\n      this.terminal.hideCursor();\n    }\n    this.requestRender();\n  }\n  getClearOnShrink() {\n    return this.clearOnShrink;\n  }\n  /**\n   * Set whether to trigger full re-render when content shrinks.\n   * When true (default), empty rows are cleared when content shrinks.\n   * When false, empty rows remain (reduces redraws on slower terminals).\n   */\n  setClearOnShrink(enabled) {\n    this.clearOnShrink = enabled;\n  }\n  getFocusedComponent() {\n    return this.focusedComponent;\n  }\n  setFocus(component) {\n    this.setFocusInternal({ component, overlayFocusRestore: \"clear\" });\n  }\n  setFocusInternal({ component, overlayFocusRestore }) {\n    const previousFocus = this.focusedComponent;\n    let nextFocus = component;\n    const previousFocusedOverlay = previousFocus ? this.overlayStack.find((entry) => entry.component === previousFocus && this.isOverlayVisible(entry)) : void 0;\n    const nextFocusIsOverlay = nextFocus ? this.overlayStack.some((entry) => entry.component === nextFocus) : false;\n    const restoreState = this.getVisibleOverlayFocusRestore();\n    if (nextFocus && !nextFocusIsOverlay) {\n      if (restoreState.status === \"blocked\" && restoreState.blockedBy === previousFocus) {\n        if (restoreState.resume.status === \"focus-target\" || !this.isComponentMounted(restoreState.blockedBy)) {\n          nextFocus = this.resolveBlockedOverlayFocusResume(restoreState);\n        } else {\n          this.overlayFocusRestore = {\n            status: \"blocked\",\n            overlay: restoreState.overlay,\n            blockedBy: nextFocus,\n            resume: restoreState.resume\n          };\n        }\n      } else if (previousFocusedOverlay && restoreState.status !== \"inactive\" && restoreState.overlay === previousFocusedOverlay && !this.isOverlayFocusAncestor(previousFocusedOverlay, nextFocus)) {\n        this.overlayFocusRestore = {\n          status: \"blocked\",\n          overlay: previousFocusedOverlay,\n          blockedBy: nextFocus,\n          resume: { status: \"restore-overlay\" }\n        };\n      }\n    } else if (nextFocus === null) {\n      if (restoreState.status === \"blocked\" && restoreState.blockedBy === previousFocus) {\n        nextFocus = this.resolveBlockedOverlayFocusResume(restoreState);\n      } else if (overlayFocusRestore === \"clear\") {\n        this.clearOverlayFocusRestore();\n      }\n    }\n    if (isFocusable(this.focusedComponent)) {\n      this.focusedComponent.focused = false;\n    }\n    this.focusedComponent = nextFocus;\n    if (isFocusable(nextFocus)) {\n      nextFocus.focused = true;\n    }\n    const focusedOverlay = nextFocus ? this.overlayStack.find((entry) => entry.component === nextFocus && this.isOverlayVisible(entry)) : void 0;\n    if (focusedOverlay) {\n      this.overlayFocusRestore = { status: \"eligible\", overlay: focusedOverlay };\n    }\n  }\n  clearOverlayFocusRestore() {\n    this.overlayFocusRestore = { status: \"inactive\" };\n  }\n  clearOverlayFocusRestoreFor(overlay) {\n    if (this.overlayFocusRestore.status !== \"inactive\" && this.overlayFocusRestore.overlay === overlay) {\n      this.clearOverlayFocusRestore();\n    }\n  }\n  resolveBlockedOverlayFocusResume(restoreState) {\n    if (restoreState.resume.status === \"restore-overlay\")\n      return restoreState.overlay.component;\n    this.clearOverlayFocusRestore();\n    return restoreState.resume.target;\n  }\n  getVisibleOverlayFocusRestore() {\n    const restoreState = this.overlayFocusRestore;\n    if (restoreState.status === \"inactive\")\n      return restoreState;\n    if (!this.overlayStack.includes(restoreState.overlay) || !this.isOverlayVisible(restoreState.overlay)) {\n      return { status: \"inactive\" };\n    }\n    return restoreState;\n  }\n  isOverlayFocusAncestor(entry, component) {\n    const visited = /* @__PURE__ */ new Set();\n    let current = entry.preFocus;\n    while (current && !visited.has(current)) {\n      visited.add(current);\n      if (current === component)\n        return true;\n      current = this.overlayStack.find((overlay) => overlay.component === current)?.preFocus ?? null;\n    }\n    return false;\n  }\n  retargetOverlayPreFocus(removed) {\n    for (const overlay of this.overlayStack) {\n      if (overlay !== removed && overlay.preFocus === removed.component) {\n        overlay.preFocus = removed.preFocus;\n      }\n    }\n  }\n  getMountedRoots() {\n    return this.children;\n  }\n  isComponentMounted(component) {\n    return this.getMountedRoots().some((child) => this.containsComponent(child, component));\n  }\n  containsComponent(root, target) {\n    if (root === target)\n      return true;\n    if (!(root instanceof Container))\n      return false;\n    return root.children.some((child) => this.containsComponent(child, target));\n  }\n  /**\n   * Show an overlay component with configurable positioning and sizing.\n   * Returns a handle to control the overlay's visibility.\n   */\n  showOverlay(component, options) {\n    const entry = {\n      component,\n      ...options === void 0 ? {} : { options },\n      preFocus: this.focusedComponent,\n      hidden: false,\n      focusOrder: ++this.focusOrderCounter\n    };\n    this.overlayStack.push(entry);\n    if (!options?.nonCapturing && this.isOverlayVisible(entry)) {\n      this.setFocus(component);\n    }\n    this.terminal.hideCursor();\n    this.requestRender();\n    return {\n      hide: () => {\n        const index = this.overlayStack.indexOf(entry);\n        if (index !== -1) {\n          this.clearOverlayFocusRestoreFor(entry);\n          this.retargetOverlayPreFocus(entry);\n          this.overlayStack.splice(index, 1);\n          if (this.focusedComponent === component) {\n            const topVisible = this.getTopmostVisibleOverlay();\n            this.setFocus(topVisible?.component ?? entry.preFocus);\n          }\n          if (this.overlayStack.length === 0)\n            this.terminal.hideCursor();\n          this.requestRender();\n        }\n      },\n      setHidden: (hidden) => {\n        if (entry.hidden === hidden)\n          return;\n        entry.hidden = hidden;\n        if (hidden) {\n          this.clearOverlayFocusRestoreFor(entry);\n          if (this.focusedComponent === component) {\n            const topVisible = this.getTopmostVisibleOverlay();\n            this.setFocus(topVisible?.component ?? entry.preFocus);\n          }\n        } else {\n          if (!options?.nonCapturing && this.isOverlayVisible(entry)) {\n            entry.focusOrder = ++this.focusOrderCounter;\n            this.setFocus(component);\n          }\n        }\n        this.requestRender();\n      },\n      isHidden: () => entry.hidden,\n      focus: () => {\n        if (!this.overlayStack.includes(entry) || !this.isOverlayVisible(entry))\n          return;\n        entry.focusOrder = ++this.focusOrderCounter;\n        this.setFocus(component);\n        this.requestRender();\n      },\n      unfocus: (unfocusOptions) => {\n        const isFocused = this.focusedComponent === component;\n        const restoreState = this.overlayFocusRestore;\n        const hasPendingRestore = restoreState.status !== \"inactive\" && restoreState.overlay === entry;\n        if (!isFocused && !hasPendingRestore)\n          return;\n        if (restoreState.status === \"blocked\" && restoreState.overlay === entry && this.focusedComponent === restoreState.blockedBy) {\n          if (unfocusOptions) {\n            this.overlayFocusRestore = {\n              status: \"blocked\",\n              overlay: entry,\n              blockedBy: restoreState.blockedBy,\n              resume: { status: \"focus-target\", target: unfocusOptions.target }\n            };\n          } else {\n            this.clearOverlayFocusRestore();\n          }\n          this.requestRender();\n          return;\n        }\n        this.clearOverlayFocusRestoreFor(entry);\n        if (isFocused || unfocusOptions) {\n          const topVisible = this.getTopmostVisibleOverlay();\n          const fallbackTarget = topVisible && topVisible !== entry ? topVisible.component : entry.preFocus;\n          this.setFocus(unfocusOptions ? unfocusOptions.target : fallbackTarget);\n        }\n        this.requestRender();\n      },\n      isFocused: () => this.focusedComponent === component\n    };\n  }\n  /** Hide the topmost overlay and restore previous focus. */\n  hideOverlay() {\n    const overlay = this.overlayStack[this.overlayStack.length - 1];\n    if (!overlay)\n      return;\n    this.clearOverlayFocusRestoreFor(overlay);\n    this.retargetOverlayPreFocus(overlay);\n    this.overlayStack.pop();\n    if (this.focusedComponent === overlay.component) {\n      const topVisible = this.getTopmostVisibleOverlay();\n      this.setFocus(topVisible?.component ?? overlay.preFocus);\n    }\n    if (this.overlayStack.length === 0)\n      this.terminal.hideCursor();\n    this.requestRender();\n  }\n  /** Check if there are any visible overlays */\n  hasOverlay() {\n    return this.overlayStack.some((o) => this.isOverlayVisible(o));\n  }\n  /** Check if the focused component is a visible overlay */\n  isOverlayFocused() {\n    return this.overlayStack.some((entry) => entry.component === this.focusedComponent && this.isOverlayVisible(entry));\n  }\n  /** Check if an overlay entry is currently visible */\n  isOverlayVisible(entry) {\n    if (entry.hidden)\n      return false;\n    if (entry.options?.visible) {\n      return entry.options.visible(this.terminal.columns, this.terminal.rows);\n    }\n    return true;\n  }\n  /** Find the visual-frontmost visible capturing overlay, if any */\n  getTopmostVisibleOverlay() {\n    let topmost;\n    for (const overlay of this.overlayStack) {\n      if (overlay.options?.nonCapturing || !this.isOverlayVisible(overlay))\n        continue;\n      if (!topmost || overlay.focusOrder > topmost.focusOrder) {\n        topmost = overlay;\n      }\n    }\n    return topmost;\n  }\n  invalidate() {\n    for (const root of this.getMountedRoots())\n      root.invalidate();\n    for (const overlay of this.overlayStack)\n      overlay.component.invalidate();\n  }\n  start() {\n    this.stopped = false;\n    this.beforeTerminalStart();\n    this.terminal.start((data) => this.handleTerminalInput(data), () => this.requestRender());\n    this.afterTerminalStart();\n    this.terminal.hideCursor();\n    if (this.terminalColorSchemeNotificationsEnabled) {\n      this.terminal.write(\"\\x1B[?2031h\");\n    }\n    this.queryCellSize();\n    this.requestRender();\n  }\n  addInputListener(listener) {\n    this.inputListeners.add(listener);\n    return () => {\n      this.inputListeners.delete(listener);\n    };\n  }\n  removeInputListener(listener) {\n    this.inputListeners.delete(listener);\n  }\n  onTerminalColorSchemeChange(listener) {\n    this.terminalColorSchemeListeners.add(listener);\n    return () => {\n      this.terminalColorSchemeListeners.delete(listener);\n    };\n  }\n  setTerminalColorSchemeNotifications(enabled) {\n    if (this.terminalColorSchemeNotificationsEnabled === enabled) {\n      return;\n    }\n    this.terminalColorSchemeNotificationsEnabled = enabled;\n    if (!this.stopped) {\n      this.terminal.write(enabled ? \"\\x1B[?2031h\" : \"\\x1B[?2031l\");\n    }\n  }\n  queryCellSize() {\n    if (!getCapabilities().images) {\n      return;\n    }\n    this.terminal.write(\"\\x1B[16t\");\n  }\n  stop(options = {}) {\n    this.stopped = true;\n    this.cancelRenderTimer();\n    if (this.terminalColorSchemeNotificationsEnabled) {\n      this.terminal.write(\"\\x1B[?2031l\");\n    }\n    this.beforeTerminalStop(options);\n    this.terminal.showCursor();\n    this.terminal.stop();\n    this.afterTerminalStop(options);\n  }\n  renderNow(force = false) {\n    if (force)\n      this.resetRenderState();\n    this.renderRequested = false;\n    this.cancelRenderTimer();\n    this.lastRenderAt = performance.now();\n    this.doRender();\n  }\n  requestRender(force = false) {\n    if (force) {\n      this.resetRenderState();\n      this.requestImmediateRender();\n      return;\n    }\n    if (this.renderRequested)\n      return;\n    this.renderRequested = true;\n    process.nextTick(() => this.scheduleRender());\n  }\n  requestImmediateRender() {\n    this.cancelRenderTimer();\n    this.renderRequested = true;\n    if (this.immediateRenderScheduled)\n      return;\n    this.immediateRenderScheduled = true;\n    process.nextTick(() => {\n      this.immediateRenderScheduled = false;\n      if (this.stopped || !this.renderRequested)\n        return;\n      this.cancelRenderTimer();\n      this.renderRequested = false;\n      this.lastRenderAt = performance.now();\n      this.doRender();\n    });\n  }\n  cancelRenderTimer() {\n    if (!this.renderTimer)\n      return;\n    clearTimeout(this.renderTimer);\n    this.renderTimer = void 0;\n  }\n  scheduleRender() {\n    if (this.stopped || this.renderTimer || !this.renderRequested) {\n      return;\n    }\n    const elapsed = performance.now() - this.lastRenderAt;\n    const delay = Math.max(0, _TuiBase.MIN_RENDER_INTERVAL_MS - elapsed);\n    this.renderTimer = setTimeout(() => {\n      this.renderTimer = void 0;\n      if (this.stopped || !this.renderRequested) {\n        return;\n      }\n      this.renderRequested = false;\n      this.lastRenderAt = performance.now();\n      this.doRender();\n      if (this.renderRequested) {\n        this.scheduleRender();\n      }\n    }, delay);\n  }\n  handleTerminalInput(data) {\n    if (this.consumeOsc11BackgroundResponse(data)) {\n      return;\n    }\n    if (this.consumeTerminalColorSchemeReport(data)) {\n      return;\n    }\n    if (this.inputListeners.size > 0) {\n      let current = data;\n      for (const listener of this.inputListeners) {\n        const result = listener(current);\n        if (result?.consume) {\n          return;\n        }\n        if (result?.data !== void 0) {\n          current = result.data;\n        }\n      }\n      if (current.length === 0) {\n        return;\n      }\n      data = current;\n    }\n    if (this.consumeCellSizeResponse(data)) {\n      return;\n    }\n    if (matchesKey(data, \"shift+ctrl+d\") && this.onDebug) {\n      this.onDebug();\n      return;\n    }\n    const focusedOverlay = this.overlayStack.find((o) => o.component === this.focusedComponent);\n    if (focusedOverlay && !this.isOverlayVisible(focusedOverlay)) {\n      const topVisible = this.getTopmostVisibleOverlay();\n      if (topVisible) {\n        this.setFocus(topVisible.component);\n      } else {\n        this.setFocusInternal({ component: focusedOverlay.preFocus, overlayFocusRestore: \"preserve\" });\n      }\n    }\n    const focusIsOverlay = this.overlayStack.some((o) => o.component === this.focusedComponent);\n    if (!focusIsOverlay) {\n      const restoreState = this.getVisibleOverlayFocusRestore();\n      if (restoreState.status === \"eligible\") {\n        this.setFocus(restoreState.overlay.component);\n      } else if (restoreState.status === \"blocked\" && restoreState.blockedBy !== this.focusedComponent) {\n        if (restoreState.resume.status === \"restore-overlay\") {\n          this.setFocus(restoreState.overlay.component);\n        } else {\n          this.clearOverlayFocusRestore();\n          this.setFocus(restoreState.resume.target);\n        }\n      }\n    }\n    if (this.focusedComponent?.handleInput) {\n      if (isKeyRelease(data) && !this.focusedComponent.wantsKeyRelease) {\n        return;\n      }\n      this.focusedComponent.handleInput(data);\n      this.requestImmediateRender();\n    }\n  }\n  consumeOsc11BackgroundResponse(data) {\n    if (this.pendingOsc11BackgroundReplies <= 0) {\n      return false;\n    }\n    if (!isOsc11BackgroundColorResponse(data)) {\n      return false;\n    }\n    const rgb2 = parseOsc11BackgroundColor(data);\n    this.pendingOsc11BackgroundReplies -= 1;\n    const query = this.pendingOsc11BackgroundQueries.shift();\n    if (query && !query.settled) {\n      query.settled = true;\n      if (query.timer) {\n        clearTimeout(query.timer);\n        query.timer = void 0;\n      }\n      query.resolve?.(rgb2);\n      query.resolve = void 0;\n    }\n    return true;\n  }\n  consumeTerminalColorSchemeReport(data) {\n    const scheme = parseTerminalColorSchemeReport(data);\n    if (!scheme) {\n      return false;\n    }\n    for (const listener of this.terminalColorSchemeListeners) {\n      listener(scheme);\n    }\n    return true;\n  }\n  consumeCellSizeResponse(data) {\n    const match = data.match(/^\\x1b\\[6;(\\d+);(\\d+)t$/);\n    if (!match) {\n      return false;\n    }\n    const heightPx = parseInt(match[1], 10);\n    const widthPx = parseInt(match[2], 10);\n    if (heightPx <= 0 || widthPx <= 0) {\n      return true;\n    }\n    setCellDimensions({ widthPx, heightPx });\n    this.invalidate();\n    this.requestRender();\n    return true;\n  }\n  /**\n   * Resolve overlay layout from options.\n   * Returns { width, row, col, maxHeight } for rendering.\n   */\n  resolveOverlayLayout(options, overlayHeight, termWidth, termHeight) {\n    const opt = options ?? {};\n    const margin = typeof opt.margin === \"number\" ? { top: opt.margin, right: opt.margin, bottom: opt.margin, left: opt.margin } : opt.margin ?? {};\n    const marginTop = Math.max(0, margin.top ?? 0);\n    const marginRight = Math.max(0, margin.right ?? 0);\n    const marginBottom = Math.max(0, margin.bottom ?? 0);\n    const marginLeft = Math.max(0, margin.left ?? 0);\n    const availWidth = Math.max(1, termWidth - marginLeft - marginRight);\n    const availHeight = Math.max(1, termHeight - marginTop - marginBottom);\n    let width = parseSizeValue(opt.width, termWidth) ?? Math.min(80, availWidth);\n    if (opt.minWidth !== void 0) {\n      width = Math.max(width, opt.minWidth);\n    }\n    width = Math.max(1, Math.min(width, availWidth));\n    let maxHeight = parseSizeValue(opt.maxHeight, termHeight);\n    if (maxHeight !== void 0) {\n      maxHeight = Math.max(1, Math.min(maxHeight, availHeight));\n    }\n    const effectiveHeight = maxHeight !== void 0 ? Math.min(overlayHeight, maxHeight) : overlayHeight;\n    let row;\n    let col;\n    if (opt.row !== void 0) {\n      if (typeof opt.row === \"string\") {\n        const match = opt.row.match(/^(\\d+(?:\\.\\d+)?)%$/);\n        if (match) {\n          const maxRow = Math.max(0, availHeight - effectiveHeight);\n          const percent = parseFloat(match[1]) / 100;\n          row = marginTop + Math.floor(maxRow * percent);\n        } else {\n          row = this.resolveAnchorRow(\"center\", effectiveHeight, availHeight, marginTop);\n        }\n      } else {\n        row = opt.row;\n      }\n    } else {\n      const anchor = opt.anchor ?? \"center\";\n      row = this.resolveAnchorRow(anchor, effectiveHeight, availHeight, marginTop);\n    }\n    if (opt.col !== void 0) {\n      if (typeof opt.col === \"string\") {\n        const match = opt.col.match(/^(\\d+(?:\\.\\d+)?)%$/);\n        if (match) {\n          const maxCol = Math.max(0, availWidth - width);\n          const percent = parseFloat(match[1]) / 100;\n          col = marginLeft + Math.floor(maxCol * percent);\n        } else {\n          col = this.resolveAnchorCol(\"center\", width, availWidth, marginLeft);\n        }\n      } else {\n        col = opt.col;\n      }\n    } else {\n      const anchor = opt.anchor ?? \"center\";\n      col = this.resolveAnchorCol(anchor, width, availWidth, marginLeft);\n    }\n    if (opt.offsetY !== void 0)\n      row += opt.offsetY;\n    if (opt.offsetX !== void 0)\n      col += opt.offsetX;\n    row = Math.max(marginTop, Math.min(row, termHeight - marginBottom - effectiveHeight));\n    col = Math.max(marginLeft, Math.min(col, termWidth - marginRight - width));\n    return { width, row, col, maxHeight };\n  }\n  resolveAnchorRow(anchor, height, availHeight, marginTop) {\n    switch (anchor) {\n      case \"top-left\":\n      case \"top-center\":\n      case \"top-right\":\n        return marginTop;\n      case \"bottom-left\":\n      case \"bottom-center\":\n      case \"bottom-right\":\n        return marginTop + availHeight - height;\n      case \"left-center\":\n      case \"center\":\n      case \"right-center\":\n        return marginTop + Math.floor((availHeight - height) / 2);\n    }\n  }\n  resolveAnchorCol(anchor, width, availWidth, marginLeft) {\n    switch (anchor) {\n      case \"top-left\":\n      case \"left-center\":\n      case \"bottom-left\":\n        return marginLeft;\n      case \"top-right\":\n      case \"right-center\":\n      case \"bottom-right\":\n        return marginLeft + availWidth - width;\n      case \"top-center\":\n      case \"center\":\n      case \"bottom-center\":\n        return marginLeft + Math.floor((availWidth - width) / 2);\n    }\n  }\n  /** Composite all overlays into content lines (sorted by focusOrder, higher = on top). */\n  compositeOverlays(lines, termWidth, termHeight) {\n    if (this.overlayStack.length === 0)\n      return lines;\n    const result = [...lines];\n    const rendered = [];\n    let minLinesNeeded = result.length;\n    const visibleEntries = this.overlayStack.filter((e) => this.isOverlayVisible(e));\n    visibleEntries.sort((a, b) => a.focusOrder - b.focusOrder);\n    for (const entry of visibleEntries) {\n      const { component, options } = entry;\n      const { width, maxHeight } = this.resolveOverlayLayout(options, 0, termWidth, termHeight);\n      let overlayLines = component.render(width);\n      if (maxHeight !== void 0 && overlayLines.length > maxHeight) {\n        overlayLines = overlayLines.slice(0, maxHeight);\n      }\n      const { row, col } = this.resolveOverlayLayout(options, overlayLines.length, termWidth, termHeight);\n      rendered.push({ overlayLines, row, col, w: width });\n      minLinesNeeded = Math.max(minLinesNeeded, row + overlayLines.length);\n    }\n    const workingHeight = Math.max(result.length, termHeight, minLinesNeeded);\n    while (result.length < workingHeight) {\n      result.push(\"\");\n    }\n    const viewportStart = Math.max(0, workingHeight - termHeight);\n    for (const { overlayLines, row, col, w } of rendered) {\n      for (let i = 0; i < overlayLines.length; i++) {\n        const idx = viewportStart + row + i;\n        if (idx >= 0 && idx < result.length) {\n          const truncatedOverlayLine = visibleWidth(overlayLines[i]) > w ? sliceByColumn(overlayLines[i], 0, w, true) : overlayLines[i];\n          result[idx] = this.compositeLineAt(result[idx], truncatedOverlayLine, col, w, termWidth);\n        }\n      }\n    }\n    return result;\n  }\n  applyLineResets(lines) {\n    const reset = SEGMENT_RESET;\n    for (let i = 0; i < lines.length; i++) {\n      const line = lines[i];\n      if (!isImageLine(line)) {\n        lines[i] = normalizeTerminalOutput(line) + reset;\n      }\n    }\n    return lines;\n  }\n  compositeLineAt(baseLine, overlayLine, startCol, overlayWidth, totalWidth) {\n    return compositeTuiLine(baseLine, overlayLine, startCol, overlayWidth, totalWidth);\n  }\n  /**\n   * Find and extract cursor position from rendered lines.\n   * Searches for CURSOR_MARKER, calculates its position, and strips it from the output.\n   * Only scans the bottom terminal height lines (visible viewport).\n   * @param lines - Rendered lines to search\n   * @param height - Terminal height (visible viewport size)\n   * @returns Cursor position { row, col } or null if no marker found\n   */\n  extractCursorPosition(lines, height) {\n    const viewportTop = Math.max(0, lines.length - height);\n    for (let row = lines.length - 1; row >= viewportTop; row--) {\n      const line = lines[row];\n      const markerIndex = line.indexOf(CURSOR_MARKER);\n      if (markerIndex !== -1) {\n        const beforeMarker = line.slice(0, markerIndex);\n        const col = visibleWidth(beforeMarker);\n        lines[row] = line.slice(0, markerIndex) + line.slice(markerIndex + CURSOR_MARKER.length);\n        return { row, col };\n      }\n    }\n    return null;\n  }\n  /**\n   * Query the terminal's default background color with OSC 11 (`ESC ] 11 ; ? BEL`).\n   * @param timeoutMs Query timeout in milliseconds.\n   * @returns Promise containing the parsed RGB color, or undefined if it times out or fails to parse.\n   */\n  queryTerminalBackgroundColor({ timeoutMs }) {\n    return new Promise((resolve15) => {\n      const query = {\n        settled: false,\n        resolve: resolve15,\n        timer: void 0\n      };\n      query.timer = setTimeout(() => {\n        if (query.settled) {\n          return;\n        }\n        query.settled = true;\n        query.timer = void 0;\n        query.resolve?.(void 0);\n        query.resolve = void 0;\n      }, timeoutMs);\n      this.pendingOsc11BackgroundQueries.push(query);\n      this.pendingOsc11BackgroundReplies += 1;\n      this.terminal.write(\"\\x1B]11;?\\x07\");\n    });\n  }\n  /**\n   * Query the terminal's color-scheme preference with DSR (`CSI ? 996 n`).\n   * Terminals that support the color palette notification protocol reply with\n   * `CSI ? 997 ; 1 n` for dark or `CSI ? 997 ; 2 n` for light.\n   */\n  queryTerminalColorScheme({ timeoutMs }) {\n    return new Promise((resolve15) => {\n      let settled = false;\n      let timer;\n      let unsubscribe = () => {\n      };\n      const settle = (scheme) => {\n        if (settled)\n          return;\n        settled = true;\n        if (timer) {\n          clearTimeout(timer);\n          timer = void 0;\n        }\n        unsubscribe();\n        resolve15(scheme);\n      };\n      unsubscribe = this.onTerminalColorSchemeChange(settle);\n      timer = setTimeout(() => settle(void 0), timeoutMs);\n      this.terminal.write(\"\\x1B[?996n\");\n    });\n  }\n};\n\n// node_modules/.pnpm/@earendil-works+pi-tui@0.84.2/node_modules/@earendil-works/pi-tui/dist/undo-stack.js\nvar UndoStack = class {\n  stack = [];\n  /** Push a deep clone of the given state onto the stack. */\n  push(state) {\n    this.stack.push(structuredClone(state));\n  }\n  /** Pop and return the most recent snapshot, or undefined if empty. */\n  pop() {\n    return this.stack.pop();\n  }\n  /** Remove all snapshots. */\n  clear() {\n    this.stack.length = 0;\n  }\n  get length() {\n    return this.stack.length;\n  }\n};\n\n// node_modules/.pnpm/@earendil-works+pi-tui@0.84.2/node_modules/@earendil-works/pi-tui/dist/word-navigation.js\nvar wordSegmenter2 = getWordSegmenter();\nfunction findWordBackward(text, cursor, options) {\n  if (cursor <= 0)\n    return 0;\n  const textBeforeCursor = text.slice(0, cursor);\n  const segmentFn = options?.segment;\n  const isAtomic = options?.isAtomicSegment;\n  const segments = segmentFn ? [...segmentFn(textBeforeCursor)] : [...wordSegmenter2.segment(textBeforeCursor)];\n  let newCursor = cursor;\n  while (segments.length > 0 && !isAtomic?.(segments[segments.length - 1]?.segment || \"\") && isWhitespaceChar(segments[segments.length - 1]?.segment || \"\")) {\n    newCursor -= segments.pop()?.segment.length || 0;\n  }\n  if (segments.length === 0)\n    return newCursor;\n  const last = segments[segments.length - 1];\n  if (isAtomic?.(last.segment)) {\n    newCursor -= last.segment.length;\n  } else if (last.isWordLike) {\n    const segment = last.segment;\n    const matches = [...segment.matchAll(new RegExp(PUNCTUATION_REGEX, \"g\"))];\n    if (matches.length <= 0) {\n      newCursor -= segment.length;\n    } else {\n      const lastMatch = matches[matches.length - 1];\n      newCursor -= segment.length - (lastMatch.index + lastMatch[0].length);\n    }\n  } else {\n    while (segments.length > 0 && !isAtomic?.(segments[segments.length - 1]?.segment || \"\") && !segments[segments.length - 1]?.isWordLike && !isWhitespaceChar(segments[segments.length - 1]?.segment || \"\")) {\n      newCursor -= segments.pop()?.segment.length || 0;\n    }\n  }\n  return newCursor;\n}\nfunction findWordForward(text, cursor, options) {\n  if (cursor >= text.length)\n    return text.length;\n  const textAfterCursor = text.slice(cursor);\n  const segmentFn = options?.segment;\n  const isAtomic = options?.isAtomicSegment;\n  const segments = segmentFn ? segmentFn(textAfterCursor) : wordSegmenter2.segment(textAfterCursor);\n  const iterator = segments[Symbol.iterator]();\n  let next = iterator.next();\n  let newCursor = cursor;\n  while (!next.done && !isAtomic?.(next.value.segment) && isWhitespaceChar(next.value.segment)) {\n    newCursor += next.value.segment.length;\n    next = iterator.next();\n  }\n  if (next.done)\n    return newCursor;\n  if (isAtomic?.(next.value.segment)) {\n    newCursor += next.value.segment.length;\n  } else if (next.value.isWordLike) {\n    newCursor += PUNCTUATION_REGEX.exec(next.value.segment)?.index ?? next.value.segment.length;\n  } else {\n    while (!next.done && !isAtomic?.(next.value.segment) && !next.value.isWordLike && !isWhitespaceChar(next.value.segment)) {\n      newCursor += next.value.segment.length;\n      next = iterator.next();\n    }\n  }\n  return newCursor;\n}\n\n// node_modules/.pnpm/@earendil-works+pi-tui@0.84.2/node_modules/@earendil-works/pi-tui/dist/components/select-list.js\nvar DEFAULT_PRIMARY_COLUMN_WIDTH = 32;\nvar PRIMARY_COLUMN_GAP = 2;\nvar MIN_DESCRIPTION_WIDTH = 10;\nvar normalizeToSingleLine = (text) => text.replace(/[\\r\\n]+/g, \" \").trim();\nvar clamp = (value, min, max) => Math.max(min, Math.min(value, max));\nvar SelectList = class {\n  items = [];\n  filteredItems = [];\n  selectedIndex = 0;\n  maxVisible = 5;\n  theme;\n  layout;\n  onSelect;\n  onCancel;\n  onSelectionChange;\n  constructor(items, maxVisible, theme2, layout = {}) {\n    this.items = items;\n    this.filteredItems = items;\n    this.maxVisible = maxVisible;\n    this.theme = theme2;\n    this.layout = layout;\n  }\n  setFilter(filter) {\n    this.filteredItems = this.items.filter((item) => item.value.toLowerCase().startsWith(filter.toLowerCase()));\n    this.selectedIndex = 0;\n  }\n  setSelectedIndex(index) {\n    this.selectedIndex = Math.max(0, Math.min(index, this.filteredItems.length - 1));\n  }\n  invalidate() {\n  }\n  render(width) {\n    const lines = [];\n    if (this.filteredItems.length === 0) {\n      lines.push(this.theme.noMatch(\"  No matching commands\"));\n      return lines;\n    }\n    const primaryColumnWidth = this.getPrimaryColumnWidth();\n    const startIndex = Math.max(0, Math.min(this.selectedIndex - Math.floor(this.maxVisible / 2), this.filteredItems.length - this.maxVisible));\n    const endIndex = Math.min(startIndex + this.maxVisible, this.filteredItems.length);\n    for (let i = startIndex; i < endIndex; i++) {\n      const item = this.filteredItems[i];\n      if (!item)\n        continue;\n      const isSelected = i === this.selectedIndex;\n      const descriptionSingleLine = item.description ? normalizeToSingleLine(item.description) : void 0;\n      lines.push(this.renderItem(item, isSelected, width, descriptionSingleLine, primaryColumnWidth));\n    }\n    if (startIndex > 0 || endIndex < this.filteredItems.length) {\n      const scrollText = `  (${this.selectedIndex + 1}/${this.filteredItems.length})`;\n      lines.push(this.theme.scrollInfo(truncateToWidth(scrollText, width - 2, \"\")));\n    }\n    return lines;\n  }\n  handleInput(keyData) {\n    const kb = getKeybindings();\n    if (kb.matches(keyData, \"tui.select.up\")) {\n      this.selectedIndex = this.selectedIndex === 0 ? this.filteredItems.length - 1 : this.selectedIndex - 1;\n      this.notifySelectionChange();\n    } else if (kb.matches(keyData, \"tui.select.down\")) {\n      this.selectedIndex = this.selectedIndex === this.filteredItems.length - 1 ? 0 : this.selectedIndex + 1;\n      this.notifySelectionChange();\n    } else if (kb.matches(keyData, \"tui.select.confirm\")) {\n      const selectedItem = this.filteredItems[this.selectedIndex];\n      if (selectedItem && this.onSelect) {\n        this.onSelect(selectedItem);\n      }\n    } else if (kb.matches(keyData, \"tui.select.cancel\")) {\n      if (this.onCancel) {\n        this.onCancel();\n      }\n    }\n  }\n  renderItem(item, isSelected, width, descriptionSingleLine, primaryColumnWidth) {\n    const prefix = isSelected ? \"\\u2192 \" : \"  \";\n    const prefixWidth = visibleWidth(prefix);\n    if (descriptionSingleLine && width > 40) {\n      const effectivePrimaryColumnWidth = Math.max(1, Math.min(primaryColumnWidth, width - prefixWidth - 4));\n      const maxPrimaryWidth = Math.max(1, effectivePrimaryColumnWidth - PRIMARY_COLUMN_GAP);\n      const truncatedValue2 = this.truncatePrimary(item, isSelected, maxPrimaryWidth, effectivePrimaryColumnWidth);\n      const truncatedValueWidth = visibleWidth(truncatedValue2);\n      const spacing = \" \".repeat(Math.max(1, effectivePrimaryColumnWidth - truncatedValueWidth));\n      const descriptionStart = prefixWidth + truncatedValueWidth + spacing.length;\n      const remainingWidth = width - descriptionStart - 2;\n      if (remainingWidth > MIN_DESCRIPTION_WIDTH) {\n        const truncatedDesc = truncateToWidth(descriptionSingleLine, remainingWidth, \"\");\n        if (isSelected) {\n          return this.theme.selectedText(`${prefix}${truncatedValue2}${spacing}${truncatedDesc}`);\n        }\n        const descText = this.theme.description(spacing + truncatedDesc);\n        return prefix + truncatedValue2 + descText;\n      }\n    }\n    const maxWidth = width - prefixWidth - 2;\n    const truncatedValue = this.truncatePrimary(item, isSelected, maxWidth, maxWidth);\n    if (isSelected) {\n      return this.theme.selectedText(`${prefix}${truncatedValue}`);\n    }\n    return prefix + truncatedValue;\n  }\n  getPrimaryColumnWidth() {\n    const { min, max } = this.getPrimaryColumnBounds();\n    const widestPrimary = this.filteredItems.reduce((widest, item) => {\n      return Math.max(widest, visibleWidth(this.getDisplayValue(item)) + PRIMARY_COLUMN_GAP);\n    }, 0);\n    return clamp(widestPrimary, min, max);\n  }\n  getPrimaryColumnBounds() {\n    const rawMin = this.layout.minPrimaryColumnWidth ?? this.layout.maxPrimaryColumnWidth ?? DEFAULT_PRIMARY_COLUMN_WIDTH;\n    const rawMax = this.layout.maxPrimaryColumnWidth ?? this.layout.minPrimaryColumnWidth ?? DEFAULT_PRIMARY_COLUMN_WIDTH;\n    return {\n      min: Math.max(1, Math.min(rawMin, rawMax)),\n      max: Math.max(1, Math.max(rawMin, rawMax))\n    };\n  }\n  truncatePrimary(item, isSelected, maxWidth, columnWidth) {\n    const displayValue = this.getDisplayValue(item);\n    const truncatedValue = this.layout.truncatePrimary ? this.layout.truncatePrimary({\n      text: displayValue,\n      maxWidth,\n      columnWidth,\n      item,\n      isSelected\n    }) : truncateToWidth(displayValue, maxWidth, \"\");\n    return truncateToWidth(truncatedValue, maxWidth, \"\");\n  }\n  getDisplayValue(item) {\n    return item.label || item.value;\n  }\n  notifySelectionChange() {\n    const selectedItem = this.filteredItems[this.selectedIndex];\n    if (selectedItem && this.onSelectionChange) {\n      this.onSelectionChange(selectedItem);\n    }\n  }\n  getSelectedItem() {\n    const item = this.filteredItems[this.selectedIndex];\n    return item || null;\n  }\n};\n\n// node_modules/.pnpm/@earendil-works+pi-tui@0.84.2/node_modules/@earendil-works/pi-tui/dist/components/editor.js\nvar graphemeSegmenter2 = getGraphemeSegmenter();\nvar wordSegmenter3 = getWordSegmenter();\nvar PASTE_MARKER_REGEX = /\\[paste #(\\d+)( (\\+\\d+ lines|\\d+ chars))?\\]/g;\nvar PASTE_MARKER_SINGLE = /^\\[paste #(\\d+)( (\\+\\d+ lines|\\d+ chars))?\\]$/;\nfunction isPasteMarker(segment) {\n  return segment.length >= 10 && PASTE_MARKER_SINGLE.test(segment);\n}\nfunction segmentWithMarkers(text, baseSegmenter, validIds) {\n  if (validIds.size === 0 || !text.includes(\"[paste #\")) {\n    return baseSegmenter.segment(text);\n  }\n  const markers = [];\n  for (const m of text.matchAll(PASTE_MARKER_REGEX)) {\n    const id = Number.parseInt(m[1], 10);\n    if (!validIds.has(id))\n      continue;\n    markers.push({ start: m.index, end: m.index + m[0].length });\n  }\n  if (markers.length === 0) {\n    return baseSegmenter.segment(text);\n  }\n  const baseSegments = baseSegmenter.segment(text);\n  const result = [];\n  let markerIdx = 0;\n  for (const seg of baseSegments) {\n    while (markerIdx < markers.length && markers[markerIdx].end <= seg.index) {\n      markerIdx++;\n    }\n    const marker = markerIdx < markers.length ? markers[markerIdx] : null;\n    if (marker && seg.index >= marker.start && seg.index < marker.end) {\n      if (seg.index === marker.start) {\n        const markerText = text.slice(marker.start, marker.end);\n        result.push({\n          segment: markerText,\n          index: marker.start,\n          input: text\n        });\n      }\n    } else {\n      result.push(seg);\n    }\n  }\n  return result;\n}\nfunction wordWrapLine(line, maxWidth, preSegmented) {\n  if (!line || maxWidth <= 0) {\n    return [{ text: \"\", startIndex: 0, endIndex: 0 }];\n  }\n  const lineWidth = visibleWidth(line);\n  if (lineWidth <= maxWidth) {\n    return [{ text: line, startIndex: 0, endIndex: line.length }];\n  }\n  const chunks = [];\n  const segments = preSegmented ?? [...graphemeSegmenter2.segment(line)];\n  let currentWidth = 0;\n  let chunkStart = 0;\n  let wrapOppIndex = -1;\n  let wrapOppWidth = 0;\n  for (let i = 0; i < segments.length; i++) {\n    const seg = segments[i];\n    const grapheme = seg.segment;\n    const gWidth = visibleWidth(grapheme);\n    const charIndex = seg.index;\n    const isWs = !isPasteMarker(grapheme) && isWhitespaceChar(grapheme);\n    if (currentWidth + gWidth > maxWidth) {\n      if (wrapOppIndex >= 0 && currentWidth - wrapOppWidth + gWidth <= maxWidth) {\n        chunks.push({ text: line.slice(chunkStart, wrapOppIndex), startIndex: chunkStart, endIndex: wrapOppIndex });\n        chunkStart = wrapOppIndex;\n        currentWidth -= wrapOppWidth;\n      } else if (chunkStart < charIndex) {\n        chunks.push({ text: line.slice(chunkStart, charIndex), startIndex: chunkStart, endIndex: charIndex });\n        chunkStart = charIndex;\n        currentWidth = 0;\n      }\n      wrapOppIndex = -1;\n    }\n    if (gWidth > maxWidth) {\n      const subChunks = wordWrapLine(grapheme, maxWidth);\n      for (let j = 0; j < subChunks.length - 1; j++) {\n        const sc = subChunks[j];\n        chunks.push({ text: sc.text, startIndex: charIndex + sc.startIndex, endIndex: charIndex + sc.endIndex });\n      }\n      const last = subChunks[subChunks.length - 1];\n      chunkStart = charIndex + last.startIndex;\n      currentWidth = visibleWidth(last.text);\n      wrapOppIndex = -1;\n      continue;\n    }\n    currentWidth += gWidth;\n    const next = segments[i + 1];\n    if (isWs && next && (isPasteMarker(next.segment) || !isWhitespaceChar(next.segment))) {\n      wrapOppIndex = next.index;\n      wrapOppWidth = currentWidth;\n    } else if (!isWs && next && !isWhitespaceChar(next.segment)) {\n      const isCjk = !isPasteMarker(grapheme) && cjkBreakRegex.test(grapheme);\n      const nextIsCjk = !isPasteMarker(next.segment) && cjkBreakRegex.test(next.segment);\n      if (isCjk || nextIsCjk) {\n        wrapOppIndex = next.index;\n        wrapOppWidth = currentWidth;\n      }\n    }\n  }\n  chunks.push({ text: line.slice(chunkStart), startIndex: chunkStart, endIndex: line.length });\n  return chunks;\n}\nvar SLASH_COMMAND_SELECT_LIST_LAYOUT = {\n  minPrimaryColumnWidth: 12,\n  maxPrimaryColumnWidth: 32\n};\nvar ATTACHMENT_AUTOCOMPLETE_DEBOUNCE_MS = 20;\nvar DEFAULT_AUTOCOMPLETE_TRIGGER_CHARACTERS = [\"@\", \"#\"];\nfunction escapeCharacterClass(value) {\n  return value.replace(/[\\\\^$.*+?()[\\]{}|-]/g, \"\\\\$&\");\n}\nfunction buildTriggerPattern(triggerCharacters) {\n  return new RegExp(`(?:^|[\\\\s])[${triggerCharacters.map(escapeCharacterClass).join(\"\")}][^\\\\s]*$`);\n}\nfunction buildDebouncePattern(triggerCharacters) {\n  const escapedWithoutAt = triggerCharacters.filter((character) => character !== \"@\").map(escapeCharacterClass);\n  return new RegExp(`(?:^|[ \\\\t])(?:@(?:\"[^\"]*|[^\\\\s]*)|[${escapedWithoutAt.join(\"\")}][^\\\\s]*)$`);\n}\nfunction createScrollBorder(direction, hiddenLineCount, width) {\n  const availableWidth = Math.max(0, width);\n  const indicator = `\\u2500\\u2500\\u2500 ${direction} ${hiddenLineCount} more `;\n  const remaining = availableWidth - visibleWidth(indicator);\n  if (remaining >= 0)\n    return indicator + \"\\u2500\".repeat(remaining);\n  const ellipsis = \"...\".slice(0, availableWidth);\n  const indicatorWidth = availableWidth - visibleWidth(ellipsis);\n  return sliceByColumn(indicator, 0, indicatorWidth, true) + ellipsis;\n}\nvar Editor = class {\n  state = {\n    lines: [\"\"],\n    cursorLine: 0,\n    cursorCol: 0\n  };\n  /** Focusable interface - set by TUI when focus changes */\n  focused = false;\n  tui;\n  theme;\n  paddingX = 0;\n  // Store last render width for cursor navigation\n  lastWidth = 80;\n  // Vertical scrolling support\n  scrollOffset = 0;\n  // Border color (can be changed dynamically)\n  borderColor;\n  // Autocomplete support\n  autocompleteProvider;\n  autocompleteTriggerCharacters = [...DEFAULT_AUTOCOMPLETE_TRIGGER_CHARACTERS];\n  autocompleteTriggerPattern = buildTriggerPattern(this.autocompleteTriggerCharacters);\n  autocompleteDebouncePattern = buildDebouncePattern(this.autocompleteTriggerCharacters);\n  autocompleteList;\n  autocompleteState = null;\n  autocompletePrefix = \"\";\n  autocompleteMaxVisible = 5;\n  autocompleteAbort;\n  autocompleteDebounceTimer;\n  autocompleteRequestTask = Promise.resolve();\n  autocompleteStartToken = 0;\n  autocompleteRequestId = 0;\n  // Paste tracking for large pastes\n  pastes = /* @__PURE__ */ new Map();\n  pasteCounter = 0;\n  // Bracketed paste mode buffering\n  pasteBuffer = \"\";\n  isInPaste = false;\n  // Prompt history for up/down navigation\n  history = [];\n  historyIndex = -1;\n  // -1 = not browsing, 0 = most recent, 1 = older, etc.\n  historyDraft = null;\n  // Kill ring for Emacs-style kill/yank operations\n  killRing = new KillRing();\n  lastAction = null;\n  // Character jump mode\n  jumpMode = null;\n  // Preferred visual column for vertical cursor movement (sticky column)\n  preferredVisualCol = null;\n  // When the cursor is snapped to the start of an atomic segment, e.g. a\n  // paste marker, cursorCol no longer reflects where the cursor would have\n  // landed. This field stores the pre-snap cursorCol so that the next\n  // vertical move can resolve it to a visual column on whatever VL it belongs\n  // to.\n  snappedFromCursorCol = null;\n  // Undo support\n  undoStack = new UndoStack();\n  onSubmit;\n  onChange;\n  disableSubmit = false;\n  constructor(tui, theme2, options = {}) {\n    this.tui = tui;\n    this.theme = theme2;\n    this.borderColor = theme2.borderColor;\n    const paddingX = options.paddingX ?? 0;\n    this.paddingX = Number.isFinite(paddingX) ? Math.max(0, Math.floor(paddingX)) : 0;\n    const maxVisible = options.autocompleteMaxVisible ?? 5;\n    this.autocompleteMaxVisible = Number.isFinite(maxVisible) ? Math.max(3, Math.min(20, Math.floor(maxVisible))) : 5;\n  }\n  /** Set of currently valid paste IDs, for marker-aware segmentation. */\n  validPasteIds() {\n    return new Set(this.pastes.keys());\n  }\n  /** Segment text with paste-marker awareness, only merging markers with valid IDs. */\n  segment(text, mode) {\n    return segmentWithMarkers(text, mode === \"word\" ? wordSegmenter3 : graphemeSegmenter2, this.validPasteIds());\n  }\n  getPaddingX() {\n    return this.paddingX;\n  }\n  setPaddingX(padding) {\n    const newPadding = Number.isFinite(padding) ? Math.max(0, Math.floor(padding)) : 0;\n    if (this.paddingX !== newPadding) {\n      this.paddingX = newPadding;\n      this.tui.requestRender();\n    }\n  }\n  getAutocompleteMaxVisible() {\n    return this.autocompleteMaxVisible;\n  }\n  setAutocompleteMaxVisible(maxVisible) {\n    const newMaxVisible = Number.isFinite(maxVisible) ? Math.max(3, Math.min(20, Math.floor(maxVisible))) : 5;\n    if (this.autocompleteMaxVisible !== newMaxVisible) {\n      this.autocompleteMaxVisible = newMaxVisible;\n      this.tui.requestRender();\n    }\n  }\n  setAutocompleteProvider(provider) {\n    this.cancelAutocomplete();\n    this.autocompleteProvider = provider;\n    this.setAutocompleteTriggerCharacters(provider.triggerCharacters ?? []);\n  }\n  /**\n   * Add a prompt to history for up/down arrow navigation.\n   * Called after successful submission.\n   */\n  addToHistory(text) {\n    const trimmed = text.trim();\n    if (!trimmed)\n      return;\n    if (this.history.length > 0 && this.history[0] === trimmed)\n      return;\n    this.history.unshift(trimmed);\n    if (this.history.length > 100) {\n      this.history.pop();\n    }\n  }\n  isEditorEmpty() {\n    return this.state.lines.length === 1 && this.state.lines[0] === \"\";\n  }\n  isOnFirstVisualLine() {\n    const visualLines = this.buildVisualLineMap(this.lastWidth);\n    const currentVisualLine = this.findCurrentVisualLine(visualLines);\n    return currentVisualLine === 0;\n  }\n  isOnLastVisualLine() {\n    const visualLines = this.buildVisualLineMap(this.lastWidth);\n    const currentVisualLine = this.findCurrentVisualLine(visualLines);\n    return currentVisualLine === visualLines.length - 1;\n  }\n  navigateHistory(direction) {\n    this.lastAction = null;\n    if (this.history.length === 0)\n      return;\n    const newIndex = this.historyIndex - direction;\n    if (newIndex < -1 || newIndex >= this.history.length)\n      return;\n    if (this.historyIndex === -1 && newIndex >= 0) {\n      this.pushUndoSnapshot();\n      this.historyDraft = structuredClone(this.state);\n    }\n    this.historyIndex = newIndex;\n    if (this.historyIndex === -1) {\n      const draft = this.historyDraft;\n      this.historyDraft = null;\n      if (draft) {\n        this.state = draft;\n        this.preferredVisualCol = null;\n        this.snappedFromCursorCol = null;\n        this.scrollOffset = 0;\n        if (this.onChange)\n          this.onChange(this.getText());\n      } else {\n        this.setTextInternal(\"\");\n      }\n    } else {\n      this.setTextInternal(this.history[this.historyIndex] || \"\", direction === -1 ? \"start\" : \"end\");\n    }\n  }\n  exitHistoryBrowsing() {\n    this.historyIndex = -1;\n    this.historyDraft = null;\n  }\n  /** Internal setText that doesn't reset history state - used by navigateHistory */\n  setTextInternal(text, cursorPlacement = \"end\") {\n    const lines = text.split(\"\\n\");\n    this.state.lines = lines.length === 0 ? [\"\"] : lines;\n    this.state.cursorLine = cursorPlacement === \"start\" ? 0 : this.state.lines.length - 1;\n    this.setCursorCol(cursorPlacement === \"start\" ? 0 : this.state.lines[this.state.cursorLine]?.length || 0);\n    this.scrollOffset = 0;\n    if (this.onChange) {\n      this.onChange(this.getText());\n    }\n  }\n  invalidate() {\n  }\n  render(width) {\n    const maxPadding = Math.max(0, Math.floor((width - 1) / 2));\n    const paddingX = Math.min(this.paddingX, maxPadding);\n    const contentWidth = Math.max(1, width - paddingX * 2);\n    const layoutWidth = Math.max(1, contentWidth - (paddingX ? 0 : 1));\n    this.lastWidth = layoutWidth;\n    const horizontal = this.borderColor(\"\\u2500\");\n    const layoutLines = this.layoutText(layoutWidth);\n    const terminalRows = this.tui.terminal.rows;\n    const maxVisibleLines = Math.max(5, Math.floor(terminalRows * 0.3));\n    let cursorLineIndex = layoutLines.findIndex((line) => line.hasCursor);\n    if (cursorLineIndex === -1)\n      cursorLineIndex = 0;\n    if (cursorLineIndex < this.scrollOffset) {\n      this.scrollOffset = cursorLineIndex;\n    } else if (cursorLineIndex >= this.scrollOffset + maxVisibleLines) {\n      this.scrollOffset = cursorLineIndex - maxVisibleLines + 1;\n    }\n    const maxScrollOffset = Math.max(0, layoutLines.length - maxVisibleLines);\n    this.scrollOffset = Math.max(0, Math.min(this.scrollOffset, maxScrollOffset));\n    const visibleLines = layoutLines.slice(this.scrollOffset, this.scrollOffset + maxVisibleLines);\n    const result = [];\n    const leftPadding = \" \".repeat(paddingX);\n    const rightPadding = leftPadding;\n    if (this.scrollOffset > 0) {\n      const border = createScrollBorder(\"\\u2191\", this.scrollOffset, width);\n      result.push(this.borderColor(border));\n    } else {\n      result.push(horizontal.repeat(width));\n    }\n    const emitCursorMarker = this.focused;\n    for (const layoutLine of visibleLines) {\n      let displayText = layoutLine.text;\n      let lineVisibleWidth = visibleWidth(layoutLine.text);\n      let cursorInPadding = false;\n      if (layoutLine.hasCursor && layoutLine.cursorPos !== void 0) {\n        const before = displayText.slice(0, layoutLine.cursorPos);\n        const after = displayText.slice(layoutLine.cursorPos);\n        const marker = emitCursorMarker ? CURSOR_MARKER : \"\";\n        if (after.length > 0) {\n          const afterGraphemes = [...this.segment(after, \"grapheme\")];\n          const firstGrapheme = afterGraphemes[0]?.segment || \"\";\n          const restAfter = after.slice(firstGrapheme.length);\n          const cursor = `\\x1B[7m${firstGrapheme}\\x1B[0m`;\n          displayText = before + marker + cursor + restAfter;\n        } else {\n          const cursor = \"\\x1B[7m \\x1B[0m\";\n          displayText = before + marker + cursor;\n          lineVisibleWidth = lineVisibleWidth + 1;\n          if (lineVisibleWidth > contentWidth && paddingX > 0) {\n            cursorInPadding = true;\n          }\n        }\n      }\n      const padding = \" \".repeat(Math.max(0, contentWidth - lineVisibleWidth));\n      const lineRightPadding = cursorInPadding ? rightPadding.slice(1) : rightPadding;\n      result.push(`${leftPadding}${displayText}${padding}${lineRightPadding}`);\n    }\n    const linesBelow = layoutLines.length - (this.scrollOffset + visibleLines.length);\n    if (linesBelow > 0) {\n      const border = createScrollBorder(\"\\u2193\", linesBelow, width);\n      result.push(this.borderColor(border));\n    } else {\n      result.push(horizontal.repeat(width));\n    }\n    if (this.autocompleteState && this.autocompleteList) {\n      const autocompleteResult = this.autocompleteList.render(contentWidth);\n      for (const line of autocompleteResult) {\n        const lineWidth = visibleWidth(line);\n        const linePadding = \" \".repeat(Math.max(0, contentWidth - lineWidth));\n        result.push(`${leftPadding}${line}${linePadding}${rightPadding}`);\n      }\n    }\n    return result;\n  }\n  handleInput(data) {\n    const kb = getKeybindings();\n    if (this.jumpMode !== null) {\n      if (kb.matches(data, \"tui.editor.jumpForward\") || kb.matches(data, \"tui.editor.jumpBackward\")) {\n        this.jumpMode = null;\n        return;\n      }\n      const printable2 = decodePrintableKey(data) ?? (data.charCodeAt(0) >= 32 ? data : void 0);\n      if (printable2 !== void 0) {\n        const direction = this.jumpMode;\n        this.jumpMode = null;\n        this.jumpToChar(printable2, direction);\n        return;\n      }\n      this.jumpMode = null;\n    }\n    if (data.includes(\"\\x1B[200~\")) {\n      this.isInPaste = true;\n      this.pasteBuffer = \"\";\n      data = data.replace(\"\\x1B[200~\", \"\");\n    }\n    if (this.isInPaste) {\n      this.pasteBuffer += data;\n      const endIndex = this.pasteBuffer.indexOf(\"\\x1B[201~\");\n      if (endIndex !== -1) {\n        const pasteContent = this.pasteBuffer.substring(0, endIndex);\n        if (pasteContent.length > 0) {\n          this.handlePaste(pasteContent);\n        }\n        this.isInPaste = false;\n        const remaining = this.pasteBuffer.substring(endIndex + 6);\n        this.pasteBuffer = \"\";\n        if (remaining.length > 0) {\n          this.handleInput(remaining);\n        }\n        return;\n      }\n      return;\n    }\n    if (kb.matches(data, \"tui.input.copy\")) {\n      return;\n    }\n    if (kb.matches(data, \"tui.editor.undo\")) {\n      this.undo();\n      return;\n    }\n    if (this.autocompleteState && this.autocompleteList) {\n      if (kb.matches(data, \"tui.select.cancel\")) {\n        this.cancelAutocomplete();\n        return;\n      }\n      if (kb.matches(data, \"tui.select.up\") || kb.matches(data, \"tui.select.down\")) {\n        this.autocompleteList.handleInput(data);\n        return;\n      }\n      if (kb.matches(data, \"tui.input.tab\")) {\n        const selected = this.autocompleteList.getSelectedItem();\n        if (selected && this.autocompleteProvider) {\n          this.pushUndoSnapshot();\n          this.lastAction = null;\n          const result = this.autocompleteProvider.applyCompletion(this.state.lines, this.state.cursorLine, this.state.cursorCol, selected, this.autocompletePrefix);\n          this.state.lines = result.lines;\n          this.state.cursorLine = result.cursorLine;\n          this.setCursorCol(result.cursorCol);\n          this.cancelAutocomplete();\n          if (this.onChange)\n            this.onChange(this.getText());\n        }\n        return;\n      }\n      if (kb.matches(data, \"tui.select.confirm\")) {\n        const selected = this.autocompleteList.getSelectedItem();\n        if (selected && this.autocompleteProvider) {\n          this.pushUndoSnapshot();\n          this.lastAction = null;\n          const result = this.autocompleteProvider.applyCompletion(this.state.lines, this.state.cursorLine, this.state.cursorCol, selected, this.autocompletePrefix);\n          this.state.lines = result.lines;\n          this.state.cursorLine = result.cursorLine;\n          this.setCursorCol(result.cursorCol);\n          if (this.autocompletePrefix.startsWith(\"/\")) {\n            this.cancelAutocomplete();\n          } else {\n            this.cancelAutocomplete();\n            if (this.onChange)\n              this.onChange(this.getText());\n            return;\n          }\n        }\n      }\n    }\n    if (kb.matches(data, \"tui.input.tab\") && !this.autocompleteState) {\n      this.handleTabCompletion();\n      return;\n    }\n    if (kb.matches(data, \"tui.editor.deleteToLineEnd\")) {\n      this.deleteToEndOfLine();\n      return;\n    }\n    if (kb.matches(data, \"tui.editor.deleteToLineStart\")) {\n      this.deleteToStartOfLine();\n      return;\n    }\n    if (kb.matches(data, \"tui.editor.deleteWordBackward\")) {\n      this.deleteWordBackwards();\n      return;\n    }\n    if (kb.matches(data, \"tui.editor.deleteWordForward\")) {\n      this.deleteWordForward();\n      return;\n    }\n    if (kb.matches(data, \"tui.editor.deleteCharBackward\") || matchesKey(data, \"shift+backspace\")) {\n      this.handleBackspace();\n      return;\n    }\n    if (kb.matches(data, \"tui.editor.deleteCharForward\") || matchesKey(data, \"shift+delete\")) {\n      this.handleForwardDelete();\n      return;\n    }\n    if (kb.matches(data, \"tui.editor.yank\")) {\n      this.yank();\n      return;\n    }\n    if (kb.matches(data, \"tui.editor.yankPop\")) {\n      this.yankPop();\n      return;\n    }\n    if (kb.matches(data, \"tui.editor.historyPrevious\")) {\n      this.cancelAutocomplete();\n      this.navigateHistory(-1);\n      return;\n    }\n    if (kb.matches(data, \"tui.editor.historyNext\")) {\n      this.cancelAutocomplete();\n      this.navigateHistory(1);\n      return;\n    }\n    if (kb.matches(data, \"tui.editor.cursorLineStart\")) {\n      this.moveToLineStart();\n      return;\n    }\n    if (kb.matches(data, \"tui.editor.cursorLineEnd\")) {\n      this.moveToLineEnd();\n      return;\n    }\n    if (kb.matches(data, \"tui.editor.cursorWordLeft\")) {\n      this.moveWordBackwards();\n      return;\n    }\n    if (kb.matches(data, \"tui.editor.cursorWordRight\")) {\n      this.moveWordForwards();\n      return;\n    }\n    if (kb.matches(data, \"tui.input.newLine\") || data.charCodeAt(0) === 10 && data.length > 1 || data === \"\\x1B\\r\" || data === \"\\x1B[13;2~\" || data.length > 1 && data.includes(\"\\x1B\") && data.includes(\"\\r\") || data === \"\\n\" && data.length === 1) {\n      if (this.shouldSubmitOnBackslashEnter(data, kb)) {\n        this.handleBackspace();\n        this.submitValue();\n        return;\n      }\n      this.addNewLine();\n      return;\n    }\n    if (kb.matches(data, \"tui.input.submit\")) {\n      if (this.disableSubmit)\n        return;\n      const currentLine = this.state.lines[this.state.cursorLine] || \"\";\n      if (this.state.cursorCol > 0 && currentLine[this.state.cursorCol - 1] === \"\\\\\") {\n        this.handleBackspace();\n        this.addNewLine();\n        return;\n      }\n      this.submitValue();\n      return;\n    }\n    if (kb.matches(data, \"tui.editor.cursorUp\")) {\n      if (this.isOnFirstVisualLine() && (this.isEditorEmpty() || this.historyIndex > -1 || this.state.cursorCol === 0)) {\n        this.navigateHistory(-1);\n      } else if (this.isOnFirstVisualLine()) {\n        this.moveToLineStart();\n      } else {\n        this.moveCursor(-1, 0);\n      }\n      return;\n    }\n    if (kb.matches(data, \"tui.editor.cursorDown\")) {\n      if (this.historyIndex > -1 && this.isOnLastVisualLine()) {\n        this.navigateHistory(1);\n      } else if (this.isOnLastVisualLine()) {\n        this.moveToLineEnd();\n      } else {\n        this.moveCursor(1, 0);\n      }\n      return;\n    }\n    if (kb.matches(data, \"tui.editor.cursorRight\")) {\n      this.moveCursor(0, 1);\n      return;\n    }\n    if (kb.matches(data, \"tui.editor.cursorLeft\")) {\n      this.moveCursor(0, -1);\n      return;\n    }\n    if (kb.matches(data, \"tui.editor.pageUp\")) {\n      this.pageScroll(-1);\n      return;\n    }\n    if (kb.matches(data, \"tui.editor.pageDown\")) {\n      this.pageScroll(1);\n      return;\n    }\n    if (kb.matches(data, \"tui.editor.jumpForward\")) {\n      this.jumpMode = \"forward\";\n      return;\n    }\n    if (kb.matches(data, \"tui.editor.jumpBackward\")) {\n      this.jumpMode = \"backward\";\n      return;\n    }\n    if (matchesKey(data, \"shift+space\")) {\n      this.insertCharacter(\" \");\n      return;\n    }\n    const printable = decodePrintableKey(data);\n    if (printable !== void 0) {\n      this.insertCharacter(printable);\n      return;\n    }\n    if (data.charCodeAt(0) >= 32) {\n      this.insertCharacter(data);\n    }\n  }\n  layoutText(contentWidth) {\n    const layoutLines = [];\n    if (this.state.lines.length === 0 || this.state.lines.length === 1 && this.state.lines[0] === \"\") {\n      layoutLines.push({\n        text: \"\",\n        hasCursor: true,\n        cursorPos: 0\n      });\n      return layoutLines;\n    }\n    for (let i = 0; i < this.state.lines.length; i++) {\n      const line = this.state.lines[i] || \"\";\n      const isCurrentLine = i === this.state.cursorLine;\n      const lineVisibleWidth = visibleWidth(line);\n      if (lineVisibleWidth <= contentWidth) {\n        if (isCurrentLine) {\n          layoutLines.push({\n            text: line,\n            hasCursor: true,\n            cursorPos: this.state.cursorCol\n          });\n        } else {\n          layoutLines.push({\n            text: line,\n            hasCursor: false\n          });\n        }\n      } else {\n        const chunks = wordWrapLine(line, contentWidth, [...this.segment(line, \"grapheme\")]);\n        for (let chunkIndex = 0; chunkIndex < chunks.length; chunkIndex++) {\n          const chunk = chunks[chunkIndex];\n          if (!chunk)\n            continue;\n          const cursorPos = this.state.cursorCol;\n          const isLastChunk = chunkIndex === chunks.length - 1;\n          let hasCursorInChunk = false;\n          let adjustedCursorPos = 0;\n          if (isCurrentLine) {\n            if (isLastChunk) {\n              hasCursorInChunk = cursorPos >= chunk.startIndex;\n              adjustedCursorPos = cursorPos - chunk.startIndex;\n            } else {\n              hasCursorInChunk = cursorPos >= chunk.startIndex && cursorPos < chunk.endIndex;\n              if (hasCursorInChunk) {\n                adjustedCursorPos = cursorPos - chunk.startIndex;\n                if (adjustedCursorPos > chunk.text.length) {\n                  adjustedCursorPos = chunk.text.length;\n                }\n              }\n            }\n          }\n          if (hasCursorInChunk) {\n            layoutLines.push({\n              text: chunk.text,\n              hasCursor: true,\n              cursorPos: adjustedCursorPos\n            });\n          } else {\n            layoutLines.push({\n              text: chunk.text,\n              hasCursor: false\n            });\n          }\n        }\n      }\n    }\n    return layoutLines;\n  }\n  getText() {\n    return this.state.lines.join(\"\\n\");\n  }\n  expandPasteMarkers(text) {\n    let result = text;\n    for (const [pasteId, pasteContent] of this.pastes) {\n      const markerRegex = new RegExp(`\\\\[paste #${pasteId}( (\\\\+\\\\d+ lines|\\\\d+ chars))?\\\\]`, \"g\");\n      result = result.replace(markerRegex, () => pasteContent);\n    }\n    return result;\n  }\n  /**\n   * Get text with paste markers expanded to their actual content.\n   * Use this when you need the full content (e.g., for external editor).\n   */\n  getExpandedText() {\n    return this.expandPasteMarkers(this.state.lines.join(\"\\n\"));\n  }\n  getLines() {\n    return [...this.state.lines];\n  }\n  getCursor() {\n    return { line: this.state.cursorLine, col: this.state.cursorCol };\n  }\n  setText(text) {\n    this.cancelAutocomplete();\n    this.lastAction = null;\n    this.exitHistoryBrowsing();\n    const normalized = this.normalizeText(text);\n    if (this.getText() !== normalized) {\n      this.pushUndoSnapshot();\n    }\n    this.pastes.clear();\n    this.pasteCounter = 0;\n    this.setTextInternal(normalized);\n  }\n  /**\n   * Insert text at the current cursor position.\n   * Used for programmatic insertion (e.g., clipboard image markers).\n   * This is atomic for undo - single undo restores entire pre-insert state.\n   */\n  insertTextAtCursor(text) {\n    if (!text)\n      return;\n    this.cancelAutocomplete();\n    this.pushUndoSnapshot();\n    this.lastAction = null;\n    this.exitHistoryBrowsing();\n    this.insertTextAtCursorInternal(text);\n  }\n  /**\n   * Normalize text for editor storage:\n   * - Normalize line endings (\\r\\n and \\r -> \\n)\n   * - Expand tabs to 4 spaces\n   */\n  normalizeText(text) {\n    return text.replace(/\\r\\n/g, \"\\n\").replace(/\\r/g, \"\\n\").replace(/\\t/g, \"    \");\n  }\n  /**\n   * Internal text insertion at cursor. Handles single and multi-line text.\n   * Does not push undo snapshots or trigger autocomplete - caller is responsible.\n   * Normalizes line endings and calls onChange once at the end.\n   */\n  insertTextAtCursorInternal(text) {\n    if (!text)\n      return;\n    const normalized = this.normalizeText(text);\n    const insertedLines = normalized.split(\"\\n\");\n    const currentLine = this.state.lines[this.state.cursorLine] || \"\";\n    const beforeCursor = currentLine.slice(0, this.state.cursorCol);\n    const afterCursor = currentLine.slice(this.state.cursorCol);\n    if (insertedLines.length === 1) {\n      this.state.lines[this.state.cursorLine] = beforeCursor + normalized + afterCursor;\n      this.setCursorCol(this.state.cursorCol + normalized.length);\n    } else {\n      this.state.lines = [\n        // All lines before current line\n        ...this.state.lines.slice(0, this.state.cursorLine),\n        // The first inserted line merged with text before cursor\n        beforeCursor + insertedLines[0],\n        // All middle inserted lines\n        ...insertedLines.slice(1, -1),\n        // The last inserted line with text after cursor\n        insertedLines[insertedLines.length - 1] + afterCursor,\n        // All lines after current line\n        ...this.state.lines.slice(this.state.cursorLine + 1)\n      ];\n      this.state.cursorLine += insertedLines.length - 1;\n      this.setCursorCol((insertedLines[insertedLines.length - 1] || \"\").length);\n    }\n    if (this.onChange) {\n      this.onChange(this.getText());\n    }\n  }\n  // All the editor methods from before...\n  insertCharacter(char, skipUndoCoalescing) {\n    this.exitHistoryBrowsing();\n    if (!skipUndoCoalescing) {\n      if (isWhitespaceChar(char) || this.lastAction !== \"type-word\") {\n        this.pushUndoSnapshot();\n      }\n      this.lastAction = \"type-word\";\n    }\n    const line = this.state.lines[this.state.cursorLine] || \"\";\n    const before = line.slice(0, this.state.cursorCol);\n    const after = line.slice(this.state.cursorCol);\n    this.state.lines[this.state.cursorLine] = before + char + after;\n    this.setCursorCol(this.state.cursorCol + char.length);\n    if (this.onChange) {\n      this.onChange(this.getText());\n    }\n    if (!this.autocompleteState) {\n      if (char === \"/\" && this.isAtStartOfMessage()) {\n        this.tryTriggerAutocomplete();\n      } else if (this.autocompleteTriggerCharacters.includes(char)) {\n        const currentLine = this.state.lines[this.state.cursorLine] || \"\";\n        const textBeforeCursor = currentLine.slice(0, this.state.cursorCol);\n        const charBeforeSymbol = textBeforeCursor[textBeforeCursor.length - 2];\n        if (textBeforeCursor.length === 1 || charBeforeSymbol === \" \" || charBeforeSymbol === \"\t\") {\n          this.tryTriggerAutocomplete();\n        }\n      } else if (/[a-zA-Z0-9.\\-_]/.test(char)) {\n        const currentLine = this.state.lines[this.state.cursorLine] || \"\";\n        const textBeforeCursor = currentLine.slice(0, this.state.cursorCol);\n        if (this.isInSlashCommandContext(textBeforeCursor)) {\n          this.tryTriggerAutocomplete();\n        } else if (this.autocompleteTriggerPattern.test(textBeforeCursor)) {\n          this.tryTriggerAutocomplete();\n        }\n      }\n    } else {\n      this.updateAutocomplete();\n    }\n  }\n  handlePaste(pastedText) {\n    this.cancelAutocomplete();\n    this.exitHistoryBrowsing();\n    this.lastAction = null;\n    this.pushUndoSnapshot();\n    const decodedText = pastedText.replace(/\\x1b\\[(\\d+);5u/g, (match, code) => {\n      const cp = Number(code);\n      if (cp >= 97 && cp <= 122)\n        return String.fromCharCode(cp - 96);\n      if (cp >= 65 && cp <= 90)\n        return String.fromCharCode(cp - 64);\n      return match;\n    });\n    const cleanText = this.normalizeText(decodedText);\n    let filteredText = cleanText.split(\"\").filter((char) => char === \"\\n\" || char.charCodeAt(0) >= 32).join(\"\");\n    if (/^[/~.]/.test(filteredText)) {\n      const currentLine = this.state.lines[this.state.cursorLine] || \"\";\n      const charBeforeCursor = this.state.cursorCol > 0 ? currentLine[this.state.cursorCol - 1] : \"\";\n      if (charBeforeCursor && /\\w/.test(charBeforeCursor)) {\n        filteredText = ` ${filteredText}`;\n      }\n    }\n    const pastedLines = filteredText.split(\"\\n\");\n    const totalChars = filteredText.length;\n    if (pastedLines.length > 10 || totalChars > 1e3) {\n      this.pasteCounter++;\n      const pasteId = this.pasteCounter;\n      this.pastes.set(pasteId, filteredText);\n      const marker = pastedLines.length > 10 ? `[paste #${pasteId} +${pastedLines.length} lines]` : `[paste #${pasteId} ${totalChars} chars]`;\n      this.insertTextAtCursorInternal(marker);\n      return;\n    }\n    if (pastedLines.length === 1) {\n      this.insertTextAtCursorInternal(filteredText);\n      return;\n    }\n    this.insertTextAtCursorInternal(filteredText);\n  }\n  addNewLine() {\n    this.cancelAutocomplete();\n    this.exitHistoryBrowsing();\n    this.lastAction = null;\n    this.pushUndoSnapshot();\n    const currentLine = this.state.lines[this.state.cursorLine] || \"\";\n    const before = currentLine.slice(0, this.state.cursorCol);\n    const after = currentLine.slice(this.state.cursorCol);\n    this.state.lines[this.state.cursorLine] = before;\n    this.state.lines.splice(this.state.cursorLine + 1, 0, after);\n    this.state.cursorLine++;\n    this.setCursorCol(0);\n    if (this.onChange) {\n      this.onChange(this.getText());\n    }\n  }\n  shouldSubmitOnBackslashEnter(data, kb) {\n    if (this.disableSubmit)\n      return false;\n    if (!matchesKey(data, \"enter\"))\n      return false;\n    const submitKeys = kb.getKeys(\"tui.input.submit\");\n    const hasShiftEnter = submitKeys.includes(\"shift+enter\") || submitKeys.includes(\"shift+return\");\n    if (!hasShiftEnter)\n      return false;\n    const currentLine = this.state.lines[this.state.cursorLine] || \"\";\n    return this.state.cursorCol > 0 && currentLine[this.state.cursorCol - 1] === \"\\\\\";\n  }\n  submitValue() {\n    this.cancelAutocomplete();\n    const result = this.expandPasteMarkers(this.state.lines.join(\"\\n\")).trim();\n    this.state = { lines: [\"\"], cursorLine: 0, cursorCol: 0 };\n    this.pastes.clear();\n    this.pasteCounter = 0;\n    this.exitHistoryBrowsing();\n    this.scrollOffset = 0;\n    this.undoStack.clear();\n    this.lastAction = null;\n    if (this.onChange)\n      this.onChange(\"\");\n    if (this.onSubmit)\n      this.onSubmit(result);\n  }\n  handleBackspace() {\n    this.exitHistoryBrowsing();\n    this.lastAction = null;\n    if (this.state.cursorCol > 0) {\n      this.pushUndoSnapshot();\n      let line = this.state.lines[this.state.cursorLine] || \"\";\n      const beforeCursor = line.slice(0, this.state.cursorCol);\n      const graphemes = [...this.segment(beforeCursor, \"grapheme\")];\n      const lastGrapheme = graphemes[graphemes.length - 1];\n      const graphemeLength = lastGrapheme ? lastGrapheme.segment.length : 1;\n      const isPastedSegmented = PASTE_MARKER_SINGLE.exec(lastGrapheme.segment);\n      if (isPastedSegmented) {\n        const targetId = Number(isPastedSegmented[1]);\n        this.pastes.delete(targetId);\n        this.pasteCounter--;\n        const higherIds = [...this.pastes.keys()].filter((id) => id > targetId).sort((a, b) => a - b);\n        for (const id of higherIds) {\n          this.pastes.set(id - 1, this.pastes.get(id));\n          this.pastes.delete(id);\n        }\n        this.state.lines = this.state.lines.map((line2) => line2.replace(PASTE_MARKER_REGEX, (fullMatch, idGroup, suffixGroup) => {\n          const x = Number(idGroup);\n          if (x <= targetId)\n            return fullMatch;\n          return `[paste #${x - 1}${suffixGroup}]`;\n        }));\n      }\n      line = this.state.lines[this.state.cursorLine] || \"\";\n      const before = line.slice(0, this.state.cursorCol - graphemeLength);\n      const after = line.slice(this.state.cursorCol);\n      this.state.lines[this.state.cursorLine] = before + after;\n      this.setCursorCol(this.state.cursorCol - graphemeLength);\n    } else if (this.state.cursorLine > 0) {\n      this.pushUndoSnapshot();\n      const currentLine = this.state.lines[this.state.cursorLine] || \"\";\n      const previousLine = this.state.lines[this.state.cursorLine - 1] || \"\";\n      this.state.lines[this.state.cursorLine - 1] = previousLine + currentLine;\n      this.state.lines.splice(this.state.cursorLine, 1);\n      this.state.cursorLine--;\n      this.setCursorCol(previousLine.length);\n    }\n    if (this.onChange) {\n      this.onChange(this.getText());\n    }\n    if (this.autocompleteState) {\n      this.updateAutocomplete();\n    } else {\n      const currentLine = this.state.lines[this.state.cursorLine] || \"\";\n      const textBeforeCursor = currentLine.slice(0, this.state.cursorCol);\n      if (this.isInSlashCommandContext(textBeforeCursor)) {\n        this.tryTriggerAutocomplete();\n      } else if (this.autocompleteTriggerPattern.test(textBeforeCursor)) {\n        this.tryTriggerAutocomplete();\n      }\n    }\n  }\n  /**\n   * Set cursor column and clear preferredVisualCol.\n   * Use this for all non-vertical cursor movements to reset sticky column behavior.\n   */\n  setCursorCol(col) {\n    this.state.cursorCol = col;\n    this.preferredVisualCol = null;\n    this.snappedFromCursorCol = null;\n  }\n  /**\n   * Move cursor to a target visual line, applying sticky column logic.\n   * Shared by moveCursor() and pageScroll().\n   */\n  moveToVisualLine(visualLines, currentVisualLine, targetVisualLine) {\n    const currentVL = visualLines[currentVisualLine];\n    const targetVL = visualLines[targetVisualLine];\n    if (!(currentVL && targetVL))\n      return;\n    let currentVisualCol;\n    if (this.snappedFromCursorCol !== null) {\n      const vlIndex = this.findVisualLineAt(visualLines, currentVL.logicalLine, this.snappedFromCursorCol);\n      currentVisualCol = this.snappedFromCursorCol - visualLines[vlIndex].startCol;\n    } else {\n      currentVisualCol = this.state.cursorCol - currentVL.startCol;\n    }\n    const isLastSourceSegment = currentVisualLine === visualLines.length - 1 || visualLines[currentVisualLine + 1]?.logicalLine !== currentVL.logicalLine;\n    const sourceMaxVisualCol = isLastSourceSegment ? currentVL.length : Math.max(0, currentVL.length - 1);\n    const isLastTargetSegment = targetVisualLine === visualLines.length - 1 || visualLines[targetVisualLine + 1]?.logicalLine !== targetVL.logicalLine;\n    const targetMaxVisualCol = isLastTargetSegment ? targetVL.length : Math.max(0, targetVL.length - 1);\n    const moveToVisualCol = this.computeVerticalMoveColumn(currentVisualCol, sourceMaxVisualCol, targetMaxVisualCol);\n    this.state.cursorLine = targetVL.logicalLine;\n    const targetCol = targetVL.startCol + moveToVisualCol;\n    const logicalLine = this.state.lines[targetVL.logicalLine] || \"\";\n    this.state.cursorCol = Math.min(targetCol, logicalLine.length);\n    const segments = [...this.segment(logicalLine, \"grapheme\")];\n    for (const seg of segments) {\n      if (seg.index > this.state.cursorCol)\n        break;\n      if (seg.segment.length <= 1)\n        continue;\n      if (this.state.cursorCol < seg.index + seg.segment.length) {\n        const isContinuation = seg.index < targetVL.startCol;\n        const isMovingDown = targetVisualLine > currentVisualLine;\n        if (isContinuation && isMovingDown) {\n          const segEnd = seg.index + seg.segment.length;\n          let next = targetVisualLine + 1;\n          while (next < visualLines.length && visualLines[next].logicalLine === targetVL.logicalLine && visualLines[next].startCol < segEnd) {\n            next++;\n          }\n          if (next < visualLines.length) {\n            this.moveToVisualLine(visualLines, currentVisualLine, next);\n            return;\n          }\n        }\n        this.snappedFromCursorCol = this.state.cursorCol;\n        this.state.cursorCol = seg.index;\n        return;\n      }\n    }\n    this.snappedFromCursorCol = null;\n  }\n  /**\n   * Compute the target visual column for vertical cursor movement.\n   * Implements the sticky column decision table:\n   *\n   * | P | S | T | U | Scenario                                             | Set Preferred | Move To     |\n   * |---|---|---|---| ---------------------------------------------------- |---------------|-------------|\n   * | 0 | * | 0 | - | Start nav, target fits                               | null          | current     |\n   * | 0 | * | 1 | - | Start nav, target shorter                            | current       | target end  |\n   * | 1 | 0 | 0 | 0 | Clamped, target fits preferred                       | null          | preferred   |\n   * | 1 | 0 | 0 | 1 | Clamped, target longer but still can't fit preferred | keep          | target end  |\n   * | 1 | 0 | 1 | - | Clamped, target even shorter                         | keep          | target end  |\n   * | 1 | 1 | 0 | - | Rewrapped, target fits current                       | null          | current     |\n   * | 1 | 1 | 1 | - | Rewrapped, target shorter than current               | current       | target end  |\n   *\n   * Where:\n   * - P = preferred col is set\n   * - S = cursor in middle of source line (not clamped to end)\n   * - T = target line shorter than current visual col\n   * - U = target line shorter than preferred col\n   */\n  computeVerticalMoveColumn(currentVisualCol, sourceMaxVisualCol, targetMaxVisualCol) {\n    const hasPreferred = this.preferredVisualCol !== null;\n    const cursorInMiddle = currentVisualCol < sourceMaxVisualCol;\n    const targetTooShort = targetMaxVisualCol < currentVisualCol;\n    if (!hasPreferred || cursorInMiddle) {\n      if (targetTooShort) {\n        this.preferredVisualCol = currentVisualCol;\n        return targetMaxVisualCol;\n      }\n      this.preferredVisualCol = null;\n      return currentVisualCol;\n    }\n    const targetCantFitPreferred = targetMaxVisualCol < this.preferredVisualCol;\n    if (targetTooShort || targetCantFitPreferred) {\n      return targetMaxVisualCol;\n    }\n    const result = this.preferredVisualCol;\n    this.preferredVisualCol = null;\n    return result;\n  }\n  moveToLineStart() {\n    this.lastAction = null;\n    this.setCursorCol(0);\n  }\n  moveToLineEnd() {\n    this.lastAction = null;\n    const currentLine = this.state.lines[this.state.cursorLine] || \"\";\n    this.setCursorCol(currentLine.length);\n  }\n  deleteToStartOfLine() {\n    this.exitHistoryBrowsing();\n    const currentLine = this.state.lines[this.state.cursorLine] || \"\";\n    if (this.state.cursorCol > 0) {\n      this.pushUndoSnapshot();\n      const deletedText = currentLine.slice(0, this.state.cursorCol);\n      this.killRing.push(deletedText, { prepend: true, accumulate: this.lastAction === \"kill\" });\n      this.lastAction = \"kill\";\n      this.state.lines[this.state.cursorLine] = currentLine.slice(this.state.cursorCol);\n      this.setCursorCol(0);\n    } else if (this.state.cursorLine > 0) {\n      this.pushUndoSnapshot();\n      this.killRing.push(\"\\n\", { prepend: true, accumulate: this.lastAction === \"kill\" });\n      this.lastAction = \"kill\";\n      const previousLine = this.state.lines[this.state.cursorLine - 1] || \"\";\n      this.state.lines[this.state.cursorLine - 1] = previousLine + currentLine;\n      this.state.lines.splice(this.state.cursorLine, 1);\n      this.state.cursorLine--;\n      this.setCursorCol(previousLine.length);\n    }\n    if (this.onChange) {\n      this.onChange(this.getText());\n    }\n  }\n  deleteToEndOfLine() {\n    this.exitHistoryBrowsing();\n    const currentLine = this.state.lines[this.state.cursorLine] || \"\";\n    if (this.state.cursorCol < currentLine.length) {\n      this.pushUndoSnapshot();\n      const deletedText = currentLine.slice(this.state.cursorCol);\n      this.killRing.push(deletedText, { prepend: false, accumulate: this.lastAction === \"kill\" });\n      this.lastAction = \"kill\";\n      this.state.lines[this.state.cursorLine] = currentLine.slice(0, this.state.cursorCol);\n    } else if (this.state.cursorLine < this.state.lines.length - 1) {\n      this.pushUndoSnapshot();\n      this.killRing.push(\"\\n\", { prepend: false, accumulate: this.lastAction === \"kill\" });\n      this.lastAction = \"kill\";\n      const nextLine = this.state.lines[this.state.cursorLine + 1] || \"\";\n      this.state.lines[this.state.cursorLine] = currentLine + nextLine;\n      this.state.lines.splice(this.state.cursorLine + 1, 1);\n    }\n    if (this.onChange) {\n      this.onChange(this.getText());\n    }\n  }\n  deleteWordBackwards() {\n    this.exitHistoryBrowsing();\n    const currentLine = this.state.lines[this.state.cursorLine] || \"\";\n    if (this.state.cursorCol === 0) {\n      if (this.state.cursorLine > 0) {\n        this.pushUndoSnapshot();\n        this.killRing.push(\"\\n\", { prepend: true, accumulate: this.lastAction === \"kill\" });\n        this.lastAction = \"kill\";\n        const previousLine = this.state.lines[this.state.cursorLine - 1] || \"\";\n        this.state.lines[this.state.cursorLine - 1] = previousLine + currentLine;\n        this.state.lines.splice(this.state.cursorLine, 1);\n        this.state.cursorLine--;\n        this.setCursorCol(previousLine.length);\n      }\n    } else {\n      this.pushUndoSnapshot();\n      const wasKill = this.lastAction === \"kill\";\n      const oldCursorCol = this.state.cursorCol;\n      this.moveWordBackwards();\n      const deleteFrom = this.state.cursorCol;\n      this.setCursorCol(oldCursorCol);\n      const deletedText = currentLine.slice(deleteFrom, this.state.cursorCol);\n      this.killRing.push(deletedText, { prepend: true, accumulate: wasKill });\n      this.lastAction = \"kill\";\n      this.state.lines[this.state.cursorLine] = currentLine.slice(0, deleteFrom) + currentLine.slice(this.state.cursorCol);\n      this.setCursorCol(deleteFrom);\n    }\n    if (this.onChange) {\n      this.onChange(this.getText());\n    }\n  }\n  deleteWordForward() {\n    this.exitHistoryBrowsing();\n    const currentLine = this.state.lines[this.state.cursorLine] || \"\";\n    if (this.state.cursorCol >= currentLine.length) {\n      if (this.state.cursorLine < this.state.lines.length - 1) {\n        this.pushUndoSnapshot();\n        this.killRing.push(\"\\n\", { prepend: false, accumulate: this.lastAction === \"kill\" });\n        this.lastAction = \"kill\";\n        const nextLine = this.state.lines[this.state.cursorLine + 1] || \"\";\n        this.state.lines[this.state.cursorLine] = currentLine + nextLine;\n        this.state.lines.splice(this.state.cursorLine + 1, 1);\n      }\n    } else {\n      this.pushUndoSnapshot();\n      const wasKill = this.lastAction === \"kill\";\n      const oldCursorCol = this.state.cursorCol;\n      this.moveWordForwards();\n      const deleteTo = this.state.cursorCol;\n      this.setCursorCol(oldCursorCol);\n      const deletedText = currentLine.slice(this.state.cursorCol, deleteTo);\n      this.killRing.push(deletedText, { prepend: false, accumulate: wasKill });\n      this.lastAction = \"kill\";\n      this.state.lines[this.state.cursorLine] = currentLine.slice(0, this.state.cursorCol) + currentLine.slice(deleteTo);\n    }\n    if (this.onChange) {\n      this.onChange(this.getText());\n    }\n  }\n  handleForwardDelete() {\n    this.exitHistoryBrowsing();\n    this.lastAction = null;\n    const currentLine = this.state.lines[this.state.cursorLine] || \"\";\n    if (this.state.cursorCol < currentLine.length) {\n      this.pushUndoSnapshot();\n      const afterCursor = currentLine.slice(this.state.cursorCol);\n      const graphemes = [...this.segment(afterCursor, \"grapheme\")];\n      const firstGrapheme = graphemes[0];\n      const graphemeLength = firstGrapheme ? firstGrapheme.segment.length : 1;\n      const before = currentLine.slice(0, this.state.cursorCol);\n      const after = currentLine.slice(this.state.cursorCol + graphemeLength);\n      this.state.lines[this.state.cursorLine] = before + after;\n    } else if (this.state.cursorLine < this.state.lines.length - 1) {\n      this.pushUndoSnapshot();\n      const nextLine = this.state.lines[this.state.cursorLine + 1] || \"\";\n      this.state.lines[this.state.cursorLine] = currentLine + nextLine;\n      this.state.lines.splice(this.state.cursorLine + 1, 1);\n    }\n    if (this.onChange) {\n      this.onChange(this.getText());\n    }\n    if (this.autocompleteState) {\n      this.updateAutocomplete();\n    } else {\n      const currentLine2 = this.state.lines[this.state.cursorLine] || \"\";\n      const textBeforeCursor = currentLine2.slice(0, this.state.cursorCol);\n      if (this.isInSlashCommandContext(textBeforeCursor)) {\n        this.tryTriggerAutocomplete();\n      } else if (this.autocompleteTriggerPattern.test(textBeforeCursor)) {\n        this.tryTriggerAutocomplete();\n      }\n    }\n  }\n  /**\n   * Build a mapping from visual lines to logical positions.\n   * Returns an array where each element represents a visual line with:\n   * - logicalLine: index into this.state.lines\n   * - startCol: starting column in the logical line\n   * - length: length of this visual line segment\n   */\n  buildVisualLineMap(width) {\n    const visualLines = [];\n    for (let i = 0; i < this.state.lines.length; i++) {\n      const line = this.state.lines[i] || \"\";\n      const lineVisWidth = visibleWidth(line);\n      if (line.length === 0) {\n        visualLines.push({ logicalLine: i, startCol: 0, length: 0 });\n      } else if (lineVisWidth <= width) {\n        visualLines.push({ logicalLine: i, startCol: 0, length: line.length });\n      } else {\n        const chunks = wordWrapLine(line, width, [...this.segment(line, \"grapheme\")]);\n        for (const chunk of chunks) {\n          visualLines.push({\n            logicalLine: i,\n            startCol: chunk.startIndex,\n            length: chunk.endIndex - chunk.startIndex\n          });\n        }\n      }\n    }\n    return visualLines;\n  }\n  /**\n   * Find the visual line index that contains the given logical position.\n   */\n  findVisualLineAt(visualLines, line, col) {\n    for (let i = 0; i < visualLines.length; i++) {\n      const vl = visualLines[i];\n      if (!vl || vl.logicalLine !== line)\n        continue;\n      const offset = col - vl.startCol;\n      const isLastSegmentOfLine = i === visualLines.length - 1 || visualLines[i + 1]?.logicalLine !== vl.logicalLine;\n      if (offset >= 0 && (offset < vl.length || isLastSegmentOfLine && offset === vl.length)) {\n        return i;\n      }\n    }\n    return visualLines.length - 1;\n  }\n  /**\n   * Find the visual line index for the current cursor position.\n   */\n  findCurrentVisualLine(visualLines) {\n    return this.findVisualLineAt(visualLines, this.state.cursorLine, this.state.cursorCol);\n  }\n  moveCursor(deltaLine, deltaCol) {\n    this.lastAction = null;\n    const visualLines = this.buildVisualLineMap(this.lastWidth);\n    const currentVisualLine = this.findCurrentVisualLine(visualLines);\n    if (deltaLine !== 0) {\n      const targetVisualLine = currentVisualLine + deltaLine;\n      if (targetVisualLine >= 0 && targetVisualLine < visualLines.length) {\n        this.moveToVisualLine(visualLines, currentVisualLine, targetVisualLine);\n      }\n    }\n    if (deltaCol !== 0) {\n      const currentLine = this.state.lines[this.state.cursorLine] || \"\";\n      if (deltaCol > 0) {\n        if (this.state.cursorCol < currentLine.length) {\n          const afterCursor = currentLine.slice(this.state.cursorCol);\n          const graphemes = [...this.segment(afterCursor, \"grapheme\")];\n          const firstGrapheme = graphemes[0];\n          this.setCursorCol(this.state.cursorCol + (firstGrapheme ? firstGrapheme.segment.length : 1));\n        } else if (this.state.cursorLine < this.state.lines.length - 1) {\n          this.state.cursorLine++;\n          this.setCursorCol(0);\n        } else {\n          const currentVL = visualLines[currentVisualLine];\n          if (currentVL) {\n            this.preferredVisualCol = this.state.cursorCol - currentVL.startCol;\n          }\n        }\n      } else {\n        if (this.state.cursorCol > 0) {\n          const beforeCursor = currentLine.slice(0, this.state.cursorCol);\n          const graphemes = [...this.segment(beforeCursor, \"grapheme\")];\n          const lastGrapheme = graphemes[graphemes.length - 1];\n          this.setCursorCol(this.state.cursorCol - (lastGrapheme ? lastGrapheme.segment.length : 1));\n        } else if (this.state.cursorLine > 0) {\n          this.state.cursorLine--;\n          const prevLine = this.state.lines[this.state.cursorLine] || \"\";\n          this.setCursorCol(prevLine.length);\n        }\n      }\n    }\n    if (this.autocompleteState) {\n      this.updateAutocomplete();\n    }\n  }\n  /**\n   * Scroll by a page (direction: -1 for up, 1 for down).\n   * Moves cursor by the page size while keeping it in bounds.\n   */\n  pageScroll(direction) {\n    this.lastAction = null;\n    const terminalRows = this.tui.terminal.rows;\n    const pageSize = Math.max(5, Math.floor(terminalRows * 0.3));\n    const visualLines = this.buildVisualLineMap(this.lastWidth);\n    const currentVisualLine = this.findCurrentVisualLine(visualLines);\n    const targetVisualLine = Math.max(0, Math.min(visualLines.length - 1, currentVisualLine + direction * pageSize));\n    this.moveToVisualLine(visualLines, currentVisualLine, targetVisualLine);\n  }\n  moveWordBackwards() {\n    this.lastAction = null;\n    const currentLine = this.state.lines[this.state.cursorLine] || \"\";\n    if (this.state.cursorCol === 0) {\n      if (this.state.cursorLine > 0) {\n        this.state.cursorLine--;\n        const prevLine = this.state.lines[this.state.cursorLine] || \"\";\n        this.setCursorCol(prevLine.length);\n      }\n      return;\n    }\n    this.setCursorCol(findWordBackward(currentLine, this.state.cursorCol, {\n      segment: (text) => this.segment(text, \"word\"),\n      isAtomicSegment: isPasteMarker\n    }));\n  }\n  /**\n   * Yank (paste) the most recent kill ring entry at cursor position.\n   */\n  yank() {\n    if (this.killRing.length === 0)\n      return;\n    this.pushUndoSnapshot();\n    const text = this.killRing.peek();\n    this.insertYankedText(text);\n    this.lastAction = \"yank\";\n  }\n  /**\n   * Cycle through kill ring (only works immediately after yank or yank-pop).\n   * Replaces the last yanked text with the previous entry in the ring.\n   */\n  yankPop() {\n    if (this.lastAction !== \"yank\" || this.killRing.length <= 1)\n      return;\n    this.pushUndoSnapshot();\n    this.deleteYankedText();\n    this.killRing.rotate();\n    const text = this.killRing.peek();\n    this.insertYankedText(text);\n    this.lastAction = \"yank\";\n  }\n  /**\n   * Insert text at cursor position (used by yank operations).\n   */\n  insertYankedText(text) {\n    this.exitHistoryBrowsing();\n    const lines = text.split(\"\\n\");\n    if (lines.length === 1) {\n      const currentLine = this.state.lines[this.state.cursorLine] || \"\";\n      const before = currentLine.slice(0, this.state.cursorCol);\n      const after = currentLine.slice(this.state.cursorCol);\n      this.state.lines[this.state.cursorLine] = before + text + after;\n      this.setCursorCol(this.state.cursorCol + text.length);\n    } else {\n      const currentLine = this.state.lines[this.state.cursorLine] || \"\";\n      const before = currentLine.slice(0, this.state.cursorCol);\n      const after = currentLine.slice(this.state.cursorCol);\n      this.state.lines[this.state.cursorLine] = before + (lines[0] || \"\");\n      for (let i = 1; i < lines.length - 1; i++) {\n        this.state.lines.splice(this.state.cursorLine + i, 0, lines[i] || \"\");\n      }\n      const lastLineIndex = this.state.cursorLine + lines.length - 1;\n      this.state.lines.splice(lastLineIndex, 0, (lines[lines.length - 1] || \"\") + after);\n      this.state.cursorLine = lastLineIndex;\n      this.setCursorCol((lines[lines.length - 1] || \"\").length);\n    }\n    if (this.onChange) {\n      this.onChange(this.getText());\n    }\n  }\n  /**\n   * Delete the previously yanked text (used by yank-pop).\n   * The yanked text is derived from killRing[end] since it hasn't been rotated yet.\n   */\n  deleteYankedText() {\n    const yankedText = this.killRing.peek();\n    if (!yankedText)\n      return;\n    const yankLines = yankedText.split(\"\\n\");\n    if (yankLines.length === 1) {\n      const currentLine = this.state.lines[this.state.cursorLine] || \"\";\n      const deleteLen = yankedText.length;\n      const before = currentLine.slice(0, this.state.cursorCol - deleteLen);\n      const after = currentLine.slice(this.state.cursorCol);\n      this.state.lines[this.state.cursorLine] = before + after;\n      this.setCursorCol(this.state.cursorCol - deleteLen);\n    } else {\n      const startLine = this.state.cursorLine - (yankLines.length - 1);\n      const startCol = (this.state.lines[startLine] || \"\").length - (yankLines[0] || \"\").length;\n      const afterCursor = (this.state.lines[this.state.cursorLine] || \"\").slice(this.state.cursorCol);\n      const beforeYank = (this.state.lines[startLine] || \"\").slice(0, startCol);\n      this.state.lines.splice(startLine, yankLines.length, beforeYank + afterCursor);\n      this.state.cursorLine = startLine;\n      this.setCursorCol(startCol);\n    }\n    if (this.onChange) {\n      this.onChange(this.getText());\n    }\n  }\n  pushUndoSnapshot() {\n    this.undoStack.push({ state: this.state, pastes: this.pastes, pasteCounter: this.pasteCounter });\n  }\n  undo() {\n    this.exitHistoryBrowsing();\n    const snapshot = this.undoStack.pop();\n    if (!snapshot)\n      return;\n    Object.assign(this.state, snapshot.state);\n    this.pastes = snapshot.pastes;\n    this.pasteCounter = snapshot.pasteCounter;\n    this.lastAction = null;\n    this.preferredVisualCol = null;\n    if (this.onChange) {\n      this.onChange(this.getText());\n    }\n  }\n  /**\n   * Jump to the first occurrence of a character in the specified direction.\n   * Multi-line search. Case-sensitive. Skips the current cursor position.\n   */\n  jumpToChar(char, direction) {\n    this.lastAction = null;\n    const isForward = direction === \"forward\";\n    const lines = this.state.lines;\n    const end = isForward ? lines.length : -1;\n    const step = isForward ? 1 : -1;\n    for (let lineIdx = this.state.cursorLine; lineIdx !== end; lineIdx += step) {\n      const line = lines[lineIdx] || \"\";\n      const isCurrentLine = lineIdx === this.state.cursorLine;\n      const searchFrom = isCurrentLine ? isForward ? this.state.cursorCol + 1 : this.state.cursorCol - 1 : void 0;\n      const idx = isForward ? line.indexOf(char, searchFrom) : line.lastIndexOf(char, searchFrom);\n      if (idx !== -1) {\n        this.state.cursorLine = lineIdx;\n        this.setCursorCol(idx);\n        return;\n      }\n    }\n  }\n  moveWordForwards() {\n    this.lastAction = null;\n    const currentLine = this.state.lines[this.state.cursorLine] || \"\";\n    if (this.state.cursorCol >= currentLine.length) {\n      if (this.state.cursorLine < this.state.lines.length - 1) {\n        this.state.cursorLine++;\n        this.setCursorCol(0);\n      }\n      return;\n    }\n    this.setCursorCol(findWordForward(currentLine, this.state.cursorCol, {\n      segment: (text) => this.segment(text, \"word\"),\n      isAtomicSegment: isPasteMarker\n    }));\n  }\n  // Slash menu only allowed on the first line of the editor\n  isSlashMenuAllowed() {\n    return this.state.cursorLine === 0;\n  }\n  // Helper method to check if cursor is at start of message (for slash command detection)\n  isAtStartOfMessage() {\n    if (!this.isSlashMenuAllowed())\n      return false;\n    const currentLine = this.state.lines[this.state.cursorLine] || \"\";\n    const beforeCursor = currentLine.slice(0, this.state.cursorCol);\n    return beforeCursor.trim() === \"\" || beforeCursor.trim() === \"/\";\n  }\n  isInSlashCommandContext(textBeforeCursor) {\n    return this.isSlashMenuAllowed() && textBeforeCursor.trimStart().startsWith(\"/\");\n  }\n  // Autocomplete methods\n  /**\n   * Find the best autocomplete item index for the given prefix.\n   * Returns -1 if no match is found.\n   *\n   * Match priority:\n   * 1. Exact match (prefix === item.value) -> always selected\n   * 2. Prefix match -> first item whose value starts with prefix\n   * 3. No match -> -1 (keep default highlight)\n   *\n   * Matching is case-sensitive and checks item.value only.\n   */\n  getBestAutocompleteMatchIndex(items, prefix) {\n    if (!prefix)\n      return -1;\n    let firstPrefixIndex = -1;\n    for (let i = 0; i < items.length; i++) {\n      const value = items[i].value;\n      if (value === prefix) {\n        return i;\n      }\n      if (firstPrefixIndex === -1 && value.startsWith(prefix)) {\n        firstPrefixIndex = i;\n      }\n    }\n    return firstPrefixIndex;\n  }\n  createAutocompleteList(prefix, items) {\n    const layout = prefix.startsWith(\"/\") ? SLASH_COMMAND_SELECT_LIST_LAYOUT : void 0;\n    return new SelectList(items, this.autocompleteMaxVisible, this.theme.selectList, layout);\n  }\n  tryTriggerAutocomplete(explicitTab = false) {\n    this.requestAutocomplete({ force: false, explicitTab });\n  }\n  handleTabCompletion() {\n    if (!this.autocompleteProvider)\n      return;\n    const currentLine = this.state.lines[this.state.cursorLine] || \"\";\n    const beforeCursor = currentLine.slice(0, this.state.cursorCol);\n    if (this.isInSlashCommandContext(beforeCursor) && !beforeCursor.trimStart().includes(\" \")) {\n      this.handleSlashCommandCompletion();\n    } else {\n      this.forceFileAutocomplete(true);\n    }\n  }\n  handleSlashCommandCompletion() {\n    this.requestAutocomplete({ force: false, explicitTab: true });\n  }\n  forceFileAutocomplete(explicitTab = false) {\n    this.requestAutocomplete({ force: true, explicitTab });\n  }\n  requestAutocomplete(options) {\n    if (!this.autocompleteProvider)\n      return;\n    if (options.force) {\n      const shouldTrigger = !this.autocompleteProvider.shouldTriggerFileCompletion || this.autocompleteProvider.shouldTriggerFileCompletion(this.state.lines, this.state.cursorLine, this.state.cursorCol);\n      if (!shouldTrigger) {\n        return;\n      }\n    }\n    this.cancelAutocompleteRequest();\n    const startToken = ++this.autocompleteStartToken;\n    const debounceMs = this.getAutocompleteDebounceMs(options);\n    if (debounceMs > 0) {\n      this.autocompleteDebounceTimer = setTimeout(() => {\n        this.autocompleteDebounceTimer = void 0;\n        void this.startAutocompleteRequest(startToken, options);\n      }, debounceMs);\n      return;\n    }\n    void this.startAutocompleteRequest(startToken, options);\n  }\n  async startAutocompleteRequest(startToken, options) {\n    const previousTask = this.autocompleteRequestTask;\n    this.autocompleteRequestTask = (async () => {\n      await previousTask;\n      if (startToken !== this.autocompleteStartToken || !this.autocompleteProvider) {\n        return;\n      }\n      const controller = new AbortController();\n      this.autocompleteAbort = controller;\n      const requestId = ++this.autocompleteRequestId;\n      const snapshotText = this.getText();\n      const snapshotLine = this.state.cursorLine;\n      const snapshotCol = this.state.cursorCol;\n      await this.runAutocompleteRequest(requestId, controller, snapshotText, snapshotLine, snapshotCol, options);\n    })();\n    await this.autocompleteRequestTask;\n  }\n  setAutocompleteTriggerCharacters(triggerCharacters) {\n    const next = [...DEFAULT_AUTOCOMPLETE_TRIGGER_CHARACTERS];\n    for (const character of triggerCharacters) {\n      if (character.length !== 1 || character === \"/\" || isWhitespaceChar(character) || next.includes(character)) {\n        continue;\n      }\n      next.push(character);\n    }\n    this.autocompleteTriggerCharacters = next;\n    this.autocompleteTriggerPattern = buildTriggerPattern(next);\n    this.autocompleteDebouncePattern = buildDebouncePattern(next);\n  }\n  getAutocompleteDebounceMs(options) {\n    if (options.explicitTab || options.force) {\n      return 0;\n    }\n    const currentLine = this.state.lines[this.state.cursorLine] || \"\";\n    const textBeforeCursor = currentLine.slice(0, this.state.cursorCol);\n    return this.autocompleteDebouncePattern.test(textBeforeCursor) ? ATTACHMENT_AUTOCOMPLETE_DEBOUNCE_MS : 0;\n  }\n  async runAutocompleteRequest(requestId, controller, snapshotText, snapshotLine, snapshotCol, options) {\n    if (!this.autocompleteProvider)\n      return;\n    const suggestions = await this.autocompleteProvider.getSuggestions(this.state.lines, this.state.cursorLine, this.state.cursorCol, { signal: controller.signal, force: options.force });\n    if (!this.isAutocompleteRequestCurrent(requestId, controller, snapshotText, snapshotLine, snapshotCol)) {\n      return;\n    }\n    this.autocompleteAbort = void 0;\n    if (!suggestions || !Array.isArray(suggestions.items) || suggestions.items.length === 0) {\n      this.cancelAutocomplete();\n      this.tui.requestRender();\n      return;\n    }\n    if (options.force && options.explicitTab && suggestions.items.length === 1) {\n      const item = suggestions.items[0];\n      this.pushUndoSnapshot();\n      this.lastAction = null;\n      const result = this.autocompleteProvider.applyCompletion(this.state.lines, this.state.cursorLine, this.state.cursorCol, item, suggestions.prefix);\n      this.state.lines = result.lines;\n      this.state.cursorLine = result.cursorLine;\n      this.setCursorCol(result.cursorCol);\n      if (this.onChange)\n        this.onChange(this.getText());\n      this.tui.requestRender();\n      return;\n    }\n    this.applyAutocompleteSuggestions(suggestions, options.force ? \"force\" : \"regular\");\n    this.tui.requestRender();\n  }\n  isAutocompleteRequestCurrent(requestId, controller, snapshotText, snapshotLine, snapshotCol) {\n    return !controller.signal.aborted && requestId === this.autocompleteRequestId && this.getText() === snapshotText && this.state.cursorLine === snapshotLine && this.state.cursorCol === snapshotCol;\n  }\n  applyAutocompleteSuggestions(suggestions, state) {\n    this.autocompletePrefix = suggestions.prefix;\n    this.autocompleteList = this.createAutocompleteList(suggestions.prefix, suggestions.items);\n    const bestMatchIndex = this.getBestAutocompleteMatchIndex(suggestions.items, suggestions.prefix);\n    if (bestMatchIndex >= 0) {\n      this.autocompleteList.setSelectedIndex(bestMatchIndex);\n    }\n    this.autocompleteState = state;\n  }\n  cancelAutocompleteRequest() {\n    this.autocompleteStartToken += 1;\n    if (this.autocompleteDebounceTimer) {\n      clearTimeout(this.autocompleteDebounceTimer);\n      this.autocompleteDebounceTimer = void 0;\n    }\n    this.autocompleteAbort?.abort();\n    this.autocompleteAbort = void 0;\n  }\n  clearAutocompleteUi() {\n    this.autocompleteState = null;\n    this.autocompleteList = void 0;\n    this.autocompletePrefix = \"\";\n  }\n  cancelAutocomplete() {\n    this.cancelAutocompleteRequest();\n    this.clearAutocompleteUi();\n  }\n  isShowingAutocomplete() {\n    return this.autocompleteState !== null;\n  }\n  updateAutocomplete() {\n    if (!this.autocompleteState || !this.autocompleteProvider)\n      return;\n    this.requestAutocomplete({ force: this.autocompleteState === \"force\", explicitTab: false });\n  }\n};\n\n// node_modules/.pnpm/@earendil-works+pi-tui@0.84.2/node_modules/@earendil-works/pi-tui/dist/layout-node.js\nvar LAYOUT_NODE = Symbol.for(\"@earendil-works/pi-tui/layout-node\");\nfunction getLayoutNode(component) {\n  const candidate = component;\n  return typeof candidate[LAYOUT_NODE] === \"function\" ? candidate[LAYOUT_NODE]() : void 0;\n}\n\n// node_modules/.pnpm/@earendil-works+pi-tui@0.84.2/node_modules/@earendil-works/pi-tui/dist/components/stack.js\nfunction isStackEntry(child) {\n  return !(\"render\" in child);\n}\nfunction normalizeSize(value, fallback) {\n  return value === void 0 || !Number.isFinite(value) ? fallback : Math.max(0, Math.floor(value));\n}\nvar Stack = class extends Container {\n  entries = [];\n  gap;\n  align;\n  constructor(children = [], options = {}) {\n    super();\n    this.gap = normalizeSize(options.gap, 0);\n    this.align = options.align ?? \"stretch\";\n    for (const child of children) {\n      if (isStackEntry(child))\n        this.addChild(child.component, child);\n      else\n        this.addChild(child);\n    }\n  }\n  addChild(component, options = {}) {\n    super.addChild(component);\n    this.entries.push({\n      component,\n      ...options.basis === void 0 ? {} : { basis: options.basis },\n      ...options.grow === void 0 ? {} : { grow: normalizeSize(options.grow, 0) },\n      ...options.shrink === void 0 ? {} : { shrink: normalizeSize(options.shrink, 1) },\n      ...options.minSize === void 0 ? {} : { minSize: normalizeSize(options.minSize, 0) },\n      ...options.maxSize === void 0 ? {} : { maxSize: normalizeSize(options.maxSize, Number.MAX_SAFE_INTEGER) },\n      ...options.visible === void 0 ? {} : { visible: options.visible }\n    });\n  }\n  removeChild(component) {\n    super.removeChild(component);\n    const index = this.entries.findIndex((entry) => entry.component === component);\n    if (index !== -1)\n      this.entries.splice(index, 1);\n  }\n  clear() {\n    super.clear();\n    this.entries.length = 0;\n  }\n  [LAYOUT_NODE]() {\n    return {\n      type: this.layoutType,\n      entries: this.entries,\n      gap: this.gap,\n      align: this.align\n    };\n  }\n};\nfunction visibleStackEntries(entries, viewport) {\n  return entries.filter((entry) => entry.visible?.(viewport) ?? true);\n}\nfunction clampSize(size, entry) {\n  const min = Math.max(0, Math.floor(entry.minSize ?? 0));\n  const max = Math.max(min, Math.floor(entry.maxSize ?? Number.MAX_SAFE_INTEGER));\n  return Math.max(min, Math.min(max, Math.max(0, Math.floor(size))));\n}\nfunction distribute(sizes, entries, amount, mode) {\n  let remaining = amount;\n  while (remaining > 0) {\n    const candidates = entries.map((entry, index) => ({ entry, index })).filter(({ entry, index }) => {\n      if (mode === \"grow\") {\n        return (entry.grow ?? 0) > 0 && sizes[index] < (entry.maxSize ?? Number.MAX_SAFE_INTEGER);\n      }\n      return (entry.shrink ?? 1) > 0 && sizes[index] > (entry.minSize ?? 0);\n    });\n    if (candidates.length === 0)\n      return;\n    const totalWeight = candidates.reduce((sum, { entry, index }) => {\n      return sum + (mode === \"grow\" ? entry.grow ?? 0 : (entry.shrink ?? 1) * Math.max(1, sizes[index]));\n    }, 0);\n    let distributed = 0;\n    for (const { entry, index } of candidates) {\n      if (remaining <= 0)\n        break;\n      const weight = mode === \"grow\" ? entry.grow ?? 0 : (entry.shrink ?? 1) * Math.max(1, sizes[index]);\n      const proposed = Math.max(1, Math.floor(remaining * weight / totalWeight));\n      const capacity = mode === \"grow\" ? (entry.maxSize ?? Number.MAX_SAFE_INTEGER) - sizes[index] : sizes[index] - (entry.minSize ?? 0);\n      const delta = Math.min(remaining, proposed, capacity);\n      if (delta <= 0)\n        continue;\n      sizes[index] = sizes[index] + (mode === \"grow\" ? delta : -delta);\n      remaining -= delta;\n      distributed += delta;\n    }\n    if (distributed === 0)\n      return;\n  }\n}\nfunction allocateStackSizes(entries, intrinsicSizes, availableSize, gap) {\n  const sizes = entries.map((entry, index) => clampSize(entry.basis === void 0 || entry.basis === \"auto\" ? intrinsicSizes[index] ?? 0 : entry.basis, entry));\n  if (availableSize === void 0)\n    return sizes;\n  const contentSize = Math.max(0, Math.floor(availableSize) - Math.max(0, entries.length - 1) * gap);\n  const total = sizes.reduce((sum, size) => sum + size, 0);\n  if (total < contentSize)\n    distribute(sizes, entries, contentSize - total, \"grow\");\n  else if (total > contentSize)\n    distribute(sizes, entries, total - contentSize, \"shrink\");\n  return sizes;\n}\n\n// node_modules/.pnpm/@earendil-works+pi-tui@0.84.2/node_modules/@earendil-works/pi-tui/dist/components/h-stack.js\nvar HStack = class extends Stack {\n  layoutType = \"hstack\";\n  constructor(children = [], options = {}) {\n    super(children, options);\n  }\n  render(width) {\n    const safeWidth = Math.max(1, width);\n    const viewport = { width: safeWidth, height: Number.MAX_SAFE_INTEGER };\n    const entries = visibleStackEntries(this.entries, viewport);\n    if (entries.length === 0)\n      return [];\n    const intrinsicWidths = entries.map((entry) => {\n      const lines = entry.component.render(safeWidth);\n      return lines.reduce((max, line) => Math.max(max, visibleWidth(line)), 0);\n    });\n    const widths = allocateStackSizes(entries, intrinsicWidths, safeWidth, this.gap);\n    const rendered = entries.map((entry, index) => widths[index] === 0 ? [] : entry.component.render(widths[index]));\n    const height = rendered.reduce((max, lines) => Math.max(max, lines.length), 0);\n    const result = Array.from({ length: height }, () => \"\");\n    let x = 0;\n    for (let index = 0; index < rendered.length; index++) {\n      const lines = rendered[index];\n      const childWidth = widths[index];\n      let offset = 0;\n      if (this.align === \"center\")\n        offset = Math.floor((height - lines.length) / 2);\n      else if (this.align === \"end\")\n        offset = height - lines.length;\n      for (let row = 0; row < lines.length; row++) {\n        const target = row + offset;\n        if (target < 0 || target >= result.length)\n          continue;\n        result[target] = compositeTuiLine(result[target], lines[row], x, childWidth, safeWidth);\n      }\n      x += childWidth + this.gap;\n    }\n    return result;\n  }\n};\n\n// node_modules/.pnpm/@earendil-works+pi-tui@0.84.2/node_modules/@earendil-works/pi-tui/dist/components/image.js\nvar Image = class {\n  base64Data;\n  mimeType;\n  dimensions;\n  theme;\n  options;\n  imageId;\n  cachedLines;\n  cachedWidth;\n  constructor(base64Data, mimeType, theme2, options = {}, dimensions) {\n    this.base64Data = base64Data;\n    this.mimeType = mimeType;\n    this.theme = theme2;\n    this.options = options;\n    this.dimensions = dimensions || getImageDimensions(base64Data, mimeType) || { widthPx: 800, heightPx: 600 };\n    this.imageId = options.imageId;\n  }\n  /** Get the Kitty image ID used by this image (if any). */\n  getImageId() {\n    return this.imageId;\n  }\n  invalidate() {\n    this.cachedLines = void 0;\n    this.cachedWidth = void 0;\n  }\n  render(width) {\n    if (this.cachedLines && this.cachedWidth === width) {\n      return this.cachedLines;\n    }\n    const maxWidth = Math.max(1, Math.min(width - 2, this.options.maxWidthCells ?? 60));\n    const cellDimensions2 = getCellDimensions();\n    const defaultMaxHeight = Math.max(1, Math.ceil(maxWidth * cellDimensions2.widthPx / cellDimensions2.heightPx));\n    const maxHeight = this.options.maxHeightCells ?? defaultMaxHeight;\n    const caps = getCapabilities();\n    let lines;\n    if (caps.images) {\n      if (caps.images === \"kitty\" && this.imageId === void 0) {\n        this.imageId = allocateImageId();\n      }\n      const result = renderImage(this.base64Data, this.dimensions, {\n        maxWidthCells: maxWidth,\n        maxHeightCells: maxHeight,\n        imageId: this.imageId,\n        moveCursor: false\n      });\n      if (result) {\n        if (result.imageId) {\n          this.imageId = result.imageId;\n        }\n        if (caps.images === \"kitty\") {\n          lines = [result.sequence];\n          for (let i = 0; i < result.rows - 1; i++) {\n            lines.push(\"\");\n          }\n        } else {\n          lines = [];\n          for (let i = 0; i < result.rows - 1; i++) {\n            lines.push(\"\");\n          }\n          const rowOffset = result.rows - 1;\n          const moveUp = rowOffset > 0 ? `\\x1B[${rowOffset}A` : \"\";\n          lines.push(moveUp + result.sequence);\n        }\n      } else {\n        const fallback = imageFallback(this.mimeType, this.dimensions, this.options.filename);\n        lines = [truncateToWidth(this.theme.fallbackColor(fallback), width)];\n      }\n    } else {\n      const fallback = imageFallback(this.mimeType, this.dimensions, this.options.filename);\n      lines = [truncateToWidth(this.theme.fallbackColor(fallback), width)];\n    }\n    this.cachedLines = lines;\n    this.cachedWidth = width;\n    return lines;\n  }\n};\n\n// node_modules/.pnpm/@earendil-works+pi-tui@0.84.2/node_modules/@earendil-works/pi-tui/dist/components/input.js\nvar segmenter = getGraphemeSegmenter();\nvar Input = class {\n  value = \"\";\n  cursor = 0;\n  // Cursor position in the value\n  onSubmit;\n  onEscape;\n  /** Focusable interface - set by TUI when focus changes */\n  focused = false;\n  // Bracketed paste mode buffering\n  pasteBuffer = \"\";\n  isInPaste = false;\n  // Kill ring for Emacs-style kill/yank operations\n  killRing = new KillRing();\n  lastAction = null;\n  // Undo support\n  undoStack = new UndoStack();\n  getValue() {\n    return this.value;\n  }\n  setValue(value) {\n    this.value = value;\n    this.cursor = Math.min(this.cursor, value.length);\n  }\n  handleInput(data) {\n    if (data.includes(\"\\x1B[200~\")) {\n      this.isInPaste = true;\n      this.pasteBuffer = \"\";\n      data = data.replace(\"\\x1B[200~\", \"\");\n    }\n    if (this.isInPaste) {\n      this.pasteBuffer += data;\n      const endIndex = this.pasteBuffer.indexOf(\"\\x1B[201~\");\n      if (endIndex !== -1) {\n        const pasteContent = this.pasteBuffer.substring(0, endIndex);\n        this.handlePaste(pasteContent);\n        this.isInPaste = false;\n        const remaining = this.pasteBuffer.substring(endIndex + 6);\n        this.pasteBuffer = \"\";\n        if (remaining) {\n          this.handleInput(remaining);\n        }\n      }\n      return;\n    }\n    const kb = getKeybindings();\n    if (kb.matches(data, \"tui.select.cancel\")) {\n      if (this.onEscape)\n        this.onEscape();\n      return;\n    }\n    if (kb.matches(data, \"tui.editor.undo\")) {\n      this.undo();\n      return;\n    }\n    if (kb.matches(data, \"tui.input.submit\") || data === \"\\n\") {\n      if (this.onSubmit)\n        this.onSubmit(this.value);\n      return;\n    }\n    if (kb.matches(data, \"tui.editor.deleteCharBackward\")) {\n      this.handleBackspace();\n      return;\n    }\n    if (kb.matches(data, \"tui.editor.deleteCharForward\")) {\n      this.handleForwardDelete();\n      return;\n    }\n    if (kb.matches(data, \"tui.editor.deleteWordBackward\")) {\n      this.deleteWordBackwards();\n      return;\n    }\n    if (kb.matches(data, \"tui.editor.deleteWordForward\")) {\n      this.deleteWordForward();\n      return;\n    }\n    if (kb.matches(data, \"tui.editor.deleteToLineStart\")) {\n      this.deleteToLineStart();\n      return;\n    }\n    if (kb.matches(data, \"tui.editor.deleteToLineEnd\")) {\n      this.deleteToLineEnd();\n      return;\n    }\n    if (kb.matches(data, \"tui.editor.yank\")) {\n      this.yank();\n      return;\n    }\n    if (kb.matches(data, \"tui.editor.yankPop\")) {\n      this.yankPop();\n      return;\n    }\n    if (kb.matches(data, \"tui.editor.cursorLeft\")) {\n      this.lastAction = null;\n      if (this.cursor > 0) {\n        const beforeCursor = this.value.slice(0, this.cursor);\n        const graphemes = [...segmenter.segment(beforeCursor)];\n        const lastGrapheme = graphemes[graphemes.length - 1];\n        this.cursor -= lastGrapheme ? lastGrapheme.segment.length : 1;\n      }\n      return;\n    }\n    if (kb.matches(data, \"tui.editor.cursorRight\")) {\n      this.lastAction = null;\n      if (this.cursor < this.value.length) {\n        const afterCursor = this.value.slice(this.cursor);\n        const graphemes = [...segmenter.segment(afterCursor)];\n        const firstGrapheme = graphemes[0];\n        this.cursor += firstGrapheme ? firstGrapheme.segment.length : 1;\n      }\n      return;\n    }\n    if (kb.matches(data, \"tui.editor.cursorLineStart\")) {\n      this.lastAction = null;\n      this.cursor = 0;\n      return;\n    }\n    if (kb.matches(data, \"tui.editor.cursorLineEnd\")) {\n      this.lastAction = null;\n      this.cursor = this.value.length;\n      return;\n    }\n    if (kb.matches(data, \"tui.editor.cursorWordLeft\")) {\n      this.moveWordBackwards();\n      return;\n    }\n    if (kb.matches(data, \"tui.editor.cursorWordRight\")) {\n      this.moveWordForwards();\n      return;\n    }\n    const kittyPrintable = decodeKittyPrintable(data);\n    if (kittyPrintable !== void 0) {\n      this.insertCharacter(kittyPrintable);\n      return;\n    }\n    const hasControlChars = [...data].some((ch) => {\n      const code = ch.charCodeAt(0);\n      return code < 32 || code === 127 || code >= 128 && code <= 159;\n    });\n    if (!hasControlChars) {\n      this.insertCharacter(data);\n    }\n  }\n  insertCharacter(char) {\n    if (isWhitespaceChar(char) || this.lastAction !== \"type-word\") {\n      this.pushUndo();\n    }\n    this.lastAction = \"type-word\";\n    this.value = this.value.slice(0, this.cursor) + char + this.value.slice(this.cursor);\n    this.cursor += char.length;\n  }\n  handleBackspace() {\n    this.lastAction = null;\n    if (this.cursor > 0) {\n      this.pushUndo();\n      const beforeCursor = this.value.slice(0, this.cursor);\n      const graphemes = [...segmenter.segment(beforeCursor)];\n      const lastGrapheme = graphemes[graphemes.length - 1];\n      const graphemeLength = lastGrapheme ? lastGrapheme.segment.length : 1;\n      this.value = this.value.slice(0, this.cursor - graphemeLength) + this.value.slice(this.cursor);\n      this.cursor -= graphemeLength;\n    }\n  }\n  handleForwardDelete() {\n    this.lastAction = null;\n    if (this.cursor < this.value.length) {\n      this.pushUndo();\n      const afterCursor = this.value.slice(this.cursor);\n      const graphemes = [...segmenter.segment(afterCursor)];\n      const firstGrapheme = graphemes[0];\n      const graphemeLength = firstGrapheme ? firstGrapheme.segment.length : 1;\n      this.value = this.value.slice(0, this.cursor) + this.value.slice(this.cursor + graphemeLength);\n    }\n  }\n  deleteToLineStart() {\n    if (this.cursor === 0)\n      return;\n    this.pushUndo();\n    const deletedText = this.value.slice(0, this.cursor);\n    this.killRing.push(deletedText, { prepend: true, accumulate: this.lastAction === \"kill\" });\n    this.lastAction = \"kill\";\n    this.value = this.value.slice(this.cursor);\n    this.cursor = 0;\n  }\n  deleteToLineEnd() {\n    if (this.cursor >= this.value.length)\n      return;\n    this.pushUndo();\n    const deletedText = this.value.slice(this.cursor);\n    this.killRing.push(deletedText, { prepend: false, accumulate: this.lastAction === \"kill\" });\n    this.lastAction = \"kill\";\n    this.value = this.value.slice(0, this.cursor);\n  }\n  deleteWordBackwards() {\n    if (this.cursor === 0)\n      return;\n    const wasKill = this.lastAction === \"kill\";\n    this.pushUndo();\n    const oldCursor = this.cursor;\n    this.moveWordBackwards();\n    const deleteFrom = this.cursor;\n    this.cursor = oldCursor;\n    const deletedText = this.value.slice(deleteFrom, this.cursor);\n    this.killRing.push(deletedText, { prepend: true, accumulate: wasKill });\n    this.lastAction = \"kill\";\n    this.value = this.value.slice(0, deleteFrom) + this.value.slice(this.cursor);\n    this.cursor = deleteFrom;\n  }\n  deleteWordForward() {\n    if (this.cursor >= this.value.length)\n      return;\n    const wasKill = this.lastAction === \"kill\";\n    this.pushUndo();\n    const oldCursor = this.cursor;\n    this.moveWordForwards();\n    const deleteTo = this.cursor;\n    this.cursor = oldCursor;\n    const deletedText = this.value.slice(this.cursor, deleteTo);\n    this.killRing.push(deletedText, { prepend: false, accumulate: wasKill });\n    this.lastAction = \"kill\";\n    this.value = this.value.slice(0, this.cursor) + this.value.slice(deleteTo);\n  }\n  yank() {\n    const text = this.killRing.peek();\n    if (!text)\n      return;\n    this.pushUndo();\n    this.value = this.value.slice(0, this.cursor) + text + this.value.slice(this.cursor);\n    this.cursor += text.length;\n    this.lastAction = \"yank\";\n  }\n  yankPop() {\n    if (this.lastAction !== \"yank\" || this.killRing.length <= 1)\n      return;\n    this.pushUndo();\n    const prevText = this.killRing.peek() || \"\";\n    this.value = this.value.slice(0, this.cursor - prevText.length) + this.value.slice(this.cursor);\n    this.cursor -= prevText.length;\n    this.killRing.rotate();\n    const text = this.killRing.peek() || \"\";\n    this.value = this.value.slice(0, this.cursor) + text + this.value.slice(this.cursor);\n    this.cursor += text.length;\n    this.lastAction = \"yank\";\n  }\n  pushUndo() {\n    this.undoStack.push({ value: this.value, cursor: this.cursor });\n  }\n  undo() {\n    const snapshot = this.undoStack.pop();\n    if (!snapshot)\n      return;\n    this.value = snapshot.value;\n    this.cursor = snapshot.cursor;\n    this.lastAction = null;\n  }\n  moveWordBackwards() {\n    if (this.cursor === 0)\n      return;\n    this.lastAction = null;\n    this.cursor = findWordBackward(this.value, this.cursor);\n  }\n  moveWordForwards() {\n    if (this.cursor >= this.value.length)\n      return;\n    this.lastAction = null;\n    this.cursor = findWordForward(this.value, this.cursor);\n  }\n  handlePaste(pastedText) {\n    this.lastAction = null;\n    this.pushUndo();\n    const cleanText = pastedText.replace(/\\r\\n/g, \"\").replace(/\\r/g, \"\").replace(/\\n/g, \"\").replace(/\\t/g, \"    \");\n    this.value = this.value.slice(0, this.cursor) + cleanText + this.value.slice(this.cursor);\n    this.cursor += cleanText.length;\n  }\n  invalidate() {\n  }\n  render(width) {\n    const prompt = \"> \";\n    const availableWidth = width - prompt.length;\n    if (availableWidth <= 0) {\n      return [prompt];\n    }\n    let visibleText = \"\";\n    let cursorDisplay = this.cursor;\n    const totalWidth = visibleWidth(this.value);\n    if (totalWidth < availableWidth) {\n      visibleText = this.value;\n    } else {\n      const scrollWidth = this.cursor === this.value.length ? availableWidth - 1 : availableWidth;\n      const cursorCol = visibleWidth(this.value.slice(0, this.cursor));\n      if (scrollWidth > 0) {\n        const halfWidth = Math.floor(scrollWidth / 2);\n        let startCol = 0;\n        if (cursorCol < halfWidth) {\n          startCol = 0;\n        } else if (cursorCol > totalWidth - halfWidth) {\n          startCol = Math.max(0, totalWidth - scrollWidth);\n        } else {\n          startCol = Math.max(0, cursorCol - halfWidth);\n        }\n        visibleText = sliceByColumn(this.value, startCol, scrollWidth, true);\n        const beforeCursor2 = sliceByColumn(this.value, startCol, Math.max(0, cursorCol - startCol), true);\n        cursorDisplay = beforeCursor2.length;\n      } else {\n        visibleText = \"\";\n        cursorDisplay = 0;\n      }\n    }\n    const graphemes = [...segmenter.segment(visibleText.slice(cursorDisplay))];\n    const cursorGrapheme = graphemes[0];\n    const beforeCursor = visibleText.slice(0, cursorDisplay);\n    const atCursor = cursorGrapheme?.segment ?? \" \";\n    const afterCursor = visibleText.slice(cursorDisplay + atCursor.length);\n    const marker = this.focused ? CURSOR_MARKER : \"\";\n    const cursorChar = `\\x1B[7m${atCursor}\\x1B[27m`;\n    const textWithCursor = beforeCursor + marker + cursorChar + afterCursor;\n    const visualLength = visibleWidth(textWithCursor);\n    const padding = \" \".repeat(Math.max(0, availableWidth - visualLength));\n    const line = prompt + textWithCursor + padding;\n    return [line];\n  }\n};\n\n// node_modules/.pnpm/@earendil-works+pi-tui@0.84.2/node_modules/@earendil-works/pi-tui/dist/components/markdown.js\nimport { Marked, Tokenizer } from \"marked\";\n\n// node_modules/.pnpm/@earendil-works+pi-tui@0.84.2/node_modules/@earendil-works/pi-tui/dist/latex.js\nvar SYMBOLS = {\n  alpha: \"\\u03B1\",\n  beta: \"\\u03B2\",\n  gamma: \"\\u03B3\",\n  delta: \"\\u03B4\",\n  epsilon: \"\\u03F5\",\n  varepsilon: \"\\u03B5\",\n  zeta: \"\\u03B6\",\n  eta: \"\\u03B7\",\n  theta: \"\\u03B8\",\n  vartheta: \"\\u03D1\",\n  iota: \"\\u03B9\",\n  kappa: \"\\u03BA\",\n  varkappa: \"\\u03F0\",\n  lambda: \"\\u03BB\",\n  mu: \"\\u03BC\",\n  nu: \"\\u03BD\",\n  xi: \"\\u03BE\",\n  pi: \"\\u03C0\",\n  varpi: \"\\u03D6\",\n  rho: \"\\u03C1\",\n  varrho: \"\\u03F1\",\n  sigma: \"\\u03C3\",\n  varsigma: \"\\u03C2\",\n  tau: \"\\u03C4\",\n  upsilon: \"\\u03C5\",\n  phi: \"\\u03D5\",\n  varphi: \"\\u03C6\",\n  chi: \"\\u03C7\",\n  psi: \"\\u03C8\",\n  omega: \"\\u03C9\",\n  Gamma: \"\\u0393\",\n  Delta: \"\\u0394\",\n  Theta: \"\\u0398\",\n  Lambda: \"\\u039B\",\n  Xi: \"\\u039E\",\n  Pi: \"\\u03A0\",\n  Sigma: \"\\u03A3\",\n  Upsilon: \"\\u03A5\",\n  Phi: \"\\u03A6\",\n  Psi: \"\\u03A8\",\n  Omega: \"\\u03A9\",\n  pm: \"\\xB1\",\n  mp: \"\\u2213\",\n  times: \"\\xD7\",\n  div: \"\\xF7\",\n  cdot: \"\\xB7\",\n  ast: \"\\u2217\",\n  star: \"\\u22C6\",\n  circ: \"\\u2218\",\n  bullet: \"\\u2022\",\n  oplus: \"\\u2295\",\n  ominus: \"\\u2296\",\n  otimes: \"\\u2297\",\n  oslash: \"\\u2298\",\n  odot: \"\\u2299\",\n  bigcirc: \"\\u25CB\",\n  dagger: \"\\u2020\",\n  ddagger: \"\\u2021\",\n  amalg: \"\\u2A3F\",\n  uplus: \"\\u228E\",\n  sqcap: \"\\u2293\",\n  sqcup: \"\\u2294\",\n  triangleleft: \"\\u25C1\",\n  triangleright: \"\\u25B7\",\n  wr: \"\\u2240\",\n  cap: \"\\u2229\",\n  cup: \"\\u222A\",\n  bigcap: \"\\u22C2\",\n  bigcup: \"\\u22C3\",\n  bigwedge: \"\\u22C0\",\n  bigvee: \"\\u22C1\",\n  bigsqcup: \"\\u2A06\",\n  biguplus: \"\\u2A04\",\n  bigoplus: \"\\u2A01\",\n  bigotimes: \"\\u2A02\",\n  bigodot: \"\\u2A00\",\n  setminus: \"\\u2216\",\n  in: \"\\u2208\",\n  notin: \"\\u2209\",\n  ni: \"\\u220B\",\n  subset: \"\\u2282\",\n  supset: \"\\u2283\",\n  subseteq: \"\\u2286\",\n  supseteq: \"\\u2287\",\n  sqsubset: \"\\u228F\",\n  sqsupset: \"\\u2290\",\n  sqsubseteq: \"\\u2291\",\n  sqsupseteq: \"\\u2292\",\n  prec: \"\\u227A\",\n  preceq: \"\\u227C\",\n  succ: \"\\u227B\",\n  succeq: \"\\u227D\",\n  ll: \"\\u226A\",\n  gg: \"\\u226B\",\n  le: \"\\u2264\",\n  leq: \"\\u2264\",\n  leqslant: \"\\u2264\",\n  ge: \"\\u2265\",\n  geq: \"\\u2265\",\n  geqslant: \"\\u2265\",\n  ne: \"\\u2260\",\n  neq: \"\\u2260\",\n  equiv: \"\\u2261\",\n  approx: \"\\u2248\",\n  sim: \"\\u223C\",\n  simeq: \"\\u2243\",\n  cong: \"\\u2245\",\n  asymp: \"\\u224D\",\n  doteq: \"\\u2250\",\n  propto: \"\\u221D\",\n  parallel: \"\\u2225\",\n  perp: \"\\u22A5\",\n  mid: \"\\u2223\",\n  vdash: \"\\u22A2\",\n  dashv: \"\\u22A3\",\n  models: \"\\u22A8\",\n  Vdash: \"\\u22A9\",\n  Vvdash: \"\\u22AA\",\n  nvdash: \"\\u22AC\",\n  nvDash: \"\\u22AD\",\n  forall: \"\\u2200\",\n  exists: \"\\u2203\",\n  nexists: \"\\u2204\",\n  neg: \"\\xAC\",\n  land: \"\\u2227\",\n  wedge: \"\\u2227\",\n  lor: \"\\u2228\",\n  vee: \"\\u2228\",\n  to: \"\\u2192\",\n  rightarrow: \"\\u2192\",\n  longrightarrow: \"\\u2192\",\n  leftarrow: \"\\u2190\",\n  longleftarrow: \"\\u2190\",\n  gets: \"\\u2190\",\n  leftrightarrow: \"\\u2194\",\n  longleftrightarrow: \"\\u2194\",\n  hookleftarrow: \"\\u21A9\",\n  hookrightarrow: \"\\u21AA\",\n  twoheadleftarrow: \"\\u219E\",\n  twoheadrightarrow: \"\\u21A0\",\n  leftharpoonup: \"\\u21BC\",\n  leftharpoondown: \"\\u21BD\",\n  rightharpoonup: \"\\u21C0\",\n  rightharpoondown: \"\\u21C1\",\n  rightleftharpoons: \"\\u21CC\",\n  leftrightharpoons: \"\\u21CB\",\n  nearrow: \"\\u2197\",\n  searrow: \"\\u2198\",\n  swarrow: \"\\u2199\",\n  nwarrow: \"\\u2196\",\n  rightsquigarrow: \"\\u21DD\",\n  leadsto: \"\\u21DD\",\n  Rightarrow: \"\\u21D2\",\n  Longrightarrow: \"\\u21D2\",\n  Leftarrow: \"\\u21D0\",\n  Longleftarrow: \"\\u21D0\",\n  Leftrightarrow: \"\\u21D4\",\n  Longleftrightarrow: \"\\u21D4\",\n  implies: \"\\u21D2\",\n  iff: \"\\u21D4\",\n  mapsto: \"\\u21A6\",\n  longmapsto: \"\\u21A6\",\n  uparrow: \"\\u2191\",\n  downarrow: \"\\u2193\",\n  partial: \"\\u2202\",\n  nabla: \"\\u2207\",\n  int: \"\\u222B\",\n  iint: \"\\u222C\",\n  iiint: \"\\u222D\",\n  oint: \"\\u222E\",\n  sum: \"\\u2211\",\n  prod: \"\\u220F\",\n  coprod: \"\\u2210\",\n  infty: \"\\u221E\",\n  emptyset: \"\\u2205\",\n  varnothing: \"\\u2205\",\n  angle: \"\\u2220\",\n  therefore: \"\\u2234\",\n  because: \"\\u2235\",\n  aleph: \"\\u2135\",\n  beth: \"\\u2136\",\n  gimel: \"\\u2137\",\n  daleth: \"\\u2138\",\n  top: \"\\u22A4\",\n  bot: \"\\u22A5\",\n  triangle: \"\\u25B3\",\n  square: \"\\u25A1\",\n  lozenge: \"\\u25CA\",\n  checkmark: \"\\u2713\",\n  complement: \"\\u2201\",\n  wp: \"\\u2118\",\n  prime: \"\\u2032\",\n  ldots: \"\\u2026\",\n  dots: \"\\u2026\",\n  cdots: \"\\u22EF\",\n  vdots: \"\\u22EE\",\n  ddots: \"\\u22F1\",\n  ell: \"\\u2113\",\n  hbar: \"\\u210F\",\n  Im: \"\\u2111\",\n  Re: \"\\u211C\",\n  langle: \"\\u27E8\",\n  rangle: \"\\u27E9\",\n  vert: \"|\",\n  lvert: \"|\",\n  rvert: \"|\",\n  Vert: \"\\u2016\",\n  lVert: \"\\u2016\",\n  rVert: \"\\u2016\",\n  lbrace: \"{\",\n  rbrace: \"}\",\n  backslash: \"\\\\\",\n  lfloor: \"\\u230A\",\n  rfloor: \"\\u230B\",\n  lceil: \"\\u2308\",\n  rceil: \"\\u2309\",\n  colon: \":\"\n};\nvar NAMED_OPERATORS = /* @__PURE__ */ new Set([\n  \"arccos\",\n  \"arcsin\",\n  \"arctan\",\n  \"arg\",\n  \"cos\",\n  \"cosh\",\n  \"cot\",\n  \"coth\",\n  \"csc\",\n  \"deg\",\n  \"det\",\n  \"dim\",\n  \"exp\",\n  \"gcd\",\n  \"hom\",\n  \"inf\",\n  \"ker\",\n  \"lg\",\n  \"lim\",\n  \"liminf\",\n  \"limsup\",\n  \"ln\",\n  \"log\",\n  \"max\",\n  \"min\",\n  \"Pr\",\n  \"sec\",\n  \"sin\",\n  \"sinh\",\n  \"sup\",\n  \"tan\",\n  \"tanh\"\n]);\nvar LIMIT_OPERATORS = /* @__PURE__ */ new Set([\n  \"argmax\",\n  \"argmin\",\n  \"inf\",\n  \"injlim\",\n  \"lim\",\n  \"liminf\",\n  \"limsup\",\n  \"max\",\n  \"min\",\n  \"projlim\",\n  \"sup\"\n]);\nvar DISPLAY_LIMIT_SYMBOLS = /* @__PURE__ */ new Set([\n  \"bigcap\",\n  \"bigcup\",\n  \"bigodot\",\n  \"bigoplus\",\n  \"bigotimes\",\n  \"bigsqcup\",\n  \"biguplus\",\n  \"bigvee\",\n  \"bigwedge\",\n  \"coprod\",\n  \"int\",\n  \"iint\",\n  \"iiint\",\n  \"oint\",\n  \"prod\",\n  \"sum\"\n]);\nvar RELATION_COMMANDS = /* @__PURE__ */ new Set([\n  \"Leftarrow\",\n  \"Leftrightarrow\",\n  \"Longleftarrow\",\n  \"Longleftrightarrow\",\n  \"Longrightarrow\",\n  \"Rightarrow\",\n  \"Vdash\",\n  \"Vvdash\",\n  \"approx\",\n  \"asymp\",\n  \"cong\",\n  \"dashv\",\n  \"doteq\",\n  \"downarrow\",\n  \"equiv\",\n  \"ge\",\n  \"geq\",\n  \"geqslant\",\n  \"gets\",\n  \"gg\",\n  \"hookleftarrow\",\n  \"hookrightarrow\",\n  \"iff\",\n  \"implies\",\n  \"in\",\n  \"leadsto\",\n  \"le\",\n  \"leftarrow\",\n  \"leftharpoondown\",\n  \"leftharpoonup\",\n  \"leftrightarrow\",\n  \"leftrightharpoons\",\n  \"leq\",\n  \"leqslant\",\n  \"ll\",\n  \"longleftarrow\",\n  \"longleftrightarrow\",\n  \"longmapsto\",\n  \"longrightarrow\",\n  \"mapsto\",\n  \"mid\",\n  \"models\",\n  \"ne\",\n  \"nearrow\",\n  \"neq\",\n  \"ni\",\n  \"notin\",\n  \"nvdash\",\n  \"nvDash\",\n  \"nwarrow\",\n  \"parallel\",\n  \"perp\",\n  \"prec\",\n  \"preceq\",\n  \"propto\",\n  \"rightharpoondown\",\n  \"rightharpoonup\",\n  \"rightleftharpoons\",\n  \"rightarrow\",\n  \"rightsquigarrow\",\n  \"searrow\",\n  \"sim\",\n  \"simeq\",\n  \"sqsubset\",\n  \"sqsubseteq\",\n  \"sqsupset\",\n  \"sqsupseteq\",\n  \"subset\",\n  \"subseteq\",\n  \"succ\",\n  \"succeq\",\n  \"supset\",\n  \"supseteq\",\n  \"swarrow\",\n  \"to\",\n  \"triangleleft\",\n  \"triangleright\",\n  \"twoheadleftarrow\",\n  \"twoheadrightarrow\",\n  \"uparrow\",\n  \"vdash\"\n]);\nvar NEGATED_SYMBOLS = {\n  \"<\": \"\\u226E\",\n  \">\": \"\\u226F\",\n  \"=\": \"\\u2260\",\n  \"\\u2208\": \"\\u2209\",\n  \"\\u220B\": \"\\u220C\",\n  \"\\u2223\": \"\\u2224\",\n  \"\\u2225\": \"\\u2226\",\n  \"\\u223C\": \"\\u2241\",\n  \"\\u2243\": \"\\u2244\",\n  \"\\u2245\": \"\\u2247\",\n  \"\\u2248\": \"\\u2249\",\n  \"\\u2261\": \"\\u2262\",\n  \"\\u2264\": \"\\u2270\",\n  \"\\u2265\": \"\\u2271\",\n  \"\\u227A\": \"\\u2280\",\n  \"\\u227B\": \"\\u2281\",\n  \"\\u2282\": \"\\u2284\",\n  \"\\u2283\": \"\\u2285\",\n  \"\\u2286\": \"\\u2288\",\n  \"\\u2287\": \"\\u2289\",\n  \"\\u22A2\": \"\\u22AC\",\n  \"\\u22A8\": \"\\u22AD\",\n  \"\\u2194\": \"\\u21AE\",\n  \"\\u2190\": \"\\u219A\",\n  \"\\u2192\": \"\\u219B\",\n  \"\\u21D2\": \"\\u21CF\",\n  \"\\u21D0\": \"\\u21CD\",\n  \"\\u21D4\": \"\\u21CE\",\n  \"\\u227C\": \"\\u22E0\",\n  \"\\u227D\": \"\\u22E1\"\n};\nvar BLACKBOARD = {\n  C: \"\\u2102\",\n  H: \"\\u210D\",\n  N: \"\\u2115\",\n  P: \"\\u2119\",\n  Q: \"\\u211A\",\n  R: \"\\u211D\",\n  Z: \"\\u2124\"\n};\nvar SUPERSCRIPTS = {\n  \"0\": \"\\u2070\",\n  \"1\": \"\\xB9\",\n  \"2\": \"\\xB2\",\n  \"3\": \"\\xB3\",\n  \"4\": \"\\u2074\",\n  \"5\": \"\\u2075\",\n  \"6\": \"\\u2076\",\n  \"7\": \"\\u2077\",\n  \"8\": \"\\u2078\",\n  \"9\": \"\\u2079\",\n  \"+\": \"\\u207A\",\n  \"-\": \"\\u207B\",\n  \"=\": \"\\u207C\",\n  \"(\": \"\\u207D\",\n  \")\": \"\\u207E\",\n  a: \"\\u1D43\",\n  b: \"\\u1D47\",\n  c: \"\\u1D9C\",\n  d: \"\\u1D48\",\n  e: \"\\u1D49\",\n  f: \"\\u1DA0\",\n  g: \"\\u1D4D\",\n  h: \"\\u02B0\",\n  i: \"\\u2071\",\n  j: \"\\u02B2\",\n  k: \"\\u1D4F\",\n  l: \"\\u02E1\",\n  m: \"\\u1D50\",\n  n: \"\\u207F\",\n  o: \"\\u1D52\",\n  p: \"\\u1D56\",\n  r: \"\\u02B3\",\n  s: \"\\u02E2\",\n  t: \"\\u1D57\",\n  u: \"\\u1D58\",\n  v: \"\\u1D5B\",\n  w: \"\\u02B7\",\n  x: \"\\u02E3\",\n  y: \"\\u02B8\",\n  z: \"\\u1DBB\"\n};\nvar SUBSCRIPTS = {\n  \"0\": \"\\u2080\",\n  \"1\": \"\\u2081\",\n  \"2\": \"\\u2082\",\n  \"3\": \"\\u2083\",\n  \"4\": \"\\u2084\",\n  \"5\": \"\\u2085\",\n  \"6\": \"\\u2086\",\n  \"7\": \"\\u2087\",\n  \"8\": \"\\u2088\",\n  \"9\": \"\\u2089\",\n  \"+\": \"\\u208A\",\n  \"-\": \"\\u208B\",\n  \"=\": \"\\u208C\",\n  \"(\": \"\\u208D\",\n  \")\": \"\\u208E\",\n  a: \"\\u2090\",\n  e: \"\\u2091\",\n  h: \"\\u2095\",\n  i: \"\\u1D62\",\n  j: \"\\u2C7C\",\n  k: \"\\u2096\",\n  l: \"\\u2097\",\n  m: \"\\u2098\",\n  n: \"\\u2099\",\n  o: \"\\u2092\",\n  p: \"\\u209A\",\n  r: \"\\u1D63\",\n  s: \"\\u209B\",\n  t: \"\\u209C\",\n  u: \"\\u1D64\",\n  v: \"\\u1D65\",\n  x: \"\\u2093\"\n};\nvar SPACING_COMMANDS = /* @__PURE__ */ new Set([\n  \",\",\n  \":\",\n  \";\",\n  \" \",\n  \">\",\n  \"enspace\",\n  \"enskip\",\n  \"medspace\",\n  \"quad\",\n  \"qquad\",\n  \"thickspace\",\n  \"thinspace\"\n]);\nvar NEGATIVE_SPACING_COMMANDS = /* @__PURE__ */ new Set([\"!\", \"negmedspace\", \"negthickspace\", \"negthinspace\"]);\nvar NEGATIVE_SPACE = \"\\0\";\nvar IGNORED_COMMANDS = /* @__PURE__ */ new Set([\n  \"displaystyle\",\n  \"limits\",\n  \"nolimits\",\n  \"scriptstyle\",\n  \"scriptscriptstyle\",\n  \"textstyle\"\n]);\nvar SIZE_COMMANDS = /* @__PURE__ */ new Set([\n  \"big\",\n  \"Big\",\n  \"bigg\",\n  \"Bigg\",\n  \"bigl\",\n  \"Bigl\",\n  \"biggl\",\n  \"Biggl\",\n  \"bigr\",\n  \"Bigr\",\n  \"biggr\",\n  \"Biggr\"\n]);\nvar PLAIN_WRAPPERS = /* @__PURE__ */ new Set([\n  \"emph\",\n  \"mathcal\",\n  \"mathbf\",\n  \"mathfrak\",\n  \"mathit\",\n  \"mathrm\",\n  \"mathnormal\",\n  \"mathscr\",\n  \"mathsf\",\n  \"mathtt\",\n  \"mathup\",\n  \"mbox\",\n  \"overbrace\",\n  \"pmb\",\n  \"smash\",\n  \"substack\",\n  \"text\",\n  \"textbf\",\n  \"textit\",\n  \"textmd\",\n  \"textnormal\",\n  \"textrm\",\n  \"textsc\",\n  \"textsf\",\n  \"textsl\",\n  \"texttt\",\n  \"textup\",\n  \"underbrace\",\n  \"bm\",\n  \"boldsymbol\"\n]);\nvar ACCENTS = {\n  acute: \"\\u0301\",\n  bar: \"\\u0305\",\n  breve: \"\\u0306\",\n  check: \"\\u030C\",\n  ddot: \"\\u0308\",\n  dot: \"\\u0307\",\n  grave: \"\\u0300\",\n  hat: \"\\u0302\",\n  mathring: \"\\u030A\",\n  overleftarrow: \"\\u20D6\",\n  overleftrightarrow: \"\\u20E1\",\n  overline: \"\\u0305\",\n  overrightarrow: \"\\u20D7\",\n  tilde: \"\\u0303\",\n  underline: \"\\u0332\",\n  vec: \"\\u20D7\",\n  widehat: \"\\u0302\",\n  widetilde: \"\\u0303\"\n};\nfunction replaceCharacters(value, replacements) {\n  let result = \"\";\n  for (const character of value) {\n    const replacement = replacements[character];\n    if (replacement === void 0) {\n      return void 0;\n    }\n    result += replacement;\n  }\n  return result;\n}\nfunction formatScript(value, kind) {\n  value = value.trim();\n  const replacements = kind === \"sub\" ? SUBSCRIPTS : SUPERSCRIPTS;\n  const unicode = replaceCharacters(value.replace(/\\s*([=+-])\\s*/g, \"$1\"), replacements);\n  if (unicode !== void 0) {\n    return unicode;\n  }\n  const prefix = kind === \"sub\" ? \"_\" : \"^\";\n  if (Array.from(value).length === 1 || kind === \"sub\" && /^[A-Za-z]+$/.test(value)) {\n    return `${prefix}${value}`;\n  }\n  return `${prefix}(${value})`;\n}\nfunction formatFraction(numerator, denominator) {\n  numerator = numerator.trim();\n  denominator = denominator.trim();\n  const simpleNumerator = /^[\\p{L}\\p{N}.]+$/u.test(numerator);\n  const simpleDenominator = /^[\\p{N}.]+$/u.test(denominator) || Array.from(denominator).length === 1;\n  return `${simpleNumerator ? numerator : `(${numerator})`}/${simpleDenominator ? denominator : `(${denominator})`}`;\n}\nfunction formatRoot(value, symbol = \"\\u221A\") {\n  value = value.trim();\n  return /^[\\p{L}\\p{N}.]+$/u.test(value) ? `${symbol}${value}` : `${symbol}(${value})`;\n}\nvar NAMED_OPERATOR_START = \"\\u{F0004}\";\nvar NAMED_OPERATOR_END = \"\\u{F0005}\";\nvar NAMED_OPERATOR_LEFT_SPACING_PATTERN = /(?<=[\\p{L}\\p{N})\\]}\\u{f0001}])\\u{f0004}/gu;\nvar NAMED_OPERATOR_RIGHT_SPACING_PATTERN = /\\u{f0005}(?=[\\p{L}\\p{N}√\\u{f0000}])/gu;\nfunction normalizeOutput(value) {\n  return value.replace(NAMED_OPERATOR_LEFT_SPACING_PATTERN, \" \").replaceAll(NAMED_OPERATOR_START, \"\").replace(NAMED_OPERATOR_RIGHT_SPACING_PATTERN, \" \").replaceAll(NAMED_OPERATOR_END, \"\").split(\"\\n\").map((line) => line.replace(/[ \\t]+/g, \" \").trim()).filter((line, index, lines) => line.length > 0 || index > 0 && index < lines.length - 1).join(\"\\n\").trim();\n}\nvar LAYOUT_MARKER_START = \"\\u{F0000}\";\nvar LAYOUT_MARKER_END = \"\\u{F0001}\";\nvar LAYOUT_MARKER_PATTERN = /\\u{f0000}(\\d+)\\u{f0001}/gu;\nvar TRAILING_LAYOUT_MARKER_PATTERN = /\\u{f0000}(\\d+)\\u{f0001}$/u;\nvar PROTECTED_SPACE = \"\\u{F0002}\";\nfunction padLayoutLine(line, width, centered = false) {\n  const padding = Math.max(0, width - visibleWidth(line));\n  const left = centered ? Math.floor(padding / 2) : 0;\n  return `${\" \".repeat(left)}${line}${\" \".repeat(padding - left)}`;\n}\nfunction joinLayouts(layouts) {\n  if (layouts.length === 0) {\n    return { lines: [\"\"], width: 0, baseline: 0 };\n  }\n  const baseline = Math.max(...layouts.map((layout) => layout.baseline));\n  const below = Math.max(...layouts.map((layout) => layout.lines.length - layout.baseline - 1));\n  const lines = [];\n  for (let row = 0; row <= baseline + below; row++) {\n    let line = \"\";\n    for (const layout of layouts) {\n      const sourceRow = row - baseline + layout.baseline;\n      line += sourceRow >= 0 && sourceRow < layout.lines.length ? padLayoutLine(layout.lines[sourceRow] ?? \"\", layout.width) : \" \".repeat(layout.width);\n    }\n    lines.push(line.trimEnd());\n  }\n  return {\n    lines,\n    width: layouts.reduce((width, layout) => width + layout.width, 0),\n    baseline\n  };\n}\nfunction renderLayout(source, nodes) {\n  const renderedLines = [];\n  let firstBaseline = 0;\n  for (const sourceLine of source.split(\"\\n\")) {\n    const layouts = [];\n    let position = 0;\n    let previousNode;\n    for (const match of sourceLine.matchAll(LAYOUT_MARKER_PATTERN)) {\n      const index = match.index;\n      const node = nodes[Number(match[1])];\n      if (!node) {\n        continue;\n      }\n      if (index > position) {\n        const sliced = sourceLine.slice(position, index);\n        const trimmed = (previousNode ? sliced.trimStart() : sliced).trimEnd();\n        const preserveLeadingSpace = previousNode?.type === \"matrix\" && /^\\s/.test(sliced);\n        const preserveTrailingSpace = node.type === \"matrix\" && /\\s$/.test(sliced);\n        const text = trimmed ? `${preserveLeadingSpace ? \" \" : \"\"}${trimmed}${preserveTrailingSpace ? \" \" : \"\"}` : preserveLeadingSpace || preserveTrailingSpace ? \" \" : \"\";\n        layouts.push({ lines: [text], width: visibleWidth(text), baseline: 0 });\n      }\n      if (node.type === \"fraction\") {\n        const numerator = renderLayout(node.numerator, nodes);\n        const denominator = renderLayout(node.denominator, nodes);\n        const contentWidth = Math.max(numerator.width, denominator.width, 1);\n        const width = contentWidth + 2;\n        layouts.push({\n          lines: [\n            ...numerator.lines.map((line) => padLayoutLine(line, width, true)),\n            ` ${\"\\u2500\".repeat(contentWidth)} `,\n            ...denominator.lines.map((line) => padLayoutLine(line, width, true))\n          ],\n          width,\n          baseline: numerator.lines.length\n        });\n      } else if (node.type === \"operator\") {\n        const contentWidth = Math.max(visibleWidth(node.operator), node.lower === void 0 ? 0 : visibleWidth(node.lower), node.upper === void 0 ? 0 : visibleWidth(node.upper));\n        const lines = [];\n        if (node.upper !== void 0) {\n          lines.push(`${padLayoutLine(node.upper, contentWidth, true)} `);\n        }\n        lines.push(`${padLayoutLine(node.operator, contentWidth, true)} `);\n        if (node.lower !== void 0) {\n          lines.push(`${padLayoutLine(node.lower, contentWidth, true)} `);\n        }\n        layouts.push({\n          lines,\n          width: contentWidth + 1,\n          baseline: node.upper === void 0 ? 0 : 1\n        });\n      } else {\n        const width = Math.max(0, ...node.lines.map((line) => visibleWidth(line)));\n        layouts.push({\n          lines: node.lines.map((line) => padLayoutLine(line, width)),\n          width,\n          baseline: node.baseline\n        });\n      }\n      position = index + match[0].length;\n      previousNode = node;\n    }\n    if (position < sourceLine.length) {\n      const sliced = sourceLine.slice(position);\n      const trimmed = previousNode ? sliced.trimStart() : sliced;\n      const text = previousNode?.type === \"matrix\" && /^\\s/.test(sliced) ? ` ${trimmed}` : trimmed;\n      layouts.push({ lines: [text], width: visibleWidth(text), baseline: 0 });\n    }\n    const lineLayout = joinLayouts(layouts);\n    if (renderedLines.length === 0) {\n      firstBaseline = lineLayout.baseline;\n    }\n    renderedLines.push(...lineLayout.lines);\n  }\n  return {\n    lines: renderedLines,\n    width: Math.max(0, ...renderedLines.map((line) => visibleWidth(line))),\n    baseline: firstBaseline\n  };\n}\nvar LatexParser = class _LatexParser {\n  source;\n  layoutNodes;\n  display;\n  position = 0;\n  supported = true;\n  stackFractions = true;\n  constructor(source, layoutNodes, display) {\n    this.source = source;\n    this.layoutNodes = layoutNodes;\n    this.display = display;\n  }\n  render() {\n    const rendered = this.parseSequence();\n    if (!this.supported || this.position !== this.source.length) {\n      return void 0;\n    }\n    return normalizeOutput(rendered);\n  }\n  parseSequence(endCharacter) {\n    let result = \"\";\n    while (this.position < this.source.length) {\n      const character = this.source[this.position];\n      if (endCharacter && character === endCharacter) {\n        this.position++;\n        return result;\n      }\n      if (character === \"}\") {\n        this.supported = false;\n        return result;\n      }\n      if (character === \"{\") {\n        this.position++;\n        result += this.parseSequence(\"}\");\n        continue;\n      }\n      if (character === \"\\\\\") {\n        const command = this.parseCommand();\n        if (command === NEGATIVE_SPACE) {\n          result = result.trimEnd();\n          if (result.endsWith(NAMED_OPERATOR_END)) {\n            result = result.slice(0, -NAMED_OPERATOR_END.length);\n          }\n        } else {\n          result += command;\n        }\n        continue;\n      }\n      if (character === \"^\" || character === \"_\") {\n        this.position++;\n        result = result.trimEnd();\n        const script = formatScript(this.parseRequiredArgument(false), character === \"_\" ? \"sub\" : \"sup\");\n        if (result.endsWith(NAMED_OPERATOR_END)) {\n          result = `${result.slice(0, -NAMED_OPERATOR_END.length)}${script}${NAMED_OPERATOR_END}`;\n        } else {\n          result += script;\n        }\n        continue;\n      }\n      if (/\\s/.test(character)) {\n        result += this.parseWhitespace();\n        continue;\n      }\n      if (character === \"=\" || character === \"<\" || character === \">\") {\n        result = `${result.trimEnd()} ${character} `;\n        this.position++;\n        continue;\n      }\n      if (character === \"&\") {\n        this.position++;\n        continue;\n      }\n      if (character === \"~\") {\n        this.position++;\n        result += \" \";\n        continue;\n      }\n      if (character === \".\") {\n        const marker = TRAILING_LAYOUT_MARKER_PATTERN.exec(result);\n        const node = marker ? this.layoutNodes[Number(marker[1])] : void 0;\n        if (node?.type === \"matrix\") {\n          const lastLine = node.lines.length - 1;\n          node.lines[lastLine] = `${node.lines[lastLine] ?? \"\"}${character}`;\n          this.position++;\n          continue;\n        }\n      }\n      result += character;\n      this.position++;\n    }\n    if (endCharacter) {\n      this.supported = false;\n    }\n    return result;\n  }\n  parseWhitespace() {\n    while (this.position < this.source.length && /\\s/.test(this.source[this.position] ?? \"\")) {\n      this.position++;\n    }\n    return \" \";\n  }\n  parseCommand() {\n    this.position++;\n    if (this.position >= this.source.length) {\n      this.supported = false;\n      return \"\";\n    }\n    let command = \"\";\n    const first = this.source[this.position] ?? \"\";\n    if (first === \"\\n\" || first === \"\\r\") {\n      this.position++;\n      if (first === \"\\r\" && this.source[this.position] === \"\\n\") {\n        this.position++;\n      }\n      return \" \";\n    }\n    if (/[A-Za-z]/.test(first)) {\n      const start = this.position;\n      while (this.position < this.source.length && /[A-Za-z]/.test(this.source[this.position] ?? \"\")) {\n        this.position++;\n      }\n      command = this.source.slice(start, this.position);\n    } else {\n      command = first;\n      this.position++;\n    }\n    if (command === \"\\\\\") {\n      return \"\\n\";\n    }\n    if (SPACING_COMMANDS.has(command)) {\n      return \" \";\n    }\n    if (NEGATIVE_SPACING_COMMANDS.has(command)) {\n      return NEGATIVE_SPACE;\n    }\n    if (IGNORED_COMMANDS.has(command)) {\n      return \"\";\n    }\n    if (command === \"{\" || command === \"}\" || command === \"$\" || command === \"%\" || command === \"#\" || command === \"_\" || command === \"&\") {\n      return command;\n    }\n    if (command === \"|\") {\n      return \"\\u2016\";\n    }\n    if (command === \"not\") {\n      const value = this.parseRequiredArgument(false).trim();\n      const negated = NEGATED_SYMBOLS[value];\n      if (negated !== void 0) {\n        return ` ${negated} `;\n      }\n      const characters = Array.from(value);\n      if (characters.length === 0) {\n        this.supported = false;\n        return \"\";\n      }\n      return ` ${characters[0]}\\u0338${characters.slice(1).join(\"\")} `;\n    }\n    if (LIMIT_OPERATORS.has(command)) {\n      return this.parseOperator(command, \"bracket\", true, true);\n    }\n    const symbol = SYMBOLS[command];\n    if (symbol !== void 0) {\n      if (DISPLAY_LIMIT_SYMBOLS.has(command)) {\n        return this.parseOperator(symbol, \"script\", true);\n      }\n      return command === \"cdot\" || command === \"times\" || RELATION_COMMANDS.has(command) ? ` ${symbol} ` : symbol;\n    }\n    if (NAMED_OPERATORS.has(command)) {\n      return `${NAMED_OPERATOR_START}${command}${NAMED_OPERATOR_END}`;\n    }\n    if (SIZE_COMMANDS.has(command)) {\n      return \"\";\n    }\n    if (command === \"left\" || command === \"middle\" || command === \"right\") {\n      if (this.source[this.position] === \".\") {\n        this.position++;\n      }\n      return \"\";\n    }\n    if (command === \"frac\" || command === \"dfrac\" || command === \"tfrac\") {\n      const shouldStack = this.display && this.stackFractions && command !== \"tfrac\";\n      const numerator = this.parseRequiredArgument(!shouldStack);\n      const denominator = this.parseRequiredArgument(!shouldStack);\n      if (shouldStack) {\n        const index = this.layoutNodes.push({\n          type: \"fraction\",\n          numerator: normalizeOutput(numerator),\n          denominator: normalizeOutput(denominator)\n        }) - 1;\n        return `${LAYOUT_MARKER_START}${index}${LAYOUT_MARKER_END}`;\n      }\n      return formatFraction(numerator, denominator);\n    }\n    if (command === \"sqrt\") {\n      const degree = this.parseOptionalArgument()?.trim();\n      const value = this.parseRequiredArgument();\n      if (degree === void 0 || degree === \"2\") {\n        return formatRoot(value);\n      }\n      if (degree === \"3\") {\n        return formatRoot(value, \"\\u221B\");\n      }\n      if (degree === \"4\") {\n        return formatRoot(value, \"\\u221C\");\n      }\n      return `${formatScript(degree, \"sup\")}${formatRoot(value)}`;\n    }\n    if (command === \"boxed\" || command === \"fbox\") {\n      return `[${this.parseRequiredArgument().trim()}]`;\n    }\n    if (command === \"binom\" || command === \"dbinom\" || command === \"tbinom\") {\n      return `(${this.parseRequiredArgument()} choose ${this.parseRequiredArgument()})`;\n    }\n    const accent = ACCENTS[command];\n    if (accent !== void 0) {\n      const value = this.parseRequiredArgument();\n      return Array.from(value).length === 1 ? `${value}${accent}` : `${command}(${value})`;\n    }\n    if (command === \"mathbb\") {\n      const value = this.parseRequiredArgument();\n      return Array.from(value, (character) => BLACKBOARD[character] ?? character).join(\"\");\n    }\n    if (command === \"operatorname\") {\n      const starred = this.source[this.position] === \"*\";\n      if (starred) {\n        this.position++;\n      }\n      const operator = normalizeOutput(this.parseRequiredArgument()).trim();\n      return this.parseOperator(operator, \"bracket\", starred, true);\n    }\n    if (command === \"mod\" || command === \"bmod\") {\n      return \" mod \";\n    }\n    if (command === \"pmod\" || command === \"pod\") {\n      const value = this.parseRequiredArgument().trim();\n      return command === \"pmod\" ? ` (mod ${value})` : ` (${value})`;\n    }\n    if (command === \"overset\" || command === \"stackrel\") {\n      const upper = this.parseRequiredArgument();\n      const value = this.parseRequiredArgument().trim();\n      return `${value}${formatScript(upper, \"sup\")}`;\n    }\n    if (command === \"underset\") {\n      const lower = this.parseRequiredArgument();\n      const value = this.parseRequiredArgument().trim();\n      return `${value}${formatScript(lower, \"sub\")}`;\n    }\n    if (PLAIN_WRAPPERS.has(command)) {\n      const value = this.parseRequiredArgument();\n      return command.startsWith(\"text\") || command === \"mbox\" ? value : value.trim();\n    }\n    if (command === \"begin\") {\n      return this.parseEnvironment();\n    }\n    if (command === \"end\") {\n      this.supported = false;\n      return \"\";\n    }\n    this.supported = false;\n    return `\\\\${command}`;\n  }\n  parseOperator(operator, inlineLowerStyle, displayLimits, spaced = false) {\n    let useDisplayLimits = displayLimits;\n    let modifierPosition = this.position;\n    while (modifierPosition < this.source.length && /[ \\t]/.test(this.source[modifierPosition] ?? \"\")) {\n      modifierPosition++;\n    }\n    const modifier = /^\\\\(limits|nolimits)(?![A-Za-z])/.exec(this.source.slice(modifierPosition));\n    if (modifier) {\n      useDisplayLimits = modifier[1] === \"limits\";\n      this.position = modifierPosition + modifier[0].length;\n    }\n    let lower;\n    let upper;\n    while (true) {\n      let scriptPosition = this.position;\n      while (scriptPosition < this.source.length && /[ \\t]/.test(this.source[scriptPosition] ?? \"\")) {\n        scriptPosition++;\n      }\n      const kind = this.source[scriptPosition];\n      if (kind !== \"_\" && kind !== \"^\") {\n        break;\n      }\n      this.position = scriptPosition + 1;\n      const value = normalizeOutput(this.parseRequiredArgument(false)).replaceAll(\" \", \"\");\n      if (kind === \"_\") {\n        if (lower !== void 0) {\n          this.supported = false;\n        }\n        lower = value;\n      } else {\n        if (upper !== void 0) {\n          this.supported = false;\n        }\n        upper = value;\n      }\n    }\n    if (this.display && useDisplayLimits && (lower !== void 0 || upper !== void 0)) {\n      const index = this.layoutNodes.push({ type: \"operator\", operator, lower, upper }) - 1;\n      return `${LAYOUT_MARKER_START}${index}${LAYOUT_MARKER_END}`;\n    }\n    let rendered = operator;\n    if (lower !== void 0) {\n      rendered += inlineLowerStyle === \"bracket\" ? `[${lower}]` : formatScript(lower, \"sub\");\n    }\n    if (upper !== void 0) {\n      rendered += formatScript(upper, \"sup\");\n    }\n    return spaced ? ` ${rendered} ` : rendered;\n  }\n  parseRequiredArgument(stackFractions = true) {\n    const previousStackFractions = this.stackFractions;\n    this.stackFractions = previousStackFractions && stackFractions;\n    const value = this.parseRequiredArgumentValue();\n    this.stackFractions = previousStackFractions;\n    return value;\n  }\n  parseRequiredArgumentValue() {\n    while (this.position < this.source.length && /\\s/.test(this.source[this.position] ?? \"\")) {\n      this.position++;\n    }\n    if (this.position >= this.source.length) {\n      this.supported = false;\n      return \"\";\n    }\n    if (this.source[this.position] === \"{\") {\n      this.position++;\n      return this.parseSequence(\"}\");\n    }\n    if (this.source[this.position] === \"\\\\\") {\n      return this.parseCommand();\n    }\n    const value = this.source[this.position] ?? \"\";\n    this.position++;\n    return value;\n  }\n  parseOptionalArgument() {\n    while (this.position < this.source.length && /[ \\t]/.test(this.source[this.position] ?? \"\")) {\n      this.position++;\n    }\n    if (this.source[this.position] !== \"[\") {\n      return void 0;\n    }\n    const end = this.source.indexOf(\"]\", this.position + 1);\n    if (end < 0) {\n      this.supported = false;\n      return void 0;\n    }\n    const value = this.source.slice(this.position + 1, end);\n    this.position = end + 1;\n    return this.renderNested(value);\n  }\n  readRawGroup() {\n    while (this.position < this.source.length && /[ \\t]/.test(this.source[this.position] ?? \"\")) {\n      this.position++;\n    }\n    if (this.source[this.position] !== \"{\") {\n      this.supported = false;\n      return void 0;\n    }\n    const start = ++this.position;\n    let depth = 1;\n    while (this.position < this.source.length) {\n      const character = this.source[this.position];\n      if (character === \"\\\\\") {\n        this.position += 2;\n        continue;\n      }\n      if (character === \"{\")\n        depth++;\n      if (character === \"}\")\n        depth--;\n      if (depth === 0) {\n        const value = this.source.slice(start, this.position);\n        this.position++;\n        return value;\n      }\n      this.position++;\n    }\n    this.supported = false;\n    return void 0;\n  }\n  splitEnvironmentRows(body) {\n    return body.split(/\\\\\\\\(?:\\[[^\\]\\n]*\\])?/);\n  }\n  parseEnvironment() {\n    const environment = this.readRawGroup();\n    if (!environment) {\n      return \"\";\n    }\n    const endMarker = `\\\\end{${environment}}`;\n    const end = this.source.indexOf(endMarker, this.position);\n    if (end < 0) {\n      this.supported = false;\n      return \"\";\n    }\n    const body = this.source.slice(this.position, end);\n    this.position = end + endMarker.length;\n    if (environment === \"equation\" || environment === \"equation*\" || environment === \"displaymath\") {\n      return this.renderNested(body).trim();\n    }\n    if (environment === \"aligned\" || environment === \"align\" || environment === \"align*\" || environment === \"alignedat\" || environment === \"alignat\" || environment === \"alignat*\" || environment === \"gather\" || environment === \"gathered\" || environment === \"multline\" || environment === \"multline*\" || environment === \"split\") {\n      const alignedAt = [\"alignedat\", \"alignat\", \"alignat*\"].includes(environment);\n      const alignedBody = alignedAt ? body.replace(/^\\s*\\{[^}]*\\}/, \"\") : body;\n      return this.splitEnvironmentRows(alignedBody).map((row) => {\n        const cells = row.split(\"&\");\n        const source = alignedAt ? Array.from({ length: Math.ceil(cells.length / 2) }, (_, index) => cells.slice(index * 2, index * 2 + 2).join(\"\")).join(\" \") : cells.join(\"\");\n        return this.renderNested(source).trim();\n      }).filter(Boolean).join(\"\\n\");\n    }\n    if (environment === \"cases\" || environment === \"cases*\") {\n      const rows = this.splitEnvironmentRows(body).map((row) => row.split(\"&\").map((cell) => this.renderNested(cell, false).trim())).filter((row) => row.some(Boolean));\n      return rows.map((row, index) => {\n        const value = (row[0] ?? \"\").replace(/,\\s*$/, \"\");\n        const condition = row[1] ?? \"\";\n        const delimiter2 = index === 0 ? \"\\u23A7\" : index === rows.length - 1 ? \"\\u23A9\" : \"\\u23A8\";\n        const conditionPrefix = /^(?:if|when|for|otherwise)\\b/i.test(condition) ? \" \" : \" if \";\n        return `${delimiter2} ${value}${condition ? `${conditionPrefix}${condition}` : \"\"}`;\n      }).join(\"\\n\");\n    }\n    if ([\"array\", \"matrix\", \"smallmatrix\", \"pmatrix\", \"bmatrix\", \"Bmatrix\", \"vmatrix\", \"Vmatrix\"].includes(environment)) {\n      const matrixBody = environment === \"array\" ? body.replace(/^\\s*\\{[^}]*\\}/, \"\") : body;\n      return this.renderMatrix(environment, matrixBody);\n    }\n    this.supported = false;\n    return body;\n  }\n  renderMatrix(environment, body) {\n    const matrix = this.splitEnvironmentRows(body).map((row) => row.split(\"&\").map((cell) => this.renderNested(cell, false).trim())).filter((row) => row.some(Boolean));\n    const columnCount = Math.max(0, ...matrix.map((row) => row.length));\n    const columnWidths = Array.from({ length: columnCount }, (_, column) => Math.max(0, ...matrix.map((row) => visibleWidth(row[column] ?? \"\"))));\n    const rows = matrix.map((row) => Array.from({ length: columnCount }, (_, column) => {\n      const cell = row[column] ?? \"\";\n      return `${cell}${PROTECTED_SPACE.repeat(Math.max(0, (columnWidths[column] ?? 0) - visibleWidth(cell)))}`;\n    }).join(\" \\u2502 \"));\n    let lines;\n    if (environment === \"array\" || environment === \"matrix\" || environment === \"smallmatrix\") {\n      lines = rows;\n    } else {\n      const delimiters = {\n        pmatrix: [\"\\u239B\", \"\\u239E\", \"\\u239C\", \"\\u239F\", \"\\u239D\", \"\\u23A0\"],\n        bmatrix: [\"\\u23A1\", \"\\u23A4\", \"\\u23A2\", \"\\u23A5\", \"\\u23A3\", \"\\u23A6\"],\n        Bmatrix: [\"\\u23A7\", \"\\u23AB\", \"\\u23A8\", \"\\u23AC\", \"\\u23A9\", \"\\u23AD\"],\n        vmatrix: [\"\\u2502\", \"\\u2502\", \"\\u2502\", \"\\u2502\", \"\\u2502\", \"\\u2502\"],\n        Vmatrix: [\"\\u2551\", \"\\u2551\", \"\\u2551\", \"\\u2551\", \"\\u2551\", \"\\u2551\"]\n      };\n      const delimiter2 = delimiters[environment];\n      if (!delimiter2) {\n        this.supported = false;\n        return rows.join(\"\\n\");\n      }\n      lines = rows.map((row, index2) => {\n        const left = index2 === 0 ? delimiter2[0] : index2 === rows.length - 1 ? delimiter2[4] : delimiter2[2];\n        const right = index2 === 0 ? delimiter2[1] : index2 === rows.length - 1 ? delimiter2[5] : delimiter2[3];\n        return `${left} ${row} ${right}`;\n      });\n    }\n    if (lines.length <= 1) {\n      return lines[0] ?? \"\";\n    }\n    const index = this.layoutNodes.push({ type: \"matrix\", lines, baseline: 0 }) - 1;\n    return `${LAYOUT_MARKER_START}${index}${LAYOUT_MARKER_END}`;\n  }\n  renderNested(source, stackFractions = true) {\n    const rendered = new _LatexParser(source, this.layoutNodes, this.display && stackFractions).render();\n    if (rendered === void 0) {\n      this.supported = false;\n      return source;\n    }\n    return rendered;\n  }\n};\nfunction renderLatex(source, options = {}) {\n  const layoutNodes = [];\n  const rendered = new LatexParser(source, layoutNodes, options.display === true).render();\n  if (rendered === void 0) {\n    return void 0;\n  }\n  if (layoutNodes.length === 0) {\n    return rendered.replaceAll(PROTECTED_SPACE, \" \");\n  }\n  const lines = renderLayout(rendered, layoutNodes).lines;\n  const indentation = Math.min(...lines.filter((line) => line.trim()).map((line) => line.length - line.trimStart().length));\n  return lines.map((line) => line.slice(indentation).trimEnd()).join(\"\\n\").trimEnd().replaceAll(PROTECTED_SPACE, \" \");\n}\n\n// node_modules/.pnpm/@earendil-works+pi-tui@0.84.2/node_modules/@earendil-works/pi-tui/dist/components/markdown.js\nvar STRICT_STRIKETHROUGH_REGEX = /^(~~)(?=[^\\s~])((?:\\\\.|[^\\\\])*?(?:\\\\.|[^\\s~\\\\]))\\1(?=[^~]|$)/;\nvar StrictStrikethroughTokenizer = class extends Tokenizer {\n  del(src) {\n    const match = STRICT_STRIKETHROUGH_REGEX.exec(src);\n    if (!match) {\n      return void 0;\n    }\n    const text = match[2];\n    return {\n      type: \"del\",\n      raw: match[0],\n      text,\n      tokens: this.lexer.inlineTokens(text)\n    };\n  }\n};\nfunction isEscaped(source, index) {\n  let backslashes = 0;\n  for (let position = index - 1; position >= 0 && source[position] === \"\\\\\"; position--) {\n    backslashes++;\n  }\n  return backslashes % 2 === 1;\n}\nfunction findClosingDelimiter(source, closing, start) {\n  let index = source.indexOf(closing, start);\n  while (index >= 0 && isEscaped(source, index)) {\n    index = source.indexOf(closing, index + closing.length);\n  }\n  return index;\n}\nfunction looksLikePendingDollarMath(source) {\n  return /\\\\[A-Za-z]+|[_^=+*/<>()[\\]|±≤≥≠≈∈→⇒∞∫∑√-]/.test(source);\n}\nfunction tokenizeInlineLatex(source) {\n  let opening = \"\";\n  let closing = \"\";\n  if (source.startsWith(\"$$\")) {\n    opening = \"$$\";\n    closing = \"$$\";\n  } else if (source.startsWith(\"\\\\(\")) {\n    opening = \"\\\\(\";\n    closing = \"\\\\)\";\n  } else if (source.startsWith(\"\\\\[\")) {\n    opening = \"\\\\[\";\n    closing = \"\\\\]\";\n  } else if (source.startsWith(\"$\") && !/^\\$\\s/.test(source)) {\n    opening = \"$\";\n    closing = \"$\";\n  } else {\n    return void 0;\n  }\n  const closingIndex = findClosingDelimiter(source, closing, opening.length);\n  if (closingIndex >= 0 && opening === \"$\" && (/\\s$/.test(source.slice(opening.length, closingIndex)) || /^\\d/.test(source.slice(closingIndex + 1)) || /^[A-Z_][A-Z0-9_]*(?:[^A-Za-z0-9_\\s])?$/.test(source.slice(opening.length, closingIndex)) && /^[A-Za-z_][A-Za-z0-9_]*/.test(source.slice(closingIndex + 1)) || source.slice(opening.length, closingIndex).includes(\"`\"))) {\n    return void 0;\n  }\n  if (closingIndex < 0) {\n    const pendingSource = source.slice(opening.length);\n    if (opening.startsWith(\"\\\\\") || looksLikePendingDollarMath(pendingSource)) {\n      return { type: \"latex\", raw: source, text: pendingSource, pending: true };\n    }\n    return void 0;\n  }\n  const text = source.slice(opening.length, closingIndex);\n  if (!text || text.includes(\"\\n\")) {\n    return void 0;\n  }\n  const raw = source.slice(0, closingIndex + closing.length);\n  return { type: \"latex\", raw, text };\n}\nfunction tokenizeBlockLatex(source) {\n  const dollarMatch = /^ {0,3}\\$\\$[ \\t]*(?:\\n)?([\\s\\S]*?)\\$\\$[ \\t]*(?:\\n|$)/.exec(source);\n  if (dollarMatch?.[1]) {\n    return { type: \"latexBlock\", raw: dollarMatch[0], text: dollarMatch[1].trim() };\n  }\n  const bracketMatch = /^ {0,3}\\\\\\[[ \\t]*(?:\\n)?([\\s\\S]*?)\\\\\\][ \\t]*(?:\\n|$)/.exec(source);\n  if (bracketMatch?.[1]) {\n    return { type: \"latexBlock\", raw: bracketMatch[0], text: bracketMatch[1].trim() };\n  }\n  const pendingBracket = /^ {0,3}\\\\\\[[ \\t]*(?:\\n)?([\\s\\S]*)$/.exec(source);\n  if (pendingBracket) {\n    return { type: \"latexBlock\", raw: pendingBracket[0], text: pendingBracket[1], pending: true };\n  }\n  const pendingDollar = /^ {0,3}\\$\\$[ \\t]*(?:\\n)?([\\s\\S]*)$/.exec(source);\n  if (pendingDollar?.[1] && looksLikePendingDollarMath(pendingDollar[1])) {\n    return { type: \"latexBlock\", raw: pendingDollar[0], text: pendingDollar[1], pending: true };\n  }\n  return void 0;\n}\nvar LATEX_MARKDOWN_EXTENSIONS = [\n  {\n    name: \"latexBlock\",\n    level: \"block\",\n    start(source) {\n      const match = /(?:^|\\n) {0,3}(?:\\$\\$|\\\\\\[)/.exec(source);\n      return match ? match.index + (match[0].startsWith(\"\\n\") ? 1 : 0) : void 0;\n    },\n    tokenizer: tokenizeBlockLatex\n  },\n  {\n    name: \"latex\",\n    level: \"inline\",\n    start(source) {\n      const indices = [source.indexOf(\"$\"), source.indexOf(\"\\\\(\"), source.indexOf(\"\\\\[\")].filter((index) => index >= 0);\n      return indices.length > 0 ? Math.min(...indices) : void 0;\n    },\n    tokenizer: tokenizeInlineLatex\n  }\n];\nfunction trimPartialClosingFences(tokens) {\n  const token = tokens[tokens.length - 1];\n  if (token?.type === \"list\") {\n    trimPartialClosingFences(token.items[token.items.length - 1]?.tokens ?? []);\n    return;\n  }\n  if (token?.type === \"blockquote\") {\n    trimPartialClosingFences(token.tokens ?? []);\n    return;\n  }\n  if (token?.type !== \"code\") {\n    return;\n  }\n  const marker = /^(`{3,}|~{3,})/.exec(token.raw)?.[1];\n  const lastLine = token.raw.split(\"\\n\").pop();\n  if (!marker || !lastLine || lastLine.length >= marker.length || lastLine !== marker[0]?.repeat(lastLine.length)) {\n    return;\n  }\n  token.text = token.text.slice(0, -lastLine.length).replace(/\\n$/, \"\");\n}\nvar markdownParser = new Marked();\nmarkdownParser.setOptions({\n  tokenizer: new StrictStrikethroughTokenizer()\n});\nmarkdownParser.use({ extensions: [...LATEX_MARKDOWN_EXTENSIONS] });\nvar Markdown = class {\n  text;\n  paddingX;\n  // Left/right padding\n  paddingY;\n  // Top/bottom padding\n  defaultTextStyle;\n  theme;\n  options;\n  defaultStylePrefix;\n  // Cache for rendered output\n  cachedText;\n  cachedWidth;\n  cachedLines;\n  constructor(text, paddingX, paddingY, theme2, defaultTextStyle, options) {\n    this.text = text;\n    this.paddingX = paddingX;\n    this.paddingY = paddingY;\n    this.theme = theme2;\n    this.defaultTextStyle = defaultTextStyle;\n    this.options = options ? { ...options } : {};\n  }\n  setText(text) {\n    this.text = text;\n    this.invalidate();\n  }\n  invalidate() {\n    this.cachedText = void 0;\n    this.cachedWidth = void 0;\n    this.cachedLines = void 0;\n  }\n  render(width) {\n    if (this.cachedLines && this.cachedText === this.text && this.cachedWidth === width) {\n      return this.cachedLines;\n    }\n    const contentWidth = Math.max(1, width - this.paddingX * 2);\n    const text = this.options.transform?.(this.text, contentWidth) ?? this.text;\n    if (!text || text.trim() === \"\") {\n      const result2 = [];\n      this.cachedText = this.text;\n      this.cachedWidth = width;\n      this.cachedLines = result2;\n      return result2;\n    }\n    const normalizedText = text.replace(/\\t/g, \"   \");\n    const tokens = markdownParser.lexer(normalizedText);\n    trimPartialClosingFences(tokens);\n    const renderedLines = [];\n    for (let i = 0; i < tokens.length; i++) {\n      const token = tokens[i];\n      const nextToken = tokens[i + 1];\n      const tokenLines = this.renderToken(token, contentWidth, nextToken?.type);\n      for (const tokenLine of tokenLines) {\n        renderedLines.push(tokenLine);\n      }\n    }\n    const wrappedLines = [];\n    for (const line of renderedLines) {\n      if (isImageLine(line)) {\n        wrappedLines.push(line);\n      } else {\n        for (const wrappedLine of wrapTextWithAnsi(line, contentWidth)) {\n          wrappedLines.push(wrappedLine);\n        }\n      }\n    }\n    const leftMargin = \" \".repeat(this.paddingX);\n    const rightMargin = \" \".repeat(this.paddingX);\n    const bgFn = this.defaultTextStyle?.bgColor;\n    const contentLines = [];\n    for (const line of wrappedLines) {\n      if (isImageLine(line)) {\n        contentLines.push(line);\n        continue;\n      }\n      const lineWithMargins = leftMargin + line + rightMargin;\n      if (bgFn) {\n        contentLines.push(applyBackgroundToLine(lineWithMargins, width, bgFn));\n      } else {\n        const visibleLen = visibleWidth(lineWithMargins);\n        const paddingNeeded = Math.max(0, width - visibleLen);\n        contentLines.push(lineWithMargins + \" \".repeat(paddingNeeded));\n      }\n    }\n    const emptyLine = \" \".repeat(width);\n    const emptyLines = [];\n    for (let i = 0; i < this.paddingY; i++) {\n      const line = bgFn ? applyBackgroundToLine(emptyLine, width, bgFn) : emptyLine;\n      emptyLines.push(line);\n    }\n    const result = emptyLines.concat(contentLines, emptyLines);\n    this.cachedText = this.text;\n    this.cachedWidth = width;\n    this.cachedLines = result;\n    return result.length > 0 ? result : [\"\"];\n  }\n  /**\n   * Apply default text style to a string.\n   * This is the base styling applied to all text content.\n   * NOTE: Background color is NOT applied here - it's applied at the padding stage\n   * to ensure it extends to the full line width.\n   */\n  applyDefaultStyle(text) {\n    if (!this.defaultTextStyle) {\n      return text;\n    }\n    let styled = text;\n    if (this.defaultTextStyle.color) {\n      styled = this.defaultTextStyle.color(styled);\n    }\n    if (this.defaultTextStyle.bold) {\n      styled = this.theme.bold(styled);\n    }\n    if (this.defaultTextStyle.italic) {\n      styled = this.theme.italic(styled);\n    }\n    if (this.defaultTextStyle.strikethrough) {\n      styled = this.theme.strikethrough(styled);\n    }\n    if (this.defaultTextStyle.underline) {\n      styled = this.theme.underline(styled);\n    }\n    return styled;\n  }\n  getDefaultStylePrefix() {\n    if (!this.defaultTextStyle) {\n      return \"\";\n    }\n    if (this.defaultStylePrefix !== void 0) {\n      return this.defaultStylePrefix;\n    }\n    const sentinel = \"\\0\";\n    let styled = sentinel;\n    if (this.defaultTextStyle.color) {\n      styled = this.defaultTextStyle.color(styled);\n    }\n    if (this.defaultTextStyle.bold) {\n      styled = this.theme.bold(styled);\n    }\n    if (this.defaultTextStyle.italic) {\n      styled = this.theme.italic(styled);\n    }\n    if (this.defaultTextStyle.strikethrough) {\n      styled = this.theme.strikethrough(styled);\n    }\n    if (this.defaultTextStyle.underline) {\n      styled = this.theme.underline(styled);\n    }\n    const sentinelIndex = styled.indexOf(sentinel);\n    this.defaultStylePrefix = sentinelIndex >= 0 ? styled.slice(0, sentinelIndex) : \"\";\n    return this.defaultStylePrefix;\n  }\n  getStylePrefix(styleFn) {\n    const sentinel = \"\\0\";\n    const styled = styleFn(sentinel);\n    const sentinelIndex = styled.indexOf(sentinel);\n    return sentinelIndex >= 0 ? styled.slice(0, sentinelIndex) : \"\";\n  }\n  getDefaultInlineStyleContext() {\n    return {\n      applyText: (text) => this.applyDefaultStyle(text),\n      stylePrefix: this.getDefaultStylePrefix()\n    };\n  }\n  renderToken(token, width, nextTokenType, styleContext) {\n    const lines = [];\n    switch (token.type) {\n      case \"heading\": {\n        const headingLevel = token.depth;\n        const headingPrefix = `${\"#\".repeat(headingLevel)} `;\n        let headingStyleFn;\n        if (headingLevel === 1) {\n          headingStyleFn = (text) => this.theme.heading(this.theme.bold(this.theme.underline(text)));\n        } else {\n          headingStyleFn = (text) => this.theme.heading(this.theme.bold(text));\n        }\n        const headingStyleContext = {\n          applyText: headingStyleFn,\n          stylePrefix: this.getStylePrefix(headingStyleFn)\n        };\n        const headingText = this.renderInlineTokens(token.tokens || [], headingStyleContext);\n        const styledHeading = headingLevel >= 3 ? headingStyleFn(headingPrefix) + headingText : headingText;\n        lines.push(styledHeading);\n        if (nextTokenType && nextTokenType !== \"space\") {\n          lines.push(\"\");\n        }\n        break;\n      }\n      case \"paragraph\": {\n        const paragraphText = this.renderInlineTokens(token.tokens || [], styleContext);\n        lines.push(paragraphText);\n        if (nextTokenType && nextTokenType !== \"list\" && nextTokenType !== \"space\") {\n          lines.push(\"\");\n        }\n        break;\n      }\n      case \"text\":\n        lines.push(this.renderInlineTokens([token], styleContext));\n        break;\n      case \"latexBlock\": {\n        const latexToken = token;\n        const rendered = !latexToken.pending && this.options.renderLatex !== false ? renderLatex(latexToken.text, { display: true }) ?? latexToken.raw.trim() : latexToken.raw.trim();\n        for (const line of rendered.split(\"\\n\")) {\n          lines.push(this.applyDefaultStyle(line));\n        }\n        if (nextTokenType && nextTokenType !== \"space\") {\n          lines.push(\"\");\n        }\n        break;\n      }\n      case \"code\": {\n        const indent = this.theme.codeBlockIndent ?? \"  \";\n        lines.push(this.theme.codeBlockBorder(`\\`\\`\\`${token.lang || \"\"}`));\n        if (this.theme.highlightCode) {\n          const highlightedLines = this.theme.highlightCode(token.text, token.lang);\n          for (const hlLine of highlightedLines) {\n            lines.push(`${indent}${hlLine}`);\n          }\n        } else {\n          const codeLines = token.text.split(\"\\n\");\n          for (const codeLine of codeLines) {\n            lines.push(`${indent}${this.theme.codeBlock(codeLine)}`);\n          }\n        }\n        lines.push(this.theme.codeBlockBorder(\"```\"));\n        if (nextTokenType && nextTokenType !== \"space\") {\n          lines.push(\"\");\n        }\n        break;\n      }\n      case \"list\": {\n        const listLines = this.renderList(token, 0, width, styleContext);\n        lines.push(...listLines);\n        break;\n      }\n      case \"table\": {\n        const tableLines = this.renderTable(token, width, nextTokenType, styleContext);\n        lines.push(...tableLines);\n        break;\n      }\n      case \"blockquote\": {\n        const quoteStyle = (text) => this.theme.quote(this.theme.italic(text));\n        const quoteStylePrefix = this.getStylePrefix(quoteStyle);\n        const applyQuoteStyle = (line) => {\n          if (!quoteStylePrefix) {\n            return quoteStyle(line);\n          }\n          const lineWithReappliedStyle = line.replace(/\\x1b\\[0m/g, `\\x1B[0m${quoteStylePrefix}`);\n          return quoteStyle(lineWithReappliedStyle);\n        };\n        const quoteContentWidth = Math.max(1, width - 2);\n        const quoteInlineStyleContext = {\n          applyText: (text) => text,\n          stylePrefix: quoteStylePrefix\n        };\n        const quoteTokens = token.tokens || [];\n        const renderedQuoteLines = [];\n        for (let i = 0; i < quoteTokens.length; i++) {\n          const quoteToken = quoteTokens[i];\n          const nextQuoteToken = quoteTokens[i + 1];\n          renderedQuoteLines.push(...this.renderToken(quoteToken, quoteContentWidth, nextQuoteToken?.type, quoteInlineStyleContext));\n        }\n        while (renderedQuoteLines.length > 0 && renderedQuoteLines[renderedQuoteLines.length - 1] === \"\") {\n          renderedQuoteLines.pop();\n        }\n        for (const quoteLine of renderedQuoteLines) {\n          const styledLine = applyQuoteStyle(quoteLine);\n          const wrappedLines = wrapTextWithAnsi(styledLine, quoteContentWidth);\n          for (const wrappedLine of wrappedLines) {\n            lines.push(this.theme.quoteBorder(\"\\u2502 \") + wrappedLine);\n          }\n        }\n        if (nextTokenType && nextTokenType !== \"space\") {\n          lines.push(\"\");\n        }\n        break;\n      }\n      case \"hr\":\n        lines.push(this.theme.hr(\"\\u2500\".repeat(Math.min(width, 80))));\n        if (nextTokenType && nextTokenType !== \"space\") {\n          lines.push(\"\");\n        }\n        break;\n      case \"html\":\n        if (\"raw\" in token && typeof token.raw === \"string\") {\n          lines.push(this.applyDefaultStyle(token.raw.trim()));\n        }\n        break;\n      case \"space\":\n        lines.push(\"\");\n        break;\n      default:\n        if (\"text\" in token && typeof token.text === \"string\") {\n          lines.push(token.text);\n        }\n    }\n    return lines;\n  }\n  renderInlineTokens(tokens, styleContext) {\n    let result = \"\";\n    const resolvedStyleContext = styleContext ?? this.getDefaultInlineStyleContext();\n    const { applyText, stylePrefix } = resolvedStyleContext;\n    const applyTextWithNewlines = (text) => {\n      const segments = text.split(\"\\n\");\n      return segments.map((segment) => applyText(segment)).join(\"\\n\");\n    };\n    for (const token of tokens) {\n      switch (token.type) {\n        case \"latex\": {\n          const latexToken = token;\n          const rendered = !latexToken.pending && this.options.renderLatex !== false ? renderLatex(latexToken.text) ?? latexToken.raw : latexToken.raw;\n          result += applyTextWithNewlines(rendered);\n          break;\n        }\n        case \"escape\":\n          result += applyTextWithNewlines(this.options.preserveBackslashEscapes ? token.raw : token.text);\n          break;\n        case \"text\":\n          if (token.tokens && token.tokens.length > 0) {\n            result += this.renderInlineTokens(token.tokens, resolvedStyleContext);\n          } else {\n            result += applyTextWithNewlines(token.text);\n          }\n          break;\n        case \"paragraph\":\n          result += this.renderInlineTokens(token.tokens || [], resolvedStyleContext);\n          break;\n        case \"strong\": {\n          const boldContent = this.renderInlineTokens(token.tokens || [], resolvedStyleContext);\n          result += this.theme.bold(boldContent) + stylePrefix;\n          break;\n        }\n        case \"em\": {\n          const italicContent = this.renderInlineTokens(token.tokens || [], resolvedStyleContext);\n          result += this.theme.italic(italicContent) + stylePrefix;\n          break;\n        }\n        case \"codespan\":\n          result += this.theme.code(token.text) + stylePrefix;\n          break;\n        case \"link\": {\n          const linkText = this.renderInlineTokens(token.tokens || [], resolvedStyleContext);\n          const styledLink = this.theme.link(this.theme.underline(linkText));\n          if (getCapabilities().hyperlinks) {\n            result += hyperlink(styledLink, token.href) + stylePrefix;\n          } else {\n            const hrefForComparison = token.href.startsWith(\"mailto:\") ? token.href.slice(7) : token.href;\n            if (token.text === token.href || token.text === hrefForComparison) {\n              result += styledLink + stylePrefix;\n            } else {\n              result += styledLink + this.theme.linkUrl(` (${token.href})`) + stylePrefix;\n            }\n          }\n          break;\n        }\n        case \"br\":\n          result += \"\\n\";\n          break;\n        case \"del\": {\n          const delContent = this.renderInlineTokens(token.tokens || [], resolvedStyleContext);\n          result += this.theme.strikethrough(delContent) + stylePrefix;\n          break;\n        }\n        case \"html\":\n          if (\"raw\" in token && typeof token.raw === \"string\") {\n            result += applyTextWithNewlines(token.raw);\n          }\n          break;\n        default:\n          if (\"text\" in token && typeof token.text === \"string\") {\n            result += applyTextWithNewlines(token.text);\n          }\n      }\n    }\n    while (stylePrefix && result.endsWith(stylePrefix)) {\n      result = result.slice(0, -stylePrefix.length);\n    }\n    return result;\n  }\n  getOrderedListMarker(item) {\n    const match = /^(?: {0,3})(\\d{1,9}[.)])[ \\t]+/.exec(item.raw);\n    return match ? `${match[1]} ` : void 0;\n  }\n  getUnorderedListMarker(item) {\n    const match = /^(?: {0,3})([-+*])(?:[ \\t]+|(?=\\r?\\n|$))/.exec(item.raw);\n    return match ? `${match[1]} ` : void 0;\n  }\n  /**\n   * Render a list with proper nesting support\n   */\n  renderList(token, depth, width, styleContext) {\n    const lines = [];\n    const indent = \"    \".repeat(depth);\n    const startNumber = typeof token.start === \"number\" ? token.start : 1;\n    for (let i = 0; i < token.items.length; i++) {\n      const item = token.items[i];\n      const isLastItem = i === token.items.length - 1;\n      const bullet = token.ordered ? this.options.preserveOrderedListMarkers ? this.getOrderedListMarker(item) ?? `${startNumber + i}. ` : `${startNumber + i}. ` : this.options.preserveOrderedListMarkers ? this.getUnorderedListMarker(item) ?? \"- \" : \"- \";\n      const taskMarker = item.task ? `[${item.checked ? \"x\" : \" \"}] ` : \"\";\n      const marker = bullet + taskMarker;\n      const firstPrefix = indent + this.theme.listBullet(marker);\n      const continuationPrefix = indent + \" \".repeat(visibleWidth(marker));\n      const itemWidth = Math.max(1, width - visibleWidth(firstPrefix));\n      let renderedAnyLine = false;\n      for (const itemToken of item.tokens) {\n        if (itemToken.type === \"list\") {\n          lines.push(...this.renderList(itemToken, depth + 1, width, styleContext));\n          renderedAnyLine = true;\n          continue;\n        }\n        const itemLines = this.renderToken(itemToken, itemWidth, void 0, styleContext);\n        for (const line of itemLines) {\n          for (const wrappedLine of wrapTextWithAnsi(line, itemWidth)) {\n            const linePrefix = renderedAnyLine ? continuationPrefix : firstPrefix;\n            lines.push(linePrefix + wrappedLine);\n            renderedAnyLine = true;\n          }\n        }\n      }\n      if (!renderedAnyLine) {\n        lines.push(firstPrefix);\n      }\n      if (token.loose && !isLastItem) {\n        lines.push(\"\");\n      }\n    }\n    return lines;\n  }\n  /**\n   * Get the visible width of the longest word in a string.\n   */\n  getLongestWordWidth(text, maxWidth) {\n    const words = text.split(/\\s+/).filter((word) => word.length > 0);\n    let longest = 0;\n    for (const word of words) {\n      longest = Math.max(longest, visibleWidth(word));\n    }\n    if (maxWidth === void 0) {\n      return longest;\n    }\n    return Math.min(longest, maxWidth);\n  }\n  /**\n   * Wrap a table cell to fit into a column.\n   *\n   * Delegates to wrapTextWithAnsi() so ANSI codes + long tokens are handled\n   * consistently with the rest of the renderer.\n   */\n  wrapCellText(text, maxWidth) {\n    return wrapTextWithAnsi(text, Math.max(1, maxWidth));\n  }\n  /**\n   * Render a table with width-aware cell wrapping.\n   * Cells that don't fit are wrapped to multiple lines.\n   */\n  renderTable(token, availableWidth, nextTokenType, styleContext) {\n    const lines = [];\n    const numCols = token.header.length;\n    if (numCols === 0) {\n      return lines;\n    }\n    const borderOverhead = 3 * numCols + 1;\n    const availableForCells = availableWidth - borderOverhead;\n    if (availableForCells < numCols) {\n      const fallbackLines = token.raw ? wrapTextWithAnsi(token.raw, availableWidth) : [];\n      if (nextTokenType && nextTokenType !== \"space\") {\n        fallbackLines.push(\"\");\n      }\n      return fallbackLines;\n    }\n    const maxUnbrokenWordWidth = 30;\n    const naturalWidths = [];\n    const minWordWidths = [];\n    for (let i = 0; i < numCols; i++) {\n      const headerText = this.renderInlineTokens(token.header[i].tokens || [], styleContext);\n      naturalWidths[i] = visibleWidth(headerText);\n      minWordWidths[i] = Math.max(1, this.getLongestWordWidth(headerText, maxUnbrokenWordWidth));\n    }\n    for (const row of token.rows) {\n      for (let i = 0; i < row.length; i++) {\n        const cellText = this.renderInlineTokens(row[i].tokens || [], styleContext);\n        naturalWidths[i] = Math.max(naturalWidths[i] || 0, visibleWidth(cellText));\n        minWordWidths[i] = Math.max(minWordWidths[i] || 1, this.getLongestWordWidth(cellText, maxUnbrokenWordWidth));\n      }\n    }\n    let minColumnWidths = minWordWidths;\n    let minCellsWidth = minColumnWidths.reduce((a, b) => a + b, 0);\n    if (minCellsWidth > availableForCells) {\n      minColumnWidths = new Array(numCols).fill(1);\n      const remaining = availableForCells - numCols;\n      if (remaining > 0) {\n        const totalWeight = minWordWidths.reduce((total, width) => total + Math.max(0, width - 1), 0);\n        const growth = minWordWidths.map((width) => {\n          const weight = Math.max(0, width - 1);\n          return totalWeight > 0 ? Math.floor(weight / totalWeight * remaining) : 0;\n        });\n        for (let i = 0; i < numCols; i++) {\n          minColumnWidths[i] += growth[i] ?? 0;\n        }\n        const allocated = growth.reduce((total, width) => total + width, 0);\n        let leftover = remaining - allocated;\n        for (let i = 0; leftover > 0 && i < numCols; i++) {\n          minColumnWidths[i]++;\n          leftover--;\n        }\n      }\n      minCellsWidth = minColumnWidths.reduce((a, b) => a + b, 0);\n    }\n    const totalNaturalWidth = naturalWidths.reduce((a, b) => a + b, 0) + borderOverhead;\n    let columnWidths;\n    if (totalNaturalWidth <= availableWidth) {\n      columnWidths = naturalWidths.map((width, index) => Math.max(width, minColumnWidths[index]));\n    } else {\n      const totalGrowPotential = naturalWidths.reduce((total, width, index) => {\n        return total + Math.max(0, width - minColumnWidths[index]);\n      }, 0);\n      const extraWidth = Math.max(0, availableForCells - minCellsWidth);\n      columnWidths = minColumnWidths.map((minWidth, index) => {\n        const naturalWidth = naturalWidths[index];\n        const minWidthDelta = Math.max(0, naturalWidth - minWidth);\n        let grow = 0;\n        if (totalGrowPotential > 0) {\n          grow = Math.floor(minWidthDelta / totalGrowPotential * extraWidth);\n        }\n        return minWidth + grow;\n      });\n      const allocated = columnWidths.reduce((a, b) => a + b, 0);\n      let remaining = availableForCells - allocated;\n      while (remaining > 0) {\n        let grew = false;\n        for (let i = 0; i < numCols && remaining > 0; i++) {\n          if (columnWidths[i] < naturalWidths[i]) {\n            columnWidths[i]++;\n            remaining--;\n            grew = true;\n          }\n        }\n        if (!grew) {\n          break;\n        }\n      }\n    }\n    const topBorderCells = columnWidths.map((w) => \"\\u2500\".repeat(w));\n    lines.push(`\\u250C\\u2500${topBorderCells.join(\"\\u2500\\u252C\\u2500\")}\\u2500\\u2510`);\n    const headerCellLines = token.header.map((cell, i) => {\n      const text = this.renderInlineTokens(cell.tokens || [], styleContext);\n      return this.wrapCellText(text, columnWidths[i]);\n    });\n    const headerLineCount = Math.max(...headerCellLines.map((c) => c.length));\n    for (let lineIdx = 0; lineIdx < headerLineCount; lineIdx++) {\n      const rowParts = headerCellLines.map((cellLines, colIdx) => {\n        const text = cellLines[lineIdx] || \"\";\n        const padded = text + \" \".repeat(Math.max(0, columnWidths[colIdx] - visibleWidth(text)));\n        return this.theme.bold(padded);\n      });\n      lines.push(`\\u2502 ${rowParts.join(\" \\u2502 \")} \\u2502`);\n    }\n    const separatorCells = columnWidths.map((w) => \"\\u2500\".repeat(w));\n    const separatorLine = `\\u251C\\u2500${separatorCells.join(\"\\u2500\\u253C\\u2500\")}\\u2500\\u2524`;\n    lines.push(separatorLine);\n    for (let rowIndex = 0; rowIndex < token.rows.length; rowIndex++) {\n      const row = token.rows[rowIndex];\n      const rowCellLines = row.map((cell, i) => {\n        const text = this.renderInlineTokens(cell.tokens || [], styleContext);\n        return this.wrapCellText(text, columnWidths[i]);\n      });\n      const rowLineCount = Math.max(...rowCellLines.map((c) => c.length));\n      for (let lineIdx = 0; lineIdx < rowLineCount; lineIdx++) {\n        const rowParts = rowCellLines.map((cellLines, colIdx) => {\n          const text = cellLines[lineIdx] || \"\";\n          return text + \" \".repeat(Math.max(0, columnWidths[colIdx] - visibleWidth(text)));\n        });\n        lines.push(`\\u2502 ${rowParts.join(\" \\u2502 \")} \\u2502`);\n      }\n      if (rowIndex < token.rows.length - 1) {\n        lines.push(separatorLine);\n      }\n    }\n    const bottomBorderCells = columnWidths.map((w) => \"\\u2500\".repeat(w));\n    lines.push(`\\u2514\\u2500${bottomBorderCells.join(\"\\u2500\\u2534\\u2500\")}\\u2500\\u2518`);\n    if (nextTokenType && nextTokenType !== \"space\") {\n      lines.push(\"\");\n    }\n    return lines;\n  }\n};\n\n// node_modules/.pnpm/@earendil-works+pi-tui@0.84.2/node_modules/@earendil-works/pi-tui/dist/components/scroll-view.js\nvar ScrollView = class extends Container {\n  child;\n  followEnd;\n  primary;\n  overscroll;\n  scrollbarStyle;\n  currentScrollbar;\n  scrollbarHideDelayMs;\n  currentScrollTop = 0;\n  contentHeight = 0;\n  currentViewportHeight = 0;\n  followingEnd;\n  followSuppressedAtEnd = false;\n  requestRenderCallback;\n  transientScrollbarVisible = false;\n  scrollbarActive = false;\n  scrollbarHideTimer;\n  constructor(component, options = {}) {\n    super();\n    if (options.axis !== void 0 && options.axis !== \"vertical\") {\n      throw new Error(`Unsupported ScrollView axis: ${options.axis}`);\n    }\n    this.child = component;\n    this.children.push(component);\n    this.followEnd = (options.follow ?? \"none\") === \"end\";\n    this.followingEnd = this.followEnd;\n    this.primary = options.primary ?? false;\n    this.overscroll = options.overscroll ?? \"chain\";\n    this.currentScrollbar = options.scrollbar ?? \"hidden\";\n    this.scrollbarStyle = options.scrollbarStyle ?? ((text) => `\\x1B[100m${text}\\x1B[49m`);\n    this.scrollbarHideDelayMs = Math.max(0, Math.floor(options.scrollbarHideDelayMs ?? 1e3));\n  }\n  get scrollTop() {\n    return this.currentScrollTop;\n  }\n  get isFollowingEnd() {\n    return this.followingEnd;\n  }\n  get viewportHeight() {\n    return this.currentViewportHeight;\n  }\n  get scrollbar() {\n    return this.currentScrollbar;\n  }\n  get isScrollbarVisible() {\n    if (this.scrollbar === \"always\")\n      return this.currentViewportHeight > 0;\n    return this.scrollbar === \"auto\" && this.contentHeight > this.currentViewportHeight && this.transientScrollbarVisible;\n  }\n  setScrollbar(scrollbar) {\n    if (scrollbar === this.currentScrollbar)\n      return;\n    this.currentScrollbar = scrollbar;\n    if (scrollbar !== \"auto\")\n      this.hideTransientScrollbar();\n    else if (this.scrollbarActive)\n      this.markScrollbarActivity();\n    this.requestRenderCallback?.();\n  }\n  getContentWidth(width) {\n    return this.scrollbar === \"always\" && width > 1 ? width - 1 : width;\n  }\n  markScrollbarActivity() {\n    if (this.scrollbar !== \"auto\" || this.contentHeight <= this.currentViewportHeight)\n      return;\n    this.transientScrollbarVisible = true;\n    if (this.scrollbarHideTimer) {\n      clearTimeout(this.scrollbarHideTimer);\n      this.scrollbarHideTimer = void 0;\n    }\n    if (this.scrollbarActive)\n      return;\n    this.scrollbarHideTimer = setTimeout(() => {\n      this.scrollbarHideTimer = void 0;\n      this.transientScrollbarVisible = false;\n      this.requestRenderCallback?.();\n    }, this.scrollbarHideDelayMs);\n    this.scrollbarHideTimer.unref();\n  }\n  hideTransientScrollbar() {\n    this.transientScrollbarVisible = false;\n    if (!this.scrollbarHideTimer)\n      return;\n    clearTimeout(this.scrollbarHideTimer);\n    this.scrollbarHideTimer = void 0;\n  }\n  setScrollbarActive(active) {\n    if (active === this.scrollbarActive)\n      return;\n    this.scrollbarActive = active;\n    this.markScrollbarActivity();\n  }\n  scrollTo(scrollTop, options = {}) {\n    const requested = Number.isFinite(scrollTop) ? Math.trunc(scrollTop) : this.currentScrollTop;\n    const maxScrollTop = Math.max(0, this.contentHeight - this.currentViewportHeight);\n    const next = Math.max(0, Math.min(maxScrollTop, requested));\n    const nextFollowSuppressedAtEnd = options.disableFollow === true && next === maxScrollTop;\n    const nextFollowingEnd = !nextFollowSuppressedAtEnd && this.followEnd && next === maxScrollTop;\n    if (next === this.currentScrollTop && nextFollowingEnd === this.followingEnd && nextFollowSuppressedAtEnd === this.followSuppressedAtEnd) {\n      return;\n    }\n    const moved = next !== this.currentScrollTop;\n    this.currentScrollTop = next;\n    this.followingEnd = nextFollowingEnd;\n    this.followSuppressedAtEnd = nextFollowSuppressedAtEnd;\n    if (moved)\n      this.markScrollbarActivity();\n    this.requestRenderCallback?.();\n  }\n  scrollBy(lines) {\n    const requested = Number.isFinite(lines) ? Math.trunc(lines) : 0;\n    if (requested === 0)\n      return 0;\n    const maxScrollTop = Math.max(0, this.contentHeight - this.currentViewportHeight);\n    const start = this.followingEnd ? maxScrollTop : this.currentScrollTop;\n    const next = Math.max(0, Math.min(maxScrollTop, start + requested));\n    const moved = next - start;\n    const wasFollowingEnd = this.followingEnd;\n    this.currentScrollTop = next;\n    this.followingEnd = this.followEnd && next === maxScrollTop;\n    this.followSuppressedAtEnd = false;\n    if (moved !== 0)\n      this.markScrollbarActivity();\n    if (moved !== 0 || this.followingEnd !== wasFollowingEnd)\n      this.requestRenderCallback?.();\n    return requested - moved;\n  }\n  scrollToStart() {\n    const changed = this.currentScrollTop !== 0 || this.followingEnd !== (this.followEnd && this.contentHeight <= this.currentViewportHeight);\n    this.currentScrollTop = 0;\n    this.followingEnd = this.followEnd && this.contentHeight <= this.currentViewportHeight;\n    this.followSuppressedAtEnd = false;\n    if (changed) {\n      this.markScrollbarActivity();\n      this.requestRenderCallback?.();\n    }\n  }\n  scrollToEnd() {\n    const next = Math.max(0, this.contentHeight - this.currentViewportHeight);\n    const changed = this.currentScrollTop !== next || this.followingEnd !== this.followEnd;\n    this.currentScrollTop = next;\n    this.followingEnd = this.followEnd;\n    this.followSuppressedAtEnd = false;\n    if (changed) {\n      this.markScrollbarActivity();\n      this.requestRenderCallback?.();\n    }\n  }\n  updateLayout(contentHeight, viewportHeight, requestRender) {\n    this.contentHeight = Math.max(0, Math.floor(contentHeight));\n    this.currentViewportHeight = Math.max(0, Math.floor(viewportHeight));\n    this.requestRenderCallback = requestRender;\n    const maxScrollTop = Math.max(0, this.contentHeight - this.currentViewportHeight);\n    if (this.followingEnd)\n      this.currentScrollTop = maxScrollTop;\n    else\n      this.currentScrollTop = Math.max(0, Math.min(this.currentScrollTop, maxScrollTop));\n    if (this.currentScrollTop < maxScrollTop)\n      this.followSuppressedAtEnd = false;\n    if (this.followEnd && this.currentScrollTop === maxScrollTop && !this.followSuppressedAtEnd) {\n      this.followingEnd = true;\n    }\n    if (this.contentHeight <= this.currentViewportHeight)\n      this.hideTransientScrollbar();\n  }\n  addChild(_component) {\n    throw new Error(\"ScrollView has exactly one child\");\n  }\n  removeChild(_component) {\n    throw new Error(\"ScrollView child cannot be removed\");\n  }\n  clear() {\n    throw new Error(\"ScrollView child cannot be cleared\");\n  }\n  render(width) {\n    const contentWidth = this.getContentWidth(width);\n    const lines = this.child.render(contentWidth);\n    return contentWidth === width ? lines : lines.map((line) => `${line} `);\n  }\n  [LAYOUT_NODE]() {\n    return { type: \"scroll\", component: this.child, state: this };\n  }\n};\n\n// node_modules/.pnpm/@earendil-works+pi-tui@0.84.2/node_modules/@earendil-works/pi-tui/dist/components/settings-list.js\nvar SettingsList = class {\n  items;\n  filteredItems;\n  theme;\n  selectedIndex = 0;\n  maxVisible;\n  onChange;\n  onCancel;\n  searchInput;\n  searchEnabled;\n  // Submenu state\n  submenuComponent = null;\n  submenuItemIndex = null;\n  constructor(items, maxVisible, theme2, onChange, onCancel, options = {}) {\n    this.items = items;\n    this.filteredItems = items;\n    this.maxVisible = maxVisible;\n    this.theme = theme2;\n    this.onChange = onChange;\n    this.onCancel = onCancel;\n    this.searchEnabled = options.enableSearch ?? false;\n    if (this.searchEnabled) {\n      this.searchInput = new Input();\n    }\n  }\n  /** Update an item's currentValue */\n  updateValue(id, newValue) {\n    const item = this.items.find((i) => i.id === id);\n    if (item) {\n      item.currentValue = newValue;\n    }\n  }\n  invalidate() {\n    this.submenuComponent?.invalidate?.();\n  }\n  render(width) {\n    if (this.submenuComponent) {\n      return this.submenuComponent.render(width);\n    }\n    return this.renderMainList(width);\n  }\n  renderMainList(width) {\n    const lines = [];\n    if (this.searchEnabled && this.searchInput) {\n      lines.push(...this.searchInput.render(width));\n      lines.push(\"\");\n    }\n    if (this.items.length === 0) {\n      lines.push(this.theme.hint(\"  No settings available\"));\n      if (this.searchEnabled) {\n        this.addHintLine(lines, width);\n      }\n      return lines;\n    }\n    const displayItems = this.searchEnabled ? this.filteredItems : this.items;\n    if (displayItems.length === 0) {\n      lines.push(truncateToWidth(this.theme.hint(\"  No matching settings\"), width));\n      this.addHintLine(lines, width);\n      return lines;\n    }\n    const startIndex = Math.max(0, Math.min(this.selectedIndex - Math.floor(this.maxVisible / 2), displayItems.length - this.maxVisible));\n    const endIndex = Math.min(startIndex + this.maxVisible, displayItems.length);\n    const maxLabelWidth = Math.min(30, Math.max(...this.items.map((item) => visibleWidth(item.label))));\n    for (let i = startIndex; i < endIndex; i++) {\n      const item = displayItems[i];\n      if (!item)\n        continue;\n      const isSelected = i === this.selectedIndex;\n      const prefix = isSelected ? this.theme.cursor : \"  \";\n      const prefixWidth = visibleWidth(prefix);\n      const labelPadded = item.label + \" \".repeat(Math.max(0, maxLabelWidth - visibleWidth(item.label)));\n      const labelText = this.theme.label(labelPadded, isSelected);\n      const separator = \"  \";\n      const usedWidth = prefixWidth + maxLabelWidth + visibleWidth(separator);\n      const valueMaxWidth = width - usedWidth - 2;\n      const valueText = this.theme.value(truncateToWidth(item.currentValue, valueMaxWidth, \"\"), isSelected);\n      lines.push(truncateToWidth(prefix + labelText + separator + valueText, width));\n    }\n    if (startIndex > 0 || endIndex < displayItems.length) {\n      const scrollText = `  (${this.selectedIndex + 1}/${displayItems.length})`;\n      lines.push(this.theme.hint(truncateToWidth(scrollText, width - 2, \"\")));\n    }\n    const selectedItem = displayItems[this.selectedIndex];\n    if (selectedItem?.description) {\n      lines.push(\"\");\n      const wrappedDesc = wrapTextWithAnsi(selectedItem.description, width - 4);\n      for (const line of wrappedDesc) {\n        lines.push(this.theme.description(`  ${line}`));\n      }\n    }\n    this.addHintLine(lines, width);\n    return lines;\n  }\n  handleInput(data) {\n    if (this.submenuComponent) {\n      this.submenuComponent.handleInput?.(data);\n      return;\n    }\n    const kb = getKeybindings();\n    const displayItems = this.searchEnabled ? this.filteredItems : this.items;\n    if (kb.matches(data, \"tui.select.up\")) {\n      if (displayItems.length === 0)\n        return;\n      this.selectedIndex = this.selectedIndex === 0 ? displayItems.length - 1 : this.selectedIndex - 1;\n    } else if (kb.matches(data, \"tui.select.down\")) {\n      if (displayItems.length === 0)\n        return;\n      this.selectedIndex = this.selectedIndex === displayItems.length - 1 ? 0 : this.selectedIndex + 1;\n    } else if (kb.matches(data, \"tui.select.confirm\") || data === \" \" && (!this.searchEnabled || this.searchInput?.getValue().length === 0)) {\n      this.activateItem();\n    } else if (kb.matches(data, \"tui.select.cancel\")) {\n      this.onCancel();\n    } else if (this.searchEnabled && this.searchInput) {\n      this.searchInput.handleInput(data);\n      this.applyFilter(this.searchInput.getValue());\n    }\n  }\n  activateItem() {\n    const item = this.searchEnabled ? this.filteredItems[this.selectedIndex] : this.items[this.selectedIndex];\n    if (!item)\n      return;\n    if (item.submenu) {\n      this.submenuItemIndex = this.selectedIndex;\n      this.submenuComponent = item.submenu(item.currentValue, (selectedValue) => {\n        if (selectedValue !== void 0) {\n          item.currentValue = selectedValue;\n          this.onChange(item.id, selectedValue);\n        }\n        this.closeSubmenu();\n      });\n    } else if (item.values && item.values.length > 0) {\n      const currentIndex = item.values.indexOf(item.currentValue);\n      const nextIndex = (currentIndex + 1) % item.values.length;\n      const newValue = item.values[nextIndex];\n      item.currentValue = newValue;\n      this.onChange(item.id, newValue);\n    }\n  }\n  closeSubmenu() {\n    this.submenuComponent = null;\n    if (this.submenuItemIndex !== null) {\n      this.selectedIndex = this.submenuItemIndex;\n      this.submenuItemIndex = null;\n    }\n  }\n  applyFilter(query) {\n    this.filteredItems = fuzzyFilter(this.items, query, (item) => item.label);\n    this.selectedIndex = 0;\n  }\n  addHintLine(lines, width) {\n    lines.push(\"\");\n    lines.push(truncateToWidth(this.theme.hint(this.searchEnabled ? \"  Type to search \\xB7 Enter/Space to change \\xB7 Esc to cancel\" : \"  Enter/Space to change \\xB7 Esc to cancel\"), width));\n  }\n};\n\n// node_modules/.pnpm/@earendil-works+pi-tui@0.84.2/node_modules/@earendil-works/pi-tui/dist/components/spacer.js\nvar Spacer = class {\n  lines;\n  constructor(lines = 1) {\n    this.lines = lines;\n  }\n  setLines(lines) {\n    this.lines = lines;\n  }\n  invalidate() {\n  }\n  render(_width) {\n    const result = [];\n    for (let i = 0; i < this.lines; i++) {\n      result.push(\"\");\n    }\n    return result;\n  }\n};\n\n// node_modules/.pnpm/@earendil-works+pi-tui@0.84.2/node_modules/@earendil-works/pi-tui/dist/components/truncated-text.js\nvar TruncatedText = class {\n  text;\n  paddingX;\n  paddingY;\n  constructor(text, paddingX = 0, paddingY = 0) {\n    this.text = text;\n    this.paddingX = paddingX;\n    this.paddingY = paddingY;\n  }\n  invalidate() {\n  }\n  render(width) {\n    const result = [];\n    const emptyLine = \" \".repeat(width);\n    for (let i = 0; i < this.paddingY; i++) {\n      result.push(emptyLine);\n    }\n    const availableWidth = Math.max(1, width - this.paddingX * 2);\n    let singleLineText = this.text;\n    const newlineIndex = this.text.indexOf(\"\\n\");\n    if (newlineIndex !== -1) {\n      singleLineText = this.text.substring(0, newlineIndex);\n    }\n    const displayText = truncateToWidth(singleLineText, availableWidth);\n    const leftPadding = \" \".repeat(this.paddingX);\n    const rightPadding = \" \".repeat(this.paddingX);\n    const lineWithPadding = leftPadding + displayText + rightPadding;\n    const lineVisibleWidth = visibleWidth(lineWithPadding);\n    const paddingNeeded = Math.max(0, width - lineVisibleWidth);\n    const finalLine = lineWithPadding + \" \".repeat(paddingNeeded);\n    result.push(finalLine);\n    for (let i = 0; i < this.paddingY; i++) {\n      result.push(emptyLine);\n    }\n    return result;\n  }\n};\n\n// node_modules/.pnpm/@earendil-works+pi-tui@0.84.2/node_modules/@earendil-works/pi-tui/dist/components/v-stack.js\nvar VStack = class extends Stack {\n  layoutType = \"vstack\";\n  constructor(children = [], options = {}) {\n    super(children, options);\n  }\n  render(width) {\n    const viewport = { width: Math.max(1, width), height: Number.MAX_SAFE_INTEGER };\n    const entries = visibleStackEntries(this.entries, viewport);\n    const rendered = entries.map((entry) => entry.component.render(viewport.width));\n    const sizes = allocateStackSizes(entries, rendered.map((lines2) => lines2.length), void 0, this.gap);\n    const lines = [];\n    for (let index = 0; index < entries.length; index++) {\n      if (index > 0) {\n        for (let gap = 0; gap < this.gap; gap++)\n          lines.push(\"\");\n      }\n      const childLines = rendered[index].slice(0, sizes[index]);\n      lines.push(...childLines);\n      for (let padding = childLines.length; padding < sizes[index]; padding++)\n        lines.push(\"\");\n    }\n    return lines;\n  }\n};\n\n// node_modules/.pnpm/@earendil-works+pi-tui@0.84.2/node_modules/@earendil-works/pi-tui/dist/stdin-buffer.js\nimport { EventEmitter as EventEmitter2 } from \"events\";\nvar ESC = \"\\x1B\";\nvar DEFAULT_SEQUENCE_TIMEOUT_MS = 50;\nvar DEFAULT_ESCAPE_TIMEOUT_MS = 10;\nvar BRACKETED_PASTE_START = \"\\x1B[200~\";\nvar BRACKETED_PASTE_END = \"\\x1B[201~\";\nfunction isCompleteSequence(data) {\n  if (!data.startsWith(ESC)) {\n    return \"not-escape\";\n  }\n  if (data.length === 1) {\n    return \"incomplete\";\n  }\n  const afterEsc = data.slice(1);\n  if (afterEsc.startsWith(\"[\")) {\n    if (afterEsc.startsWith(\"[M\")) {\n      return data.length >= 6 ? \"complete\" : \"incomplete\";\n    }\n    return isCompleteCsiSequence(data);\n  }\n  if (afterEsc.startsWith(\"]\")) {\n    return isCompleteOscSequence(data);\n  }\n  if (afterEsc.startsWith(\"P\")) {\n    return isCompleteDcsSequence(data);\n  }\n  if (afterEsc.startsWith(\"_\")) {\n    return isCompleteApcSequence(data);\n  }\n  if (afterEsc.startsWith(\"O\")) {\n    return afterEsc.length >= 2 ? \"complete\" : \"incomplete\";\n  }\n  if (afterEsc.length === 1) {\n    return \"complete\";\n  }\n  return \"complete\";\n}\nfunction isCompleteCsiSequence(data) {\n  if (!data.startsWith(`${ESC}[`)) {\n    return \"complete\";\n  }\n  if (data.length < 3) {\n    return \"incomplete\";\n  }\n  const payload = data.slice(2);\n  const lastChar = payload[payload.length - 1];\n  const lastCharCode = lastChar.charCodeAt(0);\n  if (lastCharCode >= 64 && lastCharCode <= 126) {\n    if (payload.startsWith(\"<\")) {\n      const mouseMatch = /^<\\d+;\\d+;\\d+[Mm]$/.test(payload);\n      if (mouseMatch) {\n        return \"complete\";\n      }\n      if (lastChar === \"M\" || lastChar === \"m\") {\n        const parts = payload.slice(1, -1).split(\";\");\n        if (parts.length === 3 && parts.every((p) => /^\\d+$/.test(p))) {\n          return \"complete\";\n        }\n      }\n      return \"incomplete\";\n    }\n    return \"complete\";\n  }\n  return \"incomplete\";\n}\nfunction isCompleteOscSequence(data) {\n  if (!data.startsWith(`${ESC}]`)) {\n    return \"complete\";\n  }\n  if (data.endsWith(`${ESC}\\\\`) || data.endsWith(\"\\x07\")) {\n    return \"complete\";\n  }\n  return \"incomplete\";\n}\nfunction isCompleteDcsSequence(data) {\n  if (!data.startsWith(`${ESC}P`)) {\n    return \"complete\";\n  }\n  if (data.endsWith(`${ESC}\\\\`)) {\n    return \"complete\";\n  }\n  return \"incomplete\";\n}\nfunction isCompleteApcSequence(data) {\n  if (!data.startsWith(`${ESC}_`)) {\n    return \"complete\";\n  }\n  if (data.endsWith(`${ESC}\\\\`)) {\n    return \"complete\";\n  }\n  return \"incomplete\";\n}\nfunction parseUnmodifiedKittyPrintableCodepoint(sequence3) {\n  const match = sequence3.match(/^\\x1b\\[(\\d+)(?::\\d*)?(?::\\d+)?u$/);\n  if (!match)\n    return void 0;\n  const codepoint = parseInt(match[1], 10);\n  return codepoint >= 32 ? codepoint : void 0;\n}\nfunction extractCompleteSequences(buffer) {\n  const sequences = [];\n  let pos = 0;\n  while (pos < buffer.length) {\n    const remaining = buffer.slice(pos);\n    if (remaining.startsWith(ESC)) {\n      let seqEnd = 1;\n      while (seqEnd <= remaining.length) {\n        const candidate = remaining.slice(0, seqEnd);\n        const status = isCompleteSequence(candidate);\n        if (status === \"complete\") {\n          if (candidate === \"\\x1B\\x1B\") {\n            const nextChar = remaining[seqEnd];\n            if (nextChar === \"[\" || // CSI\n            nextChar === \"]\" || // OSC\n            nextChar === \"O\" || // SS3\n            nextChar === \"P\" || // DCS\n            nextChar === \"_\") {\n              sequences.push(ESC);\n              pos += 1;\n              break;\n            }\n          }\n          sequences.push(candidate);\n          pos += seqEnd;\n          break;\n        } else if (status === \"incomplete\") {\n          seqEnd++;\n        } else {\n          sequences.push(candidate);\n          pos += seqEnd;\n          break;\n        }\n      }\n      if (seqEnd > remaining.length) {\n        return { sequences, remainder: remaining };\n      }\n    } else {\n      sequences.push(remaining[0]);\n      pos++;\n    }\n  }\n  return { sequences, remainder: \"\" };\n}\nvar StdinBuffer = class extends EventEmitter2 {\n  buffer = \"\";\n  timeout = null;\n  timeoutMs;\n  escapeTimeoutMs;\n  pasteMode = false;\n  pasteBuffer = \"\";\n  pendingKittyPrintableCodepoint;\n  constructor(options = {}) {\n    super();\n    this.timeoutMs = options.timeout ?? DEFAULT_SEQUENCE_TIMEOUT_MS;\n    this.escapeTimeoutMs = options.escapeTimeout ?? DEFAULT_ESCAPE_TIMEOUT_MS;\n  }\n  process(data) {\n    if (this.timeout) {\n      clearTimeout(this.timeout);\n      this.timeout = null;\n    }\n    let str2;\n    if (Buffer.isBuffer(data)) {\n      if (data.length === 1 && data[0] > 127) {\n        const byte = data[0] - 128;\n        str2 = `\\x1B${String.fromCharCode(byte)}`;\n      } else {\n        str2 = data.toString();\n      }\n    } else {\n      str2 = data;\n    }\n    if (str2.length === 0 && this.buffer.length === 0) {\n      this.emitDataSequence(\"\");\n      return;\n    }\n    this.buffer += str2;\n    if (this.pasteMode) {\n      this.pasteBuffer += this.buffer;\n      this.buffer = \"\";\n      const endIndex = this.pasteBuffer.indexOf(BRACKETED_PASTE_END);\n      if (endIndex !== -1) {\n        const pastedContent = this.pasteBuffer.slice(0, endIndex);\n        const remaining = this.pasteBuffer.slice(endIndex + BRACKETED_PASTE_END.length);\n        this.pasteMode = false;\n        this.pasteBuffer = \"\";\n        this.pendingKittyPrintableCodepoint = void 0;\n        this.emit(\"paste\", pastedContent);\n        if (remaining.length > 0) {\n          this.process(remaining);\n        }\n      }\n      return;\n    }\n    const startIndex = this.buffer.indexOf(BRACKETED_PASTE_START);\n    if (startIndex !== -1) {\n      if (startIndex > 0) {\n        const beforePaste = this.buffer.slice(0, startIndex);\n        const result2 = extractCompleteSequences(beforePaste);\n        for (const sequence3 of result2.sequences) {\n          this.emitDataSequence(sequence3);\n        }\n      }\n      this.pendingKittyPrintableCodepoint = void 0;\n      this.buffer = this.buffer.slice(startIndex + BRACKETED_PASTE_START.length);\n      this.pasteMode = true;\n      this.pasteBuffer = this.buffer;\n      this.buffer = \"\";\n      const endIndex = this.pasteBuffer.indexOf(BRACKETED_PASTE_END);\n      if (endIndex !== -1) {\n        const pastedContent = this.pasteBuffer.slice(0, endIndex);\n        const remaining = this.pasteBuffer.slice(endIndex + BRACKETED_PASTE_END.length);\n        this.pasteMode = false;\n        this.pasteBuffer = \"\";\n        this.pendingKittyPrintableCodepoint = void 0;\n        this.emit(\"paste\", pastedContent);\n        if (remaining.length > 0) {\n          this.process(remaining);\n        }\n      }\n      return;\n    }\n    const result = extractCompleteSequences(this.buffer);\n    this.buffer = result.remainder;\n    for (const sequence3 of result.sequences) {\n      this.emitDataSequence(sequence3);\n    }\n    if (this.buffer.length > 0) {\n      const timeoutMs = this.buffer === ESC ? this.escapeTimeoutMs : this.timeoutMs;\n      this.timeout = setTimeout(() => {\n        const flushed = this.flush();\n        for (const sequence3 of flushed) {\n          this.emitDataSequence(sequence3);\n        }\n      }, timeoutMs);\n    }\n  }\n  emitDataSequence(sequence3) {\n    const rawCodepoint = sequence3.length === 1 ? sequence3.codePointAt(0) : void 0;\n    if (rawCodepoint !== void 0 && rawCodepoint === this.pendingKittyPrintableCodepoint) {\n      this.pendingKittyPrintableCodepoint = void 0;\n      return;\n    }\n    this.pendingKittyPrintableCodepoint = parseUnmodifiedKittyPrintableCodepoint(sequence3);\n    this.emit(\"data\", sequence3);\n  }\n  flush() {\n    if (this.timeout) {\n      clearTimeout(this.timeout);\n      this.timeout = null;\n    }\n    if (this.buffer.length === 0) {\n      return [];\n    }\n    const sequences = [this.buffer];\n    this.buffer = \"\";\n    this.pendingKittyPrintableCodepoint = void 0;\n    return sequences;\n  }\n  clear() {\n    if (this.timeout) {\n      clearTimeout(this.timeout);\n      this.timeout = null;\n    }\n    this.buffer = \"\";\n    this.pasteMode = false;\n    this.pasteBuffer = \"\";\n    this.pendingKittyPrintableCodepoint = void 0;\n  }\n  getBuffer() {\n    return this.buffer;\n  }\n  destroy() {\n    this.clear();\n  }\n};\n\n// node_modules/.pnpm/@earendil-works+pi-tui@0.84.2/node_modules/@earendil-works/pi-tui/dist/terminal.js\nimport * as fs2 from \"node:fs\";\nimport { createRequire as createRequire3 } from \"node:module\";\nimport * as path4 from \"node:path\";\nimport { fileURLToPath as fileURLToPath5 } from \"node:url\";\n\n// node_modules/.pnpm/@earendil-works+pi-tui@0.84.2/node_modules/@earendil-works/pi-tui/dist/native-modifiers.js\nimport { createRequire as createRequire2 } from \"node:module\";\nimport * as path3 from \"node:path\";\nimport { fileURLToPath as fileURLToPath4 } from \"node:url\";\nvar cjsRequire = createRequire2(import.meta.url);\nvar nativeModifiersHelper;\nfunction isNativeModifiersHelper(value) {\n  if (typeof value !== \"object\" || value === null)\n    return false;\n  const candidate = value.isModifierPressed;\n  return typeof candidate === \"function\";\n}\nfunction loadNativeModifiersHelper() {\n  if (nativeModifiersHelper !== void 0)\n    return nativeModifiersHelper ?? void 0;\n  nativeModifiersHelper = null;\n  const arch2 = process.arch;\n  if (arch2 !== \"x64\" && arch2 !== \"arm64\")\n    return void 0;\n  let nativePath;\n  if (process.platform === \"darwin\") {\n    nativePath = path3.join(\"native\", \"darwin\", \"prebuilds\", `darwin-${arch2}`, \"darwin-modifiers.node\");\n  } else if (process.platform === \"win32\") {\n    nativePath = path3.join(\"native\", \"win32\", \"prebuilds\", `win32-${arch2}`, \"win32-console-mode.node\");\n  } else {\n    return void 0;\n  }\n  const moduleDir = path3.dirname(fileURLToPath4(import.meta.url));\n  const candidates = [\n    path3.join(moduleDir, \"..\", nativePath),\n    path3.join(moduleDir, nativePath),\n    path3.join(path3.dirname(process.execPath), nativePath)\n  ];\n  for (const modulePath of candidates) {\n    try {\n      const helper = cjsRequire(modulePath);\n      if (isNativeModifiersHelper(helper)) {\n        nativeModifiersHelper = helper;\n        return helper;\n      }\n    } catch {\n    }\n  }\n  return void 0;\n}\nfunction isNativeModifierPressed(key) {\n  const helper = loadNativeModifiersHelper();\n  if (!helper)\n    return false;\n  try {\n    return helper.isModifierPressed(key) === true;\n  } catch {\n    return false;\n  }\n}\n\n// node_modules/.pnpm/@earendil-works+pi-tui@0.84.2/node_modules/@earendil-works/pi-tui/dist/terminal.js\nvar cjsRequire2 = createRequire3(import.meta.url);\nvar TERMINAL_PROGRESS_KEEPALIVE_MS = 1e3;\nvar TERMINAL_PROGRESS_ACTIVE_SEQUENCE = \"\\x1B]9;4;3\\x07\";\nvar TERMINAL_PROGRESS_CLEAR_SEQUENCE = \"\\x1B]9;4;0\\x07\";\nvar NATIVE_SHIFT_ENTER_SEQUENCE = \"\\x1B[13;2u\";\nvar DESIRED_KITTY_KEYBOARD_PROTOCOL_FLAGS = 7;\nvar KEYBOARD_PROTOCOL_RESPONSE_FRAGMENT_TIMEOUT_MS = 150;\nvar KITTY_KEYBOARD_PROTOCOL_QUERY = `\\x1B[>${DESIRED_KITTY_KEYBOARD_PROTOCOL_FLAGS}u\\x1B[?u\\x1B[c`;\nfunction parseKeyboardProtocolNegotiationSequence(sequence3) {\n  const kittyFlags = sequence3.match(/^\\x1b\\[\\?(\\d+)u$/);\n  if (kittyFlags) {\n    return { type: \"kitty-flags\", flags: Number.parseInt(kittyFlags[1], 10) };\n  }\n  if (/^\\x1b\\[\\?[\\d;]*c$/.test(sequence3)) {\n    return { type: \"device-attributes\" };\n  }\n  return void 0;\n}\nfunction isKeyboardProtocolNegotiationSequencePrefix(sequence3) {\n  return sequence3 === \"\\x1B[\" || /^\\x1b\\[\\?[\\d;]*$/.test(sequence3);\n}\nfunction isAppleTerminalSession() {\n  return process.platform === \"darwin\" && process.env.TERM_PROGRAM === \"Apple_Terminal\";\n}\nfunction normalizeNativeShiftEnterInput(data, shouldDetectNativeShiftEnter, isShiftPressed) {\n  if (shouldDetectNativeShiftEnter && data === \"\\r\" && isShiftPressed)\n    return NATIVE_SHIFT_ENTER_SEQUENCE;\n  return data;\n}\nvar DEFAULT_ESCAPE_TIMEOUT_MS2 = 10;\nvar DEFAULT_SSH_ESCAPE_TIMEOUT_MS = 100;\nfunction resolveEscapeTimeoutMs(env = process.env) {\n  const configured = Number(env.PI_TUI_ESC_TIMEOUT);\n  if (Number.isFinite(configured) && configured > 0) {\n    return configured;\n  }\n  if (env.SSH_CONNECTION || env.SSH_TTY) {\n    return DEFAULT_SSH_ESCAPE_TIMEOUT_MS;\n  }\n  return DEFAULT_ESCAPE_TIMEOUT_MS2;\n}\nvar ProcessTerminal = class {\n  wasRaw = false;\n  inputHandler;\n  resizeHandler;\n  _kittyProtocolActive = false;\n  _modifyOtherKeysActive = false;\n  keyboardProtocolPushed = false;\n  keyboardProtocolNegotiationBuffer = \"\";\n  keyboardProtocolBufferFlushTimer;\n  stdinBuffer;\n  stdinDataHandler;\n  progressInterval;\n  writeLogPath = (() => {\n    const env = process.env.PI_TUI_WRITE_LOG || \"\";\n    if (!env)\n      return \"\";\n    try {\n      if (fs2.statSync(env).isDirectory()) {\n        const now = /* @__PURE__ */ new Date();\n        const ts = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, \"0\")}-${String(now.getDate()).padStart(2, \"0\")}_${String(now.getHours()).padStart(2, \"0\")}-${String(now.getMinutes()).padStart(2, \"0\")}-${String(now.getSeconds()).padStart(2, \"0\")}`;\n        return path4.join(env, `tui-${ts}-${process.pid}.log`);\n      }\n    } catch {\n    }\n    return env;\n  })();\n  get kittyProtocolActive() {\n    return this._kittyProtocolActive;\n  }\n  get modifyOtherKeysActive() {\n    return this._modifyOtherKeysActive;\n  }\n  start(onInput, onResize) {\n    this.inputHandler = onInput;\n    this.resizeHandler = onResize;\n    this.wasRaw = process.stdin.isRaw || false;\n    if (process.stdin.setRawMode) {\n      process.stdin.setRawMode(true);\n    }\n    process.stdin.setEncoding(\"utf8\");\n    process.stdin.resume();\n    process.stdout.write(\"\\x1B[?2004h\");\n    process.stdout.on(\"resize\", this.resizeHandler);\n    if (process.platform !== \"win32\") {\n      process.kill(process.pid, \"SIGWINCH\");\n    }\n    this.enableWindowsVTInput();\n    this.queryAndEnableKittyProtocol();\n  }\n  /**\n   * Set up StdinBuffer to split batched input into individual sequences.\n   * This ensures components receive single events, making matchesKey/isKeyRelease work correctly.\n   *\n   * Also watches for Kitty protocol response and enables it when detected.\n   * This is done here (after stdinBuffer parsing) rather than on raw stdin\n   * to handle the case where the response arrives split across multiple events.\n   */\n  setupStdinBuffer() {\n    this.stdinBuffer = new StdinBuffer({ escapeTimeout: resolveEscapeTimeoutMs() });\n    this.stdinBuffer.on(\"data\", (sequence3) => {\n      const negotiationSequence = this.readKeyboardProtocolNegotiationSequence(sequence3);\n      if (negotiationSequence === \"pending\") {\n        this.scheduleKeyboardProtocolNegotiationBufferFlush();\n        return;\n      }\n      if (this.handleKeyboardProtocolNegotiationSequence(negotiationSequence)) {\n        return;\n      }\n      this.forwardInputSequence(sequence3);\n    });\n    this.stdinBuffer.on(\"paste\", (content) => {\n      if (this.inputHandler) {\n        this.inputHandler(`\\x1B[200~${content}\\x1B[201~`);\n      }\n    });\n    this.stdinDataHandler = (data) => {\n      this.stdinBuffer.process(data);\n    };\n  }\n  /**\n   * Query terminal for Kitty keyboard protocol support and enable it if available.\n   *\n   * Kitty's progressive enhancement detection requires requesting the desired\n   * flags before querying them. The trailing DA query is a sentinel supported by\n   * terminals that do not know Kitty keyboard protocol; receiving DA before a\n   * Kitty response enables modifyOtherKeys fallback without a startup timeout.\n   *\n   * The requested flags are:\n   * - 1 = disambiguate escape codes\n   * - 2 = report event types (press/repeat/release)\n   * - 4 = report alternate keys (shifted key, base layout key)\n   */\n  queryAndEnableKittyProtocol() {\n    this.setupStdinBuffer();\n    process.stdin.on(\"data\", this.stdinDataHandler);\n    this.keyboardProtocolPushed = true;\n    this.clearKeyboardProtocolNegotiationBuffer();\n    process.stdout.write(KITTY_KEYBOARD_PROTOCOL_QUERY);\n  }\n  handleKeyboardProtocolNegotiationSequence(negotiationSequence) {\n    if (!negotiationSequence)\n      return false;\n    this.clearKeyboardProtocolNegotiationBuffer();\n    if (negotiationSequence.type === \"kitty-flags\") {\n      if (negotiationSequence.flags !== 0) {\n        this.disableModifyOtherKeys();\n        if (!this._kittyProtocolActive) {\n          this._kittyProtocolActive = true;\n          setKittyProtocolActive(true);\n        }\n      } else {\n        this.enableModifyOtherKeys();\n      }\n      return true;\n    }\n    if (!this._kittyProtocolActive) {\n      this.enableModifyOtherKeys();\n    }\n    return true;\n  }\n  readKeyboardProtocolNegotiationSequence(sequence3) {\n    if (this.keyboardProtocolNegotiationBuffer) {\n      const bufferedSequence = this.keyboardProtocolNegotiationBuffer + sequence3;\n      const negotiationSequence2 = parseKeyboardProtocolNegotiationSequence(bufferedSequence);\n      if (negotiationSequence2) {\n        this.clearKeyboardProtocolNegotiationBuffer();\n        return negotiationSequence2;\n      }\n      if (isKeyboardProtocolNegotiationSequencePrefix(bufferedSequence)) {\n        this.setKeyboardProtocolNegotiationBuffer(bufferedSequence);\n        return \"pending\";\n      }\n      this.flushKeyboardProtocolNegotiationBufferAsInput();\n    }\n    const negotiationSequence = parseKeyboardProtocolNegotiationSequence(sequence3);\n    if (negotiationSequence)\n      return negotiationSequence;\n    if (isKeyboardProtocolNegotiationSequencePrefix(sequence3)) {\n      this.setKeyboardProtocolNegotiationBuffer(sequence3);\n      return \"pending\";\n    }\n    return void 0;\n  }\n  setKeyboardProtocolNegotiationBuffer(sequence3) {\n    this.clearKeyboardProtocolNegotiationBufferFlushTimer();\n    this.keyboardProtocolNegotiationBuffer = sequence3;\n  }\n  clearKeyboardProtocolNegotiationBuffer() {\n    this.clearKeyboardProtocolNegotiationBufferFlushTimer();\n    this.keyboardProtocolNegotiationBuffer = \"\";\n  }\n  flushKeyboardProtocolNegotiationBufferAsInput() {\n    if (!this.keyboardProtocolNegotiationBuffer)\n      return;\n    const sequence3 = this.keyboardProtocolNegotiationBuffer;\n    this.clearKeyboardProtocolNegotiationBuffer();\n    this.forwardInputSequence(sequence3);\n  }\n  scheduleKeyboardProtocolNegotiationBufferFlush() {\n    if (!this.keyboardProtocolNegotiationBuffer || this.keyboardProtocolBufferFlushTimer)\n      return;\n    this.keyboardProtocolBufferFlushTimer = setTimeout(() => {\n      this.keyboardProtocolBufferFlushTimer = void 0;\n      this.flushKeyboardProtocolNegotiationBufferAsInput();\n    }, KEYBOARD_PROTOCOL_RESPONSE_FRAGMENT_TIMEOUT_MS);\n  }\n  clearKeyboardProtocolNegotiationBufferFlushTimer() {\n    if (!this.keyboardProtocolBufferFlushTimer)\n      return;\n    clearTimeout(this.keyboardProtocolBufferFlushTimer);\n    this.keyboardProtocolBufferFlushTimer = void 0;\n  }\n  forwardInputSequence(sequence3) {\n    if (!this.inputHandler)\n      return;\n    const shouldDetectNativeShiftEnter = sequence3 === \"\\r\" && (isAppleTerminalSession() || process.platform === \"win32\");\n    const input = normalizeNativeShiftEnterInput(sequence3, shouldDetectNativeShiftEnter, shouldDetectNativeShiftEnter && isNativeModifierPressed(\"shift\"));\n    this.inputHandler(input);\n  }\n  enableModifyOtherKeys() {\n    if (this._kittyProtocolActive || this._modifyOtherKeysActive)\n      return;\n    process.stdout.write(\"\\x1B[>4;2m\");\n    this._modifyOtherKeysActive = true;\n  }\n  disableModifyOtherKeys() {\n    if (!this._modifyOtherKeysActive)\n      return;\n    process.stdout.write(\"\\x1B[>4;0m\");\n    this._modifyOtherKeysActive = false;\n  }\n  /**\n   * On Windows, add ENABLE_VIRTUAL_TERMINAL_INPUT (0x0200) to the stdin\n   * console handle so the terminal sends VT sequences for modified keys\n   * (e.g. \\x1b[Z for Shift+Tab). Without this, libuv's ReadConsoleInputW\n   * discards modifier state and Shift+Tab arrives as plain \\t.\n   */\n  enableWindowsVTInput() {\n    if (process.platform !== \"win32\")\n      return;\n    try {\n      const arch2 = process.arch;\n      if (arch2 !== \"x64\" && arch2 !== \"arm64\")\n        return;\n      const moduleDir = path4.dirname(fileURLToPath5(import.meta.url));\n      const nativePath = path4.join(\"native\", \"win32\", \"prebuilds\", `win32-${arch2}`, \"win32-console-mode.node\");\n      const candidates = [\n        path4.join(moduleDir, \"..\", nativePath),\n        path4.join(moduleDir, nativePath),\n        path4.join(path4.dirname(process.execPath), nativePath)\n      ];\n      for (const modulePath of candidates) {\n        try {\n          const helper = cjsRequire2(modulePath);\n          helper.enableVirtualTerminalInput?.();\n          return;\n        } catch {\n        }\n      }\n    } catch {\n    }\n  }\n  async drainInput(maxMs = 1e3, idleMs = 50) {\n    const shouldDisableKittyProtocol = this.keyboardProtocolPushed || this._kittyProtocolActive;\n    this.clearKeyboardProtocolNegotiationBuffer();\n    if (shouldDisableKittyProtocol) {\n      process.stdout.write(\"\\x1B[<u\");\n      this.keyboardProtocolPushed = false;\n      this._kittyProtocolActive = false;\n      setKittyProtocolActive(false);\n    }\n    this.disableModifyOtherKeys();\n    const previousHandler = this.inputHandler;\n    this.inputHandler = void 0;\n    let lastDataTime = Date.now();\n    const onData = () => {\n      lastDataTime = Date.now();\n    };\n    process.stdin.on(\"data\", onData);\n    const endTime = Date.now() + maxMs;\n    try {\n      while (true) {\n        const now = Date.now();\n        const timeLeft = endTime - now;\n        if (timeLeft <= 0)\n          break;\n        if (now - lastDataTime >= idleMs)\n          break;\n        await new Promise((resolve15) => setTimeout(resolve15, Math.min(idleMs, timeLeft)));\n      }\n    } finally {\n      process.stdin.removeListener(\"data\", onData);\n      this.inputHandler = previousHandler;\n    }\n  }\n  stop() {\n    if (this.clearProgressInterval()) {\n      process.stdout.write(TERMINAL_PROGRESS_CLEAR_SEQUENCE);\n    }\n    process.stdout.write(\"\\x1B[?2004l\");\n    const shouldDisableKittyProtocol = this.keyboardProtocolPushed || this._kittyProtocolActive;\n    this.clearKeyboardProtocolNegotiationBuffer();\n    if (shouldDisableKittyProtocol) {\n      process.stdout.write(\"\\x1B[<u\");\n      this.keyboardProtocolPushed = false;\n      this._kittyProtocolActive = false;\n      setKittyProtocolActive(false);\n    }\n    this.disableModifyOtherKeys();\n    if (this.stdinBuffer) {\n      this.stdinBuffer.destroy();\n      this.stdinBuffer = void 0;\n    }\n    if (this.stdinDataHandler) {\n      process.stdin.removeListener(\"data\", this.stdinDataHandler);\n      this.stdinDataHandler = void 0;\n    }\n    this.inputHandler = void 0;\n    if (this.resizeHandler) {\n      process.stdout.removeListener(\"resize\", this.resizeHandler);\n      this.resizeHandler = void 0;\n    }\n    process.stdin.pause();\n    if (process.stdin.setRawMode) {\n      process.stdin.setRawMode(this.wasRaw);\n    }\n  }\n  write(data) {\n    process.stdout.write(data);\n    if (this.writeLogPath) {\n      try {\n        fs2.appendFileSync(this.writeLogPath, data, { encoding: \"utf8\" });\n      } catch {\n      }\n    }\n  }\n  get columns() {\n    return process.stdout.columns || Number(process.env.COLUMNS) || 80;\n  }\n  get rows() {\n    return process.stdout.rows || Number(process.env.LINES) || 24;\n  }\n  moveBy(lines) {\n    if (lines > 0) {\n      process.stdout.write(`\\x1B[${lines}B`);\n    } else if (lines < 0) {\n      process.stdout.write(`\\x1B[${-lines}A`);\n    }\n  }\n  hideCursor() {\n    process.stdout.write(\"\\x1B[?25l\");\n  }\n  showCursor() {\n    process.stdout.write(\"\\x1B[?25h\");\n  }\n  clearLine() {\n    process.stdout.write(\"\\x1B[K\");\n  }\n  clearFromCursor() {\n    process.stdout.write(\"\\x1B[J\");\n  }\n  clearScreen() {\n    process.stdout.write(\"\\x1B[2J\\x1B[H\");\n  }\n  setTitle(title) {\n    process.stdout.write(`\\x1B]0;${title}\\x07`);\n  }\n  setProgress(active) {\n    if (active) {\n      process.stdout.write(TERMINAL_PROGRESS_ACTIVE_SEQUENCE);\n      if (!this.progressInterval) {\n        this.progressInterval = setInterval(() => {\n          process.stdout.write(TERMINAL_PROGRESS_ACTIVE_SEQUENCE);\n        }, TERMINAL_PROGRESS_KEEPALIVE_MS);\n      }\n    } else {\n      this.clearProgressInterval();\n      process.stdout.write(TERMINAL_PROGRESS_CLEAR_SEQUENCE);\n    }\n  }\n  clearProgressInterval() {\n    if (!this.progressInterval)\n      return false;\n    clearInterval(this.progressInterval);\n    this.progressInterval = void 0;\n    return true;\n  }\n};\n\n// node_modules/.pnpm/@earendil-works+pi-tui@0.84.2/node_modules/@earendil-works/pi-tui/dist/alt-screen-search.js\nvar segmenter2 = getGraphemeSegmenter();\nfunction appendMappedText(text, span, corpus) {\n  corpus.text += text;\n  for (let index = 0; index < text.length; index++)\n    corpus.source.push(span);\n}\nfunction buildSearchCorpus(lines) {\n  const corpus = { text: \"\", source: [] };\n  let pendingSeparator = false;\n  for (let row = 0; row < lines.length; row++) {\n    const line = stripTerminalSequences(lines[row] ?? \"\");\n    let column = 0;\n    for (const grapheme of segmenter2.segment(line)) {\n      const text = grapheme.segment;\n      const width = visibleWidth(text);\n      if (/^\\s+$/u.test(text)) {\n        if (corpus.text.length > 0)\n          pendingSeparator = true;\n        column += width;\n        continue;\n      }\n      if (pendingSeparator) {\n        appendMappedText(\" \", void 0, corpus);\n        pendingSeparator = false;\n      }\n      appendMappedText(text, { row, startCol: column, endCol: column + width }, corpus);\n      column += width;\n    }\n    if (corpus.text.length > 0)\n      pendingSeparator = true;\n  }\n  return corpus;\n}\nfunction normalizeQuery(query) {\n  return query.replace(/\\s+/gu, \" \").trim();\n}\nfunction escapeRegExp(text) {\n  return text.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\nfunction findAltScreenSearchMatches(lines, query) {\n  const normalizedQuery = normalizeQuery(query);\n  if (!normalizedQuery)\n    return [];\n  const corpus = buildSearchCorpus(lines);\n  const expression = new RegExp(escapeRegExp(normalizedQuery), \"giu\");\n  const matches = [];\n  for (const match of corpus.text.matchAll(expression)) {\n    const start = match.index;\n    const end = start + match[0].length;\n    const segments = [];\n    for (let index = start; index < end; index++) {\n      const span = corpus.source[index];\n      if (!span)\n        continue;\n      const previous = segments[segments.length - 1];\n      if (previous && previous.row === span.row && span.startCol <= previous.endCol) {\n        previous.endCol = Math.max(previous.endCol, span.endCol);\n      } else {\n        segments.push({ ...span });\n      }\n    }\n    if (segments.length > 0)\n      matches.push({ segments });\n  }\n  return matches;\n}\nfunction getAltScreenSearchMatchKey(match) {\n  const first = match.segments[0];\n  const last = match.segments[match.segments.length - 1];\n  return first && last ? `${first.row}:${first.startCol}:${last.row}:${last.endCol}` : \"\";\n}\nvar AltScreenSearchComponent = class {\n  input = new Input();\n  onQueryChange;\n  resultCount = 0;\n  resultIndex = -1;\n  _focused = false;\n  constructor(onQueryChange) {\n    this.onQueryChange = onQueryChange;\n  }\n  get focused() {\n    return this._focused;\n  }\n  set focused(value) {\n    this._focused = value;\n    this.input.focused = value;\n  }\n  setResult(index, count) {\n    this.resultIndex = index;\n    this.resultCount = count;\n  }\n  handleInput(data) {\n    const previous = this.input.getValue();\n    this.input.handleInput(data);\n    const query = this.input.getValue();\n    if (query !== previous)\n      this.onQueryChange(query);\n  }\n  invalidate() {\n    this.input.invalidate();\n  }\n  render(width) {\n    const safeWidth = Math.max(1, width);\n    const label = \" Find transcript\";\n    const query = this.input.getValue();\n    const status = !query ? \"\" : this.resultCount === 0 ? \"No matches \" : `${this.resultIndex + 1}/${this.resultCount} `;\n    const labelWidth = visibleWidth(label);\n    const statusWidth = visibleWidth(status);\n    const gap = \" \".repeat(Math.max(1, safeWidth - labelWidth - statusWidth));\n    const title = truncateToWidth(`${label}${gap}${status}`, safeWidth, \"\");\n    const padding = \" \".repeat(Math.max(0, safeWidth - visibleWidth(title)));\n    return [`\\x1B[7m${title}${padding}\\x1B[27m`, ...this.input.render(safeWidth)];\n  }\n};\n\n// node_modules/.pnpm/@earendil-works+pi-tui@0.84.2/node_modules/@earendil-works/pi-tui/dist/components/alt-screen-flash.js\nvar DEFAULT_DURATION_MS = 1e3;\nvar AltScreenFlashContainer = class {\n  entries = [];\n  nextId = 0;\n  requestRender;\n  constructor(requestRender) {\n    this.requestRender = requestRender;\n  }\n  flash(message, durationMs = DEFAULT_DURATION_MS) {\n    const id = this.nextId++;\n    const timer = setTimeout(() => {\n      const index = this.entries.findIndex((entry) => entry.id === id);\n      if (index === -1)\n        return;\n      this.entries.splice(index, 1);\n      this.requestRender();\n    }, Math.max(0, durationMs));\n    timer.unref();\n    this.entries.push({ id, message, timer });\n    this.requestRender();\n  }\n  dispose() {\n    for (const entry of this.entries)\n      clearTimeout(entry.timer);\n    this.entries.length = 0;\n  }\n  invalidate() {\n  }\n  render(width) {\n    return this.entries.map((entry) => {\n      const message = truncateToWidth(` ${entry.message} `, width, \"\");\n      return `\\x1B[7m${message}\\x1B[27m`;\n    });\n  }\n};\n\n// node_modules/.pnpm/@earendil-works+pi-tui@0.84.2/node_modules/@earendil-works/pi-tui/dist/layout.js\nvar OSC133_ZONE_PREFIX = /^(?:\\x1b\\]133;[ABC](?:\\x07|\\x1b\\\\))+/;\nfunction intersect(a, b) {\n  const x = Math.max(a.x, b.x);\n  const y = Math.max(a.y, b.y);\n  const right = Math.min(a.x + a.width, b.x + b.width);\n  const bottom = Math.min(a.y + a.height, b.y + b.height);\n  return { x, y, width: Math.max(0, right - x), height: Math.max(0, bottom - y) };\n}\nfunction renderCached(context, component, width) {\n  const safeWidth = Math.max(1, Math.floor(width));\n  let widths = context.renderCache.get(component);\n  if (!widths) {\n    widths = /* @__PURE__ */ new Map();\n    context.renderCache.set(component, widths);\n  }\n  let lines = widths.get(safeWidth);\n  if (!lines) {\n    lines = component.render(safeWidth);\n    widths.set(safeWidth, lines);\n  }\n  return lines;\n}\nfunction measureHeight(context, component, width) {\n  return renderCached(context, component, width).length;\n}\nfunction measureWidth(context, component, width) {\n  return renderCached(context, component, width).reduce((max, line) => Math.max(max, visibleWidth(line)), 0);\n}\nfunction withParent(box, parent) {\n  box.parent = parent;\n  return box;\n}\nfunction translateBox(box, deltaY) {\n  box.rect.y += deltaY;\n  for (const child of box.children)\n    translateBox(child, deltaY);\n}\nfunction updateClips(box, parentClip) {\n  box.clip = intersect(parentClip, box.rect);\n  for (const child of box.children)\n    updateClips(child, box.clip);\n}\nfunction layoutComponent(context, component, x, y, width, height, clip) {\n  const safeWidth = Math.max(1, Math.floor(width));\n  const node = getLayoutNode(component);\n  if (!node) {\n    const lines = renderCached(context, component, safeWidth);\n    const allocatedHeight2 = height === void 0 ? lines.length : Math.max(0, Math.floor(height));\n    let lineOffset = 0;\n    if (lines.length > allocatedHeight2 && allocatedHeight2 > 0) {\n      const cursorLine = lines.findIndex((line) => line.includes(CURSOR_MARKER));\n      if (cursorLine >= allocatedHeight2)\n        lineOffset = cursorLine - allocatedHeight2 + 1;\n    }\n    return {\n      component,\n      rect: { x, y, width: safeWidth, height: allocatedHeight2 },\n      clip: intersect(clip, { x, y, width: safeWidth, height: allocatedHeight2 }),\n      children: [],\n      lines,\n      lineOffset,\n      layer: 0\n    };\n  }\n  if (node.type === \"scroll\") {\n    const previousScrollTop = node.state.scrollTop;\n    const contentWidth = node.state.getContentWidth(safeWidth);\n    const childBox = layoutComponent(context, node.component, x, y - previousScrollTop, contentWidth, void 0, clip);\n    const contentHeight = childBox.rect.height;\n    const viewportHeight = height === void 0 ? contentHeight : Math.max(0, Math.floor(height));\n    node.state.updateLayout(contentHeight, viewportHeight, context.requestRender);\n    translateBox(childBox, previousScrollTop - node.state.scrollTop);\n    const scrollView = node.state;\n    if (node.state.primary || !context.primaryScrollView)\n      context.primaryScrollView = scrollView;\n    const rect2 = { x, y, width: safeWidth, height: viewportHeight };\n    const childClip = intersect(clip, rect2);\n    const box2 = {\n      component,\n      rect: rect2,\n      clip: childClip,\n      children: [childBox],\n      scrollView,\n      scrollContentLines: renderCached(context, node.component, contentWidth),\n      layer: 0\n    };\n    childBox.parent = box2;\n    updateClips(childBox, childClip);\n    return box2;\n  }\n  const entries = visibleStackEntries(node.entries, context.viewport);\n  const gapTotal = Math.max(0, entries.length - 1) * node.gap;\n  if (node.type === \"vstack\") {\n    const intrinsicHeights2 = entries.map((entry) => typeof entry.basis === \"number\" ? entry.basis : measureHeight(context, entry.component, safeWidth));\n    const sizes = allocateStackSizes(entries, intrinsicHeights2, height, node.gap);\n    const naturalHeight = sizes.reduce((sum, size) => sum + size, 0) + gapTotal;\n    const allocatedHeight2 = height === void 0 ? naturalHeight : Math.max(0, Math.floor(height));\n    const rect2 = { x, y, width: safeWidth, height: allocatedHeight2 };\n    const box2 = {\n      component,\n      rect: rect2,\n      clip: intersect(clip, rect2),\n      children: [],\n      layer: 0\n    };\n    let childY = y;\n    for (let index = 0; index < entries.length; index++) {\n      box2.children.push(withParent(layoutComponent(context, entries[index].component, x, childY, safeWidth, sizes[index], box2.clip), box2));\n      childY += sizes[index] + node.gap;\n    }\n    return box2;\n  }\n  const intrinsicWidths = entries.map((entry) => typeof entry.basis === \"number\" ? entry.basis : measureWidth(context, entry.component, safeWidth));\n  const widths = allocateStackSizes(entries, intrinsicWidths, safeWidth, node.gap);\n  const intrinsicHeights = entries.map((entry, index) => measureHeight(context, entry.component, Math.max(1, widths[index])));\n  const allocatedHeight = height === void 0 ? intrinsicHeights.reduce((max, childHeight) => Math.max(max, childHeight), 0) : Math.max(0, height);\n  const rect = { x, y, width: safeWidth, height: allocatedHeight };\n  const box = {\n    component,\n    rect,\n    clip: intersect(clip, rect),\n    children: [],\n    layer: 0\n  };\n  let childX = x;\n  for (let index = 0; index < entries.length; index++) {\n    const naturalChildHeight = intrinsicHeights[index];\n    const childHeight = node.align === \"stretch\" ? allocatedHeight : Math.min(allocatedHeight, naturalChildHeight);\n    let childY = y;\n    if (node.align === \"center\")\n      childY += Math.floor((allocatedHeight - childHeight) / 2);\n    else if (node.align === \"end\")\n      childY += allocatedHeight - childHeight;\n    const childWidth = widths[index];\n    if (childWidth === 0) {\n      box.children.push({\n        component: entries[index].component,\n        rect: { x: childX, y: childY, width: 0, height: childHeight },\n        clip: { x: childX, y: childY, width: 0, height: 0 },\n        children: [],\n        parent: box,\n        layer: 0\n      });\n    } else {\n      box.children.push(withParent(layoutComponent(context, entries[index].component, childX, childY, childWidth, childHeight, box.clip), box));\n    }\n    childX += childWidth + node.gap;\n  }\n  return box;\n}\nfunction styleScrollbarCell(line, column, totalWidth, style) {\n  if (isImageLine(line))\n    return line;\n  const graphemeRange = getGraphemeCellRange(line, column);\n  const start = graphemeRange?.start ?? column;\n  const end = graphemeRange?.end ?? column + 1;\n  const before = sliceByColumn(line, 0, start, true);\n  const target = sliceByColumn(line, start, end - start, true);\n  const after = sliceByColumn(line, end, Math.max(0, totalWidth - end), true);\n  let targetPrefix = \"\";\n  let targetIndex = 0;\n  while (targetIndex < target.length) {\n    const ansi = extractAnsiCode(target, targetIndex);\n    if (!ansi)\n      break;\n    targetPrefix += ansi.code;\n    targetIndex += ansi.length;\n  }\n  const targetText = target.slice(targetIndex) || \" \".repeat(end - start);\n  const beforePadding = \" \".repeat(Math.max(0, start - visibleWidth(before)));\n  return `${before}${beforePadding}${targetPrefix}${style(targetText)}${after}`;\n}\nfunction getScrollbarGeometry(box) {\n  if (!box.scrollView?.isScrollbarVisible || box.rect.width <= 0 || box.rect.height <= 0)\n    return void 0;\n  const contentHeight = box.children[0]?.rect.height ?? box.scrollContentLines?.length ?? 0;\n  const trackHeight = box.rect.height;\n  const minThumbHeight = Math.min(2, trackHeight);\n  const thumbHeight = Math.max(minThumbHeight, Math.min(trackHeight, Math.round(trackHeight * trackHeight / contentHeight)));\n  const maxScrollTop = Math.max(0, contentHeight - trackHeight);\n  const maxThumbTop = trackHeight - thumbHeight;\n  const thumbOffset = maxScrollTop === 0 ? 0 : Math.round(box.scrollView.scrollTop / maxScrollTop * maxThumbTop);\n  const column = box.rect.x + box.rect.width - 1;\n  if (column < box.clip.x || column >= box.clip.x + box.clip.width)\n    return void 0;\n  return {\n    column,\n    trackTop: box.rect.y,\n    trackHeight,\n    thumbTop: box.rect.y + thumbOffset,\n    thumbHeight,\n    maxScrollTop\n  };\n}\nfunction paintScrollbar(box, screen, totalWidth) {\n  const geometry = getScrollbarGeometry(box);\n  if (!geometry || !box.scrollView)\n    return;\n  for (let offset = 0; offset < geometry.thumbHeight; offset++) {\n    const row = geometry.thumbTop + offset;\n    if (row < box.clip.y || row >= box.clip.y + box.clip.height || row < 0 || row >= screen.length)\n      continue;\n    screen[row] = styleScrollbarCell(screen[row] ?? \"\", geometry.column, totalWidth, box.scrollView.scrollbarStyle);\n  }\n}\nfunction paintBox(box, screen, totalWidth) {\n  if (box.lines) {\n    const offset = box.lineOffset ?? 0;\n    const firstRow = Math.max(box.rect.y, box.clip.y, 0);\n    const lastRow = Math.min(box.rect.y + box.rect.height, box.clip.y + box.clip.height, screen.length);\n    for (let row = firstRow; row < lastRow; row++) {\n      const sourceLine = box.lines[offset + row - box.rect.y];\n      if (sourceLine === void 0)\n        continue;\n      let line = sourceLine.replace(OSC133_ZONE_PREFIX, \"\");\n      const imageMetadata = getKittyImageMetadata(line);\n      if (imageMetadata) {\n        const clipBottom = Math.min(screen.length, box.clip.y + box.clip.height);\n        const visibleRows = Math.min(imageMetadata.rows, clipBottom - row);\n        if (visibleRows < imageMetadata.rows)\n          line = cropKittyImageLine(line, 0, visibleRows);\n      }\n      if (box.rect.x === 0 && box.rect.width >= totalWidth && (isImageLine(line) || !screen[row])) {\n        screen[row] = line;\n      } else {\n        screen[row] = compositeTuiLine(screen[row] ?? \"\", line, box.rect.x, box.rect.width, totalWidth);\n      }\n    }\n  }\n  for (const child of box.children)\n    paintBox(child, screen, totalWidth);\n  if (box.scrollView && box.scrollContentLines && box.scrollView.scrollTop > 0 && box.rect.height > 0) {\n    for (let imageRow = box.scrollView.scrollTop - 1; imageRow >= 0; imageRow--) {\n      const imageLine = box.scrollContentLines[imageRow] ?? \"\";\n      const metadata = getKittyImageMetadata(imageLine);\n      if (metadata) {\n        const hiddenRows = box.scrollView.scrollTop - imageRow;\n        if (hiddenRows < metadata.rows) {\n          const visibleRows = Math.min(box.rect.height, metadata.rows - hiddenRows);\n          const cropped = cropKittyImageLine(imageLine, hiddenRows, visibleRows);\n          if (box.rect.x === 0 && box.rect.width >= totalWidth)\n            screen[box.rect.y] = cropped;\n        }\n        break;\n      }\n      if (imageLine !== \"\")\n        break;\n    }\n  }\n  paintScrollbar(box, screen, totalWidth);\n}\nfunction renderLayoutFrame(root, width, height, requestRender) {\n  const safeWidth = Math.max(1, Math.floor(width));\n  const safeHeight = Math.max(1, Math.floor(height));\n  const context = {\n    viewport: { width: safeWidth, height: safeHeight },\n    renderCache: /* @__PURE__ */ new Map(),\n    requestRender,\n    primaryScrollView: void 0\n  };\n  const rootBox = layoutComponent(context, root, 0, 0, safeWidth, safeHeight, {\n    x: 0,\n    y: 0,\n    width: safeWidth,\n    height: safeHeight\n  });\n  const lines = Array.from({ length: safeHeight }, () => \"\");\n  paintBox(rootBox, lines, safeWidth);\n  return {\n    root: rootBox,\n    width: safeWidth,\n    height: safeHeight,\n    lines,\n    ...context.primaryScrollView === void 0 ? {} : { primaryScrollView: context.primaryScrollView }\n  };\n}\nfunction containsPoint(rect, x, y) {\n  return x >= rect.x && x < rect.x + rect.width && y >= rect.y && y < rect.y + rect.height;\n}\nfunction getScrollViewBox(frame2, scrollView) {\n  const visit = (box) => {\n    if (box.scrollView === scrollView)\n      return box;\n    for (const child of box.children) {\n      const match = visit(child);\n      if (match)\n        return match;\n    }\n    return void 0;\n  };\n  return visit(frame2.root);\n}\nfunction getScrollViewsAt(frame2, x, y) {\n  const result = [];\n  const visit = (box, depth) => {\n    if (!containsPoint(box.clip, x, y))\n      return;\n    if (box.scrollView && containsPoint(box.rect, x, y))\n      result.push({ scrollView: box.scrollView, depth });\n    for (const child of box.children)\n      visit(child, depth + 1);\n  };\n  visit(frame2.root, 0);\n  result.sort((a, b) => b.depth - a.depth);\n  return result.map((entry) => entry.scrollView);\n}\n\n// node_modules/.pnpm/@earendil-works+pi-tui@0.84.2/node_modules/@earendil-works/pi-tui/dist/tui-alt-screen.js\nvar ENTER_ALT_SCREEN = \"\\x1B[?1049h\";\nvar EXIT_ALT_SCREEN = \"\\x1B[?1049l\";\nvar DISABLE_AUTOWRAP = \"\\x1B[?7l\";\nvar ENABLE_AUTOWRAP = \"\\x1B[?7h\";\nvar ENABLE_BUTTON_MOTION_MOUSE = \"\\x1B[?1000h\\x1B[?1002h\\x1B[?1004h\\x1B[?1006h\";\nvar ENABLE_ALL_MOTION_MOUSE = \"\\x1B[?1000h\\x1B[?1002h\\x1B[?1003h\\x1B[?1004h\\x1B[?1006h\";\nvar DISABLE_MOUSE = \"\\x1B[?1006l\\x1B[?1004l\\x1B[?1003l\\x1B[?1002l\\x1B[?1000l\";\nvar FOCUS_IN = \"\\x1B[I\";\nvar FOCUS_OUT = \"\\x1B[O\";\nvar BEGIN_SYNCHRONIZED_OUTPUT = \"\\x1B[?2026h\";\nvar END_SYNCHRONIZED_OUTPUT = \"\\x1B[?2026l\";\nvar OSC133_ZONE_PREFIX2 = /^(?:\\x1b\\]133;[ABC](?:\\x07|\\x1b\\\\))+/;\nvar OSC133_PROMPT_START = /^\\x1b\\]133;A(?:\\x07|\\x1b\\\\)/;\nvar PAGE_SCROLL_OVERLAP = 4;\nvar MAX_CACHED_OFFSCREEN_KITTY_IMAGES = 16;\nvar MAX_CACHED_OFFSCREEN_KITTY_TRANSMISSION_BYTES = 32 * 1024 * 1024;\nvar MAX_CACHED_OFFSCREEN_KITTY_DECODED_BYTES = 64 * 1024 * 1024;\nvar DOUBLE_CLICK_INTERVAL_MS = 500;\nvar wordSegmenter4 = getWordSegmenter();\nvar TuiAltScreen = class extends TuiBase {\n  mode = \"fullscreen\";\n  [VIEWPORT_TUI] = true;\n  previousScreen = [];\n  lastDocument = [];\n  previousScreenWidth = 0;\n  previousScreenHeight = 0;\n  layoutRoot;\n  currentLayout;\n  implicitDocument;\n  implicitScrollView;\n  flashes;\n  altScreenActive = false;\n  imageProtocol = null;\n  savedCapabilities;\n  uploadedKittyImages = /* @__PURE__ */ new Map();\n  selectionAnchor;\n  selectionFocus;\n  selectionGranularity = \"character\";\n  selectionInitialRange;\n  lastClick;\n  selectionDragPointer;\n  selectionAutoScrollDirection = 0;\n  selectionAutoScrollTimer;\n  selectionPressActive = false;\n  scrollbarDrag;\n  scrollbarHover;\n  activeSearch;\n  pressedUrl;\n  selectionDragged = false;\n  wheelScrollLines;\n  mouseEnabled;\n  searchMatchStyle;\n  searchCurrentMatchStyle;\n  openUrl;\n  onRightClickPaste;\n  copySelection;\n  constructor(terminal, showHardwareCursor, logDirectory, options = {}) {\n    super(terminal, showHardwareCursor, logDirectory);\n    this.implicitDocument = {\n      render: (width) => super.render(width),\n      invalidate: () => {\n        for (const child of this.children)\n          child.invalidate();\n      }\n    };\n    this.implicitScrollView = new ScrollView(this.implicitDocument, { follow: \"end\", primary: true });\n    this.flashes = new AltScreenFlashContainer(() => this.requestRender());\n    this.wheelScrollLines = Math.max(1, Math.floor(options.wheelScrollLines ?? 1));\n    this.mouseEnabled = options.mouse ?? true;\n    this.searchMatchStyle = options.searchMatchStyle ?? ((text) => `\\x1B[4m${text}\\x1B[24m`);\n    this.searchCurrentMatchStyle = options.searchCurrentMatchStyle ?? ((text) => `\\x1B[1;7m${text}\\x1B[22;27m`);\n    this.openUrl = options.openUrl;\n    this.onRightClickPaste = options.onRightClickPaste;\n    this.copySelection = options.copySelection;\n    this.addInputListener((data) => this.handleViewportInput(data));\n  }\n  get viewportTop() {\n    return this.getPrimaryScrollView().scrollTop;\n  }\n  get isFollowingOutput() {\n    return this.getPrimaryScrollView().isFollowingEnd;\n  }\n  setLayoutRoot(component) {\n    if (this.layoutRoot === component)\n      return;\n    this.layoutRoot = component;\n    this.currentLayout = void 0;\n    this.requestRender();\n  }\n  render(width) {\n    return this.layoutRoot?.render(width) ?? super.render(width);\n  }\n  getMountedRoots() {\n    return this.layoutRoot ? [this.layoutRoot] : this.children;\n  }\n  getPrimaryScrollView() {\n    return this.currentLayout?.primaryScrollView ?? this.implicitScrollView;\n  }\n  beforeTerminalStart() {\n    this.stopSelectionAutoScroll();\n    this.selectionPressActive = false;\n    this.stopScrollbarHover();\n    this.stopScrollbarDrag();\n    this.flashes.dispose();\n    this.altScreenActive = true;\n    const capabilities = getCapabilities();\n    this.imageProtocol = capabilities.images;\n    this.uploadedKittyImages.clear();\n    if (capabilities.images === \"iterm2\") {\n      this.savedCapabilities = capabilities;\n      setCapabilities({ ...capabilities, images: null });\n      this.invalidate();\n    }\n    this.lastDocument = [];\n    this.selectionAnchor = void 0;\n    this.selectionFocus = void 0;\n    this.selectionGranularity = \"character\";\n    this.selectionInitialRange = void 0;\n    this.lastClick = void 0;\n    this.pressedUrl = void 0;\n    this.selectionDragged = false;\n    this.resetRenderState();\n    const term = process.env.TERM?.toLowerCase() ?? \"\";\n    const mouseSequence = process.env.TMUX !== void 0 || process.env.ZELLIJ !== void 0 || process.env.STY !== void 0 || term.startsWith(\"tmux\") || term.startsWith(\"screen\") ? ENABLE_BUTTON_MOTION_MOUSE : ENABLE_ALL_MOTION_MOUSE;\n    this.terminal.write(`${ENTER_ALT_SCREEN}${DISABLE_AUTOWRAP}${this.mouseEnabled ? mouseSequence : \"\"}\\x1B[2J\\x1B[H\\x1B[?25l`);\n  }\n  beforeTerminalStop(_options) {\n    this.closeSearch();\n    this.stopSelectionAutoScroll();\n    this.selectionPressActive = false;\n    this.stopScrollbarHover();\n    this.stopScrollbarDrag();\n    this.flashes.dispose();\n    if (!this.altScreenActive)\n      return;\n    this.terminal.write(`${BEGIN_SYNCHRONIZED_OUTPUT}${this.deleteKittyImages()}${this.mouseEnabled ? DISABLE_MOUSE : \"\"}${ENABLE_AUTOWRAP}${END_SYNCHRONIZED_OUTPUT}`);\n    this.uploadedKittyImages.clear();\n  }\n  afterTerminalStop(options) {\n    if (!this.altScreenActive)\n      return;\n    this.altScreenActive = false;\n    if (options.preserveScreen) {\n      this.terminal.write(`${BEGIN_SYNCHRONIZED_OUTPUT}${EXIT_ALT_SCREEN}\\x1B[?25h${END_SYNCHRONIZED_OUTPUT}`);\n    } else {\n      const width = Math.max(1, this.terminal.columns);\n      const documentLines = this.render(width).map((line) => line.replace(OSC133_ZONE_PREFIX2, \"\"));\n      this.lastDocument = this.applyLineResets(documentLines.map((line) => line.replaceAll(CURSOR_MARKER, \"\"))).map((line) => isImageLine(line) || visibleWidth(line) <= width ? line : sliceByColumn(line, 0, width, true));\n      let buffer = `${BEGIN_SYNCHRONIZED_OUTPUT}${EXIT_ALT_SCREEN}${DISABLE_AUTOWRAP}`;\n      for (let row = 0; row < this.lastDocument.length; row++) {\n        if (row > 0)\n          buffer += \"\\r\\n\";\n        buffer += `\\r\\x1B[2K${this.lastDocument[row] ?? \"\"}`;\n      }\n      buffer += `\\x1B[0m${ENABLE_AUTOWRAP}\\r\n\\x1B[?25h${END_SYNCHRONIZED_OUTPUT}`;\n      this.terminal.write(buffer);\n    }\n    if (this.savedCapabilities) {\n      setCapabilities(this.savedCapabilities);\n      this.savedCapabilities = void 0;\n    }\n  }\n  deleteKittyImages() {\n    return this.imageProtocol === \"kitty\" ? deleteAllKittyImages() : \"\";\n  }\n  prepareKittyScreen(screen) {\n    const visibleImageIds = /* @__PURE__ */ new Set();\n    const lines = screen.map((line) => {\n      const placement = getKittyImagePlacement(line);\n      if (!placement)\n        return line;\n      visibleImageIds.add(placement.imageId);\n      const cachedImage = this.uploadedKittyImages.get(placement.imageId);\n      const nextCachedImage = {\n        transmissionGeneration: placement.transmissionGeneration,\n        transmissionBytes: placement.transmissionBytes,\n        estimatedDecodedBytes: placement.estimatedDecodedBytes\n      };\n      if (cachedImage)\n        this.uploadedKittyImages.delete(placement.imageId);\n      this.uploadedKittyImages.set(placement.imageId, nextCachedImage);\n      return cachedImage?.transmissionGeneration === placement.transmissionGeneration ? placement.replacementLine : line;\n    });\n    let cachedOffscreenImageCount = 0;\n    let cachedOffscreenTransmissionBytes = 0;\n    let cachedOffscreenDecodedBytes = 0;\n    for (const [imageId, cachedImage] of this.uploadedKittyImages) {\n      if (visibleImageIds.has(imageId))\n        continue;\n      cachedOffscreenImageCount += 1;\n      cachedOffscreenTransmissionBytes += cachedImage.transmissionBytes;\n      cachedOffscreenDecodedBytes += cachedImage.estimatedDecodedBytes;\n    }\n    let evictedImageDeletion = \"\";\n    for (const [imageId, cachedImage] of this.uploadedKittyImages) {\n      if (cachedOffscreenImageCount <= MAX_CACHED_OFFSCREEN_KITTY_IMAGES && cachedOffscreenTransmissionBytes <= MAX_CACHED_OFFSCREEN_KITTY_TRANSMISSION_BYTES && cachedOffscreenDecodedBytes <= MAX_CACHED_OFFSCREEN_KITTY_DECODED_BYTES) {\n        break;\n      }\n      if (visibleImageIds.has(imageId))\n        continue;\n      evictedImageDeletion += deleteKittyImage(imageId);\n      this.uploadedKittyImages.delete(imageId);\n      cachedOffscreenImageCount -= 1;\n      cachedOffscreenTransmissionBytes -= cachedImage.transmissionBytes;\n      cachedOffscreenDecodedBytes -= cachedImage.estimatedDecodedBytes;\n    }\n    return { lines, evictedImageDeletion };\n  }\n  resetRenderState() {\n    this.previousScreen = [];\n    this.previousScreenWidth = 0;\n    this.previousScreenHeight = 0;\n    this.currentLayout = void 0;\n  }\n  scrollBy(lines) {\n    this.getPrimaryScrollView().scrollBy(lines);\n    this.requestRender();\n  }\n  scrollToTop() {\n    this.getPrimaryScrollView().scrollToStart();\n    this.requestRender();\n  }\n  scrollToBottom() {\n    this.getPrimaryScrollView().scrollToEnd();\n    this.requestRender();\n  }\n  scrollToPrompt(direction) {\n    if (!this.currentLayout)\n      return;\n    const scrollView = this.getPrimaryScrollView();\n    const lines = getScrollViewBox(this.currentLayout, scrollView)?.scrollContentLines;\n    if (!lines)\n      return;\n    for (let row = scrollView.scrollTop + direction; row >= 0 && row < lines.length; row += direction) {\n      if (!OSC133_PROMPT_START.test(lines[row] ?? \"\"))\n        continue;\n      scrollView.scrollTo(row);\n      this.requestRender();\n      return;\n    }\n  }\n  openSearch() {\n    if (this.activeSearch) {\n      this.activeSearch.overlay?.focus();\n      return;\n    }\n    const component = new AltScreenSearchComponent((query) => this.updateSearchQuery(query));\n    const search = {\n      component,\n      query: \"\",\n      matches: [],\n      selectedIndex: -1,\n      anchorRow: this.getPrimaryScrollView().scrollTop,\n      selectionMode: \"query\"\n    };\n    this.activeSearch = search;\n    search.overlay = this.showOverlay(component, {\n      anchor: \"top-right\",\n      width: \"40%\",\n      minWidth: 24,\n      margin: 1\n    });\n  }\n  closeSearch() {\n    const search = this.activeSearch;\n    if (!search)\n      return;\n    this.activeSearch = void 0;\n    search.overlay?.hide();\n    this.requestRender();\n  }\n  updateSearchQuery(query) {\n    const search = this.activeSearch;\n    if (!search || query === search.query)\n      return;\n    const selected = search.matches[search.selectedIndex];\n    search.anchorRow = selected?.segments[0]?.row ?? this.getPrimaryScrollView().scrollTop;\n    search.query = query;\n    search.selectionMode = \"query\";\n    search.component.setResult(-1, 0);\n    this.requestRender();\n  }\n  navigateSearch(direction) {\n    const search = this.activeSearch;\n    if (!search?.query)\n      return;\n    search.selectionMode = direction < 0 ? \"previous\" : \"next\";\n    this.requestRender();\n  }\n  refreshSearch(layout) {\n    const search = this.activeSearch;\n    if (!search)\n      return false;\n    const scrollView = layout.primaryScrollView ?? this.implicitScrollView;\n    const box = getScrollViewBox(layout, scrollView);\n    const lines = box?.scrollContentLines;\n    if (!lines || !search.query.trim()) {\n      search.matches = [];\n      search.selectedIndex = -1;\n      search.selectedKey = void 0;\n      search.selectionMode = \"retain\";\n      search.component.setResult(-1, 0);\n      return false;\n    }\n    const shouldRevealSelection = search.selectionMode !== \"retain\";\n    const matches = findAltScreenSearchMatches(lines, search.query);\n    const exactIndex = search.selectedKey ? matches.findIndex((match) => getAltScreenSearchMatchKey(match) === search.selectedKey) : -1;\n    let selectedIndex = -1;\n    if (matches.length > 0) {\n      if (search.selectionMode === \"query\") {\n        selectedIndex = matches.findIndex((match) => (match.segments[0]?.row ?? 0) >= search.anchorRow);\n        if (selectedIndex < 0)\n          selectedIndex = 0;\n      } else if (search.selectionMode === \"next\") {\n        const baseIndex = exactIndex >= 0 ? exactIndex : Math.min(search.selectedIndex, matches.length - 1);\n        selectedIndex = baseIndex < 0 ? 0 : (baseIndex + 1) % matches.length;\n      } else if (search.selectionMode === \"previous\") {\n        const baseIndex = exactIndex >= 0 ? exactIndex : Math.min(search.selectedIndex, matches.length - 1);\n        selectedIndex = baseIndex < 0 ? matches.length - 1 : (baseIndex - 1 + matches.length) % matches.length;\n      } else {\n        selectedIndex = exactIndex >= 0 ? exactIndex : Math.min(Math.max(0, search.selectedIndex), matches.length - 1);\n      }\n    }\n    search.matches = matches;\n    search.selectedIndex = selectedIndex;\n    search.selectedKey = selectedIndex >= 0 ? getAltScreenSearchMatchKey(matches[selectedIndex]) : void 0;\n    search.selectionMode = \"retain\";\n    search.component.setResult(selectedIndex, matches.length);\n    if (!shouldRevealSelection)\n      return false;\n    const selected = matches[selectedIndex];\n    const firstSegment = selected?.segments[0];\n    const lastSegment = selected?.segments[selected.segments.length - 1];\n    if (!box || !firstSegment || !lastSegment || scrollView.viewportHeight <= 0)\n      return false;\n    const before = scrollView.scrollTop;\n    const visibleBottom = before + scrollView.viewportHeight - 1;\n    let target = before;\n    if (firstSegment.row < before || lastSegment.row > visibleBottom) {\n      target = firstSegment.row - Math.floor(scrollView.viewportHeight / 3);\n    }\n    scrollView.scrollTo(target, { disableFollow: true });\n    return scrollView.scrollTop !== before;\n  }\n  /** Show a transient message in the alternate-screen flash stack. */\n  flash(message, durationMs) {\n    this.flashes.flash(message, durationMs);\n  }\n  shouldDeferViewportInputToOverlay() {\n    return this.isOverlayFocused() && this.activeSearch?.overlay?.isFocused() !== true;\n  }\n  handleViewportInput(data) {\n    if (data === FOCUS_OUT) {\n      const hadActiveSelection = this.selectionPressActive;\n      const hadNonEmptyActiveSelection = hadActiveSelection && this.getSelectionBounds() !== void 0;\n      this.selectionPressActive = false;\n      this.stopSelectionAutoScroll();\n      this.stopScrollbarHover();\n      this.stopScrollbarDrag();\n      this.pressedUrl = void 0;\n      this.selectionDragged = false;\n      if (hadActiveSelection) {\n        this.selectionAnchor = void 0;\n        this.selectionFocus = void 0;\n        this.selectionGranularity = \"character\";\n        this.selectionInitialRange = void 0;\n        if (hadNonEmptyActiveSelection)\n          this.requestRender();\n      }\n      this.lastClick = void 0;\n      return { consume: true };\n    }\n    if (data === FOCUS_IN)\n      return { consume: true };\n    const wheelEvent = this.parseWheelEvent(data);\n    if (wheelEvent) {\n      if (this.shouldDeferViewportInputToOverlay())\n        return void 0;\n      this.routeWheel(wheelEvent);\n      return { consume: true };\n    }\n    const mouseEvent = this.parseSgrMouseEvent(data);\n    if (mouseEvent) {\n      if (this.handleRightClickPaste(mouseEvent))\n        return { consume: true };\n      const handled = this.handleScrollbarMouseEvent(mouseEvent);\n      if (!this.scrollbarDrag)\n        this.updateScrollbarHover(mouseEvent.x, mouseEvent.y);\n      if (!handled)\n        this.handleSelectionMouseEvent(mouseEvent);\n      return { consume: true };\n    }\n    if (this.isMouseSequence(data))\n      return { consume: true };\n    const keybindings = getKeybindings();\n    const isRelease = isKeyRelease(data);\n    if (keybindings.matches(data, \"tui.altScreen.search\")) {\n      if (!isRelease)\n        this.openSearch();\n      return { consume: true };\n    }\n    if (this.activeSearch?.overlay?.isFocused()) {\n      if (keybindings.matches(data, \"tui.altScreen.searchNext\")) {\n        if (!isRelease)\n          this.navigateSearch(1);\n        return { consume: true };\n      }\n      if (keybindings.matches(data, \"tui.altScreen.searchPrevious\")) {\n        if (!isRelease)\n          this.navigateSearch(-1);\n        return { consume: true };\n      }\n      if (keybindings.matches(data, \"tui.altScreen.searchClose\")) {\n        if (!isRelease)\n          this.closeSearch();\n        return { consume: true };\n      }\n    }\n    if (this.shouldDeferViewportInputToOverlay())\n      return void 0;\n    if (keybindings.matches(data, \"tui.altScreen.pageUp\")) {\n      if (!isRelease) {\n        this.scrollBy(-Math.max(1, this.getPrimaryScrollView().viewportHeight - PAGE_SCROLL_OVERLAP));\n      }\n      return { consume: true };\n    }\n    if (keybindings.matches(data, \"tui.altScreen.pageDown\")) {\n      if (!isRelease) {\n        this.scrollBy(Math.max(1, this.getPrimaryScrollView().viewportHeight - PAGE_SCROLL_OVERLAP));\n      }\n      return { consume: true };\n    }\n    if (keybindings.matches(data, \"tui.altScreen.halfPageUp\")) {\n      if (!isRelease)\n        this.scrollBy(-Math.max(1, Math.floor(this.getPrimaryScrollView().viewportHeight / 2)));\n      return { consume: true };\n    }\n    if (keybindings.matches(data, \"tui.altScreen.halfPageDown\")) {\n      if (!isRelease)\n        this.scrollBy(Math.max(1, Math.floor(this.getPrimaryScrollView().viewportHeight / 2)));\n      return { consume: true };\n    }\n    if (keybindings.matches(data, \"tui.altScreen.lineUp\")) {\n      if (!isRelease)\n        this.scrollBy(-1);\n      return { consume: true };\n    }\n    if (keybindings.matches(data, \"tui.altScreen.lineDown\")) {\n      if (!isRelease)\n        this.scrollBy(1);\n      return { consume: true };\n    }\n    if (keybindings.matches(data, \"tui.altScreen.previousPrompt\")) {\n      if (!isRelease)\n        this.scrollToPrompt(-1);\n      return { consume: true };\n    }\n    if (keybindings.matches(data, \"tui.altScreen.nextPrompt\")) {\n      if (!isRelease)\n        this.scrollToPrompt(1);\n      return { consume: true };\n    }\n    if (keybindings.matches(data, \"tui.altScreen.top\")) {\n      if (!isRelease)\n        this.scrollToTop();\n      return { consume: true };\n    }\n    if (keybindings.matches(data, \"tui.altScreen.bottom\")) {\n      if (!isRelease)\n        this.scrollToBottom();\n      return { consume: true };\n    }\n    return void 0;\n  }\n  parseWheelEvent(data) {\n    const sgr = /^\\x1b\\[<(\\d+);(\\d+);(\\d+)[Mm]$/.exec(data);\n    if (sgr) {\n      const button = Number.parseInt(sgr[1], 10);\n      if ((button & 64) === 0)\n        return void 0;\n      const direction = button & 3;\n      if (direction !== 0 && direction !== 1)\n        return void 0;\n      return {\n        direction: direction === 0 ? -1 : 1,\n        x: Number.parseInt(sgr[2], 10) - 1,\n        y: Number.parseInt(sgr[3], 10) - 1\n      };\n    }\n    if (data.length === 6 && data.startsWith(\"\\x1B[M\")) {\n      const button = data.charCodeAt(3) - 32;\n      if ((button & 64) === 0)\n        return void 0;\n      const direction = button & 3;\n      if (direction !== 0 && direction !== 1)\n        return void 0;\n      return {\n        direction: direction === 0 ? -1 : 1,\n        x: data.charCodeAt(4) - 33,\n        y: data.charCodeAt(5) - 33\n      };\n    }\n    return void 0;\n  }\n  routeWheel(event) {\n    let remaining = event.direction * this.wheelScrollLines;\n    const seen = /* @__PURE__ */ new Set();\n    for (const scrollView of this.currentLayout ? getScrollViewsAt(this.currentLayout, event.x, event.y) : []) {\n      seen.add(scrollView);\n      remaining = scrollView.scrollBy(remaining);\n      if (remaining === 0 || scrollView.overscroll === \"contain\")\n        break;\n    }\n    const primary = this.getPrimaryScrollView();\n    if (remaining !== 0 && !seen.has(primary))\n      primary.scrollBy(remaining);\n    this.updateScrollbarHover(event.x, event.y);\n    this.requestRender();\n  }\n  parseSgrMouseEvent(data) {\n    const match = /^\\x1b\\[<(\\d+);(\\d+);(\\d+)([Mm])$/.exec(data);\n    if (!match)\n      return void 0;\n    return {\n      button: Number.parseInt(match[1], 10),\n      x: Number.parseInt(match[2], 10) - 1,\n      y: Number.parseInt(match[3], 10) - 1,\n      release: match[4] === \"m\"\n    };\n  }\n  handleRightClickPaste(event) {\n    if (!this.onRightClickPaste || process.platform !== \"win32\" || event.release || event.button !== 2) {\n      return false;\n    }\n    try {\n      this.onRightClickPaste();\n    } catch {\n    }\n    return true;\n  }\n  getScrollbarTargetAt(x, y) {\n    if (this.hasOverlay() || !this.currentLayout)\n      return void 0;\n    for (const scrollView of getScrollViewsAt(this.currentLayout, x, y)) {\n      const box = getScrollViewBox(this.currentLayout, scrollView);\n      const geometry = box ? getScrollbarGeometry(box) : void 0;\n      if (geometry && x === geometry.column && y >= geometry.thumbTop && y < geometry.thumbTop + geometry.thumbHeight) {\n        return { scrollView, geometry };\n      }\n    }\n    return void 0;\n  }\n  setScrollbarHover(scrollView) {\n    if (scrollView === this.scrollbarHover)\n      return;\n    this.scrollbarHover?.setScrollbarActive(false);\n    this.scrollbarHover = scrollView;\n    this.scrollbarHover?.setScrollbarActive(true);\n  }\n  updateScrollbarHover(x, y) {\n    this.setScrollbarHover(this.getScrollbarTargetAt(x, y)?.scrollView);\n  }\n  stopScrollbarHover() {\n    this.setScrollbarHover(void 0);\n  }\n  handleScrollbarMouseEvent(event) {\n    if (this.scrollbarDrag) {\n      if (event.release) {\n        this.stopScrollbarDrag();\n        return true;\n      }\n      const box = this.currentLayout ? getScrollViewBox(this.currentLayout, this.scrollbarDrag.scrollView) : void 0;\n      const geometry = box ? getScrollbarGeometry(box) : void 0;\n      if (geometry) {\n        const maxThumbOffset = geometry.trackHeight - geometry.thumbHeight;\n        const thumbOffset = Math.max(0, Math.min(maxThumbOffset, event.y - geometry.trackTop - this.scrollbarDrag.grabOffset));\n        const scrollTop = maxThumbOffset === 0 ? 0 : Math.round(thumbOffset / maxThumbOffset * geometry.maxScrollTop);\n        this.scrollbarDrag.scrollView.scrollTo(scrollTop);\n      }\n      return true;\n    }\n    if (event.release || (event.button & 32) !== 0 || (event.button & 3) !== 0)\n      return false;\n    const target = this.getScrollbarTargetAt(event.x, event.y);\n    if (!target)\n      return false;\n    this.stopSelectionAutoScroll();\n    this.selectionPressActive = false;\n    this.selectionAnchor = void 0;\n    this.selectionFocus = void 0;\n    this.selectionGranularity = \"character\";\n    this.selectionInitialRange = void 0;\n    this.lastClick = void 0;\n    this.pressedUrl = void 0;\n    this.selectionDragged = false;\n    this.setScrollbarHover(target.scrollView);\n    this.scrollbarDrag = {\n      scrollView: target.scrollView,\n      grabOffset: event.y - target.geometry.thumbTop\n    };\n    return true;\n  }\n  stopScrollbarDrag() {\n    this.scrollbarDrag = void 0;\n  }\n  getScrollSelectionPoint(scrollView, x, y) {\n    if (!this.currentLayout)\n      return void 0;\n    const box = getScrollViewBox(this.currentLayout, scrollView);\n    if (!box || box.rect.height <= 0 || box.clip.height <= 0)\n      return void 0;\n    const visibleTop = Math.max(0, box.rect.y, box.clip.y);\n    const visibleBottom = Math.min(this.terminal.rows - 1, box.rect.y + box.rect.height - 1, box.clip.y + box.clip.height - 1);\n    if (visibleBottom < visibleTop)\n      return void 0;\n    const pointerRow = Math.max(visibleTop, Math.min(visibleBottom, y));\n    const maxContentRow = Math.max(0, (box.scrollContentLines?.length ?? 1) - 1);\n    return {\n      row: Math.max(0, Math.min(maxContentRow, scrollView.scrollTop + pointerRow - box.rect.y)),\n      col: Math.max(0, Math.min(box.rect.width - 1, x - box.rect.x)),\n      scrollView\n    };\n  }\n  getSelectionPoint(event, scrollView) {\n    if (scrollView) {\n      const point = this.getScrollSelectionPoint(scrollView, event.x, event.y);\n      if (point)\n        return point;\n    }\n    return {\n      row: Math.max(0, Math.min(this.terminal.rows - 1, event.y)),\n      col: Math.max(0, Math.min(this.terminal.columns - 1, event.x))\n    };\n  }\n  getSelectionSourceLine(point) {\n    if (point.scrollView && this.currentLayout) {\n      const lines = getScrollViewBox(this.currentLayout, point.scrollView)?.scrollContentLines;\n      if (lines)\n        return lines[point.row] ?? \"\";\n    }\n    return this.previousScreen[point.row] ?? \"\";\n  }\n  getWordSelection(point) {\n    const line = stripTerminalSequences(this.getSelectionSourceLine(point));\n    let start = 0;\n    for (const segment of wordSegmenter4.segment(line)) {\n      const end = start + visibleWidth(segment.segment);\n      if (point.col >= start && point.col < end) {\n        return {\n          start: { ...point, col: start },\n          end: { ...point, col: end, boundary: true }\n        };\n      }\n      start = end;\n    }\n    return void 0;\n  }\n  getLineSelection(point) {\n    return {\n      start: { ...point, col: 0 },\n      end: { ...point, col: visibleWidth(this.getSelectionSourceLine(point)), boundary: true }\n    };\n  }\n  updateSelectionFocus(point) {\n    if (this.selectionGranularity === \"character\" || !this.selectionInitialRange) {\n      this.selectionFocus = point;\n      return;\n    }\n    const range = this.selectionGranularity === \"word\" ? this.getWordSelection(point) : this.getLineSelection(point);\n    if (!range)\n      return;\n    const initial = this.selectionInitialRange;\n    const targetBeforeInitial = range.start.row < initial.start.row || range.start.row === initial.start.row && range.start.col < initial.start.col;\n    if (targetBeforeInitial) {\n      this.selectionAnchor = initial.end;\n      this.selectionFocus = range.start;\n    } else {\n      this.selectionAnchor = initial.start;\n      this.selectionFocus = range.end;\n    }\n  }\n  getClickCount(point, word) {\n    const now = Date.now();\n    const previous = this.lastClick;\n    const count = word && previous && now - previous.timestamp <= DOUBLE_CLICK_INTERVAL_MS && previous.row === point.row && previous.scrollView === point.scrollView && previous.wordStart === word.start.col && previous.wordEnd === word.end.col ? previous.count % 3 + 1 : 1;\n    this.lastClick = word ? {\n      timestamp: now,\n      count,\n      row: point.row,\n      scrollView: point.scrollView,\n      wordStart: word.start.col,\n      wordEnd: word.end.col\n    } : void 0;\n    return count;\n  }\n  updateSelectionAutoScroll(event) {\n    const scrollView = this.selectionAnchor?.scrollView;\n    if (!scrollView || !this.currentLayout) {\n      this.stopSelectionAutoScroll();\n      return;\n    }\n    const box = getScrollViewBox(this.currentLayout, scrollView);\n    if (!box || box.rect.height <= 0 || box.clip.height <= 0) {\n      this.stopSelectionAutoScroll();\n      return;\n    }\n    const visibleTop = Math.max(0, box.rect.y, box.clip.y);\n    const visibleBottom = Math.min(this.terminal.rows - 1, box.rect.y + box.rect.height - 1, box.clip.y + box.clip.height - 1);\n    this.selectionDragPointer = { x: event.x, y: event.y };\n    this.selectionAutoScrollDirection = event.y <= visibleTop ? -1 : event.y >= visibleBottom ? 1 : 0;\n    if (this.selectionAutoScrollDirection === 0) {\n      this.stopSelectionAutoScroll();\n      return;\n    }\n    if (this.selectionAutoScrollTimer)\n      return;\n    this.selectionAutoScrollTimer = setInterval(() => this.autoScrollSelection(), 50);\n    this.selectionAutoScrollTimer.unref();\n  }\n  autoScrollSelection() {\n    const scrollView = this.selectionAnchor?.scrollView;\n    const pointer = this.selectionDragPointer;\n    const direction = this.selectionAutoScrollDirection;\n    if (!scrollView || !pointer || direction === 0) {\n      this.stopSelectionAutoScroll();\n      return;\n    }\n    const remaining = scrollView.scrollBy(direction);\n    if (remaining === direction) {\n      this.stopSelectionAutoScroll();\n      return;\n    }\n    const point = this.getScrollSelectionPoint(scrollView, pointer.x, pointer.y);\n    if (point)\n      this.updateSelectionFocus(point);\n    this.requestRender();\n  }\n  stopSelectionAutoScroll() {\n    if (this.selectionAutoScrollTimer) {\n      clearInterval(this.selectionAutoScrollTimer);\n      this.selectionAutoScrollTimer = void 0;\n    }\n    this.selectionAutoScrollDirection = 0;\n    this.selectionDragPointer = void 0;\n  }\n  handleSelectionMouseEvent(event) {\n    const button = event.button & 3;\n    if (button !== 0 && !(event.release && button === 3))\n      return;\n    const anchorScrollView = this.selectionAnchor?.scrollView;\n    const point = this.getSelectionPoint(event, anchorScrollView);\n    if (event.release) {\n      if (!this.selectionPressActive)\n        return;\n      this.selectionPressActive = false;\n      this.stopSelectionAutoScroll();\n      if (!this.selectionAnchor)\n        return;\n      this.updateSelectionFocus(point);\n      const clickedUrl = !this.selectionDragged && this.selectionAnchor.scrollView === point.scrollView && this.selectionAnchor.row === point.row && this.selectionAnchor.col === point.col ? this.pressedUrl : void 0;\n      this.pressedUrl = void 0;\n      if (clickedUrl && this.openUrl) {\n        this.selectionAnchor = void 0;\n        this.selectionFocus = void 0;\n        try {\n          this.openUrl(clickedUrl);\n        } catch {\n        }\n        this.requestRender();\n        return;\n      }\n      void this.copySelectionToClipboard();\n      this.requestRender();\n      return;\n    }\n    if ((event.button & 32) !== 0) {\n      if (!this.selectionPressActive || !this.selectionAnchor)\n        return;\n      this.selectionDragged = true;\n      this.lastClick = void 0;\n      this.pressedUrl = void 0;\n      this.updateSelectionFocus(point);\n      this.updateSelectionAutoScroll(event);\n      this.requestRender();\n      return;\n    }\n    this.stopSelectionAutoScroll();\n    this.selectionPressActive = true;\n    const scrollView = !this.hasOverlay() && this.currentLayout ? getScrollViewsAt(this.currentLayout, event.x, event.y)[0] : void 0;\n    const anchor = this.getSelectionPoint(event, scrollView);\n    const word = this.getWordSelection(anchor);\n    const clickCount = this.getClickCount(anchor, word);\n    const range = clickCount === 2 ? word : clickCount === 3 ? this.getLineSelection(anchor) : void 0;\n    this.selectionGranularity = range ? clickCount === 2 ? \"word\" : \"line\" : \"character\";\n    this.selectionInitialRange = range;\n    this.selectionAnchor = range?.start ?? anchor;\n    this.selectionFocus = range?.end ?? anchor;\n    this.selectionDragged = false;\n    this.pressedUrl = range ? void 0 : getOsc8LinkAtColumn(this.previousScreen[Math.max(0, Math.min(this.terminal.rows - 1, event.y))] ?? \"\", Math.max(0, Math.min(this.terminal.columns - 1, event.x)));\n    this.requestRender();\n  }\n  getSelectionBounds() {\n    if (!this.selectionAnchor || !this.selectionFocus)\n      return void 0;\n    if (this.selectionAnchor.scrollView !== this.selectionFocus.scrollView)\n      return void 0;\n    const anchorBeforeFocus = this.selectionAnchor.row < this.selectionFocus.row || this.selectionAnchor.row === this.selectionFocus.row && this.selectionAnchor.col < this.selectionFocus.col;\n    if (this.selectionAnchor.row === this.selectionFocus.row && this.selectionAnchor.col === this.selectionFocus.col) {\n      return void 0;\n    }\n    return anchorBeforeFocus ? { start: this.selectionAnchor, end: this.selectionFocus } : { start: this.selectionFocus, end: this.selectionAnchor };\n  }\n  getSelectionColumns(line, row, selection, minColumn = 0, maxColumn = visibleWidth(line)) {\n    const lineWidth = visibleWidth(line);\n    let start = Math.max(0, minColumn);\n    let end = Math.min(lineWidth, maxColumn);\n    if (row === selection.start.row) {\n      start = getGraphemeCellRange(line, selection.start.col)?.start ?? Math.min(selection.start.col, lineWidth);\n    }\n    if (row === selection.end.row) {\n      end = selection.end.boundary ? Math.min(selection.end.col, lineWidth) : getGraphemeCellRange(line, selection.end.col)?.end ?? Math.min(selection.end.col + 1, lineWidth);\n    }\n    return { start: Math.max(minColumn, start), end: Math.min(maxColumn, end) };\n  }\n  async copySelectionToClipboard() {\n    const selection = this.getSelectionBounds();\n    if (!selection)\n      return;\n    let sourceLines = this.previousScreen;\n    if (selection.start.scrollView) {\n      if (!this.currentLayout)\n        return;\n      const box = getScrollViewBox(this.currentLayout, selection.start.scrollView);\n      if (!box?.scrollContentLines)\n        return;\n      sourceLines = box.scrollContentLines;\n    }\n    const lines = [];\n    for (let row = selection.start.row; row <= selection.end.row; row++) {\n      const line = sourceLines[row] ?? \"\";\n      const columns = this.getSelectionColumns(line, row, selection);\n      lines.push(stripTerminalSequences(sliceByColumn(line, columns.start, Math.max(0, columns.end - columns.start), true)).trimEnd());\n    }\n    const text = lines.join(\"\\n\");\n    if (text.length === 0)\n      return;\n    if (this.copySelection) {\n      const ok2 = await this.copySelection(text);\n      this.flash(ok2 ? \"Copied!\" : \"Copy failed\");\n      return;\n    }\n    this.terminal.write(`\\x1B]52;c;${Buffer.from(text).toString(\"base64\")}\\x07`);\n    this.flash(\"Copied!\");\n  }\n  applySearchTextHighlight(text, current) {\n    const style = current ? this.searchCurrentMatchStyle : this.searchMatchStyle;\n    let result = \"\";\n    let plainStart = 0;\n    let index = 0;\n    while (index < text.length) {\n      const ansi = extractAnsiCode(text, index);\n      if (!ansi) {\n        index += 1;\n        continue;\n      }\n      if (index > plainStart)\n        result += style(text.slice(plainStart, index));\n      result += ansi.code;\n      index += ansi.length;\n      plainStart = index;\n    }\n    if (plainStart < text.length)\n      result += style(text.slice(plainStart));\n    return result;\n  }\n  applySearchHighlights(screen, layout) {\n    const search = this.activeSearch;\n    if (!search || search.selectedIndex < 0 || search.matches.length === 0)\n      return screen;\n    const scrollView = layout.primaryScrollView ?? this.implicitScrollView;\n    const box = getScrollViewBox(layout, scrollView);\n    if (!box)\n      return screen;\n    const rangesByRow = /* @__PURE__ */ new Map();\n    const scrollbarColumn = getScrollbarGeometry(box)?.column;\n    const minRow = Math.max(0, box.rect.y, box.clip.y);\n    const maxRow = Math.min(screen.length, box.rect.y + box.rect.height, box.clip.y + box.clip.height);\n    const minColumn = Math.max(0, box.rect.x, box.clip.x);\n    const maxColumn = Math.min(this.terminal.columns, box.rect.x + box.rect.width, box.clip.x + box.clip.width, scrollbarColumn ?? Number.POSITIVE_INFINITY);\n    for (let matchIndex = 0; matchIndex < search.matches.length; matchIndex++) {\n      for (const segment of search.matches[matchIndex].segments) {\n        const row = box.rect.y + segment.row - scrollView.scrollTop;\n        if (row < minRow || row >= maxRow)\n          continue;\n        const startCol = Math.max(minColumn, box.rect.x + segment.startCol);\n        const endCol = Math.min(maxColumn, box.rect.x + segment.endCol);\n        if (endCol <= startCol)\n          continue;\n        const ranges = rangesByRow.get(row) ?? [];\n        ranges.push({ startCol, endCol, current: matchIndex === search.selectedIndex });\n        rangesByRow.set(row, ranges);\n      }\n    }\n    const result = [...screen];\n    for (const [row, ranges] of rangesByRow) {\n      let line = result[row] ?? \"\";\n      if (isImageLine(line))\n        continue;\n      const lineWidth = visibleWidth(line);\n      for (const range of ranges.sort((a, b) => b.startCol - a.startCol)) {\n        const startCol = Math.min(range.startCol, lineWidth);\n        const endCol = Math.min(range.endCol, lineWidth);\n        if (endCol <= startCol)\n          continue;\n        const before = sliceByColumn(line, 0, startCol, true);\n        const highlighted = sliceByColumn(line, startCol, endCol - startCol, true);\n        const after = sliceByColumn(line, endCol, Math.max(0, lineWidth - endCol), true);\n        line = `${before}${this.applySearchTextHighlight(highlighted, range.current)}${after}`;\n      }\n      result[row] = line;\n    }\n    return result;\n  }\n  applySelectionHighlight(text) {\n    let result = \"\\x1B[7m\";\n    let index = 0;\n    while (index < text.length) {\n      const ansi = extractAnsiCode(text, index);\n      if (!ansi) {\n        result += text[index];\n        index += 1;\n        continue;\n      }\n      result += ansi.code;\n      if (ansi.code.endsWith(\"m\"))\n        result += \"\\x1B[7m\";\n      index += ansi.length;\n    }\n    return `${result}\\x1B[27m`;\n  }\n  applySelection(screen, layout = this.currentLayout) {\n    const selection = this.getSelectionBounds();\n    if (!selection)\n      return screen;\n    let screenSelection = selection;\n    let minRow = 0;\n    let maxRow = screen.length - 1;\n    let minColumn = 0;\n    let maxColumn = this.terminal.columns;\n    if (selection.start.scrollView) {\n      if (!layout)\n        return screen;\n      const box = getScrollViewBox(layout, selection.start.scrollView);\n      if (!box)\n        return screen;\n      minRow = Math.max(0, box.rect.y, box.clip.y);\n      maxRow = Math.min(screen.length - 1, box.rect.y + box.rect.height - 1, box.clip.y + box.clip.height - 1);\n      minColumn = Math.max(0, box.rect.x, box.clip.x);\n      maxColumn = Math.min(this.terminal.columns, box.rect.x + box.rect.width, box.clip.x + box.clip.width);\n      screenSelection = {\n        start: {\n          ...selection.start,\n          row: box.rect.y + selection.start.row - selection.start.scrollView.scrollTop,\n          col: box.rect.x + selection.start.col\n        },\n        end: {\n          ...selection.end,\n          row: box.rect.y + selection.end.row - selection.start.scrollView.scrollTop,\n          col: box.rect.x + selection.end.col\n        }\n      };\n    }\n    return screen.map((line, row) => {\n      if (row < minRow || row > maxRow || row < screenSelection.start.row || row > screenSelection.end.row || isImageLine(line)) {\n        return line;\n      }\n      const lineWidth = visibleWidth(line);\n      const columns = this.getSelectionColumns(line, row, screenSelection, minColumn, maxColumn);\n      if (columns.end <= columns.start)\n        return line;\n      const before = sliceByColumn(line, 0, columns.start, true);\n      const selected = sliceByColumn(line, columns.start, columns.end - columns.start, true);\n      const after = sliceByColumn(line, columns.end, Math.max(0, lineWidth - columns.end), true);\n      return `${before}${this.applySelectionHighlight(selected)}${after}`;\n    });\n  }\n  isMouseSequence(data) {\n    return /^\\x1b\\[<\\d+;\\d+;\\d+[Mm]$/.test(data) || data.length === 6 && data.startsWith(\"\\x1B[M\");\n  }\n  compositeFlashes(screen, width, height) {\n    const flashLines = this.flashes.render(width).slice(-height);\n    if (flashLines.length === 0)\n      return screen;\n    const result = [...screen];\n    while (result.length < height)\n      result.push(\"\");\n    for (let row = 0; row < flashLines.length; row++) {\n      const line = flashLines[row];\n      const flashWidth = visibleWidth(line);\n      if (flashWidth === 0)\n        continue;\n      result[row] = compositeTuiLine(result[row] ?? \"\", line, width - flashWidth, flashWidth, width);\n    }\n    return result;\n  }\n  doRender() {\n    if (this.stopped || !this.altScreenActive)\n      return;\n    const width = Math.max(1, this.terminal.columns);\n    const height = Math.max(1, this.terminal.rows);\n    const root = this.layoutRoot ?? this.implicitScrollView;\n    let nextLayout = renderLayoutFrame(root, width, height, () => this.requestRender());\n    if (this.refreshSearch(nextLayout)) {\n      nextLayout = renderLayoutFrame(root, width, height, () => this.requestRender());\n    }\n    let screen = nextLayout.lines.map((line) => line.replace(OSC133_ZONE_PREFIX2, \"\"));\n    screen = this.applySearchHighlights(screen, nextLayout);\n    screen = this.compositeOverlays(screen, width, height);\n    if (screen.length > height)\n      screen = screen.slice(screen.length - height);\n    screen = this.applySelection(screen, nextLayout);\n    screen = this.compositeFlashes(screen, width, height);\n    const cursorPos = this.extractCursorPosition(screen, height);\n    screen = this.applyLineResets(screen).map((line) => {\n      if (isImageLine(line) || visibleWidth(line) <= width)\n        return line;\n      return sliceByColumn(line, 0, width, true);\n    });\n    const fullRedraw = this.previousScreen.length === 0 || this.previousScreenWidth !== width || this.previousScreenHeight !== height;\n    const imagesNeedRedraw = screen.some((line, row) => line !== this.previousScreen[row] && (isImageLine(line) || isImageLine(this.previousScreen[row] ?? \"\")));\n    const redrawImages = fullRedraw || imagesNeedRedraw;\n    const hadUploadedKittyImages = this.uploadedKittyImages.size > 0;\n    const preparedKittyScreen = redrawImages && this.imageProtocol === \"kitty\" ? this.prepareKittyScreen(screen) : { lines: screen, evictedImageDeletion: \"\" };\n    let buffer = BEGIN_SYNCHRONIZED_OUTPUT;\n    if (fullRedraw) {\n      this.fullRedrawCount += 1;\n      const clearImages = this.imageProtocol === \"kitty\" && hadUploadedKittyImages ? deleteAllKittyPlacements() : this.deleteKittyImages();\n      buffer += `${clearImages}\\x1B[2J`;\n    } else if (imagesNeedRedraw) {\n      if (this.imageProtocol === \"iterm2\")\n        buffer += \"\\x1B[2J\";\n      else if (this.imageProtocol === \"kitty\")\n        buffer += deleteAllKittyPlacements();\n    }\n    buffer += preparedKittyScreen.evictedImageDeletion;\n    for (let row = 0; row < height; row++) {\n      if (!fullRedraw && !imagesNeedRedraw && screen[row] === this.previousScreen[row])\n        continue;\n      buffer += `\\x1B[${row + 1};1H\\x1B[2K${preparedKittyScreen.lines[row] ?? \"\"}`;\n    }\n    if (cursorPos) {\n      buffer += `\\x1B[${cursorPos.row + 1};${Math.min(width, cursorPos.col) + 1}H`;\n      buffer += this.getShowHardwareCursor() ? \"\\x1B[?25h\" : \"\\x1B[?25l\";\n    } else {\n      buffer += \"\\x1B[?25l\";\n    }\n    buffer += END_SYNCHRONIZED_OUTPUT;\n    this.terminal.write(buffer);\n    this.previousScreen = screen;\n    this.previousScreenWidth = width;\n    this.previousScreenHeight = height;\n    this.currentLayout = nextLayout;\n  }\n};\n\n// node_modules/.pnpm/@earendil-works+pi-tui@0.84.2/node_modules/@earendil-works/pi-tui/dist/tui-main-screen.js\nimport * as fs3 from \"node:fs\";\nimport * as path5 from \"node:path\";\nvar KITTY_SEQUENCE_PREFIX = \"\\x1B_G\";\nfunction parseKittyImageHeader(line) {\n  const sequenceStart = line.indexOf(KITTY_SEQUENCE_PREFIX);\n  if (sequenceStart === -1)\n    return void 0;\n  const paramsStart = sequenceStart + KITTY_SEQUENCE_PREFIX.length;\n  const paramsEnd = line.indexOf(\";\", paramsStart);\n  if (paramsEnd === -1)\n    return void 0;\n  const ids = [];\n  let rows = 1;\n  for (const param of line.slice(paramsStart, paramsEnd).split(\",\")) {\n    const [key, value] = param.split(\"=\", 2);\n    if (value === void 0)\n      continue;\n    const numberValue = Number(value);\n    if (!Number.isInteger(numberValue) || numberValue <= 0 || numberValue > 4294967295)\n      continue;\n    if (key === \"i\")\n      ids.push(numberValue);\n    else if (key === \"r\")\n      rows = numberValue;\n  }\n  return { ids, rows };\n}\nfunction extractKittyImageIds(line) {\n  return parseKittyImageHeader(line)?.ids ?? [];\n}\nfunction extractKittyImageRows(line) {\n  return parseKittyImageHeader(line)?.rows ?? 1;\n}\nfunction isTermuxSession() {\n  return Boolean(process.env.TERMUX_VERSION);\n}\nvar TuiMainScreen = class extends TuiBase {\n  mode = \"regular\";\n  previousLines = [];\n  previousKittyImageIds = /* @__PURE__ */ new Set();\n  previousWidth = 0;\n  previousHeight = 0;\n  cursorRow = 0;\n  hardwareCursorRow = 0;\n  maxLinesRendered = 0;\n  previousViewportTop = 0;\n  captureRenderState() {\n    return {\n      previousLines: [...this.previousLines],\n      previousWidth: this.previousWidth,\n      previousHeight: this.previousHeight,\n      cursorRow: this.cursorRow,\n      hardwareCursorRow: this.hardwareCursorRow,\n      maxLinesRendered: this.maxLinesRendered,\n      previousViewportTop: this.previousViewportTop\n    };\n  }\n  restoreRenderState(state) {\n    this.previousLines = state.previousLines.map((line) => isImageLine(line) ? \"\" : line);\n    this.previousKittyImageIds = /* @__PURE__ */ new Set();\n    this.previousWidth = state.previousWidth;\n    this.previousHeight = state.previousHeight;\n    this.cursorRow = state.cursorRow;\n    this.hardwareCursorRow = state.hardwareCursorRow;\n    this.maxLinesRendered = state.maxLinesRendered;\n    this.previousViewportTop = state.previousViewportTop;\n  }\n  resetRenderState() {\n    this.previousLines = [];\n    this.previousWidth = -1;\n    this.previousHeight = -1;\n    this.cursorRow = 0;\n    this.hardwareCursorRow = 0;\n    this.maxLinesRendered = 0;\n    this.previousViewportTop = 0;\n  }\n  beforeTerminalStop(options) {\n    if (options.preserveScreen || this.previousLines.length === 0)\n      return;\n    this.terminal.write(\" \");\n    const targetRow = this.previousLines.length;\n    const lineDiff = targetRow - this.hardwareCursorRow;\n    if (lineDiff > 0)\n      this.terminal.write(`\\x1B[${lineDiff}B`);\n    else if (lineDiff < 0)\n      this.terminal.write(`\\x1B[${-lineDiff}A`);\n    this.terminal.write(\"\\r\\n\");\n  }\n  collectKittyImageIds(lines) {\n    const ids = /* @__PURE__ */ new Set();\n    for (const line of lines) {\n      for (const id of extractKittyImageIds(line)) {\n        ids.add(id);\n      }\n    }\n    return ids;\n  }\n  deleteKittyImages(ids) {\n    let buffer = \"\";\n    for (const id of ids) {\n      buffer += deleteKittyImage(id);\n    }\n    return buffer;\n  }\n  getKittyImageReservedRows(lines, index, maxIndex = lines.length - 1) {\n    const rows = extractKittyImageRows(lines[index] ?? \"\");\n    if (rows <= 1)\n      return 1;\n    const maxRows = Math.min(rows, maxIndex - index + 1, lines.length - index);\n    let reservedRows = 1;\n    while (reservedRows < maxRows) {\n      const line = lines[index + reservedRows] ?? \"\";\n      if (isImageLine(line) || visibleWidth(line) > 0)\n        break;\n      reservedRows++;\n    }\n    return reservedRows;\n  }\n  expandChangedRangeForKittyImages(firstChanged, lastChanged, newLines) {\n    let expandedFirstChanged = firstChanged;\n    let expandedLastChanged = lastChanged;\n    const expandForLines = (lines) => {\n      for (let i = 0; i < lines.length; i++) {\n        if (extractKittyImageIds(lines[i]).length === 0)\n          continue;\n        const blockEnd = i + this.getKittyImageReservedRows(lines, i) - 1;\n        if (i >= firstChanged || i <= lastChanged && blockEnd >= firstChanged) {\n          expandedFirstChanged = Math.min(expandedFirstChanged, i);\n          expandedLastChanged = Math.max(expandedLastChanged, blockEnd);\n        }\n      }\n    };\n    expandForLines(this.previousLines);\n    expandForLines(newLines);\n    return { firstChanged: expandedFirstChanged, lastChanged: expandedLastChanged };\n  }\n  deleteChangedKittyImages(firstChanged, lastChanged) {\n    if (firstChanged < 0 || lastChanged < firstChanged)\n      return \"\";\n    const ids = /* @__PURE__ */ new Set();\n    const maxLine = Math.min(lastChanged, this.previousLines.length - 1);\n    for (let i = firstChanged; i <= maxLine; i++) {\n      for (const id of extractKittyImageIds(this.previousLines[i] ?? \"\")) {\n        ids.add(id);\n      }\n    }\n    return this.deleteKittyImages(ids);\n  }\n  doRender() {\n    if (this.stopped)\n      return;\n    const width = this.terminal.columns;\n    const height = this.terminal.rows;\n    const widthChanged = this.previousWidth !== 0 && this.previousWidth !== width;\n    const heightChanged = this.previousHeight !== 0 && this.previousHeight !== height;\n    const previousBufferLength = this.previousHeight > 0 ? this.previousViewportTop + this.previousHeight : height;\n    let prevViewportTop = heightChanged ? Math.max(0, previousBufferLength - height) : this.previousViewportTop;\n    let viewportTop = prevViewportTop;\n    let hardwareCursorRow = this.hardwareCursorRow;\n    const computeLineDiff = (targetRow) => {\n      const currentScreenRow = hardwareCursorRow - prevViewportTop;\n      const targetScreenRow = targetRow - viewportTop;\n      return targetScreenRow - currentScreenRow;\n    };\n    let newLines = this.render(width);\n    if (this.hasOverlayEntries) {\n      newLines = this.compositeOverlays(newLines, width, height);\n    }\n    const cursorPos = this.extractCursorPosition(newLines, height);\n    newLines = this.applyLineResets(newLines);\n    const fullRender = (clear) => {\n      this.fullRedrawCount += 1;\n      let buffer2 = \"\\x1B[?2026h\";\n      if (clear) {\n        buffer2 += this.deleteKittyImages(this.previousKittyImageIds);\n        buffer2 += \"\\x1B[2J\\x1B[H\\x1B[3J\";\n      }\n      for (let i = 0; i < newLines.length; i++) {\n        if (i > 0)\n          buffer2 += \"\\r\\n\";\n        const line = newLines[i];\n        const isImage = isImageLine(line);\n        const imageReservedRows = isImage ? this.getKittyImageReservedRows(newLines, i) : 1;\n        if (imageReservedRows > 1 && imageReservedRows <= height) {\n          for (let row = 1; row < imageReservedRows; row++) {\n            buffer2 += \"\\r\\n\";\n          }\n          buffer2 += `\\x1B[${imageReservedRows - 1}A`;\n          buffer2 += line;\n          buffer2 += `\\x1B[${imageReservedRows - 1}B`;\n          i += imageReservedRows - 1;\n          continue;\n        }\n        buffer2 += line;\n      }\n      buffer2 += \"\\x1B[?2026l\";\n      this.terminal.write(buffer2);\n      this.cursorRow = Math.max(0, newLines.length - 1);\n      this.hardwareCursorRow = this.cursorRow;\n      if (clear) {\n        this.maxLinesRendered = newLines.length;\n      } else {\n        this.maxLinesRendered = Math.max(this.maxLinesRendered, newLines.length);\n      }\n      const bufferLength = Math.max(height, newLines.length);\n      this.previousViewportTop = Math.max(0, bufferLength - height);\n      this.positionHardwareCursor(cursorPos, newLines.length);\n      this.previousLines = newLines;\n      this.previousKittyImageIds = this.collectKittyImageIds(newLines);\n      this.previousWidth = width;\n      this.previousHeight = height;\n    };\n    const debugRedraw = process.env.PI_DEBUG_REDRAW === \"1\";\n    const logRedraw = (reason) => {\n      if (!debugRedraw)\n        return;\n      const logPath = path5.join(this.logDirectory, \"pi-debug.log\");\n      const msg = `[${(/* @__PURE__ */ new Date()).toISOString()}] fullRender: ${reason} (prev=${this.previousLines.length}, new=${newLines.length}, height=${height})\n`;\n      fs3.mkdirSync(path5.dirname(logPath), { recursive: true });\n      fs3.appendFileSync(logPath, msg);\n    };\n    if (this.previousLines.length === 0 && !widthChanged && !heightChanged) {\n      logRedraw(\"first render\");\n      fullRender(false);\n      return;\n    }\n    if (widthChanged) {\n      logRedraw(`terminal width changed (${this.previousWidth} -> ${width})`);\n      fullRender(true);\n      return;\n    }\n    if (heightChanged && !isTermuxSession()) {\n      logRedraw(`terminal height changed (${this.previousHeight} -> ${height})`);\n      fullRender(true);\n      return;\n    }\n    if (this.getClearOnShrink() && newLines.length < this.maxLinesRendered && !this.hasOverlayEntries) {\n      logRedraw(`clearOnShrink (maxLinesRendered=${this.maxLinesRendered})`);\n      fullRender(true);\n      return;\n    }\n    let firstChanged = -1;\n    let lastChanged = -1;\n    const maxLines = Math.max(newLines.length, this.previousLines.length);\n    for (let i = 0; i < maxLines; i++) {\n      const oldLine = i < this.previousLines.length ? this.previousLines[i] : \"\";\n      const newLine = i < newLines.length ? newLines[i] : \"\";\n      if (oldLine !== newLine) {\n        if (firstChanged === -1) {\n          firstChanged = i;\n        }\n        lastChanged = i;\n      }\n    }\n    const appendedLines = newLines.length > this.previousLines.length;\n    if (appendedLines) {\n      if (firstChanged === -1) {\n        firstChanged = this.previousLines.length;\n      }\n      lastChanged = newLines.length - 1;\n    }\n    if (firstChanged !== -1) {\n      const expandedRange = this.expandChangedRangeForKittyImages(firstChanged, lastChanged, newLines);\n      firstChanged = expandedRange.firstChanged;\n      lastChanged = expandedRange.lastChanged;\n    }\n    const appendStart = appendedLines && firstChanged === this.previousLines.length && firstChanged > 0;\n    if (firstChanged === -1) {\n      this.positionHardwareCursor(cursorPos, newLines.length);\n      this.previousViewportTop = prevViewportTop;\n      this.previousHeight = height;\n      return;\n    }\n    if (firstChanged >= newLines.length) {\n      if (this.previousLines.length > newLines.length) {\n        let buffer2 = \"\\x1B[?2026h\";\n        buffer2 += this.deleteChangedKittyImages(firstChanged, lastChanged);\n        const targetRow = Math.max(0, newLines.length - 1);\n        if (targetRow < prevViewportTop) {\n          logRedraw(`deleted lines moved viewport up (${targetRow} < ${prevViewportTop})`);\n          fullRender(true);\n          return;\n        }\n        const lineDiff2 = computeLineDiff(targetRow);\n        if (lineDiff2 > 0)\n          buffer2 += `\\x1B[${lineDiff2}B`;\n        else if (lineDiff2 < 0)\n          buffer2 += `\\x1B[${-lineDiff2}A`;\n        buffer2 += \"\\r\";\n        const extraLines = this.previousLines.length - newLines.length;\n        if (extraLines > height) {\n          logRedraw(`extraLines > height (${extraLines} > ${height})`);\n          fullRender(true);\n          return;\n        }\n        const clearStartOffset = newLines.length === 0 ? 0 : 1;\n        if (extraLines > 0 && clearStartOffset > 0) {\n          buffer2 += `\\x1B[${clearStartOffset}B`;\n        }\n        for (let i = 0; i < extraLines; i++) {\n          buffer2 += \"\\r\\x1B[2K\";\n          if (i < extraLines - 1)\n            buffer2 += \"\\x1B[1B\";\n        }\n        const moveBack = Math.max(0, extraLines - 1 + clearStartOffset);\n        if (moveBack > 0) {\n          buffer2 += `\\x1B[${moveBack}A`;\n        }\n        buffer2 += \"\\x1B[?2026l\";\n        this.terminal.write(buffer2);\n        this.cursorRow = targetRow;\n        this.hardwareCursorRow = targetRow;\n      }\n      this.positionHardwareCursor(cursorPos, newLines.length);\n      this.previousLines = newLines;\n      this.previousKittyImageIds = this.collectKittyImageIds(newLines);\n      this.previousWidth = width;\n      this.previousHeight = height;\n      this.previousViewportTop = prevViewportTop;\n      return;\n    }\n    if (firstChanged < prevViewportTop) {\n      logRedraw(`firstChanged < viewportTop (${firstChanged} < ${prevViewportTop})`);\n      fullRender(true);\n      return;\n    }\n    let buffer = \"\\x1B[?2026h\";\n    buffer += this.deleteChangedKittyImages(firstChanged, lastChanged);\n    const prevViewportBottom = prevViewportTop + height - 1;\n    const moveTargetRow = appendStart ? firstChanged - 1 : firstChanged;\n    if (moveTargetRow > prevViewportBottom) {\n      const currentScreenRow = Math.max(0, Math.min(height - 1, hardwareCursorRow - prevViewportTop));\n      const moveToBottom = height - 1 - currentScreenRow;\n      if (moveToBottom > 0) {\n        buffer += `\\x1B[${moveToBottom}B`;\n      }\n      const scroll = moveTargetRow - prevViewportBottom;\n      buffer += \"\\r\\n\".repeat(scroll);\n      prevViewportTop += scroll;\n      viewportTop += scroll;\n      hardwareCursorRow = moveTargetRow;\n    }\n    const lineDiff = computeLineDiff(moveTargetRow);\n    if (lineDiff > 0) {\n      buffer += `\\x1B[${lineDiff}B`;\n    } else if (lineDiff < 0) {\n      buffer += `\\x1B[${-lineDiff}A`;\n    }\n    buffer += appendStart ? \"\\r\\n\" : \"\\r\";\n    const renderEnd = Math.min(lastChanged, newLines.length - 1);\n    for (let i = firstChanged; i <= renderEnd; i++) {\n      if (i > firstChanged)\n        buffer += \"\\r\\n\";\n      const line = newLines[i];\n      const isImage = isImageLine(line);\n      const imageReservedRows = isImage ? this.getKittyImageReservedRows(newLines, i, renderEnd) : 1;\n      if (imageReservedRows > 1) {\n        const imageStartScreenRow = i - viewportTop;\n        if (imageStartScreenRow < 0 || imageStartScreenRow + imageReservedRows > height) {\n          logRedraw(`kitty image pre-clear would scroll (${imageStartScreenRow} + ${imageReservedRows} > ${height})`);\n          fullRender(true);\n          return;\n        }\n        buffer += \"\\x1B[2K\";\n        for (let row = 1; row < imageReservedRows; row++) {\n          buffer += \"\\r\\n\\x1B[2K\";\n        }\n        buffer += `\\x1B[${imageReservedRows - 1}A`;\n        buffer += line;\n        buffer += `\\x1B[${imageReservedRows - 1}B`;\n        i += imageReservedRows - 1;\n        continue;\n      }\n      buffer += \"\\x1B[2K\";\n      if (!isImage && visibleWidth(line) > width) {\n        const crashLogPath = path5.join(this.logDirectory, \"pi-crash.log\");\n        const crashData = [\n          `Crash at ${(/* @__PURE__ */ new Date()).toISOString()}`,\n          `Terminal width: ${width}`,\n          `Line ${i} visible width: ${visibleWidth(line)}`,\n          \"\",\n          \"=== All rendered lines ===\",\n          ...newLines.map((l, idx) => `[${idx}] (w=${visibleWidth(l)}) ${l}`),\n          \"\"\n        ].join(\"\\n\");\n        fs3.mkdirSync(path5.dirname(crashLogPath), { recursive: true });\n        fs3.writeFileSync(crashLogPath, crashData);\n        this.stop();\n        const errorMsg = [\n          `Rendered line ${i} exceeds terminal width (${visibleWidth(line)} > ${width}).`,\n          \"\",\n          \"This is likely caused by a custom TUI component not truncating its output.\",\n          \"Use visibleWidth() to measure and truncateToWidth() to truncate lines.\",\n          \"\",\n          `Debug log written to: ${crashLogPath}`\n        ].join(\"\\n\");\n        throw new Error(errorMsg);\n      }\n      buffer += line;\n    }\n    let finalCursorRow = renderEnd;\n    if (this.previousLines.length > newLines.length) {\n      if (renderEnd < newLines.length - 1) {\n        const moveDown = newLines.length - 1 - renderEnd;\n        buffer += `\\x1B[${moveDown}B`;\n        finalCursorRow = newLines.length - 1;\n      }\n      const extraLines = this.previousLines.length - newLines.length;\n      for (let i = newLines.length; i < this.previousLines.length; i++) {\n        buffer += \"\\r\\n\\x1B[2K\";\n      }\n      buffer += `\\x1B[${extraLines}A`;\n    }\n    buffer += \"\\x1B[?2026l\";\n    if (process.env.PI_TUI_DEBUG === \"1\") {\n      const debugDir = \"/tmp/tui\";\n      fs3.mkdirSync(debugDir, { recursive: true });\n      const debugPath = path5.join(debugDir, `render-${Date.now()}-${Math.random().toString(36).slice(2)}.log`);\n      const debugData = [\n        `firstChanged: ${firstChanged}`,\n        `viewportTop: ${viewportTop}`,\n        `cursorRow: ${this.cursorRow}`,\n        `height: ${height}`,\n        `lineDiff: ${lineDiff}`,\n        `hardwareCursorRow: ${hardwareCursorRow}`,\n        `renderEnd: ${renderEnd}`,\n        `finalCursorRow: ${finalCursorRow}`,\n        `cursorPos: ${JSON.stringify(cursorPos)}`,\n        `newLines.length: ${newLines.length}`,\n        `previousLines.length: ${this.previousLines.length}`,\n        \"\",\n        \"=== newLines ===\",\n        JSON.stringify(newLines, null, 2),\n        \"\",\n        \"=== previousLines ===\",\n        JSON.stringify(this.previousLines, null, 2),\n        \"\",\n        \"=== buffer ===\",\n        JSON.stringify(buffer)\n      ].join(\"\\n\");\n      fs3.writeFileSync(debugPath, debugData);\n    }\n    this.terminal.write(buffer);\n    this.cursorRow = Math.max(0, newLines.length - 1);\n    this.hardwareCursorRow = finalCursorRow;\n    this.maxLinesRendered = Math.max(this.maxLinesRendered, newLines.length);\n    this.previousViewportTop = Math.max(prevViewportTop, finalCursorRow - height + 1);\n    this.positionHardwareCursor(cursorPos, newLines.length);\n    this.previousLines = newLines;\n    this.previousKittyImageIds = this.collectKittyImageIds(newLines);\n    this.previousWidth = width;\n    this.previousHeight = height;\n  }\n  /**\n   * Position the hardware cursor for IME candidate window.\n   * @param cursorPos The cursor position extracted from rendered output, or null\n   * @param totalLines Total number of rendered lines\n   */\n  positionHardwareCursor(cursorPos, totalLines) {\n    if (!cursorPos || totalLines <= 0) {\n      this.terminal.hideCursor();\n      return;\n    }\n    const targetRow = Math.max(0, Math.min(cursorPos.row, totalLines - 1));\n    const targetCol = Math.max(0, cursorPos.col);\n    const rowDelta = targetRow - this.hardwareCursorRow;\n    let buffer = \"\";\n    if (rowDelta > 0) {\n      buffer += `\\x1B[${rowDelta}B`;\n    } else if (rowDelta < 0) {\n      buffer += `\\x1B[${-rowDelta}A`;\n    }\n    buffer += `\\x1B[${targetCol + 1}G`;\n    if (buffer) {\n      this.terminal.write(buffer);\n    }\n    this.hardwareCursorRow = targetRow;\n    if (this.getShowHardwareCursor()) {\n      this.terminal.showCursor();\n    } else {\n      this.terminal.hideCursor();\n    }\n  }\n};\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/cli/list-models.js\nimport chalk4 from \"chalk\";\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/core/auth-guidance.js\nimport { join as join12 } from \"node:path\";\nvar UNKNOWN_PROVIDER = \"unknown\";\nfunction getProviderLoginHelp() {\n  return [\n    \"Use /login to log into a provider via OAuth or API key. See:\",\n    `  ${join12(getDocsPath(), \"providers.md\")}`,\n    `  ${join12(getDocsPath(), \"models.md\")}`\n  ].join(\"\\n\");\n}\nfunction formatNoModelsAvailableMessage() {\n  return `No models available. ${getProviderLoginHelp()}`;\n}\nfunction formatNoModelSelectedMessage() {\n  return `No model selected.\n\n${getProviderLoginHelp()}\n\nThen use /model to select a model.`;\n}\nfunction formatNoApiKeyFoundMessage(provider) {\n  const providerDisplay = provider === UNKNOWN_PROVIDER ? \"the selected model\" : provider;\n  return `No API key found for ${providerDisplay}.\n\n${getProviderLoginHelp()}`;\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/cli/list-models.js\nfunction formatTokenCount(count) {\n  if (count >= 1e6) {\n    const millions = count / 1e6;\n    return millions % 1 === 0 ? `${millions}M` : `${millions.toFixed(1)}M`;\n  }\n  if (count >= 1e3) {\n    const thousands = count / 1e3;\n    return thousands % 1 === 0 ? `${thousands}K` : `${thousands.toFixed(1)}K`;\n  }\n  return count.toString();\n}\nasync function listModels(modelRuntime, searchPattern, signal) {\n  const loadError = modelRuntime.getError();\n  if (loadError) {\n    console.error(chalk4.yellow(`Warning: errors loading models.json:\n${loadError}`));\n  }\n  const models = [...await modelRuntime.getAvailable(void 0, { signal })];\n  if (models.length === 0) {\n    console.log(formatNoModelsAvailableMessage());\n    return;\n  }\n  let filteredModels = models;\n  if (searchPattern) {\n    filteredModels = fuzzyFilter(models, searchPattern, (m) => `${m.provider} ${m.id}`);\n  }\n  if (filteredModels.length === 0) {\n    console.log(`No models matching \"${searchPattern}\"`);\n    return;\n  }\n  filteredModels.sort((a, b) => {\n    const providerCmp = a.provider.localeCompare(b.provider);\n    if (providerCmp !== 0)\n      return providerCmp;\n    return a.id.localeCompare(b.id);\n  });\n  const rows = filteredModels.map((m) => ({\n    provider: m.provider,\n    model: m.id,\n    context: formatTokenCount(m.contextWindow),\n    maxOut: formatTokenCount(m.maxTokens),\n    thinking: m.reasoning ? \"yes\" : \"no\",\n    images: m.input.includes(\"image\") ? \"yes\" : \"no\"\n  }));\n  const headers = {\n    provider: \"provider\",\n    model: \"model\",\n    context: \"context\",\n    maxOut: \"max-out\",\n    thinking: \"thinking\",\n    images: \"images\"\n  };\n  const widths = {\n    provider: Math.max(headers.provider.length, ...rows.map((r) => r.provider.length)),\n    model: Math.max(headers.model.length, ...rows.map((r) => r.model.length)),\n    context: Math.max(headers.context.length, ...rows.map((r) => r.context.length)),\n    maxOut: Math.max(headers.maxOut.length, ...rows.map((r) => r.maxOut.length)),\n    thinking: Math.max(headers.thinking.length, ...rows.map((r) => r.thinking.length)),\n    images: Math.max(headers.images.length, ...rows.map((r) => r.images.length))\n  };\n  const headerLine = [\n    headers.provider.padEnd(widths.provider),\n    headers.model.padEnd(widths.model),\n    headers.context.padEnd(widths.context),\n    headers.maxOut.padEnd(widths.maxOut),\n    headers.thinking.padEnd(widths.thinking),\n    headers.images.padEnd(widths.images)\n  ].join(\"  \");\n  console.log(headerLine);\n  for (const row of rows) {\n    const line = [\n      row.provider.padEnd(widths.provider),\n      row.model.padEnd(widths.model),\n      row.context.padEnd(widths.context),\n      row.maxOut.padEnd(widths.maxOut),\n      row.thinking.padEnd(widths.thinking),\n      row.images.padEnd(widths.images)\n    ].join(\"  \");\n    console.log(line);\n  }\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/cli/project-trust.js\nimport chalk6 from \"chalk\";\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/cli/startup-ui.js\nimport { existsSync as existsSync8 } from \"fs\";\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/core/experimental.js\nvar PREFER_STRICT_TOOL_SAMPLING = { type: \"json_schema\", strict: \"prefer\" };\nfunction areExperimentalFeaturesEnabled() {\n  return process.env.PI_EXPERIMENTAL === \"1\";\n}\nfunction getExperimentalToolSampling() {\n  return areExperimentalFeaturesEnabled() ? PREFER_STRICT_TOOL_SAMPLING : void 0;\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/core/keybindings.js\nimport { existsSync as existsSync4, readFileSync as readFileSync3 } from \"fs\";\nimport { join as join13 } from \"path\";\nvar KEYBINDINGS = {\n  ...TUI_KEYBINDINGS,\n  \"app.interrupt\": { defaultKeys: \"escape\", description: \"Cancel or abort\" },\n  \"app.clear\": { defaultKeys: \"ctrl+c\", description: \"Clear editor\" },\n  \"app.exit\": { defaultKeys: \"ctrl+d\", description: \"Exit when editor is empty\" },\n  \"app.suspend\": {\n    defaultKeys: process.platform === \"win32\" ? [] : \"ctrl+z\",\n    description: \"Suspend to background\"\n  },\n  \"app.thinking.cycle\": {\n    defaultKeys: \"shift+tab\",\n    description: \"Cycle thinking level\"\n  },\n  \"app.model.cycleForward\": {\n    defaultKeys: \"ctrl+p\",\n    description: \"Cycle to next model\"\n  },\n  \"app.model.cycleBackward\": {\n    defaultKeys: \"shift+ctrl+p\",\n    description: \"Cycle to previous model\"\n  },\n  \"app.model.select\": { defaultKeys: \"ctrl+l\", description: \"Open model selector\" },\n  \"app.tools.expand\": { defaultKeys: \"ctrl+o\", description: \"Toggle tool output\" },\n  \"app.thinking.toggle\": {\n    defaultKeys: \"ctrl+t\",\n    description: \"Toggle thinking blocks\"\n  },\n  \"app.session.toggleNamedFilter\": {\n    defaultKeys: \"ctrl+n\",\n    description: \"Toggle named session filter\"\n  },\n  \"app.editor.external\": {\n    defaultKeys: \"ctrl+g\",\n    description: \"Open external editor\"\n  },\n  \"app.message.copy\": {\n    defaultKeys: \"ctrl+x\",\n    description: \"Copy message to clipboard\"\n  },\n  \"app.message.followUp\": {\n    defaultKeys: \"alt+enter\",\n    description: \"Queue follow-up message\"\n  },\n  \"app.message.dequeue\": {\n    defaultKeys: \"alt+up\",\n    description: \"Restore queued messages\"\n  },\n  \"app.clipboard.pasteImage\": {\n    defaultKeys: process.platform === \"win32\" ? \"alt+v\" : \"ctrl+v\",\n    description: \"Paste image from clipboard (text fallback)\"\n  },\n  \"app.session.new\": { defaultKeys: [], description: \"Start a new session\" },\n  \"app.session.tree\": { defaultKeys: [], description: \"Open session tree\" },\n  \"app.session.fork\": { defaultKeys: [], description: \"Fork current session\" },\n  \"app.session.resume\": { defaultKeys: [], description: \"Resume a session\" },\n  \"app.tree.foldOrUp\": {\n    defaultKeys: process.platform === \"darwin\" ? [\"alt+left\", \"ctrl+left\"] : [\"ctrl+left\", \"alt+left\"],\n    description: \"Fold tree branch or move up\"\n  },\n  \"app.tree.unfoldOrDown\": {\n    defaultKeys: process.platform === \"darwin\" ? [\"alt+right\", \"ctrl+right\"] : [\"ctrl+right\", \"alt+right\"],\n    description: \"Unfold tree branch or move down\"\n  },\n  \"app.tree.editLabel\": {\n    defaultKeys: \"shift+l\",\n    description: \"Edit tree label\"\n  },\n  \"app.tree.toggleLabelTimestamp\": {\n    defaultKeys: \"shift+t\",\n    description: \"Toggle tree label timestamps\"\n  },\n  \"app.session.togglePath\": {\n    defaultKeys: \"ctrl+p\",\n    description: \"Toggle session path display\"\n  },\n  \"app.session.toggleSort\": {\n    defaultKeys: \"ctrl+s\",\n    description: \"Toggle session sort mode\"\n  },\n  \"app.session.rename\": {\n    defaultKeys: \"ctrl+r\",\n    description: \"Rename session\"\n  },\n  \"app.session.delete\": {\n    defaultKeys: \"ctrl+d\",\n    description: \"Delete session\"\n  },\n  \"app.session.deleteNoninvasive\": {\n    defaultKeys: \"ctrl+backspace\",\n    description: \"Delete session when query is empty\"\n  },\n  \"app.models.save\": {\n    defaultKeys: \"ctrl+s\",\n    description: \"Save model selection\"\n  },\n  \"app.models.enableAll\": {\n    defaultKeys: \"ctrl+a\",\n    description: \"Enable all models\"\n  },\n  \"app.models.clearAll\": {\n    defaultKeys: \"ctrl+x\",\n    description: \"Clear all models\"\n  },\n  \"app.models.toggleProvider\": {\n    defaultKeys: \"ctrl+p\",\n    description: \"Toggle all models for provider\"\n  },\n  \"app.models.reorderUp\": {\n    defaultKeys: \"alt+up\",\n    description: \"Move model up in order\"\n  },\n  \"app.models.reorderDown\": {\n    defaultKeys: \"alt+down\",\n    description: \"Move model down in order\"\n  },\n  \"app.tree.filter.default\": {\n    defaultKeys: \"ctrl+d\",\n    description: \"Tree filter: default view\"\n  },\n  \"app.tree.filter.noTools\": {\n    defaultKeys: \"ctrl+t\",\n    description: \"Tree filter: hide tool results\"\n  },\n  \"app.tree.filter.userOnly\": {\n    defaultKeys: \"ctrl+u\",\n    description: \"Tree filter: user messages only\"\n  },\n  \"app.tree.filter.labeledOnly\": {\n    defaultKeys: \"ctrl+l\",\n    description: \"Tree filter: labeled entries only\"\n  },\n  \"app.tree.filter.all\": {\n    defaultKeys: \"ctrl+a\",\n    description: \"Tree filter: show all entries\"\n  },\n  \"app.tree.filter.cycleForward\": {\n    defaultKeys: \"ctrl+o\",\n    description: \"Tree filter: cycle forward\"\n  },\n  \"app.tree.filter.cycleBackward\": {\n    defaultKeys: \"shift+ctrl+o\",\n    description: \"Tree filter: cycle backward\"\n  }\n};\nvar KEYBINDING_NAME_MIGRATIONS = {\n  cursorUp: \"tui.editor.cursorUp\",\n  cursorDown: \"tui.editor.cursorDown\",\n  cursorLeft: \"tui.editor.cursorLeft\",\n  cursorRight: \"tui.editor.cursorRight\",\n  cursorWordLeft: \"tui.editor.cursorWordLeft\",\n  cursorWordRight: \"tui.editor.cursorWordRight\",\n  cursorLineStart: \"tui.editor.cursorLineStart\",\n  cursorLineEnd: \"tui.editor.cursorLineEnd\",\n  jumpForward: \"tui.editor.jumpForward\",\n  jumpBackward: \"tui.editor.jumpBackward\",\n  pageUp: \"tui.editor.pageUp\",\n  pageDown: \"tui.editor.pageDown\",\n  deleteCharBackward: \"tui.editor.deleteCharBackward\",\n  deleteCharForward: \"tui.editor.deleteCharForward\",\n  deleteWordBackward: \"tui.editor.deleteWordBackward\",\n  deleteWordForward: \"tui.editor.deleteWordForward\",\n  deleteToLineStart: \"tui.editor.deleteToLineStart\",\n  deleteToLineEnd: \"tui.editor.deleteToLineEnd\",\n  yank: \"tui.editor.yank\",\n  yankPop: \"tui.editor.yankPop\",\n  undo: \"tui.editor.undo\",\n  newLine: \"tui.input.newLine\",\n  submit: \"tui.input.submit\",\n  tab: \"tui.input.tab\",\n  copy: \"tui.input.copy\",\n  selectUp: \"tui.select.up\",\n  selectDown: \"tui.select.down\",\n  selectPageUp: \"tui.select.pageUp\",\n  selectPageDown: \"tui.select.pageDown\",\n  selectConfirm: \"tui.select.confirm\",\n  selectCancel: \"tui.select.cancel\",\n  interrupt: \"app.interrupt\",\n  clear: \"app.clear\",\n  exit: \"app.exit\",\n  suspend: \"app.suspend\",\n  cycleThinkingLevel: \"app.thinking.cycle\",\n  cycleModelForward: \"app.model.cycleForward\",\n  cycleModelBackward: \"app.model.cycleBackward\",\n  selectModel: \"app.model.select\",\n  expandTools: \"app.tools.expand\",\n  toggleThinking: \"app.thinking.toggle\",\n  toggleSessionNamedFilter: \"app.session.toggleNamedFilter\",\n  externalEditor: \"app.editor.external\",\n  followUp: \"app.message.followUp\",\n  dequeue: \"app.message.dequeue\",\n  pasteImage: \"app.clipboard.pasteImage\",\n  newSession: \"app.session.new\",\n  tree: \"app.session.tree\",\n  fork: \"app.session.fork\",\n  resume: \"app.session.resume\",\n  treeFoldOrUp: \"app.tree.foldOrUp\",\n  treeUnfoldOrDown: \"app.tree.unfoldOrDown\",\n  treeEditLabel: \"app.tree.editLabel\",\n  treeToggleLabelTimestamp: \"app.tree.toggleLabelTimestamp\",\n  toggleSessionPath: \"app.session.togglePath\",\n  toggleSessionSort: \"app.session.toggleSort\",\n  renameSession: \"app.session.rename\",\n  deleteSession: \"app.session.delete\",\n  deleteSessionNoninvasive: \"app.session.deleteNoninvasive\"\n};\nfunction isLegacyKeybindingName(key) {\n  return key in KEYBINDING_NAME_MIGRATIONS;\n}\nfunction toKeybindingsConfig(value) {\n  const config = {};\n  for (const [key, binding] of Object.entries(value)) {\n    if (typeof binding === \"string\") {\n      config[key] = binding;\n      continue;\n    }\n    if (Array.isArray(binding) && binding.every((entry) => typeof entry === \"string\")) {\n      config[key] = binding;\n    }\n  }\n  return config;\n}\nfunction migrateKeybindingsConfig(rawConfig) {\n  const config = {};\n  let migrated = false;\n  for (const [key, value] of Object.entries(rawConfig)) {\n    const nextKey = isLegacyKeybindingName(key) ? KEYBINDING_NAME_MIGRATIONS[key] : key;\n    if (nextKey !== key) {\n      migrated = true;\n    }\n    if (key !== nextKey && Object.hasOwn(rawConfig, nextKey)) {\n      migrated = true;\n      continue;\n    }\n    config[nextKey] = value;\n  }\n  return { config: orderKeybindingsConfig(config), migrated };\n}\nfunction orderKeybindingsConfig(config) {\n  const ordered2 = {};\n  for (const keybinding of Object.keys(KEYBINDINGS)) {\n    if (Object.hasOwn(config, keybinding)) {\n      ordered2[keybinding] = config[keybinding];\n    }\n  }\n  const extras = Object.keys(config).filter((key) => !Object.hasOwn(ordered2, key)).sort();\n  for (const key of extras) {\n    ordered2[key] = config[key];\n  }\n  return ordered2;\n}\nfunction loadRawConfig(path12) {\n  if (!existsSync4(path12))\n    return void 0;\n  try {\n    const parsed = JSON.parse(readFileSync3(path12, \"utf-8\"));\n    if (typeof parsed !== \"object\" || parsed === null)\n      return void 0;\n    return parsed;\n  } catch {\n    return void 0;\n  }\n}\nvar KeybindingsManager2 = class _KeybindingsManager extends KeybindingsManager {\n  configPath;\n  constructor(userBindings = {}, configPath) {\n    super(KEYBINDINGS, userBindings);\n    this.configPath = configPath;\n  }\n  static create(agentDir = getAgentDir()) {\n    const configPath = join13(agentDir, \"keybindings.json\");\n    const userBindings = _KeybindingsManager.loadFromFile(configPath);\n    return new _KeybindingsManager(userBindings, configPath);\n  }\n  reload() {\n    if (!this.configPath)\n      return;\n    this.setUserBindings(_KeybindingsManager.loadFromFile(this.configPath));\n  }\n  getEffectiveConfig() {\n    return this.getResolvedBindings();\n  }\n  static loadFromFile(path12) {\n    const rawConfig = loadRawConfig(path12);\n    if (!rawConfig)\n      return {};\n    return toKeybindingsConfig(migrateKeybindingsConfig(rawConfig).config);\n  }\n};\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/core/package-manager.js\nimport { createHash } from \"node:crypto\";\nimport { chmodSync as chmodSync2, existsSync as existsSync5, mkdirSync as mkdirSync3, readdirSync as readdirSync2, readFileSync as readFileSync5, rmSync, statSync as statSync4, writeFileSync as writeFileSync3 } from \"node:fs\";\nimport { homedir as homedir6 } from \"node:os\";\nimport { basename as basename3, dirname as dirname9, join as join14, relative as relative2, resolve as resolve3, sep as sep3 } from \"node:path\";\nimport { globSync } from \"glob\";\nimport ignore from \"ignore\";\nimport { minimatch as minimatch2 } from \"minimatch\";\nimport { maxSatisfying, rcompare, satisfies, valid, validRange } from \"semver\";\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/utils/git.js\nimport hostedGitInfo from \"hosted-git-info\";\nfunction splitRef(url) {\n  const scpLikeMatch = url.match(/^git@([^:]+):(.+)$/);\n  if (scpLikeMatch) {\n    const pathWithMaybeRef2 = scpLikeMatch[2] ?? \"\";\n    const refSeparator2 = pathWithMaybeRef2.indexOf(\"@\");\n    if (refSeparator2 < 0)\n      return { repo: url };\n    const repoPath2 = pathWithMaybeRef2.slice(0, refSeparator2);\n    const ref2 = pathWithMaybeRef2.slice(refSeparator2 + 1);\n    if (!repoPath2 || !ref2)\n      return { repo: url };\n    return {\n      repo: `git@${scpLikeMatch[1] ?? \"\"}:${repoPath2}`,\n      ref: ref2\n    };\n  }\n  if (url.includes(\"://\")) {\n    try {\n      const parsed = new URL(url);\n      const pathWithMaybeRef2 = parsed.pathname.replace(/^\\/+/, \"\");\n      const refSeparator2 = pathWithMaybeRef2.indexOf(\"@\");\n      if (refSeparator2 < 0)\n        return { repo: url };\n      const repoPath2 = pathWithMaybeRef2.slice(0, refSeparator2);\n      const ref2 = pathWithMaybeRef2.slice(refSeparator2 + 1);\n      if (!repoPath2 || !ref2)\n        return { repo: url };\n      parsed.pathname = `/${repoPath2}`;\n      return {\n        repo: parsed.toString().replace(/\\/$/, \"\"),\n        ref: ref2\n      };\n    } catch {\n      return { repo: url };\n    }\n  }\n  const slashIndex = url.indexOf(\"/\");\n  if (slashIndex < 0) {\n    return { repo: url };\n  }\n  const host = url.slice(0, slashIndex);\n  const pathWithMaybeRef = url.slice(slashIndex + 1);\n  const refSeparator = pathWithMaybeRef.indexOf(\"@\");\n  if (refSeparator < 0) {\n    return { repo: url };\n  }\n  const repoPath = pathWithMaybeRef.slice(0, refSeparator);\n  const ref = pathWithMaybeRef.slice(refSeparator + 1);\n  if (!repoPath || !ref) {\n    return { repo: url };\n  }\n  return {\n    repo: `${host}/${repoPath}`,\n    ref\n  };\n}\nfunction decodeForValidation(value) {\n  try {\n    return decodeURIComponent(value);\n  } catch {\n    return null;\n  }\n}\nfunction hasUnsafeGitInstallPart(value, allowSlash) {\n  const decoded = decodeForValidation(value);\n  if (decoded === null) {\n    return true;\n  }\n  const candidates = [value, decoded];\n  for (const candidate of candidates) {\n    if (candidate.includes(\"\\0\") || candidate.includes(\"\\\\\") || candidate.startsWith(\"/\")) {\n      return true;\n    }\n    if (!allowSlash && candidate.includes(\"/\")) {\n      return true;\n    }\n    if (candidate.split(\"/\").includes(\"..\")) {\n      return true;\n    }\n  }\n  return false;\n}\nfunction buildGitSource(args) {\n  if (args.path.startsWith(\"/\")) {\n    return null;\n  }\n  const normalizedPath = args.path.replace(/\\.git$/, \"\").replace(/^\\/+/, \"\");\n  if (!args.host || !normalizedPath || normalizedPath.split(\"/\").length < 2) {\n    return null;\n  }\n  if (hasUnsafeGitInstallPart(args.host, false) || hasUnsafeGitInstallPart(normalizedPath, true)) {\n    return null;\n  }\n  return {\n    type: \"git\",\n    repo: args.repo,\n    host: args.host,\n    path: normalizedPath,\n    ref: args.ref,\n    pinned: Boolean(args.ref)\n  };\n}\nfunction parseGenericGitUrl(url) {\n  const { repo: repoWithoutRef, ref } = splitRef(url);\n  let repo = repoWithoutRef;\n  let host = \"\";\n  let path12 = \"\";\n  const scpLikeMatch = repoWithoutRef.match(/^git@([^:]+):(.+)$/);\n  if (scpLikeMatch) {\n    host = scpLikeMatch[1] ?? \"\";\n    path12 = scpLikeMatch[2] ?? \"\";\n  } else if (repoWithoutRef.startsWith(\"https://\") || repoWithoutRef.startsWith(\"http://\") || repoWithoutRef.startsWith(\"ssh://\") || repoWithoutRef.startsWith(\"git://\")) {\n    try {\n      const parsed = new URL(repoWithoutRef);\n      host = parsed.hostname;\n      path12 = parsed.pathname.replace(/^\\/+/, \"\");\n    } catch {\n      return null;\n    }\n  } else {\n    const slashIndex = repoWithoutRef.indexOf(\"/\");\n    if (slashIndex < 0) {\n      return null;\n    }\n    host = repoWithoutRef.slice(0, slashIndex);\n    path12 = repoWithoutRef.slice(slashIndex + 1);\n    if (!host.includes(\".\") && host !== \"localhost\") {\n      return null;\n    }\n    repo = `https://${repoWithoutRef}`;\n  }\n  return buildGitSource({ repo, host, path: path12, ref });\n}\nfunction parseGitUrl(source) {\n  const trimmed = source.trim();\n  const hasGitPrefix = trimmed.startsWith(\"git:\");\n  const url = hasGitPrefix ? trimmed.slice(4).trim() : trimmed;\n  if (!hasGitPrefix && !/^(https?|ssh|git):\\/\\//i.test(url)) {\n    return null;\n  }\n  const split = splitRef(url);\n  const hostedCandidates = [split.ref ? `${split.repo}#${split.ref}` : void 0, url].filter((value) => Boolean(value));\n  for (const candidate of hostedCandidates) {\n    const info = hostedGitInfo.fromUrl(candidate);\n    if (info) {\n      if (split.ref && info.project?.includes(\"@\")) {\n        continue;\n      }\n      const useHttpsPrefix = !split.repo.startsWith(\"http://\") && !split.repo.startsWith(\"https://\") && !split.repo.startsWith(\"ssh://\") && !split.repo.startsWith(\"git://\") && !split.repo.startsWith(\"git@\");\n      return buildGitSource({\n        repo: useHttpsPrefix ? `https://${split.repo}` : split.repo,\n        host: info.domain || \"\",\n        path: `${info.user}/${info.project}`,\n        ref: info.committish || split.ref || void 0\n      });\n    }\n  }\n  const httpsCandidates = [split.ref ? `https://${split.repo}#${split.ref}` : void 0, `https://${url}`].filter((value) => Boolean(value));\n  for (const candidate of httpsCandidates) {\n    const info = hostedGitInfo.fromUrl(candidate);\n    if (info) {\n      if (split.ref && info.project?.includes(\"@\")) {\n        continue;\n      }\n      return buildGitSource({\n        repo: `https://${split.repo}`,\n        host: info.domain || \"\",\n        path: `${info.user}/${info.project}`,\n        ref: info.committish || split.ref || void 0\n      });\n    }\n  }\n  return parseGenericGitUrl(url);\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/core/output-guard.js\nvar stdoutTakeoverState;\nvar RAW_STDOUT_RETRY_DELAY_MS = 10;\nvar rawStdoutWriteTail = Promise.resolve();\nfunction getRawStdoutWrite() {\n  if (stdoutTakeoverState) {\n    return stdoutTakeoverState.rawStdoutWrite;\n  }\n  return process.stdout.write.bind(process.stdout);\n}\nasync function writeRawStdoutChunk(text) {\n  while (true) {\n    try {\n      await new Promise((resolve15, reject) => {\n        try {\n          getRawStdoutWrite()(text, (error) => {\n            if (error)\n              reject(error);\n            else\n              resolve15();\n          });\n        } catch (error) {\n          reject(error instanceof Error ? error : new Error(String(error)));\n        }\n      });\n      return;\n    } catch (error) {\n      const writeError = error instanceof Error ? error : new Error(String(error));\n      const code = writeError.code;\n      if (code !== \"ENOBUFS\" && code !== \"EAGAIN\" && code !== \"EWOULDBLOCK\") {\n        throw writeError;\n      }\n      await new Promise((resolve15) => setTimeout(resolve15, RAW_STDOUT_RETRY_DELAY_MS));\n    }\n  }\n}\nfunction takeOverStdout() {\n  if (stdoutTakeoverState) {\n    return;\n  }\n  const rawStdoutWrite = process.stdout.write.bind(process.stdout);\n  const rawStderrWrite = process.stderr.write.bind(process.stderr);\n  const originalStdoutWrite = process.stdout.write;\n  process.stdout.write = ((chunk, encodingOrCallback, callback) => {\n    if (typeof encodingOrCallback === \"function\") {\n      return rawStderrWrite(String(chunk), encodingOrCallback);\n    }\n    return rawStderrWrite(String(chunk), callback);\n  });\n  stdoutTakeoverState = {\n    rawStdoutWrite,\n    rawStderrWrite,\n    originalStdoutWrite\n  };\n}\nfunction restoreStdout() {\n  if (!stdoutTakeoverState) {\n    return;\n  }\n  process.stdout.write = stdoutTakeoverState.originalStdoutWrite;\n  stdoutTakeoverState = void 0;\n}\nfunction isStdoutTakenOver() {\n  return stdoutTakeoverState !== void 0;\n}\nfunction writeRawStdout(text) {\n  if (text.length === 0) {\n    return;\n  }\n  rawStdoutWriteTail = rawStdoutWriteTail.then(() => writeRawStdoutChunk(text));\n  void rawStdoutWriteTail.catch(() => {\n    process.exit(1);\n  });\n}\nasync function waitForRawStdoutBackpressure() {\n  while (true) {\n    const tail = rawStdoutWriteTail;\n    await tail;\n    if (tail === rawStdoutWriteTail) {\n      return;\n    }\n  }\n}\nasync function flushRawStdout() {\n  await waitForRawStdoutBackpressure();\n  await writeRawStdoutChunk(\"\");\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/core/pi-manifest.js\nimport { readFileSync as readFileSync4 } from \"node:fs\";\nvar RESOURCE_FIELDS = [\"extensions\", \"skills\", \"prompts\", \"themes\"];\nfunction isObject(value) {\n  return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\nfunction readPiManifest(packageJsonPath) {\n  try {\n    const pkg2 = JSON.parse(readFileSync4(packageJsonPath, \"utf-8\"));\n    if (!isObject(pkg2) || !isObject(pkg2.pi)) {\n      return null;\n    }\n    const manifest = {};\n    for (const field of RESOURCE_FIELDS) {\n      const entries = pkg2.pi[field];\n      if (Array.isArray(entries) && entries.every((entry) => typeof entry === \"string\")) {\n        manifest[field] = entries;\n      }\n    }\n    return manifest;\n  } catch {\n    return null;\n  }\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/core/package-manager.js\nfunction getEnv() {\n  if (process.platform !== \"linux\" || Object.keys(process.env).length > 0) {\n    return process.env;\n  }\n  try {\n    const data = readFileSync5(\"/proc/self/environ\", \"utf-8\");\n    const env = {};\n    for (const entry of data.split(\"\\0\")) {\n      const idx = entry.indexOf(\"=\");\n      if (idx > 0) {\n        env[entry.slice(0, idx)] = entry.slice(idx + 1);\n      }\n    }\n    return env;\n  } catch {\n    return process.env;\n  }\n}\nvar NETWORK_TIMEOUT_MS = 1e4;\nvar UPDATE_CHECK_CONCURRENCY = 4;\nvar GIT_UPDATE_CONCURRENCY = 4;\nfunction isOfflineModeEnabled() {\n  const value = process.env.PI_OFFLINE;\n  if (!value)\n    return false;\n  return value === \"1\" || value.toLowerCase() === \"true\" || value.toLowerCase() === \"yes\";\n}\nfunction isExactNpmVersion(version) {\n  return valid(version ?? \"\") !== null;\n}\nfunction getNpmVersionRange(version) {\n  return version ? validRange(version) ?? void 0 : void 0;\n}\nfunction resourcePrecedenceRank(m) {\n  if (m.origin === \"package\")\n    return 4;\n  const scopeBase = m.scope === \"project\" ? 0 : 2;\n  return scopeBase + (m.source === \"local\" ? 0 : 1);\n}\nvar RESOURCE_TYPES = [\"extensions\", \"skills\", \"prompts\", \"themes\"];\nvar FILE_PATTERNS = {\n  extensions: /\\.(ts|js)$/,\n  skills: /\\.md$/,\n  prompts: /\\.md$/,\n  themes: /\\.json$/\n};\nvar IGNORE_FILE_NAMES = [\".gitignore\", \".ignore\", \".fdignore\"];\nfunction toPosixPath(p) {\n  return p.split(sep3).join(\"/\");\n}\nfunction getHomeDir() {\n  return process.env.HOME || homedir6();\n}\nfunction getExtensionTempFolder(agentDir) {\n  const tempFolder = join14(agentDir, \"tmp\", \"extensions\");\n  mkdirSync3(tempFolder, { recursive: true, mode: 448 });\n  chmodSync2(tempFolder, 448);\n  return tempFolder;\n}\nfunction prefixIgnorePattern(line, prefix) {\n  const trimmed = line.trim();\n  if (!trimmed)\n    return null;\n  if (trimmed.startsWith(\"#\") && !trimmed.startsWith(\"\\\\#\"))\n    return null;\n  let pattern = line;\n  let negated = false;\n  if (pattern.startsWith(\"!\")) {\n    negated = true;\n    pattern = pattern.slice(1);\n  } else if (pattern.startsWith(\"\\\\!\")) {\n    pattern = pattern.slice(1);\n  }\n  if (pattern.startsWith(\"/\")) {\n    pattern = pattern.slice(1);\n  }\n  const prefixed = prefix ? `${prefix}${pattern}` : pattern;\n  return negated ? `!${prefixed}` : prefixed;\n}\nfunction addIgnoreRules(ig, dir, rootDir) {\n  const relativeDir = relative2(rootDir, dir);\n  const prefix = relativeDir ? `${toPosixPath(relativeDir)}/` : \"\";\n  for (const filename of IGNORE_FILE_NAMES) {\n    const ignorePath = join14(dir, filename);\n    if (!existsSync5(ignorePath))\n      continue;\n    try {\n      const content = readFileSync5(ignorePath, \"utf-8\");\n      const patterns = content.split(/\\r?\\n/).map((line) => prefixIgnorePattern(line, prefix)).filter((line) => Boolean(line));\n      if (patterns.length > 0) {\n        ig.add(patterns);\n      }\n    } catch {\n    }\n  }\n}\nfunction isPattern(s) {\n  return s.startsWith(\"!\") || s.startsWith(\"+\") || s.startsWith(\"-\") || s.includes(\"*\") || s.includes(\"?\");\n}\nfunction isOverridePattern(s) {\n  return s.startsWith(\"!\") || s.startsWith(\"+\") || s.startsWith(\"-\");\n}\nfunction hasGlobPattern(s) {\n  return s.includes(\"*\") || s.includes(\"?\");\n}\nfunction splitPatterns(entries) {\n  const plain = [];\n  const patterns = [];\n  for (const entry of entries) {\n    if (isPattern(entry)) {\n      patterns.push(entry);\n    } else {\n      plain.push(entry);\n    }\n  }\n  return { plain, patterns };\n}\nfunction collectFiles(dir, filePattern, skipNodeModules = true, ignoreMatcher, rootDir) {\n  const files = [];\n  if (!existsSync5(dir))\n    return files;\n  const root = rootDir ?? dir;\n  const ig = ignoreMatcher ?? ignore();\n  addIgnoreRules(ig, dir, root);\n  try {\n    const entries = readdirSync2(dir, { withFileTypes: true });\n    for (const entry of entries) {\n      if (entry.name.startsWith(\".\"))\n        continue;\n      if (skipNodeModules && entry.name === \"node_modules\")\n        continue;\n      const fullPath = join14(dir, entry.name);\n      let isDir = entry.isDirectory();\n      let isFile = entry.isFile();\n      if (entry.isSymbolicLink()) {\n        try {\n          const stats = statSync4(fullPath);\n          isDir = stats.isDirectory();\n          isFile = stats.isFile();\n        } catch {\n          continue;\n        }\n      }\n      const relPath = toPosixPath(relative2(root, fullPath));\n      const ignorePath = isDir ? `${relPath}/` : relPath;\n      if (ig.ignores(ignorePath))\n        continue;\n      if (isDir) {\n        files.push(...collectFiles(fullPath, filePattern, skipNodeModules, ig, root));\n      } else if (isFile && filePattern.test(entry.name)) {\n        files.push(fullPath);\n      }\n    }\n  } catch {\n  }\n  return files;\n}\nfunction collectSkillEntries(dir, mode, ignoreMatcher, rootDir) {\n  const entries = [];\n  if (!existsSync5(dir))\n    return entries;\n  const root = rootDir ?? dir;\n  const ig = ignoreMatcher ?? ignore();\n  addIgnoreRules(ig, dir, root);\n  try {\n    const dirEntries = readdirSync2(dir, { withFileTypes: true });\n    for (const entry of dirEntries) {\n      if (entry.name !== \"SKILL.md\") {\n        continue;\n      }\n      const fullPath = join14(dir, entry.name);\n      let isFile = entry.isFile();\n      if (entry.isSymbolicLink()) {\n        try {\n          isFile = statSync4(fullPath).isFile();\n        } catch {\n          continue;\n        }\n      }\n      const relPath = toPosixPath(relative2(root, fullPath));\n      if (isFile && !ig.ignores(relPath)) {\n        entries.push(fullPath);\n        return entries;\n      }\n    }\n    for (const entry of dirEntries) {\n      if (entry.name.startsWith(\".\"))\n        continue;\n      if (entry.name === \"node_modules\")\n        continue;\n      const fullPath = join14(dir, entry.name);\n      let isDir = entry.isDirectory();\n      let isFile = entry.isFile();\n      if (entry.isSymbolicLink()) {\n        try {\n          const stats = statSync4(fullPath);\n          isDir = stats.isDirectory();\n          isFile = stats.isFile();\n        } catch {\n          continue;\n        }\n      }\n      const relPath = toPosixPath(relative2(root, fullPath));\n      if (mode === \"pi\" && dir === root && isFile && entry.name.endsWith(\".md\") && !ig.ignores(relPath)) {\n        entries.push(fullPath);\n        continue;\n      }\n      if (!isDir)\n        continue;\n      if (ig.ignores(`${relPath}/`))\n        continue;\n      entries.push(...collectSkillEntries(fullPath, mode, ig, root));\n    }\n  } catch {\n  }\n  return entries;\n}\nfunction collectAutoSkillEntries(dir, mode) {\n  return collectSkillEntries(dir, mode);\n}\nfunction findGitRepoRoot(startDir) {\n  let dir = resolve3(startDir);\n  while (true) {\n    if (existsSync5(join14(dir, \".git\"))) {\n      return dir;\n    }\n    const parent = dirname9(dir);\n    if (parent === dir) {\n      return null;\n    }\n    dir = parent;\n  }\n}\nfunction collectAncestorAgentsSkillDirs(startDir) {\n  const skillDirs = [];\n  const resolvedStartDir = resolve3(startDir);\n  const gitRepoRoot = findGitRepoRoot(resolvedStartDir);\n  let dir = resolvedStartDir;\n  while (true) {\n    skillDirs.push(join14(dir, \".agents\", \"skills\"));\n    if (gitRepoRoot && dir === gitRepoRoot) {\n      break;\n    }\n    const parent = dirname9(dir);\n    if (parent === dir) {\n      break;\n    }\n    dir = parent;\n  }\n  return skillDirs;\n}\nfunction collectAutoPromptEntries(dir) {\n  const entries = [];\n  if (!existsSync5(dir))\n    return entries;\n  const ig = ignore();\n  addIgnoreRules(ig, dir, dir);\n  try {\n    const dirEntries = readdirSync2(dir, { withFileTypes: true });\n    for (const entry of dirEntries) {\n      if (entry.name.startsWith(\".\"))\n        continue;\n      if (entry.name === \"node_modules\")\n        continue;\n      const fullPath = join14(dir, entry.name);\n      let isFile = entry.isFile();\n      if (entry.isSymbolicLink()) {\n        try {\n          isFile = statSync4(fullPath).isFile();\n        } catch {\n          continue;\n        }\n      }\n      const relPath = toPosixPath(relative2(dir, fullPath));\n      if (ig.ignores(relPath))\n        continue;\n      if (isFile && entry.name.endsWith(\".md\")) {\n        entries.push(fullPath);\n      }\n    }\n  } catch {\n  }\n  return entries;\n}\nfunction collectAutoThemeEntries(dir) {\n  const entries = [];\n  if (!existsSync5(dir))\n    return entries;\n  const ig = ignore();\n  addIgnoreRules(ig, dir, dir);\n  try {\n    const dirEntries = readdirSync2(dir, { withFileTypes: true });\n    for (const entry of dirEntries) {\n      if (entry.name.startsWith(\".\"))\n        continue;\n      if (entry.name === \"node_modules\")\n        continue;\n      const fullPath = join14(dir, entry.name);\n      let isFile = entry.isFile();\n      if (entry.isSymbolicLink()) {\n        try {\n          isFile = statSync4(fullPath).isFile();\n        } catch {\n          continue;\n        }\n      }\n      const relPath = toPosixPath(relative2(dir, fullPath));\n      if (ig.ignores(relPath))\n        continue;\n      if (isFile && entry.name.endsWith(\".json\")) {\n        entries.push(fullPath);\n      }\n    }\n  } catch {\n  }\n  return entries;\n}\nfunction resolveExtensionEntries(dir) {\n  const packageJsonPath = join14(dir, \"package.json\");\n  if (existsSync5(packageJsonPath)) {\n    const manifest = readPiManifest(packageJsonPath);\n    if (manifest?.extensions?.length) {\n      const entries = [];\n      for (const extPath of manifest.extensions) {\n        const resolvedExtPath = resolve3(dir, extPath);\n        if (existsSync5(resolvedExtPath)) {\n          entries.push(resolvedExtPath);\n        }\n      }\n      if (entries.length > 0) {\n        return entries;\n      }\n    }\n  }\n  const indexTs = join14(dir, \"index.ts\");\n  const indexJs = join14(dir, \"index.js\");\n  if (existsSync5(indexTs)) {\n    return [indexTs];\n  }\n  if (existsSync5(indexJs)) {\n    return [indexJs];\n  }\n  return null;\n}\nfunction collectAutoExtensionEntries(dir) {\n  const entries = [];\n  if (!existsSync5(dir))\n    return entries;\n  const rootEntries = resolveExtensionEntries(dir);\n  if (rootEntries) {\n    return rootEntries;\n  }\n  const ig = ignore();\n  addIgnoreRules(ig, dir, dir);\n  try {\n    const dirEntries = readdirSync2(dir, { withFileTypes: true });\n    for (const entry of dirEntries) {\n      if (entry.name.startsWith(\".\"))\n        continue;\n      if (entry.name === \"node_modules\")\n        continue;\n      const fullPath = join14(dir, entry.name);\n      let isDir = entry.isDirectory();\n      let isFile = entry.isFile();\n      if (entry.isSymbolicLink()) {\n        try {\n          const stats = statSync4(fullPath);\n          isDir = stats.isDirectory();\n          isFile = stats.isFile();\n        } catch {\n          continue;\n        }\n      }\n      const relPath = toPosixPath(relative2(dir, fullPath));\n      const ignorePath = isDir ? `${relPath}/` : relPath;\n      if (ig.ignores(ignorePath))\n        continue;\n      if (isFile && (entry.name.endsWith(\".ts\") || entry.name.endsWith(\".js\"))) {\n        entries.push(fullPath);\n      } else if (isDir) {\n        const resolvedEntries = resolveExtensionEntries(fullPath);\n        if (resolvedEntries) {\n          entries.push(...resolvedEntries);\n        }\n      }\n    }\n  } catch {\n  }\n  return entries;\n}\nfunction collectResourceFiles(dir, resourceType) {\n  if (resourceType === \"skills\") {\n    return collectSkillEntries(dir, \"pi\");\n  }\n  if (resourceType === \"extensions\") {\n    return collectAutoExtensionEntries(dir);\n  }\n  return collectFiles(dir, FILE_PATTERNS[resourceType]);\n}\nfunction matchesAnyPattern(filePath, patterns, baseDir) {\n  const rel = toPosixPath(relative2(baseDir, filePath));\n  const name = basename3(filePath);\n  const filePathPosix = toPosixPath(filePath);\n  const isSkillFile = name === \"SKILL.md\";\n  const parentDir = isSkillFile ? dirname9(filePath) : void 0;\n  const parentRel = isSkillFile ? toPosixPath(relative2(baseDir, parentDir)) : void 0;\n  const parentName = isSkillFile ? basename3(parentDir) : void 0;\n  const parentDirPosix = isSkillFile ? toPosixPath(parentDir) : void 0;\n  return patterns.some((pattern) => {\n    const normalizedPattern = toPosixPath(pattern);\n    if (minimatch2(rel, normalizedPattern) || minimatch2(name, normalizedPattern) || minimatch2(filePathPosix, normalizedPattern)) {\n      return true;\n    }\n    if (!isSkillFile)\n      return false;\n    return minimatch2(parentRel, normalizedPattern) || minimatch2(parentName, normalizedPattern) || minimatch2(parentDirPosix, normalizedPattern);\n  });\n}\nfunction normalizeExactPattern(pattern) {\n  const normalized = pattern.startsWith(\"./\") || pattern.startsWith(\".\\\\\") ? pattern.slice(2) : pattern;\n  return toPosixPath(normalized);\n}\nfunction matchesAnyExactPattern(filePath, patterns, baseDir) {\n  if (patterns.length === 0)\n    return false;\n  const rel = toPosixPath(relative2(baseDir, filePath));\n  const name = basename3(filePath);\n  const filePathPosix = toPosixPath(filePath);\n  const isSkillFile = name === \"SKILL.md\";\n  const parentDir = isSkillFile ? dirname9(filePath) : void 0;\n  const parentRel = isSkillFile ? toPosixPath(relative2(baseDir, parentDir)) : void 0;\n  const parentDirPosix = isSkillFile ? toPosixPath(parentDir) : void 0;\n  return patterns.some((pattern) => {\n    const normalized = normalizeExactPattern(pattern);\n    if (normalized === rel || normalized === filePathPosix) {\n      return true;\n    }\n    if (!isSkillFile)\n      return false;\n    return normalized === parentRel || normalized === parentDirPosix;\n  });\n}\nfunction getOverridePatterns(entries) {\n  return entries.filter((pattern) => pattern.startsWith(\"!\") || pattern.startsWith(\"+\") || pattern.startsWith(\"-\"));\n}\nfunction isEnabledByOverrides(filePath, patterns, baseDir) {\n  const overrides = getOverridePatterns(patterns);\n  const excludes = overrides.filter((pattern) => pattern.startsWith(\"!\")).map((pattern) => pattern.slice(1));\n  const forceIncludes = overrides.filter((pattern) => pattern.startsWith(\"+\")).map((pattern) => pattern.slice(1));\n  const forceExcludes = overrides.filter((pattern) => pattern.startsWith(\"-\")).map((pattern) => pattern.slice(1));\n  let enabled = true;\n  if (excludes.length > 0 && matchesAnyPattern(filePath, excludes, baseDir)) {\n    enabled = false;\n  }\n  if (forceIncludes.length > 0 && matchesAnyExactPattern(filePath, forceIncludes, baseDir)) {\n    enabled = true;\n  }\n  if (forceExcludes.length > 0 && matchesAnyExactPattern(filePath, forceExcludes, baseDir)) {\n    enabled = false;\n  }\n  return enabled;\n}\nfunction applyPatterns(allPaths, patterns, baseDir) {\n  const includes = [];\n  const excludes = [];\n  const forceIncludes = [];\n  const forceExcludes = [];\n  for (const p of patterns) {\n    if (p.startsWith(\"+\")) {\n      forceIncludes.push(p.slice(1));\n    } else if (p.startsWith(\"-\")) {\n      forceExcludes.push(p.slice(1));\n    } else if (p.startsWith(\"!\")) {\n      excludes.push(p.slice(1));\n    } else {\n      includes.push(p);\n    }\n  }\n  let result;\n  if (includes.length === 0) {\n    result = [...allPaths];\n  } else {\n    result = allPaths.filter((filePath) => matchesAnyPattern(filePath, includes, baseDir));\n  }\n  if (excludes.length > 0) {\n    result = result.filter((filePath) => !matchesAnyPattern(filePath, excludes, baseDir));\n  }\n  if (forceIncludes.length > 0) {\n    for (const filePath of allPaths) {\n      if (!result.includes(filePath) && matchesAnyExactPattern(filePath, forceIncludes, baseDir)) {\n        result.push(filePath);\n      }\n    }\n  }\n  if (forceExcludes.length > 0) {\n    result = result.filter((filePath) => !matchesAnyExactPattern(filePath, forceExcludes, baseDir));\n  }\n  return new Set(result);\n}\nfunction applyAutoloadDisabledPatterns(allPaths, patterns, baseDir) {\n  const result = /* @__PURE__ */ new Map();\n  for (const pattern of patterns) {\n    const target = pattern.slice(pattern.startsWith(\"+\") || pattern.startsWith(\"-\") || pattern.startsWith(\"!\") ? 1 : 0);\n    const enabled = !pattern.startsWith(\"-\") && !pattern.startsWith(\"!\");\n    const exact = pattern.startsWith(\"+\") || pattern.startsWith(\"-\");\n    for (const filePath of allPaths) {\n      if (exact ? matchesAnyExactPattern(filePath, [target], baseDir) : matchesAnyPattern(filePath, [target], baseDir)) {\n        result.set(filePath, enabled);\n      }\n    }\n  }\n  return result;\n}\nvar DefaultPackageManager = class {\n  cwd;\n  agentDir;\n  settingsManager;\n  globalNpmRoot;\n  globalNpmRootCommandKey;\n  progressCallback;\n  constructor(options) {\n    this.cwd = resolvePath(options.cwd);\n    this.agentDir = resolvePath(options.agentDir);\n    this.settingsManager = options.settingsManager;\n  }\n  setProgressCallback(callback) {\n    this.progressCallback = callback;\n  }\n  addSourceToSettings(source, options) {\n    const scope = options?.local ? \"project\" : \"user\";\n    const currentSettings = scope === \"project\" ? this.settingsManager.getProjectSettings() : this.settingsManager.getGlobalSettings();\n    const currentPackages = currentSettings.packages ?? [];\n    const normalizedSource = this.normalizePackageSourceForSettings(source, scope);\n    const matchIndex = currentPackages.findIndex((existing) => this.packageSourcesMatch(existing, source, scope));\n    if (matchIndex !== -1) {\n      const existing = currentPackages[matchIndex];\n      if (this.getPackageSourceString(existing) === normalizedSource) {\n        return false;\n      }\n      const nextPackages2 = [...currentPackages];\n      nextPackages2[matchIndex] = typeof existing === \"string\" ? normalizedSource : { ...existing, source: normalizedSource };\n      if (scope === \"project\") {\n        this.settingsManager.setProjectPackages(nextPackages2);\n      } else {\n        this.settingsManager.setPackages(nextPackages2);\n      }\n      return true;\n    }\n    const nextPackages = [...currentPackages, normalizedSource];\n    if (scope === \"project\") {\n      this.settingsManager.setProjectPackages(nextPackages);\n    } else {\n      this.settingsManager.setPackages(nextPackages);\n    }\n    return true;\n  }\n  removeSourceFromSettings(source, options) {\n    const scope = options?.local ? \"project\" : \"user\";\n    const currentSettings = scope === \"project\" ? this.settingsManager.getProjectSettings() : this.settingsManager.getGlobalSettings();\n    const currentPackages = currentSettings.packages ?? [];\n    const nextPackages = currentPackages.filter((existing) => !this.packageSourcesMatch(existing, source, scope));\n    const changed = nextPackages.length !== currentPackages.length;\n    if (!changed) {\n      return false;\n    }\n    if (scope === \"project\") {\n      this.settingsManager.setProjectPackages(nextPackages);\n    } else {\n      this.settingsManager.setPackages(nextPackages);\n    }\n    return true;\n  }\n  getInstalledPath(source, scope) {\n    const parsed = this.parseSource(source);\n    if (parsed.type === \"npm\") {\n      const path12 = this.getNpmInstallPath(parsed, scope);\n      return existsSync5(path12) ? path12 : void 0;\n    }\n    if (parsed.type === \"git\") {\n      const path12 = this.getGitInstallPath(parsed, scope);\n      return existsSync5(path12) ? path12 : void 0;\n    }\n    if (parsed.type === \"local\") {\n      const baseDir = this.getBaseDirForScope(scope);\n      const path12 = this.resolvePathFromBase(parsed.path, baseDir);\n      return existsSync5(path12) ? path12 : void 0;\n    }\n    return void 0;\n  }\n  emitProgress(event) {\n    this.progressCallback?.(event);\n  }\n  async withProgress(action, source, message, operation) {\n    this.emitProgress({ type: \"start\", action, source, message });\n    try {\n      await operation();\n      this.emitProgress({ type: \"complete\", action, source });\n    } catch (error) {\n      const errorMessage2 = error instanceof Error ? error.message : String(error);\n      this.emitProgress({ type: \"error\", action, source, message: errorMessage2 });\n      throw error;\n    }\n  }\n  async resolve(onMissing) {\n    const accumulator = this.createAccumulator();\n    const globalSettings = this.settingsManager.getGlobalSettings();\n    const projectSettings = this.settingsManager.getProjectSettings();\n    const allPackages = [];\n    for (const pkg2 of projectSettings.packages ?? []) {\n      allPackages.push({ pkg: pkg2, scope: \"project\" });\n    }\n    for (const pkg2 of globalSettings.packages ?? []) {\n      allPackages.push({ pkg: pkg2, scope: \"user\" });\n    }\n    const packageSources = this.dedupePackages(allPackages);\n    await this.resolvePackageSources(packageSources, accumulator, onMissing);\n    const globalBaseDir = this.agentDir;\n    const projectBaseDir = join14(this.cwd, CONFIG_DIR_NAME);\n    for (const resourceType of RESOURCE_TYPES) {\n      const target = this.getTargetMap(accumulator, resourceType);\n      const globalEntries = globalSettings[resourceType] ?? [];\n      const projectEntries = projectSettings[resourceType] ?? [];\n      this.resolveLocalEntries(projectEntries, resourceType, target, {\n        source: \"local\",\n        scope: \"project\",\n        origin: \"top-level\"\n      }, projectBaseDir);\n      this.resolveLocalEntries(globalEntries, resourceType, target, {\n        source: \"local\",\n        scope: \"user\",\n        origin: \"top-level\"\n      }, globalBaseDir);\n    }\n    this.addAutoDiscoveredResources(accumulator, globalSettings, projectSettings, globalBaseDir, projectBaseDir);\n    return this.toResolvedPaths(accumulator);\n  }\n  async resolveExtensionSources(sources, options) {\n    const accumulator = this.createAccumulator();\n    const scope = options?.temporary ? \"temporary\" : options?.local ? \"project\" : \"user\";\n    const packageSources = sources.map((source) => ({ pkg: source, scope }));\n    await this.resolvePackageSources(packageSources, accumulator);\n    return this.toResolvedPaths(accumulator);\n  }\n  listConfiguredPackages() {\n    const globalSettings = this.settingsManager.getGlobalSettings();\n    const projectSettings = this.settingsManager.getProjectSettings();\n    const configuredPackages = [];\n    for (const pkg2 of globalSettings.packages ?? []) {\n      const source = typeof pkg2 === \"string\" ? pkg2 : pkg2.source;\n      configuredPackages.push({\n        source,\n        scope: \"user\",\n        filtered: typeof pkg2 === \"object\",\n        installedPath: this.getInstalledPath(source, \"user\")\n      });\n    }\n    for (const pkg2 of projectSettings.packages ?? []) {\n      const source = typeof pkg2 === \"string\" ? pkg2 : pkg2.source;\n      configuredPackages.push({\n        source,\n        scope: \"project\",\n        filtered: typeof pkg2 === \"object\",\n        installedPath: this.getInstalledPath(source, \"project\")\n      });\n    }\n    return configuredPackages;\n  }\n  async install(source, options) {\n    const parsed = this.parseSource(source);\n    const scope = options?.local ? \"project\" : \"user\";\n    this.assertProjectTrustedForScope(scope);\n    await this.withProgress(\"install\", source, `Installing ${source}...`, async () => {\n      if (parsed.type === \"npm\") {\n        await this.installNpm(parsed, scope, false);\n        return;\n      }\n      if (parsed.type === \"git\") {\n        await this.installGit(parsed, scope);\n        return;\n      }\n      if (parsed.type === \"local\") {\n        const resolved = this.resolvePath(parsed.path);\n        if (!existsSync5(resolved)) {\n          throw new Error(`Path does not exist: ${resolved}`);\n        }\n        return;\n      }\n      throw new Error(`Unsupported install source: ${source}`);\n    });\n  }\n  async installAndPersist(source, options) {\n    await this.install(source, options);\n    this.addSourceToSettings(source, options);\n  }\n  async remove(source, options) {\n    const parsed = this.parseSource(source);\n    const scope = options?.local ? \"project\" : \"user\";\n    this.assertProjectTrustedForScope(scope);\n    await this.withProgress(\"remove\", source, `Removing ${source}...`, async () => {\n      if (parsed.type === \"npm\") {\n        await this.uninstallNpm(parsed, scope);\n        return;\n      }\n      if (parsed.type === \"git\") {\n        await this.removeGit(parsed, scope);\n        return;\n      }\n      if (parsed.type === \"local\") {\n        return;\n      }\n      throw new Error(`Unsupported remove source: ${source}`);\n    });\n  }\n  async removeAndPersist(source, options) {\n    await this.remove(source, options);\n    return this.removeSourceFromSettings(source, options);\n  }\n  async update(source) {\n    const globalSettings = this.settingsManager.getGlobalSettings();\n    const projectSettings = this.settingsManager.getProjectSettings();\n    const identity = source ? this.getPackageIdentity(source) : void 0;\n    let matched = false;\n    const updateSources = [];\n    for (const pkg2 of globalSettings.packages ?? []) {\n      const sourceStr = typeof pkg2 === \"string\" ? pkg2 : pkg2.source;\n      if (identity && this.getPackageIdentity(sourceStr, \"user\") !== identity)\n        continue;\n      matched = true;\n      updateSources.push({ source: sourceStr, scope: \"user\" });\n    }\n    for (const pkg2 of projectSettings.packages ?? []) {\n      const sourceStr = typeof pkg2 === \"string\" ? pkg2 : pkg2.source;\n      if (identity && this.getPackageIdentity(sourceStr, \"project\") !== identity)\n        continue;\n      matched = true;\n      updateSources.push({ source: sourceStr, scope: \"project\" });\n    }\n    if (source && !matched) {\n      throw new Error(this.buildNoMatchingPackageMessage(source, [\n        ...globalSettings.packages ?? [],\n        ...projectSettings.packages ?? []\n      ]));\n    }\n    await this.updateConfiguredSources(updateSources);\n  }\n  async updateConfiguredSources(sources) {\n    if (isOfflineModeEnabled() || sources.length === 0) {\n      return;\n    }\n    const npmCandidates = [];\n    const gitCandidates = [];\n    for (const entry of sources) {\n      const parsed = this.parseSource(entry.source);\n      if (parsed.type === \"npm\") {\n        if (!parsed.pinned) {\n          npmCandidates.push({ ...entry, parsed });\n        }\n      } else if (parsed.type === \"git\") {\n        gitCandidates.push({ ...entry, parsed });\n      }\n    }\n    const npmCheckTasks = npmCandidates.map((entry) => async () => ({\n      entry,\n      shouldUpdate: await this.shouldUpdateNpmSource(entry.parsed, entry.scope)\n    }));\n    const npmCheckResults = await this.runWithConcurrency(npmCheckTasks, UPDATE_CHECK_CONCURRENCY);\n    const userNpmUpdates = [];\n    const projectNpmUpdates = [];\n    for (const result of npmCheckResults) {\n      if (!result.shouldUpdate) {\n        continue;\n      }\n      if (result.entry.scope === \"user\") {\n        userNpmUpdates.push(result.entry);\n      } else {\n        projectNpmUpdates.push(result.entry);\n      }\n    }\n    const tasks = [];\n    if (userNpmUpdates.length > 0) {\n      tasks.push(this.updateNpmBatch(userNpmUpdates, \"user\"));\n    }\n    if (projectNpmUpdates.length > 0) {\n      tasks.push(this.updateNpmBatch(projectNpmUpdates, \"project\"));\n    }\n    if (gitCandidates.length > 0) {\n      const gitTasks = gitCandidates.map((entry) => async () => this.withProgress(\"update\", entry.source, `Updating ${entry.source}...`, async () => {\n        await this.updateGit(entry.parsed, entry.scope);\n      }));\n      tasks.push(this.runWithConcurrency(gitTasks, GIT_UPDATE_CONCURRENCY).then(() => {\n      }));\n    }\n    await Promise.all(tasks);\n  }\n  async shouldUpdateNpmSource(source, scope) {\n    const installedPath = this.getManagedNpmInstallPath(source, scope);\n    const installedVersion = existsSync5(installedPath) ? this.getInstalledNpmVersion(installedPath) : void 0;\n    if (!installedVersion) {\n      return true;\n    }\n    try {\n      const targetVersion = await this.getLatestNpmVersion(source.version ? source.spec : source.name, source.range);\n      return targetVersion !== installedVersion;\n    } catch {\n      return true;\n    }\n  }\n  async updateNpmBatch(sources, scope) {\n    if (sources.length === 0) {\n      return;\n    }\n    const sourceLabel = sources.length === 1 ? sources[0].source : `${scope} npm packages`;\n    const message = sources.length === 1 ? `Updating ${sources[0].source}...` : `Updating ${scope} npm packages...`;\n    const specs = sources.map((entry) => entry.parsed.version ? entry.parsed.spec : `${entry.parsed.name}@latest`);\n    await this.withProgress(\"update\", sourceLabel, message, async () => {\n      await this.installNpmBatch(specs, scope);\n    });\n  }\n  async installNpmBatch(specs, scope) {\n    const installRoot = this.getNpmInstallRoot(scope, false);\n    this.ensureNpmProject(installRoot);\n    await this.runNpmCommand(this.getNpmInstallArgs(specs, installRoot));\n  }\n  async checkForAvailableUpdates() {\n    if (isOfflineModeEnabled()) {\n      return [];\n    }\n    const globalSettings = this.settingsManager.getGlobalSettings();\n    const projectSettings = this.settingsManager.getProjectSettings();\n    const allPackages = [];\n    for (const pkg2 of projectSettings.packages ?? []) {\n      allPackages.push({ pkg: pkg2, scope: \"project\" });\n    }\n    for (const pkg2 of globalSettings.packages ?? []) {\n      allPackages.push({ pkg: pkg2, scope: \"user\" });\n    }\n    const packageSources = this.dedupePackages(allPackages);\n    const checks = packageSources.filter((entry) => entry.scope !== \"temporary\").map((entry) => async () => {\n      const source = typeof entry.pkg === \"string\" ? entry.pkg : entry.pkg.source;\n      const parsed = this.parseSource(source);\n      if (parsed.type === \"local\" || parsed.pinned) {\n        return void 0;\n      }\n      if (parsed.type === \"npm\") {\n        const installedPath2 = this.getNpmInstallPath(parsed, entry.scope);\n        if (!existsSync5(installedPath2)) {\n          return void 0;\n        }\n        const hasUpdate2 = await this.npmHasAvailableUpdate(parsed, installedPath2);\n        if (!hasUpdate2) {\n          return void 0;\n        }\n        return {\n          source,\n          displayName: parsed.name,\n          type: \"npm\",\n          scope: entry.scope\n        };\n      }\n      const installedPath = this.getGitInstallPath(parsed, entry.scope);\n      if (!existsSync5(installedPath)) {\n        return void 0;\n      }\n      const hasUpdate = await this.gitHasAvailableUpdate(installedPath);\n      if (!hasUpdate) {\n        return void 0;\n      }\n      return {\n        source,\n        displayName: `${parsed.host}/${parsed.path}`,\n        type: \"git\",\n        scope: entry.scope\n      };\n    });\n    const results = await this.runWithConcurrency(checks, UPDATE_CHECK_CONCURRENCY);\n    return results.filter((result) => result !== void 0);\n  }\n  async resolvePackageSources(sources, accumulator, onMissing) {\n    for (const { pkg: pkg2, scope } of sources) {\n      const sourceStr = typeof pkg2 === \"string\" ? pkg2 : pkg2.source;\n      const filter = typeof pkg2 === \"object\" ? pkg2 : void 0;\n      const deltaBase = this.findAutoloadDeltaBase(pkg2, scope, sources);\n      const resolvedSource = deltaBase?.source ?? sourceStr;\n      const resolvedScope = deltaBase?.scope ?? scope;\n      const parsed = this.parseSource(resolvedSource);\n      const metadata = { source: sourceStr, scope, origin: \"package\" };\n      if (parsed.type === \"local\") {\n        const baseDir = this.getBaseDirForScope(resolvedScope);\n        this.resolveLocalExtensionSource(parsed, accumulator, filter, metadata, baseDir);\n        continue;\n      }\n      const installMissing = async () => {\n        if (isOfflineModeEnabled())\n          return false;\n        if (!onMissing) {\n          await this.installParsedSource(parsed, resolvedScope);\n          return true;\n        }\n        const action = await onMissing(resolvedSource);\n        if (action === \"skip\")\n          return false;\n        if (action === \"error\")\n          throw new Error(`Missing source: ${resolvedSource}`);\n        await this.installParsedSource(parsed, resolvedScope);\n        return true;\n      };\n      if (parsed.type === \"npm\") {\n        let installedPath = this.getNpmInstallPath(parsed, resolvedScope);\n        const needsInstall = !existsSync5(installedPath) || !await this.installedNpmMatchesConfiguredVersion(parsed, installedPath);\n        if (needsInstall) {\n          const installed = await installMissing();\n          if (!installed)\n            continue;\n          installedPath = this.getNpmInstallPath(parsed, resolvedScope);\n        }\n        metadata.baseDir = installedPath;\n        this.collectPackageResources(installedPath, accumulator, filter, metadata);\n        continue;\n      }\n      if (parsed.type === \"git\") {\n        const installedPath = this.getGitInstallPath(parsed, resolvedScope);\n        if (!existsSync5(installedPath)) {\n          const installed = await installMissing();\n          if (!installed)\n            continue;\n        } else if (resolvedScope === \"temporary\" && !parsed.pinned && !isOfflineModeEnabled()) {\n          await this.refreshTemporaryGitSource(parsed, resolvedSource);\n        }\n        metadata.baseDir = installedPath;\n        this.collectPackageResources(installedPath, accumulator, filter, metadata);\n      }\n    }\n  }\n  findAutoloadDeltaBase(pkg2, scope, sources) {\n    if (scope !== \"project\" || typeof pkg2 !== \"object\" || pkg2.autoload !== false)\n      return void 0;\n    const identity = this.getPackageIdentity(pkg2.source, scope);\n    const userEntry = sources.find((entry) => entry.scope === \"user\" && this.getPackageIdentity(this.getPackageSourceString(entry.pkg), \"user\") === identity);\n    return userEntry ? { source: this.getPackageSourceString(userEntry.pkg), scope: \"user\" } : void 0;\n  }\n  resolveLocalExtensionSource(source, accumulator, filter, metadata, baseDir) {\n    const resolved = this.resolvePathFromBase(source.path, baseDir);\n    if (!existsSync5(resolved)) {\n      return;\n    }\n    try {\n      const stats = statSync4(resolved);\n      if (stats.isFile()) {\n        metadata.baseDir = dirname9(resolved);\n        this.addResource(accumulator.extensions, resolved, metadata, true);\n        return;\n      }\n      if (stats.isDirectory()) {\n        metadata.baseDir = resolved;\n        const resources = this.collectPackageResources(resolved, accumulator, filter, metadata);\n        if (!resources) {\n          this.addResource(accumulator.extensions, resolved, metadata, true);\n        }\n      }\n    } catch {\n      return;\n    }\n  }\n  async installParsedSource(parsed, scope) {\n    if (parsed.type === \"npm\") {\n      await this.installNpm(parsed, scope, scope === \"temporary\");\n      return;\n    }\n    if (parsed.type === \"git\") {\n      await this.installGit(parsed, scope);\n      return;\n    }\n  }\n  getPackageSourceString(pkg2) {\n    return typeof pkg2 === \"string\" ? pkg2 : pkg2.source;\n  }\n  getSourceMatchKeyForInput(source) {\n    const parsed = this.parseSource(source);\n    if (parsed.type === \"npm\") {\n      return `npm:${parsed.name}`;\n    }\n    if (parsed.type === \"git\") {\n      return `git:${parsed.host}/${parsed.path}`;\n    }\n    return `local:${this.resolvePath(parsed.path)}`;\n  }\n  getSourceMatchKeyForSettings(source, scope) {\n    const parsed = this.parseSource(source);\n    if (parsed.type === \"npm\") {\n      return `npm:${parsed.name}`;\n    }\n    if (parsed.type === \"git\") {\n      return `git:${parsed.host}/${parsed.path}`;\n    }\n    const baseDir = this.getBaseDirForScope(scope);\n    return `local:${this.resolvePathFromBase(parsed.path, baseDir)}`;\n  }\n  buildNoMatchingPackageMessage(source, configuredPackages) {\n    const suggestion = this.findSuggestedConfiguredSource(source, configuredPackages);\n    if (!suggestion) {\n      return `No matching package found for ${source}`;\n    }\n    return `No matching package found for ${source}. Did you mean ${suggestion}?`;\n  }\n  findSuggestedConfiguredSource(source, configuredPackages) {\n    const trimmedSource = source.trim();\n    const suggestions = /* @__PURE__ */ new Set();\n    for (const pkg2 of configuredPackages) {\n      const sourceStr = this.getPackageSourceString(pkg2);\n      const parsed = this.parseSource(sourceStr);\n      if (parsed.type === \"npm\") {\n        if (trimmedSource === parsed.name || trimmedSource === parsed.spec) {\n          suggestions.add(sourceStr);\n        }\n        continue;\n      }\n      if (parsed.type === \"git\") {\n        const shorthand = `${parsed.host}/${parsed.path}`;\n        const shorthandWithRef = parsed.ref ? `${shorthand}@${parsed.ref}` : void 0;\n        if (trimmedSource === shorthand || shorthandWithRef && trimmedSource === shorthandWithRef) {\n          suggestions.add(sourceStr);\n        }\n      }\n    }\n    return suggestions.values().next().value;\n  }\n  packageSourcesMatch(existing, inputSource, scope) {\n    const left = this.getSourceMatchKeyForSettings(this.getPackageSourceString(existing), scope);\n    const right = this.getSourceMatchKeyForInput(inputSource);\n    return left === right;\n  }\n  normalizePackageSourceForSettings(source, scope) {\n    const parsed = this.parseSource(source);\n    if (parsed.type !== \"local\") {\n      return source;\n    }\n    const baseDir = this.getBaseDirForScope(scope);\n    const resolved = this.resolvePath(parsed.path);\n    const rel = relative2(baseDir, resolved);\n    return rel || \".\";\n  }\n  parseSource(source) {\n    if (source.startsWith(\"npm:\")) {\n      const spec = source.slice(\"npm:\".length).trim();\n      const { name, version } = this.parseNpmSpec(spec);\n      return {\n        type: \"npm\",\n        spec,\n        name,\n        version,\n        range: getNpmVersionRange(version),\n        pinned: isExactNpmVersion(version)\n      };\n    }\n    if (isLocalPath(source)) {\n      return { type: \"local\", path: source };\n    }\n    const gitParsed = parseGitUrl(source);\n    if (gitParsed) {\n      return gitParsed;\n    }\n    return { type: \"local\", path: source };\n  }\n  async installedNpmMatchesConfiguredVersion(source, installedPath) {\n    const installedVersion = this.getInstalledNpmVersion(installedPath);\n    if (!installedVersion) {\n      return false;\n    }\n    return source.range ? satisfies(installedVersion, source.range) : true;\n  }\n  async npmHasAvailableUpdate(source, installedPath) {\n    if (isOfflineModeEnabled()) {\n      return false;\n    }\n    const installedVersion = this.getInstalledNpmVersion(installedPath);\n    if (!installedVersion) {\n      return false;\n    }\n    try {\n      const targetVersion = await this.getLatestNpmVersion(source.version ? source.spec : source.name, source.range);\n      return targetVersion !== installedVersion;\n    } catch {\n      return false;\n    }\n  }\n  getInstalledNpmVersion(installedPath) {\n    const packageJsonPath = join14(installedPath, \"package.json\");\n    if (!existsSync5(packageJsonPath))\n      return void 0;\n    try {\n      const content = readFileSync5(packageJsonPath, \"utf-8\");\n      const pkg2 = JSON.parse(content);\n      return pkg2.version;\n    } catch {\n      return void 0;\n    }\n  }\n  async getLatestNpmVersion(packageSpec, range) {\n    const npmCommand = this.getNpmCommand();\n    const stdout = await this.runCommandCapture(npmCommand.command, [...npmCommand.args, \"view\", packageSpec, \"version\", \"--json\"], { cwd: this.cwd, timeoutMs: NETWORK_TIMEOUT_MS });\n    const raw = stdout.trim();\n    if (!raw)\n      throw new Error(\"Empty response from npm view\");\n    const parsed = JSON.parse(raw);\n    if (typeof parsed === \"string\") {\n      return parsed;\n    }\n    if (Array.isArray(parsed)) {\n      const versions = parsed.filter((value) => typeof value === \"string\" && value.length > 0);\n      const latest = range ? maxSatisfying(versions, range) : [...versions].sort(rcompare)[0];\n      if (latest)\n        return latest;\n    }\n    throw new Error(\"Unexpected response from npm view\");\n  }\n  async gitHasAvailableUpdate(installedPath) {\n    if (isOfflineModeEnabled()) {\n      return false;\n    }\n    try {\n      const localHead = await this.runCommandCapture(\"git\", [\"rev-parse\", \"HEAD\"], {\n        cwd: installedPath,\n        timeoutMs: NETWORK_TIMEOUT_MS\n      });\n      const remoteHead = await this.getRemoteGitHead(installedPath);\n      return localHead.trim() !== remoteHead.trim();\n    } catch {\n      return false;\n    }\n  }\n  async getRemoteGitHead(installedPath) {\n    const upstreamRef = await this.getGitUpstreamRef(installedPath);\n    if (upstreamRef) {\n      const remoteHead2 = await this.runGitRemoteCommand(installedPath, [\"ls-remote\", \"origin\", upstreamRef]);\n      const match2 = remoteHead2.match(/^([0-9a-f]{40})\\s+/m);\n      if (match2?.[1]) {\n        return match2[1];\n      }\n    }\n    const remoteHead = await this.runGitRemoteCommand(installedPath, [\"ls-remote\", \"origin\", \"HEAD\"]);\n    const match = remoteHead.match(/^([0-9a-f]{40})\\s+HEAD$/m);\n    if (!match?.[1]) {\n      throw new Error(\"Failed to determine remote HEAD\");\n    }\n    return match[1];\n  }\n  async getLocalGitUpdateTarget(installedPath) {\n    try {\n      const upstream = await this.runCommandCapture(\"git\", [\"rev-parse\", \"--abbrev-ref\", \"@{upstream}\"], {\n        cwd: installedPath,\n        timeoutMs: NETWORK_TIMEOUT_MS\n      });\n      const trimmedUpstream = upstream.trim();\n      if (!trimmedUpstream.startsWith(\"origin/\")) {\n        throw new Error(`Unsupported upstream remote: ${trimmedUpstream}`);\n      }\n      const branch = trimmedUpstream.slice(\"origin/\".length);\n      if (!branch) {\n        throw new Error(\"Missing upstream branch name\");\n      }\n      const head = await this.runCommandCapture(\"git\", [\"rev-parse\", \"@{upstream}\"], {\n        cwd: installedPath,\n        timeoutMs: NETWORK_TIMEOUT_MS\n      });\n      return {\n        ref: \"@{upstream}\",\n        head,\n        fetchArgs: [\n          \"fetch\",\n          \"--prune\",\n          \"--no-tags\",\n          \"origin\",\n          `+refs/heads/${branch}:refs/remotes/origin/${branch}`\n        ]\n      };\n    } catch {\n      await this.runCommand(\"git\", [\"remote\", \"set-head\", \"origin\", \"-a\"], { cwd: installedPath }).catch(() => {\n      });\n      const head = await this.runCommandCapture(\"git\", [\"rev-parse\", \"origin/HEAD\"], {\n        cwd: installedPath,\n        timeoutMs: NETWORK_TIMEOUT_MS\n      });\n      const originHeadRef = await this.runCommandCapture(\"git\", [\"symbolic-ref\", \"refs/remotes/origin/HEAD\"], {\n        cwd: installedPath,\n        timeoutMs: NETWORK_TIMEOUT_MS\n      }).catch(() => \"\");\n      const branch = originHeadRef.trim().replace(/^refs\\/remotes\\/origin\\//, \"\");\n      if (branch) {\n        return {\n          ref: \"origin/HEAD\",\n          head,\n          fetchArgs: [\n            \"fetch\",\n            \"--prune\",\n            \"--no-tags\",\n            \"origin\",\n            `+refs/heads/${branch}:refs/remotes/origin/${branch}`\n          ]\n        };\n      }\n      return {\n        ref: \"origin/HEAD\",\n        head,\n        fetchArgs: [\"fetch\", \"--prune\", \"--no-tags\", \"origin\", \"+HEAD:refs/remotes/origin/HEAD\"]\n      };\n    }\n  }\n  async getGitUpstreamRef(installedPath) {\n    try {\n      const upstream = await this.runCommandCapture(\"git\", [\"rev-parse\", \"--abbrev-ref\", \"@{upstream}\"], {\n        cwd: installedPath,\n        timeoutMs: NETWORK_TIMEOUT_MS\n      });\n      const trimmed = upstream.trim();\n      if (!trimmed.startsWith(\"origin/\")) {\n        return void 0;\n      }\n      const branch = trimmed.slice(\"origin/\".length);\n      return branch ? `refs/heads/${branch}` : void 0;\n    } catch {\n      return void 0;\n    }\n  }\n  runGitRemoteCommand(installedPath, args) {\n    return this.runCommandCapture(\"git\", args, {\n      cwd: installedPath,\n      timeoutMs: NETWORK_TIMEOUT_MS,\n      env: {\n        GIT_TERMINAL_PROMPT: \"0\"\n      }\n    });\n  }\n  async runWithConcurrency(tasks, limit) {\n    if (tasks.length === 0) {\n      return [];\n    }\n    const results = new Array(tasks.length);\n    let nextIndex = 0;\n    const workerCount = Math.max(1, Math.min(limit, tasks.length));\n    const worker = async () => {\n      while (true) {\n        const index = nextIndex;\n        nextIndex += 1;\n        if (index >= tasks.length) {\n          return;\n        }\n        results[index] = await tasks[index]();\n      }\n    };\n    await Promise.all(Array.from({ length: workerCount }, () => worker()));\n    return results;\n  }\n  /**\n   * Get a unique identity for a package, ignoring version/ref.\n   * Used to detect when the same package is in both global and project settings.\n   * For git packages, uses normalized host/path to ensure SSH and HTTPS URLs\n   * for the same repository are treated as identical.\n   */\n  getPackageIdentity(source, scope) {\n    const parsed = this.parseSource(source);\n    if (parsed.type === \"npm\") {\n      return `npm:${parsed.name}`;\n    }\n    if (parsed.type === \"git\") {\n      return `git:${parsed.host}/${parsed.path}`;\n    }\n    if (scope) {\n      const baseDir = this.getBaseDirForScope(scope);\n      return `local:${this.resolvePathFromBase(parsed.path, baseDir)}`;\n    }\n    return `local:${this.resolvePath(parsed.path)}`;\n  }\n  /**\n   * Dedupe packages: if same package identity appears in both global and project,\n   * keep only the project one (project wins). A project entry with autoload=false\n   * is a delta over the global entry, so both are kept (delta first).\n   */\n  dedupePackages(packages) {\n    const result = [];\n    const seen = /* @__PURE__ */ new Map();\n    for (const entry of packages) {\n      const identity = this.getPackageIdentity(this.getPackageSourceString(entry.pkg), entry.scope);\n      const index = seen.get(identity);\n      if (index === void 0) {\n        seen.set(identity, result.length);\n        result.push(entry);\n        continue;\n      }\n      const existing = result[index];\n      if (existing?.scope === \"project\" && entry.scope === \"user\") {\n        if (typeof existing.pkg === \"object\" && existing.pkg.autoload === false)\n          result.push(entry);\n      } else if (entry.scope === \"project\") {\n        result[index] = entry;\n      }\n    }\n    return result;\n  }\n  parseNpmSpec(spec) {\n    const match = spec.match(/^(@?[^@]+(?:\\/[^@]+)?)(?:@(.+))?$/);\n    if (!match) {\n      return { name: spec };\n    }\n    const name = match[1] ?? spec;\n    const version = match[2];\n    return { name, version };\n  }\n  assertProjectTrustedForScope(scope) {\n    if (scope === \"project\" && !this.settingsManager.isProjectTrusted()) {\n      throw new Error(\"Project is not trusted; refusing to access project package storage\");\n    }\n  }\n  getNpmCommand() {\n    const configuredCommand = this.settingsManager.getNpmCommand();\n    if (!configuredCommand || configuredCommand.length === 0) {\n      return { command: \"npm\", args: [] };\n    }\n    const [command, ...args] = configuredCommand;\n    if (!command) {\n      throw new Error(\"Invalid npmCommand: first array entry must be a non-empty command\");\n    }\n    return { command, args };\n  }\n  getPackageManagerName() {\n    const npmCommand = this.getNpmCommand();\n    const commandParts = [npmCommand.command, ...npmCommand.args];\n    const separatorIndex = commandParts.lastIndexOf(\"--\");\n    const packageManagerCommand = separatorIndex >= 0 ? commandParts[separatorIndex + 1] : npmCommand.command;\n    return packageManagerCommand ? basename3(packageManagerCommand).replace(/\\.(cmd|exe)$/i, \"\") : \"\";\n  }\n  async runNpmCommand(args, options) {\n    const npmCommand = this.getNpmCommand();\n    await this.runCommand(npmCommand.command, [...npmCommand.args, ...args], options);\n  }\n  getGitDependencyInstallArgs() {\n    const configuredCommand = this.settingsManager.getNpmCommand();\n    if (configuredCommand && configuredCommand.length > 0) {\n      return [\"install\"];\n    }\n    return [\"install\", \"--omit=dev\"];\n  }\n  runNpmCommandSync(args) {\n    const npmCommand = this.getNpmCommand();\n    return this.runCommandSync(npmCommand.command, [...npmCommand.args, ...args]);\n  }\n  getNpmInstallArgs(specs, installRoot) {\n    const packageManagerName = this.getPackageManagerName();\n    if (packageManagerName === \"bun\") {\n      return [\"install\", ...specs, \"--cwd\", installRoot, \"--omit=peer\"];\n    }\n    if (packageManagerName === \"pnpm\") {\n      return [\n        \"install\",\n        ...specs,\n        \"--prefix\",\n        installRoot,\n        \"--config.auto-install-peers=false\",\n        \"--config.strict-peer-dependencies=false\",\n        \"--config.strict-dep-builds=false\"\n      ];\n    }\n    return [\"install\", ...specs, \"--prefix\", installRoot, \"--legacy-peer-deps\"];\n  }\n  async installNpm(source, scope, temporary) {\n    const installRoot = this.getNpmInstallRoot(scope, temporary);\n    this.ensureNpmProject(installRoot);\n    await this.runNpmCommand(this.getNpmInstallArgs([source.spec], installRoot));\n  }\n  async uninstallNpm(source, scope) {\n    const installRoot = this.getNpmInstallRoot(scope, false);\n    if (!existsSync5(installRoot)) {\n      return;\n    }\n    const packageManagerName = this.getPackageManagerName();\n    if (packageManagerName === \"bun\") {\n      await this.runNpmCommand([\"uninstall\", source.name, \"--cwd\", installRoot]);\n      return;\n    }\n    const args = [\"uninstall\", source.name, \"--prefix\", installRoot];\n    if (packageManagerName !== \"pnpm\") {\n      args.push(\"--legacy-peer-deps\");\n    }\n    await this.runNpmCommand(args);\n  }\n  async installGit(source, scope) {\n    const targetDir = this.getGitInstallPath(source, scope);\n    if (existsSync5(targetDir)) {\n      if (source.ref) {\n        await this.ensureGitRef(targetDir, [\"fetch\", \"origin\", source.ref], \"FETCH_HEAD\");\n        return;\n      }\n      const target = await this.getLocalGitUpdateTarget(targetDir);\n      await this.ensureGitRef(targetDir, target.fetchArgs, target.ref);\n      return;\n    }\n    const gitRoot = this.getGitInstallRoot(scope);\n    if (gitRoot) {\n      this.ensureGitIgnore(gitRoot);\n    }\n    mkdirSync3(dirname9(targetDir), { recursive: true });\n    rmSync(this.getGitUpdateMarkerPath(targetDir), { force: true });\n    try {\n      await this.runCommand(\"git\", [\"clone\", source.repo, targetDir]);\n      if (source.ref) {\n        await this.runCommand(\"git\", [\"checkout\", source.ref], { cwd: targetDir });\n      }\n      const packageJsonPath = join14(targetDir, \"package.json\");\n      if (existsSync5(packageJsonPath)) {\n        await this.runNpmCommand(this.getGitDependencyInstallArgs(), { cwd: targetDir });\n      }\n    } catch (error) {\n      rmSync(targetDir, { recursive: true, force: true });\n      this.pruneEmptyGitParents(targetDir, gitRoot);\n      throw error;\n    }\n  }\n  async updateGit(source, scope) {\n    const targetDir = this.getGitInstallPath(source, scope);\n    if (!existsSync5(targetDir)) {\n      await this.installGit(source, scope);\n      return;\n    }\n    if (source.ref) {\n      await this.ensureGitRef(targetDir, [\"fetch\", \"origin\", source.ref], \"FETCH_HEAD\");\n      return;\n    }\n    const target = await this.getLocalGitUpdateTarget(targetDir);\n    await this.ensureGitRef(targetDir, target.fetchArgs, target.ref);\n  }\n  hasMissingGitDependencies(targetDir) {\n    const packageJsonPath = join14(targetDir, \"package.json\");\n    if (!existsSync5(packageJsonPath))\n      return false;\n    try {\n      const manifest = JSON.parse(readFileSync5(packageJsonPath, \"utf-8\"));\n      if (!manifest.dependencies || typeof manifest.dependencies !== \"object\" || Array.isArray(manifest.dependencies)) {\n        return false;\n      }\n      const nodeModulesDir = resolve3(targetDir, \"node_modules\");\n      return Object.keys(manifest.dependencies).some((name) => {\n        const dependencyPath = resolve3(nodeModulesDir, name);\n        if (!dependencyPath.startsWith(`${nodeModulesDir}${sep3}`))\n          return false;\n        return !existsSync5(dependencyPath);\n      });\n    } catch {\n      return false;\n    }\n  }\n  async repairMissingGitDependencies(targetDir) {\n    if (!this.hasMissingGitDependencies(targetDir))\n      return;\n    await this.runNpmCommand(this.getGitDependencyInstallArgs(), { cwd: targetDir });\n  }\n  getGitUpdateMarkerPath(targetDir) {\n    return join14(dirname9(targetDir), `.${basename3(targetDir)}.pi-update-incomplete`);\n  }\n  async cleanAndInstallGitDependencies(targetDir, markerPath) {\n    try {\n      await this.runCommand(\"git\", [\"clean\", \"-fdx\"], { cwd: targetDir });\n    } catch (error) {\n      await this.repairMissingGitDependencies(targetDir).catch(() => {\n      });\n      throw error;\n    }\n    const packageJsonPath = join14(targetDir, \"package.json\");\n    if (existsSync5(packageJsonPath)) {\n      await this.runNpmCommand(this.getGitDependencyInstallArgs(), { cwd: targetDir });\n    }\n    rmSync(markerPath, { force: true });\n  }\n  async ensureGitRef(targetDir, fetchArgs, ref) {\n    await this.runCommand(\"git\", fetchArgs, { cwd: targetDir });\n    const localHead = await this.runCommandCapture(\"git\", [\"rev-parse\", \"HEAD\"], {\n      cwd: targetDir,\n      timeoutMs: NETWORK_TIMEOUT_MS\n    });\n    const commitRef = `${ref}^{commit}`;\n    const targetHead = await this.runCommandCapture(\"git\", [\"rev-parse\", commitRef], {\n      cwd: targetDir,\n      timeoutMs: NETWORK_TIMEOUT_MS\n    });\n    const markerPath = this.getGitUpdateMarkerPath(targetDir);\n    if (localHead.trim() === targetHead.trim()) {\n      if (existsSync5(markerPath)) {\n        await this.cleanAndInstallGitDependencies(targetDir, markerPath);\n      } else {\n        await this.repairMissingGitDependencies(targetDir);\n      }\n      return;\n    }\n    writeFileSync3(markerPath, \"\", \"utf-8\");\n    await this.runCommand(\"git\", [\"reset\", \"--hard\", commitRef], { cwd: targetDir });\n    await this.cleanAndInstallGitDependencies(targetDir, markerPath);\n  }\n  async refreshTemporaryGitSource(source, sourceStr) {\n    if (isOfflineModeEnabled()) {\n      return;\n    }\n    try {\n      await this.withProgress(\"pull\", sourceStr, `Refreshing ${sourceStr}...`, async () => {\n        await this.updateGit(source, \"temporary\");\n      });\n    } catch {\n    }\n  }\n  async removeGit(source, scope) {\n    const targetDir = this.getGitInstallPath(source, scope);\n    rmSync(targetDir, { recursive: true, force: true });\n    rmSync(this.getGitUpdateMarkerPath(targetDir), { force: true });\n    this.pruneEmptyGitParents(targetDir, this.getGitInstallRoot(scope));\n  }\n  pruneEmptyGitParents(targetDir, installRoot) {\n    if (!installRoot)\n      return;\n    const resolvedRoot = resolve3(installRoot);\n    let current = dirname9(targetDir);\n    while (current.startsWith(resolvedRoot) && current !== resolvedRoot) {\n      if (!existsSync5(current)) {\n        current = dirname9(current);\n        continue;\n      }\n      const entries = readdirSync2(current);\n      if (entries.length > 0) {\n        break;\n      }\n      try {\n        rmSync(current, { recursive: true, force: true });\n      } catch {\n        break;\n      }\n      current = dirname9(current);\n    }\n  }\n  ensureNpmProject(installRoot) {\n    if (!existsSync5(installRoot)) {\n      mkdirSync3(installRoot, { recursive: true });\n    }\n    markPathIgnoredByCloudSync(installRoot);\n    this.ensureGitIgnore(installRoot);\n    const packageJsonPath = join14(installRoot, \"package.json\");\n    if (!existsSync5(packageJsonPath)) {\n      const pkgJson = { name: \"pi-extensions\", private: true };\n      writeFileSync3(packageJsonPath, JSON.stringify(pkgJson, null, 2), \"utf-8\");\n    }\n  }\n  ensureGitIgnore(dir) {\n    if (!existsSync5(dir)) {\n      mkdirSync3(dir, { recursive: true });\n    }\n    const ignorePath = join14(dir, \".gitignore\");\n    if (!existsSync5(ignorePath)) {\n      writeFileSync3(ignorePath, \"*\\n!.gitignore\\n\", \"utf-8\");\n    }\n  }\n  getNpmInstallRoot(scope, temporary) {\n    if (temporary) {\n      return this.getTemporaryDir(\"npm\");\n    }\n    if (scope === \"project\") {\n      this.assertProjectTrustedForScope(scope);\n      return join14(this.cwd, CONFIG_DIR_NAME, \"npm\");\n    }\n    return join14(this.agentDir, \"npm\");\n  }\n  getGlobalNpmRoot() {\n    const npmCommand = this.getNpmCommand();\n    const commandKey = [npmCommand.command, ...npmCommand.args].join(\"\\0\");\n    if (this.globalNpmRoot && this.globalNpmRootCommandKey === commandKey) {\n      return this.globalNpmRoot;\n    }\n    if (this.getPackageManagerName() === \"bun\") {\n      const binDir = this.runNpmCommandSync([\"pm\", \"bin\", \"-g\"]).trim();\n      this.globalNpmRoot = join14(dirname9(binDir), \"install\", \"global\", \"node_modules\");\n    } else {\n      this.globalNpmRoot = this.runNpmCommandSync([\"root\", \"-g\"]).trim();\n    }\n    this.globalNpmRootCommandKey = commandKey;\n    return this.globalNpmRoot;\n  }\n  getPnpmGlobalPackagePath(packageName) {\n    if (this.getPackageManagerName() !== \"pnpm\") {\n      return void 0;\n    }\n    const output = this.runNpmCommandSync([\"list\", \"-g\", \"--depth\", \"0\", \"--json\"]);\n    const entries = JSON.parse(output);\n    for (const entry of entries) {\n      const path12 = entry.dependencies?.[packageName]?.path;\n      if (path12)\n        return path12;\n    }\n    return void 0;\n  }\n  getManagedNpmInstallPath(source, scope) {\n    if (scope === \"temporary\") {\n      return join14(this.getTemporaryDir(\"npm\"), \"node_modules\", source.name);\n    }\n    if (scope === \"project\") {\n      this.assertProjectTrustedForScope(scope);\n      return join14(this.cwd, CONFIG_DIR_NAME, \"npm\", \"node_modules\", source.name);\n    }\n    return join14(this.agentDir, \"npm\", \"node_modules\", source.name);\n  }\n  getLegacyGlobalNpmInstallPath(source) {\n    try {\n      return this.getPnpmGlobalPackagePath(source.name) ?? join14(this.getGlobalNpmRoot(), source.name);\n    } catch {\n      return void 0;\n    }\n  }\n  getNpmInstallPath(source, scope) {\n    const managedPath = this.getManagedNpmInstallPath(source, scope);\n    if (scope !== \"user\" || existsSync5(managedPath)) {\n      return managedPath;\n    }\n    const legacyPath = this.getLegacyGlobalNpmInstallPath(source);\n    return legacyPath && existsSync5(legacyPath) ? legacyPath : managedPath;\n  }\n  getGitInstallPath(source, scope) {\n    if (scope === \"temporary\") {\n      return this.getTemporaryDir(`git-${source.host}`, source.path);\n    }\n    const installRoot = this.getGitInstallRoot(scope);\n    if (!installRoot) {\n      throw new Error(\"Missing git install root\");\n    }\n    return this.resolveManagedPath(installRoot, source.host, source.path);\n  }\n  getGitInstallRoot(scope) {\n    if (scope === \"temporary\") {\n      return void 0;\n    }\n    if (scope === \"project\") {\n      this.assertProjectTrustedForScope(scope);\n      return join14(this.cwd, CONFIG_DIR_NAME, \"git\");\n    }\n    return join14(this.agentDir, \"git\");\n  }\n  getTemporaryDir(prefix, suffix) {\n    const root = this.resolveManagedPath(getExtensionTempFolder(this.agentDir), prefix);\n    const hash = createHash(\"sha256\").update(`${prefix}-${suffix ?? \"\"}`).digest(\"hex\").slice(0, 8);\n    return this.resolveManagedPath(root, hash, suffix ?? \"\");\n  }\n  resolveManagedPath(root, ...parts) {\n    const resolvedRoot = resolve3(root);\n    const resolvedPath = resolve3(resolvedRoot, ...parts);\n    if (resolvedPath !== resolvedRoot && !resolvedPath.startsWith(`${resolvedRoot}${sep3}`)) {\n      throw new Error(`Refusing to use path outside package install root: ${resolvedPath}`);\n    }\n    return resolvedPath;\n  }\n  getBaseDirForScope(scope) {\n    if (scope === \"project\") {\n      this.assertProjectTrustedForScope(scope);\n      return join14(this.cwd, CONFIG_DIR_NAME);\n    }\n    if (scope === \"user\") {\n      return this.agentDir;\n    }\n    return this.cwd;\n  }\n  resolvePath(input) {\n    return resolvePath(input, this.cwd, { homeDir: getHomeDir(), trim: true });\n  }\n  resolvePathFromBase(input, baseDir) {\n    return resolvePath(input, baseDir, { homeDir: getHomeDir(), trim: true });\n  }\n  collectPackageResources(packageRoot, accumulator, filter, metadata) {\n    if (filter) {\n      for (const resourceType of RESOURCE_TYPES) {\n        const patterns = filter[resourceType];\n        const target = this.getTargetMap(accumulator, resourceType);\n        if (filter.autoload === false) {\n          this.applyPackageDeltaFilter(packageRoot, patterns ?? [], resourceType, target, metadata);\n        } else if (patterns !== void 0) {\n          this.applyPackageFilter(packageRoot, patterns, resourceType, target, metadata);\n        } else {\n          this.collectDefaultResources(packageRoot, resourceType, target, metadata);\n        }\n      }\n      return true;\n    }\n    const manifest = readPiManifest(join14(packageRoot, \"package.json\"));\n    if (manifest) {\n      for (const resourceType of RESOURCE_TYPES) {\n        const entries = manifest[resourceType];\n        this.addManifestEntries(entries, packageRoot, resourceType, this.getTargetMap(accumulator, resourceType), metadata);\n      }\n      return true;\n    }\n    let hasAnyDir = false;\n    for (const resourceType of RESOURCE_TYPES) {\n      const dir = join14(packageRoot, resourceType);\n      if (existsSync5(dir)) {\n        const files = collectResourceFiles(dir, resourceType);\n        for (const f of files) {\n          this.addResource(this.getTargetMap(accumulator, resourceType), f, metadata, true);\n        }\n        hasAnyDir = true;\n      }\n    }\n    return hasAnyDir;\n  }\n  collectDefaultResources(packageRoot, resourceType, target, metadata) {\n    const manifest = readPiManifest(join14(packageRoot, \"package.json\"));\n    const entries = manifest?.[resourceType];\n    if (entries) {\n      this.addManifestEntries(entries, packageRoot, resourceType, target, metadata);\n      return;\n    }\n    const dir = join14(packageRoot, resourceType);\n    if (existsSync5(dir)) {\n      const files = collectResourceFiles(dir, resourceType);\n      for (const f of files) {\n        this.addResource(target, f, metadata, true);\n      }\n    }\n  }\n  applyPackageFilter(packageRoot, userPatterns, resourceType, target, metadata) {\n    const { allFiles } = this.collectManifestFiles(packageRoot, resourceType);\n    if (userPatterns.length === 0) {\n      for (const f of allFiles) {\n        this.addResource(target, f, metadata, false);\n      }\n      return;\n    }\n    const enabledByUser = applyPatterns(allFiles, userPatterns, packageRoot);\n    for (const f of allFiles) {\n      const enabled = enabledByUser.has(f);\n      this.addResource(target, f, metadata, enabled);\n    }\n  }\n  applyPackageDeltaFilter(packageRoot, userPatterns, resourceType, target, metadata) {\n    if (userPatterns.length === 0) {\n      return;\n    }\n    const { allFiles } = this.collectManifestFiles(packageRoot, resourceType);\n    const enabledByUser = applyAutoloadDisabledPatterns(allFiles, userPatterns, packageRoot);\n    for (const [filePath, enabled] of enabledByUser) {\n      this.addResource(target, filePath, metadata, enabled);\n    }\n  }\n  /**\n   * Collect all files from a package for a resource type, applying manifest patterns.\n   * Returns { allFiles, enabledByManifest } where enabledByManifest is the set of files\n   * that pass the manifest's own patterns.\n   */\n  collectManifestFiles(packageRoot, resourceType) {\n    const manifest = readPiManifest(join14(packageRoot, \"package.json\"));\n    const entries = manifest?.[resourceType];\n    if (entries && entries.length > 0) {\n      const allFiles2 = this.collectFilesFromManifestEntries(entries, packageRoot, resourceType);\n      const manifestPatterns = entries.filter(isOverridePattern);\n      const enabledByManifest = manifestPatterns.length > 0 ? applyPatterns(allFiles2, manifestPatterns, packageRoot) : new Set(allFiles2);\n      return { allFiles: Array.from(enabledByManifest), enabledByManifest };\n    }\n    const conventionDir = join14(packageRoot, resourceType);\n    if (!existsSync5(conventionDir)) {\n      return { allFiles: [], enabledByManifest: /* @__PURE__ */ new Set() };\n    }\n    const allFiles = collectResourceFiles(conventionDir, resourceType);\n    return { allFiles, enabledByManifest: new Set(allFiles) };\n  }\n  addManifestEntries(entries, root, resourceType, target, metadata) {\n    if (!entries)\n      return;\n    const allFiles = this.collectFilesFromManifestEntries(entries, root, resourceType);\n    const patterns = entries.filter(isOverridePattern);\n    const enabledPaths = applyPatterns(allFiles, patterns, root);\n    for (const f of allFiles) {\n      if (enabledPaths.has(f)) {\n        this.addResource(target, f, metadata, true);\n      }\n    }\n  }\n  collectFilesFromManifestEntries(entries, root, resourceType) {\n    const sourceEntries = entries.filter((entry) => !isOverridePattern(entry));\n    const resolved = sourceEntries.flatMap((entry) => {\n      if (!hasGlobPattern(entry)) {\n        return [resolve3(root, entry)];\n      }\n      return globSync(entry, {\n        cwd: root,\n        absolute: true,\n        dot: false,\n        nodir: false\n      }).map((match) => resolve3(match));\n    });\n    return this.collectFilesFromPaths(resolved, resourceType);\n  }\n  resolveLocalEntries(entries, resourceType, target, metadata, baseDir) {\n    if (entries.length === 0)\n      return;\n    const { plain, patterns } = splitPatterns(entries);\n    const resolvedPlain = plain.map((p) => this.resolvePathFromBase(p, baseDir));\n    const allFiles = this.collectFilesFromPaths(resolvedPlain, resourceType);\n    const enabledPaths = applyPatterns(allFiles, patterns, baseDir);\n    for (const f of allFiles) {\n      this.addResource(target, f, metadata, enabledPaths.has(f));\n    }\n  }\n  addAutoDiscoveredResources(accumulator, globalSettings, projectSettings, globalBaseDir, projectBaseDir) {\n    const userMetadata = {\n      source: \"auto\",\n      scope: \"user\",\n      origin: \"top-level\",\n      baseDir: globalBaseDir\n    };\n    const projectMetadata = {\n      source: \"auto\",\n      scope: \"project\",\n      origin: \"top-level\",\n      baseDir: projectBaseDir\n    };\n    const userOverrides = {\n      extensions: globalSettings.extensions ?? [],\n      skills: globalSettings.skills ?? [],\n      prompts: globalSettings.prompts ?? [],\n      themes: globalSettings.themes ?? []\n    };\n    const projectOverrides = {\n      extensions: projectSettings.extensions ?? [],\n      skills: projectSettings.skills ?? [],\n      prompts: projectSettings.prompts ?? [],\n      themes: projectSettings.themes ?? []\n    };\n    const userDirs = {\n      extensions: join14(globalBaseDir, \"extensions\"),\n      skills: join14(globalBaseDir, \"skills\"),\n      prompts: join14(globalBaseDir, \"prompts\"),\n      themes: join14(globalBaseDir, \"themes\")\n    };\n    const projectDirs = {\n      extensions: join14(projectBaseDir, \"extensions\"),\n      skills: join14(projectBaseDir, \"skills\"),\n      prompts: join14(projectBaseDir, \"prompts\"),\n      themes: join14(projectBaseDir, \"themes\")\n    };\n    const userAgentsSkillsDir = join14(getHomeDir(), \".agents\", \"skills\");\n    const projectTrusted = this.settingsManager.isProjectTrusted();\n    const projectAgentsSkillDirs = projectTrusted ? collectAncestorAgentsSkillDirs(this.cwd).filter((dir) => resolve3(dir) !== resolve3(userAgentsSkillsDir)) : [];\n    const addResources = (resourceType, paths, metadata, overrides, baseDir) => {\n      const target = this.getTargetMap(accumulator, resourceType);\n      for (const path12 of paths) {\n        const enabled = isEnabledByOverrides(path12, overrides, baseDir);\n        this.addResource(target, path12, metadata, enabled);\n      }\n    };\n    if (projectTrusted) {\n      addResources(\"extensions\", collectAutoExtensionEntries(projectDirs.extensions), projectMetadata, projectOverrides.extensions, projectBaseDir);\n      addResources(\"skills\", collectAutoSkillEntries(projectDirs.skills, \"pi\"), projectMetadata, projectOverrides.skills, projectBaseDir);\n    }\n    for (const agentsSkillsDir of projectAgentsSkillDirs) {\n      const agentsBaseDir = dirname9(agentsSkillsDir);\n      const agentsMetadata = {\n        ...projectMetadata,\n        baseDir: agentsBaseDir\n      };\n      addResources(\"skills\", collectAutoSkillEntries(agentsSkillsDir, \"agents\"), agentsMetadata, projectOverrides.skills, agentsBaseDir);\n    }\n    if (projectTrusted) {\n      addResources(\"prompts\", collectAutoPromptEntries(projectDirs.prompts), projectMetadata, projectOverrides.prompts, projectBaseDir);\n      addResources(\"themes\", collectAutoThemeEntries(projectDirs.themes), projectMetadata, projectOverrides.themes, projectBaseDir);\n    }\n    addResources(\"extensions\", collectAutoExtensionEntries(userDirs.extensions), userMetadata, userOverrides.extensions, globalBaseDir);\n    addResources(\"skills\", collectAutoSkillEntries(userDirs.skills, \"pi\"), userMetadata, userOverrides.skills, globalBaseDir);\n    const userAgentsBaseDir = dirname9(userAgentsSkillsDir);\n    const userAgentsMetadata = {\n      ...userMetadata,\n      baseDir: userAgentsBaseDir\n    };\n    addResources(\"skills\", collectAutoSkillEntries(userAgentsSkillsDir, \"agents\"), userAgentsMetadata, userOverrides.skills, userAgentsBaseDir);\n    addResources(\"prompts\", collectAutoPromptEntries(userDirs.prompts), userMetadata, userOverrides.prompts, globalBaseDir);\n    addResources(\"themes\", collectAutoThemeEntries(userDirs.themes), userMetadata, userOverrides.themes, globalBaseDir);\n  }\n  collectFilesFromPaths(paths, resourceType) {\n    const files = [];\n    for (const p of paths) {\n      if (!existsSync5(p))\n        continue;\n      try {\n        const stats = statSync4(p);\n        if (stats.isFile()) {\n          files.push(p);\n        } else if (stats.isDirectory()) {\n          files.push(...collectResourceFiles(p, resourceType));\n        }\n      } catch {\n      }\n    }\n    return files;\n  }\n  getTargetMap(accumulator, resourceType) {\n    switch (resourceType) {\n      case \"extensions\":\n        return accumulator.extensions;\n      case \"skills\":\n        return accumulator.skills;\n      case \"prompts\":\n        return accumulator.prompts;\n      case \"themes\":\n        return accumulator.themes;\n      default:\n        throw new Error(`Unknown resource type: ${resourceType}`);\n    }\n  }\n  addResource(map, path12, metadata, enabled) {\n    if (!path12)\n      return;\n    if (!map.has(path12)) {\n      map.set(path12, { metadata, enabled });\n    }\n  }\n  createAccumulator() {\n    return {\n      extensions: /* @__PURE__ */ new Map(),\n      skills: /* @__PURE__ */ new Map(),\n      prompts: /* @__PURE__ */ new Map(),\n      themes: /* @__PURE__ */ new Map()\n    };\n  }\n  toResolvedPaths(accumulator) {\n    const mapToResolved = (entries) => {\n      const resolved = Array.from(entries.entries()).map(([path12, { metadata, enabled }]) => ({\n        path: path12,\n        enabled,\n        metadata\n      }));\n      resolved.sort((a, b) => resourcePrecedenceRank(a.metadata) - resourcePrecedenceRank(b.metadata));\n      const seen = /* @__PURE__ */ new Set();\n      return resolved.filter((entry) => {\n        const canonicalPath = canonicalizePath(entry.path);\n        if (seen.has(canonicalPath))\n          return false;\n        seen.add(canonicalPath);\n        return true;\n      });\n    };\n    return {\n      extensions: mapToResolved(accumulator.extensions),\n      skills: mapToResolved(accumulator.skills),\n      prompts: mapToResolved(accumulator.prompts),\n      themes: mapToResolved(accumulator.themes)\n    };\n  }\n  spawnCommand(command, args, options) {\n    const env = getEnv();\n    return spawnProcess(command, args, {\n      cwd: options?.cwd,\n      stdio: isStdoutTakenOver() ? [\"ignore\", 2, 2] : \"inherit\",\n      env\n    });\n  }\n  spawnCaptureCommand(command, args, options) {\n    const baseEnv = getEnv();\n    const env = options?.env ? { ...baseEnv, ...options.env } : baseEnv;\n    return spawnProcess(command, args, {\n      cwd: options?.cwd,\n      stdio: [\"ignore\", \"pipe\", \"pipe\"],\n      env\n    });\n  }\n  runCommandCapture(command, args, options) {\n    return new Promise((resolvePromise, reject) => {\n      const child = this.spawnCaptureCommand(command, args, options);\n      let stdout = \"\";\n      let stderr = \"\";\n      let timedOut = false;\n      const timeout = typeof options?.timeoutMs === \"number\" ? setTimeout(() => {\n        timedOut = true;\n        child.kill();\n      }, options.timeoutMs) : void 0;\n      child.stdout?.on(\"data\", (data) => {\n        stdout += data.toString();\n      });\n      child.stderr?.on(\"data\", (data) => {\n        stderr += data.toString();\n      });\n      child.once(\"error\", (error) => {\n        if (timeout)\n          clearTimeout(timeout);\n        reject(error);\n      });\n      child.once(\"close\", (code, signal) => {\n        if (timeout)\n          clearTimeout(timeout);\n        if (timedOut) {\n          reject(new Error(`${command} ${args.join(\" \")} timed out after ${options?.timeoutMs}ms`));\n          return;\n        }\n        if (code === 0) {\n          resolvePromise(stdout.trim());\n          return;\n        }\n        const exitStatus = code === null ? `signal ${signal ?? \"unknown\"}` : `code ${code}`;\n        reject(new Error(`${command} ${args.join(\" \")} failed with ${exitStatus}: ${stderr || stdout}`));\n      });\n    });\n  }\n  runCommand(command, args, options) {\n    return new Promise((resolvePromise, reject) => {\n      const child = this.spawnCommand(command, args, options);\n      child.on(\"error\", reject);\n      child.on(\"exit\", (code) => {\n        if (code === 0) {\n          resolvePromise();\n        } else {\n          reject(new Error(`${command} ${args.join(\" \")} failed with code ${code}`));\n        }\n      });\n    });\n  }\n  runCommandSync(command, args) {\n    const env = getEnv();\n    const result = spawnProcessSync(command, args, {\n      stdio: [\"ignore\", \"pipe\", \"pipe\"],\n      encoding: \"utf-8\",\n      env\n    });\n    if (result.error || result.status !== 0) {\n      throw new Error(`Failed to run ${command} ${args.join(\" \")}: ${result.error?.message || result.stderr || result.stdout}`);\n    }\n    return (result.stdout || result.stderr || \"\").trim();\n  }\n};\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/core/settings-manager.js\nimport { randomUUID } from \"crypto\";\nimport { existsSync as existsSync6, mkdirSync as mkdirSync4, readFileSync as readFileSync6, writeFileSync as writeFileSync4 } from \"fs\";\nimport { dirname as dirname10, join as join15 } from \"path\";\nimport lockfile2 from \"proper-lockfile\";\nfunction isMergeableObject(value) {\n  return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\nfunction deepMergeObjects(base, overrides) {\n  const result = { ...base };\n  for (const key of Object.keys(overrides)) {\n    const overrideValue = overrides[key];\n    if (overrideValue === void 0) {\n      continue;\n    }\n    const baseValue = base[key];\n    result[key] = isMergeableObject(baseValue) && isMergeableObject(overrideValue) ? deepMergeObjects(baseValue, overrideValue) : overrideValue;\n  }\n  return result;\n}\nfunction deepMergeSettings(base, overrides) {\n  return deepMergeObjects(base, overrides);\n}\nfunction parseTimeoutSetting(value, settingName) {\n  const timeoutMs = parseHttpIdleTimeoutMs(value);\n  if (timeoutMs !== void 0) {\n    return timeoutMs;\n  }\n  if (value !== void 0) {\n    throw new Error(`Invalid ${settingName} setting: ${String(value)}`);\n  }\n  return void 0;\n}\nvar FileSettingsStorage = class {\n  globalSettingsPath;\n  projectSettingsPath;\n  constructor(cwd, agentDir) {\n    const resolvedCwd = resolvePath(cwd);\n    const resolvedAgentDir = resolvePath(agentDir);\n    this.globalSettingsPath = join15(resolvedAgentDir, \"settings.json\");\n    this.projectSettingsPath = join15(resolvedCwd, CONFIG_DIR_NAME, \"settings.json\");\n  }\n  acquireLockSyncWithRetry(path12) {\n    const maxAttempts = 10;\n    const delayMs = 20;\n    let lastError;\n    for (let attempt = 1; attempt <= maxAttempts; attempt++) {\n      try {\n        return lockfile2.lockSync(path12, { realpath: false });\n      } catch (error) {\n        const code = typeof error === \"object\" && error !== null && \"code\" in error ? String(error.code) : void 0;\n        if (code !== \"ELOCKED\" || attempt === maxAttempts) {\n          throw error;\n        }\n        lastError = error;\n        const start = Date.now();\n        while (Date.now() - start < delayMs) {\n        }\n      }\n    }\n    throw lastError ?? new Error(\"Failed to acquire settings lock\");\n  }\n  withLock(scope, fn) {\n    const path12 = scope === \"global\" ? this.globalSettingsPath : this.projectSettingsPath;\n    const dir = dirname10(path12);\n    let release;\n    try {\n      const fileExists2 = existsSync6(path12);\n      if (fileExists2) {\n        release = this.acquireLockSyncWithRetry(path12);\n      }\n      const current = fileExists2 ? readFileSync6(path12, \"utf-8\") : void 0;\n      const next = fn(current);\n      if (next !== void 0) {\n        if (!existsSync6(dir)) {\n          mkdirSync4(dir, { recursive: true });\n        }\n        if (!release) {\n          release = this.acquireLockSyncWithRetry(path12);\n        }\n        writeFileSync4(path12, next, \"utf-8\");\n      }\n    } finally {\n      if (release) {\n        release();\n      }\n    }\n  }\n};\nvar InMemorySettingsStorage = class {\n  global;\n  project;\n  withLock(scope, fn) {\n    const current = scope === \"global\" ? this.global : this.project;\n    const next = fn(current);\n    if (next !== void 0) {\n      if (scope === \"global\") {\n        this.global = next;\n      } else {\n        this.project = next;\n      }\n    }\n  }\n};\nvar SettingsManager = class _SettingsManager {\n  storage;\n  globalSettings;\n  projectSettings;\n  settings;\n  projectTrusted;\n  modifiedFields = /* @__PURE__ */ new Set();\n  // Track global fields modified during session\n  modifiedNestedFields = /* @__PURE__ */ new Map();\n  // Track global nested field modifications\n  modifiedProjectFields = /* @__PURE__ */ new Set();\n  // Track project fields modified during session\n  modifiedProjectNestedFields = /* @__PURE__ */ new Map();\n  // Track project nested field modifications\n  globalSettingsLoadError = null;\n  // Track if global settings file had parse errors\n  projectSettingsLoadError = null;\n  // Track if project settings file had parse errors\n  writeQueue = Promise.resolve();\n  errors;\n  constructor(storage, initialGlobal, initialProject, globalLoadError = null, projectLoadError = null, initialErrors = [], projectTrusted = true) {\n    this.storage = storage;\n    this.globalSettings = initialGlobal;\n    this.projectSettings = initialProject;\n    this.projectTrusted = projectTrusted;\n    this.globalSettingsLoadError = globalLoadError;\n    this.projectSettingsLoadError = projectLoadError;\n    this.errors = [...initialErrors];\n    this.settings = deepMergeSettings(this.globalSettings, this.projectSettings);\n  }\n  /** Create a SettingsManager that loads from files */\n  static create(cwd, agentDir = getAgentDir(), options = {}) {\n    const storage = new FileSettingsStorage(cwd, agentDir);\n    return _SettingsManager.fromStorage(storage, options);\n  }\n  /** Create a SettingsManager from an arbitrary storage backend */\n  static fromStorage(storage, options = {}) {\n    const projectTrusted = options.projectTrusted ?? true;\n    const globalLoad = _SettingsManager.tryLoadFromStorage(storage, \"global\");\n    const projectLoad = _SettingsManager.tryLoadFromStorage(storage, \"project\", projectTrusted);\n    const initialErrors = [];\n    if (globalLoad.error) {\n      initialErrors.push({ scope: \"global\", error: globalLoad.error });\n    }\n    if (projectLoad.error) {\n      initialErrors.push({ scope: \"project\", error: projectLoad.error });\n    }\n    return new _SettingsManager(storage, globalLoad.settings, projectLoad.settings, globalLoad.error, projectLoad.error, initialErrors, projectTrusted);\n  }\n  /** Create an in-memory SettingsManager (no file I/O) */\n  static inMemory(settings = {}, options = {}) {\n    const storage = new InMemorySettingsStorage();\n    const initialSettings = _SettingsManager.migrateSettings(structuredClone(settings));\n    storage.withLock(\"global\", () => JSON.stringify(initialSettings, null, 2));\n    return _SettingsManager.fromStorage(storage, options);\n  }\n  static loadFromStorage(storage, scope, projectTrusted = true) {\n    if (scope === \"project\" && !projectTrusted) {\n      return {};\n    }\n    let content;\n    storage.withLock(scope, (current) => {\n      content = current;\n      return void 0;\n    });\n    if (!content) {\n      return {};\n    }\n    const settings = JSON.parse(content);\n    return _SettingsManager.migrateSettings(settings);\n  }\n  static tryLoadFromStorage(storage, scope, projectTrusted = true) {\n    try {\n      return { settings: _SettingsManager.loadFromStorage(storage, scope, projectTrusted), error: null };\n    } catch (error) {\n      return { settings: {}, error };\n    }\n  }\n  /** Migrate old settings format to new format */\n  static migrateSettings(settings) {\n    if (\"queueMode\" in settings && !(\"steeringMode\" in settings)) {\n      settings.steeringMode = settings.queueMode;\n      delete settings.queueMode;\n    }\n    if (!(\"transport\" in settings) && typeof settings.websockets === \"boolean\") {\n      settings.transport = settings.websockets ? \"websocket\" : \"sse\";\n      delete settings.websockets;\n    }\n    if (\"skills\" in settings && typeof settings.skills === \"object\" && settings.skills !== null && !Array.isArray(settings.skills)) {\n      const skillsSettings = settings.skills;\n      if (skillsSettings.enableSkillCommands !== void 0 && settings.enableSkillCommands === void 0) {\n        settings.enableSkillCommands = skillsSettings.enableSkillCommands;\n      }\n      if (Array.isArray(skillsSettings.customDirectories) && skillsSettings.customDirectories.length > 0) {\n        settings.skills = skillsSettings.customDirectories;\n      } else {\n        delete settings.skills;\n      }\n    }\n    if (\"retry\" in settings && typeof settings.retry === \"object\" && settings.retry !== null && !Array.isArray(settings.retry)) {\n      const retrySettings = settings.retry;\n      const providerSettings = typeof retrySettings.provider === \"object\" && retrySettings.provider !== null ? retrySettings.provider : void 0;\n      if (typeof retrySettings.maxDelayMs === \"number\" && (providerSettings?.maxRetryDelayMs === void 0 || providerSettings?.maxRetryDelayMs === null)) {\n        retrySettings.provider = {\n          ...providerSettings ?? {},\n          maxRetryDelayMs: retrySettings.maxDelayMs\n        };\n      }\n      delete retrySettings.maxDelayMs;\n    }\n    return settings;\n  }\n  getGlobalSettings() {\n    return structuredClone(this.globalSettings);\n  }\n  getProjectSettings() {\n    return structuredClone(this.projectSettings);\n  }\n  isProjectTrusted() {\n    return this.projectTrusted;\n  }\n  setProjectTrusted(trusted) {\n    if (this.projectTrusted === trusted) {\n      return;\n    }\n    this.projectTrusted = trusted;\n    this.modifiedProjectFields.clear();\n    this.modifiedProjectNestedFields.clear();\n    if (!trusted) {\n      this.projectSettings = {};\n      this.projectSettingsLoadError = null;\n      this.settings = deepMergeSettings(this.globalSettings, this.projectSettings);\n      return;\n    }\n    const projectLoad = _SettingsManager.tryLoadFromStorage(this.storage, \"project\", trusted);\n    this.projectSettings = projectLoad.settings;\n    this.projectSettingsLoadError = projectLoad.error;\n    if (projectLoad.error) {\n      this.recordError(\"project\", projectLoad.error);\n    }\n    this.settings = deepMergeSettings(this.globalSettings, this.projectSettings);\n  }\n  async reload() {\n    await this.writeQueue;\n    const globalLoad = _SettingsManager.tryLoadFromStorage(this.storage, \"global\");\n    if (!globalLoad.error) {\n      this.globalSettings = globalLoad.settings;\n      this.globalSettingsLoadError = null;\n    } else {\n      this.globalSettingsLoadError = globalLoad.error;\n      this.recordError(\"global\", globalLoad.error);\n    }\n    this.modifiedFields.clear();\n    this.modifiedNestedFields.clear();\n    this.modifiedProjectFields.clear();\n    this.modifiedProjectNestedFields.clear();\n    const projectLoad = _SettingsManager.tryLoadFromStorage(this.storage, \"project\", this.projectTrusted);\n    if (!projectLoad.error) {\n      this.projectSettings = projectLoad.settings;\n      this.projectSettingsLoadError = null;\n    } else {\n      this.projectSettingsLoadError = projectLoad.error;\n      this.recordError(\"project\", projectLoad.error);\n    }\n    this.settings = deepMergeSettings(this.globalSettings, this.projectSettings);\n  }\n  /** Apply additional overrides on top of current settings */\n  applyOverrides(overrides) {\n    this.settings = deepMergeSettings(this.settings, overrides);\n  }\n  /** Mark a global field as modified during this session */\n  markModified(field, nestedKey) {\n    this.modifiedFields.add(field);\n    if (nestedKey) {\n      if (!this.modifiedNestedFields.has(field)) {\n        this.modifiedNestedFields.set(field, /* @__PURE__ */ new Set());\n      }\n      this.modifiedNestedFields.get(field).add(nestedKey);\n    }\n  }\n  /** Mark a project field as modified during this session */\n  markProjectModified(field, nestedKey) {\n    this.modifiedProjectFields.add(field);\n    if (nestedKey) {\n      if (!this.modifiedProjectNestedFields.has(field)) {\n        this.modifiedProjectNestedFields.set(field, /* @__PURE__ */ new Set());\n      }\n      this.modifiedProjectNestedFields.get(field).add(nestedKey);\n    }\n  }\n  assertProjectTrustedForWrite() {\n    if (!this.projectTrusted) {\n      throw new Error(\"Project is not trusted; refusing to write project settings\");\n    }\n  }\n  recordError(scope, error) {\n    const normalizedError = error instanceof Error ? error : new Error(String(error));\n    this.errors.push({ scope, error: normalizedError });\n  }\n  clearModifiedScope(scope) {\n    if (scope === \"global\") {\n      this.modifiedFields.clear();\n      this.modifiedNestedFields.clear();\n      return;\n    }\n    this.modifiedProjectFields.clear();\n    this.modifiedProjectNestedFields.clear();\n  }\n  enqueueWrite(scope, task) {\n    this.writeQueue = this.writeQueue.then(() => {\n      if (scope === \"project\") {\n        this.assertProjectTrustedForWrite();\n      }\n      task();\n      this.clearModifiedScope(scope);\n    }).catch((error) => {\n      this.recordError(scope, error);\n    });\n  }\n  cloneModifiedNestedFields(source) {\n    const snapshot = /* @__PURE__ */ new Map();\n    for (const [key, value] of source.entries()) {\n      snapshot.set(key, new Set(value));\n    }\n    return snapshot;\n  }\n  persistScopedSettings(scope, snapshotSettings, modifiedFields, modifiedNestedFields) {\n    this.storage.withLock(scope, (current) => {\n      const currentFileSettings = current ? _SettingsManager.migrateSettings(JSON.parse(current)) : {};\n      const mergedSettings = { ...currentFileSettings };\n      for (const field of modifiedFields) {\n        const value = snapshotSettings[field];\n        if (modifiedNestedFields.has(field) && typeof value === \"object\" && value !== null) {\n          const nestedModified = modifiedNestedFields.get(field);\n          const baseNested = currentFileSettings[field] ?? {};\n          const inMemoryNested = value;\n          const mergedNested = { ...baseNested };\n          for (const nestedKey of nestedModified) {\n            mergedNested[nestedKey] = inMemoryNested[nestedKey];\n          }\n          mergedSettings[field] = mergedNested;\n        } else {\n          mergedSettings[field] = value;\n        }\n      }\n      return JSON.stringify(mergedSettings, null, 2);\n    });\n  }\n  save() {\n    this.settings = deepMergeSettings(this.globalSettings, this.projectSettings);\n    if (this.globalSettingsLoadError) {\n      return;\n    }\n    const snapshotGlobalSettings = structuredClone(this.globalSettings);\n    const modifiedFields = new Set(this.modifiedFields);\n    const modifiedNestedFields = this.cloneModifiedNestedFields(this.modifiedNestedFields);\n    this.enqueueWrite(\"global\", () => {\n      this.persistScopedSettings(\"global\", snapshotGlobalSettings, modifiedFields, modifiedNestedFields);\n    });\n  }\n  saveProjectSettings(settings) {\n    this.assertProjectTrustedForWrite();\n    this.projectSettings = structuredClone(settings);\n    this.settings = deepMergeSettings(this.globalSettings, this.projectSettings);\n    if (this.projectSettingsLoadError) {\n      return;\n    }\n    const snapshotProjectSettings = structuredClone(this.projectSettings);\n    const modifiedFields = new Set(this.modifiedProjectFields);\n    const modifiedNestedFields = this.cloneModifiedNestedFields(this.modifiedProjectNestedFields);\n    this.enqueueWrite(\"project\", () => {\n      this.persistScopedSettings(\"project\", snapshotProjectSettings, modifiedFields, modifiedNestedFields);\n    });\n  }\n  updateProjectSettings(field, update) {\n    this.assertProjectTrustedForWrite();\n    const projectSettings = structuredClone(this.projectSettings);\n    update(projectSettings);\n    this.markProjectModified(field);\n    this.saveProjectSettings(projectSettings);\n  }\n  async flush() {\n    await this.writeQueue;\n  }\n  drainErrors() {\n    const drained = [...this.errors];\n    this.errors = [];\n    return drained;\n  }\n  getLastChangelogVersion() {\n    return this.settings.lastChangelogVersion;\n  }\n  setLastChangelogVersion(version) {\n    this.globalSettings.lastChangelogVersion = version;\n    this.markModified(\"lastChangelogVersion\");\n    this.save();\n  }\n  getSessionDir() {\n    const sessionDir = this.settings.sessionDir;\n    return sessionDir ? normalizePath(sessionDir) : sessionDir;\n  }\n  getDefaultProvider() {\n    return this.settings.defaultProvider;\n  }\n  getDefaultModel() {\n    return this.settings.defaultModel;\n  }\n  setDefaultProvider(provider) {\n    this.globalSettings.defaultProvider = provider;\n    this.markModified(\"defaultProvider\");\n    this.save();\n  }\n  setDefaultModel(modelId) {\n    this.globalSettings.defaultModel = modelId;\n    this.markModified(\"defaultModel\");\n    this.save();\n  }\n  setDefaultModelAndProvider(provider, modelId) {\n    this.globalSettings.defaultProvider = provider;\n    this.globalSettings.defaultModel = modelId;\n    this.markModified(\"defaultProvider\");\n    this.markModified(\"defaultModel\");\n    this.save();\n  }\n  getSteeringMode() {\n    return this.settings.steeringMode || \"one-at-a-time\";\n  }\n  setSteeringMode(mode) {\n    this.globalSettings.steeringMode = mode;\n    this.markModified(\"steeringMode\");\n    this.save();\n  }\n  getFollowUpMode() {\n    return this.settings.followUpMode || \"one-at-a-time\";\n  }\n  setFollowUpMode(mode) {\n    this.globalSettings.followUpMode = mode;\n    this.markModified(\"followUpMode\");\n    this.save();\n  }\n  getThemeSetting() {\n    const value = this.settings.theme;\n    if (typeof value === \"string\")\n      return value;\n    return void 0;\n  }\n  getTheme() {\n    const theme2 = this.getThemeSetting();\n    return theme2?.includes(\"/\") ? void 0 : theme2;\n  }\n  setTheme(theme2) {\n    this.globalSettings.theme = theme2;\n    this.markModified(\"theme\");\n    this.save();\n  }\n  getDefaultThinkingLevel() {\n    return this.settings.defaultThinkingLevel;\n  }\n  setDefaultThinkingLevel(level) {\n    this.globalSettings.defaultThinkingLevel = level;\n    this.markModified(\"defaultThinkingLevel\");\n    this.save();\n  }\n  getTransport() {\n    return this.settings.transport ?? \"auto\";\n  }\n  setTransport(transport) {\n    this.globalSettings.transport = transport;\n    this.markModified(\"transport\");\n    this.save();\n  }\n  getCompactionEnabled() {\n    return this.settings.compaction?.enabled ?? true;\n  }\n  setCompactionEnabled(enabled) {\n    if (!this.globalSettings.compaction) {\n      this.globalSettings.compaction = {};\n    }\n    this.globalSettings.compaction.enabled = enabled;\n    this.markModified(\"compaction\", \"enabled\");\n    this.save();\n  }\n  getCompactionReserveTokens() {\n    return this.settings.compaction?.reserveTokens ?? 16384;\n  }\n  getCompactionKeepRecentTokens() {\n    return this.settings.compaction?.keepRecentTokens ?? 2e4;\n  }\n  getCompactionSettings() {\n    return {\n      enabled: this.getCompactionEnabled(),\n      reserveTokens: this.getCompactionReserveTokens(),\n      keepRecentTokens: this.getCompactionKeepRecentTokens()\n    };\n  }\n  getBranchSummarySettings() {\n    return {\n      reserveTokens: this.settings.branchSummary?.reserveTokens ?? 16384,\n      skipPrompt: this.settings.branchSummary?.skipPrompt ?? false\n    };\n  }\n  getBranchSummarySkipPrompt() {\n    return this.settings.branchSummary?.skipPrompt ?? false;\n  }\n  getRetryEnabled() {\n    return this.settings.retry?.enabled ?? true;\n  }\n  setRetryEnabled(enabled) {\n    if (!this.globalSettings.retry) {\n      this.globalSettings.retry = {};\n    }\n    this.globalSettings.retry.enabled = enabled;\n    this.markModified(\"retry\", \"enabled\");\n    this.save();\n  }\n  getRetrySettings() {\n    return {\n      enabled: this.getRetryEnabled(),\n      maxRetries: this.settings.retry?.maxRetries ?? 3,\n      baseDelayMs: this.settings.retry?.baseDelayMs ?? 2e3\n    };\n  }\n  getHttpIdleTimeoutMs() {\n    return parseTimeoutSetting(this.settings.httpIdleTimeoutMs, \"httpIdleTimeoutMs\") ?? DEFAULT_HTTP_IDLE_TIMEOUT_MS;\n  }\n  setHttpIdleTimeoutMs(timeoutMs) {\n    if (!Number.isFinite(timeoutMs) || timeoutMs < 0) {\n      throw new Error(`Invalid httpIdleTimeoutMs setting: ${String(timeoutMs)}`);\n    }\n    this.globalSettings.httpIdleTimeoutMs = Math.floor(timeoutMs);\n    this.markModified(\"httpIdleTimeoutMs\");\n    this.save();\n  }\n  getProviderRetrySettings() {\n    return {\n      timeoutMs: this.settings.retry?.provider?.timeoutMs,\n      maxRetries: this.settings.retry?.provider?.maxRetries,\n      maxRetryDelayMs: this.settings.retry?.provider?.maxRetryDelayMs ?? 6e4\n    };\n  }\n  getWebSocketConnectTimeoutMs() {\n    return parseTimeoutSetting(this.settings.websocketConnectTimeoutMs, \"websocketConnectTimeoutMs\");\n  }\n  getHideThinkingBlock() {\n    return this.settings.hideThinkingBlock ?? false;\n  }\n  getShowCacheMissNotices() {\n    return this.settings.showCacheMissNotices ?? false;\n  }\n  getExternalEditorCommand() {\n    const configuredEditor = this.settings.externalEditor;\n    if (typeof configuredEditor === \"string\" && configuredEditor.trim() !== \"\") {\n      return configuredEditor;\n    }\n    const environmentEditor = process.env.VISUAL || process.env.EDITOR;\n    if (environmentEditor) {\n      return environmentEditor;\n    }\n    return process.platform === \"win32\" ? \"notepad\" : \"nano\";\n  }\n  setHideThinkingBlock(hide) {\n    this.globalSettings.hideThinkingBlock = hide;\n    this.markModified(\"hideThinkingBlock\");\n    this.save();\n  }\n  setShowCacheMissNotices(show) {\n    this.globalSettings.showCacheMissNotices = show;\n    this.markModified(\"showCacheMissNotices\");\n    this.save();\n  }\n  getShellPath() {\n    const shellPath = this.settings.shellPath;\n    return shellPath ? normalizePath(shellPath) : shellPath;\n  }\n  setShellPath(path12) {\n    this.globalSettings.shellPath = path12;\n    this.markModified(\"shellPath\");\n    this.save();\n  }\n  getQuietStartup() {\n    return this.settings.quietStartup ?? false;\n  }\n  setQuietStartup(quiet) {\n    this.globalSettings.quietStartup = quiet;\n    this.markModified(\"quietStartup\");\n    this.save();\n  }\n  getDefaultProjectTrust() {\n    const value = this.globalSettings.defaultProjectTrust;\n    return value === \"always\" || value === \"never\" ? value : \"ask\";\n  }\n  setDefaultProjectTrust(defaultProjectTrust) {\n    this.globalSettings.defaultProjectTrust = defaultProjectTrust;\n    this.markModified(\"defaultProjectTrust\");\n    this.save();\n  }\n  getShellCommandPrefix() {\n    return this.settings.shellCommandPrefix;\n  }\n  setShellCommandPrefix(prefix) {\n    this.globalSettings.shellCommandPrefix = prefix;\n    this.markModified(\"shellCommandPrefix\");\n    this.save();\n  }\n  getNpmCommand() {\n    return this.settings.npmCommand ? [...this.settings.npmCommand] : void 0;\n  }\n  setNpmCommand(command) {\n    this.globalSettings.npmCommand = command ? [...command] : void 0;\n    this.markModified(\"npmCommand\");\n    this.save();\n  }\n  getCollapseChangelog() {\n    return this.settings.collapseChangelog ?? false;\n  }\n  setCollapseChangelog(collapse) {\n    this.globalSettings.collapseChangelog = collapse;\n    this.markModified(\"collapseChangelog\");\n    this.save();\n  }\n  getEnableInstallTelemetry() {\n    return this.settings.enableInstallTelemetry ?? true;\n  }\n  setEnableInstallTelemetry(enabled) {\n    this.globalSettings.enableInstallTelemetry = enabled;\n    this.markModified(\"enableInstallTelemetry\");\n    this.save();\n  }\n  getEnableAnalytics() {\n    return this.settings.enableAnalytics ?? false;\n  }\n  getTrackingId() {\n    return this.settings.trackingId;\n  }\n  /** Set the analytics opt-in preference; generates a tracking identifier on first opt-in */\n  setEnableAnalytics(enabled) {\n    this.globalSettings.enableAnalytics = enabled;\n    this.markModified(\"enableAnalytics\");\n    if (enabled && !this.globalSettings.trackingId) {\n      this.globalSettings.trackingId = randomUUID();\n      this.markModified(\"trackingId\");\n    }\n    this.save();\n  }\n  getPackages() {\n    return [...this.settings.packages ?? []];\n  }\n  setPackages(packages) {\n    this.globalSettings.packages = packages;\n    this.markModified(\"packages\");\n    this.save();\n  }\n  setProjectPackages(packages) {\n    this.updateProjectSettings(\"packages\", (settings) => {\n      settings.packages = packages;\n    });\n  }\n  getExtensionPaths() {\n    return [...this.settings.extensions ?? []];\n  }\n  setExtensionPaths(paths) {\n    this.globalSettings.extensions = paths;\n    this.markModified(\"extensions\");\n    this.save();\n  }\n  setProjectExtensionPaths(paths) {\n    this.updateProjectSettings(\"extensions\", (settings) => {\n      settings.extensions = paths;\n    });\n  }\n  getSkillPaths() {\n    return [...this.settings.skills ?? []];\n  }\n  setSkillPaths(paths) {\n    this.globalSettings.skills = paths;\n    this.markModified(\"skills\");\n    this.save();\n  }\n  setProjectSkillPaths(paths) {\n    this.updateProjectSettings(\"skills\", (settings) => {\n      settings.skills = paths;\n    });\n  }\n  getPromptTemplatePaths() {\n    return [...this.settings.prompts ?? []];\n  }\n  setPromptTemplatePaths(paths) {\n    this.globalSettings.prompts = paths;\n    this.markModified(\"prompts\");\n    this.save();\n  }\n  setProjectPromptTemplatePaths(paths) {\n    this.updateProjectSettings(\"prompts\", (settings) => {\n      settings.prompts = paths;\n    });\n  }\n  getThemePaths() {\n    return [...this.settings.themes ?? []];\n  }\n  setThemePaths(paths) {\n    this.globalSettings.themes = paths;\n    this.markModified(\"themes\");\n    this.save();\n  }\n  setProjectThemePaths(paths) {\n    this.updateProjectSettings(\"themes\", (settings) => {\n      settings.themes = paths;\n    });\n  }\n  getEnableSkillCommands() {\n    return this.settings.enableSkillCommands ?? true;\n  }\n  setEnableSkillCommands(enabled) {\n    this.globalSettings.enableSkillCommands = enabled;\n    this.markModified(\"enableSkillCommands\");\n    this.save();\n  }\n  getThinkingBudgets() {\n    return this.settings.thinkingBudgets;\n  }\n  getShowImages() {\n    return this.settings.terminal?.showImages ?? true;\n  }\n  setShowImages(show) {\n    if (!this.globalSettings.terminal) {\n      this.globalSettings.terminal = {};\n    }\n    this.globalSettings.terminal.showImages = show;\n    this.markModified(\"terminal\", \"showImages\");\n    this.save();\n  }\n  getImageWidthCells() {\n    const width = this.settings.terminal?.imageWidthCells;\n    if (typeof width !== \"number\" || !Number.isFinite(width)) {\n      return 60;\n    }\n    return Math.max(1, Math.floor(width));\n  }\n  setImageWidthCells(width) {\n    if (!this.globalSettings.terminal) {\n      this.globalSettings.terminal = {};\n    }\n    this.globalSettings.terminal.imageWidthCells = Math.max(1, Math.floor(width));\n    this.markModified(\"terminal\", \"imageWidthCells\");\n    this.save();\n  }\n  getClearOnShrink() {\n    if (this.settings.terminal?.clearOnShrink !== void 0) {\n      return this.settings.terminal.clearOnShrink;\n    }\n    return process.env.PI_CLEAR_ON_SHRINK === \"1\";\n  }\n  setClearOnShrink(enabled) {\n    if (!this.globalSettings.terminal) {\n      this.globalSettings.terminal = {};\n    }\n    this.globalSettings.terminal.clearOnShrink = enabled;\n    this.markModified(\"terminal\", \"clearOnShrink\");\n    this.save();\n  }\n  getShowTerminalProgress() {\n    return this.settings.terminal?.showTerminalProgress ?? false;\n  }\n  setShowTerminalProgress(enabled) {\n    if (!this.globalSettings.terminal) {\n      this.globalSettings.terminal = {};\n    }\n    this.globalSettings.terminal.showTerminalProgress = enabled;\n    this.markModified(\"terminal\", \"showTerminalProgress\");\n    this.save();\n  }\n  getTuiMode() {\n    return this.settings.tuiMode === \"fullscreen\" ? \"fullscreen\" : \"regular\";\n  }\n  setTuiMode(mode) {\n    this.globalSettings.tuiMode = mode;\n    this.markModified(\"tuiMode\");\n    this.save();\n  }\n  getFullscreenExitOutput() {\n    return this.settings.fullscreenExitOutput === \"resume-hint\" ? \"resume-hint\" : \"transcript\";\n  }\n  setFullscreenExitOutput(output) {\n    this.globalSettings.fullscreenExitOutput = output;\n    this.markModified(\"fullscreenExitOutput\");\n    this.save();\n  }\n  getFullscreenScrollbar() {\n    const mode = this.settings.fullscreenScrollbar;\n    return mode === \"always\" || mode === \"hidden\" ? mode : \"auto\";\n  }\n  setFullscreenScrollbar(mode) {\n    this.globalSettings.fullscreenScrollbar = mode;\n    this.markModified(\"fullscreenScrollbar\");\n    this.save();\n  }\n  getImageAutoResize() {\n    return this.settings.images?.autoResize ?? true;\n  }\n  setImageAutoResize(enabled) {\n    if (!this.globalSettings.images) {\n      this.globalSettings.images = {};\n    }\n    this.globalSettings.images.autoResize = enabled;\n    this.markModified(\"images\", \"autoResize\");\n    this.save();\n  }\n  getBlockImages() {\n    return this.settings.images?.blockImages ?? false;\n  }\n  setBlockImages(blocked) {\n    if (!this.globalSettings.images) {\n      this.globalSettings.images = {};\n    }\n    this.globalSettings.images.blockImages = blocked;\n    this.markModified(\"images\", \"blockImages\");\n    this.save();\n  }\n  getEnabledModels() {\n    return this.settings.enabledModels;\n  }\n  getDefaultTools() {\n    const tools = this.settings.defaultTools;\n    return tools ? [...tools] : void 0;\n  }\n  setEnabledModels(patterns) {\n    this.globalSettings.enabledModels = patterns;\n    this.markModified(\"enabledModels\");\n    this.save();\n  }\n  getDoubleEscapeAction() {\n    return this.settings.doubleEscapeAction ?? \"tree\";\n  }\n  setDoubleEscapeAction(action) {\n    this.globalSettings.doubleEscapeAction = action;\n    this.markModified(\"doubleEscapeAction\");\n    this.save();\n  }\n  getTreeFilterMode() {\n    const mode = this.settings.treeFilterMode;\n    const valid3 = [\"default\", \"no-tools\", \"user-only\", \"labeled-only\", \"all\"];\n    return mode && valid3.includes(mode) ? mode : \"default\";\n  }\n  setTreeFilterMode(mode) {\n    this.globalSettings.treeFilterMode = mode;\n    this.markModified(\"treeFilterMode\");\n    this.save();\n  }\n  getShowHardwareCursor() {\n    return this.settings.showHardwareCursor ?? process.env.PI_HARDWARE_CURSOR === \"1\";\n  }\n  setShowHardwareCursor(enabled) {\n    this.globalSettings.showHardwareCursor = enabled;\n    this.markModified(\"showHardwareCursor\");\n    this.save();\n  }\n  getEditorPaddingX() {\n    return this.settings.editorPaddingX ?? 0;\n  }\n  setEditorPaddingX(padding) {\n    this.globalSettings.editorPaddingX = Math.max(0, Math.min(3, Math.floor(padding)));\n    this.markModified(\"editorPaddingX\");\n    this.save();\n  }\n  getOutputPad() {\n    return this.settings.outputPad === 0 ? 0 : 1;\n  }\n  setOutputPad(padding) {\n    this.globalSettings.outputPad = padding;\n    this.markModified(\"outputPad\");\n    this.save();\n  }\n  getAutocompleteMaxVisible() {\n    return this.settings.autocompleteMaxVisible ?? 5;\n  }\n  setAutocompleteMaxVisible(maxVisible) {\n    this.globalSettings.autocompleteMaxVisible = Math.max(3, Math.min(20, Math.floor(maxVisible)));\n    this.markModified(\"autocompleteMaxVisible\");\n    this.save();\n  }\n  getCodeBlockIndent() {\n    return this.settings.markdown?.codeBlockIndent ?? \"  \";\n  }\n  getMermaidRenderingMode() {\n    const mode = this.settings.markdown?.mermaid;\n    return mode === \"off\" || mode === \"final\" ? mode : \"streaming\";\n  }\n  setMermaidRenderingMode(mode) {\n    this.globalSettings.markdown ??= {};\n    this.globalSettings.markdown.mermaid = mode;\n    this.markModified(\"markdown\", \"mermaid\");\n    this.save();\n  }\n  getWarnings() {\n    return { ...this.settings.warnings ?? {} };\n  }\n  setWarnings(warnings) {\n    this.globalSettings.warnings = { ...warnings };\n    this.markModified(\"warnings\");\n    this.save();\n  }\n};\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/theme/theme.js\nimport * as fs4 from \"node:fs\";\nimport * as path6 from \"node:path\";\nimport chalk5 from \"chalk\";\nimport { Type as Type4 } from \"typebox\";\nimport { Compile as Compile3 } from \"typebox/compile\";\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/utils/fs-watch.js\nimport { watch } from \"node:fs\";\nvar FS_WATCH_RETRY_DELAY_MS = 5e3;\nfunction closeWatcher(watcher) {\n  if (!watcher) {\n    return;\n  }\n  try {\n    watcher.close();\n  } catch {\n  }\n}\nfunction watchWithErrorHandler(path12, listener, onError) {\n  try {\n    const watcher = watch(path12, listener);\n    watcher.on(\"error\", onError);\n    return watcher;\n  } catch {\n    onError();\n    return null;\n  }\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/utils/syntax-highlight.js\nimport hljs from \"highlight.js/lib/index.js\";\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/utils/html.js\nfunction decodeCodePoint(codePoint) {\n  if (!Number.isInteger(codePoint) || codePoint < 0 || codePoint > 1114111) {\n    return void 0;\n  }\n  return String.fromCodePoint(codePoint);\n}\nfunction decodeHtmlEntity(entity) {\n  switch (entity) {\n    case \"amp\":\n      return \"&\";\n    case \"lt\":\n      return \"<\";\n    case \"gt\":\n      return \">\";\n    case \"quot\":\n      return '\"';\n    case \"apos\":\n      return \"'\";\n  }\n  if (entity.startsWith(\"#x\") || entity.startsWith(\"#X\")) {\n    return decodeCodePoint(Number.parseInt(entity.slice(2), 16));\n  }\n  if (entity.startsWith(\"#\")) {\n    return decodeCodePoint(Number.parseInt(entity.slice(1), 10));\n  }\n  return void 0;\n}\nfunction decodeHtmlEntityAt(html, index) {\n  const semicolonIndex = html.indexOf(\";\", index + 1);\n  if (semicolonIndex === -1 || semicolonIndex - index > 16) {\n    return void 0;\n  }\n  const entity = html.slice(index + 1, semicolonIndex);\n  const decoded = decodeHtmlEntity(entity);\n  if (decoded === void 0) {\n    return void 0;\n  }\n  return { text: decoded, length: semicolonIndex - index + 1 };\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/utils/syntax-highlight.js\nvar SPAN_CLOSE = \"</span>\";\nvar HIGHLIGHT_CLASS_PREFIX = \"hljs-\";\nfunction getScopeFromSpanTag(tag) {\n  const match = /\\sclass\\s*=\\s*(?:\"([^\"]*)\"|'([^']*)')/.exec(tag);\n  const classValue = match?.[1] ?? match?.[2];\n  if (!classValue) {\n    return void 0;\n  }\n  for (const className of classValue.split(/\\s+/)) {\n    if (className.startsWith(HIGHLIGHT_CLASS_PREFIX)) {\n      return className.slice(HIGHLIGHT_CLASS_PREFIX.length);\n    }\n  }\n  return void 0;\n}\nfunction getScopeFormatter(scope, theme2) {\n  const exact = theme2[scope];\n  if (exact) {\n    return exact;\n  }\n  const dotIndex = scope.indexOf(\".\");\n  if (dotIndex !== -1) {\n    const prefixFormatter = theme2[scope.slice(0, dotIndex)];\n    if (prefixFormatter) {\n      return prefixFormatter;\n    }\n  }\n  const dashIndex = scope.indexOf(\"-\");\n  if (dashIndex !== -1) {\n    const prefixFormatter = theme2[scope.slice(0, dashIndex)];\n    if (prefixFormatter) {\n      return prefixFormatter;\n    }\n  }\n  return void 0;\n}\nfunction getActiveFormatter(scopes, theme2) {\n  for (let i = scopes.length - 1; i >= 0; i--) {\n    const scope = scopes[i];\n    if (!scope) {\n      continue;\n    }\n    const formatter = getScopeFormatter(scope, theme2);\n    if (formatter) {\n      return formatter;\n    }\n  }\n  return theme2.default;\n}\nfunction isSpanOpenTagStart(html, index) {\n  if (!html.startsWith(\"<span\", index)) {\n    return false;\n  }\n  const nextChar = html[index + \"<span\".length];\n  return nextChar === \">\" || nextChar === \" \" || nextChar === \"\t\" || nextChar === \"\\n\" || nextChar === \"\\r\";\n}\nfunction renderHighlightedHtml(html, theme2 = {}) {\n  let output = \"\";\n  let textBuffer = \"\";\n  const scopes = [];\n  const flushText = () => {\n    if (!textBuffer) {\n      return;\n    }\n    const formatter = getActiveFormatter(scopes, theme2);\n    output += formatter ? formatter(textBuffer) : textBuffer;\n    textBuffer = \"\";\n  };\n  let index = 0;\n  while (index < html.length) {\n    if (isSpanOpenTagStart(html, index)) {\n      const tagEndIndex = html.indexOf(\">\", index + 5);\n      if (tagEndIndex !== -1) {\n        flushText();\n        const tag = html.slice(index, tagEndIndex + 1);\n        const scope = getScopeFromSpanTag(tag);\n        scopes.push(scope);\n        index = tagEndIndex + 1;\n        continue;\n      }\n    }\n    if (html.startsWith(SPAN_CLOSE, index)) {\n      flushText();\n      if (scopes.length > 0) {\n        scopes.pop();\n      }\n      index += SPAN_CLOSE.length;\n      continue;\n    }\n    if (html[index] === \"&\") {\n      const decoded = decodeHtmlEntityAt(html, index);\n      if (decoded) {\n        textBuffer += decoded.text;\n        index += decoded.length;\n        continue;\n      }\n    }\n    textBuffer += html[index];\n    index++;\n  }\n  flushText();\n  return output;\n}\nfunction highlight(code, options = {}) {\n  const html = options.language ? hljs.highlight(code, {\n    language: options.language,\n    ignoreIllegals: options.ignoreIllegals\n  }).value : hljs.highlightAuto(code, options.languageSubset).value;\n  return renderHighlightedHtml(html, options.theme);\n}\nfunction supportsLanguage(name) {\n  return hljs.getLanguage(name) !== void 0;\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/theme/theme.js\nvar ColorValueSchema = Type4.Union([\n  Type4.String(),\n  // hex \"#ff0000\", var ref \"primary\", or empty \"\"\n  Type4.Integer({ minimum: 0, maximum: 255 })\n  // 256-color index\n]);\nvar ThemeJsonSchema = Type4.Object({\n  $schema: Type4.Optional(Type4.String()),\n  name: Type4.String(),\n  vars: Type4.Optional(Type4.Record(Type4.String(), ColorValueSchema)),\n  colors: Type4.Object({\n    // Core UI (10 colors)\n    accent: ColorValueSchema,\n    border: ColorValueSchema,\n    borderAccent: ColorValueSchema,\n    borderMuted: ColorValueSchema,\n    success: ColorValueSchema,\n    error: ColorValueSchema,\n    warning: ColorValueSchema,\n    muted: ColorValueSchema,\n    dim: ColorValueSchema,\n    text: ColorValueSchema,\n    thinkingText: ColorValueSchema,\n    // Backgrounds & Content Text (11 required, 3 optional)\n    selectedBg: ColorValueSchema,\n    scrollbarThumb: Type4.Optional(ColorValueSchema),\n    searchMatchBg: Type4.Optional(ColorValueSchema),\n    searchMatchText: Type4.Optional(ColorValueSchema),\n    userMessageBg: ColorValueSchema,\n    userMessageText: ColorValueSchema,\n    customMessageBg: ColorValueSchema,\n    customMessageText: ColorValueSchema,\n    customMessageLabel: ColorValueSchema,\n    toolPendingBg: ColorValueSchema,\n    toolSuccessBg: ColorValueSchema,\n    toolErrorBg: ColorValueSchema,\n    toolTitle: ColorValueSchema,\n    toolOutput: ColorValueSchema,\n    // Markdown (10 colors)\n    mdHeading: ColorValueSchema,\n    mdLink: ColorValueSchema,\n    mdLinkUrl: ColorValueSchema,\n    mdCode: ColorValueSchema,\n    mdCodeBlock: ColorValueSchema,\n    mdCodeBlockBorder: ColorValueSchema,\n    mdQuote: ColorValueSchema,\n    mdQuoteBorder: ColorValueSchema,\n    mdHr: ColorValueSchema,\n    mdListBullet: ColorValueSchema,\n    // Tool Diffs (3 colors)\n    toolDiffAdded: ColorValueSchema,\n    toolDiffRemoved: ColorValueSchema,\n    toolDiffContext: ColorValueSchema,\n    // Syntax Highlighting (9 colors)\n    syntaxComment: ColorValueSchema,\n    syntaxKeyword: ColorValueSchema,\n    syntaxFunction: ColorValueSchema,\n    syntaxVariable: ColorValueSchema,\n    syntaxString: ColorValueSchema,\n    syntaxNumber: ColorValueSchema,\n    syntaxType: ColorValueSchema,\n    syntaxOperator: ColorValueSchema,\n    syntaxPunctuation: ColorValueSchema,\n    // Thinking Level Borders (6 colors)\n    thinkingOff: ColorValueSchema,\n    thinkingMinimal: ColorValueSchema,\n    thinkingLow: ColorValueSchema,\n    thinkingMedium: ColorValueSchema,\n    thinkingHigh: ColorValueSchema,\n    thinkingXhigh: ColorValueSchema,\n    thinkingMax: Type4.Optional(ColorValueSchema),\n    // Bash Mode (1 color)\n    bashMode: ColorValueSchema\n  }),\n  export: Type4.Optional(Type4.Object({\n    pageBg: Type4.Optional(ColorValueSchema),\n    cardBg: Type4.Optional(ColorValueSchema),\n    infoBg: Type4.Optional(ColorValueSchema)\n  }))\n});\nvar validateThemeJson = Compile3(ThemeJsonSchema);\nfunction hexToRgb2(hex) {\n  const cleaned = hex.replace(\"#\", \"\");\n  if (cleaned.length !== 6) {\n    throw new Error(`Invalid hex color: ${hex}`);\n  }\n  const r = parseInt(cleaned.substring(0, 2), 16);\n  const g = parseInt(cleaned.substring(2, 4), 16);\n  const b = parseInt(cleaned.substring(4, 6), 16);\n  if (Number.isNaN(r) || Number.isNaN(g) || Number.isNaN(b)) {\n    throw new Error(`Invalid hex color: ${hex}`);\n  }\n  return { r, g, b };\n}\nvar CUBE_VALUES = [0, 95, 135, 175, 215, 255];\nvar GRAY_VALUES = Array.from({ length: 24 }, (_, i) => 8 + i * 10);\nfunction findClosestCubeIndex(value) {\n  let minDist = Infinity;\n  let minIdx = 0;\n  for (let i = 0; i < CUBE_VALUES.length; i++) {\n    const dist = Math.abs(value - CUBE_VALUES[i]);\n    if (dist < minDist) {\n      minDist = dist;\n      minIdx = i;\n    }\n  }\n  return minIdx;\n}\nfunction findClosestGrayIndex(gray) {\n  let minDist = Infinity;\n  let minIdx = 0;\n  for (let i = 0; i < GRAY_VALUES.length; i++) {\n    const dist = Math.abs(gray - GRAY_VALUES[i]);\n    if (dist < minDist) {\n      minDist = dist;\n      minIdx = i;\n    }\n  }\n  return minIdx;\n}\nfunction colorDistance(r1, g1, b1, r2, g2, b2) {\n  const dr = r1 - r2;\n  const dg = g1 - g2;\n  const db = b1 - b2;\n  return dr * dr * 0.299 + dg * dg * 0.587 + db * db * 0.114;\n}\nfunction rgbTo256(r, g, b) {\n  const rIdx = findClosestCubeIndex(r);\n  const gIdx = findClosestCubeIndex(g);\n  const bIdx = findClosestCubeIndex(b);\n  const cubeR = CUBE_VALUES[rIdx];\n  const cubeG = CUBE_VALUES[gIdx];\n  const cubeB = CUBE_VALUES[bIdx];\n  const cubeIndex = 16 + 36 * rIdx + 6 * gIdx + bIdx;\n  const cubeDist = colorDistance(r, g, b, cubeR, cubeG, cubeB);\n  const gray = Math.round(0.299 * r + 0.587 * g + 0.114 * b);\n  const grayIdx = findClosestGrayIndex(gray);\n  const grayValue = GRAY_VALUES[grayIdx];\n  const grayIndex = 232 + grayIdx;\n  const grayDist = colorDistance(r, g, b, grayValue, grayValue, grayValue);\n  const maxC = Math.max(r, g, b);\n  const minC = Math.min(r, g, b);\n  const spread = maxC - minC;\n  if (spread < 10 && grayDist < cubeDist) {\n    return grayIndex;\n  }\n  return cubeIndex;\n}\nfunction hexTo256(hex) {\n  const { r, g, b } = hexToRgb2(hex);\n  return rgbTo256(r, g, b);\n}\nfunction fgAnsi(color, mode) {\n  if (color === \"\")\n    return \"\\x1B[39m\";\n  if (typeof color === \"number\")\n    return `\\x1B[38;5;${color}m`;\n  if (color.startsWith(\"#\")) {\n    if (mode === \"truecolor\") {\n      const { r, g, b } = hexToRgb2(color);\n      return `\\x1B[38;2;${r};${g};${b}m`;\n    } else {\n      const index = hexTo256(color);\n      return `\\x1B[38;5;${index}m`;\n    }\n  }\n  throw new Error(`Invalid color value: ${color}`);\n}\nfunction bgAnsi(color, mode) {\n  if (color === \"\")\n    return \"\\x1B[49m\";\n  if (typeof color === \"number\")\n    return `\\x1B[48;5;${color}m`;\n  if (color.startsWith(\"#\")) {\n    if (mode === \"truecolor\") {\n      const { r, g, b } = hexToRgb2(color);\n      return `\\x1B[48;2;${r};${g};${b}m`;\n    } else {\n      const index = hexTo256(color);\n      return `\\x1B[48;5;${index}m`;\n    }\n  }\n  throw new Error(`Invalid color value: ${color}`);\n}\nfunction resolveVarRefs(value, vars, visited = /* @__PURE__ */ new Set()) {\n  if (typeof value === \"number\" || value === \"\" || value.startsWith(\"#\")) {\n    return value;\n  }\n  if (visited.has(value)) {\n    throw new Error(`Circular variable reference detected: ${value}`);\n  }\n  if (!(value in vars)) {\n    throw new Error(`Variable reference not found: ${value}`);\n  }\n  visited.add(value);\n  return resolveVarRefs(vars[value], vars, visited);\n}\nfunction resolveThemeColors(colors, vars = {}) {\n  const resolved = {};\n  for (const [key, value] of Object.entries(colors)) {\n    resolved[key] = resolveVarRefs(value, vars);\n  }\n  return resolved;\n}\nfunction withThemeColorFallbacks(colors) {\n  return {\n    ...colors,\n    thinkingMax: colors.thinkingMax ?? colors.thinkingXhigh,\n    scrollbarThumb: colors.scrollbarThumb ?? colors.selectedBg,\n    searchMatchBg: colors.searchMatchBg ?? colors.selectedBg,\n    searchMatchText: colors.searchMatchText ?? colors.text\n  };\n}\nvar Theme = class {\n  name;\n  sourcePath;\n  sourceInfo;\n  fgColors;\n  bgColors;\n  mode;\n  constructor(fgColors, bgColors, mode, options = {}) {\n    this.name = options.name;\n    this.sourcePath = options.sourcePath;\n    this.sourceInfo = options.sourceInfo;\n    this.mode = mode;\n    this.fgColors = /* @__PURE__ */ new Map();\n    const colors = {\n      ...fgColors,\n      thinkingMax: fgColors.thinkingMax ?? fgColors.thinkingXhigh,\n      searchMatchText: fgColors.searchMatchText ?? fgColors.text\n    };\n    for (const [key, value] of Object.entries(colors)) {\n      this.fgColors.set(key, fgAnsi(value, mode));\n    }\n    this.bgColors = /* @__PURE__ */ new Map();\n    const backgrounds = {\n      ...bgColors,\n      scrollbarThumb: bgColors.scrollbarThumb ?? bgColors.selectedBg,\n      searchMatchBg: bgColors.searchMatchBg ?? bgColors.selectedBg\n    };\n    for (const [key, value] of Object.entries(backgrounds)) {\n      this.bgColors.set(key, bgAnsi(value, mode));\n    }\n  }\n  fg(color, text) {\n    const ansi = this.fgColors.get(color);\n    if (!ansi)\n      throw new Error(`Unknown theme color: ${color}`);\n    return `${ansi}${text}\\x1B[39m`;\n  }\n  bg(color, text) {\n    const ansi = this.bgColors.get(color);\n    if (!ansi)\n      throw new Error(`Unknown theme background color: ${color}`);\n    return `${ansi}${text}\\x1B[49m`;\n  }\n  bold(text) {\n    return chalk5.bold(text);\n  }\n  italic(text) {\n    return chalk5.italic(text);\n  }\n  underline(text) {\n    return chalk5.underline(text);\n  }\n  inverse(text) {\n    return chalk5.inverse(text);\n  }\n  strikethrough(text) {\n    return chalk5.strikethrough(text);\n  }\n  getFgAnsi(color) {\n    const ansi = this.fgColors.get(color);\n    if (!ansi)\n      throw new Error(`Unknown theme color: ${color}`);\n    return ansi;\n  }\n  getBgAnsi(color) {\n    const ansi = this.bgColors.get(color);\n    if (!ansi)\n      throw new Error(`Unknown theme background color: ${color}`);\n    return ansi;\n  }\n  getColorMode() {\n    return this.mode;\n  }\n  getThinkingBorderColor(level) {\n    switch (level) {\n      case \"off\":\n        return (str2) => this.fg(\"thinkingOff\", str2);\n      case \"minimal\":\n        return (str2) => this.fg(\"thinkingMinimal\", str2);\n      case \"low\":\n        return (str2) => this.fg(\"thinkingLow\", str2);\n      case \"medium\":\n        return (str2) => this.fg(\"thinkingMedium\", str2);\n      case \"high\":\n        return (str2) => this.fg(\"thinkingHigh\", str2);\n      case \"xhigh\":\n        return (str2) => this.fg(\"thinkingXhigh\", str2);\n      case \"max\":\n        return (str2) => this.fg(\"thinkingMax\", str2);\n      default:\n        return (str2) => this.fg(\"thinkingOff\", str2);\n    }\n  }\n  getBashModeBorderColor() {\n    return (str2) => this.fg(\"bashMode\", str2);\n  }\n};\nvar BUILTIN_THEMES;\nfunction getBuiltinThemes() {\n  if (!BUILTIN_THEMES) {\n    const themesDir = getThemesDir();\n    const darkPath = path6.join(themesDir, \"dark.json\");\n    const lightPath = path6.join(themesDir, \"light.json\");\n    BUILTIN_THEMES = {\n      dark: JSON.parse(fs4.readFileSync(darkPath, \"utf-8\")),\n      light: JSON.parse(fs4.readFileSync(lightPath, \"utf-8\"))\n    };\n  }\n  return BUILTIN_THEMES;\n}\nfunction getAvailableThemes() {\n  return getAvailableThemesWithPaths().map(({ name }) => name);\n}\nfunction getAvailableThemesWithPaths() {\n  const themesDir = getThemesDir();\n  const result = [];\n  const seen = /* @__PURE__ */ new Set();\n  const addTheme = (themeInfo) => {\n    if (seen.has(themeInfo.name)) {\n      return;\n    }\n    seen.add(themeInfo.name);\n    result.push(themeInfo);\n  };\n  for (const name of Object.keys(getBuiltinThemes())) {\n    addTheme({ name, path: path6.join(themesDir, `${name}.json`) });\n  }\n  for (const themeInfo of getCustomThemeInfos()) {\n    addTheme(themeInfo);\n  }\n  for (const [name, theme2] of registeredThemes.entries()) {\n    addTheme({ name, path: theme2.sourcePath });\n  }\n  return result.sort((a, b) => a.name.localeCompare(b.name));\n}\nfunction getCustomThemeInfos() {\n  const customThemesDir = getCustomThemesDir();\n  const result = [];\n  if (!fs4.existsSync(customThemesDir)) {\n    return result;\n  }\n  for (const file of fs4.readdirSync(customThemesDir)) {\n    if (!file.endsWith(\".json\")) {\n      continue;\n    }\n    const themePath = path6.join(customThemesDir, file);\n    try {\n      const customTheme = loadThemeFromPath(themePath);\n      if (customTheme.name) {\n        result.push({ name: customTheme.name, path: themePath });\n      }\n    } catch {\n    }\n  }\n  return result;\n}\nfunction assertThemeNameIsValid(name) {\n  if (name.includes(\"/\")) {\n    throw new Error(`Invalid theme name \"${name}\": theme names cannot contain \"/\" because it is reserved for automatic light/dark theme settings.`);\n  }\n}\nfunction parseThemeJson(label, json) {\n  if (!validateThemeJson.Check(json)) {\n    const errors = Array.from(validateThemeJson.Errors(json));\n    const missingColors = /* @__PURE__ */ new Set();\n    const otherErrors = [];\n    for (const error of errors) {\n      if (error.keyword === \"required\" && error.instancePath === \"/colors\") {\n        const requiredProperties = error.params.requiredProperties;\n        for (const requiredProperty of requiredProperties ?? []) {\n          missingColors.add(requiredProperty);\n        }\n        continue;\n      }\n      const path12 = error.instancePath || \"/\";\n      otherErrors.push(`  - ${path12}: ${error.message}`);\n    }\n    let errorMessage2 = `Invalid theme \"${label}\":\n`;\n    if (missingColors.size > 0) {\n      errorMessage2 += \"\\nMissing required color tokens:\\n\";\n      errorMessage2 += Array.from(missingColors).sort().map((color) => `  - ${color}`).join(\"\\n\");\n      errorMessage2 += `\n\nPlease add these colors to your theme's \"colors\" object.`;\n      errorMessage2 += \"\\nSee the built-in themes (dark.json, light.json) for reference values.\";\n    }\n    if (otherErrors.length > 0) {\n      errorMessage2 += `\n\nOther errors:\n${otherErrors.join(\"\\n\")}`;\n    }\n    throw new Error(errorMessage2);\n  }\n  const themeJson = json;\n  assertThemeNameIsValid(themeJson.name);\n  return themeJson;\n}\nfunction parseThemeJsonContent(label, content) {\n  let json;\n  try {\n    json = JSON.parse(content);\n  } catch (error) {\n    throw new Error(`Failed to parse theme ${label}: ${error}`);\n  }\n  return parseThemeJson(label, json);\n}\nfunction loadThemeJson(name) {\n  const builtinThemes = getBuiltinThemes();\n  if (name in builtinThemes) {\n    return builtinThemes[name];\n  }\n  const registeredTheme = registeredThemes.get(name);\n  if (registeredTheme?.sourcePath) {\n    const content2 = fs4.readFileSync(registeredTheme.sourcePath, \"utf-8\");\n    return parseThemeJsonContent(registeredTheme.sourcePath, content2);\n  }\n  if (registeredTheme) {\n    throw new Error(`Theme \"${name}\" does not have a source path for export`);\n  }\n  const customThemesDir = getCustomThemesDir();\n  const themePath = path6.join(customThemesDir, `${name}.json`);\n  if (!fs4.existsSync(themePath)) {\n    throw new Error(`Theme not found: ${name}`);\n  }\n  const content = fs4.readFileSync(themePath, \"utf-8\");\n  return parseThemeJsonContent(name, content);\n}\nfunction createTheme(themeJson, mode, sourcePath) {\n  const colorMode = mode ?? (getCapabilities().trueColor ? \"truecolor\" : \"256color\");\n  const resolvedColors = resolveThemeColors(withThemeColorFallbacks(themeJson.colors), themeJson.vars);\n  const fgColors = {};\n  const bgColors = {};\n  const bgColorKeys = /* @__PURE__ */ new Set([\n    \"selectedBg\",\n    \"scrollbarThumb\",\n    \"searchMatchBg\",\n    \"userMessageBg\",\n    \"customMessageBg\",\n    \"toolPendingBg\",\n    \"toolSuccessBg\",\n    \"toolErrorBg\"\n  ]);\n  for (const [key, value] of Object.entries(resolvedColors)) {\n    if (bgColorKeys.has(key)) {\n      bgColors[key] = value;\n    } else {\n      fgColors[key] = value;\n    }\n  }\n  return new Theme(fgColors, bgColors, colorMode, {\n    name: themeJson.name,\n    sourcePath\n  });\n}\nfunction loadThemeFromPath(themePath, mode) {\n  const content = fs4.readFileSync(themePath, \"utf-8\");\n  const themeJson = parseThemeJsonContent(themePath, content);\n  return createTheme(themeJson, mode, themePath);\n}\nfunction loadTheme(name, mode) {\n  const registeredTheme = registeredThemes.get(name);\n  if (registeredTheme) {\n    return registeredTheme;\n  }\n  const themeJson = loadThemeJson(name);\n  return createTheme(themeJson, mode);\n}\nfunction getThemeByName(name) {\n  try {\n    return loadTheme(name);\n  } catch {\n    return void 0;\n  }\n}\nfunction parseAutoThemeSetting(themeSetting) {\n  if (!themeSetting)\n    return void 0;\n  const slashIndex = themeSetting.indexOf(\"/\");\n  if (slashIndex === -1 || themeSetting.indexOf(\"/\", slashIndex + 1) !== -1) {\n    return void 0;\n  }\n  const lightTheme = themeSetting.slice(0, slashIndex).trim();\n  const darkTheme = themeSetting.slice(slashIndex + 1).trim();\n  if (!lightTheme || !darkTheme) {\n    return void 0;\n  }\n  return { lightTheme, darkTheme };\n}\nfunction resolveThemeSetting(themeSetting, terminalTheme) {\n  const autoTheme = parseAutoThemeSetting(themeSetting);\n  if (autoTheme) {\n    return terminalTheme === \"light\" ? autoTheme.lightTheme : autoTheme.darkTheme;\n  }\n  if (themeSetting?.includes(\"/\"))\n    return void 0;\n  if (typeof themeSetting === \"string\")\n    return themeSetting;\n  return void 0;\n}\nfunction getColorFgBgBackgroundIndex(colorfgbg) {\n  const parts = colorfgbg.split(\";\");\n  for (let i = parts.length - 1; i >= 0; i--) {\n    const bg = parseInt(parts[i].trim(), 10);\n    if (Number.isInteger(bg) && bg >= 0 && bg <= 255) {\n      return bg;\n    }\n  }\n  return void 0;\n}\nfunction getRgbColorLuminance({ r, g, b }) {\n  const toLinear = (channel) => {\n    const value = channel / 255;\n    return value <= 0.03928 ? value / 12.92 : ((value + 0.055) / 1.055) ** 2.4;\n  };\n  return 0.2126 * toLinear(r) + 0.7152 * toLinear(g) + 0.0722 * toLinear(b);\n}\nfunction getAnsiColorLuminance(index) {\n  return getRgbColorLuminance(hexToRgb2(ansi256ToHex(index)));\n}\nfunction getThemeForRgbColor(rgb2) {\n  return getRgbColorLuminance(rgb2) >= 0.5 ? \"light\" : \"dark\";\n}\nfunction detectTerminalBackgroundFromEnv(options = {}) {\n  const env = options.env ?? process.env;\n  const colorfgbg = env.COLORFGBG || \"\";\n  const bg = getColorFgBgBackgroundIndex(colorfgbg);\n  if (bg !== void 0) {\n    return {\n      theme: getAnsiColorLuminance(bg) >= 0.5 ? \"light\" : \"dark\",\n      source: \"COLORFGBG\",\n      detail: `background color index ${bg}`,\n      confidence: \"high\"\n    };\n  }\n  return {\n    theme: \"dark\",\n    source: \"fallback\",\n    detail: \"no terminal background hint found\",\n    confidence: \"low\"\n  };\n}\nasync function detectTerminalBackgroundTheme({ ui, timeoutMs, env }) {\n  try {\n    const rgb2 = await ui.queryTerminalBackgroundColor({ timeoutMs });\n    if (rgb2) {\n      return {\n        theme: getThemeForRgbColor(rgb2),\n        source: \"terminal background\",\n        detail: `OSC 11 background rgb(${rgb2.r}, ${rgb2.g}, ${rgb2.b})`,\n        confidence: \"high\"\n      };\n    }\n  } catch {\n  }\n  return detectTerminalBackgroundFromEnv({ env });\n}\nasync function detectTerminalThemeForAuto({ ui, timeoutMs, env }) {\n  let colorSchemePromise;\n  try {\n    colorSchemePromise = ui.queryTerminalColorScheme?.({ timeoutMs });\n  } catch {\n  }\n  const backgroundThemePromise = detectTerminalBackgroundTheme({ ui, timeoutMs, env });\n  try {\n    const colorScheme = await colorSchemePromise;\n    if (colorScheme)\n      return colorScheme;\n  } catch {\n  }\n  return (await backgroundThemePromise).theme;\n}\nfunction getDefaultTheme() {\n  return detectTerminalBackgroundFromEnv().theme;\n}\nvar THEME_KEY = Symbol.for(\"@earendil-works/pi-coding-agent:theme\");\nvar THEME_KEY_OLD = Symbol.for(\"@mariozechner/pi-coding-agent:theme\");\nvar theme = new Proxy({}, {\n  get(_target, prop) {\n    const t = globalThis[THEME_KEY];\n    if (!t)\n      throw new Error(\"Theme not initialized. Call initTheme() first.\");\n    return t[prop];\n  }\n});\nfunction setGlobalTheme(t) {\n  globalThis[THEME_KEY] = t;\n  globalThis[THEME_KEY_OLD] = t;\n}\nvar currentThemeName;\nvar themeWatcher;\nvar themeReloadTimer;\nvar onThemeChangeCallback;\nvar registeredThemes = /* @__PURE__ */ new Map();\nfunction setRegisteredThemes(themes) {\n  registeredThemes.clear();\n  for (const theme2 of themes) {\n    if (theme2.name) {\n      assertThemeNameIsValid(theme2.name);\n      registeredThemes.set(theme2.name, theme2);\n    }\n  }\n}\nfunction initTheme(themeName, enableWatcher = false) {\n  const name = themeName ?? getDefaultTheme();\n  currentThemeName = name;\n  try {\n    setGlobalTheme(loadTheme(name));\n    if (enableWatcher) {\n      startThemeWatcher();\n    }\n  } catch (_error) {\n    currentThemeName = \"dark\";\n    setGlobalTheme(loadTheme(\"dark\"));\n  }\n}\nfunction setTheme(name, enableWatcher = false) {\n  currentThemeName = name;\n  try {\n    setGlobalTheme(loadTheme(name));\n    if (enableWatcher) {\n      startThemeWatcher();\n    }\n    if (onThemeChangeCallback) {\n      onThemeChangeCallback();\n    }\n    return { success: true };\n  } catch (error) {\n    currentThemeName = \"dark\";\n    setGlobalTheme(loadTheme(\"dark\"));\n    return {\n      success: false,\n      error: error instanceof Error ? error.message : String(error)\n    };\n  }\n}\nfunction setThemeInstance(themeInstance) {\n  setGlobalTheme(themeInstance);\n  currentThemeName = \"<in-memory>\";\n  stopThemeWatcher();\n  if (onThemeChangeCallback) {\n    onThemeChangeCallback();\n  }\n}\nfunction onThemeChange(callback) {\n  onThemeChangeCallback = callback;\n}\nfunction startThemeWatcher() {\n  stopThemeWatcher();\n  if (!currentThemeName || currentThemeName === \"dark\" || currentThemeName === \"light\") {\n    return;\n  }\n  const customThemesDir = getCustomThemesDir();\n  const watchedThemeName = currentThemeName;\n  const watchedFileName = `${watchedThemeName}.json`;\n  const themeFile = path6.join(customThemesDir, watchedFileName);\n  if (!fs4.existsSync(themeFile)) {\n    return;\n  }\n  const scheduleReload = () => {\n    if (themeReloadTimer) {\n      clearTimeout(themeReloadTimer);\n    }\n    themeReloadTimer = setTimeout(() => {\n      themeReloadTimer = void 0;\n      if (currentThemeName !== watchedThemeName) {\n        return;\n      }\n      if (!fs4.existsSync(themeFile)) {\n        return;\n      }\n      try {\n        const reloadedTheme = loadThemeFromPath(themeFile);\n        registeredThemes.set(watchedThemeName, reloadedTheme);\n        setGlobalTheme(reloadedTheme);\n        if (onThemeChangeCallback) {\n          onThemeChangeCallback();\n        }\n      } catch (_error) {\n      }\n    }, 100);\n  };\n  themeWatcher = watchWithErrorHandler(customThemesDir, (_eventType, filename) => {\n    if (currentThemeName !== watchedThemeName) {\n      return;\n    }\n    if (!filename) {\n      scheduleReload();\n      return;\n    }\n    if (filename !== watchedFileName) {\n      return;\n    }\n    scheduleReload();\n  }, () => {\n    closeWatcher(themeWatcher);\n    themeWatcher = void 0;\n  }) ?? void 0;\n}\nfunction stopThemeWatcher() {\n  if (themeReloadTimer) {\n    clearTimeout(themeReloadTimer);\n    themeReloadTimer = void 0;\n  }\n  closeWatcher(themeWatcher);\n  themeWatcher = void 0;\n}\nfunction ansi256ToHex(index) {\n  const basicColors = [\n    \"#000000\",\n    \"#800000\",\n    \"#008000\",\n    \"#808000\",\n    \"#000080\",\n    \"#800080\",\n    \"#008080\",\n    \"#c0c0c0\",\n    \"#808080\",\n    \"#ff0000\",\n    \"#00ff00\",\n    \"#ffff00\",\n    \"#0000ff\",\n    \"#ff00ff\",\n    \"#00ffff\",\n    \"#ffffff\"\n  ];\n  if (index < 16) {\n    return basicColors[index];\n  }\n  if (index < 232) {\n    const cubeIndex = index - 16;\n    const r = Math.floor(cubeIndex / 36);\n    const g = Math.floor(cubeIndex % 36 / 6);\n    const b = cubeIndex % 6;\n    const toHex = (n) => (n === 0 ? 0 : 55 + n * 40).toString(16).padStart(2, \"0\");\n    return `#${toHex(r)}${toHex(g)}${toHex(b)}`;\n  }\n  const gray = 8 + (index - 232) * 10;\n  const grayHex = gray.toString(16).padStart(2, \"0\");\n  return `#${grayHex}${grayHex}${grayHex}`;\n}\nfunction getResolvedThemeColors(themeName) {\n  const name = themeName ?? currentThemeName ?? getDefaultTheme();\n  const isLight = name === \"light\";\n  const themeJson = loadThemeJson(name);\n  const resolved = resolveThemeColors(withThemeColorFallbacks(themeJson.colors), themeJson.vars);\n  const defaultText = isLight ? \"#000000\" : \"#e5e5e7\";\n  const cssColors = {};\n  for (const [key, value] of Object.entries(resolved)) {\n    if (typeof value === \"number\") {\n      cssColors[key] = ansi256ToHex(value);\n    } else if (value === \"\") {\n      cssColors[key] = defaultText;\n    } else {\n      cssColors[key] = value;\n    }\n  }\n  return cssColors;\n}\nfunction getThemeExportColors(themeName) {\n  const name = themeName ?? currentThemeName ?? getDefaultTheme();\n  try {\n    const themeJson = loadThemeJson(name);\n    const exportSection = themeJson.export;\n    if (!exportSection)\n      return {};\n    const vars = themeJson.vars ?? {};\n    const resolve15 = (value) => {\n      if (value === void 0)\n        return void 0;\n      const resolved = resolveVarRefs(value, vars);\n      if (typeof resolved === \"number\")\n        return ansi256ToHex(resolved);\n      if (resolved === \"\")\n        return void 0;\n      return resolved;\n    };\n    return {\n      pageBg: resolve15(exportSection.pageBg),\n      cardBg: resolve15(exportSection.cardBg),\n      infoBg: resolve15(exportSection.infoBg)\n    };\n  } catch {\n    return {};\n  }\n}\nvar cachedHighlightThemeFor;\nvar cachedCliHighlightTheme;\nfunction buildCliHighlightTheme(t) {\n  return {\n    keyword: (s) => t.fg(\"syntaxKeyword\", s),\n    built_in: (s) => t.fg(\"syntaxType\", s),\n    literal: (s) => t.fg(\"syntaxNumber\", s),\n    number: (s) => t.fg(\"syntaxNumber\", s),\n    regexp: (s) => t.fg(\"syntaxString\", s),\n    string: (s) => t.fg(\"syntaxString\", s),\n    comment: (s) => t.fg(\"syntaxComment\", s),\n    doctag: (s) => t.fg(\"syntaxComment\", s),\n    meta: (s) => t.fg(\"muted\", s),\n    function: (s) => t.fg(\"syntaxFunction\", s),\n    title: (s) => t.fg(\"syntaxFunction\", s),\n    class: (s) => t.fg(\"syntaxType\", s),\n    type: (s) => t.fg(\"syntaxType\", s),\n    tag: (s) => t.fg(\"syntaxPunctuation\", s),\n    name: (s) => t.fg(\"syntaxKeyword\", s),\n    attr: (s) => t.fg(\"syntaxVariable\", s),\n    variable: (s) => t.fg(\"syntaxVariable\", s),\n    params: (s) => t.fg(\"syntaxVariable\", s),\n    operator: (s) => t.fg(\"syntaxOperator\", s),\n    punctuation: (s) => t.fg(\"syntaxPunctuation\", s),\n    emphasis: (s) => t.italic(s),\n    strong: (s) => t.bold(s),\n    link: (s) => t.underline(s),\n    addition: (s) => t.fg(\"toolDiffAdded\", s),\n    deletion: (s) => t.fg(\"toolDiffRemoved\", s)\n  };\n}\nfunction getCliHighlightTheme(t) {\n  if (cachedHighlightThemeFor !== t || !cachedCliHighlightTheme) {\n    cachedHighlightThemeFor = t;\n    cachedCliHighlightTheme = buildCliHighlightTheme(t);\n  }\n  return cachedCliHighlightTheme;\n}\nfunction highlightCode(code, lang) {\n  const validLang = lang && supportsLanguage(lang) ? lang : void 0;\n  if (!validLang) {\n    return code.split(\"\\n\").map((line) => theme.fg(\"mdCodeBlock\", line));\n  }\n  const opts = {\n    language: validLang,\n    ignoreIllegals: true,\n    theme: getCliHighlightTheme(theme)\n  };\n  try {\n    return highlight(code, opts).split(\"\\n\");\n  } catch {\n    return code.split(\"\\n\");\n  }\n}\nfunction getLanguageFromPath(filePath) {\n  const ext = filePath.split(\".\").pop()?.toLowerCase();\n  if (!ext)\n    return void 0;\n  const extToLang = {\n    ts: \"typescript\",\n    tsx: \"typescript\",\n    js: \"javascript\",\n    jsx: \"javascript\",\n    mjs: \"javascript\",\n    cjs: \"javascript\",\n    py: \"python\",\n    rb: \"ruby\",\n    rs: \"rust\",\n    go: \"go\",\n    java: \"java\",\n    kt: \"kotlin\",\n    swift: \"swift\",\n    c: \"c\",\n    h: \"c\",\n    cpp: \"cpp\",\n    cc: \"cpp\",\n    cxx: \"cpp\",\n    hpp: \"cpp\",\n    cs: \"csharp\",\n    php: \"php\",\n    sh: \"bash\",\n    bash: \"bash\",\n    zsh: \"bash\",\n    fish: \"fish\",\n    ps1: \"powershell\",\n    sql: \"sql\",\n    html: \"html\",\n    htm: \"html\",\n    css: \"css\",\n    scss: \"scss\",\n    sass: \"sass\",\n    less: \"less\",\n    json: \"json\",\n    yaml: \"yaml\",\n    yml: \"yaml\",\n    toml: \"toml\",\n    xml: \"xml\",\n    md: \"markdown\",\n    markdown: \"markdown\",\n    dockerfile: \"dockerfile\",\n    makefile: \"makefile\",\n    cmake: \"cmake\",\n    lua: \"lua\",\n    perl: \"perl\",\n    r: \"r\",\n    scala: \"scala\",\n    clj: \"clojure\",\n    ex: \"elixir\",\n    exs: \"elixir\",\n    erl: \"erlang\",\n    hs: \"haskell\",\n    ml: \"ocaml\",\n    vim: \"vim\",\n    graphql: \"graphql\",\n    proto: \"protobuf\",\n    tf: \"hcl\",\n    hcl: \"hcl\"\n  };\n  return extToLang[ext];\n}\nfunction getMarkdownTheme() {\n  return {\n    heading: (text) => theme.fg(\"mdHeading\", text),\n    link: (text) => theme.fg(\"mdLink\", text),\n    linkUrl: (text) => theme.fg(\"mdLinkUrl\", text),\n    code: (text) => theme.fg(\"mdCode\", text),\n    codeBlock: (text) => theme.fg(\"mdCodeBlock\", text),\n    codeBlockBorder: (text) => theme.fg(\"mdCodeBlockBorder\", text),\n    quote: (text) => theme.fg(\"mdQuote\", text),\n    quoteBorder: (text) => theme.fg(\"mdQuoteBorder\", text),\n    hr: (text) => theme.fg(\"mdHr\", text),\n    listBullet: (text) => theme.fg(\"mdListBullet\", text),\n    bold: (text) => theme.bold(text),\n    italic: (text) => theme.italic(text),\n    underline: (text) => theme.underline(text),\n    strikethrough: (text) => chalk5.strikethrough(text),\n    highlightCode: (code, lang) => {\n      const validLang = lang && supportsLanguage(lang) ? lang : void 0;\n      if (!validLang) {\n        return code.split(\"\\n\").map((line) => theme.fg(\"mdCodeBlock\", line));\n      }\n      const opts = {\n        language: validLang,\n        ignoreIllegals: true,\n        theme: getCliHighlightTheme(theme)\n      };\n      try {\n        return highlight(code, opts).split(\"\\n\");\n      } catch {\n        return code.split(\"\\n\").map((line) => theme.fg(\"mdCodeBlock\", line));\n      }\n    }\n  };\n}\nfunction getSelectListTheme() {\n  return {\n    selectedPrefix: (text) => theme.fg(\"accent\", text),\n    selectedText: (text) => theme.fg(\"accent\", text),\n    description: (text) => theme.fg(\"muted\", text),\n    scrollInfo: (text) => theme.fg(\"muted\", text),\n    noMatch: (text) => theme.fg(\"muted\", text)\n  };\n}\nfunction getEditorTheme() {\n  return {\n    borderColor: (text) => theme.fg(\"borderMuted\", text),\n    selectList: getSelectListTheme()\n  };\n}\nfunction getSettingsListTheme() {\n  return {\n    label: (text, selected) => selected ? theme.fg(\"accent\", text) : text,\n    value: (text, selected) => selected ? theme.fg(\"accent\", text) : theme.fg(\"muted\", text),\n    description: (text) => theme.fg(\"dim\", text),\n    cursor: theme.fg(\"accent\", \"\\u2192 \"),\n    hint: (text) => theme.fg(\"dim\", text)\n  };\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/countdown-timer.js\nvar CountdownTimer = class {\n  intervalId;\n  remainingSeconds;\n  tui;\n  onTick;\n  onExpire;\n  constructor(timeoutMs, tui, onTick, onExpire) {\n    this.tui = tui;\n    this.onTick = onTick;\n    this.onExpire = onExpire;\n    this.remainingSeconds = Math.ceil(timeoutMs / 1e3);\n    this.onTick(this.remainingSeconds);\n    this.intervalId = setInterval(() => {\n      this.remainingSeconds--;\n      this.onTick(this.remainingSeconds);\n      this.tui?.requestRender();\n      if (this.remainingSeconds <= 0) {\n        this.dispose();\n        this.onExpire();\n      }\n    }, 1e3);\n  }\n  dispose() {\n    if (this.intervalId) {\n      clearInterval(this.intervalId);\n      this.intervalId = void 0;\n    }\n  }\n};\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/dynamic-border.js\nvar DynamicBorder = class {\n  color;\n  constructor(color = (str2) => theme.fg(\"border\", str2)) {\n    this.color = color;\n  }\n  invalidate() {\n  }\n  render(width) {\n    return [this.color(\"\\u2500\".repeat(Math.max(1, width)))];\n  }\n};\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/keybinding-hints.js\nfunction formatKeyPart(part, options) {\n  const displayPart = process.platform === \"darwin\" && part.toLowerCase() === \"alt\" ? \"option\" : part;\n  return options.capitalize ? displayPart.charAt(0).toUpperCase() + displayPart.slice(1) : displayPart;\n}\nfunction formatKeyText(key, options = {}) {\n  return key.split(\"/\").map((k) => k.split(\"+\").map((part) => formatKeyPart(part, options)).join(\"+\")).join(\"/\");\n}\nfunction formatKeys(keys, options = {}) {\n  if (keys.length === 0)\n    return \"\";\n  return formatKeyText(keys.join(\"/\"), options);\n}\nfunction keyText(keybinding) {\n  return formatKeys(getKeybindings().getKeys(keybinding));\n}\nfunction keyDisplayText(keybinding) {\n  return formatKeys(getKeybindings().getKeys(keybinding), { capitalize: true });\n}\nfunction keyHint(keybinding, description) {\n  return theme.fg(\"dim\", keyText(keybinding)) + theme.fg(\"muted\", ` ${description}`);\n}\nfunction rawKeyHint(key, description) {\n  return theme.fg(\"dim\", formatKeyText(key)) + theme.fg(\"muted\", ` ${description}`);\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/extension-input.js\nvar ExtensionInputComponent = class extends Container {\n  input;\n  onSubmitCallback;\n  onCancelCallback;\n  titleText;\n  baseTitle;\n  countdown;\n  // Focusable implementation - propagate to input for IME cursor positioning\n  _focused = false;\n  get focused() {\n    return this._focused;\n  }\n  set focused(value) {\n    this._focused = value;\n    this.input.focused = value;\n  }\n  constructor(title, _placeholder, onSubmit, onCancel, opts) {\n    super();\n    this.onSubmitCallback = onSubmit;\n    this.onCancelCallback = onCancel;\n    this.baseTitle = title;\n    this.addChild(new DynamicBorder());\n    this.addChild(new Spacer(1));\n    this.titleText = new Text(theme.fg(\"accent\", title), 1, 0);\n    this.addChild(this.titleText);\n    this.addChild(new Spacer(1));\n    if (opts?.timeout && opts.timeout > 0 && opts.tui) {\n      this.countdown = new CountdownTimer(opts.timeout, opts.tui, (s) => this.titleText.setText(theme.fg(\"accent\", `${this.baseTitle} (${s}s)`)), () => this.onCancelCallback());\n    }\n    this.input = new Input();\n    this.addChild(this.input);\n    this.addChild(new Spacer(1));\n    this.addChild(new Text(`${keyHint(\"tui.select.confirm\", \"submit\")}  ${keyHint(\"tui.select.cancel\", \"cancel\")}`, 1, 0));\n    this.addChild(new Spacer(1));\n    this.addChild(new DynamicBorder());\n  }\n  handleInput(keyData) {\n    const kb = getKeybindings();\n    if (kb.matches(keyData, \"tui.select.confirm\") || keyData === \"\\n\") {\n      this.onSubmitCallback(this.input.getValue());\n    } else if (kb.matches(keyData, \"tui.select.cancel\")) {\n      this.onCancelCallback();\n    } else {\n      this.input.handleInput(keyData);\n    }\n  }\n  dispose() {\n    this.countdown?.dispose();\n  }\n};\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/extension-selector.js\nvar ExtensionSelectorComponent = class extends Container {\n  options;\n  selectedIndex = 0;\n  listContainer;\n  onSelectCallback;\n  onCancelCallback;\n  titleText;\n  baseTitle;\n  countdown;\n  onToggleToolsExpanded;\n  constructor(title, options, onSelect, onCancel, opts) {\n    super();\n    this.options = options;\n    this.onSelectCallback = onSelect;\n    this.onCancelCallback = onCancel;\n    this.onToggleToolsExpanded = opts?.onToggleToolsExpanded;\n    this.baseTitle = title;\n    this.addChild(new DynamicBorder());\n    this.addChild(new Spacer(1));\n    this.titleText = new Text(theme.fg(\"accent\", theme.bold(title)), 1, 0);\n    this.addChild(this.titleText);\n    this.addChild(new Spacer(1));\n    if (opts?.timeout && opts.timeout > 0 && opts.tui) {\n      this.countdown = new CountdownTimer(opts.timeout, opts.tui, (s) => this.titleText.setText(theme.fg(\"accent\", theme.bold(`${this.baseTitle} (${s}s)`))), () => this.onCancelCallback());\n    }\n    this.listContainer = new Container();\n    this.addChild(this.listContainer);\n    this.addChild(new Spacer(1));\n    this.addChild(new Text(rawKeyHint(\"\\u2191\\u2193\", \"navigate\") + \"  \" + keyHint(\"tui.select.confirm\", \"select\") + \"  \" + keyHint(\"tui.select.cancel\", \"cancel\"), 1, 0));\n    this.addChild(new Spacer(1));\n    this.addChild(new DynamicBorder());\n    this.updateList();\n  }\n  updateList() {\n    this.listContainer.clear();\n    for (let i = 0; i < this.options.length; i++) {\n      const isSelected = i === this.selectedIndex;\n      const text = isSelected ? theme.fg(\"accent\", \"\\u2192 \") + theme.fg(\"accent\", this.options[i]) : `  ${theme.fg(\"text\", this.options[i])}`;\n      this.listContainer.addChild(new Text(text, 1, 0));\n    }\n  }\n  handleInput(keyData) {\n    const kb = getKeybindings();\n    if (kb.matches(keyData, \"app.tools.expand\")) {\n      this.onToggleToolsExpanded?.();\n    } else if (kb.matches(keyData, \"tui.select.up\") || keyData === \"k\") {\n      this.selectedIndex = Math.max(0, this.selectedIndex - 1);\n      this.updateList();\n    } else if (kb.matches(keyData, \"tui.select.down\") || keyData === \"j\") {\n      this.selectedIndex = Math.min(this.options.length - 1, this.selectedIndex + 1);\n      this.updateList();\n    } else if (kb.matches(keyData, \"tui.select.confirm\") || keyData === \"\\n\") {\n      const selected = this.options[this.selectedIndex];\n      if (selected)\n        this.onSelectCallback(selected);\n    } else if (kb.matches(keyData, \"tui.select.cancel\")) {\n      this.onCancelCallback();\n    }\n  }\n  dispose() {\n    this.countdown?.dispose();\n  }\n};\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/first-time-setup.js\nvar THEME_OPTIONS = [\n  { value: \"dark\", label: \"Dark\" },\n  { value: \"light\", label: \"Light\" }\n];\nvar ANALYTICS_OPTIONS = [\n  { value: true, label: \"Share anonymous usage data\" },\n  { value: false, label: \"Don't share\" }\n];\nvar SETUP_LOGO_LINES = [\"\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\", \"\\u2588\\u2588  \\u2588\\u2588\", \"\\u2588\\u2588\\u2588\\u2588  \\u2588\\u2588\", \"\\u2588\\u2588    \\u2588\\u2588\"];\nvar FirstTimeSetupComponent = class extends Container {\n  step = \"theme\";\n  themeIndex;\n  analyticsIndex = 0;\n  options;\n  constructor(options) {\n    super();\n    this.options = options;\n    this.themeIndex = Math.max(0, THEME_OPTIONS.findIndex((option) => option.value === options.detectedTheme));\n    this.update();\n  }\n  // Rebuild the whole dialog on every change so theme previews recolor all text.\n  update() {\n    this.clear();\n    this.addChild(new DynamicBorder());\n    this.addChild(new Spacer(1));\n    this.addChild(new Text(theme.fg(\"accent\", SETUP_LOGO_LINES.join(\"\\n\")), 1, 0));\n    this.addChild(new Spacer(1));\n    this.addChild(new Text(theme.fg(\"accent\", theme.bold(`Welcome to ${APP_NAME}, the minimal coding agent.`)), 1, 0));\n    this.addChild(new Spacer(1));\n    if (this.step === \"theme\") {\n      this.addChild(new Text(theme.fg(\"text\", \"Pick a theme.\"), 1, 0));\n      this.addChild(new Text(theme.fg(\"muted\", `Detected system appearance: ${this.options.detectedTheme}`), 1, 0));\n      this.addChild(new Spacer(1));\n      this.addOptionList(THEME_OPTIONS.map((option) => option.label), this.themeIndex);\n    } else {\n      this.addChild(new Text(theme.fg(\"text\", \"Opt-in to anonymous usage data sharing?\"), 1, 0));\n      this.addChild(new Text(theme.fg(\"muted\", \"Opting in stores a tracking identifier in settings.json and enables anonymous\\nusage analytics. This helps us to better debug, reproduce, and resolve issues\\nand bugs within Pi. You can observe what is shared using /privacy and make\\nchanges anytime in settings.json.\"), 1, 0));\n      this.addChild(new Spacer(1));\n      this.addOptionList(ANALYTICS_OPTIONS.map((option) => option.label), this.analyticsIndex);\n    }\n    this.addChild(new Spacer(1));\n    this.addChild(new Text(rawKeyHint(\"\\u2191\\u2193\", \"navigate\") + \"  \" + keyHint(\"tui.select.confirm\", this.step === \"theme\" ? \"continue\" : \"finish\") + \"  \" + keyHint(\"tui.select.cancel\", \"skip setup\"), 1, 0));\n    this.addChild(new Spacer(1));\n    this.addChild(new DynamicBorder());\n  }\n  addOptionList(labels, selectedIndex) {\n    for (let i = 0; i < labels.length; i++) {\n      const isSelected = i === selectedIndex;\n      const prefix = isSelected ? theme.fg(\"accent\", \"\\u2192 \") : \"  \";\n      const label = isSelected ? theme.fg(\"accent\", labels[i]) : theme.fg(\"text\", labels[i]);\n      this.addChild(new Text(`${prefix}${label}`, 1, 0));\n    }\n  }\n  moveSelection(delta) {\n    if (this.step === \"theme\") {\n      const next = Math.max(0, Math.min(THEME_OPTIONS.length - 1, this.themeIndex + delta));\n      if (next !== this.themeIndex) {\n        this.themeIndex = next;\n        this.options.onThemePreview(THEME_OPTIONS[this.themeIndex].value);\n      }\n    } else {\n      this.analyticsIndex = Math.max(0, Math.min(ANALYTICS_OPTIONS.length - 1, this.analyticsIndex + delta));\n    }\n    this.update();\n  }\n  handleInput(keyData) {\n    const kb = getKeybindings();\n    if (kb.matches(keyData, \"tui.select.up\") || keyData === \"k\") {\n      this.moveSelection(-1);\n    } else if (kb.matches(keyData, \"tui.select.down\") || keyData === \"j\") {\n      this.moveSelection(1);\n    } else if (kb.matches(keyData, \"tui.select.confirm\") || keyData === \"\\n\") {\n      if (this.step === \"theme\") {\n        this.step = \"analytics\";\n        this.update();\n      } else {\n        this.options.onSubmit({\n          theme: THEME_OPTIONS[this.themeIndex].value,\n          shareAnalytics: ANALYTICS_OPTIONS[this.analyticsIndex].value\n        });\n      }\n    } else if (kb.matches(keyData, \"tui.select.cancel\")) {\n      this.options.onCancel();\n    }\n  }\n};\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/cli/startup-ui.js\nvar OFFICIAL_PACKAGE_NAME = \"@earendil-works/pi-coding-agent\";\nvar OFFICIAL_APP_NAME = \"pi\";\nvar OFFICIAL_CONFIG_DIR_NAME = \".pi\";\nfunction isOfficialDistribution({ packageName, appName, configDirName }) {\n  return packageName === OFFICIAL_PACKAGE_NAME && appName === OFFICIAL_APP_NAME && configDirName === OFFICIAL_CONFIG_DIR_NAME;\n}\nfunction loadThemes(resources) {\n  const themes = [];\n  const seen = /* @__PURE__ */ new Set();\n  for (const resource of resources) {\n    if (!resource.enabled)\n      continue;\n    try {\n      const loadedTheme = loadThemeFromPath(resource.path);\n      if (loadedTheme.name) {\n        if (seen.has(loadedTheme.name))\n          continue;\n        seen.add(loadedTheme.name);\n      }\n      themes.push(loadedTheme);\n    } catch {\n    }\n  }\n  return themes;\n}\nasync function loadStartupThemes(settingsManager) {\n  const globalSettingsManager = SettingsManager.inMemory(settingsManager.getGlobalSettings(), {\n    projectTrusted: false\n  });\n  const packageManager = new DefaultPackageManager({\n    cwd: process.cwd(),\n    agentDir: getAgentDir(),\n    settingsManager: globalSettingsManager\n  });\n  const resolvedPaths = await packageManager.resolve(async () => \"skip\");\n  return loadThemes(resolvedPaths.themes);\n}\nasync function createStartupTui(settingsManager) {\n  setRegisteredThemes(await loadStartupThemes(settingsManager));\n  const terminalTheme = detectTerminalBackgroundFromEnv().theme;\n  initTheme(resolveThemeSetting(settingsManager.getThemeSetting(), terminalTheme) ?? terminalTheme);\n  setKeybindings(KeybindingsManager2.create());\n  const ui = new TuiMainScreen(new ProcessTerminal(), settingsManager.getShowHardwareCursor(), getAgentDir());\n  ui.setClearOnShrink(settingsManager.getClearOnShrink());\n  return ui;\n}\nfunction startStartupTui(ui, settingsManager) {\n  ui.start();\n  void applyDetectedStartupTheme(ui, settingsManager);\n}\nasync function applyDetectedStartupTheme(ui, settingsManager) {\n  const themeSetting = settingsManager.getThemeSetting();\n  if (themeSetting && !parseAutoThemeSetting(themeSetting))\n    return;\n  const terminalTheme = await detectTerminalThemeForAuto({ ui, timeoutMs: 100 });\n  setTheme(resolveThemeSetting(themeSetting, terminalTheme) ?? terminalTheme);\n  ui.invalidate();\n  ui.requestRender();\n}\nasync function clearStartupTui(ui) {\n  ui.clear();\n  ui.requestRender();\n  await new Promise((resolve15) => setTimeout(resolve15, 25));\n}\nfunction shouldRunFirstTimeSetup(settingsPath = getSettingsPath()) {\n  if (!isOfficialDistribution({\n    packageName: PACKAGE_NAME,\n    appName: APP_NAME,\n    configDirName: CONFIG_DIR_NAME\n  })) {\n    return false;\n  }\n  if (!areExperimentalFeaturesEnabled()) {\n    return false;\n  }\n  if (process.env[ENV_AGENT_DIR]) {\n    return false;\n  }\n  return !existsSync8(settingsPath);\n}\nasync function showStartupSelector(settingsManager, title, options) {\n  const ui = await createStartupTui(settingsManager);\n  return new Promise((resolve15) => {\n    let settled = false;\n    const finish = async (result) => {\n      if (settled) {\n        return;\n      }\n      settled = true;\n      await clearStartupTui(ui);\n      ui.stop();\n      resolve15(result);\n    };\n    const selector = new ExtensionSelectorComponent(title, options.map((option) => option.label), (option) => void finish(options.find((entry) => entry.label === option)?.value), () => void finish(void 0), { tui: ui });\n    ui.addChild(selector);\n    ui.setFocus(selector);\n    startStartupTui(ui, settingsManager);\n  });\n}\nasync function showFirstTimeSetup(settingsManager) {\n  const ui = await createStartupTui(settingsManager);\n  return new Promise((resolve15) => {\n    let settled = false;\n    const finish = async (result) => {\n      if (settled) {\n        return;\n      }\n      settled = true;\n      if (result) {\n        settingsManager.setTheme(result.theme);\n        settingsManager.setEnableAnalytics(result.shareAnalytics);\n        await settingsManager.flush();\n      }\n      await clearStartupTui(ui);\n      ui.stop();\n      resolve15();\n    };\n    const showSetup = async () => {\n      ui.start();\n      const detectedTheme = await detectTerminalThemeForAuto({ ui, timeoutMs: 100 });\n      setTheme(detectedTheme);\n      const component = new FirstTimeSetupComponent({\n        detectedTheme,\n        onThemePreview: (themeName) => {\n          setTheme(themeName);\n          ui.requestRender();\n        },\n        onSubmit: (result) => void finish(result),\n        onCancel: () => void finish(void 0)\n      });\n      ui.addChild(component);\n      ui.setFocus(component);\n      ui.requestRender();\n    };\n    void showSetup();\n  });\n}\nasync function showStartupInput(settingsManager, title, placeholder) {\n  const ui = await createStartupTui(settingsManager);\n  return new Promise((resolve15) => {\n    let settled = false;\n    const finish = async (result) => {\n      if (settled) {\n        return;\n      }\n      settled = true;\n      input.dispose();\n      await clearStartupTui(ui);\n      ui.stop();\n      resolve15(result);\n    };\n    const input = new ExtensionInputComponent(title, placeholder, (value) => void finish(value), () => void finish(void 0), {\n      tui: ui\n    });\n    ui.addChild(input);\n    ui.setFocus(input);\n    startStartupTui(ui, settingsManager);\n  });\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/cli/project-trust.js\nfunction createProjectTrustContext(options) {\n  return {\n    cwd: options.cwd,\n    mode: options.mode === \"interactive\" ? \"tui\" : options.mode,\n    hasUI: options.hasUI,\n    ui: {\n      select: async (title, selectOptions) => {\n        if (!options.hasUI) {\n          return void 0;\n        }\n        if (options.mode !== \"interactive\") {\n          return void 0;\n        }\n        return showStartupSelector(options.settingsManager, title, selectOptions.map((option) => ({ label: option, value: option })));\n      },\n      confirm: async (title, message) => {\n        if (!options.hasUI) {\n          return false;\n        }\n        if (options.mode !== \"interactive\") {\n          return false;\n        }\n        return await showStartupSelector(options.settingsManager, `${title}\n${message}`, [\n          { label: \"Yes\", value: true },\n          { label: \"No\", value: false }\n        ]) ?? false;\n      },\n      input: async (title, placeholder) => {\n        if (!options.hasUI) {\n          return void 0;\n        }\n        if (options.mode !== \"interactive\") {\n          return void 0;\n        }\n        return showStartupInput(options.settingsManager, title, placeholder);\n      },\n      notify: (message, type = \"info\") => {\n        if (options.mode !== \"interactive\") {\n          const color = type === \"error\" ? chalk6.red : type === \"warning\" ? chalk6.yellow : chalk6.cyan;\n          console.error(color(message));\n        }\n      }\n    }\n  };\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/session-selector.js\nimport { spawnSync as spawnSync3 } from \"node:child_process\";\nimport { existsSync as existsSync9 } from \"node:fs\";\nimport { unlink } from \"node:fs/promises\";\nimport * as os2 from \"node:os\";\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/session-selector-search.js\nfunction normalizeWhitespaceLower(text) {\n  return text.toLowerCase().replace(/\\s+/g, \" \").trim();\n}\nfunction getSessionSearchText(session) {\n  return `${session.id} ${session.name ?? \"\"} ${session.allMessagesText} ${session.cwd}`;\n}\nfunction hasSessionName(session) {\n  return Boolean(session.name?.trim());\n}\nfunction matchesNameFilter(session, filter) {\n  if (filter === \"all\")\n    return true;\n  return hasSessionName(session);\n}\nfunction parseSearchQuery(query) {\n  const trimmed = query.trim();\n  if (!trimmed) {\n    return { mode: \"tokens\", tokens: [], regex: null };\n  }\n  if (trimmed.startsWith(\"re:\")) {\n    const pattern = trimmed.slice(3).trim();\n    if (!pattern) {\n      return { mode: \"regex\", tokens: [], regex: null, error: \"Empty regex\" };\n    }\n    try {\n      return { mode: \"regex\", tokens: [], regex: new RegExp(pattern, \"i\") };\n    } catch (err2) {\n      const msg = err2 instanceof Error ? err2.message : String(err2);\n      return { mode: \"regex\", tokens: [], regex: null, error: msg };\n    }\n  }\n  const tokens = [];\n  let buf = \"\";\n  let inQuote = false;\n  let hadUnclosedQuote = false;\n  const flush = (kind) => {\n    const v = buf.trim();\n    buf = \"\";\n    if (!v)\n      return;\n    tokens.push({ kind, value: v });\n  };\n  for (let i = 0; i < trimmed.length; i++) {\n    const ch = trimmed[i];\n    if (ch === '\"') {\n      if (inQuote) {\n        flush(\"phrase\");\n        inQuote = false;\n      } else {\n        flush(\"fuzzy\");\n        inQuote = true;\n      }\n      continue;\n    }\n    if (!inQuote && /\\s/.test(ch)) {\n      flush(\"fuzzy\");\n      continue;\n    }\n    buf += ch;\n  }\n  if (inQuote) {\n    hadUnclosedQuote = true;\n  }\n  if (hadUnclosedQuote) {\n    return {\n      mode: \"tokens\",\n      tokens: trimmed.split(/\\s+/).map((t) => t.trim()).filter((t) => t.length > 0).map((t) => ({ kind: \"fuzzy\", value: t })),\n      regex: null\n    };\n  }\n  flush(inQuote ? \"phrase\" : \"fuzzy\");\n  return { mode: \"tokens\", tokens, regex: null };\n}\nfunction matchSession(session, parsed) {\n  const text = getSessionSearchText(session);\n  if (parsed.mode === \"regex\") {\n    if (!parsed.regex) {\n      return { matches: false, score: 0 };\n    }\n    const idx = text.search(parsed.regex);\n    if (idx < 0)\n      return { matches: false, score: 0 };\n    return { matches: true, score: idx * 0.1 };\n  }\n  if (parsed.tokens.length === 0) {\n    return { matches: true, score: 0 };\n  }\n  let totalScore = 0;\n  let normalizedText = null;\n  for (const token of parsed.tokens) {\n    if (token.kind === \"phrase\") {\n      if (normalizedText === null) {\n        normalizedText = normalizeWhitespaceLower(text);\n      }\n      const phrase = normalizeWhitespaceLower(token.value);\n      if (!phrase)\n        continue;\n      const idx = normalizedText.indexOf(phrase);\n      if (idx < 0)\n        return { matches: false, score: 0 };\n      totalScore += idx * 0.1;\n      continue;\n    }\n    const m = fuzzyMatch(token.value, text);\n    if (!m.matches)\n      return { matches: false, score: 0 };\n    totalScore += m.score;\n  }\n  return { matches: true, score: totalScore };\n}\nfunction filterAndSortSessions(sessions, query, sortMode, nameFilter = \"all\") {\n  const nameFiltered = nameFilter === \"all\" ? sessions : sessions.filter((session) => matchesNameFilter(session, nameFilter));\n  const trimmed = query.trim();\n  if (!trimmed)\n    return nameFiltered;\n  const parsed = parseSearchQuery(query);\n  if (parsed.error)\n    return [];\n  if (sortMode === \"recent\") {\n    const filtered = [];\n    for (const s of nameFiltered) {\n      const res = matchSession(s, parsed);\n      if (res.matches)\n        filtered.push(s);\n    }\n    return filtered;\n  }\n  const scored = [];\n  for (const s of nameFiltered) {\n    const res = matchSession(s, parsed);\n    if (!res.matches)\n      continue;\n    scored.push({ session: s, score: res.score });\n  }\n  scored.sort((a, b) => {\n    if (a.score !== b.score)\n      return a.score - b.score;\n    return b.session.modified.getTime() - a.session.modified.getTime();\n  });\n  return scored.map((r) => r.session);\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/session-selector.js\nfunction shortenPath(path12) {\n  const home = os2.homedir();\n  if (!path12)\n    return path12;\n  if (path12.startsWith(home)) {\n    return `~${path12.slice(home.length)}`;\n  }\n  return path12;\n}\nfunction formatSessionDate(date) {\n  const now = /* @__PURE__ */ new Date();\n  const diffMs = now.getTime() - date.getTime();\n  const diffMins = Math.floor(diffMs / 6e4);\n  const diffHours = Math.floor(diffMs / 36e5);\n  const diffDays = Math.floor(diffMs / 864e5);\n  if (diffMins < 1)\n    return \"now\";\n  if (diffMins < 60)\n    return `${diffMins}m`;\n  if (diffHours < 24)\n    return `${diffHours}h`;\n  if (diffDays < 7)\n    return `${diffDays}d`;\n  if (diffDays < 30)\n    return `${Math.floor(diffDays / 7)}w`;\n  if (diffDays < 365)\n    return `${Math.floor(diffDays / 30)}mo`;\n  return `${Math.floor(diffDays / 365)}y`;\n}\nfunction canonicalizePath2(path12) {\n  if (!path12)\n    return path12;\n  return canonicalizePath(path12);\n}\nvar SessionSelectorHeader = class {\n  scope;\n  sortMode;\n  nameFilter;\n  requestRender;\n  loading = false;\n  loadProgress = null;\n  showPath = false;\n  confirmingDeletePath = null;\n  statusMessage = null;\n  statusTimeout = null;\n  showRenameHint = false;\n  constructor(scope, sortMode, nameFilter, requestRender) {\n    this.scope = scope;\n    this.sortMode = sortMode;\n    this.nameFilter = nameFilter;\n    this.requestRender = requestRender;\n  }\n  setScope(scope) {\n    this.scope = scope;\n  }\n  setSortMode(sortMode) {\n    this.sortMode = sortMode;\n  }\n  setNameFilter(nameFilter) {\n    this.nameFilter = nameFilter;\n  }\n  setLoading(loading) {\n    this.loading = loading;\n    this.loadProgress = null;\n  }\n  setProgress(loaded, total) {\n    this.loadProgress = { loaded, total };\n  }\n  setShowPath(showPath) {\n    this.showPath = showPath;\n  }\n  setShowRenameHint(show) {\n    this.showRenameHint = show;\n  }\n  setConfirmingDeletePath(path12) {\n    this.confirmingDeletePath = path12;\n  }\n  clearStatusTimeout() {\n    if (!this.statusTimeout)\n      return;\n    clearTimeout(this.statusTimeout);\n    this.statusTimeout = null;\n  }\n  setStatusMessage(msg, autoHideMs) {\n    this.clearStatusTimeout();\n    this.statusMessage = msg;\n    if (!msg || !autoHideMs)\n      return;\n    this.statusTimeout = setTimeout(() => {\n      this.statusMessage = null;\n      this.statusTimeout = null;\n      this.requestRender();\n    }, autoHideMs);\n  }\n  invalidate() {\n  }\n  render(width) {\n    const title = this.scope === \"current\" ? \"Resume Session (Current Folder)\" : \"Resume Session (All)\";\n    const leftText = theme.bold(title);\n    const sortLabel = this.sortMode === \"threaded\" ? \"Threaded\" : this.sortMode === \"recent\" ? \"Recent\" : \"Fuzzy\";\n    const sortText = theme.fg(\"muted\", \"Sort: \") + theme.fg(\"accent\", sortLabel);\n    const nameLabel = this.nameFilter === \"all\" ? \"All\" : \"Named\";\n    const nameText = theme.fg(\"muted\", \"Name: \") + theme.fg(\"accent\", nameLabel);\n    let scopeText;\n    if (this.loading) {\n      const progressText = this.loadProgress ? `${this.loadProgress.loaded}/${this.loadProgress.total}` : \"...\";\n      scopeText = `${theme.fg(\"muted\", \"\\u25CB Current Folder | \")}${theme.fg(\"accent\", `Loading ${progressText}`)}`;\n    } else if (this.scope === \"current\") {\n      scopeText = `${theme.fg(\"accent\", \"\\u25C9 Current Folder\")}${theme.fg(\"muted\", \" | \\u25CB All\")}`;\n    } else {\n      scopeText = `${theme.fg(\"muted\", \"\\u25CB Current Folder | \")}${theme.fg(\"accent\", \"\\u25C9 All\")}`;\n    }\n    const rightText = truncateToWidth(`${scopeText}  ${nameText}  ${sortText}`, width, \"\");\n    const availableLeft = Math.max(0, width - visibleWidth(rightText) - 1);\n    const left = truncateToWidth(leftText, availableLeft, \"\");\n    const spacing = Math.max(0, width - visibleWidth(left) - visibleWidth(rightText));\n    let hintLine1;\n    let hintLine2;\n    if (this.confirmingDeletePath !== null) {\n      const confirmHint = `Delete session? ${keyHint(\"tui.select.confirm\", \"confirm\")} \\xB7 ${keyHint(\"tui.select.cancel\", \"cancel\")}`;\n      hintLine1 = theme.fg(\"error\", truncateToWidth(confirmHint, width, \"\\u2026\"));\n      hintLine2 = \"\";\n    } else if (this.statusMessage) {\n      const color = this.statusMessage.type === \"error\" ? \"error\" : \"accent\";\n      hintLine1 = theme.fg(color, truncateToWidth(this.statusMessage.message, width, \"\\u2026\"));\n      hintLine2 = \"\";\n    } else {\n      const pathState = this.showPath ? \"(on)\" : \"(off)\";\n      const sep10 = theme.fg(\"muted\", \" \\xB7 \");\n      const hint1 = keyHint(\"tui.input.tab\", \"scope\") + sep10 + theme.fg(\"muted\", 're:<pattern> regex \\xB7 \"phrase\" exact');\n      const hint2Parts = [\n        keyHint(\"app.session.toggleSort\", \"sort\"),\n        keyHint(\"app.session.toggleNamedFilter\", \"named\"),\n        keyHint(\"app.session.delete\", \"delete\"),\n        keyHint(\"app.session.togglePath\", `path ${pathState}`)\n      ];\n      if (this.showRenameHint) {\n        hint2Parts.push(keyHint(\"app.session.rename\", \"rename\"));\n      }\n      const hint2 = hint2Parts.join(sep10);\n      hintLine1 = truncateToWidth(hint1, width, \"\\u2026\");\n      hintLine2 = truncateToWidth(hint2, width, \"\\u2026\");\n    }\n    return [`${left}${\" \".repeat(spacing)}${rightText}`, hintLine1, hintLine2];\n  }\n};\nfunction buildSessionTree(sessions) {\n  const byPath = /* @__PURE__ */ new Map();\n  for (const session of sessions) {\n    const sessionPath = canonicalizePath2(session.path) ?? session.path;\n    byPath.set(sessionPath, { session, children: [], latestActivity: session.modified.getTime() });\n  }\n  const roots = [];\n  for (const session of sessions) {\n    const sessionPath = canonicalizePath2(session.path) ?? session.path;\n    const node = byPath.get(sessionPath);\n    const parentPath = canonicalizePath2(session.parentSessionPath);\n    if (parentPath && byPath.has(parentPath)) {\n      byPath.get(parentPath).children.push(node);\n    } else {\n      roots.push(node);\n    }\n  }\n  const updateLatestActivity = (node) => {\n    let latestActivity = node.session.modified.getTime();\n    for (const child of node.children) {\n      latestActivity = Math.max(latestActivity, updateLatestActivity(child));\n    }\n    node.latestActivity = latestActivity;\n    return latestActivity;\n  };\n  for (const root of roots) {\n    updateLatestActivity(root);\n  }\n  const sortNodes = (nodes) => {\n    nodes.sort((a, b) => b.latestActivity - a.latestActivity);\n    for (const node of nodes) {\n      sortNodes(node.children);\n    }\n  };\n  sortNodes(roots);\n  return roots;\n}\nfunction flattenSessionTree(roots) {\n  const result = [];\n  const walk = (node, depth, ancestorContinues, isLast) => {\n    result.push({ session: node.session, depth, isLast, ancestorContinues });\n    for (let i = 0; i < node.children.length; i++) {\n      const childIsLast = i === node.children.length - 1;\n      const continues = depth > 0 ? !isLast : false;\n      walk(node.children[i], depth + 1, [...ancestorContinues, continues], childIsLast);\n    }\n  };\n  for (let i = 0; i < roots.length; i++) {\n    walk(roots[i], 0, [], i === roots.length - 1);\n  }\n  return result;\n}\nvar SessionList = class {\n  getSelectedSessionPath() {\n    const selected = this.filteredSessions[this.selectedIndex];\n    return selected?.session.path;\n  }\n  allSessions = [];\n  filteredSessions = [];\n  selectedIndex = 0;\n  searchInput;\n  showCwd = false;\n  sortMode = \"threaded\";\n  nameFilter = \"all\";\n  keybindings;\n  showPath = false;\n  confirmingDeletePath = null;\n  currentSessionCanonicalPath;\n  onSelect;\n  onCancel;\n  onExit = () => {\n  };\n  onToggleScope;\n  onToggleSort;\n  onToggleNameFilter;\n  onTogglePath;\n  onDeleteConfirmationChange;\n  onDeleteSession;\n  onRenameSession;\n  onError;\n  maxVisible = 10;\n  // Max sessions visible (one line each)\n  // Focusable implementation - propagate to searchInput for IME cursor positioning\n  _focused = false;\n  get focused() {\n    return this._focused;\n  }\n  set focused(value) {\n    this._focused = value;\n    this.searchInput.focused = value;\n  }\n  constructor(sessions, showCwd, sortMode, nameFilter, keybindings, currentSessionFilePath) {\n    this.allSessions = sessions;\n    this.filteredSessions = [];\n    this.searchInput = new Input();\n    this.showCwd = showCwd;\n    this.sortMode = sortMode;\n    this.nameFilter = nameFilter;\n    this.keybindings = keybindings;\n    this.currentSessionCanonicalPath = canonicalizePath2(currentSessionFilePath);\n    this.filterSessions(\"\");\n    this.searchInput.onSubmit = () => {\n      if (this.filteredSessions[this.selectedIndex]) {\n        const selected = this.filteredSessions[this.selectedIndex];\n        if (this.onSelect) {\n          this.onSelect(selected.session.path);\n        }\n      }\n    };\n  }\n  setSortMode(sortMode) {\n    this.sortMode = sortMode;\n    this.filterSessions(this.searchInput.getValue());\n  }\n  setNameFilter(nameFilter) {\n    this.nameFilter = nameFilter;\n    this.filterSessions(this.searchInput.getValue());\n  }\n  setSessions(sessions, showCwd) {\n    this.allSessions = sessions;\n    this.showCwd = showCwd;\n    this.filterSessions(this.searchInput.getValue());\n  }\n  filterSessions(query) {\n    const trimmed = query.trim();\n    const nameFiltered = this.nameFilter === \"all\" ? this.allSessions : this.allSessions.filter((session) => hasSessionName(session));\n    if (this.sortMode === \"threaded\" && !trimmed) {\n      const roots = buildSessionTree(nameFiltered);\n      this.filteredSessions = flattenSessionTree(roots);\n    } else {\n      const filtered = filterAndSortSessions(nameFiltered, query, this.sortMode, \"all\");\n      this.filteredSessions = filtered.map((session) => ({\n        session,\n        depth: 0,\n        isLast: true,\n        ancestorContinues: []\n      }));\n    }\n    this.selectedIndex = Math.min(this.selectedIndex, Math.max(0, this.filteredSessions.length - 1));\n  }\n  setConfirmingDeletePath(path12) {\n    this.confirmingDeletePath = path12;\n    this.onDeleteConfirmationChange?.(path12);\n  }\n  startDeleteConfirmationForSelectedSession() {\n    const selected = this.filteredSessions[this.selectedIndex];\n    if (!selected)\n      return;\n    if (this.isCurrentSessionPath(selected.session.path)) {\n      this.onError?.(\"Cannot delete the currently active session\");\n      return;\n    }\n    this.setConfirmingDeletePath(selected.session.path);\n  }\n  isCurrentSessionPath(path12) {\n    if (!this.currentSessionCanonicalPath)\n      return false;\n    return (canonicalizePath2(path12) ?? path12) === this.currentSessionCanonicalPath;\n  }\n  invalidate() {\n  }\n  render(width) {\n    const lines = [];\n    lines.push(...this.searchInput.render(width));\n    lines.push(\"\");\n    if (this.filteredSessions.length === 0) {\n      let emptyMessage;\n      if (this.nameFilter === \"named\") {\n        const toggleKey = keyText(\"app.session.toggleNamedFilter\");\n        if (this.showCwd) {\n          emptyMessage = `  No named sessions found. Press ${toggleKey} to show all.`;\n        } else {\n          emptyMessage = `  No named sessions in current folder. Press ${toggleKey} to show all, or Tab to view all.`;\n        }\n      } else if (this.showCwd) {\n        emptyMessage = \"  No sessions found\";\n      } else {\n        emptyMessage = \"  No sessions in current folder. Press Tab to view all.\";\n      }\n      lines.push(theme.fg(\"muted\", truncateToWidth(emptyMessage, width, \"\\u2026\")));\n      return lines;\n    }\n    const startIndex = Math.max(0, Math.min(this.selectedIndex - Math.floor(this.maxVisible / 2), this.filteredSessions.length - this.maxVisible));\n    const endIndex = Math.min(startIndex + this.maxVisible, this.filteredSessions.length);\n    for (let i = startIndex; i < endIndex; i++) {\n      const node = this.filteredSessions[i];\n      const session = node.session;\n      const isSelected = i === this.selectedIndex;\n      const isConfirmingDelete = session.path === this.confirmingDeletePath;\n      const isCurrent = this.isCurrentSessionPath(session.path);\n      const prefix = this.buildTreePrefix(node);\n      const hasName = !!session.name;\n      const displayText = session.name ?? session.firstMessage;\n      const normalizedMessage = displayText.replace(/[\\x00-\\x1f\\x7f]/g, \" \").trim();\n      const age = formatSessionDate(session.modified);\n      const msgCount = String(session.messageCount);\n      let rightPart = `${msgCount} ${age}`;\n      if (this.showCwd && session.cwd) {\n        rightPart = `${shortenPath(session.cwd)} ${rightPart}`;\n      }\n      if (this.showPath) {\n        rightPart = `${shortenPath(session.path)} ${rightPart}`;\n      }\n      const cursor = isSelected ? theme.fg(\"accent\", \"\\u203A \") : \"  \";\n      const prefixWidth = visibleWidth(prefix);\n      const rightWidth = visibleWidth(rightPart) + 2;\n      const availableForMsg = width - 2 - prefixWidth - rightWidth;\n      const truncatedMsg = truncateToWidth(normalizedMessage, Math.max(10, availableForMsg), \"\\u2026\");\n      let messageColor = null;\n      if (isConfirmingDelete) {\n        messageColor = \"error\";\n      } else if (isCurrent) {\n        messageColor = \"accent\";\n      } else if (hasName) {\n        messageColor = \"warning\";\n      }\n      let styledMsg = messageColor ? theme.fg(messageColor, truncatedMsg) : truncatedMsg;\n      if (isSelected) {\n        styledMsg = theme.bold(styledMsg);\n      }\n      const leftPart = cursor + theme.fg(\"dim\", prefix) + styledMsg;\n      const leftWidth = visibleWidth(leftPart);\n      const spacing = Math.max(1, width - leftWidth - visibleWidth(rightPart));\n      const styledRight = theme.fg(isConfirmingDelete ? \"error\" : \"dim\", rightPart);\n      let line = leftPart + \" \".repeat(spacing) + styledRight;\n      if (isSelected) {\n        line = theme.bg(\"selectedBg\", line);\n      }\n      lines.push(truncateToWidth(line, width));\n    }\n    if (startIndex > 0 || endIndex < this.filteredSessions.length) {\n      const scrollText = `  (${this.selectedIndex + 1}/${this.filteredSessions.length})`;\n      const scrollInfo = theme.fg(\"muted\", truncateToWidth(scrollText, width, \"\"));\n      lines.push(scrollInfo);\n    }\n    return lines;\n  }\n  buildTreePrefix(node) {\n    if (node.depth === 0) {\n      return \"\";\n    }\n    const parts = node.ancestorContinues.map((continues) => continues ? \"\\u2502  \" : \"   \");\n    const branch = node.isLast ? \"\\u2514\\u2500 \" : \"\\u251C\\u2500 \";\n    return parts.join(\"\") + branch;\n  }\n  handleInput(keyData) {\n    const kb = getKeybindings();\n    if (this.confirmingDeletePath !== null) {\n      if (kb.matches(keyData, \"tui.select.confirm\")) {\n        const pathToDelete = this.confirmingDeletePath;\n        this.setConfirmingDeletePath(null);\n        void this.onDeleteSession?.(pathToDelete);\n        return;\n      }\n      if (kb.matches(keyData, \"tui.select.cancel\")) {\n        this.setConfirmingDeletePath(null);\n        return;\n      }\n      return;\n    }\n    if (kb.matches(keyData, \"tui.input.tab\")) {\n      if (this.onToggleScope) {\n        this.onToggleScope();\n      }\n      return;\n    }\n    if (kb.matches(keyData, \"app.session.toggleSort\")) {\n      this.onToggleSort?.();\n      return;\n    }\n    if (this.keybindings.matches(keyData, \"app.session.toggleNamedFilter\")) {\n      this.onToggleNameFilter?.();\n      return;\n    }\n    if (kb.matches(keyData, \"app.session.togglePath\")) {\n      this.showPath = !this.showPath;\n      this.onTogglePath?.(this.showPath);\n      return;\n    }\n    if (kb.matches(keyData, \"app.session.delete\")) {\n      this.startDeleteConfirmationForSelectedSession();\n      return;\n    }\n    if (kb.matches(keyData, \"app.session.rename\")) {\n      const selected = this.filteredSessions[this.selectedIndex];\n      if (selected) {\n        this.onRenameSession?.(selected.session.path);\n      }\n      return;\n    }\n    if (kb.matches(keyData, \"app.session.deleteNoninvasive\")) {\n      if (this.searchInput.getValue().length > 0) {\n        this.searchInput.handleInput(keyData);\n        this.filterSessions(this.searchInput.getValue());\n        return;\n      }\n      this.startDeleteConfirmationForSelectedSession();\n      return;\n    }\n    if (kb.matches(keyData, \"tui.select.up\")) {\n      this.selectedIndex = Math.max(0, this.selectedIndex - 1);\n    } else if (kb.matches(keyData, \"tui.select.down\")) {\n      this.selectedIndex = Math.min(this.filteredSessions.length - 1, this.selectedIndex + 1);\n    } else if (kb.matches(keyData, \"tui.select.pageUp\")) {\n      this.selectedIndex = Math.max(0, this.selectedIndex - this.maxVisible);\n    } else if (kb.matches(keyData, \"tui.select.pageDown\")) {\n      this.selectedIndex = Math.min(this.filteredSessions.length - 1, this.selectedIndex + this.maxVisible);\n    } else if (kb.matches(keyData, \"tui.select.confirm\")) {\n      const selected = this.filteredSessions[this.selectedIndex];\n      if (selected && this.onSelect) {\n        this.onSelect(selected.session.path);\n      }\n    } else if (kb.matches(keyData, \"tui.select.cancel\")) {\n      if (this.onCancel) {\n        this.onCancel();\n      }\n    } else {\n      this.searchInput.handleInput(keyData);\n      this.filterSessions(this.searchInput.getValue());\n    }\n  }\n};\nasync function deleteSessionFile(sessionPath) {\n  const trashArgs = sessionPath.startsWith(\"-\") ? [\"--\", sessionPath] : [sessionPath];\n  const trashResult = spawnSync3(\"trash\", trashArgs, { encoding: \"utf-8\" });\n  const getTrashErrorHint = () => {\n    const parts = [];\n    if (trashResult.error) {\n      parts.push(trashResult.error.message);\n    }\n    const stderr = trashResult.stderr?.trim();\n    if (stderr) {\n      parts.push(stderr.split(\"\\n\")[0] ?? stderr);\n    }\n    if (parts.length === 0)\n      return null;\n    return `trash: ${parts.join(\" \\xB7 \").slice(0, 200)}`;\n  };\n  if (trashResult.status === 0 || !existsSync9(sessionPath)) {\n    return { ok: true, method: \"trash\" };\n  }\n  try {\n    await unlink(sessionPath);\n    return { ok: true, method: \"unlink\" };\n  } catch (err2) {\n    const unlinkError = err2 instanceof Error ? err2.message : String(err2);\n    const trashErrorHint = getTrashErrorHint();\n    const error = trashErrorHint ? `${unlinkError} (${trashErrorHint})` : unlinkError;\n    return { ok: false, method: \"unlink\", error };\n  }\n}\nvar SessionSelectorComponent = class extends Container {\n  handleInput(data) {\n    if (this.mode === \"rename\") {\n      const kb = getKeybindings();\n      if (kb.matches(data, \"tui.select.cancel\")) {\n        this.exitRenameMode();\n        return;\n      }\n      this.renameInput.handleInput(data);\n      return;\n    }\n    this.sessionList.handleInput(data);\n  }\n  canRename = true;\n  sessionList;\n  header;\n  keybindings;\n  scope = \"current\";\n  sortMode = \"threaded\";\n  nameFilter = \"all\";\n  currentSessions = null;\n  allSessions = null;\n  currentSessionsLoader;\n  allSessionsLoader;\n  requestRender;\n  renameSession;\n  currentLoading = false;\n  allLoading = false;\n  allLoadSeq = 0;\n  mode = \"list\";\n  renameInput = new Input();\n  renameTargetPath = null;\n  // Focusable implementation - propagate to sessionList for IME cursor positioning\n  _focused = false;\n  get focused() {\n    return this._focused;\n  }\n  set focused(value) {\n    this._focused = value;\n    this.sessionList.focused = value;\n    this.renameInput.focused = value;\n    if (value && this.mode === \"rename\") {\n      this.renameInput.focused = true;\n    }\n  }\n  buildBaseLayout(content, options) {\n    this.clear();\n    this.addChild(new Spacer(1));\n    this.addChild(new DynamicBorder((s) => theme.fg(\"accent\", s)));\n    this.addChild(new Spacer(1));\n    if (options?.showHeader ?? true) {\n      this.addChild(this.header);\n      this.addChild(new Spacer(1));\n    }\n    this.addChild(content);\n    this.addChild(new Spacer(1));\n    this.addChild(new DynamicBorder((s) => theme.fg(\"accent\", s)));\n  }\n  constructor(currentSessionsLoader, allSessionsLoader, onSelect, onCancel, onExit, requestRender, options, currentSessionFilePath) {\n    super();\n    this.keybindings = options?.keybindings ?? KeybindingsManager2.create();\n    this.currentSessionsLoader = currentSessionsLoader;\n    this.allSessionsLoader = allSessionsLoader;\n    this.requestRender = requestRender;\n    this.header = new SessionSelectorHeader(this.scope, this.sortMode, this.nameFilter, this.requestRender);\n    const renameSession = options?.renameSession;\n    this.renameSession = renameSession;\n    this.canRename = !!renameSession;\n    this.header.setShowRenameHint(options?.showRenameHint ?? this.canRename);\n    this.sessionList = new SessionList([], false, this.sortMode, this.nameFilter, this.keybindings, currentSessionFilePath);\n    this.buildBaseLayout(this.sessionList);\n    this.renameInput.onSubmit = (value) => {\n      void this.confirmRename(value);\n    };\n    const clearStatusMessage = () => this.header.setStatusMessage(null);\n    this.sessionList.onSelect = (sessionPath) => {\n      clearStatusMessage();\n      onSelect(sessionPath);\n    };\n    this.sessionList.onCancel = () => {\n      clearStatusMessage();\n      onCancel();\n    };\n    this.sessionList.onExit = () => {\n      clearStatusMessage();\n      onExit();\n    };\n    this.sessionList.onToggleScope = () => this.toggleScope();\n    this.sessionList.onToggleSort = () => this.toggleSortMode();\n    this.sessionList.onToggleNameFilter = () => this.toggleNameFilter();\n    this.sessionList.onRenameSession = (sessionPath) => {\n      if (!renameSession)\n        return;\n      if (this.scope === \"current\" && this.currentLoading)\n        return;\n      if (this.scope === \"all\" && this.allLoading)\n        return;\n      const sessions = this.scope === \"all\" ? this.allSessions ?? [] : this.currentSessions ?? [];\n      const session = sessions.find((s) => s.path === sessionPath);\n      this.enterRenameMode(sessionPath, session?.name);\n    };\n    this.sessionList.onTogglePath = (showPath) => {\n      this.header.setShowPath(showPath);\n      this.requestRender();\n    };\n    this.sessionList.onDeleteConfirmationChange = (path12) => {\n      this.header.setConfirmingDeletePath(path12);\n      this.requestRender();\n    };\n    this.sessionList.onError = (msg) => {\n      this.header.setStatusMessage({ type: \"error\", message: msg }, 3e3);\n      this.requestRender();\n    };\n    this.sessionList.onDeleteSession = async (sessionPath) => {\n      const result = await deleteSessionFile(sessionPath);\n      if (result.ok) {\n        if (this.currentSessions) {\n          this.currentSessions = this.currentSessions.filter((s) => s.path !== sessionPath);\n        }\n        if (this.allSessions) {\n          this.allSessions = this.allSessions.filter((s) => s.path !== sessionPath);\n        }\n        const sessions = this.scope === \"all\" ? this.allSessions ?? [] : this.currentSessions ?? [];\n        const showCwd = this.scope === \"all\";\n        this.sessionList.setSessions(sessions, showCwd);\n        const msg = result.method === \"trash\" ? \"Session moved to trash\" : \"Session deleted\";\n        this.header.setStatusMessage({ type: \"info\", message: msg }, 2e3);\n        await this.refreshSessionsAfterMutation();\n      } else {\n        const errorMessage2 = result.error ?? \"Unknown error\";\n        this.header.setStatusMessage({ type: \"error\", message: `Failed to delete: ${errorMessage2}` }, 3e3);\n      }\n      this.requestRender();\n    };\n    this.loadCurrentSessions();\n  }\n  loadCurrentSessions() {\n    void this.loadScope(\"current\", \"initial\");\n  }\n  enterRenameMode(sessionPath, currentName) {\n    this.mode = \"rename\";\n    this.renameTargetPath = sessionPath;\n    this.renameInput.setValue(currentName ?? \"\");\n    this.renameInput.focused = true;\n    const panel = new Container();\n    panel.addChild(new Text(theme.bold(\"Rename Session\"), 1, 0));\n    panel.addChild(new Spacer(1));\n    panel.addChild(this.renameInput);\n    panel.addChild(new Spacer(1));\n    panel.addChild(new Text(theme.fg(\"muted\", `${keyText(\"tui.select.confirm\")} to save \\xB7 ${keyText(\"tui.select.cancel\")} to cancel`), 1, 0));\n    this.buildBaseLayout(panel, { showHeader: false });\n    this.requestRender();\n  }\n  exitRenameMode() {\n    this.mode = \"list\";\n    this.renameTargetPath = null;\n    this.buildBaseLayout(this.sessionList);\n    this.requestRender();\n  }\n  async confirmRename(value) {\n    const next = value.trim();\n    if (!next)\n      return;\n    const target = this.renameTargetPath;\n    if (!target) {\n      this.exitRenameMode();\n      return;\n    }\n    const renameSession = this.renameSession;\n    if (!renameSession) {\n      this.exitRenameMode();\n      return;\n    }\n    try {\n      await renameSession(target, next);\n      await this.refreshSessionsAfterMutation();\n    } finally {\n      this.exitRenameMode();\n    }\n  }\n  async loadScope(scope, reason) {\n    const showCwd = scope === \"all\";\n    if (scope === \"current\") {\n      this.currentLoading = true;\n    } else {\n      this.allLoading = true;\n    }\n    const seq = scope === \"all\" ? ++this.allLoadSeq : void 0;\n    this.header.setScope(scope);\n    this.header.setLoading(true);\n    this.requestRender();\n    const onProgress = (loaded, total) => {\n      if (scope !== this.scope)\n        return;\n      if (seq !== void 0 && seq !== this.allLoadSeq)\n        return;\n      this.header.setProgress(loaded, total);\n      this.requestRender();\n    };\n    try {\n      const sessions = await (scope === \"current\" ? this.currentSessionsLoader(onProgress) : this.allSessionsLoader(onProgress));\n      if (scope === \"current\") {\n        this.currentSessions = sessions;\n        this.currentLoading = false;\n      } else {\n        this.allSessions = sessions;\n        this.allLoading = false;\n      }\n      if (scope !== this.scope)\n        return;\n      if (seq !== void 0 && seq !== this.allLoadSeq)\n        return;\n      this.header.setLoading(false);\n      this.sessionList.setSessions(sessions, showCwd);\n      this.requestRender();\n    } catch (err2) {\n      if (scope === \"current\") {\n        this.currentLoading = false;\n      } else {\n        this.allLoading = false;\n      }\n      if (scope !== this.scope)\n        return;\n      if (seq !== void 0 && seq !== this.allLoadSeq)\n        return;\n      const message = err2 instanceof Error ? err2.message : String(err2);\n      this.header.setLoading(false);\n      this.header.setStatusMessage({ type: \"error\", message: `Failed to load sessions: ${message}` }, 4e3);\n      if (reason === \"initial\") {\n        this.sessionList.setSessions([], showCwd);\n      }\n      this.requestRender();\n    }\n  }\n  toggleSortMode() {\n    this.sortMode = this.sortMode === \"threaded\" ? \"recent\" : this.sortMode === \"recent\" ? \"relevance\" : \"threaded\";\n    this.header.setSortMode(this.sortMode);\n    this.sessionList.setSortMode(this.sortMode);\n    this.requestRender();\n  }\n  toggleNameFilter() {\n    this.nameFilter = this.nameFilter === \"all\" ? \"named\" : \"all\";\n    this.header.setNameFilter(this.nameFilter);\n    this.sessionList.setNameFilter(this.nameFilter);\n    this.requestRender();\n  }\n  async refreshSessionsAfterMutation() {\n    await this.loadScope(this.scope, \"refresh\");\n  }\n  toggleScope() {\n    if (this.scope === \"current\") {\n      this.scope = \"all\";\n      this.header.setScope(this.scope);\n      if (this.allSessions !== null) {\n        this.header.setLoading(false);\n        this.sessionList.setSessions(this.allSessions, true);\n        this.requestRender();\n        return;\n      }\n      if (!this.allLoading) {\n        void this.loadScope(\"all\", \"toggle\");\n      }\n      return;\n    }\n    this.scope = \"current\";\n    this.header.setScope(this.scope);\n    this.header.setLoading(this.currentLoading);\n    this.sessionList.setSessions(this.currentSessions ?? [], false);\n    this.requestRender();\n  }\n  getSessionList() {\n    return this.sessionList;\n  }\n};\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/cli/session-picker.js\nasync function selectSession(currentSessionsLoader, allSessionsLoader, settingsManager) {\n  const ui = await createStartupTui(settingsManager);\n  return new Promise((resolve15) => {\n    const keybindings = KeybindingsManager2.create();\n    setKeybindings(keybindings);\n    let resolved = false;\n    const selector = new SessionSelectorComponent(currentSessionsLoader, allSessionsLoader, (path12) => {\n      if (!resolved) {\n        resolved = true;\n        ui.stop();\n        resolve15(path12);\n      }\n    }, () => {\n      if (!resolved) {\n        resolved = true;\n        ui.stop();\n        resolve15(null);\n      }\n    }, () => {\n      ui.stop();\n      process.exit(0);\n    }, () => ui.requestRender(), { showRenameHint: false, keybindings });\n    ui.addChild(selector);\n    ui.setFocus(selector.getSessionList());\n    startStartupTui(ui, settingsManager);\n  });\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session-runtime.js\nimport { copyFileSync, existsSync as existsSync23, mkdirSync as mkdirSync10 } from \"node:fs\";\nimport { basename as basename11, join as join34, resolve as resolve13 } from \"node:path\";\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/core/extensions/runner.js\nvar RESERVED_KEYBINDINGS_FOR_EXTENSION_CONFLICTS = [\n  \"app.interrupt\",\n  \"app.clear\",\n  \"app.exit\",\n  \"app.suspend\",\n  \"app.thinking.cycle\",\n  \"app.model.cycleForward\",\n  \"app.model.cycleBackward\",\n  \"app.model.select\",\n  \"app.tools.expand\",\n  \"app.thinking.toggle\",\n  \"app.editor.external\",\n  \"app.message.copy\",\n  \"app.message.followUp\",\n  \"tui.input.submit\",\n  \"tui.select.confirm\",\n  \"tui.select.cancel\",\n  \"tui.input.copy\",\n  \"tui.editor.deleteToLineEnd\"\n];\nvar buildBuiltinKeybindings = (resolvedKeybindings) => {\n  const builtinKeybindings = {};\n  for (const [keybinding, keys] of Object.entries(resolvedKeybindings)) {\n    if (keys === void 0)\n      continue;\n    const keyList = Array.isArray(keys) ? keys : [keys];\n    const restrictOverride = RESERVED_KEYBINDINGS_FOR_EXTENSION_CONFLICTS.includes(keybinding);\n    for (const key of keyList) {\n      const normalizedKey = key.toLowerCase();\n      const existing = builtinKeybindings[normalizedKey];\n      if (existing?.restrictOverride && !restrictOverride)\n        continue;\n      builtinKeybindings[normalizedKey] = {\n        keybinding,\n        restrictOverride\n      };\n    }\n  }\n  return builtinKeybindings;\n};\nasync function emitSessionShutdownEvent(extensionRunner, event) {\n  if (extensionRunner.hasHandlers(\"session_shutdown\")) {\n    await extensionRunner.emit(event);\n    return true;\n  }\n  return false;\n}\nasync function emitProjectTrustEvent(extensionsResult, event, ctx) {\n  const errors = [];\n  for (const ext of extensionsResult.extensions) {\n    const handlers = ext.handlers.get(\"project_trust\");\n    if (!handlers || handlers.length === 0)\n      continue;\n    for (const handler of handlers) {\n      try {\n        const handlerResult = await handler(event, ctx);\n        if (handlerResult.trusted === \"undecided\") {\n          continue;\n        }\n        return { result: handlerResult, errors };\n      } catch (error) {\n        errors.push({\n          extensionPath: ext.path,\n          event: event.type,\n          error: error instanceof Error ? error.message : String(error),\n          stack: error instanceof Error ? error.stack : void 0\n        });\n      }\n    }\n  }\n  return { errors };\n}\nvar noOpUIContext = {\n  select: async () => void 0,\n  confirm: async () => false,\n  input: async () => void 0,\n  notify: () => {\n  },\n  onTerminalInput: () => () => {\n  },\n  setStatus: () => {\n  },\n  setWorkingMessage: () => {\n  },\n  setWorkingVisible: () => {\n  },\n  setWorkingIndicator: () => {\n  },\n  setHiddenThinkingLabel: () => {\n  },\n  setWidget: () => {\n  },\n  setFooter: () => {\n  },\n  setHeader: () => {\n  },\n  setTitle: () => {\n  },\n  custom: async () => void 0,\n  pasteToEditor: () => {\n  },\n  setEditorText: () => {\n  },\n  getEditorText: () => \"\",\n  editor: async () => void 0,\n  addAutocompleteProvider: () => {\n  },\n  setEditorComponent: () => {\n  },\n  getEditorComponent: () => void 0,\n  get theme() {\n    return theme;\n  },\n  getAllThemes: () => [],\n  getTheme: () => void 0,\n  setTheme: (_theme) => ({ success: false, error: \"UI not available\" }),\n  getToolsExpanded: () => false,\n  setToolsExpanded: () => {\n  }\n};\nvar ExtensionRunner = class {\n  extensions;\n  runtime;\n  uiContext;\n  mode = \"print\";\n  cwd;\n  sessionManager;\n  modelRegistry;\n  errorListeners = /* @__PURE__ */ new Set();\n  getModel = () => void 0;\n  getScopedModels = () => [];\n  isIdleFn = () => true;\n  isProjectTrustedFn = () => true;\n  getSignalFn = () => void 0;\n  waitForIdleFn = async () => {\n  };\n  abortFn = () => {\n  };\n  hasPendingMessagesFn = () => false;\n  getContextUsageFn = () => void 0;\n  compactFn = () => {\n  };\n  getSystemPromptFn = () => \"\";\n  getSystemPromptOptionsFn = () => ({ cwd: this.cwd });\n  newSessionHandler = async () => ({ cancelled: false });\n  forkHandler = async () => ({ cancelled: false });\n  navigateTreeHandler = async () => ({ cancelled: false });\n  switchSessionHandler = async () => ({ cancelled: false });\n  reloadHandler = async () => {\n  };\n  shutdownHandler = () => {\n  };\n  shortcutDiagnostics = [];\n  commandDiagnostics = [];\n  staleMessage;\n  constructor(extensions, runtime, cwd, sessionManager, modelRegistry) {\n    this.extensions = extensions;\n    this.runtime = runtime;\n    this.uiContext = noOpUIContext;\n    this.cwd = cwd;\n    this.sessionManager = sessionManager;\n    this.modelRegistry = modelRegistry;\n  }\n  bindCore(actions, contextActions, providerActions) {\n    this.runtime.sendMessage = actions.sendMessage;\n    this.runtime.sendUserMessage = actions.sendUserMessage;\n    this.runtime.appendEntry = actions.appendEntry;\n    this.runtime.setSessionName = actions.setSessionName;\n    this.runtime.getSessionName = actions.getSessionName;\n    this.runtime.setLabel = actions.setLabel;\n    this.runtime.getActiveTools = actions.getActiveTools;\n    this.runtime.getAllTools = actions.getAllTools;\n    this.runtime.setActiveTools = actions.setActiveTools;\n    this.runtime.refreshTools = actions.refreshTools;\n    this.runtime.getCommands = actions.getCommands;\n    this.runtime.setModel = actions.setModel;\n    this.runtime.getThinkingLevel = actions.getThinkingLevel;\n    this.runtime.setThinkingLevel = actions.setThinkingLevel;\n    this.getModel = contextActions.getModel;\n    this.getScopedModels = contextActions.getScopedModels;\n    this.isIdleFn = contextActions.isIdle;\n    this.isProjectTrustedFn = contextActions.isProjectTrusted;\n    this.getSignalFn = contextActions.getSignal;\n    this.abortFn = contextActions.abort;\n    this.hasPendingMessagesFn = contextActions.hasPendingMessages;\n    this.shutdownHandler = contextActions.shutdown;\n    this.getContextUsageFn = contextActions.getContextUsage;\n    this.compactFn = contextActions.compact;\n    this.getSystemPromptFn = contextActions.getSystemPrompt;\n    this.getSystemPromptOptionsFn = contextActions.getSystemPromptOptions ?? (() => ({ cwd: this.cwd }));\n    for (const { name, config, extensionPath } of this.runtime.pendingProviderRegistrations) {\n      try {\n        if (providerActions?.registerProvider) {\n          providerActions.registerProvider(name, config);\n        } else {\n          this.modelRegistry.registerProvider(name, config);\n        }\n      } catch (err2) {\n        this.emitError({\n          extensionPath,\n          event: \"register_provider\",\n          error: err2 instanceof Error ? err2.message : String(err2),\n          stack: err2 instanceof Error ? err2.stack : void 0\n        });\n      }\n    }\n    this.runtime.pendingProviderRegistrations = [];\n    for (const { provider, extensionPath } of this.runtime.pendingNativeProviderRegistrations) {\n      try {\n        if (providerActions?.registerNativeProvider) {\n          providerActions.registerNativeProvider(provider);\n        } else {\n          this.modelRegistry.registerProvider(provider);\n        }\n      } catch (err2) {\n        this.emitError({\n          extensionPath,\n          event: \"register_provider\",\n          error: err2 instanceof Error ? err2.message : String(err2),\n          stack: err2 instanceof Error ? err2.stack : void 0\n        });\n      }\n    }\n    this.runtime.pendingNativeProviderRegistrations = [];\n    this.runtime.registerProvider = (name, config) => {\n      if (providerActions?.registerProvider) {\n        providerActions.registerProvider(name, config);\n        return;\n      }\n      this.modelRegistry.registerProvider(name, config);\n    };\n    this.runtime.registerNativeProvider = (provider) => {\n      if (providerActions?.registerNativeProvider) {\n        providerActions.registerNativeProvider(provider);\n        return;\n      }\n      this.modelRegistry.registerProvider(provider);\n    };\n    this.runtime.unregisterProvider = (name) => {\n      if (providerActions?.unregisterProvider) {\n        providerActions.unregisterProvider(name);\n        return;\n      }\n      this.modelRegistry.unregisterProvider(name);\n    };\n  }\n  bindCommandContext(actions) {\n    if (actions) {\n      this.waitForIdleFn = actions.waitForIdle;\n      this.newSessionHandler = actions.newSession;\n      this.forkHandler = actions.fork;\n      this.navigateTreeHandler = actions.navigateTree;\n      this.switchSessionHandler = actions.switchSession;\n      this.reloadHandler = actions.reload;\n      return;\n    }\n    this.waitForIdleFn = async () => {\n    };\n    this.newSessionHandler = async () => ({ cancelled: false });\n    this.forkHandler = async () => ({ cancelled: false });\n    this.navigateTreeHandler = async () => ({ cancelled: false });\n    this.switchSessionHandler = async () => ({ cancelled: false });\n    this.reloadHandler = async () => {\n    };\n  }\n  setUIContext(uiContext, mode = \"print\") {\n    this.uiContext = uiContext ?? noOpUIContext;\n    this.mode = mode;\n  }\n  getUIContext() {\n    return this.uiContext;\n  }\n  hasUI() {\n    return this.uiContext !== noOpUIContext;\n  }\n  getExtensionPaths() {\n    return this.extensions.map((e) => e.path);\n  }\n  /** Get all registered tools from all extensions (first registration per name wins). */\n  getAllRegisteredTools() {\n    const toolsByName = /* @__PURE__ */ new Map();\n    for (const ext of this.extensions) {\n      for (const tool of ext.tools.values()) {\n        if (!toolsByName.has(tool.definition.name)) {\n          toolsByName.set(tool.definition.name, tool);\n        }\n      }\n    }\n    return Array.from(toolsByName.values());\n  }\n  /** Get a tool definition by name. Returns undefined if not found. */\n  getToolDefinition(toolName) {\n    for (const ext of this.extensions) {\n      const tool = ext.tools.get(toolName);\n      if (tool) {\n        return tool.definition;\n      }\n    }\n    return void 0;\n  }\n  getFlags() {\n    const allFlags = /* @__PURE__ */ new Map();\n    for (const ext of this.extensions) {\n      for (const [name, flag] of ext.flags) {\n        if (!allFlags.has(name)) {\n          allFlags.set(name, flag);\n        }\n      }\n    }\n    return allFlags;\n  }\n  setFlagValue(name, value) {\n    this.runtime.flagValues.set(name, value);\n  }\n  getFlagValues() {\n    return new Map(this.runtime.flagValues);\n  }\n  getShortcuts(resolvedKeybindings) {\n    this.shortcutDiagnostics = [];\n    const builtinKeybindings = buildBuiltinKeybindings(resolvedKeybindings);\n    const extensionShortcuts = /* @__PURE__ */ new Map();\n    const addDiagnostic = (message, extensionPath) => {\n      this.shortcutDiagnostics.push({ type: \"warning\", message, path: extensionPath });\n      if (!this.hasUI()) {\n        console.warn(message);\n      }\n    };\n    for (const ext of this.extensions) {\n      for (const [key, shortcut] of ext.shortcuts) {\n        const normalizedKey = key.toLowerCase();\n        const builtInKeybinding = builtinKeybindings[normalizedKey];\n        if (builtInKeybinding?.restrictOverride === true) {\n          addDiagnostic(`Extension shortcut '${key}' from ${shortcut.extensionPath} conflicts with built-in shortcut. Skipping.`, shortcut.extensionPath);\n          continue;\n        }\n        if (builtInKeybinding?.restrictOverride === false) {\n          addDiagnostic(`Extension shortcut conflict: '${key}' is built-in shortcut for ${builtInKeybinding.keybinding} and ${shortcut.extensionPath}. Using ${shortcut.extensionPath}.`, shortcut.extensionPath);\n        }\n        const existingExtensionShortcut = extensionShortcuts.get(normalizedKey);\n        if (existingExtensionShortcut) {\n          addDiagnostic(`Extension shortcut conflict: '${key}' registered by both ${existingExtensionShortcut.extensionPath} and ${shortcut.extensionPath}. Using ${shortcut.extensionPath}.`, shortcut.extensionPath);\n        }\n        extensionShortcuts.set(normalizedKey, shortcut);\n      }\n    }\n    return extensionShortcuts;\n  }\n  getShortcutDiagnostics() {\n    return this.shortcutDiagnostics;\n  }\n  invalidate(message = \"This extension ctx is stale after session replacement or reload. Do not use a captured pi or command ctx after ctx.newSession(), ctx.fork(), ctx.switchSession(), or ctx.reload(). For newSession, fork, and switchSession, move post-replacement work into withSession and use the ctx passed to withSession. For reload, do not use the old ctx after await ctx.reload().\") {\n    if (!this.staleMessage) {\n      this.staleMessage = message;\n      this.runtime.invalidate(message);\n    }\n  }\n  assertActive() {\n    if (this.staleMessage) {\n      throw new Error(this.staleMessage);\n    }\n  }\n  onError(listener) {\n    this.errorListeners.add(listener);\n    return () => this.errorListeners.delete(listener);\n  }\n  emitError(error) {\n    for (const listener of this.errorListeners) {\n      listener(error);\n    }\n  }\n  hasHandlers(eventType) {\n    for (const ext of this.extensions) {\n      const handlers = ext.handlers.get(eventType);\n      if (handlers && handlers.length > 0) {\n        return true;\n      }\n    }\n    return false;\n  }\n  getMessageRenderer(customType) {\n    for (const ext of this.extensions) {\n      const renderer = ext.messageRenderers.get(customType);\n      if (renderer) {\n        return renderer;\n      }\n    }\n    return void 0;\n  }\n  getMarkdownTransformers() {\n    return this.extensions.flatMap((ext) => ext.markdownTransformer ? [ext.markdownTransformer] : []);\n  }\n  getEntryRenderer(customType) {\n    for (const ext of this.extensions) {\n      const renderer = ext.entryRenderers?.get(customType);\n      if (renderer) {\n        return renderer;\n      }\n    }\n    return void 0;\n  }\n  resolveRegisteredCommands() {\n    const commands = [];\n    const counts = /* @__PURE__ */ new Map();\n    for (const ext of this.extensions) {\n      for (const command of ext.commands.values()) {\n        commands.push(command);\n        counts.set(command.name, (counts.get(command.name) ?? 0) + 1);\n      }\n    }\n    const seen = /* @__PURE__ */ new Map();\n    const takenInvocationNames = /* @__PURE__ */ new Set();\n    return commands.map((command) => {\n      const occurrence = (seen.get(command.name) ?? 0) + 1;\n      seen.set(command.name, occurrence);\n      let invocationName = (counts.get(command.name) ?? 0) > 1 ? `${command.name}:${occurrence}` : command.name;\n      if (takenInvocationNames.has(invocationName)) {\n        let suffix = occurrence;\n        do {\n          suffix++;\n          invocationName = `${command.name}:${suffix}`;\n        } while (takenInvocationNames.has(invocationName));\n      }\n      takenInvocationNames.add(invocationName);\n      return {\n        ...command,\n        invocationName\n      };\n    });\n  }\n  getModelRegistry() {\n    return this.modelRegistry;\n  }\n  getRegisteredCommands() {\n    this.commandDiagnostics = [];\n    return this.resolveRegisteredCommands();\n  }\n  getCommandDiagnostics() {\n    return this.commandDiagnostics;\n  }\n  getCommand(name) {\n    return this.resolveRegisteredCommands().find((command) => command.invocationName === name);\n  }\n  /**\n   * Request a graceful shutdown. Called by extension tools and event handlers.\n   * The actual shutdown behavior is provided by the mode via bindExtensions().\n   */\n  shutdown() {\n    this.shutdownHandler();\n  }\n  getActiveTools() {\n    this.assertActive();\n    return this.runtime.getActiveTools();\n  }\n  /**\n   * Create an ExtensionContext for use in event handlers and tool execution.\n   * Context values are resolved at call time, so changes via bindCore/bindUI are reflected.\n   */\n  createContext() {\n    const runner = this;\n    const getModel2 = this.getModel;\n    const getScopedModels = this.getScopedModels;\n    return {\n      get ui() {\n        runner.assertActive();\n        return runner.uiContext;\n      },\n      get mode() {\n        runner.assertActive();\n        return runner.mode;\n      },\n      get hasUI() {\n        runner.assertActive();\n        return runner.hasUI();\n      },\n      get cwd() {\n        runner.assertActive();\n        return runner.cwd;\n      },\n      get sessionManager() {\n        runner.assertActive();\n        return runner.sessionManager;\n      },\n      get modelRegistry() {\n        runner.assertActive();\n        return runner.modelRegistry;\n      },\n      get model() {\n        runner.assertActive();\n        return getModel2();\n      },\n      get scopedModels() {\n        runner.assertActive();\n        return getScopedModels();\n      },\n      get thinkingLevel() {\n        runner.assertActive();\n        return runner.runtime.getThinkingLevel();\n      },\n      isIdle: () => {\n        runner.assertActive();\n        return runner.isIdleFn();\n      },\n      isProjectTrusted: () => {\n        runner.assertActive();\n        return runner.isProjectTrustedFn();\n      },\n      get signal() {\n        runner.assertActive();\n        return runner.getSignalFn();\n      },\n      abort: () => {\n        runner.assertActive();\n        runner.abortFn();\n      },\n      hasPendingMessages: () => {\n        runner.assertActive();\n        return runner.hasPendingMessagesFn();\n      },\n      shutdown: () => {\n        runner.assertActive();\n        runner.shutdownHandler();\n      },\n      getContextUsage: () => {\n        runner.assertActive();\n        return runner.getContextUsageFn();\n      },\n      compact: (options) => {\n        runner.assertActive();\n        runner.compactFn(options);\n      },\n      getSystemPrompt: () => {\n        runner.assertActive();\n        return runner.getSystemPromptFn();\n      }\n    };\n  }\n  createCommandContext() {\n    const context = Object.defineProperties({}, Object.getOwnPropertyDescriptors(this.createContext()));\n    context.getSystemPromptOptions = () => {\n      this.assertActive();\n      return this.getSystemPromptOptionsFn();\n    };\n    context.waitForIdle = () => {\n      this.assertActive();\n      return this.waitForIdleFn();\n    };\n    context.newSession = (options) => {\n      this.assertActive();\n      return this.newSessionHandler(options);\n    };\n    context.fork = (entryId, options) => {\n      this.assertActive();\n      return this.forkHandler(entryId, options);\n    };\n    context.navigateTree = (targetId, options) => {\n      this.assertActive();\n      return this.navigateTreeHandler(targetId, options);\n    };\n    context.switchSession = (sessionPath, options) => {\n      this.assertActive();\n      return this.switchSessionHandler(sessionPath, options);\n    };\n    context.reload = () => {\n      this.assertActive();\n      return this.reloadHandler();\n    };\n    return context;\n  }\n  isSessionBeforeEvent(event) {\n    return event.type === \"session_before_switch\" || event.type === \"session_before_fork\" || event.type === \"session_before_compact\" || event.type === \"session_before_tree\";\n  }\n  async emit(event) {\n    const ctx = this.createContext();\n    let result;\n    for (const ext of this.extensions) {\n      const handlers = ext.handlers.get(event.type);\n      if (!handlers || handlers.length === 0)\n        continue;\n      for (const handler of handlers) {\n        try {\n          const handlerResult = await handler(event, ctx);\n          if (this.isSessionBeforeEvent(event) && handlerResult) {\n            result = handlerResult;\n            if (result.cancel) {\n              return result;\n            }\n          }\n        } catch (err2) {\n          const message = err2 instanceof Error ? err2.message : String(err2);\n          const stack = err2 instanceof Error ? err2.stack : void 0;\n          this.emitError({\n            extensionPath: ext.path,\n            event: event.type,\n            error: message,\n            stack\n          });\n        }\n      }\n    }\n    return result;\n  }\n  async emitMessageEnd(event) {\n    const ctx = this.createContext();\n    let currentMessage = event.message;\n    let modified = false;\n    for (const ext of this.extensions) {\n      const handlers = ext.handlers.get(\"message_end\");\n      if (!handlers || handlers.length === 0)\n        continue;\n      for (const handler of handlers) {\n        try {\n          const currentEvent = { ...event, message: currentMessage };\n          const handlerResult = await handler(currentEvent, ctx);\n          if (!handlerResult?.message)\n            continue;\n          if (handlerResult.message.role !== currentMessage.role) {\n            this.emitError({\n              extensionPath: ext.path,\n              event: \"message_end\",\n              error: \"message_end handlers must return a message with the same role\"\n            });\n            continue;\n          }\n          currentMessage = handlerResult.message;\n          modified = true;\n        } catch (err2) {\n          const message = err2 instanceof Error ? err2.message : String(err2);\n          const stack = err2 instanceof Error ? err2.stack : void 0;\n          this.emitError({\n            extensionPath: ext.path,\n            event: \"message_end\",\n            error: message,\n            stack\n          });\n        }\n      }\n    }\n    return modified ? currentMessage : void 0;\n  }\n  async emitToolResult(event) {\n    const ctx = this.createContext();\n    const currentEvent = { ...event };\n    let modified = false;\n    for (const ext of this.extensions) {\n      const handlers = ext.handlers.get(\"tool_result\");\n      if (!handlers || handlers.length === 0)\n        continue;\n      for (const handler of handlers) {\n        try {\n          const handlerResult = await handler(currentEvent, ctx);\n          if (!handlerResult)\n            continue;\n          if (handlerResult.content !== void 0) {\n            currentEvent.content = handlerResult.content;\n            modified = true;\n          }\n          if (handlerResult.details !== void 0) {\n            currentEvent.details = handlerResult.details;\n            modified = true;\n          }\n          if (handlerResult.isError !== void 0) {\n            currentEvent.isError = handlerResult.isError;\n            modified = true;\n          }\n          if (handlerResult.usage !== void 0) {\n            currentEvent.usage = handlerResult.usage;\n            modified = true;\n          }\n        } catch (err2) {\n          const message = err2 instanceof Error ? err2.message : String(err2);\n          const stack = err2 instanceof Error ? err2.stack : void 0;\n          this.emitError({\n            extensionPath: ext.path,\n            event: \"tool_result\",\n            error: message,\n            stack\n          });\n        }\n      }\n    }\n    if (!modified) {\n      return void 0;\n    }\n    return {\n      content: currentEvent.content,\n      details: currentEvent.details,\n      isError: currentEvent.isError,\n      usage: currentEvent.usage\n    };\n  }\n  async emitToolCall(event) {\n    const ctx = this.createContext();\n    let result;\n    for (const ext of this.extensions) {\n      const handlers = ext.handlers.get(\"tool_call\");\n      if (!handlers || handlers.length === 0)\n        continue;\n      for (const handler of handlers) {\n        const handlerResult = await handler(event, ctx);\n        if (handlerResult) {\n          result = handlerResult;\n          if (result.block) {\n            return result;\n          }\n        }\n      }\n    }\n    return result;\n  }\n  async emitUserBash(event) {\n    const ctx = this.createContext();\n    for (const ext of this.extensions) {\n      const handlers = ext.handlers.get(\"user_bash\");\n      if (!handlers || handlers.length === 0)\n        continue;\n      for (const handler of handlers) {\n        try {\n          const handlerResult = await handler(event, ctx);\n          if (handlerResult) {\n            return handlerResult;\n          }\n        } catch (err2) {\n          const message = err2 instanceof Error ? err2.message : String(err2);\n          const stack = err2 instanceof Error ? err2.stack : void 0;\n          this.emitError({\n            extensionPath: ext.path,\n            event: \"user_bash\",\n            error: message,\n            stack\n          });\n        }\n      }\n    }\n    return void 0;\n  }\n  async emitContext(messages) {\n    const ctx = this.createContext();\n    let currentMessages = structuredClone(messages);\n    for (const ext of this.extensions) {\n      const handlers = ext.handlers.get(\"context\");\n      if (!handlers || handlers.length === 0)\n        continue;\n      for (const handler of handlers) {\n        try {\n          const event = { type: \"context\", messages: currentMessages };\n          const handlerResult = await handler(event, ctx);\n          if (handlerResult && handlerResult.messages) {\n            currentMessages = handlerResult.messages;\n          }\n        } catch (err2) {\n          const message = err2 instanceof Error ? err2.message : String(err2);\n          const stack = err2 instanceof Error ? err2.stack : void 0;\n          this.emitError({\n            extensionPath: ext.path,\n            event: \"context\",\n            error: message,\n            stack\n          });\n        }\n      }\n    }\n    return currentMessages;\n  }\n  async emitBeforeProviderRequest(payload) {\n    const ctx = this.createContext();\n    let currentPayload = payload;\n    for (const ext of this.extensions) {\n      const handlers = ext.handlers.get(\"before_provider_request\");\n      if (!handlers || handlers.length === 0)\n        continue;\n      for (const handler of handlers) {\n        try {\n          const event = {\n            type: \"before_provider_request\",\n            payload: currentPayload\n          };\n          const handlerResult = await handler(event, ctx);\n          if (handlerResult !== void 0) {\n            currentPayload = handlerResult;\n          }\n        } catch (err2) {\n          const message = err2 instanceof Error ? err2.message : String(err2);\n          const stack = err2 instanceof Error ? err2.stack : void 0;\n          this.emitError({\n            extensionPath: ext.path,\n            event: \"before_provider_request\",\n            error: message,\n            stack\n          });\n        }\n      }\n    }\n    return currentPayload;\n  }\n  async emitBeforeProviderHeaders(headers) {\n    const ctx = this.createContext();\n    for (const ext of this.extensions) {\n      const handlers = ext.handlers.get(\"before_provider_headers\");\n      if (!handlers || handlers.length === 0)\n        continue;\n      for (const handler of handlers) {\n        try {\n          const event = {\n            type: \"before_provider_headers\",\n            headers\n          };\n          await handler(event, ctx);\n        } catch (err2) {\n          const message = err2 instanceof Error ? err2.message : String(err2);\n          const stack = err2 instanceof Error ? err2.stack : void 0;\n          this.emitError({\n            extensionPath: ext.path,\n            event: \"before_provider_headers\",\n            error: message,\n            stack\n          });\n        }\n      }\n    }\n    return headers;\n  }\n  async emitBeforeAgentStart(prompt, images, systemPrompt, systemPromptOptions) {\n    let currentSystemPrompt = systemPrompt;\n    const ctx = Object.defineProperties({}, Object.getOwnPropertyDescriptors(this.createContext()));\n    ctx.getSystemPrompt = () => {\n      this.assertActive();\n      return currentSystemPrompt;\n    };\n    const messages = [];\n    let systemPromptModified = false;\n    for (const ext of this.extensions) {\n      const handlers = ext.handlers.get(\"before_agent_start\");\n      if (!handlers || handlers.length === 0)\n        continue;\n      for (const handler of handlers) {\n        try {\n          const event = {\n            type: \"before_agent_start\",\n            prompt,\n            images,\n            systemPrompt: currentSystemPrompt,\n            systemPromptOptions\n          };\n          const handlerResult = await handler(event, ctx);\n          if (handlerResult) {\n            const result = handlerResult;\n            if (result.message) {\n              messages.push(result.message);\n            }\n            if (result.systemPrompt !== void 0) {\n              currentSystemPrompt = result.systemPrompt;\n              systemPromptModified = true;\n            }\n          }\n        } catch (err2) {\n          const message = err2 instanceof Error ? err2.message : String(err2);\n          const stack = err2 instanceof Error ? err2.stack : void 0;\n          this.emitError({\n            extensionPath: ext.path,\n            event: \"before_agent_start\",\n            error: message,\n            stack\n          });\n        }\n      }\n    }\n    if (messages.length > 0 || systemPromptModified) {\n      return {\n        messages: messages.length > 0 ? messages : void 0,\n        systemPrompt: systemPromptModified ? currentSystemPrompt : void 0\n      };\n    }\n    return void 0;\n  }\n  async emitResourcesDiscover(cwd, reason) {\n    const ctx = this.createContext();\n    const skillPaths = [];\n    const promptPaths = [];\n    const themePaths = [];\n    for (const ext of this.extensions) {\n      const handlers = ext.handlers.get(\"resources_discover\");\n      if (!handlers || handlers.length === 0)\n        continue;\n      for (const handler of handlers) {\n        try {\n          const event = { type: \"resources_discover\", cwd, reason };\n          const handlerResult = await handler(event, ctx);\n          const result = handlerResult;\n          if (result?.skillPaths?.length) {\n            skillPaths.push(...result.skillPaths.map((path12) => ({ path: path12, extensionPath: ext.path })));\n          }\n          if (result?.promptPaths?.length) {\n            promptPaths.push(...result.promptPaths.map((path12) => ({ path: path12, extensionPath: ext.path })));\n          }\n          if (result?.themePaths?.length) {\n            themePaths.push(...result.themePaths.map((path12) => ({ path: path12, extensionPath: ext.path })));\n          }\n        } catch (err2) {\n          const message = err2 instanceof Error ? err2.message : String(err2);\n          const stack = err2 instanceof Error ? err2.stack : void 0;\n          this.emitError({\n            extensionPath: ext.path,\n            event: \"resources_discover\",\n            error: message,\n            stack\n          });\n        }\n      }\n    }\n    return { skillPaths, promptPaths, themePaths };\n  }\n  /** Emit input event. Transforms chain, \"handled\" short-circuits. */\n  async emitInput(text, images, source, streamingBehavior) {\n    const ctx = this.createContext();\n    let currentText = text;\n    let currentImages = images;\n    for (const ext of this.extensions) {\n      for (const handler of ext.handlers.get(\"input\") ?? []) {\n        try {\n          const event = {\n            type: \"input\",\n            text: currentText,\n            images: currentImages,\n            source,\n            streamingBehavior\n          };\n          const result = await handler(event, ctx);\n          if (result?.action === \"handled\")\n            return result;\n          if (result?.action === \"transform\") {\n            currentText = result.text;\n            currentImages = result.images ?? currentImages;\n          }\n        } catch (err2) {\n          this.emitError({\n            extensionPath: ext.path,\n            event: \"input\",\n            error: err2 instanceof Error ? err2.message : String(err2),\n            stack: err2 instanceof Error ? err2.stack : void 0\n          });\n        }\n      }\n    }\n    return currentText !== text || currentImages !== images ? { action: \"transform\", text: currentText, images: currentImages } : { action: \"continue\" };\n  }\n};\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/core/session-cwd.js\nimport { existsSync as existsSync10 } from \"node:fs\";\nfunction getMissingSessionCwdIssue(sessionManager, fallbackCwd) {\n  const sessionFile = sessionManager.getSessionFile();\n  if (!sessionFile) {\n    return void 0;\n  }\n  const sessionCwd = sessionManager.getCwd();\n  if (!sessionCwd || existsSync10(sessionCwd)) {\n    return void 0;\n  }\n  return {\n    sessionFile,\n    sessionCwd,\n    fallbackCwd\n  };\n}\nfunction formatMissingSessionCwdError(issue) {\n  const sessionFile = issue.sessionFile ? `\nSession file: ${issue.sessionFile}` : \"\";\n  return `Stored session working directory does not exist: ${issue.sessionCwd}${sessionFile}\nCurrent working directory: ${issue.fallbackCwd}`;\n}\nfunction formatMissingSessionCwdPrompt(issue) {\n  return `cwd from session file does not exist\n${issue.sessionCwd}\n\ncontinue in current cwd\n${issue.fallbackCwd}`;\n}\nvar MissingSessionCwdError = class extends Error {\n  issue;\n  constructor(issue) {\n    super(formatMissingSessionCwdError(issue));\n    this.name = \"MissingSessionCwdError\";\n    this.issue = issue;\n  }\n};\nfunction assertSessionCwdExists(sessionManager, fallbackCwd) {\n  const issue = getMissingSessionCwdIssue(sessionManager, fallbackCwd);\n  if (issue) {\n    throw new MissingSessionCwdError(issue);\n  }\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/core/session-manager.js\nimport { randomUUID as randomUUID2 } from \"crypto\";\nimport { appendFileSync as appendFileSync3, closeSync, createReadStream, existsSync as existsSync11, mkdirSync as mkdirSync5, openSync, readdirSync as readdirSync4, readSync, statSync as statSync5, writeFileSync as writeFileSync5 } from \"fs\";\nimport { readdir, stat as stat2 } from \"fs/promises\";\nimport { join as join17, resolve as resolve4 } from \"path\";\nimport { createInterface } from \"readline\";\nimport { StringDecoder } from \"string_decoder\";\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/core/messages.js\nvar COMPACTION_SUMMARY_PREFIX = `The conversation history before this point was compacted into the following summary:\n\n<summary>\n`;\nvar COMPACTION_SUMMARY_SUFFIX = `\n</summary>`;\nvar BRANCH_SUMMARY_PREFIX = `The following is a summary of a branch that this conversation came back from:\n\n<summary>\n`;\nvar BRANCH_SUMMARY_SUFFIX = `</summary>`;\nfunction bashExecutionToText(msg) {\n  let text = `Ran \\`${msg.command}\\`\n`;\n  if (msg.output) {\n    text += `\\`\\`\\`\n${msg.output}\n\\`\\`\\``;\n  } else {\n    text += \"(no output)\";\n  }\n  if (msg.cancelled) {\n    text += \"\\n\\n(command cancelled)\";\n  } else if (msg.exitCode !== null && msg.exitCode !== void 0 && msg.exitCode !== 0) {\n    text += `\n\nCommand exited with code ${msg.exitCode}`;\n  }\n  if (msg.truncated && msg.fullOutputPath) {\n    text += `\n\n[Output truncated. Full output: ${msg.fullOutputPath}]`;\n  }\n  return text;\n}\nfunction createBranchSummaryMessage(summary, fromId, timestamp) {\n  return {\n    role: \"branchSummary\",\n    summary,\n    fromId,\n    timestamp: new Date(timestamp).getTime()\n  };\n}\nfunction createCompactionSummaryMessage(summary, tokensBefore, timestamp) {\n  return {\n    role: \"compactionSummary\",\n    summary,\n    tokensBefore,\n    timestamp: new Date(timestamp).getTime()\n  };\n}\nfunction createCustomMessage(customType, content, display, details, timestamp) {\n  return {\n    role: \"custom\",\n    customType,\n    content,\n    display,\n    details,\n    timestamp: new Date(timestamp).getTime()\n  };\n}\nfunction convertToLlm(messages) {\n  return messages.map((m) => {\n    switch (m.role) {\n      case \"bashExecution\":\n        if (m.excludeFromContext) {\n          return void 0;\n        }\n        return {\n          role: \"user\",\n          content: [{ type: \"text\", text: bashExecutionToText(m) }],\n          timestamp: m.timestamp\n        };\n      case \"custom\": {\n        const content = typeof m.content === \"string\" ? [{ type: \"text\", text: m.content }] : m.content;\n        return {\n          role: \"user\",\n          content,\n          timestamp: m.timestamp\n        };\n      }\n      case \"branchSummary\":\n        return {\n          role: \"user\",\n          content: [{ type: \"text\", text: BRANCH_SUMMARY_PREFIX + m.summary + BRANCH_SUMMARY_SUFFIX }],\n          timestamp: m.timestamp\n        };\n      case \"compactionSummary\":\n        return {\n          role: \"user\",\n          content: [\n            { type: \"text\", text: COMPACTION_SUMMARY_PREFIX + m.summary + COMPACTION_SUMMARY_SUFFIX }\n          ],\n          timestamp: m.timestamp\n        };\n      case \"user\":\n      case \"assistant\":\n      case \"toolResult\":\n        return m;\n      default:\n        const _exhaustiveCheck = m;\n        return void 0;\n    }\n  }).filter((m) => m !== void 0);\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/core/session-manager.js\nvar CURRENT_SESSION_VERSION = 3;\nfunction createSessionId() {\n  return uuidv7();\n}\nfunction assertValidSessionId(id) {\n  if (!/^[A-Za-z0-9](?:[A-Za-z0-9._-]*[A-Za-z0-9])?$/.test(id)) {\n    throw new Error(\"Session id must be non-empty, contain only alphanumeric characters, '-', '_', and '.', and start and end with an alphanumeric character\");\n  }\n}\nfunction generateId(byId) {\n  for (let i = 0; i < 100; i++) {\n    const id = randomUUID2().slice(0, 8);\n    if (!byId.has(id))\n      return id;\n  }\n  return randomUUID2();\n}\nfunction migrateV1ToV2(entries) {\n  const ids = /* @__PURE__ */ new Set();\n  let prevId = null;\n  for (const entry of entries) {\n    if (entry.type === \"session\") {\n      entry.version = 2;\n      continue;\n    }\n    entry.id = generateId(ids);\n    entry.parentId = prevId;\n    prevId = entry.id;\n    if (entry.type === \"compaction\") {\n      const comp = entry;\n      if (typeof comp.firstKeptEntryIndex === \"number\") {\n        const targetEntry = entries[comp.firstKeptEntryIndex];\n        if (targetEntry && targetEntry.type !== \"session\") {\n          comp.firstKeptEntryId = targetEntry.id;\n        }\n        delete comp.firstKeptEntryIndex;\n      }\n    }\n  }\n}\nfunction migrateV2ToV3(entries) {\n  for (const entry of entries) {\n    if (entry.type === \"session\") {\n      entry.version = 3;\n      continue;\n    }\n    if (entry.type === \"message\") {\n      const msgEntry = entry;\n      if (msgEntry.message && msgEntry.message.role === \"hookMessage\") {\n        msgEntry.message.role = \"custom\";\n      }\n    }\n  }\n}\nfunction migrateToCurrentVersion(entries) {\n  const header = entries.find((e) => e.type === \"session\");\n  const version = header?.version ?? 1;\n  if (version >= CURRENT_SESSION_VERSION)\n    return false;\n  if (version < 2)\n    migrateV1ToV2(entries);\n  if (version < 3)\n    migrateV2ToV3(entries);\n  return true;\n}\nfunction migrateSessionEntries(entries) {\n  migrateToCurrentVersion(entries);\n}\nfunction parseSessionEntries(content) {\n  const entries = [];\n  const lines = content.trim().split(\"\\n\");\n  for (const line of lines) {\n    if (!line.trim())\n      continue;\n    try {\n      const entry = JSON.parse(line);\n      entries.push(entry);\n    } catch {\n    }\n  }\n  return entries;\n}\nfunction getLatestCompactionEntry(entries) {\n  for (let i = entries.length - 1; i >= 0; i--) {\n    if (entries[i].type === \"compaction\") {\n      return entries[i];\n    }\n  }\n  return null;\n}\nfunction buildEntryIndex(entries, byId) {\n  if (byId)\n    return byId;\n  const index = /* @__PURE__ */ new Map();\n  for (const entry of entries) {\n    index.set(entry.id, entry);\n  }\n  return index;\n}\nfunction buildSessionPath(entries, leafId, byId) {\n  const index = buildEntryIndex(entries, byId);\n  let leaf;\n  if (leafId === null) {\n    return [];\n  }\n  if (leafId) {\n    leaf = index.get(leafId);\n  }\n  leaf ??= entries[entries.length - 1];\n  if (!leaf) {\n    return [];\n  }\n  const path12 = [];\n  let current = leaf;\n  while (current) {\n    path12.push(current);\n    current = current.parentId ? index.get(current.parentId) : void 0;\n  }\n  path12.reverse();\n  return path12;\n}\nfunction getSessionContextSettings(path12) {\n  let thinkingLevel = \"off\";\n  let model = null;\n  for (const entry of path12) {\n    if (entry.type === \"thinking_level_change\") {\n      thinkingLevel = entry.thinkingLevel;\n    } else if (entry.type === \"model_change\") {\n      model = { provider: entry.provider, modelId: entry.modelId };\n    } else if (entry.type === \"message\" && entry.message.role === \"assistant\") {\n      model = { provider: entry.message.provider, modelId: entry.message.model };\n    }\n  }\n  return { thinkingLevel, model };\n}\nfunction sessionEntryToContextMessages(entry) {\n  if (entry.type === \"message\") {\n    const message = entry.message;\n    if ((message.role === \"user\" || message.role === \"assistant\" || message.role === \"toolResult\") && message.content == null) {\n      return [{ ...message, content: [] }];\n    }\n    return [message];\n  }\n  if (entry.type === \"custom_message\") {\n    return [\n      createCustomMessage(entry.customType, entry.content ?? [], entry.display, entry.details, entry.timestamp)\n    ];\n  }\n  if (entry.type === \"branch_summary\" && entry.summary) {\n    return [createBranchSummaryMessage(entry.summary, entry.fromId, entry.timestamp)];\n  }\n  if (entry.type === \"compaction\") {\n    return [createCompactionSummaryMessage(entry.summary, entry.tokensBefore, entry.timestamp)];\n  }\n  return [];\n}\nfunction buildContextEntries(entries, leafId, byId) {\n  const path12 = buildSessionPath(entries, leafId, byId);\n  let compaction = null;\n  for (const entry of path12) {\n    if (entry.type === \"compaction\") {\n      compaction = entry;\n    }\n  }\n  if (!compaction) {\n    return path12;\n  }\n  const compactionIdx = path12.findIndex((entry) => entry.id === compaction.id);\n  if (compactionIdx < 0) {\n    return path12;\n  }\n  const contextEntries = [compaction];\n  let foundFirstKept = false;\n  for (let i = 0; i < compactionIdx; i++) {\n    const entry = path12[i];\n    if (entry.id === compaction.firstKeptEntryId) {\n      foundFirstKept = true;\n    }\n    if (foundFirstKept) {\n      contextEntries.push(entry);\n    }\n  }\n  contextEntries.push(...path12.slice(compactionIdx + 1));\n  return contextEntries;\n}\nfunction buildSessionContext(entries, leafId, byId) {\n  const path12 = buildSessionPath(entries, leafId, byId);\n  const { thinkingLevel, model } = getSessionContextSettings(path12);\n  const messages = buildContextEntries(entries, leafId, byId).flatMap(sessionEntryToContextMessages);\n  return { messages, thinkingLevel, model };\n}\nfunction getDefaultSessionDirPath(cwd, agentDir = getAgentDir()) {\n  const resolvedCwd = resolvePath(cwd);\n  const resolvedAgentDir = resolvePath(agentDir);\n  const safePath = `--${resolvedCwd.replace(/^[/\\\\]/, \"\").replace(/[/\\\\:]/g, \"-\")}--`;\n  return join17(resolvedAgentDir, \"sessions\", safePath);\n}\nfunction getDefaultSessionDir(cwd, agentDir = getAgentDir()) {\n  const sessionDir = getDefaultSessionDirPath(cwd, agentDir);\n  if (!existsSync11(sessionDir)) {\n    mkdirSync5(sessionDir, { recursive: true });\n  }\n  return sessionDir;\n}\nvar SESSION_READ_BUFFER_SIZE = 1024 * 1024;\nvar SESSION_HEADER_READ_BUFFER_SIZE = 4096;\nvar MAX_SESSION_HEADER_SCAN_BYTES = 1024 * 1024;\nvar SessionHeaderScanLimitError = class extends Error {\n  constructor(filePath) {\n    super(`Session header exceeds ${MAX_SESSION_HEADER_SCAN_BYTES}-byte scan limit: ${filePath}`);\n    this.name = \"SessionHeaderScanLimitError\";\n  }\n};\nfunction parseSessionEntryLine(line) {\n  if (!line.trim())\n    return null;\n  try {\n    return JSON.parse(line);\n  } catch {\n    return null;\n  }\n}\nfunction loadEntriesFromFile(filePath) {\n  const resolvedFilePath = normalizePath(filePath);\n  if (!existsSync11(resolvedFilePath))\n    return [];\n  const entries = [];\n  const fd = openSync(resolvedFilePath, \"r\");\n  try {\n    const decoder = new StringDecoder(\"utf8\");\n    const buffer = Buffer.allocUnsafe(SESSION_READ_BUFFER_SIZE);\n    let pending = \"\";\n    while (true) {\n      const bytesRead = readSync(fd, buffer, 0, buffer.length, null);\n      if (bytesRead === 0)\n        break;\n      pending += decoder.write(buffer.subarray(0, bytesRead));\n      let lineStart = 0;\n      let newlineIndex = pending.indexOf(\"\\n\", lineStart);\n      while (newlineIndex !== -1) {\n        const entry = parseSessionEntryLine(pending.slice(lineStart, newlineIndex));\n        if (entry)\n          entries.push(entry);\n        lineStart = newlineIndex + 1;\n        newlineIndex = pending.indexOf(\"\\n\", lineStart);\n      }\n      pending = pending.slice(lineStart);\n    }\n    pending += decoder.end();\n    const finalEntry = parseSessionEntryLine(pending);\n    if (finalEntry)\n      entries.push(finalEntry);\n  } finally {\n    closeSync(fd);\n  }\n  if (entries.length === 0)\n    return entries;\n  const header = entries[0];\n  if (header.type !== \"session\" || typeof header.id !== \"string\") {\n    return [];\n  }\n  return entries;\n}\nfunction parseSessionHeaderCandidate(line) {\n  if (!line.trim())\n    return void 0;\n  const entry = parseSessionEntryLine(line);\n  if (!entry)\n    return void 0;\n  if (entry.type !== \"session\" || typeof entry.id !== \"string\")\n    return null;\n  return entry;\n}\nfunction readSessionHeader(filePath) {\n  const fd = openSync(filePath, \"r\");\n  try {\n    const decoder = new StringDecoder(\"utf8\");\n    const buffer = Buffer.allocUnsafe(SESSION_HEADER_READ_BUFFER_SIZE);\n    const lineChunks = [];\n    let scannedBytes = 0;\n    while (scannedBytes < MAX_SESSION_HEADER_SCAN_BYTES) {\n      const readLength = Math.min(buffer.length, MAX_SESSION_HEADER_SCAN_BYTES - scannedBytes);\n      const bytesRead = readSync(fd, buffer, 0, readLength, null);\n      if (bytesRead === 0) {\n        lineChunks.push(decoder.end());\n        return parseSessionHeaderCandidate(lineChunks.join(\"\")) ?? null;\n      }\n      scannedBytes += bytesRead;\n      const chunk = decoder.write(buffer.subarray(0, bytesRead));\n      let lineStart = 0;\n      let newlineIndex = chunk.indexOf(\"\\n\", lineStart);\n      while (newlineIndex !== -1) {\n        lineChunks.push(chunk.slice(lineStart, newlineIndex));\n        const header = parseSessionHeaderCandidate(lineChunks.join(\"\"));\n        if (header !== void 0)\n          return header;\n        lineChunks.length = 0;\n        lineStart = newlineIndex + 1;\n        newlineIndex = chunk.indexOf(\"\\n\", lineStart);\n      }\n      lineChunks.push(chunk.slice(lineStart));\n    }\n    const probe = Buffer.allocUnsafe(1);\n    if (readSync(fd, probe, 0, probe.length, null) === 0) {\n      lineChunks.push(decoder.end());\n      return parseSessionHeaderCandidate(lineChunks.join(\"\")) ?? null;\n    }\n    throw new SessionHeaderScanLimitError(filePath);\n  } finally {\n    closeSync(fd);\n  }\n}\nfunction readSessionHeaderForDiscovery(filePath) {\n  try {\n    return readSessionHeader(filePath);\n  } catch {\n    return null;\n  }\n}\nfunction getSessionHeaderCwd(header) {\n  const cwd = header.cwd;\n  return typeof cwd === \"string\" ? cwd : void 0;\n}\nfunction sessionCwdMatches(cwd, resolvedCwd) {\n  return cwd !== void 0 && cwd !== \"\" && resolvePath(cwd) === resolvedCwd;\n}\nfunction findMostRecentSession(sessionDir, cwd) {\n  const resolvedSessionDir = normalizePath(sessionDir);\n  const resolvedCwd = cwd ? resolvePath(cwd) : void 0;\n  try {\n    const files = readdirSync4(resolvedSessionDir).filter((f) => f.endsWith(\".jsonl\")).map((f) => join17(resolvedSessionDir, f)).map((path12) => ({ path: path12, header: readSessionHeaderForDiscovery(path12) })).filter((file) => file.header !== null && (!resolvedCwd || sessionCwdMatches(getSessionHeaderCwd(file.header), resolvedCwd))).map(({ path: path12 }) => ({ path: path12, mtime: statSync5(path12).mtime })).sort((a, b) => b.mtime.getTime() - a.mtime.getTime());\n    return files[0]?.path || null;\n  } catch {\n    return null;\n  }\n}\nfunction isMessageWithContent(message) {\n  return typeof message.role === \"string\" && \"content\" in message;\n}\nfunction extractTextContent(message) {\n  const content = message.content;\n  if (typeof content === \"string\") {\n    return content;\n  }\n  return content.filter((block) => block.type === \"text\").map((block) => block.text).join(\" \");\n}\nfunction getMessageActivityTime(entry) {\n  const message = entry.message;\n  if (!isMessageWithContent(message))\n    return void 0;\n  if (message.role !== \"user\" && message.role !== \"assistant\")\n    return void 0;\n  const msgTimestamp = message.timestamp;\n  if (typeof msgTimestamp === \"number\") {\n    return msgTimestamp;\n  }\n  const t = new Date(entry.timestamp).getTime();\n  return Number.isNaN(t) ? void 0 : t;\n}\nasync function buildSessionInfo(filePath) {\n  try {\n    const stats = await stat2(filePath);\n    let header = null;\n    let messageCount = 0;\n    let firstMessage = \"\";\n    const allMessages = [];\n    let name;\n    let lastActivityTime;\n    const rl = createInterface({\n      input: createReadStream(filePath, { encoding: \"utf8\" }),\n      crlfDelay: Infinity\n    });\n    for await (const line of rl) {\n      const entry = parseSessionEntryLine(line);\n      if (!entry)\n        continue;\n      if (!header) {\n        if (entry.type !== \"session\")\n          return null;\n        header = entry;\n        continue;\n      }\n      if (entry.type === \"session_info\") {\n        name = entry.name?.trim() || void 0;\n      }\n      if (entry.type !== \"message\")\n        continue;\n      messageCount++;\n      const activityTime = getMessageActivityTime(entry);\n      if (typeof activityTime === \"number\") {\n        lastActivityTime = Math.max(lastActivityTime ?? 0, activityTime);\n      }\n      const message = entry.message;\n      if (!isMessageWithContent(message))\n        continue;\n      if (message.role !== \"user\" && message.role !== \"assistant\")\n        continue;\n      const textContent = extractTextContent(message);\n      if (!textContent)\n        continue;\n      allMessages.push(textContent);\n      if (!firstMessage && message.role === \"user\") {\n        firstMessage = textContent;\n      }\n    }\n    if (!header)\n      return null;\n    const cwd = typeof header.cwd === \"string\" ? header.cwd : \"\";\n    const parentSessionPath = header.parentSession;\n    const headerTime = typeof header.timestamp === \"string\" ? new Date(header.timestamp).getTime() : NaN;\n    const modified = typeof lastActivityTime === \"number\" && lastActivityTime > 0 ? new Date(lastActivityTime) : !Number.isNaN(headerTime) ? new Date(headerTime) : stats.mtime;\n    return {\n      path: filePath,\n      id: header.id,\n      cwd,\n      name,\n      parentSessionPath,\n      created: new Date(header.timestamp),\n      modified,\n      messageCount,\n      firstMessage: firstMessage || \"(no messages)\",\n      allMessagesText: allMessages.join(\" \")\n    };\n  } catch {\n    return null;\n  }\n}\nvar MAX_CONCURRENT_SESSION_INFO_LOADS = 10;\nasync function buildSessionInfosWithConcurrency(files, onLoaded) {\n  const results = new Array(files.length).fill(null);\n  const inFlight = /* @__PURE__ */ new Set();\n  let nextIndex = 0;\n  const startNext = () => {\n    const index = nextIndex++;\n    const file = files[index];\n    if (!file)\n      return;\n    let task;\n    task = buildSessionInfo(file).then((info) => {\n      results[index] = info;\n    }).catch(() => {\n      results[index] = null;\n    }).finally(() => {\n      inFlight.delete(task);\n      onLoaded();\n    });\n    inFlight.add(task);\n  };\n  while (nextIndex < files.length || inFlight.size > 0) {\n    while (nextIndex < files.length && inFlight.size < MAX_CONCURRENT_SESSION_INFO_LOADS) {\n      startNext();\n    }\n    if (inFlight.size > 0) {\n      await Promise.race(inFlight);\n    }\n  }\n  return results;\n}\nasync function listSessionsFromDir(dir, onProgress, progressOffset = 0, progressTotal) {\n  const sessions = [];\n  if (!existsSync11(dir)) {\n    return sessions;\n  }\n  try {\n    const dirEntries = await readdir(dir);\n    const files = dirEntries.filter((f) => f.endsWith(\".jsonl\")).map((f) => join17(dir, f));\n    const total = progressTotal ?? files.length;\n    let loaded = 0;\n    const results = await buildSessionInfosWithConcurrency(files, () => {\n      loaded++;\n      onProgress?.(progressOffset + loaded, total);\n    });\n    for (const info of results) {\n      if (info) {\n        sessions.push(info);\n      }\n    }\n  } catch {\n  }\n  return sessions;\n}\nvar SessionManager = class _SessionManager {\n  sessionId = \"\";\n  sessionFile;\n  sessionDir;\n  cwd;\n  persist;\n  flushed = false;\n  fileEntries = [];\n  byId = /* @__PURE__ */ new Map();\n  labelsById = /* @__PURE__ */ new Map();\n  labelTimestampsById = /* @__PURE__ */ new Map();\n  leafId = null;\n  constructor(cwd, sessionDir, sessionFile, persist, newSessionOptions, preloadedFileEntries) {\n    this.cwd = resolvePath(cwd);\n    this.sessionDir = normalizePath(sessionDir);\n    this.persist = persist;\n    if (persist && this.sessionDir && !existsSync11(this.sessionDir)) {\n      mkdirSync5(this.sessionDir, { recursive: true });\n    }\n    if (sessionFile) {\n      this._setSessionFile(sessionFile, preloadedFileEntries);\n    } else {\n      this.newSession(newSessionOptions);\n    }\n  }\n  /** Switch to a different session file (used for resume and branching) */\n  setSessionFile(sessionFile) {\n    this._setSessionFile(sessionFile);\n  }\n  _setSessionFile(sessionFile, preloadedFileEntries) {\n    this.sessionFile = resolvePath(sessionFile);\n    if (existsSync11(this.sessionFile)) {\n      this.fileEntries = preloadedFileEntries ?? loadEntriesFromFile(this.sessionFile);\n      if (this.fileEntries.length === 0) {\n        const explicitPath = this.sessionFile;\n        if (statSync5(explicitPath).size > 0) {\n          throw new Error(`Session file is not a valid ${APP_NAME} session: ${explicitPath}`);\n        }\n        this.newSession();\n        this.sessionFile = explicitPath;\n        this._rewriteFile();\n        this.flushed = true;\n        return;\n      }\n      const header = this.fileEntries.find((e) => e.type === \"session\");\n      this.sessionId = header?.id ?? createSessionId();\n      if (migrateToCurrentVersion(this.fileEntries)) {\n        this._rewriteFile();\n      }\n      this._buildIndex();\n      this.flushed = true;\n    } else {\n      const explicitPath = this.sessionFile;\n      this.newSession();\n      this.sessionFile = explicitPath;\n    }\n  }\n  newSession(options) {\n    if (options?.id !== void 0) {\n      assertValidSessionId(options.id);\n    }\n    this.sessionId = options?.id ?? createSessionId();\n    const timestamp = (/* @__PURE__ */ new Date()).toISOString();\n    const header = {\n      type: \"session\",\n      version: CURRENT_SESSION_VERSION,\n      id: this.sessionId,\n      timestamp,\n      cwd: this.cwd,\n      parentSession: options?.parentSession\n    };\n    this.fileEntries = [header];\n    this.byId.clear();\n    this.labelsById.clear();\n    this.labelTimestampsById.clear();\n    this.leafId = null;\n    this.flushed = false;\n    if (this.persist) {\n      const fileTimestamp = timestamp.replace(/[:.]/g, \"-\");\n      this.sessionFile = join17(this.getSessionDir(), `${fileTimestamp}_${this.sessionId}.jsonl`);\n    }\n    return this.sessionFile;\n  }\n  _buildIndex() {\n    this.byId.clear();\n    this.labelsById.clear();\n    this.labelTimestampsById.clear();\n    this.leafId = null;\n    for (const entry of this.fileEntries) {\n      if (entry.type === \"session\")\n        continue;\n      this.byId.set(entry.id, entry);\n      this.leafId = entry.id;\n      if (entry.type === \"label\") {\n        if (entry.label) {\n          this.labelsById.set(entry.targetId, entry.label);\n          this.labelTimestampsById.set(entry.targetId, entry.timestamp);\n        } else {\n          this.labelsById.delete(entry.targetId);\n          this.labelTimestampsById.delete(entry.targetId);\n        }\n      }\n    }\n  }\n  _rewriteFile() {\n    if (!this.persist || !this.sessionFile)\n      return;\n    const fd = openSync(this.sessionFile, \"w\");\n    try {\n      for (const entry of this.fileEntries) {\n        writeFileSync5(fd, `${JSON.stringify(entry)}\n`);\n      }\n    } finally {\n      closeSync(fd);\n    }\n  }\n  isPersisted() {\n    return this.persist;\n  }\n  getCwd() {\n    return this.cwd;\n  }\n  getSessionDir() {\n    return this.sessionDir;\n  }\n  usesDefaultSessionDir() {\n    return this.sessionDir === getDefaultSessionDirPath(this.cwd);\n  }\n  getSessionId() {\n    return this.sessionId;\n  }\n  getSessionFile() {\n    return this.sessionFile;\n  }\n  _persist(entry) {\n    if (!this.persist || !this.sessionFile)\n      return;\n    const hasAssistant = this.fileEntries.some((e) => e.type === \"message\" && e.message.role === \"assistant\");\n    if (!hasAssistant) {\n      if (this.flushed) {\n        appendFileSync3(this.sessionFile, `${JSON.stringify(entry)}\n`);\n      } else {\n        this.flushed = false;\n      }\n      return;\n    }\n    if (!this.flushed) {\n      const fd = openSync(this.sessionFile, \"wx\");\n      try {\n        for (const e of this.fileEntries) {\n          writeFileSync5(fd, `${JSON.stringify(e)}\n`);\n        }\n      } finally {\n        closeSync(fd);\n      }\n      this.flushed = true;\n    } else {\n      appendFileSync3(this.sessionFile, `${JSON.stringify(entry)}\n`);\n    }\n  }\n  _appendEntry(entry) {\n    this.fileEntries.push(entry);\n    this.byId.set(entry.id, entry);\n    this.leafId = entry.id;\n    this._persist(entry);\n  }\n  /** Append a message as child of current leaf, then advance leaf. Returns entry id.\n   * Does not allow writing CompactionSummaryMessage and BranchSummaryMessage directly.\n   * Reason: we want these to be top-level entries in the session, not message session entries,\n   * so it is easier to find them.\n   * These need to be appended via appendCompaction() and appendBranchSummary() methods.\n   */\n  appendMessage(message) {\n    const entry = {\n      type: \"message\",\n      id: generateId(this.byId),\n      parentId: this.leafId,\n      timestamp: (/* @__PURE__ */ new Date()).toISOString(),\n      message\n    };\n    this._appendEntry(entry);\n    return entry.id;\n  }\n  /** Append a thinking level change as child of current leaf, then advance leaf. Returns entry id. */\n  appendThinkingLevelChange(thinkingLevel) {\n    const entry = {\n      type: \"thinking_level_change\",\n      id: generateId(this.byId),\n      parentId: this.leafId,\n      timestamp: (/* @__PURE__ */ new Date()).toISOString(),\n      thinkingLevel\n    };\n    this._appendEntry(entry);\n    return entry.id;\n  }\n  /** Append a model change as child of current leaf, then advance leaf. Returns entry id. */\n  appendModelChange(provider, modelId) {\n    const entry = {\n      type: \"model_change\",\n      id: generateId(this.byId),\n      parentId: this.leafId,\n      timestamp: (/* @__PURE__ */ new Date()).toISOString(),\n      provider,\n      modelId\n    };\n    this._appendEntry(entry);\n    return entry.id;\n  }\n  /** Append a compaction summary as child of current leaf, then advance leaf. Returns entry id. */\n  appendCompaction(summary, firstKeptEntryId, tokensBefore, details, fromHook, usage) {\n    const entry = {\n      type: \"compaction\",\n      id: generateId(this.byId),\n      parentId: this.leafId,\n      timestamp: (/* @__PURE__ */ new Date()).toISOString(),\n      summary,\n      firstKeptEntryId,\n      tokensBefore,\n      details,\n      usage,\n      fromHook\n    };\n    this._appendEntry(entry);\n    return entry.id;\n  }\n  /** Append a custom entry (for extensions) as child of current leaf, then advance leaf. Returns entry id. */\n  appendCustomEntry(customType, data) {\n    const entry = {\n      type: \"custom\",\n      customType,\n      data,\n      id: generateId(this.byId),\n      parentId: this.leafId,\n      timestamp: (/* @__PURE__ */ new Date()).toISOString()\n    };\n    this._appendEntry(entry);\n    return entry.id;\n  }\n  /** Append a session info entry (e.g., display name). Returns entry id. */\n  appendSessionInfo(name) {\n    const sanitizedName = name.replace(/[\\r\\n]+/g, \" \").trim();\n    const entry = {\n      type: \"session_info\",\n      id: generateId(this.byId),\n      parentId: this.leafId,\n      timestamp: (/* @__PURE__ */ new Date()).toISOString(),\n      name: sanitizedName\n    };\n    this._appendEntry(entry);\n    return entry.id;\n  }\n  /** Get the current session name from the latest session_info entry, if any. */\n  getSessionName() {\n    const entries = this.getEntries();\n    for (let i = entries.length - 1; i >= 0; i--) {\n      const entry = entries[i];\n      if (entry.type === \"session_info\") {\n        return entry.name?.trim() || void 0;\n      }\n    }\n    return void 0;\n  }\n  /**\n   * Append a custom message entry (for extensions) that participates in LLM context.\n   * @param customType Extension identifier for filtering on reload\n   * @param content Message content (string or TextContent/ImageContent array)\n   * @param display Whether to show in TUI (true = styled display, false = hidden)\n   * @param details Optional extension-specific metadata (not sent to LLM)\n   * @returns Entry id\n   */\n  appendCustomMessageEntry(customType, content, display, details) {\n    const entry = {\n      type: \"custom_message\",\n      customType,\n      content,\n      display,\n      details,\n      id: generateId(this.byId),\n      parentId: this.leafId,\n      timestamp: (/* @__PURE__ */ new Date()).toISOString()\n    };\n    this._appendEntry(entry);\n    return entry.id;\n  }\n  // =========================================================================\n  // Tree Traversal\n  // =========================================================================\n  getLeafId() {\n    return this.leafId;\n  }\n  getLeafEntry() {\n    return this.leafId ? this.byId.get(this.leafId) : void 0;\n  }\n  getEntry(id) {\n    return this.byId.get(id);\n  }\n  /**\n   * Get all direct children of an entry.\n   */\n  getChildren(parentId) {\n    const children = [];\n    for (const entry of this.byId.values()) {\n      if (entry.parentId === parentId) {\n        children.push(entry);\n      }\n    }\n    return children;\n  }\n  /**\n   * Get the label for an entry, if any.\n   */\n  getLabel(id) {\n    return this.labelsById.get(id);\n  }\n  /**\n   * Set or clear a label on an entry.\n   * Labels are user-defined markers for bookmarking/navigation.\n   * Pass undefined or empty string to clear the label.\n   */\n  appendLabelChange(targetId, label) {\n    if (!this.byId.has(targetId)) {\n      throw new Error(`Entry ${targetId} not found`);\n    }\n    const entry = {\n      type: \"label\",\n      id: generateId(this.byId),\n      parentId: this.leafId,\n      timestamp: (/* @__PURE__ */ new Date()).toISOString(),\n      targetId,\n      label\n    };\n    this._appendEntry(entry);\n    if (label) {\n      this.labelsById.set(targetId, label);\n      this.labelTimestampsById.set(targetId, entry.timestamp);\n    } else {\n      this.labelsById.delete(targetId);\n      this.labelTimestampsById.delete(targetId);\n    }\n    return entry.id;\n  }\n  /**\n   * Walk from entry to root, returning all entries in path order.\n   * Includes all entry types (messages, compaction, model changes, etc.).\n   * Use buildSessionContext() to get the resolved messages for the LLM.\n   */\n  getBranch(fromId) {\n    const path12 = [];\n    const startId = fromId ?? this.leafId;\n    let current = startId ? this.byId.get(startId) : void 0;\n    while (current) {\n      path12.push(current);\n      current = current.parentId ? this.byId.get(current.parentId) : void 0;\n    }\n    path12.reverse();\n    return path12;\n  }\n  /**\n   * Build the active, compaction-aware entry list for context/rendering.\n   * Uses tree traversal from current leaf.\n   */\n  buildContextEntries() {\n    return buildContextEntries(this.getEntries(), this.leafId, this.byId);\n  }\n  /**\n   * Build the session context (what gets sent to the LLM).\n   * Uses tree traversal from current leaf.\n   */\n  buildSessionContext() {\n    return buildSessionContext(this.getEntries(), this.leafId, this.byId);\n  }\n  /**\n   * Get session header.\n   */\n  getHeader() {\n    const h = this.fileEntries.find((e) => e.type === \"session\");\n    return h ? h : null;\n  }\n  /**\n   * Get all session entries (excludes header). Returns a shallow copy.\n   * The session is append-only: use appendXXX() to add entries, branch() to\n   * change the leaf pointer. Entries cannot be modified or deleted.\n   */\n  getEntries() {\n    return this.fileEntries.filter((e) => e.type !== \"session\");\n  }\n  /**\n   * Get the session as a tree structure. Returns a shallow defensive copy of all entries.\n   * A well-formed session has exactly one root (first entry with parentId === null).\n   * Orphaned entries (broken parent chain) are also returned as roots.\n   */\n  getTree() {\n    const entries = this.getEntries();\n    const nodeMap = /* @__PURE__ */ new Map();\n    const roots = [];\n    for (const entry of entries) {\n      const label = this.labelsById.get(entry.id);\n      const labelTimestamp = this.labelTimestampsById.get(entry.id);\n      nodeMap.set(entry.id, { entry, children: [], label, labelTimestamp });\n    }\n    for (const entry of entries) {\n      const node = nodeMap.get(entry.id);\n      if (entry.parentId === null || entry.parentId === entry.id) {\n        roots.push(node);\n      } else {\n        const parent = nodeMap.get(entry.parentId);\n        if (parent) {\n          parent.children.push(node);\n        } else {\n          roots.push(node);\n        }\n      }\n    }\n    const stack = [...roots];\n    while (stack.length > 0) {\n      const node = stack.pop();\n      node.children.sort((a, b) => new Date(a.entry.timestamp).getTime() - new Date(b.entry.timestamp).getTime());\n      stack.push(...node.children);\n    }\n    return roots;\n  }\n  // =========================================================================\n  // Branching\n  // =========================================================================\n  /**\n   * Start a new branch from an earlier entry.\n   * Moves the leaf pointer to the specified entry. The next appendXXX() call\n   * will create a child of that entry, forming a new branch. Existing entries\n   * are not modified or deleted.\n   */\n  branch(branchFromId) {\n    if (!this.byId.has(branchFromId)) {\n      throw new Error(`Entry ${branchFromId} not found`);\n    }\n    this.leafId = branchFromId;\n  }\n  /**\n   * Reset the leaf pointer to null (before any entries).\n   * The next appendXXX() call will create a new root entry (parentId = null).\n   * Use this when navigating to re-edit the first user message.\n   */\n  resetLeaf() {\n    this.leafId = null;\n  }\n  /**\n   * Start a new branch with a summary of the abandoned path.\n   * Same as branch(), but also appends a branch_summary entry that captures\n   * context from the abandoned conversation path.\n   */\n  branchWithSummary(branchFromId, summary, details, fromHook, usage) {\n    if (branchFromId !== null && !this.byId.has(branchFromId)) {\n      throw new Error(`Entry ${branchFromId} not found`);\n    }\n    this.leafId = branchFromId;\n    const entry = {\n      type: \"branch_summary\",\n      id: generateId(this.byId),\n      parentId: branchFromId,\n      timestamp: (/* @__PURE__ */ new Date()).toISOString(),\n      fromId: branchFromId ?? \"root\",\n      summary,\n      details,\n      usage,\n      fromHook\n    };\n    this._appendEntry(entry);\n    return entry.id;\n  }\n  /**\n   * Create a new session file containing only the path from root to the specified leaf.\n   * Useful for extracting a single conversation path from a branched session.\n   * Returns the new session file path, or undefined if not persisting.\n   */\n  createBranchedSession(leafId) {\n    const previousSessionFile = this.sessionFile;\n    const path12 = this.getBranch(leafId);\n    if (path12.length === 0) {\n      throw new Error(`Entry ${leafId} not found`);\n    }\n    const pathWithoutLabels = [];\n    let pathParentId = null;\n    for (const entry of path12) {\n      if (entry.type === \"label\")\n        continue;\n      pathWithoutLabels.push({ ...entry, parentId: pathParentId });\n      pathParentId = entry.id;\n    }\n    const newSessionId = createSessionId();\n    const timestamp = (/* @__PURE__ */ new Date()).toISOString();\n    const fileTimestamp = timestamp.replace(/[:.]/g, \"-\");\n    const newSessionFile = join17(this.getSessionDir(), `${fileTimestamp}_${newSessionId}.jsonl`);\n    const header = {\n      type: \"session\",\n      version: CURRENT_SESSION_VERSION,\n      id: newSessionId,\n      timestamp,\n      cwd: this.cwd,\n      parentSession: this.persist ? previousSessionFile : void 0\n    };\n    const pathEntryIds = new Set(pathWithoutLabels.map((e) => e.id));\n    const labelsToWrite = [];\n    for (const [targetId, label] of this.labelsById) {\n      if (pathEntryIds.has(targetId)) {\n        labelsToWrite.push({ targetId, label, timestamp: this.labelTimestampsById.get(targetId) });\n      }\n    }\n    if (this.persist) {\n      const lastEntryId = pathWithoutLabels[pathWithoutLabels.length - 1]?.id || null;\n      let parentId2 = lastEntryId;\n      const labelEntries2 = [];\n      for (const { targetId, label, timestamp: labelTimestamp } of labelsToWrite) {\n        const labelEntry = {\n          type: \"label\",\n          id: generateId(new Set(pathEntryIds)),\n          parentId: parentId2,\n          timestamp: labelTimestamp,\n          targetId,\n          label\n        };\n        pathEntryIds.add(labelEntry.id);\n        labelEntries2.push(labelEntry);\n        parentId2 = labelEntry.id;\n      }\n      this.fileEntries = [header, ...pathWithoutLabels, ...labelEntries2];\n      this.sessionId = newSessionId;\n      this.sessionFile = newSessionFile;\n      this._buildIndex();\n      const hasAssistant = this.fileEntries.some((e) => e.type === \"message\" && e.message.role === \"assistant\");\n      if (hasAssistant) {\n        this._rewriteFile();\n        this.flushed = true;\n      } else {\n        this.flushed = false;\n      }\n      return newSessionFile;\n    }\n    const labelEntries = [];\n    let parentId = pathWithoutLabels[pathWithoutLabels.length - 1]?.id || null;\n    for (const { targetId, label, timestamp: labelTimestamp } of labelsToWrite) {\n      const labelEntry = {\n        type: \"label\",\n        id: generateId(/* @__PURE__ */ new Set([...pathEntryIds, ...labelEntries.map((e) => e.id)])),\n        parentId,\n        timestamp: labelTimestamp,\n        targetId,\n        label\n      };\n      labelEntries.push(labelEntry);\n      parentId = labelEntry.id;\n    }\n    this.fileEntries = [header, ...pathWithoutLabels, ...labelEntries];\n    this.sessionId = newSessionId;\n    this._buildIndex();\n    return void 0;\n  }\n  /**\n   * Create a new session.\n   * @param cwd Working directory (stored in session header)\n   * @param sessionDir Optional session directory. If omitted, uses default (~/.pi/agent/sessions/<encoded-cwd>/).\n   */\n  static create(cwd, sessionDir, options) {\n    const dir = sessionDir ? normalizePath(sessionDir) : getDefaultSessionDir(cwd);\n    return new _SessionManager(cwd, dir, void 0, true, options);\n  }\n  /**\n   * Open a specific session file.\n   * @param path Path to session file\n   * @param sessionDir Optional session directory for /new or /branch. If omitted, derives from file's parent.\n   * @param cwdOverride Optional cwd override instead of the session header cwd.\n   */\n  static open(path12, sessionDir, cwdOverride) {\n    const resolvedPath = resolvePath(path12);\n    let header = null;\n    let preloadedFileEntries;\n    if (cwdOverride === void 0 && existsSync11(resolvedPath)) {\n      try {\n        header = readSessionHeader(resolvedPath);\n      } catch (error) {\n        if (!(error instanceof SessionHeaderScanLimitError))\n          throw error;\n        preloadedFileEntries = loadEntriesFromFile(resolvedPath);\n        const firstEntry = preloadedFileEntries[0];\n        header = firstEntry?.type === \"session\" ? firstEntry : null;\n      }\n    }\n    const cwd = cwdOverride ?? (header ? getSessionHeaderCwd(header) : void 0) ?? process.cwd();\n    const dir = sessionDir ? normalizePath(sessionDir) : resolve4(resolvedPath, \"..\");\n    return new _SessionManager(cwd, dir, resolvedPath, true, void 0, preloadedFileEntries);\n  }\n  /**\n   * Continue the most recent session, or create new if none.\n   * @param cwd Working directory\n   * @param sessionDir Optional session directory. If omitted, uses default (~/.pi/agent/sessions/<encoded-cwd>/).\n   */\n  static continueRecent(cwd, sessionDir) {\n    const dir = sessionDir ? normalizePath(sessionDir) : getDefaultSessionDir(cwd);\n    const filterCwd = sessionDir !== void 0 && dir !== getDefaultSessionDirPath(cwd);\n    const mostRecent = findMostRecentSession(dir, filterCwd ? cwd : void 0);\n    if (mostRecent) {\n      return new _SessionManager(cwd, dir, mostRecent, true);\n    }\n    return new _SessionManager(cwd, dir, void 0, true);\n  }\n  /** Create an in-memory session (no file persistence) */\n  static inMemory(cwd = process.cwd(), options) {\n    return new _SessionManager(cwd, \"\", void 0, false, options);\n  }\n  /**\n   * Fork a session from another project directory into the current project.\n   * Creates a new session in the target cwd with the full history from the source session.\n   * @param sourcePath Path to the source session file\n   * @param targetCwd Target working directory (where the new session will be stored)\n   * @param sessionDir Optional session directory. If omitted, uses default for targetCwd.\n   */\n  static forkFrom(sourcePath, targetCwd, sessionDir, options) {\n    const resolvedSourcePath = resolvePath(sourcePath);\n    const resolvedTargetCwd = resolvePath(targetCwd);\n    const sourceEntries = loadEntriesFromFile(resolvedSourcePath);\n    if (sourceEntries.length === 0) {\n      throw new Error(`Cannot fork: source session file is empty or invalid: ${resolvedSourcePath}`);\n    }\n    const sourceHeader = sourceEntries.find((e) => e.type === \"session\");\n    if (!sourceHeader) {\n      throw new Error(`Cannot fork: source session has no header: ${resolvedSourcePath}`);\n    }\n    const dir = sessionDir ? normalizePath(sessionDir) : getDefaultSessionDir(resolvedTargetCwd);\n    if (!existsSync11(dir)) {\n      mkdirSync5(dir, { recursive: true });\n    }\n    if (options?.id !== void 0) {\n      assertValidSessionId(options.id);\n    }\n    const newSessionId = options?.id ?? createSessionId();\n    const timestamp = (/* @__PURE__ */ new Date()).toISOString();\n    const fileTimestamp = timestamp.replace(/[:.]/g, \"-\");\n    const newSessionFile = join17(dir, `${fileTimestamp}_${newSessionId}.jsonl`);\n    const newHeader = {\n      type: \"session\",\n      version: CURRENT_SESSION_VERSION,\n      id: newSessionId,\n      timestamp,\n      cwd: resolvedTargetCwd,\n      parentSession: resolvedSourcePath\n    };\n    writeFileSync5(newSessionFile, `${JSON.stringify(newHeader)}\n`, { flag: \"wx\" });\n    for (const entry of sourceEntries) {\n      if (entry.type !== \"session\") {\n        appendFileSync3(newSessionFile, `${JSON.stringify(entry)}\n`);\n      }\n    }\n    return new _SessionManager(resolvedTargetCwd, dir, newSessionFile, true);\n  }\n  /**\n   * List all sessions for a directory.\n   * @param cwd Working directory (used to compute default session directory)\n   * @param sessionDir Optional session directory. If omitted, uses default (~/.pi/agent/sessions/<encoded-cwd>/).\n   * @param onProgress Optional callback for progress updates (loaded, total)\n   */\n  static async list(cwd, sessionDir, onProgress) {\n    const dir = sessionDir ? normalizePath(sessionDir) : getDefaultSessionDir(cwd);\n    const filterCwd = sessionDir !== void 0 && dir !== getDefaultSessionDirPath(cwd);\n    const resolvedCwd = resolvePath(cwd);\n    const sessions = (await listSessionsFromDir(dir, onProgress)).filter((session) => !filterCwd || sessionCwdMatches(session.cwd, resolvedCwd));\n    sessions.sort((a, b) => b.modified.getTime() - a.modified.getTime());\n    return sessions;\n  }\n  static async listAll(sessionDirOrOnProgress, onProgress) {\n    const customSessionDir = typeof sessionDirOrOnProgress === \"string\" ? normalizePath(sessionDirOrOnProgress) : void 0;\n    const progress = typeof sessionDirOrOnProgress === \"function\" ? sessionDirOrOnProgress : onProgress;\n    if (customSessionDir) {\n      const sessions = await listSessionsFromDir(customSessionDir, progress);\n      sessions.sort((a, b) => b.modified.getTime() - a.modified.getTime());\n      return sessions;\n    }\n    const sessionsDir = getSessionsDir();\n    try {\n      if (!existsSync11(sessionsDir)) {\n        return [];\n      }\n      const entries = await readdir(sessionsDir, { withFileTypes: true });\n      const dirs = entries.filter((entry) => entry.isDirectory() || entry.isSymbolicLink()).map((entry) => join17(sessionsDir, entry.name));\n      let totalFiles = 0;\n      const dirFiles = [];\n      for (const dir of dirs) {\n        try {\n          const files = (await readdir(dir)).filter((f) => f.endsWith(\".jsonl\"));\n          dirFiles.push(files.map((f) => join17(dir, f)));\n          totalFiles += files.length;\n        } catch {\n          dirFiles.push([]);\n        }\n      }\n      let loaded = 0;\n      const sessions = [];\n      const allFiles = dirFiles.flat();\n      const results = await buildSessionInfosWithConcurrency(allFiles, () => {\n        loaded++;\n        progress?.(loaded, totalFiles);\n      });\n      for (const info of results) {\n        if (info) {\n          sessions.push(info);\n        }\n      }\n      sessions.sort((a, b) => b.modified.getTime() - a.modified.getTime());\n      return sessions;\n    } catch {\n      return [];\n    }\n  }\n};\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session-services.js\nimport { join as join33 } from \"node:path\";\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/core/resource-loader.js\nimport { existsSync as existsSync22, readdirSync as readdirSync9, readFileSync as readFileSync18, statSync as statSync10 } from \"node:fs\";\nimport { basename as basename10, dirname as dirname21, join as join32, resolve as resolve12, sep as sep9 } from \"node:path\";\nimport chalk8 from \"chalk\";\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/core/event-bus.js\nimport { EventEmitter as EventEmitter3 } from \"node:events\";\nfunction createEventBus() {\n  const emitter = new EventEmitter3();\n  return {\n    emit: (channel, data) => {\n      emitter.emit(channel, data);\n    },\n    on: (channel, handler) => {\n      const safeHandler = async (data) => {\n        try {\n          await handler(data);\n        } catch (err2) {\n          console.error(`Event handler error (${channel}):`, err2);\n        }\n      };\n      emitter.on(channel, safeHandler);\n      return () => emitter.off(channel, safeHandler);\n    },\n    clear: () => {\n      emitter.removeAllListeners();\n    }\n  };\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/core/extensions/loader.js\nimport * as fs7 from \"node:fs\";\nimport { createRequire as createRequire5 } from \"node:module\";\nimport * as path11 from \"node:path\";\nimport { fileURLToPath as fileURLToPath6 } from \"node:url\";\n\n// node_modules/.pnpm/@earendil-works+pi-agent-core@0.84.4_ws@8.21.3/node_modules/@earendil-works/pi-agent-core/dist/index.js\nvar dist_exports2 = {};\n__export(dist_exports2, {\n  AGENT_TELEMETRY_SCHEMAS: () => AGENT_TELEMETRY_SCHEMAS,\n  AI_TELEMETRY_SCHEMA: () => AI_TELEMETRY_SCHEMA,\n  Agent: () => Agent,\n  AgentHarness: () => AgentHarness,\n  BRANCH_SUMMARY_PREFIX: () => BRANCH_SUMMARY_PREFIX2,\n  BRANCH_SUMMARY_SUFFIX: () => BRANCH_SUMMARY_SUFFIX2,\n  BranchSummaryError: () => BranchSummaryError,\n  COMPACTION_SUMMARY_PREFIX: () => COMPACTION_SUMMARY_PREFIX2,\n  COMPACTION_SUMMARY_SUFFIX: () => COMPACTION_SUMMARY_SUFFIX2,\n  Closed: () => Closed,\n  CompactionError: () => CompactionError,\n  DEFAULT_COMPACTION_SETTINGS: () => DEFAULT_COMPACTION_SETTINGS,\n  DEFAULT_MAX_BYTES: () => DEFAULT_MAX_BYTES2,\n  DEFAULT_MAX_LINES: () => DEFAULT_MAX_LINES,\n  ExecutionError: () => ExecutionError,\n  FileError: () => FileError,\n  GREP_MAX_LINE_LENGTH: () => GREP_MAX_LINE_LENGTH,\n  HARNESS_TELEMETRY_SCHEMA: () => HARNESS_TELEMETRY_SCHEMA,\n  HarnessClosed: () => HarnessClosed,\n  HarnessFault: () => HarnessFault,\n  HarnessNotImplemented: () => HarnessNotImplemented,\n  InMemorySessionRepo: () => InMemorySessionRepo,\n  InMemorySessionStorage: () => InMemorySessionStorage,\n  InMemoryTelemetryContext: () => InMemoryTelemetryContext,\n  InvalidLane: () => InvalidLane,\n  InvalidMessage: () => InvalidMessage,\n  JsonlSessionRepo: () => JsonlSessionRepo,\n  LaneBusy: () => LaneBusy,\n  LaneExists: () => LaneExists,\n  MissingIdentities: () => MissingIdentities,\n  NOOP_TELEMETRY_CONTEXT: () => NOOP_TELEMETRY_CONTEXT,\n  NoActiveOperation: () => NoActiveOperation,\n  NoActiveRun: () => NoActiveRun,\n  NothingToCompact: () => NothingToCompact,\n  NothingToResume: () => NothingToResume,\n  Result: () => Result,\n  Session: () => Session,\n  SessionError: () => SessionError,\n  TaggedError: () => TaggedError,\n  UnknownQueueItem: () => UnknownQueueItem,\n  UnknownSkill: () => UnknownSkill,\n  UnknownTarget: () => UnknownTarget,\n  UnknownTemplate: () => UnknownTemplate,\n  agentLoop: () => agentLoop,\n  agentLoopContinue: () => agentLoopContinue,\n  assertJsonSerializable: () => assertJsonSerializable,\n  bashExecutionToText: () => bashExecutionToText2,\n  buildContextEntries: () => buildContextEntries2,\n  buildSessionContext: () => buildSessionContext2,\n  calculateContextTokens: () => calculateContextTokens2,\n  collectEntriesForBranchSummary: () => collectEntriesForBranchSummary,\n  compact: () => compact,\n  convertToLlm: () => convertToLlm2,\n  createBashTool: () => createBashTool,\n  createBranchSummaryMessage: () => createBranchSummaryMessage2,\n  createCompactionSummaryMessage: () => createCompactionSummaryMessage2,\n  createCustomMessage: () => createCustomMessage2,\n  createEditTool: () => createEditTool,\n  createReadTool: () => createReadTool,\n  createScanningSessionSearch: () => createScanningSessionSearch,\n  createTypedSpanStarter: () => createTypedSpanStarter,\n  createWriteTool: () => createWriteTool,\n  defaultContextEntryTransform: () => defaultContextEntryTransform,\n  defineTelemetrySchema: () => defineTelemetrySchema,\n  err: () => err,\n  estimateContextTokens: () => estimateContextTokens2,\n  estimateTokens: () => estimateTokens2,\n  executeShellWithCapture: () => executeShellWithCapture,\n  findCutPoint: () => findCutPoint,\n  findTurnStartIndex: () => findTurnStartIndex,\n  formatPromptTemplateInvocation: () => formatPromptTemplateInvocation,\n  formatSize: () => formatSize,\n  formatSkillInvocation: () => formatSkillInvocation,\n  formatSkillsForSystemPrompt: () => formatSkillsForSystemPrompt,\n  generateBranchSummary: () => generateBranchSummary,\n  generateSummary: () => generateSummary,\n  generateSummaryWithUsage: () => generateSummaryWithUsage,\n  getLastAssistantUsage: () => getLastAssistantUsage,\n  getOrThrow: () => getOrThrow,\n  getOrUndefined: () => getOrUndefined,\n  loadPromptTemplates: () => loadPromptTemplates,\n  loadSkills: () => loadSkills,\n  loadSourcedPromptTemplates: () => loadSourcedPromptTemplates,\n  loadSourcedSkills: () => loadSourcedSkills,\n  matchError: () => matchError,\n  ok: () => ok,\n  parseCommandArgs: () => parseCommandArgs,\n  prepareBranchEntries: () => prepareBranchEntries,\n  prepareCompaction: () => prepareCompaction,\n  runAgentLoop: () => runAgentLoop,\n  runAgentLoopContinue: () => runAgentLoopContinue,\n  sanitizeBinaryOutput: () => sanitizeBinaryOutput2,\n  scanningEntries: () => scanningEntries,\n  serializeConversation: () => serializeConversation,\n  sessionEntryToContextMessages: () => sessionEntryToContextMessages2,\n  setDefaultStreamFn: () => setDefaultStreamFn,\n  shouldCompact: () => shouldCompact,\n  startAiSpan: () => startAiSpan,\n  startHarnessSpan: () => startHarnessSpan,\n  streamProxy: () => streamProxy,\n  substituteArgs: () => substituteArgs,\n  toError: () => toError,\n  truncateHead: () => truncateHead,\n  truncateLine: () => truncateLine,\n  truncateTail: () => truncateTail,\n  uuidv7: () => uuidv72\n});\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.4_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/index.js\nimport { Type as Type5 } from \"typebox\";\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.4_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/utils/event-stream.js\nvar EventStream2 = class {\n  queue = [];\n  waiting = [];\n  done = false;\n  finalResultPromise;\n  resolveFinalResult;\n  isComplete;\n  extractResult;\n  constructor(isComplete, extractResult) {\n    this.isComplete = isComplete;\n    this.extractResult = extractResult;\n    this.finalResultPromise = new Promise((resolve15) => {\n      this.resolveFinalResult = resolve15;\n    });\n  }\n  push(event) {\n    if (this.done)\n      return;\n    if (this.isComplete(event)) {\n      this.done = true;\n      this.resolveFinalResult(this.extractResult(event));\n    }\n    const waiter = this.waiting.shift();\n    if (waiter) {\n      waiter({ value: event, done: false });\n    } else {\n      this.queue.push(event);\n    }\n  }\n  end(result) {\n    this.done = true;\n    if (result !== void 0) {\n      this.resolveFinalResult(result);\n    }\n    while (this.waiting.length > 0) {\n      const waiter = this.waiting.shift();\n      waiter({ value: void 0, done: true });\n    }\n  }\n  async *[Symbol.asyncIterator]() {\n    while (true) {\n      if (this.queue.length > 0) {\n        yield this.queue.shift();\n      } else if (this.done) {\n        return;\n      } else {\n        const result = await new Promise((resolve15) => this.waiting.push(resolve15));\n        if (result.done)\n          return;\n        yield result.value;\n      }\n    }\n  }\n  result() {\n    return this.finalResultPromise;\n  }\n};\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.4_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/utils/json-parse.js\nimport { parse as partialParse2 } from \"partial-json\";\nvar VALID_JSON_ESCAPES2 = /* @__PURE__ */ new Set(['\"', \"\\\\\", \"/\", \"b\", \"f\", \"n\", \"r\", \"t\", \"u\"]);\nfunction isControlCharacter2(char) {\n  const codePoint = char.codePointAt(0);\n  return codePoint !== void 0 && codePoint >= 0 && codePoint <= 31;\n}\nfunction escapeControlCharacter2(char) {\n  switch (char) {\n    case \"\\b\":\n      return \"\\\\b\";\n    case \"\\f\":\n      return \"\\\\f\";\n    case \"\\n\":\n      return \"\\\\n\";\n    case \"\\r\":\n      return \"\\\\r\";\n    case \"\t\":\n      return \"\\\\t\";\n    default:\n      return `\\\\u${char.codePointAt(0)?.toString(16).padStart(4, \"0\") ?? \"0000\"}`;\n  }\n}\nfunction repairJson2(json) {\n  let repaired = \"\";\n  let inString = false;\n  for (let index = 0; index < json.length; index++) {\n    const char = json[index];\n    if (!inString) {\n      repaired += char;\n      if (char === '\"') {\n        inString = true;\n      }\n      continue;\n    }\n    if (char === '\"') {\n      repaired += char;\n      inString = false;\n      continue;\n    }\n    if (char === \"\\\\\") {\n      const nextChar = json[index + 1];\n      if (nextChar === void 0) {\n        repaired += \"\\\\\\\\\";\n        continue;\n      }\n      if (nextChar === \"u\") {\n        const unicodeDigits = json.slice(index + 2, index + 6);\n        if (/^[0-9a-fA-F]{4}$/.test(unicodeDigits)) {\n          repaired += `\\\\u${unicodeDigits}`;\n          index += 5;\n          continue;\n        }\n      }\n      if (VALID_JSON_ESCAPES2.has(nextChar)) {\n        repaired += `\\\\${nextChar}`;\n        index += 1;\n        continue;\n      }\n      repaired += \"\\\\\\\\\";\n      continue;\n    }\n    repaired += isControlCharacter2(char) ? escapeControlCharacter2(char) : char;\n  }\n  return repaired;\n}\nfunction parseJsonWithRepair2(json) {\n  try {\n    return JSON.parse(json);\n  } catch (error) {\n    const repairedJson = repairJson2(json);\n    if (repairedJson !== json) {\n      return JSON.parse(repairedJson);\n    }\n    throw error;\n  }\n}\nfunction parseStreamingJson2(partialJson) {\n  if (!partialJson || partialJson.trim() === \"\") {\n    return {};\n  }\n  try {\n    return parseJsonWithRepair2(partialJson);\n  } catch {\n    try {\n      const result = partialParse2(partialJson);\n      return result ?? {};\n    } catch {\n      try {\n        const result = partialParse2(repairJson2(partialJson));\n        return result ?? {};\n      } catch {\n        return {};\n      }\n    }\n  }\n}\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.4_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/utils/retry.js\nfunction buildProviderErrorPattern2(patterns) {\n  return new RegExp(patterns.join(\"|\"), \"i\");\n}\nvar NON_RETRYABLE_PROVIDER_LIMIT_ERROR_PATTERN2 = buildProviderErrorPattern2([\n  // OpenCode Go/free-tier limits returned as 429 JSON error types by OpenCode's\n  // Zen API. These are subscription/account limits, not transient throttles.\n  \"GoUsageLimitError\",\n  \"FreeUsageLimitError\",\n  // OpenCode Go subscription-limit text asks users to enable available-balance\n  // usage after rolling/weekly/monthly limits are reached.\n  \"Monthly usage limit reached\",\n  \"available balance\",\n  // Generic quota/budget/billing exhaustion. `insufficient_quota` is OpenAI's\n  // quota/billing error code; the other strings cover common gateway wording.\n  \"insufficient_quota\",\n  \"out of budget\",\n  \"quota exceeded\",\n  \"billing\"\n]);\nvar RETRYABLE_PROVIDER_ERROR_PATTERN2 = buildProviderErrorPattern2([\n  // Generic provider load, HTTP status, and server-side transient failures.\n  \"overloaded\",\n  \"rate.?limit\",\n  \"too many requests\",\n  \"429\",\n  \"500\",\n  \"502\",\n  \"503\",\n  \"504\",\n  \"524\",\n  \"service.?unavailable\",\n  \"server.?error\",\n  \"internal.?error\",\n  // Wrapper/provider text for transient upstream failures, including OpenRouter\n  // \"Provider returned error\" responses (#2264).\n  \"provider.?returned.?error\",\n  \"exceeded request buffer limit while retrying upstream\",\n  // Network, proxy, and fetch transport failures. This includes OpenAI Codex\n  // raw-fetch failures such as \"upstream connect\", \"connection refused\", and\n  // \"reset before headers\" (#733), plus OpenRouter connection drops (#3317).\n  \"network.?error\",\n  \"connection.?error\",\n  \"connection.?refused\",\n  \"connection.?lost\",\n  \"other side closed\",\n  \"fetch failed\",\n  \"getaddrinfo\",\n  \"ENOTFOUND\",\n  \"EAI_AGAIN\",\n  \"upstream.?connect\",\n  \"reset before headers\",\n  \"socket hang up\",\n  \"socket connection was closed\",\n  \"timed? out\",\n  \"timeout\",\n  \"terminated\",\n  // WebSocket transports can report close/error text instead of HTTP/fetch text.\n  \"websocket.?closed\",\n  \"websocket.?error\",\n  // Premature stream endings from SDKs and transports. Anthropic can throw\n  // \"stream ended without ...\" and \"Anthropic stream ended before message_stop\"\n  // (#4433); Bedrock/Smithy can throw an HTTP/2 no-response error (#3594).\n  \"ended without\",\n  \"stream ended before message_stop\",\n  \"stream ended before a terminal response event\",\n  \"http2 request did not get a response\",\n  // Provider-requested retry delay cap failures should flow through the outer\n  // retry policy so callers can surface/abort the backoff (#1123).\n  \"retry delay\",\n  // Explicit retry guidance emitted mid-stream by OpenAI Responses and Bedrock\n  // stream exceptions (#6019).\n  \"you can retry your request\",\n  \"try your request again\",\n  \"please retry your request\",\n  // gRPC based providers (e.g. NVIDIA NIM)\n  \"ResourceExhausted\"\n]);\nvar RetrySleepAbortError2 = class extends Error {\n  constructor() {\n    super(\"Aborted\");\n  }\n};\nfunction sleep4(ms, signal) {\n  return new Promise((resolve15, reject) => {\n    if (signal?.aborted) {\n      reject(new RetrySleepAbortError2());\n      return;\n    }\n    const timeout = setTimeout(resolve15, ms);\n    signal?.addEventListener(\"abort\", () => {\n      clearTimeout(timeout);\n      reject(new RetrySleepAbortError2());\n    }, { once: true });\n  });\n}\nasync function retryAssistantCall2(produce, policy, signal, callbacks) {\n  const maxAttempts = policy?.enabled ? policy.maxRetries : 0;\n  let attempt = 0;\n  let lastRetry;\n  for (; ; ) {\n    const response = await produce();\n    if (response.stopReason === \"aborted\") {\n      if (lastRetry)\n        await callbacks?.onRetryFinished?.(false, lastRetry.attempt);\n      return response;\n    }\n    if (response.stopReason !== \"error\") {\n      if (lastRetry)\n        await callbacks?.onRetryFinished?.(true, lastRetry.attempt);\n      return response;\n    }\n    if (attempt >= maxAttempts || !isRetryableAssistantError2(response)) {\n      if (lastRetry)\n        await callbacks?.onRetryFinished?.(false, lastRetry.attempt, response.errorMessage);\n      return response;\n    }\n    attempt++;\n    lastRetry = { attempt, errorMessage: response.errorMessage || \"Unknown error\" };\n    const delayMs = policy.baseDelayMs * 2 ** (attempt - 1);\n    await callbacks?.onRetryScheduled?.(attempt, maxAttempts, delayMs, lastRetry.errorMessage);\n    try {\n      await sleep4(delayMs, signal);\n    } catch (error) {\n      await callbacks?.onRetryFinished?.(false, attempt, lastRetry.errorMessage);\n      if (error instanceof RetrySleepAbortError2) {\n        return { ...response, stopReason: \"aborted\", errorMessage: void 0 };\n      }\n      throw error;\n    }\n    await callbacks?.onRetryAttemptStart?.();\n  }\n}\nfunction isRetryableAssistantError2(message) {\n  if (message.stopReason !== \"error\" || !message.errorMessage)\n    return false;\n  const errorMessage2 = message.errorMessage;\n  if (NON_RETRYABLE_PROVIDER_LIMIT_ERROR_PATTERN2.test(errorMessage2))\n    return false;\n  return RETRYABLE_PROVIDER_ERROR_PATTERN2.test(errorMessage2);\n}\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.4_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/utils/text.js\nfunction contentText2(content, separator = \"\\n\") {\n  if (typeof content === \"string\")\n    return content;\n  return content.filter((block) => block.type === \"text\").map((block) => block.text).join(separator);\n}\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.4_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/utils/uuid.js\nvar lastTimestamp2 = -Infinity;\nvar sequence2 = 0;\nfunction fillRandomBytes2(bytes) {\n  if (globalThis.crypto?.getRandomValues) {\n    globalThis.crypto.getRandomValues(bytes);\n    return;\n  }\n  for (let i = 0; i < bytes.length; i++) {\n    bytes[i] = Math.floor(Math.random() * 256);\n  }\n}\nfunction uuidv72() {\n  const random = new Uint8Array(16);\n  fillRandomBytes2(random);\n  const timestamp = Date.now();\n  if (timestamp > lastTimestamp2) {\n    sequence2 = random[6] * 16777216 + random[7] * 65536 + random[8] * 256 + random[9];\n    lastTimestamp2 = timestamp;\n  } else {\n    sequence2 = sequence2 + 1 >>> 0;\n    if (sequence2 === 0)\n      lastTimestamp2++;\n  }\n  const bytes = new Uint8Array(16);\n  bytes[0] = lastTimestamp2 / 1099511627776 & 255;\n  bytes[1] = lastTimestamp2 / 4294967296 & 255;\n  bytes[2] = lastTimestamp2 / 16777216 & 255;\n  bytes[3] = lastTimestamp2 / 65536 & 255;\n  bytes[4] = lastTimestamp2 / 256 & 255;\n  bytes[5] = lastTimestamp2 & 255;\n  bytes[6] = 112 | sequence2 >>> 28 & 15;\n  bytes[7] = sequence2 >>> 20 & 255;\n  bytes[8] = 128 | sequence2 >>> 14 & 63;\n  bytes[9] = sequence2 >>> 6 & 255;\n  bytes[10] = (sequence2 & 63) << 2 | random[10] & 3;\n  bytes[11] = random[11];\n  bytes[12] = random[12];\n  bytes[13] = random[13];\n  bytes[14] = random[14];\n  bytes[15] = random[15];\n  const hex = Array.from(bytes, (byte) => byte.toString(16).padStart(2, \"0\"));\n  return `${hex.slice(0, 4).join(\"\")}-${hex.slice(4, 6).join(\"\")}-${hex.slice(6, 8).join(\"\")}-${hex.slice(8, 10).join(\"\")}-${hex.slice(10, 16).join(\"\")}`;\n}\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.4_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/utils/validation.js\nimport { Compile as Compile4 } from \"typebox/compile\";\nimport { Value as Value2 } from \"typebox/value\";\nvar validatorCache2 = /* @__PURE__ */ new WeakMap();\nvar TYPEBOX_KIND2 = Symbol.for(\"TypeBox.Kind\");\nfunction getSchemaTypes2(schema) {\n  if (typeof schema.type === \"string\") {\n    return [schema.type];\n  }\n  if (Array.isArray(schema.type)) {\n    return schema.type.filter((type) => typeof type === \"string\");\n  }\n  return [];\n}\nfunction matchesJsonType2(value, type) {\n  switch (type) {\n    case \"number\":\n      return typeof value === \"number\";\n    case \"integer\":\n      return typeof value === \"number\" && Number.isInteger(value);\n    case \"boolean\":\n      return typeof value === \"boolean\";\n    case \"string\":\n      return typeof value === \"string\";\n    case \"null\":\n      return value === null;\n    case \"array\":\n      return Array.isArray(value);\n    case \"object\":\n      return typeof value === \"object\" && value !== null && !Array.isArray(value);\n    default:\n      return false;\n  }\n}\nfunction getSubSchemaValidator2(schema) {\n  try {\n    return getValidator2(schema);\n  } catch {\n    return void 0;\n  }\n}\nfunction coercePrimitiveByType2(value, type) {\n  switch (type) {\n    case \"number\": {\n      if (value === null) {\n        return 0;\n      }\n      if (typeof value === \"string\" && value.trim() !== \"\") {\n        const parsed = Number(value);\n        if (Number.isFinite(parsed)) {\n          return parsed;\n        }\n      }\n      if (typeof value === \"boolean\") {\n        return value ? 1 : 0;\n      }\n      return value;\n    }\n    case \"integer\": {\n      if (value === null) {\n        return 0;\n      }\n      if (typeof value === \"string\" && value.trim() !== \"\") {\n        const parsed = Number(value);\n        if (Number.isInteger(parsed)) {\n          return parsed;\n        }\n      }\n      if (typeof value === \"boolean\") {\n        return value ? 1 : 0;\n      }\n      return value;\n    }\n    case \"boolean\": {\n      if (value === null) {\n        return false;\n      }\n      if (typeof value === \"string\") {\n        if (value === \"true\") {\n          return true;\n        }\n        if (value === \"false\") {\n          return false;\n        }\n      }\n      if (typeof value === \"number\") {\n        if (value === 1) {\n          return true;\n        }\n        if (value === 0) {\n          return false;\n        }\n      }\n      return value;\n    }\n    case \"string\": {\n      if (value === null) {\n        return \"\";\n      }\n      if (typeof value === \"number\" || typeof value === \"boolean\") {\n        return String(value);\n      }\n      return value;\n    }\n    case \"null\": {\n      if (value === \"\" || value === 0 || value === false) {\n        return null;\n      }\n      return value;\n    }\n    default:\n      return value;\n  }\n}\nfunction applySchemaObjectCoercion2(value, schema) {\n  const properties = schema.properties;\n  const definedKeys = new Set(properties ? Object.keys(properties) : []);\n  if (properties) {\n    for (const [key, propertySchema] of Object.entries(properties)) {\n      if (!(key in value)) {\n        continue;\n      }\n      value[key] = coerceWithJsonSchema2(value[key], propertySchema);\n    }\n  }\n  if (schema.additionalProperties && typeof schema.additionalProperties === \"object\") {\n    for (const [key, propertyValue] of Object.entries(value)) {\n      if (definedKeys.has(key)) {\n        continue;\n      }\n      value[key] = coerceWithJsonSchema2(propertyValue, schema.additionalProperties);\n    }\n  }\n}\nfunction applySchemaArrayCoercion2(value, schema) {\n  if (Array.isArray(schema.items)) {\n    for (let index = 0; index < value.length; index++) {\n      const itemSchema = schema.items[index];\n      if (!itemSchema) {\n        continue;\n      }\n      value[index] = coerceWithJsonSchema2(value[index], itemSchema);\n    }\n    return;\n  }\n  if (schema.items && typeof schema.items === \"object\") {\n    for (let index = 0; index < value.length; index++) {\n      value[index] = coerceWithJsonSchema2(value[index], schema.items);\n    }\n  }\n}\nfunction coerceWithUnionSchema2(value, schemas) {\n  for (const schema of schemas) {\n    const validator = getSubSchemaValidator2(schema);\n    if (validator?.Check(value)) {\n      return value;\n    }\n  }\n  for (const schema of schemas) {\n    const candidate = structuredClone(value);\n    const coerced = coerceWithJsonSchema2(candidate, schema);\n    const validator = getSubSchemaValidator2(schema);\n    if (validator?.Check(coerced)) {\n      return coerced;\n    }\n  }\n  return value;\n}\nfunction coerceWithJsonSchema2(value, schema) {\n  let nextValue = value;\n  if (Array.isArray(schema.allOf)) {\n    for (const nested of schema.allOf) {\n      nextValue = coerceWithJsonSchema2(nextValue, nested);\n    }\n  }\n  if (Array.isArray(schema.anyOf)) {\n    nextValue = coerceWithUnionSchema2(nextValue, schema.anyOf);\n  }\n  if (Array.isArray(schema.oneOf)) {\n    nextValue = coerceWithUnionSchema2(nextValue, schema.oneOf);\n  }\n  const schemaTypes = getSchemaTypes2(schema);\n  const matchesUnionMember = schemaTypes.length > 1 && schemaTypes.some((schemaType) => matchesJsonType2(nextValue, schemaType));\n  if (schemaTypes.length > 0 && !matchesUnionMember) {\n    for (const schemaType of schemaTypes) {\n      const candidate = coercePrimitiveByType2(nextValue, schemaType);\n      if (candidate !== nextValue) {\n        nextValue = candidate;\n        break;\n      }\n    }\n  }\n  if (schemaTypes.includes(\"object\") && typeof nextValue === \"object\" && nextValue !== null && !Array.isArray(nextValue)) {\n    applySchemaObjectCoercion2(nextValue, schema);\n  }\n  if (schemaTypes.includes(\"array\") && Array.isArray(nextValue)) {\n    applySchemaArrayCoercion2(nextValue, schema);\n  }\n  return nextValue;\n}\nfunction normalizeOptionalNulls2(value, schema) {\n  if (Array.isArray(value)) {\n    if (Array.isArray(schema.items)) {\n      for (let index = 0; index < value.length; index++) {\n        const itemSchema = schema.items[index];\n        if (itemSchema)\n          normalizeOptionalNulls2(value[index], itemSchema);\n      }\n    } else if (schema.items) {\n      for (const item of value)\n        normalizeOptionalNulls2(item, schema.items);\n    }\n    return;\n  }\n  if (typeof value !== \"object\" || value === null || !schema.properties)\n    return;\n  const object = value;\n  const required = new Set(schema.required ?? []);\n  for (const [key, propertySchema] of Object.entries(schema.properties)) {\n    if (!(key in object))\n      continue;\n    if (object[key] === null && !required.has(key) && typeof propertySchema.$ref !== \"string\" && getSubSchemaValidator2(propertySchema)?.Check(null) === false) {\n      delete object[key];\n    } else {\n      normalizeOptionalNulls2(object[key], propertySchema);\n    }\n  }\n}\nfunction getValidator2(schema) {\n  const key = schema;\n  const cached = validatorCache2.get(key);\n  if (cached) {\n    return cached;\n  }\n  const validator = Compile4(schema);\n  validatorCache2.set(key, validator);\n  return validator;\n}\nfunction formatValidationPath3(error) {\n  if (error.keyword === \"required\") {\n    const requiredProperties = error.params.requiredProperties;\n    const requiredProperty = requiredProperties?.[0];\n    if (requiredProperty) {\n      const basePath = error.instancePath.replace(/^\\//, \"\").replace(/\\//g, \".\");\n      return basePath ? `${basePath}.${requiredProperty}` : requiredProperty;\n    }\n  }\n  const path12 = error.instancePath.replace(/^\\//, \"\").replace(/\\//g, \".\");\n  return path12 || \"root\";\n}\nfunction validateToolArguments2(tool, toolCall) {\n  const args = structuredClone(toolCall.arguments);\n  normalizeOptionalNulls2(args, tool.parameters);\n  Value2.Convert(tool.parameters, args);\n  const validator = getValidator2(tool.parameters);\n  if (!Object.getOwnPropertySymbols(tool.parameters).includes(TYPEBOX_KIND2)) {\n    const coerced = coerceWithJsonSchema2(args, tool.parameters);\n    if (coerced !== args) {\n      if (typeof args === \"object\" && args !== null && typeof coerced === \"object\" && coerced !== null) {\n        for (const key of Object.keys(args)) {\n          delete args[key];\n        }\n        Object.assign(args, coerced);\n      } else {\n        return validator.Check(coerced) ? coerced : args;\n      }\n    }\n  }\n  if (validator.Check(args)) {\n    return args;\n  }\n  const errors = validator.Errors(args).map((error) => `  - ${formatValidationPath3(error)}: ${error.message}`).join(\"\\n\") || \"Unknown validation error\";\n  const errorMessage2 = `Validation failed for tool \"${toolCall.name}\":\n${errors}\n\nReceived arguments:\n${JSON.stringify(toolCall.arguments, null, 2)}`;\n  throw new Error(errorMessage2);\n}\n\n// node_modules/.pnpm/@earendil-works+pi-telemetry@0.84.4/node_modules/@earendil-works/pi-telemetry/dist/noop.js\nfunction startNoopSpan(_options, callback) {\n  try {\n    return Promise.resolve(callback(noopTelemetrySpan));\n  } catch (error) {\n    return Promise.reject(error);\n  }\n}\nvar noopTelemetrySpan = {\n  startSpan: startNoopSpan,\n  addEvent: () => {\n  },\n  setAttributes: () => {\n  },\n  setStatus: () => {\n  }\n};\nObject.freeze(noopTelemetrySpan);\nvar NOOP_TELEMETRY_CONTEXT = noopTelemetrySpan;\n\n// node_modules/.pnpm/@earendil-works+pi-telemetry@0.84.4/node_modules/@earendil-works/pi-telemetry/dist/memory.js\nfunction copyAttributeValue(value) {\n  return Array.isArray(value) ? [...value] : value;\n}\nfunction copyAttributes(attributes) {\n  const copy = {};\n  if (!attributes)\n    return copy;\n  for (const [name, value] of Object.entries(attributes)) {\n    if (value !== void 0)\n      copy[name] = copyAttributeValue(value);\n  }\n  return copy;\n}\nfunction mergeAttributes(current, attributes) {\n  const merged = copyAttributes(current);\n  for (const [name, value] of Object.entries(attributes)) {\n    if (value !== void 0)\n      merged[name] = copyAttributeValue(value);\n  }\n  return merged;\n}\nfunction copyStatus(status) {\n  if (status.status === \"ok\")\n    return { status: \"ok\" };\n  return status.error ? { status: \"error\", error: { name: status.error.name, message: status.error.message } } : { status: \"error\" };\n}\nfunction automaticErrorStatus(error) {\n  try {\n    if (error instanceof Error) {\n      return { status: \"error\", error: { name: error.name, message: error.message } };\n    }\n  } catch {\n  }\n  return { status: \"error\" };\n}\nfunction settleSpan(state, span, failed, error) {\n  if (span.settled)\n    return;\n  if (failed && !span.explicitStatus)\n    span.status = automaticErrorStatus(error);\n  span.settled = true;\n  span.endSequence = state.nextEndSequence++;\n}\nfunction createSpan(state, parent, options) {\n  const name = options.name;\n  const attributes = copyAttributes(options.attributes);\n  return {\n    id: state.nextSpanId++,\n    parentId: parent?.id ?? null,\n    name,\n    attributes,\n    events: [],\n    status: { status: \"ok\" },\n    explicitStatus: false,\n    settled: false\n  };\n}\nfunction startInMemorySpan(state, parent, options, callback) {\n  if (parent?.settled)\n    return NOOP_TELEMETRY_CONTEXT.startSpan(options, callback);\n  let recordedSpan;\n  try {\n    recordedSpan = createSpan(state, parent, options);\n    state.spans.push(recordedSpan);\n  } catch {\n    return NOOP_TELEMETRY_CONTEXT.startSpan(options, callback);\n  }\n  const span = {\n    startSpan: (childOptions, childCallback) => startInMemorySpan(state, recordedSpan, childOptions, childCallback),\n    addEvent(name, attributes) {\n      if (recordedSpan.settled)\n        return;\n      try {\n        recordedSpan.events.push({ name, attributes: copyAttributes(attributes) });\n      } catch {\n      }\n    },\n    setAttributes(attributes) {\n      if (recordedSpan.settled)\n        return;\n      try {\n        recordedSpan.attributes = mergeAttributes(recordedSpan.attributes, attributes);\n      } catch {\n      }\n    },\n    setStatus(status) {\n      if (recordedSpan.settled)\n        return;\n      try {\n        recordedSpan.status = copyStatus(status);\n        recordedSpan.explicitStatus = true;\n      } catch {\n      }\n    }\n  };\n  let result;\n  try {\n    result = callback(span);\n  } catch (error) {\n    settleSpan(state, recordedSpan, true, error);\n    return Promise.reject(error);\n  }\n  return Promise.resolve(result).then((value) => {\n    settleSpan(state, recordedSpan, false);\n    return value;\n  }, (error) => {\n    settleSpan(state, recordedSpan, true, error);\n    throw error;\n  });\n}\nvar InMemoryTelemetryContext = class {\n  state = {\n    spans: [],\n    nextSpanId: 1,\n    nextEndSequence: 1\n  };\n  startSpan(options, callback) {\n    return startInMemorySpan(this.state, void 0, options, callback);\n  }\n  /** Returns detached snapshots in span-start order. */\n  getSpans() {\n    return this.state.spans.map((span) => ({\n      id: span.id,\n      parentId: span.parentId,\n      name: span.name,\n      attributes: copyAttributes(span.attributes),\n      events: span.events.map((event) => ({\n        name: event.name,\n        attributes: copyAttributes(event.attributes)\n      })),\n      status: copyStatus(span.status),\n      settled: span.settled,\n      ...span.endSequence === void 0 ? {} : { endSequence: span.endSequence }\n    }));\n  }\n};\n\n// node_modules/.pnpm/@earendil-works+pi-telemetry@0.84.4/node_modules/@earendil-works/pi-telemetry/dist/index.js\nfunction defineTelemetrySchema(schema) {\n  return schema;\n}\nfunction bindTypedSpanStarter(telemetryContext) {\n  const startSpan = (name, attributes, callback) => telemetryContext.startSpan({ name, attributes }, (span) => callback(span, bindTypedSpanStarter(span)));\n  return startSpan;\n}\nfunction createTypedSpanStarter(telemetryContext, _schemas) {\n  return bindTypedSpanStarter(telemetryContext);\n}\n\n// node_modules/.pnpm/@earendil-works+pi-agent-core@0.84.4_ws@8.21.3/node_modules/@earendil-works/pi-agent-core/dist/stream-fn.js\nvar defaultStreamFn;\nfunction setDefaultStreamFn(streamFn) {\n  defaultStreamFn = streamFn;\n}\nfunction getDefaultStreamFn() {\n  if (!defaultStreamFn) {\n    throw new Error(\"No default stream function configured. Pass streamFn explicitly or call setDefaultStreamFn().\");\n  }\n  return defaultStreamFn;\n}\n\n// node_modules/.pnpm/@earendil-works+pi-agent-core@0.84.4_ws@8.21.3/node_modules/@earendil-works/pi-agent-core/dist/agent-loop.js\nfunction agentLoop(prompts, context, config, signal, streamFn) {\n  const stream11 = createAgentStream();\n  void runAgentLoop(prompts, context, config, async (event) => {\n    stream11.push(event);\n  }, signal, streamFn).then((messages) => {\n    stream11.end(messages);\n  });\n  return stream11;\n}\nfunction agentLoopContinue(context, config, signal, streamFn) {\n  if (context.messages.length === 0) {\n    throw new Error(\"Cannot continue: no messages in context\");\n  }\n  if (context.messages[context.messages.length - 1].role === \"assistant\") {\n    throw new Error(\"Cannot continue from message role: assistant\");\n  }\n  const stream11 = createAgentStream();\n  void runAgentLoopContinue(context, config, async (event) => {\n    stream11.push(event);\n  }, signal, streamFn).then((messages) => {\n    stream11.end(messages);\n  });\n  return stream11;\n}\nasync function runAgentLoop(prompts, context, config, emit, signal, streamFn) {\n  const newMessages = [...prompts];\n  const currentContext = {\n    ...context,\n    messages: [...context.messages, ...prompts]\n  };\n  await emit({ type: \"agent_start\" });\n  await emit({ type: \"turn_start\" });\n  for (const prompt of prompts) {\n    await emit({ type: \"message_start\", message: prompt });\n    await emit({ type: \"message_end\", message: prompt });\n  }\n  await runLoop(currentContext, newMessages, config, signal, emit, streamFn ?? getDefaultStreamFn());\n  return newMessages;\n}\nasync function runAgentLoopContinue(context, config, emit, signal, streamFn) {\n  if (context.messages.length === 0) {\n    throw new Error(\"Cannot continue: no messages in context\");\n  }\n  if (context.messages[context.messages.length - 1].role === \"assistant\") {\n    throw new Error(\"Cannot continue from message role: assistant\");\n  }\n  const newMessages = [];\n  const currentContext = { ...context };\n  await emit({ type: \"agent_start\" });\n  await emit({ type: \"turn_start\" });\n  await runLoop(currentContext, newMessages, config, signal, emit, streamFn ?? getDefaultStreamFn());\n  return newMessages;\n}\nfunction createAgentStream() {\n  return new EventStream2((event) => event.type === \"agent_end\", (event) => event.type === \"agent_end\" ? event.messages : []);\n}\nasync function runLoop(initialContext, newMessages, initialConfig, signal, emit, streamFunction) {\n  let currentContext = initialContext;\n  let config = initialConfig;\n  let lastCompletedTurn;\n  let pendingMessages = await config.getSteeringMessages?.() || [];\n  while (true) {\n    let hasMoreToolCalls = true;\n    while (hasMoreToolCalls || pendingMessages.length > 0) {\n      if (lastCompletedTurn) {\n        const nextTurnSnapshot = await config.prepareNextTurn?.(lastCompletedTurn);\n        if (nextTurnSnapshot) {\n          currentContext = nextTurnSnapshot.context ?? currentContext;\n          config = {\n            ...config,\n            model: nextTurnSnapshot.model ?? config.model,\n            reasoning: nextTurnSnapshot.thinkingLevel === void 0 ? config.reasoning : nextTurnSnapshot.thinkingLevel === \"off\" ? void 0 : nextTurnSnapshot.thinkingLevel\n          };\n        }\n        if (pendingMessages.length === 0) {\n          pendingMessages = await config.getSteeringMessages?.() || [];\n        }\n        await emit({ type: \"turn_start\" });\n      }\n      if (pendingMessages.length > 0) {\n        for (const message2 of pendingMessages) {\n          await emit({ type: \"message_start\", message: message2 });\n          await emit({ type: \"message_end\", message: message2 });\n          currentContext.messages.push(message2);\n          newMessages.push(message2);\n        }\n        pendingMessages = [];\n      }\n      const message = await streamAssistantResponse(currentContext, config, signal, emit, streamFunction);\n      newMessages.push(message);\n      if (message.stopReason === \"error\" || message.stopReason === \"aborted\") {\n        await emit({ type: \"turn_end\", message, toolResults: [] });\n        await emit({ type: \"agent_end\", messages: newMessages });\n        return;\n      }\n      const toolCalls = message.content.filter((c) => c.type === \"toolCall\");\n      const toolResults = [];\n      hasMoreToolCalls = false;\n      if (toolCalls.length > 0) {\n        const executedToolBatch = message.stopReason === \"length\" ? await failToolCallsFromTruncatedMessage(toolCalls, emit) : await executeToolCalls(currentContext, message, config, signal, emit);\n        toolResults.push(...executedToolBatch.messages);\n        hasMoreToolCalls = !executedToolBatch.terminate;\n        for (const result of toolResults) {\n          currentContext.messages.push(result);\n          newMessages.push(result);\n        }\n      }\n      await emit({ type: \"turn_end\", message, toolResults });\n      lastCompletedTurn = {\n        message,\n        toolResults,\n        context: currentContext,\n        newMessages\n      };\n      if (await config.shouldStopAfterTurn?.(lastCompletedTurn)) {\n        await emit({ type: \"agent_end\", messages: newMessages });\n        return;\n      }\n      pendingMessages = await config.getSteeringMessages?.() || [];\n    }\n    const followUpMessages = await config.getFollowUpMessages?.() || [];\n    if (followUpMessages.length > 0) {\n      pendingMessages = followUpMessages;\n      continue;\n    }\n    break;\n  }\n  await emit({ type: \"agent_end\", messages: newMessages });\n}\nasync function streamAssistantResponse(context, config, signal, emit, streamFunction) {\n  let messages = context.messages;\n  if (config.transformContext) {\n    messages = await config.transformContext(messages, signal);\n  }\n  const llmMessages = await config.convertToLlm(messages);\n  const llmContext = {\n    systemPrompt: context.systemPrompt,\n    messages: llmMessages,\n    tools: context.tools\n  };\n  const resolvedApiKey = (config.getApiKey ? await config.getApiKey(config.model.provider) : void 0) || config.apiKey;\n  const response = await streamFunction(config.model, llmContext, {\n    ...config,\n    apiKey: resolvedApiKey,\n    signal\n  });\n  let partialMessage = null;\n  let addedPartial = false;\n  for await (const event of response) {\n    switch (event.type) {\n      case \"start\":\n        partialMessage = event.partial;\n        context.messages.push(partialMessage);\n        addedPartial = true;\n        await emit({ type: \"message_start\", message: { ...partialMessage } });\n        break;\n      case \"text_start\":\n      case \"text_delta\":\n      case \"text_end\":\n      case \"thinking_start\":\n      case \"thinking_delta\":\n      case \"thinking_end\":\n      case \"toolcall_start\":\n      case \"toolcall_delta\":\n      case \"toolcall_end\":\n        if (partialMessage) {\n          partialMessage = event.partial;\n          context.messages[context.messages.length - 1] = partialMessage;\n          await emit({\n            type: \"message_update\",\n            assistantMessageEvent: event,\n            message: { ...partialMessage }\n          });\n        }\n        break;\n      case \"done\":\n      case \"error\": {\n        const finalMessage2 = await response.result();\n        if (addedPartial) {\n          context.messages[context.messages.length - 1] = finalMessage2;\n        } else {\n          context.messages.push(finalMessage2);\n        }\n        if (!addedPartial) {\n          await emit({ type: \"message_start\", message: { ...finalMessage2 } });\n        }\n        await emit({ type: \"message_end\", message: finalMessage2 });\n        return finalMessage2;\n      }\n    }\n  }\n  const finalMessage = await response.result();\n  if (addedPartial) {\n    context.messages[context.messages.length - 1] = finalMessage;\n  } else {\n    context.messages.push(finalMessage);\n    await emit({ type: \"message_start\", message: { ...finalMessage } });\n  }\n  await emit({ type: \"message_end\", message: finalMessage });\n  return finalMessage;\n}\nasync function failToolCallsFromTruncatedMessage(toolCalls, emit) {\n  const messages = [];\n  for (const toolCall of toolCalls) {\n    await emit({\n      type: \"tool_execution_start\",\n      toolCallId: toolCall.id,\n      toolName: toolCall.name,\n      args: toolCall.arguments\n    });\n    const finalized = {\n      toolCall,\n      result: createErrorToolResult(`Tool call \"${toolCall.name}\" was not executed: the response hit the output token limit, so its arguments may be truncated. Re-issue the tool call with complete arguments.`),\n      isError: true\n    };\n    await emitToolExecutionEnd(finalized, emit);\n    const toolResultMessage = createToolResultMessage(finalized);\n    await emitToolResultMessage(toolResultMessage, emit);\n    messages.push(toolResultMessage);\n  }\n  return { messages, terminate: false };\n}\nasync function executeToolCalls(currentContext, assistantMessage, config, signal, emit) {\n  const toolCalls = assistantMessage.content.filter((c) => c.type === \"toolCall\");\n  const hasSequentialToolCall = toolCalls.some((tc) => currentContext.tools?.find((t) => t.name === tc.name)?.executionMode === \"sequential\");\n  if (config.toolExecution === \"sequential\" || hasSequentialToolCall) {\n    return executeToolCallsSequential(currentContext, assistantMessage, toolCalls, config, signal, emit);\n  }\n  return executeToolCallsParallel(currentContext, assistantMessage, toolCalls, config, signal, emit);\n}\nasync function executeToolCallsSequential(currentContext, assistantMessage, toolCalls, config, signal, emit) {\n  const finalizedCalls = [];\n  const messages = [];\n  for (const toolCall of toolCalls) {\n    await emit({\n      type: \"tool_execution_start\",\n      toolCallId: toolCall.id,\n      toolName: toolCall.name,\n      args: toolCall.arguments\n    });\n    const preparation = await prepareToolCall(currentContext, assistantMessage, toolCall, config, signal);\n    let finalized;\n    if (preparation.kind === \"immediate\") {\n      finalized = {\n        toolCall,\n        result: preparation.result,\n        isError: preparation.isError\n      };\n    } else {\n      const executed = await executePreparedToolCall(preparation, signal, emit);\n      finalized = await finalizeExecutedToolCall(currentContext, assistantMessage, preparation, executed, config, signal);\n    }\n    await emitToolExecutionEnd(finalized, emit);\n    const toolResultMessage = createToolResultMessage(finalized);\n    await emitToolResultMessage(toolResultMessage, emit);\n    finalizedCalls.push(finalized);\n    messages.push(toolResultMessage);\n    if (signal?.aborted) {\n      break;\n    }\n  }\n  return {\n    messages,\n    terminate: shouldTerminateToolBatch(finalizedCalls)\n  };\n}\nasync function executeToolCallsParallel(currentContext, assistantMessage, toolCalls, config, signal, emit) {\n  const finalizedCalls = [];\n  for (const toolCall of toolCalls) {\n    await emit({\n      type: \"tool_execution_start\",\n      toolCallId: toolCall.id,\n      toolName: toolCall.name,\n      args: toolCall.arguments\n    });\n    const preparation = await prepareToolCall(currentContext, assistantMessage, toolCall, config, signal);\n    if (preparation.kind === \"immediate\") {\n      const finalized = {\n        toolCall,\n        result: preparation.result,\n        isError: preparation.isError\n      };\n      await emitToolExecutionEnd(finalized, emit);\n      finalizedCalls.push(finalized);\n      if (signal?.aborted) {\n        break;\n      }\n      continue;\n    }\n    finalizedCalls.push(async () => {\n      const executed = await executePreparedToolCall(preparation, signal, emit);\n      const finalized = await finalizeExecutedToolCall(currentContext, assistantMessage, preparation, executed, config, signal);\n      await emitToolExecutionEnd(finalized, emit);\n      return finalized;\n    });\n    if (signal?.aborted) {\n      break;\n    }\n  }\n  const orderedFinalizedCalls = await Promise.all(finalizedCalls.map((entry) => typeof entry === \"function\" ? entry() : Promise.resolve(entry)));\n  const messages = [];\n  for (const finalized of orderedFinalizedCalls) {\n    const toolResultMessage = createToolResultMessage(finalized);\n    await emitToolResultMessage(toolResultMessage, emit);\n    messages.push(toolResultMessage);\n  }\n  return {\n    messages,\n    terminate: shouldTerminateToolBatch(orderedFinalizedCalls)\n  };\n}\nfunction shouldTerminateToolBatch(finalizedCalls) {\n  return finalizedCalls.length > 0 && finalizedCalls.every((finalized) => finalized.result.terminate === true);\n}\nfunction prepareToolCallArguments(tool, toolCall) {\n  if (!tool.prepareArguments) {\n    return toolCall;\n  }\n  const preparedArguments = tool.prepareArguments(toolCall.arguments);\n  if (preparedArguments === toolCall.arguments) {\n    return toolCall;\n  }\n  return {\n    ...toolCall,\n    arguments: preparedArguments\n  };\n}\nasync function prepareToolCall(currentContext, assistantMessage, toolCall, config, signal) {\n  const tool = currentContext.tools?.find((t) => t.name === toolCall.name);\n  if (!tool) {\n    return {\n      kind: \"immediate\",\n      result: createErrorToolResult(`Tool ${toolCall.name} not found`),\n      isError: true\n    };\n  }\n  try {\n    const preparedToolCall = prepareToolCallArguments(tool, toolCall);\n    const validatedArgs = validateToolArguments2(tool, preparedToolCall);\n    if (config.beforeToolCall) {\n      const beforeResult = await config.beforeToolCall({\n        assistantMessage,\n        toolCall,\n        args: validatedArgs,\n        context: currentContext\n      }, signal);\n      if (signal?.aborted) {\n        return {\n          kind: \"immediate\",\n          result: createErrorToolResult(\"Operation aborted\"),\n          isError: true\n        };\n      }\n      if (beforeResult?.block) {\n        const result = createErrorToolResult(beforeResult.reason || \"Tool execution was blocked\");\n        if (beforeResult.terminate === true) {\n          result.terminate = true;\n        }\n        return {\n          kind: \"immediate\",\n          result,\n          isError: true\n        };\n      }\n    }\n    if (signal?.aborted) {\n      return {\n        kind: \"immediate\",\n        result: createErrorToolResult(\"Operation aborted\"),\n        isError: true\n      };\n    }\n    return {\n      kind: \"prepared\",\n      toolCall,\n      tool,\n      args: validatedArgs\n    };\n  } catch (error) {\n    return {\n      kind: \"immediate\",\n      result: createErrorToolResult(error instanceof Error ? error.message : String(error)),\n      isError: true\n    };\n  }\n}\nasync function executePreparedToolCall(prepared, signal, emit) {\n  const updateEvents = [];\n  let acceptingUpdates = true;\n  try {\n    const result = await prepared.tool.execute(prepared.toolCall.id, prepared.args, signal, (partialResult) => {\n      if (!acceptingUpdates)\n        return;\n      updateEvents.push(Promise.resolve(emit({\n        type: \"tool_execution_update\",\n        toolCallId: prepared.toolCall.id,\n        toolName: prepared.toolCall.name,\n        args: prepared.toolCall.arguments,\n        partialResult\n      })));\n    });\n    acceptingUpdates = false;\n    await Promise.all(updateEvents);\n    return { result, isError: false };\n  } catch (error) {\n    acceptingUpdates = false;\n    await Promise.all(updateEvents);\n    return {\n      result: createErrorToolResult(error instanceof Error ? error.message : String(error)),\n      isError: true\n    };\n  } finally {\n    acceptingUpdates = false;\n  }\n}\nasync function finalizeExecutedToolCall(currentContext, assistantMessage, prepared, executed, config, signal) {\n  let result = executed.result;\n  let isError = executed.isError;\n  if (config.afterToolCall) {\n    try {\n      const afterResult = await config.afterToolCall({\n        assistantMessage,\n        toolCall: prepared.toolCall,\n        args: prepared.args,\n        result,\n        isError,\n        context: currentContext\n      }, signal);\n      if (afterResult) {\n        result = {\n          ...result,\n          content: afterResult.content ?? result.content,\n          details: afterResult.details ?? result.details,\n          usage: afterResult.usage ?? result.usage,\n          terminate: afterResult.terminate ?? result.terminate\n        };\n        isError = afterResult.isError ?? isError;\n      }\n    } catch (error) {\n      result = createErrorToolResult(error instanceof Error ? error.message : String(error));\n      isError = true;\n    }\n  }\n  return {\n    toolCall: prepared.toolCall,\n    result,\n    isError\n  };\n}\nfunction createErrorToolResult(message) {\n  return {\n    content: [{ type: \"text\", text: message }],\n    details: {}\n  };\n}\nasync function emitToolExecutionEnd(finalized, emit) {\n  await emit({\n    type: \"tool_execution_end\",\n    toolCallId: finalized.toolCall.id,\n    toolName: finalized.toolCall.name,\n    result: finalized.result,\n    isError: finalized.isError\n  });\n}\nfunction createToolResultMessage(finalized) {\n  return {\n    role: \"toolResult\",\n    toolCallId: finalized.toolCall.id,\n    toolName: finalized.toolCall.name,\n    // Untyped tools (JS extensions) can return results without content; normalize\n    // so the null never enters session history or provider payloads.\n    content: finalized.result.content ?? [],\n    details: finalized.result.details,\n    usage: finalized.result.usage,\n    ...finalized.result.addedToolNames?.length ? { addedToolNames: finalized.result.addedToolNames } : {},\n    isError: finalized.isError,\n    timestamp: Date.now()\n  };\n}\nasync function emitToolResultMessage(toolResultMessage, emit) {\n  await emit({ type: \"message_start\", message: toolResultMessage });\n  await emit({ type: \"message_end\", message: toolResultMessage });\n}\n\n// node_modules/.pnpm/@earendil-works+pi-agent-core@0.84.4_ws@8.21.3/node_modules/@earendil-works/pi-agent-core/dist/agent.js\nfunction defaultConvertToLlm(messages) {\n  return messages.filter((message) => message.role === \"user\" || message.role === \"assistant\" || message.role === \"toolResult\");\n}\nvar EMPTY_USAGE = {\n  input: 0,\n  output: 0,\n  cacheRead: 0,\n  cacheWrite: 0,\n  totalTokens: 0,\n  cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 }\n};\nvar DEFAULT_MODEL = {\n  id: \"unknown\",\n  name: \"unknown\",\n  api: \"unknown\",\n  provider: \"unknown\",\n  baseUrl: \"\",\n  reasoning: false,\n  input: [],\n  cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },\n  contextWindow: 0,\n  maxTokens: 0\n};\nfunction createMutableAgentState(initialState) {\n  let tools = initialState?.tools?.slice() ?? [];\n  let messages = initialState?.messages?.slice() ?? [];\n  return {\n    systemPrompt: initialState?.systemPrompt ?? \"\",\n    model: initialState?.model ?? DEFAULT_MODEL,\n    thinkingLevel: initialState?.thinkingLevel ?? \"off\",\n    get tools() {\n      return tools;\n    },\n    set tools(nextTools) {\n      tools = nextTools.slice();\n    },\n    get messages() {\n      return messages;\n    },\n    set messages(nextMessages) {\n      messages = nextMessages.slice();\n    },\n    isStreaming: false,\n    streamingMessage: void 0,\n    pendingToolCalls: /* @__PURE__ */ new Set(),\n    errorMessage: void 0\n  };\n}\nvar PendingMessageQueue = class {\n  messages = [];\n  mode;\n  constructor(mode) {\n    this.mode = mode;\n  }\n  enqueue(message) {\n    this.messages.push(message);\n  }\n  hasItems() {\n    return this.messages.length > 0;\n  }\n  drain() {\n    if (this.mode === \"all\") {\n      const drained = this.messages.slice();\n      this.messages = [];\n      return drained;\n    }\n    const first = this.messages[0];\n    if (!first) {\n      return [];\n    }\n    this.messages = this.messages.slice(1);\n    return [first];\n  }\n  clear() {\n    this.messages = [];\n  }\n};\nvar Agent = class {\n  _state;\n  listeners = /* @__PURE__ */ new Set();\n  steeringQueue;\n  followUpQueue;\n  convertToLlm;\n  transformContext;\n  streamFunction;\n  getApiKey;\n  onPayload;\n  onResponse;\n  beforeToolCall;\n  afterToolCall;\n  shouldStopAfterTurn;\n  prepareNextTurn;\n  prepareNextTurnWithContext;\n  activeRun;\n  /** Session identifier forwarded to providers for cache-aware backends. */\n  sessionId;\n  /** Optional per-level thinking token budgets forwarded to the stream function. */\n  thinkingBudgets;\n  /** Preferred transport forwarded to the stream function. */\n  transport;\n  /** Optional cap for provider-requested retry delays. */\n  maxRetryDelayMs;\n  /** Tool execution strategy for assistant messages that contain multiple tool calls. */\n  toolExecution;\n  constructor(options) {\n    const runtimeOptions = options ?? {};\n    this._state = createMutableAgentState(runtimeOptions.initialState);\n    this.convertToLlm = runtimeOptions.convertToLlm ?? defaultConvertToLlm;\n    this.transformContext = runtimeOptions.transformContext;\n    this.streamFunction = runtimeOptions.streamFn ?? getDefaultStreamFn();\n    this.getApiKey = runtimeOptions.getApiKey;\n    this.onPayload = runtimeOptions.onPayload;\n    this.onResponse = runtimeOptions.onResponse;\n    this.beforeToolCall = runtimeOptions.beforeToolCall;\n    this.afterToolCall = runtimeOptions.afterToolCall;\n    this.shouldStopAfterTurn = runtimeOptions.shouldStopAfterTurn;\n    this.prepareNextTurn = runtimeOptions.prepareNextTurn;\n    this.prepareNextTurnWithContext = runtimeOptions.prepareNextTurnWithContext;\n    this.steeringQueue = new PendingMessageQueue(runtimeOptions.steeringMode ?? \"one-at-a-time\");\n    this.followUpQueue = new PendingMessageQueue(runtimeOptions.followUpMode ?? \"one-at-a-time\");\n    this.sessionId = runtimeOptions.sessionId;\n    this.thinkingBudgets = runtimeOptions.thinkingBudgets;\n    this.transport = runtimeOptions.transport ?? \"auto\";\n    this.maxRetryDelayMs = runtimeOptions.maxRetryDelayMs;\n    this.toolExecution = runtimeOptions.toolExecution ?? \"parallel\";\n  }\n  /**\n   * Subscribe to agent lifecycle events.\n   *\n   * Listener promises are awaited in subscription order and are included in\n   * the current run's settlement. Listeners also receive the active abort\n   * signal for the current run.\n   *\n   * `agent_end` is the final emitted event for a run, but the agent does not\n   * become idle until all awaited listeners for that event have settled.\n   */\n  subscribe(listener) {\n    this.listeners.add(listener);\n    return () => this.listeners.delete(listener);\n  }\n  /**\n   * Current agent state.\n   *\n   * Assigning `state.tools` or `state.messages` copies the provided top-level array.\n   */\n  get state() {\n    return this._state;\n  }\n  /** Controls how queued steering messages are drained. */\n  set steeringMode(mode) {\n    this.steeringQueue.mode = mode;\n  }\n  get steeringMode() {\n    return this.steeringQueue.mode;\n  }\n  /** Controls how queued follow-up messages are drained. */\n  set followUpMode(mode) {\n    this.followUpQueue.mode = mode;\n  }\n  get followUpMode() {\n    return this.followUpQueue.mode;\n  }\n  /** Queue a message to be injected after the current assistant turn finishes. */\n  steer(message) {\n    this.steeringQueue.enqueue(message);\n  }\n  /** Queue a message to run only after the agent would otherwise stop. */\n  followUp(message) {\n    this.followUpQueue.enqueue(message);\n  }\n  /** Remove all queued steering messages. */\n  clearSteeringQueue() {\n    this.steeringQueue.clear();\n  }\n  /** Remove all queued follow-up messages. */\n  clearFollowUpQueue() {\n    this.followUpQueue.clear();\n  }\n  /** Remove all queued steering and follow-up messages. */\n  clearAllQueues() {\n    this.clearSteeringQueue();\n    this.clearFollowUpQueue();\n  }\n  /** Returns true when either queue still contains pending messages. */\n  hasQueuedMessages() {\n    return this.steeringQueue.hasItems() || this.followUpQueue.hasItems();\n  }\n  /** Active abort signal for the current run, if any. */\n  get signal() {\n    return this.activeRun?.abortController.signal;\n  }\n  /** Abort the current run, if one is active. */\n  abort() {\n    this.activeRun?.abortController.abort();\n  }\n  /**\n   * Resolve when the current run and all awaited event listeners have finished.\n   *\n   * This resolves after `agent_end` listeners settle.\n   */\n  waitForIdle() {\n    return this.activeRun?.promise ?? Promise.resolve();\n  }\n  /** Clear transcript state, runtime state, and queued messages. */\n  reset() {\n    if (this.activeRun) {\n      throw new Error(\"Agent is already processing. Wait for completion before resetting.\");\n    }\n    this._state.messages = [];\n    this._state.isStreaming = false;\n    this._state.streamingMessage = void 0;\n    this._state.pendingToolCalls = /* @__PURE__ */ new Set();\n    this._state.errorMessage = void 0;\n    this.clearFollowUpQueue();\n    this.clearSteeringQueue();\n  }\n  async prompt(input, images) {\n    if (this.activeRun) {\n      throw new Error(\"Agent is already processing a prompt. Use steer() or followUp() to queue messages, or wait for completion.\");\n    }\n    const messages = this.normalizePromptInput(input, images);\n    await this.runPromptMessages(messages);\n  }\n  /** Continue from the current transcript. The last message must be a user or tool-result message. */\n  async continue() {\n    if (this.activeRun) {\n      throw new Error(\"Agent is already processing. Wait for completion before continuing.\");\n    }\n    const lastMessage = this._state.messages[this._state.messages.length - 1];\n    if (!lastMessage) {\n      throw new Error(\"No messages to continue from\");\n    }\n    if (lastMessage.role === \"assistant\") {\n      const queuedSteering = this.steeringQueue.drain();\n      if (queuedSteering.length > 0) {\n        await this.runPromptMessages(queuedSteering, { skipInitialSteeringPoll: true });\n        return;\n      }\n      const queuedFollowUps = this.followUpQueue.drain();\n      if (queuedFollowUps.length > 0) {\n        await this.runPromptMessages(queuedFollowUps);\n        return;\n      }\n      throw new Error(\"Cannot continue from message role: assistant\");\n    }\n    await this.runContinuation();\n  }\n  normalizePromptInput(input, images) {\n    if (Array.isArray(input)) {\n      return input;\n    }\n    if (typeof input !== \"string\") {\n      return [input];\n    }\n    const content = [{ type: \"text\", text: input }];\n    if (images && images.length > 0) {\n      content.push(...images);\n    }\n    return [{ role: \"user\", content, timestamp: Date.now() }];\n  }\n  async runPromptMessages(messages, options = {}) {\n    await this.runWithLifecycle(async (signal) => {\n      await runAgentLoop(messages, this.createContextSnapshot(), this.createLoopConfig(options), (event) => this.processEvents(event), signal, this.streamFunction);\n    });\n  }\n  async runContinuation() {\n    await this.runWithLifecycle(async (signal) => {\n      await runAgentLoopContinue(this.createContextSnapshot(), this.createLoopConfig(), (event) => this.processEvents(event), signal, this.streamFunction);\n    });\n  }\n  createContextSnapshot() {\n    return {\n      systemPrompt: this._state.systemPrompt,\n      messages: this._state.messages.slice(),\n      tools: this._state.tools.slice()\n    };\n  }\n  createLoopConfig(options = {}) {\n    let skipInitialSteeringPoll = options.skipInitialSteeringPoll === true;\n    const shouldStopAfterTurn = this.shouldStopAfterTurn;\n    return {\n      model: this._state.model,\n      reasoning: this._state.thinkingLevel === \"off\" ? void 0 : this._state.thinkingLevel,\n      sessionId: this.sessionId,\n      onPayload: this.onPayload,\n      onResponse: this.onResponse,\n      transport: this.transport,\n      thinkingBudgets: this.thinkingBudgets,\n      maxRetryDelayMs: this.maxRetryDelayMs,\n      toolExecution: this.toolExecution,\n      beforeToolCall: this.beforeToolCall,\n      afterToolCall: this.afterToolCall,\n      shouldStopAfterTurn: shouldStopAfterTurn ? async (context) => await shouldStopAfterTurn(context, this.signal) : void 0,\n      prepareNextTurn: this.prepareNextTurnWithContext || this.prepareNextTurn ? async (context) => {\n        if (this.prepareNextTurnWithContext) {\n          return await this.prepareNextTurnWithContext(context, this.signal);\n        }\n        return await this.prepareNextTurn?.(this.signal);\n      } : void 0,\n      convertToLlm: this.convertToLlm,\n      transformContext: this.transformContext,\n      getApiKey: this.getApiKey,\n      getSteeringMessages: async () => {\n        if (skipInitialSteeringPoll) {\n          skipInitialSteeringPoll = false;\n          return [];\n        }\n        return this.steeringQueue.drain();\n      },\n      getFollowUpMessages: async () => this.followUpQueue.drain()\n    };\n  }\n  async runWithLifecycle(executor) {\n    if (this.activeRun) {\n      throw new Error(\"Agent is already processing.\");\n    }\n    const abortController = new AbortController();\n    let resolvePromise = () => {\n    };\n    const promise = new Promise((resolve15) => {\n      resolvePromise = resolve15;\n    });\n    this.activeRun = { promise, resolve: resolvePromise, abortController };\n    this._state.isStreaming = true;\n    this._state.streamingMessage = void 0;\n    this._state.errorMessage = void 0;\n    try {\n      await executor(abortController.signal);\n    } catch (error) {\n      await this.handleRunFailure(error, abortController.signal.aborted);\n    } finally {\n      this.finishRun();\n    }\n  }\n  async handleRunFailure(error, aborted) {\n    const failureMessage = {\n      role: \"assistant\",\n      content: [{ type: \"text\", text: \"\" }],\n      api: this._state.model.api,\n      provider: this._state.model.provider,\n      model: this._state.model.id,\n      usage: EMPTY_USAGE,\n      stopReason: aborted ? \"aborted\" : \"error\",\n      errorMessage: error instanceof Error ? error.message : String(error),\n      timestamp: Date.now()\n    };\n    await this.processEvents({ type: \"message_start\", message: failureMessage });\n    await this.processEvents({ type: \"message_end\", message: failureMessage });\n    await this.processEvents({ type: \"turn_end\", message: failureMessage, toolResults: [] });\n    await this.processEvents({ type: \"agent_end\", messages: [failureMessage] });\n  }\n  finishRun() {\n    this._state.isStreaming = false;\n    this._state.streamingMessage = void 0;\n    this._state.pendingToolCalls = /* @__PURE__ */ new Set();\n    this.activeRun?.resolve();\n    this.activeRun = void 0;\n  }\n  /**\n   * Reduce internal state for a loop event, then await listeners.\n   *\n   * `agent_end` only means no further loop events will be emitted. The run is\n   * considered idle later, after all awaited listeners for `agent_end` finish\n   * and `finishRun()` clears runtime-owned state.\n   */\n  async processEvents(event) {\n    switch (event.type) {\n      case \"message_start\":\n        this._state.streamingMessage = event.message;\n        break;\n      case \"message_update\":\n        this._state.streamingMessage = event.message;\n        break;\n      case \"message_end\":\n        this._state.streamingMessage = void 0;\n        this._state.messages.push(event.message);\n        break;\n      case \"tool_execution_start\": {\n        const pendingToolCalls = new Set(this._state.pendingToolCalls);\n        pendingToolCalls.add(event.toolCallId);\n        this._state.pendingToolCalls = pendingToolCalls;\n        break;\n      }\n      case \"tool_execution_end\": {\n        const pendingToolCalls = new Set(this._state.pendingToolCalls);\n        pendingToolCalls.delete(event.toolCallId);\n        this._state.pendingToolCalls = pendingToolCalls;\n        break;\n      }\n      case \"turn_end\":\n        if (event.message.role === \"assistant\" && event.message.errorMessage) {\n          this._state.errorMessage = event.message.errorMessage;\n        }\n        break;\n      case \"agent_end\":\n        this._state.streamingMessage = void 0;\n        break;\n    }\n    const signal = this.activeRun?.abortController.signal;\n    if (!signal) {\n      throw new Error(\"Agent listener invoked outside active run\");\n    }\n    for (const listener of this.listeners) {\n      await listener(event, signal);\n    }\n  }\n};\n\n// node_modules/.pnpm/@earendil-works+pi-agent-core@0.84.4_ws@8.21.3/node_modules/@earendil-works/pi-agent-core/dist/harness/result.js\nvar Result = {\n  ok(value) {\n    return { ok: true, value };\n  },\n  err(error) {\n    return { ok: false, error };\n  },\n  isOk(result) {\n    return result.ok;\n  },\n  isErr(result) {\n    return !result.ok;\n  }\n};\nfunction TaggedError(tag) {\n  class TaggedErrorClass extends Error {\n    _tag = tag;\n    constructor(props) {\n      super(props.message);\n      this.name = tag;\n      Object.assign(this, props);\n    }\n    toJSON() {\n      const payload = {};\n      for (const key of Object.keys(this)) {\n        if (key !== \"_tag\")\n          payload[key] = this[key];\n      }\n      return { _tag: tag, message: this.message, ...payload };\n    }\n    static is(value) {\n      return value instanceof TaggedErrorClass;\n    }\n  }\n  return TaggedErrorClass;\n}\nfunction matchError(error, matchers) {\n  const matcher = matchers[error._tag];\n  return matcher(error);\n}\n\n// node_modules/.pnpm/@earendil-works+pi-agent-core@0.84.4_ws@8.21.3/node_modules/@earendil-works/pi-agent-core/dist/harness/agent-harness.js\nvar LaneBusy = class extends TaggedError(\"LaneBusy\") {\n};\nvar MissingIdentities = class extends TaggedError(\"MissingIdentities\") {\n};\nvar NoActiveRun = class extends TaggedError(\"NoActiveRun\") {\n};\nvar NoActiveOperation = class extends TaggedError(\"NoActiveOperation\") {\n};\nvar NothingToResume = class extends TaggedError(\"NothingToResume\") {\n};\nvar InvalidMessage = class extends TaggedError(\"InvalidMessage\") {\n};\nvar UnknownSkill = class extends TaggedError(\"UnknownSkill\") {\n};\nvar UnknownTemplate = class extends TaggedError(\"UnknownTemplate\") {\n};\nvar UnknownTarget = class extends TaggedError(\"UnknownTarget\") {\n};\nvar UnknownQueueItem = class extends TaggedError(\"UnknownQueueItem\") {\n};\nvar LaneExists = class extends TaggedError(\"LaneExists\") {\n};\nvar InvalidLane = class extends TaggedError(\"InvalidLane\") {\n};\nvar NothingToCompact = class extends TaggedError(\"NothingToCompact\") {\n};\nvar Closed = class extends TaggedError(\"Closed\") {\n};\nvar HarnessFault = class extends Error {\n  cause;\n  constructor(message, cause) {\n    super(message);\n    this.name = \"HarnessFault\";\n    this.cause = cause;\n  }\n};\nvar HarnessClosed = class extends Error {\n  constructor() {\n    super(\"AgentHarness was closed while the operation was active\");\n    this.name = \"HarnessClosed\";\n  }\n};\nvar HarnessNotImplemented = class extends Error {\n  operation;\n  constructor(operation) {\n    super(`AgentHarness.${operation} is not implemented yet`);\n    this.name = \"HarnessNotImplemented\";\n    this.operation = operation;\n  }\n};\nvar UnavailableRegistry = class {\n  operation;\n  isClosed;\n  constructor(operation, isClosed) {\n    this.operation = operation;\n    this.isClosed = isClosed;\n  }\n  on(_name, _handler, _options) {\n    throw this.isClosed() ? new HarnessClosed() : new HarnessNotImplemented(this.operation);\n  }\n};\nvar AgentHarness = class _AgentHarness {\n  name = \"main\";\n  session;\n  hooks;\n  events;\n  durableSession;\n  model;\n  thinkingLevel;\n  activeToolNames;\n  tools;\n  resources;\n  streamOptions;\n  retryPolicy;\n  compactionSettings;\n  steeringMode;\n  followUpMode;\n  closed = false;\n  constructor(options) {\n    this.durableSession = options.session;\n    this.session = options.session;\n    this.hooks = new UnavailableRegistry(\"hooks.on\", () => this.closed);\n    this.events = new UnavailableRegistry(\"events.on\", () => this.closed);\n    this.model = options.model;\n    this.thinkingLevel = options.thinkingLevel ?? \"off\";\n    this.activeToolNames = [...options.activeToolNames ?? options.tools?.map((tool) => tool.name) ?? []];\n    this.tools = [...options.tools ?? []];\n    this.resources = {\n      skills: options.resources?.skills ? [...options.resources.skills] : void 0,\n      promptTemplates: options.resources?.promptTemplates ? [...options.resources.promptTemplates] : void 0\n    };\n    this.streamOptions = { ...options.streamOptions ?? {} };\n    this.retryPolicy = options.retry ?? { enabled: false, maxRetries: 0, baseDelayMs: 1e3 };\n    this.compactionSettings = options.compaction ?? {\n      enabled: true,\n      reserveTokens: 16384,\n      keepRecentTokens: 2e4\n    };\n    this.steeringMode = options.steeringMode ?? \"one-at-a-time\";\n    this.followUpMode = options.followUpMode ?? \"one-at-a-time\";\n  }\n  static async create(options) {\n    const [record] = await options.session.findRecords({ limit: 1 });\n    if (record !== void 0)\n      throw new HarnessNotImplemented(\"create.restore\");\n    return { harness: new _AgentHarness(options), suspended: [] };\n  }\n  unavailable(operation) {\n    return Promise.reject(this.closed ? new HarnessClosed() : new HarnessNotImplemented(operation));\n  }\n  async getLeafId() {\n    return this.durableSession.getLeafId();\n  }\n  async prompt(_input, _images) {\n    return this.unavailable(\"prompt\");\n  }\n  async skill(_name, _additionalInstructions) {\n    return this.unavailable(\"skill\");\n  }\n  async promptFromTemplate(_name, _args) {\n    return this.unavailable(\"promptFromTemplate\");\n  }\n  async compact(_options) {\n    return this.unavailable(\"compact\");\n  }\n  async navigateTree(_targetId, _options) {\n    return this.unavailable(\"navigateTree\");\n  }\n  async resume() {\n    return this.unavailable(\"resume\");\n  }\n  async abort() {\n    return this.unavailable(\"abort\");\n  }\n  async steer(_input, _images) {\n    return this.unavailable(\"steer\");\n  }\n  async followUp(_input, _images) {\n    return this.unavailable(\"followUp\");\n  }\n  async nextRun(_input, _images) {\n    return this.unavailable(\"nextRun\");\n  }\n  async cancelQueued(_entryId) {\n    return this.unavailable(\"cancelQueued\");\n  }\n  async recordUsage(_usage, _options) {\n    return this.unavailable(\"recordUsage\");\n  }\n  async waitForIdle() {\n    return this.unavailable(\"waitForIdle\");\n  }\n  async runWhenIdle(_callback) {\n    return this.unavailable(\"runWhenIdle\");\n  }\n  async peekAction() {\n    return this.unavailable(\"peekAction\");\n  }\n  async executeAction() {\n    return this.unavailable(\"executeAction\");\n  }\n  async runToCompletion() {\n    return this.unavailable(\"runToCompletion\");\n  }\n  async getModel() {\n    return this.model;\n  }\n  async setModel(model) {\n    this.model = model;\n  }\n  async getThinkingLevel() {\n    return this.thinkingLevel;\n  }\n  async setThinkingLevel(level) {\n    this.thinkingLevel = level;\n  }\n  async getActiveTools() {\n    return [...this.activeToolNames];\n  }\n  async setActiveTools(names) {\n    this.activeToolNames = [...names];\n  }\n  async watch() {\n    return this.unavailable(\"watch\");\n  }\n  async lane(_name) {\n    return this.unavailable(\"lane\");\n  }\n  async createLane(_name, _at) {\n    return this.unavailable(\"createLane\");\n  }\n  async lanes() {\n    return this.unavailable(\"lanes\");\n  }\n  async getTools() {\n    return [...this.tools];\n  }\n  async setTools(tools, activeNames) {\n    this.tools = [...tools];\n    this.activeToolNames = [...activeNames ?? tools.map((tool) => tool.name)];\n  }\n  async getResources() {\n    return {\n      skills: this.resources.skills ? [...this.resources.skills] : void 0,\n      promptTemplates: this.resources.promptTemplates ? [...this.resources.promptTemplates] : void 0\n    };\n  }\n  async setResources(resources) {\n    this.resources = {\n      skills: resources.skills ? [...resources.skills] : void 0,\n      promptTemplates: resources.promptTemplates ? [...resources.promptTemplates] : void 0\n    };\n  }\n  async getStreamOptions() {\n    return { ...this.streamOptions };\n  }\n  async setStreamOptions(options) {\n    this.streamOptions = { ...options };\n  }\n  async getRetryPolicy() {\n    return { ...this.retryPolicy };\n  }\n  async setRetryPolicy(policy) {\n    this.retryPolicy = { ...policy };\n  }\n  async getCompactionSettings() {\n    return { ...this.compactionSettings };\n  }\n  async setCompactionSettings(settings) {\n    this.compactionSettings = { ...settings };\n  }\n  async getSteeringMode() {\n    return this.steeringMode;\n  }\n  async setSteeringMode(mode) {\n    this.steeringMode = mode;\n  }\n  async getFollowUpMode() {\n    return this.followUpMode;\n  }\n  async setFollowUpMode(mode) {\n    this.followUpMode = mode;\n  }\n  async watchSession() {\n    return this.unavailable(\"watchSession\");\n  }\n  async close() {\n    this.closed = true;\n  }\n};\n\n// node_modules/.pnpm/@earendil-works+pi-agent-core@0.84.4_ws@8.21.3/node_modules/@earendil-works/pi-agent-core/dist/harness/messages.js\nvar COMPACTION_SUMMARY_PREFIX2 = `The conversation history before this point was compacted into the following summary:\n\n<summary>\n`;\nvar COMPACTION_SUMMARY_SUFFIX2 = `\n</summary>`;\nvar BRANCH_SUMMARY_PREFIX2 = `The following is a summary of a branch that this conversation came back from:\n\n<summary>\n`;\nvar BRANCH_SUMMARY_SUFFIX2 = `</summary>`;\nfunction bashExecutionToText2(msg) {\n  let text = `Ran \\`${msg.command}\\`\n`;\n  if (msg.output) {\n    text += `\\`\\`\\`\n${msg.output}\n\\`\\`\\``;\n  } else {\n    text += \"(no output)\";\n  }\n  if (msg.cancelled) {\n    text += \"\\n\\n(command cancelled)\";\n  } else if (msg.exitCode !== null && msg.exitCode !== void 0 && msg.exitCode !== 0) {\n    text += `\n\nCommand exited with code ${msg.exitCode}`;\n  }\n  if (msg.truncated && msg.fullOutputPath) {\n    text += `\n\n[Output truncated. Full output: ${msg.fullOutputPath}]`;\n  }\n  return text;\n}\nfunction createBranchSummaryMessage2(summary, fromId, timestamp) {\n  return {\n    role: \"branchSummary\",\n    summary,\n    fromId,\n    timestamp: typeof timestamp === \"number\" ? timestamp : new Date(timestamp).getTime()\n  };\n}\nfunction createCompactionSummaryMessage2(summary, tokensBefore, timestamp) {\n  return {\n    role: \"compactionSummary\",\n    summary,\n    tokensBefore,\n    timestamp: typeof timestamp === \"number\" ? timestamp : new Date(timestamp).getTime()\n  };\n}\nfunction createCustomMessage2(customType, content, display, details, timestamp) {\n  return {\n    role: \"custom\",\n    customType,\n    content,\n    display,\n    details,\n    timestamp: typeof timestamp === \"number\" ? timestamp : new Date(timestamp).getTime()\n  };\n}\nfunction convertToLlm2(messages) {\n  return messages.map((m) => {\n    switch (m.role) {\n      case \"bashExecution\":\n        if (m.excludeFromContext) {\n          return void 0;\n        }\n        return {\n          role: \"user\",\n          content: [{ type: \"text\", text: bashExecutionToText2(m) }],\n          timestamp: m.timestamp\n        };\n      case \"custom\": {\n        const content = typeof m.content === \"string\" ? [{ type: \"text\", text: m.content }] : m.content;\n        return {\n          role: \"user\",\n          content,\n          timestamp: m.timestamp\n        };\n      }\n      case \"branchSummary\":\n        return {\n          role: \"user\",\n          content: [{ type: \"text\", text: BRANCH_SUMMARY_PREFIX2 + m.summary + BRANCH_SUMMARY_SUFFIX2 }],\n          timestamp: m.timestamp\n        };\n      case \"compactionSummary\":\n        return {\n          role: \"user\",\n          content: [\n            { type: \"text\", text: COMPACTION_SUMMARY_PREFIX2 + m.summary + COMPACTION_SUMMARY_SUFFIX2 }\n          ],\n          timestamp: m.timestamp\n        };\n      case \"user\":\n      case \"assistant\":\n      case \"toolResult\":\n        return m;\n      default:\n        return void 0;\n    }\n  }).filter((m) => m !== void 0);\n}\n\n// node_modules/.pnpm/@earendil-works+pi-agent-core@0.84.4_ws@8.21.3/node_modules/@earendil-works/pi-agent-core/dist/harness/session/context.js\nfunction deriveSessionContextState(pathEntries) {\n  let thinkingLevel = \"off\";\n  let model = null;\n  let activeToolNames = null;\n  for (const entry of pathEntries) {\n    if (entry.type === \"thinking_level_change\") {\n      thinkingLevel = entry.thinkingLevel;\n    } else if (entry.type === \"model_change\") {\n      model = { provider: entry.provider, modelId: entry.modelId };\n    } else if (entry.type === \"message\" && entry.message.role === \"assistant\") {\n      model = { provider: entry.message.provider, modelId: entry.message.model };\n    } else if (entry.type === \"active_tools_change\") {\n      activeToolNames = [...entry.activeToolNames];\n    }\n  }\n  return { thinkingLevel, model, activeToolNames };\n}\nfunction defaultContextEntryTransform(pathEntries) {\n  let compaction;\n  let compactionIndex = -1;\n  for (let index = pathEntries.length - 1; index >= 0; index--) {\n    const entry = pathEntries[index];\n    if (entry.type === \"compaction\") {\n      compaction = entry;\n      compactionIndex = index;\n      break;\n    }\n  }\n  return compaction === void 0 ? [...pathEntries] : [compaction, ...pathEntries.slice(compactionIndex + 1)];\n}\nfunction buildContextEntries2(pathEntries, options = {}) {\n  let entries = defaultContextEntryTransform(pathEntries);\n  for (const transform of options.entryTransforms ?? [])\n    entries = [...transform(entries)];\n  return entries;\n}\nfunction sessionEntryToContextMessages2(entry, index, entries, options = {}) {\n  if (entry.type === \"message\") {\n    if (entry.message.role === \"assistant\" && entry.message.stopReason === \"deferred\")\n      return [];\n    return [entry.message];\n  }\n  if (entry.type === \"compaction\") {\n    return [\n      createCompactionSummaryMessage2(entry.summary, entry.tokensBefore, entry.timestamp),\n      ...entry.retainedTail\n    ];\n  }\n  if (entry.type === \"branch_summary\" && entry.summary) {\n    return [createBranchSummaryMessage2(entry.summary, entry.fromId, entry.timestamp)];\n  }\n  if (entry.type === \"custom\") {\n    return [...options.entryProjectors?.[entry.customType]?.(entry, index, entries) ?? []];\n  }\n  return [];\n}\nfunction buildSessionContext2(pathEntries, options = {}) {\n  const state = deriveSessionContextState(pathEntries);\n  const contextEntries = buildContextEntries2(pathEntries, options);\n  const messages = contextEntries.flatMap((entry, index) => sessionEntryToContextMessages2(entry, index, contextEntries, options));\n  return { ...state, messages };\n}\n\n// node_modules/.pnpm/@earendil-works+pi-agent-core@0.84.4_ws@8.21.3/node_modules/@earendil-works/pi-agent-core/dist/harness/session/types.js\nvar SessionError = class extends Error {\n  code;\n  constructor(code, message, cause) {\n    super(message, cause === void 0 ? void 0 : { cause });\n    this.name = \"SessionError\";\n    this.code = code;\n  }\n};\n\n// node_modules/.pnpm/@earendil-works+pi-agent-core@0.84.4_ws@8.21.3/node_modules/@earendil-works/pi-agent-core/dist/harness/session/session.js\nfunction invalidPayload(reason) {\n  throw new SessionError(\"invalid_payload\", `Durable payload ${reason}`);\n}\nfunction assertValidLimit(limit) {\n  if (limit !== void 0 && (!Number.isInteger(limit) || limit <= 0)) {\n    throw new SessionError(\"invalid_query\", \"limit must be a positive integer\");\n  }\n}\nfunction assertValidCursor(afterSeq) {\n  if (afterSeq !== void 0 && (!Number.isInteger(afterSeq) || afterSeq < 0)) {\n    throw new SessionError(\"invalid_query\", \"cursor sequence must be a non-negative integer\");\n  }\n}\nfunction assertJsonSerializable(value) {\n  const active = /* @__PURE__ */ new WeakSet();\n  const stack = [{ value }];\n  while (stack.length > 0) {\n    const frame2 = stack.pop();\n    if (\"exit\" in frame2) {\n      active.delete(frame2.exit);\n      continue;\n    }\n    const candidate = frame2.value;\n    if (candidate === null || typeof candidate === \"string\" || typeof candidate === \"boolean\") {\n      continue;\n    }\n    if (typeof candidate === \"number\") {\n      if (!Number.isFinite(candidate))\n        invalidPayload(\"contains a non-finite number\");\n      continue;\n    }\n    if (typeof candidate !== \"object\")\n      invalidPayload(`contains ${typeof candidate}`);\n    if (active.has(candidate))\n      invalidPayload(\"contains a cycle\");\n    active.add(candidate);\n    stack.push({ exit: candidate });\n    if (Array.isArray(candidate)) {\n      if (Object.getPrototypeOf(candidate) !== Array.prototype) {\n        invalidPayload(\"contains a non-standard array\");\n      }\n      if (Object.getOwnPropertySymbols(candidate).length > 0 || Object.getOwnPropertyNames(candidate).length !== candidate.length + 1) {\n        invalidPayload(\"contains an array with unsupported properties\");\n      }\n      for (let index = candidate.length - 1; index >= 0; index--) {\n        if (!Object.hasOwn(candidate, index))\n          invalidPayload(\"contains a sparse array\");\n        const descriptor = Object.getOwnPropertyDescriptor(candidate, index);\n        if (!(\"value\" in descriptor))\n          invalidPayload(\"contains an array accessor\");\n        stack.push({ value: descriptor.value });\n      }\n      continue;\n    }\n    const prototype = Object.getPrototypeOf(candidate);\n    if (prototype !== Object.prototype && prototype !== null) {\n      invalidPayload(\"contains a non-plain object\");\n    }\n    if (Object.getOwnPropertySymbols(candidate).length > 0) {\n      invalidPayload(\"contains a symbol-keyed property\");\n    }\n    const keys = Object.keys(candidate);\n    if (Object.getOwnPropertyNames(candidate).length !== keys.length) {\n      invalidPayload(\"contains a non-enumerable property\");\n    }\n    for (let index = keys.length - 1; index >= 0; index--) {\n      const descriptor = Object.getOwnPropertyDescriptor(candidate, keys[index]);\n      if (!(\"value\" in descriptor))\n        invalidPayload(\"contains an accessor\");\n      stack.push({ value: descriptor.value });\n    }\n  }\n}\nvar Session = class {\n  storage;\n  idGenerator;\n  constructor(storage, options = {}) {\n    this.storage = storage;\n    this.idGenerator = options.idGenerator ?? { next: () => uuidv72() };\n  }\n  async getMetadata() {\n    return this.storage.getMetadata();\n  }\n  view(lane) {\n    if (lane === \"main\")\n      return this;\n    return {\n      getLeafId: () => this.getLeafIdForLane(lane),\n      getEntry: (id) => this.getEntry(id),\n      getStats: () => this.getStats(),\n      getName: () => this.getName(),\n      setName: (name) => this.setName(name),\n      getLabel: (targetId) => this.getLabel(targetId),\n      setLabel: (targetId, label) => this.setLabel(targetId, label),\n      findEntries: (query) => this.queryEntries(query),\n      findEntry: async (query = {}) => (await this.queryEntries(query, 1))[0],\n      findEntriesOnBranch: (query) => this.queryBranchEntries(lane, query),\n      findEntryOnBranch: async (query = {}) => (await this.queryBranchEntries(lane, query, 1))[0],\n      appendMessage: (message) => this.appendMessageToLane(lane, message),\n      appendCustomEntry: (customType, data) => this.appendCustomEntryToLane(lane, customType, data)\n    };\n  }\n  async getLeafId() {\n    return this.getLeafIdForLane(\"main\");\n  }\n  async getEntry(id) {\n    return this.storage.getEntry(id);\n  }\n  async getStats() {\n    return this.storage.getStats();\n  }\n  async getName() {\n    return this.storage.getName();\n  }\n  async setName(name) {\n    await this.storage.setName(name);\n  }\n  async getLabel(targetId) {\n    return this.storage.getLabel(targetId);\n  }\n  async setLabel(targetId, label) {\n    await this.storage.setLabel(targetId, label);\n  }\n  async findEntries(query) {\n    return this.queryEntries(query);\n  }\n  async findEntry(query = {}) {\n    return (await this.queryEntries(query, 1))[0];\n  }\n  async findEntriesOnBranch(query) {\n    return this.queryBranchEntries(\"main\", query);\n  }\n  async findEntryOnBranch(query = {}) {\n    return (await this.queryBranchEntries(\"main\", query, 1))[0];\n  }\n  async appendMessage(message) {\n    return this.appendMessageToLane(\"main\", message);\n  }\n  async appendCustomEntry(customType, data) {\n    return this.appendCustomEntryToLane(\"main\", customType, data);\n  }\n  async getLanes() {\n    return this.storage.getLanes();\n  }\n  async createLane(lane, at) {\n    await this.storage.createLane(lane, at);\n  }\n  async moveLane(lane, to) {\n    await this.storage.moveLane(lane, to);\n  }\n  async appendEntry(entry, lane) {\n    return this.commitEntry(entry, lane);\n  }\n  async appendRecord(record) {\n    return this.commitRecord(record);\n  }\n  async findRecords(query) {\n    return this.queryRecords(query);\n  }\n  async findOpenOperations(lane, options) {\n    assertValidLimit(options?.limit);\n    return this.storage.findOpenOperations(lane, options);\n  }\n  async getLog(options) {\n    return this.queryLog(options);\n  }\n  /** Returns the lane's current leaf, or null when empty. Throws when the lane does not exist. */\n  async getLeafIdForLane(lane) {\n    const pointer = (await this.getLanes()).find((candidate) => candidate.lane === lane);\n    if (!pointer)\n      throw new SessionError(\"invalid_lane\", `Lane not found: ${lane}`);\n    return pointer.leafId;\n  }\n  async queryEntries(query = {}, resultLimit = query.limit) {\n    assertValidLimit(query.limit);\n    assertValidCursor(query.cursor?.afterSeq);\n    return this.storage.findEntries(resultLimit === query.limit ? query : { ...query, limit: resultLimit });\n  }\n  /**\n   * Queries from `query.start` toward the root, defaulting to the lane's current leaf.\n   * `resultLimit` lets single-entry queries cap results without changing the caller's query.\n   */\n  async queryBranchEntries(defaultLane, query = {}, resultLimit = query.limit) {\n    assertValidLimit(query.limit);\n    assertValidCursor(query.cursor?.afterSeq);\n    const start = query.start ?? await this.getLeafIdForLane(defaultLane);\n    if (start === null)\n      return [];\n    const storageQuery = resultLimit === query.limit ? query : { ...query, limit: resultLimit };\n    return this.storage.findEntriesOnBranch({ ...storageQuery, start });\n  }\n  async queryRecords(query = {}) {\n    assertValidLimit(query.limit);\n    assertValidCursor(query.afterSeq);\n    if (query.operationKind !== void 0 && query.type !== \"operation_started\") {\n      throw new SessionError(\"invalid_query\", 'operationKind requires type \"operation_started\"');\n    }\n    return this.storage.findRecords(query);\n  }\n  async queryLog(options = {}) {\n    assertValidLimit(options.limit);\n    assertValidCursor(options.afterSeq);\n    return this.storage.getLog(options);\n  }\n  async appendMessageToLane(lane, message) {\n    const entry = await this.commitEntry({ type: \"message\", id: this.idGenerator.next(), message }, lane);\n    return entry.id;\n  }\n  async appendCustomEntryToLane(lane, customType, data) {\n    const entry = await this.commitEntry(data === void 0 ? { type: \"custom\", id: this.idGenerator.next(), customType } : { type: \"custom\", id: this.idGenerator.next(), customType, data }, lane);\n    return entry.id;\n  }\n  async commitEntry(entry, lane) {\n    assertJsonSerializable(entry);\n    return this.storage.appendEntry(entry, lane);\n  }\n  async commitRecord(record) {\n    assertJsonSerializable(record);\n    return this.storage.appendRecord(record);\n  }\n};\n\n// node_modules/.pnpm/@earendil-works+pi-agent-core@0.84.4_ws@8.21.3/node_modules/@earendil-works/pi-agent-core/dist/harness/types.js\nfunction ok(value) {\n  return { ok: true, value };\n}\nfunction err(error) {\n  return { ok: false, error };\n}\nfunction getOrThrow(result) {\n  if (!result.ok)\n    throw result.error;\n  return result.value;\n}\nfunction getOrUndefined(result) {\n  return result.ok ? result.value : void 0;\n}\nfunction toError(error) {\n  if (error instanceof Error)\n    return error;\n  if (typeof error === \"string\")\n    return new Error(error);\n  try {\n    return new Error(JSON.stringify(error));\n  } catch {\n    return new Error(String(error));\n  }\n}\nvar FileError = class extends Error {\n  /** Backend-independent error code. */\n  code;\n  /** Absolute addressed path associated with the failure, when available. */\n  path;\n  constructor(code, message, path12, cause) {\n    super(message, cause === void 0 ? void 0 : { cause });\n    this.name = \"FileError\";\n    this.code = code;\n    this.path = path12;\n  }\n};\nvar ExecutionError = class extends Error {\n  /** Backend-independent error code. */\n  code;\n  constructor(code, message, cause) {\n    super(message, cause === void 0 ? void 0 : { cause });\n    this.name = \"ExecutionError\";\n    this.code = code;\n  }\n};\nvar CompactionError = class extends Error {\n  /** Backend-independent error code. */\n  code;\n  constructor(code, message, cause) {\n    super(message, cause === void 0 ? void 0 : { cause });\n    this.name = \"CompactionError\";\n    this.code = code;\n  }\n};\nvar BranchSummaryError = class extends Error {\n  /** Backend-independent error code. */\n  code;\n  constructor(code, message, cause) {\n    super(message, cause === void 0 ? void 0 : { cause });\n    this.name = \"BranchSummaryError\";\n    this.code = code;\n  }\n};\n\n// node_modules/.pnpm/@earendil-works+pi-agent-core@0.84.4_ws@8.21.3/node_modules/@earendil-works/pi-agent-core/dist/harness/session/jsonl/errors.js\nvar JsonlDecodeError = class extends Error {\n  kind;\n  constructor(kind, message, cause) {\n    super(message, cause === void 0 ? void 0 : { cause });\n    this.name = \"JsonlDecodeError\";\n    this.kind = kind;\n  }\n};\nfunction fileResult(result, message) {\n  if (!result.ok) {\n    throw new SessionError(result.error.code === \"not_found\" ? \"not_found\" : \"storage\", `${message}: ${result.error.message}`, result.error);\n  }\n  return result.value;\n}\nfunction invalidFile(path12, line, cause) {\n  return new SessionError(\"invalid_entry\", `Invalid JSONL v4 session ${path12}: line ${line} ${cause.message}`, cause);\n}\n\n// node_modules/.pnpm/@earendil-works+pi-agent-core@0.84.4_ws@8.21.3/node_modules/@earendil-works/pi-agent-core/dist/harness/session/jsonl/codec.js\nvar ENTRY_TYPES = /* @__PURE__ */ new Set([\n  \"message\",\n  \"model_change\",\n  \"thinking_level_change\",\n  \"active_tools_change\",\n  \"compaction\",\n  \"branch_summary\",\n  \"custom\"\n]);\nvar RECORD_TYPES = /* @__PURE__ */ new Set([\n  \"operation_started\",\n  \"abort_requested\",\n  \"operation_finished\",\n  \"step_attempt\",\n  \"tool_started\",\n  \"queue_enqueued\",\n  \"queue_cancelled\",\n  \"write_deferred\",\n  \"usage\"\n]);\nvar OPERATION_KINDS = /* @__PURE__ */ new Set([\"run\", \"compaction\", \"navigation\"]);\nfunction isObject2(value) {\n  return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\nfunction parseObject(line) {\n  let value;\n  try {\n    value = JSON.parse(line);\n  } catch (error) {\n    throw new JsonlDecodeError(\"syntax\", \"is not valid JSON\", error instanceof Error ? error : void 0);\n  }\n  if (!isObject2(value))\n    throw new JsonlDecodeError(\"schema\", \"is not a JSON object\");\n  return value;\n}\nfunction requireString(value, field) {\n  if (typeof value !== \"string\")\n    throw new JsonlDecodeError(\"schema\", `has invalid ${field}`);\n  return value;\n}\nfunction requireSequence(value) {\n  if (!Number.isSafeInteger(value) || value <= 0) {\n    throw new JsonlDecodeError(\"schema\", \"has invalid seq\");\n  }\n  return value;\n}\nfunction requireTimestamp(value) {\n  if (!Number.isSafeInteger(value) || value < 0) {\n    throw new JsonlDecodeError(\"schema\", \"has invalid timestamp\");\n  }\n  return value;\n}\nfunction requireNullableId(value, field) {\n  if (value !== null && typeof value !== \"string\") {\n    throw new JsonlDecodeError(\"schema\", `has invalid ${field}`);\n  }\n  return value;\n}\nfunction decodeHeader(line) {\n  const value = parseObject(line);\n  if (value.kind !== \"header\")\n    throw new JsonlDecodeError(\"schema\", \"is not a header\");\n  if (value.version !== 4)\n    throw new JsonlDecodeError(\"schema\", \"has unsupported session version\");\n  const parentSessionId = value.parentSessionId;\n  if (parentSessionId !== void 0 && typeof parentSessionId !== \"string\") {\n    throw new JsonlDecodeError(\"schema\", \"has invalid parentSessionId\");\n  }\n  const legacyParentSessionPath = value.legacyParentSessionPath;\n  if (legacyParentSessionPath !== void 0 && typeof legacyParentSessionPath !== \"string\") {\n    throw new JsonlDecodeError(\"schema\", \"has invalid legacyParentSessionPath\");\n  }\n  if (parentSessionId !== void 0 && legacyParentSessionPath !== void 0) {\n    throw new JsonlDecodeError(\"schema\", \"has both parentSessionId and legacyParentSessionPath\");\n  }\n  const metadataValue = value.metadata;\n  if (metadataValue !== void 0 && !isObject2(metadataValue)) {\n    throw new JsonlDecodeError(\"schema\", \"has invalid metadata\");\n  }\n  const metadata = metadataValue;\n  return {\n    kind: \"header\",\n    version: 4,\n    id: requireString(value.id, \"id\"),\n    createdAt: requireTimestamp(value.createdAt),\n    cwd: requireString(value.cwd, \"cwd\"),\n    parentSessionId,\n    legacyParentSessionPath,\n    metadata\n  };\n}\nfunction parseHeader(line) {\n  try {\n    return ok(decodeHeader(line));\n  } catch (error) {\n    if (error instanceof JsonlDecodeError)\n      return err(error);\n    throw error;\n  }\n}\nfunction encodeHeader(header) {\n  return `${JSON.stringify(header)}\n`;\n}\nfunction metadataFromHeader(header, path12, modifiedAt) {\n  return {\n    id: header.id,\n    createdAt: header.createdAt,\n    cwd: header.cwd,\n    path: path12,\n    modifiedAt,\n    sourceFormat: 4,\n    ...header.parentSessionId === void 0 ? {} : { parentSessionId: header.parentSessionId },\n    ...header.legacyParentSessionPath === void 0 ? {} : { legacyParentSessionPath: header.legacyParentSessionPath },\n    ...header.metadata === void 0 ? {} : { metadata: header.metadata }\n  };\n}\nfunction parseEntryMutation(value, seq) {\n  const lane = value.lane === void 0 ? void 0 : requireString(value.lane, \"lane\");\n  const id = requireString(value.id, \"id\");\n  const type = requireString(value.type, \"entry type\");\n  if (!ENTRY_TYPES.has(type)) {\n    throw new JsonlDecodeError(\"schema\", `has unknown entry type ${type}`);\n  }\n  const parentId = requireNullableId(value.parentId, \"parentId\");\n  const timestamp = requireTimestamp(value.timestamp);\n  if (type === \"custom\")\n    requireString(value.customType, \"customType\");\n  const { kind: _kind, lane: _lane, ...entryFields } = value;\n  const entry = { ...entryFields, id, type, parentId, seq, timestamp };\n  return lane === void 0 ? { kind: \"entry\", entry } : { kind: \"entry\", lane, entry };\n}\nfunction parseRecordMutation(value, seq) {\n  const id = requireString(value.id, \"id\");\n  const lane = requireString(value.lane, \"lane\");\n  const type = requireString(value.type, \"record type\");\n  if (!RECORD_TYPES.has(type)) {\n    throw new JsonlDecodeError(\"schema\", `has unknown record type ${type}`);\n  }\n  const timestamp = requireTimestamp(value.timestamp);\n  if (type === \"operation_started\") {\n    if (!isObject2(value.intent))\n      throw new JsonlDecodeError(\"schema\", \"has invalid intent\");\n    const operationKind = requireString(value.intent.kind, \"operation kind\");\n    if (!OPERATION_KINDS.has(operationKind)) {\n      throw new JsonlDecodeError(\"schema\", `has unknown operation kind ${operationKind}`);\n    }\n  }\n  if (type === \"operation_finished\")\n    requireString(value.runId, \"runId\");\n  const { kind: _kind, ...recordFields } = value;\n  return {\n    kind: \"record\",\n    record: { ...recordFields, id, lane, type, seq, timestamp }\n  };\n}\nfunction parseLaneMutation(value, seq) {\n  return {\n    kind: \"lane\",\n    seq,\n    lane: requireString(value.lane, \"lane\"),\n    leafId: requireNullableId(value.leafId, \"leafId\")\n  };\n}\nfunction parseFactMutation(value, seq) {\n  if (value.fact === \"name\") {\n    if (value.name !== void 0 && typeof value.name !== \"string\") {\n      throw new JsonlDecodeError(\"schema\", \"has invalid name\");\n    }\n    return { kind: \"fact\", seq, fact: \"name\", name: value.name };\n  }\n  if (value.fact === \"label\") {\n    if (value.label !== void 0 && typeof value.label !== \"string\") {\n      throw new JsonlDecodeError(\"schema\", \"has invalid label\");\n    }\n    return {\n      kind: \"fact\",\n      seq,\n      fact: \"label\",\n      targetId: requireString(value.targetId, \"targetId\"),\n      label: value.label\n    };\n  }\n  throw new JsonlDecodeError(\"schema\", \"has unknown fact type\");\n}\nfunction decodeMutation(line) {\n  const value = parseObject(line);\n  const seq = requireSequence(value.seq);\n  switch (value.kind) {\n    case \"entry\":\n      return parseEntryMutation(value, seq);\n    case \"record\":\n      return parseRecordMutation(value, seq);\n    case \"lane\":\n      return parseLaneMutation(value, seq);\n    case \"fact\":\n      return parseFactMutation(value, seq);\n    default:\n      throw new JsonlDecodeError(\"schema\", \"has unknown mutation kind\");\n  }\n}\nfunction parseMutation(line) {\n  try {\n    return ok(decodeMutation(line));\n  } catch (error) {\n    if (error instanceof JsonlDecodeError)\n      return err(error);\n    throw error;\n  }\n}\nfunction encodeMutation(mutation) {\n  switch (mutation.kind) {\n    case \"entry\":\n      return `${JSON.stringify({ kind: \"entry\", lane: mutation.lane, ...mutation.entry })}\n`;\n    case \"record\":\n      return `${JSON.stringify({ kind: \"record\", ...mutation.record })}\n`;\n    case \"lane\":\n      return `${JSON.stringify(mutation)}\n`;\n    case \"fact\":\n      return `${JSON.stringify(mutation)}\n`;\n  }\n}\n\n// node_modules/.pnpm/@earendil-works+pi-agent-core@0.84.4_ws@8.21.3/node_modules/@earendil-works/pi-agent-core/dist/harness/session/state.js\nfunction invalidMutation(message) {\n  throw new SessionError(\"invalid_entry\", `Invalid session mutation: ${message}`);\n}\nfunction assertValidLimit2(limit) {\n  if (limit !== void 0 && (!Number.isInteger(limit) || limit <= 0)) {\n    throw new SessionError(\"invalid_query\", \"limit must be a positive integer\");\n  }\n}\nfunction assertValidCursor2(afterSeq) {\n  if (afterSeq !== void 0 && (!Number.isInteger(afterSeq) || afterSeq < 0)) {\n    throw new SessionError(\"invalid_query\", \"cursor sequence must be a non-negative integer\");\n  }\n}\nfunction* ordered(items, order) {\n  if (order === \"oldestFirst\") {\n    yield* items;\n    return;\n  }\n  for (let index = items.length - 1; index >= 0; index--)\n    yield items[index];\n}\nvar SessionState = class {\n  sequence = 0;\n  usedIds = /* @__PURE__ */ new Set();\n  entries = [];\n  entriesById = /* @__PURE__ */ new Map();\n  records = [];\n  openOperationsByLane = /* @__PURE__ */ new Map();\n  lanes = /* @__PURE__ */ new Map([[\"main\", null]]);\n  log = [];\n  stats = {\n    messageCount: 0,\n    cachedTokens: 0,\n    uncachedTokens: 0,\n    totalTokens: 0,\n    costTotal: 0\n  };\n  name;\n  labels = /* @__PURE__ */ new Map();\n  get nextSequence() {\n    return this.sequence + 1;\n  }\n  getLanes() {\n    return [...this.lanes].map(([lane, leafId]) => ({ lane, leafId }));\n  }\n  requireLane(lane) {\n    const leafId = this.lanes.get(lane);\n    if (leafId === void 0)\n      throw new SessionError(\"invalid_lane\", `Lane not found: ${lane}`);\n    return leafId;\n  }\n  validateNewLane(lane) {\n    if (this.lanes.has(lane))\n      throw new SessionError(\"already_exists\", `Lane already exists: ${lane}`);\n  }\n  validateTarget(targetId) {\n    if (targetId !== null && !this.entriesById.has(targetId)) {\n      throw new SessionError(\"not_found\", `Entry not found: ${targetId}`);\n    }\n  }\n  validateUnusedId(id) {\n    if (this.usedIds.has(id))\n      throw new SessionError(\"already_exists\", `Session id already exists: ${id}`);\n  }\n  applyMutation(mutation, invalid = invalidMutation) {\n    const seq = mutation.kind === \"entry\" ? mutation.entry.seq : mutation.kind === \"record\" ? mutation.record.seq : mutation.seq;\n    if (seq !== this.sequence + 1)\n      invalid(`has non-consecutive seq ${seq}`);\n    switch (mutation.kind) {\n      case \"entry\": {\n        if (this.usedIds.has(mutation.entry.id))\n          invalid(`contains duplicate id ${mutation.entry.id}`);\n        if (mutation.lane !== void 0) {\n          const leafId = this.lanes.get(mutation.lane);\n          if (leafId === void 0)\n            invalid(`references missing lane ${mutation.lane}`);\n          if (mutation.entry.parentId !== leafId)\n            invalid(\"does not chain to the lane leaf\");\n        }\n        if (mutation.entry.parentId !== null && !this.entriesById.has(mutation.entry.parentId)) {\n          invalid(`references missing parent ${mutation.entry.parentId}`);\n        }\n        this.sequence = seq;\n        this.usedIds.add(mutation.entry.id);\n        this.entries.push(mutation.entry);\n        this.entriesById.set(mutation.entry.id, mutation.entry);\n        if (mutation.lane !== void 0)\n          this.lanes.set(mutation.lane, mutation.entry.id);\n        this.log.push({ kind: \"entry\", seq, entry: mutation.entry });\n        if (mutation.entry.type === \"message\")\n          this.stats.messageCount += 1;\n        break;\n      }\n      case \"record\": {\n        if (!this.lanes.has(mutation.record.lane))\n          invalid(`references missing lane ${mutation.record.lane}`);\n        if (this.usedIds.has(mutation.record.id))\n          invalid(`contains duplicate id ${mutation.record.id}`);\n        this.sequence = seq;\n        this.usedIds.add(mutation.record.id);\n        this.records.push(mutation.record);\n        if (mutation.record.type === \"operation_started\") {\n          let openOperations = this.openOperationsByLane.get(mutation.record.lane);\n          if (!openOperations) {\n            openOperations = /* @__PURE__ */ new Map();\n            this.openOperationsByLane.set(mutation.record.lane, openOperations);\n          }\n          openOperations.set(mutation.record.id, mutation.record);\n        } else if (mutation.record.type === \"operation_finished\") {\n          this.openOperationsByLane.get(mutation.record.lane)?.delete(mutation.record.runId);\n        }\n        this.log.push({ kind: \"record\", seq, record: mutation.record });\n        if (mutation.record.type === \"usage\") {\n          this.stats.cachedTokens += mutation.record.usage.cacheRead;\n          this.stats.uncachedTokens += mutation.record.usage.input + mutation.record.usage.cacheWrite;\n          this.stats.totalTokens += mutation.record.usage.totalTokens;\n          this.stats.costTotal += mutation.record.usage.cost.total;\n        }\n        break;\n      }\n      case \"lane\":\n        if (mutation.leafId !== null && !this.entriesById.has(mutation.leafId)) {\n          invalid(`references missing lane target ${mutation.leafId}`);\n        }\n        this.sequence = seq;\n        this.lanes.set(mutation.lane, mutation.leafId);\n        this.log.push({ kind: \"lane\", seq, lane: mutation.lane, leafId: mutation.leafId });\n        break;\n      case \"fact\":\n        if (mutation.fact === \"label\" && !this.entriesById.has(mutation.targetId)) {\n          invalid(`references missing label target ${mutation.targetId}`);\n        }\n        this.sequence = seq;\n        if (mutation.fact === \"name\") {\n          this.name = mutation.name;\n          this.log.push({ kind: \"fact\", seq, fact: \"name\", name: mutation.name });\n        } else {\n          if (mutation.label === void 0)\n            this.labels.delete(mutation.targetId);\n          else\n            this.labels.set(mutation.targetId, mutation.label);\n          this.log.push({\n            kind: \"fact\",\n            seq,\n            fact: \"label\",\n            targetId: mutation.targetId,\n            label: mutation.label\n          });\n        }\n        break;\n    }\n  }\n  getEntry(id) {\n    return this.entriesById.get(id);\n  }\n  findEntries(query = {}) {\n    assertValidLimit2(query.limit);\n    assertValidCursor2(query.cursor?.afterSeq);\n    const results = [];\n    for (const entry of ordered(this.entries, query.order)) {\n      if (!this.matchesEntryQuery(entry, query))\n        continue;\n      results.push(entry);\n      if (results.length === query.limit)\n        break;\n    }\n    return results;\n  }\n  findEntriesOnBranch(query) {\n    assertValidLimit2(query.limit);\n    assertValidCursor2(query.cursor?.afterSeq);\n    const results = [];\n    if (query.order === \"oldestFirst\") {\n      for (const entry of [...this.walkToRoot(query.start)].reverse()) {\n        const reachedBound = entry.id === query.stopAtId || entry.type === query.stopAtType;\n        if (this.matchesEntryQuery(entry, query))\n          results.push(entry);\n        if (reachedBound || results.length === query.limit)\n          break;\n      }\n    } else {\n      for (const entry of this.walkToRoot(query.start, query)) {\n        if (this.matchesEntryQuery(entry, query))\n          results.push(entry);\n        if (results.length === query.limit)\n          break;\n      }\n    }\n    return results;\n  }\n  findRecords(query = {}) {\n    assertValidLimit2(query.limit);\n    assertValidCursor2(query.afterSeq);\n    const results = [];\n    for (const record of ordered(this.records, query.order)) {\n      if (!this.matchesRecordQuery(record, query))\n        continue;\n      results.push(record);\n      if (results.length === query.limit)\n        break;\n    }\n    return results;\n  }\n  findOpenOperations(lane, options) {\n    assertValidLimit2(options?.limit);\n    const openOperationsById = this.openOperationsByLane.get(lane);\n    const openOperations = openOperationsById ? [...openOperationsById.values()].reverse() : [];\n    return options?.limit === void 0 ? openOperations : openOperations.slice(0, options.limit);\n  }\n  getLog(options = {}) {\n    assertValidLimit2(options.limit);\n    assertValidCursor2(options.afterSeq);\n    const results = [];\n    for (const item of this.log) {\n      if (options.afterSeq !== void 0 && item.seq <= options.afterSeq)\n        continue;\n      results.push(item);\n      if (results.length === options.limit)\n        break;\n    }\n    return results;\n  }\n  getName() {\n    return this.name;\n  }\n  getLabel(id) {\n    return this.labels.get(id);\n  }\n  getStats() {\n    return this.stats;\n  }\n  createForkMutations(options) {\n    let copiedEntries;\n    let forkLanes;\n    if (options.scope === \"tree\") {\n      copiedEntries = this.findEntries({ order: \"oldestFirst\" });\n      forkLanes = this.getLanes();\n    } else {\n      const selectedEntryId = options.entryId ?? this.requireLane(\"main\");\n      let targetId = null;\n      if (selectedEntryId !== null) {\n        const entry = this.getEntry(selectedEntryId);\n        if (!entry || entry.type !== \"message\") {\n          throw new SessionError(\"invalid_fork_target\", `Fork target is not a message entry: ${selectedEntryId}`);\n        }\n        const position = options.position ?? (options.entryId === void 0 ? \"at\" : \"before\");\n        targetId = position === \"at\" ? entry.id : entry.parentId;\n      }\n      copiedEntries = targetId === null ? [] : this.findEntriesOnBranch({ start: targetId, order: \"oldestFirst\" });\n      forkLanes = [{ lane: \"main\", leafId: targetId }];\n    }\n    const mutations = [];\n    let sequence3 = 1;\n    for (const sourceEntry of copiedEntries) {\n      mutations.push({ kind: \"entry\", entry: { ...structuredClone(sourceEntry), seq: sequence3++ } });\n    }\n    for (const pointer of forkLanes) {\n      mutations.push({ kind: \"lane\", seq: sequence3++, lane: pointer.lane, leafId: pointer.leafId });\n    }\n    if (this.name !== void 0) {\n      mutations.push({ kind: \"fact\", seq: sequence3++, fact: \"name\", name: this.name });\n    }\n    for (const entry of copiedEntries) {\n      const label = this.labels.get(entry.id);\n      if (label !== void 0) {\n        mutations.push({ kind: \"fact\", seq: sequence3++, fact: \"label\", targetId: entry.id, label });\n      }\n    }\n    return mutations;\n  }\n  *walkToRoot(start, bounds) {\n    if (start === null)\n      return;\n    const visited = /* @__PURE__ */ new Set();\n    let current = this.entriesById.get(start);\n    if (!current)\n      throw new SessionError(\"not_found\", `Entry not found: ${start}`);\n    while (current) {\n      if (visited.has(current.id)) {\n        throw new SessionError(\"invalid_entry\", `Session branch contains a cycle at ${current.id}`);\n      }\n      visited.add(current.id);\n      yield current;\n      if (current.id === bounds?.stopAtId || current.type === bounds?.stopAtType || current.parentId === null)\n        break;\n      const parentId = current.parentId;\n      current = this.entriesById.get(parentId);\n      if (!current)\n        throw new SessionError(\"invalid_entry\", `Entry not found: ${parentId}`);\n    }\n  }\n  matchesEntryQuery(entry, query) {\n    return (query.type === void 0 || entry.type === query.type) && (query.customType === void 0 || entry.type === \"custom\" && entry.customType === query.customType) && (query.cursor === void 0 || (query.order === \"oldestFirst\" ? entry.seq > query.cursor.afterSeq : entry.seq < query.cursor.afterSeq));\n  }\n  matchesRecordQuery(record, query) {\n    return (query.lane === void 0 || record.lane === query.lane) && (query.type === void 0 || record.type === query.type) && (query.runId === void 0 || (record.type === \"operation_started\" ? record.id === query.runId : \"runId\" in record && record.runId === query.runId)) && (query.operationKind === void 0 || record.type === \"operation_started\" && record.intent.kind === query.operationKind) && (query.afterSeq === void 0 || record.seq > query.afterSeq);\n  }\n};\n\n// node_modules/.pnpm/@earendil-works+pi-agent-core@0.84.4_ws@8.21.3/node_modules/@earendil-works/pi-agent-core/dist/harness/session/jsonl/storage.js\nasync function publishFileAtomically(fs8, destinationPath, populate) {\n  const tempPath = `${destinationPath}.tmp`;\n  try {\n    await populate(tempPath);\n    fileResult(await fs8.renameFile(tempPath, destinationPath), `Failed to publish staged file ${destinationPath}`);\n  } catch (error) {\n    await fs8.remove(tempPath, { force: true });\n    throw error;\n  }\n}\nvar JsonlSessionStorage = class _JsonlSessionStorage {\n  fs;\n  metadata;\n  state = new SessionState();\n  tail = Promise.resolve();\n  constructor(fs8, metadata) {\n    this.fs = fs8;\n    this.metadata = structuredClone(metadata);\n  }\n  static async create(fs8, path12, header) {\n    fileResult(await fs8.writeFile(path12, encodeHeader(header)), `Failed to initialize session ${path12}`);\n    const fileInfo = fileResult(await fs8.fileInfo(path12), `Failed to read session metadata ${path12}`);\n    return new _JsonlSessionStorage(fs8, metadataFromHeader(header, path12, fileInfo.mtimeMs));\n  }\n  static async load(fs8, path12) {\n    const content = fileResult(await fs8.readTextFile(path12), `Failed to read session ${path12}`);\n    const physicalLines = content.split(\"\\n\");\n    if (physicalLines.at(-1) === \"\")\n      physicalLines.pop();\n    if (physicalLines.length === 0 || !physicalLines[0]) {\n      throw invalidFile(path12, 1, new JsonlDecodeError(\"schema\", \"is missing a header\"));\n    }\n    const headerResult = parseHeader(physicalLines[0]);\n    if (!headerResult.ok)\n      throw invalidFile(path12, 1, headerResult.error);\n    const fileInfo = fileResult(await fs8.fileInfo(path12), `Failed to read session metadata ${path12}`);\n    const storage = new _JsonlSessionStorage(fs8, metadataFromHeader(headerResult.value, path12, fileInfo.mtimeMs));\n    for (let index = 1; index < physicalLines.length; index++) {\n      const line = physicalLines[index];\n      const mutationResult = parseMutation(line);\n      if (!mutationResult.ok) {\n        const isTornTail = index === physicalLines.length - 1 && mutationResult.error.kind === \"syntax\";\n        if (isTornTail) {\n          const validPrefix = `${physicalLines.slice(0, index).join(\"\\n\")}\n`;\n          await publishFileAtomically(fs8, path12, async (tempPath) => {\n            fileResult(await fs8.writeFile(tempPath, validPrefix), `Failed to stage torn-tail repair ${path12}`);\n          });\n          return storage;\n        }\n        throw invalidFile(path12, index + 1, mutationResult.error);\n      }\n      try {\n        storage.applyMutation(mutationResult.value);\n      } catch (error) {\n        if (error instanceof SessionError && error.code === \"invalid_entry\") {\n          throw invalidFile(path12, index + 1, error);\n        }\n        throw error;\n      }\n    }\n    if (!content.endsWith(\"\\n\")) {\n      fileResult(await fs8.appendFile(path12, \"\\n\"), `Failed to repair unterminated session tail ${path12}`);\n    }\n    return storage;\n  }\n  async fork(path12, header, options) {\n    const mutations = this.state.createForkMutations(options);\n    await publishFileAtomically(this.fs, path12, async (tempPath) => {\n      const targetStorage = await _JsonlSessionStorage.create(this.fs, tempPath, header);\n      for (const mutation of mutations) {\n        await targetStorage.appendMutation(mutation);\n        targetStorage.applyMutation(mutation);\n      }\n    });\n    return _JsonlSessionStorage.load(this.fs, path12);\n  }\n  async drain() {\n    await this.tail;\n  }\n  async getMetadata() {\n    return structuredClone(this.metadata);\n  }\n  async getLanes() {\n    return this.state.getLanes();\n  }\n  createLane(lane, at) {\n    return this.enqueue(async () => {\n      this.state.validateNewLane(lane);\n      this.state.validateTarget(at);\n      const mutation = { kind: \"lane\", seq: this.state.nextSequence, lane, leafId: at };\n      await this.appendMutation(mutation);\n      this.applyMutation(mutation);\n    });\n  }\n  moveLane(lane, to) {\n    return this.enqueue(async () => {\n      this.state.requireLane(lane);\n      this.state.validateTarget(to);\n      const mutation = { kind: \"lane\", seq: this.state.nextSequence, lane, leafId: to };\n      await this.appendMutation(mutation);\n      this.applyMutation(mutation);\n    });\n  }\n  appendEntry(newEntry, lane) {\n    return this.enqueue(async () => {\n      const parentId = this.state.requireLane(lane);\n      this.state.validateUnusedId(newEntry.id);\n      const entry = {\n        ...structuredClone(newEntry),\n        parentId,\n        seq: this.state.nextSequence,\n        timestamp: Date.now()\n      };\n      const mutation = { kind: \"entry\", lane, entry };\n      await this.appendMutation(mutation);\n      this.applyMutation(mutation);\n      return structuredClone(entry);\n    });\n  }\n  appendRecord(newRecord) {\n    return this.enqueue(async () => {\n      this.state.requireLane(newRecord.lane);\n      this.state.validateUnusedId(newRecord.id);\n      const currentOpenOperationId = this.state.findOpenOperations(newRecord.lane, { limit: 1 })[0]?.id;\n      if (newRecord.type === \"operation_started\" && currentOpenOperationId !== void 0) {\n        throw new SessionError(\"storage\", `Lane ${newRecord.lane} already has an open operation ${currentOpenOperationId}`);\n      }\n      const record = {\n        ...structuredClone(newRecord),\n        seq: this.state.nextSequence,\n        timestamp: Date.now()\n      };\n      const mutation = { kind: \"record\", record };\n      await this.appendMutation(mutation);\n      this.applyMutation(mutation);\n      return structuredClone(record);\n    });\n  }\n  async getEntry(id) {\n    const entry = this.state.getEntry(id);\n    return entry === void 0 ? void 0 : structuredClone(entry);\n  }\n  async findEntries(query = {}) {\n    return structuredClone(this.state.findEntries(query));\n  }\n  async findEntriesOnBranch(query) {\n    return structuredClone(this.state.findEntriesOnBranch(query));\n  }\n  async findRecords(query = {}) {\n    return structuredClone(this.state.findRecords(query));\n  }\n  async findOpenOperations(lane, options) {\n    return structuredClone(this.state.findOpenOperations(lane, options));\n  }\n  async getLog(options = {}) {\n    return structuredClone(this.state.getLog(options));\n  }\n  async getName() {\n    return this.state.getName();\n  }\n  setName(name) {\n    return this.enqueue(async () => {\n      const mutation = { kind: \"fact\", seq: this.state.nextSequence, fact: \"name\", name };\n      await this.appendMutation(mutation);\n      this.applyMutation(mutation);\n    });\n  }\n  async getLabel(id) {\n    return this.state.getLabel(id);\n  }\n  setLabel(id, label) {\n    return this.enqueue(async () => {\n      this.state.validateTarget(id);\n      const mutation = {\n        kind: \"fact\",\n        seq: this.state.nextSequence,\n        fact: \"label\",\n        targetId: id,\n        label\n      };\n      await this.appendMutation(mutation);\n      this.applyMutation(mutation);\n    });\n  }\n  async getStats() {\n    return structuredClone(this.state.getStats());\n  }\n  enqueue(operation) {\n    const result = this.tail.then(operation);\n    this.tail = result.then(() => void 0, () => void 0);\n    return result;\n  }\n  async appendMutation(mutation) {\n    fileResult(await this.fs.appendFile(this.metadata.path, encodeMutation(mutation)), `Failed to append session ${this.metadata.path}`);\n  }\n  applyMutation(mutation) {\n    this.state.applyMutation(mutation);\n  }\n};\n\n// node_modules/.pnpm/@earendil-works+pi-agent-core@0.84.4_ws@8.21.3/node_modules/@earendil-works/pi-agent-core/dist/harness/session/jsonl/repo.js\nvar SESSION_ID_PATTERN = /^[A-Za-z0-9](?:[A-Za-z0-9._-]*[A-Za-z0-9])?$/;\nfunction validateSessionId(id) {\n  if (!SESSION_ID_PATTERN.test(id)) {\n    throw new SessionError(\"invalid_payload\", \"Session id must be non-empty, contain only alphanumeric characters, '-', '_', and '.', and start and end with an alphanumeric character\");\n  }\n}\nfunction jsonlSessionDirectoryName(cwd) {\n  return `--${cwd.replace(/^[/\\\\]/, \"\").replace(/[/\\\\:]/g, \"-\")}--`;\n}\nasync function jsonlSessionsRoot(options) {\n  return fileResult(await options.fs.absolutePath(options.sessionsRoot), `Failed to resolve sessions root ${options.sessionsRoot}`);\n}\nasync function jsonlSessionDirectory(fs8, sessionsRoot, cwd) {\n  return fileResult(await fs8.joinPath([sessionsRoot, jsonlSessionDirectoryName(cwd)]), `Failed to resolve sessions directory for ${cwd}`);\n}\nasync function jsonlSessionDirectories(options, cwd) {\n  const sessionsRoot = await jsonlSessionsRoot(options);\n  if (cwd !== void 0) {\n    const resolvedCwd = fileResult(await options.fs.absolutePath(cwd), `Failed to resolve session cwd ${cwd}`);\n    const directory = await jsonlSessionDirectory(options.fs, sessionsRoot, resolvedCwd);\n    return fileResult(await options.fs.exists(directory), `Failed to check sessions directory ${directory}`) ? [directory] : [];\n  }\n  if (!fileResult(await options.fs.exists(sessionsRoot), `Failed to check sessions directory ${sessionsRoot}`))\n    return [];\n  return fileResult(await options.fs.listDir(sessionsRoot), `Failed to list sessions directory ${sessionsRoot}`).filter((entry) => entry.kind === \"directory\" || entry.kind === \"symlink\").map((entry) => entry.path);\n}\nasync function listJsonlSessionMetadata(options, query = {}) {\n  const metadata = [];\n  for (const directory of await jsonlSessionDirectories(options, query.cwd)) {\n    const files = fileResult(await options.fs.listDir(directory), `Failed to list sessions directory ${directory}`).filter((entry) => entry.kind !== \"directory\" && entry.name.endsWith(\".jsonl\"));\n    for (const file of files) {\n      const [firstLine] = fileResult(await options.fs.readTextLines(file.path, { maxLines: 1 }), `Failed to read session header ${file.path}`);\n      if (!firstLine)\n        continue;\n      const headerResult = parseHeader(firstLine);\n      if (!headerResult.ok)\n        continue;\n      metadata.push(metadataFromHeader(headerResult.value, file.path, file.mtimeMs));\n    }\n  }\n  return metadata.sort((left, right) => right.modifiedAt - left.modifiedAt);\n}\nasync function loadJsonlSessionStorage(options, metadata) {\n  if (!fileResult(await options.fs.exists(metadata.path), `Failed to check session ${metadata.path}`)) {\n    throw new SessionError(\"not_found\", `Session not found: ${metadata.id}`);\n  }\n  const storage = await JsonlSessionStorage.load(options.fs, metadata.path);\n  const loadedMetadata = await storage.getMetadata();\n  if (loadedMetadata.id !== metadata.id) {\n    throw new SessionError(\"invalid_entry\", `Session id does not match header: ${metadata.id}`);\n  }\n  return storage;\n}\nfunction sessionFileName(createdAt, id) {\n  const timestamp = new Date(createdAt).toISOString().replace(/[:.]/g, \"-\");\n  return `${timestamp}_${id}.jsonl`;\n}\nvar JsonlSessionRepo = class {\n  fs;\n  sessionsRootInput;\n  activeCreateDestinations = /* @__PURE__ */ new Set();\n  rootPromise;\n  constructor(options) {\n    this.fs = options.fs;\n    this.sessionsRootInput = options.sessionsRoot;\n  }\n  async create(options) {\n    const destination = await this.resolveCreateDestination(options);\n    return this.claimCreateDestination(destination, async () => {\n      const { header, path: path12 } = await this.prepareCreate(destination, options);\n      return new Session(await JsonlSessionStorage.create(this.fs, path12, header));\n    });\n  }\n  async open(metadata) {\n    return new Session(await this.loadStorage(metadata));\n  }\n  async list(options = {}) {\n    return this.listDirect(options);\n  }\n  async delete(metadata) {\n    fileResult(await this.fs.remove(metadata.path, { force: true }), `Failed to delete session ${metadata.path}`);\n  }\n  async fork(source, options) {\n    const sourceStorage = await this.loadStorage(source);\n    const createOptions = {\n      ...options,\n      parentSessionId: options.parentSessionId ?? source.id\n    };\n    const destination = await this.resolveCreateDestination(createOptions);\n    return this.claimCreateDestination(destination, async () => {\n      const { header, path: path12 } = await this.prepareCreate(destination, createOptions);\n      return new Session(await sourceStorage.fork(path12, header, options));\n    });\n  }\n  async loadStorage(metadata) {\n    return loadJsonlSessionStorage({ fs: this.fs, sessionsRoot: this.sessionsRootInput }, metadata);\n  }\n  async resolveCreateDestination(options) {\n    const id = options.id ?? uuidv72();\n    validateSessionId(id);\n    const cwd = fileResult(await this.fs.absolutePath(options.cwd), `Failed to resolve session cwd ${options.cwd}`);\n    return { id, cwd };\n  }\n  /**\n   * Prevent same-process create/fork races for one logical destination. The durable filename includes a\n   * timestamp, so the async filesystem existence check alone can let two concurrent calls both decide the\n   * same {cwd, id} is free and publish duplicate sessions.\n   */\n  async claimCreateDestination(destination, operation) {\n    const key = `${destination.cwd}\\0${destination.id}`;\n    if (this.activeCreateDestinations.has(key)) {\n      throw new SessionError(\"already_exists\", `Session already exists: ${destination.id}`);\n    }\n    this.activeCreateDestinations.add(key);\n    try {\n      return await operation();\n    } finally {\n      this.activeCreateDestinations.delete(key);\n    }\n  }\n  async prepareCreate(destination, options) {\n    const { id, cwd } = destination;\n    if (await this.sessionIdExists(id, cwd)) {\n      throw new SessionError(\"already_exists\", `Session already exists: ${id}`);\n    }\n    const createdAt = Date.now();\n    const sessionDirectory = await this.sessionDirectory(cwd);\n    const path12 = fileResult(await this.fs.joinPath([sessionDirectory, sessionFileName(createdAt, id)]), `Failed to resolve path for session ${id}`);\n    if (options.metadata !== void 0)\n      assertJsonSerializable(options.metadata);\n    const header = {\n      kind: \"header\",\n      version: 4,\n      id,\n      createdAt,\n      cwd,\n      parentSessionId: options.parentSessionId,\n      metadata: options.metadata\n    };\n    fileResult(await this.fs.createDir(sessionDirectory, { recursive: true }), `Failed to create sessions directory`);\n    return { header, path: path12 };\n  }\n  async listDirect(options) {\n    return listJsonlSessionMetadata({ fs: this.fs, sessionsRoot: this.sessionsRootInput }, options);\n  }\n  async sessionIdExists(id, cwd) {\n    const suffix = `_${id}.jsonl`;\n    const directory = await this.sessionDirectory(cwd);\n    if (!fileResult(await this.fs.exists(directory), `Failed to check sessions directory ${directory}`))\n      return false;\n    const files = fileResult(await this.fs.listDir(directory), `Failed to list sessions directory ${directory}`);\n    return files.some((entry) => entry.kind !== \"directory\" && entry.name.endsWith(suffix));\n  }\n  async sessionDirectory(cwd) {\n    return fileResult(await this.fs.joinPath([await this.root(), jsonlSessionDirectoryName(cwd)]), `Failed to resolve sessions directory for ${cwd}`);\n  }\n  root() {\n    this.rootPromise ??= this.fs.absolutePath(this.sessionsRootInput).then((result) => fileResult(result, `Failed to resolve sessions root ${this.sessionsRootInput}`));\n    return this.rootPromise;\n  }\n};\n\n// node_modules/.pnpm/@earendil-works+pi-agent-core@0.84.4_ws@8.21.3/node_modules/@earendil-works/pi-agent-core/dist/harness/session/memory.js\nvar InMemorySessionStorage = class _InMemorySessionStorage {\n  metadata;\n  state = new SessionState();\n  constructor(metadata) {\n    this.metadata = structuredClone(metadata);\n  }\n  fork(metadata, options) {\n    const storage = new _InMemorySessionStorage(metadata);\n    for (const mutation of this.state.createForkMutations(options))\n      storage.state.applyMutation(mutation);\n    return storage;\n  }\n  async getMetadata() {\n    return structuredClone(this.metadata);\n  }\n  async getLanes() {\n    return this.state.getLanes();\n  }\n  async createLane(lane, at) {\n    this.state.validateNewLane(lane);\n    this.state.validateTarget(at);\n    this.state.applyMutation({ kind: \"lane\", seq: this.state.nextSequence, lane, leafId: at });\n  }\n  async moveLane(lane, to) {\n    this.state.requireLane(lane);\n    this.state.validateTarget(to);\n    this.state.applyMutation({ kind: \"lane\", seq: this.state.nextSequence, lane, leafId: to });\n  }\n  async appendEntry(newEntry, lane) {\n    const parentId = this.state.requireLane(lane);\n    this.state.validateUnusedId(newEntry.id);\n    const entry = {\n      ...structuredClone(newEntry),\n      parentId,\n      seq: this.state.nextSequence,\n      timestamp: Date.now()\n    };\n    this.state.applyMutation({ kind: \"entry\", lane, entry });\n    return structuredClone(entry);\n  }\n  async appendRecord(newRecord) {\n    this.state.requireLane(newRecord.lane);\n    this.state.validateUnusedId(newRecord.id);\n    const currentOpenOperationId = this.state.findOpenOperations(newRecord.lane, { limit: 1 })[0]?.id;\n    if (newRecord.type === \"operation_started\" && currentOpenOperationId !== void 0) {\n      throw new SessionError(\"storage\", `Lane ${newRecord.lane} already has an open operation ${currentOpenOperationId}`);\n    }\n    const record = {\n      ...structuredClone(newRecord),\n      seq: this.state.nextSequence,\n      timestamp: Date.now()\n    };\n    this.state.applyMutation({ kind: \"record\", record });\n    return structuredClone(record);\n  }\n  async getEntry(id) {\n    const entry = this.state.getEntry(id);\n    return entry === void 0 ? void 0 : structuredClone(entry);\n  }\n  async findEntries(query = {}) {\n    return structuredClone(this.state.findEntries(query));\n  }\n  async findEntriesOnBranch(query) {\n    return structuredClone(this.state.findEntriesOnBranch(query));\n  }\n  async findRecords(query = {}) {\n    return structuredClone(this.state.findRecords(query));\n  }\n  async findOpenOperations(lane, options) {\n    return structuredClone(this.state.findOpenOperations(lane, options));\n  }\n  async getLog(options = {}) {\n    return structuredClone(this.state.getLog(options));\n  }\n  async getName() {\n    return this.state.getName();\n  }\n  async setName(name) {\n    this.state.applyMutation({ kind: \"fact\", seq: this.state.nextSequence, fact: \"name\", name });\n  }\n  async getLabel(id) {\n    return this.state.getLabel(id);\n  }\n  async setLabel(id, label) {\n    this.state.validateTarget(id);\n    this.state.applyMutation({\n      kind: \"fact\",\n      seq: this.state.nextSequence,\n      fact: \"label\",\n      targetId: id,\n      label\n    });\n  }\n  async getStats() {\n    return structuredClone(this.state.getStats());\n  }\n};\nvar InMemorySessionRepo = class {\n  sessions = /* @__PURE__ */ new Map();\n  async create(options = {}) {\n    const id = options.id ?? uuidv72();\n    if (this.sessions.has(id))\n      throw new SessionError(\"already_exists\", `Session already exists: ${id}`);\n    const storage = new InMemorySessionStorage({\n      id,\n      createdAt: Date.now(),\n      parentSessionId: options.parentSessionId\n    });\n    this.sessions.set(id, storage);\n    return new Session(storage);\n  }\n  async open(metadata) {\n    return new Session(this.requireStorage(metadata.id));\n  }\n  async list() {\n    return Promise.all([...this.sessions.values()].map((storage) => storage.getMetadata()));\n  }\n  async delete(metadata) {\n    this.sessions.delete(metadata.id);\n  }\n  async fork(source, options = {}) {\n    const sourceStorage = this.requireStorage(source.id);\n    const id = options.id ?? uuidv72();\n    if (this.sessions.has(id))\n      throw new SessionError(\"already_exists\", `Session already exists: ${id}`);\n    const storage = sourceStorage.fork({ id, createdAt: Date.now(), parentSessionId: options.parentSessionId ?? source.id }, options);\n    this.sessions.set(id, storage);\n    return new Session(storage);\n  }\n  requireStorage(id) {\n    const storage = this.sessions.get(id);\n    if (!storage)\n      throw new SessionError(\"not_found\", `Session not found: ${id}`);\n    return storage;\n  }\n};\n\n// node_modules/.pnpm/@earendil-works+pi-agent-core@0.84.4_ws@8.21.3/node_modules/@earendil-works/pi-agent-core/dist/harness/compaction/utils.js\nfunction createFileOps() {\n  return {\n    read: /* @__PURE__ */ new Set(),\n    written: /* @__PURE__ */ new Set(),\n    edited: /* @__PURE__ */ new Set()\n  };\n}\nfunction extractFileOpsFromMessage(message, fileOps) {\n  if (message.role !== \"assistant\")\n    return;\n  if (!(\"content\" in message) || !Array.isArray(message.content))\n    return;\n  for (const block of message.content) {\n    if (typeof block !== \"object\" || block === null)\n      continue;\n    if (!(\"type\" in block) || block.type !== \"toolCall\")\n      continue;\n    if (!(\"arguments\" in block) || !(\"name\" in block))\n      continue;\n    const args = block.arguments;\n    if (!args)\n      continue;\n    const path12 = typeof args.path === \"string\" ? args.path : void 0;\n    if (!path12)\n      continue;\n    switch (block.name) {\n      case \"read\":\n        fileOps.read.add(path12);\n        break;\n      case \"write\":\n        fileOps.written.add(path12);\n        break;\n      case \"edit\":\n        fileOps.edited.add(path12);\n        break;\n    }\n  }\n}\nfunction computeFileLists(fileOps) {\n  const modified = /* @__PURE__ */ new Set([...fileOps.edited, ...fileOps.written]);\n  const readOnly = [...fileOps.read].filter((f) => !modified.has(f)).sort();\n  const modifiedFiles = [...modified].sort();\n  return { readFiles: readOnly, modifiedFiles };\n}\nfunction formatFileOperations(readFiles, modifiedFiles) {\n  const sections = [];\n  if (readFiles.length > 0) {\n    sections.push(`<read-files>\n${readFiles.join(\"\\n\")}\n</read-files>`);\n  }\n  if (modifiedFiles.length > 0) {\n    sections.push(`<modified-files>\n${modifiedFiles.join(\"\\n\")}\n</modified-files>`);\n  }\n  if (sections.length === 0)\n    return \"\";\n  return `\n\n${sections.join(\"\\n\\n\")}`;\n}\nvar TOOL_RESULT_MAX_CHARS = 2e3;\nfunction safeJsonStringify4(value) {\n  try {\n    return JSON.stringify(value) ?? \"undefined\";\n  } catch {\n    return \"[unserializable]\";\n  }\n}\nfunction truncateForSummary(text, maxChars) {\n  if (text.length <= maxChars)\n    return text;\n  const truncatedChars = text.length - maxChars;\n  return `${text.slice(0, maxChars)}\n\n[... ${truncatedChars} more characters truncated]`;\n}\nfunction serializeConversation(messages) {\n  const parts = [];\n  for (const msg of messages) {\n    if (msg.role === \"user\") {\n      const content = contentText2(msg.content, \"\");\n      if (content)\n        parts.push(`[User]: ${content}`);\n    } else if (msg.role === \"assistant\") {\n      const thinkingParts = [];\n      const toolCalls = [];\n      for (const block of msg.content) {\n        if (block.type === \"thinking\") {\n          thinkingParts.push(block.thinking);\n        } else if (block.type === \"toolCall\") {\n          const args = block.arguments;\n          const argsStr = Object.entries(args).map(([k, v]) => `${k}=${safeJsonStringify4(v)}`).join(\", \");\n          toolCalls.push(`${block.name}(${argsStr})`);\n        }\n      }\n      if (thinkingParts.length > 0) {\n        parts.push(`[Assistant thinking]: ${thinkingParts.join(\"\\n\")}`);\n      }\n      if (msg.content.some((block) => block.type === \"text\")) {\n        parts.push(`[Assistant]: ${contentText2(msg.content)}`);\n      }\n      if (toolCalls.length > 0) {\n        parts.push(`[Assistant tool calls]: ${toolCalls.join(\"; \")}`);\n      }\n    } else if (msg.role === \"toolResult\") {\n      const content = contentText2(msg.content, \"\");\n      if (content) {\n        parts.push(`[Tool result]: ${truncateForSummary(content, TOOL_RESULT_MAX_CHARS)}`);\n      }\n    }\n  }\n  return parts.join(\"\\n\\n\");\n}\n\n// node_modules/.pnpm/@earendil-works+pi-agent-core@0.84.4_ws@8.21.3/node_modules/@earendil-works/pi-agent-core/dist/harness/compaction/compaction.js\nfunction safeJsonStringify5(value) {\n  try {\n    return JSON.stringify(value) ?? \"undefined\";\n  } catch {\n    return \"[unserializable]\";\n  }\n}\nfunction extractFileOperations(messages, entries, prevCompactionIndex) {\n  const fileOps = createFileOps();\n  if (prevCompactionIndex >= 0) {\n    const prevCompaction = entries[prevCompactionIndex];\n    if (prevCompaction.details) {\n      const details = prevCompaction.details;\n      if (Array.isArray(details.readFiles)) {\n        for (const f of details.readFiles)\n          fileOps.read.add(f);\n      }\n      if (Array.isArray(details.modifiedFiles)) {\n        for (const f of details.modifiedFiles)\n          fileOps.edited.add(f);\n      }\n    }\n  }\n  for (const msg of messages) {\n    extractFileOpsFromMessage(msg, fileOps);\n  }\n  return fileOps;\n}\nfunction getMessageFromEntry(entry) {\n  if (entry.type === \"message\") {\n    return entry.message;\n  }\n  if (entry.type === \"branch_summary\") {\n    return createBranchSummaryMessage2(entry.summary, entry.fromId, entry.timestamp);\n  }\n  if (entry.type === \"compaction\") {\n    return createCompactionSummaryMessage2(entry.summary, entry.tokensBefore, entry.timestamp);\n  }\n  return void 0;\n}\nfunction getMessageFromEntryForCompaction(entry) {\n  if (entry.type === \"compaction\") {\n    return void 0;\n  }\n  return getMessageFromEntry(entry);\n}\nasync function completeSimpleWithRetries(models, model, context, options, retry, callbacks) {\n  const requestOptions = {\n    ...options,\n    cacheRetention: \"none\",\n    sessionId: uuidv72()\n  };\n  return retryAssistantCall2(() => models.completeSimple(model, context, requestOptions), retry, requestOptions.signal, callbacks);\n}\nfunction combineUsage(first, second) {\n  return {\n    input: first.input + second.input,\n    output: first.output + second.output,\n    cacheRead: first.cacheRead + second.cacheRead,\n    cacheWrite: first.cacheWrite + second.cacheWrite,\n    ...first.cacheWrite1h !== void 0 || second.cacheWrite1h !== void 0 ? { cacheWrite1h: (first.cacheWrite1h ?? 0) + (second.cacheWrite1h ?? 0) } : {},\n    ...first.reasoning !== void 0 || second.reasoning !== void 0 ? { reasoning: (first.reasoning ?? 0) + (second.reasoning ?? 0) } : {},\n    totalTokens: first.totalTokens + second.totalTokens,\n    cost: {\n      input: first.cost.input + second.cost.input,\n      output: first.cost.output + second.cost.output,\n      cacheRead: first.cost.cacheRead + second.cost.cacheRead,\n      cacheWrite: first.cost.cacheWrite + second.cost.cacheWrite,\n      total: first.cost.total + second.cost.total\n    }\n  };\n}\nvar DEFAULT_COMPACTION_SETTINGS = {\n  enabled: true,\n  reserveTokens: 16384,\n  keepRecentTokens: 2e4\n};\nfunction calculateContextTokens2(usage) {\n  return usage.totalTokens || usage.input + usage.output + usage.cacheRead + usage.cacheWrite;\n}\nfunction getAssistantUsage(msg) {\n  if (msg.role === \"assistant\" && \"usage\" in msg) {\n    const assistantMsg = msg;\n    if (assistantMsg.stopReason !== \"aborted\" && assistantMsg.stopReason !== \"error\" && assistantMsg.usage && calculateContextTokens2(assistantMsg.usage) > 0) {\n      return assistantMsg.usage;\n    }\n  }\n  return void 0;\n}\nfunction getLastAssistantUsage(entries) {\n  for (let i = entries.length - 1; i >= 0; i--) {\n    const entry = entries[i];\n    if (entry.type === \"message\") {\n      const usage = getAssistantUsage(entry.message);\n      if (usage)\n        return usage;\n    }\n  }\n  return void 0;\n}\nfunction getLastAssistantUsageInfo2(messages) {\n  for (let i = messages.length - 1; i >= 0; i--) {\n    const usage = getAssistantUsage(messages[i]);\n    if (usage)\n      return { usage, index: i };\n  }\n  return void 0;\n}\nfunction estimateContextTokens2(messages) {\n  const usageInfo = getLastAssistantUsageInfo2(messages);\n  if (!usageInfo) {\n    let estimated = 0;\n    for (const message of messages) {\n      estimated += estimateTokens2(message);\n    }\n    return {\n      tokens: estimated,\n      usageTokens: 0,\n      trailingTokens: estimated,\n      lastUsageIndex: null\n    };\n  }\n  const usageTokens = calculateContextTokens2(usageInfo.usage);\n  let trailingTokens = 0;\n  for (let i = usageInfo.index + 1; i < messages.length; i++) {\n    trailingTokens += estimateTokens2(messages[i]);\n  }\n  return {\n    tokens: usageTokens + trailingTokens,\n    usageTokens,\n    trailingTokens,\n    lastUsageIndex: usageInfo.index\n  };\n}\nfunction shouldCompact(contextTokens, contextWindow, settings) {\n  if (!settings.enabled)\n    return false;\n  return contextTokens > contextWindow - settings.reserveTokens;\n}\nvar ESTIMATED_IMAGE_CHARS2 = 4800;\nfunction estimateTextAndImageContentChars2(content) {\n  if (typeof content === \"string\") {\n    return content.length;\n  }\n  let chars = 0;\n  for (const block of content) {\n    if (block.type === \"text\" && block.text) {\n      chars += block.text.length;\n    } else if (block.type === \"image\") {\n      chars += ESTIMATED_IMAGE_CHARS2;\n    }\n  }\n  return chars;\n}\nfunction estimateTokens2(message) {\n  let chars = 0;\n  switch (message.role) {\n    case \"user\": {\n      chars = estimateTextAndImageContentChars2(message.content);\n      return Math.ceil(chars / 4);\n    }\n    case \"assistant\": {\n      const assistant = message;\n      for (const block of assistant.content) {\n        if (block.type === \"text\") {\n          chars += block.text.length;\n        } else if (block.type === \"thinking\") {\n          chars += block.thinking.length;\n        } else if (block.type === \"toolCall\") {\n          chars += block.name.length + safeJsonStringify5(block.arguments).length;\n        }\n      }\n      return Math.ceil(chars / 4);\n    }\n    case \"custom\":\n    case \"toolResult\": {\n      chars = estimateTextAndImageContentChars2(message.content);\n      return Math.ceil(chars / 4);\n    }\n    case \"bashExecution\": {\n      chars = message.command.length + message.output.length;\n      return Math.ceil(chars / 4);\n    }\n    case \"branchSummary\":\n    case \"compactionSummary\": {\n      chars = message.summary.length;\n      return Math.ceil(chars / 4);\n    }\n  }\n  return 0;\n}\nfunction findValidCutPoints(entries, startIndex, endIndex) {\n  const cutPoints = [];\n  for (let i = startIndex; i < endIndex; i++) {\n    const entry = entries[i];\n    switch (entry.type) {\n      case \"message\": {\n        const role = entry.message.role;\n        switch (role) {\n          case \"bashExecution\":\n          case \"custom\":\n          case \"branchSummary\":\n          case \"compactionSummary\":\n          case \"user\":\n          case \"assistant\":\n            cutPoints.push(i);\n            break;\n          case \"toolResult\":\n            break;\n        }\n        break;\n      }\n      case \"thinking_level_change\":\n      case \"model_change\":\n      case \"active_tools_change\":\n      case \"compaction\":\n      case \"branch_summary\":\n      case \"custom\":\n        break;\n    }\n    if (entry.type === \"branch_summary\")\n      cutPoints.push(i);\n  }\n  return cutPoints;\n}\nfunction findTurnStartIndex(entries, entryIndex, startIndex) {\n  for (let i = entryIndex; i >= startIndex; i--) {\n    const entry = entries[i];\n    if (entry.type === \"branch_summary\") {\n      return i;\n    }\n    if (entry.type === \"message\") {\n      const role = entry.message.role;\n      if (role === \"user\" || role === \"bashExecution\") {\n        return i;\n      }\n    }\n  }\n  return -1;\n}\nfunction findCutPoint(entries, startIndex, endIndex, keepRecentTokens) {\n  const cutPoints = findValidCutPoints(entries, startIndex, endIndex);\n  if (cutPoints.length === 0) {\n    return { firstKeptEntryIndex: startIndex, turnStartIndex: -1, isSplitTurn: false };\n  }\n  let accumulatedTokens = 0;\n  let cutIndex = cutPoints[0];\n  for (let i = endIndex - 1; i >= startIndex; i--) {\n    const entry = entries[i];\n    if (entry.type !== \"message\")\n      continue;\n    const messageTokens = estimateTokens2(entry.message);\n    accumulatedTokens += messageTokens;\n    if (accumulatedTokens >= keepRecentTokens) {\n      for (let c = 0; c < cutPoints.length; c++) {\n        if (cutPoints[c] >= i) {\n          cutIndex = cutPoints[c];\n          break;\n        }\n      }\n      break;\n    }\n  }\n  while (cutIndex > startIndex) {\n    const prevEntry = entries[cutIndex - 1];\n    if (prevEntry.type === \"compaction\") {\n      break;\n    }\n    if (prevEntry.type === \"message\") {\n      break;\n    }\n    cutIndex--;\n  }\n  const cutEntry = entries[cutIndex];\n  const isUserMessage = cutEntry.type === \"message\" && cutEntry.message.role === \"user\";\n  const turnStartIndex = isUserMessage ? -1 : findTurnStartIndex(entries, cutIndex, startIndex);\n  return {\n    firstKeptEntryIndex: cutIndex,\n    turnStartIndex,\n    isSplitTurn: !isUserMessage && turnStartIndex !== -1\n  };\n}\nvar SUMMARIZATION_SYSTEM_PROMPT = `You are a context summarization assistant. Your task is to read a conversation between a user and an AI assistant, then produce a structured summary following the exact format specified.\n\nDo NOT continue the conversation. Do NOT respond to any questions in the conversation. ONLY output the structured summary.`;\nvar SUMMARIZATION_PROMPT = `The messages above are a conversation to summarize. Create a structured context checkpoint summary that another LLM will use to continue the work.\n\nUse this EXACT format:\n\n## Goal\n[What is the user trying to accomplish? Can be multiple items if the session covers different tasks.]\n\n## Constraints & Preferences\n- [Any constraints, preferences, or requirements mentioned by user]\n- [Or \"(none)\" if none were mentioned]\n\n## Progress\n### Done\n- [x] [Completed tasks/changes]\n\n### In Progress\n- [ ] [Current work]\n\n### Blocked\n- [Issues preventing progress, if any]\n\n## Key Decisions\n- **[Decision]**: [Brief rationale]\n\n## Next Steps\n1. [Ordered list of what should happen next]\n\n## Critical Context\n- [Any data, examples, or references needed to continue]\n- [Or \"(none)\" if not applicable]\n\nKeep each section concise. Preserve exact file paths, function names, and error messages.`;\nvar UPDATE_SUMMARIZATION_PROMPT = `The messages above are NEW conversation messages to incorporate into the existing summary provided in <previous-summary> tags.\n\nUpdate the existing structured summary with new information. RULES:\n- PRESERVE all existing information from the previous summary\n- ADD new progress, decisions, and context from the new messages\n- UPDATE the Progress section: move items from \"In Progress\" to \"Done\" when completed\n- UPDATE \"Next Steps\" based on what was accomplished\n- PRESERVE exact file paths, function names, and error messages\n- If something is no longer relevant, you may remove it\n\nUse this EXACT format:\n\n## Goal\n[Preserve existing goals, add new ones if the task expanded]\n\n## Constraints & Preferences\n- [Preserve existing, add new ones discovered]\n\n## Progress\n### Done\n- [x] [Include previously done items AND newly completed items]\n\n### In Progress\n- [ ] [Current work - update based on progress]\n\n### Blocked\n- [Current blockers - remove if resolved]\n\n## Key Decisions\n- **[Decision]**: [Brief rationale] (preserve all previous, add new)\n\n## Next Steps\n1. [Update based on current state]\n\n## Critical Context\n- [Preserve important context, add new if needed]\n\nKeep each section concise. Preserve exact file paths, function names, and error messages.`;\nasync function generateSummary(currentMessages, models, model, reserveTokens, signal, customInstructions, previousSummary, thinkingLevel, retry, callbacks) {\n  const result = await generateSummaryWithUsage(currentMessages, models, model, reserveTokens, signal, customInstructions, previousSummary, thinkingLevel, retry, callbacks);\n  return result.ok ? ok(result.value.text) : err(result.error);\n}\nasync function generateSummaryWithUsage(currentMessages, models, model, reserveTokens, signal, customInstructions, previousSummary, thinkingLevel, retry, callbacks) {\n  const maxTokens = Math.min(Math.floor(0.8 * reserveTokens), model.maxTokens > 0 ? model.maxTokens : Number.POSITIVE_INFINITY);\n  let basePrompt = previousSummary ? UPDATE_SUMMARIZATION_PROMPT : SUMMARIZATION_PROMPT;\n  if (customInstructions) {\n    basePrompt = `${basePrompt}\n\nAdditional focus: ${customInstructions}`;\n  }\n  const llmMessages = convertToLlm2(currentMessages);\n  const conversationText = serializeConversation(llmMessages);\n  let promptText = `<conversation>\n${conversationText}\n</conversation>\n\n`;\n  if (previousSummary) {\n    promptText += `<previous-summary>\n${previousSummary}\n</previous-summary>\n\n`;\n  }\n  promptText += basePrompt;\n  const summarizationMessages = [\n    {\n      role: \"user\",\n      content: [{ type: \"text\", text: promptText }],\n      timestamp: Date.now()\n    }\n  ];\n  const completionOptions = model.reasoning && thinkingLevel && thinkingLevel !== \"off\" ? { maxTokens, signal, reasoning: thinkingLevel } : { maxTokens, signal };\n  const response = await completeSimpleWithRetries(models, model, { systemPrompt: SUMMARIZATION_SYSTEM_PROMPT, messages: summarizationMessages }, completionOptions, retry, callbacks);\n  if (response.stopReason === \"aborted\") {\n    return err(new CompactionError(\"aborted\", response.errorMessage || \"Summarization aborted\"));\n  }\n  if (response.stopReason === \"error\") {\n    return err(new CompactionError(\"summarization_failed\", `Summarization failed: ${response.errorMessage || \"Unknown error\"}`));\n  }\n  const textContent = contentText2(response.content);\n  return ok({ text: textContent, usage: response.usage });\n}\nfunction prepareCompaction(pathEntries, settings) {\n  if (pathEntries.length === 0 || pathEntries[pathEntries.length - 1].type === \"compaction\") {\n    return ok(void 0);\n  }\n  let prevCompactionIndex = -1;\n  for (let i = pathEntries.length - 1; i >= 0; i--) {\n    if (pathEntries[i].type === \"compaction\") {\n      prevCompactionIndex = i;\n      break;\n    }\n  }\n  let previousSummary;\n  let compactableEntries = pathEntries;\n  if (prevCompactionIndex >= 0) {\n    const prevCompaction = pathEntries[prevCompactionIndex];\n    previousSummary = prevCompaction.summary;\n    const virtualRetainedEntries = prevCompaction.retainedTail.map((message, index) => ({\n      type: \"message\",\n      id: `${prevCompaction.id}:retained:${index}`,\n      parentId: index === 0 ? prevCompaction.id : `${prevCompaction.id}:retained:${index - 1}`,\n      seq: prevCompaction.seq,\n      timestamp: message.timestamp,\n      message\n    }));\n    compactableEntries = [...virtualRetainedEntries, ...pathEntries.slice(prevCompactionIndex + 1)];\n  }\n  const boundaryEnd = compactableEntries.length;\n  const tokensBefore = estimateContextTokens2(buildSessionContext2(pathEntries).messages).tokens;\n  const cutPoint = findCutPoint(compactableEntries, 0, boundaryEnd, settings.keepRecentTokens);\n  const historyEnd = cutPoint.isSplitTurn ? cutPoint.turnStartIndex : cutPoint.firstKeptEntryIndex;\n  const messagesToSummarize = [];\n  for (let i = 0; i < historyEnd; i++) {\n    const msg = getMessageFromEntryForCompaction(compactableEntries[i]);\n    if (msg)\n      messagesToSummarize.push(msg);\n  }\n  const turnPrefixMessages = [];\n  if (cutPoint.isSplitTurn) {\n    for (let i = cutPoint.turnStartIndex; i < cutPoint.firstKeptEntryIndex; i++) {\n      const msg = getMessageFromEntryForCompaction(compactableEntries[i]);\n      if (msg)\n        turnPrefixMessages.push(msg);\n    }\n  }\n  const retainedTail = [];\n  for (let i = cutPoint.firstKeptEntryIndex; i < boundaryEnd; i++) {\n    const msg = getMessageFromEntryForCompaction(compactableEntries[i]);\n    if (msg)\n      retainedTail.push(msg);\n  }\n  const fileOps = extractFileOperations(messagesToSummarize, pathEntries, prevCompactionIndex);\n  if (cutPoint.isSplitTurn) {\n    for (const msg of turnPrefixMessages) {\n      extractFileOpsFromMessage(msg, fileOps);\n    }\n  }\n  return ok({\n    messagesToSummarize,\n    turnPrefixMessages,\n    retainedTail,\n    isSplitTurn: cutPoint.isSplitTurn,\n    tokensBefore,\n    previousSummary,\n    fileOps,\n    settings\n  });\n}\nvar TURN_PREFIX_SUMMARIZATION_PROMPT = `This is the PREFIX of a turn that was too large to keep. The SUFFIX (recent work) is retained.\n\nSummarize the prefix to provide context for the retained suffix:\n\n## Original Request\n[What did the user ask for in this turn?]\n\n## Early Progress\n- [Key decisions and work done in the prefix]\n\n## Context for Suffix\n- [Information needed to understand the retained recent work]\n\nBe concise. Focus on what's needed to understand the kept suffix.`;\nasync function compact(preparation, models, model, customInstructions, signal, thinkingLevel, retry, callbacks) {\n  const { messagesToSummarize, turnPrefixMessages, retainedTail, isSplitTurn, tokensBefore, previousSummary, fileOps, settings } = preparation;\n  let summary;\n  let summaryUsage;\n  if (isSplitTurn && turnPrefixMessages.length > 0) {\n    let historyText = \"No prior history.\";\n    let historyUsage;\n    if (messagesToSummarize.length > 0) {\n      const historyResult = await generateSummaryWithUsage(messagesToSummarize, models, model, settings.reserveTokens, signal, customInstructions, previousSummary, thinkingLevel, retry, callbacks);\n      if (!historyResult.ok)\n        return err(historyResult.error);\n      historyText = historyResult.value.text;\n      historyUsage = historyResult.value.usage;\n    }\n    const turnPrefixResult = await generateTurnPrefixSummary(turnPrefixMessages, models, model, settings.reserveTokens, signal, thinkingLevel, retry, callbacks);\n    if (!turnPrefixResult.ok)\n      return err(turnPrefixResult.error);\n    summary = `${historyText}\n\n---\n\n**Turn Context (split turn):**\n\n${turnPrefixResult.value.text}`;\n    summaryUsage = historyUsage ? combineUsage(historyUsage, turnPrefixResult.value.usage) : turnPrefixResult.value.usage;\n  } else {\n    const summaryResult = await generateSummaryWithUsage(messagesToSummarize, models, model, settings.reserveTokens, signal, customInstructions, previousSummary, thinkingLevel, retry, callbacks);\n    if (!summaryResult.ok)\n      return err(summaryResult.error);\n    summary = summaryResult.value.text;\n    summaryUsage = summaryResult.value.usage;\n  }\n  const { readFiles, modifiedFiles } = computeFileLists(fileOps);\n  summary += formatFileOperations(readFiles, modifiedFiles);\n  return ok({\n    summary,\n    tokensBefore,\n    usage: summaryUsage,\n    retainedTail,\n    details: { readFiles, modifiedFiles }\n  });\n}\nasync function generateTurnPrefixSummary(messages, models, model, reserveTokens, signal, thinkingLevel, retry, callbacks) {\n  const maxTokens = Math.min(Math.floor(0.5 * reserveTokens), model.maxTokens > 0 ? model.maxTokens : Number.POSITIVE_INFINITY);\n  const llmMessages = convertToLlm2(messages);\n  const conversationText = serializeConversation(llmMessages);\n  const promptText = `<conversation>\n${conversationText}\n</conversation>\n\n${TURN_PREFIX_SUMMARIZATION_PROMPT}`;\n  const summarizationMessages = [\n    {\n      role: \"user\",\n      content: [{ type: \"text\", text: promptText }],\n      timestamp: Date.now()\n    }\n  ];\n  const completionOptions = model.reasoning && thinkingLevel && thinkingLevel !== \"off\" ? { maxTokens, signal, reasoning: thinkingLevel } : { maxTokens, signal };\n  const response = await completeSimpleWithRetries(models, model, { systemPrompt: SUMMARIZATION_SYSTEM_PROMPT, messages: summarizationMessages }, completionOptions, retry, callbacks);\n  if (response.stopReason === \"aborted\") {\n    return err(new CompactionError(\"aborted\", response.errorMessage || \"Turn prefix summarization aborted\"));\n  }\n  if (response.stopReason === \"error\") {\n    return err(new CompactionError(\"summarization_failed\", `Turn prefix summarization failed: ${response.errorMessage || \"Unknown error\"}`));\n  }\n  return ok({\n    text: contentText2(response.content),\n    usage: response.usage\n  });\n}\n\n// node_modules/.pnpm/@earendil-works+pi-agent-core@0.84.4_ws@8.21.3/node_modules/@earendil-works/pi-agent-core/dist/harness/compaction/branch-summarization.js\nasync function collectEntriesForBranchSummary(session, oldLeafId, targetId) {\n  if (!oldLeafId) {\n    return { entries: [], commonAncestorId: null };\n  }\n  const oldPath = new Set((await session.findEntriesOnBranch({ start: oldLeafId })).map((entry) => entry.id));\n  const targetPath = await session.findEntriesOnBranch({ start: targetId });\n  let commonAncestorId = null;\n  for (const entry of targetPath) {\n    if (oldPath.has(entry.id)) {\n      commonAncestorId = entry.id;\n      break;\n    }\n  }\n  const entries = [];\n  let current = oldLeafId;\n  while (current && current !== commonAncestorId) {\n    const entry = await session.getEntry(current);\n    if (!entry)\n      throw new SessionError(\"invalid_entry\", `Entry ${current} not found`);\n    entries.push(entry);\n    current = entry.parentId;\n  }\n  entries.reverse();\n  return { entries, commonAncestorId };\n}\nfunction getMessageFromEntry2(entry) {\n  switch (entry.type) {\n    case \"message\":\n      if (entry.message.role === \"toolResult\")\n        return void 0;\n      return entry.message;\n    case \"branch_summary\":\n      return createBranchSummaryMessage2(entry.summary, entry.fromId, entry.timestamp);\n    case \"compaction\":\n      return createCompactionSummaryMessage2(entry.summary, entry.tokensBefore, entry.timestamp);\n    case \"thinking_level_change\":\n    case \"model_change\":\n    case \"active_tools_change\":\n    case \"custom\":\n      return void 0;\n  }\n}\nfunction prepareBranchEntries(entries, tokenBudget = 0) {\n  const messages = [];\n  const fileOps = createFileOps();\n  let totalTokens = 0;\n  for (const entry of entries) {\n    if (entry.type === \"branch_summary\" && entry.details) {\n      const details = entry.details;\n      if (Array.isArray(details.readFiles)) {\n        for (const f of details.readFiles)\n          fileOps.read.add(f);\n      }\n      if (Array.isArray(details.modifiedFiles)) {\n        for (const f of details.modifiedFiles) {\n          fileOps.edited.add(f);\n        }\n      }\n    }\n  }\n  for (let i = entries.length - 1; i >= 0; i--) {\n    const entry = entries[i];\n    const message = getMessageFromEntry2(entry);\n    if (!message)\n      continue;\n    extractFileOpsFromMessage(message, fileOps);\n    const tokens = estimateTokens2(message);\n    if (tokenBudget > 0 && totalTokens + tokens > tokenBudget) {\n      if (entry.type === \"compaction\" || entry.type === \"branch_summary\") {\n        if (totalTokens < tokenBudget * 0.9) {\n          messages.unshift(message);\n          totalTokens += tokens;\n        }\n      }\n      break;\n    }\n    messages.unshift(message);\n    totalTokens += tokens;\n  }\n  return { messages, fileOps, totalTokens };\n}\nvar BRANCH_SUMMARY_PREAMBLE = `The user explored a different conversation branch before returning here.\nSummary of that exploration:\n\n`;\nvar BRANCH_SUMMARY_PROMPT = `Create a structured summary of this conversation branch for context when returning later.\n\nUse this EXACT format:\n\n## Goal\n[What was the user trying to accomplish in this branch?]\n\n## Constraints & Preferences\n- [Any constraints, preferences, or requirements mentioned]\n- [Or \"(none)\" if none were mentioned]\n\n## Progress\n### Done\n- [x] [Completed tasks/changes]\n\n### In Progress\n- [ ] [Work that was started but not finished]\n\n### Blocked\n- [Issues preventing progress, if any]\n\n## Key Decisions\n- **[Decision]**: [Brief rationale]\n\n## Next Steps\n1. [What should happen next to continue this work]\n\nKeep each section concise. Preserve exact file paths, function names, and error messages.`;\nasync function generateBranchSummary(entries, options) {\n  const { models, model, signal, customInstructions, replaceInstructions, reserveTokens = 16384, retry, callbacks } = options;\n  const contextWindow = model.contextWindow || 128e3;\n  const tokenBudget = contextWindow - reserveTokens;\n  const { messages, fileOps } = prepareBranchEntries(entries, tokenBudget);\n  if (messages.length === 0) {\n    return ok({ summary: \"No content to summarize\", readFiles: [], modifiedFiles: [] });\n  }\n  const llmMessages = convertToLlm2(messages);\n  const conversationText = serializeConversation(llmMessages);\n  let instructions;\n  if (replaceInstructions && customInstructions) {\n    instructions = customInstructions;\n  } else if (customInstructions) {\n    instructions = `${BRANCH_SUMMARY_PROMPT}\n\nAdditional focus: ${customInstructions}`;\n  } else {\n    instructions = BRANCH_SUMMARY_PROMPT;\n  }\n  const promptText = `<conversation>\n${conversationText}\n</conversation>\n\n${instructions}`;\n  const summarizationMessages = [\n    {\n      role: \"user\",\n      content: [{ type: \"text\", text: promptText }],\n      timestamp: Date.now()\n    }\n  ];\n  const response = await completeSimpleWithRetries(models, model, { systemPrompt: SUMMARIZATION_SYSTEM_PROMPT, messages: summarizationMessages }, { signal, maxTokens: 2048 }, retry, callbacks);\n  if (response.stopReason === \"aborted\") {\n    return err(new BranchSummaryError(\"aborted\", response.errorMessage || \"Branch summary aborted\"));\n  }\n  if (response.stopReason === \"error\") {\n    return err(new BranchSummaryError(\"summarization_failed\", `Branch summary failed: ${response.errorMessage || \"Unknown error\"}`));\n  }\n  let summary = contentText2(response.content);\n  summary = BRANCH_SUMMARY_PREAMBLE + summary;\n  const { readFiles, modifiedFiles } = computeFileLists(fileOps);\n  summary += formatFileOperations(readFiles, modifiedFiles);\n  return ok({\n    summary: summary || \"No summary generated\",\n    usage: response.usage,\n    readFiles,\n    modifiedFiles\n  });\n}\n\n// node_modules/.pnpm/@earendil-works+pi-agent-core@0.84.4_ws@8.21.3/node_modules/@earendil-works/pi-agent-core/dist/harness/prompt-templates.js\nimport { parse } from \"yaml\";\nasync function loadPromptTemplates(env, paths) {\n  const promptTemplates = [];\n  const diagnostics = [];\n  for (const path12 of Array.isArray(paths) ? paths : [paths]) {\n    const infoResult = await env.fileInfo(path12);\n    if (!infoResult.ok) {\n      if (infoResult.error.code !== \"not_found\") {\n        diagnostics.push({\n          type: \"warning\",\n          code: \"file_info_failed\",\n          message: infoResult.error.message,\n          path: path12\n        });\n      }\n      continue;\n    }\n    const info = infoResult.value;\n    const kind = await resolveKind(env, info, diagnostics);\n    if (kind === \"directory\") {\n      const result = await loadTemplatesFromDir(env, info.path);\n      promptTemplates.push(...result.promptTemplates);\n      diagnostics.push(...result.diagnostics);\n    } else if (kind === \"file\" && info.name.endsWith(\".md\")) {\n      const result = await loadTemplateFromFile(env, info.path, info.name);\n      if (result.promptTemplate)\n        promptTemplates.push(result.promptTemplate);\n      diagnostics.push(...result.diagnostics);\n    }\n  }\n  return { promptTemplates, diagnostics };\n}\nasync function loadSourcedPromptTemplates(env, inputs, mapPromptTemplate) {\n  const promptTemplates = [];\n  const diagnostics = [];\n  for (const input of inputs) {\n    const result = await loadPromptTemplates(env, input.path);\n    for (const promptTemplate of result.promptTemplates) {\n      promptTemplates.push({\n        promptTemplate: mapPromptTemplate ? mapPromptTemplate(promptTemplate, input.source) : promptTemplate,\n        source: input.source\n      });\n    }\n    for (const diagnostic of result.diagnostics)\n      diagnostics.push({ ...diagnostic, source: input.source });\n  }\n  return { promptTemplates, diagnostics };\n}\nasync function loadTemplatesFromDir(env, dir) {\n  const promptTemplates = [];\n  const diagnostics = [];\n  const entriesResult = await env.listDir(dir);\n  if (!entriesResult.ok) {\n    diagnostics.push({\n      type: \"warning\",\n      code: \"list_failed\",\n      message: entriesResult.error.message,\n      path: dir\n    });\n    return { promptTemplates, diagnostics };\n  }\n  const entries = entriesResult.value;\n  for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {\n    const kind = await resolveKind(env, entry, diagnostics);\n    if (kind !== \"file\" || !entry.name.endsWith(\".md\"))\n      continue;\n    const result = await loadTemplateFromFile(env, entry.path, entry.name);\n    if (result.promptTemplate)\n      promptTemplates.push(result.promptTemplate);\n    diagnostics.push(...result.diagnostics);\n  }\n  return { promptTemplates, diagnostics };\n}\nasync function loadTemplateFromFile(env, filePath, fileName) {\n  const diagnostics = [];\n  const rawContent = await env.readTextFile(filePath);\n  if (!rawContent.ok) {\n    diagnostics.push({\n      type: \"warning\",\n      code: \"read_failed\",\n      message: rawContent.error.message,\n      path: filePath\n    });\n    return { promptTemplate: null, diagnostics };\n  }\n  const parsed = parseFrontmatter(rawContent.value);\n  if (!parsed.ok) {\n    diagnostics.push({\n      type: \"warning\",\n      code: \"parse_failed\",\n      message: parsed.error.message,\n      path: filePath\n    });\n    return { promptTemplate: null, diagnostics };\n  }\n  const { frontmatter, body } = parsed.value;\n  const firstLine = body.split(\"\\n\").find((line) => line.trim());\n  let description = typeof frontmatter.description === \"string\" ? frontmatter.description : \"\";\n  if (!description && firstLine) {\n    description = firstLine.slice(0, 60);\n    if (firstLine.length > 60)\n      description += \"...\";\n  }\n  return {\n    promptTemplate: {\n      name: fileName.replace(/\\.md$/i, \"\"),\n      description,\n      content: body\n    },\n    diagnostics\n  };\n}\nasync function resolveKind(env, info, diagnostics) {\n  if (info.kind === \"file\" || info.kind === \"directory\")\n    return info.kind;\n  const canonicalPath = await env.canonicalPath(info.path);\n  if (!canonicalPath.ok) {\n    if (canonicalPath.error.code !== \"not_found\") {\n      diagnostics.push({\n        type: \"warning\",\n        code: \"file_info_failed\",\n        message: canonicalPath.error.message,\n        path: info.path\n      });\n    }\n    return void 0;\n  }\n  const target = await env.fileInfo(canonicalPath.value);\n  if (!target.ok) {\n    if (target.error.code !== \"not_found\") {\n      diagnostics.push({\n        type: \"warning\",\n        code: \"file_info_failed\",\n        message: target.error.message,\n        path: info.path\n      });\n    }\n    return void 0;\n  }\n  return target.value.kind === \"file\" || target.value.kind === \"directory\" ? target.value.kind : void 0;\n}\nfunction parseFrontmatter(content) {\n  try {\n    const normalized = content.replace(/\\r\\n/g, \"\\n\").replace(/\\r/g, \"\\n\");\n    if (!normalized.startsWith(\"---\"))\n      return { ok: true, value: { frontmatter: {}, body: normalized } };\n    const endIndex = normalized.indexOf(\"\\n---\", 3);\n    if (endIndex === -1)\n      return { ok: true, value: { frontmatter: {}, body: normalized } };\n    const yamlString = normalized.slice(4, endIndex);\n    const body = normalized.slice(endIndex + 4).trim();\n    return { ok: true, value: { frontmatter: parse(yamlString) ?? {}, body } };\n  } catch (error) {\n    return { ok: false, error: toError(error) };\n  }\n}\nfunction parseCommandArgs(argsString) {\n  const args = [];\n  let current = \"\";\n  let inQuote = null;\n  for (let i = 0; i < argsString.length; i++) {\n    const char = argsString[i];\n    if (inQuote) {\n      if (char === inQuote)\n        inQuote = null;\n      else\n        current += char;\n    } else if (char === '\"' || char === \"'\") {\n      inQuote = char;\n    } else if (char === \" \" || char === \"\t\") {\n      if (current) {\n        args.push(current);\n        current = \"\";\n      }\n    } else {\n      current += char;\n    }\n  }\n  if (current)\n    args.push(current);\n  return args;\n}\nfunction substituteArgs(content, args) {\n  let result = content;\n  result = result.replace(/\\$(\\d+)/g, (_, num) => args[parseInt(num, 10) - 1] ?? \"\");\n  result = result.replace(/\\$\\{@:(\\d+)(?::(\\d+))?\\}/g, (_, startStr, lengthStr) => {\n    let start = parseInt(startStr, 10) - 1;\n    if (start < 0)\n      start = 0;\n    if (lengthStr)\n      return args.slice(start, start + parseInt(lengthStr, 10)).join(\" \");\n    return args.slice(start).join(\" \");\n  });\n  const allArgs = args.join(\" \");\n  result = result.replace(/\\$ARGUMENTS/g, allArgs);\n  result = result.replace(/\\$@/g, allArgs);\n  return result;\n}\nfunction formatPromptTemplateInvocation(template, args = []) {\n  return substituteArgs(template.content, args);\n}\n\n// node_modules/.pnpm/@earendil-works+pi-agent-core@0.84.4_ws@8.21.3/node_modules/@earendil-works/pi-agent-core/dist/harness/skills.js\nimport ignore2 from \"ignore\";\nimport { parse as parse2 } from \"yaml\";\nvar MAX_NAME_LENGTH = 64;\nvar MAX_DESCRIPTION_LENGTH = 1024;\nvar IGNORE_FILE_NAMES2 = [\".gitignore\", \".ignore\", \".fdignore\"];\nfunction formatSkillInvocation(skill, additionalInstructions) {\n  const skillBlock = `<skill name=\"${skill.name}\" location=\"${skill.filePath}\">\nReferences are relative to ${dirnameEnvPath(skill.filePath)}.\n\n${skill.content}\n</skill>`;\n  return additionalInstructions ? `${skillBlock}\n\n${additionalInstructions}` : skillBlock;\n}\nasync function loadSkills(env, dirs) {\n  const skills = [];\n  const diagnostics = [];\n  for (const dir of Array.isArray(dirs) ? dirs : [dirs]) {\n    const rootInfoResult = await env.fileInfo(dir);\n    if (!rootInfoResult.ok) {\n      if (rootInfoResult.error.code !== \"not_found\") {\n        diagnostics.push({\n          type: \"warning\",\n          code: \"file_info_failed\",\n          message: rootInfoResult.error.message,\n          path: dir\n        });\n      }\n      continue;\n    }\n    const rootInfo = rootInfoResult.value;\n    if (await resolveKind2(env, rootInfo, diagnostics) !== \"directory\")\n      continue;\n    const result = await loadSkillsFromDirInternal(env, rootInfo.path, true, ignore2(), rootInfo.path);\n    skills.push(...result.skills);\n    diagnostics.push(...result.diagnostics);\n  }\n  return { skills, diagnostics };\n}\nasync function loadSourcedSkills(env, inputs, mapSkill) {\n  const skills = [];\n  const diagnostics = [];\n  for (const input of inputs) {\n    const result = await loadSkills(env, input.path);\n    for (const skill of result.skills) {\n      skills.push({ skill: mapSkill ? mapSkill(skill, input.source) : skill, source: input.source });\n    }\n    for (const diagnostic of result.diagnostics)\n      diagnostics.push({ ...diagnostic, source: input.source });\n  }\n  return { skills, diagnostics };\n}\nasync function loadSkillsFromDirInternal(env, dir, includeRootFiles, ignoreMatcher, rootDir) {\n  const skills = [];\n  const diagnostics = [];\n  const dirInfoResult = await env.fileInfo(dir);\n  if (!dirInfoResult.ok) {\n    if (dirInfoResult.error.code !== \"not_found\") {\n      diagnostics.push({\n        type: \"warning\",\n        code: \"file_info_failed\",\n        message: dirInfoResult.error.message,\n        path: dir\n      });\n    }\n    return { skills, diagnostics };\n  }\n  const dirInfo = dirInfoResult.value;\n  if (await resolveKind2(env, dirInfo, diagnostics) !== \"directory\")\n    return { skills, diagnostics };\n  await addIgnoreRules2(env, ignoreMatcher, dir, rootDir, diagnostics);\n  const entriesResult = await env.listDir(dir);\n  if (!entriesResult.ok) {\n    diagnostics.push({ type: \"warning\", code: \"list_failed\", message: entriesResult.error.message, path: dir });\n    return { skills, diagnostics };\n  }\n  const entries = entriesResult.value;\n  for (const entry of entries) {\n    if (entry.name !== \"SKILL.md\")\n      continue;\n    const fullPath = entry.path;\n    const kind = await resolveKind2(env, entry, diagnostics);\n    if (kind !== \"file\")\n      continue;\n    const relPath = relativeEnvPath(rootDir, fullPath);\n    if (ignoreMatcher.ignores(relPath))\n      continue;\n    const result = await loadSkillFromFile(env, fullPath, dirInfo.name);\n    if (result.skill)\n      skills.push(result.skill);\n    diagnostics.push(...result.diagnostics);\n    return { skills, diagnostics };\n  }\n  for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {\n    if (entry.name.startsWith(\".\") || entry.name === \"node_modules\")\n      continue;\n    const fullPath = entry.path;\n    const kind = await resolveKind2(env, entry, diagnostics);\n    if (!kind)\n      continue;\n    const relPath = relativeEnvPath(rootDir, fullPath);\n    const ignorePath = kind === \"directory\" ? `${relPath}/` : relPath;\n    if (ignoreMatcher.ignores(ignorePath))\n      continue;\n    if (kind === \"directory\") {\n      const result2 = await loadSkillsFromDirInternal(env, fullPath, false, ignoreMatcher, rootDir);\n      skills.push(...result2.skills);\n      diagnostics.push(...result2.diagnostics);\n      continue;\n    }\n    if (kind !== \"file\" || !includeRootFiles || !entry.name.endsWith(\".md\"))\n      continue;\n    const result = await loadSkillFromFile(env, fullPath, dirInfo.name);\n    if (result.skill)\n      skills.push(result.skill);\n    diagnostics.push(...result.diagnostics);\n  }\n  return { skills, diagnostics };\n}\nasync function addIgnoreRules2(env, ig, dir, rootDir, diagnostics) {\n  const relativeDir = relativeEnvPath(rootDir, dir);\n  const prefix = relativeDir ? `${relativeDir}/` : \"\";\n  for (const filename of IGNORE_FILE_NAMES2) {\n    const ignorePathResult = await env.joinPath([dir, filename]);\n    if (!ignorePathResult.ok) {\n      diagnostics.push({\n        type: \"warning\",\n        code: \"file_info_failed\",\n        message: ignorePathResult.error.message,\n        path: dir\n      });\n      continue;\n    }\n    const ignorePath = ignorePathResult.value;\n    const info = await env.fileInfo(ignorePath);\n    if (!info.ok) {\n      if (info.error.code !== \"not_found\") {\n        diagnostics.push({\n          type: \"warning\",\n          code: \"file_info_failed\",\n          message: info.error.message,\n          path: ignorePath\n        });\n      }\n      continue;\n    }\n    if (info.value.kind !== \"file\")\n      continue;\n    const content = await env.readTextFile(ignorePath);\n    if (!content.ok) {\n      diagnostics.push({ type: \"warning\", code: \"read_failed\", message: content.error.message, path: ignorePath });\n      continue;\n    }\n    const patterns = content.value.split(/\\r?\\n/).map((line) => prefixIgnorePattern2(line, prefix)).filter((line) => Boolean(line));\n    if (patterns.length > 0)\n      ig.add(patterns);\n  }\n}\nfunction prefixIgnorePattern2(line, prefix) {\n  const trimmed = line.trim();\n  if (!trimmed)\n    return null;\n  if (trimmed.startsWith(\"#\") && !trimmed.startsWith(\"\\\\#\"))\n    return null;\n  let pattern = line;\n  let negated = false;\n  if (pattern.startsWith(\"!\")) {\n    negated = true;\n    pattern = pattern.slice(1);\n  } else if (pattern.startsWith(\"\\\\!\")) {\n    pattern = pattern.slice(1);\n  }\n  if (pattern.startsWith(\"/\"))\n    pattern = pattern.slice(1);\n  const prefixed = prefix ? `${prefix}${pattern}` : pattern;\n  return negated ? `!${prefixed}` : prefixed;\n}\nasync function loadSkillFromFile(env, filePath, parentDirName) {\n  const diagnostics = [];\n  const isDeclaredSkill = filePath.replace(/[\\\\/]+$/, \"\").split(/[\\\\/]/).pop() === \"SKILL.md\";\n  const rawContent = await env.readTextFile(filePath);\n  if (!rawContent.ok) {\n    diagnostics.push({ type: \"warning\", code: \"read_failed\", message: rawContent.error.message, path: filePath });\n    return { skill: null, diagnostics };\n  }\n  const parsed = parseFrontmatter2(rawContent.value);\n  if (!parsed.ok) {\n    if (isDeclaredSkill) {\n      diagnostics.push({ type: \"warning\", code: \"parse_failed\", message: parsed.error.message, path: filePath });\n    }\n    return { skill: null, diagnostics };\n  }\n  const { frontmatter, body } = parsed.value;\n  const description = typeof frontmatter.description === \"string\" ? frontmatter.description : void 0;\n  if (!isDeclaredSkill && (!description || description.trim() === \"\")) {\n    return { skill: null, diagnostics };\n  }\n  for (const error of validateDescription(description)) {\n    diagnostics.push({ type: \"warning\", code: \"invalid_metadata\", message: error, path: filePath });\n  }\n  const frontmatterName = typeof frontmatter.name === \"string\" ? frontmatter.name : void 0;\n  const name = frontmatterName || parentDirName;\n  for (const error of validateName(name, parentDirName)) {\n    diagnostics.push({ type: \"warning\", code: \"invalid_metadata\", message: error, path: filePath });\n  }\n  if (!description || description.trim() === \"\") {\n    return { skill: null, diagnostics };\n  }\n  return {\n    skill: {\n      name,\n      description,\n      content: body,\n      filePath,\n      disableModelInvocation: frontmatter[\"disable-model-invocation\"] === true\n    },\n    diagnostics\n  };\n}\nfunction validateName(name, parentDirName) {\n  const errors = [];\n  if (name !== parentDirName)\n    errors.push(`name \"${name}\" does not match parent directory \"${parentDirName}\"`);\n  if (name.length > MAX_NAME_LENGTH)\n    errors.push(`name exceeds ${MAX_NAME_LENGTH} characters (${name.length})`);\n  if (!/^[a-z0-9-]+$/.test(name)) {\n    errors.push(\"name contains invalid characters (must be lowercase a-z, 0-9, hyphens only)\");\n  }\n  if (name.startsWith(\"-\") || name.endsWith(\"-\"))\n    errors.push(\"name must not start or end with a hyphen\");\n  if (name.includes(\"--\"))\n    errors.push(\"name must not contain consecutive hyphens\");\n  return errors;\n}\nfunction validateDescription(description) {\n  const errors = [];\n  if (!description || description.trim() === \"\") {\n    errors.push(\"description is required\");\n  } else if (description.length > MAX_DESCRIPTION_LENGTH) {\n    errors.push(`description exceeds ${MAX_DESCRIPTION_LENGTH} characters (${description.length})`);\n  }\n  return errors;\n}\nfunction parseFrontmatter2(content) {\n  try {\n    const normalized = content.replace(/\\r\\n/g, \"\\n\").replace(/\\r/g, \"\\n\");\n    if (!normalized.startsWith(\"---\"))\n      return { ok: true, value: { frontmatter: {}, body: normalized } };\n    const endIndex = normalized.indexOf(\"\\n---\", 3);\n    if (endIndex === -1)\n      return { ok: true, value: { frontmatter: {}, body: normalized } };\n    const yamlString = normalized.slice(4, endIndex);\n    const body = normalized.slice(endIndex + 4).trim();\n    return { ok: true, value: { frontmatter: parse2(yamlString) ?? {}, body } };\n  } catch (error) {\n    return { ok: false, error: toError(error) };\n  }\n}\nasync function resolveKind2(env, info, diagnostics) {\n  if (info.kind === \"file\" || info.kind === \"directory\")\n    return info.kind;\n  const canonicalPath = await env.canonicalPath(info.path);\n  if (!canonicalPath.ok) {\n    if (canonicalPath.error.code !== \"not_found\") {\n      diagnostics.push({\n        type: \"warning\",\n        code: \"file_info_failed\",\n        message: canonicalPath.error.message,\n        path: info.path\n      });\n    }\n    return void 0;\n  }\n  const target = await env.fileInfo(canonicalPath.value);\n  if (!target.ok) {\n    if (target.error.code !== \"not_found\") {\n      diagnostics.push({\n        type: \"warning\",\n        code: \"file_info_failed\",\n        message: target.error.message,\n        path: info.path\n      });\n    }\n    return void 0;\n  }\n  return target.value.kind === \"file\" || target.value.kind === \"directory\" ? target.value.kind : void 0;\n}\nfunction dirnameEnvPath(path12) {\n  const normalized = path12.replace(/[\\\\/]+$/, \"\");\n  const separatorIndex = Math.max(normalized.lastIndexOf(\"/\"), normalized.lastIndexOf(\"\\\\\"));\n  if (separatorIndex === 2 && normalized[1] === \":\")\n    return normalized.slice(0, 3);\n  return separatorIndex <= 0 ? \"/\" : normalized.slice(0, separatorIndex);\n}\nfunction relativeEnvPath(root, path12) {\n  const normalizedRoot = root.replace(/\\\\/g, \"/\").replace(/\\/+$/, \"\");\n  const normalizedPath = path12.replace(/\\\\/g, \"/\").replace(/\\/+$/, \"\");\n  if (normalizedPath === normalizedRoot)\n    return \"\";\n  return normalizedPath.startsWith(`${normalizedRoot}/`) ? normalizedPath.slice(normalizedRoot.length + 1) : normalizedPath.replace(/^\\/+/, \"\");\n}\n\n// node_modules/.pnpm/@earendil-works+pi-agent-core@0.84.4_ws@8.21.3/node_modules/@earendil-works/pi-agent-core/dist/harness/system-prompt.js\nfunction formatSkillsForSystemPrompt(skills) {\n  const visibleSkills = skills.filter((skill) => !skill.disableModelInvocation);\n  if (visibleSkills.length === 0)\n    return \"\";\n  const lines = [\n    \"The following skills provide specialized instructions for specific tasks.\",\n    \"Read the full skill file when the task matches its description.\",\n    \"When a skill file references a relative path, resolve it against the skill directory (parent of SKILL.md / dirname of the path) and use that absolute path in tool commands.\",\n    \"\",\n    \"<available_skills>\"\n  ];\n  for (const skill of visibleSkills) {\n    lines.push(\"  <skill>\");\n    lines.push(`    <name>${escapeXml(skill.name)}</name>`);\n    lines.push(`    <description>${escapeXml(skill.description)}</description>`);\n    lines.push(`    <location>${escapeXml(skill.filePath)}</location>`);\n    lines.push(\"  </skill>\");\n  }\n  lines.push(\"</available_skills>\");\n  return lines.join(\"\\n\");\n}\nfunction escapeXml(value) {\n  return value.replace(/&/g, \"&amp;\").replace(/</g, \"&lt;\").replace(/>/g, \"&gt;\").replace(/\"/g, \"&quot;\").replace(/'/g, \"&apos;\");\n}\n\n// node_modules/.pnpm/@earendil-works+pi-agent-core@0.84.4_ws@8.21.3/node_modules/@earendil-works/pi-agent-core/dist/harness/telemetry.js\nvar AI_TELEMETRY_SCHEMA = {\n  version: 1,\n  spans: {\n    \"pi.ai.request\": {\n      description: \"One logical request to an AI provider\",\n      parents: { kind: \"any\" },\n      startAttributes: {\n        \"pi.ai.operation\": {\n          type: \"string\",\n          required: true,\n          values: [\"stream\", \"fetch_deferred\", \"cancel_deferred\", \"generate_images\"],\n          description: \"Logical provider operation\"\n        },\n        \"pi.ai.provider\": {\n          type: \"string\",\n          required: true,\n          description: \"Selected provider id\"\n        },\n        \"pi.ai.model\": {\n          type: \"string\",\n          required: true,\n          description: \"Requested model id\"\n        },\n        \"pi.ai.api\": {\n          type: \"string\",\n          required: true,\n          description: \"Provider API id\"\n        },\n        \"pi.ai.streaming\": {\n          type: \"boolean\",\n          required: true,\n          description: \"Whether this operation returns a stream\"\n        },\n        \"pi.ai.deferred\": {\n          type: \"boolean\",\n          required: false,\n          description: \"Whether the operation requests or participates in deferred execution\"\n        }\n      },\n      endAttributes: {\n        \"pi.ai.response.model\": { type: \"string\", description: \"Concrete response model\" },\n        \"pi.ai.response.id\": {\n          type: \"string\",\n          cardinality: \"high\",\n          description: \"Provider response id\"\n        },\n        \"pi.ai.response.stop_reason\": {\n          type: \"string\",\n          values: [\"stop\", \"length\", \"tool_use\", \"error\", \"aborted\", \"deferred\"],\n          description: \"Normalized terminal response reason\"\n        },\n        \"pi.ai.http.status_code\": { type: \"number\", description: \"Final HTTP status\" },\n        \"pi.ai.usage.input_tokens\": { type: \"number\", description: \"Reported input tokens\" },\n        \"pi.ai.usage.output_tokens\": { type: \"number\", description: \"Reported output tokens\" },\n        \"pi.ai.usage.cache_read_tokens\": { type: \"number\", description: \"Reported cache-read tokens\" },\n        \"pi.ai.usage.cache_write_tokens\": {\n          type: \"number\",\n          description: \"Reported cache-write tokens\"\n        },\n        \"pi.ai.usage.reasoning_tokens\": { type: \"number\", description: \"Reported reasoning tokens\" },\n        \"pi.ai.usage.total_tokens\": { type: \"number\", description: \"Reported total tokens\" },\n        \"pi.ai.usage.cost\": { type: \"number\", description: \"Reported total cost\" },\n        \"pi.ai.stream.chunk_count\": { type: \"number\", description: \"Streamed update chunk count\" },\n        \"pi.ai.stream.time_to_first_chunk_ms\": {\n          type: \"number\",\n          description: \"Elapsed milliseconds to first update chunk\"\n        },\n        \"pi.ai.error.type\": {\n          type: \"string\",\n          cardinality: \"low\",\n          description: \"Provider or transport error class\"\n        }\n      },\n      status: { default: \"ok\", errorWhen: \"The operation throws or returns an error result\" }\n    }\n  }\n};\nfunction startAiSpan(telemetryContext, name, attributes, callback) {\n  return telemetryContext.startSpan({ name, attributes }, (span) => callback(span));\n}\nvar HOOK_NAMES = [\n  \"before_run\",\n  \"before_resume\",\n  \"before_run_end\",\n  \"transform_context\",\n  \"before_request\",\n  \"before_payload\",\n  \"after_response\",\n  \"before_tool\",\n  \"after_tool\",\n  \"before_compaction\",\n  \"before_navigation\"\n];\nvar EVENT_TYPES = [\n  \"run_start\",\n  \"run_resume\",\n  \"run_suspend\",\n  \"run_abort\",\n  \"run_end\",\n  \"fault\",\n  \"handler_error\",\n  \"turn_start\",\n  \"turn_end\",\n  \"retry_scheduled\",\n  \"retry_start\",\n  \"retry_end\",\n  \"message_start\",\n  \"message_update\",\n  \"message_end\",\n  \"tool_start\",\n  \"tool_update\",\n  \"tool_end\",\n  \"entry_added\",\n  \"write_pending\",\n  \"queue_update\",\n  \"fact_update\",\n  \"config_update\",\n  \"compaction_start\",\n  \"compaction_end\",\n  \"navigation_start\",\n  \"navigation_end\",\n  \"lane_created\",\n  \"usage\"\n];\nvar operationStartAttributes = {\n  \"pi.session.id\": {\n    type: \"string\",\n    required: true,\n    cardinality: \"high\",\n    description: \"Session id\"\n  },\n  \"pi.lane.name\": {\n    type: \"string\",\n    required: true,\n    cardinality: \"high\",\n    description: \"Lane name\"\n  },\n  \"pi.operation.id\": {\n    type: \"string\",\n    required: true,\n    cardinality: \"high\",\n    description: \"Durable operation id\"\n  },\n  \"pi.operation.recovery\": {\n    type: \"boolean\",\n    required: true,\n    description: \"Whether this invocation resumes durable work\"\n  }\n};\nvar operationErrorAttributes = {\n  \"pi.error.code\": {\n    type: \"string\",\n    cardinality: \"low\",\n    description: \"Stable operation error code\"\n  },\n  \"pi.error.type\": {\n    type: \"string\",\n    cardinality: \"low\",\n    description: \"Low-cardinality operation error class\"\n  }\n};\nvar HARNESS_TELEMETRY_SCHEMA = {\n  version: 1,\n  spans: {\n    \"pi.harness.run\": {\n      description: \"One admitted in-process run invocation\",\n      parents: { kind: \"root_or_external\" },\n      startAttributes: {\n        ...operationStartAttributes,\n        \"pi.operation.kind\": {\n          type: \"string\",\n          required: true,\n          values: [\"run\"],\n          description: \"Run operation kind\"\n        }\n      },\n      endAttributes: {\n        \"pi.operation.outcome\": {\n          type: \"string\",\n          values: [\"completed\", \"aborted\", \"failed\", \"suspended\"],\n          description: \"Run invocation outcome\"\n        },\n        ...operationErrorAttributes\n      },\n      status: { default: \"ok\", errorWhen: \"The run fails or throws\" }\n    },\n    \"pi.harness.compaction\": {\n      description: \"One admitted in-process manual compaction invocation\",\n      parents: { kind: \"root_or_external\" },\n      startAttributes: {\n        ...operationStartAttributes,\n        \"pi.operation.kind\": {\n          type: \"string\",\n          required: true,\n          values: [\"compaction\"],\n          description: \"Compaction operation kind\"\n        }\n      },\n      endAttributes: {\n        \"pi.operation.outcome\": {\n          type: \"string\",\n          values: [\"completed\", \"declined\", \"aborted\", \"failed\"],\n          description: \"Compaction invocation outcome\"\n        },\n        ...operationErrorAttributes\n      },\n      status: { default: \"ok\", errorWhen: \"The compaction fails or throws\" }\n    },\n    \"pi.harness.navigation\": {\n      description: \"One admitted in-process navigation invocation\",\n      parents: { kind: \"root_or_external\" },\n      startAttributes: {\n        ...operationStartAttributes,\n        \"pi.operation.kind\": {\n          type: \"string\",\n          required: true,\n          values: [\"navigation\"],\n          description: \"Navigation operation kind\"\n        }\n      },\n      endAttributes: {\n        \"pi.operation.outcome\": {\n          type: \"string\",\n          values: [\"completed\", \"declined\", \"aborted\", \"failed\"],\n          description: \"Navigation invocation outcome\"\n        },\n        ...operationErrorAttributes\n      },\n      status: { default: \"ok\", errorWhen: \"The navigation fails or throws\" }\n    },\n    \"pi.harness.checkpoint\": {\n      description: \"One run checkpoint\",\n      parents: { kind: \"spans\", spans: [\"pi.harness.run\"] },\n      startAttributes: {\n        \"pi.lane.name\": {\n          type: \"string\",\n          required: true,\n          cardinality: \"high\",\n          description: \"Lane name\"\n        },\n        \"pi.operation.id\": {\n          type: \"string\",\n          required: true,\n          cardinality: \"high\",\n          description: \"Durable operation id\"\n        },\n        \"pi.checkpoint.kind\": {\n          type: \"string\",\n          required: true,\n          values: [\"normal\", \"failure_drain\", \"abort_reconcile\"],\n          description: \"Checkpoint purpose\"\n        }\n      },\n      endAttributes: {},\n      status: { default: \"ok\", errorWhen: \"Checkpoint work throws\" }\n    },\n    \"pi.harness.turn\": {\n      description: \"One assistant response and its tool batch\",\n      parents: { kind: \"spans\", spans: [\"pi.harness.run\"] },\n      startAttributes: {\n        \"pi.lane.name\": {\n          type: \"string\",\n          required: true,\n          cardinality: \"high\",\n          description: \"Lane name\"\n        },\n        \"pi.operation.id\": {\n          type: \"string\",\n          required: true,\n          cardinality: \"high\",\n          description: \"Durable operation id\"\n        },\n        \"pi.turn.id\": {\n          type: \"string\",\n          required: true,\n          cardinality: \"high\",\n          description: \"Invocation-local turn id\"\n        }\n      },\n      endAttributes: {},\n      status: { default: \"ok\", errorWhen: \"Turn work throws\" }\n    },\n    \"pi.harness.step\": {\n      description: \"One durable retry attempt\",\n      parents: {\n        kind: \"spans\",\n        spans: [\"pi.harness.turn\", \"pi.harness.checkpoint\", \"pi.harness.compaction\", \"pi.harness.navigation\"]\n      },\n      startAttributes: {\n        \"pi.lane.name\": {\n          type: \"string\",\n          required: true,\n          cardinality: \"high\",\n          description: \"Lane name\"\n        },\n        \"pi.operation.id\": {\n          type: \"string\",\n          required: true,\n          cardinality: \"high\",\n          description: \"Durable operation id\"\n        },\n        \"pi.step.kind\": {\n          type: \"string\",\n          required: true,\n          values: [\"assistant\", \"compaction\", \"branch_summary\"],\n          description: \"Retryable step kind\"\n        },\n        \"pi.step.attempt\": {\n          type: \"number\",\n          required: true,\n          description: \"One-based durable attempt number\"\n        },\n        \"pi.compaction.reason\": {\n          type: \"string\",\n          required: false,\n          values: [\"manual\", \"threshold\", \"overflow\"],\n          description: \"Compaction trigger\"\n        }\n      },\n      endAttributes: {\n        \"pi.step.outcome\": {\n          type: \"string\",\n          values: [\"succeeded\", \"retry\", \"failed\", \"aborted\", \"deferred\", \"overflow\"],\n          description: \"Attempt outcome\"\n        }\n      },\n      status: { default: \"ok\", errorWhen: \"The attempt retries, fails, or throws\" }\n    },\n    \"pi.harness.tool\": {\n      description: \"One raw phase-2 tool execution\",\n      parents: { kind: \"spans\", spans: [\"pi.harness.turn\", \"pi.harness.run\"] },\n      startAttributes: {\n        \"pi.lane.name\": {\n          type: \"string\",\n          required: true,\n          cardinality: \"high\",\n          description: \"Lane name\"\n        },\n        \"pi.operation.id\": {\n          type: \"string\",\n          required: true,\n          cardinality: \"high\",\n          description: \"Durable operation id\"\n        },\n        \"pi.turn.id\": {\n          type: \"string\",\n          required: false,\n          cardinality: \"high\",\n          description: \"Invocation-local live turn id\"\n        },\n        \"pi.tool.name\": {\n          type: \"string\",\n          required: true,\n          description: \"Tool name\"\n        },\n        \"pi.tool.call_id\": {\n          type: \"string\",\n          required: true,\n          cardinality: \"high\",\n          description: \"Tool call id\"\n        },\n        \"pi.tool.replay\": {\n          type: \"string\",\n          required: true,\n          values: [\"never\", \"safe\"],\n          description: \"Declared replay policy\"\n        },\n        \"pi.tool.recovery\": {\n          type: \"boolean\",\n          required: true,\n          description: \"Whether this is recovery execution\"\n        }\n      },\n      endAttributes: {\n        \"pi.tool.is_error\": {\n          type: \"boolean\",\n          description: \"Whether raw phase-2 execution returned an error\"\n        }\n      },\n      status: { default: \"ok\", errorWhen: \"Raw phase-2 execution returns an error\" }\n    },\n    \"pi.harness.hook\": {\n      description: \"One registered hook handler invocation\",\n      parents: { kind: \"any\" },\n      startAttributes: {\n        \"pi.lane.name\": {\n          type: \"string\",\n          required: true,\n          cardinality: \"high\",\n          description: \"Lane name\"\n        },\n        \"pi.operation.id\": {\n          type: \"string\",\n          required: false,\n          cardinality: \"high\",\n          description: \"Durable operation id when accepted\"\n        },\n        \"pi.hook.name\": {\n          type: \"string\",\n          required: true,\n          values: HOOK_NAMES,\n          description: \"Hook name\"\n        },\n        \"pi.hook.registration_id\": {\n          type: \"string\",\n          required: false,\n          description: \"Stable hook registration id\"\n        }\n      },\n      endAttributes: {\n        \"pi.hook.outcome\": {\n          type: \"string\",\n          values: [\"completed\", \"skipped\", \"blocked\", \"failed\"],\n          description: \"Handler outcome\"\n        }\n      },\n      status: { default: \"ok\", errorWhen: \"The handler throws\" }\n    },\n    \"pi.harness.sleep\": {\n      description: \"One retry delay\",\n      parents: { kind: \"spans\", spans: [\"pi.harness.step\", \"pi.harness.run\"] },\n      startAttributes: {\n        \"pi.operation.id\": {\n          type: \"string\",\n          required: true,\n          cardinality: \"high\",\n          description: \"Durable operation id\"\n        },\n        \"pi.sleep.delay_ms\": {\n          type: \"number\",\n          required: true,\n          description: \"Requested delay in milliseconds\"\n        }\n      },\n      endAttributes: {\n        \"pi.sleep.outcome\": {\n          type: \"string\",\n          values: [\"elapsed\", \"aborted\"],\n          description: \"Delay outcome\"\n        }\n      },\n      status: { default: \"ok\", errorWhen: \"Sleep work throws\" }\n    },\n    \"pi.harness.event_handler\": {\n      description: \"One passive event listener invocation\",\n      parents: { kind: \"any\" },\n      startAttributes: {\n        \"pi.event.type\": {\n          type: \"string\",\n          required: true,\n          cardinality: \"low\",\n          values: EVENT_TYPES,\n          description: \"Delivered harness event type\"\n        },\n        \"pi.lane.name\": {\n          type: \"string\",\n          required: false,\n          cardinality: \"high\",\n          description: \"Lane name for lane-scoped events\"\n        }\n      },\n      endAttributes: {},\n      status: { default: \"ok\", errorWhen: \"The listener throws\" }\n    },\n    \"pi.session.write\": {\n      description: \"One committed session mutation\",\n      parents: { kind: \"any\" },\n      startAttributes: {\n        \"pi.lane.name\": {\n          type: \"string\",\n          required: true,\n          cardinality: \"high\",\n          description: \"Lane name\"\n        },\n        \"pi.operation.id\": {\n          type: \"string\",\n          required: false,\n          cardinality: \"high\",\n          description: \"Durable operation id when accepted\"\n        },\n        \"pi.session.mutation\": {\n          type: \"string\",\n          required: true,\n          values: [\"entry\", \"record\", \"lane\", \"fact\"],\n          description: \"Session mutation kind\"\n        },\n        \"pi.session.item_type\": {\n          type: \"string\",\n          required: false,\n          description: \"Entry, record, lane, or fact subtype\"\n        }\n      },\n      endAttributes: {\n        \"pi.session.seq\": {\n          type: \"number\",\n          description: \"Committed session sequence when exposed\"\n        }\n      },\n      status: { default: \"ok\", errorWhen: \"Storage rejects the mutation\" }\n    }\n  }\n};\nvar AGENT_TELEMETRY_SCHEMAS = [AI_TELEMETRY_SCHEMA, HARNESS_TELEMETRY_SCHEMA];\nfunction startHarnessSpan(telemetryContext, name, attributes, callback) {\n  return telemetryContext.startSpan({ name, attributes }, (span) => callback(span));\n}\n\n// node_modules/.pnpm/@earendil-works+pi-agent-core@0.84.4_ws@8.21.3/node_modules/@earendil-works/pi-agent-core/dist/harness/tools/bash.js\nimport { Type as Type6 } from \"typebox\";\n\n// node_modules/.pnpm/@earendil-works+pi-agent-core@0.84.4_ws@8.21.3/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/truncate.js\nvar DEFAULT_MAX_LINES = 2e3;\nvar DEFAULT_MAX_BYTES2 = 50 * 1024;\nvar GREP_MAX_LINE_LENGTH = 500;\nvar runtimeBuffer = globalThis.Buffer;\nvar nonAsciiPattern = /[^\\x00-\\x7f]/;\nfunction utf8ByteLength(content) {\n  if (runtimeBuffer)\n    return runtimeBuffer.byteLength(content, \"utf8\");\n  const firstNonAscii = content.search(nonAsciiPattern);\n  if (firstNonAscii === -1)\n    return content.length;\n  let bytes = firstNonAscii;\n  for (let i = firstNonAscii; i < content.length; i++) {\n    const code = content.charCodeAt(i);\n    if (code <= 127) {\n      bytes += 1;\n    } else if (code <= 2047) {\n      bytes += 2;\n    } else if (code >= 55296 && code <= 56319 && i + 1 < content.length) {\n      const next = content.charCodeAt(i + 1);\n      if (next >= 56320 && next <= 57343) {\n        bytes += 4;\n        i++;\n      } else {\n        bytes += 3;\n      }\n    } else {\n      bytes += 3;\n    }\n  }\n  return bytes;\n}\nfunction splitLinesForCounting(content) {\n  if (content.length === 0)\n    return [];\n  const lines = content.split(\"\\n\");\n  if (content.endsWith(\"\\n\"))\n    lines.pop();\n  return lines;\n}\nfunction replaceUnpairedSurrogates(content) {\n  let output = \"\";\n  for (let i = 0; i < content.length; i++) {\n    const code = content.charCodeAt(i);\n    if (code >= 55296 && code <= 56319) {\n      if (i + 1 < content.length) {\n        const next = content.charCodeAt(i + 1);\n        if (next >= 56320 && next <= 57343) {\n          output += content[i] + content[i + 1];\n          i++;\n          continue;\n        }\n      }\n      output += \"\\uFFFD\";\n    } else if (code >= 56320 && code <= 57343) {\n      output += \"\\uFFFD\";\n    } else {\n      output += content[i];\n    }\n  }\n  return output;\n}\nfunction formatSize(bytes) {\n  if (bytes < 1024) {\n    return `${bytes}B`;\n  } else if (bytes < 1024 * 1024) {\n    return `${(bytes / 1024).toFixed(1)}KB`;\n  } else {\n    return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;\n  }\n}\nfunction truncateHead(content, options = {}) {\n  const maxLines = options.maxLines ?? DEFAULT_MAX_LINES;\n  const maxBytes = options.maxBytes ?? DEFAULT_MAX_BYTES2;\n  const totalBytes = utf8ByteLength(content);\n  const lines = splitLinesForCounting(content);\n  const totalLines = lines.length;\n  if (totalLines <= maxLines && totalBytes <= maxBytes) {\n    return {\n      content,\n      truncated: false,\n      truncatedBy: null,\n      totalLines,\n      totalBytes,\n      outputLines: totalLines,\n      outputBytes: totalBytes,\n      lastLinePartial: false,\n      firstLineExceedsLimit: false,\n      maxLines,\n      maxBytes\n    };\n  }\n  const firstLineBytes = utf8ByteLength(lines[0]);\n  if (firstLineBytes > maxBytes) {\n    return {\n      content: \"\",\n      truncated: true,\n      truncatedBy: \"bytes\",\n      totalLines,\n      totalBytes,\n      outputLines: 0,\n      outputBytes: 0,\n      lastLinePartial: false,\n      firstLineExceedsLimit: true,\n      maxLines,\n      maxBytes\n    };\n  }\n  const outputLinesArr = [];\n  let outputBytesCount = 0;\n  let truncatedBy = \"lines\";\n  for (let i = 0; i < lines.length && i < maxLines; i++) {\n    const line = lines[i];\n    const lineBytes = utf8ByteLength(line) + (i > 0 ? 1 : 0);\n    if (outputBytesCount + lineBytes > maxBytes) {\n      truncatedBy = \"bytes\";\n      break;\n    }\n    outputLinesArr.push(line);\n    outputBytesCount += lineBytes;\n  }\n  if (outputLinesArr.length >= maxLines && outputBytesCount <= maxBytes) {\n    truncatedBy = \"lines\";\n  }\n  const outputContent = outputLinesArr.join(\"\\n\");\n  const finalOutputBytes = utf8ByteLength(outputContent);\n  return {\n    content: outputContent,\n    truncated: true,\n    truncatedBy,\n    totalLines,\n    totalBytes,\n    outputLines: outputLinesArr.length,\n    outputBytes: finalOutputBytes,\n    lastLinePartial: false,\n    firstLineExceedsLimit: false,\n    maxLines,\n    maxBytes\n  };\n}\nfunction truncateTail(content, options = {}) {\n  const maxLines = options.maxLines ?? DEFAULT_MAX_LINES;\n  const maxBytes = options.maxBytes ?? DEFAULT_MAX_BYTES2;\n  const totalBytes = utf8ByteLength(content);\n  const lines = splitLinesForCounting(content);\n  const totalLines = lines.length;\n  if (totalLines <= maxLines && totalBytes <= maxBytes) {\n    return {\n      content,\n      truncated: false,\n      truncatedBy: null,\n      totalLines,\n      totalBytes,\n      outputLines: totalLines,\n      outputBytes: totalBytes,\n      lastLinePartial: false,\n      firstLineExceedsLimit: false,\n      maxLines,\n      maxBytes\n    };\n  }\n  const outputLinesArr = [];\n  let outputBytesCount = 0;\n  let truncatedBy = \"lines\";\n  let lastLinePartial = false;\n  for (let i = lines.length - 1; i >= 0 && outputLinesArr.length < maxLines; i--) {\n    const line = lines[i];\n    const lineBytes = utf8ByteLength(line) + (outputLinesArr.length > 0 ? 1 : 0);\n    if (outputBytesCount + lineBytes > maxBytes) {\n      truncatedBy = \"bytes\";\n      if (outputLinesArr.length === 0) {\n        const truncatedLine = truncateStringToBytesFromEnd(line, maxBytes);\n        outputLinesArr.unshift(truncatedLine);\n        outputBytesCount = utf8ByteLength(truncatedLine);\n        lastLinePartial = true;\n      }\n      break;\n    }\n    outputLinesArr.unshift(line);\n    outputBytesCount += lineBytes;\n  }\n  if (outputLinesArr.length >= maxLines && outputBytesCount <= maxBytes) {\n    truncatedBy = \"lines\";\n  }\n  const outputContent = outputLinesArr.join(\"\\n\");\n  const finalOutputBytes = utf8ByteLength(outputContent);\n  return {\n    content: outputContent,\n    truncated: true,\n    truncatedBy,\n    totalLines,\n    totalBytes,\n    outputLines: outputLinesArr.length,\n    outputBytes: finalOutputBytes,\n    lastLinePartial,\n    firstLineExceedsLimit: false,\n    maxLines,\n    maxBytes\n  };\n}\nfunction truncateStringToBytesFromEnd(str2, maxBytes) {\n  if (maxBytes <= 0)\n    return \"\";\n  let outputBytes = 0;\n  let start = str2.length;\n  let needsReplacement = false;\n  for (let i = str2.length; i > 0; ) {\n    let characterStart = i - 1;\n    const code = str2.charCodeAt(characterStart);\n    let characterBytes;\n    let unpairedSurrogate = false;\n    if (code >= 56320 && code <= 57343 && characterStart > 0) {\n      const previous = str2.charCodeAt(characterStart - 1);\n      if (previous >= 55296 && previous <= 56319) {\n        characterStart--;\n        characterBytes = 4;\n      } else {\n        characterBytes = 3;\n        unpairedSurrogate = true;\n      }\n    } else if (code >= 55296 && code <= 57343) {\n      characterBytes = 3;\n      unpairedSurrogate = true;\n    } else {\n      characterBytes = code <= 127 ? 1 : code <= 2047 ? 2 : 3;\n    }\n    if (outputBytes + characterBytes > maxBytes)\n      break;\n    outputBytes += characterBytes;\n    start = characterStart;\n    needsReplacement ||= unpairedSurrogate;\n    i = characterStart;\n  }\n  const output = str2.slice(start);\n  return needsReplacement ? replaceUnpairedSurrogates(output) : output;\n}\nfunction truncateLine(line, maxChars = GREP_MAX_LINE_LENGTH) {\n  if (line.length <= maxChars) {\n    return { text: line, wasTruncated: false };\n  }\n  return { text: `${line.slice(0, maxChars)}... [truncated]`, wasTruncated: true };\n}\n\n// node_modules/.pnpm/@earendil-works+pi-agent-core@0.84.4_ws@8.21.3/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/shell-output.js\nfunction toExecutionError(error) {\n  if (error instanceof ExecutionError)\n    return error;\n  const cause = toError(error);\n  return new ExecutionError(\"unknown\", cause.message, cause);\n}\nfunction sanitizeBinaryOutput2(str2) {\n  return Array.from(str2).filter((char) => {\n    const code = char.codePointAt(0);\n    if (code === void 0)\n      return false;\n    if (code === 9 || code === 10 || code === 13)\n      return true;\n    if (code <= 31)\n      return false;\n    if (code >= 65529 && code <= 65531)\n      return false;\n    return true;\n  }).join(\"\");\n}\nfunction trimToLastUtf8Bytes(text, maxBytes, encoder) {\n  const bytes = encoder.encode(text);\n  if (bytes.byteLength <= maxBytes)\n    return text;\n  let start = bytes.byteLength - maxBytes;\n  while (start < bytes.byteLength && ((bytes[start] ?? 0) & 192) === 128)\n    start++;\n  return new TextDecoder().decode(bytes.subarray(start));\n}\nasync function executeShellWithCapture(env, command, options) {\n  let tailOutput = \"\";\n  const maxOutputBytes = DEFAULT_MAX_BYTES2 * 2;\n  const encoder = new TextEncoder();\n  let totalBytes = 0;\n  let completedLines = 0;\n  let hasOpenLine = false;\n  let currentLineBytes = 0;\n  let fullOutputPath;\n  let fullOutputRequested = false;\n  let acceptingOutput = true;\n  let writeChain = Promise.resolve(ok(void 0));\n  let captureError;\n  const appendFullOutput = (text) => {\n    if (!fullOutputRequested || captureError)\n      return;\n    writeChain = writeChain.then(async (previous) => {\n      if (!previous.ok)\n        return previous;\n      if (!fullOutputPath)\n        return err(new ExecutionError(\"unknown\", \"Full output path was not created\"));\n      const appendResult = await env.appendFile(fullOutputPath, text);\n      return appendResult.ok ? ok(void 0) : err(toExecutionError(appendResult.error));\n    });\n  };\n  const ensureFullOutputFile = (initialContent) => {\n    if (fullOutputRequested || captureError)\n      return;\n    fullOutputRequested = true;\n    writeChain = writeChain.then(async (previous) => {\n      if (!previous.ok)\n        return previous;\n      const tempFile = await env.createTempFile({ prefix: \"bash-\", suffix: \".log\" });\n      if (!tempFile.ok)\n        return err(toExecutionError(tempFile.error));\n      fullOutputPath = tempFile.value;\n      const appendResult = await env.appendFile(tempFile.value, initialContent);\n      return appendResult.ok ? ok(void 0) : err(toExecutionError(appendResult.error));\n    });\n  };\n  const createProgress = () => {\n    const tailTruncation = truncateTail(tailOutput);\n    const totalLines = completedLines + (hasOpenLine ? 1 : 0);\n    const truncated = totalLines > DEFAULT_MAX_LINES || totalBytes > DEFAULT_MAX_BYTES2;\n    const truncation = {\n      ...tailTruncation,\n      truncated,\n      truncatedBy: truncated ? tailTruncation.truncatedBy ?? (totalBytes > DEFAULT_MAX_BYTES2 ? \"bytes\" : \"lines\") : null,\n      totalLines,\n      totalBytes\n    };\n    return {\n      output: truncated ? truncation.content : tailOutput,\n      truncation,\n      fullOutputPath,\n      lastLineBytes: currentLineBytes\n    };\n  };\n  const onChunk = (chunk) => {\n    if (!acceptingOutput)\n      return;\n    try {\n      const text = sanitizeBinaryOutput2(chunk).replace(/\\r/g, \"\");\n      const textBytes = encoder.encode(text).byteLength;\n      totalBytes += textBytes;\n      const newlineCount = text.split(\"\\n\").length - 1;\n      completedLines += newlineCount;\n      const lastNewline = text.lastIndexOf(\"\\n\");\n      if (lastNewline >= 0) {\n        const trailingText = text.slice(lastNewline + 1);\n        currentLineBytes = encoder.encode(trailingText).byteLength;\n        hasOpenLine = trailingText.length > 0;\n      } else if (text.length > 0) {\n        currentLineBytes += textBytes;\n        hasOpenLine = true;\n      }\n      tailOutput += text;\n      const totalLines = completedLines + (hasOpenLine ? 1 : 0);\n      if ((totalBytes > DEFAULT_MAX_BYTES2 || totalLines > DEFAULT_MAX_LINES) && !fullOutputRequested) {\n        ensureFullOutputFile(tailOutput);\n      } else if (fullOutputRequested) {\n        appendFullOutput(text);\n      }\n      tailOutput = trimToLastUtf8Bytes(tailOutput, maxOutputBytes, encoder);\n      options?.onChunk?.(text, createProgress);\n    } catch (error) {\n      captureError = toExecutionError(error);\n    }\n  };\n  try {\n    const result = await env.exec(command, {\n      cwd: options?.cwd,\n      env: options?.env,\n      inheritEnv: options?.inheritEnv,\n      timeout: options?.timeout,\n      abortSignal: options?.abortSignal,\n      onStdout: onChunk,\n      onStderr: onChunk\n    });\n    acceptingOutput = false;\n    let progress = createProgress();\n    if (progress.truncation.truncated && !fullOutputRequested)\n      ensureFullOutputFile(tailOutput);\n    const writeResult = await writeChain;\n    if (!writeResult.ok)\n      return err(writeResult.error);\n    if (captureError)\n      return err(captureError);\n    progress = createProgress();\n    if (!result.ok) {\n      if (result.error.code === \"aborted\" || options?.abortSignal?.aborted) {\n        return ok({\n          ...progress,\n          exitCode: void 0,\n          cancelled: true,\n          truncated: progress.truncation.truncated\n        });\n      }\n      if (options?.returnExecutionErrors) {\n        return ok({\n          ...progress,\n          exitCode: void 0,\n          cancelled: false,\n          truncated: progress.truncation.truncated,\n          executionError: result.error\n        });\n      }\n      return err(result.error);\n    }\n    const cancelled = options?.abortSignal?.aborted ?? false;\n    return ok({\n      ...progress,\n      exitCode: cancelled ? void 0 : result.value.exitCode,\n      cancelled,\n      truncated: progress.truncation.truncated\n    });\n  } catch (error) {\n    acceptingOutput = false;\n    return err(toExecutionError(error));\n  }\n}\n\n// node_modules/.pnpm/@earendil-works+pi-agent-core@0.84.4_ws@8.21.3/node_modules/@earendil-works/pi-agent-core/dist/harness/tools/bash.js\nvar MAX_TIMEOUT_SECONDS = 2147483647 / 1e3;\nvar BASH_UPDATE_THROTTLE_MS = 100;\nvar bashSchema = Type6.Object({\n  command: Type6.String({ description: \"Bash command to execute\" }),\n  timeout: Type6.Optional(Type6.Number({ description: \"Timeout in seconds (optional, no default timeout)\" }))\n});\nfunction validateTimeout(timeout) {\n  if (timeout === void 0)\n    return;\n  if (!Number.isFinite(timeout) || timeout <= 0) {\n    throw new Error(\"Invalid timeout: must be a finite number of seconds\");\n  }\n  if (timeout > MAX_TIMEOUT_SECONDS) {\n    throw new Error(`Invalid timeout: maximum is ${MAX_TIMEOUT_SECONDS} seconds`);\n  }\n}\nfunction createBashTool(options) {\n  return {\n    name: \"bash\",\n    label: \"bash\",\n    description: `Execute a bash command in the current working directory. Returns stdout and stderr. Output is truncated to last ${DEFAULT_MAX_LINES} lines or ${DEFAULT_MAX_BYTES2 / 1024}KB (whichever is hit first). If truncated, full output is saved to a temp file. Optionally provide a timeout in seconds.`,\n    parameters: bashSchema,\n    async execute(_toolCallId, { command, timeout }, signal, onUpdate, context) {\n      validateTimeout(timeout);\n      const { env } = context;\n      const execution = {\n        command: options?.commandPrefix ? `${options.commandPrefix}\n${command}` : command,\n        cwd: env.cwd,\n        env: {},\n        inheritEnv: true\n      };\n      await options?.prepare?.(execution, context, signal);\n      let getLatestProgress;\n      let updateTimer;\n      let updateDirty = false;\n      let lastUpdateAt = 0;\n      const emitOutputUpdate = () => {\n        if (!onUpdate || !updateDirty || !getLatestProgress)\n          return;\n        updateDirty = false;\n        lastUpdateAt = Date.now();\n        const progress = getLatestProgress();\n        onUpdate({\n          content: [{ type: \"text\", text: progress.output }],\n          details: {\n            truncation: progress.truncation.truncated ? progress.truncation : void 0,\n            fullOutputPath: progress.fullOutputPath\n          }\n        });\n      };\n      const clearUpdateTimer = () => {\n        if (!updateTimer)\n          return;\n        clearTimeout(updateTimer);\n        updateTimer = void 0;\n      };\n      const scheduleOutputUpdate = () => {\n        if (!onUpdate)\n          return;\n        updateDirty = true;\n        const delay = BASH_UPDATE_THROTTLE_MS - (Date.now() - lastUpdateAt);\n        if (delay <= 0) {\n          clearUpdateTimer();\n          emitOutputUpdate();\n          return;\n        }\n        updateTimer ??= setTimeout(() => {\n          updateTimer = void 0;\n          emitOutputUpdate();\n        }, delay);\n      };\n      onUpdate?.({ content: [], details: void 0 });\n      try {\n        const capture = getOrThrow(await executeShellWithCapture(env, execution.command, {\n          cwd: execution.cwd,\n          env: execution.env,\n          inheritEnv: execution.inheritEnv,\n          timeout,\n          abortSignal: signal,\n          returnExecutionErrors: true,\n          onChunk: (_chunk, getProgress) => {\n            getLatestProgress = getProgress;\n            scheduleOutputUpdate();\n          }\n        }));\n        clearUpdateTimer();\n        getLatestProgress = () => capture;\n        updateDirty = true;\n        emitOutputUpdate();\n        let outputText = capture.output;\n        let details;\n        if (capture.truncation.truncated) {\n          details = { truncation: capture.truncation, fullOutputPath: capture.fullOutputPath };\n          const startLine = capture.truncation.totalLines - capture.truncation.outputLines + 1;\n          const endLine = capture.truncation.totalLines;\n          if (capture.truncation.lastLinePartial) {\n            const lastLineSize = formatSize(capture.lastLineBytes);\n            outputText += `\n\n[Showing last ${formatSize(capture.truncation.outputBytes)} of line ${endLine} (line is ${lastLineSize}). Full output: ${capture.fullOutputPath}]`;\n          } else if (capture.truncation.truncatedBy === \"lines\") {\n            outputText += `\n\n[Showing lines ${startLine}-${endLine} of ${capture.truncation.totalLines}. Full output: ${capture.fullOutputPath}]`;\n          } else {\n            outputText += `\n\n[Showing lines ${startLine}-${endLine} of ${capture.truncation.totalLines} (${formatSize(DEFAULT_MAX_BYTES2)} limit). Full output: ${capture.fullOutputPath}]`;\n          }\n        }\n        const appendStatus = (status) => `${outputText ? `${outputText}\n\n` : \"\"}${status}`;\n        if (capture.cancelled)\n          throw new Error(appendStatus(\"Command aborted\"));\n        if (capture.executionError?.code === \"timeout\") {\n          throw new Error(appendStatus(`Command timed out after ${timeout} seconds`), {\n            cause: capture.executionError\n          });\n        }\n        if (capture.executionError)\n          throw capture.executionError;\n        if (capture.exitCode !== 0 && capture.exitCode !== void 0) {\n          throw new Error(appendStatus(`Command exited with code ${capture.exitCode}`));\n        }\n        return { content: [{ type: \"text\", text: outputText || \"(no output)\" }], details };\n      } finally {\n        clearUpdateTimer();\n      }\n    }\n  };\n}\n\n// node_modules/.pnpm/@earendil-works+pi-agent-core@0.84.4_ws@8.21.3/node_modules/@earendil-works/pi-agent-core/dist/harness/tools/edit.js\nimport { Type as Type7 } from \"typebox\";\n\n// node_modules/.pnpm/@earendil-works+pi-agent-core@0.84.4_ws@8.21.3/node_modules/@earendil-works/pi-agent-core/dist/harness/tools/edit-diff.js\nimport * as Diff from \"diff\";\nfunction detectLineEnding(content) {\n  const crlfIdx = content.indexOf(\"\\r\\n\");\n  const lfIdx = content.indexOf(\"\\n\");\n  if (lfIdx === -1)\n    return \"\\n\";\n  if (crlfIdx === -1)\n    return \"\\n\";\n  return crlfIdx < lfIdx ? \"\\r\\n\" : \"\\n\";\n}\nfunction normalizeToLF(text) {\n  return text.replace(/\\r\\n/g, \"\\n\").replace(/\\r/g, \"\\n\");\n}\nfunction restoreLineEndings(text, ending) {\n  return ending === \"\\r\\n\" ? text.replace(/\\n/g, \"\\r\\n\") : text;\n}\nfunction normalizeForFuzzyMatch(text) {\n  return text.normalize(\"NFKC\").split(\"\\n\").map((line) => line.trimEnd()).join(\"\\n\").replace(/[\\u2018\\u2019\\u201A\\u201B]/g, \"'\").replace(/[\\u201C\\u201D\\u201E\\u201F]/g, '\"').replace(/[\\u2010\\u2011\\u2012\\u2013\\u2014\\u2015\\u2212]/g, \"-\").replace(/[\\u00A0\\u2002-\\u200A\\u202F\\u205F\\u3000]/g, \" \");\n}\nfunction splitLinesWithEndings(content) {\n  return content.match(/[^\\n]*\\n|[^\\n]+/g) ?? [];\n}\nfunction getLineSpans(content) {\n  let offset = 0;\n  return splitLinesWithEndings(content).map((line) => {\n    const span = { start: offset, end: offset + line.length };\n    offset = span.end;\n    return span;\n  });\n}\nfunction getReplacementLineRange(lines, replacement) {\n  const replacementStart = replacement.matchIndex;\n  const replacementEnd = replacement.matchIndex + replacement.matchLength;\n  let startLine = -1;\n  for (let i = 0; i < lines.length; i++) {\n    const line = lines[i];\n    if (replacementStart >= line.start && replacementStart < line.end) {\n      startLine = i;\n      break;\n    }\n  }\n  if (startLine === -1) {\n    throw new Error(\"Replacement range is outside the base content.\");\n  }\n  let endLine = startLine;\n  while (endLine < lines.length && lines[endLine].end < replacementEnd) {\n    endLine++;\n  }\n  if (endLine >= lines.length) {\n    throw new Error(\"Replacement range is outside the base content.\");\n  }\n  return { startLine, endLine: endLine + 1 };\n}\nfunction applyReplacements(content, replacements, offset = 0) {\n  let result = content;\n  for (let i = replacements.length - 1; i >= 0; i--) {\n    const replacement = replacements[i];\n    const matchIndex = replacement.matchIndex - offset;\n    result = result.substring(0, matchIndex) + replacement.newText + result.substring(matchIndex + replacement.matchLength);\n  }\n  return result;\n}\nfunction applyReplacementsPreservingUnchangedLines(originalContent, baseContent, replacements) {\n  const originalLines = splitLinesWithEndings(originalContent);\n  const baseLines = getLineSpans(baseContent);\n  if (originalLines.length !== baseLines.length) {\n    throw new Error(\"Cannot preserve unchanged lines because the base content has a different line count.\");\n  }\n  const groups = [];\n  const sortedReplacements = [...replacements].sort((a, b) => a.matchIndex - b.matchIndex);\n  for (const replacement of sortedReplacements) {\n    const range = getReplacementLineRange(baseLines, replacement);\n    const current = groups[groups.length - 1];\n    if (current && range.startLine < current.endLine) {\n      current.endLine = Math.max(current.endLine, range.endLine);\n      current.replacements.push(replacement);\n      continue;\n    }\n    groups.push({ ...range, replacements: [replacement] });\n  }\n  let originalLineIndex = 0;\n  let result = \"\";\n  for (const group of groups) {\n    result += originalLines.slice(originalLineIndex, group.startLine).join(\"\");\n    const groupStartOffset = baseLines[group.startLine].start;\n    const groupEndOffset = baseLines[group.endLine - 1].end;\n    result += applyReplacements(baseContent.slice(groupStartOffset, groupEndOffset), group.replacements, groupStartOffset);\n    originalLineIndex = group.endLine;\n  }\n  result += originalLines.slice(originalLineIndex).join(\"\");\n  return result;\n}\nfunction fuzzyFindText(content, oldText) {\n  const exactIndex = content.indexOf(oldText);\n  if (exactIndex !== -1) {\n    return {\n      found: true,\n      index: exactIndex,\n      matchLength: oldText.length,\n      usedFuzzyMatch: false,\n      contentForReplacement: content\n    };\n  }\n  const fuzzyContent = normalizeForFuzzyMatch(content);\n  const fuzzyOldText = normalizeForFuzzyMatch(oldText);\n  const fuzzyIndex = fuzzyContent.indexOf(fuzzyOldText);\n  if (fuzzyIndex === -1) {\n    return {\n      found: false,\n      index: -1,\n      matchLength: 0,\n      usedFuzzyMatch: false,\n      contentForReplacement: content\n    };\n  }\n  return {\n    found: true,\n    index: fuzzyIndex,\n    matchLength: fuzzyOldText.length,\n    usedFuzzyMatch: true,\n    contentForReplacement: fuzzyContent\n  };\n}\nfunction stripBom(content) {\n  return content.startsWith(\"\\uFEFF\") ? { bom: \"\\uFEFF\", text: content.slice(1) } : { bom: \"\", text: content };\n}\nfunction countOccurrences(content, oldText) {\n  const fuzzyContent = normalizeForFuzzyMatch(content);\n  const fuzzyOldText = normalizeForFuzzyMatch(oldText);\n  return fuzzyContent.split(fuzzyOldText).length - 1;\n}\nfunction getNotFoundError(path12, editIndex, totalEdits) {\n  if (totalEdits === 1) {\n    return new Error(`Could not find the exact text in ${path12}. The old text must match exactly including all whitespace and newlines.`);\n  }\n  return new Error(`Could not find edits[${editIndex}] in ${path12}. The oldText must match exactly including all whitespace and newlines.`);\n}\nfunction getDuplicateError(path12, editIndex, totalEdits, occurrences) {\n  if (totalEdits === 1) {\n    return new Error(`Found ${occurrences} occurrences of the text in ${path12}. The text must be unique. Please provide more context to make it unique.`);\n  }\n  return new Error(`Found ${occurrences} occurrences of edits[${editIndex}] in ${path12}. Each oldText must be unique. Please provide more context to make it unique.`);\n}\nfunction getEmptyOldTextError(path12, editIndex, totalEdits) {\n  if (totalEdits === 1) {\n    return new Error(`oldText must not be empty in ${path12}.`);\n  }\n  return new Error(`edits[${editIndex}].oldText must not be empty in ${path12}.`);\n}\nfunction getNoChangeError(path12, totalEdits) {\n  if (totalEdits === 1) {\n    return new Error(`No changes made to ${path12}. The replacement produced identical content. This might indicate an issue with special characters or the text not existing as expected.`);\n  }\n  return new Error(`No changes made to ${path12}. The replacements produced identical content.`);\n}\nfunction applyEditsToNormalizedContent(normalizedContent, edits, path12) {\n  const normalizedEdits = edits.map((edit) => ({\n    oldText: normalizeToLF(edit.oldText),\n    newText: normalizeToLF(edit.newText)\n  }));\n  for (let i = 0; i < normalizedEdits.length; i++) {\n    if (normalizedEdits[i].oldText.length === 0) {\n      throw getEmptyOldTextError(path12, i, normalizedEdits.length);\n    }\n  }\n  const initialMatches = normalizedEdits.map((edit) => fuzzyFindText(normalizedContent, edit.oldText));\n  const usedFuzzyMatch = initialMatches.some((match) => match.usedFuzzyMatch);\n  const replacementBaseContent = usedFuzzyMatch ? normalizeForFuzzyMatch(normalizedContent) : normalizedContent;\n  const matchedEdits = [];\n  for (let i = 0; i < normalizedEdits.length; i++) {\n    const edit = normalizedEdits[i];\n    const matchResult = fuzzyFindText(replacementBaseContent, edit.oldText);\n    if (!matchResult.found) {\n      throw getNotFoundError(path12, i, normalizedEdits.length);\n    }\n    const occurrences = countOccurrences(replacementBaseContent, edit.oldText);\n    if (occurrences > 1) {\n      throw getDuplicateError(path12, i, normalizedEdits.length, occurrences);\n    }\n    matchedEdits.push({\n      editIndex: i,\n      matchIndex: matchResult.index,\n      matchLength: matchResult.matchLength,\n      newText: edit.newText\n    });\n  }\n  matchedEdits.sort((a, b) => a.matchIndex - b.matchIndex);\n  for (let i = 1; i < matchedEdits.length; i++) {\n    const previous = matchedEdits[i - 1];\n    const current = matchedEdits[i];\n    if (previous.matchIndex + previous.matchLength > current.matchIndex) {\n      throw new Error(`edits[${previous.editIndex}] and edits[${current.editIndex}] overlap in ${path12}. Merge them into one edit or target disjoint regions.`);\n    }\n  }\n  const baseContent = normalizedContent;\n  const newContent = usedFuzzyMatch ? applyReplacementsPreservingUnchangedLines(normalizedContent, replacementBaseContent, matchedEdits) : applyReplacements(replacementBaseContent, matchedEdits);\n  if (baseContent === newContent) {\n    throw getNoChangeError(path12, normalizedEdits.length);\n  }\n  return { baseContent, newContent };\n}\nfunction generateUnifiedPatch(path12, oldContent, newContent, contextLines = 4) {\n  return Diff.createTwoFilesPatch(path12, path12, oldContent, newContent, void 0, void 0, {\n    context: contextLines,\n    headerOptions: Diff.FILE_HEADERS_ONLY\n  });\n}\nfunction generateDiffString(oldContent, newContent, contextLines = 4) {\n  const parts = Diff.diffLines(oldContent, newContent);\n  const output = [];\n  const oldLines = oldContent.split(\"\\n\");\n  const newLines = newContent.split(\"\\n\");\n  const maxLineNum = Math.max(oldLines.length, newLines.length);\n  const lineNumWidth = String(maxLineNum).length;\n  let oldLineNum = 1;\n  let newLineNum = 1;\n  let lastWasChange = false;\n  let firstChangedLine;\n  for (let i = 0; i < parts.length; i++) {\n    const part = parts[i];\n    const raw = part.value.split(\"\\n\");\n    if (raw[raw.length - 1] === \"\") {\n      raw.pop();\n    }\n    if (part.added || part.removed) {\n      if (firstChangedLine === void 0) {\n        firstChangedLine = newLineNum;\n      }\n      for (const line of raw) {\n        if (part.added) {\n          const lineNum = String(newLineNum).padStart(lineNumWidth, \" \");\n          output.push(`+${lineNum} ${line}`);\n          newLineNum++;\n        } else {\n          const lineNum = String(oldLineNum).padStart(lineNumWidth, \" \");\n          output.push(`-${lineNum} ${line}`);\n          oldLineNum++;\n        }\n      }\n      lastWasChange = true;\n    } else {\n      const nextPartIsChange = i < parts.length - 1 && (parts[i + 1].added || parts[i + 1].removed);\n      const hasLeadingChange = lastWasChange;\n      const hasTrailingChange = nextPartIsChange;\n      if (hasLeadingChange && hasTrailingChange) {\n        if (raw.length <= contextLines * 2) {\n          for (const line of raw) {\n            const lineNum = String(oldLineNum).padStart(lineNumWidth, \" \");\n            output.push(` ${lineNum} ${line}`);\n            oldLineNum++;\n            newLineNum++;\n          }\n        } else {\n          const leadingLines = raw.slice(0, contextLines);\n          const trailingLines = raw.slice(raw.length - contextLines);\n          const skippedLines = raw.length - leadingLines.length - trailingLines.length;\n          for (const line of leadingLines) {\n            const lineNum = String(oldLineNum).padStart(lineNumWidth, \" \");\n            output.push(` ${lineNum} ${line}`);\n            oldLineNum++;\n            newLineNum++;\n          }\n          output.push(` ${\"\".padStart(lineNumWidth, \" \")} ...`);\n          oldLineNum += skippedLines;\n          newLineNum += skippedLines;\n          for (const line of trailingLines) {\n            const lineNum = String(oldLineNum).padStart(lineNumWidth, \" \");\n            output.push(` ${lineNum} ${line}`);\n            oldLineNum++;\n            newLineNum++;\n          }\n        }\n      } else if (hasLeadingChange) {\n        const shownLines = raw.slice(0, contextLines);\n        const skippedLines = raw.length - shownLines.length;\n        for (const line of shownLines) {\n          const lineNum = String(oldLineNum).padStart(lineNumWidth, \" \");\n          output.push(` ${lineNum} ${line}`);\n          oldLineNum++;\n          newLineNum++;\n        }\n        if (skippedLines > 0) {\n          output.push(` ${\"\".padStart(lineNumWidth, \" \")} ...`);\n          oldLineNum += skippedLines;\n          newLineNum += skippedLines;\n        }\n      } else if (hasTrailingChange) {\n        const skippedLines = Math.max(0, raw.length - contextLines);\n        if (skippedLines > 0) {\n          output.push(` ${\"\".padStart(lineNumWidth, \" \")} ...`);\n          oldLineNum += skippedLines;\n          newLineNum += skippedLines;\n        }\n        for (const line of raw.slice(skippedLines)) {\n          const lineNum = String(oldLineNum).padStart(lineNumWidth, \" \");\n          output.push(` ${lineNum} ${line}`);\n          oldLineNum++;\n          newLineNum++;\n        }\n      } else {\n        oldLineNum += raw.length;\n        newLineNum += raw.length;\n      }\n      lastWasChange = false;\n    }\n  }\n  return { diff: output.join(\"\\n\"), firstChangedLine };\n}\n\n// node_modules/.pnpm/@earendil-works+pi-agent-core@0.84.4_ws@8.21.3/node_modules/@earendil-works/pi-agent-core/dist/harness/tools/file-mutation-queue.js\nvar states = /* @__PURE__ */ new WeakMap();\nfunction getState(env) {\n  let state = states.get(env);\n  if (!state) {\n    state = { queues: /* @__PURE__ */ new Map(), registration: Promise.resolve() };\n    states.set(env, state);\n  }\n  return state;\n}\nasync function getMutationQueueKey(env, path12) {\n  const absolutePath = getOrThrow(await env.absolutePath(path12));\n  const canonicalPath = await env.canonicalPath(absolutePath);\n  if (canonicalPath.ok)\n    return canonicalPath.value;\n  if (canonicalPath.error.code === \"not_found\" || canonicalPath.error.code === \"not_supported\")\n    return absolutePath;\n  throw canonicalPath.error;\n}\nasync function withFileMutationQueue(env, path12, fn) {\n  const state = getState(env);\n  const registration = state.registration.then(async () => {\n    const key2 = await getMutationQueueKey(env, path12);\n    const currentQueue2 = state.queues.get(key2) ?? Promise.resolve();\n    let releaseNext2 = () => {\n    };\n    const nextQueue = new Promise((resolve15) => {\n      releaseNext2 = resolve15;\n    });\n    const chainedQueue2 = currentQueue2.then(() => nextQueue);\n    state.queues.set(key2, chainedQueue2);\n    return { key: key2, currentQueue: currentQueue2, chainedQueue: chainedQueue2, releaseNext: releaseNext2 };\n  });\n  state.registration = registration.then(() => void 0, () => void 0);\n  const { key, currentQueue, chainedQueue, releaseNext } = await registration;\n  await currentQueue;\n  try {\n    return await fn();\n  } finally {\n    releaseNext();\n    if (state.queues.get(key) === chainedQueue)\n      state.queues.delete(key);\n  }\n}\n\n// node_modules/.pnpm/@earendil-works+pi-agent-core@0.84.4_ws@8.21.3/node_modules/@earendil-works/pi-agent-core/dist/harness/tools/path-utils.js\nvar UNICODE_SPACES2 = /[\\u00A0\\u2000-\\u200A\\u202F\\u205F\\u3000]/g;\nvar NARROW_NO_BREAK_SPACE2 = \"\\u202F\";\nfunction normalizeToolPath(path12) {\n  const normalized = path12.replace(UNICODE_SPACES2, \" \");\n  return normalized.startsWith(\"@\") ? normalized.slice(1) : normalized;\n}\nasync function resolveToolPath(env, path12, signal) {\n  return getOrThrow(await env.absolutePath(normalizeToolPath(path12), signal));\n}\nasync function resolveReadToolPath(env, path12, signal) {\n  const resolved = await resolveToolPath(env, path12, signal);\n  const variants = [\n    resolved,\n    resolved.replace(/ (AM|PM)\\./gi, `${NARROW_NO_BREAK_SPACE2}$1.`),\n    resolved.normalize(\"NFD\"),\n    resolved.replace(/'/g, \"\\u2019\"),\n    resolved.normalize(\"NFD\").replace(/'/g, \"\\u2019\")\n  ];\n  for (const variant of new Set(variants)) {\n    if (getOrThrow(await env.exists(variant, signal)))\n      return variant;\n  }\n  return resolved;\n}\n\n// node_modules/.pnpm/@earendil-works+pi-agent-core@0.84.4_ws@8.21.3/node_modules/@earendil-works/pi-agent-core/dist/harness/tools/edit.js\nvar replaceEditSchema = Type7.Object({\n  oldText: Type7.String({\n    description: \"Exact text for one targeted replacement. It must be unique in the original file and must not overlap with any other edits[].oldText in the same call.\"\n  }),\n  newText: Type7.String({ description: \"Replacement text for this targeted edit.\" })\n}, {});\nvar editSchema = Type7.Object({\n  path: Type7.String({ description: \"Path to the file to edit (relative or absolute)\" }),\n  edits: Type7.Array(replaceEditSchema, {\n    description: \"One or more targeted replacements. Each edit is matched against the original file, not incrementally. Do not include overlapping or nested edits. If two changes touch the same block or nearby lines, merge them into one edit instead.\"\n  })\n}, {});\nfunction isSingleEditInput(value) {\n  if (!value || typeof value !== \"object\" || Array.isArray(value))\n    return false;\n  const edit = value;\n  return typeof edit.oldText === \"string\" && typeof edit.newText === \"string\";\n}\nfunction prepareEditArguments(input) {\n  if (!input || typeof input !== \"object\")\n    return input;\n  const args = input;\n  if (typeof args.edits === \"string\") {\n    try {\n      const parsed = JSON.parse(args.edits);\n      if (Array.isArray(parsed)) {\n        args.edits = parsed;\n      } else if (isSingleEditInput(parsed)) {\n        args.edits = [parsed];\n      }\n    } catch {\n    }\n  } else if (isSingleEditInput(args.edits)) {\n    args.edits = [args.edits];\n  }\n  const legacy = args;\n  if (typeof legacy.oldText !== \"string\" || typeof legacy.newText !== \"string\")\n    return args;\n  const edits = Array.isArray(legacy.edits) ? [...legacy.edits] : [];\n  edits.push({ oldText: legacy.oldText, newText: legacy.newText });\n  const { oldText: _oldText, newText: _newText, ...rest } = legacy;\n  return { ...rest, edits };\n}\nfunction validateEditInput(input) {\n  if (!Array.isArray(input.edits) || input.edits.length === 0) {\n    throw new Error(\"Edit tool input is invalid. edits must contain at least one replacement.\");\n  }\n  return { path: input.path, edits: input.edits };\n}\nfunction editAccessError(path12, error) {\n  return new Error(`Could not edit file: ${path12}. Error code: ${error.code}.`, { cause: error });\n}\nfunction createEditTool() {\n  return {\n    name: \"edit\",\n    label: \"edit\",\n    description: \"Edit a single file using exact text replacement. Every edits[].oldText must match a unique, non-overlapping region of the original file. If two changes affect the same block or nearby lines, merge them into one edit instead of emitting overlapping edits. Do not include large unchanged regions just to connect distant changes.\",\n    parameters: editSchema,\n    prepareArguments: prepareEditArguments,\n    async execute(_toolCallId, input, signal, _onUpdate, { env }) {\n      const { path: path12, edits } = validateEditInput(input);\n      const absolutePath = await resolveToolPath(env, path12, signal);\n      return withFileMutationQueue(env, absolutePath, async () => {\n        if (signal?.aborted)\n          throw new Error(\"Operation aborted\");\n        const info = await env.fileInfo(absolutePath, signal);\n        if (!info.ok)\n          throw editAccessError(path12, info.error);\n        if (info.value.kind !== \"file\" && info.value.kind !== \"symlink\") {\n          throw new Error(`Could not edit file: ${path12}. Path is not a file.`);\n        }\n        const readResult = await env.readTextFile(absolutePath, signal);\n        if (!readResult.ok)\n          throw editAccessError(path12, readResult.error);\n        if (signal?.aborted)\n          throw new Error(\"Operation aborted\");\n        const { bom, text: content } = stripBom(readResult.value);\n        const originalEnding = detectLineEnding(content);\n        const normalizedContent = normalizeToLF(content);\n        const { baseContent, newContent } = applyEditsToNormalizedContent(normalizedContent, edits, path12);\n        if (signal?.aborted)\n          throw new Error(\"Operation aborted\");\n        const finalContent = bom + restoreLineEndings(newContent, originalEnding);\n        const writeResult = await env.writeFile(absolutePath, finalContent, signal);\n        if (!writeResult.ok)\n          throw editAccessError(path12, writeResult.error);\n        if (signal?.aborted)\n          throw new Error(\"Operation aborted\");\n        const diffResult = generateDiffString(baseContent, newContent);\n        return {\n          content: [{ type: \"text\", text: `Successfully replaced ${edits.length} block(s) in ${path12}.` }],\n          details: {\n            diff: diffResult.diff,\n            patch: generateUnifiedPatch(path12, baseContent, newContent),\n            firstChangedLine: diffResult.firstChangedLine\n          }\n        };\n      });\n    }\n  };\n}\n\n// node_modules/.pnpm/@earendil-works+pi-agent-core@0.84.4_ws@8.21.3/node_modules/@earendil-works/pi-agent-core/dist/harness/tools/read.js\nimport { Type as Type8 } from \"typebox\";\n\n// node_modules/.pnpm/@earendil-works+pi-agent-core@0.84.4_ws@8.21.3/node_modules/@earendil-works/pi-agent-core/dist/harness/tools/image.js\nvar PNG_SIGNATURE2 = [137, 80, 78, 71, 13, 10, 26, 10];\nfunction detectSupportedImageMimeType2(buffer) {\n  if (startsWith2(buffer, [255, 216, 255]))\n    return buffer[3] === 247 ? void 0 : \"image/jpeg\";\n  if (startsWith2(buffer, PNG_SIGNATURE2))\n    return isPng2(buffer) && !isAnimatedPng2(buffer) ? \"image/png\" : void 0;\n  if (startsWithAscii2(buffer, 0, \"GIF\"))\n    return \"image/gif\";\n  if (startsWithAscii2(buffer, 0, \"RIFF\") && startsWithAscii2(buffer, 8, \"WEBP\"))\n    return \"image/webp\";\n  if (startsWithAscii2(buffer, 0, \"BM\") && isBmp2(buffer))\n    return \"image/bmp\";\n  return void 0;\n}\nfunction encodeBase64(bytes) {\n  const alphabet = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\";\n  let output = \"\";\n  for (let index = 0; index < bytes.length; index += 3) {\n    const first = bytes[index] ?? 0;\n    const second = bytes[index + 1];\n    const third = bytes[index + 2];\n    output += alphabet[first >> 2];\n    output += alphabet[(first & 3) << 4 | (second ?? 0) >> 4];\n    output += second === void 0 ? \"=\" : alphabet[(second & 15) << 2 | (third ?? 0) >> 6];\n    output += third === void 0 ? \"=\" : alphabet[third & 63];\n  }\n  return output;\n}\nfunction isPng2(buffer) {\n  return buffer.length >= 16 && readUint32BE2(buffer, PNG_SIGNATURE2.length) === 13 && startsWithAscii2(buffer, 12, \"IHDR\");\n}\nfunction isAnimatedPng2(buffer) {\n  let offset = PNG_SIGNATURE2.length;\n  while (offset + 8 <= buffer.length) {\n    const chunkLength = readUint32BE2(buffer, offset);\n    const chunkTypeOffset = offset + 4;\n    if (startsWithAscii2(buffer, chunkTypeOffset, \"acTL\"))\n      return true;\n    if (startsWithAscii2(buffer, chunkTypeOffset, \"IDAT\"))\n      return false;\n    const nextOffset = offset + 8 + chunkLength + 4;\n    if (nextOffset <= offset || nextOffset > buffer.length)\n      return false;\n    offset = nextOffset;\n  }\n  return false;\n}\nfunction isBmp2(buffer) {\n  if (buffer.length < 26)\n    return false;\n  const declaredFileSize = readUint32LE2(buffer, 2);\n  const pixelDataOffset = readUint32LE2(buffer, 10);\n  const dibHeaderSize = readUint32LE2(buffer, 14);\n  if (declaredFileSize !== 0 && declaredFileSize < 26)\n    return false;\n  if (pixelDataOffset < 14 + dibHeaderSize)\n    return false;\n  if (declaredFileSize !== 0 && pixelDataOffset >= declaredFileSize)\n    return false;\n  let colorPlanes;\n  let bitsPerPixel;\n  if (dibHeaderSize === 12) {\n    colorPlanes = readUint16LE2(buffer, 22);\n    bitsPerPixel = readUint16LE2(buffer, 24);\n  } else if (dibHeaderSize >= 40 && dibHeaderSize <= 124) {\n    if (buffer.length < 30)\n      return false;\n    colorPlanes = readUint16LE2(buffer, 26);\n    bitsPerPixel = readUint16LE2(buffer, 28);\n  } else {\n    return false;\n  }\n  return colorPlanes === 1 && [1, 4, 8, 16, 24, 32].includes(bitsPerPixel);\n}\nfunction readUint16LE2(buffer, offset) {\n  return (buffer[offset] ?? 0) + ((buffer[offset + 1] ?? 0) << 8);\n}\nfunction readUint32BE2(buffer, offset) {\n  return (buffer[offset] ?? 0) * 16777216 + ((buffer[offset + 1] ?? 0) << 16) + ((buffer[offset + 2] ?? 0) << 8) + (buffer[offset + 3] ?? 0);\n}\nfunction readUint32LE2(buffer, offset) {\n  return (buffer[offset] ?? 0) + ((buffer[offset + 1] ?? 0) << 8) + ((buffer[offset + 2] ?? 0) << 16) + (buffer[offset + 3] ?? 0) * 16777216;\n}\nfunction startsWith2(buffer, bytes) {\n  if (buffer.length < bytes.length)\n    return false;\n  return bytes.every((byte, index) => buffer[index] === byte);\n}\nfunction startsWithAscii2(buffer, offset, text) {\n  if (buffer.length < offset + text.length)\n    return false;\n  for (let index = 0; index < text.length; index++) {\n    if (buffer[offset + index] !== text.charCodeAt(index))\n      return false;\n  }\n  return true;\n}\n\n// node_modules/.pnpm/@earendil-works+pi-agent-core@0.84.4_ws@8.21.3/node_modules/@earendil-works/pi-agent-core/dist/harness/tools/read.js\nvar readSchema = Type8.Object({\n  path: Type8.String({ description: \"Path to the file to read (relative or absolute)\" }),\n  offset: Type8.Optional(Type8.Number({ description: \"Line number to start reading from (1-indexed)\" })),\n  limit: Type8.Optional(Type8.Number({ description: \"Maximum number of lines to read\" }))\n});\nfunction createReadTool(options) {\n  return {\n    name: \"read\",\n    label: \"read\",\n    description: `Read the contents of a file. Supports text files and images (jpg, png, gif, webp, bmp). Images are sent as attachments. For text files, output is truncated to ${DEFAULT_MAX_LINES} lines or ${DEFAULT_MAX_BYTES2 / 1024}KB (whichever is hit first). Use offset/limit for large files. When you need the full file, continue with offset until complete.`,\n    parameters: readSchema,\n    async execute(_toolCallId, { path: path12, offset, limit }, signal, _onUpdate, { env }) {\n      const absolutePath = await resolveReadToolPath(env, path12, signal);\n      const bytes = getOrThrow(await env.readBinaryFile(absolutePath, signal));\n      const mimeType = detectSupportedImageMimeType2(bytes);\n      if (mimeType) {\n        if (options?.imageProcessor) {\n          const processed = await options.imageProcessor(bytes, mimeType, {\n            autoResizeImages: options.autoResizeImages ?? true\n          });\n          if (!processed.ok) {\n            return {\n              content: [{ type: \"text\", text: `Read image file [${mimeType}]\n${processed.message}` }],\n              details: void 0\n            };\n          }\n          const hints = processed.hints.length > 0 ? `\n${processed.hints.join(\"\\n\")}` : \"\";\n          return {\n            content: [\n              { type: \"text\", text: `Read image file [${processed.mimeType}]${hints}` },\n              { type: \"image\", data: processed.data, mimeType: processed.mimeType }\n            ],\n            details: void 0\n          };\n        }\n        if (mimeType === \"image/bmp\") {\n          return {\n            content: [\n              {\n                type: \"text\",\n                text: \"Read image file [image/bmp]\\n[Image omitted: configure an imageProcessor to convert BMP images.]\"\n              }\n            ],\n            details: void 0\n          };\n        }\n        return {\n          content: [\n            { type: \"text\", text: `Read image file [${mimeType}]` },\n            { type: \"image\", data: encodeBase64(bytes), mimeType }\n          ],\n          details: void 0\n        };\n      }\n      const textContent = new TextDecoder().decode(bytes);\n      const allLines = textContent.split(\"\\n\");\n      const totalFileLines = allLines.length;\n      const startLine = offset ? Math.max(0, offset - 1) : 0;\n      const startLineDisplay = startLine + 1;\n      if (startLine >= allLines.length) {\n        throw new Error(`Offset ${offset} is beyond end of file (${allLines.length} lines total)`);\n      }\n      let selectedContent;\n      let userLimitedLines;\n      if (limit !== void 0) {\n        const endLine = Math.min(startLine + limit, allLines.length);\n        selectedContent = allLines.slice(startLine, endLine).join(\"\\n\");\n        userLimitedLines = endLine - startLine;\n      } else {\n        selectedContent = allLines.slice(startLine).join(\"\\n\");\n      }\n      const truncation = truncateHead(selectedContent);\n      let outputText;\n      let details;\n      if (truncation.firstLineExceedsLimit) {\n        const firstLineSize = formatSize(new TextEncoder().encode(allLines[startLine]).byteLength);\n        outputText = `[Line ${startLineDisplay} is ${firstLineSize}, exceeds ${formatSize(DEFAULT_MAX_BYTES2)} limit. Use bash: sed -n '${startLineDisplay}p' ${path12} | head -c ${DEFAULT_MAX_BYTES2}]`;\n        details = { truncation };\n      } else if (truncation.truncated) {\n        const endLineDisplay = startLineDisplay + truncation.outputLines - 1;\n        const nextOffset = endLineDisplay + 1;\n        outputText = truncation.content;\n        if (truncation.truncatedBy === \"lines\") {\n          outputText += `\n\n[Showing lines ${startLineDisplay}-${endLineDisplay} of ${totalFileLines}. Use offset=${nextOffset} to continue.]`;\n        } else {\n          outputText += `\n\n[Showing lines ${startLineDisplay}-${endLineDisplay} of ${totalFileLines} (${formatSize(DEFAULT_MAX_BYTES2)} limit). Use offset=${nextOffset} to continue.]`;\n        }\n        details = { truncation };\n      } else if (userLimitedLines !== void 0 && startLine + userLimitedLines < allLines.length) {\n        const remaining = allLines.length - (startLine + userLimitedLines);\n        const nextOffset = startLine + userLimitedLines + 1;\n        outputText = `${truncation.content}\n\n[${remaining} more lines in file. Use offset=${nextOffset} to continue.]`;\n      } else {\n        outputText = truncation.content;\n      }\n      return { content: [{ type: \"text\", text: outputText }], details };\n    }\n  };\n}\n\n// node_modules/.pnpm/@earendil-works+pi-agent-core@0.84.4_ws@8.21.3/node_modules/@earendil-works/pi-agent-core/dist/harness/tools/write.js\nimport { Type as Type9 } from \"typebox\";\nvar writeSchema = Type9.Object({\n  path: Type9.String({ description: \"Path to the file to write (relative or absolute)\" }),\n  content: Type9.String({ description: \"Content to write to the file\" })\n});\nfunction createWriteTool() {\n  return {\n    name: \"write\",\n    label: \"write\",\n    description: \"Write content to a file. Creates the file if it doesn't exist, overwrites if it does. Automatically creates parent directories.\",\n    parameters: writeSchema,\n    async execute(_toolCallId, { path: path12, content }, signal, _onUpdate, { env }) {\n      const absolutePath = await resolveToolPath(env, path12, signal);\n      return withFileMutationQueue(env, absolutePath, async () => {\n        if (signal?.aborted)\n          throw new Error(\"Operation aborted\");\n        getOrThrow(await env.writeFile(absolutePath, content, signal));\n        if (signal?.aborted)\n          throw new Error(\"Operation aborted\");\n        return {\n          content: [{ type: \"text\", text: `Successfully wrote ${content.length} bytes to ${path12}` }],\n          details: void 0\n        };\n      });\n    }\n  };\n}\n\n// node_modules/.pnpm/@earendil-works+pi-agent-core@0.84.4_ws@8.21.3/node_modules/@earendil-works/pi-agent-core/dist/proxy.js\nvar ProxyMessageEventStream = class extends EventStream2 {\n  constructor() {\n    super((event) => event.type === \"done\" || event.type === \"error\", (event) => {\n      if (event.type === \"done\")\n        return event.message;\n      if (event.type === \"error\")\n        return event.error;\n      throw new Error(\"Unexpected event type\");\n    });\n  }\n};\nfunction buildProxyRequestOptions(options) {\n  return {\n    temperature: options.temperature,\n    samplingParams: options.samplingParams,\n    maxTokens: options.maxTokens,\n    reasoning: options.reasoning,\n    cacheRetention: options.cacheRetention,\n    sessionId: options.sessionId,\n    headers: options.headers,\n    metadata: options.metadata,\n    transport: options.transport,\n    thinkingBudgets: options.thinkingBudgets,\n    maxRetryDelayMs: options.maxRetryDelayMs\n  };\n}\nfunction streamProxy(model, context, options) {\n  const stream11 = new ProxyMessageEventStream();\n  (async () => {\n    const partial = {\n      role: \"assistant\",\n      stopReason: \"pending\",\n      content: [],\n      api: model.api,\n      provider: model.provider,\n      model: model.id,\n      usage: {\n        input: 0,\n        output: 0,\n        cacheRead: 0,\n        cacheWrite: 0,\n        totalTokens: 0,\n        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 }\n      },\n      timestamp: Date.now()\n    };\n    let reader;\n    const abortHandler = () => {\n      if (reader) {\n        reader.cancel(\"Request aborted by user\").catch(() => {\n        });\n      }\n    };\n    if (options.signal) {\n      options.signal.addEventListener(\"abort\", abortHandler);\n    }\n    try {\n      const response = await fetch(`${options.proxyUrl}/api/stream`, {\n        method: \"POST\",\n        headers: {\n          Authorization: `Bearer ${options.authToken}`,\n          \"Content-Type\": \"application/json\"\n        },\n        body: JSON.stringify({\n          model,\n          context,\n          options: buildProxyRequestOptions(options)\n        }),\n        signal: options.signal\n      });\n      if (!response.ok) {\n        let errorMessage2 = `Proxy error: ${response.status} ${response.statusText}`;\n        try {\n          const errorData = await response.json();\n          if (errorData.error) {\n            errorMessage2 = `Proxy error: ${errorData.error}`;\n          }\n        } catch {\n        }\n        throw new Error(errorMessage2);\n      }\n      reader = response.body.getReader();\n      const decoder = new TextDecoder();\n      let buffer = \"\";\n      while (true) {\n        const { done, value } = await reader.read();\n        if (done)\n          break;\n        if (options.signal?.aborted) {\n          throw new Error(\"Request aborted by user\");\n        }\n        buffer += decoder.decode(value, { stream: true });\n        const lines = buffer.split(\"\\n\");\n        buffer = lines.pop() || \"\";\n        for (const line of lines) {\n          if (line.startsWith(\"data: \")) {\n            const data = line.slice(6).trim();\n            if (data) {\n              const proxyEvent = JSON.parse(data);\n              const event = processProxyEvent(proxyEvent, partial);\n              if (event) {\n                stream11.push(event);\n              }\n            }\n          }\n        }\n      }\n      if (options.signal?.aborted) {\n        throw new Error(\"Request aborted by user\");\n      }\n      stream11.end();\n    } catch (error) {\n      const errorMessage2 = error instanceof Error ? error.message : String(error);\n      const reason = options.signal?.aborted ? \"aborted\" : \"error\";\n      partial.stopReason = reason;\n      partial.errorMessage = errorMessage2;\n      stream11.push({\n        type: \"error\",\n        reason,\n        error: partial\n      });\n      stream11.end();\n    } finally {\n      if (options.signal) {\n        options.signal.removeEventListener(\"abort\", abortHandler);\n      }\n    }\n  })();\n  return stream11;\n}\nfunction processProxyEvent(proxyEvent, partial) {\n  switch (proxyEvent.type) {\n    case \"start\":\n      return { type: \"start\", partial };\n    case \"text_start\":\n      partial.content[proxyEvent.contentIndex] = { type: \"text\", text: \"\" };\n      return { type: \"text_start\", contentIndex: proxyEvent.contentIndex, partial };\n    case \"text_delta\": {\n      const content = partial.content[proxyEvent.contentIndex];\n      if (content?.type === \"text\") {\n        content.text += proxyEvent.delta;\n        return {\n          type: \"text_delta\",\n          contentIndex: proxyEvent.contentIndex,\n          delta: proxyEvent.delta,\n          partial\n        };\n      }\n      throw new Error(\"Received text_delta for non-text content\");\n    }\n    case \"text_end\": {\n      const content = partial.content[proxyEvent.contentIndex];\n      if (content?.type === \"text\") {\n        content.textSignature = proxyEvent.contentSignature;\n        return {\n          type: \"text_end\",\n          contentIndex: proxyEvent.contentIndex,\n          content: content.text,\n          partial\n        };\n      }\n      throw new Error(\"Received text_end for non-text content\");\n    }\n    case \"thinking_start\":\n      partial.content[proxyEvent.contentIndex] = { type: \"thinking\", thinking: \"\" };\n      return { type: \"thinking_start\", contentIndex: proxyEvent.contentIndex, partial };\n    case \"thinking_delta\": {\n      const content = partial.content[proxyEvent.contentIndex];\n      if (content?.type === \"thinking\") {\n        content.thinking += proxyEvent.delta;\n        return {\n          type: \"thinking_delta\",\n          contentIndex: proxyEvent.contentIndex,\n          delta: proxyEvent.delta,\n          partial\n        };\n      }\n      throw new Error(\"Received thinking_delta for non-thinking content\");\n    }\n    case \"thinking_end\": {\n      const content = partial.content[proxyEvent.contentIndex];\n      if (content?.type === \"thinking\") {\n        content.thinkingSignature = proxyEvent.contentSignature;\n        return {\n          type: \"thinking_end\",\n          contentIndex: proxyEvent.contentIndex,\n          content: content.thinking,\n          partial\n        };\n      }\n      throw new Error(\"Received thinking_end for non-thinking content\");\n    }\n    case \"toolcall_start\":\n      partial.content[proxyEvent.contentIndex] = {\n        type: \"toolCall\",\n        id: proxyEvent.id,\n        name: proxyEvent.toolName,\n        arguments: {},\n        partialJson: \"\"\n      };\n      return { type: \"toolcall_start\", contentIndex: proxyEvent.contentIndex, partial };\n    case \"toolcall_delta\": {\n      const content = partial.content[proxyEvent.contentIndex];\n      if (content?.type === \"toolCall\") {\n        content.partialJson += proxyEvent.delta;\n        content.arguments = parseStreamingJson2(content.partialJson) || {};\n        partial.content[proxyEvent.contentIndex] = { ...content };\n        return {\n          type: \"toolcall_delta\",\n          contentIndex: proxyEvent.contentIndex,\n          delta: proxyEvent.delta,\n          partial\n        };\n      }\n      throw new Error(\"Received toolcall_delta for non-toolCall content\");\n    }\n    case \"toolcall_end\": {\n      const content = partial.content[proxyEvent.contentIndex];\n      if (content?.type === \"toolCall\") {\n        Object.assign(content, proxyEvent.toolCall);\n        delete content.partialJson;\n        return {\n          type: \"toolcall_end\",\n          contentIndex: proxyEvent.contentIndex,\n          toolCall: content,\n          partial\n        };\n      }\n      return void 0;\n    }\n    case \"done\":\n      partial.stopReason = proxyEvent.reason;\n      partial.usage = proxyEvent.usage;\n      return { type: \"done\", reason: proxyEvent.reason, message: partial };\n    case \"error\":\n      partial.stopReason = proxyEvent.reason;\n      partial.errorMessage = proxyEvent.errorMessage;\n      partial.usage = proxyEvent.usage;\n      return { type: \"error\", reason: proxyEvent.reason, error: partial };\n    default: {\n      const _exhaustiveCheck = proxyEvent;\n      console.warn(`Unhandled proxy event type: ${proxyEvent.type}`);\n      return void 0;\n    }\n  }\n}\n\n// node_modules/.pnpm/@earendil-works+pi-agent-core@0.84.4_ws@8.21.3/node_modules/@earendil-works/pi-agent-core/dist/search/scanning.js\nfunction defaultSearchText(_metadata, entry, label) {\n  return label === void 0 ? JSON.stringify(entry) : `${JSON.stringify(entry)} ${label}`;\n}\nasync function* scanReadableEntries(readable, metadata, options, query = {}) {\n  const projectText = options.projectText ?? defaultSearchText;\n  const pageSize = query.limit ?? options.pageSize ?? 100;\n  let afterSeq = query.afterSeq ?? 0;\n  const entryTypes = query.entryTypes === void 0 ? void 0 : new Set(query.entryTypes);\n  while (true) {\n    const entries = await readable.findEntries({\n      order: \"oldestFirst\",\n      limit: pageSize,\n      cursor: { afterSeq },\n      type: query.entryTypes?.length === 1 ? query.entryTypes[0] : void 0\n    });\n    if (entries.length === 0)\n      break;\n    for (const entry of entries) {\n      if (entryTypes !== void 0 && !entryTypes.has(entry.type))\n        continue;\n      const label = await readable.getLabel(entry.id);\n      yield {\n        entryId: entry.id,\n        seq: entry.seq,\n        type: entry.type,\n        timestamp: entry.timestamp,\n        text: projectText(metadata, entry, label),\n        fields: label === void 0 ? void 0 : { label }\n      };\n    }\n    afterSeq = entries[entries.length - 1]?.seq ?? afterSeq;\n    if (entries.length < pageSize)\n      break;\n  }\n}\nasync function* scanningEntries(readable, options = {}) {\n  yield* scanReadableEntries(readable, await readable.getMetadata(), options);\n}\nasync function* arraySource(readables) {\n  yield* readables;\n}\nfunction readablesFor(source, options) {\n  return typeof source === \"function\" ? source(options) : arraySource(source);\n}\nfunction defaultMatch(queryText, candidate) {\n  return candidate.text.toLowerCase().includes(queryText);\n}\nfunction throwIfAborted(signal) {\n  if (!signal?.aborted)\n    return;\n  if (signal.reason instanceof Error)\n    throw signal.reason;\n  const error = new Error(\"The operation was aborted\");\n  error.name = \"AbortError\";\n  throw error;\n}\nfunction createDefaultScanningHit(metadata, candidate) {\n  return {\n    sessionId: metadata.id,\n    entryId: candidate.entryId,\n    timestamp: candidate.timestamp,\n    snippet: candidate.text\n  };\n}\nfunction createScanningSessionSearch(source, options = {}) {\n  const createHit = options.createHit ?? ((metadata, candidate) => createDefaultScanningHit(metadata, candidate));\n  return {\n    async *search(text, searchOptions = {}) {\n      const normalizedText = text.trim().toLowerCase();\n      if (!normalizedText || searchOptions.limit !== void 0 && searchOptions.limit <= 0)\n        return;\n      if (searchOptions.entryTypes?.length === 0)\n        return;\n      let hitCount = 0;\n      const seenSessionIds = /* @__PURE__ */ new Set();\n      const entryTypes = searchOptions.entryTypes === void 0 ? void 0 : new Set(searchOptions.entryTypes);\n      const sourceOptions = options.sourceOptions?.(normalizedText, searchOptions);\n      for await (const readable of readablesFor(source, sourceOptions)) {\n        throwIfAborted(searchOptions.signal);\n        const metadata = await readable.getMetadata();\n        if (seenSessionIds.has(metadata.id))\n          throw new Error(`Duplicate sessionId: ${metadata.id}`);\n        seenSessionIds.add(metadata.id);\n        for await (const candidate of scanReadableEntries(readable, metadata, options, {\n          entryTypes: searchOptions.entryTypes\n        })) {\n          throwIfAborted(searchOptions.signal);\n          if (entryTypes !== void 0 && !entryTypes.has(candidate.type))\n            continue;\n          const matches = options.match?.(normalizedText, candidate, metadata) ?? defaultMatch(normalizedText, candidate);\n          if (!matches)\n            continue;\n          yield createHit(metadata, candidate);\n          hitCount += 1;\n          if (searchOptions.limit !== void 0 && hitCount >= searchOptions.limit)\n            return;\n        }\n      }\n    }\n  };\n}\n\n// node_modules/.pnpm/@earendil-works+pi-ai@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-ai/dist/oauth.js\nvar oauth_exports = {};\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/core/extensions/loader.js\nimport { createJiti } from \"jiti/static\";\nimport * as _bundledTypebox from \"typebox\";\nimport * as _bundledTypeboxCompile from \"typebox/compile\";\nimport * as _bundledTypeboxValue from \"typebox/value\";\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/index.js\nvar index_exports = {};\n__export(index_exports, {\n  AgentSession: () => AgentSession,\n  AgentSessionRuntime: () => AgentSessionRuntime,\n  ArminComponent: () => ArminComponent,\n  AssistantMessageComponent: () => AssistantMessageComponent,\n  BashExecutionComponent: () => BashExecutionComponent,\n  BorderedLoader: () => BorderedLoader,\n  BranchSummaryMessageComponent: () => BranchSummaryMessageComponent,\n  CONFIG_DIR_NAME: () => CONFIG_DIR_NAME,\n  CURRENT_SESSION_VERSION: () => CURRENT_SESSION_VERSION,\n  CompactionSummaryMessageComponent: () => CompactionSummaryMessageComponent,\n  CredentialSynchronizationError: () => CredentialSynchronizationError,\n  CustomEditor: () => CustomEditor,\n  CustomMessageComponent: () => CustomMessageComponent,\n  DEFAULT_COMPACTION_SETTINGS: () => DEFAULT_COMPACTION_SETTINGS2,\n  DEFAULT_MAX_BYTES: () => DEFAULT_MAX_BYTES3,\n  DEFAULT_MAX_LINES: () => DEFAULT_MAX_LINES2,\n  DefaultPackageManager: () => DefaultPackageManager,\n  DefaultResourceLoader: () => DefaultResourceLoader,\n  DynamicBorder: () => DynamicBorder,\n  ExtensionEditorComponent: () => ExtensionEditorComponent,\n  ExtensionInputComponent: () => ExtensionInputComponent,\n  ExtensionRunner: () => ExtensionRunner,\n  ExtensionSelectorComponent: () => ExtensionSelectorComponent,\n  FooterComponent: () => FooterComponent,\n  InteractiveMode: () => InteractiveMode,\n  LoginDialogComponent: () => LoginDialogComponent,\n  ModelRegistry: () => ModelRegistry,\n  ModelRuntime: () => ModelRuntime,\n  ModelSelectorComponent: () => ModelSelectorComponent,\n  OAuthSelectorComponent: () => OAuthSelectorComponent,\n  ProjectTrustStore: () => ProjectTrustStore,\n  RpcClient: () => RpcClient,\n  SessionManager: () => SessionManager,\n  SessionSelectorComponent: () => SessionSelectorComponent,\n  SettingsManager: () => SettingsManager,\n  SettingsSelectorComponent: () => SettingsSelectorComponent,\n  ShowImagesSelectorComponent: () => ShowImagesSelectorComponent,\n  SkillInvocationMessageComponent: () => SkillInvocationMessageComponent,\n  Theme: () => Theme,\n  ThemeSelectorComponent: () => ThemeSelectorComponent,\n  ThinkingSelectorComponent: () => ThinkingSelectorComponent,\n  ToolExecutionComponent: () => ToolExecutionComponent,\n  TreeSelectorComponent: () => TreeSelectorComponent,\n  UserMessageComponent: () => UserMessageComponent,\n  UserMessageSelectorComponent: () => UserMessageSelectorComponent,\n  VERSION: () => VERSION,\n  buildContextEntries: () => buildContextEntries,\n  buildSessionContext: () => buildSessionContext,\n  calculateContextTokens: () => calculateContextTokens3,\n  collectEntriesForBranchSummary: () => collectEntriesForBranchSummary2,\n  compact: () => compact2,\n  convertToLlm: () => convertToLlm,\n  convertToPng: () => convertToPng,\n  copyToClipboard: () => copyToClipboard,\n  createAgentSession: () => createAgentSession,\n  createAgentSessionFromServices: () => createAgentSessionFromServices,\n  createAgentSessionRuntime: () => createAgentSessionRuntime,\n  createAgentSessionServices: () => createAgentSessionServices,\n  createBashTool: () => createBashTool2,\n  createBashToolDefinition: () => createBashToolDefinition,\n  createCodingTools: () => createCodingTools,\n  createEditTool: () => createEditTool2,\n  createEditToolDefinition: () => createEditToolDefinition,\n  createEventBus: () => createEventBus,\n  createExtensionRuntime: () => createExtensionRuntime,\n  createFindTool: () => createFindTool,\n  createFindToolDefinition: () => createFindToolDefinition,\n  createGrepTool: () => createGrepTool,\n  createGrepToolDefinition: () => createGrepToolDefinition,\n  createLocalBashOperations: () => createLocalBashOperations,\n  createLsTool: () => createLsTool,\n  createLsToolDefinition: () => createLsToolDefinition,\n  createReadOnlyTools: () => createReadOnlyTools,\n  createReadTool: () => createReadTool2,\n  createReadToolDefinition: () => createReadToolDefinition,\n  createSyntheticSourceInfo: () => createSyntheticSourceInfo,\n  createWriteTool: () => createWriteTool2,\n  createWriteToolDefinition: () => createWriteToolDefinition,\n  defineTool: () => defineTool,\n  discoverAndLoadExtensions: () => discoverAndLoadExtensions,\n  estimateTokens: () => estimateTokens3,\n  findCutPoint: () => findCutPoint2,\n  findTurnStartIndex: () => findTurnStartIndex2,\n  formatDimensionNote: () => formatDimensionNote,\n  formatSize: () => formatSize2,\n  formatSkillsForPrompt: () => formatSkillsForPrompt,\n  generateBranchSummary: () => generateBranchSummary2,\n  generateDiffString: () => generateDiffString2,\n  generateSummary: () => generateSummary2,\n  generateSummaryWithUsage: () => generateSummaryWithUsage2,\n  generateUnifiedPatch: () => generateUnifiedPatch2,\n  getAgentDir: () => getAgentDir,\n  getDocsPath: () => getDocsPath,\n  getExamplesPath: () => getExamplesPath,\n  getLanguageFromPath: () => getLanguageFromPath,\n  getLastAssistantUsage: () => getLastAssistantUsage2,\n  getLatestCompactionEntry: () => getLatestCompactionEntry,\n  getMarkdownTheme: () => getMarkdownTheme,\n  getPackageDir: () => getPackageDir,\n  getReadmePath: () => getReadmePath,\n  getSelectListTheme: () => getSelectListTheme,\n  getSettingsListTheme: () => getSettingsListTheme,\n  getShellConfig: () => getShellConfig,\n  hasTrustRequiringProjectResources: () => hasTrustRequiringProjectResources,\n  highlightCode: () => highlightCode,\n  initTheme: () => initTheme,\n  isBashToolResult: () => isBashToolResult,\n  isEditToolResult: () => isEditToolResult,\n  isFindToolResult: () => isFindToolResult,\n  isGrepToolResult: () => isGrepToolResult,\n  isLsToolResult: () => isLsToolResult,\n  isReadToolResult: () => isReadToolResult,\n  isToolCallEventType: () => isToolCallEventType,\n  isWriteToolResult: () => isWriteToolResult,\n  keyHint: () => keyHint,\n  keyText: () => keyText,\n  loadProjectContextFiles: () => loadProjectContextFiles,\n  loadSkills: () => loadSkills2,\n  loadSkillsFromDir: () => loadSkillsFromDir,\n  main: () => main,\n  migrateSessionEntries: () => migrateSessionEntries,\n  parseArgs: () => parseArgs,\n  parseFrontmatter: () => parseFrontmatter3,\n  parseSessionEntries: () => parseSessionEntries,\n  parseSkillBlock: () => parseSkillBlock,\n  prepareBranchEntries: () => prepareBranchEntries2,\n  rawKeyHint: () => rawKeyHint,\n  readStoredCredential: () => readStoredCredential,\n  renderDiff: () => renderDiff,\n  resizeImage: () => resizeImage,\n  resolveCliModel: () => resolveCliModel,\n  resolveModelScopeWithDiagnostics: () => resolveModelScopeWithDiagnostics,\n  runPrintMode: () => runPrintMode,\n  runRpcMode: () => runRpcMode,\n  serializeConversation: () => serializeConversation2,\n  sessionEntryToContextMessages: () => sessionEntryToContextMessages,\n  shouldCompact: () => shouldCompact2,\n  stripFrontmatter: () => stripFrontmatter,\n  truncateHead: () => truncateHead2,\n  truncateLine: () => truncateLine2,\n  truncateTail: () => truncateTail2,\n  truncateToVisualLines: () => truncateToVisualLines,\n  withFileMutationQueue: () => withFileMutationQueue2,\n  wrapRegisteredTool: () => wrapRegisteredTool,\n  wrapRegisteredTools: () => wrapRegisteredTools\n});\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session.js\nimport { existsSync as existsSync16, mkdirSync as mkdirSync7, readFileSync as readFileSync11, writeFileSync as writeFileSync7 } from \"node:fs\";\nimport { basename as basename8, dirname as dirname15 } from \"node:path\";\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/utils/frontmatter.js\nimport { parse as parse3 } from \"yaml\";\nvar normalizeNewlines = (value) => value.replace(/\\r\\n/g, \"\\n\").replace(/\\r/g, \"\\n\");\nvar extractFrontmatter = (content) => {\n  const normalized = normalizeNewlines(content);\n  if (!normalized.startsWith(\"---\")) {\n    return { yamlString: null, body: normalized };\n  }\n  const endIndex = normalized.indexOf(\"\\n---\", 3);\n  if (endIndex === -1) {\n    return { yamlString: null, body: normalized };\n  }\n  return {\n    yamlString: normalized.slice(4, endIndex),\n    body: normalized.slice(endIndex + 4).trim()\n  };\n};\nvar parseFrontmatter3 = (content) => {\n  const { yamlString, body } = extractFrontmatter(content);\n  if (!yamlString) {\n    return { frontmatter: {}, body };\n  }\n  const parsed = parse3(yamlString);\n  return { frontmatter: parsed ?? {}, body };\n};\nvar stripFrontmatter = (content) => parseFrontmatter3(content).body;\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/utils/sleep.js\nfunction sleep5(ms, signal) {\n  return new Promise((resolve15, reject) => {\n    if (signal?.aborted) {\n      reject(new Error(\"Aborted\"));\n      return;\n    }\n    const timeout = setTimeout(resolve15, ms);\n    signal?.addEventListener(\"abort\", () => {\n      clearTimeout(timeout);\n      reject(new Error(\"Aborted\"));\n    });\n  });\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/utils/tool-result-images.js\nasync function normalizeToolResultImages(content, options) {\n  if (!content.some((block) => block.type === \"image\")) {\n    return content;\n  }\n  const autoResizeImages = options?.autoResizeImages ?? true;\n  const normalized = [];\n  let changed = false;\n  for (const block of content) {\n    if (block.type !== \"image\") {\n      normalized.push(block);\n      continue;\n    }\n    const processed = await processImage(Buffer.from(block.data, \"base64\"), block.mimeType, { autoResizeImages });\n    if (!processed.ok) {\n      normalized.push(block);\n      continue;\n    }\n    if (processed.data === block.data && processed.mimeType === block.mimeType && processed.hints.length === 0) {\n      normalized.push(block);\n      continue;\n    }\n    normalized.push({ type: \"image\", data: processed.data, mimeType: processed.mimeType });\n    if (processed.hints.length > 0) {\n      normalized.push({ type: \"text\", text: processed.hints.join(\"\\n\") });\n    }\n    changed = true;\n  }\n  return changed ? normalized : content;\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/core/bash-executor.js\nimport { randomBytes } from \"node:crypto\";\nimport { createWriteStream } from \"node:fs\";\nimport { tmpdir } from \"node:os\";\nimport { join as join18 } from \"node:path\";\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/utils/ansi.js\nfunction ansiRegex({ onlyFirst = false } = {}) {\n  const ST = \"(?:\\\\u0007|\\\\u001B\\\\u005C|\\\\u009C)\";\n  const osc = `(?:\\\\u001B\\\\][\\\\s\\\\S]*?${ST})`;\n  const csi = \"[\\\\u001B\\\\u009B][[\\\\]()#;?]*(?:\\\\d{1,4}(?:[;:]\\\\d{0,4})*)?[\\\\dA-PR-TZcf-nq-uy=><~]\";\n  const pattern = `${osc}|${csi}`;\n  return new RegExp(pattern, onlyFirst ? void 0 : \"g\");\n}\nvar regex = ansiRegex();\nfunction stripAnsi(value) {\n  if (typeof value !== \"string\") {\n    throw new TypeError(`Expected a \\`string\\`, got \\`${typeof value}\\``);\n  }\n  if (!value.includes(\"\\x1B\") && !value.includes(\"\\x9B\")) {\n    return value;\n  }\n  return value.replace(regex, \"\");\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/truncate.js\nvar DEFAULT_MAX_LINES2 = 2e3;\nvar DEFAULT_MAX_BYTES3 = 50 * 1024;\nvar GREP_MAX_LINE_LENGTH2 = 500;\nfunction splitLinesForCounting2(content) {\n  if (content.length === 0) {\n    return [];\n  }\n  const lines = content.split(\"\\n\");\n  if (content.endsWith(\"\\n\")) {\n    lines.pop();\n  }\n  return lines;\n}\nfunction formatSize2(bytes) {\n  if (bytes < 1024) {\n    return `${bytes}B`;\n  } else if (bytes < 1024 * 1024) {\n    return `${(bytes / 1024).toFixed(1)}KB`;\n  } else {\n    return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;\n  }\n}\nfunction truncateHead2(content, options = {}) {\n  const maxLines = options.maxLines ?? DEFAULT_MAX_LINES2;\n  const maxBytes = options.maxBytes ?? DEFAULT_MAX_BYTES3;\n  const totalBytes = Buffer.byteLength(content, \"utf-8\");\n  const lines = splitLinesForCounting2(content);\n  const totalLines = lines.length;\n  if (totalLines <= maxLines && totalBytes <= maxBytes) {\n    return {\n      content,\n      truncated: false,\n      truncatedBy: null,\n      totalLines,\n      totalBytes,\n      outputLines: totalLines,\n      outputBytes: totalBytes,\n      lastLinePartial: false,\n      firstLineExceedsLimit: false,\n      maxLines,\n      maxBytes\n    };\n  }\n  const firstLineBytes = Buffer.byteLength(lines[0], \"utf-8\");\n  if (firstLineBytes > maxBytes) {\n    return {\n      content: \"\",\n      truncated: true,\n      truncatedBy: \"bytes\",\n      totalLines,\n      totalBytes,\n      outputLines: 0,\n      outputBytes: 0,\n      lastLinePartial: false,\n      firstLineExceedsLimit: true,\n      maxLines,\n      maxBytes\n    };\n  }\n  const outputLinesArr = [];\n  let outputBytesCount = 0;\n  let truncatedBy = \"lines\";\n  for (let i = 0; i < lines.length && i < maxLines; i++) {\n    const line = lines[i];\n    const lineBytes = Buffer.byteLength(line, \"utf-8\") + (i > 0 ? 1 : 0);\n    if (outputBytesCount + lineBytes > maxBytes) {\n      truncatedBy = \"bytes\";\n      break;\n    }\n    outputLinesArr.push(line);\n    outputBytesCount += lineBytes;\n  }\n  if (outputLinesArr.length >= maxLines && outputBytesCount <= maxBytes) {\n    truncatedBy = \"lines\";\n  }\n  const outputContent = outputLinesArr.join(\"\\n\");\n  const finalOutputBytes = Buffer.byteLength(outputContent, \"utf-8\");\n  return {\n    content: outputContent,\n    truncated: true,\n    truncatedBy,\n    totalLines,\n    totalBytes,\n    outputLines: outputLinesArr.length,\n    outputBytes: finalOutputBytes,\n    lastLinePartial: false,\n    firstLineExceedsLimit: false,\n    maxLines,\n    maxBytes\n  };\n}\nfunction truncateTail2(content, options = {}) {\n  const maxLines = options.maxLines ?? DEFAULT_MAX_LINES2;\n  const maxBytes = options.maxBytes ?? DEFAULT_MAX_BYTES3;\n  const totalBytes = Buffer.byteLength(content, \"utf-8\");\n  const lines = splitLinesForCounting2(content);\n  const totalLines = lines.length;\n  if (totalLines <= maxLines && totalBytes <= maxBytes) {\n    return {\n      content,\n      truncated: false,\n      truncatedBy: null,\n      totalLines,\n      totalBytes,\n      outputLines: totalLines,\n      outputBytes: totalBytes,\n      lastLinePartial: false,\n      firstLineExceedsLimit: false,\n      maxLines,\n      maxBytes\n    };\n  }\n  const outputLinesArr = [];\n  let outputBytesCount = 0;\n  let truncatedBy = \"lines\";\n  let lastLinePartial = false;\n  for (let i = lines.length - 1; i >= 0 && outputLinesArr.length < maxLines; i--) {\n    const line = lines[i];\n    const lineBytes = Buffer.byteLength(line, \"utf-8\") + (outputLinesArr.length > 0 ? 1 : 0);\n    if (outputBytesCount + lineBytes > maxBytes) {\n      truncatedBy = \"bytes\";\n      if (outputLinesArr.length === 0) {\n        const truncatedLine = truncateStringToBytesFromEnd2(line, maxBytes);\n        outputLinesArr.unshift(truncatedLine);\n        outputBytesCount = Buffer.byteLength(truncatedLine, \"utf-8\");\n        lastLinePartial = true;\n      }\n      break;\n    }\n    outputLinesArr.unshift(line);\n    outputBytesCount += lineBytes;\n  }\n  if (outputLinesArr.length >= maxLines && outputBytesCount <= maxBytes) {\n    truncatedBy = \"lines\";\n  }\n  const outputContent = outputLinesArr.join(\"\\n\");\n  const finalOutputBytes = Buffer.byteLength(outputContent, \"utf-8\");\n  return {\n    content: outputContent,\n    truncated: true,\n    truncatedBy,\n    totalLines,\n    totalBytes,\n    outputLines: outputLinesArr.length,\n    outputBytes: finalOutputBytes,\n    lastLinePartial,\n    firstLineExceedsLimit: false,\n    maxLines,\n    maxBytes\n  };\n}\nfunction truncateStringToBytesFromEnd2(str2, maxBytes) {\n  const buf = Buffer.from(str2, \"utf-8\");\n  if (buf.length <= maxBytes) {\n    return str2;\n  }\n  let start = buf.length - maxBytes;\n  while (start < buf.length && (buf[start] & 192) === 128) {\n    start++;\n  }\n  return buf.slice(start).toString(\"utf-8\");\n}\nfunction truncateLine2(line, maxChars = GREP_MAX_LINE_LENGTH2) {\n  if (line.length <= maxChars) {\n    return { text: line, wasTruncated: false };\n  }\n  return { text: `${line.slice(0, maxChars)}... [truncated]`, wasTruncated: true };\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/core/bash-executor.js\nasync function executeBashWithOperations(command, cwd, operations, options) {\n  const outputChunks = [];\n  let outputBytes = 0;\n  const maxOutputBytes = DEFAULT_MAX_BYTES3 * 2;\n  let tempFilePath;\n  let tempFileStream;\n  let totalBytes = 0;\n  const ensureTempFile = () => {\n    if (tempFilePath) {\n      return;\n    }\n    const id = randomBytes(8).toString(\"hex\");\n    tempFilePath = join18(tmpdir(), `pi-bash-${id}.log`);\n    tempFileStream = createWriteStream(tempFilePath);\n    for (const chunk of outputChunks) {\n      tempFileStream.write(chunk);\n    }\n  };\n  const decoder = new TextDecoder();\n  const onData = (data) => {\n    totalBytes += data.length;\n    const text = sanitizeBinaryOutput(stripAnsi(decoder.decode(data, { stream: true }))).replace(/\\r/g, \"\");\n    if (totalBytes > DEFAULT_MAX_BYTES3) {\n      ensureTempFile();\n    }\n    if (tempFileStream) {\n      tempFileStream.write(text);\n    }\n    outputChunks.push(text);\n    outputBytes += text.length;\n    while (outputBytes > maxOutputBytes && outputChunks.length > 1) {\n      const removed = outputChunks.shift();\n      outputBytes -= removed.length;\n    }\n    if (options?.onChunk) {\n      options.onChunk(text);\n    }\n  };\n  try {\n    const result = await operations.exec(command, cwd, {\n      onData,\n      signal: options?.signal\n    });\n    const fullOutput = outputChunks.join(\"\");\n    const truncationResult = truncateTail2(fullOutput);\n    if (truncationResult.truncated) {\n      ensureTempFile();\n    }\n    if (tempFileStream) {\n      tempFileStream.end();\n    }\n    const cancelled = options?.signal?.aborted ?? false;\n    return {\n      output: truncationResult.truncated ? truncationResult.content : fullOutput,\n      exitCode: cancelled ? void 0 : result.exitCode ?? void 0,\n      cancelled,\n      truncated: truncationResult.truncated,\n      fullOutputPath: tempFilePath\n    };\n  } catch (err2) {\n    if (options?.signal?.aborted) {\n      const fullOutput = outputChunks.join(\"\");\n      const truncationResult = truncateTail2(fullOutput);\n      if (truncationResult.truncated) {\n        ensureTempFile();\n      }\n      if (tempFileStream) {\n        tempFileStream.end();\n      }\n      return {\n        output: truncationResult.truncated ? truncationResult.content : fullOutput,\n        exitCode: void 0,\n        cancelled: true,\n        truncated: truncationResult.truncated,\n        fullOutputPath: tempFilePath\n      };\n    }\n    if (tempFileStream) {\n      tempFileStream.end();\n    }\n    throw err2;\n  }\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/core/compaction/utils.js\nfunction createFileOps2() {\n  return {\n    read: /* @__PURE__ */ new Set(),\n    written: /* @__PURE__ */ new Set(),\n    edited: /* @__PURE__ */ new Set()\n  };\n}\nfunction extractFileOpsFromMessage2(message, fileOps) {\n  if (message.role !== \"assistant\")\n    return;\n  if (!(\"content\" in message) || !Array.isArray(message.content))\n    return;\n  for (const block of message.content) {\n    if (typeof block !== \"object\" || block === null)\n      continue;\n    if (!(\"type\" in block) || block.type !== \"toolCall\")\n      continue;\n    if (!(\"arguments\" in block) || !(\"name\" in block))\n      continue;\n    const args = block.arguments;\n    if (!args)\n      continue;\n    const path12 = typeof args.path === \"string\" ? args.path : void 0;\n    if (!path12)\n      continue;\n    switch (block.name) {\n      case \"read\":\n        fileOps.read.add(path12);\n        break;\n      case \"write\":\n        fileOps.written.add(path12);\n        break;\n      case \"edit\":\n        fileOps.edited.add(path12);\n        break;\n    }\n  }\n}\nfunction computeFileLists2(fileOps) {\n  const modified = /* @__PURE__ */ new Set([...fileOps.edited, ...fileOps.written]);\n  const readOnly = [...fileOps.read].filter((f) => !modified.has(f)).sort();\n  const modifiedFiles = [...modified].sort();\n  return { readFiles: readOnly, modifiedFiles };\n}\nfunction formatFileOperations2(readFiles, modifiedFiles) {\n  const sections = [];\n  if (readFiles.length > 0) {\n    sections.push(`<read-files>\n${readFiles.join(\"\\n\")}\n</read-files>`);\n  }\n  if (modifiedFiles.length > 0) {\n    sections.push(`<modified-files>\n${modifiedFiles.join(\"\\n\")}\n</modified-files>`);\n  }\n  if (sections.length === 0)\n    return \"\";\n  return `\n\n${sections.join(\"\\n\\n\")}`;\n}\nvar TOOL_RESULT_MAX_CHARS2 = 2e3;\nfunction truncateForSummary2(text, maxChars) {\n  if (text.length <= maxChars)\n    return text;\n  const truncatedChars = text.length - maxChars;\n  return `${text.slice(0, maxChars)}\n\n[... ${truncatedChars} more characters truncated]`;\n}\nfunction serializeConversation2(messages) {\n  const parts = [];\n  for (const msg of messages) {\n    if (msg.role === \"user\") {\n      const content = contentText(msg.content, \"\");\n      if (content)\n        parts.push(`[User]: ${content}`);\n    } else if (msg.role === \"assistant\") {\n      const thinkingParts = [];\n      const toolCalls = [];\n      for (const block of msg.content) {\n        if (block.type === \"thinking\") {\n          thinkingParts.push(block.thinking);\n        } else if (block.type === \"toolCall\") {\n          const args = block.arguments;\n          const argsStr = Object.entries(args).map(([k, v]) => `${k}=${JSON.stringify(v)}`).join(\", \");\n          toolCalls.push(`${block.name}(${argsStr})`);\n        }\n      }\n      if (thinkingParts.length > 0) {\n        parts.push(`[Assistant thinking]: ${thinkingParts.join(\"\\n\")}`);\n      }\n      if (msg.content.some((block) => block.type === \"text\")) {\n        parts.push(`[Assistant]: ${contentText(msg.content)}`);\n      }\n      if (toolCalls.length > 0) {\n        parts.push(`[Assistant tool calls]: ${toolCalls.join(\"; \")}`);\n      }\n    } else if (msg.role === \"toolResult\") {\n      const content = contentText(msg.content, \"\");\n      if (content) {\n        parts.push(`[Tool result]: ${truncateForSummary2(content, TOOL_RESULT_MAX_CHARS2)}`);\n      }\n    }\n  }\n  return parts.join(\"\\n\\n\");\n}\nvar SUMMARIZATION_SYSTEM_PROMPT2 = `You are a context summarization assistant. Your task is to read a conversation between a user and an AI assistant, then produce a structured summary following the exact format specified.\n\nDo NOT continue the conversation. Do NOT respond to any questions in the conversation. ONLY output the structured summary.`;\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/core/compaction/compaction.js\nfunction extractFileOperations2(messages, entries, prevCompactionIndex) {\n  const fileOps = createFileOps2();\n  if (prevCompactionIndex >= 0) {\n    const prevCompaction = entries[prevCompactionIndex];\n    if (!prevCompaction.fromHook && prevCompaction.details) {\n      const details = prevCompaction.details;\n      if (Array.isArray(details.readFiles)) {\n        for (const f of details.readFiles)\n          fileOps.read.add(f);\n      }\n      if (Array.isArray(details.modifiedFiles)) {\n        for (const f of details.modifiedFiles)\n          fileOps.edited.add(f);\n      }\n    }\n  }\n  for (const msg of messages) {\n    extractFileOpsFromMessage2(msg, fileOps);\n  }\n  return fileOps;\n}\nfunction getMessageFromEntryForCompaction2(entry) {\n  if (entry.type === \"compaction\") {\n    return void 0;\n  }\n  return sessionEntryToContextMessages(entry)[0];\n}\nfunction combineUsage2(first, second) {\n  return {\n    input: first.input + second.input,\n    output: first.output + second.output,\n    cacheRead: first.cacheRead + second.cacheRead,\n    cacheWrite: first.cacheWrite + second.cacheWrite,\n    ...first.cacheWrite1h !== void 0 || second.cacheWrite1h !== void 0 ? { cacheWrite1h: (first.cacheWrite1h ?? 0) + (second.cacheWrite1h ?? 0) } : {},\n    ...first.reasoning !== void 0 || second.reasoning !== void 0 ? { reasoning: (first.reasoning ?? 0) + (second.reasoning ?? 0) } : {},\n    totalTokens: first.totalTokens + second.totalTokens,\n    cost: {\n      input: first.cost.input + second.cost.input,\n      output: first.cost.output + second.cost.output,\n      cacheRead: first.cost.cacheRead + second.cost.cacheRead,\n      cacheWrite: first.cost.cacheWrite + second.cost.cacheWrite,\n      total: first.cost.total + second.cost.total\n    }\n  };\n}\nvar DEFAULT_COMPACTION_SETTINGS2 = {\n  enabled: true,\n  reserveTokens: 16384,\n  keepRecentTokens: 2e4\n};\nfunction calculateContextTokens3(usage) {\n  return usage.totalTokens || usage.input + usage.output + usage.cacheRead + usage.cacheWrite;\n}\nfunction getAssistantUsage2(msg) {\n  if (msg.role === \"assistant\" && \"usage\" in msg) {\n    const assistantMsg = msg;\n    if (assistantMsg.stopReason !== \"aborted\" && assistantMsg.stopReason !== \"error\" && assistantMsg.usage && calculateContextTokens3(assistantMsg.usage) > 0) {\n      return assistantMsg.usage;\n    }\n  }\n  return void 0;\n}\nfunction getLastAssistantUsage2(entries) {\n  for (let i = entries.length - 1; i >= 0; i--) {\n    const entry = entries[i];\n    if (entry.type === \"message\") {\n      const usage = getAssistantUsage2(entry.message);\n      if (usage)\n        return usage;\n    }\n  }\n  return void 0;\n}\nfunction getLastAssistantUsageInfo3(messages) {\n  for (let i = messages.length - 1; i >= 0; i--) {\n    const usage = getAssistantUsage2(messages[i]);\n    if (usage)\n      return { usage, index: i };\n  }\n  return void 0;\n}\nfunction estimateContextTokens3(messages) {\n  const usageInfo = getLastAssistantUsageInfo3(messages);\n  if (!usageInfo) {\n    let estimated = 0;\n    for (const message of messages) {\n      estimated += estimateTokens3(message);\n    }\n    return {\n      tokens: estimated,\n      usageTokens: 0,\n      trailingTokens: estimated,\n      lastUsageIndex: null\n    };\n  }\n  const usageTokens = calculateContextTokens3(usageInfo.usage);\n  let trailingTokens = 0;\n  for (let i = usageInfo.index + 1; i < messages.length; i++) {\n    trailingTokens += estimateTokens3(messages[i]);\n  }\n  return {\n    tokens: usageTokens + trailingTokens,\n    usageTokens,\n    trailingTokens,\n    lastUsageIndex: usageInfo.index\n  };\n}\nfunction shouldCompact2(contextTokens, contextWindow, settings) {\n  if (!settings.enabled)\n    return false;\n  return contextTokens > contextWindow - settings.reserveTokens;\n}\nvar ESTIMATED_IMAGE_CHARS3 = 4800;\nfunction estimateTextAndImageContentChars3(content) {\n  if (typeof content === \"string\") {\n    return content.length;\n  }\n  let chars = 0;\n  for (const block of content) {\n    if (block.type === \"text\" && block.text) {\n      chars += block.text.length;\n    } else if (block.type === \"image\") {\n      chars += ESTIMATED_IMAGE_CHARS3;\n    }\n  }\n  return chars;\n}\nfunction estimateTokens3(message) {\n  let chars = 0;\n  switch (message.role) {\n    case \"user\": {\n      chars = estimateTextAndImageContentChars3(message.content);\n      return Math.ceil(chars / 4);\n    }\n    case \"assistant\": {\n      const assistant = message;\n      for (const block of assistant.content) {\n        if (block.type === \"text\") {\n          chars += block.text.length;\n        } else if (block.type === \"thinking\") {\n          chars += block.thinking.length;\n        } else if (block.type === \"toolCall\") {\n          chars += block.name.length + JSON.stringify(block.arguments).length;\n        }\n      }\n      return Math.ceil(chars / 4);\n    }\n    case \"custom\":\n    case \"toolResult\": {\n      chars = estimateTextAndImageContentChars3(message.content);\n      return Math.ceil(chars / 4);\n    }\n    case \"bashExecution\": {\n      chars = message.command.length + message.output.length;\n      return Math.ceil(chars / 4);\n    }\n    case \"branchSummary\":\n    case \"compactionSummary\": {\n      chars = message.summary.length;\n      return Math.ceil(chars / 4);\n    }\n  }\n  return 0;\n}\nfunction isCutPointMessage(message) {\n  switch (message.role) {\n    case \"user\":\n    case \"assistant\":\n    case \"bashExecution\":\n    case \"custom\":\n    case \"branchSummary\":\n    case \"compactionSummary\":\n      return true;\n    case \"toolResult\":\n      return false;\n  }\n  return false;\n}\nfunction isTurnStartMessage(message) {\n  switch (message.role) {\n    case \"user\":\n    case \"bashExecution\":\n    case \"custom\":\n    case \"branchSummary\":\n    case \"compactionSummary\":\n      return true;\n    case \"assistant\":\n    case \"toolResult\":\n      return false;\n  }\n  return false;\n}\nfunction isTurnStartEntry(entry) {\n  if (entry.type === \"compaction\") {\n    return false;\n  }\n  return sessionEntryToContextMessages(entry).some(isTurnStartMessage);\n}\nfunction findValidCutPoints2(entries, startIndex, endIndex) {\n  const cutPoints = [];\n  for (let i = startIndex; i < endIndex; i++) {\n    const entry = entries[i];\n    if (entry.type === \"compaction\") {\n      continue;\n    }\n    if (sessionEntryToContextMessages(entry).some(isCutPointMessage)) {\n      cutPoints.push(i);\n    }\n  }\n  return cutPoints;\n}\nfunction findTurnStartIndex2(entries, entryIndex, startIndex) {\n  for (let i = entryIndex; i >= startIndex; i--) {\n    if (isTurnStartEntry(entries[i])) {\n      return i;\n    }\n  }\n  return -1;\n}\nfunction findCutPoint2(entries, startIndex, endIndex, keepRecentTokens) {\n  const cutPoints = findValidCutPoints2(entries, startIndex, endIndex);\n  if (cutPoints.length === 0) {\n    return { firstKeptEntryIndex: startIndex, turnStartIndex: -1, isSplitTurn: false };\n  }\n  let accumulatedTokens = 0;\n  let cutIndex = cutPoints[0];\n  for (let i = endIndex - 1; i >= startIndex; i--) {\n    const entry = entries[i];\n    const messageTokens = sessionEntryToContextMessages(entry).reduce((sum, message) => sum + estimateTokens3(message), 0);\n    if (messageTokens === 0)\n      continue;\n    accumulatedTokens += messageTokens;\n    if (accumulatedTokens >= keepRecentTokens) {\n      for (let c = 0; c < cutPoints.length; c++) {\n        if (cutPoints[c] >= i) {\n          cutIndex = cutPoints[c];\n          break;\n        }\n      }\n      break;\n    }\n  }\n  while (cutIndex > startIndex) {\n    const prevEntry = entries[cutIndex - 1];\n    if (prevEntry.type === \"compaction\" || sessionEntryToContextMessages(prevEntry).length > 0) {\n      break;\n    }\n    cutIndex--;\n  }\n  const cutEntry = entries[cutIndex];\n  const startsTurn = isTurnStartEntry(cutEntry);\n  const turnStartIndex = startsTurn ? -1 : findTurnStartIndex2(entries, cutIndex, startIndex);\n  return {\n    firstKeptEntryIndex: cutIndex,\n    turnStartIndex,\n    isSplitTurn: !startsTurn && turnStartIndex !== -1\n  };\n}\nvar SUMMARIZATION_PROMPT2 = `The messages above are a conversation to summarize. Create a structured context checkpoint summary that another LLM will use to continue the work.\n\nUse this EXACT format:\n\n## Goal\n[What is the user trying to accomplish? Can be multiple items if the session covers different tasks.]\n\n## Constraints & Preferences\n- [Any constraints, preferences, or requirements mentioned by user]\n- [Or \"(none)\" if none were mentioned]\n\n## Progress\n### Done\n- [x] [Completed tasks/changes]\n\n### In Progress\n- [ ] [Current work]\n\n### Blocked\n- [Issues preventing progress, if any]\n\n## Key Decisions\n- **[Decision]**: [Brief rationale]\n\n## Next Steps\n1. [Ordered list of what should happen next]\n\n## Critical Context\n- [Any data, examples, or references needed to continue]\n- [Or \"(none)\" if not applicable]\n\nKeep each section concise. Preserve exact file paths, function names, and error messages.`;\nvar UPDATE_SUMMARIZATION_PROMPT2 = `The messages above are NEW conversation messages to incorporate into the existing summary provided in <previous-summary> tags.\n\nUpdate the existing structured summary with new information. RULES:\n- PRESERVE all existing information from the previous summary\n- ADD new progress, decisions, and context from the new messages\n- UPDATE the Progress section: move items from \"In Progress\" to \"Done\" when completed\n- UPDATE \"Next Steps\" based on what was accomplished\n- PRESERVE exact file paths, function names, and error messages\n- If something is no longer relevant, you may remove it\n\nUse this EXACT format:\n\n## Goal\n[Preserve existing goals, add new ones if the task expanded]\n\n## Constraints & Preferences\n- [Preserve existing, add new ones discovered]\n\n## Progress\n### Done\n- [x] [Include previously done items AND newly completed items]\n\n### In Progress\n- [ ] [Current work - update based on progress]\n\n### Blocked\n- [Current blockers - remove if resolved]\n\n## Key Decisions\n- **[Decision]**: [Brief rationale] (preserve all previous, add new)\n\n## Next Steps\n1. [Update based on current state]\n\n## Critical Context\n- [Preserve important context, add new if needed]\n\nKeep each section concise. Preserve exact file paths, function names, and error messages.`;\nfunction createSummarizationOptions(model, maxTokens, apiKey, headers, env, signal, thinkingLevel) {\n  const options = { maxTokens, signal, apiKey, headers, env };\n  if (model.reasoning && thinkingLevel && thinkingLevel !== \"off\") {\n    options.reasoning = thinkingLevel;\n  }\n  return options;\n}\nasync function completeSummarization(model, context, options, streamFn, retry, callbacks) {\n  const requestOptions = {\n    ...options,\n    cacheRetention: \"none\",\n    sessionId: uuidv7()\n  };\n  const produce = async () => streamFn ? (await streamFn(model, context, requestOptions)).result() : completeSimple(model, context, requestOptions);\n  return retryAssistantCall(produce, retry, requestOptions.signal, callbacks);\n}\nasync function generateSummary2(currentMessages, model, reserveTokens, apiKey, headers, signal, customInstructions, previousSummary, thinkingLevel, streamFn, env, retry, callbacks) {\n  return (await generateSummaryWithUsage2(currentMessages, model, reserveTokens, apiKey, headers, signal, customInstructions, previousSummary, thinkingLevel, streamFn, env, retry, callbacks)).text;\n}\nasync function generateSummaryWithUsage2(currentMessages, model, reserveTokens, apiKey, headers, signal, customInstructions, previousSummary, thinkingLevel, streamFn, env, retry, callbacks) {\n  const maxTokens = Math.min(Math.floor(0.8 * reserveTokens), model.maxTokens > 0 ? model.maxTokens : Number.POSITIVE_INFINITY);\n  let basePrompt = previousSummary ? UPDATE_SUMMARIZATION_PROMPT2 : SUMMARIZATION_PROMPT2;\n  if (customInstructions) {\n    basePrompt = `${basePrompt}\n\nAdditional focus: ${customInstructions}`;\n  }\n  const llmMessages = convertToLlm(currentMessages);\n  const conversationText = serializeConversation2(llmMessages);\n  let promptText = `<conversation>\n${conversationText}\n</conversation>\n\n`;\n  if (previousSummary) {\n    promptText += `<previous-summary>\n${previousSummary}\n</previous-summary>\n\n`;\n  }\n  promptText += basePrompt;\n  const summarizationMessages = [\n    {\n      role: \"user\",\n      content: [{ type: \"text\", text: promptText }],\n      timestamp: Date.now()\n    }\n  ];\n  const completionOptions = createSummarizationOptions(model, maxTokens, apiKey, headers, env, signal, thinkingLevel);\n  const response = await completeSummarization(model, { systemPrompt: SUMMARIZATION_SYSTEM_PROMPT2, messages: summarizationMessages }, completionOptions, streamFn, retry, callbacks);\n  if (response.stopReason === \"error\") {\n    throw new Error(`Summarization failed: ${response.errorMessage || \"Unknown error\"}`);\n  }\n  const textContent = contentText(response.content);\n  return { text: textContent, usage: response.usage };\n}\nfunction prepareCompaction2(pathEntries, settings) {\n  if (pathEntries.length > 0 && pathEntries[pathEntries.length - 1].type === \"compaction\") {\n    return void 0;\n  }\n  let prevCompactionIndex = -1;\n  for (let i = pathEntries.length - 1; i >= 0; i--) {\n    if (pathEntries[i].type === \"compaction\") {\n      prevCompactionIndex = i;\n      break;\n    }\n  }\n  let previousSummary;\n  let boundaryStart = 0;\n  if (prevCompactionIndex >= 0) {\n    const prevCompaction = pathEntries[prevCompactionIndex];\n    previousSummary = prevCompaction.summary;\n    const firstKeptEntryIndex = pathEntries.findIndex((entry) => entry.id === prevCompaction.firstKeptEntryId);\n    boundaryStart = firstKeptEntryIndex >= 0 ? firstKeptEntryIndex : prevCompactionIndex + 1;\n  }\n  const boundaryEnd = pathEntries.length;\n  const tokensBefore = estimateContextTokens3(buildSessionContext(pathEntries).messages).tokens;\n  const cutPoint = findCutPoint2(pathEntries, boundaryStart, boundaryEnd, settings.keepRecentTokens);\n  const firstKeptEntry = pathEntries[cutPoint.firstKeptEntryIndex];\n  if (!firstKeptEntry?.id) {\n    return void 0;\n  }\n  const firstKeptEntryId = firstKeptEntry.id;\n  const historyEnd = cutPoint.isSplitTurn ? cutPoint.turnStartIndex : cutPoint.firstKeptEntryIndex;\n  const messagesToSummarize = [];\n  for (let i = boundaryStart; i < historyEnd; i++) {\n    const msg = getMessageFromEntryForCompaction2(pathEntries[i]);\n    if (msg)\n      messagesToSummarize.push(msg);\n  }\n  const turnPrefixMessages = [];\n  if (cutPoint.isSplitTurn) {\n    for (let i = cutPoint.turnStartIndex; i < cutPoint.firstKeptEntryIndex; i++) {\n      const msg = getMessageFromEntryForCompaction2(pathEntries[i]);\n      if (msg)\n        turnPrefixMessages.push(msg);\n    }\n  }\n  if (messagesToSummarize.length === 0 && turnPrefixMessages.length === 0) {\n    return void 0;\n  }\n  const fileOps = extractFileOperations2(messagesToSummarize, pathEntries, prevCompactionIndex);\n  if (cutPoint.isSplitTurn) {\n    for (const msg of turnPrefixMessages) {\n      extractFileOpsFromMessage2(msg, fileOps);\n    }\n  }\n  return {\n    firstKeptEntryId,\n    messagesToSummarize,\n    turnPrefixMessages,\n    isSplitTurn: cutPoint.isSplitTurn,\n    tokensBefore,\n    previousSummary,\n    fileOps,\n    settings\n  };\n}\nvar TURN_PREFIX_SUMMARIZATION_PROMPT2 = `This is the PREFIX of a turn that was too large to keep. The SUFFIX (recent work) is retained.\n\nSummarize the prefix to provide context for the retained suffix:\n\n## Original Request\n[What did the user ask for in this turn?]\n\n## Early Progress\n- [Key decisions and work done in the prefix]\n\n## Context for Suffix\n- [Information needed to understand the retained recent work]\n\nBe concise. Focus on what's needed to understand the kept suffix.`;\nasync function compact2(preparation, model, apiKey, headers, customInstructions, signal, thinkingLevel, streamFn, env, retry, callbacks) {\n  const { firstKeptEntryId, messagesToSummarize, turnPrefixMessages, isSplitTurn, tokensBefore, previousSummary, fileOps, settings } = preparation;\n  let summary;\n  let summaryUsage;\n  if (isSplitTurn && turnPrefixMessages.length > 0) {\n    let historyText = \"No prior history.\";\n    let historyUsage;\n    if (messagesToSummarize.length > 0) {\n      const historyResult = await generateSummaryWithUsage2(messagesToSummarize, model, settings.reserveTokens, apiKey, headers, signal, customInstructions, previousSummary, thinkingLevel, streamFn, env, retry, callbacks);\n      historyText = historyResult.text;\n      historyUsage = historyResult.usage;\n    }\n    const turnPrefixResult = await generateTurnPrefixSummary2(turnPrefixMessages, model, settings.reserveTokens, apiKey, headers, env, signal, thinkingLevel, streamFn, retry, callbacks);\n    summary = `${historyText}\n\n---\n\n**Turn Context (split turn):**\n\n${turnPrefixResult.text}`;\n    summaryUsage = historyUsage ? combineUsage2(historyUsage, turnPrefixResult.usage) : turnPrefixResult.usage;\n  } else {\n    const result = await generateSummaryWithUsage2(messagesToSummarize, model, settings.reserveTokens, apiKey, headers, signal, customInstructions, previousSummary, thinkingLevel, streamFn, env, retry, callbacks);\n    summary = result.text;\n    summaryUsage = result.usage;\n  }\n  const { readFiles, modifiedFiles } = computeFileLists2(fileOps);\n  summary += formatFileOperations2(readFiles, modifiedFiles);\n  if (!firstKeptEntryId) {\n    throw new Error(\"First kept entry has no UUID - session may need migration\");\n  }\n  return {\n    summary,\n    firstKeptEntryId,\n    tokensBefore,\n    usage: summaryUsage,\n    details: { readFiles, modifiedFiles }\n  };\n}\nasync function generateTurnPrefixSummary2(messages, model, reserveTokens, apiKey, headers, env, signal, thinkingLevel, streamFn, retry, callbacks) {\n  const maxTokens = Math.min(Math.floor(0.5 * reserveTokens), model.maxTokens > 0 ? model.maxTokens : Number.POSITIVE_INFINITY);\n  const llmMessages = convertToLlm(messages);\n  const conversationText = serializeConversation2(llmMessages);\n  const promptText = `<conversation>\n${conversationText}\n</conversation>\n\n${TURN_PREFIX_SUMMARIZATION_PROMPT2}`;\n  const summarizationMessages = [\n    {\n      role: \"user\",\n      content: [{ type: \"text\", text: promptText }],\n      timestamp: Date.now()\n    }\n  ];\n  const response = await completeSummarization(model, { systemPrompt: SUMMARIZATION_SYSTEM_PROMPT2, messages: summarizationMessages }, createSummarizationOptions(model, maxTokens, apiKey, headers, env, signal, thinkingLevel), streamFn, retry, callbacks);\n  if (response.stopReason === \"error\") {\n    throw new Error(`Turn prefix summarization failed: ${response.errorMessage || \"Unknown error\"}`);\n  }\n  return {\n    text: contentText(response.content),\n    usage: response.usage\n  };\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/core/compaction/branch-summarization.js\nfunction collectEntriesForBranchSummary2(session, oldLeafId, targetId) {\n  if (!oldLeafId) {\n    return { entries: [], commonAncestorId: null };\n  }\n  const oldPath = new Set(session.getBranch(oldLeafId).map((e) => e.id));\n  const targetPath = session.getBranch(targetId);\n  let commonAncestorId = null;\n  for (let i = targetPath.length - 1; i >= 0; i--) {\n    if (oldPath.has(targetPath[i].id)) {\n      commonAncestorId = targetPath[i].id;\n      break;\n    }\n  }\n  const entries = [];\n  let current = oldLeafId;\n  while (current && current !== commonAncestorId) {\n    const entry = session.getEntry(current);\n    if (!entry)\n      break;\n    entries.push(entry);\n    current = entry.parentId;\n  }\n  entries.reverse();\n  return { entries, commonAncestorId };\n}\nfunction getMessageFromEntry3(entry) {\n  switch (entry.type) {\n    case \"message\":\n      if (entry.message.role === \"toolResult\")\n        return void 0;\n      return entry.message;\n    case \"custom_message\":\n      return createCustomMessage(entry.customType, entry.content, entry.display, entry.details, entry.timestamp);\n    case \"branch_summary\":\n      return createBranchSummaryMessage(entry.summary, entry.fromId, entry.timestamp);\n    case \"compaction\":\n      return createCompactionSummaryMessage(entry.summary, entry.tokensBefore, entry.timestamp);\n    // These don't contribute to conversation content\n    case \"thinking_level_change\":\n    case \"model_change\":\n    case \"custom\":\n    case \"label\":\n    case \"session_info\":\n      return void 0;\n  }\n}\nfunction prepareBranchEntries2(entries, tokenBudget = 0) {\n  const messages = [];\n  const fileOps = createFileOps2();\n  let totalTokens = 0;\n  for (const entry of entries) {\n    if (entry.type === \"branch_summary\" && !entry.fromHook && entry.details) {\n      const details = entry.details;\n      if (Array.isArray(details.readFiles)) {\n        for (const f of details.readFiles)\n          fileOps.read.add(f);\n      }\n      if (Array.isArray(details.modifiedFiles)) {\n        for (const f of details.modifiedFiles) {\n          fileOps.edited.add(f);\n        }\n      }\n    }\n  }\n  for (let i = entries.length - 1; i >= 0; i--) {\n    const entry = entries[i];\n    const message = getMessageFromEntry3(entry);\n    if (!message)\n      continue;\n    extractFileOpsFromMessage2(message, fileOps);\n    const tokens = estimateTokens3(message);\n    if (tokenBudget > 0 && totalTokens + tokens > tokenBudget) {\n      if (entry.type === \"compaction\" || entry.type === \"branch_summary\") {\n        if (totalTokens < tokenBudget * 0.9) {\n          messages.unshift(message);\n          totalTokens += tokens;\n        }\n      }\n      break;\n    }\n    messages.unshift(message);\n    totalTokens += tokens;\n  }\n  return { messages, fileOps, totalTokens };\n}\nvar BRANCH_SUMMARY_PREAMBLE2 = `The user explored a different conversation branch before returning here.\nSummary of that exploration:\n\n`;\nvar BRANCH_SUMMARY_PROMPT2 = `Create a structured summary of this conversation branch for context when returning later.\n\nUse this EXACT format:\n\n## Goal\n[What was the user trying to accomplish in this branch?]\n\n## Constraints & Preferences\n- [Any constraints, preferences, or requirements mentioned]\n- [Or \"(none)\" if none were mentioned]\n\n## Progress\n### Done\n- [x] [Completed tasks/changes]\n\n### In Progress\n- [ ] [Work that was started but not finished]\n\n### Blocked\n- [Issues preventing progress, if any]\n\n## Key Decisions\n- **[Decision]**: [Brief rationale]\n\n## Next Steps\n1. [What should happen next to continue this work]\n\nKeep each section concise. Preserve exact file paths, function names, and error messages.`;\nasync function generateBranchSummary2(entries, options) {\n  const { model, apiKey, headers, env, signal, customInstructions, replaceInstructions, reserveTokens = 16384, streamFn, retry, callbacks } = options;\n  const contextWindow = model.contextWindow || 128e3;\n  const tokenBudget = contextWindow - reserveTokens;\n  const { messages, fileOps } = prepareBranchEntries2(entries, tokenBudget);\n  if (messages.length === 0) {\n    return { summary: \"No content to summarize\" };\n  }\n  const llmMessages = convertToLlm(messages);\n  const conversationText = serializeConversation2(llmMessages);\n  let instructions;\n  if (replaceInstructions && customInstructions) {\n    instructions = customInstructions;\n  } else if (customInstructions) {\n    instructions = `${BRANCH_SUMMARY_PROMPT2}\n\nAdditional focus: ${customInstructions}`;\n  } else {\n    instructions = BRANCH_SUMMARY_PROMPT2;\n  }\n  const promptText = `<conversation>\n${conversationText}\n</conversation>\n\n${instructions}`;\n  const summarizationMessages = [\n    {\n      role: \"user\",\n      content: [{ type: \"text\", text: promptText }],\n      timestamp: Date.now()\n    }\n  ];\n  const context = { systemPrompt: SUMMARIZATION_SYSTEM_PROMPT2, messages: summarizationMessages };\n  const requestOptions = { apiKey, headers, env, signal, maxTokens: 2048 };\n  const response = await completeSummarization(model, context, requestOptions, streamFn, retry, callbacks);\n  if (response.stopReason === \"aborted\") {\n    return { aborted: true };\n  }\n  if (response.stopReason === \"error\") {\n    return { error: response.errorMessage || \"Summarization failed\" };\n  }\n  let summary = contentText(response.content);\n  summary = BRANCH_SUMMARY_PREAMBLE2 + summary;\n  const { readFiles, modifiedFiles } = computeFileLists2(fileOps);\n  summary += formatFileOperations2(readFiles, modifiedFiles);\n  return {\n    summary: summary || \"No summary generated\",\n    usage: response.usage,\n    readFiles,\n    modifiedFiles\n  };\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/core/export-html/index.js\nimport { existsSync as existsSync12, readFileSync as readFileSync8, writeFileSync as writeFileSync6 } from \"fs\";\nimport { basename as basename4, join as join19 } from \"path\";\nfunction parseColor(color) {\n  const hexMatch = color.match(/^#([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/);\n  if (hexMatch) {\n    return {\n      r: Number.parseInt(hexMatch[1], 16),\n      g: Number.parseInt(hexMatch[2], 16),\n      b: Number.parseInt(hexMatch[3], 16)\n    };\n  }\n  const rgbMatch = color.match(/^rgb\\s*\\(\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)\\s*\\)$/);\n  if (rgbMatch) {\n    return {\n      r: Number.parseInt(rgbMatch[1], 10),\n      g: Number.parseInt(rgbMatch[2], 10),\n      b: Number.parseInt(rgbMatch[3], 10)\n    };\n  }\n  return void 0;\n}\nfunction getLuminance(r, g, b) {\n  const toLinear = (c) => {\n    const s = c / 255;\n    return s <= 0.03928 ? s / 12.92 : ((s + 0.055) / 1.055) ** 2.4;\n  };\n  return 0.2126 * toLinear(r) + 0.7152 * toLinear(g) + 0.0722 * toLinear(b);\n}\nfunction adjustBrightness(color, factor) {\n  const parsed = parseColor(color);\n  if (!parsed)\n    return color;\n  const adjust = (c) => Math.min(255, Math.max(0, Math.round(c * factor)));\n  return `rgb(${adjust(parsed.r)}, ${adjust(parsed.g)}, ${adjust(parsed.b)})`;\n}\nfunction deriveExportColors(baseColor) {\n  const parsed = parseColor(baseColor);\n  if (!parsed) {\n    return {\n      pageBg: \"rgb(24, 24, 30)\",\n      cardBg: \"rgb(30, 30, 36)\",\n      infoBg: \"rgb(60, 55, 40)\"\n    };\n  }\n  const luminance = getLuminance(parsed.r, parsed.g, parsed.b);\n  const isLight = luminance > 0.5;\n  if (isLight) {\n    return {\n      pageBg: adjustBrightness(baseColor, 0.96),\n      cardBg: baseColor,\n      infoBg: `rgb(${Math.min(255, parsed.r + 10)}, ${Math.min(255, parsed.g + 5)}, ${Math.max(0, parsed.b - 20)})`\n    };\n  }\n  return {\n    pageBg: adjustBrightness(baseColor, 0.7),\n    cardBg: adjustBrightness(baseColor, 0.85),\n    infoBg: `rgb(${Math.min(255, parsed.r + 20)}, ${Math.min(255, parsed.g + 15)}, ${parsed.b})`\n  };\n}\nfunction generateThemeVars(themeName) {\n  const colors = getResolvedThemeColors(themeName);\n  const lines = [];\n  for (const [key, value] of Object.entries(colors)) {\n    lines.push(`--${key}: ${value};`);\n  }\n  const themeExport = getThemeExportColors(themeName);\n  const userMessageBg = colors.userMessageBg || \"#343541\";\n  const derivedColors = deriveExportColors(userMessageBg);\n  lines.push(`--exportPageBg: ${themeExport.pageBg ?? derivedColors.pageBg};`);\n  lines.push(`--exportCardBg: ${themeExport.cardBg ?? derivedColors.cardBg};`);\n  lines.push(`--exportInfoBg: ${themeExport.infoBg ?? derivedColors.infoBg};`);\n  return lines.join(\"\\n      \");\n}\nfunction generateHtml(sessionData, themeName) {\n  const templateDir = getExportTemplateDir();\n  const template = readFileSync8(join19(templateDir, \"template.html\"), \"utf-8\");\n  const templateCss = readFileSync8(join19(templateDir, \"template.css\"), \"utf-8\");\n  const templateJs = readFileSync8(join19(templateDir, \"template.js\"), \"utf-8\");\n  const markedJs = readFileSync8(join19(templateDir, \"vendor\", \"marked.min.js\"), \"utf-8\");\n  const hljsJs = readFileSync8(join19(templateDir, \"vendor\", \"highlight.min.js\"), \"utf-8\");\n  const themeVars = generateThemeVars(themeName);\n  const colors = getResolvedThemeColors(themeName);\n  const themeExport = getThemeExportColors(themeName);\n  const derivedExportColors = deriveExportColors(colors.userMessageBg || \"#343541\");\n  const bodyBg = themeExport.pageBg ?? derivedExportColors.pageBg;\n  const containerBg = themeExport.cardBg ?? derivedExportColors.cardBg;\n  const infoBg = themeExport.infoBg ?? derivedExportColors.infoBg;\n  const sessionDataBase64 = Buffer.from(JSON.stringify(sessionData)).toString(\"base64\");\n  const css = templateCss.replace(\"{{THEME_VARS}}\", themeVars).replace(\"{{BODY_BG}}\", bodyBg).replace(\"{{CONTAINER_BG}}\", containerBg).replace(\"{{INFO_BG}}\", infoBg);\n  return template.replace(\"{{CSS}}\", css).replace(\"{{JS}}\", templateJs).replace(\"{{SESSION_DATA}}\", sessionDataBase64).replace(\"{{MARKED_JS}}\", markedJs).replace(\"{{HIGHLIGHT_JS}}\", hljsJs);\n}\nvar TEMPLATE_RENDERED_TOOLS = /* @__PURE__ */ new Set([\"bash\", \"read\", \"write\", \"edit\", \"ls\"]);\nfunction preRenderCustomTools(entries, toolRenderer) {\n  const renderedTools = {};\n  for (const entry of entries) {\n    if (entry.type !== \"message\")\n      continue;\n    const msg = entry.message;\n    if (msg.role === \"assistant\" && Array.isArray(msg.content)) {\n      for (const block of msg.content) {\n        if (block.type === \"toolCall\" && !TEMPLATE_RENDERED_TOOLS.has(block.name)) {\n          const callHtml = toolRenderer.renderCall(block.id, block.name, block.arguments);\n          if (callHtml) {\n            renderedTools[block.id] = { callHtml };\n          }\n        }\n      }\n    }\n    if (msg.role === \"toolResult\" && msg.toolCallId) {\n      const toolName = msg.toolName || \"\";\n      const existing = renderedTools[msg.toolCallId];\n      if (existing || !TEMPLATE_RENDERED_TOOLS.has(toolName)) {\n        const rendered = toolRenderer.renderResult(msg.toolCallId, toolName, msg.content, msg.details, msg.isError || false);\n        if (rendered) {\n          renderedTools[msg.toolCallId] = {\n            ...existing,\n            resultHtmlCollapsed: rendered.collapsed,\n            resultHtmlExpanded: rendered.expanded\n          };\n        }\n      }\n    }\n  }\n  return renderedTools;\n}\nasync function exportSessionToHtml(sm, state, options) {\n  const opts = typeof options === \"string\" ? { outputPath: options } : options || {};\n  const sessionFile = sm.getSessionFile();\n  if (!sessionFile) {\n    throw new Error(\"Cannot export in-memory session to HTML\");\n  }\n  if (!existsSync12(sessionFile)) {\n    throw new Error(\"Nothing to export yet - start a conversation first\");\n  }\n  const entries = sm.getEntries();\n  let renderedTools;\n  if (opts.toolRenderer) {\n    renderedTools = preRenderCustomTools(entries, opts.toolRenderer);\n    if (Object.keys(renderedTools).length === 0) {\n      renderedTools = void 0;\n    }\n  }\n  const sessionData = {\n    header: sm.getHeader(),\n    entries,\n    leafId: sm.getLeafId(),\n    systemPrompt: state?.systemPrompt,\n    tools: state?.tools?.map((t) => ({ name: t.name, description: t.description, parameters: t.parameters })),\n    renderedTools\n  };\n  const html = generateHtml(sessionData, opts.themeName);\n  let outputPath = opts.outputPath ? normalizePath(opts.outputPath) : void 0;\n  if (!outputPath) {\n    const sessionBasename = basename4(sessionFile, \".jsonl\");\n    outputPath = `${APP_NAME}-session-${sessionBasename}.html`;\n  }\n  writeFileSync6(outputPath, html, \"utf8\");\n  return outputPath;\n}\nasync function exportFromFile(inputPath, options) {\n  const opts = typeof options === \"string\" ? { outputPath: options } : options || {};\n  const resolvedInputPath = resolvePath(inputPath);\n  if (!existsSync12(resolvedInputPath)) {\n    throw new Error(`File not found: ${resolvedInputPath}`);\n  }\n  const sm = SessionManager.open(resolvedInputPath);\n  const sessionData = {\n    header: sm.getHeader(),\n    entries: sm.getEntries(),\n    leafId: sm.getLeafId(),\n    systemPrompt: void 0,\n    tools: void 0\n  };\n  const html = generateHtml(sessionData, opts.themeName);\n  let outputPath = opts.outputPath ? normalizePath(opts.outputPath) : void 0;\n  if (!outputPath) {\n    const inputBasename = basename4(resolvedInputPath, \".jsonl\");\n    outputPath = `${APP_NAME}-session-${inputBasename}.html`;\n  }\n  writeFileSync6(outputPath, html, \"utf8\");\n  return outputPath;\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/core/export-html/ansi-to-html.js\nvar ANSI_COLORS = [\n  \"#000000\",\n  // 0: black\n  \"#800000\",\n  // 1: red\n  \"#008000\",\n  // 2: green\n  \"#808000\",\n  // 3: yellow\n  \"#000080\",\n  // 4: blue\n  \"#800080\",\n  // 5: magenta\n  \"#008080\",\n  // 6: cyan\n  \"#c0c0c0\",\n  // 7: white\n  \"#808080\",\n  // 8: bright black\n  \"#ff0000\",\n  // 9: bright red\n  \"#00ff00\",\n  // 10: bright green\n  \"#ffff00\",\n  // 11: bright yellow\n  \"#0000ff\",\n  // 12: bright blue\n  \"#ff00ff\",\n  // 13: bright magenta\n  \"#00ffff\",\n  // 14: bright cyan\n  \"#ffffff\"\n  // 15: bright white\n];\nfunction color256ToHex(index) {\n  if (index < 16) {\n    return ANSI_COLORS[index];\n  }\n  if (index < 232) {\n    const cubeIndex = index - 16;\n    const r = Math.floor(cubeIndex / 36);\n    const g = Math.floor(cubeIndex % 36 / 6);\n    const b = cubeIndex % 6;\n    const toComponent = (n) => n === 0 ? 0 : 55 + n * 40;\n    const toHex = (n) => toComponent(n).toString(16).padStart(2, \"0\");\n    return `#${toHex(r)}${toHex(g)}${toHex(b)}`;\n  }\n  const gray = 8 + (index - 232) * 10;\n  const grayHex = gray.toString(16).padStart(2, \"0\");\n  return `#${grayHex}${grayHex}${grayHex}`;\n}\nfunction escapeHtml(text) {\n  return text.replace(/&/g, \"&amp;\").replace(/</g, \"&lt;\").replace(/>/g, \"&gt;\").replace(/\"/g, \"&quot;\").replace(/'/g, \"&#039;\");\n}\nfunction createEmptyStyle() {\n  return {\n    fg: null,\n    bg: null,\n    bold: false,\n    dim: false,\n    italic: false,\n    underline: false\n  };\n}\nfunction styleToInlineCSS(style) {\n  const parts = [];\n  if (style.fg)\n    parts.push(`color:${style.fg}`);\n  if (style.bg)\n    parts.push(`background-color:${style.bg}`);\n  if (style.bold)\n    parts.push(\"font-weight:bold\");\n  if (style.dim)\n    parts.push(\"opacity:0.6\");\n  if (style.italic)\n    parts.push(\"font-style:italic\");\n  if (style.underline)\n    parts.push(\"text-decoration:underline\");\n  return parts.join(\";\");\n}\nfunction hasStyle(style) {\n  return style.fg !== null || style.bg !== null || style.bold || style.dim || style.italic || style.underline;\n}\nfunction applySgrCode(params, style) {\n  let i = 0;\n  while (i < params.length) {\n    const code = params[i];\n    if (code === 0) {\n      style.fg = null;\n      style.bg = null;\n      style.bold = false;\n      style.dim = false;\n      style.italic = false;\n      style.underline = false;\n    } else if (code === 1) {\n      style.bold = true;\n    } else if (code === 2) {\n      style.dim = true;\n    } else if (code === 3) {\n      style.italic = true;\n    } else if (code === 4) {\n      style.underline = true;\n    } else if (code === 22) {\n      style.bold = false;\n      style.dim = false;\n    } else if (code === 23) {\n      style.italic = false;\n    } else if (code === 24) {\n      style.underline = false;\n    } else if (code >= 30 && code <= 37) {\n      style.fg = ANSI_COLORS[code - 30];\n    } else if (code === 38) {\n      if (params[i + 1] === 5 && params.length > i + 2) {\n        style.fg = color256ToHex(params[i + 2]);\n        i += 2;\n      } else if (params[i + 1] === 2 && params.length > i + 4) {\n        const r = params[i + 2];\n        const g = params[i + 3];\n        const b = params[i + 4];\n        style.fg = `rgb(${r},${g},${b})`;\n        i += 4;\n      }\n    } else if (code === 39) {\n      style.fg = null;\n    } else if (code >= 40 && code <= 47) {\n      style.bg = ANSI_COLORS[code - 40];\n    } else if (code === 48) {\n      if (params[i + 1] === 5 && params.length > i + 2) {\n        style.bg = color256ToHex(params[i + 2]);\n        i += 2;\n      } else if (params[i + 1] === 2 && params.length > i + 4) {\n        const r = params[i + 2];\n        const g = params[i + 3];\n        const b = params[i + 4];\n        style.bg = `rgb(${r},${g},${b})`;\n        i += 4;\n      }\n    } else if (code === 49) {\n      style.bg = null;\n    } else if (code >= 90 && code <= 97) {\n      style.fg = ANSI_COLORS[code - 90 + 8];\n    } else if (code >= 100 && code <= 107) {\n      style.bg = ANSI_COLORS[code - 100 + 8];\n    }\n    i++;\n  }\n}\nvar ANSI_REGEX = /\\x1b\\[([\\d;]*)m/g;\nfunction ansiToHtml(text) {\n  const style = createEmptyStyle();\n  let result = \"\";\n  let lastIndex = 0;\n  let inSpan = false;\n  ANSI_REGEX.lastIndex = 0;\n  let match = ANSI_REGEX.exec(text);\n  while (match !== null) {\n    const beforeText = text.slice(lastIndex, match.index);\n    if (beforeText) {\n      result += escapeHtml(beforeText);\n    }\n    const paramStr = match[1];\n    const params = paramStr ? paramStr.split(\";\").map((p) => parseInt(p, 10) || 0) : [0];\n    if (inSpan) {\n      result += \"</span>\";\n      inSpan = false;\n    }\n    applySgrCode(params, style);\n    if (hasStyle(style)) {\n      result += `<span style=\"${styleToInlineCSS(style)}\">`;\n      inSpan = true;\n    }\n    lastIndex = match.index + match[0].length;\n    match = ANSI_REGEX.exec(text);\n  }\n  const remainingText = text.slice(lastIndex);\n  if (remainingText) {\n    result += escapeHtml(remainingText);\n  }\n  if (inSpan) {\n    result += \"</span>\";\n  }\n  return result;\n}\nfunction ansiLinesToHtml(lines) {\n  return lines.map((line) => `<div class=\"ansi-line\">${ansiToHtml(line) || \"&nbsp;\"}</div>`).join(\"\");\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/core/export-html/tool-renderer.js\nvar ANSI_ESCAPE_REGEX = /\\x1b\\[[\\d;]*m/g;\nfunction isBlankRenderedLine(line) {\n  return line.replace(ANSI_ESCAPE_REGEX, \"\").trim().length === 0;\n}\nfunction trimRenderedResultLines(lines) {\n  let start = 0;\n  let end = lines.length;\n  while (start < end && isBlankRenderedLine(lines[start]))\n    start++;\n  while (end > start && isBlankRenderedLine(lines[end - 1]))\n    end--;\n  return lines.slice(start, end);\n}\nfunction createToolHtmlRenderer(deps) {\n  const { getToolDefinition, theme: theme2, cwd, width = 100 } = deps;\n  const renderedCallComponents = /* @__PURE__ */ new Map();\n  const renderedResultComponents = /* @__PURE__ */ new Map();\n  const renderedStates = /* @__PURE__ */ new Map();\n  const renderedArgs = /* @__PURE__ */ new Map();\n  const getState2 = (toolCallId) => {\n    let state = renderedStates.get(toolCallId);\n    if (!state) {\n      state = {};\n      renderedStates.set(toolCallId, state);\n    }\n    return state;\n  };\n  const createRenderContext = (toolCallId, lastComponent, expanded, isPartial, isError) => {\n    return {\n      args: renderedArgs.get(toolCallId),\n      toolCallId,\n      invalidate: () => {\n      },\n      lastComponent,\n      state: getState2(toolCallId),\n      cwd,\n      executionStarted: true,\n      argsComplete: true,\n      isPartial,\n      expanded,\n      showImages: false,\n      isError\n    };\n  };\n  return {\n    renderCall(toolCallId, toolName, args) {\n      try {\n        renderedArgs.set(toolCallId, args);\n        const toolDef = getToolDefinition(toolName);\n        if (!toolDef?.renderCall) {\n          return void 0;\n        }\n        const component = toolDef.renderCall(args, theme2, createRenderContext(toolCallId, renderedCallComponents.get(toolCallId), false, true, false));\n        renderedCallComponents.set(toolCallId, component);\n        const lines = component.render(width);\n        return ansiLinesToHtml(lines);\n      } catch {\n        return void 0;\n      }\n    },\n    renderResult(toolCallId, toolName, result, details, isError) {\n      try {\n        const toolDef = getToolDefinition(toolName);\n        if (!toolDef?.renderResult) {\n          return void 0;\n        }\n        const agentToolResult = {\n          content: result,\n          details,\n          isError\n        };\n        const collapsedComponent = toolDef.renderResult(agentToolResult, { expanded: false, isPartial: false }, theme2, createRenderContext(toolCallId, renderedResultComponents.get(toolCallId), false, false, isError));\n        renderedResultComponents.set(toolCallId, collapsedComponent);\n        const collapsed = ansiLinesToHtml(trimRenderedResultLines(collapsedComponent.render(width)));\n        const expandedComponent = toolDef.renderResult(agentToolResult, { expanded: true, isPartial: false }, theme2, createRenderContext(toolCallId, renderedResultComponents.get(toolCallId), true, false, isError));\n        renderedResultComponents.set(toolCallId, expandedComponent);\n        const expanded = ansiLinesToHtml(trimRenderedResultLines(expandedComponent.render(width)));\n        return {\n          ...collapsed && collapsed !== expanded ? { collapsed } : {},\n          expanded\n        };\n      } catch {\n        return void 0;\n      }\n    }\n  };\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/core/extensions/types.js\nfunction defineTool(tool) {\n  return tool;\n}\nfunction isBashToolResult(e) {\n  return e.toolName === \"bash\";\n}\nfunction isReadToolResult(e) {\n  return e.toolName === \"read\";\n}\nfunction isEditToolResult(e) {\n  return e.toolName === \"edit\";\n}\nfunction isWriteToolResult(e) {\n  return e.toolName === \"write\";\n}\nfunction isGrepToolResult(e) {\n  return e.toolName === \"grep\";\n}\nfunction isFindToolResult(e) {\n  return e.toolName === \"find\";\n}\nfunction isLsToolResult(e) {\n  return e.toolName === \"ls\";\n}\nfunction isToolCallEventType(toolName, event) {\n  return event.toolName === toolName;\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/tool-definition-wrapper.js\nfunction wrapToolDefinition(definition, ctxFactory) {\n  return {\n    name: definition.name,\n    label: definition.label,\n    description: definition.description,\n    parameters: definition.parameters,\n    constrainedSampling: definition.constrainedSampling,\n    prepareArguments: definition.prepareArguments,\n    executionMode: definition.executionMode,\n    execute: (toolCallId, params, signal, onUpdate, ctx) => definition.execute(toolCallId, params, signal, onUpdate, ctx ?? ctxFactory?.())\n  };\n}\nfunction createToolDefinitionFromAgentTool(tool) {\n  return {\n    name: tool.name,\n    label: tool.label,\n    description: tool.description,\n    parameters: tool.parameters,\n    constrainedSampling: tool.constrainedSampling,\n    prepareArguments: tool.prepareArguments,\n    executionMode: tool.executionMode,\n    execute: async (toolCallId, params, signal, onUpdate) => tool.execute(toolCallId, params, signal, onUpdate)\n  };\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/core/extensions/wrapper.js\nfunction wrapRegisteredTool(registeredTool, runner) {\n  const tool = wrapToolDefinition(registeredTool.definition, () => runner.createContext());\n  const execute = tool.execute;\n  return {\n    ...tool,\n    execute: async (toolCallId, params, signal, onUpdate) => {\n      const activeBefore = runner.getActiveTools();\n      const result = await execute(toolCallId, params, signal, onUpdate);\n      const activeAfter = runner.getActiveTools();\n      if (!activeBefore.every((name) => activeAfter.includes(name)))\n        return result;\n      const beforeNames = new Set(activeBefore);\n      const addedToolNames = activeAfter.filter((name) => !beforeNames.has(name));\n      if (addedToolNames.length === 0)\n        return result;\n      return {\n        ...result,\n        addedToolNames: [.../* @__PURE__ */ new Set([...result.addedToolNames ?? [], ...addedToolNames])]\n      };\n    }\n  };\n}\nfunction wrapRegisteredTools(registeredTools, runner) {\n  return registeredTools.map((tool) => wrapRegisteredTool(tool, runner));\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/core/model-registry.js\nvar ModelRegistry = class {\n  runtime;\n  constructor(runtime) {\n    this.runtime = runtime;\n  }\n  /** Reload models.json asynchronously. Await before making synchronous registry reads. */\n  refresh(options) {\n    return this.runtime.refresh(options);\n  }\n  getError() {\n    return this.runtime.getError();\n  }\n  getAll() {\n    return [...this.runtime.getModels()];\n  }\n  getAvailable() {\n    return [...this.runtime.getAvailableSnapshot()];\n  }\n  find(provider, modelId) {\n    return this.runtime.getModel(provider, modelId);\n  }\n  hasConfiguredAuth(model) {\n    return this.runtime.hasConfiguredAuth(model.provider);\n  }\n  async getApiKeyAndHeaders(model) {\n    try {\n      const resolution = await this.runtime.getAuth(model);\n      if (!resolution) {\n        const compatibility = this.runtime.getCompatibilityRequestConfig(model);\n        if (compatibility.authHeader) {\n          return { ok: false, error: `No API key found for \"${model.provider}\"` };\n        }\n        return { ok: true, headers: compatibility.headers };\n      }\n      return {\n        ok: true,\n        apiKey: resolution.auth.apiKey,\n        headers: resolution.auth.headers,\n        ...resolution.auth.baseUrl ? { baseUrl: resolution.auth.baseUrl } : {},\n        env: resolution.env\n      };\n    } catch (error) {\n      const cause = error instanceof Error ? error.cause : void 0;\n      const message = cause instanceof Error ? cause.message : error instanceof Error ? error.message : String(error);\n      return {\n        ok: false,\n        error: message === \"authHeader requires a resolved API key\" ? `No API key found for \"${model.provider}\"` : message\n      };\n    }\n  }\n  getProviderAuthStatus(provider) {\n    return this.runtime.getProviderAuthStatus(provider);\n  }\n  getProvider(provider) {\n    return this.runtime.getProvider(provider);\n  }\n  complete(model, context, options) {\n    return this.runtime.complete(model, context, options);\n  }\n  getProviderDisplayName(provider) {\n    return this.runtime.getProvider(provider)?.name ?? provider;\n  }\n  getProviderAuth(provider) {\n    return this.runtime.getAuth(provider);\n  }\n  async getApiKeyForProvider(provider) {\n    try {\n      return (await this.runtime.getAuth(provider))?.auth.apiKey;\n    } catch {\n      return void 0;\n    }\n  }\n  isUsingOAuth(model) {\n    return this.runtime.isUsingOAuth(model.provider);\n  }\n  registerProvider(providerOrName, config) {\n    if (typeof providerOrName === \"string\") {\n      if (!config)\n        throw new Error(\"Provider config is required when registering by name\");\n      this.runtime.registerProvider(providerOrName, config);\n      return;\n    }\n    this.runtime.registerNativeProvider(providerOrName);\n  }\n  unregisterProvider(providerName) {\n    this.runtime.unregisterProvider(providerName);\n  }\n  getRegisteredProviderConfig(providerName) {\n    return this.runtime.getRegisteredProviderConfig(providerName);\n  }\n  getRegisteredNativeProvider(providerName) {\n    return this.runtime.getRegisteredNativeProvider(providerName);\n  }\n  getRegisteredProviderIds() {\n    return this.runtime.getRegisteredProviderIds();\n  }\n};\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/core/prompt-templates.js\nimport { existsSync as existsSync13, readdirSync as readdirSync5, readFileSync as readFileSync9, statSync as statSync6 } from \"fs\";\nimport { basename as basename5, dirname as dirname11, join as join20, resolve as resolve5, sep as sep4 } from \"path\";\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/core/source-info.js\nfunction createSourceInfo(path12, metadata) {\n  return {\n    path: path12,\n    source: metadata.source,\n    scope: metadata.scope,\n    origin: metadata.origin,\n    baseDir: metadata.baseDir\n  };\n}\nfunction createSyntheticSourceInfo(path12, options) {\n  return {\n    path: path12,\n    source: options.source,\n    scope: options.scope ?? \"temporary\",\n    origin: options.origin ?? \"top-level\",\n    baseDir: options.baseDir\n  };\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/core/prompt-templates.js\nfunction parseCommandArgs2(argsString) {\n  const args = [];\n  let current = \"\";\n  let inQuote = null;\n  for (let i = 0; i < argsString.length; i++) {\n    const char = argsString[i];\n    if (inQuote) {\n      if (char === inQuote) {\n        inQuote = null;\n      } else {\n        current += char;\n      }\n    } else if (char === '\"' || char === \"'\") {\n      inQuote = char;\n    } else if (/\\s/.test(char)) {\n      if (current) {\n        args.push(current);\n        current = \"\";\n      }\n    } else {\n      current += char;\n    }\n  }\n  if (current) {\n    args.push(current);\n  }\n  return args;\n}\nfunction substituteArgs2(content, args) {\n  const allArgs = args.join(\" \");\n  return content.replace(/\\$\\{(\\d+|ARGUMENTS|@):-([^}]*)\\}|\\$\\{@:(\\d+)(?::(\\d+))?\\}|\\$(ARGUMENTS|@|\\d+)/g, (_match, defaultTarget, defaultValue, sliceStart, sliceLength, simple) => {\n    if (defaultTarget) {\n      const value = defaultTarget === \"@\" || defaultTarget === \"ARGUMENTS\" ? allArgs : args[parseInt(defaultTarget, 10) - 1];\n      return value ? value : defaultValue;\n    }\n    if (sliceStart) {\n      let start = parseInt(sliceStart, 10) - 1;\n      if (start < 0)\n        start = 0;\n      if (sliceLength) {\n        const length = parseInt(sliceLength, 10);\n        return args.slice(start, start + length).join(\" \");\n      }\n      return args.slice(start).join(\" \");\n    }\n    if (simple === \"ARGUMENTS\" || simple === \"@\") {\n      return allArgs;\n    }\n    const index = parseInt(simple, 10) - 1;\n    return args[index] ?? \"\";\n  });\n}\nfunction loadTemplateFromFile2(filePath, sourceInfo) {\n  try {\n    const rawContent = readFileSync9(filePath, \"utf-8\");\n    const { frontmatter, body } = parseFrontmatter3(rawContent);\n    const name = basename5(filePath).replace(/\\.md$/, \"\");\n    let description = frontmatter.description || \"\";\n    if (!description) {\n      const firstLine = body.split(\"\\n\").find((line) => line.trim());\n      if (firstLine) {\n        description = firstLine.slice(0, 60);\n        if (firstLine.length > 60)\n          description += \"...\";\n      }\n    }\n    return {\n      name,\n      description,\n      ...frontmatter[\"argument-hint\"] && { argumentHint: frontmatter[\"argument-hint\"] },\n      content: body,\n      sourceInfo,\n      filePath\n    };\n  } catch {\n    return null;\n  }\n}\nfunction loadTemplatesFromDir2(dir, getSourceInfo) {\n  const templates = [];\n  if (!existsSync13(dir)) {\n    return templates;\n  }\n  try {\n    const entries = readdirSync5(dir, { withFileTypes: true });\n    for (const entry of entries) {\n      const fullPath = join20(dir, entry.name);\n      let isFile = entry.isFile();\n      if (entry.isSymbolicLink()) {\n        try {\n          const stats = statSync6(fullPath);\n          isFile = stats.isFile();\n        } catch {\n          continue;\n        }\n      }\n      if (isFile && entry.name.endsWith(\".md\")) {\n        const template = loadTemplateFromFile2(fullPath, getSourceInfo(fullPath));\n        if (template) {\n          templates.push(template);\n        }\n      }\n    }\n  } catch {\n    return templates;\n  }\n  return templates;\n}\nfunction loadPromptTemplates2(options) {\n  const resolvedCwd = resolvePath(options.cwd);\n  const resolvedAgentDir = resolvePath(options.agentDir);\n  const promptPaths = options.promptPaths;\n  const includeDefaults = options.includeDefaults;\n  const templates = [];\n  const globalPromptsDir = join20(resolvedAgentDir, \"prompts\");\n  const projectPromptsDir = resolve5(resolvedCwd, CONFIG_DIR_NAME, \"prompts\");\n  const isUnderPath = (target, root) => {\n    const normalizedRoot = resolve5(root);\n    if (target === normalizedRoot) {\n      return true;\n    }\n    const prefix = normalizedRoot.endsWith(sep4) ? normalizedRoot : `${normalizedRoot}${sep4}`;\n    return target.startsWith(prefix);\n  };\n  const getSourceInfo = (resolvedPath) => {\n    if (isUnderPath(resolvedPath, globalPromptsDir)) {\n      return createSyntheticSourceInfo(resolvedPath, {\n        source: \"local\",\n        scope: \"user\",\n        baseDir: globalPromptsDir\n      });\n    }\n    if (isUnderPath(resolvedPath, projectPromptsDir)) {\n      return createSyntheticSourceInfo(resolvedPath, {\n        source: \"local\",\n        scope: \"project\",\n        baseDir: projectPromptsDir\n      });\n    }\n    return createSyntheticSourceInfo(resolvedPath, {\n      source: \"local\",\n      baseDir: statSync6(resolvedPath).isDirectory() ? resolvedPath : dirname11(resolvedPath)\n    });\n  };\n  if (includeDefaults) {\n    templates.push(...loadTemplatesFromDir2(globalPromptsDir, getSourceInfo));\n    templates.push(...loadTemplatesFromDir2(projectPromptsDir, getSourceInfo));\n  }\n  for (const rawPath of promptPaths) {\n    const resolvedPath = resolvePath(rawPath, resolvedCwd, { trim: true });\n    if (!existsSync13(resolvedPath)) {\n      continue;\n    }\n    try {\n      const stats = statSync6(resolvedPath);\n      if (stats.isDirectory()) {\n        templates.push(...loadTemplatesFromDir2(resolvedPath, getSourceInfo));\n      } else if (stats.isFile() && resolvedPath.endsWith(\".md\")) {\n        const template = loadTemplateFromFile2(resolvedPath, getSourceInfo(resolvedPath));\n        if (template) {\n          templates.push(template);\n        }\n      }\n    } catch {\n    }\n  }\n  return templates;\n}\nfunction expandPromptTemplate(text, templates) {\n  if (!text.startsWith(\"/\"))\n    return text;\n  const match = text.match(/^\\/([^\\s]+)(?:\\s+([\\s\\S]*))?$/);\n  if (!match)\n    return text;\n  const templateName = match[1];\n  const argsString = match[2] ?? \"\";\n  const template = templates.find((t) => t.name === templateName);\n  if (template) {\n    const args = parseCommandArgs2(argsString);\n    return substituteArgs2(template.content, args);\n  }\n  return text;\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/core/skills.js\nimport { existsSync as existsSync14, readdirSync as readdirSync6, readFileSync as readFileSync10, statSync as statSync7 } from \"fs\";\nimport ignore3 from \"ignore\";\nimport { basename as basename6, dirname as dirname12, join as join21, relative as relative3, resolve as resolve6, sep as sep5 } from \"path\";\nvar MAX_NAME_LENGTH2 = 64;\nvar MAX_DESCRIPTION_LENGTH2 = 1024;\nvar IGNORE_FILE_NAMES3 = [\".gitignore\", \".ignore\", \".fdignore\"];\nfunction toPosixPath2(p) {\n  return p.split(sep5).join(\"/\");\n}\nfunction prefixIgnorePattern3(line, prefix) {\n  const trimmed = line.trim();\n  if (!trimmed)\n    return null;\n  if (trimmed.startsWith(\"#\") && !trimmed.startsWith(\"\\\\#\"))\n    return null;\n  let pattern = line;\n  let negated = false;\n  if (pattern.startsWith(\"!\")) {\n    negated = true;\n    pattern = pattern.slice(1);\n  } else if (pattern.startsWith(\"\\\\!\")) {\n    pattern = pattern.slice(1);\n  }\n  if (pattern.startsWith(\"/\")) {\n    pattern = pattern.slice(1);\n  }\n  const prefixed = prefix ? `${prefix}${pattern}` : pattern;\n  return negated ? `!${prefixed}` : prefixed;\n}\nfunction addIgnoreRules3(ig, dir, rootDir) {\n  const relativeDir = relative3(rootDir, dir);\n  const prefix = relativeDir ? `${toPosixPath2(relativeDir)}/` : \"\";\n  for (const filename of IGNORE_FILE_NAMES3) {\n    const ignorePath = join21(dir, filename);\n    if (!existsSync14(ignorePath))\n      continue;\n    try {\n      const content = readFileSync10(ignorePath, \"utf-8\");\n      const patterns = content.split(/\\r?\\n/).map((line) => prefixIgnorePattern3(line, prefix)).filter((line) => Boolean(line));\n      if (patterns.length > 0) {\n        ig.add(patterns);\n      }\n    } catch {\n    }\n  }\n}\nfunction validateName2(name) {\n  const errors = [];\n  if (name.length > MAX_NAME_LENGTH2) {\n    errors.push(`name exceeds ${MAX_NAME_LENGTH2} characters (${name.length})`);\n  }\n  if (!/^[a-z0-9-]+$/.test(name)) {\n    errors.push(`name contains invalid characters (must be lowercase a-z, 0-9, hyphens only)`);\n  }\n  if (name.startsWith(\"-\") || name.endsWith(\"-\")) {\n    errors.push(`name must not start or end with a hyphen`);\n  }\n  if (name.includes(\"--\")) {\n    errors.push(`name must not contain consecutive hyphens`);\n  }\n  return errors;\n}\nfunction validateDescription2(description) {\n  const errors = [];\n  if (!description || description.trim() === \"\") {\n    errors.push(\"description is required\");\n  } else if (description.length > MAX_DESCRIPTION_LENGTH2) {\n    errors.push(`description exceeds ${MAX_DESCRIPTION_LENGTH2} characters (${description.length})`);\n  }\n  return errors;\n}\nfunction createSkillSourceInfo(filePath, baseDir, source) {\n  switch (source) {\n    case \"user\":\n      return createSyntheticSourceInfo(filePath, {\n        source: \"local\",\n        scope: \"user\",\n        baseDir\n      });\n    case \"project\":\n      return createSyntheticSourceInfo(filePath, {\n        source: \"local\",\n        scope: \"project\",\n        baseDir\n      });\n    case \"path\":\n      return createSyntheticSourceInfo(filePath, {\n        source: \"local\",\n        baseDir\n      });\n    default:\n      return createSyntheticSourceInfo(filePath, { source, baseDir });\n  }\n}\nfunction loadSkillsFromDir(options) {\n  const { dir, source } = options;\n  return loadSkillsFromDirInternal2(dir, source, true);\n}\nfunction loadSkillsFromDirInternal2(dir, source, includeRootFiles, ignoreMatcher, rootDir) {\n  const skills = [];\n  const diagnostics = [];\n  if (!existsSync14(dir)) {\n    return { skills, diagnostics };\n  }\n  const root = rootDir ?? dir;\n  const ig = ignoreMatcher ?? ignore3();\n  addIgnoreRules3(ig, dir, root);\n  try {\n    const entries = readdirSync6(dir, { withFileTypes: true });\n    for (const entry of entries) {\n      if (entry.name !== \"SKILL.md\") {\n        continue;\n      }\n      const fullPath = join21(dir, entry.name);\n      let isFile = entry.isFile();\n      if (entry.isSymbolicLink()) {\n        try {\n          isFile = statSync7(fullPath).isFile();\n        } catch {\n          continue;\n        }\n      }\n      const relPath = toPosixPath2(relative3(root, fullPath));\n      if (!isFile || ig.ignores(relPath)) {\n        continue;\n      }\n      const result = loadSkillFromFile2(fullPath, source);\n      if (result.skill) {\n        skills.push(result.skill);\n      }\n      diagnostics.push(...result.diagnostics);\n      return { skills, diagnostics };\n    }\n    for (const entry of entries) {\n      if (entry.name.startsWith(\".\")) {\n        continue;\n      }\n      if (entry.name === \"node_modules\") {\n        continue;\n      }\n      const fullPath = join21(dir, entry.name);\n      let isDirectory = entry.isDirectory();\n      let isFile = entry.isFile();\n      if (entry.isSymbolicLink()) {\n        try {\n          const stats = statSync7(fullPath);\n          isDirectory = stats.isDirectory();\n          isFile = stats.isFile();\n        } catch {\n          continue;\n        }\n      }\n      const relPath = toPosixPath2(relative3(root, fullPath));\n      const ignorePath = isDirectory ? `${relPath}/` : relPath;\n      if (ig.ignores(ignorePath)) {\n        continue;\n      }\n      if (isDirectory) {\n        const subResult = loadSkillsFromDirInternal2(fullPath, source, false, ig, root);\n        skills.push(...subResult.skills);\n        diagnostics.push(...subResult.diagnostics);\n        continue;\n      }\n      if (!isFile || !includeRootFiles || !entry.name.endsWith(\".md\")) {\n        continue;\n      }\n      const result = loadSkillFromFile2(fullPath, source);\n      if (result.skill) {\n        skills.push(result.skill);\n      }\n      diagnostics.push(...result.diagnostics);\n    }\n  } catch {\n  }\n  return { skills, diagnostics };\n}\nfunction loadSkillFromFile2(filePath, source) {\n  const diagnostics = [];\n  try {\n    const rawContent = readFileSync10(filePath, \"utf-8\");\n    const { frontmatter } = parseFrontmatter3(rawContent);\n    const skillDir = dirname12(filePath);\n    const parentDirName = basename6(skillDir);\n    const descErrors = validateDescription2(frontmatter.description);\n    for (const error of descErrors) {\n      diagnostics.push({ type: \"warning\", message: error, path: filePath });\n    }\n    const name = frontmatter.name || parentDirName;\n    const nameErrors = validateName2(name);\n    for (const error of nameErrors) {\n      diagnostics.push({ type: \"warning\", message: error, path: filePath });\n    }\n    if (!frontmatter.description || frontmatter.description.trim() === \"\") {\n      return { skill: null, diagnostics };\n    }\n    return {\n      skill: {\n        name,\n        description: frontmatter.description,\n        filePath,\n        baseDir: skillDir,\n        sourceInfo: createSkillSourceInfo(filePath, skillDir, source),\n        disableModelInvocation: frontmatter[\"disable-model-invocation\"] === true\n      },\n      diagnostics\n    };\n  } catch (error) {\n    const message = error instanceof Error ? error.message : \"failed to parse skill file\";\n    diagnostics.push({ type: \"warning\", message, path: filePath });\n    return { skill: null, diagnostics };\n  }\n}\nfunction formatSkillsForPrompt(skills) {\n  const visibleSkills = skills.filter((s) => !s.disableModelInvocation);\n  if (visibleSkills.length === 0) {\n    return \"\";\n  }\n  const lines = [\n    \"\\n\\nThe following skills provide specialized instructions for specific tasks.\",\n    \"Use the read tool to load a skill's file when the task matches its description.\",\n    \"When a skill file references a relative path, resolve it against the skill directory (parent of SKILL.md / dirname of the path) and use that absolute path in tool commands.\",\n    \"\",\n    \"<available_skills>\"\n  ];\n  for (const skill of visibleSkills) {\n    lines.push(\"  <skill>\");\n    lines.push(`    <name>${escapeXml2(skill.name)}</name>`);\n    lines.push(`    <description>${escapeXml2(skill.description)}</description>`);\n    lines.push(`    <location>${escapeXml2(skill.filePath)}</location>`);\n    lines.push(\"  </skill>\");\n  }\n  lines.push(\"</available_skills>\");\n  return lines.join(\"\\n\");\n}\nfunction escapeXml2(str2) {\n  return str2.replace(/&/g, \"&amp;\").replace(/</g, \"&lt;\").replace(/>/g, \"&gt;\").replace(/\"/g, \"&quot;\").replace(/'/g, \"&apos;\");\n}\nfunction loadSkills2(options) {\n  const { agentDir, skillPaths, includeDefaults } = options;\n  const resolvedCwd = resolvePath(options.cwd);\n  const resolvedAgentDir = resolvePath(agentDir ?? getAgentDir());\n  const skillMap = /* @__PURE__ */ new Map();\n  const realPathSet = /* @__PURE__ */ new Set();\n  const allDiagnostics = [];\n  const collisionDiagnostics = [];\n  function addSkills(result) {\n    allDiagnostics.push(...result.diagnostics);\n    for (const skill of result.skills) {\n      const realPath = canonicalizePath(skill.filePath);\n      if (realPathSet.has(realPath)) {\n        continue;\n      }\n      const existing = skillMap.get(skill.name);\n      if (existing) {\n        collisionDiagnostics.push({\n          type: \"collision\",\n          message: `name \"${skill.name}\" collision`,\n          path: skill.filePath,\n          collision: {\n            resourceType: \"skill\",\n            name: skill.name,\n            winnerPath: existing.filePath,\n            loserPath: skill.filePath\n          }\n        });\n      } else {\n        skillMap.set(skill.name, skill);\n        realPathSet.add(realPath);\n      }\n    }\n  }\n  if (includeDefaults) {\n    addSkills(loadSkillsFromDirInternal2(join21(resolvedAgentDir, \"skills\"), \"user\", true));\n    addSkills(loadSkillsFromDirInternal2(resolve6(resolvedCwd, CONFIG_DIR_NAME, \"skills\"), \"project\", true));\n  }\n  const userSkillsDir = join21(resolvedAgentDir, \"skills\");\n  const projectSkillsDir = resolve6(resolvedCwd, CONFIG_DIR_NAME, \"skills\");\n  const isUnderPath = (target, root) => {\n    const normalizedRoot = resolve6(root);\n    if (target === normalizedRoot) {\n      return true;\n    }\n    const prefix = normalizedRoot.endsWith(sep5) ? normalizedRoot : `${normalizedRoot}${sep5}`;\n    return target.startsWith(prefix);\n  };\n  const getSource = (resolvedPath) => {\n    if (!includeDefaults) {\n      if (isUnderPath(resolvedPath, userSkillsDir))\n        return \"user\";\n      if (isUnderPath(resolvedPath, projectSkillsDir))\n        return \"project\";\n    }\n    return \"path\";\n  };\n  for (const rawPath of skillPaths) {\n    const resolvedPath = resolvePath(rawPath, resolvedCwd, { trim: true });\n    if (!existsSync14(resolvedPath)) {\n      allDiagnostics.push({ type: \"warning\", message: \"skill path does not exist\", path: resolvedPath });\n      continue;\n    }\n    try {\n      const stats = statSync7(resolvedPath);\n      const source = getSource(resolvedPath);\n      if (stats.isDirectory()) {\n        addSkills(loadSkillsFromDirInternal2(resolvedPath, source, true));\n      } else if (stats.isFile() && resolvedPath.endsWith(\".md\")) {\n        const result = loadSkillFromFile2(resolvedPath, source);\n        if (result.skill) {\n          addSkills({ skills: [result.skill], diagnostics: result.diagnostics });\n        } else {\n          allDiagnostics.push(...result.diagnostics);\n        }\n      } else {\n        allDiagnostics.push({ type: \"warning\", message: \"skill path is not a markdown file\", path: resolvedPath });\n      }\n    } catch (error) {\n      const message = error instanceof Error ? error.message : \"failed to read skill path\";\n      allDiagnostics.push({ type: \"warning\", message, path: resolvedPath });\n    }\n  }\n  return {\n    skills: Array.from(skillMap.values()),\n    diagnostics: [...allDiagnostics, ...collisionDiagnostics]\n  };\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/core/system-prompt.js\nfunction buildSystemPrompt(options) {\n  const { customPrompt, selectedTools, toolSnippets, promptGuidelines, appendSystemPrompt, cwd, contextFiles: providedContextFiles, skills: providedSkills } = options;\n  const promptCwd = cwd.replace(/\\\\/g, \"/\");\n  const appendSection = appendSystemPrompt ? `\n\n${appendSystemPrompt}` : \"\";\n  const contextFiles = providedContextFiles ?? [];\n  const skills = providedSkills ?? [];\n  if (customPrompt) {\n    let prompt2 = customPrompt;\n    if (appendSection) {\n      prompt2 += appendSection;\n    }\n    if (contextFiles.length > 0) {\n      prompt2 += \"\\n\\n<project_context>\\n\\n\";\n      prompt2 += \"Project-specific instructions and guidelines:\\n\\n\";\n      for (const { path: filePath, content } of contextFiles) {\n        prompt2 += `<project_instructions path=\"${filePath}\">\n${content}\n</project_instructions>\n\n`;\n      }\n      prompt2 += \"</project_context>\\n\";\n    }\n    const customPromptHasRead = !selectedTools || selectedTools.includes(\"read\");\n    if (customPromptHasRead && skills.length > 0) {\n      prompt2 += formatSkillsForPrompt(skills);\n    }\n    prompt2 += `\nCurrent working directory: ${promptCwd}\n`;\n    return prompt2;\n  }\n  const readmePath = getReadmePath();\n  const docsPath = getDocsPath();\n  const examplesPath = getExamplesPath();\n  const tools = selectedTools || [\"read\", \"bash\", \"edit\", \"write\"];\n  const visibleTools = tools.filter((name) => !!toolSnippets?.[name]);\n  const toolsList = visibleTools.length > 0 ? visibleTools.map((name) => `- ${name}: ${toolSnippets[name]}`).join(\"\\n\") : \"(none)\";\n  const guidelinesList = [];\n  const guidelinesSet = /* @__PURE__ */ new Set();\n  const addGuideline = (guideline) => {\n    if (guidelinesSet.has(guideline)) {\n      return;\n    }\n    guidelinesSet.add(guideline);\n    guidelinesList.push(guideline);\n  };\n  const hasBash = tools.includes(\"bash\");\n  const hasGrep = tools.includes(\"grep\");\n  const hasFind = tools.includes(\"find\");\n  const hasLs = tools.includes(\"ls\");\n  const hasRead = tools.includes(\"read\");\n  if (hasBash && !hasGrep && !hasFind && !hasLs) {\n    addGuideline(\"Use bash for file operations like ls, rg, find\");\n  }\n  for (const guideline of promptGuidelines ?? []) {\n    const normalized = guideline.trim();\n    if (normalized.length > 0) {\n      addGuideline(normalized);\n    }\n  }\n  addGuideline(\"Be concise in your responses\");\n  addGuideline(\"Show file paths clearly when working with files\");\n  const guidelines = guidelinesList.map((g) => `- ${g}`).join(\"\\n\");\n  let prompt = `You are an expert coding assistant operating inside pi, a coding agent harness. You help users by reading files, executing commands, editing code, and writing new files.\n\nAvailable tools:\n${toolsList}\n\nIn addition to the tools above, you may have access to other custom tools depending on the project.\n\nGuidelines:\n${guidelines}\n\nPi documentation (read only when the user asks about pi itself, its SDK, extensions, themes, skills, or TUI):\n- Main documentation: ${readmePath}\n- Additional docs: ${docsPath}\n- Examples: ${examplesPath} (extensions, custom tools, SDK)\n- When reading pi docs or examples, resolve docs/... under Additional docs and examples/... under Examples, not the current working directory\n- When asked about: extensions (docs/extensions.md, examples/extensions/), themes (docs/themes.md), skills (docs/skills.md), prompt templates (docs/prompt-templates.md), TUI components (docs/tui.md), keybindings (docs/keybindings.md), SDK integrations (docs/sdk.md), custom providers (docs/custom-provider.md), adding models (docs/models.md), pi packages (docs/packages.md), environment variables (docs/environment-variables.md)\n- When working on pi topics, read the docs and examples, and follow .md cross-references before implementing\n- Always read pi .md files completely and follow links to related docs (e.g., tui.md for TUI API details)`;\n  if (appendSection) {\n    prompt += appendSection;\n  }\n  if (contextFiles.length > 0) {\n    prompt += \"\\n\\n<project_context>\\n\\n\";\n    prompt += \"Project-specific instructions and guidelines:\\n\\n\";\n    for (const { path: filePath, content } of contextFiles) {\n      prompt += `<project_instructions path=\"${filePath}\">\n${content}\n</project_instructions>\n\n`;\n    }\n    prompt += \"</project_context>\\n\";\n  }\n  if (hasRead && skills.length > 0) {\n    prompt += formatSkillsForPrompt(skills);\n  }\n  prompt += `\nCurrent working directory: ${promptCwd}`;\n  return prompt;\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/bash.js\nimport { constants as constants3 } from \"node:fs\";\nimport { access as fsAccess } from \"node:fs/promises\";\nimport { spawn as spawn3 } from \"child_process\";\nimport { Type as Type10 } from \"typebox\";\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/visual-truncate.js\nfunction truncateToVisualLines(text, maxVisualLines, width, paddingX = 0) {\n  if (!text) {\n    return { visualLines: [], skippedCount: 0 };\n  }\n  const tempText = new Text(text, paddingX, 0);\n  const allVisualLines = tempText.render(width);\n  if (allVisualLines.length <= maxVisualLines) {\n    return { visualLines: allVisualLines, skippedCount: 0 };\n  }\n  const truncatedLines = allVisualLines.slice(-maxVisualLines);\n  const skippedCount = allVisualLines.length - maxVisualLines;\n  return { visualLines: truncatedLines, skippedCount };\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/output-accumulator.js\nimport { randomBytes as randomBytes2 } from \"node:crypto\";\nimport { createWriteStream as createWriteStream2 } from \"node:fs\";\nimport { tmpdir as tmpdir2 } from \"node:os\";\nimport { join as join22 } from \"node:path\";\nfunction defaultTempFilePath(prefix) {\n  const id = randomBytes2(8).toString(\"hex\");\n  return join22(tmpdir2(), `${prefix}-${id}.log`);\n}\nfunction byteLength(text) {\n  return Buffer.byteLength(text, \"utf-8\");\n}\nvar OutputAccumulator = class {\n  maxLines;\n  maxBytes;\n  maxRollingBytes;\n  tempFilePrefix;\n  decoder = new TextDecoder();\n  rawChunks = [];\n  tailText = \"\";\n  tailBytes = 0;\n  tailStartsAtLineBoundary = true;\n  totalRawBytes = 0;\n  totalDecodedBytes = 0;\n  completedLines = 0;\n  totalLines = 0;\n  currentLineBytes = 0;\n  hasOpenLine = false;\n  finished = false;\n  tempFilePath;\n  tempFileStream;\n  constructor(options = {}) {\n    this.maxLines = options.maxLines ?? DEFAULT_MAX_LINES2;\n    this.maxBytes = options.maxBytes ?? DEFAULT_MAX_BYTES3;\n    this.maxRollingBytes = Math.max(this.maxBytes * 2, 1);\n    this.tempFilePrefix = options.tempFilePrefix ?? \"pi-output\";\n  }\n  append(data) {\n    if (this.finished) {\n      throw new Error(\"Cannot append to a finished output accumulator\");\n    }\n    this.totalRawBytes += data.length;\n    this.appendDecodedText(this.decoder.decode(data, { stream: true }));\n    if (this.tempFileStream || this.shouldUseTempFile()) {\n      this.ensureTempFile();\n      this.tempFileStream?.write(data);\n    } else if (data.length > 0) {\n      this.rawChunks.push(data);\n    }\n  }\n  finish() {\n    if (this.finished) {\n      return;\n    }\n    this.finished = true;\n    this.appendDecodedText(this.decoder.decode());\n    if (this.shouldUseTempFile()) {\n      this.ensureTempFile();\n    }\n  }\n  snapshot(options = {}) {\n    const tailTruncation = truncateTail2(this.getSnapshotText(), {\n      maxLines: this.maxLines,\n      maxBytes: this.maxBytes\n    });\n    const truncated = this.totalLines > this.maxLines || this.totalDecodedBytes > this.maxBytes;\n    const truncatedBy = truncated ? tailTruncation.truncatedBy ?? (this.totalDecodedBytes > this.maxBytes ? \"bytes\" : \"lines\") : null;\n    const truncation = {\n      ...tailTruncation,\n      truncated,\n      truncatedBy,\n      totalLines: this.totalLines,\n      totalBytes: this.totalDecodedBytes,\n      maxLines: this.maxLines,\n      maxBytes: this.maxBytes\n    };\n    if (options.persistIfTruncated && truncation.truncated) {\n      this.ensureTempFile();\n    }\n    return {\n      content: truncation.content,\n      truncation,\n      fullOutputPath: this.tempFilePath\n    };\n  }\n  async closeTempFile() {\n    if (!this.tempFileStream) {\n      return;\n    }\n    const stream11 = this.tempFileStream;\n    this.tempFileStream = void 0;\n    await new Promise((resolve15, reject) => {\n      const onError = (error) => {\n        stream11.off(\"finish\", onFinish);\n        reject(error);\n      };\n      const onFinish = () => {\n        stream11.off(\"error\", onError);\n        resolve15();\n      };\n      stream11.once(\"error\", onError);\n      stream11.once(\"finish\", onFinish);\n      stream11.end();\n    });\n  }\n  getLastLineBytes() {\n    return this.currentLineBytes;\n  }\n  appendDecodedText(text) {\n    if (text.length === 0) {\n      return;\n    }\n    const bytes = byteLength(text);\n    this.totalDecodedBytes += bytes;\n    this.tailText += text;\n    this.tailBytes += bytes;\n    if (this.tailBytes > this.maxRollingBytes * 2) {\n      this.trimTail();\n    }\n    let newlines = 0;\n    let lastNewline = -1;\n    for (let i = text.indexOf(\"\\n\"); i !== -1; i = text.indexOf(\"\\n\", i + 1)) {\n      newlines++;\n      lastNewline = i;\n    }\n    if (newlines === 0) {\n      this.currentLineBytes += bytes;\n      this.hasOpenLine = true;\n    } else {\n      this.completedLines += newlines;\n      const tail = text.slice(lastNewline + 1);\n      this.currentLineBytes = byteLength(tail);\n      this.hasOpenLine = tail.length > 0;\n    }\n    this.totalLines = this.completedLines + (this.hasOpenLine ? 1 : 0);\n  }\n  trimTail() {\n    const buffer = Buffer.from(this.tailText, \"utf-8\");\n    if (buffer.length <= this.maxRollingBytes) {\n      this.tailBytes = buffer.length;\n      return;\n    }\n    let start = buffer.length - this.maxRollingBytes;\n    while (start < buffer.length && (buffer[start] & 192) === 128) {\n      start++;\n    }\n    this.tailStartsAtLineBoundary = start === 0 ? this.tailStartsAtLineBoundary : buffer[start - 1] === 10;\n    this.tailText = buffer.subarray(start).toString(\"utf-8\");\n    this.tailBytes = byteLength(this.tailText);\n  }\n  getSnapshotText() {\n    if (this.tailStartsAtLineBoundary) {\n      return this.tailText;\n    }\n    const firstNewline = this.tailText.indexOf(\"\\n\");\n    return firstNewline === -1 ? this.tailText : this.tailText.slice(firstNewline + 1);\n  }\n  shouldUseTempFile() {\n    return this.totalRawBytes > this.maxBytes || this.totalDecodedBytes > this.maxBytes || this.totalLines > this.maxLines;\n  }\n  ensureTempFile() {\n    if (this.tempFilePath) {\n      return;\n    }\n    this.tempFilePath = defaultTempFilePath(this.tempFilePrefix);\n    this.tempFileStream = createWriteStream2(this.tempFilePath);\n    for (const chunk of this.rawChunks) {\n      this.tempFileStream.write(chunk);\n    }\n    this.rawChunks = [];\n  }\n};\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/render-utils.js\nimport * as os3 from \"node:os\";\nimport { pathToFileURL as pathToFileURL2 } from \"node:url\";\nfunction shortenPath2(path12) {\n  if (typeof path12 !== \"string\")\n    return \"\";\n  const home = os3.homedir();\n  if (path12.startsWith(home)) {\n    return `~${path12.slice(home.length)}`;\n  }\n  return path12;\n}\nfunction linkPath(styledText, rawPath, cwd) {\n  if (!getCapabilities().hyperlinks)\n    return styledText;\n  const absolutePath = resolvePath(rawPath, cwd);\n  return hyperlink(styledText, pathToFileURL2(absolutePath).href);\n}\nfunction str(value) {\n  if (typeof value === \"string\")\n    return value;\n  if (value == null)\n    return \"\";\n  return null;\n}\nfunction replaceTabs(text) {\n  return text.replace(/\\t/g, \"   \");\n}\nfunction normalizeDisplayText(text) {\n  return text.replace(/\\r/g, \"\");\n}\nfunction getTextOutput(result, showImages) {\n  if (!result)\n    return \"\";\n  const textBlocks = result.content.filter((c) => c.type === \"text\");\n  const imageBlocks = result.content.filter((c) => c.type === \"image\");\n  let output = textBlocks.map((c) => sanitizeBinaryOutput(stripAnsi(c.text || \"\")).replace(/\\r/g, \"\")).join(\"\\n\");\n  const caps = getCapabilities();\n  if (imageBlocks.length > 0 && (!caps.images || !showImages)) {\n    const imageIndicators = imageBlocks.map((img) => {\n      const mimeType = img.mimeType ?? \"image/unknown\";\n      const dims = img.data && img.mimeType ? getImageDimensions(img.data, img.mimeType) ?? void 0 : void 0;\n      return imageFallback(mimeType, dims);\n    }).join(\"\\n\");\n    output = output ? `${output}\n${imageIndicators}` : imageIndicators;\n  }\n  return output;\n}\nfunction invalidArgText(theme2) {\n  return theme2.fg(\"error\", \"[invalid arg]\");\n}\nfunction renderToolPath(rawPath, theme2, cwd, options) {\n  if (rawPath === null)\n    return invalidArgText(theme2);\n  const value = rawPath || options?.emptyFallback;\n  if (!value)\n    return theme2.fg(\"toolOutput\", \"...\");\n  return linkPath(theme2.fg(\"accent\", shortenPath2(value)), value, cwd);\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/bash.js\nvar MAX_TIMEOUT_MS = 2147483647;\nvar MAX_TIMEOUT_SECONDS2 = MAX_TIMEOUT_MS / 1e3;\nfunction resolveTimeoutMs(timeout) {\n  if (timeout === void 0)\n    return void 0;\n  if (!Number.isFinite(timeout) || timeout <= 0) {\n    throw new Error(\"Invalid timeout: must be a finite number of seconds\");\n  }\n  const timeoutMs = timeout * 1e3;\n  if (timeoutMs > MAX_TIMEOUT_MS) {\n    throw new Error(`Invalid timeout: maximum is ${MAX_TIMEOUT_SECONDS2} seconds`);\n  }\n  return timeoutMs;\n}\nvar bashSchema2 = Type10.Object({\n  command: Type10.String({ description: \"Bash command to execute\" }),\n  timeout: Type10.Optional(Type10.Number({ description: \"Timeout in seconds (optional, no default timeout)\" }))\n});\nvar bashToolSystemPromptContribution = {\n  snippet: \"Execute bash commands (ls, grep, find, etc.)\",\n  guidelines: [\"You can inspect PI_* environment variables for current model and session details.\"]\n};\nfunction createLocalBashOperations(options) {\n  return {\n    exec: async (command, cwd, { onData, signal, timeout, env }) => {\n      const timeoutMs = resolveTimeoutMs(timeout);\n      if (signal?.aborted) {\n        throw new Error(\"aborted\");\n      }\n      const shellConfig = getShellConfig(options?.shellPath);\n      try {\n        await fsAccess(cwd, constants3.F_OK);\n      } catch {\n        throw new Error(`Working directory does not exist: ${cwd}\nCannot execute bash commands.`);\n      }\n      const commandFromStdin = shellConfig.commandTransport === \"stdin\";\n      const child = spawn3(shellConfig.shell, commandFromStdin ? shellConfig.args : [...shellConfig.args, command], {\n        cwd,\n        detached: process.platform !== \"win32\",\n        env: env ?? getShellEnv(),\n        stdio: [commandFromStdin ? \"pipe\" : \"ignore\", \"pipe\", \"pipe\"],\n        windowsHide: true\n      });\n      if (commandFromStdin) {\n        child.stdin?.on(\"error\", () => {\n        });\n        child.stdin?.end(command);\n      }\n      if (child.pid)\n        trackDetachedChildPid(child.pid);\n      let timedOut = false;\n      let timeoutHandle;\n      const onAbort = () => {\n        if (child.pid)\n          killProcessTree(child.pid);\n      };\n      try {\n        if (timeoutMs !== void 0) {\n          timeoutHandle = setTimeout(() => {\n            timedOut = true;\n            if (child.pid)\n              killProcessTree(child.pid);\n          }, timeoutMs);\n        }\n        child.stdout?.on(\"data\", onData);\n        child.stderr?.on(\"data\", onData);\n        if (signal) {\n          if (signal.aborted)\n            onAbort();\n          else\n            signal.addEventListener(\"abort\", onAbort, { once: true });\n        }\n        const exitCode = await waitForChildProcess(child);\n        if (signal?.aborted) {\n          throw new Error(\"aborted\");\n        }\n        if (timedOut) {\n          throw new Error(`timeout:${timeout}`);\n        }\n        return { exitCode };\n      } finally {\n        if (child.pid)\n          untrackDetachedChildPid(child.pid);\n        if (timeoutHandle)\n          clearTimeout(timeoutHandle);\n        if (signal)\n          signal.removeEventListener(\"abort\", onAbort);\n      }\n    }\n  };\n}\nfunction resolveSpawnContext(command, cwd, spawnHook, exposeSessionEnvironment, ctx) {\n  const env = { ...getShellEnv() };\n  delete env.PI_SESSION_ID;\n  delete env.PI_SESSION_FILE;\n  delete env.PI_PROVIDER;\n  delete env.PI_MODEL;\n  delete env.PI_REASONING_LEVEL;\n  if (exposeSessionEnvironment && ctx) {\n    const model = ctx.model;\n    env.PI_SESSION_ID = ctx.sessionManager.getSessionId();\n    const sessionFile = ctx.sessionManager.getSessionFile();\n    if (sessionFile)\n      env.PI_SESSION_FILE = sessionFile;\n    if (model) {\n      env.PI_PROVIDER = model.provider;\n      env.PI_MODEL = model.id;\n    }\n    if (ctx.thinkingLevel)\n      env.PI_REASONING_LEVEL = ctx.thinkingLevel;\n  }\n  const baseContext = { command, cwd, env };\n  return spawnHook ? spawnHook(baseContext) : baseContext;\n}\nvar BASH_PREVIEW_LINES = 5;\nvar BASH_UPDATE_THROTTLE_MS2 = 100;\nvar BashResultRenderComponent = class extends Container {\n  state = {\n    cachedWidth: void 0,\n    cachedLines: void 0,\n    cachedSkipped: void 0\n  };\n};\nfunction formatDuration(ms) {\n  return `${(ms / 1e3).toFixed(1)}s`;\n}\nfunction formatBashCall(args) {\n  const command = str(args?.command);\n  const timeout = args?.timeout;\n  const timeoutSuffix = timeout ? theme.fg(\"muted\", ` (timeout ${timeout}s)`) : \"\";\n  const commandDisplay = command === null ? invalidArgText(theme) : command ? command : theme.fg(\"toolOutput\", \"...\");\n  return theme.fg(\"toolTitle\", theme.bold(`$ ${commandDisplay}`)) + timeoutSuffix;\n}\nfunction rebuildBashResultRenderComponent(component, result, options, showImages, startedAt, endedAt) {\n  const state = component.state;\n  component.clear();\n  let output = getTextOutput(result, showImages).trim();\n  const truncation = result.details?.truncation;\n  const fullOutputPath = result.details?.fullOutputPath;\n  if (!options.isPartial && truncation?.truncated && fullOutputPath && output.endsWith(\"]\")) {\n    const footerStart = output.lastIndexOf(\"\\n\\n[\");\n    if (footerStart !== -1 && output.slice(footerStart).includes(fullOutputPath)) {\n      output = output.slice(0, footerStart).trimEnd();\n    }\n  }\n  if (output) {\n    const styledOutput = output.split(\"\\n\").map((line) => theme.fg(\"toolOutput\", line)).join(\"\\n\");\n    if (options.expanded) {\n      component.addChild(new Text(`\n${styledOutput}`, 0, 0));\n    } else {\n      component.addChild({\n        render: (width) => {\n          if (state.cachedLines === void 0 || state.cachedWidth !== width) {\n            const preview = truncateToVisualLines(styledOutput, BASH_PREVIEW_LINES, width);\n            state.cachedLines = preview.visualLines;\n            state.cachedSkipped = preview.skippedCount;\n            state.cachedWidth = width;\n          }\n          if (state.cachedSkipped && state.cachedSkipped > 0) {\n            const hint = theme.fg(\"muted\", `... (${state.cachedSkipped} earlier lines,`) + ` ${keyHint(\"app.tools.expand\", \"to expand\")}${theme.fg(\"muted\", \")\")}`;\n            return [\"\", truncateToWidth(hint, width, \"...\"), ...state.cachedLines ?? []];\n          }\n          return [\"\", ...state.cachedLines ?? []];\n        },\n        invalidate: () => {\n          state.cachedWidth = void 0;\n          state.cachedLines = void 0;\n          state.cachedSkipped = void 0;\n        }\n      });\n    }\n  }\n  if (truncation?.truncated || fullOutputPath) {\n    const warnings = [];\n    if (fullOutputPath) {\n      warnings.push(`Full output: ${fullOutputPath}`);\n    }\n    if (truncation?.truncated) {\n      if (truncation.truncatedBy === \"lines\") {\n        warnings.push(`Truncated: showing ${truncation.outputLines} of ${truncation.totalLines} lines`);\n      } else {\n        warnings.push(`Truncated: ${truncation.outputLines} lines shown (${formatSize2(truncation.maxBytes ?? DEFAULT_MAX_BYTES3)} limit)`);\n      }\n    }\n    component.addChild(new Text(`\n${theme.fg(\"warning\", `[${warnings.join(\". \")}]`)}`, 0, 0));\n  }\n  if (startedAt !== void 0) {\n    const label = options.isPartial ? \"Elapsed\" : \"Took\";\n    const endTime = endedAt ?? Date.now();\n    component.addChild(new Text(`\n${theme.fg(\"muted\", `${label} ${formatDuration(endTime - startedAt)}`)}`, 0, 0));\n  }\n}\nfunction createBashToolDefinition(cwd, options) {\n  const ops = options?.operations ?? createLocalBashOperations({ shellPath: options?.shellPath });\n  const commandPrefix = options?.commandPrefix;\n  const exposeSessionEnvironment = options?.exposeSessionEnvironment ?? true;\n  const spawnHook = options?.spawnHook;\n  return {\n    name: \"bash\",\n    label: \"bash\",\n    description: `Execute a bash command in the current working directory. Returns stdout and stderr. Output is truncated to last ${DEFAULT_MAX_LINES2} lines or ${DEFAULT_MAX_BYTES3 / 1024}KB (whichever is hit first). If truncated, full output is saved to a temp file. Optionally provide a timeout in seconds.`,\n    promptSnippet: bashToolSystemPromptContribution.snippet,\n    promptGuidelines: exposeSessionEnvironment ? [...bashToolSystemPromptContribution.guidelines] : void 0,\n    parameters: bashSchema2,\n    constrainedSampling: getExperimentalToolSampling(),\n    async execute(_toolCallId, { command, timeout }, signal, onUpdate, ctx) {\n      const resolvedCommand = commandPrefix ? `${commandPrefix}\n${command}` : command;\n      const spawnContext = resolveSpawnContext(resolvedCommand, cwd, spawnHook, exposeSessionEnvironment, ctx);\n      const output = new OutputAccumulator({ tempFilePrefix: \"pi-bash\" });\n      let acceptingOutput = true;\n      let updateTimer;\n      let updateDirty = false;\n      let lastUpdateAt = 0;\n      const emitOutputUpdate = () => {\n        if (!onUpdate || !updateDirty)\n          return;\n        updateDirty = false;\n        lastUpdateAt = Date.now();\n        const snapshot = output.snapshot({ persistIfTruncated: true });\n        onUpdate({\n          content: [{ type: \"text\", text: snapshot.content || \"\" }],\n          details: {\n            truncation: snapshot.truncation.truncated ? snapshot.truncation : void 0,\n            fullOutputPath: snapshot.fullOutputPath\n          }\n        });\n      };\n      const clearUpdateTimer = () => {\n        if (updateTimer) {\n          clearTimeout(updateTimer);\n          updateTimer = void 0;\n        }\n      };\n      const scheduleOutputUpdate = () => {\n        if (!onUpdate)\n          return;\n        updateDirty = true;\n        const delay = BASH_UPDATE_THROTTLE_MS2 - (Date.now() - lastUpdateAt);\n        if (delay <= 0) {\n          clearUpdateTimer();\n          emitOutputUpdate();\n          return;\n        }\n        updateTimer ??= setTimeout(() => {\n          updateTimer = void 0;\n          emitOutputUpdate();\n        }, delay);\n      };\n      if (onUpdate) {\n        onUpdate({ content: [], details: void 0 });\n      }\n      const handleData = (data) => {\n        if (!acceptingOutput)\n          return;\n        output.append(data);\n        scheduleOutputUpdate();\n      };\n      const finishOutput = async () => {\n        acceptingOutput = false;\n        output.finish();\n        clearUpdateTimer();\n        emitOutputUpdate();\n        const snapshot = output.snapshot({ persistIfTruncated: true });\n        await output.closeTempFile();\n        return snapshot;\n      };\n      const formatOutput = (snapshot, emptyText = \"(no output)\") => {\n        const truncation = snapshot.truncation;\n        let text = snapshot.content || emptyText;\n        let details;\n        if (truncation.truncated) {\n          details = { truncation, fullOutputPath: snapshot.fullOutputPath };\n          const startLine = truncation.totalLines - truncation.outputLines + 1;\n          const endLine = truncation.totalLines;\n          if (truncation.lastLinePartial) {\n            const lastLineSize = formatSize2(output.getLastLineBytes());\n            text += `\n\n[Showing last ${formatSize2(truncation.outputBytes)} of line ${endLine} (line is ${lastLineSize}). Full output: ${snapshot.fullOutputPath}]`;\n          } else if (truncation.truncatedBy === \"lines\") {\n            text += `\n\n[Showing lines ${startLine}-${endLine} of ${truncation.totalLines}. Full output: ${snapshot.fullOutputPath}]`;\n          } else {\n            text += `\n\n[Showing lines ${startLine}-${endLine} of ${truncation.totalLines} (${formatSize2(DEFAULT_MAX_BYTES3)} limit). Full output: ${snapshot.fullOutputPath}]`;\n          }\n        }\n        return { text, details };\n      };\n      const appendStatus = (text, status) => `${text ? `${text}\n\n` : \"\"}${status}`;\n      try {\n        let exitCode;\n        try {\n          const result = await ops.exec(spawnContext.command, spawnContext.cwd, {\n            onData: handleData,\n            signal,\n            timeout,\n            env: spawnContext.env\n          });\n          exitCode = result.exitCode;\n        } catch (err2) {\n          const snapshot2 = await finishOutput();\n          const { text } = formatOutput(snapshot2, \"\");\n          if (err2 instanceof Error && err2.message === \"aborted\") {\n            throw new Error(appendStatus(text, \"Command aborted\"));\n          }\n          if (err2 instanceof Error && err2.message.startsWith(\"timeout:\")) {\n            const timeoutSecs = err2.message.split(\":\")[1];\n            throw new Error(appendStatus(text, `Command timed out after ${timeoutSecs} seconds`));\n          }\n          throw err2;\n        }\n        const snapshot = await finishOutput();\n        const { text: outputText, details } = formatOutput(snapshot);\n        if (exitCode !== 0 && exitCode !== null) {\n          throw new Error(appendStatus(outputText, `Command exited with code ${exitCode}`));\n        }\n        return { content: [{ type: \"text\", text: outputText }], details };\n      } finally {\n        clearUpdateTimer();\n      }\n    },\n    renderCall(args, _theme, context) {\n      const state = context.state;\n      if (context.executionStarted && state.startedAt === void 0) {\n        state.startedAt = Date.now();\n        state.endedAt = void 0;\n      }\n      const text = context.lastComponent ?? new Text(\"\", 0, 0);\n      text.setText(formatBashCall(args));\n      return text;\n    },\n    renderResult(result, options2, _theme, context) {\n      const state = context.state;\n      if (state.startedAt !== void 0 && options2.isPartial && !state.interval) {\n        state.interval = setInterval(() => context.invalidate(), 1e3);\n      }\n      if (!options2.isPartial || context.isError) {\n        state.endedAt ??= Date.now();\n        if (state.interval) {\n          clearInterval(state.interval);\n          state.interval = void 0;\n        }\n      }\n      const component = context.lastComponent ?? new BashResultRenderComponent();\n      rebuildBashResultRenderComponent(component, result, options2, context.showImages, state.startedAt, state.endedAt);\n      component.invalidate();\n      return component;\n    }\n  };\n}\nfunction createBashTool2(cwd, options) {\n  const definition = createBashToolDefinition(cwd, options);\n  const tool = wrapToolDefinition(definition);\n  Object.assign(tool, {\n    promptSnippet: definition.promptSnippet,\n    promptGuidelines: definition.promptGuidelines\n  });\n  return tool;\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/edit.js\nimport { constants as constants5 } from \"fs\";\nimport { access as fsAccess2, readFile as fsReadFile, writeFile as fsWriteFile } from \"fs/promises\";\nimport { Type as Type11 } from \"typebox\";\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/diff.js\nimport * as Diff2 from \"diff\";\nfunction parseDiffLine(line) {\n  const match = line.match(/^([+-\\s])(\\s*\\d*)\\s(.*)$/);\n  if (!match)\n    return null;\n  return { prefix: match[1], lineNum: match[2], content: match[3] };\n}\nfunction replaceTabs2(text) {\n  return text.replace(/\\t/g, \"   \");\n}\nfunction renderIntraLineDiff(oldContent, newContent) {\n  const wordDiff = Diff2.diffWords(oldContent, newContent);\n  let removedLine = \"\";\n  let addedLine = \"\";\n  let isFirstRemoved = true;\n  let isFirstAdded = true;\n  for (const part of wordDiff) {\n    if (part.removed) {\n      let value = part.value;\n      if (isFirstRemoved) {\n        const leadingWs = value.match(/^(\\s*)/)?.[1] || \"\";\n        value = value.slice(leadingWs.length);\n        removedLine += leadingWs;\n        isFirstRemoved = false;\n      }\n      if (value) {\n        removedLine += theme.inverse(value);\n      }\n    } else if (part.added) {\n      let value = part.value;\n      if (isFirstAdded) {\n        const leadingWs = value.match(/^(\\s*)/)?.[1] || \"\";\n        value = value.slice(leadingWs.length);\n        addedLine += leadingWs;\n        isFirstAdded = false;\n      }\n      if (value) {\n        addedLine += theme.inverse(value);\n      }\n    } else {\n      removedLine += part.value;\n      addedLine += part.value;\n    }\n  }\n  return { removedLine, addedLine };\n}\nfunction renderDiff(diffText, _options = {}) {\n  const lines = diffText.split(\"\\n\");\n  const result = [];\n  let i = 0;\n  while (i < lines.length) {\n    const line = lines[i];\n    const parsed = parseDiffLine(line);\n    if (!parsed) {\n      result.push(theme.fg(\"toolDiffContext\", line));\n      i++;\n      continue;\n    }\n    if (parsed.prefix === \"-\") {\n      const removedLines = [];\n      while (i < lines.length) {\n        const p = parseDiffLine(lines[i]);\n        if (!p || p.prefix !== \"-\")\n          break;\n        removedLines.push({ lineNum: p.lineNum, content: p.content });\n        i++;\n      }\n      const addedLines = [];\n      while (i < lines.length) {\n        const p = parseDiffLine(lines[i]);\n        if (!p || p.prefix !== \"+\")\n          break;\n        addedLines.push({ lineNum: p.lineNum, content: p.content });\n        i++;\n      }\n      if (removedLines.length === 1 && addedLines.length === 1) {\n        const removed = removedLines[0];\n        const added = addedLines[0];\n        const { removedLine, addedLine } = renderIntraLineDiff(replaceTabs2(removed.content), replaceTabs2(added.content));\n        result.push(theme.fg(\"toolDiffRemoved\", `-${removed.lineNum} ${removedLine}`));\n        result.push(theme.fg(\"toolDiffAdded\", `+${added.lineNum} ${addedLine}`));\n      } else {\n        for (const removed of removedLines) {\n          result.push(theme.fg(\"toolDiffRemoved\", `-${removed.lineNum} ${replaceTabs2(removed.content)}`));\n        }\n        for (const added of addedLines) {\n          result.push(theme.fg(\"toolDiffAdded\", `+${added.lineNum} ${replaceTabs2(added.content)}`));\n        }\n      }\n    } else if (parsed.prefix === \"+\") {\n      result.push(theme.fg(\"toolDiffAdded\", `+${parsed.lineNum} ${replaceTabs2(parsed.content)}`));\n      i++;\n    } else {\n      result.push(theme.fg(\"toolDiffContext\", ` ${parsed.lineNum} ${replaceTabs2(parsed.content)}`));\n      i++;\n    }\n  }\n  return result.join(\"\\n\");\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/edit-diff.js\nimport * as Diff3 from \"diff\";\nimport { constants as constants4 } from \"fs\";\nimport { access as access3, readFile as readFile3 } from \"fs/promises\";\nfunction detectLineEnding2(content) {\n  const crlfIdx = content.indexOf(\"\\r\\n\");\n  const lfIdx = content.indexOf(\"\\n\");\n  if (lfIdx === -1)\n    return \"\\n\";\n  if (crlfIdx === -1)\n    return \"\\n\";\n  return crlfIdx < lfIdx ? \"\\r\\n\" : \"\\n\";\n}\nfunction normalizeToLF2(text) {\n  return text.replace(/\\r\\n/g, \"\\n\").replace(/\\r/g, \"\\n\");\n}\nfunction restoreLineEndings2(text, ending) {\n  return ending === \"\\r\\n\" ? text.replace(/\\n/g, \"\\r\\n\") : text;\n}\nfunction normalizeForFuzzyMatch2(text) {\n  return text.normalize(\"NFKC\").split(\"\\n\").map((line) => line.trimEnd()).join(\"\\n\").replace(/[\\u2018\\u2019\\u201A\\u201B]/g, \"'\").replace(/[\\u201C\\u201D\\u201E\\u201F]/g, '\"').replace(/[\\u2010\\u2011\\u2012\\u2013\\u2014\\u2015\\u2212]/g, \"-\").replace(/[\\u00A0\\u2002-\\u200A\\u202F\\u205F\\u3000]/g, \" \");\n}\nfunction splitLinesWithEndings2(content) {\n  return content.match(/[^\\n]*\\n|[^\\n]+/g) ?? [];\n}\nfunction getLineSpans2(content) {\n  let offset = 0;\n  return splitLinesWithEndings2(content).map((line) => {\n    const span = { start: offset, end: offset + line.length };\n    offset = span.end;\n    return span;\n  });\n}\nfunction getReplacementLineRange2(lines, replacement) {\n  const replacementStart = replacement.matchIndex;\n  const replacementEnd = replacement.matchIndex + replacement.matchLength;\n  let startLine = -1;\n  for (let i = 0; i < lines.length; i++) {\n    const line = lines[i];\n    if (replacementStart >= line.start && replacementStart < line.end) {\n      startLine = i;\n      break;\n    }\n  }\n  if (startLine === -1) {\n    throw new Error(\"Replacement range is outside the base content.\");\n  }\n  let endLine = startLine;\n  while (endLine < lines.length && lines[endLine].end < replacementEnd) {\n    endLine++;\n  }\n  if (endLine >= lines.length) {\n    throw new Error(\"Replacement range is outside the base content.\");\n  }\n  return { startLine, endLine: endLine + 1 };\n}\nfunction applyReplacements2(content, replacements, offset = 0) {\n  let result = content;\n  for (let i = replacements.length - 1; i >= 0; i--) {\n    const replacement = replacements[i];\n    const matchIndex = replacement.matchIndex - offset;\n    result = result.substring(0, matchIndex) + replacement.newText + result.substring(matchIndex + replacement.matchLength);\n  }\n  return result;\n}\nfunction applyReplacementsPreservingUnchangedLines2(originalContent, baseContent, replacements) {\n  const originalLines = splitLinesWithEndings2(originalContent);\n  const baseLines = getLineSpans2(baseContent);\n  if (originalLines.length !== baseLines.length) {\n    throw new Error(\"Cannot preserve unchanged lines because the base content has a different line count.\");\n  }\n  const groups = [];\n  const sortedReplacements = [...replacements].sort((a, b) => a.matchIndex - b.matchIndex);\n  for (const replacement of sortedReplacements) {\n    const range = getReplacementLineRange2(baseLines, replacement);\n    const current = groups[groups.length - 1];\n    if (current && range.startLine < current.endLine) {\n      current.endLine = Math.max(current.endLine, range.endLine);\n      current.replacements.push(replacement);\n      continue;\n    }\n    groups.push({ ...range, replacements: [replacement] });\n  }\n  let originalLineIndex = 0;\n  let result = \"\";\n  for (const group of groups) {\n    result += originalLines.slice(originalLineIndex, group.startLine).join(\"\");\n    const groupStartOffset = baseLines[group.startLine].start;\n    const groupEndOffset = baseLines[group.endLine - 1].end;\n    result += applyReplacements2(baseContent.slice(groupStartOffset, groupEndOffset), group.replacements, groupStartOffset);\n    originalLineIndex = group.endLine;\n  }\n  result += originalLines.slice(originalLineIndex).join(\"\");\n  return result;\n}\nfunction fuzzyFindText2(content, oldText) {\n  const exactIndex = content.indexOf(oldText);\n  if (exactIndex !== -1) {\n    return {\n      found: true,\n      index: exactIndex,\n      matchLength: oldText.length,\n      usedFuzzyMatch: false,\n      contentForReplacement: content\n    };\n  }\n  const fuzzyContent = normalizeForFuzzyMatch2(content);\n  const fuzzyOldText = normalizeForFuzzyMatch2(oldText);\n  const fuzzyIndex = fuzzyContent.indexOf(fuzzyOldText);\n  if (fuzzyIndex === -1) {\n    return {\n      found: false,\n      index: -1,\n      matchLength: 0,\n      usedFuzzyMatch: false,\n      contentForReplacement: content\n    };\n  }\n  return {\n    found: true,\n    index: fuzzyIndex,\n    matchLength: fuzzyOldText.length,\n    usedFuzzyMatch: true,\n    contentForReplacement: fuzzyContent\n  };\n}\nfunction stripBom2(content) {\n  return content.startsWith(\"\\uFEFF\") ? { bom: \"\\uFEFF\", text: content.slice(1) } : { bom: \"\", text: content };\n}\nfunction countOccurrences2(content, oldText) {\n  const fuzzyContent = normalizeForFuzzyMatch2(content);\n  const fuzzyOldText = normalizeForFuzzyMatch2(oldText);\n  return fuzzyContent.split(fuzzyOldText).length - 1;\n}\nfunction getNotFoundError2(path12, editIndex, totalEdits) {\n  if (totalEdits === 1) {\n    return new Error(`Could not find the exact text in ${path12}. The old text must match exactly including all whitespace and newlines.`);\n  }\n  return new Error(`Could not find edits[${editIndex}] in ${path12}. The oldText must match exactly including all whitespace and newlines.`);\n}\nfunction getDuplicateError2(path12, editIndex, totalEdits, occurrences) {\n  if (totalEdits === 1) {\n    return new Error(`Found ${occurrences} occurrences of the text in ${path12}. The text must be unique. Please provide more context to make it unique.`);\n  }\n  return new Error(`Found ${occurrences} occurrences of edits[${editIndex}] in ${path12}. Each oldText must be unique. Please provide more context to make it unique.`);\n}\nfunction getEmptyOldTextError2(path12, editIndex, totalEdits) {\n  if (totalEdits === 1) {\n    return new Error(`oldText must not be empty in ${path12}.`);\n  }\n  return new Error(`edits[${editIndex}].oldText must not be empty in ${path12}.`);\n}\nfunction getNoChangeError2(path12, totalEdits) {\n  if (totalEdits === 1) {\n    return new Error(`No changes made to ${path12}. The replacement produced identical content. This might indicate an issue with special characters or the text not existing as expected.`);\n  }\n  return new Error(`No changes made to ${path12}. The replacements produced identical content.`);\n}\nfunction applyEditsToNormalizedContent2(normalizedContent, edits, path12) {\n  const normalizedEdits = edits.map((edit) => ({\n    oldText: normalizeToLF2(edit.oldText),\n    newText: normalizeToLF2(edit.newText)\n  }));\n  for (let i = 0; i < normalizedEdits.length; i++) {\n    if (normalizedEdits[i].oldText.length === 0) {\n      throw getEmptyOldTextError2(path12, i, normalizedEdits.length);\n    }\n  }\n  const initialMatches = normalizedEdits.map((edit) => fuzzyFindText2(normalizedContent, edit.oldText));\n  const usedFuzzyMatch = initialMatches.some((match) => match.usedFuzzyMatch);\n  const replacementBaseContent = usedFuzzyMatch ? normalizeForFuzzyMatch2(normalizedContent) : normalizedContent;\n  const matchedEdits = [];\n  for (let i = 0; i < normalizedEdits.length; i++) {\n    const edit = normalizedEdits[i];\n    const matchResult = fuzzyFindText2(replacementBaseContent, edit.oldText);\n    if (!matchResult.found) {\n      throw getNotFoundError2(path12, i, normalizedEdits.length);\n    }\n    const occurrences = countOccurrences2(replacementBaseContent, edit.oldText);\n    if (occurrences > 1) {\n      throw getDuplicateError2(path12, i, normalizedEdits.length, occurrences);\n    }\n    matchedEdits.push({\n      editIndex: i,\n      matchIndex: matchResult.index,\n      matchLength: matchResult.matchLength,\n      newText: edit.newText\n    });\n  }\n  matchedEdits.sort((a, b) => a.matchIndex - b.matchIndex);\n  for (let i = 1; i < matchedEdits.length; i++) {\n    const previous = matchedEdits[i - 1];\n    const current = matchedEdits[i];\n    if (previous.matchIndex + previous.matchLength > current.matchIndex) {\n      throw new Error(`edits[${previous.editIndex}] and edits[${current.editIndex}] overlap in ${path12}. Merge them into one edit or target disjoint regions.`);\n    }\n  }\n  const baseContent = normalizedContent;\n  const newContent = usedFuzzyMatch ? applyReplacementsPreservingUnchangedLines2(normalizedContent, replacementBaseContent, matchedEdits) : applyReplacements2(replacementBaseContent, matchedEdits);\n  if (baseContent === newContent) {\n    throw getNoChangeError2(path12, normalizedEdits.length);\n  }\n  return { baseContent, newContent };\n}\nfunction generateUnifiedPatch2(path12, oldContent, newContent, contextLines = 4) {\n  return Diff3.createTwoFilesPatch(path12, path12, oldContent, newContent, void 0, void 0, {\n    context: contextLines,\n    headerOptions: Diff3.FILE_HEADERS_ONLY\n  });\n}\nfunction generateDiffString2(oldContent, newContent, contextLines = 4) {\n  const parts = Diff3.diffLines(oldContent, newContent);\n  const output = [];\n  const oldLines = oldContent.split(\"\\n\");\n  const newLines = newContent.split(\"\\n\");\n  const maxLineNum = Math.max(oldLines.length, newLines.length);\n  const lineNumWidth = String(maxLineNum).length;\n  let oldLineNum = 1;\n  let newLineNum = 1;\n  let lastWasChange = false;\n  let firstChangedLine;\n  for (let i = 0; i < parts.length; i++) {\n    const part = parts[i];\n    const raw = part.value.split(\"\\n\");\n    if (raw[raw.length - 1] === \"\") {\n      raw.pop();\n    }\n    if (part.added || part.removed) {\n      if (firstChangedLine === void 0) {\n        firstChangedLine = newLineNum;\n      }\n      for (const line of raw) {\n        if (part.added) {\n          const lineNum = String(newLineNum).padStart(lineNumWidth, \" \");\n          output.push(`+${lineNum} ${line}`);\n          newLineNum++;\n        } else {\n          const lineNum = String(oldLineNum).padStart(lineNumWidth, \" \");\n          output.push(`-${lineNum} ${line}`);\n          oldLineNum++;\n        }\n      }\n      lastWasChange = true;\n    } else {\n      const nextPartIsChange = i < parts.length - 1 && (parts[i + 1].added || parts[i + 1].removed);\n      const hasLeadingChange = lastWasChange;\n      const hasTrailingChange = nextPartIsChange;\n      if (hasLeadingChange && hasTrailingChange) {\n        if (raw.length <= contextLines * 2) {\n          for (const line of raw) {\n            const lineNum = String(oldLineNum).padStart(lineNumWidth, \" \");\n            output.push(` ${lineNum} ${line}`);\n            oldLineNum++;\n            newLineNum++;\n          }\n        } else {\n          const leadingLines = raw.slice(0, contextLines);\n          const trailingLines = raw.slice(raw.length - contextLines);\n          const skippedLines = raw.length - leadingLines.length - trailingLines.length;\n          for (const line of leadingLines) {\n            const lineNum = String(oldLineNum).padStart(lineNumWidth, \" \");\n            output.push(` ${lineNum} ${line}`);\n            oldLineNum++;\n            newLineNum++;\n          }\n          output.push(` ${\"\".padStart(lineNumWidth, \" \")} ...`);\n          oldLineNum += skippedLines;\n          newLineNum += skippedLines;\n          for (const line of trailingLines) {\n            const lineNum = String(oldLineNum).padStart(lineNumWidth, \" \");\n            output.push(` ${lineNum} ${line}`);\n            oldLineNum++;\n            newLineNum++;\n          }\n        }\n      } else if (hasLeadingChange) {\n        const shownLines = raw.slice(0, contextLines);\n        const skippedLines = raw.length - shownLines.length;\n        for (const line of shownLines) {\n          const lineNum = String(oldLineNum).padStart(lineNumWidth, \" \");\n          output.push(` ${lineNum} ${line}`);\n          oldLineNum++;\n          newLineNum++;\n        }\n        if (skippedLines > 0) {\n          output.push(` ${\"\".padStart(lineNumWidth, \" \")} ...`);\n          oldLineNum += skippedLines;\n          newLineNum += skippedLines;\n        }\n      } else if (hasTrailingChange) {\n        const skippedLines = Math.max(0, raw.length - contextLines);\n        if (skippedLines > 0) {\n          output.push(` ${\"\".padStart(lineNumWidth, \" \")} ...`);\n          oldLineNum += skippedLines;\n          newLineNum += skippedLines;\n        }\n        for (const line of raw.slice(skippedLines)) {\n          const lineNum = String(oldLineNum).padStart(lineNumWidth, \" \");\n          output.push(` ${lineNum} ${line}`);\n          oldLineNum++;\n          newLineNum++;\n        }\n      } else {\n        oldLineNum += raw.length;\n        newLineNum += raw.length;\n      }\n      lastWasChange = false;\n    }\n  }\n  return { diff: output.join(\"\\n\"), firstChangedLine };\n}\nasync function computeEditsDiff(path12, edits, cwd) {\n  const absolutePath = resolveToCwd(path12, cwd);\n  try {\n    try {\n      await access3(absolutePath, constants4.R_OK);\n    } catch (error) {\n      const errorMessage2 = error instanceof Error && \"code\" in error ? `Error code: ${error.code}` : String(error);\n      return { error: `Could not edit file: ${path12}. ${errorMessage2}.` };\n    }\n    const rawContent = await readFile3(absolutePath, \"utf-8\");\n    const { text: content } = stripBom2(rawContent);\n    const normalizedContent = normalizeToLF2(content);\n    const { baseContent, newContent } = applyEditsToNormalizedContent2(normalizedContent, edits, path12);\n    return generateDiffString2(baseContent, newContent);\n  } catch (err2) {\n    return { error: err2 instanceof Error ? err2.message : String(err2) };\n  }\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/file-mutation-queue.js\nimport { realpath } from \"node:fs/promises\";\nimport { resolve as resolve7 } from \"node:path\";\nvar fileMutationQueues = /* @__PURE__ */ new Map();\nvar registrationQueue = Promise.resolve();\nfunction isMissingPathError(error) {\n  return typeof error === \"object\" && error !== null && \"code\" in error && (error.code === \"ENOENT\" || error.code === \"ENOTDIR\");\n}\nasync function getMutationQueueKey2(filePath) {\n  const resolvedPath = resolve7(filePath);\n  try {\n    return await realpath(resolvedPath);\n  } catch (error) {\n    if (isMissingPathError(error)) {\n      return resolvedPath;\n    }\n    throw error;\n  }\n}\nasync function withFileMutationQueue2(filePath, fn) {\n  const registration = registrationQueue.then(async () => {\n    const key2 = await getMutationQueueKey2(filePath);\n    const currentQueue2 = fileMutationQueues.get(key2) ?? Promise.resolve();\n    let releaseNext2;\n    const nextQueue = new Promise((resolveQueue) => {\n      releaseNext2 = resolveQueue;\n    });\n    const chainedQueue2 = currentQueue2.then(() => nextQueue);\n    fileMutationQueues.set(key2, chainedQueue2);\n    return { key: key2, currentQueue: currentQueue2, chainedQueue: chainedQueue2, releaseNext: releaseNext2 };\n  });\n  registrationQueue = registration.then(() => void 0, () => void 0);\n  const { key, currentQueue, chainedQueue, releaseNext } = await registration;\n  await currentQueue;\n  try {\n    return await fn();\n  } finally {\n    releaseNext();\n    if (fileMutationQueues.get(key) === chainedQueue) {\n      fileMutationQueues.delete(key);\n    }\n  }\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/edit.js\nvar replaceEditSchema2 = Type11.Object({\n  oldText: Type11.String({\n    description: \"Exact text for one targeted replacement. It must be unique in the original file and must not overlap with any other edits[].oldText in the same call.\"\n  }),\n  newText: Type11.String({ description: \"Replacement text for this targeted edit.\" })\n}, {});\nvar editSchema2 = Type11.Object({\n  path: Type11.String({ description: \"Path to the file to edit (relative or absolute)\" }),\n  edits: Type11.Array(replaceEditSchema2, {\n    description: \"One or more targeted replacements. Each edit is matched against the original file, not incrementally. Do not include overlapping or nested edits. If two changes touch the same block or nearby lines, merge them into one edit instead.\"\n  })\n}, {});\nvar editToolSystemPromptContribution = {\n  snippet: \"Make precise file edits with exact text replacement, including multiple disjoint edits in one call\",\n  guidelines: [\n    \"Use edit for precise changes (edits[].oldText must match exactly)\",\n    \"When changing multiple separate locations in one file, use one edit call with multiple entries in edits[] instead of multiple edit calls\",\n    \"Each edits[].oldText is matched against the original file, not after earlier edits are applied. Do not emit overlapping or nested edits. Merge nearby changes into one edit.\",\n    \"Keep edits[].oldText as small as possible while still being unique in the file. Do not pad with large unchanged regions.\"\n  ]\n};\nvar defaultEditOperations = {\n  readFile: (path12) => fsReadFile(path12),\n  writeFile: (path12, content) => fsWriteFile(path12, content, \"utf-8\"),\n  access: (path12) => fsAccess2(path12, constants5.R_OK | constants5.W_OK)\n};\nfunction prepareEditArguments2(input) {\n  if (!input || typeof input !== \"object\") {\n    return input;\n  }\n  const args = input;\n  if (typeof args.edits === \"string\") {\n    try {\n      const parsed = JSON.parse(args.edits);\n      if (Array.isArray(parsed))\n        args.edits = parsed;\n    } catch {\n    }\n  }\n  const legacy = args;\n  if (typeof legacy.oldText !== \"string\" || typeof legacy.newText !== \"string\") {\n    return args;\n  }\n  const edits = Array.isArray(legacy.edits) ? [...legacy.edits] : [];\n  edits.push({ oldText: legacy.oldText, newText: legacy.newText });\n  const { oldText: _oldText, newText: _newText, ...rest } = legacy;\n  return { ...rest, edits };\n}\nfunction validateEditInput2(input) {\n  if (!Array.isArray(input.edits) || input.edits.length === 0) {\n    throw new Error(\"Edit tool input is invalid. edits must contain at least one replacement.\");\n  }\n  return { path: input.path, edits: input.edits };\n}\nfunction createEditCallRenderComponent() {\n  return Object.assign(new Box(1, 1, (text) => text), {\n    preview: void 0,\n    previewArgsKey: void 0,\n    previewPending: false,\n    settledError: false\n  });\n}\nfunction getEditCallRenderComponent(state, lastComponent) {\n  if (lastComponent instanceof Box) {\n    const component2 = lastComponent;\n    state.callComponent = component2;\n    return component2;\n  }\n  if (state.callComponent) {\n    return state.callComponent;\n  }\n  const component = createEditCallRenderComponent();\n  state.callComponent = component;\n  return component;\n}\nfunction getRenderablePreviewInput(args) {\n  if (!args) {\n    return null;\n  }\n  const path12 = typeof args.path === \"string\" ? args.path : typeof args.file_path === \"string\" ? args.file_path : null;\n  if (!path12) {\n    return null;\n  }\n  if (Array.isArray(args.edits) && args.edits.length > 0 && args.edits.every((edit) => typeof edit?.oldText === \"string\" && typeof edit?.newText === \"string\")) {\n    return { path: path12, edits: args.edits };\n  }\n  if (typeof args.oldText === \"string\" && typeof args.newText === \"string\") {\n    return { path: path12, edits: [{ oldText: args.oldText, newText: args.newText }] };\n  }\n  return null;\n}\nfunction formatEditCall(args, theme2, cwd) {\n  const pathDisplay = renderToolPath(str(args?.file_path ?? args?.path), theme2, cwd);\n  return `${theme2.fg(\"toolTitle\", theme2.bold(\"edit\"))} ${pathDisplay}`;\n}\nfunction formatEditResult(args, preview, result, theme2, isError) {\n  const rawPath = str(args?.file_path ?? args?.path);\n  const previewDiff = preview && !(\"error\" in preview) ? preview.diff : void 0;\n  const previewError = preview && \"error\" in preview ? preview.error : void 0;\n  if (isError) {\n    const errorText = result.content.filter((c) => c.type === \"text\").map((c) => c.text || \"\").join(\"\\n\");\n    if (!errorText || errorText === previewError) {\n      return void 0;\n    }\n    return theme2.fg(\"error\", errorText);\n  }\n  const resultDiff = result.details?.diff;\n  if (resultDiff && resultDiff !== previewDiff) {\n    return renderDiff(resultDiff, { filePath: rawPath ?? void 0 });\n  }\n  return void 0;\n}\nfunction getEditHeaderBg(preview, settledError, theme2) {\n  if (preview) {\n    if (\"error\" in preview) {\n      return (text) => theme2.bg(\"toolErrorBg\", text);\n    }\n    return (text) => theme2.bg(\"toolSuccessBg\", text);\n  }\n  if (settledError) {\n    return (text) => theme2.bg(\"toolErrorBg\", text);\n  }\n  return (text) => theme2.bg(\"toolPendingBg\", text);\n}\nfunction buildEditCallComponent(component, args, theme2, cwd) {\n  component.setBgFn(getEditHeaderBg(component.preview, component.settledError, theme2));\n  component.clear();\n  component.addChild(new Text(formatEditCall(args, theme2, cwd), 0, 0));\n  if (!component.preview) {\n    return component;\n  }\n  const body = \"error\" in component.preview ? theme2.fg(\"error\", component.preview.error) : renderDiff(component.preview.diff);\n  component.addChild(new Spacer(1));\n  component.addChild(new Text(body, 0, 0));\n  return component;\n}\nfunction setEditPreview(component, preview, argsKey) {\n  const current = component.preview;\n  const changed = current === void 0 || (\"error\" in current && \"error\" in preview ? current.error !== preview.error : \"error\" in current !== \"error\" in preview) || !(\"error\" in current) && !(\"error\" in preview) && (current.diff !== preview.diff || current.firstChangedLine !== preview.firstChangedLine);\n  component.preview = preview;\n  component.previewArgsKey = argsKey;\n  component.previewPending = false;\n  return changed;\n}\nfunction createEditToolDefinition(cwd, options) {\n  const ops = options?.operations ?? defaultEditOperations;\n  return {\n    name: \"edit\",\n    label: \"edit\",\n    description: \"Edit a single file using exact text replacement. Every edits[].oldText must match a unique, non-overlapping region of the original file. If two changes affect the same block or nearby lines, merge them into one edit instead of emitting overlapping edits. Do not include large unchanged regions just to connect distant changes.\",\n    promptSnippet: editToolSystemPromptContribution.snippet,\n    promptGuidelines: [...editToolSystemPromptContribution.guidelines],\n    parameters: editSchema2,\n    constrainedSampling: getExperimentalToolSampling(),\n    renderShell: \"self\",\n    prepareArguments: prepareEditArguments2,\n    async execute(_toolCallId, input, signal, _onUpdate, _ctx) {\n      const { path: path12, edits } = validateEditInput2(input);\n      const absolutePath = resolveToCwd(path12, cwd);\n      return withFileMutationQueue2(absolutePath, async () => {\n        const throwIfAborted2 = () => {\n          if (signal?.aborted)\n            throw new Error(\"Operation aborted\");\n        };\n        throwIfAborted2();\n        try {\n          await ops.access(absolutePath);\n        } catch (error) {\n          throwIfAborted2();\n          const errorMessage2 = error instanceof Error && \"code\" in error ? `Error code: ${error.code}` : String(error);\n          throw new Error(`Could not edit file: ${path12}. ${errorMessage2}.`);\n        }\n        throwIfAborted2();\n        const buffer = await ops.readFile(absolutePath);\n        const rawContent = buffer.toString(\"utf-8\");\n        throwIfAborted2();\n        const { bom, text: content } = stripBom2(rawContent);\n        const originalEnding = detectLineEnding2(content);\n        const normalizedContent = normalizeToLF2(content);\n        const { baseContent, newContent } = applyEditsToNormalizedContent2(normalizedContent, edits, path12);\n        throwIfAborted2();\n        const finalContent = bom + restoreLineEndings2(newContent, originalEnding);\n        await ops.writeFile(absolutePath, finalContent);\n        throwIfAborted2();\n        const diffResult = generateDiffString2(baseContent, newContent);\n        const patch = generateUnifiedPatch2(path12, baseContent, newContent);\n        return {\n          content: [\n            {\n              type: \"text\",\n              text: `Successfully replaced ${edits.length} block(s) in ${path12}.`\n            }\n          ],\n          details: { diff: diffResult.diff, patch, firstChangedLine: diffResult.firstChangedLine }\n        };\n      });\n    },\n    renderCall(args, theme2, context) {\n      const component = getEditCallRenderComponent(context.state, context.lastComponent);\n      const previewInput = getRenderablePreviewInput(args);\n      const argsKey = previewInput ? JSON.stringify({ path: previewInput.path, edits: previewInput.edits }) : void 0;\n      if (component.previewArgsKey !== argsKey) {\n        component.preview = void 0;\n        component.previewArgsKey = argsKey;\n        component.previewPending = false;\n        component.settledError = false;\n      }\n      if (context.argsComplete && previewInput && !component.preview && !component.previewPending) {\n        component.previewPending = true;\n        const requestKey = argsKey;\n        void computeEditsDiff(previewInput.path, previewInput.edits, context.cwd).then((preview) => {\n          if (component.previewArgsKey === requestKey) {\n            setEditPreview(component, preview, requestKey);\n            context.invalidate();\n          }\n        });\n      }\n      return buildEditCallComponent(component, args, theme2, context.cwd);\n    },\n    renderResult(result, _options, theme2, context) {\n      const callComponent = context.state.callComponent;\n      const previewInput = getRenderablePreviewInput(context.args);\n      const argsKey = previewInput ? JSON.stringify({ path: previewInput.path, edits: previewInput.edits }) : void 0;\n      const typedResult = result;\n      const resultDiff = !context.isError ? typedResult.details?.diff : void 0;\n      let changed = false;\n      if (callComponent) {\n        if (typeof resultDiff === \"string\") {\n          changed = setEditPreview(callComponent, { diff: resultDiff, firstChangedLine: typedResult.details?.firstChangedLine }, argsKey) || changed;\n        }\n        if (callComponent.settledError !== context.isError) {\n          callComponent.settledError = context.isError;\n          changed = true;\n        }\n        if (changed) {\n          buildEditCallComponent(callComponent, context.args, theme2, context.cwd);\n        }\n      }\n      const output = formatEditResult(context.args, callComponent?.preview, typedResult, theme2, context.isError);\n      const component = context.lastComponent ?? new Container();\n      component.clear();\n      if (!output) {\n        return component;\n      }\n      component.addChild(new Spacer(1));\n      component.addChild(new Text(output, 1, 0));\n      return component;\n    }\n  };\n}\nfunction createEditTool2(cwd, options) {\n  return wrapToolDefinition(createEditToolDefinition(cwd, options));\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/find.js\nimport { createInterface as createInterface2 } from \"node:readline\";\nimport { spawn as spawn4 } from \"child_process\";\nimport path7 from \"path\";\nimport { Type as Type12 } from \"typebox\";\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/utils/tools-manager.js\nimport { spawnSync as spawnSync4 } from \"child_process\";\nimport { chmodSync as chmodSync3, createWriteStream as createWriteStream3, existsSync as existsSync15, mkdirSync as mkdirSync6, readdirSync as readdirSync7, renameSync, rmSync as rmSync2 } from \"fs\";\nimport { arch, platform } from \"os\";\nimport { join as join23 } from \"path\";\nimport { Readable } from \"stream\";\nimport { pipeline } from \"stream/promises\";\nvar TOOLS_DIR = getBinDir();\nvar NETWORK_TIMEOUT_MS2 = 1e4;\nvar DOWNLOAD_TIMEOUT_MS = 12e4;\nfunction isOfflineModeEnabled2() {\n  const value = process.env.PI_OFFLINE;\n  if (!value)\n    return false;\n  return value === \"1\" || value.toLowerCase() === \"true\" || value.toLowerCase() === \"yes\";\n}\nvar TOOLS = {\n  fd: {\n    name: \"fd\",\n    repo: \"sharkdp/fd\",\n    binaryName: \"fd\",\n    systemBinaryNames: [\"fd\", \"fdfind\"],\n    tagPrefix: \"v\",\n    getAssetName: (version, plat, architecture) => {\n      if (plat === \"darwin\") {\n        const archStr = architecture === \"arm64\" ? \"aarch64\" : \"x86_64\";\n        return `fd-v${version}-${archStr}-apple-darwin.tar.gz`;\n      } else if (plat === \"linux\") {\n        const archStr = architecture === \"arm64\" ? \"aarch64\" : \"x86_64\";\n        return `fd-v${version}-${archStr}-unknown-linux-gnu.tar.gz`;\n      } else if (plat === \"win32\") {\n        const archStr = architecture === \"arm64\" ? \"aarch64\" : \"x86_64\";\n        return `fd-v${version}-${archStr}-pc-windows-msvc.zip`;\n      }\n      return null;\n    }\n  },\n  rg: {\n    name: \"ripgrep\",\n    repo: \"BurntSushi/ripgrep\",\n    binaryName: \"rg\",\n    tagPrefix: \"\",\n    getAssetName: (version, plat, architecture) => {\n      if (plat === \"darwin\") {\n        const archStr = architecture === \"arm64\" ? \"aarch64\" : \"x86_64\";\n        return `ripgrep-${version}-${archStr}-apple-darwin.tar.gz`;\n      } else if (plat === \"linux\") {\n        if (architecture === \"arm64\") {\n          return `ripgrep-${version}-aarch64-unknown-linux-gnu.tar.gz`;\n        }\n        return `ripgrep-${version}-x86_64-unknown-linux-musl.tar.gz`;\n      } else if (plat === \"win32\") {\n        const archStr = architecture === \"arm64\" ? \"aarch64\" : \"x86_64\";\n        return `ripgrep-${version}-${archStr}-pc-windows-msvc.zip`;\n      }\n      return null;\n    }\n  }\n};\nfunction commandExists(cmd) {\n  try {\n    const result = spawnSync4(cmd, [\"--version\"], { stdio: \"pipe\" });\n    return result.error === void 0 || result.error === null;\n  } catch {\n    return false;\n  }\n}\nfunction getToolPath(tool) {\n  const config = TOOLS[tool];\n  if (!config)\n    return null;\n  const localPath = join23(TOOLS_DIR, config.binaryName + (platform() === \"win32\" ? \".exe\" : \"\"));\n  if (existsSync15(localPath)) {\n    return localPath;\n  }\n  const systemBinaryNames = config.systemBinaryNames ?? [config.binaryName];\n  for (const systemBinaryName of systemBinaryNames) {\n    if (commandExists(systemBinaryName)) {\n      return systemBinaryName;\n    }\n  }\n  return null;\n}\nasync function getLatestVersion(repo) {\n  const response = await fetchWithRetry(`https://api.github.com/repos/${repo}/releases/latest`, {\n    headers: { \"User-Agent\": `${APP_NAME}-coding-agent` }\n  }, { timeoutMs: NETWORK_TIMEOUT_MS2 });\n  if (!response.ok) {\n    throw new Error(`GitHub API error: ${response.status}`);\n  }\n  const data = await response.json();\n  return data.tag_name.replace(/^v/, \"\");\n}\nasync function downloadFile(url, dest) {\n  const response = await fetchWithRetry(url, void 0, { timeoutMs: DOWNLOAD_TIMEOUT_MS });\n  if (!response.ok) {\n    throw new Error(`Failed to download: ${response.status}`);\n  }\n  if (!response.body) {\n    throw new Error(\"No response body\");\n  }\n  const fileStream = createWriteStream3(dest);\n  await pipeline(Readable.fromWeb(response.body), fileStream);\n}\nfunction findBinaryRecursively(rootDir, binaryFileName) {\n  const stack = [rootDir];\n  while (stack.length > 0) {\n    const currentDir = stack.pop();\n    if (!currentDir)\n      continue;\n    const entries = readdirSync7(currentDir, { withFileTypes: true });\n    for (const entry of entries) {\n      const fullPath = join23(currentDir, entry.name);\n      if (entry.isFile() && entry.name === binaryFileName) {\n        return fullPath;\n      }\n      if (entry.isDirectory()) {\n        stack.push(fullPath);\n      }\n    }\n  }\n  return null;\n}\nfunction formatSpawnFailure(result) {\n  if (result.error?.message) {\n    return result.error.message;\n  }\n  const stderr = result.stderr?.toString().trim();\n  if (stderr) {\n    return stderr;\n  }\n  const stdout = result.stdout?.toString().trim();\n  if (stdout) {\n    return stdout;\n  }\n  return `exit status ${result.status ?? \"unknown\"}`;\n}\nfunction runExtractionCommand(command, args) {\n  const result = spawnSync4(command, args, { stdio: \"pipe\" });\n  if (!result.error && result.status === 0) {\n    return null;\n  }\n  return `${command}: ${formatSpawnFailure(result)}`;\n}\nfunction extractTarGzArchive(archivePath, extractDir, assetName) {\n  const failure = runExtractionCommand(\"tar\", [\"xzf\", archivePath, \"-C\", extractDir]);\n  if (failure) {\n    throw new Error(`Failed to extract ${assetName}: ${failure}`);\n  }\n}\nfunction getWindowsTarCommand() {\n  const systemRoot = process.env.SystemRoot ?? process.env.WINDIR;\n  if (systemRoot) {\n    const systemTar = join23(systemRoot, \"System32\", \"tar.exe\");\n    if (existsSync15(systemTar)) {\n      return systemTar;\n    }\n  }\n  return \"tar.exe\";\n}\nfunction extractZipArchive(archivePath, extractDir, assetName) {\n  const failures = [];\n  if (platform() === \"win32\") {\n    const tarFailure = runExtractionCommand(getWindowsTarCommand(), [\"xf\", archivePath, \"-C\", extractDir]);\n    if (!tarFailure)\n      return;\n    failures.push(tarFailure);\n    const script = \"& { param($archive, $destination) $ErrorActionPreference = 'Stop'; Expand-Archive -LiteralPath $archive -DestinationPath $destination -Force }\";\n    const powershellFailure = runExtractionCommand(\"powershell.exe\", [\n      \"-NoLogo\",\n      \"-NoProfile\",\n      \"-NonInteractive\",\n      \"-ExecutionPolicy\",\n      \"Bypass\",\n      \"-Command\",\n      script,\n      archivePath,\n      extractDir\n    ]);\n    if (!powershellFailure)\n      return;\n    failures.push(powershellFailure);\n  } else {\n    const unzipFailure = runExtractionCommand(\"unzip\", [\"-q\", archivePath, \"-d\", extractDir]);\n    if (!unzipFailure)\n      return;\n    failures.push(unzipFailure);\n    const tarFailure = runExtractionCommand(\"tar\", [\"xf\", archivePath, \"-C\", extractDir]);\n    if (!tarFailure)\n      return;\n    failures.push(tarFailure);\n  }\n  throw new Error(`Failed to extract ${assetName}: ${failures.join(\"; \")}`);\n}\nasync function downloadTool(tool) {\n  const config = TOOLS[tool];\n  if (!config)\n    throw new Error(`Unknown tool: ${tool}`);\n  const plat = platform();\n  const architecture = arch();\n  let version = await getLatestVersion(config.repo);\n  if (tool === \"fd\" && plat === \"darwin\" && architecture === \"x64\") {\n    version = \"10.3.0\";\n  }\n  const assetName = config.getAssetName(version, plat, architecture);\n  if (!assetName) {\n    throw new Error(`Unsupported platform: ${plat}/${architecture}`);\n  }\n  mkdirSync6(TOOLS_DIR, { recursive: true });\n  const downloadUrl = `https://github.com/${config.repo}/releases/download/${config.tagPrefix}${version}/${assetName}`;\n  const archivePath = join23(TOOLS_DIR, assetName);\n  const binaryExt = plat === \"win32\" ? \".exe\" : \"\";\n  const binaryPath = join23(TOOLS_DIR, config.binaryName + binaryExt);\n  await downloadFile(downloadUrl, archivePath);\n  const extractDir = join23(TOOLS_DIR, `extract_tmp_${config.binaryName}_${process.pid}_${Date.now()}_${Math.random().toString(36).slice(2, 10)}`);\n  mkdirSync6(extractDir, { recursive: true });\n  try {\n    if (assetName.endsWith(\".tar.gz\")) {\n      extractTarGzArchive(archivePath, extractDir, assetName);\n    } else if (assetName.endsWith(\".zip\")) {\n      extractZipArchive(archivePath, extractDir, assetName);\n    } else {\n      throw new Error(`Unsupported archive format: ${assetName}`);\n    }\n    const binaryFileName = config.binaryName + binaryExt;\n    const extractedDir = join23(extractDir, assetName.replace(/\\.(tar\\.gz|zip)$/, \"\"));\n    const extractedBinaryCandidates = [join23(extractedDir, binaryFileName), join23(extractDir, binaryFileName)];\n    let extractedBinary = extractedBinaryCandidates.find((candidate) => existsSync15(candidate));\n    if (!extractedBinary) {\n      extractedBinary = findBinaryRecursively(extractDir, binaryFileName) ?? void 0;\n    }\n    if (extractedBinary) {\n      renameSync(extractedBinary, binaryPath);\n    } else {\n      throw new Error(`Binary not found in archive: expected ${binaryFileName} under ${extractDir}`);\n    }\n    if (plat !== \"win32\") {\n      chmodSync3(binaryPath, 493);\n    }\n  } finally {\n    rmSync2(archivePath, { force: true });\n    rmSync2(extractDir, { recursive: true, force: true });\n  }\n  return binaryPath;\n}\nvar TERMUX_PACKAGES = {\n  fd: \"fd\",\n  rg: \"ripgrep\"\n};\nasync function ensureTool(tool, onStatus) {\n  const existingPath = getToolPath(tool);\n  if (existingPath) {\n    return existingPath;\n  }\n  const config = TOOLS[tool];\n  if (!config)\n    return void 0;\n  if (isOfflineModeEnabled2()) {\n    onStatus?.({ type: \"warning\", message: `${config.name} not found. Offline mode enabled, skipping download.` });\n    return void 0;\n  }\n  if (platform() === \"android\") {\n    const pkgName = TERMUX_PACKAGES[tool] ?? tool;\n    onStatus?.({ type: \"warning\", message: `${config.name} not found. Install with: pkg install ${pkgName}` });\n    return void 0;\n  }\n  onStatus?.({ type: \"info\", message: `${config.name} not found. Downloading...` });\n  try {\n    const path12 = await downloadTool(tool);\n    onStatus?.({ type: \"info\", message: `${config.name} installed to ${path12}` });\n    return path12;\n  } catch (e) {\n    onStatus?.({\n      type: \"warning\",\n      message: `Failed to download ${config.name}: ${e instanceof Error ? e.message : e}`\n    });\n    return void 0;\n  }\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/find.js\nfunction relativizeFindResultPath(resultPath, searchPath, pathModule = path7) {\n  const hadTrailingSeparator = resultPath.endsWith(pathModule.sep) || pathModule.sep === \"\\\\\" && resultPath.endsWith(\"/\");\n  const relativePath = pathModule.isAbsolute(resultPath) ? pathModule.relative(searchPath, resultPath) : resultPath;\n  const posixPath = relativePath.split(pathModule.sep).join(\"/\");\n  return hadTrailingSeparator && !posixPath.endsWith(\"/\") ? `${posixPath}/` : posixPath;\n}\nvar findSchema = Type12.Object({\n  pattern: Type12.String({\n    description: \"Glob pattern to match files, e.g. '*.ts', '**/*.json', or 'src/**/*.spec.ts'\"\n  }),\n  path: Type12.Optional(Type12.String({ description: \"Directory to search in (default: current directory)\" })),\n  limit: Type12.Optional(Type12.Number({ description: \"Maximum number of results (default: 1000)\" }))\n});\nvar findToolSystemPromptContribution = {\n  snippet: \"Find files by glob pattern (respects .gitignore)\",\n  guidelines: []\n};\nvar DEFAULT_LIMIT = 1e3;\nvar defaultFindOperations = {\n  exists: pathExists,\n  // This is a placeholder. Actual fd execution happens in execute() when no custom glob is provided.\n  glob: () => []\n};\nfunction formatFindCall(args, theme2) {\n  const pattern = str(args?.pattern);\n  const rawPath = str(args?.path);\n  const path12 = rawPath !== null ? shortenPath2(rawPath || \".\") : null;\n  const limit = args?.limit;\n  const invalidArg = invalidArgText(theme2);\n  let text = theme2.fg(\"toolTitle\", theme2.bold(\"find\")) + \" \" + (pattern === null ? invalidArg : theme2.fg(\"accent\", pattern || \"\")) + theme2.fg(\"toolOutput\", ` in ${path12 === null ? invalidArg : path12}`);\n  if (limit !== void 0) {\n    text += theme2.fg(\"toolOutput\", ` (limit ${limit})`);\n  }\n  return text;\n}\nfunction formatFindResult(result, options, theme2, showImages) {\n  const output = getTextOutput(result, showImages).trim();\n  let text = \"\";\n  if (output) {\n    const lines = output.split(\"\\n\");\n    const maxLines = options.expanded ? lines.length : 20;\n    const displayLines = lines.slice(0, maxLines);\n    const remaining = lines.length - maxLines;\n    text += `\n${displayLines.map((line) => theme2.fg(\"toolOutput\", line)).join(\"\\n\")}`;\n    if (remaining > 0) {\n      text += `${theme2.fg(\"muted\", `\n... (${remaining} more lines,`)} ${keyHint(\"app.tools.expand\", \"to expand\")}${theme2.fg(\"muted\", \")\")}`;\n    }\n  }\n  const resultLimit = result.details?.resultLimitReached;\n  const truncation = result.details?.truncation;\n  if (resultLimit || truncation?.truncated) {\n    const warnings = [];\n    if (resultLimit)\n      warnings.push(`${resultLimit} results limit`);\n    if (truncation?.truncated)\n      warnings.push(`${formatSize2(truncation.maxBytes ?? DEFAULT_MAX_BYTES3)} limit`);\n    text += `\n${theme2.fg(\"warning\", `[Truncated: ${warnings.join(\", \")}]`)}`;\n  }\n  return text;\n}\nfunction createFindToolDefinition(cwd, options) {\n  const customOps = options?.operations;\n  return {\n    name: \"find\",\n    label: \"find\",\n    description: `Search for files by glob pattern. Returns matching file paths relative to the search directory. Respects .gitignore. Output is truncated to ${DEFAULT_LIMIT} results or ${DEFAULT_MAX_BYTES3 / 1024}KB (whichever is hit first).`,\n    promptSnippet: findToolSystemPromptContribution.snippet,\n    parameters: findSchema,\n    async execute(_toolCallId, { pattern, path: searchDir, limit }, signal, _onUpdate, _ctx) {\n      return new Promise((resolve15, reject) => {\n        if (signal?.aborted) {\n          reject(new Error(\"Operation aborted\"));\n          return;\n        }\n        let settled = false;\n        let stopChild;\n        const settle = (fn) => {\n          if (settled)\n            return;\n          settled = true;\n          signal?.removeEventListener(\"abort\", onAbort);\n          stopChild = void 0;\n          fn();\n        };\n        const onAbort = () => {\n          stopChild?.();\n          settle(() => reject(new Error(\"Operation aborted\")));\n        };\n        signal?.addEventListener(\"abort\", onAbort, { once: true });\n        (async () => {\n          try {\n            const searchPath = resolveToCwd(searchDir || \".\", cwd);\n            const effectiveLimit = limit ?? DEFAULT_LIMIT;\n            const ops = customOps ?? defaultFindOperations;\n            if (customOps?.glob) {\n              if (!await ops.exists(searchPath)) {\n                settle(() => reject(new Error(`Path not found: ${searchPath}`)));\n                return;\n              }\n              if (signal?.aborted) {\n                settle(() => reject(new Error(\"Operation aborted\")));\n                return;\n              }\n              const results = await ops.glob(pattern, searchPath, {\n                ignore: [\"**/node_modules/**\", \"**/.git/**\"],\n                limit: effectiveLimit\n              });\n              if (signal?.aborted) {\n                settle(() => reject(new Error(\"Operation aborted\")));\n                return;\n              }\n              if (results.length === 0) {\n                settle(() => resolve15({\n                  content: [{ type: \"text\", text: \"No files found matching pattern\" }],\n                  details: void 0\n                }));\n                return;\n              }\n              const relativized = results.map((p) => relativizeFindResultPath(p, searchPath));\n              const resultLimitReached = relativized.length >= effectiveLimit;\n              const rawOutput = relativized.join(\"\\n\");\n              const truncation = truncateHead2(rawOutput, { maxLines: Number.MAX_SAFE_INTEGER });\n              let resultOutput = truncation.content;\n              const details = {};\n              const notices = [];\n              if (resultLimitReached) {\n                notices.push(`${effectiveLimit} results limit reached`);\n                details.resultLimitReached = effectiveLimit;\n              }\n              if (truncation.truncated) {\n                notices.push(`${formatSize2(DEFAULT_MAX_BYTES3)} limit reached`);\n                details.truncation = truncation;\n              }\n              if (notices.length > 0) {\n                resultOutput += `\n\n[${notices.join(\". \")}]`;\n              }\n              settle(() => resolve15({\n                content: [{ type: \"text\", text: resultOutput }],\n                details: Object.keys(details).length > 0 ? details : void 0\n              }));\n              return;\n            }\n            const fdPath = await ensureTool(\"fd\");\n            if (signal?.aborted) {\n              settle(() => reject(new Error(\"Operation aborted\")));\n              return;\n            }\n            if (!fdPath) {\n              settle(() => reject(new Error(\"fd is not available and could not be downloaded\")));\n              return;\n            }\n            const args = [\"--glob\", \"--color=never\", \"--hidden\"];\n            let insideGitRepo = false;\n            for (let current = searchPath; ; ) {\n              if (await pathExists(path7.join(current, \".git\"))) {\n                insideGitRepo = true;\n                break;\n              }\n              const parent = path7.dirname(current);\n              if (parent === current)\n                break;\n              current = parent;\n            }\n            if (!insideGitRepo)\n              args.push(\"--no-require-git\");\n            args.push(\"--max-results\", String(effectiveLimit));\n            let effectivePattern = pattern;\n            if (pattern.includes(\"/\")) {\n              args.push(\"--full-path\");\n              if (!pattern.startsWith(\"/\") && !pattern.startsWith(\"**/\") && pattern !== \"**\") {\n                effectivePattern = `**/${pattern}`;\n              }\n              if (process.platform === \"win32\")\n                effectivePattern = effectivePattern.replaceAll(\"/\", String.raw`[/\\\\]`);\n            }\n            args.push(\"--\", effectivePattern, searchPath);\n            const child = spawn4(fdPath, args, { stdio: [\"ignore\", \"pipe\", \"pipe\"] });\n            const rl = createInterface2({ input: child.stdout });\n            let stderr = \"\";\n            const lines = [];\n            stopChild = () => {\n              if (!child.killed) {\n                child.kill();\n              }\n            };\n            const cleanup = () => {\n              rl.close();\n            };\n            child.stderr?.on(\"data\", (chunk) => {\n              stderr += chunk.toString();\n            });\n            rl.on(\"line\", (line) => {\n              lines.push(line);\n            });\n            child.on(\"error\", (error) => {\n              cleanup();\n              settle(() => reject(new Error(`Failed to run fd: ${error.message}`)));\n            });\n            child.on(\"close\", (code) => {\n              cleanup();\n              if (signal?.aborted) {\n                settle(() => reject(new Error(\"Operation aborted\")));\n                return;\n              }\n              const output = lines.join(\"\\n\");\n              if (code !== 0) {\n                const errorMsg = stderr.trim() || `fd exited with code ${code}`;\n                if (!output) {\n                  settle(() => reject(new Error(errorMsg)));\n                  return;\n                }\n              }\n              if (!output) {\n                settle(() => resolve15({\n                  content: [{ type: \"text\", text: \"No files found matching pattern\" }],\n                  details: void 0\n                }));\n                return;\n              }\n              const relativized = [];\n              for (const rawLine of lines) {\n                const line = rawLine.replace(/\\r$/, \"\").trim();\n                if (!line)\n                  continue;\n                relativized.push(relativizeFindResultPath(line, searchPath));\n              }\n              const resultLimitReached = relativized.length >= effectiveLimit;\n              const rawOutput = relativized.join(\"\\n\");\n              const truncation = truncateHead2(rawOutput, { maxLines: Number.MAX_SAFE_INTEGER });\n              let resultOutput = truncation.content;\n              const details = {};\n              const notices = [];\n              if (resultLimitReached) {\n                notices.push(`${effectiveLimit} results limit reached. Use limit=${effectiveLimit * 2} for more, or refine pattern`);\n                details.resultLimitReached = effectiveLimit;\n              }\n              if (truncation.truncated) {\n                notices.push(`${formatSize2(DEFAULT_MAX_BYTES3)} limit reached`);\n                details.truncation = truncation;\n              }\n              if (notices.length > 0) {\n                resultOutput += `\n\n[${notices.join(\". \")}]`;\n              }\n              settle(() => resolve15({\n                content: [{ type: \"text\", text: resultOutput }],\n                details: Object.keys(details).length > 0 ? details : void 0\n              }));\n            });\n          } catch (e) {\n            if (signal?.aborted) {\n              settle(() => reject(new Error(\"Operation aborted\")));\n              return;\n            }\n            const error = e instanceof Error ? e : new Error(String(e));\n            settle(() => reject(error));\n          }\n        })();\n      });\n    },\n    renderCall(args, theme2, context) {\n      const text = context.lastComponent ?? new Text(\"\", 0, 0);\n      text.setText(formatFindCall(args, theme2));\n      return text;\n    },\n    renderResult(result, options2, theme2, context) {\n      const text = context.lastComponent ?? new Text(\"\", 0, 0);\n      text.setText(formatFindResult(result, options2, theme2, context.showImages));\n      return text;\n    }\n  };\n}\nfunction createFindTool(cwd, options) {\n  return wrapToolDefinition(createFindToolDefinition(cwd, options));\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/grep.js\nimport { readFile as fsReadFile2, stat as fsStat } from \"node:fs/promises\";\nimport { createInterface as createInterface3 } from \"node:readline\";\nimport { spawn as spawn5 } from \"child_process\";\nimport path8 from \"path\";\nimport { Type as Type13 } from \"typebox\";\nvar grepSchema = Type13.Object({\n  pattern: Type13.String({ description: \"Search pattern (regex or literal string)\" }),\n  path: Type13.Optional(Type13.String({ description: \"Directory or file to search (default: current directory)\" })),\n  glob: Type13.Optional(Type13.String({ description: \"Filter files by glob pattern, e.g. '*.ts' or '**/*.spec.ts'\" })),\n  ignoreCase: Type13.Optional(Type13.Boolean({ description: \"Case-insensitive search (default: false)\" })),\n  literal: Type13.Optional(Type13.Boolean({ description: \"Treat pattern as literal string instead of regex (default: false)\" })),\n  context: Type13.Optional(Type13.Number({ description: \"Number of lines to show before and after each match (default: 0)\" })),\n  limit: Type13.Optional(Type13.Number({ description: \"Maximum number of matches to return (default: 100)\" }))\n});\nvar grepToolSystemPromptContribution = {\n  snippet: \"Search file contents for patterns (respects .gitignore)\",\n  guidelines: []\n};\nvar DEFAULT_LIMIT2 = 100;\nvar defaultGrepOperations = {\n  isDirectory: async (p) => (await fsStat(p)).isDirectory(),\n  readFile: (p) => fsReadFile2(p, \"utf-8\")\n};\nfunction formatGrepCall(args, theme2) {\n  const pattern = str(args?.pattern);\n  const rawPath = str(args?.path);\n  const path12 = rawPath !== null ? shortenPath2(rawPath || \".\") : null;\n  const glob = str(args?.glob);\n  const limit = args?.limit;\n  const invalidArg = invalidArgText(theme2);\n  let text = theme2.fg(\"toolTitle\", theme2.bold(\"grep\")) + \" \" + (pattern === null ? invalidArg : theme2.fg(\"accent\", `/${pattern || \"\"}/`)) + theme2.fg(\"toolOutput\", ` in ${path12 === null ? invalidArg : path12}`);\n  if (glob)\n    text += theme2.fg(\"toolOutput\", ` (${glob})`);\n  if (limit !== void 0)\n    text += theme2.fg(\"toolOutput\", ` limit ${limit}`);\n  return text;\n}\nfunction formatGrepResult(result, options, theme2, showImages) {\n  const output = getTextOutput(result, showImages).trim();\n  let text = \"\";\n  if (output) {\n    const lines = output.split(\"\\n\");\n    const maxLines = options.expanded ? lines.length : 15;\n    const displayLines = lines.slice(0, maxLines);\n    const remaining = lines.length - maxLines;\n    text += `\n${displayLines.map((line) => theme2.fg(\"toolOutput\", line)).join(\"\\n\")}`;\n    if (remaining > 0) {\n      text += `${theme2.fg(\"muted\", `\n... (${remaining} more lines,`)} ${keyHint(\"app.tools.expand\", \"to expand\")}${theme2.fg(\"muted\", \")\")}`;\n    }\n  }\n  const matchLimit = result.details?.matchLimitReached;\n  const truncation = result.details?.truncation;\n  const linesTruncated = result.details?.linesTruncated;\n  if (matchLimit || truncation?.truncated || linesTruncated) {\n    const warnings = [];\n    if (matchLimit)\n      warnings.push(`${matchLimit} matches limit`);\n    if (truncation?.truncated)\n      warnings.push(`${formatSize2(truncation.maxBytes ?? DEFAULT_MAX_BYTES3)} limit`);\n    if (linesTruncated)\n      warnings.push(\"some lines truncated\");\n    text += `\n${theme2.fg(\"warning\", `[Truncated: ${warnings.join(\", \")}]`)}`;\n  }\n  return text;\n}\nfunction createGrepToolDefinition(cwd, options) {\n  const customOps = options?.operations;\n  return {\n    name: \"grep\",\n    label: \"grep\",\n    description: `Search file contents for a pattern. Returns matching lines with file paths and line numbers. Respects .gitignore. Output is truncated to ${DEFAULT_LIMIT2} matches or ${DEFAULT_MAX_BYTES3 / 1024}KB (whichever is hit first). Long lines are truncated to ${GREP_MAX_LINE_LENGTH2} chars.`,\n    promptSnippet: grepToolSystemPromptContribution.snippet,\n    parameters: grepSchema,\n    async execute(_toolCallId, { pattern, path: searchDir, glob, ignoreCase, literal, context, limit }, signal, _onUpdate, _ctx) {\n      return new Promise((resolve15, reject) => {\n        if (signal?.aborted) {\n          reject(new Error(\"Operation aborted\"));\n          return;\n        }\n        let settled = false;\n        const settle = (fn) => {\n          if (!settled) {\n            settled = true;\n            fn();\n          }\n        };\n        (async () => {\n          try {\n            const rgPath = await ensureTool(\"rg\");\n            if (!rgPath) {\n              settle(() => reject(new Error(\"ripgrep (rg) is not available and could not be downloaded\")));\n              return;\n            }\n            const searchPath = resolveToCwd(searchDir || \".\", cwd);\n            const ops = customOps ?? defaultGrepOperations;\n            let isDirectory;\n            try {\n              isDirectory = await ops.isDirectory(searchPath);\n            } catch {\n              settle(() => reject(new Error(`Path not found: ${searchPath}`)));\n              return;\n            }\n            const contextValue = context && context > 0 ? context : 0;\n            const effectiveLimit = Math.max(1, limit ?? DEFAULT_LIMIT2);\n            const formatPath = (filePath) => {\n              if (isDirectory) {\n                const relative9 = path8.relative(searchPath, filePath);\n                if (relative9 && !relative9.startsWith(\"..\")) {\n                  return relative9.replace(/\\\\/g, \"/\");\n                }\n              }\n              return path8.basename(filePath);\n            };\n            const fileCache = /* @__PURE__ */ new Map();\n            const getFileLines = async (filePath) => {\n              let lines = fileCache.get(filePath);\n              if (!lines) {\n                try {\n                  const content = await ops.readFile(filePath);\n                  lines = content.replace(/\\r\\n/g, \"\\n\").replace(/\\r/g, \"\\n\").split(\"\\n\");\n                } catch {\n                  lines = [];\n                }\n                fileCache.set(filePath, lines);\n              }\n              return lines;\n            };\n            const args = [\"--json\", \"--line-number\", \"--color=never\", \"--hidden\"];\n            if (ignoreCase)\n              args.push(\"--ignore-case\");\n            if (literal)\n              args.push(\"--fixed-strings\");\n            if (glob)\n              args.push(\"--glob\", glob);\n            args.push(\"--\", pattern, searchPath);\n            const child = spawn5(rgPath, args, { stdio: [\"ignore\", \"pipe\", \"pipe\"] });\n            const rl = createInterface3({ input: child.stdout });\n            let stderr = \"\";\n            let matchCount = 0;\n            let matchLimitReached = false;\n            let linesTruncated = false;\n            let aborted = false;\n            let killedDueToLimit = false;\n            const outputLines = [];\n            const cleanup = () => {\n              rl.close();\n              signal?.removeEventListener(\"abort\", onAbort);\n            };\n            const stopChild = (dueToLimit = false) => {\n              if (!child.killed) {\n                killedDueToLimit = dueToLimit;\n                child.kill();\n              }\n            };\n            const onAbort = () => {\n              aborted = true;\n              stopChild();\n            };\n            signal?.addEventListener(\"abort\", onAbort, { once: true });\n            child.stderr?.on(\"data\", (chunk) => {\n              stderr += chunk.toString();\n            });\n            const formatBlock = async (filePath, lineNumber) => {\n              const relativePath = formatPath(filePath);\n              const lines = await getFileLines(filePath);\n              if (!lines.length)\n                return [`${relativePath}:${lineNumber}: (unable to read file)`];\n              const block = [];\n              const start = contextValue > 0 ? Math.max(1, lineNumber - contextValue) : lineNumber;\n              const end = contextValue > 0 ? Math.min(lines.length, lineNumber + contextValue) : lineNumber;\n              for (let current = start; current <= end; current++) {\n                const lineText = lines[current - 1] ?? \"\";\n                const sanitized = lineText.replace(/\\r/g, \"\");\n                const isMatchLine = current === lineNumber;\n                const { text: truncatedText, wasTruncated } = truncateLine2(sanitized);\n                if (wasTruncated)\n                  linesTruncated = true;\n                if (isMatchLine)\n                  block.push(`${relativePath}:${current}: ${truncatedText}`);\n                else\n                  block.push(`${relativePath}-${current}- ${truncatedText}`);\n              }\n              return block;\n            };\n            const matches = [];\n            rl.on(\"line\", (line) => {\n              if (!line.trim() || matchCount >= effectiveLimit)\n                return;\n              let event;\n              try {\n                event = JSON.parse(line);\n              } catch {\n                return;\n              }\n              if (event.type === \"match\") {\n                matchCount++;\n                const filePath = event.data?.path?.text;\n                const lineNumber = event.data?.line_number;\n                const lineText = event.data?.lines?.text;\n                if (filePath && typeof lineNumber === \"number\")\n                  matches.push({ filePath, lineNumber, lineText });\n                if (matchCount >= effectiveLimit) {\n                  matchLimitReached = true;\n                  stopChild(true);\n                }\n              }\n            });\n            child.on(\"error\", (error) => {\n              cleanup();\n              settle(() => reject(new Error(`Failed to run ripgrep: ${error.message}`)));\n            });\n            child.on(\"close\", async (code) => {\n              cleanup();\n              if (aborted) {\n                settle(() => reject(new Error(\"Operation aborted\")));\n                return;\n              }\n              if (!killedDueToLimit && code !== 0 && code !== 1) {\n                const errorMsg = stderr.trim() || `ripgrep exited with code ${code}`;\n                settle(() => reject(new Error(errorMsg)));\n                return;\n              }\n              if (matchCount === 0) {\n                settle(() => resolve15({ content: [{ type: \"text\", text: \"No matches found\" }], details: void 0 }));\n                return;\n              }\n              for (const match of matches) {\n                if (contextValue === 0 && match.lineText !== void 0) {\n                  const relativePath = formatPath(match.filePath);\n                  const sanitized = match.lineText.replace(/\\r\\n/g, \"\\n\").replace(/\\r/g, \"\").replace(/\\n$/, \"\");\n                  const { text: truncatedText, wasTruncated } = truncateLine2(sanitized);\n                  if (wasTruncated)\n                    linesTruncated = true;\n                  outputLines.push(`${relativePath}:${match.lineNumber}: ${truncatedText}`);\n                } else {\n                  const block = await formatBlock(match.filePath, match.lineNumber);\n                  outputLines.push(...block);\n                }\n              }\n              const rawOutput = outputLines.join(\"\\n\");\n              const truncation = truncateHead2(rawOutput, { maxLines: Number.MAX_SAFE_INTEGER });\n              let output = truncation.content;\n              const details = {};\n              const notices = [];\n              if (matchLimitReached) {\n                notices.push(`${effectiveLimit} matches limit reached. Use limit=${effectiveLimit * 2} for more, or refine pattern`);\n                details.matchLimitReached = effectiveLimit;\n              }\n              if (truncation.truncated) {\n                notices.push(`${formatSize2(DEFAULT_MAX_BYTES3)} limit reached`);\n                details.truncation = truncation;\n              }\n              if (linesTruncated) {\n                notices.push(`Some lines truncated to ${GREP_MAX_LINE_LENGTH2} chars. Use read tool to see full lines`);\n                details.linesTruncated = true;\n              }\n              if (notices.length > 0)\n                output += `\n\n[${notices.join(\". \")}]`;\n              settle(() => resolve15({\n                content: [{ type: \"text\", text: output }],\n                details: Object.keys(details).length > 0 ? details : void 0\n              }));\n            });\n          } catch (err2) {\n            settle(() => reject(err2));\n          }\n        })();\n      });\n    },\n    renderCall(args, theme2, context) {\n      const text = context.lastComponent ?? new Text(\"\", 0, 0);\n      text.setText(formatGrepCall(args, theme2));\n      return text;\n    },\n    renderResult(result, options2, theme2, context) {\n      const text = context.lastComponent ?? new Text(\"\", 0, 0);\n      text.setText(formatGrepResult(result, options2, theme2, context.showImages));\n      return text;\n    }\n  };\n}\nfunction createGrepTool(cwd, options) {\n  return wrapToolDefinition(createGrepToolDefinition(cwd, options));\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/ls.js\nimport { readdir as fsReaddir, stat as fsStat2 } from \"node:fs/promises\";\nimport nodePath from \"path\";\nimport { Type as Type14 } from \"typebox\";\nvar lsSchema = Type14.Object({\n  path: Type14.Optional(Type14.String({ description: \"Directory to list (default: current directory)\" })),\n  limit: Type14.Optional(Type14.Number({ description: \"Maximum number of entries to return (default: 500)\" }))\n});\nvar lsToolSystemPromptContribution = {\n  snippet: \"List directory contents\",\n  guidelines: []\n};\nvar DEFAULT_LIMIT3 = 500;\nvar defaultLsOperations = {\n  exists: pathExists,\n  stat: fsStat2,\n  readdir: fsReaddir\n};\nfunction formatLsCall(args, theme2, cwd) {\n  const limit = args?.limit;\n  const pathDisplay = renderToolPath(str(args?.path), theme2, cwd, { emptyFallback: \".\" });\n  let text = `${theme2.fg(\"toolTitle\", theme2.bold(\"ls\"))} ${pathDisplay}`;\n  if (limit !== void 0) {\n    text += theme2.fg(\"toolOutput\", ` (limit ${limit})`);\n  }\n  return text;\n}\nfunction formatLsResult(result, options, theme2, showImages) {\n  const output = getTextOutput(result, showImages).trim();\n  let text = \"\";\n  if (output) {\n    const lines = output.split(\"\\n\");\n    const maxLines = options.expanded ? lines.length : 20;\n    const displayLines = lines.slice(0, maxLines);\n    const remaining = lines.length - maxLines;\n    text += `\n${displayLines.map((line) => theme2.fg(\"toolOutput\", line)).join(\"\\n\")}`;\n    if (remaining > 0) {\n      text += `${theme2.fg(\"muted\", `\n... (${remaining} more lines,`)} ${keyHint(\"app.tools.expand\", \"to expand\")}${theme2.fg(\"muted\", \")\")}`;\n    }\n  }\n  const entryLimit = result.details?.entryLimitReached;\n  const truncation = result.details?.truncation;\n  if (entryLimit || truncation?.truncated) {\n    const warnings = [];\n    if (entryLimit)\n      warnings.push(`${entryLimit} entries limit`);\n    if (truncation?.truncated)\n      warnings.push(`${formatSize2(truncation.maxBytes ?? DEFAULT_MAX_BYTES3)} limit`);\n    text += `\n${theme2.fg(\"warning\", `[Truncated: ${warnings.join(\", \")}]`)}`;\n  }\n  return text;\n}\nfunction createLsToolDefinition(cwd, options) {\n  const ops = options?.operations ?? defaultLsOperations;\n  return {\n    name: \"ls\",\n    label: \"ls\",\n    description: `List directory contents. Returns entries sorted alphabetically, with '/' suffix for directories. Includes dotfiles. Output is truncated to ${DEFAULT_LIMIT3} entries or ${DEFAULT_MAX_BYTES3 / 1024}KB (whichever is hit first).`,\n    promptSnippet: lsToolSystemPromptContribution.snippet,\n    parameters: lsSchema,\n    async execute(_toolCallId, { path: path12, limit }, signal, _onUpdate, _ctx) {\n      return new Promise((resolve15, reject) => {\n        if (signal?.aborted) {\n          reject(new Error(\"Operation aborted\"));\n          return;\n        }\n        const onAbort = () => reject(new Error(\"Operation aborted\"));\n        signal?.addEventListener(\"abort\", onAbort, { once: true });\n        (async () => {\n          try {\n            const dirPath = resolveToCwd(path12 || \".\", cwd);\n            const effectiveLimit = limit ?? DEFAULT_LIMIT3;\n            if (!await ops.exists(dirPath)) {\n              reject(new Error(`Path not found: ${dirPath}`));\n              return;\n            }\n            const stat3 = await ops.stat(dirPath);\n            if (!stat3.isDirectory()) {\n              reject(new Error(`Not a directory: ${dirPath}`));\n              return;\n            }\n            let entries;\n            try {\n              entries = await ops.readdir(dirPath);\n            } catch (e) {\n              reject(new Error(`Cannot read directory: ${e.message}`));\n              return;\n            }\n            entries.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()));\n            const results = [];\n            let entryLimitReached = false;\n            for (const entry of entries) {\n              if (results.length >= effectiveLimit) {\n                entryLimitReached = true;\n                break;\n              }\n              const fullPath = nodePath.join(dirPath, entry);\n              let suffix = \"\";\n              try {\n                const entryStat = await ops.stat(fullPath);\n                if (entryStat.isDirectory())\n                  suffix = \"/\";\n              } catch {\n                continue;\n              }\n              results.push(entry + suffix);\n            }\n            signal?.removeEventListener(\"abort\", onAbort);\n            if (results.length === 0) {\n              resolve15({ content: [{ type: \"text\", text: \"(empty directory)\" }], details: void 0 });\n              return;\n            }\n            const rawOutput = results.join(\"\\n\");\n            const truncation = truncateHead2(rawOutput, { maxLines: Number.MAX_SAFE_INTEGER });\n            let output = truncation.content;\n            const details = {};\n            const notices = [];\n            if (entryLimitReached) {\n              notices.push(`${effectiveLimit} entries limit reached. Use limit=${effectiveLimit * 2} for more`);\n              details.entryLimitReached = effectiveLimit;\n            }\n            if (truncation.truncated) {\n              notices.push(`${formatSize2(DEFAULT_MAX_BYTES3)} limit reached`);\n              details.truncation = truncation;\n            }\n            if (notices.length > 0) {\n              output += `\n\n[${notices.join(\". \")}]`;\n            }\n            resolve15({\n              content: [{ type: \"text\", text: output }],\n              details: Object.keys(details).length > 0 ? details : void 0\n            });\n          } catch (e) {\n            signal?.removeEventListener(\"abort\", onAbort);\n            reject(e);\n          }\n        })();\n      });\n    },\n    renderCall(args, theme2, context) {\n      const text = context.lastComponent ?? new Text(\"\", 0, 0);\n      text.setText(formatLsCall(args, theme2, context.cwd));\n      return text;\n    },\n    renderResult(result, options2, theme2, context) {\n      const text = context.lastComponent ?? new Text(\"\", 0, 0);\n      text.setText(formatLsResult(result, options2, theme2, context.showImages));\n      return text;\n    }\n  };\n}\nfunction createLsTool(cwd, options) {\n  return wrapToolDefinition(createLsToolDefinition(cwd, options));\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/read.js\nimport { basename as basename7, dirname as dirname13, isAbsolute as isAbsolute3, relative as relative4, resolve as resolvePath2, sep as sep6 } from \"node:path\";\nimport { constants as constants6 } from \"fs\";\nimport { access as fsAccess3, readFile as fsReadFile3 } from \"fs/promises\";\nimport { Type as Type15 } from \"typebox\";\nvar readSchema2 = Type15.Object({\n  path: Type15.String({ description: \"Path to the file to read (relative or absolute)\" }),\n  offset: Type15.Optional(Type15.Number({ description: \"Line number to start reading from (1-indexed)\" })),\n  limit: Type15.Optional(Type15.Number({ description: \"Maximum number of lines to read\" }))\n});\nvar readToolSystemPromptContribution = {\n  snippet: \"Read file contents\",\n  guidelines: [\"Use read to examine files instead of cat or sed.\"]\n};\nvar COMPACT_RESOURCE_FILE_NAMES = /* @__PURE__ */ new Set([\"AGENTS.override.md\", \"AGENTS.md\", \"AGENTS.MD\", \"CLAUDE.md\", \"CLAUDE.MD\"]);\nvar defaultReadOperations = {\n  readFile: (path12) => fsReadFile3(path12),\n  access: (path12) => fsAccess3(path12, constants6.R_OK),\n  detectImageMimeType: detectSupportedImageMimeTypeFromFile\n};\nfunction formatReadLineRange(args, theme2) {\n  if (args?.offset === void 0 && args?.limit === void 0)\n    return \"\";\n  const startLine = args.offset ?? 1;\n  const endLine = args.limit !== void 0 ? startLine + args.limit - 1 : \"\";\n  return theme2.fg(\"warning\", `:${startLine}${endLine ? `-${endLine}` : \"\"}`);\n}\nfunction formatReadCall(args, theme2, cwd) {\n  const pathDisplay = renderToolPath(str(args?.file_path ?? args?.path), theme2, cwd);\n  return `${theme2.fg(\"toolTitle\", theme2.bold(\"read\"))} ${pathDisplay}${formatReadLineRange(args, theme2)}`;\n}\nfunction trimTrailingEmptyLines(lines) {\n  let end = lines.length;\n  while (end > 0 && lines[end - 1] === \"\") {\n    end--;\n  }\n  return lines.slice(0, end);\n}\nfunction getNonVisionImageNote(model) {\n  if (!model || model.input.includes(\"image\")) {\n    return void 0;\n  }\n  return \"[Current model does not support images. The image will be omitted from this request.]\";\n}\nfunction toPosixPath3(filePath) {\n  return filePath.split(sep6).join(\"/\");\n}\nfunction getPiDocsClassification(absolutePath) {\n  const packageRoot = dirname13(getReadmePath());\n  const relativePath = relative4(resolvePath2(packageRoot), resolvePath2(absolutePath));\n  if (relativePath === \"\" || relativePath === \"..\" || relativePath.startsWith(`..${sep6}`) || isAbsolute3(relativePath)) {\n    return void 0;\n  }\n  const label = toPosixPath3(relativePath);\n  if (label === \"README.md\" || label.startsWith(\"docs/\") || label.startsWith(\"examples/\")) {\n    return { kind: \"docs\", label };\n  }\n  return void 0;\n}\nfunction getCompactReadClassification(args, cwd) {\n  const rawPath = str(args?.file_path ?? args?.path);\n  if (!rawPath)\n    return void 0;\n  const absolutePath = resolveToCwd(rawPath, cwd);\n  const fileName = basename7(absolutePath);\n  if (fileName === \"SKILL.md\") {\n    return { kind: \"skill\", label: basename7(dirname13(absolutePath)) || fileName };\n  }\n  const docsClassification = getPiDocsClassification(absolutePath);\n  if (docsClassification)\n    return docsClassification;\n  if (COMPACT_RESOURCE_FILE_NAMES.has(fileName)) {\n    return { kind: \"resource\", label: formatPathRelativeToCwdOrAbsolute(absolutePath, cwd) };\n  }\n  return void 0;\n}\nfunction formatCompactReadCall(classification, args, theme2) {\n  const expandHint = theme2.fg(\"dim\", ` (${keyText(\"app.tools.expand\")} to expand)`);\n  if (classification.kind === \"skill\") {\n    return theme2.fg(\"customMessageLabel\", `\\x1B[1m[skill]\\x1B[22m `) + theme2.fg(\"customMessageText\", classification.label) + formatReadLineRange(args, theme2) + expandHint;\n  }\n  return theme2.fg(\"toolTitle\", theme2.bold(`read ${classification.kind}`)) + \" \" + theme2.fg(\"accent\", classification.label) + formatReadLineRange(args, theme2) + expandHint;\n}\nfunction formatReadResult(args, result, options, theme2, showImages, _cwd, isError) {\n  if (!options.expanded && !isError) {\n    return \"\";\n  }\n  const rawPath = str(args?.file_path ?? args?.path);\n  const output = getTextOutput(result, showImages);\n  const lang = !isError && rawPath ? getLanguageFromPath(rawPath) : void 0;\n  const renderedLines = lang ? highlightCode(replaceTabs(output), lang) : output.split(\"\\n\");\n  const lines = trimTrailingEmptyLines(renderedLines);\n  const maxLines = options.expanded ? lines.length : 10;\n  const displayLines = lines.slice(0, maxLines);\n  const remaining = lines.length - maxLines;\n  let text = `\n${displayLines.map((line) => lang ? replaceTabs(line) : theme2.fg(\"toolOutput\", replaceTabs(line))).join(\"\\n\")}`;\n  if (remaining > 0) {\n    text += `${theme2.fg(\"muted\", `\n... (${remaining} more lines,`)} ${keyHint(\"app.tools.expand\", \"to expand\")}${theme2.fg(\"muted\", \")\")}`;\n  }\n  const truncation = result.details?.truncation;\n  if (truncation?.truncated) {\n    if (truncation.firstLineExceedsLimit) {\n      text += `\n${theme2.fg(\"warning\", `[First line exceeds ${formatSize2(truncation.maxBytes ?? DEFAULT_MAX_BYTES3)} limit]`)}`;\n    } else if (truncation.truncatedBy === \"lines\") {\n      text += `\n${theme2.fg(\"warning\", `[Truncated: showing ${truncation.outputLines} of ${truncation.totalLines} lines (${truncation.maxLines ?? DEFAULT_MAX_LINES2} line limit)]`)}`;\n    } else {\n      text += `\n${theme2.fg(\"warning\", `[Truncated: ${truncation.outputLines} lines shown (${formatSize2(truncation.maxBytes ?? DEFAULT_MAX_BYTES3)} limit)]`)}`;\n    }\n  }\n  return text;\n}\nfunction createReadToolDefinition(cwd, options) {\n  const autoResizeImages = options?.autoResizeImages ?? true;\n  const ops = options?.operations ?? defaultReadOperations;\n  return {\n    name: \"read\",\n    label: \"read\",\n    description: `Read the contents of a file. Supports text files and images (jpg, png, gif, webp, bmp). Images are sent as attachments. For text files, output is truncated to ${DEFAULT_MAX_LINES2} lines or ${DEFAULT_MAX_BYTES3 / 1024}KB (whichever is hit first). Use offset/limit for large files. When you need the full file, continue with offset until complete.`,\n    promptSnippet: readToolSystemPromptContribution.snippet,\n    promptGuidelines: [...readToolSystemPromptContribution.guidelines],\n    parameters: readSchema2,\n    constrainedSampling: getExperimentalToolSampling(),\n    async execute(_toolCallId, { path: path12, offset, limit }, signal, _onUpdate, ctx) {\n      return new Promise((resolve15, reject) => {\n        if (signal?.aborted) {\n          reject(new Error(\"Operation aborted\"));\n          return;\n        }\n        let aborted = false;\n        const onAbort = () => {\n          aborted = true;\n          reject(new Error(\"Operation aborted\"));\n        };\n        signal?.addEventListener(\"abort\", onAbort, { once: true });\n        (async () => {\n          try {\n            const absolutePath = await resolveReadPathAsync(path12, cwd);\n            if (aborted)\n              return;\n            await ops.access(absolutePath);\n            if (aborted)\n              return;\n            const mimeType = ops.detectImageMimeType ? await ops.detectImageMimeType(absolutePath) : void 0;\n            let content;\n            let details;\n            const nonVisionImageNote = getNonVisionImageNote(ctx?.model);\n            if (mimeType) {\n              const buffer = await ops.readFile(absolutePath);\n              const processed = await processImage(buffer, mimeType, { autoResizeImages });\n              if (!processed.ok) {\n                let textNote = `Read image file [${mimeType}]\n${processed.message}`;\n                if (nonVisionImageNote)\n                  textNote += `\n${nonVisionImageNote}`;\n                content = [{ type: \"text\", text: textNote }];\n              } else {\n                let textNote = `Read image file [${processed.mimeType}]`;\n                if (processed.hints.length > 0)\n                  textNote += `\n${processed.hints.join(\"\\n\")}`;\n                if (nonVisionImageNote)\n                  textNote += `\n${nonVisionImageNote}`;\n                content = [\n                  { type: \"text\", text: textNote },\n                  { type: \"image\", data: processed.data, mimeType: processed.mimeType }\n                ];\n              }\n            } else {\n              const buffer = await ops.readFile(absolutePath);\n              const textContent = buffer.toString(\"utf-8\");\n              const allLines = textContent.split(\"\\n\");\n              const totalFileLines = allLines.length;\n              const startLine = offset ? Math.max(0, offset - 1) : 0;\n              const startLineDisplay = startLine + 1;\n              if (startLine >= allLines.length) {\n                throw new Error(`Offset ${offset} is beyond end of file (${allLines.length} lines total)`);\n              }\n              let selectedContent;\n              let userLimitedLines;\n              if (limit !== void 0) {\n                const endLine = Math.min(startLine + limit, allLines.length);\n                selectedContent = allLines.slice(startLine, endLine).join(\"\\n\");\n                userLimitedLines = endLine - startLine;\n              } else {\n                selectedContent = allLines.slice(startLine).join(\"\\n\");\n              }\n              const truncation = truncateHead2(selectedContent);\n              let outputText;\n              if (truncation.firstLineExceedsLimit) {\n                const firstLineSize = formatSize2(Buffer.byteLength(allLines[startLine], \"utf-8\"));\n                outputText = `[Line ${startLineDisplay} is ${firstLineSize}, exceeds ${formatSize2(DEFAULT_MAX_BYTES3)} limit. Use bash: sed -n '${startLineDisplay}p' ${path12} | head -c ${DEFAULT_MAX_BYTES3}]`;\n                details = { truncation };\n              } else if (truncation.truncated) {\n                const endLineDisplay = startLineDisplay + truncation.outputLines - 1;\n                const nextOffset = endLineDisplay + 1;\n                outputText = truncation.content;\n                if (truncation.truncatedBy === \"lines\") {\n                  outputText += `\n\n[Showing lines ${startLineDisplay}-${endLineDisplay} of ${totalFileLines}. Use offset=${nextOffset} to continue.]`;\n                } else {\n                  outputText += `\n\n[Showing lines ${startLineDisplay}-${endLineDisplay} of ${totalFileLines} (${formatSize2(DEFAULT_MAX_BYTES3)} limit). Use offset=${nextOffset} to continue.]`;\n                }\n                details = { truncation };\n              } else if (userLimitedLines !== void 0 && startLine + userLimitedLines < allLines.length) {\n                const remaining = allLines.length - (startLine + userLimitedLines);\n                const nextOffset = startLine + userLimitedLines + 1;\n                outputText = `${truncation.content}\n\n[${remaining} more lines in file. Use offset=${nextOffset} to continue.]`;\n              } else {\n                outputText = truncation.content;\n              }\n              content = [{ type: \"text\", text: outputText }];\n            }\n            if (aborted)\n              return;\n            signal?.removeEventListener(\"abort\", onAbort);\n            resolve15({ content, details });\n          } catch (error) {\n            signal?.removeEventListener(\"abort\", onAbort);\n            if (!aborted)\n              reject(error);\n          }\n        })();\n      });\n    },\n    renderCall(args, theme2, context) {\n      const text = context.lastComponent ?? new Text(\"\", 0, 0);\n      const classification = !context.expanded ? getCompactReadClassification(args, context.cwd) : void 0;\n      text.setText(classification ? formatCompactReadCall(classification, args, theme2) : formatReadCall(args, theme2, context.cwd));\n      return text;\n    },\n    renderResult(result, options2, theme2, context) {\n      const text = context.lastComponent ?? new Text(\"\", 0, 0);\n      text.setText(formatReadResult(context.args, result, options2, theme2, context.showImages, context.cwd, context.isError));\n      return text;\n    }\n  };\n}\nfunction createReadTool2(cwd, options) {\n  return wrapToolDefinition(createReadToolDefinition(cwd, options));\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/write.js\nimport { mkdir as fsMkdir, writeFile as fsWriteFile2 } from \"fs/promises\";\nimport { dirname as dirname14 } from \"path\";\nimport { Type as Type16 } from \"typebox\";\nvar writeSchema2 = Type16.Object({\n  path: Type16.String({ description: \"Path to the file to write (relative or absolute)\" }),\n  content: Type16.String({ description: \"Content to write to the file\" })\n});\nvar writeToolSystemPromptContribution = {\n  snippet: \"Create or overwrite files\",\n  guidelines: [\"Use write only for new files or complete rewrites.\"]\n};\nvar defaultWriteOperations = {\n  writeFile: (path12, content) => fsWriteFile2(path12, content, \"utf-8\"),\n  mkdir: (dir) => fsMkdir(dir, { recursive: true }).then(() => {\n  })\n};\nvar WriteCallRenderComponent = class extends Text {\n  cache;\n  constructor() {\n    super(\"\", 0, 0);\n  }\n};\nvar WRITE_PARTIAL_FULL_HIGHLIGHT_LINES = 50;\nfunction highlightSingleLine(line, lang) {\n  const highlighted = highlightCode(line, lang);\n  return highlighted[0] ?? \"\";\n}\nfunction refreshWriteHighlightPrefix(cache) {\n  const prefixCount = Math.min(WRITE_PARTIAL_FULL_HIGHLIGHT_LINES, cache.normalizedLines.length);\n  if (prefixCount === 0)\n    return;\n  const prefixSource = cache.normalizedLines.slice(0, prefixCount).join(\"\\n\");\n  const prefixHighlighted = highlightCode(prefixSource, cache.lang);\n  for (let i = 0; i < prefixCount; i++) {\n    cache.highlightedLines[i] = prefixHighlighted[i] ?? highlightSingleLine(cache.normalizedLines[i] ?? \"\", cache.lang);\n  }\n}\nfunction rebuildWriteHighlightCacheFull(rawPath, fileContent) {\n  const lang = rawPath ? getLanguageFromPath(rawPath) : void 0;\n  if (!lang)\n    return void 0;\n  const displayContent = normalizeDisplayText(fileContent);\n  const normalized = replaceTabs(displayContent);\n  return {\n    rawPath,\n    lang,\n    rawContent: fileContent,\n    normalizedLines: normalized.split(\"\\n\"),\n    highlightedLines: highlightCode(normalized, lang)\n  };\n}\nfunction updateWriteHighlightCacheIncremental(cache, rawPath, fileContent) {\n  const lang = rawPath ? getLanguageFromPath(rawPath) : void 0;\n  if (!lang)\n    return void 0;\n  if (!cache)\n    return rebuildWriteHighlightCacheFull(rawPath, fileContent);\n  if (cache.lang !== lang || cache.rawPath !== rawPath)\n    return rebuildWriteHighlightCacheFull(rawPath, fileContent);\n  if (!fileContent.startsWith(cache.rawContent))\n    return rebuildWriteHighlightCacheFull(rawPath, fileContent);\n  if (fileContent.length === cache.rawContent.length)\n    return cache;\n  const deltaRaw = fileContent.slice(cache.rawContent.length);\n  const deltaDisplay = normalizeDisplayText(deltaRaw);\n  const deltaNormalized = replaceTabs(deltaDisplay);\n  cache.rawContent = fileContent;\n  if (cache.normalizedLines.length === 0) {\n    cache.normalizedLines.push(\"\");\n    cache.highlightedLines.push(\"\");\n  }\n  const segments = deltaNormalized.split(\"\\n\");\n  const lastIndex = cache.normalizedLines.length - 1;\n  cache.normalizedLines[lastIndex] += segments[0];\n  cache.highlightedLines[lastIndex] = highlightSingleLine(cache.normalizedLines[lastIndex], cache.lang);\n  for (let i = 1; i < segments.length; i++) {\n    cache.normalizedLines.push(segments[i]);\n    cache.highlightedLines.push(highlightSingleLine(segments[i], cache.lang));\n  }\n  refreshWriteHighlightPrefix(cache);\n  return cache;\n}\nfunction trimTrailingEmptyLines2(lines) {\n  let end = lines.length;\n  while (end > 0 && lines[end - 1] === \"\") {\n    end--;\n  }\n  return lines.slice(0, end);\n}\nfunction formatWriteCall(args, options, theme2, cache, cwd) {\n  const rawPath = str(args?.file_path ?? args?.path);\n  const fileContent = str(args?.content);\n  const pathDisplay = renderToolPath(rawPath, theme2, cwd);\n  let text = `${theme2.fg(\"toolTitle\", theme2.bold(\"write\"))} ${pathDisplay}`;\n  if (fileContent === null) {\n    text += `\n\n${theme2.fg(\"error\", \"[invalid content arg - expected string]\")}`;\n  } else if (fileContent) {\n    const lang = rawPath ? getLanguageFromPath(rawPath) : void 0;\n    const renderedLines = lang ? cache?.highlightedLines ?? highlightCode(replaceTabs(normalizeDisplayText(fileContent)), lang) : normalizeDisplayText(fileContent).split(\"\\n\");\n    const lines = trimTrailingEmptyLines2(renderedLines);\n    const totalLines = lines.length;\n    const maxLines = options.expanded ? lines.length : 10;\n    const displayLines = lines.slice(0, maxLines);\n    const remaining = lines.length - maxLines;\n    text += `\n\n${displayLines.map((line) => lang ? line : theme2.fg(\"toolOutput\", replaceTabs(line))).join(\"\\n\")}`;\n    if (remaining > 0) {\n      text += `${theme2.fg(\"muted\", `\n... (${remaining} more lines, ${totalLines} total,`)} ${keyHint(\"app.tools.expand\", \"to expand\")}${theme2.fg(\"muted\", \")\")}`;\n    }\n  }\n  return text;\n}\nfunction formatWriteResult(result, theme2) {\n  if (!result.isError) {\n    return void 0;\n  }\n  const output = result.content.filter((c) => c.type === \"text\").map((c) => c.text || \"\").join(\"\\n\");\n  if (!output) {\n    return void 0;\n  }\n  return `\n${theme2.fg(\"error\", output)}`;\n}\nfunction createWriteToolDefinition(cwd, options) {\n  const ops = options?.operations ?? defaultWriteOperations;\n  return {\n    name: \"write\",\n    label: \"write\",\n    description: \"Write content to a file. Creates the file if it doesn't exist, overwrites if it does. Automatically creates parent directories.\",\n    promptSnippet: writeToolSystemPromptContribution.snippet,\n    promptGuidelines: [...writeToolSystemPromptContribution.guidelines],\n    parameters: writeSchema2,\n    constrainedSampling: getExperimentalToolSampling(),\n    async execute(_toolCallId, { path: path12, content }, signal, _onUpdate, _ctx) {\n      const absolutePath = resolveToCwd(path12, cwd);\n      const dir = dirname14(absolutePath);\n      return withFileMutationQueue2(absolutePath, async () => {\n        const throwIfAborted2 = () => {\n          if (signal?.aborted)\n            throw new Error(\"Operation aborted\");\n        };\n        throwIfAborted2();\n        await ops.mkdir(dir);\n        throwIfAborted2();\n        await ops.writeFile(absolutePath, content);\n        throwIfAborted2();\n        return {\n          content: [{ type: \"text\", text: `Successfully wrote ${content.length} bytes to ${path12}` }],\n          details: void 0\n        };\n      });\n    },\n    renderCall(args, theme2, context) {\n      const renderArgs = args;\n      const rawPath = str(renderArgs?.file_path ?? renderArgs?.path);\n      const fileContent = str(renderArgs?.content);\n      const component = context.lastComponent ?? new WriteCallRenderComponent();\n      if (fileContent !== null) {\n        component.cache = context.argsComplete ? rebuildWriteHighlightCacheFull(rawPath, fileContent) : updateWriteHighlightCacheIncremental(component.cache, rawPath, fileContent);\n      } else {\n        component.cache = void 0;\n      }\n      component.setText(formatWriteCall(renderArgs, { expanded: context.expanded, isPartial: context.isPartial }, theme2, component.cache, context.cwd));\n      return component;\n    },\n    renderResult(result, _options, theme2, context) {\n      const output = formatWriteResult({ ...result, isError: context.isError }, theme2);\n      if (!output) {\n        const component = context.lastComponent ?? new Container();\n        component.clear();\n        return component;\n      }\n      const text = context.lastComponent ?? new Text(\"\", 0, 0);\n      text.setText(output);\n      return text;\n    }\n  };\n}\nfunction createWriteTool2(cwd, options) {\n  return wrapToolDefinition(createWriteToolDefinition(cwd, options));\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/index.js\nfunction createAllToolDefinitions(cwd, options) {\n  return {\n    read: createReadToolDefinition(cwd, options?.read),\n    bash: createBashToolDefinition(cwd, options?.bash),\n    edit: createEditToolDefinition(cwd, options?.edit),\n    write: createWriteToolDefinition(cwd, options?.write),\n    grep: createGrepToolDefinition(cwd, options?.grep),\n    find: createFindToolDefinition(cwd, options?.find),\n    ls: createLsToolDefinition(cwd, options?.ls)\n  };\n}\nfunction createCodingTools(cwd, options) {\n  return [\n    createReadTool2(cwd, options?.read),\n    createBashTool2(cwd, options?.bash),\n    createEditTool2(cwd, options?.edit),\n    createWriteTool2(cwd, options?.write)\n  ];\n}\nfunction createReadOnlyTools(cwd, options) {\n  return [\n    createReadTool2(cwd, options?.read),\n    createGrepTool(cwd, options?.grep),\n    createFindTool(cwd, options?.find),\n    createLsTool(cwd, options?.ls)\n  ];\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/core/usage-totals.js\nfunction createUsageTotals() {\n  return {\n    input: 0,\n    output: 0,\n    cacheRead: 0,\n    cacheWrite: 0,\n    cost: 0\n  };\n}\nfunction addUsageToTotals(totals, usage) {\n  totals.input += usage.input;\n  totals.output += usage.output;\n  totals.cacheRead += usage.cacheRead;\n  totals.cacheWrite += usage.cacheWrite;\n  totals.cost += usage.cost.total;\n}\nfunction getUsageCostBreakdown(entries) {\n  const totalsByKey = /* @__PURE__ */ new Map();\n  for (const entry of entries) {\n    let key;\n    let usage;\n    if (entry.type === \"message\" && entry.message.role === \"assistant\") {\n      key = `${entry.message.provider}/${entry.message.responseModel ?? entry.message.model}`;\n      usage = entry.message.usage;\n    } else if (entry.type === \"message\" && entry.message.role === \"toolResult\" && entry.message.usage) {\n      key = \"Tools/summaries\";\n      usage = entry.message.usage;\n    } else if ((entry.type === \"branch_summary\" || entry.type === \"compaction\") && entry.usage) {\n      key = \"Tools/summaries\";\n      usage = entry.usage;\n    }\n    if (!key || !usage)\n      continue;\n    let totals = totalsByKey.get(key);\n    if (!totals) {\n      totals = createUsageTotals();\n      totalsByKey.set(key, totals);\n    }\n    addUsageToTotals(totals, usage);\n  }\n  return Array.from(totalsByKey, ([key, totals]) => ({\n    key,\n    cost: totals.cost,\n    tokens: totals.input + totals.output + totals.cacheRead + totals.cacheWrite\n  })).filter((entry) => entry.cost > 0 || entry.tokens > 0).sort((a, b) => b.cost - a.cost);\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session.js\nfunction parseSkillBlock(text) {\n  const match = text.match(/^<skill name=\"([^\"]+)\" location=\"([^\"]+)\">\\n([\\s\\S]*?)\\n<\\/skill>(?:\\n\\n([\\s\\S]+))?$/);\n  if (!match)\n    return null;\n  return {\n    name: match[1],\n    location: match[2],\n    content: match[3],\n    userMessage: match[4]?.trim() || void 0\n  };\n}\nfunction withoutDeletedHeaders(headers) {\n  return headers ? Object.fromEntries(Object.entries(headers).filter((entry) => entry[1] !== null)) : void 0;\n}\nfunction estimateMessagesTokens(messages) {\n  let tokens = 0;\n  for (const message of messages) {\n    tokens += estimateTokens3(message);\n  }\n  return tokens;\n}\nvar THINKING_LEVELS = [\"off\", \"minimal\", \"low\", \"medium\", \"high\"];\nvar AgentSession = class {\n  agent;\n  sessionManager;\n  settingsManager;\n  _scopedModels;\n  // Event subscription state\n  _unsubscribeAgent;\n  _eventListeners = [];\n  _isAgentRunActive = false;\n  _idleWaitPromise;\n  _resolveIdleWait;\n  /** Tracks pending steering messages for UI display. Removed when delivered. */\n  _steeringMessages = [];\n  /** Tracks pending follow-up messages for UI display. Removed when delivered. */\n  _followUpMessages = [];\n  /** Messages queued to be included with the next user prompt as context (\"asides\"). */\n  _pendingNextTurnMessages = [];\n  // Compaction state\n  _compactionAbortController = void 0;\n  _autoCompactionAbortController = void 0;\n  _overflowRecoveryAttempted = false;\n  // Branch summarization state\n  _branchSummaryAbortController = void 0;\n  // Retry state\n  _retryAbortController = void 0;\n  _retryAttempt = 0;\n  // Bash execution state\n  _bashAbortControllers = /* @__PURE__ */ new Set();\n  _pendingBashMessages = [];\n  // Extension system\n  _extensionRunner;\n  _turnIndex = 0;\n  _resourceLoader;\n  _customTools;\n  _baseToolDefinitions = /* @__PURE__ */ new Map();\n  _cwd;\n  _extensionRunnerRef;\n  _initialActiveToolNames;\n  _allowedToolNames;\n  _excludedToolNames;\n  _baseToolsOverride;\n  _sessionStartEvent;\n  _extensionUIContext;\n  _extensionMode = \"print\";\n  _extensionCommandContextActions;\n  _extensionAbortHandler;\n  _extensionShutdownHandler;\n  _extensionErrorListener;\n  _extensionErrorUnsubscriber;\n  _modelRuntime;\n  // Tool registry for extension getTools/setTools\n  _toolRegistry = /* @__PURE__ */ new Map();\n  _toolDefinitions = /* @__PURE__ */ new Map();\n  _toolPromptSnippets = /* @__PURE__ */ new Map();\n  _toolPromptGuidelines = /* @__PURE__ */ new Map();\n  // Base system prompt (without extension appends) - used to apply fresh appends each turn\n  _baseSystemPrompt = \"\";\n  _baseSystemPromptOptions;\n  _systemPromptOverride;\n  constructor(config) {\n    this.agent = config.agent;\n    this.sessionManager = config.sessionManager;\n    this.settingsManager = config.settingsManager;\n    this._scopedModels = config.scopedModels ?? [];\n    this._resourceLoader = config.resourceLoader;\n    this._customTools = config.customTools ?? [];\n    this._cwd = config.cwd;\n    this._modelRuntime = config.modelRuntime;\n    this._extensionRunnerRef = config.extensionRunnerRef;\n    this._initialActiveToolNames = config.initialActiveToolNames;\n    this._allowedToolNames = config.allowedToolNames ? new Set(config.allowedToolNames) : void 0;\n    this._excludedToolNames = config.excludedToolNames ? new Set(config.excludedToolNames) : void 0;\n    this._baseToolsOverride = config.baseToolsOverride;\n    this._sessionStartEvent = config.sessionStartEvent ?? { type: \"session_start\", reason: \"startup\" };\n    this._unsubscribeAgent = this.agent.subscribe(this._handleAgentEvent);\n    this._installAgentToolHooks();\n    this._installAgentNextTurnRefresh();\n    this._buildRuntime({\n      activeToolNames: this._initialActiveToolNames,\n      includeAllExtensionTools: true\n    });\n  }\n  get modelRuntime() {\n    return this._modelRuntime;\n  }\n  async _getRequiredRequestAuth(model) {\n    let result;\n    try {\n      result = await this._modelRuntime.getAuth(model);\n    } catch (error) {\n      const cause = error instanceof Error ? error.cause : void 0;\n      if (cause instanceof Error && cause.message === \"authHeader requires a resolved API key\") {\n        throw new Error(formatNoApiKeyFoundMessage(model.provider));\n      }\n      throw error;\n    }\n    if (result && (result.auth.apiKey || result.auth.headers)) {\n      const requestModel = result.auth.baseUrl ? { ...model, baseUrl: result.auth.baseUrl } : model;\n      return {\n        model: requestModel,\n        apiKey: result.auth.apiKey,\n        headers: withoutDeletedHeaders(result.auth.headers),\n        env: result.env\n      };\n    }\n    const isOAuth = this._modelRuntime.isUsingOAuth(model.provider);\n    if (isOAuth) {\n      throw new Error(`Authentication failed for \"${model.provider}\". Credentials may have expired or network is unavailable. Run '/login ${model.provider}' to re-authenticate.`);\n    }\n    throw new Error(formatNoApiKeyFoundMessage(model.provider));\n  }\n  async _getSummarizationRequestAuth(model) {\n    if (this.agent.streamFunction === streamSimple10) {\n      return this._getRequiredRequestAuth(model);\n    }\n    try {\n      const result = await this._modelRuntime.getAuth(model);\n      if (!result)\n        return { model };\n      const requestModel = result.auth.baseUrl ? { ...model, baseUrl: result.auth.baseUrl } : model;\n      return {\n        model: requestModel,\n        apiKey: result.auth.apiKey,\n        headers: withoutDeletedHeaders(result.auth.headers),\n        env: result.env\n      };\n    } catch {\n      return { model };\n    }\n  }\n  /**\n   * Install tool hooks once on the Agent instance.\n   *\n   * The callbacks read `this._extensionRunner` at execution time, so extension reload swaps in the\n   * new runner without reinstalling hooks. Extension-specific tool wrappers are still used to adapt\n   * registered tool execution to the extension context. Tool call and tool result interception now\n   * happens here instead of in wrappers.\n   */\n  _installAgentToolHooks() {\n    this.agent.beforeToolCall = async ({ toolCall, args }) => {\n      const runner = this._extensionRunner;\n      if (!runner.hasHandlers(\"tool_call\")) {\n        return void 0;\n      }\n      try {\n        return await runner.emitToolCall({\n          type: \"tool_call\",\n          toolName: toolCall.name,\n          toolCallId: toolCall.id,\n          input: args\n        });\n      } catch (err2) {\n        if (err2 instanceof Error) {\n          throw err2;\n        }\n        throw new Error(`Extension failed, blocking execution: ${String(err2)}`);\n      }\n    };\n    this.agent.afterToolCall = async ({ toolCall, args, result, isError }) => {\n      const runner = this._extensionRunner;\n      const hookResult = runner.hasHandlers(\"tool_result\") ? await runner.emitToolResult({\n        type: \"tool_result\",\n        toolName: toolCall.name,\n        toolCallId: toolCall.id,\n        input: args,\n        content: result.content,\n        details: result.details,\n        isError,\n        usage: result.usage\n      }) : void 0;\n      const content = hookResult?.content ?? result.content ?? [];\n      const normalizedContent = await normalizeToolResultImages(content, {\n        autoResizeImages: this.settingsManager.getImageAutoResize()\n      });\n      if (!hookResult && normalizedContent === content) {\n        return void 0;\n      }\n      return {\n        content: normalizedContent,\n        details: hookResult?.details,\n        isError: hookResult?.isError ?? isError,\n        usage: hookResult?.usage\n      };\n    };\n  }\n  _installAgentNextTurnRefresh() {\n    const previousPrepareNextTurnWithContext = this.agent.prepareNextTurnWithContext ?? (this.agent.prepareNextTurn ? async (_turn, signal) => await this.agent.prepareNextTurn?.(signal) : void 0);\n    this.agent.prepareNextTurnWithContext = async (turn, signal) => {\n      const previousSnapshot = await previousPrepareNextTurnWithContext?.(turn, signal);\n      const previousContext = previousSnapshot?.context ?? turn.context;\n      return {\n        ...previousSnapshot,\n        context: {\n          ...previousContext,\n          systemPrompt: this._systemPromptOverride ?? this._baseSystemPrompt,\n          tools: this.agent.state.tools.slice()\n        },\n        model: this.agent.state.model,\n        thinkingLevel: this.agent.state.thinkingLevel\n      };\n    };\n  }\n  // =========================================================================\n  // Event Subscription\n  // =========================================================================\n  /** Emit an event to all listeners */\n  _emit(event) {\n    for (const l of this._eventListeners) {\n      l(event);\n    }\n  }\n  _emitQueueUpdate() {\n    this._emit({\n      type: \"queue_update\",\n      steering: [...this._steeringMessages],\n      followUp: [...this._followUpMessages]\n    });\n  }\n  _getIdleWaitPromise() {\n    if (!this._idleWaitPromise) {\n      this._idleWaitPromise = new Promise((resolve15) => {\n        this._resolveIdleWait = resolve15;\n      });\n    }\n    return this._idleWaitPromise;\n  }\n  _resolveIdleWaitIfIdle() {\n    if (this._isAgentRunActive || !this._resolveIdleWait) {\n      return;\n    }\n    const resolve15 = this._resolveIdleWait;\n    this._idleWaitPromise = void 0;\n    this._resolveIdleWait = void 0;\n    resolve15();\n  }\n  async _emitAgentSettled() {\n    this._isAgentRunActive = false;\n    try {\n      await this._extensionRunner.emit({ type: \"agent_settled\" });\n      this._emit({ type: \"agent_settled\" });\n    } finally {\n      this._resolveIdleWaitIfIdle();\n    }\n  }\n  // Track last assistant message for auto-compaction check\n  _lastAssistantMessage = void 0;\n  /** Internal handler for agent events - shared by subscribe and reconnect */\n  _handleAgentEvent = async (event) => {\n    if (event.type === \"message_start\" && event.message.role === \"user\") {\n      this._overflowRecoveryAttempted = false;\n      const messageText = contentText(event.message.content, \"\");\n      if (messageText) {\n        const steeringIndex = this._steeringMessages.indexOf(messageText);\n        if (steeringIndex !== -1) {\n          this._steeringMessages.splice(steeringIndex, 1);\n          this._emitQueueUpdate();\n        } else {\n          const followUpIndex = this._followUpMessages.indexOf(messageText);\n          if (followUpIndex !== -1) {\n            this._followUpMessages.splice(followUpIndex, 1);\n            this._emitQueueUpdate();\n          }\n        }\n      }\n    }\n    await this._emitExtensionEvent(event);\n    this._emit(event.type === \"agent_end\" ? { ...event, willRetry: this._willRetryAfterAgentEnd(event) } : event);\n    if (event.type === \"message_end\") {\n      if (event.message.role === \"custom\") {\n        this.sessionManager.appendCustomMessageEntry(event.message.customType, event.message.content, event.message.display, event.message.details);\n      } else if (event.message.role === \"user\" || event.message.role === \"assistant\" || event.message.role === \"toolResult\") {\n        this.sessionManager.appendMessage(event.message);\n      }\n      if (event.message.role === \"assistant\") {\n        this._lastAssistantMessage = event.message;\n        const assistantMsg = event.message;\n        if (assistantMsg.stopReason !== \"error\" && assistantMsg.stopReason !== \"length\") {\n          this._overflowRecoveryAttempted = false;\n        }\n        if (assistantMsg.stopReason !== \"error\" && this._retryAttempt > 0) {\n          this._emit({\n            type: \"auto_retry_end\",\n            success: true,\n            attempt: this._retryAttempt\n          });\n          this._retryAttempt = 0;\n        }\n      }\n    }\n  };\n  _willRetryAfterAgentEnd(event) {\n    const settings = this.settingsManager.getRetrySettings();\n    if (!settings.enabled || this._retryAttempt >= settings.maxRetries) {\n      return false;\n    }\n    for (let i = event.messages.length - 1; i >= 0; i--) {\n      const message = event.messages[i];\n      if (message.role === \"assistant\") {\n        return this._isRetryableError(message);\n      }\n    }\n    return false;\n  }\n  /** Find the last assistant message in agent state (including aborted ones) */\n  _findLastAssistantMessage() {\n    const messages = this.agent.state.messages;\n    for (let i = messages.length - 1; i >= 0; i--) {\n      const msg = messages[i];\n      if (msg.role === \"assistant\") {\n        return msg;\n      }\n    }\n    return void 0;\n  }\n  _replaceMessageInPlace(target, replacement) {\n    if (target === replacement) {\n      return;\n    }\n    const targetRecord = target;\n    for (const key of Object.keys(targetRecord)) {\n      delete targetRecord[key];\n    }\n    Object.assign(targetRecord, replacement);\n  }\n  /** Emit extension events based on agent events */\n  async _emitExtensionEvent(event) {\n    if (event.type === \"agent_start\") {\n      this._turnIndex = 0;\n      await this._extensionRunner.emit({ type: \"agent_start\" });\n    } else if (event.type === \"agent_end\") {\n      await this._extensionRunner.emit({ type: \"agent_end\", messages: event.messages });\n    } else if (event.type === \"turn_start\") {\n      const extensionEvent = {\n        type: \"turn_start\",\n        turnIndex: this._turnIndex,\n        timestamp: Date.now()\n      };\n      await this._extensionRunner.emit(extensionEvent);\n    } else if (event.type === \"turn_end\") {\n      const extensionEvent = {\n        type: \"turn_end\",\n        turnIndex: this._turnIndex,\n        message: event.message,\n        toolResults: event.toolResults\n      };\n      await this._extensionRunner.emit(extensionEvent);\n      this._turnIndex++;\n    } else if (event.type === \"message_start\") {\n      const extensionEvent = {\n        type: \"message_start\",\n        message: event.message\n      };\n      await this._extensionRunner.emit(extensionEvent);\n    } else if (event.type === \"message_update\") {\n      const extensionEvent = {\n        type: \"message_update\",\n        message: event.message,\n        assistantMessageEvent: event.assistantMessageEvent\n      };\n      await this._extensionRunner.emit(extensionEvent);\n    } else if (event.type === \"message_end\") {\n      const extensionEvent = {\n        type: \"message_end\",\n        message: event.message\n      };\n      const replacement = await this._extensionRunner.emitMessageEnd(extensionEvent);\n      if (replacement) {\n        const normalized = (replacement.role === \"user\" || replacement.role === \"assistant\" || replacement.role === \"toolResult\" || replacement.role === \"custom\") && replacement.content == null ? { ...replacement, content: [] } : replacement;\n        this._replaceMessageInPlace(event.message, normalized);\n      }\n    } else if (event.type === \"tool_execution_start\") {\n      const extensionEvent = {\n        type: \"tool_execution_start\",\n        toolCallId: event.toolCallId,\n        toolName: event.toolName,\n        args: event.args\n      };\n      await this._extensionRunner.emit(extensionEvent);\n    } else if (event.type === \"tool_execution_update\") {\n      const extensionEvent = {\n        type: \"tool_execution_update\",\n        toolCallId: event.toolCallId,\n        toolName: event.toolName,\n        args: event.args,\n        partialResult: event.partialResult\n      };\n      await this._extensionRunner.emit(extensionEvent);\n    } else if (event.type === \"tool_execution_end\") {\n      const extensionEvent = {\n        type: \"tool_execution_end\",\n        toolCallId: event.toolCallId,\n        toolName: event.toolName,\n        result: event.result,\n        isError: event.isError\n      };\n      await this._extensionRunner.emit(extensionEvent);\n    }\n  }\n  /**\n   * Subscribe to agent events.\n   * Session persistence is handled internally (saves messages on message_end).\n   * Multiple listeners can be added. Returns unsubscribe function for this listener.\n   */\n  subscribe(listener) {\n    this._eventListeners.push(listener);\n    return () => {\n      const index = this._eventListeners.indexOf(listener);\n      if (index !== -1) {\n        this._eventListeners.splice(index, 1);\n      }\n    };\n  }\n  /** Disconnect from agent events during disposal. */\n  _disconnectFromAgent() {\n    if (this._unsubscribeAgent) {\n      this._unsubscribeAgent();\n      this._unsubscribeAgent = void 0;\n    }\n  }\n  /**\n   * Remove all listeners and disconnect from agent.\n   * Call this when completely done with the session.\n   */\n  dispose() {\n    try {\n      this.abortRetry();\n      this.abortCompaction();\n      this.abortBranchSummary();\n      this.abortBash();\n      this.agent.abort();\n    } catch {\n    }\n    this._extensionRunner.invalidate(\"This extension ctx is stale after session replacement or reload. Do not use a captured pi or command ctx after ctx.newSession(), ctx.fork(), ctx.switchSession(), or ctx.reload(). For newSession, fork, and switchSession, move post-replacement work into withSession and use the ctx passed to withSession. For reload, do not use the old ctx after await ctx.reload().\");\n    this._disconnectFromAgent();\n    this._eventListeners = [];\n    cleanupSessionResources(this.sessionId);\n  }\n  // =========================================================================\n  // Read-only State Access\n  // =========================================================================\n  /** Full agent state */\n  get state() {\n    return this.agent.state;\n  }\n  /** Current model (may be undefined if not yet selected) */\n  get model() {\n    return this.agent.state.model;\n  }\n  /** Current thinking level */\n  get thinkingLevel() {\n    return this.agent.state.thinkingLevel;\n  }\n  /** Whether the session is currently processing an agent run or post-run continuation. */\n  get isStreaming() {\n    return this._isAgentRunActive;\n  }\n  /** Whether the session has no active agent run, retry, auto-compaction, or queued continuation. */\n  get isIdle() {\n    return !this._isAgentRunActive;\n  }\n  /** Current effective system prompt (includes any per-turn extension modifications) */\n  get systemPrompt() {\n    return this.agent.state.systemPrompt;\n  }\n  /** Current retry attempt (0 if not retrying) */\n  get retryAttempt() {\n    return this._retryAttempt;\n  }\n  /**\n   * Get the names of currently active tools.\n   * Returns the names of tools currently set on the agent.\n   */\n  getActiveToolNames() {\n    return this.agent.state.tools.map((t) => t.name);\n  }\n  /**\n   * Get all configured tools with name, description, parameter schema, prompt guidelines, and source metadata.\n   */\n  getAllTools() {\n    return Array.from(this._toolDefinitions.values()).map(({ definition, sourceInfo }) => ({\n      name: definition.name,\n      description: definition.description,\n      parameters: definition.parameters,\n      promptGuidelines: definition.promptGuidelines,\n      sourceInfo\n    }));\n  }\n  getToolDefinition(name) {\n    return this._toolDefinitions.get(name)?.definition;\n  }\n  /**\n   * Set active tools by name.\n   * Only tools in the registry can be enabled. Unknown tool names are ignored.\n   * Also rebuilds the system prompt to reflect the new tool set.\n   * Changes take effect on the next agent turn.\n   */\n  setActiveToolsByName(toolNames) {\n    const tools = [];\n    const validToolNames = [];\n    for (const name of toolNames) {\n      const tool = this._toolRegistry.get(name);\n      if (tool) {\n        tools.push(tool);\n        validToolNames.push(name);\n      }\n    }\n    this.agent.state.tools = tools;\n    this._baseSystemPrompt = this._rebuildSystemPrompt(validToolNames);\n    this.agent.state.systemPrompt = this._systemPromptOverride ?? this._baseSystemPrompt;\n  }\n  /** Whether compaction or branch summarization is currently running */\n  get isCompacting() {\n    return this._autoCompactionAbortController !== void 0 || this._compactionAbortController !== void 0 || this._branchSummaryAbortController !== void 0;\n  }\n  /** All messages including custom types like BashExecutionMessage */\n  get messages() {\n    return this.agent.state.messages;\n  }\n  /** Current steering mode */\n  get steeringMode() {\n    return this.agent.steeringMode;\n  }\n  /** Current follow-up mode */\n  get followUpMode() {\n    return this.agent.followUpMode;\n  }\n  /** Current session file path, or undefined if sessions are disabled */\n  get sessionFile() {\n    return this.sessionManager.getSessionFile();\n  }\n  /** Current session ID */\n  get sessionId() {\n    return this.sessionManager.getSessionId();\n  }\n  /** Current session display name, if set */\n  get sessionName() {\n    return this.sessionManager.getSessionName();\n  }\n  /** Scoped models for cycling (from --models flag) */\n  get scopedModels() {\n    return this._scopedModels;\n  }\n  /** Update scoped models for cycling */\n  setScopedModels(scopedModels) {\n    this._scopedModels = scopedModels;\n  }\n  /** File-based prompt templates */\n  get promptTemplates() {\n    return this._resourceLoader.getPrompts().prompts;\n  }\n  _normalizePromptSnippet(text) {\n    if (!text)\n      return void 0;\n    const oneLine = text.replace(/[\\r\\n]+/g, \" \").replace(/\\s+/g, \" \").trim();\n    return oneLine.length > 0 ? oneLine : void 0;\n  }\n  _normalizePromptGuidelines(guidelines) {\n    if (!guidelines || guidelines.length === 0) {\n      return [];\n    }\n    const unique = /* @__PURE__ */ new Set();\n    for (const guideline of guidelines) {\n      const normalized = guideline.trim();\n      if (normalized.length > 0) {\n        unique.add(normalized);\n      }\n    }\n    return Array.from(unique);\n  }\n  _rebuildSystemPrompt(toolNames) {\n    const validToolNames = toolNames.filter((name) => this._toolRegistry.has(name));\n    const toolSnippets = {};\n    const promptGuidelines = [];\n    for (const name of validToolNames) {\n      const snippet = this._toolPromptSnippets.get(name);\n      if (snippet) {\n        toolSnippets[name] = snippet;\n      }\n      const toolGuidelines = this._toolPromptGuidelines.get(name);\n      if (toolGuidelines) {\n        promptGuidelines.push(...toolGuidelines);\n      }\n    }\n    const loaderSystemPrompt = this._resourceLoader.getSystemPrompt();\n    const loaderAppendSystemPrompt = this._resourceLoader.getAppendSystemPrompt();\n    const appendSystemPrompt = loaderAppendSystemPrompt.length > 0 ? loaderAppendSystemPrompt.join(\"\\n\\n\") : void 0;\n    const loadedSkills = this._resourceLoader.getSkills().skills;\n    const loadedContextFiles = this._resourceLoader.getAgentsFiles().agentsFiles;\n    this._baseSystemPromptOptions = {\n      cwd: this._cwd,\n      skills: loadedSkills,\n      contextFiles: loadedContextFiles,\n      customPrompt: loaderSystemPrompt,\n      appendSystemPrompt,\n      selectedTools: validToolNames,\n      toolSnippets,\n      promptGuidelines\n    };\n    return buildSystemPrompt(this._baseSystemPromptOptions);\n  }\n  // =========================================================================\n  // Prompting\n  // =========================================================================\n  async _runAgentPrompt(messages) {\n    this._isAgentRunActive = true;\n    try {\n      await this.agent.prompt(messages);\n      while (await this._handlePostAgentRun()) {\n        await this.agent.continue();\n      }\n    } finally {\n      this._systemPromptOverride = void 0;\n      this._flushPendingBashMessages();\n      await this._emitAgentSettled();\n    }\n  }\n  async _handlePostAgentRun() {\n    const msg = this._lastAssistantMessage;\n    this._lastAssistantMessage = void 0;\n    if (!msg) {\n      return false;\n    }\n    if (this._isRetryableError(msg) && await this._prepareRetry(msg)) {\n      return true;\n    }\n    if (msg.stopReason === \"error\" && this._retryAttempt > 0) {\n      this._emit({\n        type: \"auto_retry_end\",\n        success: false,\n        attempt: this._retryAttempt,\n        finalError: msg.errorMessage\n      });\n      this._retryAttempt = 0;\n    }\n    if (await this._checkCompaction(msg)) {\n      return true;\n    }\n    return this.agent.hasQueuedMessages();\n  }\n  /**\n   * Send a prompt to the agent.\n   * - Handles extension commands (registered via pi.registerCommand) immediately, even during streaming\n   * - Expands file-based prompt templates by default\n   * - During streaming, queues via steer() or followUp() based on streamingBehavior option\n   * - Validates model and API key before sending (when not streaming)\n   * @throws Error if streaming and no streamingBehavior specified\n   * @throws Error if no model selected or no API key available (when not streaming)\n   */\n  async prompt(text, options) {\n    const expandPromptTemplates = options?.expandPromptTemplates ?? true;\n    const preflightResult = options?.preflightResult;\n    let messages;\n    try {\n      if (expandPromptTemplates && text.startsWith(\"/\")) {\n        const handled = await this._tryExecuteExtensionCommand(text);\n        if (handled) {\n          preflightResult?.(true);\n          return;\n        }\n      }\n      if (this._compactionAbortController !== void 0) {\n        throw new Error(\"Cannot submit a prompt while compaction is in progress. Wait for compaction to finish and retry.\");\n      }\n      let currentText = text;\n      let currentImages = options?.images;\n      if (this._extensionRunner.hasHandlers(\"input\")) {\n        const inputResult = await this._extensionRunner.emitInput(currentText, currentImages, options?.source ?? \"interactive\", this.isStreaming ? options?.streamingBehavior : void 0);\n        if (inputResult.action === \"handled\") {\n          preflightResult?.(true);\n          return;\n        }\n        if (inputResult.action === \"transform\") {\n          currentText = inputResult.text;\n          currentImages = inputResult.images ?? currentImages;\n        }\n      }\n      let expandedText = currentText;\n      if (expandPromptTemplates) {\n        expandedText = this._expandSkillCommand(expandedText);\n        expandedText = expandPromptTemplate(expandedText, [...this.promptTemplates]);\n      }\n      if (this.isStreaming) {\n        if (!options?.streamingBehavior) {\n          throw new Error(\"Agent is already processing. Specify streamingBehavior ('steer' or 'followUp') to queue the message.\");\n        }\n        if (options.streamingBehavior === \"followUp\") {\n          await this._queueFollowUp(expandedText, currentImages);\n        } else {\n          await this._queueSteer(expandedText, currentImages);\n        }\n        preflightResult?.(true);\n        return;\n      }\n      this._flushPendingBashMessages();\n      if (!this.model) {\n        throw new Error(formatNoModelSelectedMessage());\n      }\n      const hasConfiguredAuth = this._modelRuntime.hasConfiguredAuth(this.model.provider) || await this._modelRuntime.checkAuth(this.model.provider) !== void 0;\n      if (!hasConfiguredAuth) {\n        const isOAuth = this._modelRuntime.isUsingOAuth(this.model.provider);\n        if (isOAuth) {\n          throw new Error(`Authentication failed for \"${this.model.provider}\". Credentials may have expired or network is unavailable. Run '/login ${this.model.provider}' to re-authenticate.`);\n        }\n        throw new Error(formatNoApiKeyFoundMessage(this.model.provider));\n      }\n      const lastAssistant = this._findLastAssistantMessage();\n      if (lastAssistant) {\n        await this._checkCompaction(lastAssistant, false);\n      }\n      messages = [];\n      const userContent = [{ type: \"text\", text: expandedText }];\n      if (currentImages) {\n        userContent.push(...currentImages);\n      }\n      messages.push({\n        role: \"user\",\n        content: userContent,\n        timestamp: Date.now()\n      });\n      for (const msg of this._pendingNextTurnMessages) {\n        messages.push(msg);\n      }\n      this._pendingNextTurnMessages = [];\n      const result = await this._extensionRunner.emitBeforeAgentStart(expandedText, currentImages, this._baseSystemPrompt, this._baseSystemPromptOptions);\n      if (result?.messages) {\n        for (const msg of result.messages) {\n          messages.push({\n            role: \"custom\",\n            customType: msg.customType,\n            // Untyped extensions can pass null/missing content; normalize at ingestion.\n            content: msg.content ?? [],\n            display: msg.display,\n            details: msg.details,\n            timestamp: Date.now()\n          });\n        }\n      }\n      if (result?.systemPrompt !== void 0) {\n        this._systemPromptOverride = result.systemPrompt;\n        this.agent.state.systemPrompt = result.systemPrompt;\n      } else {\n        this._systemPromptOverride = void 0;\n        this.agent.state.systemPrompt = this._baseSystemPrompt;\n      }\n    } catch (error) {\n      preflightResult?.(false);\n      throw error;\n    }\n    if (!messages) {\n      return;\n    }\n    preflightResult?.(true);\n    await this._runAgentPrompt(messages);\n  }\n  /**\n   * Try to execute an extension command. Returns true if command was found and executed.\n   */\n  async _tryExecuteExtensionCommand(text) {\n    const spaceIndex = text.indexOf(\" \");\n    const commandName = spaceIndex === -1 ? text.slice(1) : text.slice(1, spaceIndex);\n    const args = spaceIndex === -1 ? \"\" : text.slice(spaceIndex + 1);\n    const command = this._extensionRunner.getCommand(commandName);\n    if (!command)\n      return false;\n    const ctx = this._extensionRunner.createCommandContext();\n    try {\n      await command.handler(args, ctx);\n      return true;\n    } catch (err2) {\n      this._extensionRunner.emitError({\n        extensionPath: `command:${commandName}`,\n        event: \"command\",\n        error: err2 instanceof Error ? err2.message : String(err2)\n      });\n      return true;\n    }\n  }\n  /**\n   * Expand skill commands (/skill:name args) to their full content.\n   * Returns the expanded text, or the original text if not a skill command or skill not found.\n   * Emits errors via extension runner if file read fails.\n   */\n  _expandSkillCommand(text) {\n    if (!text.startsWith(\"/skill:\"))\n      return text;\n    const spaceIndex = text.indexOf(\" \");\n    const skillName = spaceIndex === -1 ? text.slice(7) : text.slice(7, spaceIndex);\n    const args = spaceIndex === -1 ? \"\" : text.slice(spaceIndex + 1).trim();\n    const skill = this.resourceLoader.getSkills().skills.find((s) => s.name === skillName);\n    if (!skill)\n      return text;\n    try {\n      const content = readFileSync11(skill.filePath, \"utf-8\");\n      const body = stripFrontmatter(content).trim();\n      const skillBlock = `<skill name=\"${skill.name}\" location=\"${skill.filePath}\">\nReferences are relative to ${skill.baseDir}.\n\n${body}\n</skill>`;\n      return args ? `${skillBlock}\n\n${args}` : skillBlock;\n    } catch (err2) {\n      this._extensionRunner.emitError({\n        extensionPath: skill.filePath,\n        event: \"skill_expansion\",\n        error: err2 instanceof Error ? err2.message : String(err2)\n      });\n      return text;\n    }\n  }\n  /**\n   * Queue a steering message while the agent is running.\n   * Delivered after the current assistant turn finishes executing its tool calls,\n   * before the next LLM call.\n   * Expands skill commands and prompt templates. Errors on extension commands.\n   * @param images Optional image attachments to include with the message\n   * @throws Error if text is an extension command\n   */\n  async steer(text, images) {\n    if (text.startsWith(\"/\")) {\n      this._throwIfExtensionCommand(text);\n    }\n    let expandedText = this._expandSkillCommand(text);\n    expandedText = expandPromptTemplate(expandedText, [...this.promptTemplates]);\n    await this._queueSteer(expandedText, images);\n  }\n  /**\n   * Queue a follow-up message to be processed after the agent finishes.\n   * Delivered only when agent has no more tool calls or steering messages.\n   * Expands skill commands and prompt templates. Errors on extension commands.\n   * @param images Optional image attachments to include with the message\n   * @throws Error if text is an extension command\n   */\n  async followUp(text, images) {\n    if (text.startsWith(\"/\")) {\n      this._throwIfExtensionCommand(text);\n    }\n    let expandedText = this._expandSkillCommand(text);\n    expandedText = expandPromptTemplate(expandedText, [...this.promptTemplates]);\n    await this._queueFollowUp(expandedText, images);\n  }\n  /**\n   * Internal: Queue a steering message (already expanded, no extension command check).\n   */\n  async _queueSteer(text, images) {\n    this._steeringMessages.push(text);\n    this._emitQueueUpdate();\n    const content = [{ type: \"text\", text }];\n    if (images) {\n      content.push(...images);\n    }\n    this.agent.steer({\n      role: \"user\",\n      content,\n      timestamp: Date.now()\n    });\n  }\n  /**\n   * Internal: Queue a follow-up message (already expanded, no extension command check).\n   */\n  async _queueFollowUp(text, images) {\n    this._followUpMessages.push(text);\n    this._emitQueueUpdate();\n    const content = [{ type: \"text\", text }];\n    if (images) {\n      content.push(...images);\n    }\n    this.agent.followUp({\n      role: \"user\",\n      content,\n      timestamp: Date.now()\n    });\n  }\n  /**\n   * Throw an error if the text is an extension command.\n   */\n  _throwIfExtensionCommand(text) {\n    const spaceIndex = text.indexOf(\" \");\n    const commandName = spaceIndex === -1 ? text.slice(1) : text.slice(1, spaceIndex);\n    const command = this._extensionRunner.getCommand(commandName);\n    if (command) {\n      throw new Error(`Extension command \"/${commandName}\" cannot be queued. Use prompt() or execute the command when not streaming.`);\n    }\n  }\n  /**\n   * Send a custom message to the session. Creates a CustomMessageEntry.\n   *\n   * Handles three cases:\n   * - Streaming: queues message, processed when loop pulls from queue\n   * - Not streaming + triggerTurn: appends to state/session, starts new turn\n   * - Not streaming + no trigger: appends to state/session, no turn\n   *\n   * @param message Custom message with customType, content, display, details\n   * @param options.triggerTurn If true and not streaming, triggers a new LLM turn\n   * @param options.deliverAs Delivery mode: \"steer\", \"followUp\", or \"nextTurn\"\n   */\n  async sendCustomMessage(message, options) {\n    const appMessage = {\n      role: \"custom\",\n      customType: message.customType,\n      // Untyped extensions can pass null/missing content; normalize at ingestion.\n      content: message.content ?? [],\n      display: message.display,\n      details: message.details,\n      timestamp: Date.now()\n    };\n    if (options?.deliverAs === \"nextTurn\") {\n      this._pendingNextTurnMessages.push(appMessage);\n    } else if (this.isStreaming && options?.triggerTurn !== false) {\n      if (options?.deliverAs === \"followUp\") {\n        this.agent.followUp(appMessage);\n      } else {\n        this.agent.steer(appMessage);\n      }\n    } else if (options?.triggerTurn) {\n      await this._runAgentPrompt(appMessage);\n    } else {\n      this.agent.state.messages.push(appMessage);\n      this.sessionManager.appendCustomMessageEntry(message.customType, message.content, message.display, message.details);\n      this._emit({ type: \"message_start\", message: appMessage });\n      this._emit({ type: \"message_end\", message: appMessage });\n    }\n  }\n  /**\n   * Send a user message to the agent. Always triggers a turn.\n   * When the agent is streaming, use deliverAs to specify how to queue the message.\n   *\n   * @param content User message content (string or content array)\n   * @param options.deliverAs Delivery mode when streaming: \"steer\" or \"followUp\"\n   * @param options.expandPromptTemplates Whether to dispatch extension commands and expand skill commands and prompt templates. Default: false.\n   */\n  async sendUserMessage(content, options) {\n    let text;\n    let images;\n    if (typeof content === \"string\") {\n      text = content;\n    } else {\n      const textParts = [];\n      images = [];\n      for (const part of content) {\n        if (part.type === \"text\") {\n          textParts.push(part.text);\n        } else {\n          images.push(part);\n        }\n      }\n      text = textParts.join(\"\\n\");\n      if (images.length === 0)\n        images = void 0;\n    }\n    await this.prompt(text, {\n      expandPromptTemplates: options?.expandPromptTemplates ?? false,\n      streamingBehavior: options?.deliverAs,\n      images,\n      source: \"extension\"\n    });\n  }\n  /**\n   * Clear all queued messages and return them.\n   * Useful for restoring to editor when user aborts.\n   * @returns Object with steering and followUp arrays\n   */\n  clearQueue() {\n    const steering = [...this._steeringMessages];\n    const followUp = [...this._followUpMessages];\n    this._steeringMessages = [];\n    this._followUpMessages = [];\n    this.agent.clearAllQueues();\n    this._emitQueueUpdate();\n    return { steering, followUp };\n  }\n  /** Number of pending messages (includes both steering and follow-up) */\n  get pendingMessageCount() {\n    return this._steeringMessages.length + this._followUpMessages.length;\n  }\n  /** Get pending steering messages (read-only) */\n  getSteeringMessages() {\n    return this._steeringMessages;\n  }\n  /** Get pending follow-up messages (read-only) */\n  getFollowUpMessages() {\n    return this._followUpMessages;\n  }\n  get resourceLoader() {\n    return this._resourceLoader;\n  }\n  /**\n   * Abort current operation and wait for agent to become idle.\n   */\n  async abort() {\n    this.abortRetry();\n    this.agent.abort();\n    await this.waitForIdle();\n  }\n  async waitForIdle() {\n    if (this.isIdle) {\n      return;\n    }\n    await this._getIdleWaitPromise();\n  }\n  // =========================================================================\n  // Model Management\n  // =========================================================================\n  async _emitModelSelect(nextModel, previousModel, source) {\n    if (modelsAreEqual(previousModel, nextModel))\n      return;\n    await this._extensionRunner.emit({\n      type: \"model_select\",\n      model: nextModel,\n      previousModel,\n      source\n    });\n  }\n  /**\n   * Set model directly.\n   * Validates that auth is configured, saves to session and settings.\n   * @throws Error if no auth is configured for the model\n   */\n  async setModel(model) {\n    if (!await this._modelRuntime.checkAuth(model.provider)) {\n      throw new Error(`No API key for ${model.provider}/${model.id}`);\n    }\n    const previousModel = this.model;\n    const thinkingLevel = this._getThinkingLevelForModelSwitch();\n    this.agent.state.model = model;\n    this.sessionManager.appendModelChange(model.provider, model.id);\n    this.settingsManager.setDefaultModelAndProvider(model.provider, model.id);\n    this.setThinkingLevel(thinkingLevel);\n    await this._emitModelSelect(model, previousModel, \"set\");\n  }\n  /**\n   * Cycle to next/previous model.\n   * Uses scoped models (from --models flag) if available, otherwise all available models.\n   * @param direction - \"forward\" (default) or \"backward\"\n   * @returns The new model info, or undefined if only one model available\n   */\n  async cycleModel(direction = \"forward\") {\n    if (this._scopedModels.length > 0) {\n      return this._cycleScopedModel(direction);\n    }\n    return this._cycleAvailableModel(direction);\n  }\n  async _cycleScopedModel(direction) {\n    const availableIds = new Set(this._modelRuntime.getAvailableSnapshot().map((model) => `${model.provider}\\0${model.id}`));\n    const scopedModels = this._scopedModels.filter((scoped) => availableIds.has(`${scoped.model.provider}\\0${scoped.model.id}`));\n    if (scopedModels.length <= 1)\n      return void 0;\n    const currentModel = this.model;\n    let currentIndex = scopedModels.findIndex((sm) => modelsAreEqual(sm.model, currentModel));\n    if (currentIndex === -1)\n      currentIndex = 0;\n    const len = scopedModels.length;\n    const nextIndex = direction === \"forward\" ? (currentIndex + 1) % len : (currentIndex - 1 + len) % len;\n    const next = scopedModels[nextIndex];\n    const thinkingLevel = this._getThinkingLevelForModelSwitch(next.thinkingLevel);\n    this.agent.state.model = next.model;\n    this.sessionManager.appendModelChange(next.model.provider, next.model.id);\n    this.settingsManager.setDefaultModelAndProvider(next.model.provider, next.model.id);\n    this.setThinkingLevel(thinkingLevel);\n    await this._emitModelSelect(next.model, currentModel, \"cycle\");\n    return { model: next.model, thinkingLevel: this.thinkingLevel, isScoped: true };\n  }\n  async _cycleAvailableModel(direction) {\n    const availableModels = this._modelRuntime.getAvailableSnapshot();\n    if (availableModels.length <= 1)\n      return void 0;\n    const currentModel = this.model;\n    let currentIndex = availableModels.findIndex((m) => modelsAreEqual(m, currentModel));\n    if (currentIndex === -1)\n      currentIndex = 0;\n    const len = availableModels.length;\n    const nextIndex = direction === \"forward\" ? (currentIndex + 1) % len : (currentIndex - 1 + len) % len;\n    const nextModel = availableModels[nextIndex];\n    const thinkingLevel = this._getThinkingLevelForModelSwitch();\n    this.agent.state.model = nextModel;\n    this.sessionManager.appendModelChange(nextModel.provider, nextModel.id);\n    this.settingsManager.setDefaultModelAndProvider(nextModel.provider, nextModel.id);\n    this.setThinkingLevel(thinkingLevel);\n    await this._emitModelSelect(nextModel, currentModel, \"cycle\");\n    return { model: nextModel, thinkingLevel: this.thinkingLevel, isScoped: false };\n  }\n  // =========================================================================\n  // Thinking Level Management\n  // =========================================================================\n  /**\n   * Set thinking level.\n   * Clamps to model capabilities based on available thinking levels.\n   * Saves to session and settings only if the level actually changes.\n   */\n  setThinkingLevel(level) {\n    const availableLevels = this.getAvailableThinkingLevels();\n    const effectiveLevel = availableLevels.includes(level) ? level : this._clampThinkingLevel(level, availableLevels);\n    const previousLevel = this.agent.state.thinkingLevel;\n    const isChanging = effectiveLevel !== previousLevel;\n    this.agent.state.thinkingLevel = effectiveLevel;\n    if (isChanging) {\n      this.sessionManager.appendThinkingLevelChange(effectiveLevel);\n      if (this.supportsThinking() || effectiveLevel !== \"off\") {\n        this.settingsManager.setDefaultThinkingLevel(effectiveLevel);\n      }\n      this._emit({ type: \"thinking_level_changed\", level: effectiveLevel });\n      void this._extensionRunner.emit({\n        type: \"thinking_level_select\",\n        level: effectiveLevel,\n        previousLevel\n      });\n    }\n  }\n  /**\n   * Cycle to next thinking level.\n   * @returns New level, or undefined if model doesn't support thinking\n   */\n  cycleThinkingLevel() {\n    if (!this.supportsThinking())\n      return void 0;\n    const levels = this.getAvailableThinkingLevels();\n    const currentIndex = levels.indexOf(this.thinkingLevel);\n    const nextIndex = (currentIndex + 1) % levels.length;\n    const nextLevel = levels[nextIndex];\n    this.setThinkingLevel(nextLevel);\n    return nextLevel;\n  }\n  /**\n   * Get available thinking levels for current model.\n   * The provider will clamp to what the specific model supports internally.\n   */\n  getAvailableThinkingLevels() {\n    if (!this.model)\n      return THINKING_LEVELS;\n    return getSupportedThinkingLevels(this.model);\n  }\n  /**\n   * Check if current model supports thinking/reasoning.\n   */\n  supportsThinking() {\n    return !!this.model?.reasoning;\n  }\n  _getThinkingLevelForModelSwitch(explicitLevel) {\n    if (explicitLevel !== void 0) {\n      return explicitLevel;\n    }\n    if (!this.supportsThinking()) {\n      return this.settingsManager.getDefaultThinkingLevel() ?? DEFAULT_THINKING_LEVEL;\n    }\n    return this.thinkingLevel;\n  }\n  _clampThinkingLevel(level, _availableLevels) {\n    return this.model ? clampThinkingLevel(this.model, level) : \"off\";\n  }\n  // =========================================================================\n  // Queue Mode Management\n  // =========================================================================\n  syncQueueModesFromSettings() {\n    this.agent.steeringMode = this.settingsManager.getSteeringMode();\n    this.agent.followUpMode = this.settingsManager.getFollowUpMode();\n  }\n  /**\n   * Set steering message mode.\n   * Saves to settings.\n   */\n  setSteeringMode(mode) {\n    this.agent.steeringMode = mode;\n    this.settingsManager.setSteeringMode(mode);\n  }\n  /**\n   * Set follow-up message mode.\n   * Saves to settings.\n   */\n  setFollowUpMode(mode) {\n    this.agent.followUpMode = mode;\n    this.settingsManager.setFollowUpMode(mode);\n  }\n  // =========================================================================\n  // Compaction\n  // =========================================================================\n  /**\n   * Manually compact the session context.\n   * Aborts current agent operation first.\n   * @param customInstructions Optional instructions for the compaction summary\n   */\n  async compact(customInstructions) {\n    await this.abort();\n    this._compactionAbortController = new AbortController();\n    this._emit({ type: \"compaction_start\", reason: \"manual\" });\n    try {\n      if (!this.model) {\n        throw new Error(formatNoModelSelectedMessage());\n      }\n      const { model: requestModel, apiKey, headers, env } = await this._getSummarizationRequestAuth(this.model);\n      const pathEntries = this.sessionManager.getBranch();\n      const settings = this.settingsManager.getCompactionSettings();\n      const preparation = prepareCompaction2(pathEntries, settings);\n      if (!preparation) {\n        const lastEntry = pathEntries[pathEntries.length - 1];\n        if (lastEntry?.type === \"compaction\") {\n          throw new Error(\"Already compacted\");\n        }\n        throw new Error(\"Nothing to compact (session too small)\");\n      }\n      let extensionCompaction;\n      let fromExtension = false;\n      if (this._extensionRunner.hasHandlers(\"session_before_compact\")) {\n        const result = await this._extensionRunner.emit({\n          type: \"session_before_compact\",\n          preparation,\n          branchEntries: pathEntries,\n          customInstructions,\n          reason: \"manual\",\n          willRetry: false,\n          signal: this._compactionAbortController.signal\n        });\n        if (result?.cancel) {\n          throw new Error(\"Compaction cancelled\");\n        }\n        if (result?.compaction) {\n          extensionCompaction = result.compaction;\n          fromExtension = true;\n        }\n      }\n      let summary;\n      let firstKeptEntryId;\n      let tokensBefore;\n      let usage;\n      let details;\n      if (extensionCompaction) {\n        summary = extensionCompaction.summary;\n        firstKeptEntryId = extensionCompaction.firstKeptEntryId;\n        tokensBefore = extensionCompaction.tokensBefore;\n        usage = extensionCompaction.usage;\n        details = extensionCompaction.details;\n      } else {\n        const result = await compact2(preparation, requestModel, apiKey, headers, customInstructions, this._compactionAbortController.signal, this.thinkingLevel, this.agent.streamFunction, env, this.settingsManager.getRetrySettings(), this._summarizationRetryCallbacks({ source: \"compaction\", reason: \"manual\" }));\n        summary = result.summary;\n        firstKeptEntryId = result.firstKeptEntryId;\n        tokensBefore = result.tokensBefore;\n        usage = result.usage;\n        details = result.details;\n      }\n      if (this._compactionAbortController.signal.aborted) {\n        throw new Error(\"Compaction cancelled\");\n      }\n      this.sessionManager.appendCompaction(summary, firstKeptEntryId, tokensBefore, details, fromExtension, usage);\n      const newEntries = this.sessionManager.getEntries();\n      const sessionContext = this.sessionManager.buildSessionContext();\n      this.agent.state.messages = sessionContext.messages;\n      const estimatedTokensAfter = estimateMessagesTokens(sessionContext.messages);\n      const savedCompactionEntry = newEntries.find((e) => e.type === \"compaction\" && e.summary === summary);\n      if (this._extensionRunner && savedCompactionEntry) {\n        await this._extensionRunner.emit({\n          type: \"session_compact\",\n          compactionEntry: savedCompactionEntry,\n          fromExtension,\n          reason: \"manual\",\n          willRetry: false\n        });\n      }\n      const compactionResult = {\n        summary,\n        firstKeptEntryId,\n        tokensBefore,\n        estimatedTokensAfter,\n        usage,\n        details\n      };\n      this._compactionAbortController = void 0;\n      this._emit({\n        type: \"compaction_end\",\n        reason: \"manual\",\n        result: compactionResult,\n        aborted: false,\n        willRetry: false\n      });\n      return compactionResult;\n    } catch (error) {\n      const message = error instanceof Error ? error.message : String(error);\n      const aborted = message === \"Compaction cancelled\" || error instanceof Error && error.name === \"AbortError\";\n      this._compactionAbortController = void 0;\n      this._emit({\n        type: \"compaction_end\",\n        reason: \"manual\",\n        result: void 0,\n        aborted,\n        willRetry: false,\n        errorMessage: aborted ? void 0 : `Compaction failed: ${message}`\n      });\n      throw error;\n    } finally {\n      this._compactionAbortController = void 0;\n    }\n  }\n  /**\n   * Cancel in-progress compaction (manual or auto).\n   */\n  abortCompaction() {\n    this._compactionAbortController?.abort();\n    this._autoCompactionAbortController?.abort();\n  }\n  /**\n   * Cancel in-progress branch summarization.\n   */\n  abortBranchSummary() {\n    this._branchSummaryAbortController?.abort();\n  }\n  /**\n   * Check if compaction is needed and run it.\n   * Called after agent_end and before prompt submission.\n   *\n   * Two cases:\n   * 1. Recoverable failure: LLM returned context overflow or stopped below its desired output limit;\n   *    remove the assistant message, compact, and auto-retry once\n   * 2. Threshold: Context over threshold, compact, NO auto-retry (user continues manually)\n   *\n   * @param assistantMessage The assistant message to check\n   * @param skipAbortedCheck If false, include aborted messages (for pre-prompt check). Default: true\n   */\n  async _checkCompaction(assistantMessage, skipAbortedCheck = true) {\n    const settings = this.settingsManager.getCompactionSettings();\n    if (!settings.enabled)\n      return false;\n    if (skipAbortedCheck && assistantMessage.stopReason === \"aborted\")\n      return false;\n    const contextWindow = this.model?.contextWindow ?? 0;\n    const sameModel = this.model && assistantMessage.provider === this.model.provider && assistantMessage.model === this.model.id;\n    const compactionEntry = getLatestCompactionEntry(this.sessionManager.getBranch());\n    const assistantIsFromBeforeCompaction = compactionEntry !== null && assistantMessage.timestamp <= new Date(compactionEntry.timestamp).getTime();\n    if (assistantIsFromBeforeCompaction) {\n      return false;\n    }\n    const recoverableLength = sameModel && isRecoverableLength(assistantMessage, this.model?.maxTokens ?? 0);\n    if (sameModel && (isContextOverflow(assistantMessage, contextWindow) || recoverableLength)) {\n      const willRetry = assistantMessage.stopReason !== \"stop\";\n      if (!willRetry) {\n        return await this._runAutoCompaction(\"overflow\", false);\n      }\n      if (this._overflowRecoveryAttempted) {\n        this._emit({\n          type: \"compaction_end\",\n          reason: \"overflow\",\n          result: void 0,\n          aborted: false,\n          willRetry: false,\n          errorMessage: \"Context overflow recovery failed after one compact-and-retry attempt. Try reducing context or switching to a larger-context model.\"\n        });\n        return false;\n      }\n      this._overflowRecoveryAttempted = true;\n      const messages = this.agent.state.messages;\n      if (messages.length > 0 && messages[messages.length - 1].role === \"assistant\") {\n        this.agent.state.messages = messages.slice(0, -1);\n      }\n      return await this._runAutoCompaction(\"overflow\", willRetry);\n    }\n    let contextTokens;\n    const directContextTokens = assistantMessage.usage ? calculateContextTokens3(assistantMessage.usage) : 0;\n    if (assistantMessage.stopReason === \"error\" || directContextTokens === 0) {\n      const messages = this.agent.state.messages;\n      const estimate = estimateContextTokens3(messages);\n      if (estimate.lastUsageIndex === null)\n        return false;\n      const usageMsg = messages[estimate.lastUsageIndex];\n      if (compactionEntry && usageMsg.role === \"assistant\" && usageMsg.timestamp <= new Date(compactionEntry.timestamp).getTime()) {\n        return false;\n      }\n      contextTokens = estimate.tokens;\n    } else {\n      contextTokens = directContextTokens;\n    }\n    if (shouldCompact2(contextTokens, contextWindow, settings)) {\n      return await this._runAutoCompaction(\"threshold\", false);\n    }\n    return false;\n  }\n  /**\n   * Internal: Run auto-compaction with events.\n   */\n  async _runAutoCompaction(reason, willRetry) {\n    const settings = this.settingsManager.getCompactionSettings();\n    let started = false;\n    try {\n      if (!this.model) {\n        return false;\n      }\n      const { model: requestModel, apiKey, headers, env } = await this._getSummarizationRequestAuth(this.model);\n      const pathEntries = this.sessionManager.getBranch();\n      const preparation = prepareCompaction2(pathEntries, settings);\n      if (!preparation) {\n        return false;\n      }\n      this._emit({ type: \"compaction_start\", reason });\n      this._autoCompactionAbortController = new AbortController();\n      started = true;\n      let extensionCompaction;\n      let fromExtension = false;\n      if (this._extensionRunner.hasHandlers(\"session_before_compact\")) {\n        const extensionResult = await this._extensionRunner.emit({\n          type: \"session_before_compact\",\n          preparation,\n          branchEntries: pathEntries,\n          customInstructions: void 0,\n          reason,\n          willRetry,\n          signal: this._autoCompactionAbortController.signal\n        });\n        if (extensionResult?.cancel) {\n          this._emit({\n            type: \"compaction_end\",\n            reason,\n            result: void 0,\n            aborted: true,\n            willRetry: false\n          });\n          return false;\n        }\n        if (extensionResult?.compaction) {\n          extensionCompaction = extensionResult.compaction;\n          fromExtension = true;\n        }\n      }\n      let summary;\n      let firstKeptEntryId;\n      let tokensBefore;\n      let usage;\n      let details;\n      if (extensionCompaction) {\n        summary = extensionCompaction.summary;\n        firstKeptEntryId = extensionCompaction.firstKeptEntryId;\n        tokensBefore = extensionCompaction.tokensBefore;\n        usage = extensionCompaction.usage;\n        details = extensionCompaction.details;\n      } else {\n        const compactResult = await compact2(preparation, requestModel, apiKey, headers, void 0, this._autoCompactionAbortController.signal, this.thinkingLevel, this.agent.streamFunction, env, this.settingsManager.getRetrySettings(), this._summarizationRetryCallbacks({ source: \"compaction\", reason }));\n        summary = compactResult.summary;\n        firstKeptEntryId = compactResult.firstKeptEntryId;\n        tokensBefore = compactResult.tokensBefore;\n        usage = compactResult.usage;\n        details = compactResult.details;\n      }\n      if (this._autoCompactionAbortController.signal.aborted) {\n        this._emit({\n          type: \"compaction_end\",\n          reason,\n          result: void 0,\n          aborted: true,\n          willRetry: false\n        });\n        return false;\n      }\n      this.sessionManager.appendCompaction(summary, firstKeptEntryId, tokensBefore, details, fromExtension, usage);\n      const newEntries = this.sessionManager.getEntries();\n      const sessionContext = this.sessionManager.buildSessionContext();\n      this.agent.state.messages = sessionContext.messages;\n      const estimatedTokensAfter = estimateMessagesTokens(sessionContext.messages);\n      const savedCompactionEntry = newEntries.find((e) => e.type === \"compaction\" && e.summary === summary);\n      if (this._extensionRunner && savedCompactionEntry) {\n        await this._extensionRunner.emit({\n          type: \"session_compact\",\n          compactionEntry: savedCompactionEntry,\n          fromExtension,\n          reason,\n          willRetry\n        });\n      }\n      const result = {\n        summary,\n        firstKeptEntryId,\n        tokensBefore,\n        estimatedTokensAfter,\n        usage,\n        details\n      };\n      this._emit({ type: \"compaction_end\", reason, result, aborted: false, willRetry });\n      if (willRetry) {\n        const messages = this.agent.state.messages;\n        const lastMsg = messages[messages.length - 1];\n        if (lastMsg?.role === \"assistant\" && (lastMsg.stopReason === \"error\" || lastMsg.stopReason === \"length\")) {\n          this.agent.state.messages = messages.slice(0, -1);\n        }\n        return true;\n      }\n      return this.agent.hasQueuedMessages();\n    } catch (error) {\n      const errorMessage2 = error instanceof Error ? error.message : \"compaction failed\";\n      if (started) {\n        this._emit({\n          type: \"compaction_end\",\n          reason,\n          result: void 0,\n          aborted: false,\n          willRetry: false,\n          errorMessage: reason === \"overflow\" ? `Context overflow recovery failed: ${errorMessage2}` : `Auto-compaction failed: ${errorMessage2}`\n        });\n      }\n      return false;\n    } finally {\n      this._autoCompactionAbortController = void 0;\n    }\n  }\n  /**\n   * Toggle auto-compaction setting.\n   */\n  setAutoCompactionEnabled(enabled) {\n    this.settingsManager.setCompactionEnabled(enabled);\n  }\n  /** Whether auto-compaction is enabled */\n  get autoCompactionEnabled() {\n    return this.settingsManager.getCompactionEnabled();\n  }\n  async bindExtensions(bindings) {\n    if (bindings.uiContext !== void 0) {\n      this._extensionUIContext = bindings.uiContext;\n    }\n    if (bindings.mode !== void 0) {\n      this._extensionMode = bindings.mode;\n    }\n    if (bindings.commandContextActions !== void 0) {\n      this._extensionCommandContextActions = bindings.commandContextActions;\n    }\n    if (bindings.abortHandler !== void 0) {\n      this._extensionAbortHandler = bindings.abortHandler;\n    }\n    if (bindings.shutdownHandler !== void 0) {\n      this._extensionShutdownHandler = bindings.shutdownHandler;\n    }\n    if (bindings.onError !== void 0) {\n      this._extensionErrorListener = bindings.onError;\n    }\n    this._applyExtensionBindings(this._extensionRunner);\n    await this._extensionRunner.emit(this._sessionStartEvent);\n    await this.extendResourcesFromExtensions(this._sessionStartEvent.reason === \"reload\" ? \"reload\" : \"startup\");\n  }\n  async extendResourcesFromExtensions(reason) {\n    if (!this._extensionRunner.hasHandlers(\"resources_discover\")) {\n      return;\n    }\n    const { skillPaths, promptPaths, themePaths } = await this._extensionRunner.emitResourcesDiscover(this._cwd, reason);\n    if (skillPaths.length === 0 && promptPaths.length === 0 && themePaths.length === 0) {\n      return;\n    }\n    const extensionPaths = {\n      skillPaths: this.buildExtensionResourcePaths(skillPaths),\n      promptPaths: this.buildExtensionResourcePaths(promptPaths),\n      themePaths: this.buildExtensionResourcePaths(themePaths)\n    };\n    this._resourceLoader.extendResources(extensionPaths);\n    this._baseSystemPrompt = this._rebuildSystemPrompt(this.getActiveToolNames());\n    this.agent.state.systemPrompt = this._baseSystemPrompt;\n  }\n  buildExtensionResourcePaths(entries) {\n    return entries.map((entry) => {\n      const source = this.getExtensionSourceLabel(entry.extensionPath);\n      const baseDir = entry.extensionPath.startsWith(\"<\") ? void 0 : dirname15(entry.extensionPath);\n      return {\n        path: entry.path,\n        metadata: {\n          source,\n          scope: \"temporary\",\n          origin: \"top-level\",\n          baseDir\n        }\n      };\n    });\n  }\n  getExtensionSourceLabel(extensionPath) {\n    if (extensionPath.startsWith(\"<\")) {\n      return `extension:${extensionPath.replace(/[<>]/g, \"\")}`;\n    }\n    const base = basename8(extensionPath);\n    const name = base.replace(/\\.(ts|js)$/, \"\");\n    return `extension:${name}`;\n  }\n  _applyExtensionBindings(runner) {\n    runner.setUIContext(this._extensionUIContext, this._extensionMode);\n    runner.bindCommandContext(this._extensionCommandContextActions);\n    this._extensionErrorUnsubscriber?.();\n    this._extensionErrorUnsubscriber = this._extensionErrorListener ? runner.onError(this._extensionErrorListener) : void 0;\n  }\n  _refreshCurrentModelFromRegistry() {\n    const currentModel = this.model;\n    if (!currentModel) {\n      return;\n    }\n    const refreshedModel = this._modelRuntime.getModel(currentModel.provider, currentModel.id);\n    if (!refreshedModel || refreshedModel === currentModel) {\n      return;\n    }\n    this.agent.state.model = refreshedModel;\n  }\n  _bindExtensionCore(runner) {\n    const getCommands = () => {\n      const extensionCommands = runner.getRegisteredCommands().map((command) => ({\n        name: command.invocationName,\n        description: command.description,\n        source: \"extension\",\n        sourceInfo: command.sourceInfo\n      }));\n      const templates = this.promptTemplates.map((template) => ({\n        name: template.name,\n        description: template.description,\n        source: \"prompt\",\n        sourceInfo: template.sourceInfo\n      }));\n      const skills = this._resourceLoader.getSkills().skills.map((skill) => ({\n        name: `skill:${skill.name}`,\n        description: skill.description,\n        source: \"skill\",\n        sourceInfo: skill.sourceInfo\n      }));\n      return [...extensionCommands, ...templates, ...skills];\n    };\n    runner.bindCore({\n      sendMessage: (message, options) => {\n        this.sendCustomMessage(message, options).catch((err2) => {\n          runner.emitError({\n            extensionPath: \"<runtime>\",\n            event: \"send_message\",\n            error: err2 instanceof Error ? err2.message : String(err2)\n          });\n        });\n      },\n      sendUserMessage: (content, options) => {\n        this.sendUserMessage(content, options).catch((err2) => {\n          runner.emitError({\n            extensionPath: \"<runtime>\",\n            event: \"send_user_message\",\n            error: err2 instanceof Error ? err2.message : String(err2)\n          });\n        });\n      },\n      appendEntry: (customType, data) => {\n        const entryId = this.sessionManager.appendCustomEntry(customType, data);\n        const entry = this.sessionManager.getEntry(entryId);\n        if (entry) {\n          this._emit({ type: \"entry_appended\", entry });\n        }\n      },\n      setSessionName: (name) => {\n        this.setSessionName(name);\n      },\n      getSessionName: () => {\n        return this.sessionManager.getSessionName();\n      },\n      setLabel: (entryId, label) => {\n        this.sessionManager.appendLabelChange(entryId, label);\n      },\n      getActiveTools: () => this.getActiveToolNames(),\n      getAllTools: () => this.getAllTools(),\n      setActiveTools: (toolNames) => this.setActiveToolsByName(toolNames),\n      refreshTools: () => this._refreshToolRegistry(),\n      getCommands,\n      setModel: async (model) => {\n        if (!this._modelRuntime.hasConfiguredAuth(model.provider))\n          return false;\n        await this.setModel(model);\n        return true;\n      },\n      getThinkingLevel: () => this.thinkingLevel,\n      setThinkingLevel: (level) => this.setThinkingLevel(level)\n    }, {\n      getModel: () => this.model,\n      getScopedModels: () => this._scopedModels,\n      isIdle: () => this.isIdle,\n      isProjectTrusted: () => this.settingsManager.isProjectTrusted(),\n      getSignal: () => this.agent.signal,\n      abort: () => {\n        if (this._extensionAbortHandler) {\n          this._extensionAbortHandler();\n          return;\n        }\n        void this.abort();\n      },\n      hasPendingMessages: () => this.pendingMessageCount > 0,\n      shutdown: () => {\n        this._extensionShutdownHandler?.();\n      },\n      getContextUsage: () => this.getContextUsage(),\n      compact: (options) => {\n        void (async () => {\n          try {\n            const result = await this.compact(options?.customInstructions);\n            options?.onComplete?.(result);\n          } catch (error) {\n            const err2 = error instanceof Error ? error : new Error(String(error));\n            options?.onError?.(err2);\n          }\n        })();\n      },\n      getSystemPrompt: () => this.systemPrompt,\n      getSystemPromptOptions: () => this._baseSystemPromptOptions\n    }, {\n      registerProvider: (name, config) => {\n        this._modelRuntime.registerProvider(name, config);\n        this._refreshCurrentModelFromRegistry();\n      },\n      registerNativeProvider: (provider) => {\n        this._modelRuntime.registerNativeProvider(provider);\n        this._refreshCurrentModelFromRegistry();\n      },\n      unregisterProvider: (name) => {\n        this._modelRuntime.unregisterProvider(name);\n        this._refreshCurrentModelFromRegistry();\n      }\n    });\n  }\n  _refreshToolRegistry(options) {\n    const previousRegistryNames = new Set(this._toolRegistry.keys());\n    const previousActiveToolNames = this.getActiveToolNames();\n    const allowedToolNames = this._allowedToolNames;\n    const excludedToolNames = this._excludedToolNames;\n    const isAllowedTool = (name) => (!allowedToolNames || allowedToolNames.has(name)) && !excludedToolNames?.has(name);\n    const registeredTools = this._extensionRunner.getAllRegisteredTools();\n    const allCustomTools = [\n      ...registeredTools,\n      ...this._customTools.map((definition) => ({\n        definition,\n        sourceInfo: createSyntheticSourceInfo(`<sdk:${definition.name}>`, { source: \"sdk\" })\n      }))\n    ].filter((tool) => isAllowedTool(tool.definition.name));\n    const definitionRegistry = new Map(Array.from(this._baseToolDefinitions.entries()).filter(([name]) => isAllowedTool(name)).map(([name, definition]) => [\n      name,\n      {\n        definition,\n        sourceInfo: createSyntheticSourceInfo(`<builtin:${name}>`, { source: \"builtin\" })\n      }\n    ]));\n    for (const tool of allCustomTools) {\n      definitionRegistry.set(tool.definition.name, {\n        definition: tool.definition,\n        sourceInfo: tool.sourceInfo\n      });\n    }\n    this._toolDefinitions = definitionRegistry;\n    this._toolPromptSnippets = new Map(Array.from(definitionRegistry.values()).map(({ definition }) => {\n      const snippet = this._normalizePromptSnippet(definition.promptSnippet);\n      return snippet ? [definition.name, snippet] : void 0;\n    }).filter((entry) => entry !== void 0));\n    this._toolPromptGuidelines = new Map(Array.from(definitionRegistry.values()).map(({ definition }) => {\n      const guidelines = this._normalizePromptGuidelines(definition.promptGuidelines);\n      return guidelines.length > 0 ? [definition.name, guidelines] : void 0;\n    }).filter((entry) => entry !== void 0));\n    const runner = this._extensionRunner;\n    const wrappedExtensionTools = wrapRegisteredTools(allCustomTools, runner);\n    const wrappedBuiltInTools = wrapRegisteredTools(Array.from(this._baseToolDefinitions.values()).filter((definition) => isAllowedTool(definition.name)).map((definition) => ({\n      definition,\n      sourceInfo: createSyntheticSourceInfo(`<builtin:${definition.name}>`, { source: \"builtin\" })\n    })), runner);\n    const toolRegistry = new Map(wrappedBuiltInTools.map((tool) => [tool.name, tool]));\n    for (const tool of wrappedExtensionTools) {\n      toolRegistry.set(tool.name, tool);\n    }\n    this._toolRegistry = toolRegistry;\n    const nextActiveToolNames = (options?.activeToolNames ? [...options.activeToolNames] : [...previousActiveToolNames]).filter((name) => isAllowedTool(name));\n    if (allowedToolNames) {\n      for (const toolName of this._toolRegistry.keys()) {\n        if (allowedToolNames.has(toolName)) {\n          nextActiveToolNames.push(toolName);\n        }\n      }\n    } else if (options?.includeAllExtensionTools) {\n      for (const tool of wrappedExtensionTools) {\n        nextActiveToolNames.push(tool.name);\n      }\n    } else if (!options?.activeToolNames) {\n      for (const toolName of this._toolRegistry.keys()) {\n        if (!previousRegistryNames.has(toolName)) {\n          nextActiveToolNames.push(toolName);\n        }\n      }\n    }\n    this.setActiveToolsByName([...new Set(nextActiveToolNames)]);\n  }\n  _buildRuntime(options) {\n    const autoResizeImages = this.settingsManager.getImageAutoResize();\n    const shellCommandPrefix = this.settingsManager.getShellCommandPrefix();\n    const shellPath = this.settingsManager.getShellPath();\n    const baseToolDefinitions = this._baseToolsOverride ? Object.fromEntries(Object.entries(this._baseToolsOverride).map(([name, tool]) => [\n      name,\n      createToolDefinitionFromAgentTool(tool)\n    ])) : createAllToolDefinitions(this._cwd, {\n      read: { autoResizeImages },\n      bash: { commandPrefix: shellCommandPrefix, shellPath }\n    });\n    this._baseToolDefinitions = new Map(Object.entries(baseToolDefinitions).map(([name, tool]) => [name, tool]));\n    const extensionsResult = this._resourceLoader.getExtensions();\n    if (options.flagValues) {\n      for (const [name, value] of options.flagValues) {\n        extensionsResult.runtime.flagValues.set(name, value);\n      }\n    }\n    this._extensionRunner = new ExtensionRunner(extensionsResult.extensions, extensionsResult.runtime, this._cwd, this.sessionManager, new ModelRegistry(this._modelRuntime));\n    if (this._extensionRunnerRef) {\n      this._extensionRunnerRef.current = this._extensionRunner;\n    }\n    this._bindExtensionCore(this._extensionRunner);\n    this._applyExtensionBindings(this._extensionRunner);\n    const defaultActiveToolNames = this._baseToolsOverride ? Object.keys(this._baseToolsOverride) : [\"read\", \"bash\", \"edit\", \"write\"];\n    const baseActiveToolNames = options.activeToolNames ?? defaultActiveToolNames;\n    this._refreshToolRegistry({\n      activeToolNames: baseActiveToolNames,\n      includeAllExtensionTools: options.includeAllExtensionTools\n    });\n  }\n  async reload(options) {\n    const oldRunner = this._extensionRunner;\n    const previousFlagValues = oldRunner.getFlagValues();\n    await emitSessionShutdownEvent(oldRunner, { type: \"session_shutdown\", reason: \"reload\" });\n    oldRunner.invalidate();\n    await this.settingsManager.reload();\n    this.syncQueueModesFromSettings();\n    resetApiProviders();\n    await this._resourceLoader.reload();\n    this._buildRuntime({\n      activeToolNames: this.getActiveToolNames(),\n      flagValues: previousFlagValues,\n      includeAllExtensionTools: true\n    });\n    const hasBindings = this._extensionUIContext || this._extensionCommandContextActions || this._extensionShutdownHandler || this._extensionErrorListener;\n    if (hasBindings) {\n      await options?.beforeSessionStart?.();\n      await this._extensionRunner.emit({ type: \"session_start\", reason: \"reload\" });\n      await this.extendResourcesFromExtensions(\"reload\");\n    }\n  }\n  // =========================================================================\n  // Auto-Retry\n  // =========================================================================\n  /**\n   * Check if an error is retryable (overloaded, rate limit, server errors).\n   * Context overflow errors are NOT retryable (handled by compaction instead).\n   */\n  _isRetryableError(message) {\n    if (isContextOverflow(message, this.model?.contextWindow ?? 0))\n      return false;\n    return isRetryableAssistantError(message);\n  }\n  /**\n   * Retry policy + callbacks shared by compaction and branch-summary summarization calls.\n   * Uses the same `settings.retry` budget/backoff as agent-turn retries so a single transient\n   * stream drop no longer fails the whole operation. `source` carries the context\n   * the TUI needs to render the retry and recreate the underlying indicator.\n   */\n  _summarizationRetryCallbacks(source) {\n    return {\n      onRetryScheduled: (attempt, maxAttempts, delayMs, errorMessage2) => {\n        this._emit({\n          type: \"summarization_retry_scheduled\",\n          attempt,\n          maxAttempts,\n          delayMs,\n          errorMessage: errorMessage2\n        });\n      },\n      onRetryAttemptStart: () => {\n        this._emit({\n          type: \"summarization_retry_attempt_start\",\n          ...source\n        });\n      },\n      onRetryFinished: () => {\n        this._emit({ type: \"summarization_retry_finished\" });\n      }\n    };\n  }\n  /**\n   * Prepare a retryable error for continuation with exponential backoff.\n   * @returns true if the caller should continue the agent, false otherwise\n   */\n  async _prepareRetry(message) {\n    const settings = this.settingsManager.getRetrySettings();\n    if (!settings.enabled) {\n      return false;\n    }\n    this._retryAttempt++;\n    if (this._retryAttempt > settings.maxRetries) {\n      this._retryAttempt--;\n      return false;\n    }\n    const delayMs = settings.baseDelayMs * 2 ** (this._retryAttempt - 1);\n    this._emit({\n      type: \"auto_retry_start\",\n      attempt: this._retryAttempt,\n      maxAttempts: settings.maxRetries,\n      delayMs,\n      errorMessage: message.errorMessage || \"Unknown error\"\n    });\n    const messages = this.agent.state.messages;\n    if (messages.length > 0 && messages[messages.length - 1].role === \"assistant\") {\n      this.agent.state.messages = messages.slice(0, -1);\n    }\n    this._retryAbortController = new AbortController();\n    try {\n      await sleep5(delayMs, this._retryAbortController.signal);\n    } catch {\n      const attempt = this._retryAttempt;\n      this._retryAttempt = 0;\n      this._emit({\n        type: \"auto_retry_end\",\n        success: false,\n        attempt,\n        finalError: \"Retry cancelled\"\n      });\n      return false;\n    } finally {\n      this._retryAbortController = void 0;\n    }\n    return true;\n  }\n  /**\n   * Cancel in-progress retry.\n   */\n  abortRetry() {\n    this._retryAbortController?.abort();\n  }\n  /** Whether auto-retry is currently in progress */\n  get isRetrying() {\n    return this._retryAbortController !== void 0;\n  }\n  /** Whether auto-retry is enabled */\n  get autoRetryEnabled() {\n    return this.settingsManager.getRetryEnabled();\n  }\n  /**\n   * Toggle auto-retry setting.\n   */\n  setAutoRetryEnabled(enabled) {\n    this.settingsManager.setRetryEnabled(enabled);\n  }\n  // =========================================================================\n  // Bash Execution\n  // =========================================================================\n  /**\n   * Execute a bash command.\n   * Adds result to agent context and session.\n   * @param command The bash command to execute\n   * @param onChunk Optional streaming callback for output\n   * @param options.excludeFromContext If true, command output won't be sent to LLM (!! prefix)\n   * @param options.id Optional identifier included in bash execution update events\n   * @param options.operations Custom BashOperations for remote execution\n   */\n  async executeBash(command, onChunk, options) {\n    const abortController = new AbortController();\n    this._bashAbortControllers.add(abortController);\n    const prefix = this.settingsManager.getShellCommandPrefix();\n    const shellPath = this.settingsManager.getShellPath();\n    const resolvedCommand = prefix ? `${prefix}\n${command}` : command;\n    try {\n      const result = await executeBashWithOperations(resolvedCommand, this.sessionManager.getCwd(), options?.operations ?? createLocalBashOperations({ shellPath }), {\n        onChunk: (delta) => {\n          onChunk?.(delta);\n          this._emit({ type: \"bash_execution_update\", id: options?.id, delta });\n        },\n        signal: abortController.signal\n      });\n      this.recordBashResult(command, result, options);\n      return result;\n    } finally {\n      this._bashAbortControllers.delete(abortController);\n    }\n  }\n  /**\n   * Record a bash execution result in session history.\n   * Used by executeBash and by extensions that handle bash execution themselves.\n   */\n  recordBashResult(command, result, options) {\n    const bashMessage = {\n      role: \"bashExecution\",\n      command,\n      output: result.output,\n      exitCode: result.exitCode,\n      cancelled: result.cancelled,\n      truncated: result.truncated,\n      fullOutputPath: result.fullOutputPath,\n      timestamp: Date.now(),\n      excludeFromContext: options?.excludeFromContext\n    };\n    if (this.isStreaming) {\n      this._pendingBashMessages.push(bashMessage);\n    } else {\n      this.agent.state.messages.push(bashMessage);\n      this.sessionManager.appendMessage(bashMessage);\n    }\n  }\n  /**\n   * Cancel running bash command.\n   */\n  abortBash() {\n    for (const abortController of [...this._bashAbortControllers]) {\n      abortController.abort();\n    }\n  }\n  /** Whether a bash command is currently running */\n  get isBashRunning() {\n    return this._bashAbortControllers.size > 0;\n  }\n  /** Whether there are pending bash messages waiting to be flushed */\n  get hasPendingBashMessages() {\n    return this._pendingBashMessages.length > 0;\n  }\n  /**\n   * Flush pending bash messages to agent state and session.\n   * Called after agent turn completes to maintain proper message ordering.\n   */\n  _flushPendingBashMessages() {\n    if (this._pendingBashMessages.length === 0)\n      return;\n    for (const bashMessage of this._pendingBashMessages) {\n      this.agent.state.messages.push(bashMessage);\n      this.sessionManager.appendMessage(bashMessage);\n    }\n    this._pendingBashMessages = [];\n  }\n  // =========================================================================\n  // Session Management\n  // =========================================================================\n  /**\n   * Set a display name for the current session.\n   */\n  setSessionName(name) {\n    this.sessionManager.appendSessionInfo(name);\n    const event = { type: \"session_info_changed\", name: this.sessionManager.getSessionName() };\n    this._emit(event);\n    void this._extensionRunner.emit(event);\n  }\n  // =========================================================================\n  // Tree Navigation\n  // =========================================================================\n  /**\n   * Navigate to a different node in the session tree.\n   * Unlike fork() which creates a new session file, this stays in the same file.\n   *\n   * @param targetId The entry ID to navigate to\n   * @param options.summarize Whether user wants to summarize abandoned branch\n   * @param options.customInstructions Custom instructions for summarizer\n   * @param options.replaceInstructions If true, customInstructions replaces the default prompt\n   * @param options.label Label to attach to the branch summary entry\n   * @returns Result with editorText (if user message) and cancelled status\n   */\n  async navigateTree(targetId, options = {}) {\n    if (this.isStreaming) {\n      throw new Error(\"Wait for the current response to finish before navigating the session tree.\");\n    }\n    const oldLeafId = this.sessionManager.getLeafId();\n    if (targetId === oldLeafId) {\n      return { cancelled: false };\n    }\n    if (options.summarize && !this.model) {\n      throw new Error(\"No model available for summarization\");\n    }\n    const targetEntry = this.sessionManager.getEntry(targetId);\n    if (!targetEntry) {\n      throw new Error(`Entry ${targetId} not found`);\n    }\n    const { entries: entriesToSummarize, commonAncestorId } = collectEntriesForBranchSummary2(this.sessionManager, oldLeafId, targetId);\n    let customInstructions = options.customInstructions;\n    let replaceInstructions = options.replaceInstructions;\n    let label = options.label;\n    const preparation = {\n      targetId,\n      oldLeafId,\n      commonAncestorId,\n      entriesToSummarize,\n      userWantsSummary: options.summarize ?? false,\n      customInstructions,\n      replaceInstructions,\n      label\n    };\n    this._branchSummaryAbortController = new AbortController();\n    try {\n      let extensionSummary;\n      let fromExtension = false;\n      if (this._extensionRunner.hasHandlers(\"session_before_tree\")) {\n        const result = await this._extensionRunner.emit({\n          type: \"session_before_tree\",\n          preparation,\n          signal: this._branchSummaryAbortController.signal\n        });\n        if (result?.cancel) {\n          return { cancelled: true };\n        }\n        if (result?.summary && options.summarize) {\n          extensionSummary = result.summary;\n          fromExtension = true;\n        }\n        if (result?.customInstructions !== void 0) {\n          customInstructions = result.customInstructions;\n        }\n        if (result?.replaceInstructions !== void 0) {\n          replaceInstructions = result.replaceInstructions;\n        }\n        if (result?.label !== void 0) {\n          label = result.label;\n        }\n      }\n      let summaryText;\n      let summaryDetails;\n      let summaryUsage;\n      if (options.summarize && entriesToSummarize.length > 0 && !extensionSummary) {\n        const model = this.model;\n        const { model: requestModel, apiKey, headers, env } = await this._getSummarizationRequestAuth(model);\n        const branchSummarySettings = this.settingsManager.getBranchSummarySettings();\n        const result = await generateBranchSummary2(entriesToSummarize, {\n          model: requestModel,\n          apiKey,\n          headers,\n          env,\n          signal: this._branchSummaryAbortController.signal,\n          customInstructions,\n          replaceInstructions,\n          reserveTokens: branchSummarySettings.reserveTokens,\n          streamFn: this.agent.streamFunction,\n          retry: this.settingsManager.getRetrySettings(),\n          callbacks: this._summarizationRetryCallbacks({ source: \"branchSummary\" })\n        });\n        if (result.aborted) {\n          return { cancelled: true, aborted: true };\n        }\n        if (result.error) {\n          throw new Error(result.error);\n        }\n        summaryText = result.summary;\n        summaryUsage = result.usage;\n        summaryDetails = {\n          readFiles: result.readFiles || [],\n          modifiedFiles: result.modifiedFiles || []\n        };\n      } else if (extensionSummary) {\n        summaryText = extensionSummary.summary;\n        summaryDetails = extensionSummary.details;\n        summaryUsage = extensionSummary.usage;\n      }\n      let newLeafId;\n      let editorText;\n      if (targetEntry.type === \"message\" && targetEntry.message.role === \"user\") {\n        newLeafId = targetEntry.parentId;\n        editorText = contentText(targetEntry.message.content, \"\");\n      } else if (targetEntry.type === \"custom_message\") {\n        newLeafId = targetEntry.parentId;\n        editorText = contentText(targetEntry.content, \"\");\n      } else {\n        newLeafId = targetId;\n      }\n      let summaryEntry;\n      if (summaryText) {\n        const summaryId = this.sessionManager.branchWithSummary(newLeafId, summaryText, summaryDetails, fromExtension, summaryUsage);\n        summaryEntry = this.sessionManager.getEntry(summaryId);\n        if (label) {\n          this.sessionManager.appendLabelChange(summaryId, label);\n        }\n      } else if (newLeafId === null) {\n        this.sessionManager.resetLeaf();\n      } else {\n        this.sessionManager.branch(newLeafId);\n      }\n      if (label && !summaryText) {\n        this.sessionManager.appendLabelChange(targetId, label);\n      }\n      const sessionContext = this.sessionManager.buildSessionContext();\n      this.agent.state.messages = sessionContext.messages;\n      await this._extensionRunner.emit({\n        type: \"session_tree\",\n        newLeafId: this.sessionManager.getLeafId(),\n        oldLeafId,\n        summaryEntry,\n        fromExtension: summaryText ? fromExtension : void 0\n      });\n      return { editorText, cancelled: false, summaryEntry };\n    } finally {\n      this._branchSummaryAbortController = void 0;\n    }\n  }\n  /**\n   * Get all user messages from session for fork selector.\n   */\n  getUserMessagesForForking() {\n    const entries = this.sessionManager.getEntries();\n    const result = [];\n    for (const entry of entries) {\n      if (entry.type !== \"message\")\n        continue;\n      if (entry.message.role !== \"user\")\n        continue;\n      const text = contentText(entry.message.content, \"\");\n      if (text) {\n        result.push({ entryId: entry.id, text });\n      }\n    }\n    return result;\n  }\n  /**\n   * Get session statistics. Aggregates over ALL session entries (including\n   * history that was compacted away), so token/cost totals reflect what was\n   * actually billed across the session.\n   */\n  getSessionStats() {\n    let userMessages = 0;\n    let assistantMessages = 0;\n    let toolResults = 0;\n    let totalMessages = 0;\n    let toolCalls = 0;\n    const usageTotals = createUsageTotals();\n    for (const entry of this.sessionManager.getEntries()) {\n      if ((entry.type === \"branch_summary\" || entry.type === \"compaction\") && entry.usage) {\n        addUsageToTotals(usageTotals, entry.usage);\n      }\n      if (entry.type !== \"message\")\n        continue;\n      totalMessages++;\n      const message = entry.message;\n      if (message.role === \"user\") {\n        userMessages++;\n      } else if (message.role === \"toolResult\") {\n        toolResults++;\n        if (message.usage) {\n          addUsageToTotals(usageTotals, message.usage);\n        }\n      } else if (message.role === \"assistant\") {\n        assistantMessages++;\n        const assistantMsg = message;\n        if (Array.isArray(assistantMsg.content)) {\n          toolCalls += assistantMsg.content.filter((c) => c.type === \"toolCall\").length;\n        }\n        addUsageToTotals(usageTotals, assistantMsg.usage);\n      }\n    }\n    return {\n      sessionFile: this.sessionFile,\n      sessionId: this.sessionId,\n      userMessages,\n      assistantMessages,\n      toolCalls,\n      toolResults,\n      totalMessages,\n      tokens: {\n        input: usageTotals.input,\n        output: usageTotals.output,\n        cacheRead: usageTotals.cacheRead,\n        cacheWrite: usageTotals.cacheWrite,\n        total: usageTotals.input + usageTotals.output + usageTotals.cacheRead + usageTotals.cacheWrite\n      },\n      cost: usageTotals.cost,\n      contextUsage: this.getContextUsage()\n    };\n  }\n  getContextUsage() {\n    const model = this.model;\n    if (!model)\n      return void 0;\n    const contextWindow = model.contextWindow ?? 0;\n    if (contextWindow <= 0)\n      return void 0;\n    const branchEntries = this.sessionManager.getBranch();\n    const latestCompaction = getLatestCompactionEntry(branchEntries);\n    if (latestCompaction) {\n      const compactionIndex = branchEntries.lastIndexOf(latestCompaction);\n      let hasPostCompactionUsage = false;\n      for (let i = branchEntries.length - 1; i > compactionIndex; i--) {\n        const entry = branchEntries[i];\n        if (entry.type === \"message\" && entry.message.role === \"assistant\") {\n          const assistant = entry.message;\n          if (assistant.stopReason !== \"aborted\" && assistant.stopReason !== \"error\") {\n            const contextTokens = calculateContextTokens3(assistant.usage);\n            if (contextTokens > 0) {\n              hasPostCompactionUsage = true;\n              break;\n            }\n          }\n        }\n      }\n      if (!hasPostCompactionUsage) {\n        return { tokens: null, contextWindow, percent: null };\n      }\n    }\n    const estimate = estimateContextTokens3(this.messages);\n    const percent = estimate.tokens / contextWindow * 100;\n    return {\n      tokens: estimate.tokens,\n      contextWindow,\n      percent\n    };\n  }\n  /**\n   * Export session to HTML.\n   * @param outputPath Optional output path (defaults to session directory)\n   * @param options Optional export presentation settings\n   * @returns Path to exported file\n   */\n  async exportToHtml(outputPath, options = {}) {\n    const themeName = [options.themeName, this.settingsManager.getTheme()].find((candidate) => candidate !== void 0 && getThemeByName(candidate) !== void 0);\n    const toolRenderer = createToolHtmlRenderer({\n      getToolDefinition: (name) => this.getToolDefinition(name),\n      theme,\n      cwd: this.sessionManager.getCwd()\n    });\n    return await exportSessionToHtml(this.sessionManager, this.state, {\n      outputPath,\n      themeName,\n      toolRenderer\n    });\n  }\n  /**\n   * Export the current session branch to a JSONL file.\n   * Writes the session header followed by all entries on the current branch path.\n   * @param outputPath Target file path. If omitted, generates a timestamped file in cwd.\n   * @returns The resolved output file path.\n   */\n  exportToJsonl(outputPath) {\n    const filePath = resolvePath(outputPath ?? `session-${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, \"-\")}.jsonl`, process.cwd());\n    const dir = dirname15(filePath);\n    if (!existsSync16(dir)) {\n      mkdirSync7(dir, { recursive: true });\n    }\n    const header = {\n      type: \"session\",\n      version: CURRENT_SESSION_VERSION,\n      id: this.sessionManager.getSessionId(),\n      timestamp: (/* @__PURE__ */ new Date()).toISOString(),\n      cwd: this.sessionManager.getCwd()\n    };\n    const branchEntries = this.sessionManager.getBranch();\n    const lines = [JSON.stringify(header)];\n    let prevId = null;\n    for (const entry of branchEntries) {\n      const linear = { ...entry, parentId: prevId };\n      lines.push(JSON.stringify(linear));\n      prevId = entry.id;\n    }\n    writeFileSync7(filePath, `${lines.join(\"\\n\")}\n`);\n    return filePath;\n  }\n  // =========================================================================\n  // Utilities\n  // =========================================================================\n  /**\n   * Get text content of last assistant message.\n   * Useful for /copy command.\n   * @returns Text content, or undefined if no assistant message exists\n   */\n  getLastAssistantText() {\n    const lastAssistant = this.messages.slice().reverse().find((m) => {\n      if (m.role !== \"assistant\")\n        return false;\n      const msg = m;\n      if (msg.stopReason === \"aborted\" && msg.content.length === 0)\n        return false;\n      return true;\n    });\n    if (!lastAssistant)\n      return void 0;\n    let text = \"\";\n    for (const content of lastAssistant.content) {\n      if (content.type === \"text\") {\n        text += content.text;\n      }\n    }\n    return text.trim() || void 0;\n  }\n  // =========================================================================\n  // Extension System\n  // =========================================================================\n  createReplacedSessionContext() {\n    const context = Object.defineProperties({}, Object.getOwnPropertyDescriptors(this._extensionRunner.createCommandContext()));\n    context.sendMessage = (message, options) => this.sendCustomMessage(message, options);\n    context.sendUserMessage = (content, options) => this.sendUserMessage(content, options);\n    return context;\n  }\n  /**\n   * Check if extensions have handlers for a specific event type.\n   */\n  hasExtensionHandlers(eventType) {\n    return this._extensionRunner.hasHandlers(eventType);\n  }\n  /**\n   * Get the extension runner (for setting UI context and error handlers).\n   */\n  get extensionRunner() {\n    return this._extensionRunner;\n  }\n};\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/core/sdk.js\nimport { join as join24 } from \"node:path\";\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/core/telemetry.js\nfunction isTruthyEnvFlag(value) {\n  if (!value)\n    return false;\n  return value === \"1\" || value.toLowerCase() === \"true\" || value.toLowerCase() === \"yes\";\n}\nfunction isInstallTelemetryEnabled(settingsManager, telemetryEnv = process.env.PI_TELEMETRY) {\n  return telemetryEnv !== void 0 ? isTruthyEnvFlag(telemetryEnv) : settingsManager.getEnableInstallTelemetry();\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/core/provider-attribution.js\nvar OPENROUTER_HOST = \"openrouter.ai\";\nvar NVIDIA_NIM_HOST = \"integrate.api.nvidia.com\";\nvar CLOUDFLARE_API_HOST = \"api.cloudflare.com\";\nvar CLOUDFLARE_AI_GATEWAY_HOST = \"gateway.ai.cloudflare.com\";\nvar OPENCODE_HOST = \"opencode.ai\";\nfunction matchesHost(baseUrl, expectedHost) {\n  try {\n    return new URL(baseUrl).hostname === expectedHost;\n  } catch {\n    return false;\n  }\n}\nfunction isOpenRouterModel(model) {\n  return model.provider === \"openrouter\" || model.baseUrl.includes(OPENROUTER_HOST);\n}\nfunction isNvidiaNimModel(model) {\n  return model.provider === \"nvidia\" || matchesHost(model.baseUrl, NVIDIA_NIM_HOST);\n}\nfunction isCloudflareModel(model) {\n  return model.provider === \"cloudflare-workers-ai\" || model.provider === \"cloudflare-ai-gateway\" || matchesHost(model.baseUrl, CLOUDFLARE_API_HOST) || matchesHost(model.baseUrl, CLOUDFLARE_AI_GATEWAY_HOST);\n}\nfunction getDefaultAttributionHeaders(model, settingsManager) {\n  if (!isInstallTelemetryEnabled(settingsManager)) {\n    return void 0;\n  }\n  if (isOpenRouterModel(model)) {\n    return {\n      \"HTTP-Referer\": \"https://pi.dev\",\n      \"X-OpenRouter-Title\": \"pi\",\n      \"X-OpenRouter-Categories\": \"cli-agent\"\n    };\n  }\n  if (isNvidiaNimModel(model)) {\n    return {\n      \"X-BILLING-INVOKE-ORIGIN\": \"Pi\"\n    };\n  }\n  if (isCloudflareModel(model)) {\n    return {\n      \"User-Agent\": \"pi-coding-agent\"\n    };\n  }\n  return void 0;\n}\nfunction getSessionHeaders(model, sessionId) {\n  if (!sessionId)\n    return void 0;\n  if (model.provider !== \"opencode\" && model.provider !== \"opencode-go\" && !matchesHost(model.baseUrl, OPENCODE_HOST)) {\n    return void 0;\n  }\n  return { \"x-opencode-session\": sessionId, \"x-opencode-client\": \"pi\" };\n}\nfunction mergeProviderAttributionHeaders(model, settingsManager, sessionId, ...headerSources) {\n  const merged = {\n    ...getSessionHeaders(model, sessionId),\n    ...getDefaultAttributionHeaders(model, settingsManager)\n  };\n  for (const headers of headerSources) {\n    if (headers) {\n      Object.assign(merged, headers);\n    }\n  }\n  return Object.keys(merged).length > 0 ? merged : void 0;\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/core/timings.js\nvar ENABLED = process.env.PI_TIMING === \"1\";\nvar timingNamespaces = /* @__PURE__ */ new Map();\nfunction resetTimings(namespace = \"main\") {\n  if (!ENABLED)\n    return;\n  timingNamespaces.set(namespace, { timings: [], lastTime: Date.now() });\n}\nfunction time(label, namespace = \"main\") {\n  if (!ENABLED)\n    return;\n  const now = Date.now();\n  if (!timingNamespaces.has(namespace)) {\n    resetTimings(namespace);\n  }\n  const timingNamespace = timingNamespaces.get(namespace);\n  timingNamespace.timings.push({ label, ms: now - timingNamespace.lastTime });\n  timingNamespace.lastTime = now;\n}\nfunction printTimingGroup(title, timings) {\n  const printableTimings = timings.filter((timing) => timing.ms >= 0);\n  if (printableTimings.length === 0)\n    return;\n  console.error(`\n--- ${title} ---`);\n  for (const t of printableTimings) {\n    console.error(`  ${t.label}: ${t.ms}ms`);\n  }\n  console.error(`  TOTAL: ${printableTimings.reduce((a, b) => a + b.ms, 0)}ms`);\n  console.error(`${\"-\".repeat(title.length + 8)}\n`);\n}\nfunction printTimings() {\n  if (!ENABLED)\n    return;\n  for (const [namespace, timingNamespace] of timingNamespaces) {\n    printTimingGroup(`Startup Timings: ${namespace}`, timingNamespace.timings);\n  }\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/core/sdk.js\nsetDefaultStreamFn(streamSimple10);\nfunction getDefaultAgentDir() {\n  return getAgentDir();\n}\nasync function createAgentSession(options = {}) {\n  const cwd = resolvePath(options.cwd ?? options.sessionManager?.getCwd() ?? process.cwd());\n  const agentDir = options.agentDir ? resolvePath(options.agentDir) : getDefaultAgentDir();\n  let resourceLoader = options.resourceLoader;\n  const authPath = options.agentDir ? join24(agentDir, \"auth.json\") : void 0;\n  const modelsPath = options.agentDir ? join24(agentDir, \"models.json\") : void 0;\n  const modelRuntime = options.modelRuntime ?? await ModelRuntime.create({ authPath, modelsPath });\n  const settingsManager = options.settingsManager ?? SettingsManager.create(cwd, agentDir);\n  const sessionManager = options.sessionManager ?? SessionManager.create(cwd, getDefaultSessionDir(cwd, agentDir));\n  if (!resourceLoader) {\n    resourceLoader = new DefaultResourceLoader({ cwd, agentDir, settingsManager });\n    await resourceLoader.reload();\n    time(\"resourceLoader.reload\");\n  }\n  const existingSession = sessionManager.buildSessionContext();\n  const hasExistingSession = existingSession.messages.length > 0;\n  const hasThinkingEntry = sessionManager.getBranch().some((entry) => entry.type === \"thinking_level_change\");\n  let model = options.model;\n  let modelFallbackMessage;\n  if (!model && hasExistingSession && existingSession.model) {\n    const restoredModel = modelRuntime.getModel(existingSession.model.provider, existingSession.model.modelId);\n    if (restoredModel && modelRuntime.hasConfiguredAuth(restoredModel.provider)) {\n      model = restoredModel;\n    }\n    if (!model) {\n      modelFallbackMessage = `Could not restore model ${existingSession.model.provider}/${existingSession.model.modelId}`;\n    }\n  }\n  if (!model) {\n    const result = await findInitialModel({\n      scopedModels: [],\n      isContinuing: hasExistingSession,\n      defaultProvider: settingsManager.getDefaultProvider(),\n      defaultModelId: settingsManager.getDefaultModel(),\n      defaultThinkingLevel: settingsManager.getDefaultThinkingLevel(),\n      modelRuntime\n    });\n    model = result.model;\n    if (!model) {\n      modelFallbackMessage = formatNoModelsAvailableMessage();\n    } else if (modelFallbackMessage) {\n      modelFallbackMessage += `. Using ${model.provider}/${model.id}`;\n    }\n  }\n  let thinkingLevel = options.thinkingLevel;\n  if (thinkingLevel === void 0 && hasExistingSession) {\n    thinkingLevel = hasThinkingEntry ? existingSession.thinkingLevel : settingsManager.getDefaultThinkingLevel() ?? DEFAULT_THINKING_LEVEL;\n  }\n  if (thinkingLevel === void 0) {\n    thinkingLevel = settingsManager.getDefaultThinkingLevel() ?? DEFAULT_THINKING_LEVEL;\n  }\n  if (!model) {\n    thinkingLevel = \"off\";\n  } else {\n    thinkingLevel = clampThinkingLevel(model, thinkingLevel);\n  }\n  const defaultActiveToolNames = [\"read\", \"bash\", \"edit\", \"write\"];\n  const configuredDefaultToolNames = settingsManager.getDefaultTools();\n  const allowedToolNames = options.tools ?? (options.noTools === \"all\" ? [] : void 0);\n  const excludedToolNames = options.excludeTools;\n  const excludedToolNameSet = excludedToolNames ? new Set(excludedToolNames) : void 0;\n  const initialActiveToolNames = (options.tools ?? (options.noTools ? [] : configuredDefaultToolNames ?? defaultActiveToolNames)).filter((name) => !excludedToolNameSet?.has(name));\n  let agent;\n  const convertToLlmWithBlockImages = (messages) => {\n    const converted = convertToLlm(messages);\n    if (!settingsManager.getBlockImages()) {\n      return converted;\n    }\n    return converted.map((msg) => {\n      if (msg.role === \"user\" || msg.role === \"toolResult\") {\n        const content = msg.content;\n        if (Array.isArray(content)) {\n          const hasImages = content.some((c) => c.type === \"image\");\n          if (hasImages) {\n            const filteredContent = content.map((c) => c.type === \"image\" ? { type: \"text\", text: \"Image reading is disabled.\" } : c).filter((c, i, arr) => (\n              // Dedupe consecutive \"Image reading is disabled.\" texts\n              !(c.type === \"text\" && c.text === \"Image reading is disabled.\" && i > 0 && arr[i - 1].type === \"text\" && arr[i - 1].text === \"Image reading is disabled.\")\n            ));\n            return { ...msg, content: filteredContent };\n          }\n        }\n      }\n      return msg;\n    });\n  };\n  const extensionRunnerRef = {};\n  agent = new Agent({\n    initialState: {\n      systemPrompt: \"\",\n      model,\n      thinkingLevel,\n      tools: []\n    },\n    convertToLlm: convertToLlmWithBlockImages,\n    streamFn: async (model2, context, options2) => {\n      const providerRetrySettings = settingsManager.getProviderRetrySettings();\n      const httpIdleTimeoutMs = settingsManager.getHttpIdleTimeoutMs();\n      const effectiveTimeoutMs = httpIdleTimeoutMs === 0 ? 2147483647 : httpIdleTimeoutMs;\n      const timeoutMs = options2?.timeoutMs ?? providerRetrySettings.timeoutMs ?? effectiveTimeoutMs;\n      const websocketConnectTimeoutMs = options2?.websocketConnectTimeoutMs ?? settingsManager.getWebSocketConnectTimeoutMs();\n      const headerRunner = extensionRunnerRef.current;\n      return modelRuntime.streamSimple(model2, context, {\n        ...options2,\n        timeoutMs,\n        websocketConnectTimeoutMs,\n        maxRetries: options2?.maxRetries ?? providerRetrySettings.maxRetries,\n        maxRetryDelayMs: options2?.maxRetryDelayMs ?? providerRetrySettings.maxRetryDelayMs,\n        transformHeaders: async (requestHeaders) => {\n          const headers = mergeProviderAttributionHeaders(model2, settingsManager, options2?.sessionId, requestHeaders);\n          return headerRunner?.hasHandlers(\"before_provider_headers\") ? headerRunner.emitBeforeProviderHeaders(headers ?? {}) : headers ?? {};\n        }\n      });\n    },\n    onPayload: async (payload, _model) => {\n      const runner = extensionRunnerRef.current;\n      if (!runner?.hasHandlers(\"before_provider_request\")) {\n        return payload;\n      }\n      return runner.emitBeforeProviderRequest(payload);\n    },\n    onResponse: async (response, _model) => {\n      const runner = extensionRunnerRef.current;\n      if (!runner?.hasHandlers(\"after_provider_response\")) {\n        return;\n      }\n      await runner.emit({\n        type: \"after_provider_response\",\n        status: response.status,\n        headers: response.headers\n      });\n    },\n    sessionId: sessionManager.getSessionId(),\n    transformContext: async (messages) => {\n      const runner = extensionRunnerRef.current;\n      if (!runner)\n        return messages;\n      return runner.emitContext(messages);\n    },\n    steeringMode: settingsManager.getSteeringMode(),\n    followUpMode: settingsManager.getFollowUpMode(),\n    transport: settingsManager.getTransport(),\n    thinkingBudgets: settingsManager.getThinkingBudgets(),\n    maxRetryDelayMs: settingsManager.getProviderRetrySettings().maxRetryDelayMs\n  });\n  if (hasExistingSession) {\n    agent.state.messages = existingSession.messages;\n    if (!hasThinkingEntry) {\n      sessionManager.appendThinkingLevelChange(thinkingLevel);\n    }\n  } else {\n    if (model) {\n      sessionManager.appendModelChange(model.provider, model.id);\n    }\n    sessionManager.appendThinkingLevelChange(thinkingLevel);\n  }\n  const session = new AgentSession({\n    agent,\n    sessionManager,\n    settingsManager,\n    cwd,\n    scopedModels: options.scopedModels,\n    resourceLoader,\n    customTools: options.customTools,\n    modelRuntime,\n    initialActiveToolNames,\n    allowedToolNames,\n    excludedToolNames,\n    extensionRunnerRef,\n    sessionStartEvent: options.sessionStartEvent\n  });\n  const extensionsResult = resourceLoader.getExtensions();\n  return {\n    session,\n    extensionsResult,\n    modelFallbackMessage\n  };\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/core/trust-manager.js\nimport { existsSync as existsSync17, mkdirSync as mkdirSync8, readFileSync as readFileSync12, writeFileSync as writeFileSync8 } from \"node:fs\";\nimport { homedir as homedir9 } from \"node:os\";\nimport { dirname as dirname16, join as join25 } from \"node:path\";\nimport lockfile3 from \"proper-lockfile\";\nvar TRUST_REQUIRING_PROJECT_CONFIG_RESOURCES = [\n  \"settings.json\",\n  \"extensions\",\n  \"skills\",\n  \"prompts\",\n  \"themes\",\n  \"SYSTEM.md\",\n  \"APPEND_SYSTEM.md\"\n];\nfunction normalizeCwd(cwd) {\n  return canonicalizePath(resolvePath(cwd));\n}\nfunction findNearestTrustEntry(data, cwd) {\n  let currentDir = normalizeCwd(cwd);\n  while (true) {\n    const value = data[currentDir];\n    if (value === true || value === false) {\n      return { path: currentDir, decision: value };\n    }\n    const parentDir = dirname16(currentDir);\n    if (parentDir === currentDir) {\n      return null;\n    }\n    currentDir = parentDir;\n  }\n}\nfunction getProjectTrustParentPath(cwd) {\n  const trustPath = normalizeCwd(cwd);\n  const parentDir = dirname16(trustPath);\n  return parentDir === trustPath ? void 0 : parentDir;\n}\nfunction getProjectTrustOptions(cwd, options) {\n  const trustPath = normalizeCwd(cwd);\n  const trustOptions = [\n    { label: \"Trust\", trusted: true, updates: [{ path: trustPath, decision: true }], savedPath: trustPath }\n  ];\n  const parentPath = getProjectTrustParentPath(cwd);\n  if (parentPath !== void 0) {\n    trustOptions.push({\n      label: `Trust parent folder (${parentPath})`,\n      trusted: true,\n      updates: [\n        { path: parentPath, decision: true },\n        { path: trustPath, decision: null }\n      ],\n      savedPath: parentPath\n    });\n  }\n  if (options?.includeSessionOnly) {\n    trustOptions.push({ label: \"Trust (this session only)\", trusted: true, updates: [] });\n  }\n  trustOptions.push({\n    label: \"Do not trust\",\n    trusted: false,\n    updates: [{ path: trustPath, decision: false }],\n    savedPath: trustPath\n  });\n  if (options?.includeSessionOnly) {\n    trustOptions.push({ label: \"Do not trust (this session only)\", trusted: false, updates: [] });\n  }\n  return trustOptions;\n}\nfunction readTrustFile(path12) {\n  if (!existsSync17(path12)) {\n    return {};\n  }\n  let parsed;\n  try {\n    parsed = JSON.parse(readFileSync12(path12, \"utf-8\"));\n  } catch (error) {\n    const message = error instanceof Error ? error.message : String(error);\n    throw new Error(`Failed to read trust store ${path12}: ${message}`);\n  }\n  if (typeof parsed !== \"object\" || parsed === null || Array.isArray(parsed)) {\n    throw new Error(`Invalid trust store ${path12}: expected an object`);\n  }\n  const data = {};\n  for (const [key, value] of Object.entries(parsed)) {\n    if (value !== true && value !== false && value !== null) {\n      throw new Error(`Invalid trust store ${path12}: value for ${JSON.stringify(key)} must be true, false, or null`);\n    }\n    data[key] = value;\n  }\n  return data;\n}\nfunction writeTrustFile(path12, data) {\n  const sorted = {};\n  for (const key of Object.keys(data).sort()) {\n    const value = data[key];\n    if (value === true || value === false || value === null) {\n      sorted[key] = value;\n    }\n  }\n  mkdirSync8(dirname16(path12), { recursive: true });\n  writeFileSync8(path12, `${JSON.stringify(sorted, null, 2)}\n`, \"utf-8\");\n}\nfunction acquireTrustLockSync(path12) {\n  const trustDir = dirname16(path12);\n  mkdirSync8(trustDir, { recursive: true });\n  const maxAttempts = 10;\n  const delayMs = 20;\n  let lastError;\n  for (let attempt = 1; attempt <= maxAttempts; attempt++) {\n    try {\n      return lockfile3.lockSync(trustDir, { realpath: false, lockfilePath: `${path12}.lock` });\n    } catch (error) {\n      const code = typeof error === \"object\" && error !== null && \"code\" in error ? String(error.code) : void 0;\n      if (code !== \"ELOCKED\" || attempt === maxAttempts) {\n        throw error;\n      }\n      lastError = error;\n      const start = Date.now();\n      while (Date.now() - start < delayMs) {\n      }\n    }\n  }\n  if (lastError instanceof Error) {\n    throw lastError;\n  }\n  throw new Error(\"Failed to acquire trust store lock\");\n}\nfunction withTrustFileLock(path12, fn) {\n  const release = acquireTrustLockSync(path12);\n  try {\n    return fn();\n  } finally {\n    release();\n  }\n}\nfunction hasTrustRequiringProjectResources(cwd) {\n  const homeDir = canonicalizePath(resolvePath(process.env.HOME || homedir9()));\n  const userAgentsSkillsDir = join25(homeDir, \".agents\", \"skills\");\n  let currentDir = canonicalizePath(resolvePath(cwd));\n  const configDir = join25(currentDir, CONFIG_DIR_NAME);\n  if (TRUST_REQUIRING_PROJECT_CONFIG_RESOURCES.some((entry) => existsSync17(join25(configDir, entry)))) {\n    return true;\n  }\n  while (true) {\n    const agentsSkillsDir = join25(currentDir, \".agents\", \"skills\");\n    if (agentsSkillsDir !== userAgentsSkillsDir && existsSync17(agentsSkillsDir)) {\n      return true;\n    }\n    const parentDir = dirname16(currentDir);\n    if (parentDir === currentDir) {\n      return false;\n    }\n    currentDir = parentDir;\n  }\n}\nvar ProjectTrustStore = class {\n  trustPath;\n  constructor(agentDir) {\n    this.trustPath = join25(resolvePath(agentDir), \"trust.json\");\n  }\n  get(cwd) {\n    return this.getEntry(cwd)?.decision ?? null;\n  }\n  getEntry(cwd) {\n    return withTrustFileLock(this.trustPath, () => {\n      const data = readTrustFile(this.trustPath);\n      return findNearestTrustEntry(data, cwd);\n    });\n  }\n  set(cwd, decision) {\n    this.setMany([{ path: cwd, decision }]);\n  }\n  setMany(decisions) {\n    withTrustFileLock(this.trustPath, () => {\n      const data = readTrustFile(this.trustPath);\n      for (const { path: path12, decision } of decisions) {\n        const key = normalizeCwd(path12);\n        if (decision === null) {\n          delete data[key];\n        } else {\n          data[key] = decision;\n        }\n      }\n      writeTrustFile(this.trustPath, data);\n    });\n  }\n};\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/interactive-mode.js\nimport * as crypto from \"node:crypto\";\nimport * as fs6 from \"node:fs\";\nimport * as os4 from \"node:os\";\nimport * as path10 from \"node:path\";\nimport chalk7 from \"chalk\";\nimport { spawn as spawn9, spawnSync as spawnSync7 } from \"child_process\";\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/core/cache-stats.js\nvar CACHE_TTL_MS = 5 * 60 * 1e3;\nvar NOISE_FLOOR_TOKENS = 1024;\nfunction detectMiss(prev, message, models) {\n  const usage = message.usage;\n  const promptTokens = usage.input + usage.cacheRead + usage.cacheWrite;\n  if (!prev || promptTokens <= 0 || usage.cacheRead + usage.cacheWrite === 0 && !prev.reportedCache) {\n    return void 0;\n  }\n  const missedTokens = Math.min(prev.promptTokens, promptTokens) - usage.cacheRead;\n  if (missedTokens <= NOISE_FLOOR_TOKENS)\n    return void 0;\n  const paidTokens = usage.input + usage.cacheWrite;\n  const paidPerToken = paidTokens > 0 ? (usage.cost.input + usage.cost.cacheWrite) / paidTokens : 0;\n  const readPerToken = usage.cacheRead > 0 ? usage.cost.cacheRead / usage.cacheRead : (models.getModel(message.provider, message.model)?.cost.cacheRead ?? 0) / 1e6;\n  return {\n    missedTokens,\n    missedCost: missedTokens * Math.max(0, paidPerToken - readPerToken),\n    idleMs: Math.max(0, message.timestamp - prev.timestamp),\n    modelChanged: `${message.provider}/${message.model}` !== prev.modelKey\n  };\n}\nfunction asPreviousRequest(message, reportedCache) {\n  const usage = message.usage;\n  const promptTokens = usage.input + usage.cacheRead + usage.cacheWrite;\n  if (promptTokens <= 0)\n    return void 0;\n  return {\n    promptTokens,\n    modelKey: `${message.provider}/${message.model}`,\n    timestamp: message.timestamp,\n    reportedCache: reportedCache || usage.cacheRead + usage.cacheWrite > 0\n  };\n}\nfunction scan(entries, models) {\n  let prev;\n  const totals = { missedTokens: 0, missedCost: 0, missCount: 0 };\n  const misses = /* @__PURE__ */ new Map();\n  for (const entry of entries) {\n    if (entry.type === \"compaction\" || entry.type === \"branch_summary\") {\n      prev = void 0;\n      continue;\n    }\n    if (entry.type === \"message\" && entry.message.role === \"assistant\") {\n      const miss = detectMiss(prev, entry.message, models);\n      if (miss) {\n        totals.missedTokens += miss.missedTokens;\n        totals.missedCost += miss.missedCost;\n        totals.missCount += 1;\n        misses.set(entry.message, miss);\n      }\n      prev = asPreviousRequest(entry.message, prev?.reportedCache ?? false) ?? prev;\n    }\n  }\n  return { prev, totals, misses };\n}\nfunction computeCacheWaste(entries, models) {\n  return scan(entries, models).totals;\n}\nfunction collectCacheMisses(entries, models) {\n  return scan(entries, models).misses;\n}\nfunction detectCacheMiss(entries, message, models) {\n  return detectMiss(scan(entries, models).prev, message, models);\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/core/footer-data-provider.js\nimport { execFile, spawnSync as spawnSync5 } from \"child_process\";\nimport { existsSync as existsSync18, readFileSync as readFileSync13, statSync as statSync8, unwatchFile, watchFile } from \"fs\";\nimport { dirname as dirname17, join as join26, resolve as resolve8 } from \"path\";\nfunction findGitPaths(cwd) {\n  let dir = cwd;\n  while (true) {\n    const gitPath = join26(dir, \".git\");\n    if (existsSync18(gitPath)) {\n      try {\n        const stat3 = statSync8(gitPath);\n        if (stat3.isFile()) {\n          const content = readFileSync13(gitPath, \"utf8\").trim();\n          if (content.startsWith(\"gitdir: \")) {\n            const gitDir = resolve8(dir, content.slice(8).trim());\n            const headPath = join26(gitDir, \"HEAD\");\n            if (!existsSync18(headPath))\n              return null;\n            const commonDirPath = join26(gitDir, \"commondir\");\n            const commonGitDir = existsSync18(commonDirPath) ? resolve8(gitDir, readFileSync13(commonDirPath, \"utf8\").trim()) : gitDir;\n            return { repoDir: dir, commonGitDir, headPath };\n          }\n        } else if (stat3.isDirectory()) {\n          const headPath = join26(gitPath, \"HEAD\");\n          if (!existsSync18(headPath))\n            return null;\n          return { repoDir: dir, commonGitDir: gitPath, headPath };\n        }\n      } catch {\n        return null;\n      }\n    }\n    const parent = dirname17(dir);\n    if (parent === dir)\n      return null;\n    dir = parent;\n  }\n}\nfunction resolveBranchWithGitSync(repoDir) {\n  const result = spawnSync5(\"git\", [\"--no-optional-locks\", \"symbolic-ref\", \"--quiet\", \"--short\", \"HEAD\"], {\n    cwd: repoDir,\n    encoding: \"utf8\",\n    stdio: [\"ignore\", \"pipe\", \"ignore\"]\n  });\n  const branch = result.status === 0 ? result.stdout.trim() : \"\";\n  return branch || null;\n}\nfunction resolveBranchWithGitAsync(repoDir) {\n  return new Promise((resolvePromise) => {\n    execFile(\"git\", [\"--no-optional-locks\", \"symbolic-ref\", \"--quiet\", \"--short\", \"HEAD\"], {\n      cwd: repoDir,\n      encoding: \"utf8\"\n    }, (error, stdout) => {\n      if (error) {\n        resolvePromise(null);\n        return;\n      }\n      const branch = stdout.trim();\n      resolvePromise(branch || null);\n    });\n  });\n}\nfunction isWslEnvironment() {\n  return process.platform === \"linux\" && !!(process.env.WSL_DISTRO_NAME || process.env.WSL_INTEROP);\n}\nfunction isWindowsMountedRepoPath(repoDir) {\n  return /^\\/mnt\\/[a-z](?:\\/|$)/i.test(repoDir);\n}\nfunction shouldPollGitHead(repoDir) {\n  return isWslEnvironment() && isWindowsMountedRepoPath(repoDir);\n}\nvar FooterDataProvider = class _FooterDataProvider {\n  cwd;\n  static WATCH_DEBOUNCE_MS = 500;\n  extensionStatuses = /* @__PURE__ */ new Map();\n  cachedBranch = void 0;\n  gitPaths = void 0;\n  headWatcher = null;\n  headWatchFilePath = null;\n  headWatchFileListener = null;\n  reftableWatcher = null;\n  reftableTablesListWatcher = null;\n  reftableTablesListPath = null;\n  branchChangeCallbacks = /* @__PURE__ */ new Set();\n  availableProviderCount = 0;\n  refreshTimer = null;\n  gitWatcherRetryTimer = null;\n  refreshInFlight = false;\n  refreshPending = false;\n  disposed = false;\n  constructor(cwd) {\n    this.cwd = cwd;\n    this.gitPaths = findGitPaths(cwd);\n    this.setupGitWatcher();\n  }\n  /** Current git branch, null if not in repo, \"detached\" if detached HEAD */\n  getGitBranch() {\n    if (this.cachedBranch === void 0) {\n      this.cachedBranch = this.resolveGitBranchSync();\n    }\n    return this.cachedBranch;\n  }\n  /** Extension status texts set via ctx.ui.setStatus() */\n  getExtensionStatuses() {\n    return this.extensionStatuses;\n  }\n  /** Subscribe to git branch changes. Returns unsubscribe function. */\n  onBranchChange(callback) {\n    this.branchChangeCallbacks.add(callback);\n    return () => this.branchChangeCallbacks.delete(callback);\n  }\n  /** Internal: set extension status */\n  setExtensionStatus(key, text) {\n    if (text === void 0) {\n      this.extensionStatuses.delete(key);\n    } else {\n      this.extensionStatuses.set(key, text);\n    }\n  }\n  /** Internal: clear extension statuses */\n  clearExtensionStatuses() {\n    this.extensionStatuses.clear();\n  }\n  /** Number of unique providers with available models (for footer display) */\n  getAvailableProviderCount() {\n    return this.availableProviderCount;\n  }\n  /** Internal: update available provider count */\n  setAvailableProviderCount(count) {\n    this.availableProviderCount = count;\n  }\n  setCwd(cwd) {\n    if (this.cwd === cwd) {\n      return;\n    }\n    this.cwd = cwd;\n    if (this.refreshTimer) {\n      clearTimeout(this.refreshTimer);\n      this.refreshTimer = null;\n    }\n    this.clearGitWatchers();\n    this.cachedBranch = void 0;\n    this.gitPaths = findGitPaths(cwd);\n    this.setupGitWatcher();\n    this.notifyBranchChange();\n  }\n  /** Internal: cleanup */\n  dispose() {\n    this.disposed = true;\n    if (this.refreshTimer) {\n      clearTimeout(this.refreshTimer);\n      this.refreshTimer = null;\n    }\n    this.clearGitWatchers();\n    this.branchChangeCallbacks.clear();\n  }\n  notifyBranchChange() {\n    for (const cb of this.branchChangeCallbacks)\n      cb();\n  }\n  scheduleRefresh() {\n    if (this.disposed || this.refreshTimer)\n      return;\n    if (this.refreshInFlight) {\n      this.refreshPending = true;\n      return;\n    }\n    this.refreshTimer = setTimeout(() => {\n      this.refreshTimer = null;\n      void this.refreshGitBranchAsync();\n    }, _FooterDataProvider.WATCH_DEBOUNCE_MS);\n  }\n  async refreshGitBranchAsync() {\n    if (this.disposed)\n      return;\n    if (this.refreshInFlight) {\n      this.refreshPending = true;\n      return;\n    }\n    this.refreshInFlight = true;\n    try {\n      const nextBranch = await this.resolveGitBranchAsync();\n      if (this.disposed)\n        return;\n      if (this.cachedBranch !== void 0 && this.cachedBranch !== nextBranch) {\n        this.cachedBranch = nextBranch;\n        this.notifyBranchChange();\n        return;\n      }\n      this.cachedBranch = nextBranch;\n    } finally {\n      this.refreshInFlight = false;\n      if (this.refreshPending && !this.disposed) {\n        this.refreshPending = false;\n        this.scheduleRefresh();\n      }\n    }\n  }\n  resolveGitBranchSync() {\n    try {\n      if (!this.gitPaths)\n        return null;\n      const content = readFileSync13(this.gitPaths.headPath, \"utf8\").trim();\n      if (content.startsWith(\"ref: refs/heads/\")) {\n        const branch = content.slice(16);\n        return branch === \".invalid\" ? resolveBranchWithGitSync(this.gitPaths.repoDir) ?? \"detached\" : branch;\n      }\n      return \"detached\";\n    } catch {\n      return null;\n    }\n  }\n  async resolveGitBranchAsync() {\n    try {\n      if (!this.gitPaths)\n        return null;\n      const content = readFileSync13(this.gitPaths.headPath, \"utf8\").trim();\n      if (content.startsWith(\"ref: refs/heads/\")) {\n        const branch = content.slice(16);\n        return branch === \".invalid\" ? await resolveBranchWithGitAsync(this.gitPaths.repoDir) ?? \"detached\" : branch;\n      }\n      return \"detached\";\n    } catch {\n      return null;\n    }\n  }\n  clearGitWatchers() {\n    closeWatcher(this.headWatcher);\n    this.headWatcher = null;\n    if (this.headWatchFilePath && this.headWatchFileListener) {\n      unwatchFile(this.headWatchFilePath, this.headWatchFileListener);\n      this.headWatchFilePath = null;\n      this.headWatchFileListener = null;\n    }\n    closeWatcher(this.reftableWatcher);\n    this.reftableWatcher = null;\n    closeWatcher(this.reftableTablesListWatcher);\n    this.reftableTablesListWatcher = null;\n    if (this.reftableTablesListPath) {\n      unwatchFile(this.reftableTablesListPath);\n      this.reftableTablesListPath = null;\n    }\n    if (this.gitWatcherRetryTimer) {\n      clearTimeout(this.gitWatcherRetryTimer);\n      this.gitWatcherRetryTimer = null;\n    }\n  }\n  scheduleGitWatcherRetry() {\n    if (this.disposed || this.gitWatcherRetryTimer) {\n      return;\n    }\n    this.gitWatcherRetryTimer = setTimeout(() => {\n      this.gitWatcherRetryTimer = null;\n      this.setupGitWatcher();\n    }, FS_WATCH_RETRY_DELAY_MS);\n  }\n  handleGitWatcherError() {\n    this.clearGitWatchers();\n    this.scheduleGitWatcherRetry();\n  }\n  setupGitWatcher() {\n    this.clearGitWatchers();\n    if (!this.gitPaths)\n      return;\n    const pollGitHead = shouldPollGitHead(this.gitPaths.repoDir);\n    this.headWatcher = watchWithErrorHandler(dirname17(this.gitPaths.headPath), (_eventType, filename) => {\n      if (!filename || filename === \"HEAD\") {\n        this.scheduleRefresh();\n      }\n    }, () => this.handleGitWatcherError());\n    if (pollGitHead) {\n      this.headWatchFilePath = this.gitPaths.headPath;\n      this.headWatchFileListener = (current, previous) => {\n        if (current.mtimeMs !== previous.mtimeMs || current.ctimeMs !== previous.ctimeMs || current.size !== previous.size) {\n          this.scheduleRefresh();\n        }\n      };\n      watchFile(this.headWatchFilePath, { interval: 1e3 }, this.headWatchFileListener);\n    }\n    if (!this.headWatcher && !pollGitHead) {\n      return;\n    }\n    const reftableDir = join26(this.gitPaths.commonGitDir, \"reftable\");\n    if (existsSync18(reftableDir)) {\n      this.reftableWatcher = watchWithErrorHandler(reftableDir, () => {\n        this.scheduleRefresh();\n      }, () => this.handleGitWatcherError());\n      if (!this.reftableWatcher) {\n        return;\n      }\n      const tablesListPath = join26(reftableDir, \"tables.list\");\n      if (existsSync18(tablesListPath)) {\n        this.reftableTablesListPath = tablesListPath;\n        this.reftableTablesListWatcher = watchWithErrorHandler(tablesListPath, () => {\n          this.scheduleRefresh();\n        }, () => this.handleGitWatcherError());\n        if (!this.reftableTablesListWatcher) {\n          return;\n        }\n        watchFile(tablesListPath, { interval: 250 }, (current, previous) => {\n          if (current.mtimeMs !== previous.mtimeMs || current.ctimeMs !== previous.ctimeMs || current.size !== previous.size) {\n            this.scheduleRefresh();\n          }\n        });\n      }\n    }\n  }\n};\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/core/slash-commands.js\nvar BUILTIN_SLASH_COMMANDS = [\n  { name: \"settings\", description: \"Open settings menu\" },\n  { name: \"model\", description: \"Select model (opens selector UI)\", argumentHint: \"<provider/model>\" },\n  { name: \"scoped-models\", description: \"Enable/disable models for Ctrl+P cycling\" },\n  { name: \"export\", description: \"Export session (HTML default, or specify path: .html/.jsonl)\" },\n  { name: \"import\", description: \"Import and resume a session from a JSONL file\" },\n  { name: \"share\", description: \"Share session as a secret GitHub gist\" },\n  { name: \"copy\", description: \"Copy last agent message to clipboard\" },\n  { name: \"name\", description: \"Set session display name\" },\n  { name: \"session\", description: \"Show session info and stats\" },\n  { name: \"changelog\", description: \"Show changelog entries\" },\n  { name: \"hotkeys\", description: \"Show all keyboard shortcuts\" },\n  { name: \"fork\", description: \"Create a new fork from a previous user message\" },\n  { name: \"clone\", description: \"Duplicate the current session at the current position\" },\n  { name: \"tree\", description: \"Navigate session tree (switch branches)\" },\n  { name: \"trust\", description: \"Save project trust decision for future sessions\" },\n  { name: \"login\", description: \"Configure provider authentication\", argumentHint: \"<provider>\" },\n  { name: \"logout\", description: \"Remove provider authentication\" },\n  { name: \"new\", description: \"Start a new session\" },\n  { name: \"compact\", description: \"Manually compact the session context\" },\n  { name: \"resume\", description: \"Resume a different session\" },\n  { name: \"reload\", description: \"Reload keybindings, extensions, skills, prompts, themes, and context files\" },\n  { name: \"quit\", description: `Quit ${APP_NAME}` }\n];\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/utils/changelog.js\nimport path9 from \"node:path\";\nimport { existsSync as existsSync19, readFileSync as readFileSync14 } from \"fs\";\nvar GITHUB_REPO = \"earendil-works/pi\";\nvar CHANGELOG_LINK_BASE_PATH = \"packages/coding-agent\";\nvar LEGACY_REPO_RE = /^https:\\/\\/github\\.com\\/(?:badlogic|earendil-works)\\/pi-mono(?=\\/|$)/;\nvar URL_SCHEME_RE = /^[a-z][a-z0-9+.-]*:/i;\nvar INLINE_MARKDOWN_LINK_RE = /(!?\\[[^\\]\\n]+\\]\\()([^\\s)]+)((?:\\s+[^)]*)?\\))/g;\nfunction entryVersion(entry) {\n  return `${entry.major}.${entry.minor}.${entry.patch}`;\n}\nfunction normalizeTag(version) {\n  const versionString = typeof version === \"string\" ? version : entryVersion(version);\n  return versionString.startsWith(\"v\") ? versionString : `v${versionString}`;\n}\nfunction splitLocalTarget(target) {\n  const hashIndex = target.indexOf(\"#\");\n  const beforeHash = hashIndex === -1 ? target : target.slice(0, hashIndex);\n  const fragment = hashIndex === -1 ? \"\" : target.slice(hashIndex);\n  const queryIndex = beforeHash.indexOf(\"?\");\n  if (queryIndex === -1) {\n    return { fragment, pathPart: beforeHash, query: \"\" };\n  }\n  return {\n    fragment,\n    pathPart: beforeHash.slice(0, queryIndex),\n    query: beforeHash.slice(queryIndex)\n  };\n}\nfunction normalizePathPart(value) {\n  return value.replaceAll(\"\\\\\", \"/\");\n}\nfunction resolveRepositoryPath(targetPath) {\n  const normalizedTarget = normalizePathPart(targetPath);\n  const joined = normalizedTarget.startsWith(\"/\") ? path9.posix.normalize(normalizedTarget.replace(/^\\/+/, \"\")) : path9.posix.normalize(path9.posix.join(CHANGELOG_LINK_BASE_PATH, normalizedTarget));\n  if (joined === \".\" || joined.startsWith(\"../\") || joined === \"..\") {\n    return void 0;\n  }\n  return joined;\n}\nfunction isDirectoryTarget(originalPath, repositoryPath) {\n  if (originalPath.endsWith(\"/\")) {\n    return true;\n  }\n  const basename14 = path9.posix.basename(repositoryPath);\n  return !basename14.includes(\".\");\n}\nfunction normalizeChangelogLinkTarget(target, tag) {\n  let canonicalTarget = target.replace(LEGACY_REPO_RE, `https://github.com/${GITHUB_REPO}`);\n  const repoUrl = `https://github.com/${GITHUB_REPO}`;\n  for (const route2 of [\"blob\", \"tree\"]) {\n    for (const branch of [\"main\", \"master\"]) {\n      const floatingRefPrefix = `${repoUrl}/${route2}/${branch}/`;\n      if (canonicalTarget.startsWith(floatingRefPrefix)) {\n        canonicalTarget = `${repoUrl}/${route2}/${tag}/${canonicalTarget.slice(floatingRefPrefix.length)}`;\n      }\n    }\n  }\n  if (canonicalTarget.startsWith(\"#\") || canonicalTarget.startsWith(\"//\") || URL_SCHEME_RE.test(canonicalTarget)) {\n    return canonicalTarget;\n  }\n  const { fragment, pathPart, query } = splitLocalTarget(canonicalTarget);\n  if (!pathPart) {\n    return canonicalTarget;\n  }\n  const repositoryPath = resolveRepositoryPath(pathPart);\n  if (!repositoryPath) {\n    return canonicalTarget;\n  }\n  const route = isDirectoryTarget(pathPart, repositoryPath) ? \"tree\" : \"blob\";\n  return `https://github.com/${GITHUB_REPO}/${route}/${tag}/${encodeURI(repositoryPath)}${query}${fragment}`;\n}\nfunction normalizeChangelogLinks(markdown, version) {\n  const tag = normalizeTag(version);\n  return markdown.replace(INLINE_MARKDOWN_LINK_RE, (_match, prefix, target, suffix) => {\n    return `${prefix}${normalizeChangelogLinkTarget(target, tag)}${suffix}`;\n  });\n}\nfunction parseChangelog(changelogPath) {\n  if (!existsSync19(changelogPath)) {\n    return [];\n  }\n  try {\n    const content = readFileSync14(changelogPath, \"utf-8\");\n    const lines = content.split(\"\\n\");\n    const entries = [];\n    let currentLines = [];\n    let currentVersion = null;\n    for (const line of lines) {\n      if (line.startsWith(\"## \")) {\n        if (currentVersion && currentLines.length > 0) {\n          entries.push({\n            ...currentVersion,\n            content: currentLines.join(\"\\n\").trim()\n          });\n        }\n        const versionMatch = line.match(/##\\s+\\[?(\\d+)\\.(\\d+)\\.(\\d+)\\]?/);\n        if (versionMatch) {\n          currentVersion = {\n            major: Number.parseInt(versionMatch[1], 10),\n            minor: Number.parseInt(versionMatch[2], 10),\n            patch: Number.parseInt(versionMatch[3], 10)\n          };\n          currentLines = [line];\n        } else {\n          currentVersion = null;\n          currentLines = [];\n        }\n      } else if (currentVersion) {\n        currentLines.push(line);\n      }\n    }\n    if (currentVersion && currentLines.length > 0) {\n      entries.push({\n        ...currentVersion,\n        content: currentLines.join(\"\\n\").trim()\n      });\n    }\n    return entries;\n  } catch (error) {\n    console.error(`Warning: Could not parse changelog: ${error}`);\n    return [];\n  }\n}\nfunction compareVersions(v1, v2) {\n  if (v1.major !== v2.major)\n    return v1.major - v2.major;\n  if (v1.minor !== v2.minor)\n    return v1.minor - v2.minor;\n  return v1.patch - v2.patch;\n}\nfunction getNewEntries(entries, lastVersion) {\n  const parts = lastVersion.split(\".\").map(Number);\n  const last = {\n    major: parts[0] || 0,\n    minor: parts[1] || 0,\n    patch: parts[2] || 0,\n    content: \"\"\n  };\n  return entries.filter((entry) => compareVersions(entry, last) > 0);\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/utils/clipboard.js\nimport { execFileSync, execSync as execSync3, spawn as spawn6 } from \"child_process\";\nimport { platform as platform2 } from \"os\";\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/utils/clipboard-image.js\nimport { spawnSync as spawnSync6 } from \"child_process\";\nimport { randomUUID as randomUUID3 } from \"crypto\";\nimport { readFileSync as readFileSync15, unlinkSync } from \"fs\";\nimport { tmpdir as tmpdir3 } from \"os\";\nimport { join as join28 } from \"path\";\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/utils/clipboard-native.js\nimport { createRequire as createRequire4 } from \"module\";\nimport { dirname as dirname18, join as join27 } from \"path\";\nimport { pathToFileURL as pathToFileURL3 } from \"url\";\nvar moduleRequire = createRequire4(import.meta.url);\nvar executableDirRequire = createRequire4(pathToFileURL3(join27(dirname18(process.execPath), \"package.json\")).href);\nvar hasDisplay = process.platform !== \"linux\" || Boolean(process.env.DISPLAY || process.env.WAYLAND_DISPLAY);\nfunction loadClipboardNative(requires = [moduleRequire, executableDirRequire]) {\n  for (const requireClipboard of requires) {\n    try {\n      return requireClipboard(\"@mariozechner/clipboard\");\n    } catch {\n    }\n  }\n  return null;\n}\nvar clipboard = !process.env.TERMUX_VERSION && hasDisplay ? loadClipboardNative() : null;\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/utils/clipboard-image.js\nvar SUPPORTED_IMAGE_MIME_TYPES = [\"image/png\", \"image/jpeg\", \"image/webp\", \"image/gif\"];\nvar DEFAULT_LIST_TIMEOUT_MS = 1e3;\nvar DEFAULT_READ_TIMEOUT_MS = 3e3;\nvar DEFAULT_POWERSHELL_TIMEOUT_MS = 5e3;\nvar DEFAULT_MAX_BUFFER_BYTES = 50 * 1024 * 1024;\nfunction isWaylandSession(env = process.env) {\n  return Boolean(env.WAYLAND_DISPLAY) || env.XDG_SESSION_TYPE === \"wayland\";\n}\nfunction baseMimeType2(mimeType) {\n  return mimeType.split(\";\")[0]?.trim().toLowerCase() ?? mimeType.toLowerCase();\n}\nfunction extensionForImageMimeType(mimeType) {\n  switch (baseMimeType2(mimeType)) {\n    case \"image/png\":\n      return \"png\";\n    case \"image/jpeg\":\n      return \"jpg\";\n    case \"image/webp\":\n      return \"webp\";\n    case \"image/gif\":\n      return \"gif\";\n    default:\n      return null;\n  }\n}\nfunction selectPreferredImageMimeType(mimeTypes) {\n  const normalized = mimeTypes.map((t) => t.trim()).filter(Boolean).map((t) => ({ raw: t, base: baseMimeType2(t) }));\n  for (const preferred of SUPPORTED_IMAGE_MIME_TYPES) {\n    const match = normalized.find((t) => t.base === preferred);\n    if (match) {\n      return match.raw;\n    }\n  }\n  const anyImage = normalized.find((t) => t.base.startsWith(\"image/\"));\n  return anyImage?.raw ?? null;\n}\nfunction isSupportedImageMimeType(mimeType) {\n  const base = baseMimeType2(mimeType);\n  return SUPPORTED_IMAGE_MIME_TYPES.some((t) => t === base);\n}\nasync function convertToPng2(bytes) {\n  const photon = await loadPhoton();\n  if (!photon) {\n    return null;\n  }\n  try {\n    const image = photon.PhotonImage.new_from_byteslice(bytes);\n    try {\n      return image.get_bytes();\n    } finally {\n      image.free();\n    }\n  } catch {\n    return null;\n  }\n}\nfunction runCommand(command, args, options) {\n  const timeoutMs = options?.timeoutMs ?? DEFAULT_READ_TIMEOUT_MS;\n  const maxBufferBytes = options?.maxBufferBytes ?? DEFAULT_MAX_BUFFER_BYTES;\n  const result = spawnSync6(command, args, {\n    timeout: timeoutMs,\n    maxBuffer: maxBufferBytes,\n    env: options?.env\n  });\n  if (result.error) {\n    return { ok: false, stdout: Buffer.alloc(0) };\n  }\n  if (result.status !== 0) {\n    return { ok: false, stdout: Buffer.alloc(0) };\n  }\n  const stdout = Buffer.isBuffer(result.stdout) ? result.stdout : Buffer.from(result.stdout ?? \"\", typeof result.stdout === \"string\" ? \"utf-8\" : void 0);\n  return { ok: true, stdout };\n}\nfunction readClipboardImageViaWlPaste() {\n  const list = runCommand(\"wl-paste\", [\"--list-types\"], { timeoutMs: DEFAULT_LIST_TIMEOUT_MS });\n  if (!list.ok) {\n    return null;\n  }\n  const types = list.stdout.toString(\"utf-8\").split(/\\r?\\n/).map((t) => t.trim()).filter(Boolean);\n  const selectedType = selectPreferredImageMimeType(types);\n  if (!selectedType) {\n    return null;\n  }\n  const data = runCommand(\"wl-paste\", [\"--type\", selectedType, \"--no-newline\"]);\n  if (!data.ok || data.stdout.length === 0) {\n    return null;\n  }\n  return { bytes: data.stdout, mimeType: baseMimeType2(selectedType) };\n}\nfunction isWSL(env = process.env) {\n  if (env.WSL_DISTRO_NAME || env.WSLENV) {\n    return true;\n  }\n  try {\n    const release = readFileSync15(\"/proc/version\", \"utf-8\");\n    return /microsoft|wsl/i.test(release);\n  } catch {\n    return false;\n  }\n}\nfunction readClipboardImageViaPowerShell() {\n  const tmpFile = join28(tmpdir3(), `pi-wsl-clip-${randomUUID3()}.png`);\n  try {\n    const winPathResult = runCommand(\"wslpath\", [\"-w\", tmpFile], { timeoutMs: DEFAULT_LIST_TIMEOUT_MS });\n    if (!winPathResult.ok) {\n      return null;\n    }\n    const winPath = winPathResult.stdout.toString(\"utf-8\").trim();\n    if (!winPath) {\n      return null;\n    }\n    const psQuotedWinPath = winPath.replaceAll(\"'\", \"''\");\n    const psScript = [\n      \"Add-Type -AssemblyName System.Windows.Forms\",\n      \"Add-Type -AssemblyName System.Drawing\",\n      `$path = '${psQuotedWinPath}'`,\n      \"$img = [System.Windows.Forms.Clipboard]::GetImage()\",\n      \"if ($img) { $img.Save($path, [System.Drawing.Imaging.ImageFormat]::Png); Write-Output 'ok' } else { Write-Output 'empty' }\"\n    ].join(\"; \");\n    const result = runCommand(\"powershell.exe\", [\"-NoProfile\", \"-Command\", psScript], {\n      timeoutMs: DEFAULT_POWERSHELL_TIMEOUT_MS\n    });\n    if (!result.ok) {\n      return null;\n    }\n    const output = result.stdout.toString(\"utf-8\").trim();\n    if (output !== \"ok\") {\n      return null;\n    }\n    const bytes = readFileSync15(tmpFile);\n    if (bytes.length === 0) {\n      return null;\n    }\n    return { bytes: new Uint8Array(bytes), mimeType: \"image/png\" };\n  } catch {\n    return null;\n  } finally {\n    try {\n      unlinkSync(tmpFile);\n    } catch {\n    }\n  }\n}\nfunction readClipboardImageViaXclip() {\n  const targets = runCommand(\"xclip\", [\"-selection\", \"clipboard\", \"-t\", \"TARGETS\", \"-o\"], {\n    timeoutMs: DEFAULT_LIST_TIMEOUT_MS\n  });\n  let candidateTypes = [];\n  if (targets.ok) {\n    candidateTypes = targets.stdout.toString(\"utf-8\").split(/\\r?\\n/).map((t) => t.trim()).filter(Boolean);\n  }\n  const preferred = candidateTypes.length > 0 ? selectPreferredImageMimeType(candidateTypes) : null;\n  const tryTypes = preferred ? [preferred, ...SUPPORTED_IMAGE_MIME_TYPES] : [...SUPPORTED_IMAGE_MIME_TYPES];\n  for (const mimeType of tryTypes) {\n    const data = runCommand(\"xclip\", [\"-selection\", \"clipboard\", \"-t\", mimeType, \"-o\"]);\n    if (data.ok && data.stdout.length > 0) {\n      return { bytes: data.stdout, mimeType: baseMimeType2(mimeType) };\n    }\n  }\n  return null;\n}\nasync function readClipboardImageViaNativeClipboard() {\n  if (!clipboard || !clipboard.hasImage()) {\n    return null;\n  }\n  const imageData = await clipboard.getImageBinary();\n  if (!imageData || imageData.length === 0) {\n    return null;\n  }\n  const bytes = imageData instanceof Uint8Array ? imageData : Uint8Array.from(imageData);\n  return { bytes, mimeType: \"image/png\" };\n}\nasync function readClipboardImage(options) {\n  const env = options?.env ?? process.env;\n  const platform3 = options?.platform ?? process.platform;\n  if (env.TERMUX_VERSION) {\n    return null;\n  }\n  let image = null;\n  if (platform3 === \"linux\") {\n    const wsl = isWSL(env);\n    const wayland = isWaylandSession(env);\n    if (wayland || wsl) {\n      image = readClipboardImageViaWlPaste() ?? readClipboardImageViaXclip();\n    }\n    if (!image && wsl) {\n      image = readClipboardImageViaPowerShell();\n    }\n    if (!image && !wayland) {\n      image = await readClipboardImageViaNativeClipboard() ?? readClipboardImageViaXclip();\n    }\n  } else {\n    image = await readClipboardImageViaNativeClipboard();\n  }\n  if (!image) {\n    return null;\n  }\n  if (!isSupportedImageMimeType(image.mimeType)) {\n    const pngBytes = await convertToPng2(image.bytes);\n    if (!pngBytes) {\n      return null;\n    }\n    return { bytes: pngBytes, mimeType: \"image/png\" };\n  }\n  return image;\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/utils/clipboard.js\nfunction copyToX11Clipboard(options) {\n  try {\n    execSync3(\"xclip -selection clipboard\", options);\n  } catch {\n    execSync3(\"xsel --clipboard --input\", options);\n  }\n}\nvar MAX_OSC52_ENCODED_LENGTH = 1e5;\nfunction isRemoteSession(env = process.env) {\n  return Boolean(env.SSH_CONNECTION || env.SSH_CLIENT || env.MOSH_CONNECTION);\n}\nfunction emitOsc52(text) {\n  const encoded = Buffer.from(text).toString(\"base64\");\n  if (encoded.length > MAX_OSC52_ENCODED_LENGTH) {\n    return false;\n  }\n  process.stdout.write(`\\x1B]52;c;${encoded}\\x07`);\n  return true;\n}\nvar READ_CLIPBOARD_OPTIONS = {\n  encoding: \"utf8\",\n  maxBuffer: 50 * 1024 * 1024,\n  timeout: 5e3\n};\nfunction readWaylandClipboardText() {\n  try {\n    const text = execFileSync(\"wl-paste\", [\"--no-newline\", \"--type\", \"text\"], READ_CLIPBOARD_OPTIONS);\n    return { ok: true, text: text || null };\n  } catch {\n    return { ok: false };\n  }\n}\nasync function readClipboardText() {\n  if (platform2() === \"linux\" && isWaylandSession() && process.env.WAYLAND_DISPLAY) {\n    const result = readWaylandClipboardText();\n    if (result.ok) {\n      return result.text;\n    }\n  }\n  if (!clipboard) {\n    return null;\n  }\n  try {\n    const text = await clipboard.getText();\n    return text || null;\n  } catch {\n    return null;\n  }\n}\nasync function copyToClipboard(text) {\n  let copied = false;\n  const p = platform2();\n  try {\n    if (clipboard && p !== \"linux\") {\n      await clipboard.setText(text);\n      copied = true;\n    }\n  } catch {\n  }\n  const remote = isRemoteSession();\n  if (copied && !remote) {\n    return;\n  }\n  const options = { input: text, timeout: 5e3, stdio: [\"pipe\", \"ignore\", \"ignore\"] };\n  if (!copied) {\n    try {\n      if (p === \"darwin\") {\n        execSync3(\"pbcopy\", options);\n        copied = true;\n      } else if (p === \"win32\") {\n        execSync3(\"clip\", options);\n        copied = true;\n      } else {\n        if (process.env.TERMUX_VERSION) {\n          try {\n            execSync3(\"termux-clipboard-set\", options);\n            copied = true;\n          } catch {\n          }\n        }\n        if (!copied) {\n          const hasWaylandDisplay = Boolean(process.env.WAYLAND_DISPLAY);\n          const hasX11Display = Boolean(process.env.DISPLAY);\n          const isWayland = isWaylandSession();\n          if (isWayland && hasWaylandDisplay) {\n            try {\n              execSync3(\"which wl-copy\", { stdio: \"ignore\" });\n              const wlCopyExit = await new Promise((resolve15) => {\n                const proc = spawn6(\"wl-copy\", [], { stdio: [\"pipe\", \"ignore\", \"ignore\"] });\n                proc.on(\"error\", () => resolve15(1));\n                proc.on(\"close\", (code) => resolve15(code ?? 1));\n                proc.stdin.on(\"error\", () => {\n                });\n                proc.stdin.write(text);\n                proc.stdin.end();\n              });\n              if (wlCopyExit === 0) {\n                copied = true;\n              } else if (hasX11Display) {\n                copyToX11Clipboard(options);\n                copied = true;\n              }\n            } catch {\n              if (hasX11Display) {\n                copyToX11Clipboard(options);\n                copied = true;\n              }\n            }\n          } else if (hasX11Display) {\n            copyToX11Clipboard(options);\n            copied = true;\n          }\n        }\n      }\n    } catch {\n    }\n  }\n  if (remote || !copied) {\n    const osc52Copied = emitOsc52(text);\n    copied = copied || osc52Copied;\n  }\n  if (!copied) {\n    throw new Error(\"Failed to copy to clipboard\");\n  }\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/utils/open-browser.js\nimport { spawn as spawn7 } from \"node:child_process\";\nfunction openBrowser(target) {\n  const [cmd, args] = process.platform === \"darwin\" ? [\"open\", [target]] : process.platform === \"win32\" ? [\"rundll32\", [\"url.dll,FileProtocolHandler\", target]] : [\"xdg-open\", [target]];\n  spawn7(cmd, args, { stdio: \"ignore\", detached: true }).on(\"error\", () => {\n  }).unref();\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/utils/version-check.js\nimport { compare, valid as valid2 } from \"semver\";\nvar LATEST_VERSION_URL = \"https://pi.dev/api/latest-version\";\nvar DEFAULT_VERSION_CHECK_TIMEOUT_MS = 1e4;\nfunction formatVersionCheckError(error) {\n  const rootMessage = error instanceof Error && error.message ? error.message : String(error);\n  const cause = error instanceof Error ? error.cause : void 0;\n  const causes = cause instanceof AggregateError ? cause.errors : cause === void 0 ? [] : [cause];\n  const codes = causes.map((value) => typeof value === \"object\" && value !== null && \"code\" in value && typeof value.code === \"string\" ? value.code : void 0).filter((code) => code !== void 0);\n  if (codes.length > 0)\n    return `${rootMessage} (${[...new Set(codes)].join(\", \")})`;\n  const causeMessage = causes.find((value) => value instanceof Error && Boolean(value.message))?.message;\n  return causeMessage ? `${rootMessage} (cause: ${causeMessage})` : rootMessage;\n}\nfunction comparePackageVersions(leftVersion, rightVersion) {\n  const left = valid2(leftVersion.trim());\n  const right = valid2(rightVersion.trim());\n  if (!left || !right) {\n    return void 0;\n  }\n  return compare(left, right);\n}\nfunction isNewerPackageVersion(candidateVersion, currentVersion) {\n  const comparison = comparePackageVersions(candidateVersion, currentVersion);\n  if (comparison !== void 0) {\n    return comparison > 0;\n  }\n  return candidateVersion.trim() !== currentVersion.trim();\n}\nasync function getLatestPiRelease(currentVersion, options = {}) {\n  if (process.env.PI_OFFLINE)\n    return void 0;\n  const response = await fetchWithRetry(LATEST_VERSION_URL, {\n    headers: {\n      \"User-Agent\": getPiUserAgent2(currentVersion),\n      accept: \"application/json\"\n    }\n  }, {\n    maxRetries: options.retry ? 2 : 0,\n    timeoutMs: options.timeoutMs ?? DEFAULT_VERSION_CHECK_TIMEOUT_MS\n  });\n  if (!response.ok)\n    return void 0;\n  const data = await response.json();\n  if (typeof data.version !== \"string\" || !data.version.trim()) {\n    return void 0;\n  }\n  const packageName = typeof data.packageName === \"string\" && data.packageName.trim() ? data.packageName.trim() : void 0;\n  const note = typeof data.note === \"string\" && data.note.trim() ? data.note.trim() : void 0;\n  return {\n    version: data.version.trim(),\n    packageName,\n    ...note ? { note } : {}\n  };\n}\nasync function checkForNewPiVersion(currentVersion) {\n  if (process.env.PI_SKIP_VERSION_CHECK)\n    return void 0;\n  try {\n    const latestRelease = await getLatestPiRelease(currentVersion);\n    if (latestRelease && isNewerPackageVersion(latestRelease.version, currentVersion)) {\n      return latestRelease;\n    }\n    return void 0;\n  } catch {\n    return void 0;\n  }\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/armin.js\nvar WIDTH = 31;\nvar HEIGHT = 36;\nvar BITS = [\n  255,\n  255,\n  255,\n  127,\n  255,\n  240,\n  255,\n  127,\n  255,\n  237,\n  255,\n  127,\n  255,\n  219,\n  255,\n  127,\n  255,\n  183,\n  255,\n  127,\n  255,\n  119,\n  254,\n  127,\n  63,\n  248,\n  254,\n  127,\n  223,\n  255,\n  254,\n  127,\n  223,\n  63,\n  252,\n  127,\n  159,\n  195,\n  251,\n  127,\n  111,\n  252,\n  244,\n  127,\n  247,\n  15,\n  247,\n  127,\n  247,\n  255,\n  247,\n  127,\n  247,\n  255,\n  227,\n  127,\n  247,\n  7,\n  232,\n  127,\n  239,\n  248,\n  103,\n  112,\n  15,\n  255,\n  187,\n  111,\n  241,\n  0,\n  208,\n  91,\n  253,\n  63,\n  236,\n  83,\n  193,\n  255,\n  239,\n  87,\n  159,\n  253,\n  238,\n  95,\n  159,\n  252,\n  174,\n  95,\n  31,\n  120,\n  172,\n  95,\n  63,\n  0,\n  80,\n  108,\n  127,\n  0,\n  220,\n  119,\n  255,\n  192,\n  63,\n  120,\n  255,\n  1,\n  248,\n  127,\n  255,\n  3,\n  156,\n  120,\n  255,\n  7,\n  140,\n  124,\n  255,\n  15,\n  206,\n  120,\n  255,\n  255,\n  207,\n  127,\n  255,\n  255,\n  207,\n  120,\n  255,\n  255,\n  223,\n  120,\n  255,\n  255,\n  223,\n  125,\n  255,\n  255,\n  63,\n  126,\n  255,\n  255,\n  255,\n  127\n];\nvar BYTES_PER_ROW = Math.ceil(WIDTH / 8);\nvar DISPLAY_HEIGHT = Math.ceil(HEIGHT / 2);\nvar EFFECTS = [\"typewriter\", \"scanline\", \"rain\", \"fade\", \"crt\", \"glitch\", \"dissolve\"];\nfunction getPixel(x, y) {\n  if (y >= HEIGHT)\n    return false;\n  const byteIndex = y * BYTES_PER_ROW + Math.floor(x / 8);\n  const bitIndex = x % 8;\n  return (BITS[byteIndex] >> bitIndex & 1) === 0;\n}\nfunction getChar(x, row) {\n  const upper = getPixel(x, row * 2);\n  const lower = getPixel(x, row * 2 + 1);\n  if (upper && lower)\n    return \"\\u2588\";\n  if (upper)\n    return \"\\u2580\";\n  if (lower)\n    return \"\\u2584\";\n  return \" \";\n}\nfunction buildFinalGrid() {\n  const grid = [];\n  for (let row = 0; row < DISPLAY_HEIGHT; row++) {\n    const line = [];\n    for (let x = 0; x < WIDTH; x++) {\n      line.push(getChar(x, row));\n    }\n    grid.push(line);\n  }\n  return grid;\n}\nvar ArminComponent = class {\n  ui;\n  interval = null;\n  effect;\n  finalGrid;\n  currentGrid;\n  effectState = {};\n  cachedLines = [];\n  cachedWidth = 0;\n  gridVersion = 0;\n  cachedVersion = -1;\n  constructor(ui) {\n    this.ui = ui;\n    this.effect = EFFECTS[Math.floor(Math.random() * EFFECTS.length)];\n    this.finalGrid = buildFinalGrid();\n    this.currentGrid = this.createEmptyGrid();\n    this.initEffect();\n    this.startAnimation();\n  }\n  invalidate() {\n    this.cachedWidth = 0;\n  }\n  render(width) {\n    if (width === this.cachedWidth && this.cachedVersion === this.gridVersion) {\n      return this.cachedLines;\n    }\n    const padding = 1;\n    const availableWidth = width - padding;\n    this.cachedLines = this.currentGrid.map((row) => {\n      const clipped = row.slice(0, availableWidth).join(\"\");\n      const padRight = Math.max(0, width - padding - clipped.length);\n      return ` ${theme.fg(\"accent\", clipped)}${\" \".repeat(padRight)}`;\n    });\n    const message = \"ARMIN SAYS HI\";\n    const msgPadRight = Math.max(0, width - padding - message.length);\n    this.cachedLines.push(` ${theme.fg(\"accent\", message)}${\" \".repeat(msgPadRight)}`);\n    this.cachedWidth = width;\n    this.cachedVersion = this.gridVersion;\n    return this.cachedLines;\n  }\n  createEmptyGrid() {\n    return Array.from({ length: DISPLAY_HEIGHT }, () => Array(WIDTH).fill(\" \"));\n  }\n  initEffect() {\n    switch (this.effect) {\n      case \"typewriter\":\n        this.effectState = { pos: 0 };\n        break;\n      case \"scanline\":\n        this.effectState = { row: 0 };\n        break;\n      case \"rain\":\n        this.effectState = {\n          drops: Array.from({ length: WIDTH }, () => ({\n            y: -Math.floor(Math.random() * DISPLAY_HEIGHT * 2),\n            settled: 0\n          }))\n        };\n        break;\n      case \"fade\": {\n        const positions = [];\n        for (let row = 0; row < DISPLAY_HEIGHT; row++) {\n          for (let x = 0; x < WIDTH; x++) {\n            positions.push([row, x]);\n          }\n        }\n        for (let i = positions.length - 1; i > 0; i--) {\n          const j = Math.floor(Math.random() * (i + 1));\n          [positions[i], positions[j]] = [positions[j], positions[i]];\n        }\n        this.effectState = { positions, idx: 0 };\n        break;\n      }\n      case \"crt\":\n        this.effectState = { expansion: 0 };\n        break;\n      case \"glitch\":\n        this.effectState = { phase: 0, glitchFrames: 8 };\n        break;\n      case \"dissolve\": {\n        this.currentGrid = Array.from({ length: DISPLAY_HEIGHT }, () => Array.from({ length: WIDTH }, () => {\n          const chars = [\" \", \"\\u2591\", \"\\u2592\", \"\\u2593\", \"\\u2588\", \"\\u2580\", \"\\u2584\"];\n          return chars[Math.floor(Math.random() * chars.length)];\n        }));\n        const dissolvePositions = [];\n        for (let row = 0; row < DISPLAY_HEIGHT; row++) {\n          for (let x = 0; x < WIDTH; x++) {\n            dissolvePositions.push([row, x]);\n          }\n        }\n        for (let i = dissolvePositions.length - 1; i > 0; i--) {\n          const j = Math.floor(Math.random() * (i + 1));\n          [dissolvePositions[i], dissolvePositions[j]] = [dissolvePositions[j], dissolvePositions[i]];\n        }\n        this.effectState = { positions: dissolvePositions, idx: 0 };\n        break;\n      }\n    }\n  }\n  startAnimation() {\n    const fps = this.effect === \"glitch\" ? 60 : 30;\n    this.interval = setInterval(() => {\n      const done = this.tickEffect();\n      this.updateDisplay();\n      this.ui.requestRender();\n      if (done) {\n        this.stopAnimation();\n      }\n    }, 1e3 / fps);\n  }\n  stopAnimation() {\n    if (this.interval) {\n      clearInterval(this.interval);\n      this.interval = null;\n    }\n  }\n  tickEffect() {\n    switch (this.effect) {\n      case \"typewriter\":\n        return this.tickTypewriter();\n      case \"scanline\":\n        return this.tickScanline();\n      case \"rain\":\n        return this.tickRain();\n      case \"fade\":\n        return this.tickFade();\n      case \"crt\":\n        return this.tickCrt();\n      case \"glitch\":\n        return this.tickGlitch();\n      case \"dissolve\":\n        return this.tickDissolve();\n      default:\n        return true;\n    }\n  }\n  tickTypewriter() {\n    const state = this.effectState;\n    const pixelsPerFrame = 3;\n    for (let i = 0; i < pixelsPerFrame; i++) {\n      const row = Math.floor(state.pos / WIDTH);\n      const x = state.pos % WIDTH;\n      if (row >= DISPLAY_HEIGHT)\n        return true;\n      this.currentGrid[row][x] = this.finalGrid[row][x];\n      state.pos++;\n    }\n    return false;\n  }\n  tickScanline() {\n    const state = this.effectState;\n    if (state.row >= DISPLAY_HEIGHT)\n      return true;\n    for (let x = 0; x < WIDTH; x++) {\n      this.currentGrid[state.row][x] = this.finalGrid[state.row][x];\n    }\n    state.row++;\n    return false;\n  }\n  tickRain() {\n    const state = this.effectState;\n    let allSettled = true;\n    this.currentGrid = this.createEmptyGrid();\n    for (let x = 0; x < WIDTH; x++) {\n      const drop = state.drops[x];\n      for (let row = DISPLAY_HEIGHT - 1; row >= DISPLAY_HEIGHT - drop.settled; row--) {\n        if (row >= 0) {\n          this.currentGrid[row][x] = this.finalGrid[row][x];\n        }\n      }\n      if (drop.settled >= DISPLAY_HEIGHT)\n        continue;\n      allSettled = false;\n      let targetRow = -1;\n      for (let row = DISPLAY_HEIGHT - 1 - drop.settled; row >= 0; row--) {\n        if (this.finalGrid[row][x] !== \" \") {\n          targetRow = row;\n          break;\n        }\n      }\n      drop.y++;\n      if (drop.y >= 0 && drop.y < DISPLAY_HEIGHT) {\n        if (targetRow >= 0 && drop.y >= targetRow) {\n          drop.settled = DISPLAY_HEIGHT - targetRow;\n          drop.y = -Math.floor(Math.random() * 5) - 1;\n        } else {\n          this.currentGrid[drop.y][x] = \"\\u2593\";\n        }\n      }\n    }\n    return allSettled;\n  }\n  tickFade() {\n    const state = this.effectState;\n    const pixelsPerFrame = 15;\n    for (let i = 0; i < pixelsPerFrame; i++) {\n      if (state.idx >= state.positions.length)\n        return true;\n      const [row, x] = state.positions[state.idx];\n      this.currentGrid[row][x] = this.finalGrid[row][x];\n      state.idx++;\n    }\n    return false;\n  }\n  tickCrt() {\n    const state = this.effectState;\n    const midRow = Math.floor(DISPLAY_HEIGHT / 2);\n    this.currentGrid = this.createEmptyGrid();\n    const top = midRow - state.expansion;\n    const bottom = midRow + state.expansion;\n    for (let row = Math.max(0, top); row <= Math.min(DISPLAY_HEIGHT - 1, bottom); row++) {\n      for (let x = 0; x < WIDTH; x++) {\n        this.currentGrid[row][x] = this.finalGrid[row][x];\n      }\n    }\n    state.expansion++;\n    return state.expansion > DISPLAY_HEIGHT;\n  }\n  tickGlitch() {\n    const state = this.effectState;\n    if (state.phase < state.glitchFrames) {\n      this.currentGrid = this.finalGrid.map((row) => {\n        const offset = Math.floor(Math.random() * 7) - 3;\n        const glitchRow = [...row];\n        if (Math.random() < 0.3) {\n          const shifted = glitchRow.slice(offset).concat(glitchRow.slice(0, offset));\n          return shifted.slice(0, WIDTH);\n        }\n        if (Math.random() < 0.2) {\n          const swapRow = Math.floor(Math.random() * DISPLAY_HEIGHT);\n          return [...this.finalGrid[swapRow]];\n        }\n        return glitchRow;\n      });\n      state.phase++;\n      return false;\n    }\n    this.currentGrid = this.finalGrid.map((row) => [...row]);\n    return true;\n  }\n  tickDissolve() {\n    const state = this.effectState;\n    const pixelsPerFrame = 20;\n    for (let i = 0; i < pixelsPerFrame; i++) {\n      if (state.idx >= state.positions.length)\n        return true;\n      const [row, x] = state.positions[state.idx];\n      this.currentGrid[row][x] = this.finalGrid[row][x];\n      state.idx++;\n    }\n    return false;\n  }\n  updateDisplay() {\n    this.gridVersion++;\n  }\n  dispose() {\n    this.stopAnimation();\n  }\n};\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/markdown-transform.js\nfunction createMarkdownTransform(messageType, isStreaming, transformers) {\n  return (markdown, availableWidth) => applyMarkdownTransformers(markdown, { messageType, isStreaming, availableWidth }, transformers);\n}\nfunction applyMarkdownTransformers(markdown, context, transformers) {\n  let transformedMarkdown = markdown;\n  for (const transformer of transformers) {\n    try {\n      const transformed = transformer(transformedMarkdown, context);\n      if (typeof transformed === \"string\") {\n        transformedMarkdown = transformed;\n      }\n    } catch {\n    }\n  }\n  return transformedMarkdown;\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/assistant-message.js\nvar OSC133_ZONE_START = \"\\x1B]133;A\\x07\";\nvar OSC133_ZONE_END = \"\\x1B]133;B\\x07\";\nvar OSC133_ZONE_FINAL = \"\\x1B]133;C\\x07\";\nvar AssistantMessageComponent = class extends Container {\n  contentContainer;\n  hideThinkingBlock;\n  markdownTheme;\n  hiddenThinkingLabel;\n  outputPad;\n  markdownTransformers;\n  lastMessage;\n  hasToolCalls = false;\n  isStreaming = false;\n  constructor(message, hideThinkingBlock = false, markdownTheme = getMarkdownTheme(), hiddenThinkingLabel = \"Thinking...\", outputPad = 1, markdownTransformers = []) {\n    super();\n    this.hideThinkingBlock = hideThinkingBlock;\n    this.markdownTheme = markdownTheme;\n    this.hiddenThinkingLabel = hiddenThinkingLabel;\n    this.outputPad = outputPad;\n    this.markdownTransformers = markdownTransformers;\n    this.contentContainer = new Container();\n    this.addChild(this.contentContainer);\n    if (message) {\n      this.updateContent(message);\n    }\n  }\n  invalidate() {\n    super.invalidate();\n    if (this.lastMessage) {\n      this.updateContent(this.lastMessage);\n    }\n  }\n  setHideThinkingBlock(hide) {\n    this.hideThinkingBlock = hide;\n    if (this.lastMessage) {\n      this.updateContent(this.lastMessage);\n    }\n  }\n  setHiddenThinkingLabel(label) {\n    this.hiddenThinkingLabel = label;\n    if (this.lastMessage) {\n      this.updateContent(this.lastMessage);\n    }\n  }\n  setOutputPad(padding) {\n    this.outputPad = padding;\n    if (this.lastMessage) {\n      this.updateContent(this.lastMessage);\n    }\n  }\n  render(width) {\n    const lines = super.render(width);\n    if (this.hasToolCalls || lines.length === 0) {\n      return lines;\n    }\n    lines[0] = OSC133_ZONE_START + lines[0];\n    lines[lines.length - 1] = OSC133_ZONE_END + OSC133_ZONE_FINAL + lines[lines.length - 1];\n    return lines;\n  }\n  updateContent(message, isStreaming = this.isStreaming) {\n    this.lastMessage = message;\n    this.isStreaming = isStreaming;\n    this.contentContainer.clear();\n    const hasVisibleContent = message.content.some((c) => c.type === \"text\" && c.text.trim() || c.type === \"thinking\" && c.thinking.trim());\n    if (hasVisibleContent) {\n      this.contentContainer.addChild(new Spacer(1));\n    }\n    for (let i = 0; i < message.content.length; i++) {\n      const content = message.content[i];\n      if (content.type === \"text\" && content.text.trim()) {\n        this.contentContainer.addChild(new Markdown(content.text.trim(), this.outputPad, 0, this.markdownTheme, void 0, {\n          transform: createMarkdownTransform(\"assistant\", this.isStreaming, this.markdownTransformers)\n        }));\n      } else if (content.type === \"thinking\") {\n        const thinkingBlocks = [];\n        for (; i < message.content.length; i++) {\n          const thinkingContent = message.content[i];\n          if (thinkingContent.type !== \"thinking\") {\n            break;\n          }\n          const thinking = thinkingContent.thinking.trim();\n          if (thinking) {\n            thinkingBlocks.push(thinking);\n          }\n        }\n        i--;\n        if (thinkingBlocks.length === 0) {\n          continue;\n        }\n        const hasVisibleContentAfter = message.content.slice(i + 1).some((c) => c.type === \"text\" && c.text.trim() || c.type === \"thinking\" && c.thinking.trim());\n        if (this.hideThinkingBlock) {\n          this.contentContainer.addChild(new Text(theme.italic(theme.fg(\"thinkingText\", this.hiddenThinkingLabel)), this.outputPad, 0));\n        } else {\n          this.contentContainer.addChild(new Markdown(thinkingBlocks.join(\"\\n\\n\"), this.outputPad, 0, this.markdownTheme, {\n            color: (text) => theme.fg(\"thinkingText\", text),\n            italic: true\n          }, {\n            transform: createMarkdownTransform(\"assistant-thinking\", this.isStreaming, this.markdownTransformers)\n          }));\n        }\n        if (hasVisibleContentAfter) {\n          this.contentContainer.addChild(new Spacer(1));\n        }\n      }\n    }\n    const hasToolCalls = message.content.some((c) => c.type === \"toolCall\");\n    this.hasToolCalls = hasToolCalls;\n    if (message.stopReason === \"length\") {\n      this.contentContainer.addChild(new Spacer(1));\n      this.contentContainer.addChild(new Text(theme.fg(\"error\", \"Response was truncated before completion.\"), this.outputPad, 0));\n    } else if (!hasToolCalls) {\n      if (message.stopReason === \"aborted\") {\n        const abortMessage = message.errorMessage && message.errorMessage !== \"Request was aborted\" ? message.errorMessage : \"Operation aborted\";\n        this.contentContainer.addChild(new Spacer(1));\n        this.contentContainer.addChild(new Text(theme.fg(\"error\", abortMessage), this.outputPad, 0));\n      } else if (message.stopReason === \"error\") {\n        const errorMsg = message.errorMessage || \"Unknown error\";\n        this.contentContainer.addChild(new Spacer(1));\n        this.contentContainer.addChild(new Text(theme.fg(\"error\", `Error: ${errorMsg}`), this.outputPad, 0));\n      }\n    }\n  }\n};\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/bash-execution.js\nvar PREVIEW_LINES = 20;\nvar BashExecutionComponent = class extends Container {\n  command;\n  outputLines = [];\n  status = \"running\";\n  exitCode = void 0;\n  loader;\n  truncationResult;\n  fullOutputPath;\n  expanded = false;\n  contentContainer;\n  constructor(command, ui, excludeFromContext = false) {\n    super();\n    this.command = command;\n    const colorKey = excludeFromContext ? \"dim\" : \"bashMode\";\n    const borderColor = (str2) => theme.fg(colorKey, str2);\n    this.addChild(new Spacer(1));\n    this.addChild(new DynamicBorder(borderColor));\n    this.contentContainer = new Container();\n    this.addChild(this.contentContainer);\n    const header = new Text(theme.fg(colorKey, theme.bold(`$ ${command}`)), 1, 0);\n    this.contentContainer.addChild(header);\n    this.loader = new Loader(ui, (spinner) => theme.fg(colorKey, spinner), (text) => theme.fg(\"muted\", text), `Running... (${keyText(\"tui.select.cancel\")} to cancel)`);\n    this.contentContainer.addChild(this.loader);\n    this.addChild(new DynamicBorder(borderColor));\n  }\n  /**\n   * Set whether the output is expanded (shows full output) or collapsed (preview only).\n   */\n  setExpanded(expanded) {\n    this.expanded = expanded;\n    this.updateDisplay();\n  }\n  invalidate() {\n    super.invalidate();\n    this.updateDisplay();\n  }\n  appendOutput(chunk) {\n    const clean = stripAnsi(chunk).replace(/\\r\\n/g, \"\\n\").replace(/\\r/g, \"\\n\");\n    const newLines = clean.split(\"\\n\");\n    if (this.outputLines.length > 0 && newLines.length > 0) {\n      this.outputLines[this.outputLines.length - 1] += newLines[0];\n      this.outputLines.push(...newLines.slice(1));\n    } else {\n      this.outputLines.push(...newLines);\n    }\n    this.updateDisplay();\n  }\n  setComplete(exitCode, cancelled, truncationResult, fullOutputPath) {\n    this.exitCode = exitCode;\n    this.status = cancelled ? \"cancelled\" : exitCode !== 0 && exitCode !== void 0 && exitCode !== null ? \"error\" : \"complete\";\n    this.truncationResult = truncationResult;\n    this.fullOutputPath = fullOutputPath;\n    this.loader.stop();\n    this.updateDisplay();\n  }\n  updateDisplay() {\n    const fullOutput = this.outputLines.join(\"\\n\");\n    const contextTruncation = truncateTail2(fullOutput, {\n      maxLines: DEFAULT_MAX_LINES2,\n      maxBytes: DEFAULT_MAX_BYTES3\n    });\n    const availableLines = contextTruncation.content ? contextTruncation.content.split(\"\\n\") : [];\n    const previewLogicalLines = availableLines.slice(-PREVIEW_LINES);\n    const hiddenLineCount = availableLines.length - previewLogicalLines.length;\n    this.contentContainer.clear();\n    const header = new Text(theme.fg(\"bashMode\", theme.bold(`$ ${this.command}`)), 1, 0);\n    this.contentContainer.addChild(header);\n    if (availableLines.length > 0) {\n      if (this.expanded) {\n        const displayText = availableLines.map((line) => theme.fg(\"muted\", line)).join(\"\\n\");\n        this.contentContainer.addChild(new Text(`\n${displayText}`, 1, 0));\n      } else {\n        const styledOutput = previewLogicalLines.map((line) => theme.fg(\"muted\", line)).join(\"\\n\");\n        const styledInput = `\n${styledOutput}`;\n        let cachedWidth;\n        let cachedLines;\n        this.contentContainer.addChild({\n          render: (width) => {\n            if (cachedLines === void 0 || cachedWidth !== width) {\n              const result = truncateToVisualLines(styledInput, PREVIEW_LINES, width, 1);\n              cachedLines = result.visualLines;\n              cachedWidth = width;\n            }\n            return cachedLines ?? [];\n          },\n          invalidate: () => {\n            cachedWidth = void 0;\n            cachedLines = void 0;\n          }\n        });\n      }\n    }\n    if (this.status === \"running\") {\n      this.contentContainer.addChild(this.loader);\n    } else {\n      const statusParts = [];\n      if (hiddenLineCount > 0) {\n        if (this.expanded) {\n          statusParts.push(`${theme.fg(\"muted\", \"(\")}${keyHint(\"app.tools.expand\", \"to collapse\")}${theme.fg(\"muted\", \")\")}`);\n        } else {\n          statusParts.push(`${theme.fg(\"muted\", `... ${hiddenLineCount} more lines (`)}${keyHint(\"app.tools.expand\", \"to expand\")}${theme.fg(\"muted\", \")\")}`);\n        }\n      }\n      if (this.status === \"cancelled\") {\n        statusParts.push(theme.fg(\"warning\", \"(cancelled)\"));\n      } else if (this.status === \"error\") {\n        statusParts.push(theme.fg(\"error\", `(exit ${this.exitCode})`));\n      }\n      const wasTruncated = this.truncationResult?.truncated || contextTruncation.truncated;\n      if (wasTruncated && this.fullOutputPath) {\n        statusParts.push(theme.fg(\"warning\", `Output truncated. Full output: ${this.fullOutputPath}`));\n      }\n      if (statusParts.length > 0) {\n        this.contentContainer.addChild(new Text(`\n${statusParts.join(\"\\n\")}`, 1, 0));\n      }\n    }\n  }\n  /**\n   * Get the raw output for creating BashExecutionMessage.\n   */\n  getOutput() {\n    return this.outputLines.join(\"\\n\");\n  }\n  /**\n   * Get the command that was executed.\n   */\n  getCommand() {\n    return this.command;\n  }\n};\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/bordered-loader.js\nvar BorderedLoader = class extends Container {\n  loader;\n  cancellable;\n  signalController;\n  constructor(tui, theme2, message, options) {\n    super();\n    this.cancellable = options?.cancellable ?? true;\n    const borderColor = (s) => theme2.fg(\"border\", s);\n    this.addChild(new DynamicBorder(borderColor));\n    if (this.cancellable) {\n      this.loader = new CancellableLoader(tui, (s) => theme2.fg(\"accent\", s), (s) => theme2.fg(\"muted\", s), message);\n    } else {\n      this.signalController = new AbortController();\n      this.loader = new Loader(tui, (s) => theme2.fg(\"accent\", s), (s) => theme2.fg(\"muted\", s), message);\n    }\n    this.addChild(this.loader);\n    if (this.cancellable) {\n      this.addChild(new Spacer(1));\n      this.addChild(new Text(keyHint(\"tui.select.cancel\", \"cancel\"), 1, 0));\n    }\n    this.addChild(new Spacer(1));\n    this.addChild(new DynamicBorder(borderColor));\n  }\n  get signal() {\n    if (this.cancellable) {\n      return this.loader.signal;\n    }\n    return this.signalController?.signal ?? new AbortController().signal;\n  }\n  set onAbort(fn) {\n    if (this.cancellable) {\n      this.loader.onAbort = fn;\n    }\n  }\n  handleInput(data) {\n    if (this.cancellable) {\n      this.loader.handleInput(data);\n    }\n  }\n  dispose() {\n    if (\"dispose\" in this.loader && typeof this.loader.dispose === \"function\") {\n      this.loader.dispose();\n    } else if (\"stop\" in this.loader && typeof this.loader.stop === \"function\") {\n      this.loader.stop();\n    }\n  }\n};\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/branch-summary-message.js\nvar BranchSummaryMessageComponent = class extends Box {\n  expanded = false;\n  message;\n  markdownTheme;\n  constructor(message, markdownTheme = getMarkdownTheme()) {\n    super(1, 1, (t) => theme.bg(\"customMessageBg\", t));\n    this.message = message;\n    this.markdownTheme = markdownTheme;\n    this.updateDisplay();\n  }\n  setExpanded(expanded) {\n    this.expanded = expanded;\n    this.updateDisplay();\n  }\n  invalidate() {\n    super.invalidate();\n    this.updateDisplay();\n  }\n  updateDisplay() {\n    this.clear();\n    const label = theme.fg(\"customMessageLabel\", `\\x1B[1m[branch]\\x1B[22m`);\n    this.addChild(new Text(label, 0, 0));\n    this.addChild(new Spacer(1));\n    if (this.expanded) {\n      const header = \"**Branch Summary**\\n\\n\";\n      this.addChild(new Markdown(header + this.message.summary, 0, 0, this.markdownTheme, {\n        color: (text) => theme.fg(\"customMessageText\", text)\n      }));\n    } else {\n      this.addChild(new Text(theme.fg(\"customMessageText\", \"Branch summary (\") + theme.fg(\"dim\", keyText(\"app.tools.expand\")) + theme.fg(\"customMessageText\", \" to expand)\"), 0, 0));\n    }\n  }\n};\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/compaction-summary-message.js\nvar CompactionSummaryMessageComponent = class extends Box {\n  expanded = false;\n  message;\n  markdownTheme;\n  constructor(message, markdownTheme = getMarkdownTheme()) {\n    super(1, 1, (t) => theme.bg(\"customMessageBg\", t));\n    this.message = message;\n    this.markdownTheme = markdownTheme;\n    this.updateDisplay();\n  }\n  setExpanded(expanded) {\n    this.expanded = expanded;\n    this.updateDisplay();\n  }\n  invalidate() {\n    super.invalidate();\n    this.updateDisplay();\n  }\n  updateDisplay() {\n    this.clear();\n    const tokenStr = this.message.tokensBefore.toLocaleString();\n    const label = theme.fg(\"customMessageLabel\", `\\x1B[1m[compaction]\\x1B[22m`);\n    this.addChild(new Text(label, 0, 0));\n    this.addChild(new Spacer(1));\n    if (this.expanded) {\n      const header = `**Compacted from ${tokenStr} tokens**\n\n`;\n      this.addChild(new Markdown(header + this.message.summary, 0, 0, this.markdownTheme, {\n        color: (text) => theme.fg(\"customMessageText\", text)\n      }));\n    } else {\n      this.addChild(new Text(theme.fg(\"customMessageText\", `Compacted from ${tokenStr} tokens (`) + theme.fg(\"dim\", keyText(\"app.tools.expand\")) + theme.fg(\"customMessageText\", \" to expand)\"), 0, 0));\n    }\n  }\n};\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/custom-editor.js\nvar CustomEditor = class extends Editor {\n  keybindings;\n  actionHandlers = /* @__PURE__ */ new Map();\n  // Special handlers that can be dynamically replaced\n  onEscape;\n  onCtrlD;\n  onPasteImage;\n  /** Handler for extension-registered shortcuts. Returns true if handled. */\n  onExtensionShortcut;\n  constructor(tui, theme2, keybindings, options) {\n    super(tui, theme2, options);\n    this.keybindings = keybindings;\n  }\n  /**\n   * Register a handler for an app action.\n   */\n  onAction(action, handler) {\n    this.actionHandlers.set(action, handler);\n  }\n  handleInput(data) {\n    if (this.onExtensionShortcut?.(data)) {\n      return;\n    }\n    if (this.keybindings.matches(data, \"app.clipboard.pasteImage\")) {\n      this.onPasteImage?.();\n      return;\n    }\n    if (this.keybindings.matches(data, \"app.interrupt\")) {\n      if (!this.isShowingAutocomplete()) {\n        const handler = this.onEscape ?? this.actionHandlers.get(\"app.interrupt\");\n        if (handler) {\n          handler();\n          return;\n        }\n      }\n      super.handleInput(data);\n      return;\n    }\n    if (this.keybindings.matches(data, \"app.exit\")) {\n      if (this.getText().length === 0) {\n        const handler = this.onCtrlD ?? this.actionHandlers.get(\"app.exit\");\n        if (handler)\n          handler();\n        return;\n      }\n    }\n    if (this.keybindings.matches(data, \"tui.editor.historyPrevious\") || this.keybindings.matches(data, \"tui.editor.historyNext\")) {\n      super.handleInput(data);\n      return;\n    }\n    for (const [action, handler] of this.actionHandlers) {\n      if (action !== \"app.interrupt\" && action !== \"app.exit\" && this.keybindings.matches(data, action)) {\n        handler();\n        return;\n      }\n    }\n    super.handleInput(data);\n  }\n};\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/custom-entry.js\nvar CustomEntryComponent = class extends Container {\n  entry;\n  renderer;\n  customComponent;\n  _expanded = false;\n  constructor(entry, renderer) {\n    super();\n    this.entry = entry;\n    this.renderer = renderer;\n    this.rebuild();\n  }\n  hasContent() {\n    return this.customComponent !== void 0;\n  }\n  setExpanded(expanded) {\n    if (this._expanded !== expanded) {\n      this._expanded = expanded;\n      this.rebuild();\n    }\n  }\n  invalidate() {\n    super.invalidate();\n    this.rebuild();\n  }\n  rebuild() {\n    this.clear();\n    this.customComponent = void 0;\n    let component;\n    try {\n      component = this.renderer(this.entry, { expanded: this._expanded }, theme);\n    } catch (error) {\n      const message = error instanceof Error ? error.message : String(error);\n      const box = new Box(1, 1, (text) => theme.bg(\"customMessageBg\", text));\n      box.addChild(new Text(theme.fg(\"error\", `[${this.entry.customType}] renderer failed: ${message}`), 0, 0));\n      component = box;\n    }\n    if (!component) {\n      return;\n    }\n    this.customComponent = component;\n    this.addChild(new Spacer(1));\n    this.addChild(component);\n  }\n};\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/custom-message.js\nvar CustomMessageComponent = class extends Container {\n  message;\n  customRenderer;\n  box;\n  customComponent;\n  markdownTheme;\n  _expanded = false;\n  outputPad;\n  constructor(message, customRenderer, markdownTheme = getMarkdownTheme(), outputPad = 1) {\n    super();\n    this.message = message;\n    this.customRenderer = customRenderer;\n    this.markdownTheme = markdownTheme;\n    this.outputPad = outputPad;\n    this.addChild(new Spacer(1));\n    this.box = new Box(1, 1, (t) => theme.bg(\"customMessageBg\", t));\n    this.rebuild();\n  }\n  setExpanded(expanded) {\n    if (this._expanded !== expanded) {\n      this._expanded = expanded;\n      this.rebuild();\n    }\n  }\n  setOutputPad(outputPad) {\n    if (this.outputPad !== outputPad) {\n      this.outputPad = outputPad;\n      this.rebuild();\n    }\n  }\n  invalidate() {\n    super.invalidate();\n    this.rebuild();\n  }\n  rebuild() {\n    if (this.customComponent) {\n      this.removeChild(this.customComponent);\n      this.customComponent = void 0;\n    }\n    this.removeChild(this.box);\n    if (this.customRenderer) {\n      try {\n        const component = this.customRenderer(this.message, { expanded: this._expanded, outputPad: this.outputPad }, theme);\n        if (component) {\n          this.customComponent = component;\n          this.addChild(component);\n          return;\n        }\n      } catch {\n      }\n    }\n    this.addChild(this.box);\n    this.box.clear();\n    const label = theme.fg(\"customMessageLabel\", `\\x1B[1m[${this.message.customType}]\\x1B[22m`);\n    this.box.addChild(new Text(label, 0, 0));\n    this.box.addChild(new Spacer(1));\n    let text;\n    if (typeof this.message.content === \"string\") {\n      text = this.message.content;\n    } else {\n      text = this.message.content.filter((c) => c.type === \"text\").map((c) => c.text).join(\"\\n\");\n    }\n    this.box.addChild(new Markdown(text, 0, 0, this.markdownTheme, {\n      color: (text2) => theme.fg(\"customMessageText\", text2)\n    }));\n  }\n};\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/daxnuts.js\nvar DAX_HEX = \"bbbab8b9b9b6b9b8b5bcbbb8b8b7b4b7b5b2b6b5b2b8b7b4b7b6b3b6b4b1bdbcb8bab8b6bbb8b5b8b5b1bbb8b4c2bebbc1bebac0bdbabfbcb9c1bebabfbebbc0bfbcc0bdbabbb8b5c1bfbcbfbcb8bbb9b6bfbcb8c2bfbcc1bfbcbfbbb8bdb9b6b8b7b5b9b8b5b8b8b5b5b5b2b6b5b2b8b7b4b9b8b5b9b8b5b6b5b3bab8b5bcbab7bbb9b6bbb8b5bfb9b5bdb2abbcb0a8beb2aabeb5afbfbab6bebab7c0bfbcbebdbabebbb8c0bdbabfbebbc2bebbbdbab7c3c0bdc3c0bdc1bebbc2bebabfbcb8bab9b6b7b6b3b2b1aeb6b5b2b5b4b1b5b4b2b6b5b2b7b6b4b9b8b6b7b6b3bbbab7b2afaba5988fb49e90b09481b79a88b39683b09583b7a395bfb6b0c0bdbabdbbb8bebcb9c1bfbcc0bebbbdbab7bebbb8c2bfbcc0bdbac0bcb9bdb9b6c0bcb8b5b4b2b4b3b0bab9b6b9b9b6b5b4b1b5b4b1b6b5b3b9b8b5b9b8b6b9b8b6b2aeaa968174a6836eaa856eab846eaf8973ac8973b08f79b18f7ab39786b7a89dbbb3aebfbab6c2c0bdbebcb9bfbdbac3c1bdc2bebbc0bcb9bdb9b6c1bdbabfbbb8b4b3b0b9b8b5b8b7b5b4b3b1b5b4b1b8b7b4b8b7b5bab9b6bbbab7b1afad8c7a719d735ca47860a87d65a98069ae8972ae8c75af8d77aa826ba98067aa8974b39e90b6a79dbbb2adc0bdbac1bfbdbfbbb8c1bdb9bebab6c0bdb9bfbbb8c1bdbab4b2b0b7b6b4b7b6b3b4b2b0bab9b7b6b5b2b6b5b2bab9b6bab9b6958c87977663aa836bac8772b08f7aad8c77b2917db0917db0907cac8971a77d64a87f67ac8972b29887b8a89dbfbab5bfbdbac1bebac0bcb9c0bcb9c0bcb9c1bebabebab7b8b7b4b7b6b4b5b4b1b5b4b2b7b6b3b5b4b2bab9b7bab9b6b4b1ada88f7fad8973ae8d78b19684b19685b29786b69a89b29582b1917daa856ea87e66a97e66ad866ea9826baf9280b8ada6bdbbb8bebab7bfbbb8c1bdbabfbbb8bcb8b4bcb8b5b6b4b2b7b5b3b6b5b2b8b7b4b3b2afb8b7b4b6b5b2b3b2b0b3a59aab856fad8d78b0917eb19886b49b8bb49a89b39785b0917eaf8f7cab866fa77d65a77a61a87d64a9816ab08f79b5a296c1bcb8c3bfbcc2bebbbebab7bfbbb7bdbab6c2bebab8b7b4b7b6b4b6b5b3b7b6b3b6b5b2b9b8b6b4b3b1b6b1acac8f7ca9826bae8f7aaf9583b49c8cb49c8bb79d8cb59987b19380ad8e79ae8c77af8e78ac8771a3775faa826bae8972b39888bbb6b2bebbb8bfbbb8bfbbb8c0bdb9bebbb7c0bdb9b6b5b2b9b8b5b4b3b1b8b7b5b4b3b0b7b6b4b6b5b3b1a7a0aa8772a77d65a88570b49887b19b8d9c887c907a6d987f71aa907faf917daf8e7aad8c78ac8b77a8836ca9836cac8770b49b8abdb6b2c0bcb9c0bdb9bfbbb8bebab7bfbcb9bebab7b9b8b6b5b4b2b9b8b5b8b7b5b8b7b4b7b6b4b5b4b2b3a9a2ad8973a1755da9856fb398858c776a65544b776358725d526e594d9c7f6eb1907ba68672ad8e7aab8771ac856db18f79b3a092beb9b5c1bdbabdb9b5bebab7bfbbb7bebab7bcb9b6b7b6b4b6b6b3b8b7b4b5b4b2b8b6b4b7b6b3b4b3b0b4aba4a6826ba3775fb08e79b19584a88e7daa8e7db29481ad8f7c997e6da38674ac8d79ac8e7aae917f9a7c6a896a599a7c6ab3a398c1bdbabdb9b6bcb8b5bebab6bebab7bdb9b5bdb9b6b5b4b1b7b5b3b5b4b2b7b6b3b7b6b4b3b3b0b3b2b0b4aca5a7846fa97f68ae8f7bae9383b59c8bb2937fae8e79ac8b76af927eaf927eb29683b39885b2988891786a72594c6e594d978d86bdbab7bab7b3c0bcb9c0bcb9bebab7bebbb7bdb9b6b3b2b0b4b3b0b5b4b2b4b4b1b4b3b1b4b3b1b4b3b0b6ada5aa8670a57a62ad8e7ab29b8cb69d8dab856fa9826aa88069ab8771af907db49987b19684b29886b59987b39480b09787b5a9a1bcb8b5bebab7bdb9b5bebab7bfbbb8bfbbb7bbb7b4b3b2afb8b7b5b8b7b5b3b2b0b5b4b2b6b5b3b6b4b1afa299a98975a9826baf907cb39988b49a89af8e7aac8973aa856eaf8c74b1917dae907dac907db39988b29785b49785b7a090b9aca3bfbab7bcb8b5bdb9b6bcb8b4bcb8b5bdb9b5bcb8b4b5b4b2b6b5b3b4b3b0b4b3b0b9b8b5b8b6b4908b88887467aa8f7ea78976ad8973b08b74b59885b69e8eb29888b1917cb1917db1937fae907cb19686b39a8ab29886b59b8ab8a192b6aaa3b7b2afbcb8b4bcb8b5bbb7b4c0bcb9bebab7c0bcb9b6b5b2b6b5b3b4b3b0bab9b7b7b6b4b1b0ae7b716ba083709b806f716158967764b08870b29481b69b8ab69f8fb39a89b69f90b49d8db39a89b29988b49c8cb6a090b8a496baa49593867f8f8986bfbbb7bdb9b5bcb7b4bab6b3b9b5b2bab6b2b4b3b1b3b3b0b6b5b3b8b7b5b4b2b0a7a5a38f837dae917ea084725a504c63544da28370b39784b59e8db2a093a698909b918b998e8790857e95877dad998bb39c8cb5a091b9a2938d827c95908dbebab6bbb7b3bdbab7bbb7b4bdb9b6bbb7b4b4b3b0b5b4b1b8b7b5b6b5b3b8b8b5b4b2af968f8ab29a8bab9485544b483a323073655d96887f70655f61595547403e453e3c453f3d57504f655e5b90847db39c8db7a090b6a09189807aaba6a3bdb9b6c0bcb9bebab7bcb7b4bebab7bbb7b4b3b2b0b6b5b3b2b1afb7b6b4b8b7b4b5b4b1aeaba8b5a89fac998d4d44412d25244d46444e4744322b293a3230423937433a37352d2a59504c534b48524a48988a81b59f8fb19c8d827974b2afacbdb9b5bcb8b4bdb9b5bcb8b5bdb9b6bab6b2b8b7b5b5b4b2b6b6b3b9b8b5b7b6b3b6b5b2b8b6b3b9b4b1b2a9a26c64612d25242d2625312a28352d2c453d3a78675c8d7a6ea09792aea6a0615854332b29524a479f8e82b09d90a49b96c1bdb9bebab7bfbbb8bbb8b4b9b5b1b8b4b0b9b4b0b7b6b4b8b7b5b8b7b4b6b5b3b8b6b3bab9b6b9b8b5b4b3b0b7b5b2a5a29f453d3b261e1d261f1e2e2625413936857268977865b19482b5a69caca5a07c7572453d3b746963a0948cc5bfbbc0bbb8beb9b6bbb7b3bbb6b3b7b3afb8b4b0b9b5b1b7b6b3b6b5b3b5b4b2b5b4b2b7b6b3b7b6b3b8b6b3b4b2afb7b6b3b3b1ae6d6765251f1e1e18172a22212d2523443b3971625ab19888b09482a89182877e792c25243e3634766d6abeb9b5bfbbb7bebab6bcb7b3bbb6b3b9b5b1b7b3afb8b4b0b4b3b0b5b4b1b5b4b1b4b3b1b5b4b2b8b6b4b5b3b0b9b6b4b5b4b1b6b4b27f79762a2322221c1b2d2524221b1a443e3c47413f6f676281766f867971675e5a3e37352a222166605dbab7b3bdb9b5beb9b5bcb7b3bcb7b3b9b4b0bab6b2bab6b2b5b3b0b6b4b2b3b2afb7b6b3b4b4b1b4b3b0b6b4b1b5b4b1b4b3b0b9b6b29a8c8252474230292828201f181212322c2c231e1d1c16162c26252923222d26252d2523332b2a8e8885bcb8b5bcb7b3bbb6b2bcb7b3b9b4b1b9b5b1b7b2afb7b2ae7a838e9b9b9caeadacb3b2b0b3b2afb7b7b4b6b5b3b6b6b3b7b6b3b9ada4a991808e7b6f50453f2b24231a14142923221f19181d17161f18182620201d17162a22215d5654b7b3b0bbb7b3bbb6b2b8b4b0bab5b1bbb6b2bab5b1b8b4b0bab6b22c496b4c5d735f68766e727a828285929090adaba8b7b2aeb6a59ab39682a28470a387748e76674e403a1a14141d1716181211221c1c1f1918221c1b2f2827342d2c8d8884bab6b3b9b5b2bab5b1bab5b1b9b4b0bab6b2b8b4b0b9b4b0b7b2ae325e8b365f8a3a5d833f5b7a545f70646469706b6aa08f84b08e78b18e769f7e689e7f6b9e816d907766584940362d2a1c1615201b1a1a1413201a1a251e1d393331a39e9bbab5b1bcb7b3bab6b2b8b3afb8b4b0b9b4b0b9b4b1bab5b2b5b0ac3d6c9843729d44719c426e98415f805a64716f6a699d8677b1927eb3947faa89749d7a649f7f6ba487749e837186716454463f2c25231e181837302e3a33317a7471beb9b6bcb8b4bbb6b2b6b2aebab5b1b9b5b1b8b3afbab6b2b6b1adb5aeaa4877a14c7aa44e7ba345719a3a5d80586b7f767475927b6eb1927faf8e79b08e78a78169a07861a17f6aa58570a688749b83738270666f66618a8480a49e99b7b2aebab6b2bcb8b4b9b5b1b7b2aebab5b1b9b4b0b6b1aeb6b1adb2aca8b2aca84876a04a78a2517fa74771973a5d80405c7a6161677c695fac8a75b08d77b4917aaf8971ad876fa5816aa6846ea78670a98a76ac9484ab9f96b2aca8bdb8b4bcb7b3bcb8b4bcb8b4b8b3afb7b2aeb9b4b0b8b3afb8b2aeb6afabb3aeaab2aeaa4878a14b7aa34c7ba44a759b3d63873b5f825b67766f5f569c7e6caf8c77b18f79b28f78b5927caf8e78a98872aa8a76a98a76ac917fada199b7b0acb9b3afbfb9b5c1bab6bdb6b2b8b3afbab5b1b9b4b0b6afabb7b1adb3ada9b3aeaab0aba8\";\nvar WIDTH2 = 32;\nvar HEIGHT2 = 32;\nfunction parseImage() {\n  const pixels = [];\n  for (let y = 0; y < HEIGHT2; y++) {\n    const row = [];\n    for (let x = 0; x < WIDTH2; x++) {\n      const idx = (y * WIDTH2 + x) * 6;\n      const r = parseInt(DAX_HEX.slice(idx, idx + 2), 16);\n      const g = parseInt(DAX_HEX.slice(idx + 2, idx + 4), 16);\n      const b = parseInt(DAX_HEX.slice(idx + 4, idx + 6), 16);\n      row.push([r, g, b]);\n    }\n    pixels.push(row);\n  }\n  return pixels;\n}\nfunction rgb(r, g, b, bg = false) {\n  return `\\x1B[${bg ? 48 : 38};2;${r};${g};${b}m`;\n}\nvar RESET = \"\\x1B[0m\";\nfunction buildImage() {\n  const pixels = parseImage();\n  const lines = [];\n  for (let row = 0; row < HEIGHT2; row += 2) {\n    let line = \"\";\n    for (let x = 0; x < WIDTH2; x++) {\n      const top = pixels[row][x];\n      const bottom = pixels[row + 1]?.[x] ?? top;\n      line += `${rgb(bottom[0], bottom[1], bottom[2])}${rgb(top[0], top[1], top[2], true)}\\u2584`;\n    }\n    line += RESET;\n    lines.push(line);\n  }\n  return lines;\n}\nvar DaxnutsComponent = class {\n  ui;\n  image;\n  interval = null;\n  tick = 0;\n  maxTicks = 25;\n  // ~2 seconds at 80ms\n  cachedLines = [];\n  cachedWidth = 0;\n  cachedTick = -1;\n  constructor(ui) {\n    this.ui = ui;\n    this.image = buildImage();\n    this.startAnimation();\n  }\n  invalidate() {\n    this.cachedWidth = 0;\n  }\n  startAnimation() {\n    this.interval = setInterval(() => {\n      this.tick++;\n      if (this.tick >= this.maxTicks) {\n        this.stopAnimation();\n      }\n      this.cachedWidth = 0;\n      this.ui.requestRender();\n    }, 80);\n  }\n  stopAnimation() {\n    if (this.interval) {\n      clearInterval(this.interval);\n      this.interval = null;\n    }\n  }\n  render(width) {\n    if (width === this.cachedWidth && this.cachedTick === this.tick) {\n      return this.cachedLines;\n    }\n    const t = theme;\n    const lines = [];\n    const center = (s) => {\n      const visible = s.replace(/\\x1b\\[[0-9;]*m/g, \"\").length;\n      const left = Math.max(0, Math.floor((width - visible) / 2));\n      return \" \".repeat(left) + s;\n    };\n    lines.push(\"\");\n    const revealedRows = Math.min(this.image.length, Math.floor(this.tick / this.maxTicks * (this.image.length + 3)));\n    for (let i = 0; i < this.image.length; i++) {\n      if (i < revealedRows) {\n        lines.push(center(this.image[i]));\n      } else {\n        if (i === revealedRows) {\n          const scanline = \"\\u2593\".repeat(WIDTH2);\n          lines.push(center(rgb(100, 200, 255) + scanline + RESET));\n        } else {\n          lines.push(center(\" \".repeat(WIDTH2)));\n        }\n      }\n    }\n    lines.push(\"\");\n    const textPhase = Math.max(0, this.tick - this.maxTicks * 0.6);\n    if (textPhase > 0 || this.tick >= this.maxTicks) {\n      lines.push(center(t.fg(\"accent\", \"Free Kimi K2.5 via OpenCode Zen\")));\n      lines.push(center(t.fg(\"success\", '\"Powered by daxnuts\"')));\n      lines.push(center(t.fg(\"muted\", \"\\u2014 @thdxr\")));\n    } else {\n      lines.push(\"\");\n      lines.push(\"\");\n      lines.push(\"\");\n    }\n    lines.push(\"\");\n    if (textPhase > 2 || this.tick >= this.maxTicks) {\n      lines.push(center(t.fg(\"dim\", \"Try OpenCode\")));\n      lines.push(center(t.fg(\"mdLink\", \"https://mistral.ai/news/mistral-vibe-2-0\")));\n    } else {\n      lines.push(\"\");\n      lines.push(\"\");\n    }\n    lines.push(\"\");\n    this.cachedLines = lines;\n    this.cachedWidth = width;\n    this.cachedTick = this.tick;\n    return lines;\n  }\n  dispose() {\n    this.stopAnimation();\n  }\n};\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/earendil-announcement.js\nimport * as fs5 from \"node:fs\";\nvar BLOG_URL = \"https://mariozechner.at/posts/2026-04-08-ive-sold-out/\";\nvar IMAGE_FILENAME = \"clankolas.png\";\nvar cachedImageBase64;\nvar attemptedImageLoad = false;\nfunction loadImageBase64() {\n  if (attemptedImageLoad) {\n    return cachedImageBase64;\n  }\n  attemptedImageLoad = true;\n  try {\n    cachedImageBase64 = fs5.readFileSync(getBundledInteractiveAssetPath(IMAGE_FILENAME)).toString(\"base64\");\n  } catch {\n    cachedImageBase64 = void 0;\n  }\n  return cachedImageBase64;\n}\nvar EarendilAnnouncementComponent = class extends Container {\n  constructor() {\n    super();\n    this.addChild(new DynamicBorder((text) => theme.fg(\"accent\", text)));\n    this.addChild(new Text(theme.bold(theme.fg(\"accent\", \"pi has joined Earendil\")), 1, 0));\n    this.addChild(new Spacer(1));\n    this.addChild(new Text(theme.fg(\"muted\", \"Read the blog post:\"), 1, 0));\n    this.addChild(new Text(theme.fg(\"mdLink\", BLOG_URL), 1, 0));\n    this.addChild(new Spacer(1));\n    const imageBase64 = loadImageBase64();\n    if (imageBase64) {\n      this.addChild(new Image(imageBase64, \"image/png\", { fallbackColor: (text) => theme.fg(\"muted\", text) }, { maxWidthCells: 56, filename: IMAGE_FILENAME }));\n      this.addChild(new Spacer(1));\n    }\n    this.addChild(new DynamicBorder((text) => theme.fg(\"accent\", text)));\n  }\n};\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/external-editor.js\nimport { spawn as spawn8 } from \"node:child_process\";\nimport { mkdtempSync, readFileSync as readFileSync17, rmSync as rmSync3, writeFileSync as writeFileSync9 } from \"node:fs\";\nimport { tmpdir as tmpdir4 } from \"node:os\";\nimport { join as join29 } from \"node:path\";\nasync function editInExternalEditor(options) {\n  const directory = mkdtempSync(join29(tmpdir4(), \"pi-editor-\"));\n  const filePath = join29(directory, \"prompt.md\");\n  try {\n    writeFileSync9(filePath, options.content, \"utf-8\");\n    const [editor, ...editorArgs] = options.command.split(\" \");\n    process.stdout.write(`Launching external editor: ${options.command}\nPi will resume when the editor exits.\n`);\n    const exitCode = await new Promise((resolve15) => {\n      const child = spawn8(editor, [...editorArgs, filePath], {\n        stdio: \"inherit\",\n        shell: process.platform === \"win32\"\n      });\n      child.on(\"error\", () => resolve15(null));\n      child.on(\"close\", (code) => resolve15(code));\n    });\n    if (exitCode !== 0) {\n      return { status: \"failed\" };\n    }\n    return { status: \"complete\", content: readFileSync17(filePath, \"utf-8\").replace(/\\n$/, \"\") };\n  } finally {\n    try {\n      rmSync3(directory, { recursive: true, force: true });\n    } catch {\n    }\n  }\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/extension-editor.js\nvar ExtensionEditorComponent = class extends Container {\n  editor;\n  onSubmitCallback;\n  onCancelCallback;\n  tui;\n  keybindings;\n  externalEditorCommand;\n  _focused = false;\n  get focused() {\n    return this._focused;\n  }\n  set focused(value) {\n    this._focused = value;\n    this.editor.focused = value;\n  }\n  constructor(tui, keybindings, title, prefill, onSubmit, onCancel, options, externalEditorCommand) {\n    super();\n    this.tui = tui;\n    this.keybindings = keybindings;\n    this.externalEditorCommand = externalEditorCommand || process.env.VISUAL || process.env.EDITOR || (process.platform === \"win32\" ? \"notepad\" : \"nano\");\n    this.onSubmitCallback = onSubmit;\n    this.onCancelCallback = onCancel;\n    this.addChild(new DynamicBorder());\n    this.addChild(new Spacer(1));\n    this.addChild(new Text(theme.fg(\"accent\", title), 1, 0));\n    this.addChild(new Spacer(1));\n    this.editor = new Editor(tui, getEditorTheme(), options);\n    if (prefill) {\n      this.editor.setText(prefill);\n    }\n    this.editor.onSubmit = (text) => {\n      this.onSubmitCallback(text);\n    };\n    this.addChild(this.editor);\n    this.addChild(new Spacer(1));\n    const hint = keyHint(\"tui.select.confirm\", \"submit\") + \"  \" + keyHint(\"tui.input.newLine\", \"newline\") + \"  \" + keyHint(\"tui.select.cancel\", \"cancel\") + `  ${keyHint(\"app.editor.external\", \"external editor\")}`;\n    this.addChild(new Text(hint, 1, 0));\n    this.addChild(new Spacer(1));\n    this.addChild(new DynamicBorder());\n  }\n  handleInput(keyData) {\n    const kb = getKeybindings();\n    if (kb.matches(keyData, \"tui.select.cancel\")) {\n      this.onCancelCallback();\n      return;\n    }\n    if (this.keybindings.matches(keyData, \"app.editor.external\")) {\n      void this.handleOpenExternalEditor();\n      return;\n    }\n    this.editor.handleInput(keyData);\n  }\n  async handleOpenExternalEditor() {\n    const content = this.editor.getText();\n    this.tui.stop();\n    try {\n      const result = await editInExternalEditor({\n        command: this.externalEditorCommand,\n        content\n      });\n      if (result.status === \"complete\") {\n        this.editor.setText(result.content);\n      }\n    } finally {\n      this.tui.start();\n      this.tui.requestRender(true);\n    }\n  }\n};\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/footer.js\nimport { isAbsolute as isAbsolute4, relative as relative5, resolve as resolve9, sep as sep7 } from \"node:path\";\nfunction sanitizeStatusText(text) {\n  return text.replace(/[\\r\\n\\t]/g, \" \").replace(/ +/g, \" \").trim();\n}\nfunction formatTokens(count) {\n  if (count < 1e3)\n    return count.toString();\n  if (count < 1e4)\n    return `${(count / 1e3).toFixed(1)}k`;\n  if (count < 1e6)\n    return `${Math.round(count / 1e3)}k`;\n  if (count < 1e7)\n    return `${(count / 1e6).toFixed(1)}M`;\n  return `${Math.round(count / 1e6)}M`;\n}\nfunction formatCwdForFooter(cwd, home) {\n  if (!home)\n    return cwd;\n  const resolvedCwd = resolve9(cwd);\n  const resolvedHome = resolve9(home);\n  const relativeToHome = relative5(resolvedHome, resolvedCwd);\n  const isInsideHome = relativeToHome === \"\" || relativeToHome !== \"..\" && !relativeToHome.startsWith(`..${sep7}`) && !isAbsolute4(relativeToHome);\n  if (!isInsideHome)\n    return cwd;\n  return relativeToHome === \"\" ? \"~\" : `~${sep7}${relativeToHome}`;\n}\nvar FooterComponent = class {\n  autoCompactEnabled = true;\n  session;\n  footerData;\n  constructor(session, footerData) {\n    this.session = session;\n    this.footerData = footerData;\n  }\n  setSession(session) {\n    this.session = session;\n  }\n  setAutoCompactEnabled(enabled) {\n    this.autoCompactEnabled = enabled;\n  }\n  /**\n   * No-op: git branch caching now handled by provider.\n   * Kept for compatibility with existing call sites in interactive-mode.\n   */\n  invalidate() {\n  }\n  /**\n   * Clean up resources.\n   * Git watcher cleanup now handled by provider.\n   */\n  dispose() {\n  }\n  render(width) {\n    const state = this.session.state;\n    const usageTotals = createUsageTotals();\n    let latestCacheHitRate;\n    for (const entry of this.session.sessionManager.getEntries()) {\n      if (entry.type === \"message\" && entry.message.role === \"assistant\") {\n        addUsageToTotals(usageTotals, entry.message.usage);\n        const latestPromptTokens = entry.message.usage.input + entry.message.usage.cacheRead + entry.message.usage.cacheWrite;\n        latestCacheHitRate = latestPromptTokens > 0 ? entry.message.usage.cacheRead / latestPromptTokens * 100 : void 0;\n      } else if (entry.type === \"message\" && entry.message.role === \"toolResult\" && entry.message.usage) {\n        addUsageToTotals(usageTotals, entry.message.usage);\n      } else if ((entry.type === \"branch_summary\" || entry.type === \"compaction\") && entry.usage) {\n        addUsageToTotals(usageTotals, entry.usage);\n      }\n    }\n    const contextUsage = this.session.getContextUsage();\n    const contextWindow = contextUsage?.contextWindow ?? state.model?.contextWindow ?? 0;\n    const contextPercentValue = contextUsage?.percent ?? 0;\n    const contextPercent = contextUsage?.percent !== null ? contextPercentValue.toFixed(1) : \"?\";\n    let pwd = formatCwdForFooter(this.session.sessionManager.getCwd(), process.env.HOME || process.env.USERPROFILE);\n    const branch = this.footerData.getGitBranch();\n    if (branch) {\n      pwd = `${pwd} (${branch})`;\n    }\n    const sessionName = this.session.sessionManager.getSessionName();\n    if (sessionName) {\n      pwd = `${pwd} \\u2022 ${sessionName}`;\n    }\n    const statsParts = [];\n    if (usageTotals.input)\n      statsParts.push(`\\u2191${formatTokens(usageTotals.input)}`);\n    if (usageTotals.output)\n      statsParts.push(`\\u2193${formatTokens(usageTotals.output)}`);\n    if (usageTotals.cacheRead)\n      statsParts.push(`R${formatTokens(usageTotals.cacheRead)}`);\n    if (usageTotals.cacheWrite)\n      statsParts.push(`W${formatTokens(usageTotals.cacheWrite)}`);\n    if ((usageTotals.cacheRead > 0 || usageTotals.cacheWrite > 0) && latestCacheHitRate !== void 0) {\n      statsParts.push(`CH${latestCacheHitRate.toFixed(1)}%`);\n    }\n    const usingSubscription = state.model ? state.model.provider === \"kimi-coding\" || this.session.modelRuntime.isUsingSubscription(state.model.provider) : false;\n    if (usageTotals.cost || usingSubscription) {\n      const costStr = `$${usageTotals.cost.toFixed(3)}${usingSubscription ? \" (sub)\" : \"\"}`;\n      statsParts.push(costStr);\n    }\n    let contextPercentStr;\n    const autoIndicator = this.autoCompactEnabled ? \" (auto)\" : \"\";\n    const contextPercentDisplay = contextPercent === \"?\" ? `?/${formatTokens(contextWindow)}${autoIndicator}` : `${contextPercent}%/${formatTokens(contextWindow)}${autoIndicator}`;\n    if (contextPercentValue > 90) {\n      contextPercentStr = theme.fg(\"error\", contextPercentDisplay);\n    } else if (contextPercentValue > 70) {\n      contextPercentStr = theme.fg(\"warning\", contextPercentDisplay);\n    } else {\n      contextPercentStr = contextPercentDisplay;\n    }\n    statsParts.push(contextPercentStr);\n    if (areExperimentalFeaturesEnabled()) {\n      statsParts.push(`${theme.fg(\"dim\", \"\\u2022\")} ${theme.bold(theme.fg(\"warning\", \"xp\"))}`);\n    }\n    let statsLeft = statsParts.join(\" \");\n    const modelName = state.model?.id || \"no-model\";\n    let statsLeftWidth = visibleWidth(statsLeft);\n    if (statsLeftWidth > width) {\n      statsLeft = truncateToWidth(statsLeft, width, \"...\");\n      statsLeftWidth = visibleWidth(statsLeft);\n    }\n    const minPadding = 2;\n    let rightSideWithoutProvider = modelName;\n    if (state.model?.reasoning) {\n      const thinkingLevel = state.thinkingLevel || \"off\";\n      rightSideWithoutProvider = thinkingLevel === \"off\" ? `${modelName} \\u2022 thinking off` : `${modelName} \\u2022 ${thinkingLevel}`;\n    }\n    let rightSide = rightSideWithoutProvider;\n    if (this.footerData.getAvailableProviderCount() > 1 && state.model) {\n      rightSide = `(${state.model.provider}) ${rightSideWithoutProvider}`;\n      if (statsLeftWidth + minPadding + visibleWidth(rightSide) > width) {\n        rightSide = rightSideWithoutProvider;\n      }\n    }\n    const rightSideWidth = visibleWidth(rightSide);\n    const totalNeeded = statsLeftWidth + minPadding + rightSideWidth;\n    let statsLine;\n    if (totalNeeded <= width) {\n      const padding = \" \".repeat(width - statsLeftWidth - rightSideWidth);\n      statsLine = statsLeft + padding + rightSide;\n    } else {\n      const availableForRight = width - statsLeftWidth - minPadding;\n      if (availableForRight > 0) {\n        const truncatedRight = truncateToWidth(rightSide, availableForRight, \"\");\n        const truncatedRightWidth = visibleWidth(truncatedRight);\n        const padding = \" \".repeat(Math.max(0, width - statsLeftWidth - truncatedRightWidth));\n        statsLine = statsLeft + padding + truncatedRight;\n      } else {\n        statsLine = statsLeft;\n      }\n    }\n    const dimStatsLeft = theme.fg(\"dim\", statsLeft);\n    const remainder = statsLine.slice(statsLeft.length);\n    const dimRemainder = theme.fg(\"dim\", remainder);\n    const pwdLine = truncateToWidth(theme.fg(\"dim\", pwd), width, theme.fg(\"dim\", \"...\"));\n    const lines = [pwdLine, dimStatsLeft + dimRemainder];\n    const extensionStatuses = this.footerData.getExtensionStatuses();\n    if (extensionStatuses.size > 0) {\n      const sortedStatuses = Array.from(extensionStatuses.entries()).sort(([a], [b]) => a.localeCompare(b)).map(([, text]) => sanitizeStatusText(text));\n      const statusLine = sortedStatuses.join(\" \");\n      lines.push(truncateToWidth(statusLine, width, theme.fg(\"dim\", \"...\")));\n    }\n    return lines;\n  }\n};\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/login-dialog.js\nvar LoginDialogComponent = class extends Container {\n  contentContainer;\n  input;\n  tui;\n  abortController = new AbortController();\n  inputResolver;\n  inputRejecter;\n  onComplete;\n  // Focusable implementation - propagate to input for IME cursor positioning\n  _focused = false;\n  get focused() {\n    return this._focused;\n  }\n  set focused(value) {\n    this._focused = value;\n    this.input.focused = value;\n  }\n  constructor(tui, providerId, onComplete, providerNameOverride, titleOverride) {\n    super();\n    this.tui = tui;\n    this.onComplete = onComplete;\n    const providerName = providerNameOverride || providerId;\n    const title = titleOverride ?? `Login to ${providerName}`;\n    this.addChild(new DynamicBorder());\n    this.addChild(new Text(theme.fg(\"accent\", theme.bold(title)), 1, 0));\n    this.contentContainer = new Container();\n    this.addChild(this.contentContainer);\n    this.input = new Input();\n    this.input.onSubmit = () => {\n      if (this.inputResolver) {\n        const value = this.input.getValue();\n        this.replaceInputWithSubmittedText(value);\n        this.inputResolver(value);\n        this.inputResolver = void 0;\n        this.inputRejecter = void 0;\n      }\n    };\n    this.input.onEscape = () => {\n      this.cancel();\n    };\n    this.addChild(new DynamicBorder());\n  }\n  get signal() {\n    return this.abortController.signal;\n  }\n  replaceInputWithSubmittedText(value) {\n    this.contentContainer.children = this.contentContainer.children.map((child) => child === this.input ? new Text(`> ${value}`, 0, 0) : child);\n  }\n  cancel() {\n    this.abortController.abort();\n    if (this.inputRejecter) {\n      this.inputRejecter(new Error(\"Login cancelled\"));\n      this.inputResolver = void 0;\n      this.inputRejecter = void 0;\n    }\n    this.onComplete(false, \"Login cancelled\");\n  }\n  /**\n   * Called by onAuth callback - show URL and optional instructions\n   */\n  showAuth(url, instructions) {\n    this.contentContainer.clear();\n    this.contentContainer.addChild(new Spacer(1));\n    const linkedUrl = `\\x1B]8;;${url}\\x07${url}\\x1B]8;;\\x07`;\n    this.contentContainer.addChild(new Text(theme.fg(\"accent\", linkedUrl), 1, 0));\n    const clickHint = process.platform === \"darwin\" ? \"Cmd+click to open\" : \"Ctrl+click to open\";\n    const hyperlink2 = `\\x1B]8;;${url}\\x07${clickHint}\\x1B]8;;\\x07`;\n    this.contentContainer.addChild(new Text(theme.fg(\"dim\", hyperlink2), 1, 0));\n    if (instructions) {\n      this.contentContainer.addChild(new Spacer(1));\n      this.contentContainer.addChild(new Text(theme.fg(\"warning\", instructions), 1, 0));\n    }\n    openBrowser(url);\n    this.tui.requestRender();\n  }\n  /**\n   * Called by onDeviceCode callback - show URL and user code.\n   */\n  showDeviceCode(info) {\n    this.contentContainer.clear();\n    this.contentContainer.addChild(new Spacer(1));\n    const linkedUrl = `\\x1B]8;;${info.verificationUri}\\x07${info.verificationUri}\\x1B]8;;\\x07`;\n    this.contentContainer.addChild(new Text(theme.fg(\"accent\", linkedUrl), 1, 0));\n    const clickHint = process.platform === \"darwin\" ? \"Cmd+click to open\" : \"Ctrl+click to open\";\n    const hyperlink2 = `\\x1B]8;;${info.verificationUri}\\x07${clickHint}\\x1B]8;;\\x07`;\n    this.contentContainer.addChild(new Text(theme.fg(\"dim\", hyperlink2), 1, 0));\n    this.contentContainer.addChild(new Spacer(1));\n    this.contentContainer.addChild(new Text(theme.fg(\"warning\", `Enter code: ${info.userCode}`), 1, 0));\n    this.tui.requestRender();\n  }\n  /**\n   * Show input for manual code/URL entry (for callback server providers)\n   */\n  showManualInput(prompt) {\n    this.input.setValue(\"\");\n    this.contentContainer.addChild(new Spacer(1));\n    this.contentContainer.addChild(new Text(theme.fg(\"dim\", prompt), 1, 0));\n    this.contentContainer.addChild(this.input);\n    this.contentContainer.addChild(new Text(`(${keyHint(\"tui.select.cancel\", \"to cancel\")})`, 1, 0));\n    this.tui.requestRender();\n    return new Promise((resolve15, reject) => {\n      this.inputResolver = resolve15;\n      this.inputRejecter = reject;\n    });\n  }\n  /**\n   * Called by onPrompt callback - show prompt and wait for input\n   * Note: Does NOT clear content, appends to existing (preserves URL from showAuth)\n   */\n  showPrompt(message, placeholder) {\n    this.contentContainer.addChild(new Spacer(1));\n    this.contentContainer.addChild(new Text(theme.fg(\"text\", message), 1, 0));\n    if (placeholder) {\n      this.contentContainer.addChild(new Text(theme.fg(\"dim\", `e.g., ${placeholder}`), 1, 0));\n    }\n    this.contentContainer.addChild(this.input);\n    this.contentContainer.addChild(new Text(`(${keyHint(\"tui.select.cancel\", \"to cancel,\")} ${keyHint(\"tui.select.confirm\", \"to submit\")})`, 1, 0));\n    this.input.setValue(\"\");\n    this.tui.requestRender();\n    return new Promise((resolve15, reject) => {\n      this.inputResolver = resolve15;\n      this.inputRejecter = reject;\n    });\n  }\n  /** Show informational text before another login step. */\n  showDetails(lines) {\n    this.contentContainer.clear();\n    this.contentContainer.addChild(new Spacer(1));\n    for (const line of lines) {\n      this.contentContainer.addChild(new Text(line, 1, 0));\n    }\n    this.tui.requestRender();\n  }\n  /** Show provider-owned information and links without starting an auth callback flow. */\n  showInfo(message, links = [], showCloseHint = false) {\n    this.contentContainer.addChild(new Spacer(1));\n    this.contentContainer.addChild(new Text(theme.fg(\"text\", message), 1, 0));\n    for (const link of links) {\n      const text = link.label ? `${link.label}: ${link.url}` : link.url;\n      const hyperlink2 = `\\x1B]8;;${link.url}\\x07${text}\\x1B]8;;\\x07`;\n      this.contentContainer.addChild(new Text(theme.fg(\"accent\", hyperlink2), 1, 0));\n    }\n    if (showCloseHint) {\n      this.contentContainer.addChild(new Spacer(1));\n      this.contentContainer.addChild(new Text(`(${keyHint(\"tui.select.cancel\", \"to close\")})`, 1, 0));\n    }\n    this.tui.requestRender();\n  }\n  /**\n   * Show waiting message (for polling flows like GitHub Copilot)\n   */\n  showWaiting(message) {\n    this.contentContainer.addChild(new Spacer(1));\n    this.contentContainer.addChild(new Text(theme.fg(\"dim\", message), 1, 0));\n    this.contentContainer.addChild(new Text(`(${keyHint(\"tui.select.cancel\", \"to cancel\")})`, 1, 0));\n    this.tui.requestRender();\n  }\n  /**\n   * Called by onProgress callback\n   */\n  showProgress(message) {\n    this.contentContainer.addChild(new Text(theme.fg(\"dim\", message), 1, 0));\n    this.tui.requestRender();\n  }\n  handleInput(data) {\n    const kb = getKeybindings();\n    if (kb.matches(data, \"tui.select.cancel\")) {\n      this.cancel();\n      return;\n    }\n    this.input.handleInput(data);\n  }\n};\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/mermaid.js\nimport { render } from \"grok-mermaid\";\nvar markdownParser2 = new Marked2();\nfunction isMermaid(token) {\n  return token.type === \"code\" && token.lang?.trim().split(/\\s+/, 1)[0]?.toLowerCase() === \"mermaid\";\n}\nfunction codeSpan(line) {\n  const content = line || \"\\xA0\";\n  const longestBacktickRun = Math.max(0, ...Array.from(content.matchAll(/`+/g), (match) => match[0].length));\n  const fence = \"`\".repeat(longestBacktickRun + 1);\n  const padding = content.startsWith(\"`\") || content.endsWith(\"`\") ? \" \" : \"\";\n  return `${fence}${padding}${content}${padding}${fence}`;\n}\nfunction styleSpan(span, theme2) {\n  switch (span.cls) {\n    case \"border\":\n      return theme2.fg(\"borderMuted\", span.text);\n    case \"text\":\n      return theme2.fg(\"text\", span.text);\n    case \"edge\":\n      return theme2.fg(\"accent\", span.text);\n    case \"edgeLabel\":\n      return theme2.fg(\"muted\", span.text);\n    case \"title\":\n      return theme2.fg(\"accent\", theme2.bold(span.text));\n    case \"none\":\n      return span.text;\n  }\n}\nfunction themedLines(art, theme2) {\n  return art.styled.map((row) => row.map((span) => styleSpan(span, theme2)).join(\"\"));\n}\nfunction createMermaidMarkdownTransformer(options) {\n  return (markdown, context) => {\n    const mode = options.getMode();\n    if (mode === \"off\" || context.messageType === \"assistant-thinking\" || context.isStreaming && mode !== \"streaming\") {\n      return markdown;\n    }\n    return markdownParser2.lexer(markdown).map((token) => {\n      if (!isMermaid(token))\n        return token.raw;\n      const art = render(token.text);\n      if (!art || art.width > context.availableWidth)\n        return token.raw;\n      if (!context.isStreaming && art.warnings.length > 0) {\n        const suffix = art.warnings.length > 1 ? ` (+${art.warnings.length - 1} more)` : \"\";\n        const warning = `Mermaid diagram not rendered: ${art.warnings[0]}${suffix}`;\n        const styledWarning = options.theme ? options.theme.fg(\"warning\", warning) : warning;\n        return `${token.raw}\n${codeSpan(styledWarning)}  \n`;\n      }\n      const lines = options.theme ? themedLines(art, options.theme) : art.plain;\n      return `${lines.map(codeSpan).join(\"  \\n\")}\n`;\n    }).join(\"\");\n  };\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/model-catalog-refresh.js\nvar ModelCatalogRefreshCoordinator = class {\n  activeByRuntime = /* @__PURE__ */ new WeakMap();\n  refresh(modelRuntime, signal) {\n    signal.throwIfAborted();\n    let active = this.activeByRuntime.get(modelRuntime);\n    if (!active) {\n      const controller = new AbortController();\n      let created;\n      const operation = modelRuntime.refresh({ signal: controller.signal });\n      const promise = raceWithAbortSignal2(operation, controller.signal).finally(() => {\n        if (this.activeByRuntime.get(modelRuntime) === created) {\n          this.activeByRuntime.delete(modelRuntime);\n        }\n      });\n      created = { controller, promise, waiters: 0 };\n      active = created;\n      this.activeByRuntime.set(modelRuntime, active);\n    }\n    active.waiters++;\n    return raceWithAbortSignal2(active.promise, signal).finally(() => {\n      active.waiters--;\n      if (active.waiters === 0 && this.activeByRuntime.get(modelRuntime) === active) {\n        active.controller.abort();\n      }\n    });\n  }\n};\nvar modelCatalogRefreshCoordinator = new ModelCatalogRefreshCoordinator();\nfunction refreshModelCatalogs(modelRuntime, signal) {\n  return modelCatalogRefreshCoordinator.refresh(modelRuntime, signal);\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/model-search.js\nfunction getModelSearchText(item) {\n  const { id, provider } = item;\n  const name = item.name ? ` ${item.name}` : \"\";\n  return `${id} ${provider} ${provider}/${id} ${provider} ${id}${name}`;\n}\nfunction getModelSelectorSearchText(item) {\n  const { id, provider } = item;\n  const name = item.name ? ` ${item.name}` : \"\";\n  return `${provider} ${provider}/${id} ${provider} ${id}${name}`;\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/model-selector.js\nvar ModelSelectorComponent = class extends Container {\n  searchInput;\n  // Focusable implementation - propagate to searchInput for IME cursor positioning\n  _focused = false;\n  get focused() {\n    return this._focused;\n  }\n  set focused(value) {\n    this._focused = value;\n    this.searchInput.focused = value;\n  }\n  listContainer;\n  allModels = [];\n  scopedModelItems = [];\n  activeModels = [];\n  filteredModels = [];\n  selectedIndex = 0;\n  currentModel;\n  settingsManager;\n  modelRuntime;\n  onSelectCallback;\n  onCancelCallback;\n  errorMessage;\n  refreshStatusMessage = \"Refreshing model catalogs\\u2026\";\n  refreshStatusSuccess = false;\n  tui;\n  scopedModels;\n  scope = \"all\";\n  scopeText;\n  scopeHintText;\n  refreshAbortController = new AbortController();\n  refreshTimeout;\n  closed = false;\n  constructor(tui, currentModel, settingsManager, modelRuntime, scopedModels, onSelect, onCancel, initialSearchInput) {\n    super();\n    this.tui = tui;\n    this.currentModel = currentModel;\n    this.settingsManager = settingsManager;\n    this.modelRuntime = modelRuntime;\n    this.scopedModels = scopedModels;\n    this.scope = scopedModels.length > 0 ? \"scoped\" : \"all\";\n    this.onSelectCallback = onSelect;\n    this.onCancelCallback = onCancel;\n    this.addChild(new DynamicBorder());\n    this.addChild(new Spacer(1));\n    if (scopedModels.length > 0) {\n      this.scopeText = new Text(this.getScopeText(), 0, 0);\n      this.addChild(this.scopeText);\n      this.scopeHintText = new Text(this.getScopeHintText(), 0, 0);\n      this.addChild(this.scopeHintText);\n    } else {\n      const hintText = \"Only showing models from configured providers. Use /login to add providers.\";\n      this.addChild(new Text(theme.fg(\"warning\", hintText), 0, 0));\n    }\n    this.addChild(new Spacer(1));\n    this.searchInput = new Input();\n    if (initialSearchInput) {\n      this.searchInput.setValue(initialSearchInput);\n    }\n    this.searchInput.onSubmit = () => {\n      if (this.filteredModels[this.selectedIndex]) {\n        this.handleSelect(this.filteredModels[this.selectedIndex].model);\n      }\n    };\n    this.addChild(this.searchInput);\n    this.addChild(new Spacer(1));\n    this.listContainer = new Container();\n    this.addChild(this.listContainer);\n    this.addChild(new Spacer(1));\n    this.addChild(new DynamicBorder());\n    this.loadModelsFromSnapshot();\n    if (initialSearchInput)\n      this.filterModels(initialSearchInput);\n    else\n      this.updateList();\n    this.tui.requestRender();\n    void this.refreshModels();\n  }\n  loadModelsFromSnapshot() {\n    const models = this.modelRuntime.getAvailableSnapshot().map((model) => ({\n      provider: model.provider,\n      id: model.id,\n      model\n    }));\n    this.allModels = this.sortModels(models);\n    this.scopedModels = this.scopedModels.map((scoped) => {\n      const refreshed = this.modelRuntime.getModel(scoped.model.provider, scoped.model.id);\n      return refreshed ? { ...scoped, model: refreshed } : scoped;\n    });\n    this.scopedModelItems = this.scopedModels.map((scoped) => ({\n      provider: scoped.model.provider,\n      id: scoped.model.id,\n      model: scoped.model\n    }));\n    this.activeModels = this.scope === \"scoped\" ? this.scopedModelItems : this.allModels;\n    this.filteredModels = this.activeModels;\n    const currentIndex = this.filteredModels.findIndex((item) => modelsAreEqual(this.currentModel, item.model));\n    this.selectedIndex = currentIndex >= 0 ? currentIndex : Math.min(this.selectedIndex, Math.max(0, this.filteredModels.length - 1));\n  }\n  async refreshModels() {\n    const timeoutMs = 15e3;\n    let timedOut = false;\n    this.refreshTimeout = setTimeout(() => {\n      timedOut = true;\n      this.refreshAbortController.abort();\n    }, timeoutMs);\n    try {\n      const result = await refreshModelCatalogs(this.modelRuntime, this.refreshAbortController.signal);\n      if (this.closed)\n        return;\n      this.refreshStatusMessage = \"\";\n      if (result.aborted && timedOut) {\n        this.errorMessage = \"Model refresh timed out; showing cached models.\";\n      } else if (result.errors.size === 1) {\n        this.errorMessage = `Could not refresh ${result.errors.keys().next().value}; showing cached models.`;\n      } else if (result.errors.size > 1) {\n        this.errorMessage = `Could not refresh ${result.errors.size} model catalogs (${[...result.errors.keys()].join(\", \")}); showing cached models.`;\n      } else {\n        this.errorMessage = this.modelRuntime.getError();\n        if (!this.errorMessage) {\n          this.refreshStatusMessage = \"Model catalogs refreshed.\";\n          this.refreshStatusSuccess = true;\n        }\n      }\n      this.loadModelsFromSnapshot();\n      this.filterModels(this.searchInput.getValue());\n      this.tui.requestRender();\n    } catch (error) {\n      if (this.closed)\n        return;\n      this.refreshStatusMessage = \"\";\n      this.errorMessage = timedOut ? \"Model refresh timed out; showing cached models.\" : `Could not refresh model catalogs: ${error instanceof Error ? error.message : String(error)}`;\n      this.updateList();\n      this.tui.requestRender();\n    } finally {\n      if (this.refreshTimeout)\n        clearTimeout(this.refreshTimeout);\n    }\n  }\n  dispose() {\n    if (this.closed)\n      return;\n    this.closed = true;\n    if (this.refreshTimeout)\n      clearTimeout(this.refreshTimeout);\n    this.refreshAbortController.abort();\n  }\n  sortModels(models) {\n    const sorted = [...models];\n    sorted.sort((a, b) => {\n      const aIsCurrent = modelsAreEqual(this.currentModel, a.model);\n      const bIsCurrent = modelsAreEqual(this.currentModel, b.model);\n      if (aIsCurrent && !bIsCurrent)\n        return -1;\n      if (!aIsCurrent && bIsCurrent)\n        return 1;\n      return a.provider.localeCompare(b.provider);\n    });\n    return sorted;\n  }\n  getScopeText() {\n    const allText = this.scope === \"all\" ? theme.fg(\"accent\", \"all\") : theme.fg(\"muted\", \"all\");\n    const scopedText = this.scope === \"scoped\" ? theme.fg(\"accent\", \"scoped\") : theme.fg(\"muted\", \"scoped\");\n    return `${theme.fg(\"muted\", \"Scope: \")}${allText}${theme.fg(\"muted\", \" | \")}${scopedText}`;\n  }\n  getScopeHintText() {\n    return keyHint(\"tui.input.tab\", \"scope\") + theme.fg(\"muted\", \" (all/scoped)\");\n  }\n  setScope(scope) {\n    if (this.scope === scope)\n      return;\n    this.scope = scope;\n    this.activeModels = this.scope === \"scoped\" ? this.scopedModelItems : this.allModels;\n    const currentIndex = this.activeModels.findIndex((item) => modelsAreEqual(this.currentModel, item.model));\n    this.selectedIndex = currentIndex >= 0 ? currentIndex : 0;\n    this.filterModels(this.searchInput.getValue());\n    if (this.scopeText) {\n      this.scopeText.setText(this.getScopeText());\n    }\n  }\n  filterModels(query) {\n    this.filteredModels = query ? fuzzyFilter(this.activeModels, query, ({ id, provider, model }) => getModelSelectorSearchText({ id, provider, name: model.name })) : this.activeModels;\n    this.selectedIndex = query ? 0 : Math.min(this.selectedIndex, Math.max(0, this.filteredModels.length - 1));\n    this.updateList();\n  }\n  updateList() {\n    this.listContainer.clear();\n    const maxVisible = 10;\n    const startIndex = Math.max(0, Math.min(this.selectedIndex - Math.floor(maxVisible / 2), this.filteredModels.length - maxVisible));\n    const endIndex = Math.min(startIndex + maxVisible, this.filteredModels.length);\n    for (let i = startIndex; i < endIndex; i++) {\n      const item = this.filteredModels[i];\n      if (!item)\n        continue;\n      const isSelected = i === this.selectedIndex;\n      const isCurrent = modelsAreEqual(this.currentModel, item.model);\n      let line = \"\";\n      if (isSelected) {\n        const prefix = theme.fg(\"accent\", \"\\u2192 \");\n        const modelText = `${item.id}`;\n        const providerBadge = theme.fg(\"muted\", `[${item.provider}]`);\n        const checkmark = isCurrent ? theme.fg(\"success\", \" \\u2713\") : \"\";\n        line = `${prefix + theme.fg(\"accent\", modelText)} ${providerBadge}${checkmark}`;\n      } else {\n        const modelText = `  ${item.id}`;\n        const providerBadge = theme.fg(\"muted\", `[${item.provider}]`);\n        const checkmark = isCurrent ? theme.fg(\"success\", \" \\u2713\") : \"\";\n        line = `${modelText} ${providerBadge}${checkmark}`;\n      }\n      this.listContainer.addChild(new Text(line, 0, 0));\n    }\n    if (startIndex > 0 || endIndex < this.filteredModels.length) {\n      const scrollInfo = theme.fg(\"muted\", `  (${this.selectedIndex + 1}/${this.filteredModels.length})`);\n      this.listContainer.addChild(new Text(scrollInfo, 0, 0));\n    }\n    if (this.errorMessage) {\n      const errorLines = this.errorMessage.split(\"\\n\");\n      for (const line of errorLines) {\n        this.listContainer.addChild(new Text(theme.fg(\"error\", line), 0, 0));\n      }\n    } else if (this.filteredModels.length === 0) {\n      this.listContainer.addChild(new Text(theme.fg(\"muted\", \"  No matching models\"), 0, 0));\n    } else {\n      const selected = this.filteredModels[this.selectedIndex];\n      this.listContainer.addChild(new Spacer(1));\n      this.listContainer.addChild(new Text(theme.fg(\"muted\", `  Model Name: ${selected.model.name}`), 0, 0));\n    }\n    if (this.refreshStatusMessage) {\n      this.listContainer.addChild(new Spacer(1));\n      this.listContainer.addChild(new Text(theme.fg(this.refreshStatusSuccess ? \"success\" : \"muted\", `  ${this.refreshStatusMessage}`), 0, 0));\n    }\n  }\n  handleInput(keyData) {\n    const kb = getKeybindings();\n    if (kb.matches(keyData, \"tui.input.tab\")) {\n      if (this.scopedModelItems.length > 0) {\n        const nextScope = this.scope === \"all\" ? \"scoped\" : \"all\";\n        this.setScope(nextScope);\n        if (this.scopeHintText) {\n          this.scopeHintText.setText(this.getScopeHintText());\n        }\n      }\n      return;\n    }\n    if (kb.matches(keyData, \"tui.select.up\")) {\n      if (this.filteredModels.length === 0)\n        return;\n      this.selectedIndex = this.selectedIndex === 0 ? this.filteredModels.length - 1 : this.selectedIndex - 1;\n      this.updateList();\n    } else if (kb.matches(keyData, \"tui.select.down\")) {\n      if (this.filteredModels.length === 0)\n        return;\n      this.selectedIndex = this.selectedIndex === this.filteredModels.length - 1 ? 0 : this.selectedIndex + 1;\n      this.updateList();\n    } else if (kb.matches(keyData, \"tui.select.confirm\")) {\n      const selectedModel = this.filteredModels[this.selectedIndex];\n      if (selectedModel) {\n        this.handleSelect(selectedModel.model);\n      }\n    } else if (kb.matches(keyData, \"tui.select.cancel\")) {\n      this.dispose();\n      this.onCancelCallback();\n    } else {\n      this.searchInput.handleInput(keyData);\n      this.filterModels(this.searchInput.getValue());\n    }\n  }\n  handleSelect(model) {\n    this.dispose();\n    this.settingsManager.setDefaultModelAndProvider(model.provider, model.id);\n    this.onSelectCallback(model);\n  }\n  getSearchInput() {\n    return this.searchInput;\n  }\n};\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/oauth-selector.js\nfunction formatAuthSelectorProviderType(authType) {\n  return authType === \"oauth\" ? \"subscription\" : \"API key\";\n}\nvar OAuthSelectorComponent = class extends Container {\n  searchInput;\n  // Focusable implementation - propagate to search input for IME cursor positioning\n  _focused = false;\n  get focused() {\n    return this._focused;\n  }\n  set focused(value) {\n    this._focused = value;\n    this.searchInput.focused = value;\n  }\n  listContainer;\n  allProviders;\n  filteredProviders;\n  selectedIndex = 0;\n  mode;\n  onSelectCallback;\n  onCancelCallback;\n  showAuthTypeLabels;\n  constructor(mode, providers, onSelect, onCancel, initialSearchInput) {\n    super();\n    this.mode = mode;\n    this.allProviders = providers;\n    this.filteredProviders = providers;\n    this.showAuthTypeLabels = new Set(providers.map((provider) => provider.authType)).size > 1;\n    this.onSelectCallback = onSelect;\n    this.onCancelCallback = onCancel;\n    this.addChild(new DynamicBorder());\n    this.addChild(new Spacer(1));\n    const title = mode === \"login\" ? \"Select provider to configure:\" : \"Select provider to logout:\";\n    this.addChild(new TruncatedText(theme.fg(\"accent\", theme.bold(title)), 1, 0));\n    this.addChild(new Spacer(1));\n    this.searchInput = new Input();\n    if (initialSearchInput) {\n      this.searchInput.setValue(initialSearchInput);\n    }\n    this.searchInput.onSubmit = () => {\n      const selectedProvider = this.filteredProviders[this.selectedIndex];\n      if (selectedProvider) {\n        this.onSelectCallback(selectedProvider.id, selectedProvider.authType);\n      }\n    };\n    this.addChild(this.searchInput);\n    this.addChild(new Spacer(1));\n    this.listContainer = new Container();\n    this.addChild(this.listContainer);\n    this.addChild(new Spacer(1));\n    this.addChild(new DynamicBorder());\n    this.filterProviders(initialSearchInput ?? \"\");\n  }\n  filterProviders(query) {\n    this.filteredProviders = query ? fuzzyFilter(this.allProviders, query, (provider) => `${provider.name} ${provider.id} ${provider.authType} ${provider.method?.name ?? \"\"}`) : this.allProviders;\n    this.selectedIndex = Math.max(0, Math.min(this.selectedIndex, Math.max(0, this.filteredProviders.length - 1)));\n    this.updateList();\n  }\n  updateList() {\n    this.listContainer.clear();\n    const maxVisible = 8;\n    const startIndex = Math.max(0, Math.min(this.selectedIndex - Math.floor(maxVisible / 2), this.filteredProviders.length - maxVisible));\n    const endIndex = Math.min(startIndex + maxVisible, this.filteredProviders.length);\n    for (let i = startIndex; i < endIndex; i++) {\n      const provider = this.filteredProviders[i];\n      if (!provider)\n        continue;\n      const isSelected = i === this.selectedIndex;\n      const statusIndicator = this.formatStatusIndicator(provider);\n      const authTypeLabel = this.showAuthTypeLabels ? theme.fg(\"muted\", ` [${formatAuthSelectorProviderType(provider.authType)}]`) : \"\";\n      let line = \"\";\n      if (isSelected) {\n        const prefix = theme.fg(\"accent\", \"\\u2192 \");\n        const text = theme.fg(\"accent\", provider.name);\n        line = prefix + text + authTypeLabel + statusIndicator;\n      } else {\n        const text = `  ${theme.fg(\"text\", provider.name)}`;\n        line = text + authTypeLabel + statusIndicator;\n      }\n      this.listContainer.addChild(new TruncatedText(line, 1, 0));\n    }\n    if (startIndex > 0 || endIndex < this.filteredProviders.length) {\n      const scrollInfo = theme.fg(\"muted\", `  (${this.selectedIndex + 1}/${this.filteredProviders.length})`);\n      this.listContainer.addChild(new TruncatedText(scrollInfo, 1, 0));\n    }\n    if (this.filteredProviders.length === 0) {\n      const message = this.allProviders.length === 0 ? this.mode === \"login\" ? \"No providers available\" : \"No providers logged in. Use /login first.\" : \"No matching providers\";\n      this.listContainer.addChild(new TruncatedText(theme.fg(\"muted\", `  ${message}`), 1, 0));\n    }\n  }\n  formatStatusIndicator(provider) {\n    if (!provider.status)\n      return theme.fg(\"muted\", \" \\u2022 unconfigured\");\n    if (provider.status.type !== provider.authType) {\n      const label = provider.status.type === \"oauth\" ? \"subscription configured\" : \"API key configured\";\n      return theme.fg(\"muted\", \" \\u2022 \") + theme.fg(\"warning\", label);\n    }\n    if (!provider.status.source || provider.status.source === \"OAuth\" || provider.status.source === \"stored credential\") {\n      return theme.fg(\"success\", \" \\u2713 configured\");\n    }\n    const source = /^[A-Z][A-Z0-9_]*(?:, [A-Z][A-Z0-9_]*)*$/.test(provider.status.source) ? `env: ${provider.status.source}` : provider.status.source;\n    return theme.fg(\"success\", ` \\u2713 ${source}`);\n  }\n  handleInput(keyData) {\n    const kb = getKeybindings();\n    if (kb.matches(keyData, \"tui.select.up\")) {\n      if (this.filteredProviders.length === 0)\n        return;\n      this.selectedIndex = Math.max(0, this.selectedIndex - 1);\n      this.updateList();\n    } else if (kb.matches(keyData, \"tui.select.down\")) {\n      if (this.filteredProviders.length === 0)\n        return;\n      this.selectedIndex = Math.min(this.filteredProviders.length - 1, this.selectedIndex + 1);\n      this.updateList();\n    } else if (kb.matches(keyData, \"tui.select.confirm\")) {\n      const selectedProvider = this.filteredProviders[this.selectedIndex];\n      if (selectedProvider) {\n        this.onSelectCallback(selectedProvider.id, selectedProvider.authType);\n      }\n    } else if (kb.matches(keyData, \"tui.select.cancel\")) {\n      this.onCancelCallback();\n    } else {\n      this.searchInput.handleInput(keyData);\n      this.filterProviders(this.searchInput.getValue());\n    }\n  }\n};\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/scoped-models-selector.js\nfunction isEnabled(enabledIds, id) {\n  return enabledIds === null || enabledIds.includes(id);\n}\nfunction toggle(enabledIds, id) {\n  if (enabledIds === null)\n    return [id];\n  const index = enabledIds.indexOf(id);\n  if (index >= 0)\n    return [...enabledIds.slice(0, index), ...enabledIds.slice(index + 1)];\n  return [...enabledIds, id];\n}\nfunction enableAll(enabledIds, allIds, targetIds) {\n  if (enabledIds === null)\n    return null;\n  const targets = targetIds ?? allIds;\n  const result = [...enabledIds];\n  for (const id of targets) {\n    if (!result.includes(id))\n      result.push(id);\n  }\n  return result.length === allIds.length && result.every((id) => allIds.includes(id)) ? null : result;\n}\nfunction clearAll(enabledIds, allIds, targetIds) {\n  if (enabledIds === null) {\n    return targetIds ? allIds.filter((id) => !targetIds.includes(id)) : [];\n  }\n  const targets = new Set(targetIds ?? enabledIds);\n  return enabledIds.filter((id) => !targets.has(id));\n}\nfunction move(enabledIds, id, delta) {\n  if (enabledIds === null)\n    return null;\n  const list = [...enabledIds];\n  const index = list.indexOf(id);\n  if (index < 0)\n    return list;\n  const newIndex = index + delta;\n  if (newIndex < 0 || newIndex >= list.length)\n    return list;\n  const result = [...list];\n  [result[index], result[newIndex]] = [result[newIndex], result[index]];\n  return result;\n}\nfunction getSortedIds(enabledIds, allIds) {\n  if (enabledIds === null)\n    return allIds;\n  const enabledSet = new Set(enabledIds);\n  return [...enabledIds, ...allIds.filter((id) => !enabledSet.has(id))];\n}\nvar ScopedModelsSelectorComponent = class extends Container {\n  modelsById = /* @__PURE__ */ new Map();\n  allIds = [];\n  enabledIds = null;\n  filteredItems = [];\n  selectedIndex = 0;\n  searchInput;\n  // Focusable implementation - propagate to searchInput for IME cursor positioning\n  _focused = false;\n  get focused() {\n    return this._focused;\n  }\n  set focused(value) {\n    this._focused = value;\n    this.searchInput.focused = value;\n  }\n  listContainer;\n  footerText;\n  callbacks;\n  maxVisible = 8;\n  isDirty = false;\n  refreshStatusText;\n  constructor(config, callbacks) {\n    super();\n    this.callbacks = callbacks;\n    for (const model of config.allModels) {\n      const fullId = `${model.provider}/${model.id}`;\n      this.modelsById.set(fullId, model);\n      this.allIds.push(fullId);\n    }\n    this.enabledIds = config.enabledModelIds === null ? null : [...config.enabledModelIds];\n    this.filteredItems = this.buildItems();\n    this.addChild(new DynamicBorder());\n    this.addChild(new Spacer(1));\n    this.addChild(new Text(theme.fg(\"accent\", theme.bold(\"Model Configuration\")), 0, 0));\n    this.addChild(new Text(theme.fg(\"muted\", `Session-only. ${keyText(\"app.models.save\")} to save to settings.`), 0, 0));\n    this.addChild(new Spacer(1));\n    this.searchInput = new Input();\n    this.addChild(this.searchInput);\n    this.addChild(new Spacer(1));\n    this.listContainer = new Container();\n    this.addChild(this.listContainer);\n    this.addChild(new Spacer(1));\n    if (config.refreshStatus) {\n      this.refreshStatusText = new Text(theme.fg(\"muted\", `  ${config.refreshStatus}`), 0, 0);\n      this.addChild(this.refreshStatusText);\n    }\n    this.footerText = new Text(this.getFooterText(), 0, 0);\n    this.addChild(this.footerText);\n    this.addChild(new DynamicBorder());\n    this.updateList();\n  }\n  updateModels(models, enabledModelIds) {\n    const selectedId = this.filteredItems[this.selectedIndex]?.fullId;\n    if (enabledModelIds !== void 0)\n      this.enabledIds = enabledModelIds === null ? null : [...enabledModelIds];\n    this.modelsById.clear();\n    this.allIds = [];\n    for (const model of models) {\n      const fullId = `${model.provider}/${model.id}`;\n      this.modelsById.set(fullId, model);\n      this.allIds.push(fullId);\n    }\n    this.refresh();\n    const refreshedIndex = selectedId ? this.filteredItems.findIndex((item) => item.fullId === selectedId) : -1;\n    if (refreshedIndex >= 0) {\n      this.selectedIndex = refreshedIndex;\n      this.updateList();\n    }\n  }\n  setRefreshStatus(message, kind) {\n    this.refreshStatusText?.setText(theme.fg(kind, `  ${message}`));\n  }\n  buildItems() {\n    return getSortedIds(this.enabledIds, this.allIds).map((id) => ({\n      fullId: id,\n      model: this.modelsById.get(id),\n      enabled: isEnabled(this.enabledIds, id)\n    }));\n  }\n  getFooterText() {\n    const enabledCount = this.enabledIds?.filter((id) => this.modelsById.has(id)).length ?? this.allIds.length;\n    const unavailableCount = this.enabledIds?.filter((id) => !this.modelsById.has(id)).length ?? 0;\n    const allEnabled = this.enabledIds === null;\n    const countText = allEnabled ? \"all enabled\" : `${enabledCount}/${this.allIds.length} enabled${unavailableCount ? ` \\xB7 ${unavailableCount} unavailable` : \"\"}`;\n    const parts = [\n      `${keyText(\"tui.select.confirm\")} toggle`,\n      `${keyText(\"app.models.enableAll\")} all`,\n      `${keyText(\"app.models.clearAll\")} clear`,\n      `${keyText(\"app.models.toggleProvider\")} provider`,\n      `${keyText(\"app.models.reorderUp\")}/${keyText(\"app.models.reorderDown\")} reorder`,\n      `${keyText(\"app.models.save\")} save`,\n      countText\n    ];\n    return this.isDirty ? theme.fg(\"dim\", `  ${parts.join(\" \\xB7 \")} `) + theme.fg(\"warning\", \"(unsaved)\") : theme.fg(\"dim\", `  ${parts.join(\" \\xB7 \")}`);\n  }\n  refresh() {\n    const query = this.searchInput.getValue();\n    const items = this.buildItems();\n    this.filteredItems = query ? fuzzyFilter(items, query, (item) => item.model ? getModelSearchText({ id: item.model.id, provider: item.model.provider, name: item.model.name }) : item.fullId) : items;\n    this.selectedIndex = Math.min(this.selectedIndex, Math.max(0, this.filteredItems.length - 1));\n    this.updateList();\n    this.footerText.setText(this.getFooterText());\n  }\n  notifyChange() {\n    this.callbacks.onChange(this.enabledIds === null ? null : [...this.enabledIds]);\n  }\n  updateList() {\n    this.listContainer.clear();\n    if (this.filteredItems.length === 0) {\n      this.listContainer.addChild(new Text(theme.fg(\"muted\", \"  No matching models\"), 0, 0));\n      return;\n    }\n    const startIndex = Math.max(0, Math.min(this.selectedIndex - Math.floor(this.maxVisible / 2), this.filteredItems.length - this.maxVisible));\n    const endIndex = Math.min(startIndex + this.maxVisible, this.filteredItems.length);\n    const allEnabled = this.enabledIds === null;\n    for (let i = startIndex; i < endIndex; i++) {\n      const item = this.filteredItems[i];\n      const isSelected = i === this.selectedIndex;\n      const prefix = isSelected ? theme.fg(\"accent\", \"\\u2192 \") : \"  \";\n      const id = item.model?.id ?? item.fullId;\n      const modelText = isSelected ? theme.fg(\"accent\", id) : id;\n      const providerBadge = theme.fg(\"muted\", item.model ? ` [${item.model.provider}]` : \" [unavailable]\");\n      const status = item.model ? allEnabled ? \"\" : item.enabled ? theme.fg(\"success\", \" \\u2713\") : theme.fg(\"dim\", \" \\u2717\") : theme.fg(\"dim\", \" \\u2717\");\n      this.listContainer.addChild(new Text(`${prefix}${modelText}${providerBadge}${status}`, 0, 0));\n    }\n    if (startIndex > 0 || endIndex < this.filteredItems.length) {\n      this.listContainer.addChild(new Text(theme.fg(\"muted\", `  (${this.selectedIndex + 1}/${this.filteredItems.length})`), 0, 0));\n    }\n    if (this.filteredItems.length > 0) {\n      const selected = this.filteredItems[this.selectedIndex];\n      this.listContainer.addChild(new Spacer(1));\n      this.listContainer.addChild(new Text(theme.fg(\"muted\", `  ${selected.model ? `Model Name: ${selected.model.name}` : \"Model unavailable\"}`), 0, 0));\n    }\n  }\n  handleInput(data) {\n    const kb = getKeybindings();\n    if (kb.matches(data, \"tui.select.up\")) {\n      if (this.filteredItems.length === 0)\n        return;\n      this.selectedIndex = this.selectedIndex === 0 ? this.filteredItems.length - 1 : this.selectedIndex - 1;\n      this.updateList();\n      return;\n    }\n    if (kb.matches(data, \"tui.select.down\")) {\n      if (this.filteredItems.length === 0)\n        return;\n      this.selectedIndex = this.selectedIndex === this.filteredItems.length - 1 ? 0 : this.selectedIndex + 1;\n      this.updateList();\n      return;\n    }\n    const reorderUp = kb.matches(data, \"app.models.reorderUp\");\n    const reorderDown = kb.matches(data, \"app.models.reorderDown\");\n    if (reorderUp || reorderDown) {\n      if (this.enabledIds === null)\n        return;\n      const item = this.filteredItems[this.selectedIndex];\n      if (item && isEnabled(this.enabledIds, item.fullId)) {\n        const delta = reorderUp ? -1 : 1;\n        const currentIndex = this.enabledIds.indexOf(item.fullId);\n        const newIndex = currentIndex + delta;\n        if (newIndex >= 0 && newIndex < this.enabledIds.length) {\n          this.enabledIds = move(this.enabledIds, item.fullId, delta);\n          this.isDirty = true;\n          this.selectedIndex += delta;\n          this.refresh();\n          this.notifyChange();\n        }\n      }\n      return;\n    }\n    if (kb.matches(data, \"tui.select.confirm\")) {\n      const item = this.filteredItems[this.selectedIndex];\n      if (item) {\n        this.enabledIds = toggle(this.enabledIds, item.fullId);\n        this.isDirty = true;\n        this.refresh();\n        this.notifyChange();\n      }\n      return;\n    }\n    if (kb.matches(data, \"app.models.enableAll\")) {\n      const targetIds = this.searchInput.getValue() ? this.filteredItems.map((i) => i.fullId) : void 0;\n      this.enabledIds = enableAll(this.enabledIds, this.allIds, targetIds);\n      this.isDirty = true;\n      this.refresh();\n      this.notifyChange();\n      return;\n    }\n    if (kb.matches(data, \"app.models.clearAll\")) {\n      const targetIds = this.searchInput.getValue() ? this.filteredItems.map((i) => i.fullId) : void 0;\n      this.enabledIds = clearAll(this.enabledIds, this.allIds, targetIds);\n      this.isDirty = true;\n      this.refresh();\n      this.notifyChange();\n      return;\n    }\n    if (kb.matches(data, \"app.models.toggleProvider\")) {\n      const item = this.filteredItems[this.selectedIndex];\n      if (item?.model) {\n        const provider = item.model.provider;\n        const providerIds = this.allIds.filter((id) => this.modelsById.get(id).provider === provider);\n        const allEnabled = providerIds.every((id) => isEnabled(this.enabledIds, id));\n        this.enabledIds = allEnabled ? clearAll(this.enabledIds, this.allIds, providerIds) : enableAll(this.enabledIds, this.allIds, providerIds);\n        this.isDirty = true;\n        this.refresh();\n        this.notifyChange();\n      }\n      return;\n    }\n    if (kb.matches(data, \"app.models.save\")) {\n      this.callbacks.onPersist(this.enabledIds === null ? null : [...this.enabledIds]);\n      this.isDirty = false;\n      this.footerText.setText(this.getFooterText());\n      return;\n    }\n    if (matchesKey(data, Key.ctrl(\"c\"))) {\n      if (this.searchInput.getValue()) {\n        this.searchInput.setValue(\"\");\n        this.refresh();\n      } else {\n        this.callbacks.onCancel();\n      }\n      return;\n    }\n    if (matchesKey(data, Key.escape)) {\n      this.callbacks.onCancel();\n      return;\n    }\n    this.searchInput.handleInput(data);\n    this.refresh();\n  }\n  getSearchInput() {\n    return this.searchInput;\n  }\n};\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/settings-selector.js\nvar SETTINGS_SUBMENU_SELECT_LIST_LAYOUT = {\n  minPrimaryColumnWidth: 12,\n  maxPrimaryColumnWidth: 32\n};\nvar THINKING_DESCRIPTIONS = {\n  off: \"No reasoning\",\n  minimal: \"Very brief reasoning (~1k tokens)\",\n  low: \"Light reasoning (~2k tokens)\",\n  medium: \"Moderate reasoning (~8k tokens)\",\n  high: \"Deep reasoning (~16k tokens)\",\n  xhigh: \"Extra-high reasoning (~32k tokens)\",\n  max: \"Maximum reasoning\"\n};\nvar DEFAULT_PROJECT_TRUST_LABELS = {\n  ask: \"Ask\",\n  always: \"Always trust\",\n  never: \"Never trust\"\n};\nvar DEFAULT_PROJECT_TRUST_BY_LABEL = new Map(Object.entries(DEFAULT_PROJECT_TRUST_LABELS).map(([value, label]) => [label, value]));\nvar WarningSettingsSubmenu = class extends Container {\n  settingsList;\n  state;\n  constructor(warnings, onChange, onCancel) {\n    super();\n    this.state = { ...warnings };\n    const items = [\n      {\n        id: \"anthropic-extra-usage\",\n        label: \"Anthropic extra usage\",\n        description: \"Warn when Anthropic subscription auth may use paid extra usage\",\n        currentValue: this.state.anthropicExtraUsage ?? true ? \"true\" : \"false\",\n        values: [\"true\", \"false\"]\n      }\n    ];\n    this.settingsList = new SettingsList(items, Math.min(items.length, 10), getSettingsListTheme(), (id, newValue) => {\n      switch (id) {\n        case \"anthropic-extra-usage\":\n          this.state = { ...this.state, anthropicExtraUsage: newValue === \"true\" };\n          onChange({ ...this.state });\n          break;\n      }\n    }, onCancel);\n    this.addChild(this.settingsList);\n  }\n  handleInput(data) {\n    this.settingsList.handleInput(data);\n  }\n};\nvar SelectSubmenu = class extends Container {\n  selectList;\n  constructor(title, description, options, currentValue, onSelect, onCancel, onSelectionChange) {\n    super();\n    this.addChild(new Text(theme.bold(theme.fg(\"accent\", title)), 0, 0));\n    if (description) {\n      this.addChild(new Spacer(1));\n      this.addChild(new Text(theme.fg(\"muted\", description), 0, 0));\n    }\n    this.addChild(new Spacer(1));\n    this.selectList = new SelectList(options, Math.min(options.length, 10), getSelectListTheme(), SETTINGS_SUBMENU_SELECT_LIST_LAYOUT);\n    const currentIndex = options.findIndex((o) => o.value === currentValue);\n    if (currentIndex !== -1) {\n      this.selectList.setSelectedIndex(currentIndex);\n    }\n    this.selectList.onSelect = (item) => {\n      onSelect(item.value);\n    };\n    this.selectList.onCancel = onCancel;\n    if (onSelectionChange) {\n      this.selectList.onSelectionChange = (item) => {\n        onSelectionChange(item.value);\n      };\n    }\n    this.addChild(this.selectList);\n    this.addChild(new Spacer(1));\n    this.addChild(new Text(theme.fg(\"dim\", \"  Enter to select \\xB7 Esc to go back\"), 0, 0));\n  }\n  handleInput(data) {\n    this.selectList.handleInput(data);\n  }\n};\nfunction themeItems(availableThemes) {\n  return availableThemes.map((name) => ({ value: name, label: name }));\n}\nvar AUTOMATIC_THEME_VALUE = \"/\";\nfunction singleModeThemeItems(availableThemes) {\n  return [\n    {\n      value: AUTOMATIC_THEME_VALUE,\n      label: \"Automatic\",\n      description: \"Use separate themes for light and dark terminal appearance\"\n    },\n    ...themeItems(availableThemes)\n  ];\n}\nfunction preferredTheme(availableThemes, preferred, fallback) {\n  if (preferred && availableThemes.includes(preferred))\n    return preferred;\n  if (availableThemes.includes(fallback))\n    return fallback;\n  return availableThemes[0] ?? fallback;\n}\nfunction defaultAutomaticThemes(currentThemeSetting, availableThemes) {\n  const autoTheme = parseAutoThemeSetting(currentThemeSetting);\n  if (autoTheme)\n    return autoTheme;\n  const currentFixedTheme = currentThemeSetting.includes(\"/\") ? void 0 : currentThemeSetting;\n  const themeName = preferredTheme(availableThemes, currentFixedTheme, \"dark\");\n  return { lightTheme: themeName, darkTheme: themeName };\n}\nvar ThemeSubmenu = class extends Container {\n  inputComponent;\n  callbacks;\n  availableThemes;\n  terminalTheme;\n  onDone;\n  originalThemeSetting;\n  mode;\n  singleTheme;\n  lightTheme;\n  darkTheme;\n  constructor(currentThemeSetting, terminalTheme, availableThemes, callbacks, onDone) {\n    super();\n    this.callbacks = callbacks;\n    this.availableThemes = availableThemes;\n    this.terminalTheme = terminalTheme;\n    this.onDone = onDone;\n    this.originalThemeSetting = currentThemeSetting;\n    const autoTheme = parseAutoThemeSetting(currentThemeSetting);\n    const automaticThemes = defaultAutomaticThemes(currentThemeSetting, availableThemes);\n    const fixedTheme = autoTheme || currentThemeSetting.includes(\"/\") ? void 0 : currentThemeSetting;\n    this.mode = autoTheme ? \"automatic\" : \"single\";\n    this.lightTheme = automaticThemes.lightTheme;\n    this.darkTheme = automaticThemes.darkTheme;\n    this.singleTheme = preferredTheme(availableThemes, fixedTheme ?? (autoTheme ? this.getActiveAutomaticTheme() : void 0), \"dark\");\n    if (this.mode === \"automatic\") {\n      this.showAutomaticMenu();\n    } else {\n      this.showSingleMenu();\n    }\n  }\n  handleInput(data) {\n    this.inputComponent?.handleInput?.(data);\n  }\n  setContent(renderComponent, inputComponent = renderComponent) {\n    this.clear();\n    this.addChild(renderComponent);\n    this.inputComponent = inputComponent;\n  }\n  showSingleMenu() {\n    this.mode = \"single\";\n    const menu = new SelectSubmenu(\"Theme\", \"Select a theme, or choose Automatic to follow terminal appearance.\", singleModeThemeItems(this.availableThemes), this.singleTheme, (value) => {\n      if (value === AUTOMATIC_THEME_VALUE) {\n        this.mode = \"automatic\";\n        this.callbacks.onThemePreview?.(this.getThemeSetting());\n        this.showAutomaticMenu();\n        return;\n      }\n      this.singleTheme = value;\n      this.apply(value);\n    }, () => this.cancel(), (value) => {\n      this.callbacks.onThemePreview?.(value === AUTOMATIC_THEME_VALUE ? this.getAutomaticThemeSetting() : value);\n    });\n    this.setContent(menu);\n  }\n  showAutomaticMenu() {\n    this.mode = \"automatic\";\n    const content = new Container();\n    content.addChild(new Text(theme.bold(theme.fg(\"accent\", \"Automatic Theme\")), 0, 0));\n    content.addChild(new Spacer(1));\n    content.addChild(new Text(theme.fg(\"muted\", \"Choose themes for terminal light and dark appearance.\"), 0, 0));\n    content.addChild(new Text(theme.fg(\"muted\", \"Light/dark detection requires terminal support.\"), 0, 0));\n    content.addChild(new Spacer(1));\n    const items = [\n      {\n        id: \"light-theme\",\n        label: \"Light theme\",\n        description: \"Theme to use in automatic mode when the terminal is light\",\n        currentValue: this.lightTheme,\n        submenu: (currentValue, done) => this.createThemeSelect(\"Light Theme\", \"Select the theme to use for light terminal appearance\", currentValue, done, (value) => {\n          this.lightTheme = value;\n          this.callbacks.onThemePreview?.(this.getThemeSetting());\n          done(value);\n        })\n      },\n      {\n        id: \"dark-theme\",\n        label: \"Dark theme\",\n        description: \"Theme to use in automatic mode when the terminal is dark\",\n        currentValue: this.darkTheme,\n        submenu: (currentValue, done) => this.createThemeSelect(\"Dark Theme\", \"Select the theme to use for dark terminal appearance\", currentValue, done, (value) => {\n          this.darkTheme = value;\n          this.callbacks.onThemePreview?.(this.getThemeSetting());\n          done(value);\n        })\n      },\n      {\n        id: \"apply\",\n        label: \"Apply\",\n        description: \"Save and go back\",\n        currentValue: \"save and go back\",\n        values: [\"save and go back\"]\n      },\n      {\n        id: \"single-mode\",\n        label: \"Change mode\",\n        description: \"Switch to one theme for light and dark\",\n        currentValue: \"switch to single theme\",\n        values: [\"switch to single theme\"]\n      }\n    ];\n    const settingsList = new SettingsList(items, Math.min(items.length, 10), getSettingsListTheme(), (id) => {\n      switch (id) {\n        case \"single-mode\":\n          this.mode = \"single\";\n          this.singleTheme = this.getActiveAutomaticTheme();\n          this.callbacks.onThemePreview?.(this.singleTheme);\n          this.showSingleMenu();\n          break;\n        case \"apply\":\n          this.apply(this.getAutomaticThemeSetting());\n          break;\n      }\n    }, () => this.cancel());\n    content.addChild(settingsList);\n    this.setContent(content, settingsList);\n  }\n  createThemeSelect(title, description, currentValue, done, onSelect) {\n    return new SelectSubmenu(title, description, themeItems(this.availableThemes), currentValue, onSelect, () => {\n      this.callbacks.onThemePreview?.(this.getThemeSetting());\n      done();\n    }, (value) => this.callbacks.onThemePreview?.(value));\n  }\n  getThemeSetting() {\n    return this.mode === \"automatic\" ? this.getAutomaticThemeSetting() : this.singleTheme;\n  }\n  getActiveAutomaticTheme() {\n    return this.terminalTheme === \"light\" ? this.lightTheme : this.darkTheme;\n  }\n  getAutomaticThemeSetting() {\n    return `${this.lightTheme}/${this.darkTheme}`;\n  }\n  apply(themeSetting) {\n    this.onDone(themeSetting);\n  }\n  cancel() {\n    this.callbacks.onThemePreview?.(this.originalThemeSetting);\n    this.onDone();\n  }\n};\nvar SettingsSelectorComponent = class extends Container {\n  settingsList;\n  constructor(config, callbacks) {\n    super();\n    const supportsImages = getCapabilities().images;\n    const followUpKey = keyDisplayText(\"app.message.followUp\");\n    let currentWarnings = { ...config.warnings };\n    const items = [\n      {\n        id: \"autocompact\",\n        label: \"Auto-compact\",\n        description: \"Automatically compact context when it gets too large\",\n        currentValue: config.autoCompact ? \"true\" : \"false\",\n        values: [\"true\", \"false\"]\n      },\n      {\n        id: \"steering-mode\",\n        label: \"Steering mode\",\n        description: \"Enter while streaming queues steering messages. 'one-at-a-time': deliver one, wait for response. 'all': deliver all at once.\",\n        currentValue: config.steeringMode,\n        values: [\"one-at-a-time\", \"all\"]\n      },\n      {\n        id: \"follow-up-mode\",\n        label: \"Follow-up mode\",\n        description: `${followUpKey} queues follow-up messages until agent stops. 'one-at-a-time': deliver one, wait for response. 'all': deliver all at once.`,\n        currentValue: config.followUpMode,\n        values: [\"one-at-a-time\", \"all\"]\n      },\n      {\n        id: \"transport\",\n        label: \"Transport\",\n        description: \"Preferred transport for providers that support multiple transports\",\n        currentValue: config.transport,\n        values: [\"sse\", \"websocket\", \"websocket-cached\", \"auto\"]\n      },\n      {\n        id: \"http-idle-timeout\",\n        label: \"HTTP idle timeout\",\n        description: \"Maximum idle gap while waiting for HTTP headers or body chunks. Disable for local models that pause longer than five minutes.\",\n        currentValue: formatHttpIdleTimeoutMs(config.httpIdleTimeoutMs),\n        values: HTTP_IDLE_TIMEOUT_CHOICES.map((choice) => choice.label)\n      },\n      {\n        id: \"hide-thinking\",\n        label: \"Hide thinking\",\n        description: \"Hide thinking blocks in assistant responses\",\n        currentValue: config.hideThinkingBlock ? \"true\" : \"false\",\n        values: [\"true\", \"false\"]\n      },\n      {\n        id: \"mermaid-rendering\",\n        label: \"Mermaid diagrams\",\n        description: \"Render Mermaid code blocks as Unicode diagrams\",\n        currentValue: config.mermaidRenderingMode,\n        values: [\"off\", \"final\", \"streaming\"]\n      },\n      {\n        id: \"cache-miss-notices\",\n        label: \"Cache miss notices\",\n        description: \"Show transcript notices for significant prompt-cache misses\",\n        currentValue: config.showCacheMissNotices ? \"true\" : \"false\",\n        values: [\"true\", \"false\"]\n      },\n      {\n        id: \"collapse-changelog\",\n        label: \"Collapse changelog\",\n        description: \"Show condensed changelog after updates\",\n        currentValue: config.collapseChangelog ? \"true\" : \"false\",\n        values: [\"true\", \"false\"]\n      },\n      {\n        id: \"quiet-startup\",\n        label: \"Quiet startup\",\n        description: \"Disable verbose printing at startup\",\n        currentValue: config.quietStartup ? \"true\" : \"false\",\n        values: [\"true\", \"false\"]\n      },\n      {\n        id: \"install-telemetry\",\n        label: \"Install telemetry\",\n        description: \"Send an anonymous version/update ping after changelog-detected updates\",\n        currentValue: config.enableInstallTelemetry ? \"true\" : \"false\",\n        values: [\"true\", \"false\"]\n      },\n      {\n        id: \"default-project-trust\",\n        label: \"Default project trust\",\n        description: \"Fallback behavior when no extension or saved trust decision decides project trust\",\n        currentValue: DEFAULT_PROJECT_TRUST_LABELS[config.defaultProjectTrust],\n        values: Object.values(DEFAULT_PROJECT_TRUST_LABELS)\n      },\n      {\n        id: \"double-escape-action\",\n        label: \"Double-escape action\",\n        description: \"Action when pressing Escape twice with empty editor\",\n        currentValue: config.doubleEscapeAction,\n        values: [\"tree\", \"fork\", \"none\"]\n      },\n      {\n        id: \"tree-filter-mode\",\n        label: \"Tree filter mode\",\n        description: \"Default filter when opening /tree\",\n        currentValue: config.treeFilterMode,\n        values: [\"default\", \"no-tools\", \"user-only\", \"labeled-only\", \"all\"]\n      },\n      {\n        id: \"warnings\",\n        label: \"Warnings\",\n        description: \"Enable or disable individual warnings\",\n        currentValue: \"configure\",\n        submenu: (_currentValue, done) => new WarningSettingsSubmenu(currentWarnings, (warnings) => {\n          currentWarnings = warnings;\n          callbacks.onWarningsChange(warnings);\n        }, () => done())\n      },\n      {\n        id: \"thinking\",\n        label: \"Thinking level\",\n        description: \"Reasoning depth for thinking-capable models\",\n        currentValue: config.thinkingLevel,\n        submenu: (currentValue, done) => new SelectSubmenu(\"Thinking Level\", \"Select reasoning depth for thinking-capable models\", config.availableThinkingLevels.map((level) => ({\n          value: level,\n          label: level,\n          description: THINKING_DESCRIPTIONS[level]\n        })), currentValue, (value) => {\n          callbacks.onThinkingLevelChange(value);\n          done(value);\n        }, () => done())\n      },\n      {\n        id: \"tui-mode\",\n        label: \"TUI mode\",\n        description: \"Interface layout; fullscreen mode is experimental\",\n        currentValue: config.tuiMode,\n        values: [\"regular\", \"fullscreen\"]\n      },\n      {\n        id: \"fullscreen-exit-output\",\n        label: \"Fullscreen exit output\",\n        description: \"Print the transcript or only a session resume hint when exiting fullscreen mode\",\n        currentValue: config.fullscreenExitOutput,\n        values: [\"transcript\", \"resume-hint\"]\n      },\n      {\n        id: \"fullscreen-scrollbar\",\n        label: \"Fullscreen scrollbar\",\n        description: \"Scrollbar behavior in fullscreen mode; has no effect in regular mode\",\n        currentValue: config.fullscreenScrollbar,\n        values: [\"auto\", \"always\", \"hidden\"]\n      },\n      {\n        id: \"theme\",\n        label: \"Theme\",\n        description: \"Color theme for the interface\",\n        currentValue: config.currentTheme,\n        submenu: (currentValue, done) => new ThemeSubmenu(currentValue, config.terminalTheme, config.availableThemes, callbacks, done)\n      }\n    ];\n    if (supportsImages) {\n      items.splice(1, 0, {\n        id: \"show-images\",\n        label: \"Show images\",\n        description: \"Render images inline in terminal\",\n        currentValue: config.showImages ? \"true\" : \"false\",\n        values: [\"true\", \"false\"]\n      });\n      items.splice(2, 0, {\n        id: \"image-width-cells\",\n        label: \"Image width\",\n        description: \"Preferred inline image width in terminal cells\",\n        currentValue: String(config.imageWidthCells),\n        values: [\"60\", \"80\", \"120\"]\n      });\n    }\n    items.splice(supportsImages ? 3 : 1, 0, {\n      id: \"auto-resize-images\",\n      label: \"Auto-resize images\",\n      description: \"Resize large images to 2000x2000 max for better model compatibility\",\n      currentValue: config.autoResizeImages ? \"true\" : \"false\",\n      values: [\"true\", \"false\"]\n    });\n    const autoResizeIndex = items.findIndex((item) => item.id === \"auto-resize-images\");\n    items.splice(autoResizeIndex + 1, 0, {\n      id: \"block-images\",\n      label: \"Block images\",\n      description: \"Prevent images from being sent to LLM providers\",\n      currentValue: config.blockImages ? \"true\" : \"false\",\n      values: [\"true\", \"false\"]\n    });\n    const blockImagesIndex = items.findIndex((item) => item.id === \"block-images\");\n    items.splice(blockImagesIndex + 1, 0, {\n      id: \"skill-commands\",\n      label: \"Skill commands\",\n      description: \"Register skills as /skill:name commands\",\n      currentValue: config.enableSkillCommands ? \"true\" : \"false\",\n      values: [\"true\", \"false\"]\n    });\n    const skillCommandsIndex = items.findIndex((item) => item.id === \"skill-commands\");\n    items.splice(skillCommandsIndex + 1, 0, {\n      id: \"show-hardware-cursor\",\n      label: \"Show hardware cursor\",\n      description: \"Show the terminal cursor while still positioning it for IME support\",\n      currentValue: config.showHardwareCursor ? \"true\" : \"false\",\n      values: [\"true\", \"false\"]\n    });\n    const hardwareCursorIndex = items.findIndex((item) => item.id === \"show-hardware-cursor\");\n    items.splice(hardwareCursorIndex + 1, 0, {\n      id: \"editor-padding\",\n      label: \"Editor padding\",\n      description: \"Horizontal padding for input editor (0-3)\",\n      currentValue: String(config.editorPaddingX),\n      values: [\"0\", \"1\", \"2\", \"3\"]\n    });\n    const editorPaddingIndex = items.findIndex((item) => item.id === \"editor-padding\");\n    items.splice(editorPaddingIndex + 1, 0, {\n      id: \"output-padding\",\n      label: \"Output padding\",\n      description: \"Horizontal padding for user messages, assistant messages, and thinking\",\n      currentValue: String(config.outputPad),\n      values: [\"0\", \"1\"]\n    });\n    const outputPaddingIndex = items.findIndex((item) => item.id === \"output-padding\");\n    items.splice(outputPaddingIndex + 1, 0, {\n      id: \"autocomplete-max-visible\",\n      label: \"Autocomplete max items\",\n      description: \"Max visible items in autocomplete dropdown (3-20)\",\n      currentValue: String(config.autocompleteMaxVisible),\n      values: [\"3\", \"5\", \"7\", \"10\", \"15\", \"20\"]\n    });\n    const autocompleteIndex = items.findIndex((item) => item.id === \"autocomplete-max-visible\");\n    items.splice(autocompleteIndex + 1, 0, {\n      id: \"clear-on-shrink\",\n      label: \"Clear on shrink\",\n      description: \"Clear empty rows when content shrinks (may cause flicker)\",\n      currentValue: config.clearOnShrink ? \"true\" : \"false\",\n      values: [\"true\", \"false\"]\n    });\n    const clearOnShrinkIndex = items.findIndex((item) => item.id === \"clear-on-shrink\");\n    items.splice(clearOnShrinkIndex + 1, 0, {\n      id: \"terminal-progress\",\n      label: \"Terminal progress\",\n      description: \"Show OSC 9;4 progress indicators in the terminal tab bar\",\n      currentValue: config.showTerminalProgress ? \"true\" : \"false\",\n      values: [\"true\", \"false\"]\n    });\n    this.addChild(new DynamicBorder());\n    this.settingsList = new SettingsList(items, 10, getSettingsListTheme(), (id, newValue) => {\n      switch (id) {\n        case \"autocompact\":\n          callbacks.onAutoCompactChange(newValue === \"true\");\n          break;\n        case \"show-images\":\n          callbacks.onShowImagesChange(newValue === \"true\");\n          break;\n        case \"image-width-cells\":\n          callbacks.onImageWidthCellsChange(parseInt(newValue, 10));\n          break;\n        case \"auto-resize-images\":\n          callbacks.onAutoResizeImagesChange(newValue === \"true\");\n          break;\n        case \"block-images\":\n          callbacks.onBlockImagesChange(newValue === \"true\");\n          break;\n        case \"skill-commands\":\n          callbacks.onEnableSkillCommandsChange(newValue === \"true\");\n          break;\n        case \"steering-mode\":\n          callbacks.onSteeringModeChange(newValue);\n          break;\n        case \"follow-up-mode\":\n          callbacks.onFollowUpModeChange(newValue);\n          break;\n        case \"transport\":\n          callbacks.onTransportChange(newValue);\n          break;\n        case \"http-idle-timeout\": {\n          const choice = HTTP_IDLE_TIMEOUT_CHOICES.find((item) => item.label === newValue);\n          if (choice) {\n            callbacks.onHttpIdleTimeoutMsChange(choice.timeoutMs);\n          }\n          break;\n        }\n        case \"hide-thinking\":\n          callbacks.onHideThinkingBlockChange(newValue === \"true\");\n          break;\n        case \"mermaid-rendering\":\n          callbacks.onMermaidRenderingModeChange(newValue);\n          break;\n        case \"cache-miss-notices\":\n          callbacks.onShowCacheMissNoticesChange(newValue === \"true\");\n          break;\n        case \"collapse-changelog\":\n          callbacks.onCollapseChangelogChange(newValue === \"true\");\n          break;\n        case \"quiet-startup\":\n          callbacks.onQuietStartupChange(newValue === \"true\");\n          break;\n        case \"install-telemetry\":\n          callbacks.onEnableInstallTelemetryChange(newValue === \"true\");\n          break;\n        case \"default-project-trust\": {\n          const defaultProjectTrust = DEFAULT_PROJECT_TRUST_BY_LABEL.get(newValue);\n          if (defaultProjectTrust) {\n            callbacks.onDefaultProjectTrustChange(defaultProjectTrust);\n          }\n          break;\n        }\n        case \"double-escape-action\":\n          callbacks.onDoubleEscapeActionChange(newValue);\n          break;\n        case \"tree-filter-mode\":\n          callbacks.onTreeFilterModeChange(newValue);\n          break;\n        case \"show-hardware-cursor\":\n          callbacks.onShowHardwareCursorChange(newValue === \"true\");\n          break;\n        case \"editor-padding\":\n          callbacks.onEditorPaddingXChange(parseInt(newValue, 10));\n          break;\n        case \"output-padding\":\n          callbacks.onOutputPadChange(newValue === \"0\" ? 0 : 1);\n          break;\n        case \"autocomplete-max-visible\":\n          callbacks.onAutocompleteMaxVisibleChange(parseInt(newValue, 10));\n          break;\n        case \"clear-on-shrink\":\n          callbacks.onClearOnShrinkChange(newValue === \"true\");\n          break;\n        case \"terminal-progress\":\n          callbacks.onShowTerminalProgressChange(newValue === \"true\");\n          break;\n        case \"tui-mode\":\n          callbacks.onTuiModeChange(newValue);\n          break;\n        case \"fullscreen-exit-output\":\n          callbacks.onFullscreenExitOutputChange(newValue);\n          break;\n        case \"fullscreen-scrollbar\":\n          callbacks.onFullscreenScrollbarChange(newValue);\n          break;\n        case \"theme\":\n          callbacks.onThemeChange(newValue);\n          break;\n      }\n    }, callbacks.onCancel, { enableSearch: true });\n    this.addChild(this.settingsList);\n    this.addChild(new DynamicBorder());\n  }\n  getSettingsList() {\n    return this.settingsList;\n  }\n};\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/skill-invocation-message.js\nvar SkillInvocationMessageComponent = class extends Box {\n  expanded = false;\n  skillBlock;\n  markdownTheme;\n  constructor(skillBlock, markdownTheme = getMarkdownTheme()) {\n    super(1, 1, (t) => theme.bg(\"customMessageBg\", t));\n    this.skillBlock = skillBlock;\n    this.markdownTheme = markdownTheme;\n    this.updateDisplay();\n  }\n  setExpanded(expanded) {\n    this.expanded = expanded;\n    this.updateDisplay();\n  }\n  invalidate() {\n    super.invalidate();\n    this.updateDisplay();\n  }\n  updateDisplay() {\n    this.clear();\n    if (this.expanded) {\n      const label = theme.fg(\"customMessageLabel\", `\\x1B[1m[skill]\\x1B[22m`);\n      this.addChild(new Text(label, 0, 0));\n      const header = `**${this.skillBlock.name}**\n\n`;\n      this.addChild(new Markdown(header + this.skillBlock.content, 0, 0, this.markdownTheme, {\n        color: (text) => theme.fg(\"customMessageText\", text)\n      }));\n    } else {\n      const line = theme.fg(\"customMessageLabel\", `\\x1B[1m[skill]\\x1B[22m `) + theme.fg(\"customMessageText\", this.skillBlock.name) + theme.fg(\"dim\", ` (${keyText(\"app.tools.expand\")} to expand)`);\n      this.addChild(new Text(line, 0, 0));\n    }\n  }\n};\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/status-indicator.js\nvar StatusIndicator = class extends Loader {\n  kind;\n  constructor(kind, ui, spinnerColorFn, messageColorFn, message, indicator) {\n    super(ui, spinnerColorFn, messageColorFn, message, indicator);\n    this.kind = kind;\n  }\n  dispose() {\n    this.stop();\n  }\n};\nvar WorkingStatusIndicator = class extends StatusIndicator {\n  constructor(ui, message, indicator) {\n    super(\"working\", ui, (spinner) => theme.fg(\"accent\", spinner), (text) => theme.fg(\"muted\", text), message, indicator);\n  }\n};\nvar RetryStatusIndicator = class extends StatusIndicator {\n  countdown;\n  constructor(ui, attempt, maxAttempts, delayMs) {\n    const retryMessage = (seconds) => `Retrying (${attempt}/${maxAttempts}) in ${seconds}s... (${keyText(\"app.interrupt\")} to cancel)`;\n    super(\"retry\", ui, (spinner) => theme.fg(\"warning\", spinner), (text) => theme.fg(\"muted\", text), retryMessage(Math.ceil(delayMs / 1e3)));\n    this.countdown = new CountdownTimer(delayMs, ui, (seconds) => {\n      this.setMessage(retryMessage(seconds));\n    }, () => {\n      this.countdown = void 0;\n    });\n  }\n  dispose() {\n    this.countdown?.dispose();\n    this.countdown = void 0;\n    super.dispose();\n  }\n};\nvar CompactionStatusIndicator = class extends StatusIndicator {\n  constructor(ui, reason) {\n    const cancelHint = `(${keyText(\"app.interrupt\")} to cancel)`;\n    const label = reason === \"manual\" ? `Compacting context... ${cancelHint}` : `${reason === \"overflow\" ? \"Context overflow detected, \" : \"\"}Auto-compacting... ${cancelHint}`;\n    super(\"compaction\", ui, (spinner) => theme.fg(\"accent\", spinner), (text) => theme.fg(\"muted\", text), label);\n  }\n};\nvar BranchSummaryStatusIndicator = class extends StatusIndicator {\n  constructor(ui) {\n    super(\"branchSummary\", ui, (spinner) => theme.fg(\"accent\", spinner), (text) => theme.fg(\"muted\", text), `Summarizing branch... (${keyText(\"app.interrupt\")} to cancel)`);\n  }\n};\nvar IdleStatus = class {\n  invalidate() {\n  }\n  render(width) {\n    const emptyLine = \" \".repeat(width);\n    return [emptyLine, emptyLine];\n  }\n};\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/tool-execution.js\nvar FALLBACK_PREVIEW_LINES = 10;\nvar ToolExecutionComponent = class extends Container {\n  contentBox;\n  contentText;\n  selfRenderContainer;\n  callRendererComponent;\n  resultRendererComponent;\n  rendererState = {};\n  imageComponents = [];\n  imageSpacers = [];\n  toolName;\n  toolCallId;\n  args;\n  expanded = false;\n  showImages;\n  imageWidthCells;\n  isPartial = true;\n  toolDefinition;\n  builtInToolDefinition;\n  ui;\n  cwd;\n  executionStarted = false;\n  argsComplete = false;\n  result;\n  convertedImages = /* @__PURE__ */ new Map();\n  hideComponent = false;\n  constructor(toolName, toolCallId, args, options = {}, toolDefinition, ui, cwd) {\n    super();\n    this.toolName = toolName;\n    this.toolCallId = toolCallId;\n    this.args = args;\n    this.toolDefinition = toolDefinition;\n    this.builtInToolDefinition = createAllToolDefinitions(cwd)[toolName];\n    this.showImages = options.showImages ?? true;\n    this.imageWidthCells = options.imageWidthCells ?? 60;\n    this.ui = ui;\n    this.cwd = cwd;\n    this.addChild(new Spacer(1));\n    this.contentBox = new Box(1, 1, (text) => theme.bg(\"toolPendingBg\", text));\n    this.contentText = new Text(\"\", 1, 1, (text) => theme.bg(\"toolPendingBg\", text));\n    this.selfRenderContainer = new Container();\n    if (this.hasRendererDefinition()) {\n      this.addChild(this.getRenderShell() === \"self\" ? this.selfRenderContainer : this.contentBox);\n    } else {\n      this.addChild(this.contentText);\n    }\n    this.updateDisplay();\n  }\n  getCallRenderer() {\n    if (!this.builtInToolDefinition) {\n      return this.toolDefinition?.renderCall;\n    }\n    if (!this.toolDefinition) {\n      return this.builtInToolDefinition.renderCall;\n    }\n    return this.toolDefinition.renderCall ?? this.builtInToolDefinition.renderCall;\n  }\n  getResultRenderer() {\n    if (!this.builtInToolDefinition) {\n      return this.toolDefinition?.renderResult;\n    }\n    if (!this.toolDefinition) {\n      return this.builtInToolDefinition.renderResult;\n    }\n    return this.toolDefinition.renderResult ?? this.builtInToolDefinition.renderResult;\n  }\n  hasRendererDefinition() {\n    return this.builtInToolDefinition !== void 0 || this.toolDefinition !== void 0;\n  }\n  getRenderShell() {\n    if (!this.builtInToolDefinition) {\n      return this.toolDefinition?.renderShell ?? \"default\";\n    }\n    if (!this.toolDefinition) {\n      return this.builtInToolDefinition.renderShell ?? \"default\";\n    }\n    return this.toolDefinition.renderShell ?? this.builtInToolDefinition.renderShell ?? \"default\";\n  }\n  getRenderContext(lastComponent) {\n    return {\n      args: this.args,\n      toolCallId: this.toolCallId,\n      invalidate: () => {\n        this.invalidate();\n        this.ui.requestRender();\n      },\n      lastComponent,\n      state: this.rendererState,\n      cwd: this.cwd,\n      executionStarted: this.executionStarted,\n      argsComplete: this.argsComplete,\n      isPartial: this.isPartial,\n      expanded: this.expanded,\n      showImages: this.showImages,\n      isError: this.result?.isError ?? false\n    };\n  }\n  createCallFallback() {\n    return new Text(theme.fg(\"toolTitle\", theme.bold(this.toolName)), 0, 0);\n  }\n  createResultFallback() {\n    const output = this.getTextOutput();\n    if (!output) {\n      return void 0;\n    }\n    const lines = output.split(\"\\n\");\n    const displayLines = this.expanded ? lines : lines.slice(0, FALLBACK_PREVIEW_LINES);\n    const remaining = lines.length - displayLines.length;\n    let text = displayLines.map((line) => theme.fg(\"toolOutput\", line)).join(\"\\n\");\n    if (remaining > 0) {\n      text += `${theme.fg(\"muted\", `\n... (${remaining} more lines,`)} ${keyHint(\"app.tools.expand\", \"to expand\")}${theme.fg(\"muted\", \")\")}`;\n    }\n    return new Text(text, 0, 0);\n  }\n  updateArgs(args) {\n    this.args = args;\n    this.updateDisplay();\n  }\n  markExecutionStarted() {\n    this.executionStarted = true;\n    this.updateDisplay();\n    this.ui.requestRender();\n  }\n  setArgsComplete() {\n    this.argsComplete = true;\n    this.updateDisplay();\n    this.ui.requestRender();\n  }\n  updateResult(result, isPartial = false) {\n    this.result = result;\n    this.isPartial = isPartial;\n    this.updateDisplay();\n    this.maybeConvertImagesForKitty();\n  }\n  maybeConvertImagesForKitty() {\n    const caps = getCapabilities();\n    if (caps.images !== \"kitty\")\n      return;\n    if (!this.result)\n      return;\n    const imageBlocks = this.result.content.filter((c) => c.type === \"image\");\n    for (let i = 0; i < imageBlocks.length; i++) {\n      const img = imageBlocks[i];\n      if (!img.data || !img.mimeType)\n        continue;\n      if (img.mimeType === \"image/png\")\n        continue;\n      if (this.convertedImages.has(i))\n        continue;\n      const index = i;\n      convertToPng(img.data, img.mimeType).then((converted) => {\n        if (converted) {\n          this.convertedImages.set(index, converted);\n          this.updateDisplay();\n          this.ui.requestRender();\n        }\n      });\n    }\n  }\n  setExpanded(expanded) {\n    this.expanded = expanded;\n    this.updateDisplay();\n  }\n  setShowImages(show) {\n    this.showImages = show;\n    this.updateDisplay();\n  }\n  setImageWidthCells(width) {\n    this.imageWidthCells = Math.max(1, Math.floor(width));\n    this.updateDisplay();\n  }\n  invalidate() {\n    super.invalidate();\n    this.updateDisplay();\n  }\n  render(width) {\n    if (this.hideComponent) {\n      return [];\n    }\n    if (this.hasRendererDefinition() && this.getRenderShell() === \"self\") {\n      const contentLines = this.selfRenderContainer.render(width);\n      if (contentLines.length === 0 && this.imageComponents.length === 0) {\n        return [];\n      }\n      const lines = [];\n      if (contentLines.length > 0) {\n        lines.push(\"\");\n        lines.push(...contentLines);\n      }\n      for (let i = 0; i < this.imageComponents.length; i++) {\n        const spacer = this.imageSpacers[i];\n        if (spacer) {\n          lines.push(...spacer.render(width));\n        }\n        const imageComponent = this.imageComponents[i];\n        if (imageComponent) {\n          lines.push(...imageComponent.render(width));\n        }\n      }\n      return lines;\n    }\n    return super.render(width);\n  }\n  updateDisplay() {\n    const bgFn = this.isPartial ? (text) => theme.bg(\"toolPendingBg\", text) : this.result?.isError ? (text) => theme.bg(\"toolErrorBg\", text) : (text) => theme.bg(\"toolSuccessBg\", text);\n    let hasContent = false;\n    this.hideComponent = false;\n    if (this.hasRendererDefinition()) {\n      const renderContainer = this.getRenderShell() === \"self\" ? this.selfRenderContainer : this.contentBox;\n      if (renderContainer instanceof Box) {\n        renderContainer.setBgFn(bgFn);\n      }\n      renderContainer.clear();\n      const callRenderer = this.getCallRenderer();\n      if (!callRenderer) {\n        renderContainer.addChild(this.createCallFallback());\n        hasContent = true;\n      } else {\n        try {\n          const component = callRenderer(this.args, theme, this.getRenderContext(this.callRendererComponent));\n          this.callRendererComponent = component;\n          renderContainer.addChild(component);\n          hasContent = true;\n        } catch {\n          this.callRendererComponent = void 0;\n          renderContainer.addChild(this.createCallFallback());\n          hasContent = true;\n        }\n      }\n      if (this.result) {\n        const resultRenderer = this.getResultRenderer();\n        if (!resultRenderer) {\n          const component = this.createResultFallback();\n          if (component) {\n            renderContainer.addChild(component);\n            hasContent = true;\n          }\n        } else {\n          try {\n            const component = resultRenderer({ content: this.result.content, details: this.result.details }, { expanded: this.expanded, isPartial: this.isPartial }, theme, this.getRenderContext(this.resultRendererComponent));\n            this.resultRendererComponent = component;\n            renderContainer.addChild(component);\n            hasContent = true;\n          } catch {\n            this.resultRendererComponent = void 0;\n            const component = this.createResultFallback();\n            if (component) {\n              renderContainer.addChild(component);\n              hasContent = true;\n            }\n          }\n        }\n      }\n    } else {\n      this.contentText.setCustomBgFn(bgFn);\n      this.contentText.setText(this.formatToolExecution());\n      hasContent = true;\n    }\n    for (const img of this.imageComponents) {\n      this.removeChild(img);\n    }\n    this.imageComponents = [];\n    for (const spacer of this.imageSpacers) {\n      this.removeChild(spacer);\n    }\n    this.imageSpacers = [];\n    if (this.result) {\n      const imageBlocks = this.result.content.filter((c) => c.type === \"image\");\n      const caps = getCapabilities();\n      for (let i = 0; i < imageBlocks.length; i++) {\n        const img = imageBlocks[i];\n        if (caps.images && this.showImages && img.data && img.mimeType) {\n          const converted = this.convertedImages.get(i);\n          const imageData = converted?.data ?? img.data;\n          const imageMimeType = converted?.mimeType ?? img.mimeType;\n          if (caps.images === \"kitty\" && imageMimeType !== \"image/png\")\n            continue;\n          const spacer = new Spacer(1);\n          this.addChild(spacer);\n          this.imageSpacers.push(spacer);\n          const imageComponent = new Image(imageData, imageMimeType, { fallbackColor: (s) => theme.fg(\"toolOutput\", s) }, { maxWidthCells: this.imageWidthCells });\n          this.imageComponents.push(imageComponent);\n          this.addChild(imageComponent);\n        }\n      }\n    }\n    if (this.hasRendererDefinition() && !hasContent && this.imageComponents.length === 0) {\n      this.hideComponent = true;\n    }\n  }\n  getTextOutput() {\n    return getTextOutput(this.result, this.showImages);\n  }\n  formatToolExecution() {\n    let text = theme.fg(\"toolTitle\", theme.bold(this.toolName));\n    const content = JSON.stringify(this.args, null, 2);\n    if (content) {\n      text += `\n\n${content}`;\n    }\n    const output = this.getTextOutput();\n    if (output) {\n      text += `\n${output}`;\n    }\n    return text;\n  }\n};\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/tree-selector.js\nvar TREE_GUTTER_WIDTH = 2;\nvar MIN_VISIBLE_ANCHOR_CONTENT_WIDTH = 4;\nvar MAX_VISIBLE_ANCHOR_CONTENT_WIDTH = 20;\nvar MIN_ANCHOR_CONTEXT_WIDTH = 2;\nvar MAX_ANCHOR_CONTEXT_WIDTH = 12;\nfunction renderHorizontalViewport(rows, width) {\n  const viewportWidth = Math.max(0, width - TREE_GUTTER_WIDTH);\n  const maxBodyWidth = rows.reduce((max, row) => Math.max(max, row.bodyWidth), 0);\n  const maxHorizontalScroll = Math.max(0, maxBodyWidth - viewportWidth);\n  const selectedRow = rows.find((row) => row.isSelected);\n  let horizontalScroll = 0;\n  if (selectedRow && maxHorizontalScroll > 0) {\n    const minVisibleAnchorContentWidth = Math.min(MAX_VISIBLE_ANCHOR_CONTENT_WIDTH, Math.max(MIN_VISIBLE_ANCHOR_CONTENT_WIDTH, Math.floor(viewportWidth / 3)));\n    if (selectedRow.anchorCol > viewportWidth - minVisibleAnchorContentWidth) {\n      const anchorContextWidth = Math.min(MAX_ANCHOR_CONTEXT_WIDTH, Math.max(MIN_ANCHOR_CONTEXT_WIDTH, Math.floor(viewportWidth / 4)));\n      horizontalScroll = Math.min(maxHorizontalScroll, selectedRow.anchorCol - anchorContextWidth);\n    }\n  }\n  return rows.map((row) => {\n    const line = horizontalScroll > 0 ? `${row.gutter}${sliceByColumn(row.body, horizontalScroll, viewportWidth, true)}\\x1B[0m` : row.gutter + row.body;\n    return truncateToWidth(line, width, \"\");\n  });\n}\nvar TreeList = class {\n  flatNodes = [];\n  filteredNodes = [];\n  selectedIndex = 0;\n  currentLeafId;\n  maxVisibleLines;\n  filterMode = \"default\";\n  searchQuery = \"\";\n  toolCallMap = /* @__PURE__ */ new Map();\n  multipleRoots = false;\n  showLabelTimestamps = false;\n  activePathIds = /* @__PURE__ */ new Set();\n  visibleParentMap = /* @__PURE__ */ new Map();\n  visibleChildrenMap = /* @__PURE__ */ new Map();\n  lastSelectedId = null;\n  foldedNodes = /* @__PURE__ */ new Set();\n  onSelect;\n  onCancel;\n  onCopy;\n  onLabelEdit;\n  constructor(tree, currentLeafId, maxVisibleLines, initialSelectedId, initialFilterMode) {\n    this.currentLeafId = currentLeafId;\n    this.maxVisibleLines = maxVisibleLines;\n    this.filterMode = initialFilterMode ?? \"default\";\n    this.multipleRoots = tree.length > 1;\n    this.flatNodes = this.flattenTree(tree);\n    this.buildActivePath();\n    this.applyFilter();\n    const targetId = initialSelectedId ?? currentLeafId;\n    this.selectedIndex = this.findNearestVisibleIndex(targetId);\n    this.lastSelectedId = this.filteredNodes[this.selectedIndex]?.node.entry.id ?? null;\n  }\n  /**\n   * Find the index of the nearest visible entry, walking up the parent chain if needed.\n   * Returns the index in filteredNodes, or the last index as fallback.\n   */\n  findNearestVisibleIndex(entryId) {\n    if (this.filteredNodes.length === 0)\n      return 0;\n    const entryMap = /* @__PURE__ */ new Map();\n    for (const flatNode of this.flatNodes) {\n      entryMap.set(flatNode.node.entry.id, flatNode);\n    }\n    const visibleIdToIndex = new Map(this.filteredNodes.map((node, i) => [node.node.entry.id, i]));\n    let currentId = entryId;\n    while (currentId !== null) {\n      const index = visibleIdToIndex.get(currentId);\n      if (index !== void 0)\n        return index;\n      const node = entryMap.get(currentId);\n      if (!node)\n        break;\n      currentId = node.node.entry.parentId ?? null;\n    }\n    return this.filteredNodes.length - 1;\n  }\n  /** Build the set of entry IDs on the path from root to current leaf */\n  buildActivePath() {\n    this.activePathIds.clear();\n    if (!this.currentLeafId)\n      return;\n    const entryMap = /* @__PURE__ */ new Map();\n    for (const flatNode of this.flatNodes) {\n      entryMap.set(flatNode.node.entry.id, flatNode);\n    }\n    let currentId = this.currentLeafId;\n    while (currentId) {\n      this.activePathIds.add(currentId);\n      const node = entryMap.get(currentId);\n      if (!node)\n        break;\n      currentId = node.node.entry.parentId ?? null;\n    }\n  }\n  flattenTree(roots) {\n    const result = [];\n    this.toolCallMap.clear();\n    const stack = [];\n    const containsActive = /* @__PURE__ */ new Map();\n    const leafId = this.currentLeafId;\n    {\n      const allNodes = [];\n      const preOrderStack = [...roots];\n      while (preOrderStack.length > 0) {\n        const node = preOrderStack.pop();\n        allNodes.push(node);\n        for (let i = node.children.length - 1; i >= 0; i--) {\n          preOrderStack.push(node.children[i]);\n        }\n      }\n      for (let i = allNodes.length - 1; i >= 0; i--) {\n        const node = allNodes[i];\n        let has = leafId !== null && node.entry.id === leafId;\n        for (const child of node.children) {\n          if (containsActive.get(child)) {\n            has = true;\n          }\n        }\n        containsActive.set(node, has);\n      }\n    }\n    const multipleRoots = roots.length > 1;\n    const orderedRoots = [...roots].sort((a, b) => Number(containsActive.get(b)) - Number(containsActive.get(a)));\n    for (let i = orderedRoots.length - 1; i >= 0; i--) {\n      const isLast = i === orderedRoots.length - 1;\n      stack.push([orderedRoots[i], multipleRoots ? 1 : 0, multipleRoots, multipleRoots, isLast, [], multipleRoots]);\n    }\n    while (stack.length > 0) {\n      const [node, indent, justBranched, showConnector, isLast, gutters, isVirtualRootChild] = stack.pop();\n      const entry = node.entry;\n      if (entry.type === \"message\" && entry.message.role === \"assistant\") {\n        const content = entry.message.content;\n        if (Array.isArray(content)) {\n          for (const block of content) {\n            if (typeof block === \"object\" && block !== null && \"type\" in block && block.type === \"toolCall\") {\n              const tc = block;\n              this.toolCallMap.set(tc.id, { name: tc.name, arguments: tc.arguments });\n            }\n          }\n        }\n      }\n      result.push({ node, indent, showConnector, isLast, gutters, isVirtualRootChild });\n      const children = node.children;\n      const multipleChildren = children.length > 1;\n      const orderedChildren = (() => {\n        const prioritized = [];\n        const rest = [];\n        for (const child of children) {\n          if (containsActive.get(child)) {\n            prioritized.push(child);\n          } else {\n            rest.push(child);\n          }\n        }\n        return [...prioritized, ...rest];\n      })();\n      let childIndent;\n      if (multipleChildren) {\n        childIndent = indent + 1;\n      } else if (justBranched && indent > 0) {\n        childIndent = indent + 1;\n      } else {\n        childIndent = indent;\n      }\n      const connectorDisplayed = showConnector && !isVirtualRootChild;\n      const currentDisplayIndent = this.multipleRoots ? Math.max(0, indent - 1) : indent;\n      const connectorPosition = Math.max(0, currentDisplayIndent - 1);\n      const childGutters = connectorDisplayed ? [...gutters, { position: connectorPosition, show: !isLast }] : gutters;\n      for (let i = orderedChildren.length - 1; i >= 0; i--) {\n        const childIsLast = i === orderedChildren.length - 1;\n        stack.push([\n          orderedChildren[i],\n          childIndent,\n          multipleChildren,\n          multipleChildren,\n          childIsLast,\n          childGutters,\n          false\n        ]);\n      }\n    }\n    return result;\n  }\n  applyFilter() {\n    if (this.filteredNodes.length > 0) {\n      this.lastSelectedId = this.filteredNodes[this.selectedIndex]?.node.entry.id ?? this.lastSelectedId;\n    }\n    const searchTokens = this.searchQuery.toLowerCase().split(/\\s+/).filter(Boolean);\n    this.filteredNodes = this.flatNodes.filter((flatNode) => {\n      const entry = flatNode.node.entry;\n      const isCurrentLeaf = entry.id === this.currentLeafId;\n      if (entry.type === \"message\" && entry.message.role === \"assistant\" && !isCurrentLeaf) {\n        const msg = entry.message;\n        const hasText = this.hasTextContent(msg.content);\n        const isErrorOrAborted = msg.stopReason && msg.stopReason !== \"stop\" && msg.stopReason !== \"toolUse\";\n        if (!hasText && !isErrorOrAborted) {\n          return false;\n        }\n      }\n      let passesFilter = true;\n      const isSettingsEntry = entry.type === \"label\" || entry.type === \"custom\" || entry.type === \"model_change\" || entry.type === \"thinking_level_change\" || entry.type === \"session_info\";\n      switch (this.filterMode) {\n        case \"user-only\":\n          passesFilter = entry.type === \"message\" && entry.message.role === \"user\";\n          break;\n        case \"no-tools\":\n          passesFilter = !isSettingsEntry && !(entry.type === \"message\" && entry.message.role === \"toolResult\");\n          break;\n        case \"labeled-only\":\n          passesFilter = flatNode.node.label !== void 0;\n          break;\n        case \"all\":\n          passesFilter = true;\n          break;\n        default:\n          passesFilter = !isSettingsEntry;\n          break;\n      }\n      if (!passesFilter)\n        return false;\n      if (searchTokens.length > 0) {\n        const nodeText = this.getSearchableText(flatNode.node).toLowerCase();\n        return searchTokens.every((token) => nodeText.includes(token));\n      }\n      return true;\n    });\n    if (this.foldedNodes.size > 0) {\n      const skipSet = /* @__PURE__ */ new Set();\n      for (const flatNode of this.flatNodes) {\n        const { id, parentId } = flatNode.node.entry;\n        if (parentId != null && (this.foldedNodes.has(parentId) || skipSet.has(parentId))) {\n          skipSet.add(id);\n        }\n      }\n      this.filteredNodes = this.filteredNodes.filter((flatNode) => !skipSet.has(flatNode.node.entry.id));\n    }\n    this.recalculateVisualStructure();\n    if (this.lastSelectedId) {\n      this.selectedIndex = this.findNearestVisibleIndex(this.lastSelectedId);\n    } else if (this.selectedIndex >= this.filteredNodes.length) {\n      this.selectedIndex = Math.max(0, this.filteredNodes.length - 1);\n    }\n    if (this.filteredNodes.length > 0) {\n      this.lastSelectedId = this.filteredNodes[this.selectedIndex]?.node.entry.id ?? this.lastSelectedId;\n    }\n  }\n  /**\n   * Recompute indentation/connectors for the filtered view\n   *\n   * Filtering can hide intermediate entries; descendants attach to the nearest visible ancestor.\n   * Keep indentation semantics aligned with flattenTree() so single-child chains don't drift right.\n   */\n  recalculateVisualStructure() {\n    if (this.filteredNodes.length === 0)\n      return;\n    const visibleIds = new Set(this.filteredNodes.map((n) => n.node.entry.id));\n    const entryMap = /* @__PURE__ */ new Map();\n    for (const flatNode of this.flatNodes) {\n      entryMap.set(flatNode.node.entry.id, flatNode);\n    }\n    const findVisibleAncestor = (nodeId) => {\n      let currentId = entryMap.get(nodeId)?.node.entry.parentId ?? null;\n      while (currentId !== null) {\n        if (visibleIds.has(currentId)) {\n          return currentId;\n        }\n        currentId = entryMap.get(currentId)?.node.entry.parentId ?? null;\n      }\n      return null;\n    };\n    const visibleParent = /* @__PURE__ */ new Map();\n    const visibleChildren = /* @__PURE__ */ new Map();\n    visibleChildren.set(null, []);\n    for (const flatNode of this.filteredNodes) {\n      const nodeId = flatNode.node.entry.id;\n      const ancestorId = findVisibleAncestor(nodeId);\n      visibleParent.set(nodeId, ancestorId);\n      if (!visibleChildren.has(ancestorId)) {\n        visibleChildren.set(ancestorId, []);\n      }\n      visibleChildren.get(ancestorId).push(nodeId);\n    }\n    const visibleRootIds = visibleChildren.get(null);\n    this.multipleRoots = visibleRootIds.length > 1;\n    const filteredNodeMap = /* @__PURE__ */ new Map();\n    for (const flatNode of this.filteredNodes) {\n      filteredNodeMap.set(flatNode.node.entry.id, flatNode);\n    }\n    const stack = [];\n    for (let i = visibleRootIds.length - 1; i >= 0; i--) {\n      const isLast = i === visibleRootIds.length - 1;\n      stack.push([\n        visibleRootIds[i],\n        this.multipleRoots ? 1 : 0,\n        this.multipleRoots,\n        this.multipleRoots,\n        isLast,\n        [],\n        this.multipleRoots\n      ]);\n    }\n    while (stack.length > 0) {\n      const [nodeId, indent, justBranched, showConnector, isLast, gutters, isVirtualRootChild] = stack.pop();\n      const flatNode = filteredNodeMap.get(nodeId);\n      if (!flatNode)\n        continue;\n      flatNode.indent = indent;\n      flatNode.showConnector = showConnector;\n      flatNode.isLast = isLast;\n      flatNode.gutters = gutters;\n      flatNode.isVirtualRootChild = isVirtualRootChild;\n      const children = visibleChildren.get(nodeId) || [];\n      const multipleChildren = children.length > 1;\n      let childIndent;\n      if (multipleChildren) {\n        childIndent = indent + 1;\n      } else if (justBranched && indent > 0) {\n        childIndent = indent + 1;\n      } else {\n        childIndent = indent;\n      }\n      const connectorDisplayed = showConnector && !isVirtualRootChild;\n      const currentDisplayIndent = this.multipleRoots ? Math.max(0, indent - 1) : indent;\n      const connectorPosition = Math.max(0, currentDisplayIndent - 1);\n      const childGutters = connectorDisplayed ? [...gutters, { position: connectorPosition, show: !isLast }] : gutters;\n      for (let i = children.length - 1; i >= 0; i--) {\n        const childIsLast = i === children.length - 1;\n        stack.push([\n          children[i],\n          childIndent,\n          multipleChildren,\n          multipleChildren,\n          childIsLast,\n          childGutters,\n          false\n        ]);\n      }\n    }\n    this.visibleParentMap = visibleParent;\n    this.visibleChildrenMap = visibleChildren;\n  }\n  /** Get searchable text content from a node */\n  getSearchableText(node) {\n    const entry = node.entry;\n    const parts = [];\n    if (node.label) {\n      parts.push(node.label);\n    }\n    switch (entry.type) {\n      case \"message\": {\n        const msg = entry.message;\n        parts.push(msg.role);\n        if (\"content\" in msg && msg.content) {\n          parts.push(this.extractContent(msg.content));\n        }\n        if (msg.role === \"bashExecution\") {\n          const bashMsg = msg;\n          if (bashMsg.command)\n            parts.push(bashMsg.command);\n        }\n        break;\n      }\n      case \"custom_message\": {\n        parts.push(entry.customType);\n        if (typeof entry.content === \"string\") {\n          parts.push(entry.content);\n        } else {\n          parts.push(this.extractContent(entry.content));\n        }\n        break;\n      }\n      case \"compaction\":\n        parts.push(\"compaction\");\n        break;\n      case \"branch_summary\":\n        parts.push(\"branch summary\", entry.summary);\n        break;\n      case \"session_info\":\n        parts.push(\"title\");\n        if (entry.name)\n          parts.push(entry.name);\n        break;\n      case \"model_change\":\n        parts.push(\"model\", entry.modelId);\n        break;\n      case \"thinking_level_change\":\n        parts.push(\"thinking\", entry.thinkingLevel);\n        break;\n      case \"custom\":\n        parts.push(\"custom\", entry.customType);\n        break;\n      case \"label\":\n        parts.push(\"label\", entry.label ?? \"\");\n        break;\n    }\n    return parts.join(\" \");\n  }\n  invalidate() {\n  }\n  getSearchQuery() {\n    return this.searchQuery;\n  }\n  getSelectedNode() {\n    return this.filteredNodes[this.selectedIndex]?.node;\n  }\n  copySelected() {\n    const node = this.getSelectedNode();\n    this.onCopy?.(node ? this.getEntryCopyText(node) : void 0);\n  }\n  updateNodeLabel(entryId, label, labelTimestamp) {\n    for (const flatNode of this.flatNodes) {\n      if (flatNode.node.entry.id === entryId) {\n        flatNode.node.label = label;\n        flatNode.node.labelTimestamp = label ? labelTimestamp ?? (/* @__PURE__ */ new Date()).toISOString() : void 0;\n        break;\n      }\n    }\n  }\n  getStatusLabels() {\n    let labels = \"\";\n    switch (this.filterMode) {\n      case \"no-tools\":\n        labels += \" [no-tools]\";\n        break;\n      case \"user-only\":\n        labels += \" [user]\";\n        break;\n      case \"labeled-only\":\n        labels += \" [labeled]\";\n        break;\n      case \"all\":\n        labels += \" [all]\";\n        break;\n    }\n    if (this.showLabelTimestamps) {\n      labels += \" [+label time]\";\n    }\n    return labels;\n  }\n  render(width) {\n    const lines = [];\n    if (this.filteredNodes.length === 0) {\n      lines.push(truncateToWidth(theme.fg(\"muted\", \"  No entries found\"), width));\n      lines.push(truncateToWidth(theme.fg(\"muted\", `  (0/0)${this.getStatusLabels()}`), width));\n      return lines;\n    }\n    const startIndex = Math.max(0, Math.min(this.selectedIndex - Math.floor(this.maxVisibleLines / 2), this.filteredNodes.length - this.maxVisibleLines));\n    const endIndex = Math.min(startIndex + this.maxVisibleLines, this.filteredNodes.length);\n    const renderedRows = [];\n    for (let i = startIndex; i < endIndex; i++) {\n      const flatNode = this.filteredNodes[i];\n      const entry = flatNode.node.entry;\n      const isSelected = i === this.selectedIndex;\n      const cursor = isSelected ? theme.fg(\"accent\", \"\\u203A \") : \"  \";\n      const displayIndent = this.multipleRoots ? Math.max(0, flatNode.indent - 1) : flatNode.indent;\n      const connector = flatNode.showConnector && !flatNode.isVirtualRootChild ? flatNode.isLast ? \"\\u2514\\u2500 \" : \"\\u251C\\u2500 \" : \"\";\n      const connectorPosition = connector ? displayIndent - 1 : -1;\n      const totalChars = displayIndent * 3;\n      const prefixChars = [];\n      const isFolded = this.foldedNodes.has(entry.id);\n      for (let i2 = 0; i2 < totalChars; i2++) {\n        const level = Math.floor(i2 / 3);\n        const posInLevel = i2 % 3;\n        const gutter2 = flatNode.gutters.find((g) => g.position === level);\n        if (gutter2) {\n          if (posInLevel === 0) {\n            prefixChars.push(gutter2.show ? \"\\u2502\" : \" \");\n          } else {\n            prefixChars.push(\" \");\n          }\n        } else if (connector && level === connectorPosition) {\n          if (posInLevel === 0) {\n            prefixChars.push(flatNode.isLast ? \"\\u2514\" : \"\\u251C\");\n          } else if (posInLevel === 1) {\n            const foldable = this.isFoldable(entry.id);\n            prefixChars.push(isFolded ? \"\\u229E\" : foldable ? \"\\u229F\" : \"\\u2500\");\n          } else {\n            prefixChars.push(\" \");\n          }\n        } else {\n          prefixChars.push(\" \");\n        }\n      }\n      const prefix = prefixChars.join(\"\");\n      const showsFoldInConnector = flatNode.showConnector && !flatNode.isVirtualRootChild;\n      const foldMarker = isFolded && !showsFoldInConnector ? theme.fg(\"accent\", \"\\u229E \") : \"\";\n      const isOnActivePath = this.activePathIds.has(entry.id);\n      const pathMarker = isOnActivePath ? theme.fg(\"accent\", \"\\u2022 \") : \"\";\n      const label = flatNode.node.label ? theme.fg(\"warning\", `[${flatNode.node.label}] `) : \"\";\n      const labelTimestamp = this.showLabelTimestamps && flatNode.node.label && flatNode.node.labelTimestamp ? theme.fg(\"muted\", `${this.formatLabelTimestamp(flatNode.node.labelTimestamp)} `) : \"\";\n      const content = this.getEntryDisplayText(flatNode.node, isSelected);\n      const prefixPart = theme.fg(\"dim\", prefix) + foldMarker + pathMarker;\n      const anchorCol = visibleWidth(prefixPart);\n      let gutter = cursor;\n      let body = prefixPart + label + labelTimestamp + content;\n      if (isSelected) {\n        gutter = theme.bg(\"selectedBg\", gutter);\n        body = theme.bg(\"selectedBg\", body);\n      }\n      renderedRows.push({ gutter, body, anchorCol, bodyWidth: visibleWidth(body), isSelected });\n    }\n    lines.push(...renderHorizontalViewport(renderedRows, width));\n    lines.push(truncateToWidth(theme.fg(\"muted\", `  (${this.selectedIndex + 1}/${this.filteredNodes.length})${this.getStatusLabels()}`), width));\n    return lines;\n  }\n  getEntryDisplayText(node, isSelected) {\n    const entry = node.entry;\n    let result;\n    const normalize = (s) => s.replace(/[\\n\\t]/g, \" \").trim();\n    switch (entry.type) {\n      case \"message\": {\n        const msg = entry.message;\n        const role = msg.role;\n        if (role === \"user\") {\n          const msgWithContent = msg;\n          const content = normalize(this.extractContent(msgWithContent.content));\n          result = theme.fg(\"accent\", \"user: \") + content;\n        } else if (role === \"assistant\") {\n          const msgWithContent = msg;\n          const textContent = normalize(this.extractContent(msgWithContent.content));\n          if (textContent) {\n            result = theme.fg(\"success\", \"assistant: \") + textContent;\n          } else if (msgWithContent.stopReason === \"aborted\") {\n            result = theme.fg(\"success\", \"assistant: \") + theme.fg(\"muted\", \"(aborted)\");\n          } else if (msgWithContent.errorMessage) {\n            const errMsg = normalize(msgWithContent.errorMessage).slice(0, 80);\n            result = theme.fg(\"success\", \"assistant: \") + theme.fg(\"error\", errMsg);\n          } else {\n            result = theme.fg(\"success\", \"assistant: \") + theme.fg(\"muted\", \"(no content)\");\n          }\n        } else if (role === \"toolResult\") {\n          const toolMsg = msg;\n          const toolCall = toolMsg.toolCallId ? this.toolCallMap.get(toolMsg.toolCallId) : void 0;\n          if (toolCall) {\n            result = theme.fg(\"muted\", this.formatToolCall(toolCall.name, toolCall.arguments));\n          } else {\n            result = theme.fg(\"muted\", `[${toolMsg.toolName ?? \"tool\"}]`);\n          }\n        } else if (role === \"bashExecution\") {\n          const bashMsg = msg;\n          result = theme.fg(\"dim\", `[bash]: ${normalize(bashMsg.command ?? \"\")}`);\n        } else {\n          result = theme.fg(\"dim\", `[${role}]`);\n        }\n        break;\n      }\n      case \"custom_message\": {\n        const content = typeof entry.content === \"string\" ? entry.content : entry.content.filter((c) => c.type === \"text\").map((c) => c.text).join(\"\");\n        result = theme.fg(\"customMessageLabel\", `[${entry.customType}]: `) + normalize(content);\n        break;\n      }\n      case \"compaction\": {\n        const tokens = Math.round(entry.tokensBefore / 1e3);\n        result = theme.fg(\"borderAccent\", `[compaction: ${tokens}k tokens]`);\n        break;\n      }\n      case \"branch_summary\":\n        result = theme.fg(\"warning\", `[branch summary]: `) + normalize(entry.summary);\n        break;\n      case \"model_change\":\n        result = theme.fg(\"dim\", `[model: ${entry.modelId}]`);\n        break;\n      case \"thinking_level_change\":\n        result = theme.fg(\"dim\", `[thinking: ${entry.thinkingLevel}]`);\n        break;\n      case \"custom\":\n        result = theme.fg(\"dim\", `[custom: ${entry.customType}]`);\n        break;\n      case \"label\":\n        result = theme.fg(\"dim\", `[label: ${entry.label ?? \"(cleared)\"}]`);\n        break;\n      case \"session_info\":\n        result = entry.name ? [theme.fg(\"dim\", \"[title: \"), theme.fg(\"dim\", entry.name), theme.fg(\"dim\", \"]\")].join(\"\") : [theme.fg(\"dim\", \"[title: \"), theme.italic(theme.fg(\"dim\", \"empty\")), theme.fg(\"dim\", \"]\")].join(\"\");\n        break;\n      default:\n        result = \"\";\n    }\n    return isSelected ? theme.bold(result) : result;\n  }\n  formatLabelTimestamp(timestamp) {\n    const date = new Date(timestamp);\n    const now = /* @__PURE__ */ new Date();\n    const hours = date.getHours().toString().padStart(2, \"0\");\n    const minutes = date.getMinutes().toString().padStart(2, \"0\");\n    const time2 = `${hours}:${minutes}`;\n    if (date.getFullYear() === now.getFullYear() && date.getMonth() === now.getMonth() && date.getDate() === now.getDate()) {\n      return time2;\n    }\n    const month = date.getMonth() + 1;\n    const day = date.getDate();\n    if (date.getFullYear() === now.getFullYear()) {\n      return `${month}/${day} ${time2}`;\n    }\n    const year = date.getFullYear().toString().slice(-2);\n    return `${year}/${month}/${day} ${time2}`;\n  }\n  extractContent(content) {\n    return this.extractFullContent(content).slice(0, 200);\n  }\n  extractFullContent(content) {\n    if (typeof content === \"string\")\n      return content;\n    if (!Array.isArray(content))\n      return \"\";\n    let result = \"\";\n    for (const block of content) {\n      if (typeof block === \"object\" && block !== null && \"type\" in block && block.type === \"text\") {\n        result += block.text;\n      }\n    }\n    return result;\n  }\n  getEntryCopyText(node) {\n    const entry = node.entry;\n    let text;\n    switch (entry.type) {\n      case \"message\":\n        if (entry.message.role === \"bashExecution\") {\n          text = entry.message.command;\n        } else if (\"content\" in entry.message) {\n          text = this.extractFullContent(entry.message.content);\n          if (!text && entry.message.role === \"assistant\") {\n            text = entry.message.errorMessage;\n          }\n        }\n        break;\n      case \"custom_message\":\n        text = this.extractFullContent(entry.content);\n        break;\n      case \"compaction\":\n        text = entry.summary;\n        break;\n      case \"branch_summary\":\n        text = entry.summary;\n        break;\n    }\n    return text?.trim() ? text : void 0;\n  }\n  hasTextContent(content) {\n    if (typeof content === \"string\")\n      return content.trim().length > 0;\n    if (Array.isArray(content)) {\n      for (const c of content) {\n        if (typeof c === \"object\" && c !== null && \"type\" in c && c.type === \"text\") {\n          const text = c.text;\n          if (text && text.trim().length > 0)\n            return true;\n        }\n      }\n    }\n    return false;\n  }\n  formatToolCall(name, args) {\n    const shortenPath3 = (p) => {\n      const home = process.env.HOME || process.env.USERPROFILE || \"\";\n      if (home && p.startsWith(home))\n        return `~${p.slice(home.length)}`;\n      return p;\n    };\n    switch (name) {\n      case \"read\": {\n        const path12 = shortenPath3(String(args.path || args.file_path || \"\"));\n        const offset = args.offset;\n        const limit = args.limit;\n        let display = path12;\n        if (offset !== void 0 || limit !== void 0) {\n          const start = offset ?? 1;\n          const end = limit !== void 0 ? start + limit - 1 : \"\";\n          display += `:${start}${end ? `-${end}` : \"\"}`;\n        }\n        return `[read: ${display}]`;\n      }\n      case \"write\": {\n        const path12 = shortenPath3(String(args.path || args.file_path || \"\"));\n        return `[write: ${path12}]`;\n      }\n      case \"edit\": {\n        const path12 = shortenPath3(String(args.path || args.file_path || \"\"));\n        return `[edit: ${path12}]`;\n      }\n      case \"bash\": {\n        const rawCmd = String(args.command || \"\");\n        const cmd = rawCmd.replace(/[\\n\\t]/g, \" \").trim().slice(0, 50);\n        return `[bash: ${cmd}${rawCmd.length > 50 ? \"...\" : \"\"}]`;\n      }\n      case \"grep\": {\n        const pattern = String(args.pattern || \"\");\n        const path12 = shortenPath3(String(args.path || \".\"));\n        return `[grep: /${pattern}/ in ${path12}]`;\n      }\n      case \"find\": {\n        const pattern = String(args.pattern || \"\");\n        const path12 = shortenPath3(String(args.path || \".\"));\n        return `[find: ${pattern} in ${path12}]`;\n      }\n      case \"ls\": {\n        const path12 = shortenPath3(String(args.path || \".\"));\n        return `[ls: ${path12}]`;\n      }\n      default: {\n        const argsStr = JSON.stringify(args).slice(0, 40);\n        return `[${name}: ${argsStr}${JSON.stringify(args).length > 40 ? \"...\" : \"\"}]`;\n      }\n    }\n  }\n  handleInput(keyData) {\n    const kb = getKeybindings();\n    if (kb.matches(keyData, \"tui.select.up\")) {\n      this.selectedIndex = this.selectedIndex === 0 ? this.filteredNodes.length - 1 : this.selectedIndex - 1;\n    } else if (kb.matches(keyData, \"tui.select.down\")) {\n      this.selectedIndex = this.selectedIndex === this.filteredNodes.length - 1 ? 0 : this.selectedIndex + 1;\n    } else if (kb.matches(keyData, \"app.tree.foldOrUp\")) {\n      const currentId = this.filteredNodes[this.selectedIndex]?.node.entry.id;\n      if (currentId && this.isFoldable(currentId) && !this.foldedNodes.has(currentId)) {\n        this.foldedNodes.add(currentId);\n        this.applyFilter();\n      } else {\n        this.selectedIndex = this.findBranchSegmentStart(\"up\");\n      }\n    } else if (kb.matches(keyData, \"app.tree.unfoldOrDown\")) {\n      const currentId = this.filteredNodes[this.selectedIndex]?.node.entry.id;\n      if (currentId && this.foldedNodes.has(currentId)) {\n        this.foldedNodes.delete(currentId);\n        this.applyFilter();\n      } else {\n        this.selectedIndex = this.findBranchSegmentStart(\"down\");\n      }\n    } else if (kb.matches(keyData, \"tui.editor.cursorLeft\") || kb.matches(keyData, \"tui.select.pageUp\")) {\n      this.selectedIndex = Math.max(0, this.selectedIndex - this.maxVisibleLines);\n    } else if (kb.matches(keyData, \"tui.editor.cursorRight\") || kb.matches(keyData, \"tui.select.pageDown\")) {\n      this.selectedIndex = Math.min(this.filteredNodes.length - 1, this.selectedIndex + this.maxVisibleLines);\n    } else if (kb.matches(keyData, \"tui.select.confirm\")) {\n      const selected = this.filteredNodes[this.selectedIndex];\n      if (selected && this.onSelect) {\n        this.onSelect(selected.node.entry.id);\n      }\n    } else if (kb.matches(keyData, \"app.message.copy\")) {\n      this.copySelected();\n    } else if (kb.matches(keyData, \"tui.select.cancel\")) {\n      if (this.searchQuery) {\n        this.searchQuery = \"\";\n        this.foldedNodes.clear();\n        this.applyFilter();\n      } else {\n        this.onCancel?.();\n      }\n    } else if (kb.matches(keyData, \"app.tree.filter.default\")) {\n      this.filterMode = \"default\";\n      this.foldedNodes.clear();\n      this.applyFilter();\n    } else if (kb.matches(keyData, \"app.tree.filter.noTools\")) {\n      this.filterMode = this.filterMode === \"no-tools\" ? \"default\" : \"no-tools\";\n      this.foldedNodes.clear();\n      this.applyFilter();\n    } else if (kb.matches(keyData, \"app.tree.filter.userOnly\")) {\n      this.filterMode = this.filterMode === \"user-only\" ? \"default\" : \"user-only\";\n      this.foldedNodes.clear();\n      this.applyFilter();\n    } else if (kb.matches(keyData, \"app.tree.filter.labeledOnly\")) {\n      this.filterMode = this.filterMode === \"labeled-only\" ? \"default\" : \"labeled-only\";\n      this.foldedNodes.clear();\n      this.applyFilter();\n    } else if (kb.matches(keyData, \"app.tree.filter.all\")) {\n      this.filterMode = this.filterMode === \"all\" ? \"default\" : \"all\";\n      this.foldedNodes.clear();\n      this.applyFilter();\n    } else if (kb.matches(keyData, \"app.tree.filter.cycleBackward\")) {\n      const modes = [\"default\", \"no-tools\", \"user-only\", \"labeled-only\", \"all\"];\n      const currentIndex = modes.indexOf(this.filterMode);\n      this.filterMode = modes[(currentIndex - 1 + modes.length) % modes.length];\n      this.foldedNodes.clear();\n      this.applyFilter();\n    } else if (kb.matches(keyData, \"app.tree.filter.cycleForward\")) {\n      const modes = [\"default\", \"no-tools\", \"user-only\", \"labeled-only\", \"all\"];\n      const currentIndex = modes.indexOf(this.filterMode);\n      this.filterMode = modes[(currentIndex + 1) % modes.length];\n      this.foldedNodes.clear();\n      this.applyFilter();\n    } else if (kb.matches(keyData, \"tui.editor.deleteCharBackward\")) {\n      if (this.searchQuery.length > 0) {\n        this.searchQuery = this.searchQuery.slice(0, -1);\n        this.foldedNodes.clear();\n        this.applyFilter();\n      }\n    } else if (kb.matches(keyData, \"app.tree.editLabel\")) {\n      const selected = this.filteredNodes[this.selectedIndex];\n      if (selected && this.onLabelEdit) {\n        this.onLabelEdit(selected.node.entry.id, selected.node.label);\n      }\n    } else if (kb.matches(keyData, \"app.tree.toggleLabelTimestamp\")) {\n      this.showLabelTimestamps = !this.showLabelTimestamps;\n    } else {\n      const hasControlChars = [...keyData].some((ch) => {\n        const code = ch.charCodeAt(0);\n        return code < 32 || code === 127 || code >= 128 && code <= 159;\n      });\n      if (!hasControlChars && keyData.length > 0) {\n        this.searchQuery += keyData;\n        this.foldedNodes.clear();\n        this.applyFilter();\n      }\n    }\n  }\n  /**\n   * Whether a node can be folded. A node is foldable if it has visible children\n   * and is either a root (no visible parent) or a segment start (visible parent\n   * has multiple visible children).\n   */\n  isFoldable(entryId) {\n    const children = this.visibleChildrenMap.get(entryId);\n    if (!children || children.length === 0)\n      return false;\n    const parentId = this.visibleParentMap.get(entryId);\n    if (parentId === null || parentId === void 0)\n      return true;\n    const siblings = this.visibleChildrenMap.get(parentId);\n    return siblings !== void 0 && siblings.length > 1;\n  }\n  /**\n   * Find the index of the next branch segment start in the given direction.\n   * A segment start is the first child of a branch point.\n   *\n   * \"up\" walks the visible parent chain; \"down\" walks visible children\n   * (always following the first child).\n   */\n  findBranchSegmentStart(direction) {\n    const selectedId = this.filteredNodes[this.selectedIndex]?.node.entry.id;\n    if (!selectedId)\n      return this.selectedIndex;\n    const indexByEntryId = new Map(this.filteredNodes.map((node, i) => [node.node.entry.id, i]));\n    let currentId = selectedId;\n    if (direction === \"down\") {\n      while (true) {\n        const children = this.visibleChildrenMap.get(currentId) ?? [];\n        if (children.length === 0)\n          return indexByEntryId.get(currentId);\n        if (children.length > 1)\n          return indexByEntryId.get(children[0]);\n        currentId = children[0];\n      }\n    }\n    while (true) {\n      const parentId = this.visibleParentMap.get(currentId) ?? null;\n      if (parentId === null)\n        return indexByEntryId.get(currentId);\n      const children = this.visibleChildrenMap.get(parentId) ?? [];\n      if (children.length > 1) {\n        const segmentStart = indexByEntryId.get(currentId);\n        if (segmentStart < this.selectedIndex) {\n          return segmentStart;\n        }\n      }\n      currentId = parentId;\n    }\n  }\n};\nvar SearchLine = class {\n  treeList;\n  constructor(treeList) {\n    this.treeList = treeList;\n  }\n  invalidate() {\n  }\n  render(width) {\n    const query = this.treeList.getSearchQuery();\n    if (query) {\n      return [truncateToWidth(`  ${theme.fg(\"muted\", \"Type to search:\")} ${theme.fg(\"accent\", query)}`, width)];\n    }\n    return [truncateToWidth(`  ${theme.fg(\"muted\", \"Type to search:\")}`, width)];\n  }\n  handleInput(_keyData) {\n  }\n};\nvar TreeHelp = class {\n  invalidate() {\n  }\n  render(width) {\n    const items = TREE_HELP_ITEMS.map(({ keys, label, labelFirst }) => {\n      const text = formatHelpKeys(keys);\n      if (!text)\n        return label;\n      return labelFirst ? `${label} ${text}` : `${text} ${label}`;\n    });\n    const availableWidth = Math.max(1, width);\n    const indent = \"  \";\n    const separator = \" \\xB7 \";\n    const lines = [];\n    let currentLine = \"\";\n    for (const item of items) {\n      const candidate = currentLine ? `${currentLine}${separator}${item}` : visibleWidth(`${indent}${item}`) <= availableWidth ? `${indent}${item}` : item;\n      if (!currentLine || visibleWidth(candidate) <= availableWidth) {\n        currentLine = candidate;\n        continue;\n      }\n      lines.push(...wrapTextWithAnsi(currentLine.trimEnd(), availableWidth));\n      currentLine = visibleWidth(`${indent}${item}`) <= availableWidth ? `${indent}${item}` : item;\n    }\n    if (currentLine) {\n      lines.push(...wrapTextWithAnsi(currentLine.trimEnd(), availableWidth));\n    }\n    return lines.map((line) => theme.fg(\"muted\", line));\n  }\n};\nvar TREE_HELP_ITEMS = [\n  { keys: [\"tui.select.up\", \"tui.select.down\"], label: \"move\" },\n  { keys: [\"tui.editor.cursorLeft\", \"tui.editor.cursorRight\"], label: \"page\" },\n  { keys: [\"app.tree.foldOrUp\", \"app.tree.unfoldOrDown\"], label: \"branch\" },\n  { keys: [\"app.message.copy\"], label: \"copy\" },\n  { keys: [\"app.tree.editLabel\"], label: \"label\" },\n  { keys: [\"app.tree.toggleLabelTimestamp\"], label: \"label time\" },\n  {\n    keys: [\n      \"app.tree.filter.default\",\n      \"app.tree.filter.noTools\",\n      \"app.tree.filter.userOnly\",\n      \"app.tree.filter.labeledOnly\",\n      \"app.tree.filter.all\"\n    ],\n    label: \"filters\",\n    labelFirst: true\n  },\n  { keys: [\"app.tree.filter.cycleForward\", \"app.tree.filter.cycleBackward\"], label: \"cycle\", labelFirst: true }\n];\nfunction formatHelpKeys(keybindings) {\n  const keys = [];\n  for (const keybinding of keybindings) {\n    const key = getKeybindings().getKeys(keybinding)[0];\n    if (key !== void 0)\n      keys.push(key);\n  }\n  if (keys.length === 0)\n    return \"\";\n  return formatKeyText(compactRawKeys(keys)).replace(/\\bpageUp\\b/g, \"pgup\").replace(/\\bpageDown\\b/g, \"pgdn\").replace(/\\bup\\b/g, \"\\u2191\").replace(/\\bdown\\b/g, \"\\u2193\").replace(/\\bleft\\b/g, \"\\u2190\").replace(/\\bright\\b/g, \"\\u2192\");\n}\nfunction compactRawKeys(keys) {\n  if (keys.length === 1)\n    return keys[0];\n  const parts = keys.map((key) => {\n    const separatorIndex = key.lastIndexOf(\"+\");\n    return separatorIndex === -1 ? { prefix: \"\", suffix: key } : { prefix: key.slice(0, separatorIndex + 1), suffix: key.slice(separatorIndex + 1) };\n  });\n  const prefix = parts[0].prefix;\n  return prefix && parts.every((part) => part.prefix === prefix) ? `${prefix}${parts.map((part) => part.suffix).join(\"/\")}` : keys.join(\"/\");\n}\nvar LabelInput = class {\n  input;\n  entryId;\n  onSubmit;\n  onCancel;\n  // Focusable implementation - propagate to input for IME cursor positioning\n  _focused = false;\n  get focused() {\n    return this._focused;\n  }\n  set focused(value) {\n    this._focused = value;\n    this.input.focused = value;\n  }\n  constructor(entryId, currentLabel) {\n    this.entryId = entryId;\n    this.input = new Input();\n    if (currentLabel) {\n      this.input.setValue(currentLabel);\n    }\n  }\n  invalidate() {\n  }\n  render(width) {\n    const lines = [];\n    const indent = \"  \";\n    const availableWidth = width - indent.length;\n    lines.push(truncateToWidth(`${indent}${theme.fg(\"muted\", \"Label (empty to remove):\")}`, width));\n    lines.push(...this.input.render(availableWidth).map((line) => truncateToWidth(`${indent}${line}`, width)));\n    lines.push(truncateToWidth(`${indent}${keyHint(\"tui.select.confirm\", \"save\")}  ${keyHint(\"tui.select.cancel\", \"cancel\")}`, width));\n    return lines;\n  }\n  handleInput(keyData) {\n    const kb = getKeybindings();\n    if (kb.matches(keyData, \"tui.select.confirm\")) {\n      const value = this.input.getValue().trim();\n      this.onSubmit?.(this.entryId, value || void 0);\n    } else if (kb.matches(keyData, \"tui.select.cancel\")) {\n      this.onCancel?.();\n    } else {\n      this.input.handleInput(keyData);\n    }\n  }\n};\nvar TreeSelectorComponent = class extends Container {\n  treeList;\n  labelInput = null;\n  labelInputContainer;\n  treeContainer;\n  onLabelChangeCallback;\n  onCopy;\n  // Focusable implementation - propagate to labelInput when active for IME cursor positioning\n  _focused = false;\n  get focused() {\n    return this._focused;\n  }\n  set focused(value) {\n    this._focused = value;\n    if (this.labelInput) {\n      this.labelInput.focused = value;\n    }\n  }\n  constructor(tree, currentLeafId, terminalHeight, onSelect, onCancel, onLabelChange, initialSelectedId, initialFilterMode) {\n    super();\n    this.onLabelChangeCallback = onLabelChange;\n    const maxVisibleLines = Math.max(5, Math.floor(terminalHeight / 2));\n    this.treeList = new TreeList(tree, currentLeafId, maxVisibleLines, initialSelectedId, initialFilterMode);\n    this.treeList.onSelect = onSelect;\n    this.treeList.onCancel = onCancel;\n    this.treeList.onCopy = (text) => this.onCopy?.(text);\n    this.treeList.onLabelEdit = (entryId, currentLabel) => this.showLabelInput(entryId, currentLabel);\n    this.treeContainer = new Container();\n    this.treeContainer.addChild(this.treeList);\n    this.labelInputContainer = new Container();\n    this.addChild(new Spacer(1));\n    this.addChild(new DynamicBorder());\n    this.addChild(new Text(theme.bold(\"  Session Tree\"), 1, 0));\n    this.addChild(new TreeHelp());\n    this.addChild(new SearchLine(this.treeList));\n    this.addChild(new DynamicBorder());\n    this.addChild(new Spacer(1));\n    this.addChild(this.treeContainer);\n    this.addChild(this.labelInputContainer);\n    this.addChild(new Spacer(1));\n    this.addChild(new DynamicBorder());\n    if (tree.length === 0) {\n      setTimeout(() => onCancel(), 100);\n    }\n  }\n  showLabelInput(entryId, currentLabel) {\n    this.labelInput = new LabelInput(entryId, currentLabel);\n    this.labelInput.onSubmit = (id, label) => {\n      this.treeList.updateNodeLabel(id, label);\n      this.onLabelChangeCallback?.(id, label);\n      this.hideLabelInput();\n    };\n    this.labelInput.onCancel = () => this.hideLabelInput();\n    this.labelInput.focused = this._focused;\n    this.treeContainer.clear();\n    this.labelInputContainer.clear();\n    this.labelInputContainer.addChild(this.labelInput);\n  }\n  hideLabelInput() {\n    this.labelInput = null;\n    this.labelInputContainer.clear();\n    this.treeContainer.clear();\n    this.treeContainer.addChild(this.treeList);\n  }\n  handleInput(keyData) {\n    if (this.labelInput) {\n      this.labelInput.handleInput(keyData);\n    } else {\n      this.treeList.handleInput(keyData);\n    }\n  }\n  getTreeList() {\n    return this.treeList;\n  }\n};\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/trust-selector.js\nfunction formatDecision(trustPath, decision) {\n  if (decision === null) {\n    return \"none\";\n  }\n  const label = decision.decision ? \"trusted\" : \"untrusted\";\n  if (trustPath !== void 0 && decision.path !== trustPath) {\n    return `${label} (inherited from ${decision.path})`;\n  }\n  return `${label} (${decision.path})`;\n}\nvar TrustSelectorComponent = class extends Container {\n  selectedIndex;\n  listContainer;\n  trustOptions;\n  savedDecision;\n  onSelectCallback;\n  onCancelCallback;\n  constructor(options) {\n    super();\n    this.savedDecision = options.savedDecision;\n    this.trustOptions = getProjectTrustOptions(options.cwd);\n    this.selectedIndex = Math.max(0, this.trustOptions.findIndex((option) => this.isSavedOption(option)));\n    this.onSelectCallback = options.onSelect;\n    this.onCancelCallback = options.onCancel;\n    this.addChild(new DynamicBorder());\n    this.addChild(new Spacer(1));\n    this.addChild(new Text(theme.fg(\"accent\", theme.bold(\"Project trust\")), 1, 0));\n    this.addChild(new Text(theme.fg(\"muted\", options.cwd), 1, 0));\n    this.addChild(new Spacer(1));\n    this.addChild(new Text(theme.fg(\"muted\", `Saved decision: ${formatDecision(this.trustOptions[0]?.savedPath, options.savedDecision)}`), 1, 0));\n    this.addChild(new Text(theme.fg(\"muted\", `Current session: ${options.projectTrusted ? \"trusted\" : \"untrusted\"}`), 1, 0));\n    this.addChild(new Spacer(1));\n    this.listContainer = new Container();\n    this.addChild(this.listContainer);\n    this.addChild(new Spacer(1));\n    this.addChild(new Text(rawKeyHint(\"\\u2191\\u2193\", \"navigate\") + \"  \" + keyHint(\"tui.select.confirm\", \"save\") + \"  \" + keyHint(\"tui.select.cancel\", \"cancel\"), 1, 0));\n    this.addChild(new Spacer(1));\n    this.addChild(new DynamicBorder());\n    this.updateList();\n  }\n  isSavedOption(option) {\n    return option.savedPath !== void 0 && this.savedDecision?.decision === option.trusted && this.savedDecision.path === option.savedPath;\n  }\n  updateList() {\n    this.listContainer.clear();\n    for (let i = 0; i < this.trustOptions.length; i++) {\n      const option = this.trustOptions[i];\n      if (!option) {\n        continue;\n      }\n      const isSelected = i === this.selectedIndex;\n      const isCurrent = this.isSavedOption(option);\n      const checkmark = isCurrent ? theme.fg(\"success\", \" \\u2713\") : \"\";\n      const prefix = isSelected ? theme.fg(\"accent\", \"\\u2192 \") : \"  \";\n      const label = isSelected ? theme.fg(\"accent\", option.label) : theme.fg(\"text\", option.label);\n      this.listContainer.addChild(new Text(`${prefix}${label}${checkmark}`, 1, 0));\n    }\n  }\n  handleInput(keyData) {\n    const kb = getKeybindings();\n    if (kb.matches(keyData, \"tui.select.up\") || keyData === \"k\") {\n      this.selectedIndex = Math.max(0, this.selectedIndex - 1);\n      this.updateList();\n    } else if (kb.matches(keyData, \"tui.select.down\") || keyData === \"j\") {\n      this.selectedIndex = Math.min(this.trustOptions.length - 1, this.selectedIndex + 1);\n      this.updateList();\n    } else if (kb.matches(keyData, \"tui.select.confirm\") || keyData === \"\\n\") {\n      const selected = this.trustOptions[this.selectedIndex];\n      if (selected) {\n        this.onSelectCallback({ trusted: selected.trusted, updates: selected.updates });\n      }\n    } else if (kb.matches(keyData, \"tui.select.cancel\")) {\n      this.onCancelCallback();\n    }\n  }\n};\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/user-message.js\nvar OSC133_ZONE_START2 = \"\\x1B]133;A\\x07\";\nvar OSC133_ZONE_END2 = \"\\x1B]133;B\\x07\";\nvar OSC133_ZONE_FINAL2 = \"\\x1B]133;C\\x07\";\nvar UserMessageComponent = class extends Container {\n  text;\n  markdownTheme;\n  outputPad;\n  markdownTransformers;\n  constructor(text, markdownTheme = getMarkdownTheme(), outputPad = 1, markdownTransformers = []) {\n    super();\n    this.text = text;\n    this.markdownTheme = markdownTheme;\n    this.outputPad = outputPad;\n    this.markdownTransformers = markdownTransformers;\n    this.rebuild();\n  }\n  setOutputPad(padding) {\n    this.outputPad = padding;\n    this.rebuild();\n  }\n  rebuild() {\n    this.clear();\n    const contentBox = new Box(this.outputPad, 1, (content) => theme.bg(\"userMessageBg\", content));\n    contentBox.addChild(new Markdown(this.text, 0, 0, this.markdownTheme, {\n      color: (content) => theme.fg(\"userMessageText\", content)\n    }, {\n      preserveOrderedListMarkers: true,\n      preserveBackslashEscapes: true,\n      transform: createMarkdownTransform(\"user\", false, this.markdownTransformers)\n    }));\n    this.addChild(contentBox);\n  }\n  render(width) {\n    const lines = super.render(width);\n    if (lines.length === 0) {\n      return lines;\n    }\n    lines[0] = OSC133_ZONE_START2 + lines[0];\n    lines[lines.length - 1] = OSC133_ZONE_END2 + OSC133_ZONE_FINAL2 + lines[lines.length - 1];\n    return lines;\n  }\n};\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/user-message-selector.js\nvar UserMessageList = class {\n  messages = [];\n  selectedIndex = 0;\n  onSelect;\n  onCancel;\n  maxVisible = 10;\n  // Max messages visible\n  constructor(messages, initialSelectedId) {\n    this.messages = messages;\n    const initialIndex = initialSelectedId ? messages.findIndex((message) => message.id === initialSelectedId) : -1;\n    this.selectedIndex = initialIndex >= 0 ? initialIndex : Math.max(0, messages.length - 1);\n  }\n  invalidate() {\n  }\n  render(width) {\n    const lines = [];\n    if (this.messages.length === 0) {\n      lines.push(theme.fg(\"muted\", \"  No user messages found\"));\n      return lines;\n    }\n    const startIndex = Math.max(0, Math.min(this.selectedIndex - Math.floor(this.maxVisible / 2), this.messages.length - this.maxVisible));\n    const endIndex = Math.min(startIndex + this.maxVisible, this.messages.length);\n    for (let i = startIndex; i < endIndex; i++) {\n      const message = this.messages[i];\n      const isSelected = i === this.selectedIndex;\n      const normalizedMessage = message.text.replace(/\\n/g, \" \").trim();\n      const cursor = isSelected ? theme.fg(\"accent\", \"\\u203A \") : \"  \";\n      const maxMsgWidth = width - 2;\n      const truncatedMsg = truncateToWidth(normalizedMessage, maxMsgWidth);\n      const messageLine = cursor + (isSelected ? theme.bold(truncatedMsg) : truncatedMsg);\n      lines.push(messageLine);\n      const position = i + 1;\n      const metadata = `  Message ${position} of ${this.messages.length}`;\n      const metadataLine = theme.fg(\"muted\", metadata);\n      lines.push(metadataLine);\n      lines.push(\"\");\n    }\n    if (startIndex > 0 || endIndex < this.messages.length) {\n      const scrollInfo = theme.fg(\"muted\", `  (${this.selectedIndex + 1}/${this.messages.length})`);\n      lines.push(scrollInfo);\n    }\n    return lines;\n  }\n  handleInput(keyData) {\n    const kb = getKeybindings();\n    if (kb.matches(keyData, \"tui.select.up\")) {\n      this.selectedIndex = this.selectedIndex === 0 ? this.messages.length - 1 : this.selectedIndex - 1;\n    } else if (kb.matches(keyData, \"tui.select.down\")) {\n      this.selectedIndex = this.selectedIndex === this.messages.length - 1 ? 0 : this.selectedIndex + 1;\n    } else if (kb.matches(keyData, \"tui.select.confirm\")) {\n      const selected = this.messages[this.selectedIndex];\n      if (selected && this.onSelect) {\n        this.onSelect(selected.id);\n      }\n    } else if (kb.matches(keyData, \"tui.select.cancel\")) {\n      if (this.onCancel) {\n        this.onCancel();\n      }\n    }\n  }\n};\nvar UserMessageSelectorComponent = class extends Container {\n  messageList;\n  constructor(messages, onSelect, onCancel, initialSelectedId) {\n    super();\n    this.addChild(new Spacer(1));\n    this.addChild(new Text(theme.bold(\"Fork from Message\"), 1, 0));\n    this.addChild(new Text(theme.fg(\"muted\", \"Select a user message to copy the active path up to that point into a new session\"), 1, 0));\n    this.addChild(new Spacer(1));\n    this.addChild(new DynamicBorder());\n    this.addChild(new Spacer(1));\n    this.messageList = new UserMessageList(messages, initialSelectedId);\n    this.messageList.onSelect = onSelect;\n    this.messageList.onCancel = onCancel;\n    this.addChild(this.messageList);\n    this.addChild(new Spacer(1));\n    this.addChild(new DynamicBorder());\n    if (messages.length === 0) {\n      setTimeout(() => onCancel(), 100);\n    }\n  }\n  getMessageList() {\n    return this.messageList;\n  }\n};\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/theme/theme-controller.js\nvar InteractiveThemeController = class {\n  ui;\n  getSettingsManager;\n  showError;\n  onChanged;\n  currentThemeSetting;\n  terminalTheme = detectTerminalBackgroundFromEnv().theme;\n  activeThemeName;\n  autoSyncEnabled = false;\n  terminalColorSchemeUnsubscribe;\n  constructor(ui, options) {\n    this.ui = ui;\n    this.getSettingsManager = options.getSettingsManager;\n    this.showError = options.showError;\n    this.onChanged = options.onChanged;\n    this.currentThemeSetting = options.initialThemeSetting;\n    this.activeThemeName = resolveThemeSetting(this.currentThemeSetting ?? this.getSettingsManager().getThemeSetting(), this.terminalTheme);\n    initTheme(this.activeThemeName, true);\n    this.bindTerminalColorSchemeListener();\n  }\n  rebindTui() {\n    this.terminalColorSchemeUnsubscribe?.();\n    this.bindTerminalColorSchemeListener();\n    this.ui.setTerminalColorSchemeNotifications(this.autoSyncEnabled);\n  }\n  async applyFromSettings() {\n    const settingsManager = this.getSettingsManager();\n    const themeSetting = this.currentThemeSetting ?? settingsManager.getThemeSetting();\n    const autoTheme = parseAutoThemeSetting(themeSetting);\n    if (autoTheme) {\n      this.terminalTheme = await detectTerminalThemeForAuto({ ui: this.ui, timeoutMs: 100 });\n      this.setAutoSync(true);\n      this.applyThemeName(this.terminalTheme === \"light\" ? autoTheme.lightTheme : autoTheme.darkTheme, true);\n      return;\n    }\n    this.setAutoSync(false);\n    if (themeSetting !== void 0) {\n      this.applyThemeName(themeSetting, true);\n      return;\n    }\n    const detection = await detectTerminalBackgroundTheme({ ui: this.ui, timeoutMs: 100 });\n    this.terminalTheme = detection.theme;\n    if (!this.applyThemeName(detection.theme).success)\n      return;\n    if (detection.confidence === \"high\") {\n      settingsManager.setTheme(detection.theme);\n      await settingsManager.flush();\n    }\n  }\n  getThemeSelection() {\n    return this.currentThemeSetting ?? this.getSettingsManager().getThemeSetting() ?? this.activeThemeName;\n  }\n  setThemeName(themeName, showError = false) {\n    this.setAutoSync(false);\n    const result = this.applyThemeName(themeName, showError);\n    if (result.success) {\n      this.currentThemeSetting = themeName;\n    }\n    return result;\n  }\n  async setThemeSetting(themeSetting) {\n    this.currentThemeSetting = themeSetting;\n    await this.applyFromSettings();\n  }\n  setThemeInstance(themeInstance) {\n    this.setAutoSync(false);\n    setThemeInstance(themeInstance);\n    this.activeThemeName = \"<in-memory>\";\n    this.notifyChanged();\n    return { success: true };\n  }\n  preview(themeSettingOrName) {\n    const themeName = resolveThemeSetting(themeSettingOrName, this.terminalTheme) ?? this.activeThemeName;\n    if (!themeName)\n      return;\n    if (setTheme(themeName, true).success) {\n      this.ui.invalidate();\n      this.ui.requestRender();\n    }\n  }\n  disableAutoSync() {\n    this.setAutoSync(false);\n  }\n  getTerminalTheme() {\n    return this.terminalTheme;\n  }\n  applyThemeName(themeName, showError = false) {\n    const result = setTheme(themeName, true);\n    this.activeThemeName = result.success ? themeName : \"dark\";\n    this.notifyChanged();\n    if (!result.success && showError) {\n      this.showError(`Failed to load theme \"${themeName}\": ${result.error}\nFell back to dark theme.`);\n    }\n    return result;\n  }\n  notifyChanged() {\n    this.ui.invalidate();\n    this.onChanged();\n  }\n  setAutoSync(enabled) {\n    if (this.autoSyncEnabled === enabled)\n      return;\n    this.autoSyncEnabled = enabled;\n    this.ui.setTerminalColorSchemeNotifications(enabled);\n  }\n  bindTerminalColorSchemeListener() {\n    this.terminalColorSchemeUnsubscribe = this.ui.onTerminalColorSchemeChange((terminalTheme) => this.applyTerminalTheme(terminalTheme));\n  }\n  applyTerminalTheme(terminalTheme) {\n    if (!this.autoSyncEnabled)\n      return;\n    this.terminalTheme = terminalTheme;\n    const autoTheme = parseAutoThemeSetting(this.currentThemeSetting ?? this.getSettingsManager().getThemeSetting());\n    if (!autoTheme) {\n      this.setAutoSync(false);\n      return;\n    }\n    const themeName = terminalTheme === \"light\" ? autoTheme.lightTheme : autoTheme.darkTheme;\n    if (themeName !== this.activeThemeName) {\n      this.applyThemeName(themeName);\n    }\n  }\n};\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/interactive-mode.js\nfunction isExpandable(obj) {\n  return typeof obj === \"object\" && obj !== null && \"setExpanded\" in obj && typeof obj.setExpanded === \"function\";\n}\nvar ExpandableText = class extends Text {\n  getCollapsedText;\n  getExpandedText;\n  constructor(getCollapsedText, getExpandedText, expanded = false, paddingX = 0, paddingY = 0) {\n    super(expanded ? getExpandedText() : getCollapsedText(), paddingX, paddingY);\n    this.getCollapsedText = getCollapsedText;\n    this.getExpandedText = getExpandedText;\n  }\n  setExpanded(expanded) {\n    this.setText(expanded ? this.getExpandedText() : this.getCollapsedText());\n  }\n};\nfunction isCustomSessionEntry(item) {\n  return \"type\" in item && item.type === \"custom\";\n}\nvar DEAD_TERMINAL_ERROR_CODES = /* @__PURE__ */ new Set([\"EIO\", \"EPIPE\", \"ENOTCONN\"]);\nfunction isDeadTerminalError(error) {\n  if (!error || typeof error !== \"object\" || !(\"code\" in error)) {\n    return false;\n  }\n  const code = error.code;\n  return code !== void 0 && DEAD_TERMINAL_ERROR_CODES.has(code);\n}\nvar ANTHROPIC_SUBSCRIPTION_AUTH_WARNING = \"Anthropic subscription auth is active. Third-party harness usage draws from extra usage and is billed per token, not your Claude plan limits. Manage extra usage at https://claude.ai/settings/usage. Disable this warning in /settings.\";\nfunction isAnthropicSubscriptionAuthKey(apiKey) {\n  return typeof apiKey === \"string\" && apiKey.startsWith(\"sk-ant-oat\");\n}\nfunction isUnknownModel(model) {\n  return !!model && model.provider === \"unknown\" && model.id === \"unknown\" && model.api === \"unknown\";\n}\nfunction quoteIfNeeded(value) {\n  if (value.length > 0 && !/[^a-zA-Z0-9_\\-./~:@]/.test(value)) {\n    return value;\n  }\n  return `'${value.replace(/'/g, `'\\\\''`)}'`;\n}\nfunction formatResumeCommand(sessionManager) {\n  if (!process.stdout.isTTY)\n    return void 0;\n  if (!sessionManager.isPersisted())\n    return void 0;\n  const sessionFile = sessionManager.getSessionFile();\n  if (!sessionFile || !fs6.existsSync(sessionFile))\n    return void 0;\n  const args = [APP_NAME];\n  if (!sessionManager.usesDefaultSessionDir()) {\n    args.push(\"--session-dir\", quoteIfNeeded(sessionManager.getSessionDir()));\n  }\n  args.push(\"--session\", sessionManager.getSessionId());\n  return args.join(\" \");\n}\nfunction hasDefaultModelProvider(providerId) {\n  return providerId in defaultModelPerProvider;\n}\nvar AUTH_TYPE_ORDER = { oauth: 0, api_key: 1 };\nfunction createFuzzyAutocompleteItems(items, prefix, getSearchText, toAutocompleteItem) {\n  const filtered = fuzzyFilter(items, prefix, getSearchText);\n  if (filtered.length === 0)\n    return null;\n  return filtered.map(toAutocompleteItem);\n}\nfunction getLoginProviderCompletionOptions(providerOptions) {\n  const byId = /* @__PURE__ */ new Map();\n  for (const provider of providerOptions) {\n    const existing = byId.get(provider.id);\n    if (existing) {\n      if (!existing.authTypes.includes(provider.authType)) {\n        existing.authTypes.push(provider.authType);\n        existing.authTypes.sort((a, b) => AUTH_TYPE_ORDER[a] - AUTH_TYPE_ORDER[b]);\n      }\n      continue;\n    }\n    byId.set(provider.id, {\n      id: provider.id,\n      name: provider.name,\n      authTypes: [provider.authType]\n    });\n  }\n  return Array.from(byId.values()).sort((a, b) => a.name.localeCompare(b.name));\n}\nfunction getLoginProviderSearchText(provider) {\n  const authTypes = provider.authTypes.map((authType) => `${authType} ${formatAuthSelectorProviderType(authType)}`).join(\" \");\n  return `${provider.id} ${provider.name} ${authTypes}`;\n}\nfunction formatLoginProviderCompletionDescription(provider) {\n  const authTypes = provider.authTypes.map(formatAuthSelectorProviderType).join(\"/\");\n  return provider.name === provider.id ? authTypes : `${provider.name} \\xB7 ${authTypes}`;\n}\nfunction createInteractiveTui(options) {\n  const terminal = options.terminal ?? new ProcessTerminal();\n  if (options.tuiMode === \"fullscreen\") {\n    const styleSearchMatch = (text) => theme.bg(\"searchMatchBg\", theme.fg(\"searchMatchText\", text));\n    return new TuiAltScreen(terminal, options.showHardwareCursor, options.logDirectory, {\n      searchMatchStyle: (text) => theme.underline(styleSearchMatch(text)),\n      searchCurrentMatchStyle: (text) => theme.bold(theme.inverse(styleSearchMatch(text))),\n      openUrl: openBrowser,\n      onRightClickPaste: options.onRightClickPaste,\n      copySelection: async (text) => {\n        try {\n          await copyToClipboard(text);\n          return true;\n        } catch {\n          return false;\n        }\n      }\n    });\n  }\n  return new TuiMainScreen(terminal, options.showHardwareCursor, options.logDirectory);\n}\nfunction createInteractiveTuiReference(getTui) {\n  return new Proxy({}, {\n    get: (_target, property) => {\n      const tui = getTui();\n      const value = Reflect.get(tui, property, tui);\n      if (typeof value !== \"function\")\n        return value;\n      let methodTui = tui;\n      let method = value;\n      return (...args) => {\n        const currentTui = getTui();\n        if (currentTui !== methodTui) {\n          const currentMethod = Reflect.get(currentTui, property, currentTui);\n          if (typeof currentMethod !== \"function\") {\n            throw new TypeError(`TUI property ${String(property)} is not callable`);\n          }\n          methodTui = currentTui;\n          method = currentMethod;\n        }\n        return Reflect.apply(method, methodTui, args);\n      };\n    },\n    set: (_target, property, value) => {\n      const tui = getTui();\n      return Reflect.set(tui, property, value, tui);\n    },\n    has: (_target, property) => Reflect.has(getTui(), property),\n    getPrototypeOf: () => Reflect.getPrototypeOf(getTui())\n  });\n}\nvar InteractiveMode = class _InteractiveMode {\n  runtimeHost;\n  renderer;\n  ui;\n  mainScreenRenderState;\n  loadedResourcesContainer;\n  chatContainer;\n  documentContainer;\n  transcriptScrollView;\n  fullscreenLayoutRoot;\n  pendingMessagesContainer;\n  statusContainer;\n  defaultEditor;\n  editor;\n  editorComponentFactory;\n  autocompleteProvider;\n  autocompleteProviderWrappers = [];\n  fdPath;\n  editorContainer;\n  activeSelectorToken;\n  activeSelectorDispose;\n  footer;\n  footerContainer;\n  footerDataProvider;\n  // Stored so the same manager can be injected into custom editors, selectors, and extension UI.\n  keybindings;\n  version;\n  isInitialized = false;\n  onInputCallback;\n  pendingUserInputs = [];\n  activeStatusIndicator = void 0;\n  idleStatus = new IdleStatus();\n  workingMessage = void 0;\n  workingVisible = true;\n  workingIndicatorOptions = void 0;\n  defaultWorkingMessage = \"Working...\";\n  defaultHiddenThinkingLabel = \"Thinking...\";\n  hiddenThinkingLabel = this.defaultHiddenThinkingLabel;\n  lastSigintTime = 0;\n  lastEscapeTime = 0;\n  changelogMarkdown = void 0;\n  startupNoticesShown = false;\n  anthropicSubscriptionWarningShown = false;\n  // Status line tracking (for mutating immediately-sequential status updates)\n  lastStatusSpacer = void 0;\n  lastStatusText = void 0;\n  managedToolStatusStarted = false;\n  // Streaming message tracking\n  streamingComponent = void 0;\n  streamingMessage = void 0;\n  // Tool execution tracking: toolCallId -> component\n  pendingTools = /* @__PURE__ */ new Map();\n  // Tool output expansion state\n  toolOutputExpanded = false;\n  // Thinking block visibility state\n  hideThinkingBlock = false;\n  outputPad = 1;\n  mermaidMarkdownTransformer = createMermaidMarkdownTransformer({\n    getMode: () => this.settingsManager.getMermaidRenderingMode(),\n    theme\n  });\n  // Skill commands: command name -> skill file path\n  skillCommands = /* @__PURE__ */ new Map();\n  // Agent subscription unsubscribe function\n  unsubscribe;\n  signalCleanupHandlers = [];\n  // Track if editor is in bash mode (text starts with !)\n  isBashMode = false;\n  // Track current bash execution component\n  bashComponent = void 0;\n  // Track pending bash components (shown in pending area, moved to chat on submit)\n  pendingBashComponents = [];\n  // Auto-compaction state\n  autoCompactionEscapeHandler;\n  // Auto-retry state\n  retryEscapeHandler;\n  // Messages queued while compaction is running\n  compactionQueuedMessages = [];\n  // Shutdown state\n  shutdownRequested = false;\n  // Extension UI state\n  extensionSelector = void 0;\n  extensionInput = void 0;\n  extensionEditor = void 0;\n  extensionTerminalInputSubscriptions = /* @__PURE__ */ new Set();\n  // Extension widgets (components rendered above/below the editor)\n  extensionWidgetsAbove = /* @__PURE__ */ new Map();\n  extensionWidgetsBelow = /* @__PURE__ */ new Map();\n  widgetContainerAbove;\n  widgetContainerBelow;\n  // Custom footer from extension (undefined = use built-in footer)\n  customFooter = void 0;\n  // Header container that holds the built-in or custom header\n  headerContainer;\n  // Built-in header (logo + keybinding hints + changelog)\n  builtInHeader = void 0;\n  // Custom header from extension (undefined = use built-in header)\n  customHeader = void 0;\n  options;\n  onRightClickPaste = () => {\n    void this.handleRightClickPaste();\n  };\n  autoTrustOnReloadCwd;\n  themeController;\n  // Convenience accessors\n  get session() {\n    return this.runtimeHost.session;\n  }\n  get agent() {\n    return this.session.agent;\n  }\n  get sessionManager() {\n    return this.session.sessionManager;\n  }\n  get settingsManager() {\n    return this.session.settingsManager;\n  }\n  constructor(runtimeHost, options = {}) {\n    this.runtimeHost = runtimeHost;\n    const tuiMode = options.tuiMode ?? this.settingsManager.getTuiMode();\n    this.options = { ...options, tuiMode };\n    this.autoTrustOnReloadCwd = options.autoTrustOnReloadCwd;\n    this.runtimeHost.setBeforeSessionInvalidate(() => {\n      this.resetExtensionUI();\n    });\n    this.runtimeHost.setRebindSession(async () => {\n      await this.rebindCurrentSession({ renderBeforeBind: true });\n      await this.themeController.applyFromSettings();\n    });\n    this.version = VERSION;\n    this.renderer = createInteractiveTui({\n      tuiMode,\n      showHardwareCursor: this.settingsManager.getShowHardwareCursor(),\n      logDirectory: getAgentDir(),\n      onRightClickPaste: this.onRightClickPaste\n    });\n    this.ui = createInteractiveTuiReference(() => this.renderer);\n    this.ui.setClearOnShrink(this.settingsManager.getClearOnShrink());\n    this.headerContainer = new Container();\n    this.loadedResourcesContainer = new Container();\n    this.chatContainer = new Container();\n    this.documentContainer = new Container();\n    this.documentContainer.addChild(this.headerContainer);\n    this.documentContainer.addChild(this.loadedResourcesContainer);\n    this.documentContainer.addChild(this.chatContainer);\n    this.pendingMessagesContainer = new Container();\n    this.statusContainer = new Container();\n    this.widgetContainerAbove = new Container();\n    this.widgetContainerBelow = new Container();\n    this.keybindings = KeybindingsManager2.create();\n    setKeybindings(this.keybindings);\n    const editorPaddingX = this.settingsManager.getEditorPaddingX();\n    const autocompleteMaxVisible = this.settingsManager.getAutocompleteMaxVisible();\n    this.defaultEditor = new CustomEditor(this.ui, getEditorTheme(), this.keybindings, {\n      paddingX: editorPaddingX,\n      autocompleteMaxVisible\n    });\n    this.editor = this.defaultEditor;\n    this.editorContainer = new Container();\n    this.editorContainer.addChild(this.editor);\n    this.footerDataProvider = new FooterDataProvider(this.sessionManager.getCwd());\n    this.footer = new FooterComponent(this.session, this.footerDataProvider);\n    this.footer.setAutoCompactEnabled(this.session.autoCompactionEnabled);\n    this.footerContainer = new Container();\n    this.footerContainer.addChild(this.footer);\n    this.hideThinkingBlock = this.settingsManager.getHideThinkingBlock();\n    this.outputPad = this.settingsManager.getOutputPad();\n    setRegisteredThemes(this.session.resourceLoader.getThemes().themes);\n    this.themeController = new InteractiveThemeController(this.ui, {\n      getSettingsManager: () => this.settingsManager,\n      showError: (message) => this.showError(message),\n      onChanged: () => this.updateEditorBorderColor(),\n      initialThemeSetting: options.initialThemeSetting\n    });\n  }\n  getAutocompleteSourceTag(sourceInfo) {\n    if (!sourceInfo) {\n      return void 0;\n    }\n    const scopePrefix = sourceInfo.scope === \"user\" ? \"u\" : sourceInfo.scope === \"project\" ? \"p\" : \"t\";\n    const source = sourceInfo.source.trim();\n    if (source === \"auto\" || source === \"local\" || source === \"cli\") {\n      return scopePrefix;\n    }\n    if (source.startsWith(\"npm:\")) {\n      return `${scopePrefix}:${source}`;\n    }\n    const gitSource = parseGitUrl(source);\n    if (gitSource) {\n      const ref = gitSource.ref ? `@${gitSource.ref}` : \"\";\n      return `${scopePrefix}:git:${gitSource.host}/${gitSource.path}${ref}`;\n    }\n    return scopePrefix;\n  }\n  prefixAutocompleteDescription(description, sourceInfo) {\n    const sourceTag = this.getAutocompleteSourceTag(sourceInfo);\n    if (!sourceTag) {\n      return description;\n    }\n    return description ? `[${sourceTag}] ${description}` : `[${sourceTag}]`;\n  }\n  getBuiltInCommandConflictDiagnostics(extensionRunner) {\n    const builtinNames = new Set(BUILTIN_SLASH_COMMANDS.map((command) => command.name));\n    return extensionRunner.getRegisteredCommands().filter((command) => builtinNames.has(command.name)).map((command) => ({\n      type: \"warning\",\n      message: command.invocationName === command.name ? `Extension command '/${command.name}' conflicts with built-in interactive command. Skipping in autocomplete.` : `Extension command '/${command.name}' conflicts with built-in interactive command. Available as '/${command.invocationName}'.`,\n      path: command.sourceInfo.path\n    }));\n  }\n  createBaseAutocompleteProvider() {\n    const slashCommands = BUILTIN_SLASH_COMMANDS.map((command) => ({\n      name: command.name,\n      description: command.description,\n      ...command.argumentHint && { argumentHint: command.argumentHint }\n    }));\n    const modelCommand = slashCommands.find((command) => command.name === \"model\");\n    if (modelCommand) {\n      modelCommand.getArgumentCompletions = (prefix) => {\n        const models = this.session.scopedModels.length > 0 ? this.session.scopedModels.map((s) => s.model) : this.session.modelRuntime.getAvailableSnapshot();\n        if (models.length === 0)\n          return null;\n        const items = models.map((m) => ({\n          id: m.id,\n          provider: m.provider,\n          name: m.name,\n          label: `${m.provider}/${m.id}`\n        }));\n        return createFuzzyAutocompleteItems(items, prefix, getModelSearchText, (item) => ({\n          value: item.label,\n          label: item.id,\n          description: item.provider\n        }));\n      };\n    }\n    const loginCommand = slashCommands.find((command) => command.name === \"login\");\n    if (loginCommand) {\n      loginCommand.getArgumentCompletions = (prefix) => {\n        const providers = getLoginProviderCompletionOptions(this.getLoginProviderOptions());\n        return createFuzzyAutocompleteItems(providers, prefix, getLoginProviderSearchText, (provider) => ({\n          value: provider.id,\n          label: provider.id,\n          description: formatLoginProviderCompletionDescription(provider)\n        }));\n      };\n    }\n    const templateCommands = this.session.promptTemplates.map((cmd) => ({\n      name: cmd.name,\n      description: this.prefixAutocompleteDescription(cmd.description, cmd.sourceInfo),\n      ...cmd.argumentHint && { argumentHint: cmd.argumentHint }\n    }));\n    const builtinCommandNames = new Set(slashCommands.map((c) => c.name));\n    const extensionCommands = this.session.extensionRunner.getRegisteredCommands().filter((cmd) => !builtinCommandNames.has(cmd.name)).map((cmd) => ({\n      name: cmd.invocationName,\n      description: this.prefixAutocompleteDescription(cmd.description, cmd.sourceInfo),\n      getArgumentCompletions: cmd.getArgumentCompletions\n    }));\n    this.skillCommands.clear();\n    const skillCommandList = [];\n    if (this.settingsManager.getEnableSkillCommands()) {\n      for (const skill of this.session.resourceLoader.getSkills().skills) {\n        const commandName = `skill:${skill.name}`;\n        this.skillCommands.set(commandName, skill.filePath);\n        skillCommandList.push({\n          name: commandName,\n          description: this.prefixAutocompleteDescription(skill.description, skill.sourceInfo)\n        });\n      }\n    }\n    return new CombinedAutocompleteProvider([...slashCommands, ...templateCommands, ...extensionCommands, ...skillCommandList], this.sessionManager.getCwd(), this.fdPath);\n  }\n  setupAutocompleteProvider() {\n    let provider = this.createBaseAutocompleteProvider();\n    const triggerCharacters = [];\n    for (const wrapProvider of this.autocompleteProviderWrappers) {\n      provider = wrapProvider(provider);\n      triggerCharacters.push(...provider.triggerCharacters ?? []);\n    }\n    if (triggerCharacters.length > 0) {\n      provider.triggerCharacters = [...new Set(triggerCharacters)];\n    }\n    this.autocompleteProvider = provider;\n    this.defaultEditor.setAutocompleteProvider(provider);\n    if (this.editor !== this.defaultEditor) {\n      this.editor.setAutocompleteProvider?.(provider);\n    }\n  }\n  showStartupNoticesIfNeeded() {\n    if (this.startupNoticesShown) {\n      return;\n    }\n    this.startupNoticesShown = true;\n    if (!this.changelogMarkdown) {\n      return;\n    }\n    if (this.chatContainer.children.length > 0) {\n      this.chatContainer.addChild(new Spacer(1));\n    }\n    this.chatContainer.addChild(new DynamicBorder());\n    if (this.settingsManager.getCollapseChangelog()) {\n      const versionMatch = this.changelogMarkdown.match(/##\\s+\\[?(\\d+\\.\\d+\\.\\d+)\\]?/);\n      const latestVersion = versionMatch ? versionMatch[1] : this.version;\n      const condensedText = `Updated to v${latestVersion}. Use ${theme.bold(\"/changelog\")} to view full changelog.`;\n      this.chatContainer.addChild(new Text(condensedText, 1, 0));\n    } else {\n      this.chatContainer.addChild(new Text(theme.bold(theme.fg(\"accent\", \"What's New\")), 1, 0));\n      this.chatContainer.addChild(new Spacer(1));\n      this.chatContainer.addChild(new Markdown(this.changelogMarkdown.trim(), 1, 0, this.getMarkdownThemeWithSettings()));\n      this.chatContainer.addChild(new Spacer(1));\n    }\n    this.chatContainer.addChild(new DynamicBorder());\n  }\n  mountInteractiveTui(tui, components) {\n    for (const component of components)\n      tui.addChild(component);\n    if (isViewportTUI(tui)) {\n      if (!this.fullscreenLayoutRoot)\n        throw new Error(\"Fullscreen layout is not initialized\");\n      tui.setLayoutRoot(this.fullscreenLayoutRoot);\n    }\n  }\n  stopInteractiveTui(fullscreenExitOutput) {\n    if (this.renderer.mode === \"fullscreen\" && fullscreenExitOutput === \"transcript\") {\n      while (this.renderer.hasOverlayEntries)\n        this.renderer.hideOverlay();\n      this.switchTuiMode(\"regular\", false, false);\n      this.renderer.renderNow();\n    }\n    this.ui.stop({ preserveScreen: this.renderer.mode === \"fullscreen\" });\n  }\n  switchTuiMode(mode, restoreProgress = true, startRenderer = true) {\n    const previousUi = this.renderer;\n    if (mode === previousUi.mode)\n      return true;\n    if (previousUi.hasOverlayEntries)\n      return false;\n    const components = [...previousUi.children];\n    const focus = previousUi.getFocusedComponent();\n    const terminal = previousUi.terminal;\n    const showHardwareCursor = previousUi.getShowHardwareCursor();\n    const clearOnShrink = previousUi.getClearOnShrink();\n    const onDebug = previousUi.onDebug;\n    if (previousUi instanceof TuiMainScreen) {\n      this.mainScreenRenderState = previousUi.captureRenderState();\n    }\n    previousUi.stop({ preserveScreen: true });\n    previousUi.setFocus(null);\n    previousUi.clear();\n    if (isViewportTUI(previousUi))\n      previousUi.setLayoutRoot(void 0);\n    const nextUi = createInteractiveTui({\n      tuiMode: mode,\n      showHardwareCursor,\n      logDirectory: getAgentDir(),\n      terminal,\n      onRightClickPaste: this.onRightClickPaste\n    });\n    nextUi.setClearOnShrink(clearOnShrink);\n    nextUi.onDebug = onDebug;\n    if (nextUi instanceof TuiMainScreen && this.mainScreenRenderState) {\n      nextUi.restoreRenderState(this.mainScreenRenderState);\n    }\n    this.renderer = nextUi;\n    this.options.tuiMode = mode;\n    this.mountInteractiveTui(nextUi, components);\n    nextUi.invalidate();\n    nextUi.setFocus(focus);\n    if (!startRenderer)\n      return true;\n    nextUi.start();\n    this.themeController.rebindTui();\n    this.rebindExtensionTerminalInputListeners();\n    if (restoreProgress && this.settingsManager.getShowTerminalProgress() && (this.session.isStreaming || this.session.isCompacting)) {\n      terminal.setProgress(true);\n    }\n    return true;\n  }\n  async init() {\n    if (this.isInitialized)\n      return;\n    this.registerSignalHandlers();\n    this.changelogMarkdown = this.getChangelogForDisplay();\n    if (this.session.scopedModels.length > 0 && (this.options.verbose || !this.settingsManager.getQuietStartup())) {\n      const modelList = this.session.scopedModels.map((sm) => {\n        const thinkingStr = sm.thinkingLevel ? `:${sm.thinkingLevel}` : \"\";\n        return `${sm.model.id}${thinkingStr}`;\n      }).join(\", \");\n      const cycleKeys = this.keybindings.getKeys(\"app.model.cycleForward\");\n      const cycleHint = cycleKeys.length > 0 ? theme.fg(\"muted\", ` (${formatKeyText(cycleKeys.join(\"/\"), { capitalize: true })} to cycle)`) : \"\";\n      console.log(theme.fg(\"dim\", `Model scope: ${modelList}${cycleHint}`));\n    }\n    this.renderWidgets();\n    this.transcriptScrollView = new ScrollView(this.documentContainer, {\n      follow: \"end\",\n      primary: true,\n      overscroll: \"chain\",\n      scrollbar: this.settingsManager.getFullscreenScrollbar(),\n      scrollbarStyle: (text) => theme.bg(\"scrollbarThumb\", text)\n    });\n    const dock = new VStack([\n      { component: this.pendingMessagesContainer, shrink: 1, minSize: 0 },\n      { component: this.statusContainer, shrink: 1, minSize: 0 },\n      { component: this.widgetContainerAbove, shrink: 1, minSize: 0 },\n      { component: this.editorContainer, shrink: 1, minSize: 3 },\n      { component: this.widgetContainerBelow, shrink: 1, minSize: 0 },\n      { component: this.footerContainer, shrink: 1, minSize: 1 }\n    ]);\n    this.fullscreenLayoutRoot = new VStack([\n      { component: this.transcriptScrollView, basis: 0, grow: 1, shrink: 1, minSize: 1 },\n      { component: dock, basis: \"auto\", grow: 0, shrink: 1, minSize: 1 }\n    ]);\n    this.mountInteractiveTui(this.renderer, [\n      this.documentContainer,\n      this.pendingMessagesContainer,\n      this.statusContainer,\n      this.widgetContainerAbove,\n      this.editorContainer,\n      this.widgetContainerBelow,\n      this.footerContainer\n    ]);\n    this.defaultEditor.onAction(\"app.clear\", () => this.handleCtrlC());\n    this.defaultEditor.onCtrlD = () => this.handleCtrlD();\n    this.defaultEditor.onSubmit = (text) => this.handleStartupSubmit(text);\n    this.ui.setFocus(this.editor);\n    this.ui.start();\n    this.isInitialized = true;\n    await this.themeController.applyFromSettings();\n    if (this.options.verbose || !this.settingsManager.getQuietStartup()) {\n      const logo = theme.bold(theme.fg(\"accent\", APP_NAME)) + theme.fg(\"dim\", ` v${this.version}`);\n      const hint = (keybinding, description) => keyHint(keybinding, description);\n      const expandedInstructions = [\n        hint(\"app.interrupt\", \"to interrupt\"),\n        hint(\"app.clear\", \"to clear\"),\n        rawKeyHint(`${keyText(\"app.clear\")} twice`, \"to exit\"),\n        hint(\"app.exit\", \"to exit (empty)\"),\n        hint(\"app.suspend\", \"to suspend\"),\n        keyHint(\"tui.editor.deleteToLineEnd\", \"to delete to end\"),\n        hint(\"app.thinking.cycle\", \"to cycle thinking level\"),\n        rawKeyHint(`${keyText(\"app.model.cycleForward\")}/${keyText(\"app.model.cycleBackward\")}`, \"to cycle models\"),\n        hint(\"app.model.select\", \"to select model\"),\n        hint(\"app.tools.expand\", \"to expand tools\"),\n        hint(\"app.thinking.toggle\", \"to expand thinking\"),\n        hint(\"app.editor.external\", \"for external editor\"),\n        rawKeyHint(\"/\", \"for commands\"),\n        rawKeyHint(\"!\", \"to run bash\"),\n        rawKeyHint(\"!!\", \"to run bash (no context)\"),\n        hint(\"app.message.followUp\", \"to queue follow-up\"),\n        hint(\"app.message.dequeue\", \"to edit all queued messages\"),\n        hint(\"app.clipboard.pasteImage\", \"to paste image (with text fallback)\"),\n        rawKeyHint(\"drop files\", \"to attach\")\n      ].join(\"\\n\");\n      const compactInstructions = [\n        hint(\"app.interrupt\", \"interrupt\"),\n        rawKeyHint(`${keyText(\"app.clear\")}/${keyText(\"app.exit\")}`, \"clear/exit\"),\n        rawKeyHint(\"/\", \"commands\"),\n        rawKeyHint(\"!\", \"bash\"),\n        hint(\"app.tools.expand\", \"more\")\n      ].join(theme.fg(\"muted\", \" \\xB7 \"));\n      const compactOnboarding = theme.fg(\"dim\", `Press ${keyText(\"app.tools.expand\")} to show full startup help and loaded resources.`);\n      const onboarding = theme.fg(\"dim\", `Pi can explain its own features and look up its docs. Ask it how to use or extend Pi.`);\n      this.builtInHeader = new ExpandableText(() => `${logo}\n${compactInstructions}\n${compactOnboarding}\n\n${onboarding}`, () => `${logo}\n${expandedInstructions}\n\n${onboarding}`, this.getStartupExpansionState(), 1, 0);\n      this.headerContainer.addChild(new Spacer(1));\n      this.headerContainer.addChild(this.builtInHeader);\n      this.headerContainer.addChild(new Spacer(1));\n    } else {\n      this.builtInHeader = new Text(\"\", 0, 0);\n      this.headerContainer.addChild(this.builtInHeader);\n    }\n    this.ui.requestRender();\n    const [fdPath] = await Promise.all([\n      ensureTool(\"fd\", (status) => this.showManagedToolStatus(status)),\n      ensureTool(\"rg\", (status) => this.showManagedToolStatus(status))\n    ]);\n    this.fdPath = fdPath;\n    this.setupKeyHandlers();\n    this.setupEditorSubmitHandler();\n    this.ui.requestRender();\n    await this.rebindCurrentSession();\n    this.renderInitialMessages();\n    onThemeChange(() => {\n      this.ui.invalidate();\n      this.updateEditorBorderColor();\n      this.ui.requestRender();\n    });\n    this.footerDataProvider.onBranchChange(() => {\n      this.ui.requestRender();\n    });\n    await this.updateAvailableProviderCount();\n  }\n  /**\n   * Update terminal title with session name and cwd.\n   */\n  updateTerminalTitle() {\n    const cwdBasename = path10.basename(this.sessionManager.getCwd());\n    const sessionName = this.sessionManager.getSessionName();\n    if (sessionName) {\n      this.ui.terminal.setTitle(`${APP_TITLE} - ${sessionName} - ${cwdBasename}`);\n    } else {\n      this.ui.terminal.setTitle(`${APP_TITLE} - ${cwdBasename}`);\n    }\n  }\n  /**\n   * Run the interactive mode. This is the main entry point.\n   * Initializes the UI, shows warnings, processes initial messages, and starts the interactive loop.\n   */\n  async run() {\n    await this.init();\n    if (!process.env.PI_OFFLINE) {\n      const controller = new AbortController();\n      const timeout = setTimeout(() => controller.abort(), 15e3);\n      void refreshModelCatalogs(this.session.modelRuntime, controller.signal).then(() => this.updateAvailableProviderCount()).catch(() => {\n      }).finally(() => clearTimeout(timeout));\n    }\n    checkForNewPiVersion(this.version).then((newRelease) => {\n      if (newRelease) {\n        this.showNewVersionNotification(newRelease);\n      }\n    });\n    this.checkForPackageUpdates().then((updates) => {\n      if (updates.length > 0) {\n        this.showPackageUpdateNotification(updates);\n      }\n    }).finally(() => {\n      if (process.platform === \"win32\" && this.isInitialized) {\n        this.updateTerminalTitle();\n      }\n    });\n    this.checkTmuxKeyboardSetup().then((warning) => {\n      if (warning) {\n        this.showWarning(warning);\n      }\n    });\n    const { migratedProviders, modelFallbackMessage, initialMessage, initialImages, initialMessages } = this.options;\n    if (migratedProviders && migratedProviders.length > 0) {\n      this.showWarning(`Migrated credentials to auth.json: ${migratedProviders.join(\", \")}`);\n    }\n    const modelsJsonError = this.session.modelRuntime.getError();\n    if (modelsJsonError) {\n      this.showError(`models.json error: ${modelsJsonError}`);\n    }\n    if (modelFallbackMessage) {\n      this.showWarning(modelFallbackMessage);\n    }\n    void this.maybeWarnAboutAnthropicSubscriptionAuth();\n    if (initialMessage) {\n      try {\n        await this.session.prompt(initialMessage, { images: initialImages });\n      } catch (error) {\n        const errorMessage2 = error instanceof Error ? error.message : \"Unknown error occurred\";\n        this.showError(errorMessage2);\n      }\n    }\n    if (initialMessages) {\n      for (const message of initialMessages) {\n        try {\n          await this.session.prompt(message);\n        } catch (error) {\n          const errorMessage2 = error instanceof Error ? error.message : \"Unknown error occurred\";\n          this.showError(errorMessage2);\n        }\n      }\n    }\n    while (true) {\n      const userInput = await this.getUserInput();\n      try {\n        await this.session.prompt(userInput);\n      } catch (error) {\n        const errorMessage2 = error instanceof Error ? error.message : \"Unknown error occurred\";\n        this.showError(errorMessage2);\n      }\n    }\n  }\n  async checkForPackageUpdates() {\n    if (process.env.PI_OFFLINE) {\n      return [];\n    }\n    try {\n      const packageManager = new DefaultPackageManager({\n        cwd: this.sessionManager.getCwd(),\n        agentDir: getAgentDir(),\n        settingsManager: this.settingsManager\n      });\n      const updates = await packageManager.checkForAvailableUpdates();\n      return updates.map((update) => update.displayName);\n    } catch {\n      return [];\n    }\n  }\n  async checkTmuxKeyboardSetup() {\n    if (!process.env.TMUX)\n      return void 0;\n    const runTmuxShow = (option) => {\n      return new Promise((resolve15) => {\n        const proc = spawn9(\"tmux\", [\"show\", \"-gv\", option], {\n          stdio: [\"ignore\", \"pipe\", \"ignore\"]\n        });\n        let stdout = \"\";\n        const timer = setTimeout(() => {\n          proc.kill();\n          resolve15(void 0);\n        }, 2e3);\n        proc.stdout?.on(\"data\", (data) => {\n          stdout += data.toString();\n        });\n        proc.on(\"error\", () => {\n          clearTimeout(timer);\n          resolve15(void 0);\n        });\n        proc.on(\"close\", (code) => {\n          clearTimeout(timer);\n          resolve15(code === 0 ? stdout.trim() : void 0);\n        });\n      });\n    };\n    const [extendedKeys, extendedKeysFormat] = await Promise.all([\n      runTmuxShow(\"extended-keys\"),\n      runTmuxShow(\"extended-keys-format\")\n    ]);\n    if (extendedKeys === void 0)\n      return void 0;\n    if (extendedKeys !== \"on\" && extendedKeys !== \"always\") {\n      return \"tmux extended-keys is off. Modified Enter keys may not work. Add `set -g extended-keys on` to ~/.tmux.conf and restart tmux.\";\n    }\n    if (extendedKeysFormat === \"xterm\") {\n      return \"tmux extended-keys-format is xterm. Pi works best with csi-u. Add `set -g extended-keys-format csi-u` to ~/.tmux.conf and restart tmux.\";\n    }\n    return void 0;\n  }\n  /**\n   * Get changelog entries to display on startup.\n   * Only shows new entries since last seen version, skips for resumed sessions.\n   */\n  getChangelogForDisplay() {\n    if (this.session.state.messages.length > 0) {\n      return void 0;\n    }\n    const lastVersion = this.settingsManager.getLastChangelogVersion();\n    const changelogPath = getChangelogPath();\n    const entries = parseChangelog(changelogPath);\n    if (!lastVersion) {\n      this.settingsManager.setLastChangelogVersion(VERSION);\n      this.reportInstallTelemetry(VERSION);\n      return void 0;\n    }\n    const newEntries = getNewEntries(entries, lastVersion);\n    if (newEntries.length > 0) {\n      this.settingsManager.setLastChangelogVersion(VERSION);\n      this.reportInstallTelemetry(VERSION);\n      return newEntries.map((e) => normalizeChangelogLinks(e.content, e)).join(\"\\n\\n\");\n    }\n    return void 0;\n  }\n  reportInstallTelemetry(version) {\n    if (process.env.PI_OFFLINE) {\n      return;\n    }\n    if (!isInstallTelemetryEnabled(this.settingsManager)) {\n      return;\n    }\n    void fetch(`https://pi.dev/api/report-install?version=${encodeURIComponent(version)}`, {\n      headers: {\n        \"User-Agent\": getPiUserAgent2(version)\n      },\n      signal: AbortSignal.timeout(5e3)\n    }).then(() => void 0).catch(() => void 0);\n  }\n  getMarkdownThemeWithSettings() {\n    return {\n      ...getMarkdownTheme(),\n      codeBlockIndent: this.settingsManager.getCodeBlockIndent()\n    };\n  }\n  // =========================================================================\n  // Extension System\n  // =========================================================================\n  formatDisplayPath(p) {\n    const home = os4.homedir();\n    let result = p;\n    if (result.startsWith(home)) {\n      result = `~${result.slice(home.length)}`;\n    }\n    return result;\n  }\n  formatExtensionDisplayPath(path12) {\n    let result = this.formatDisplayPath(path12);\n    result = result.replace(/\\/index\\.ts$/, \"\").replace(/\\/index\\.js$/, \"\");\n    return result;\n  }\n  formatContextPath(p) {\n    const cwd = path10.resolve(this.sessionManager.getCwd());\n    const absolutePath = path10.isAbsolute(p) ? path10.resolve(p) : path10.resolve(cwd, p);\n    const relativePath = getCwdRelativePath(absolutePath, cwd);\n    if (relativePath !== void 0) {\n      return relativePath;\n    }\n    return this.formatDisplayPath(absolutePath);\n  }\n  getStartupExpansionState() {\n    return this.options.verbose || this.toolOutputExpanded;\n  }\n  /**\n   * Get a short path relative to the package root for display.\n   */\n  getShortPath(fullPath, sourceInfo) {\n    const normalizedFullPath = fullPath.replace(/\\\\/g, \"/\");\n    const baseDir = sourceInfo?.baseDir;\n    if (baseDir && this.isPackageSource(sourceInfo)) {\n      const normalizedBaseDir = baseDir.replace(/\\\\/g, \"/\");\n      const npmRootMatch = normalizedBaseDir.match(/^(.*\\/node_modules)\\/(@?[^/]+(?:\\/[^/]+)?)$/);\n      if (npmRootMatch?.[1] && normalizedFullPath.startsWith(`${npmRootMatch[1]}/`)) {\n        return path10.posix.relative(normalizedBaseDir, normalizedFullPath);\n      }\n      const relativePath = path10.relative(path10.resolve(baseDir), path10.resolve(fullPath));\n      if (relativePath && relativePath !== \".\" && !relativePath.startsWith(\"..\") && !relativePath.startsWith(`..${path10.sep}`) && !path10.isAbsolute(relativePath)) {\n        return relativePath.replace(/\\\\/g, \"/\");\n      }\n    }\n    const source = sourceInfo?.source ?? \"\";\n    const npmMatch = normalizedFullPath.match(/node_modules\\/(@?[^/]+(?:\\/[^/]+)?)\\/(.*)/);\n    if (npmMatch && source.startsWith(\"npm:\")) {\n      return npmMatch[2];\n    }\n    const gitMatch = normalizedFullPath.match(/git\\/[^/]+\\/[^/]+\\/(.*)/);\n    if (gitMatch && source.startsWith(\"git:\")) {\n      return gitMatch[1];\n    }\n    return this.formatDisplayPath(fullPath);\n  }\n  getCompactPathLabel(resourcePath, sourceInfo) {\n    const shortPath = this.getShortPath(resourcePath, sourceInfo);\n    const normalizedPath = shortPath.replace(/\\\\/g, \"/\");\n    const segments = normalizedPath.split(\"/\").filter((segment) => segment.length > 0 && segment !== \"~\");\n    if (segments.length > 0) {\n      return segments[segments.length - 1];\n    }\n    return shortPath;\n  }\n  getCompactPackageSourceLabel(sourceInfo) {\n    const source = sourceInfo?.source ?? \"\";\n    if (source.startsWith(\"npm:\")) {\n      return source.slice(\"npm:\".length) || source;\n    }\n    const gitSource = parseGitUrl(source);\n    if (gitSource) {\n      return gitSource.path || source;\n    }\n    return source;\n  }\n  getCompactExtensionLabel(resourcePath, sourceInfo) {\n    if (!this.isPackageSource(sourceInfo)) {\n      return this.getCompactPathLabel(resourcePath, sourceInfo);\n    }\n    const sourceLabel = this.getCompactPackageSourceLabel(sourceInfo);\n    if (!sourceLabel) {\n      return this.getCompactPathLabel(resourcePath, sourceInfo);\n    }\n    const shortPath = this.getShortPath(resourcePath, sourceInfo).replace(/\\\\/g, \"/\");\n    const packagePath = shortPath.startsWith(\"extensions/\") ? shortPath.slice(\"extensions/\".length) : shortPath;\n    const parsedPath = path10.posix.parse(packagePath);\n    if (parsedPath.name === \"index\") {\n      return !parsedPath.dir || parsedPath.dir === \".\" ? sourceLabel : `${sourceLabel}:${parsedPath.dir}`;\n    }\n    return `${sourceLabel}:${packagePath}`;\n  }\n  getCompactDisplayPathSegments(resourcePath) {\n    return this.formatDisplayPath(resourcePath).replace(/\\\\/g, \"/\").split(\"/\").filter((segment) => segment.length > 0 && segment !== \"~\");\n  }\n  getCompactNonPackageExtensionLabel(resourcePath, index, allPaths) {\n    const segments = allPaths[index]?.segments;\n    if (!segments || segments.length === 0) {\n      return this.getCompactPathLabel(resourcePath);\n    }\n    for (let segmentCount = 1; segmentCount <= segments.length; segmentCount += 1) {\n      const candidate = segments.slice(-segmentCount).join(\"/\");\n      const isUnique = allPaths.every((item, itemIndex) => {\n        if (itemIndex === index) {\n          return true;\n        }\n        return item.segments.slice(-segmentCount).join(\"/\") !== candidate;\n      });\n      if (isUnique) {\n        return candidate;\n      }\n    }\n    return segments.join(\"/\");\n  }\n  getCompactExtensionLabels(extensions) {\n    const nonPackageExtensions = extensions.map((extension) => {\n      const segments = this.getCompactDisplayPathSegments(extension.path);\n      const lastSegment = segments[segments.length - 1];\n      if (segments.length > 1 && (lastSegment === \"index.ts\" || lastSegment === \"index.js\")) {\n        segments.pop();\n      }\n      return {\n        path: extension.path,\n        sourceInfo: extension.sourceInfo,\n        segments\n      };\n    }).filter((extension) => !this.isPackageSource(extension.sourceInfo));\n    return extensions.map((extension) => {\n      if (this.isPackageSource(extension.sourceInfo)) {\n        return this.getCompactExtensionLabel(extension.path, extension.sourceInfo);\n      }\n      const nonPackageIndex = nonPackageExtensions.findIndex((item) => item.path === extension.path);\n      if (nonPackageIndex === -1) {\n        return this.getCompactPathLabel(extension.path, extension.sourceInfo);\n      }\n      return this.getCompactNonPackageExtensionLabel(extension.path, nonPackageIndex, nonPackageExtensions);\n    });\n  }\n  getDisplaySourceInfo(sourceInfo) {\n    const source = sourceInfo?.source ?? \"local\";\n    const scope = sourceInfo?.scope ?? \"project\";\n    if (source === \"local\") {\n      if (scope === \"user\") {\n        return { label: \"user\", color: \"muted\" };\n      }\n      if (scope === \"project\") {\n        return { label: \"project\", color: \"muted\" };\n      }\n      if (scope === \"temporary\") {\n        return { label: \"path\", scopeLabel: \"temp\", color: \"muted\" };\n      }\n      return { label: \"path\", color: \"muted\" };\n    }\n    if (source === \"cli\") {\n      return { label: \"path\", scopeLabel: scope === \"temporary\" ? \"temp\" : void 0, color: \"muted\" };\n    }\n    const scopeLabel = scope === \"user\" ? \"user\" : scope === \"project\" ? \"project\" : scope === \"temporary\" ? \"temp\" : void 0;\n    return { label: source, scopeLabel, color: \"accent\" };\n  }\n  getScopeGroup(sourceInfo) {\n    const source = sourceInfo?.source ?? \"local\";\n    const scope = sourceInfo?.scope ?? \"project\";\n    if (source === \"cli\" || scope === \"temporary\")\n      return \"path\";\n    if (scope === \"user\")\n      return \"user\";\n    if (scope === \"project\")\n      return \"project\";\n    return \"path\";\n  }\n  isPackageSource(sourceInfo) {\n    const source = sourceInfo?.source ?? \"\";\n    return source.startsWith(\"npm:\") || source.startsWith(\"git:\");\n  }\n  buildScopeGroups(items) {\n    const groups = {\n      user: { scope: \"user\", paths: [], packages: /* @__PURE__ */ new Map() },\n      project: { scope: \"project\", paths: [], packages: /* @__PURE__ */ new Map() },\n      path: { scope: \"path\", paths: [], packages: /* @__PURE__ */ new Map() }\n    };\n    for (const item of items) {\n      const groupKey = this.getScopeGroup(item.sourceInfo);\n      const group = groups[groupKey];\n      const source = item.sourceInfo?.source ?? \"local\";\n      if (this.isPackageSource(item.sourceInfo)) {\n        const list = group.packages.get(source) ?? [];\n        list.push(item);\n        group.packages.set(source, list);\n      } else {\n        group.paths.push(item);\n      }\n    }\n    return [groups.project, groups.user, groups.path].filter((group) => group.paths.length > 0 || group.packages.size > 0);\n  }\n  formatScopeGroups(groups, options) {\n    const lines = [];\n    for (const group of groups) {\n      lines.push(`  ${theme.fg(\"accent\", group.scope)}`);\n      const sortedPaths = [...group.paths].sort((a, b) => a.path.localeCompare(b.path));\n      for (const item of sortedPaths) {\n        lines.push(theme.fg(\"dim\", `    ${options.formatPath(item)}`));\n      }\n      const sortedPackages = Array.from(group.packages.entries()).sort(([a], [b]) => a.localeCompare(b));\n      for (const [source, items] of sortedPackages) {\n        lines.push(`    ${theme.fg(\"mdLink\", source)}`);\n        const sortedPackagePaths = [...items].sort((a, b) => a.path.localeCompare(b.path));\n        for (const item of sortedPackagePaths) {\n          lines.push(theme.fg(\"dim\", `      ${options.formatPackagePath(item, source)}`));\n        }\n      }\n    }\n    return lines.join(\"\\n\");\n  }\n  findSourceInfoForPath(p, sourceInfos) {\n    const exact = sourceInfos.get(p);\n    if (exact)\n      return exact;\n    let current = p;\n    while (current.includes(\"/\")) {\n      current = current.substring(0, current.lastIndexOf(\"/\"));\n      const parent = sourceInfos.get(current);\n      if (parent)\n        return parent;\n    }\n    return void 0;\n  }\n  formatPathWithSource(p, sourceInfo) {\n    if (sourceInfo) {\n      const shortPath = this.getShortPath(p, sourceInfo);\n      const { label, scopeLabel } = this.getDisplaySourceInfo(sourceInfo);\n      const labelText = scopeLabel ? `${label} (${scopeLabel})` : label;\n      return `${labelText} ${shortPath}`;\n    }\n    return this.formatDisplayPath(p);\n  }\n  formatDiagnostics(diagnostics, sourceInfos) {\n    const lines = [];\n    const collisions = /* @__PURE__ */ new Map();\n    const otherDiagnostics = [];\n    for (const d of diagnostics) {\n      if (d.type === \"collision\" && d.collision) {\n        const list = collisions.get(d.collision.name) ?? [];\n        list.push(d);\n        collisions.set(d.collision.name, list);\n      } else {\n        otherDiagnostics.push(d);\n      }\n    }\n    for (const [name, collisionList] of collisions) {\n      const first = collisionList[0]?.collision;\n      if (!first)\n        continue;\n      lines.push(theme.fg(\"warning\", `  \"${name}\" collision:`));\n      lines.push(theme.fg(\"dim\", `    ${theme.fg(\"success\", \"\\u2713\")} ${this.formatPathWithSource(first.winnerPath, this.findSourceInfoForPath(first.winnerPath, sourceInfos))}`));\n      for (const d of collisionList) {\n        if (d.collision) {\n          lines.push(theme.fg(\"dim\", `    ${theme.fg(\"warning\", \"\\u2717\")} ${this.formatPathWithSource(d.collision.loserPath, this.findSourceInfoForPath(d.collision.loserPath, sourceInfos))} (skipped)`));\n        }\n      }\n    }\n    for (const d of otherDiagnostics) {\n      if (d.path) {\n        const formattedPath = this.formatPathWithSource(d.path, this.findSourceInfoForPath(d.path, sourceInfos));\n        lines.push(theme.fg(d.type === \"error\" ? \"error\" : \"warning\", `  ${formattedPath}`));\n        lines.push(theme.fg(d.type === \"error\" ? \"error\" : \"warning\", `    ${d.message}`));\n      } else {\n        lines.push(theme.fg(d.type === \"error\" ? \"error\" : \"warning\", `  ${d.message}`));\n      }\n    }\n    return lines.join(\"\\n\");\n  }\n  showLoadedResources(options) {\n    this.loadedResourcesContainer.clear();\n    const showListing = options?.force || this.options.verbose || !this.settingsManager.getQuietStartup();\n    const showDiagnostics = showListing || options?.showDiagnosticsWhenQuiet === true;\n    if (!showListing && !showDiagnostics) {\n      return;\n    }\n    const sectionHeader = (name, color = \"mdHeading\") => theme.fg(color, `[${name}]`);\n    const formatCompactList = (items, options2) => {\n      const labels = items.map((item) => item.trim()).filter((item) => item.length > 0);\n      if (options2?.sort !== false) {\n        labels.sort((a, b) => a.localeCompare(b));\n      }\n      return theme.fg(\"dim\", `  ${labels.join(\", \")}`);\n    };\n    const addLoadedSection = (name, collapsedBody, expandedBody = collapsedBody, color = \"mdHeading\") => {\n      const section = new ExpandableText(() => `${sectionHeader(name, color)}\n${collapsedBody}`, () => `${sectionHeader(name, color)}\n${expandedBody}`, this.getStartupExpansionState(), 0, 0);\n      this.loadedResourcesContainer.addChild(section);\n      this.loadedResourcesContainer.addChild(new Spacer(1));\n    };\n    const skillsResult = this.session.resourceLoader.getSkills();\n    const promptsResult = this.session.resourceLoader.getPrompts();\n    const themesResult = this.session.resourceLoader.getThemes();\n    const extensions = options?.extensions ?? this.session.resourceLoader.getExtensions().extensions.filter((extension) => !extension.hidden).map((extension) => ({\n      path: extension.path,\n      sourceInfo: extension.sourceInfo\n    }));\n    const sourceInfos = /* @__PURE__ */ new Map();\n    for (const extension of extensions) {\n      if (extension.sourceInfo) {\n        sourceInfos.set(extension.path, extension.sourceInfo);\n      }\n    }\n    for (const skill of skillsResult.skills) {\n      if (skill.sourceInfo) {\n        sourceInfos.set(skill.filePath, skill.sourceInfo);\n      }\n    }\n    for (const prompt of promptsResult.prompts) {\n      if (prompt.sourceInfo) {\n        sourceInfos.set(prompt.filePath, prompt.sourceInfo);\n      }\n    }\n    for (const loadedTheme of themesResult.themes) {\n      if (loadedTheme.sourcePath && loadedTheme.sourceInfo) {\n        sourceInfos.set(loadedTheme.sourcePath, loadedTheme.sourceInfo);\n      }\n    }\n    if (showListing) {\n      const systemPromptSource = this.session.resourceLoader.getSystemPromptSource();\n      const contextFiles = [\n        ...systemPromptSource ? [systemPromptSource] : [],\n        ...this.session.resourceLoader.getAppendSystemPromptSources(),\n        ...this.session.resourceLoader.getAgentsFiles().agentsFiles\n      ];\n      if (contextFiles.length > 0) {\n        this.loadedResourcesContainer.addChild(new Spacer(1));\n        const contextList = contextFiles.map((f) => theme.fg(\"dim\", `  ${this.formatDisplayPath(f.path)}`)).join(\"\\n\");\n        const contextCompactList = formatCompactList(contextFiles.map((contextFile) => this.formatContextPath(contextFile.path)), { sort: false });\n        addLoadedSection(\"Context\", contextCompactList, contextList);\n      }\n      const skills = skillsResult.skills;\n      if (skills.length > 0) {\n        const groups = this.buildScopeGroups(skills.map((skill) => ({ path: skill.filePath, sourceInfo: skill.sourceInfo })));\n        const skillList = this.formatScopeGroups(groups, {\n          formatPath: (item) => this.formatDisplayPath(item.path),\n          formatPackagePath: (item) => this.getShortPath(item.path, item.sourceInfo)\n        });\n        const skillCompactList = formatCompactList(skills.map((skill) => skill.name));\n        addLoadedSection(\"Skills\", skillCompactList, skillList);\n      }\n      const templates = this.session.promptTemplates;\n      if (templates.length > 0) {\n        const groups = this.buildScopeGroups(templates.map((template) => ({ path: template.filePath, sourceInfo: template.sourceInfo })));\n        const templateByPath = new Map(templates.map((t) => [t.filePath, t]));\n        const templateList = this.formatScopeGroups(groups, {\n          formatPath: (item) => {\n            const template = templateByPath.get(item.path);\n            return template ? `/${template.name}` : this.formatDisplayPath(item.path);\n          },\n          formatPackagePath: (item) => {\n            const template = templateByPath.get(item.path);\n            return template ? `/${template.name}` : this.formatDisplayPath(item.path);\n          }\n        });\n        const promptCompactList = formatCompactList(templates.map((template) => `/${template.name}`));\n        addLoadedSection(\"Prompts\", promptCompactList, templateList);\n      }\n      if (extensions.length > 0) {\n        const groups = this.buildScopeGroups(extensions);\n        const extList = this.formatScopeGroups(groups, {\n          formatPath: (item) => this.formatExtensionDisplayPath(item.path),\n          formatPackagePath: (item) => this.formatExtensionDisplayPath(this.getShortPath(item.path, item.sourceInfo))\n        });\n        const extensionCompactList = formatCompactList(this.getCompactExtensionLabels(extensions));\n        addLoadedSection(\"Extensions\", extensionCompactList, extList, \"mdHeading\");\n      }\n      const loadedThemes = themesResult.themes;\n      const customThemes = loadedThemes.filter((t) => t.sourcePath);\n      if (customThemes.length > 0) {\n        const groups = this.buildScopeGroups(customThemes.map((loadedTheme) => ({\n          path: loadedTheme.sourcePath,\n          sourceInfo: loadedTheme.sourceInfo\n        })));\n        const themeList = this.formatScopeGroups(groups, {\n          formatPath: (item) => this.formatDisplayPath(item.path),\n          formatPackagePath: (item) => this.getShortPath(item.path, item.sourceInfo)\n        });\n        const themeCompactList = formatCompactList(customThemes.map((loadedTheme) => loadedTheme.name ?? this.getCompactPathLabel(loadedTheme.sourcePath, loadedTheme.sourceInfo)));\n        addLoadedSection(\"Themes\", themeCompactList, themeList);\n      }\n    }\n    if (showDiagnostics) {\n      const skillDiagnostics = skillsResult.diagnostics;\n      if (skillDiagnostics.length > 0) {\n        const warningLines = this.formatDiagnostics(skillDiagnostics, sourceInfos);\n        this.loadedResourcesContainer.addChild(new Text(`${theme.fg(\"warning\", \"[Skill conflicts]\")}\n${warningLines}`, 0, 0));\n        this.loadedResourcesContainer.addChild(new Spacer(1));\n      }\n      const promptDiagnostics = promptsResult.diagnostics;\n      if (promptDiagnostics.length > 0) {\n        const warningLines = this.formatDiagnostics(promptDiagnostics, sourceInfos);\n        this.loadedResourcesContainer.addChild(new Text(`${theme.fg(\"warning\", \"[Prompt conflicts]\")}\n${warningLines}`, 0, 0));\n        this.loadedResourcesContainer.addChild(new Spacer(1));\n      }\n      const extensionDiagnostics = [];\n      const extensionErrors = this.session.resourceLoader.getExtensions().errors;\n      if (extensionErrors.length > 0) {\n        for (const error of extensionErrors) {\n          extensionDiagnostics.push({ type: \"error\", message: error.error, path: error.path });\n        }\n      }\n      const commandDiagnostics = this.session.extensionRunner.getCommandDiagnostics();\n      extensionDiagnostics.push(...commandDiagnostics);\n      extensionDiagnostics.push(...this.getBuiltInCommandConflictDiagnostics(this.session.extensionRunner));\n      const shortcutDiagnostics = this.session.extensionRunner.getShortcutDiagnostics();\n      extensionDiagnostics.push(...shortcutDiagnostics);\n      if (extensionDiagnostics.length > 0) {\n        const warningLines = this.formatDiagnostics(extensionDiagnostics, sourceInfos);\n        this.loadedResourcesContainer.addChild(new Text(`${theme.fg(\"warning\", \"[Extension issues]\")}\n${warningLines}`, 0, 0));\n        this.loadedResourcesContainer.addChild(new Spacer(1));\n      }\n      const themeDiagnostics = themesResult.diagnostics;\n      if (themeDiagnostics.length > 0) {\n        const warningLines = this.formatDiagnostics(themeDiagnostics, sourceInfos);\n        this.loadedResourcesContainer.addChild(new Text(`${theme.fg(\"warning\", \"[Theme conflicts]\")}\n${warningLines}`, 0, 0));\n        this.loadedResourcesContainer.addChild(new Spacer(1));\n      }\n    }\n  }\n  /**\n   * Initialize the extension system with TUI-based UI context.\n   */\n  async bindCurrentSessionExtensions() {\n    const uiContext = this.createExtensionUIContext();\n    await this.session.bindExtensions({\n      uiContext,\n      mode: \"tui\",\n      abortHandler: () => {\n        this.restoreQueuedMessagesToEditor({ abort: true });\n      },\n      commandContextActions: {\n        waitForIdle: () => this.session.waitForIdle(),\n        newSession: async (options) => {\n          this.clearStatusIndicator();\n          try {\n            return await this.runtimeHost.newSession(options);\n          } catch (error) {\n            return this.handleFatalRuntimeError(\"Failed to create session\", error);\n          }\n        },\n        fork: async (entryId, options) => {\n          try {\n            const result = await this.runtimeHost.fork(entryId, options);\n            if (!result.cancelled) {\n              this.editor.setText(result.selectedText ?? \"\");\n              this.showStatus(\"Forked to new session\");\n            }\n            return { cancelled: result.cancelled };\n          } catch (error) {\n            return this.handleFatalRuntimeError(\"Failed to fork session\", error);\n          }\n        },\n        navigateTree: async (targetId, options) => {\n          const result = await this.session.navigateTree(targetId, {\n            summarize: options?.summarize,\n            customInstructions: options?.customInstructions,\n            replaceInstructions: options?.replaceInstructions,\n            label: options?.label\n          });\n          if (result.cancelled) {\n            return { cancelled: true };\n          }\n          this.chatContainer.clear();\n          this.renderInitialMessages();\n          if (result.editorText && !this.editor.getText().trim()) {\n            this.editor.setText(result.editorText);\n          }\n          this.showStatus(\"Navigated to selected point\");\n          void this.flushCompactionQueue({ willRetry: false });\n          return { cancelled: false };\n        },\n        switchSession: async (sessionPath, options) => {\n          return this.handleResumeSession(sessionPath, options);\n        },\n        reload: async () => {\n          await this.handleReloadCommand();\n        }\n      },\n      shutdownHandler: () => {\n        this.shutdownRequested = true;\n        if (this.session.isIdle) {\n          void this.shutdown();\n        }\n      },\n      onError: (error) => {\n        this.showExtensionError(error.extensionPath, error.error, error.stack);\n      }\n    });\n    setRegisteredThemes(this.session.resourceLoader.getThemes().themes);\n    this.setupAutocompleteProvider();\n    const extensionRunner = this.session.extensionRunner;\n    this.setupExtensionShortcuts(extensionRunner);\n    this.showLoadedResources({ force: false, showDiagnosticsWhenQuiet: true });\n    this.showStartupNoticesIfNeeded();\n  }\n  applyFullscreenScrollbarSetting() {\n    this.transcriptScrollView?.setScrollbar(this.settingsManager.getFullscreenScrollbar());\n  }\n  applyRuntimeSettings() {\n    configureHttpDispatcher(this.settingsManager.getHttpIdleTimeoutMs());\n    this.applyFullscreenScrollbarSetting();\n    this.footer.setSession(this.session);\n    this.footer.setAutoCompactEnabled(this.session.autoCompactionEnabled);\n    this.footerDataProvider.setCwd(this.sessionManager.getCwd());\n    this.hideThinkingBlock = this.settingsManager.getHideThinkingBlock();\n    this.outputPad = this.settingsManager.getOutputPad();\n    this.ui.setShowHardwareCursor(this.settingsManager.getShowHardwareCursor());\n    const clearOnShrink = this.settingsManager.getClearOnShrink();\n    this.ui.setClearOnShrink(clearOnShrink);\n    if (!clearOnShrink && !this.activeStatusIndicator) {\n      this.statusContainer.clear();\n    }\n    const editorPaddingX = this.settingsManager.getEditorPaddingX();\n    const autocompleteMaxVisible = this.settingsManager.getAutocompleteMaxVisible();\n    this.defaultEditor.setPaddingX(editorPaddingX);\n    this.defaultEditor.setAutocompleteMaxVisible(autocompleteMaxVisible);\n    if (this.editor !== this.defaultEditor) {\n      this.editor.setPaddingX?.(editorPaddingX);\n      this.editor.setAutocompleteMaxVisible?.(autocompleteMaxVisible);\n    }\n  }\n  async rebindCurrentSession(options = {}) {\n    const session = this.session;\n    this.unsubscribe?.();\n    this.unsubscribe = void 0;\n    this.applyRuntimeSettings();\n    if (options.renderBeforeBind) {\n      this.renderCurrentSessionState();\n      this.subscribeToAgent();\n    }\n    await this.bindCurrentSessionExtensions();\n    if (this.session !== session) {\n      return;\n    }\n    if (!options.renderBeforeBind) {\n      this.subscribeToAgent();\n    }\n    await this.updateAvailableProviderCount();\n    this.updateEditorBorderColor();\n    this.updateTerminalTitle();\n  }\n  async handleFatalRuntimeError(prefix, error) {\n    const message = error instanceof Error ? error.message : String(error);\n    this.showError(`${prefix}: ${message}`);\n    stopThemeWatcher();\n    this.stop(\"transcript\");\n    process.exit(1);\n  }\n  renderCurrentSessionState() {\n    this.loadedResourcesContainer.clear();\n    this.chatContainer.clear();\n    this.pendingMessagesContainer.clear();\n    this.compactionQueuedMessages = [];\n    this.streamingComponent = void 0;\n    this.streamingMessage = void 0;\n    this.pendingTools.clear();\n    this.renderInitialMessages();\n  }\n  /**\n   * Get a registered tool definition by name (for custom rendering).\n   */\n  getRegisteredToolDefinition(toolName) {\n    return this.session.getToolDefinition(toolName);\n  }\n  getMarkdownTransformers() {\n    return [this.mermaidMarkdownTransformer, ...this.session.extensionRunner.getMarkdownTransformers()];\n  }\n  /**\n   * Set up keyboard shortcuts registered by extensions.\n   */\n  setupExtensionShortcuts(extensionRunner) {\n    const shortcuts = extensionRunner.getShortcuts(this.keybindings.getEffectiveConfig());\n    if (shortcuts.size === 0)\n      return;\n    const createContext = () => ({\n      ui: this.createExtensionUIContext(),\n      mode: \"tui\",\n      hasUI: true,\n      cwd: this.sessionManager.getCwd(),\n      sessionManager: this.sessionManager,\n      modelRegistry: extensionRunner.getModelRegistry(),\n      model: this.session.model,\n      scopedModels: this.session.scopedModels,\n      thinkingLevel: this.session.thinkingLevel,\n      isIdle: () => this.session.isIdle,\n      isProjectTrusted: () => this.settingsManager.isProjectTrusted(),\n      signal: this.session.agent.signal,\n      abort: () => {\n        this.restoreQueuedMessagesToEditor({ abort: true });\n      },\n      hasPendingMessages: () => this.session.pendingMessageCount > 0,\n      shutdown: () => {\n        this.shutdownRequested = true;\n      },\n      getContextUsage: () => this.session.getContextUsage(),\n      compact: (options) => {\n        void (async () => {\n          try {\n            const result = await this.session.compact(options?.customInstructions);\n            options?.onComplete?.(result);\n          } catch (error) {\n            const err2 = error instanceof Error ? error : new Error(String(error));\n            options?.onError?.(err2);\n          }\n        })();\n      },\n      getSystemPrompt: () => this.session.systemPrompt\n    });\n    this.defaultEditor.onExtensionShortcut = (data) => {\n      for (const [shortcutStr, shortcut] of shortcuts) {\n        if (matchesKey(data, shortcutStr)) {\n          Promise.resolve(shortcut.handler(createContext())).catch((err2) => {\n            this.showError(`Shortcut handler error: ${err2 instanceof Error ? err2.message : String(err2)}`);\n          });\n          return true;\n        }\n      }\n      return false;\n    };\n  }\n  /**\n   * Set extension status text in the footer.\n   */\n  setExtensionStatus(key, text) {\n    this.footerDataProvider.setExtensionStatus(key, text);\n    this.ui.requestRender();\n  }\n  showStatusIndicator(indicator) {\n    this.activeStatusIndicator?.dispose();\n    this.activeStatusIndicator = indicator;\n    this.statusContainer.clear();\n    this.statusContainer.addChild(indicator);\n  }\n  clearStatusIndicator(kind) {\n    if (kind && this.activeStatusIndicator?.kind !== kind) {\n      return;\n    }\n    const hadActiveStatusIndicator = this.activeStatusIndicator !== void 0;\n    this.activeStatusIndicator?.dispose();\n    this.activeStatusIndicator = void 0;\n    this.statusContainer.clear();\n    if (hadActiveStatusIndicator && this.options.tuiMode === \"regular\" && this.ui.getClearOnShrink()) {\n      this.statusContainer.addChild(this.idleStatus);\n    }\n  }\n  setWorkingVisible(visible) {\n    this.workingVisible = visible;\n    if (!visible) {\n      this.clearStatusIndicator(\"working\");\n      this.ui.requestRender();\n      return;\n    }\n    if (this.session.isStreaming && this.activeStatusIndicator?.kind !== \"working\") {\n      this.showStatusIndicator(new WorkingStatusIndicator(this.ui, this.workingMessage ?? this.defaultWorkingMessage, this.workingIndicatorOptions));\n    }\n    this.ui.requestRender();\n  }\n  setWorkingIndicator(options) {\n    this.workingIndicatorOptions = options;\n    if (this.activeStatusIndicator?.kind === \"working\") {\n      this.activeStatusIndicator.setIndicator(options);\n    }\n    this.ui.requestRender();\n  }\n  setHiddenThinkingLabel(label) {\n    this.hiddenThinkingLabel = label ?? this.defaultHiddenThinkingLabel;\n    for (const child of this.chatContainer.children) {\n      if (child instanceof AssistantMessageComponent) {\n        child.setHiddenThinkingLabel(this.hiddenThinkingLabel);\n      }\n    }\n    if (this.streamingComponent) {\n      this.streamingComponent.setHiddenThinkingLabel(this.hiddenThinkingLabel);\n    }\n    this.ui.requestRender();\n  }\n  /**\n   * Set an extension widget (string array or custom component).\n   */\n  setExtensionWidget(key, content, options) {\n    const placement = options?.placement ?? \"aboveEditor\";\n    const removeExisting = (map) => {\n      const existing = map.get(key);\n      if (existing?.dispose)\n        existing.dispose();\n      map.delete(key);\n    };\n    removeExisting(this.extensionWidgetsAbove);\n    removeExisting(this.extensionWidgetsBelow);\n    if (content === void 0) {\n      this.renderWidgets();\n      return;\n    }\n    let component;\n    if (Array.isArray(content)) {\n      const container = new Container();\n      for (const line of content.slice(0, _InteractiveMode.MAX_WIDGET_LINES)) {\n        container.addChild(new Text(line, 1, 0));\n      }\n      if (content.length > _InteractiveMode.MAX_WIDGET_LINES) {\n        container.addChild(new Text(theme.fg(\"muted\", \"... (widget truncated)\"), 1, 0));\n      }\n      component = container;\n    } else {\n      component = content(this.ui, theme);\n    }\n    const targetMap = placement === \"belowEditor\" ? this.extensionWidgetsBelow : this.extensionWidgetsAbove;\n    targetMap.set(key, component);\n    this.renderWidgets();\n  }\n  clearExtensionWidgets() {\n    for (const widget of this.extensionWidgetsAbove.values()) {\n      widget.dispose?.();\n    }\n    for (const widget of this.extensionWidgetsBelow.values()) {\n      widget.dispose?.();\n    }\n    this.extensionWidgetsAbove.clear();\n    this.extensionWidgetsBelow.clear();\n    this.renderWidgets();\n  }\n  resetExtensionUI() {\n    if (this.extensionSelector) {\n      this.hideExtensionSelector();\n    }\n    if (this.extensionInput) {\n      this.hideExtensionInput();\n    }\n    if (this.extensionEditor) {\n      this.hideExtensionEditor();\n    }\n    this.ui.hideOverlay();\n    this.clearExtensionTerminalInputListeners();\n    this.setExtensionFooter(void 0);\n    this.setExtensionHeader(void 0);\n    this.clearExtensionWidgets();\n    this.footerDataProvider.clearExtensionStatuses();\n    this.footer.invalidate();\n    this.autocompleteProviderWrappers = [];\n    this.setCustomEditorComponent(void 0);\n    this.setupAutocompleteProvider();\n    this.defaultEditor.onExtensionShortcut = void 0;\n    this.updateTerminalTitle();\n    this.workingMessage = void 0;\n    this.workingVisible = true;\n    this.setWorkingIndicator();\n    if (this.activeStatusIndicator?.kind === \"working\") {\n      this.activeStatusIndicator.setMessage(`${this.defaultWorkingMessage} (${keyText(\"app.interrupt\")} to interrupt)`);\n    }\n    this.setHiddenThinkingLabel();\n  }\n  // Maximum total widget lines to prevent viewport overflow\n  static MAX_WIDGET_LINES = 10;\n  /**\n   * Render all extension widgets to the widget container.\n   */\n  renderWidgets() {\n    if (!this.widgetContainerAbove || !this.widgetContainerBelow)\n      return;\n    this.renderWidgetContainer(this.widgetContainerAbove, this.extensionWidgetsAbove, true, true);\n    this.renderWidgetContainer(this.widgetContainerBelow, this.extensionWidgetsBelow, false, false);\n    this.ui.requestRender();\n  }\n  renderWidgetContainer(container, widgets, spacerWhenEmpty, leadingSpacer) {\n    container.clear();\n    if (widgets.size === 0) {\n      if (spacerWhenEmpty) {\n        container.addChild(new Spacer(1));\n      }\n      return;\n    }\n    if (leadingSpacer) {\n      container.addChild(new Spacer(1));\n    }\n    for (const component of widgets.values()) {\n      container.addChild(component);\n    }\n  }\n  /**\n   * Set a custom footer component, or restore the built-in footer.\n   */\n  setExtensionFooter(factory) {\n    if (this.customFooter?.dispose) {\n      this.customFooter.dispose();\n    }\n    this.footerContainer.clear();\n    if (factory) {\n      this.customFooter = factory(this.ui, theme, this.footerDataProvider);\n      this.footerContainer.addChild(this.customFooter);\n    } else {\n      this.customFooter = void 0;\n      this.footerContainer.addChild(this.footer);\n    }\n    this.ui.requestRender();\n  }\n  /**\n   * Set a custom header component, or restore the built-in header.\n   */\n  setExtensionHeader(factory) {\n    if (!this.builtInHeader) {\n      return;\n    }\n    if (this.customHeader?.dispose) {\n      this.customHeader.dispose();\n    }\n    const currentHeader = this.customHeader || this.builtInHeader;\n    const index = this.headerContainer.children.indexOf(currentHeader);\n    if (factory) {\n      this.customHeader = factory(this.ui, theme);\n      if (isExpandable(this.customHeader)) {\n        this.customHeader.setExpanded(this.toolOutputExpanded);\n      }\n      if (index !== -1) {\n        this.headerContainer.children[index] = this.customHeader;\n      } else {\n        this.headerContainer.children.unshift(this.customHeader);\n      }\n    } else {\n      this.customHeader = void 0;\n      if (isExpandable(this.builtInHeader)) {\n        this.builtInHeader.setExpanded(this.toolOutputExpanded);\n      }\n      if (index !== -1) {\n        this.headerContainer.children[index] = this.builtInHeader;\n      }\n    }\n    this.ui.requestRender();\n  }\n  addExtensionTerminalInputListener(handler) {\n    const subscription = { handler, unsubscribe: this.ui.addInputListener(handler) };\n    this.extensionTerminalInputSubscriptions.add(subscription);\n    return () => {\n      subscription.unsubscribe();\n      this.extensionTerminalInputSubscriptions.delete(subscription);\n    };\n  }\n  rebindExtensionTerminalInputListeners() {\n    for (const subscription of this.extensionTerminalInputSubscriptions) {\n      subscription.unsubscribe();\n      subscription.unsubscribe = this.ui.addInputListener(subscription.handler);\n    }\n  }\n  clearExtensionTerminalInputListeners() {\n    for (const subscription of this.extensionTerminalInputSubscriptions)\n      subscription.unsubscribe();\n    this.extensionTerminalInputSubscriptions.clear();\n  }\n  /**\n   * Create the ExtensionUIContext for extensions.\n   */\n  createProjectTrustContext(cwd) {\n    const ui = this.createExtensionUIContext();\n    return {\n      cwd,\n      mode: \"tui\",\n      hasUI: true,\n      ui: {\n        select: ui.select,\n        confirm: ui.confirm,\n        input: ui.input,\n        notify: ui.notify\n      }\n    };\n  }\n  createExtensionUIContext() {\n    return {\n      select: (title, options, opts) => this.showExtensionSelector(title, options, opts),\n      confirm: (title, message, opts) => this.showExtensionConfirm(title, message, opts),\n      input: (title, placeholder, opts) => this.showExtensionInput(title, placeholder, opts),\n      notify: (message, type) => this.showExtensionNotify(message, type),\n      onTerminalInput: (handler) => this.addExtensionTerminalInputListener(handler),\n      setStatus: (key, text) => this.setExtensionStatus(key, text),\n      setWorkingMessage: (message) => {\n        this.workingMessage = message;\n        if (this.activeStatusIndicator?.kind === \"working\") {\n          this.activeStatusIndicator.setMessage(message ?? this.defaultWorkingMessage);\n        }\n      },\n      setWorkingVisible: (visible) => this.setWorkingVisible(visible),\n      setWorkingIndicator: (options) => this.setWorkingIndicator(options),\n      setHiddenThinkingLabel: (label) => this.setHiddenThinkingLabel(label),\n      setWidget: (key, content, options) => this.setExtensionWidget(key, content, options),\n      setFooter: (factory) => this.setExtensionFooter(factory),\n      setHeader: (factory) => this.setExtensionHeader(factory),\n      setTitle: (title) => this.ui.terminal.setTitle(title),\n      custom: (factory, options) => this.showExtensionCustom(factory, options),\n      pasteToEditor: (text) => this.editor.handleInput(`\\x1B[200~${text}\\x1B[201~`),\n      setEditorText: (text) => this.editor.setText(text),\n      getEditorText: () => this.editor.getExpandedText?.() ?? this.editor.getText(),\n      editor: (title, prefill) => this.showExtensionEditor(title, prefill),\n      addAutocompleteProvider: (factory) => {\n        this.autocompleteProviderWrappers.push(factory);\n        this.setupAutocompleteProvider();\n      },\n      setEditorComponent: (factory) => this.setCustomEditorComponent(factory),\n      getEditorComponent: () => this.editorComponentFactory,\n      get theme() {\n        return theme;\n      },\n      getAllThemes: () => getAvailableThemesWithPaths(),\n      getTheme: (name) => getThemeByName(name),\n      setTheme: (themeOrName) => {\n        if (themeOrName instanceof Theme) {\n          return this.themeController.setThemeInstance(themeOrName);\n        }\n        const result = this.themeController.setThemeName(themeOrName);\n        if (result.success) {\n          if (this.settingsManager.getTheme() !== themeOrName) {\n            this.settingsManager.setTheme(themeOrName);\n          }\n        }\n        return result;\n      },\n      getToolsExpanded: () => this.toolOutputExpanded,\n      setToolsExpanded: (expanded) => this.setToolsExpanded(expanded)\n    };\n  }\n  /**\n   * Show a selector for extensions.\n   */\n  showExtensionSelector(title, options, opts) {\n    return new Promise((resolve15) => {\n      if (opts?.signal?.aborted) {\n        resolve15(void 0);\n        return;\n      }\n      const onAbort = () => {\n        this.hideExtensionSelector();\n        resolve15(void 0);\n      };\n      opts?.signal?.addEventListener(\"abort\", onAbort, { once: true });\n      this.extensionSelector = new ExtensionSelectorComponent(title, options, (option) => {\n        opts?.signal?.removeEventListener(\"abort\", onAbort);\n        this.hideExtensionSelector();\n        resolve15(option);\n      }, () => {\n        opts?.signal?.removeEventListener(\"abort\", onAbort);\n        this.hideExtensionSelector();\n        resolve15(void 0);\n      }, { tui: this.ui, timeout: opts?.timeout, onToggleToolsExpanded: () => this.toggleToolOutputExpansion() });\n      this.disposeActiveSelector();\n      this.editorContainer.clear();\n      this.editorContainer.addChild(this.extensionSelector);\n      this.ui.setFocus(this.extensionSelector);\n      this.ui.requestRender();\n    });\n  }\n  /**\n   * Hide the extension selector.\n   */\n  hideExtensionSelector() {\n    this.extensionSelector?.dispose();\n    this.editorContainer.clear();\n    this.editorContainer.addChild(this.editor);\n    this.extensionSelector = void 0;\n    this.ui.setFocus(this.editor);\n    this.ui.requestRender();\n  }\n  /**\n   * Show a confirmation dialog for extensions.\n   */\n  async showExtensionConfirm(title, message, opts) {\n    const result = await this.showExtensionSelector(`${title}\n${message}`, [\"Yes\", \"No\"], opts);\n    return result === \"Yes\";\n  }\n  async promptForMissingSessionCwd(error) {\n    const confirmed = await this.showExtensionConfirm(\"Session cwd not found\", formatMissingSessionCwdPrompt(error.issue));\n    return confirmed ? error.issue.fallbackCwd : void 0;\n  }\n  /**\n   * Show a text input for extensions.\n   */\n  showExtensionInput(title, placeholder, opts) {\n    return new Promise((resolve15) => {\n      if (opts?.signal?.aborted) {\n        resolve15(void 0);\n        return;\n      }\n      const onAbort = () => {\n        this.hideExtensionInput();\n        resolve15(void 0);\n      };\n      opts?.signal?.addEventListener(\"abort\", onAbort, { once: true });\n      this.extensionInput = new ExtensionInputComponent(title, placeholder, (value) => {\n        opts?.signal?.removeEventListener(\"abort\", onAbort);\n        this.hideExtensionInput();\n        resolve15(value);\n      }, () => {\n        opts?.signal?.removeEventListener(\"abort\", onAbort);\n        this.hideExtensionInput();\n        resolve15(void 0);\n      }, { tui: this.ui, timeout: opts?.timeout });\n      this.disposeActiveSelector();\n      this.editorContainer.clear();\n      this.editorContainer.addChild(this.extensionInput);\n      this.ui.setFocus(this.extensionInput);\n      this.ui.requestRender();\n    });\n  }\n  /**\n   * Hide the extension input.\n   */\n  hideExtensionInput() {\n    this.extensionInput?.dispose();\n    this.editorContainer.clear();\n    this.editorContainer.addChild(this.editor);\n    this.extensionInput = void 0;\n    this.ui.setFocus(this.editor);\n    this.ui.requestRender();\n  }\n  /**\n   * Show a multi-line editor for extensions (with Ctrl+G support).\n   */\n  showExtensionEditor(title, prefill) {\n    return new Promise((resolve15) => {\n      this.extensionEditor = new ExtensionEditorComponent(this.ui, this.keybindings, title, prefill, (value) => {\n        this.hideExtensionEditor();\n        resolve15(value);\n      }, () => {\n        this.hideExtensionEditor();\n        resolve15(void 0);\n      }, void 0, this.settingsManager.getExternalEditorCommand());\n      this.disposeActiveSelector();\n      this.editorContainer.clear();\n      this.editorContainer.addChild(this.extensionEditor);\n      this.ui.setFocus(this.extensionEditor);\n      this.ui.requestRender();\n    });\n  }\n  /**\n   * Hide the extension editor.\n   */\n  hideExtensionEditor() {\n    this.editorContainer.clear();\n    this.editorContainer.addChild(this.editor);\n    this.extensionEditor = void 0;\n    this.ui.setFocus(this.editor);\n    this.ui.requestRender();\n  }\n  /**\n   * Set a custom editor component from an extension.\n   * Pass undefined to restore the default editor.\n   */\n  setCustomEditorComponent(factory) {\n    this.editorComponentFactory = factory;\n    const currentText = this.editor.getText();\n    this.disposeActiveSelector();\n    this.editorContainer.clear();\n    if (factory) {\n      const newEditor = factory(this.ui, getEditorTheme(), this.keybindings);\n      newEditor.onSubmit = this.defaultEditor.onSubmit;\n      newEditor.onChange = this.defaultEditor.onChange;\n      newEditor.setText(currentText);\n      if (newEditor.borderColor !== void 0) {\n        newEditor.borderColor = this.defaultEditor.borderColor;\n      }\n      if (newEditor.setPaddingX !== void 0) {\n        newEditor.setPaddingX(this.defaultEditor.getPaddingX());\n      }\n      if (newEditor.setAutocompleteMaxVisible !== void 0) {\n        newEditor.setAutocompleteMaxVisible(this.defaultEditor.getAutocompleteMaxVisible());\n      }\n      if (newEditor.setAutocompleteProvider && this.autocompleteProvider) {\n        newEditor.setAutocompleteProvider(this.autocompleteProvider);\n      }\n      const customEditor = newEditor;\n      if (\"actionHandlers\" in customEditor && customEditor.actionHandlers instanceof Map) {\n        if (!customEditor.onEscape) {\n          customEditor.onEscape = () => this.defaultEditor.onEscape?.();\n        }\n        if (!customEditor.onCtrlD) {\n          customEditor.onCtrlD = () => this.defaultEditor.onCtrlD?.();\n        }\n        if (!customEditor.onPasteImage) {\n          customEditor.onPasteImage = () => this.defaultEditor.onPasteImage?.();\n        }\n        if (!customEditor.onExtensionShortcut) {\n          customEditor.onExtensionShortcut = (data) => this.defaultEditor.onExtensionShortcut?.(data);\n        }\n        for (const [action, handler] of this.defaultEditor.actionHandlers) {\n          customEditor.actionHandlers.set(action, handler);\n        }\n      }\n      this.editor = newEditor;\n    } else {\n      this.defaultEditor.setText(currentText);\n      this.editor = this.defaultEditor;\n    }\n    this.editorContainer.addChild(this.editor);\n    this.ui.setFocus(this.editor);\n    this.ui.requestRender();\n  }\n  /**\n   * Show a notification for extensions.\n   */\n  showExtensionNotify(message, type) {\n    if (type === \"error\") {\n      this.showError(message);\n    } else if (type === \"warning\") {\n      this.showWarning(message);\n    } else {\n      this.showStatus(message);\n    }\n  }\n  /** Show a custom component with keyboard focus. Overlay mode renders on top of existing content. */\n  async showExtensionCustom(factory, options) {\n    const savedText = this.editor.getText();\n    const isOverlay = options?.overlay ?? false;\n    const restoreEditor = () => {\n      this.editorContainer.clear();\n      this.editorContainer.addChild(this.editor);\n      this.editor.setText(savedText);\n      this.ui.setFocus(this.editor);\n      this.ui.requestRender();\n    };\n    return new Promise((resolve15, reject) => {\n      let component;\n      let closed = false;\n      const close = (result) => {\n        if (closed)\n          return;\n        closed = true;\n        if (isOverlay)\n          this.ui.hideOverlay();\n        else\n          restoreEditor();\n        resolve15(result);\n        try {\n          component?.dispose?.();\n        } catch {\n        }\n      };\n      Promise.resolve(factory(this.ui, theme, this.keybindings, close)).then((c) => {\n        if (closed)\n          return;\n        component = c;\n        if (isOverlay) {\n          const resolveOptions = () => {\n            if (options?.overlayOptions) {\n              const opts = typeof options.overlayOptions === \"function\" ? options.overlayOptions() : options.overlayOptions;\n              return opts;\n            }\n            const w = component.width;\n            return w ? { width: w } : void 0;\n          };\n          const handle = this.ui.showOverlay(component, resolveOptions());\n          options?.onHandle?.(handle);\n        } else {\n          this.disposeActiveSelector();\n          this.editorContainer.clear();\n          this.editorContainer.addChild(component);\n          this.ui.setFocus(component);\n          this.ui.requestRender();\n        }\n      }).catch((err2) => {\n        if (closed)\n          return;\n        if (!isOverlay)\n          restoreEditor();\n        reject(err2);\n      });\n    });\n  }\n  /**\n   * Show an extension error in the UI.\n   */\n  showExtensionError(extensionPath, error, stack) {\n    const errorMsg = `Extension \"${extensionPath}\" error: ${error}`;\n    const errorText = new Text(theme.fg(\"error\", errorMsg), 1, 0);\n    this.chatContainer.addChild(errorText);\n    if (stack) {\n      const stackLines = stack.split(\"\\n\").slice(1).map((line) => theme.fg(\"dim\", `  ${line.trim()}`)).join(\"\\n\");\n      if (stackLines) {\n        this.chatContainer.addChild(new Text(stackLines, 1, 0));\n      }\n    }\n    this.ui.requestRender();\n  }\n  // =========================================================================\n  // Key Handlers\n  // =========================================================================\n  setupKeyHandlers() {\n    this.defaultEditor.onEscape = () => {\n      if (this.session.isStreaming) {\n        this.restoreQueuedMessagesToEditor({ abort: true });\n      } else if (this.session.isBashRunning) {\n        this.session.abortBash();\n      } else if (this.isBashMode) {\n        this.editor.setText(\"\");\n        this.isBashMode = false;\n        this.updateEditorBorderColor();\n      } else if (!this.editor.getText().trim()) {\n        const action = this.settingsManager.getDoubleEscapeAction();\n        if (action !== \"none\") {\n          const now = Date.now();\n          if (now - this.lastEscapeTime < 500) {\n            if (action === \"tree\") {\n              this.showTreeSelector();\n            } else {\n              this.showUserMessageSelector();\n            }\n            this.lastEscapeTime = 0;\n          } else {\n            this.lastEscapeTime = now;\n          }\n        }\n      }\n    };\n    this.defaultEditor.onAction(\"app.clear\", () => this.handleCtrlC());\n    this.defaultEditor.onCtrlD = () => this.handleCtrlD();\n    this.defaultEditor.onAction(\"app.suspend\", () => this.handleCtrlZ());\n    this.defaultEditor.onAction(\"app.thinking.cycle\", () => this.cycleThinkingLevel());\n    this.defaultEditor.onAction(\"app.model.cycleForward\", () => this.cycleModel(\"forward\"));\n    this.defaultEditor.onAction(\"app.model.cycleBackward\", () => this.cycleModel(\"backward\"));\n    this.ui.onDebug = () => this.handleDebugCommand();\n    this.defaultEditor.onAction(\"app.model.select\", () => this.showModelSelector());\n    this.defaultEditor.onAction(\"app.tools.expand\", () => this.toggleToolOutputExpansion());\n    this.defaultEditor.onAction(\"app.thinking.toggle\", () => this.toggleThinkingBlockVisibility());\n    this.defaultEditor.onAction(\"app.editor.external\", () => void this.handleOpenExternalEditor());\n    this.defaultEditor.onAction(\"app.message.copy\", () => void this.handleCopyCommand({ flashConfirmation: true }));\n    this.defaultEditor.onAction(\"app.message.followUp\", () => this.handleFollowUp());\n    this.defaultEditor.onAction(\"app.message.dequeue\", () => this.handleDequeue());\n    this.defaultEditor.onAction(\"app.session.new\", () => this.handleClearCommand());\n    this.defaultEditor.onAction(\"app.session.tree\", () => this.showTreeSelector());\n    this.defaultEditor.onAction(\"app.session.fork\", () => this.showUserMessageSelector());\n    this.defaultEditor.onAction(\"app.session.resume\", () => this.showSessionSelector());\n    this.defaultEditor.onChange = (text) => {\n      const wasBashMode = this.isBashMode;\n      this.isBashMode = text.trimStart().startsWith(\"!\");\n      if (wasBashMode !== this.isBashMode) {\n        this.updateEditorBorderColor();\n      }\n    };\n    this.defaultEditor.onPasteImage = () => {\n      void this.handleClipboardPaste();\n    };\n  }\n  async handleRightClickPaste() {\n    const target = this.renderer.getFocusedComponent();\n    const handleInput = target?.handleInput;\n    if (!target || !handleInput)\n      return;\n    try {\n      const text = await readClipboardText();\n      if (!text || this.renderer.getFocusedComponent() !== target)\n        return;\n      handleInput.call(target, `\\x1B[200~${text}\\x1B[201~`);\n      this.ui.requestRender();\n    } catch {\n    }\n  }\n  async handleClipboardPaste() {\n    try {\n      const image = await readClipboardImage();\n      if (image) {\n        const tmpDir = os4.tmpdir();\n        const ext = extensionForImageMimeType(image.mimeType) ?? \"png\";\n        const fileName = `pi-clipboard-${crypto.randomUUID()}.${ext}`;\n        const filePath = path10.join(tmpDir, fileName);\n        fs6.writeFileSync(filePath, Buffer.from(image.bytes));\n        this.editor.insertTextAtCursor?.(filePath);\n        this.ui.requestRender();\n        return;\n      }\n      const text = await readClipboardText();\n      if (text) {\n        this.editor.insertTextAtCursor?.(text);\n        this.ui.requestRender();\n      }\n    } catch {\n    }\n  }\n  handleStartupSubmit(text) {\n    this.editor.setText(text);\n    this.showStatus(\"Startup is still in progress\");\n  }\n  setupEditorSubmitHandler() {\n    this.defaultEditor.onSubmit = async (text) => {\n      text = text.trim();\n      if (!text)\n        return;\n      if (text === \"/settings\") {\n        this.showSettingsSelector();\n        this.editor.setText(\"\");\n        return;\n      }\n      if (text === \"/scoped-models\") {\n        this.editor.setText(\"\");\n        await this.showModelsSelector();\n        return;\n      }\n      if (text === \"/model\" || text.startsWith(\"/model \")) {\n        const searchTerm = text.startsWith(\"/model \") ? text.slice(7).trim() : void 0;\n        this.editor.setText(\"\");\n        await this.handleModelCommand(searchTerm);\n        return;\n      }\n      if (text === \"/export\" || text.startsWith(\"/export \")) {\n        await this.handleExportCommand(text);\n        this.editor.setText(\"\");\n        return;\n      }\n      if (text === \"/import\" || text.startsWith(\"/import \")) {\n        await this.handleImportCommand(text);\n        this.editor.setText(\"\");\n        return;\n      }\n      if (text === \"/share\") {\n        await this.handleShareCommand();\n        this.editor.setText(\"\");\n        return;\n      }\n      if (text === \"/copy\") {\n        await this.handleCopyCommand();\n        this.editor.setText(\"\");\n        return;\n      }\n      if (text === \"/name\" || text.startsWith(\"/name \")) {\n        this.handleNameCommand(text);\n        this.editor.setText(\"\");\n        return;\n      }\n      if (text === \"/session\") {\n        this.handleSessionCommand();\n        this.editor.setText(\"\");\n        return;\n      }\n      if (text === \"/changelog\") {\n        this.handleChangelogCommand();\n        this.editor.setText(\"\");\n        return;\n      }\n      if (text === \"/hotkeys\") {\n        this.handleHotkeysCommand();\n        this.editor.setText(\"\");\n        return;\n      }\n      if (text === \"/fork\") {\n        this.showUserMessageSelector();\n        this.editor.setText(\"\");\n        return;\n      }\n      if (text === \"/clone\") {\n        this.editor.setText(\"\");\n        await this.handleCloneCommand();\n        return;\n      }\n      if (text === \"/tree\") {\n        this.showTreeSelector();\n        this.editor.setText(\"\");\n        return;\n      }\n      if (text === \"/trust\") {\n        this.showTrustSelector();\n        this.editor.setText(\"\");\n        return;\n      }\n      if (text === \"/login\" || text.startsWith(\"/login \")) {\n        const providerRef = text.startsWith(\"/login \") ? text.slice(7).trim() : void 0;\n        this.editor.setText(\"\");\n        await this.handleLoginCommand(providerRef);\n        return;\n      }\n      if (text === \"/logout\") {\n        this.showOAuthSelector(\"logout\");\n        this.editor.setText(\"\");\n        return;\n      }\n      if (text === \"/new\") {\n        this.editor.setText(\"\");\n        await this.handleClearCommand();\n        return;\n      }\n      if (text === \"/compact\" || text.startsWith(\"/compact \")) {\n        const customInstructions = text.startsWith(\"/compact \") ? text.slice(9).trim() : void 0;\n        this.editor.setText(\"\");\n        await this.handleCompactCommand(customInstructions);\n        return;\n      }\n      if (text === \"/reload\") {\n        this.editor.setText(\"\");\n        await this.handleReloadCommand();\n        return;\n      }\n      if (text === \"/debug\") {\n        this.handleDebugCommand();\n        this.editor.setText(\"\");\n        return;\n      }\n      if (text === \"/arminsayshi\") {\n        this.handleArminSaysHi();\n        this.editor.setText(\"\");\n        return;\n      }\n      if (text === \"/dementedelves\") {\n        this.handleDementedDelves();\n        this.editor.setText(\"\");\n        return;\n      }\n      if (text === \"/resume\") {\n        this.showSessionSelector();\n        this.editor.setText(\"\");\n        return;\n      }\n      if (text === \"/quit\") {\n        this.editor.setText(\"\");\n        await this.shutdown();\n        return;\n      }\n      if (text.startsWith(\"!\")) {\n        const isExcluded = text.startsWith(\"!!\");\n        const command = isExcluded ? text.slice(2).trim() : text.slice(1).trim();\n        if (command) {\n          if (this.session.isBashRunning) {\n            this.showWarning(\"A bash command is already running. Press Esc to cancel it first.\");\n            this.editor.setText(text);\n            return;\n          }\n          this.editor.addToHistory?.(text);\n          await this.handleBashCommand(command, isExcluded);\n          this.isBashMode = false;\n          this.updateEditorBorderColor();\n          return;\n        }\n      }\n      if (this.session.isCompacting) {\n        if (this.isExtensionCommand(text)) {\n          this.editor.addToHistory?.(text);\n          this.editor.setText(\"\");\n          await this.session.prompt(text);\n        } else {\n          this.queueCompactionMessage(text, \"steer\");\n        }\n        return;\n      }\n      if (this.session.isStreaming) {\n        this.editor.addToHistory?.(text);\n        this.editor.setText(\"\");\n        await this.session.prompt(text, { streamingBehavior: \"steer\" });\n        this.updatePendingMessagesDisplay();\n        this.ui.requestRender();\n        return;\n      }\n      this.flushPendingBashComponents();\n      if (this.onInputCallback) {\n        this.onInputCallback(text);\n      } else {\n        this.pendingUserInputs.push(text);\n      }\n      this.editor.addToHistory?.(text);\n    };\n  }\n  subscribeToAgent() {\n    this.unsubscribe = this.session.subscribe(async (event) => {\n      await this.handleEvent(event);\n    });\n  }\n  async handleEvent(event) {\n    if (!this.isInitialized) {\n      await this.init();\n    }\n    this.footer.invalidate();\n    switch (event.type) {\n      case \"agent_start\":\n        this.pendingTools.clear();\n        if (this.settingsManager.getShowTerminalProgress()) {\n          this.ui.terminal.setProgress(true);\n        }\n        if (this.retryEscapeHandler) {\n          this.defaultEditor.onEscape = this.retryEscapeHandler;\n          this.retryEscapeHandler = void 0;\n        }\n        if (this.workingVisible) {\n          this.showStatusIndicator(new WorkingStatusIndicator(this.ui, this.workingMessage ?? this.defaultWorkingMessage, this.workingIndicatorOptions));\n        } else {\n          this.clearStatusIndicator();\n        }\n        this.ui.requestRender();\n        break;\n      case \"queue_update\":\n        this.updatePendingMessagesDisplay();\n        this.ui.requestRender();\n        break;\n      case \"entry_appended\":\n        if (event.entry.type === \"custom\") {\n          this.addCustomEntryToChat(event.entry);\n          this.ui.requestRender();\n        }\n        break;\n      case \"session_info_changed\":\n        this.updateTerminalTitle();\n        this.footer.invalidate();\n        this.ui.requestRender();\n        break;\n      case \"thinking_level_changed\":\n        this.footer.invalidate();\n        this.updateEditorBorderColor();\n        break;\n      case \"message_start\":\n        if (event.message.role === \"custom\") {\n          this.addMessageToChat(event.message);\n          this.ui.requestRender();\n        } else if (event.message.role === \"user\") {\n          this.addMessageToChat(event.message);\n          this.updatePendingMessagesDisplay();\n          this.ui.requestRender();\n        } else if (event.message.role === \"assistant\") {\n          this.streamingComponent = new AssistantMessageComponent(void 0, this.hideThinkingBlock, this.getMarkdownThemeWithSettings(), this.hiddenThinkingLabel, this.outputPad, this.getMarkdownTransformers());\n          this.streamingMessage = event.message;\n          this.chatContainer.addChild(this.streamingComponent);\n          this.streamingComponent.updateContent(this.streamingMessage, true);\n          this.ui.requestRender();\n        }\n        break;\n      case \"message_update\":\n        if (this.streamingComponent && event.message.role === \"assistant\") {\n          this.streamingMessage = event.message;\n          this.streamingComponent.updateContent(this.streamingMessage, true);\n          for (const content of this.streamingMessage.content) {\n            if (content.type === \"toolCall\") {\n              if (!this.pendingTools.has(content.id)) {\n                const component = new ToolExecutionComponent(content.name, content.id, content.arguments, {\n                  showImages: this.settingsManager.getShowImages(),\n                  imageWidthCells: this.settingsManager.getImageWidthCells()\n                }, this.getRegisteredToolDefinition(content.name), this.ui, this.sessionManager.getCwd());\n                component.setExpanded(this.toolOutputExpanded);\n                this.chatContainer.addChild(component);\n                this.pendingTools.set(content.id, component);\n              } else {\n                const component = this.pendingTools.get(content.id);\n                if (component) {\n                  component.updateArgs(content.arguments);\n                }\n              }\n            }\n          }\n          this.ui.requestRender();\n        }\n        break;\n      case \"message_end\":\n        if (event.message.role === \"user\")\n          break;\n        if (this.streamingComponent && event.message.role === \"assistant\") {\n          this.streamingMessage = event.message;\n          let errorMessage2;\n          if (this.streamingMessage.stopReason === \"aborted\") {\n            const retryAttempt = this.session.retryAttempt;\n            errorMessage2 = retryAttempt > 0 ? `Aborted after ${retryAttempt} retry attempt${retryAttempt > 1 ? \"s\" : \"\"}` : \"Operation aborted\";\n            this.streamingMessage.errorMessage = errorMessage2;\n          }\n          this.streamingComponent.updateContent(this.streamingMessage, false);\n          if (this.streamingMessage.stopReason === \"aborted\" || this.streamingMessage.stopReason === \"error\") {\n            if (!errorMessage2) {\n              errorMessage2 = this.streamingMessage.errorMessage || \"Error\";\n            }\n            for (const [, component] of this.pendingTools.entries()) {\n              component.updateResult({\n                content: [{ type: \"text\", text: errorMessage2 }],\n                isError: true\n              });\n            }\n            this.pendingTools.clear();\n          } else {\n            for (const [, component] of this.pendingTools.entries()) {\n              component.setArgsComplete();\n            }\n            this.maybeShowCacheMissNotice(this.streamingMessage);\n          }\n          this.streamingComponent = void 0;\n          this.streamingMessage = void 0;\n          this.footer.invalidate();\n        }\n        this.ui.requestRender();\n        break;\n      case \"bash_execution_update\":\n        break;\n      case \"tool_execution_start\": {\n        let component = this.pendingTools.get(event.toolCallId);\n        if (!component) {\n          component = new ToolExecutionComponent(event.toolName, event.toolCallId, event.args, {\n            showImages: this.settingsManager.getShowImages(),\n            imageWidthCells: this.settingsManager.getImageWidthCells()\n          }, this.getRegisteredToolDefinition(event.toolName), this.ui, this.sessionManager.getCwd());\n          component.setExpanded(this.toolOutputExpanded);\n          this.chatContainer.addChild(component);\n          this.pendingTools.set(event.toolCallId, component);\n        }\n        component.markExecutionStarted();\n        this.ui.requestRender();\n        break;\n      }\n      case \"tool_execution_update\": {\n        const component = this.pendingTools.get(event.toolCallId);\n        if (component) {\n          component.updateResult({ ...event.partialResult, isError: false }, true);\n          this.ui.requestRender();\n        }\n        break;\n      }\n      case \"tool_execution_end\": {\n        const component = this.pendingTools.get(event.toolCallId);\n        if (component) {\n          component.updateResult({ ...event.result, isError: event.isError });\n          this.pendingTools.delete(event.toolCallId);\n          this.ui.requestRender();\n        }\n        break;\n      }\n      case \"agent_end\":\n        if (this.settingsManager.getShowTerminalProgress()) {\n          this.ui.terminal.setProgress(false);\n        }\n        this.clearStatusIndicator(\"working\");\n        if (this.streamingComponent) {\n          this.chatContainer.removeChild(this.streamingComponent);\n          this.streamingComponent = void 0;\n          this.streamingMessage = void 0;\n        }\n        this.pendingTools.clear();\n        this.ui.requestRender();\n        break;\n      case \"agent_settled\":\n        await this.checkShutdownRequested();\n        break;\n      case \"compaction_start\": {\n        if (this.settingsManager.getShowTerminalProgress()) {\n          this.ui.terminal.setProgress(true);\n        }\n        this.autoCompactionEscapeHandler = this.defaultEditor.onEscape;\n        this.defaultEditor.onEscape = () => {\n          this.session.abortCompaction();\n        };\n        this.showStatusIndicator(new CompactionStatusIndicator(this.ui, event.reason));\n        this.ui.requestRender();\n        break;\n      }\n      case \"compaction_end\": {\n        if (this.settingsManager.getShowTerminalProgress()) {\n          this.ui.terminal.setProgress(false);\n        }\n        if (this.autoCompactionEscapeHandler) {\n          this.defaultEditor.onEscape = this.autoCompactionEscapeHandler;\n          this.autoCompactionEscapeHandler = void 0;\n        }\n        this.clearStatusIndicator(\"compaction\");\n        if (event.aborted) {\n          if (event.reason === \"manual\") {\n            this.showError(\"Compaction cancelled\");\n          } else {\n            this.showStatus(\"Auto-compaction cancelled\");\n          }\n        } else if (event.result) {\n          this.chatContainer.clear();\n          this.rebuildChatFromMessages();\n          this.addMessageToChat(createCompactionSummaryMessage(event.result.summary, event.result.tokensBefore, (/* @__PURE__ */ new Date()).toISOString()));\n          this.footer.invalidate();\n        } else if (event.errorMessage) {\n          if (event.reason === \"manual\") {\n            this.showError(event.errorMessage);\n          } else {\n            this.chatContainer.addChild(new Spacer(1));\n            this.chatContainer.addChild(new Text(theme.fg(\"error\", event.errorMessage), 1, 0));\n          }\n        }\n        void this.flushCompactionQueue({ willRetry: event.willRetry });\n        this.ui.requestRender();\n        break;\n      }\n      case \"auto_retry_start\": {\n        this.retryEscapeHandler = this.defaultEditor.onEscape;\n        this.defaultEditor.onEscape = () => {\n          this.session.abortRetry();\n        };\n        this.showStatusIndicator(new RetryStatusIndicator(this.ui, event.attempt, event.maxAttempts, event.delayMs));\n        this.ui.requestRender();\n        break;\n      }\n      case \"auto_retry_end\": {\n        if (this.retryEscapeHandler) {\n          this.defaultEditor.onEscape = this.retryEscapeHandler;\n          this.retryEscapeHandler = void 0;\n        }\n        this.clearStatusIndicator(\"retry\");\n        if (!event.success) {\n          this.showError(`Retry failed after ${event.attempt} attempts: ${event.finalError || \"Unknown error\"}`);\n        }\n        this.ui.requestRender();\n        break;\n      }\n      case \"summarization_retry_scheduled\": {\n        this.showError(event.errorMessage);\n        this.showStatusIndicator(new RetryStatusIndicator(this.ui, event.attempt, event.maxAttempts, event.delayMs));\n        this.ui.requestRender();\n        break;\n      }\n      case \"summarization_retry_attempt_start\": {\n        this.clearStatusIndicator(\"retry\");\n        if (event.source === \"branchSummary\") {\n          this.showStatusIndicator(new BranchSummaryStatusIndicator(this.ui));\n        } else {\n          this.showStatusIndicator(new CompactionStatusIndicator(this.ui, event.reason));\n        }\n        this.ui.requestRender();\n        break;\n      }\n      case \"summarization_retry_finished\": {\n        this.clearStatusIndicator(\"retry\");\n        this.ui.requestRender();\n        break;\n      }\n    }\n  }\n  /** Extract text content from a user message */\n  getUserMessageText(message) {\n    if (message.role !== \"user\")\n      return \"\";\n    const textBlocks = typeof message.content === \"string\" ? [{ type: \"text\", text: message.content }] : message.content.filter((c) => c.type === \"text\");\n    return textBlocks.map((c) => c.text).join(\"\");\n  }\n  /** Show a managed-tool status update in the chat. */\n  showManagedToolStatus(status) {\n    if (!this.managedToolStatusStarted) {\n      this.chatContainer.addChild(new Spacer(1));\n      this.managedToolStatusStarted = true;\n    }\n    const message = status.type === \"warning\" ? `Warning: ${status.message}` : status.message;\n    const color = status.type === \"warning\" ? \"warning\" : \"dim\";\n    this.chatContainer.addChild(new Text(theme.fg(color, message), 1, 0));\n    this.lastStatusSpacer = void 0;\n    this.lastStatusText = void 0;\n    this.ui.requestRender();\n  }\n  /**\n   * Show a status message in the chat.\n   *\n   * If multiple status messages are emitted back-to-back (without anything else being added to the chat),\n   * we update the previous status line instead of appending new ones to avoid log spam.\n   */\n  showStatus(message) {\n    const children = this.chatContainer.children;\n    const last = children.length > 0 ? children[children.length - 1] : void 0;\n    const secondLast = children.length > 1 ? children[children.length - 2] : void 0;\n    if (last && secondLast && last === this.lastStatusText && secondLast === this.lastStatusSpacer) {\n      this.lastStatusText.setText(theme.fg(\"dim\", message));\n      this.ui.requestRender();\n      return;\n    }\n    const spacer = new Spacer(1);\n    const text = new Text(theme.fg(\"dim\", message), 1, 0);\n    this.chatContainer.addChild(spacer);\n    this.chatContainer.addChild(text);\n    this.lastStatusSpacer = spacer;\n    this.lastStatusText = text;\n    this.ui.requestRender();\n  }\n  addCustomEntryToChat(entry) {\n    const renderer = this.session.extensionRunner.getEntryRenderer(entry.customType);\n    if (!renderer) {\n      return;\n    }\n    const component = new CustomEntryComponent(entry, renderer);\n    component.setExpanded(this.toolOutputExpanded);\n    if (!component.hasContent()) {\n      return;\n    }\n    if (this.streamingComponent) {\n      const streamingIndex = this.chatContainer.children.indexOf(this.streamingComponent);\n      if (streamingIndex >= 0) {\n        this.chatContainer.children.splice(streamingIndex, 0, component);\n        return;\n      }\n    }\n    this.chatContainer.addChild(component);\n  }\n  addMessageToChat(message, options) {\n    switch (message.role) {\n      case \"bashExecution\": {\n        const component = new BashExecutionComponent(message.command, this.ui, message.excludeFromContext);\n        if (message.output) {\n          component.appendOutput(message.output);\n        }\n        component.setComplete(message.exitCode, message.cancelled, message.truncated ? { truncated: true } : void 0, message.fullOutputPath);\n        this.chatContainer.addChild(component);\n        break;\n      }\n      case \"custom\": {\n        if (message.display) {\n          const renderer = this.session.extensionRunner.getMessageRenderer(message.customType);\n          const component = new CustomMessageComponent(message, renderer, this.getMarkdownThemeWithSettings(), this.outputPad);\n          component.setExpanded(this.toolOutputExpanded);\n          this.chatContainer.addChild(component);\n        }\n        break;\n      }\n      case \"compactionSummary\": {\n        this.chatContainer.addChild(new Spacer(1));\n        const component = new CompactionSummaryMessageComponent(message, this.getMarkdownThemeWithSettings());\n        component.setExpanded(this.toolOutputExpanded);\n        this.chatContainer.addChild(component);\n        break;\n      }\n      case \"branchSummary\": {\n        this.chatContainer.addChild(new Spacer(1));\n        const component = new BranchSummaryMessageComponent(message, this.getMarkdownThemeWithSettings());\n        component.setExpanded(this.toolOutputExpanded);\n        this.chatContainer.addChild(component);\n        break;\n      }\n      case \"user\": {\n        const textContent = this.getUserMessageText(message);\n        if (textContent) {\n          if (this.chatContainer.children.length > 0) {\n            this.chatContainer.addChild(new Spacer(1));\n          }\n          const skillBlock = parseSkillBlock(textContent);\n          if (skillBlock) {\n            const component = new SkillInvocationMessageComponent(skillBlock, this.getMarkdownThemeWithSettings());\n            component.setExpanded(this.toolOutputExpanded);\n            this.chatContainer.addChild(component);\n            if (skillBlock.userMessage) {\n              this.chatContainer.addChild(new Spacer(1));\n              const userComponent = new UserMessageComponent(skillBlock.userMessage, this.getMarkdownThemeWithSettings(), this.outputPad, this.getMarkdownTransformers());\n              this.chatContainer.addChild(userComponent);\n            }\n          } else {\n            const userComponent = new UserMessageComponent(textContent, this.getMarkdownThemeWithSettings(), this.outputPad, this.getMarkdownTransformers());\n            this.chatContainer.addChild(userComponent);\n          }\n          if (options?.populateHistory) {\n            this.editor.addToHistory?.(textContent);\n          }\n        }\n        break;\n      }\n      case \"assistant\": {\n        const assistantComponent = new AssistantMessageComponent(message, this.hideThinkingBlock, this.getMarkdownThemeWithSettings(), this.hiddenThinkingLabel, this.outputPad, this.getMarkdownTransformers());\n        this.chatContainer.addChild(assistantComponent);\n        break;\n      }\n      case \"toolResult\": {\n        break;\n      }\n      default: {\n        const _exhaustive = message;\n      }\n    }\n  }\n  renderSessionItems(items, options = {}) {\n    this.pendingTools.clear();\n    const renderedPendingTools = /* @__PURE__ */ new Map();\n    const cacheMisses = this.settingsManager.getShowCacheMissNotices() ? collectCacheMisses(this.sessionManager.getEntries(), this.session.modelRuntime) : /* @__PURE__ */ new Map();\n    if (options.updateFooter) {\n      this.footer.invalidate();\n      this.updateEditorBorderColor();\n    }\n    for (const item of items) {\n      if (isCustomSessionEntry(item)) {\n        this.addCustomEntryToChat(item);\n        continue;\n      }\n      const message = item;\n      if (message.role === \"assistant\") {\n        this.addMessageToChat(message);\n        for (const content of message.content) {\n          if (content.type === \"toolCall\") {\n            const component = new ToolExecutionComponent(content.name, content.id, content.arguments, {\n              showImages: this.settingsManager.getShowImages(),\n              imageWidthCells: this.settingsManager.getImageWidthCells()\n            }, this.getRegisteredToolDefinition(content.name), this.ui, this.sessionManager.getCwd());\n            component.setExpanded(this.toolOutputExpanded);\n            this.chatContainer.addChild(component);\n            if (message.stopReason === \"aborted\" || message.stopReason === \"error\") {\n              let errorMessage2;\n              if (message.stopReason === \"aborted\") {\n                const retryAttempt = this.session.retryAttempt;\n                errorMessage2 = retryAttempt > 0 ? `Aborted after ${retryAttempt} retry attempt${retryAttempt > 1 ? \"s\" : \"\"}` : \"Operation aborted\";\n              } else {\n                errorMessage2 = message.errorMessage || \"Error\";\n              }\n              component.updateResult({ content: [{ type: \"text\", text: errorMessage2 }], isError: true });\n            } else {\n              renderedPendingTools.set(content.id, component);\n            }\n          }\n        }\n        if (message.stopReason !== \"aborted\" && message.stopReason !== \"error\") {\n          const miss = cacheMisses.get(message);\n          if (miss)\n            this.addCacheMissNotice(miss);\n        }\n      } else if (message.role === \"toolResult\") {\n        const component = renderedPendingTools.get(message.toolCallId);\n        if (component) {\n          component.updateResult(message);\n          renderedPendingTools.delete(message.toolCallId);\n        }\n      } else {\n        this.addMessageToChat(message, options);\n      }\n    }\n    for (const [toolCallId, component] of renderedPendingTools) {\n      this.pendingTools.set(toolCallId, component);\n    }\n    this.ui.requestRender();\n  }\n  /**\n   * Render session entries to chat. Used for initial load and rebuild after compaction.\n   * @param entries Compaction-aware session entries to render\n   * @param options.updateFooter Update footer state\n   * @param options.populateHistory Add user messages to editor history\n   */\n  renderSessionEntries(entries, options = {}) {\n    const items = entries.flatMap((entry) => {\n      if (entry.type === \"custom\") {\n        return [entry];\n      }\n      return sessionEntryToContextMessages(entry);\n    });\n    this.renderSessionItems(items, options);\n  }\n  /**\n   * Show a transcript notice when a completed assistant message paid for a\n   * significant cache miss. Only states observable facts: the miss itself,\n   * a model switch, or an idle gap past the cache TTL.\n   */\n  maybeShowCacheMissNotice(message) {\n    if (!this.settingsManager.getShowCacheMissNotices())\n      return;\n    const miss = detectCacheMiss(this.sessionManager.getEntries(), message, this.session.modelRuntime);\n    if (miss)\n      this.addCacheMissNotice(miss);\n  }\n  addCacheMissNotice(miss) {\n    if (miss.missedTokens < 2e4 && miss.missedCost < 0.1)\n      return;\n    const cost = miss.missedCost >= 0.01 ? ` (~$${miss.missedCost.toFixed(2)})` : \"\";\n    const reBilled = `${formatTokens(miss.missedTokens)} tokens re-billed${cost}`;\n    let label = \"Cache miss\";\n    if (miss.modelChanged) {\n      label = \"Cache miss after model switch\";\n    } else if (miss.idleMs >= CACHE_TTL_MS) {\n      label = `Cache miss after ${Math.round(miss.idleMs / 6e4)}m idle`;\n    }\n    const text = theme.fg(\"warning\", `${label}: ${reBilled}`);\n    this.chatContainer.addChild(new Spacer(1));\n    this.chatContainer.addChild(new Text(text, 1, 0));\n  }\n  renderInitialMessages() {\n    const entries = this.sessionManager.buildContextEntries();\n    this.renderSessionEntries(entries, {\n      updateFooter: true,\n      populateHistory: true\n    });\n    this.renderProjectTrustWarningIfNeeded();\n    const allEntries = this.sessionManager.getEntries();\n    const compactionCount = allEntries.filter((e) => e.type === \"compaction\").length;\n    if (compactionCount > 0) {\n      const times = compactionCount === 1 ? \"1 time\" : `${compactionCount} times`;\n      this.showStatus(`Session compacted ${times}`);\n    }\n  }\n  renderProjectTrustWarningIfNeeded() {\n    if (this.settingsManager.isProjectTrusted() || !hasTrustRequiringProjectResources(this.sessionManager.getCwd())) {\n      return;\n    }\n    if (this.chatContainer.children.length > 0) {\n      this.chatContainer.addChild(new Spacer(1));\n    }\n    this.chatContainer.addChild(new Text(theme.fg(\"warning\", `This project is not trusted. Project ${CONFIG_DIR_NAME} resources and packages are ignored. Use /trust to save a trust decision, then restart pi.`), 1, 0));\n  }\n  async getUserInput() {\n    const queuedInput = this.pendingUserInputs.shift();\n    if (queuedInput !== void 0) {\n      return queuedInput;\n    }\n    return new Promise((resolve15) => {\n      this.onInputCallback = (text) => {\n        this.onInputCallback = void 0;\n        resolve15(text);\n      };\n    });\n  }\n  rebuildChatFromMessages() {\n    this.chatContainer.clear();\n    this.renderSessionEntries(this.sessionManager.buildContextEntries());\n  }\n  // =========================================================================\n  // Key handlers\n  // =========================================================================\n  handleCtrlC() {\n    const now = Date.now();\n    if (now - this.lastSigintTime < 500) {\n      void this.shutdown();\n    } else {\n      this.clearEditor();\n      this.lastSigintTime = now;\n    }\n  }\n  handleCtrlD() {\n    void this.shutdown();\n  }\n  /**\n   * Gracefully shutdown the agent.\n   * Stops the TUI before emitting shutdown events so extension UI cleanup cannot\n   * repaint the final frame while the process is exiting.\n   */\n  isShuttingDown = false;\n  async shutdown(options) {\n    if (this.isShuttingDown)\n      return;\n    this.isShuttingDown = true;\n    if (options?.fromSignal) {\n      await this.runtimeHost.dispose();\n      this.themeController.disableAutoSync();\n      await this.ui.terminal.drainInput(1e3);\n      this.stop();\n      process.exit(0);\n    }\n    this.themeController.disableAutoSync();\n    await this.ui.terminal.drainInput(1e3);\n    this.stop();\n    await this.runtimeHost.dispose();\n    const resumeCommand = formatResumeCommand(this.sessionManager);\n    if (resumeCommand) {\n      process.stdout.write(`${chalk7.dim(\"To resume this session:\")} ${resumeCommand}\n`);\n    }\n    process.exit(0);\n  }\n  emergencyTerminalExit() {\n    this.isShuttingDown = true;\n    this.unregisterSignalHandlers();\n    killTrackedDetachedChildren();\n    process.exit(129);\n  }\n  /**\n   * Last-resort handler for uncaught exceptions. The TUI puts stdin into raw\n   * mode and hides the cursor; without this handler, an uncaught throw from\n   * anywhere (e.g. an extension's async `ChildProcess.on(\"exit\")` callback)\n   * tears down the process while leaving the terminal in raw mode with no\n   * cursor, requiring `stty sane && reset` to recover.\n   *\n   * Unlike emergencyTerminalExit, the terminal is still alive here, so we\n   * call ui.stop() to restore cooked mode, the cursor, and disable bracketed\n   * paste / Kitty / modifyOtherKeys sequences.\n   */\n  uncaughtCrash(error) {\n    if (this.isShuttingDown) {\n      process.exit(1);\n    }\n    this.isShuttingDown = true;\n    try {\n      this.unregisterSignalHandlers();\n    } catch {\n    }\n    try {\n      killTrackedDetachedChildren();\n    } catch {\n    }\n    try {\n      this.ui.stop();\n    } catch {\n    }\n    console.error(`${APP_NAME} exiting due to uncaughtException:`);\n    console.error(error);\n    process.exit(1);\n  }\n  /**\n   * Check if shutdown was requested and perform shutdown if so.\n   */\n  async checkShutdownRequested() {\n    if (!this.shutdownRequested)\n      return;\n    await this.shutdown();\n  }\n  registerSignalHandlers() {\n    this.unregisterSignalHandlers();\n    const signals = [\"SIGTERM\"];\n    if (process.platform !== \"win32\") {\n      signals.push(\"SIGHUP\");\n    }\n    for (const signal of signals) {\n      const handler = () => {\n        killTrackedDetachedChildren();\n        void this.shutdown({ fromSignal: true });\n      };\n      process.prependListener(signal, handler);\n      this.signalCleanupHandlers.push(() => process.off(signal, handler));\n    }\n    const terminalErrorHandler = (error) => {\n      if (isDeadTerminalError(error)) {\n        this.emergencyTerminalExit();\n      }\n      throw error;\n    };\n    process.stdout.on(\"error\", terminalErrorHandler);\n    process.stderr.on(\"error\", terminalErrorHandler);\n    this.signalCleanupHandlers.push(() => process.stdout.off(\"error\", terminalErrorHandler));\n    this.signalCleanupHandlers.push(() => process.stderr.off(\"error\", terminalErrorHandler));\n    const uncaughtExceptionHandler = (error) => this.uncaughtCrash(error);\n    process.prependListener(\"uncaughtException\", uncaughtExceptionHandler);\n    this.signalCleanupHandlers.push(() => process.off(\"uncaughtException\", uncaughtExceptionHandler));\n  }\n  unregisterSignalHandlers() {\n    for (const cleanup of this.signalCleanupHandlers) {\n      cleanup();\n    }\n    this.signalCleanupHandlers = [];\n  }\n  handleCtrlZ() {\n    if (process.platform === \"win32\") {\n      this.showStatus(\"Suspend to background is not supported on Windows\");\n      return;\n    }\n    const suspendKeepAlive = setInterval(() => {\n    }, 2 ** 30);\n    const ignoreSigint = () => {\n    };\n    process.on(\"SIGINT\", ignoreSigint);\n    process.once(\"SIGCONT\", () => {\n      clearInterval(suspendKeepAlive);\n      process.removeListener(\"SIGINT\", ignoreSigint);\n      this.ui.start();\n      this.ui.requestRender(true);\n    });\n    try {\n      this.ui.stop();\n      process.kill(0, \"SIGTSTP\");\n    } catch (error) {\n      clearInterval(suspendKeepAlive);\n      process.removeListener(\"SIGINT\", ignoreSigint);\n      throw error;\n    }\n  }\n  async handleFollowUp() {\n    const text = (this.editor.getExpandedText?.() ?? this.editor.getText()).trim();\n    if (!text)\n      return;\n    if (this.session.isCompacting) {\n      if (this.isExtensionCommand(text)) {\n        this.editor.addToHistory?.(text);\n        this.editor.setText(\"\");\n        await this.session.prompt(text);\n      } else {\n        this.queueCompactionMessage(text, \"followUp\");\n      }\n      return;\n    }\n    if (this.session.isStreaming) {\n      this.editor.addToHistory?.(text);\n      this.editor.setText(\"\");\n      await this.session.prompt(text, { streamingBehavior: \"followUp\" });\n      this.updatePendingMessagesDisplay();\n      this.ui.requestRender();\n    } else if (this.editor.onSubmit) {\n      this.editor.setText(\"\");\n      this.editor.onSubmit(text);\n    }\n  }\n  handleDequeue() {\n    const restored = this.restoreQueuedMessagesToEditor();\n    if (restored === 0) {\n      this.showStatus(\"No queued messages to restore\");\n    } else {\n      this.showStatus(`Restored ${restored} queued message${restored > 1 ? \"s\" : \"\"} to editor`);\n    }\n  }\n  updateEditorBorderColor() {\n    if (this.isBashMode) {\n      this.editor.borderColor = theme.getBashModeBorderColor();\n    } else {\n      const level = this.session.thinkingLevel || \"off\";\n      this.editor.borderColor = theme.getThinkingBorderColor(level);\n    }\n    this.ui.requestRender();\n  }\n  cycleThinkingLevel() {\n    const newLevel = this.session.cycleThinkingLevel();\n    if (newLevel === void 0) {\n      this.showStatus(\"Current model does not support thinking\");\n    } else {\n      this.footer.invalidate();\n      this.updateEditorBorderColor();\n      this.showStatus(`Thinking level: ${newLevel}`);\n    }\n  }\n  async cycleModel(direction) {\n    try {\n      const result = await this.session.cycleModel(direction);\n      if (result === void 0) {\n        const msg = this.session.scopedModels.length > 0 ? \"Only one model in scope\" : \"Only one model available\";\n        this.showStatus(msg);\n      } else {\n        this.footer.invalidate();\n        this.updateEditorBorderColor();\n        const thinkingStr = result.model.reasoning && result.thinkingLevel !== \"off\" ? ` (thinking: ${result.thinkingLevel})` : \"\";\n        this.showStatus(`Switched to ${result.model.name || result.model.id}${thinkingStr}`);\n        void this.maybeWarnAboutAnthropicSubscriptionAuth(result.model);\n      }\n    } catch (error) {\n      this.showError(error instanceof Error ? error.message : String(error));\n    }\n  }\n  toggleToolOutputExpansion() {\n    this.setToolsExpanded(!this.toolOutputExpanded);\n  }\n  setToolsExpanded(expanded) {\n    if (expanded === this.toolOutputExpanded)\n      return;\n    this.toolOutputExpanded = expanded;\n    const activeHeader = this.customHeader ?? this.builtInHeader;\n    if (isExpandable(activeHeader)) {\n      activeHeader.setExpanded(expanded);\n    }\n    for (const container of [this.loadedResourcesContainer, this.chatContainer]) {\n      for (const child of container.children) {\n        if (isExpandable(child)) {\n          child.setExpanded(expanded);\n        }\n      }\n    }\n    this.showStatus(`Tool output: ${expanded ? \"expanded\" : \"collapsed\"}`);\n  }\n  toggleThinkingBlockVisibility() {\n    this.hideThinkingBlock = !this.hideThinkingBlock;\n    this.settingsManager.setHideThinkingBlock(this.hideThinkingBlock);\n    this.chatContainer.clear();\n    this.rebuildChatFromMessages();\n    if (this.streamingComponent && this.streamingMessage) {\n      this.streamingComponent.setHideThinkingBlock(this.hideThinkingBlock);\n      this.streamingComponent.updateContent(this.streamingMessage);\n      this.chatContainer.addChild(this.streamingComponent);\n    }\n    this.showStatus(`Thinking blocks: ${this.hideThinkingBlock ? \"hidden\" : \"visible\"}`);\n  }\n  async handleOpenExternalEditor() {\n    const editorCmd = this.settingsManager.getExternalEditorCommand();\n    const content = this.editor.getExpandedText?.() ?? this.editor.getText();\n    this.ui.stop();\n    try {\n      const result = await editInExternalEditor({\n        command: editorCmd,\n        content\n      });\n      if (result.status === \"complete\") {\n        this.editor.setText(result.content);\n      }\n    } finally {\n      this.ui.start();\n      this.ui.requestRender(true);\n    }\n  }\n  // =========================================================================\n  // UI helpers\n  // =========================================================================\n  clearEditor() {\n    this.editor.setText(\"\");\n    this.ui.requestRender();\n  }\n  showError(errorMessage2) {\n    this.chatContainer.addChild(new Spacer(1));\n    this.chatContainer.addChild(new Text(theme.fg(\"error\", `Error: ${errorMessage2}`), this.outputPad, 0));\n    this.ui.requestRender();\n  }\n  showWarning(warningMessage) {\n    this.chatContainer.addChild(new Spacer(1));\n    this.chatContainer.addChild(new Text(theme.fg(\"warning\", `Warning: ${warningMessage}`), 1, 0));\n    this.ui.requestRender();\n  }\n  showNewVersionNotification(release) {\n    const action = theme.fg(\"accent\", `${APP_NAME} update`);\n    const updateInstruction = theme.fg(\"muted\", `New version ${release.version} is available. Run `) + action;\n    const changelogUrl = \"https://pi.dev/changelog\";\n    const changelogLink = getCapabilities().hyperlinks ? hyperlink(theme.fg(\"accent\", changelogUrl), changelogUrl) : theme.fg(\"accent\", changelogUrl);\n    const changelogLine = theme.fg(\"muted\", \"Changelog: \") + changelogLink;\n    const note = release.note?.trim();\n    this.chatContainer.addChild(new Spacer(1));\n    this.chatContainer.addChild(new DynamicBorder((text) => theme.fg(\"warning\", text)));\n    this.chatContainer.addChild(new Text(`${theme.bold(theme.fg(\"warning\", \"Update Available\"))}\n${updateInstruction}`, 1, 0));\n    if (note) {\n      this.chatContainer.addChild(new Spacer(1));\n      this.chatContainer.addChild(new Markdown(note, 1, 0, this.getMarkdownThemeWithSettings(), {\n        color: (text) => theme.fg(\"muted\", text)\n      }));\n      this.chatContainer.addChild(new Spacer(1));\n    }\n    this.chatContainer.addChild(new Text(changelogLine, 1, 0));\n    this.chatContainer.addChild(new DynamicBorder((text) => theme.fg(\"warning\", text)));\n    this.ui.requestRender();\n  }\n  showPackageUpdateNotification(packages) {\n    const action = theme.fg(\"accent\", `${APP_NAME} update --extensions`);\n    const updateInstruction = theme.fg(\"muted\", \"Package updates are available. Run \") + action;\n    const packageLines = packages.map((pkg2) => `- ${pkg2}`).join(\"\\n\");\n    this.chatContainer.addChild(new Spacer(1));\n    this.chatContainer.addChild(new DynamicBorder((text) => theme.fg(\"warning\", text)));\n    this.chatContainer.addChild(new Text(`${theme.bold(theme.fg(\"warning\", \"Package Updates Available\"))}\n${updateInstruction}\n${theme.fg(\"muted\", \"Packages:\")}\n${packageLines}`, 1, 0));\n    this.chatContainer.addChild(new DynamicBorder((text) => theme.fg(\"warning\", text)));\n    this.ui.requestRender();\n  }\n  /**\n   * Get all queued messages (read-only).\n   * Combines session queue and compaction queue.\n   */\n  getAllQueuedMessages() {\n    return {\n      steering: [\n        ...this.session.getSteeringMessages(),\n        ...this.compactionQueuedMessages.filter((msg) => msg.mode === \"steer\").map((msg) => msg.text)\n      ],\n      followUp: [\n        ...this.session.getFollowUpMessages(),\n        ...this.compactionQueuedMessages.filter((msg) => msg.mode === \"followUp\").map((msg) => msg.text)\n      ]\n    };\n  }\n  /**\n   * Clear all queued messages and return their contents.\n   * Clears both session queue and compaction queue.\n   */\n  clearAllQueues() {\n    const { steering, followUp } = this.session.clearQueue();\n    const compactionSteering = this.compactionQueuedMessages.filter((msg) => msg.mode === \"steer\").map((msg) => msg.text);\n    const compactionFollowUp = this.compactionQueuedMessages.filter((msg) => msg.mode === \"followUp\").map((msg) => msg.text);\n    this.compactionQueuedMessages = [];\n    return {\n      steering: [...steering, ...compactionSteering],\n      followUp: [...followUp, ...compactionFollowUp]\n    };\n  }\n  updatePendingMessagesDisplay() {\n    this.pendingMessagesContainer.clear();\n    const { steering: steeringMessages, followUp: followUpMessages } = this.getAllQueuedMessages();\n    if (steeringMessages.length > 0 || followUpMessages.length > 0) {\n      this.pendingMessagesContainer.addChild(new Spacer(1));\n      for (const message of steeringMessages) {\n        const text = theme.fg(\"dim\", `Steering: ${message}`);\n        this.pendingMessagesContainer.addChild(new TruncatedText(text, 1, 0));\n      }\n      for (const message of followUpMessages) {\n        const text = theme.fg(\"dim\", `Follow-up: ${message}`);\n        this.pendingMessagesContainer.addChild(new TruncatedText(text, 1, 0));\n      }\n      const dequeueHint = this.getAppKeyDisplay(\"app.message.dequeue\");\n      const hintText = theme.fg(\"dim\", `\\u21B3 ${dequeueHint} to edit all queued messages`);\n      this.pendingMessagesContainer.addChild(new TruncatedText(hintText, 1, 0));\n    }\n  }\n  restoreQueuedMessagesToEditor(options) {\n    const { steering, followUp } = this.clearAllQueues();\n    const allQueued = [...steering, ...followUp];\n    if (allQueued.length === 0) {\n      this.updatePendingMessagesDisplay();\n      if (options?.abort) {\n        this.agent.abort();\n      }\n      return 0;\n    }\n    const queuedText = allQueued.join(\"\\n\\n\");\n    const currentText = options?.currentText ?? this.editor.getText();\n    const combinedText = [queuedText, currentText].filter((t) => t.trim()).join(\"\\n\\n\");\n    this.editor.setText(combinedText);\n    this.updatePendingMessagesDisplay();\n    if (options?.abort) {\n      this.agent.abort();\n    }\n    return allQueued.length;\n  }\n  queueCompactionMessage(text, mode) {\n    this.compactionQueuedMessages.push({ text, mode });\n    this.editor.addToHistory?.(text);\n    this.editor.setText(\"\");\n    this.updatePendingMessagesDisplay();\n    this.showStatus(\"Queued message for after compaction\");\n  }\n  isExtensionCommand(text) {\n    if (!text.startsWith(\"/\"))\n      return false;\n    const extensionRunner = this.session.extensionRunner;\n    const spaceIndex = text.indexOf(\" \");\n    const commandName = spaceIndex === -1 ? text.slice(1) : text.slice(1, spaceIndex);\n    return !!extensionRunner.getCommand(commandName);\n  }\n  async flushCompactionQueue(options) {\n    if (this.compactionQueuedMessages.length === 0) {\n      return;\n    }\n    const queuedMessages = [...this.compactionQueuedMessages];\n    this.compactionQueuedMessages = [];\n    this.updatePendingMessagesDisplay();\n    const restoreQueue = (error) => {\n      this.session.clearQueue();\n      this.compactionQueuedMessages = queuedMessages;\n      this.updatePendingMessagesDisplay();\n      this.showError(`Failed to send queued message${queuedMessages.length > 1 ? \"s\" : \"\"}: ${error instanceof Error ? error.message : String(error)}`);\n    };\n    try {\n      if (options?.willRetry) {\n        for (const message of queuedMessages) {\n          if (this.isExtensionCommand(message.text)) {\n            await this.session.prompt(message.text);\n          } else if (message.mode === \"followUp\") {\n            await this.session.followUp(message.text);\n          } else {\n            await this.session.steer(message.text);\n          }\n        }\n        this.updatePendingMessagesDisplay();\n        return;\n      }\n      const firstPromptIndex = queuedMessages.findIndex((message) => !this.isExtensionCommand(message.text));\n      if (firstPromptIndex === -1) {\n        for (const message of queuedMessages) {\n          await this.session.prompt(message.text);\n        }\n        return;\n      }\n      const preCommands = queuedMessages.slice(0, firstPromptIndex);\n      const firstPrompt = queuedMessages[firstPromptIndex];\n      const rest = queuedMessages.slice(firstPromptIndex + 1);\n      for (const message of preCommands) {\n        await this.session.prompt(message.text);\n      }\n      const promptPromise = this.session.prompt(firstPrompt.text, { streamingBehavior: firstPrompt.mode }).catch((error) => {\n        restoreQueue(error);\n      });\n      for (const message of rest) {\n        if (this.isExtensionCommand(message.text)) {\n          await this.session.prompt(message.text);\n        } else if (message.mode === \"followUp\") {\n          await this.session.followUp(message.text);\n        } else {\n          await this.session.steer(message.text);\n        }\n      }\n      this.updatePendingMessagesDisplay();\n      void promptPromise;\n    } catch (error) {\n      restoreQueue(error);\n    }\n  }\n  /** Move pending bash components from pending area to chat */\n  flushPendingBashComponents() {\n    for (const component of this.pendingBashComponents) {\n      this.pendingMessagesContainer.removeChild(component);\n      this.chatContainer.addChild(component);\n    }\n    this.pendingBashComponents = [];\n  }\n  // =========================================================================\n  // Selectors\n  // =========================================================================\n  disposeActiveSelector() {\n    const dispose = this.activeSelectorDispose;\n    this.activeSelectorToken = void 0;\n    this.activeSelectorDispose = void 0;\n    dispose?.();\n  }\n  /**\n   * Shows a selector component in place of the editor.\n   * @param create Factory that receives a `done` callback and returns the component and focus target\n   */\n  showSelector(create) {\n    const token = {};\n    let dispose;\n    const done = () => {\n      dispose?.();\n      if (this.activeSelectorToken !== token)\n        return;\n      this.activeSelectorToken = void 0;\n      this.activeSelectorDispose = void 0;\n      this.editorContainer.clear();\n      this.editorContainer.addChild(this.editor);\n      this.ui.setFocus(this.editor);\n    };\n    const created = create(done);\n    dispose = created.dispose;\n    this.disposeActiveSelector();\n    this.activeSelectorToken = token;\n    this.activeSelectorDispose = dispose;\n    this.editorContainer.clear();\n    this.editorContainer.addChild(created.component);\n    this.ui.setFocus(created.focus);\n    this.ui.requestRender();\n  }\n  showSettingsSelector() {\n    this.showSelector((done) => {\n      let selector;\n      selector = new SettingsSelectorComponent({\n        autoCompact: this.session.autoCompactionEnabled,\n        showImages: this.settingsManager.getShowImages(),\n        imageWidthCells: this.settingsManager.getImageWidthCells(),\n        autoResizeImages: this.settingsManager.getImageAutoResize(),\n        blockImages: this.settingsManager.getBlockImages(),\n        enableSkillCommands: this.settingsManager.getEnableSkillCommands(),\n        steeringMode: this.session.steeringMode,\n        followUpMode: this.session.followUpMode,\n        transport: this.settingsManager.getTransport(),\n        httpIdleTimeoutMs: this.settingsManager.getHttpIdleTimeoutMs(),\n        thinkingLevel: this.session.thinkingLevel,\n        availableThinkingLevels: this.session.getAvailableThinkingLevels(),\n        currentTheme: this.themeController.getThemeSelection() || \"dark\",\n        terminalTheme: this.themeController.getTerminalTheme(),\n        availableThemes: getAvailableThemes(),\n        hideThinkingBlock: this.hideThinkingBlock,\n        mermaidRenderingMode: this.settingsManager.getMermaidRenderingMode(),\n        collapseChangelog: this.settingsManager.getCollapseChangelog(),\n        enableInstallTelemetry: this.settingsManager.getEnableInstallTelemetry(),\n        doubleEscapeAction: this.settingsManager.getDoubleEscapeAction(),\n        treeFilterMode: this.settingsManager.getTreeFilterMode(),\n        showHardwareCursor: this.settingsManager.getShowHardwareCursor(),\n        showCacheMissNotices: this.settingsManager.getShowCacheMissNotices(),\n        defaultProjectTrust: this.settingsManager.getDefaultProjectTrust(),\n        editorPaddingX: this.settingsManager.getEditorPaddingX(),\n        outputPad: this.settingsManager.getOutputPad(),\n        autocompleteMaxVisible: this.settingsManager.getAutocompleteMaxVisible(),\n        quietStartup: this.settingsManager.getQuietStartup(),\n        clearOnShrink: this.settingsManager.getClearOnShrink(),\n        showTerminalProgress: this.settingsManager.getShowTerminalProgress(),\n        tuiMode: this.ui.mode,\n        fullscreenExitOutput: this.settingsManager.getFullscreenExitOutput(),\n        fullscreenScrollbar: this.settingsManager.getFullscreenScrollbar(),\n        warnings: this.settingsManager.getWarnings()\n      }, {\n        onAutoCompactChange: (enabled) => {\n          this.session.setAutoCompactionEnabled(enabled);\n          this.footer.setAutoCompactEnabled(enabled);\n        },\n        onShowImagesChange: (enabled) => {\n          this.settingsManager.setShowImages(enabled);\n          for (const child of this.chatContainer.children) {\n            if (child instanceof ToolExecutionComponent) {\n              child.setShowImages(enabled);\n            }\n          }\n        },\n        onImageWidthCellsChange: (width) => {\n          this.settingsManager.setImageWidthCells(width);\n          for (const child of this.chatContainer.children) {\n            if (child instanceof ToolExecutionComponent) {\n              child.setImageWidthCells(width);\n            }\n          }\n        },\n        onAutoResizeImagesChange: (enabled) => {\n          this.settingsManager.setImageAutoResize(enabled);\n        },\n        onBlockImagesChange: (blocked) => {\n          this.settingsManager.setBlockImages(blocked);\n        },\n        onEnableSkillCommandsChange: (enabled) => {\n          this.settingsManager.setEnableSkillCommands(enabled);\n          this.setupAutocompleteProvider();\n        },\n        onSteeringModeChange: (mode) => {\n          this.session.setSteeringMode(mode);\n        },\n        onFollowUpModeChange: (mode) => {\n          this.session.setFollowUpMode(mode);\n        },\n        onTransportChange: (transport) => {\n          this.settingsManager.setTransport(transport);\n          this.session.agent.transport = transport;\n        },\n        onHttpIdleTimeoutMsChange: (timeoutMs) => {\n          this.settingsManager.setHttpIdleTimeoutMs(timeoutMs);\n          configureHttpDispatcher(timeoutMs);\n          this.showStatus(`HTTP idle timeout: ${formatHttpIdleTimeoutMs(timeoutMs)}`);\n        },\n        onThinkingLevelChange: (level) => {\n          this.session.setThinkingLevel(level);\n          this.footer.invalidate();\n          this.updateEditorBorderColor();\n        },\n        onThemeChange: (themeSetting) => {\n          this.settingsManager.setTheme(themeSetting);\n          void this.themeController.setThemeSetting(themeSetting);\n        },\n        onThemePreview: (themeName) => this.themeController.preview(themeName),\n        onHideThinkingBlockChange: (hidden) => {\n          this.hideThinkingBlock = hidden;\n          this.settingsManager.setHideThinkingBlock(hidden);\n          for (const child of this.chatContainer.children) {\n            if (child instanceof AssistantMessageComponent) {\n              child.setHideThinkingBlock(hidden);\n            }\n          }\n          this.chatContainer.clear();\n          this.rebuildChatFromMessages();\n        },\n        onMermaidRenderingModeChange: (mode) => {\n          this.settingsManager.setMermaidRenderingMode(mode);\n          this.chatContainer.invalidate();\n          this.ui.requestRender();\n        },\n        onShowCacheMissNoticesChange: (shown) => {\n          this.settingsManager.setShowCacheMissNotices(shown);\n          this.rebuildChatFromMessages();\n        },\n        onCollapseChangelogChange: (collapsed) => {\n          this.settingsManager.setCollapseChangelog(collapsed);\n        },\n        onEnableInstallTelemetryChange: (enabled) => {\n          this.settingsManager.setEnableInstallTelemetry(enabled);\n        },\n        onQuietStartupChange: (enabled) => {\n          this.settingsManager.setQuietStartup(enabled);\n        },\n        onDefaultProjectTrustChange: (defaultProjectTrust) => {\n          this.settingsManager.setDefaultProjectTrust(defaultProjectTrust);\n        },\n        onDoubleEscapeActionChange: (action) => {\n          this.settingsManager.setDoubleEscapeAction(action);\n        },\n        onTreeFilterModeChange: (mode) => {\n          this.settingsManager.setTreeFilterMode(mode);\n        },\n        onShowHardwareCursorChange: (enabled) => {\n          this.settingsManager.setShowHardwareCursor(enabled);\n          this.ui.setShowHardwareCursor(enabled);\n        },\n        onEditorPaddingXChange: (padding) => {\n          this.settingsManager.setEditorPaddingX(padding);\n          this.defaultEditor.setPaddingX(padding);\n          if (this.editor !== this.defaultEditor && this.editor.setPaddingX !== void 0) {\n            this.editor.setPaddingX(padding);\n          }\n        },\n        onOutputPadChange: (padding) => {\n          this.settingsManager.setOutputPad(padding);\n          this.outputPad = padding;\n          if (this.streamingComponent || this.session.isStreaming) {\n            for (const child of this.chatContainer.children) {\n              if (child instanceof AssistantMessageComponent || child instanceof CustomMessageComponent || child instanceof UserMessageComponent) {\n                child.setOutputPad(padding);\n              }\n            }\n            if (this.streamingComponent) {\n              this.streamingComponent.setOutputPad(padding);\n            }\n            this.ui.requestRender();\n            return;\n          }\n          this.rebuildChatFromMessages();\n        },\n        onAutocompleteMaxVisibleChange: (maxVisible) => {\n          this.settingsManager.setAutocompleteMaxVisible(maxVisible);\n          this.defaultEditor.setAutocompleteMaxVisible(maxVisible);\n          if (this.editor !== this.defaultEditor && this.editor.setAutocompleteMaxVisible !== void 0) {\n            this.editor.setAutocompleteMaxVisible(maxVisible);\n          }\n        },\n        onClearOnShrinkChange: (enabled) => {\n          this.settingsManager.setClearOnShrink(enabled);\n          this.ui.setClearOnShrink(enabled);\n          if (!enabled && !this.activeStatusIndicator) {\n            this.statusContainer.clear();\n          }\n        },\n        onShowTerminalProgressChange: (enabled) => {\n          this.settingsManager.setShowTerminalProgress(enabled);\n        },\n        onTuiModeChange: (mode) => {\n          if (!this.switchTuiMode(mode)) {\n            selector?.getSettingsList().updateValue(\"tui-mode\", this.ui.mode);\n            this.showStatus(\"Close active overlays before changing TUI mode\");\n            return;\n          }\n          this.settingsManager.setTuiMode(mode);\n          if (!this.activeStatusIndicator)\n            this.statusContainer.clear();\n          this.showStatus(`TUI mode: ${mode}`);\n        },\n        onFullscreenExitOutputChange: (output) => {\n          this.settingsManager.setFullscreenExitOutput(output);\n        },\n        onFullscreenScrollbarChange: (mode) => {\n          this.settingsManager.setFullscreenScrollbar(mode);\n          this.applyFullscreenScrollbarSetting();\n        },\n        onWarningsChange: (warnings) => {\n          this.settingsManager.setWarnings(warnings);\n        },\n        onCancel: () => {\n          done();\n          this.ui.requestRender();\n        }\n      });\n      return { component: selector, focus: selector.getSettingsList() };\n    });\n  }\n  async handleModelCommand(searchTerm) {\n    if (!searchTerm) {\n      this.showModelSelector();\n      return;\n    }\n    const model = await this.findExactModelMatch(searchTerm);\n    if (model) {\n      try {\n        await this.session.setModel(model);\n        this.footer.invalidate();\n        this.updateEditorBorderColor();\n        this.showStatus(`Model: ${model.id}`);\n        void this.maybeWarnAboutAnthropicSubscriptionAuth(model);\n        this.checkDaxnutsEasterEgg(model);\n      } catch (error) {\n        this.showError(error instanceof Error ? error.message : String(error));\n      }\n      return;\n    }\n    this.showModelSelector(searchTerm);\n  }\n  async findExactModelMatch(searchTerm) {\n    const cachedModels = this.session.scopedModels.length > 0 ? this.session.scopedModels.map((scoped) => scoped.model) : [...this.session.modelRuntime.getAvailableSnapshot()];\n    const cachedMatch = findExactModelReferenceMatch(searchTerm, cachedModels);\n    if (cachedMatch || this.session.scopedModels.length > 0)\n      return cachedMatch;\n    this.showStatus(\"Refreshing model catalogs\\u2026\");\n    const controller = new AbortController();\n    let timedOut = false;\n    const timeout = setTimeout(() => {\n      timedOut = true;\n      controller.abort();\n    }, 15e3);\n    try {\n      const result = await refreshModelCatalogs(this.session.modelRuntime, controller.signal);\n      if (result.aborted && timedOut) {\n        this.showWarning(\"Model refresh timed out; searching cached models.\");\n      } else if (result.errors.size > 0) {\n        this.showWarning(`Could not refresh ${[...result.errors.keys()].join(\", \")}; searching cached models.`);\n      }\n    } catch (error) {\n      this.showWarning(timedOut ? \"Model refresh timed out; searching cached models.\" : `Could not refresh model catalogs: ${error instanceof Error ? error.message : String(error)}`);\n    } finally {\n      clearTimeout(timeout);\n    }\n    return findExactModelReferenceMatch(searchTerm, [...this.session.modelRuntime.getAvailableSnapshot()]);\n  }\n  /** Update the footer's available provider count from the current snapshot without refreshing catalogs. */\n  updateAvailableProviderCount() {\n    const models = this.session.scopedModels.length > 0 ? this.session.scopedModels.map((scoped) => scoped.model) : this.session.modelRuntime.getAvailableSnapshot();\n    const uniqueProviders = new Set(models.map((model) => model.provider));\n    this.footerDataProvider.setAvailableProviderCount(uniqueProviders.size);\n  }\n  async maybeWarnAboutAnthropicSubscriptionAuth(model = this.session.model) {\n    if (this.settingsManager.getWarnings().anthropicExtraUsage === false) {\n      return;\n    }\n    if (this.anthropicSubscriptionWarningShown) {\n      return;\n    }\n    if (!model || model.provider !== \"anthropic\") {\n      return;\n    }\n    try {\n      if ((await this.session.modelRuntime.checkAuth(\"anthropic\"))?.type === \"oauth\") {\n        this.anthropicSubscriptionWarningShown = true;\n        this.showWarning(ANTHROPIC_SUBSCRIPTION_AUTH_WARNING);\n        return;\n      }\n      const apiKey = (await this.session.modelRuntime.getAuth(model.provider))?.auth.apiKey;\n      if (!isAnthropicSubscriptionAuthKey(apiKey)) {\n        return;\n      }\n      this.anthropicSubscriptionWarningShown = true;\n      this.showWarning(ANTHROPIC_SUBSCRIPTION_AUTH_WARNING);\n    } catch {\n    }\n  }\n  maybeSaveImplicitProjectTrustAfterReload() {\n    const cwd = this.sessionManager.getCwd();\n    if (this.autoTrustOnReloadCwd !== cwd) {\n      return false;\n    }\n    if (!this.settingsManager.isProjectTrusted() || !hasTrustRequiringProjectResources(cwd)) {\n      return false;\n    }\n    const trustStore = new ProjectTrustStore(this.runtimeHost.services.agentDir);\n    try {\n      if (trustStore.get(cwd) !== null) {\n        this.autoTrustOnReloadCwd = void 0;\n        return false;\n      }\n      trustStore.set(cwd, true);\n      this.autoTrustOnReloadCwd = void 0;\n      return true;\n    } catch (error) {\n      this.showWarning(`Could not save project trust after reload: ${error instanceof Error ? error.message : String(error)}`);\n      return false;\n    }\n  }\n  showTrustSelector() {\n    const cwd = this.sessionManager.getCwd();\n    const trustStore = new ProjectTrustStore(this.runtimeHost.services.agentDir);\n    const savedDecision = trustStore.getEntry(cwd);\n    this.showSelector((done) => {\n      const selector = new TrustSelectorComponent({\n        cwd,\n        savedDecision,\n        projectTrusted: this.settingsManager.isProjectTrusted(),\n        onSelect: (selection) => {\n          trustStore.setMany(selection.updates);\n          done();\n          this.showStatus(`Saved trust decision: ${selection.trusted ? \"trusted\" : \"untrusted\"}. Restart ${APP_NAME} for this to take effect.`);\n        },\n        onCancel: () => {\n          done();\n          this.ui.requestRender();\n        }\n      });\n      return { component: selector, focus: selector };\n    });\n  }\n  showModelSelector(initialSearchInput) {\n    this.showSelector((done) => {\n      const selector = new ModelSelectorComponent(this.ui, this.session.model, this.settingsManager, this.session.modelRuntime, this.session.scopedModels, async (model) => {\n        try {\n          await this.session.setModel(model);\n          this.footer.invalidate();\n          this.updateEditorBorderColor();\n          done();\n          this.showStatus(`Model: ${model.id}`);\n          void this.maybeWarnAboutAnthropicSubscriptionAuth(model);\n          this.checkDaxnutsEasterEgg(model);\n        } catch (error) {\n          done();\n          this.showError(error instanceof Error ? error.message : String(error));\n        }\n      }, () => {\n        done();\n        this.ui.requestRender();\n      }, initialSearchInput);\n      return { component: selector, focus: selector, dispose: () => selector.dispose() };\n    });\n  }\n  showModelsSelector() {\n    let availableModels = [...this.session.modelRuntime.getAvailableSnapshot()];\n    let availableModelIds = new Set(availableModels.map((model) => `${model.provider}/${model.id}`));\n    const configuredPatterns = this.settingsManager.getEnabledModels();\n    const sessionScopedModels = this.session.scopedModels;\n    const configuredEnabledIds = (models) => {\n      if (!configuredPatterns?.length)\n        return null;\n      const resolved = resolveModelScopeFromModels(configuredPatterns, models);\n      const ids = resolved.scopedModels.map((scoped) => `${scoped.model.provider}/${scoped.model.id}`);\n      for (const diagnostic of resolved.diagnostics) {\n        if (diagnostic.code === \"no-match\" && !ids.includes(diagnostic.pattern))\n          ids.push(diagnostic.pattern);\n      }\n      return ids;\n    };\n    let currentEnabledIds = sessionScopedModels.length > 0 ? sessionScopedModels.map((scoped) => `${scoped.model.provider}/${scoped.model.id}`) : configuredEnabledIds(availableModels);\n    let selectionChanged = false;\n    const updateSessionModels = (enabledIds) => {\n      currentEnabledIds = enabledIds === null ? null : [...enabledIds];\n      const hasEnabledAvailableModel = enabledIds?.some((id) => availableModelIds.has(id)) ?? false;\n      const allAvailableModelsEnabled = enabledIds !== null && [...availableModelIds].every((id) => enabledIds.includes(id));\n      if (enabledIds && hasEnabledAvailableModel && !allAvailableModelsEnabled) {\n        const newScopedModels = resolveModelScopeFromModels(enabledIds, availableModels).scopedModels;\n        this.session.setScopedModels(newScopedModels.map((scoped) => ({\n          model: scoped.model,\n          thinkingLevel: scoped.thinkingLevel\n        })));\n      } else {\n        this.session.setScopedModels([]);\n      }\n      this.updateAvailableProviderCount();\n      this.ui.requestRender();\n    };\n    this.showSelector((done) => {\n      let disposed = false;\n      let timedOut = false;\n      const controller = new AbortController();\n      const timeout = setTimeout(() => {\n        timedOut = true;\n        controller.abort();\n      }, 15e3);\n      const selector = new ScopedModelsSelectorComponent({\n        allModels: availableModels,\n        enabledModelIds: currentEnabledIds,\n        refreshStatus: \"Refreshing model catalogs\\u2026\"\n      }, {\n        onChange: (enabledIds) => {\n          selectionChanged = true;\n          updateSessionModels(enabledIds);\n        },\n        onPersist: (enabledIds) => {\n          const allEnabled = enabledIds !== null && enabledIds.length === availableModels.length && enabledIds.every((id) => availableModelIds.has(id));\n          const newPatterns = enabledIds === null || allEnabled ? void 0 : enabledIds;\n          this.settingsManager.setEnabledModels(newPatterns ? [...newPatterns] : void 0);\n          this.showStatus(\"Model selection saved to settings\");\n        },\n        onCancel: () => {\n          done();\n          this.ui.requestRender();\n        }\n      });\n      void refreshModelCatalogs(this.session.modelRuntime, controller.signal).then((result) => {\n        if (disposed)\n          return;\n        availableModels = [...this.session.modelRuntime.getAvailableSnapshot()];\n        availableModelIds = new Set(availableModels.map((model) => `${model.provider}/${model.id}`));\n        if (!selectionChanged && sessionScopedModels.length === 0) {\n          currentEnabledIds = configuredEnabledIds(availableModels);\n          selector.updateModels(availableModels, currentEnabledIds);\n        } else {\n          selector.updateModels(availableModels);\n        }\n        if (currentEnabledIds !== null)\n          updateSessionModels(currentEnabledIds);\n        if (result.aborted && timedOut) {\n          selector.setRefreshStatus(\"Model refresh timed out; showing cached models.\", \"warning\");\n        } else if (result.errors.size > 0) {\n          selector.setRefreshStatus(`Could not refresh ${[...result.errors.keys()].join(\", \")}; showing cached models.`, \"warning\");\n        } else {\n          selector.setRefreshStatus(\"Model catalogs refreshed.\", \"success\");\n        }\n        this.ui.requestRender();\n      }).catch((error) => {\n        if (disposed)\n          return;\n        selector.setRefreshStatus(timedOut ? \"Model refresh timed out; showing cached models.\" : `Could not refresh model catalogs: ${error instanceof Error ? error.message : String(error)}`, \"warning\");\n        this.ui.requestRender();\n      }).finally(() => clearTimeout(timeout));\n      return {\n        component: selector,\n        focus: selector,\n        dispose: () => {\n          disposed = true;\n          clearTimeout(timeout);\n          controller.abort();\n        }\n      };\n    });\n  }\n  showUserMessageSelector() {\n    const userMessages = this.session.getUserMessagesForForking();\n    if (userMessages.length === 0) {\n      this.showStatus(\"No messages to fork from\");\n      return;\n    }\n    const initialSelectedId = userMessages[userMessages.length - 1]?.entryId;\n    this.showSelector((done) => {\n      const selector = new UserMessageSelectorComponent(userMessages.map((m) => ({ id: m.entryId, text: m.text })), async (entryId) => {\n        done();\n        try {\n          const result = await this.runtimeHost.fork(entryId);\n          if (result.cancelled) {\n            this.ui.requestRender();\n            return;\n          }\n          this.editor.setText(result.selectedText ?? \"\");\n          this.showStatus(\"Forked to new session\");\n        } catch (error) {\n          this.showError(error instanceof Error ? error.message : String(error));\n        }\n      }, () => {\n        done();\n        this.ui.requestRender();\n      }, initialSelectedId);\n      return { component: selector, focus: selector.getMessageList() };\n    });\n  }\n  async handleCloneCommand() {\n    const leafId = this.sessionManager.getLeafId();\n    if (!leafId) {\n      this.showStatus(\"Nothing to clone yet\");\n      return;\n    }\n    try {\n      const result = await this.runtimeHost.fork(leafId, { position: \"at\" });\n      if (result.cancelled) {\n        this.ui.requestRender();\n        return;\n      }\n      this.editor.setText(\"\");\n      this.showStatus(\"Cloned to new session\");\n    } catch (error) {\n      this.showError(error instanceof Error ? error.message : String(error));\n    }\n  }\n  showTreeSelector(initialSelectedId) {\n    const tree = this.sessionManager.getTree();\n    const realLeafId = this.sessionManager.getLeafId();\n    const initialFilterMode = this.settingsManager.getTreeFilterMode();\n    if (tree.length === 0) {\n      this.showStatus(\"No entries in session\");\n      return;\n    }\n    this.showSelector((done) => {\n      const selector = new TreeSelectorComponent(tree, realLeafId, this.ui.terminal.rows, async (entryId) => {\n        if (entryId === this.sessionManager.getLeafId()) {\n          done();\n          this.showStatus(\"Already at this point\");\n          return;\n        }\n        done();\n        let wantsSummary = false;\n        let customInstructions;\n        if (!this.settingsManager.getBranchSummarySkipPrompt()) {\n          while (true) {\n            const summaryChoice = await this.showExtensionSelector(\"Summarize branch?\", [\n              \"No summary\",\n              \"Summarize\",\n              \"Summarize with custom prompt\"\n            ]);\n            if (summaryChoice === void 0) {\n              this.showTreeSelector(entryId);\n              return;\n            }\n            wantsSummary = summaryChoice !== \"No summary\";\n            if (summaryChoice === \"Summarize with custom prompt\") {\n              customInstructions = await this.showExtensionEditor(\"Custom summarization instructions\");\n              if (customInstructions === void 0) {\n                continue;\n              }\n            }\n            break;\n          }\n        }\n        if (this.session.isStreaming) {\n          this.restoreQueuedMessagesToEditor();\n          await this.session.abort();\n        }\n        let showingSummaryIndicator = false;\n        const originalOnEscape = this.defaultEditor.onEscape;\n        if (wantsSummary) {\n          this.defaultEditor.onEscape = () => {\n            this.session.abortBranchSummary();\n          };\n          this.chatContainer.addChild(new Spacer(1));\n          this.showStatusIndicator(new BranchSummaryStatusIndicator(this.ui));\n          showingSummaryIndicator = true;\n          this.ui.requestRender();\n        }\n        try {\n          const result = await this.session.navigateTree(entryId, {\n            summarize: wantsSummary,\n            customInstructions\n          });\n          if (result.aborted) {\n            this.showStatus(\"Branch summarization cancelled\");\n            this.showTreeSelector(entryId);\n            return;\n          }\n          if (result.cancelled) {\n            this.showStatus(\"Navigation cancelled\");\n            return;\n          }\n          this.chatContainer.clear();\n          this.renderInitialMessages();\n          if (result.editorText && !this.editor.getText().trim()) {\n            this.editor.setText(result.editorText);\n          }\n          this.showStatus(\"Navigated to selected point\");\n          void this.flushCompactionQueue({ willRetry: false });\n        } catch (error) {\n          this.showError(error instanceof Error ? error.message : String(error));\n        } finally {\n          if (showingSummaryIndicator) {\n            this.clearStatusIndicator(\"branchSummary\");\n          }\n          this.defaultEditor.onEscape = originalOnEscape;\n        }\n      }, () => {\n        done();\n        this.ui.requestRender();\n      }, (entryId, label) => {\n        this.sessionManager.appendLabelChange(entryId, label);\n        this.ui.requestRender();\n      }, initialSelectedId, initialFilterMode);\n      selector.onCopy = async (text) => {\n        if (!text) {\n          this.showError(\"Selected entry has no text to copy\");\n          return;\n        }\n        try {\n          await copyToClipboard(text);\n          this.showStatus(\"Copied selected message to clipboard\");\n        } catch (error) {\n          this.showError(error instanceof Error ? error.message : String(error));\n        }\n      };\n      return { component: selector, focus: selector };\n    });\n  }\n  showSessionSelector() {\n    this.showSelector((done) => {\n      const selector = new SessionSelectorComponent((onProgress) => SessionManager.list(this.sessionManager.getCwd(), this.sessionManager.getSessionDir(), onProgress), (onProgress) => this.sessionManager.usesDefaultSessionDir() ? SessionManager.listAll(onProgress) : SessionManager.listAll(this.sessionManager.getSessionDir(), onProgress), async (sessionPath) => {\n        done();\n        await this.handleResumeSession(sessionPath);\n      }, () => {\n        done();\n        this.ui.requestRender();\n      }, () => {\n        void this.shutdown();\n      }, () => this.ui.requestRender(), {\n        renameSession: async (sessionFilePath, nextName) => {\n          const next = (nextName ?? \"\").trim();\n          if (!next)\n            return;\n          const mgr = SessionManager.open(sessionFilePath);\n          mgr.appendSessionInfo(next);\n        },\n        showRenameHint: true,\n        keybindings: this.keybindings\n      }, this.sessionManager.getSessionFile());\n      return { component: selector, focus: selector };\n    });\n  }\n  async handleResumeSession(sessionPath, options) {\n    this.clearStatusIndicator();\n    try {\n      const result = await this.runtimeHost.switchSession(sessionPath, {\n        withSession: options?.withSession,\n        projectTrustContextFactory: (cwd) => this.createProjectTrustContext(cwd)\n      });\n      if (result.cancelled) {\n        return result;\n      }\n      this.showStatus(\"Resumed session\");\n      return result;\n    } catch (error) {\n      if (error instanceof MissingSessionCwdError) {\n        const selectedCwd = await this.promptForMissingSessionCwd(error);\n        if (!selectedCwd) {\n          this.showStatus(\"Resume cancelled\");\n          return { cancelled: true };\n        }\n        const result = await this.runtimeHost.switchSession(sessionPath, {\n          cwdOverride: selectedCwd,\n          withSession: options?.withSession,\n          projectTrustContextFactory: (cwd) => this.createProjectTrustContext(cwd)\n        });\n        if (result.cancelled) {\n          return result;\n        }\n        this.showStatus(\"Resumed session in current cwd\");\n        return result;\n      }\n      return this.handleFatalRuntimeError(\"Failed to resume session\", error);\n    }\n  }\n  getLoginProviderOptions(authType) {\n    const options = [];\n    for (const provider of this.session.modelRuntime.getProviders()) {\n      const authStatus = this.session.modelRuntime.getProviderAuthStatus(provider.id);\n      const status = authStatus.configured ? {\n        type: this.session.modelRuntime.isUsingOAuth(provider.id) ? \"oauth\" : \"api_key\",\n        source: authStatus.label ?? authStatus.source\n      } : void 0;\n      if ((!authType || authType === \"oauth\") && provider.auth.oauth) {\n        options.push({\n          id: provider.id,\n          name: provider.name,\n          authType: \"oauth\",\n          method: provider.auth.oauth,\n          status\n        });\n      }\n      if ((!authType || authType === \"api_key\") && provider.auth.apiKey) {\n        options.push({\n          id: provider.id,\n          name: provider.name,\n          authType: \"api_key\",\n          method: provider.auth.apiKey,\n          status\n        });\n      }\n    }\n    return options.sort((a, b) => a.name.localeCompare(b.name));\n  }\n  async getLogoutProviderOptions() {\n    return (await this.session.modelRuntime.listCredentials({ signal: AbortSignal.timeout(15e3) })).map(({ providerId, type }) => ({\n      id: providerId,\n      name: this.session.modelRuntime.getProvider(providerId)?.name ?? providerId,\n      authType: type,\n      status: { type, source: \"stored credential\" }\n    })).sort((a, b) => a.name.localeCompare(b.name));\n  }\n  findLoginProviderOptions(providerRef) {\n    const normalizedProviderRef = providerRef.trim().toLowerCase();\n    if (!normalizedProviderRef) {\n      return [];\n    }\n    return this.getLoginProviderOptions().filter((provider) => provider.id.toLowerCase() === normalizedProviderRef || provider.name.toLowerCase() === normalizedProviderRef);\n  }\n  async handleLoginCommand(providerRef) {\n    if (!providerRef) {\n      this.showLoginAuthTypeSelector();\n      return;\n    }\n    const providerOptions = this.findLoginProviderOptions(providerRef);\n    if (providerOptions.length === 1) {\n      await this.startProviderLogin(providerOptions[0]);\n      return;\n    }\n    if (providerOptions.length > 1) {\n      const providerIds = new Set(providerOptions.map((provider) => provider.id));\n      if (providerIds.size === 1) {\n        this.showLoginAuthTypeSelector(providerOptions);\n        return;\n      }\n    }\n    this.showLoginProviderSelector(void 0, providerRef);\n  }\n  async startProviderLogin(providerOption) {\n    if (providerOption.authType === \"oauth\") {\n      await this.showLoginDialog(providerOption.id, providerOption.name);\n    } else if (providerOption.method?.login) {\n      await this.showApiKeyLoginDialog(providerOption.id, providerOption.name);\n    } else {\n      this.showAmbientAuthDialog(providerOption);\n    }\n  }\n  showLoginAuthTypeSelector(providerOptions) {\n    const oauthProvider = providerOptions?.find((provider) => provider.authType === \"oauth\");\n    const oauthLoginLabel = oauthProvider?.method && \"loginLabel\" in oauthProvider.method ? oauthProvider.method.loginLabel : void 0;\n    const subscriptionLabel = oauthLoginLabel ?? \"Sign in with an account\";\n    const apiKeyLabel = \"Sign in with an API key\";\n    const availableAuthTypes = providerOptions ? new Set(providerOptions.map((provider) => provider.authType)) : /* @__PURE__ */ new Set([\"oauth\", \"api_key\"]);\n    const options = [];\n    if (availableAuthTypes.has(\"oauth\")) {\n      options.push(subscriptionLabel);\n    }\n    if (availableAuthTypes.has(\"api_key\")) {\n      options.push(apiKeyLabel);\n    }\n    if (options.length === 0) {\n      this.showStatus(\"No login methods available.\");\n      return;\n    }\n    if (providerOptions && options.length === 1) {\n      const providerOption = providerOptions[0];\n      if (providerOption) {\n        void this.startProviderLogin(providerOption);\n      }\n      return;\n    }\n    const title = providerOptions?.[0] ? `Select authentication method for ${providerOptions[0].name}:` : \"Select authentication method:\";\n    this.showSelector((done) => {\n      const selector = new ExtensionSelectorComponent(title, options, (option) => {\n        done();\n        const authType = option === subscriptionLabel ? \"oauth\" : \"api_key\";\n        if (providerOptions) {\n          const providerOption = providerOptions.find((provider) => provider.authType === authType);\n          if (providerOption) {\n            void this.startProviderLogin(providerOption);\n          }\n          return;\n        }\n        this.showLoginProviderSelector(authType);\n      }, () => {\n        done();\n        this.ui.requestRender();\n      });\n      return { component: selector, focus: selector };\n    });\n  }\n  showLoginProviderSelector(authType, initialSearchInput) {\n    const providerOptions = this.getLoginProviderOptions(authType);\n    if (providerOptions.length === 0) {\n      const message = authType === \"oauth\" ? \"No subscription providers available.\" : authType === \"api_key\" ? \"No API key providers available.\" : \"No login providers available.\";\n      this.showStatus(message);\n      return;\n    }\n    this.showSelector((done) => {\n      const selector = new OAuthSelectorComponent(\"login\", providerOptions, async (providerId, selectedAuthType) => {\n        done();\n        const providerOption = providerOptions.find((provider) => provider.id === providerId && provider.authType === selectedAuthType);\n        if (!providerOption) {\n          return;\n        }\n        await this.startProviderLogin(providerOption);\n      }, () => {\n        done();\n        if (authType) {\n          this.showLoginAuthTypeSelector();\n        } else {\n          this.ui.requestRender();\n        }\n      }, initialSearchInput);\n      return { component: selector, focus: selector };\n    });\n  }\n  async showOAuthSelector(mode) {\n    if (mode === \"login\") {\n      this.showLoginAuthTypeSelector();\n      return;\n    }\n    let providerOptions;\n    try {\n      providerOptions = await this.getLogoutProviderOptions();\n    } catch (error) {\n      this.showError(`Could not read stored credentials: ${error instanceof Error ? error.message : String(error)}`);\n      return;\n    }\n    if (providerOptions.length === 0) {\n      this.showStatus(\"No stored credentials to remove. /logout only removes credentials saved by /login; environment variables and models.json config are unchanged.\");\n      return;\n    }\n    this.showSelector((done) => {\n      const selector = new OAuthSelectorComponent(mode, providerOptions, async (providerId) => {\n        done();\n        const providerOption = providerOptions.find((provider) => provider.id === providerId);\n        if (!providerOption) {\n          return;\n        }\n        try {\n          await this.session.modelRuntime.logout(providerOption.id, {\n            signal: AbortSignal.timeout(15e3)\n          });\n          await this.updateAvailableProviderCount();\n          const message = providerOption.authType === \"oauth\" ? `Logged out of ${providerOption.name}` : `Removed stored API key for ${providerOption.name}. Environment variables and models.json config are unchanged.`;\n          this.showStatus(message);\n        } catch (error) {\n          const message = error instanceof Error ? error.message : String(error);\n          this.showError(error instanceof CredentialSynchronizationError ? `Credentials removed for ${providerOption.name}, but local model state could not be synchronized: ${message}` : `Logout failed: ${message}`);\n        }\n      }, () => {\n        done();\n        this.ui.requestRender();\n      });\n      return { component: selector, focus: selector };\n    });\n  }\n  async completeProviderAuthentication(providerId, providerName, authType, previousModel) {\n    const actionLabel = authType === \"oauth\" ? `Logged in to ${providerName}` : `Saved API key for ${providerName}`;\n    let selectedModel;\n    let selectionError;\n    if (isUnknownModel(previousModel)) {\n      const availableModels = this.session.modelRuntime.getAvailableSnapshot();\n      const providerModels = availableModels.filter((model) => model.provider === providerId);\n      if (!hasDefaultModelProvider(providerId)) {\n        selectionError = `${actionLabel}, but no default model is configured for provider \"${providerId}\". Use /model to select a model.`;\n      } else if (providerModels.length === 0) {\n        selectionError = `${actionLabel}, but no models are available for that provider. Use /model to select a model.`;\n      } else {\n        const defaultModelId = defaultModelPerProvider[providerId];\n        selectedModel = providerModels.find((model) => model.id === defaultModelId);\n        if (!selectedModel) {\n          selectionError = `${actionLabel}, but its default model \"${defaultModelId}\" is not available. Use /model to select a model.`;\n        } else {\n          try {\n            await this.session.setModel(selectedModel);\n          } catch (error) {\n            selectedModel = void 0;\n            const errorMessage2 = error instanceof Error ? error.message : String(error);\n            selectionError = `${actionLabel}, but selecting its default model failed: ${errorMessage2}. Use /model to select a model.`;\n          }\n        }\n      }\n    }\n    await this.updateAvailableProviderCount();\n    this.footer.invalidate();\n    this.updateEditorBorderColor();\n    if (selectedModel) {\n      this.showStatus(`${actionLabel}. Selected ${selectedModel.id}. Credentials saved to ${getAuthPath()}`);\n      void this.maybeWarnAboutAnthropicSubscriptionAuth(selectedModel);\n      this.checkDaxnutsEasterEgg(selectedModel);\n    } else {\n      this.showStatus(`${actionLabel}. Credentials saved to ${getAuthPath()}`);\n      if (selectionError) {\n        this.showError(selectionError);\n      } else {\n        void this.maybeWarnAboutAnthropicSubscriptionAuth();\n      }\n    }\n    const controller = new AbortController();\n    const timeout = setTimeout(() => controller.abort(), 15e3);\n    void this.session.modelRuntime.refresh({ providers: [providerId], signal: controller.signal }).then((result) => {\n      if (result.aborted) {\n        this.showWarning(`${actionLabel}, but its model catalog refresh timed out; using cached models.`);\n      } else if (result.errors.size > 0) {\n        this.showWarning(`${actionLabel}, but its model catalog could not be refreshed; using cached models.`);\n      }\n      this.updateAvailableProviderCount();\n      this.footer.invalidate();\n      this.ui.requestRender();\n    }).catch((error) => {\n      this.showWarning(`${actionLabel}, but its model catalog could not be refreshed: ${error instanceof Error ? error.message : String(error)}`);\n    }).finally(() => clearTimeout(timeout));\n  }\n  showAmbientAuthDialog(providerOption) {\n    const restoreEditor = () => {\n      this.editorContainer.clear();\n      this.editorContainer.addChild(this.editor);\n      this.ui.setFocus(this.editor);\n      this.ui.requestRender();\n    };\n    const dialog = new LoginDialogComponent(this.ui, providerOption.id, () => restoreEditor(), providerOption.name, `${providerOption.name} setup`);\n    dialog.showInfo(`${providerOption.method?.name ?? \"Authentication\"} is configured outside ${APP_NAME}.`, [], true);\n    this.editorContainer.clear();\n    this.editorContainer.addChild(dialog);\n    this.ui.setFocus(dialog);\n    this.ui.requestRender();\n  }\n  async showApiKeyLoginDialog(providerId, providerName) {\n    const previousModel = this.session.model;\n    const dialog = new LoginDialogComponent(this.ui, providerId, (_success, _message) => {\n    }, providerName);\n    if (providerId === \"amazon-bedrock\") {\n      dialog.showDetails([\n        theme.fg(\"text\", \"You can also use an AWS profile, IAM keys, or role-based credentials.\"),\n        theme.fg(\"muted\", \"See:\"),\n        theme.fg(\"accent\", `  ${path10.join(getDocsPath(), \"providers.md\")}`)\n      ]);\n    }\n    this.editorContainer.clear();\n    this.editorContainer.addChild(dialog);\n    this.ui.setFocus(dialog);\n    this.ui.requestRender();\n    const restoreEditor = () => {\n      this.editorContainer.clear();\n      this.editorContainer.addChild(this.editor);\n      this.ui.setFocus(this.editor);\n      this.ui.requestRender();\n    };\n    try {\n      await this.loginProvider(dialog, providerId, \"api_key\");\n      restoreEditor();\n      await this.completeProviderAuthentication(providerId, providerName, \"api_key\", previousModel);\n    } catch (error) {\n      restoreEditor();\n      const errorMsg = error instanceof Error ? error.message : String(error);\n      if (error instanceof CredentialSynchronizationError) {\n        this.showError(`Saved API key for ${providerName}, but local model state could not be synchronized: ${errorMsg}`);\n      } else if (errorMsg !== \"Login cancelled\") {\n        this.showError(`Failed to save API key for ${providerName}: ${errorMsg}`);\n      }\n    }\n  }\n  showAuthSelect(dialog, prompt) {\n    return new Promise((resolve15, reject) => {\n      const restoreDialog = () => {\n        this.editorContainer.clear();\n        this.editorContainer.addChild(dialog);\n        this.ui.setFocus(dialog);\n        this.ui.requestRender();\n      };\n      const labels = prompt.options.map((option) => option.label);\n      const selector = new ExtensionSelectorComponent(prompt.message, labels, (optionLabel) => {\n        restoreDialog();\n        const id = prompt.options.find((option) => option.label === optionLabel)?.id;\n        if (id)\n          resolve15(id);\n        else\n          reject(new Error(\"Login cancelled\"));\n      }, () => {\n        restoreDialog();\n        reject(new Error(\"Login cancelled\"));\n      });\n      this.editorContainer.clear();\n      this.editorContainer.addChild(selector);\n      this.ui.setFocus(selector);\n      this.ui.requestRender();\n    });\n  }\n  async showAuthPrompt(dialog, prompt) {\n    let response;\n    if (prompt.type === \"select\") {\n      response = this.showAuthSelect(dialog, prompt);\n    } else if (prompt.type === \"manual_code\") {\n      response = dialog.showManualInput(prompt.message);\n    } else {\n      response = dialog.showPrompt(prompt.message, prompt.placeholder);\n    }\n    if (!prompt.signal)\n      return response;\n    if (prompt.signal.aborted)\n      throw new Error(\"Login cancelled\");\n    const signal = prompt.signal;\n    let onAbort;\n    const aborted = new Promise((_resolve, reject) => {\n      onAbort = () => reject(new Error(\"Login cancelled\"));\n      signal.addEventListener(\"abort\", onAbort, { once: true });\n    });\n    try {\n      return await Promise.race([response, aborted]);\n    } finally {\n      if (onAbort)\n        signal.removeEventListener(\"abort\", onAbort);\n    }\n  }\n  notifyAuthDialog(dialog, event) {\n    if (event.type === \"auth_url\") {\n      dialog.showAuth(event.url, event.instructions);\n    } else if (event.type === \"device_code\") {\n      dialog.showDeviceCode(event);\n      dialog.showWaiting(\"Waiting for authentication...\");\n    } else if (event.type === \"info\") {\n      dialog.showInfo(event.message, event.links);\n    } else {\n      dialog.showProgress(event.message);\n    }\n  }\n  async loginProvider(dialog, providerId, method) {\n    await this.session.modelRuntime.login(providerId, method, {\n      signal: dialog.signal,\n      prompt: (prompt) => this.showAuthPrompt(dialog, prompt),\n      notify: (event) => this.notifyAuthDialog(dialog, event)\n    });\n  }\n  async showLoginDialog(providerId, providerName) {\n    const previousModel = this.session.model;\n    const dialog = new LoginDialogComponent(this.ui, providerId, (_success, _message) => {\n    }, providerName);\n    this.editorContainer.clear();\n    this.editorContainer.addChild(dialog);\n    this.ui.setFocus(dialog);\n    this.ui.requestRender();\n    const restoreEditor = () => {\n      this.editorContainer.clear();\n      this.editorContainer.addChild(this.editor);\n      this.ui.setFocus(this.editor);\n      this.ui.requestRender();\n    };\n    try {\n      await this.loginProvider(dialog, providerId, \"oauth\");\n      restoreEditor();\n      await this.completeProviderAuthentication(providerId, providerName, \"oauth\", previousModel);\n    } catch (error) {\n      restoreEditor();\n      const errorMsg = error instanceof Error ? error.message : String(error);\n      if (error instanceof CredentialSynchronizationError) {\n        this.showError(`Logged in to ${providerName}, but local model state could not be synchronized: ${errorMsg}`);\n      } else if (errorMsg !== \"Login cancelled\") {\n        this.showError(`Failed to login to ${providerName}: ${errorMsg}`);\n      }\n    }\n  }\n  // =========================================================================\n  // Command handlers\n  // =========================================================================\n  async handleReloadCommand() {\n    if (this.session.isStreaming) {\n      this.showWarning(\"Wait for the current response to finish before reloading.\");\n      return;\n    }\n    if (this.session.isCompacting) {\n      this.showWarning(\"Wait for compaction to finish before reloading.\");\n      return;\n    }\n    this.resetExtensionUI();\n    const reloadBox = new Container();\n    const borderColor = (s) => theme.fg(\"border\", s);\n    reloadBox.addChild(new DynamicBorder(borderColor));\n    reloadBox.addChild(new Spacer(1));\n    reloadBox.addChild(new Text(theme.fg(\"muted\", \"Reloading keybindings, extensions, skills, prompts, themes, and context files...\"), 1, 0));\n    reloadBox.addChild(new Spacer(1));\n    reloadBox.addChild(new DynamicBorder(borderColor));\n    const previousEditor = this.editor;\n    this.editorContainer.clear();\n    this.editorContainer.addChild(reloadBox);\n    this.ui.setFocus(reloadBox);\n    this.ui.requestRender(true);\n    await new Promise((resolve15) => process.nextTick(resolve15));\n    const dismissReloadBox = (editor) => {\n      this.editorContainer.clear();\n      this.editorContainer.addChild(editor);\n      this.ui.setFocus(editor);\n      this.ui.requestRender();\n    };\n    let chatRestoredBeforeSessionStart = false;\n    let reloadBoxDismissed = false;\n    const restoreChatBeforeSessionStart = () => {\n      if (chatRestoredBeforeSessionStart) {\n        return;\n      }\n      this.hideThinkingBlock = this.settingsManager.getHideThinkingBlock();\n      this.outputPad = this.settingsManager.getOutputPad();\n      this.rebuildChatFromMessages();\n      chatRestoredBeforeSessionStart = true;\n    };\n    try {\n      await this.session.reload({ beforeSessionStart: restoreChatBeforeSessionStart });\n      restoreChatBeforeSessionStart();\n      this.keybindings.reload();\n      const activeHeader = this.customHeader ?? this.builtInHeader;\n      if (isExpandable(activeHeader)) {\n        activeHeader.setExpanded(this.toolOutputExpanded);\n      }\n      setRegisteredThemes(this.session.resourceLoader.getThemes().themes);\n      await this.themeController.applyFromSettings();\n      this.applyRuntimeSettings();\n      this.setupAutocompleteProvider();\n      const runner = this.session.extensionRunner;\n      this.setupExtensionShortcuts(runner);\n      this.showLoadedResources({\n        force: false,\n        showDiagnosticsWhenQuiet: true\n      });\n      const savedImplicitProjectTrust = this.maybeSaveImplicitProjectTrustAfterReload();\n      const modelsJsonError = this.session.modelRuntime.getError();\n      if (modelsJsonError) {\n        this.showError(`models.json error: ${modelsJsonError}`);\n      }\n      this.showStatus(savedImplicitProjectTrust ? \"Reloaded keybindings, extensions, skills, prompts, themes, and context files; saved project trust\" : \"Reloaded keybindings, extensions, skills, prompts, themes, and context files\");\n      dismissReloadBox(this.editor);\n      reloadBoxDismissed = true;\n    } catch (error) {\n      if (!reloadBoxDismissed) {\n        dismissReloadBox(previousEditor);\n      }\n      this.showError(`Reload failed: ${error instanceof Error ? error.message : String(error)}`);\n    }\n  }\n  async handleExportCommand(text) {\n    const outputPath = this.getPathCommandArgument(text, \"/export\");\n    try {\n      if (outputPath?.endsWith(\".jsonl\")) {\n        const filePath = this.session.exportToJsonl(outputPath);\n        this.showStatus(`Session exported to: ${filePath}`);\n      } else {\n        const filePath = await this.session.exportToHtml(outputPath, {\n          themeName: theme.name\n        });\n        this.showStatus(`Session exported to: ${filePath}`);\n      }\n    } catch (error) {\n      this.showError(`Failed to export session: ${error instanceof Error ? error.message : \"Unknown error\"}`);\n    }\n  }\n  getPathCommandArgument(text, command) {\n    if (text === command) {\n      return void 0;\n    }\n    if (!text.startsWith(`${command} `)) {\n      return void 0;\n    }\n    const argsString = text.slice(command.length + 1).trimStart();\n    if (!argsString) {\n      return void 0;\n    }\n    const firstChar = argsString[0];\n    if (firstChar === '\"' || firstChar === \"'\") {\n      const closingQuoteIndex = argsString.indexOf(firstChar, 1);\n      if (closingQuoteIndex < 0) {\n        return void 0;\n      }\n      return argsString.slice(1, closingQuoteIndex);\n    }\n    const firstWhitespaceIndex = argsString.search(/\\s/);\n    if (firstWhitespaceIndex < 0) {\n      return argsString;\n    }\n    return argsString.slice(0, firstWhitespaceIndex);\n  }\n  async handleImportCommand(text) {\n    const inputPath = this.getPathCommandArgument(text, \"/import\");\n    if (!inputPath) {\n      this.showError(\"Usage: /import <path.jsonl>\");\n      return;\n    }\n    const confirmed = await this.showExtensionConfirm(\"Import session\", `Replace current session with ${inputPath}?`);\n    if (!confirmed) {\n      this.showStatus(\"Import cancelled\");\n      return;\n    }\n    try {\n      this.clearStatusIndicator();\n      const result = await this.runtimeHost.importFromJsonl(inputPath);\n      if (result.cancelled) {\n        this.showStatus(\"Import cancelled\");\n        return;\n      }\n      this.showStatus(`Session imported from: ${inputPath}`);\n    } catch (error) {\n      if (error instanceof MissingSessionCwdError) {\n        const selectedCwd = await this.promptForMissingSessionCwd(error);\n        if (!selectedCwd) {\n          this.showStatus(\"Import cancelled\");\n          return;\n        }\n        const result = await this.runtimeHost.importFromJsonl(inputPath, selectedCwd);\n        if (result.cancelled) {\n          this.showStatus(\"Import cancelled\");\n          return;\n        }\n        this.showStatus(`Session imported from: ${inputPath}`);\n        return;\n      }\n      if (error instanceof SessionImportFileNotFoundError) {\n        this.showError(`Failed to import session: ${error.message}`);\n        return;\n      }\n      await this.handleFatalRuntimeError(\"Failed to import session\", error);\n    }\n  }\n  async handleShareCommand() {\n    try {\n      const authResult = spawnSync7(\"gh\", [\"auth\", \"status\"], { encoding: \"utf-8\" });\n      if (authResult.status !== 0) {\n        this.showError(\"GitHub CLI is not logged in. Run 'gh auth login' first.\");\n        return;\n      }\n    } catch {\n      this.showError(\"GitHub CLI (gh) is not installed. Install it from https://cli.github.com/\");\n      return;\n    }\n    const tmpFile = path10.join(os4.tmpdir(), \"session.html\");\n    try {\n      await this.session.exportToHtml(tmpFile, { themeName: theme.name });\n    } catch (error) {\n      this.showError(`Failed to export session: ${error instanceof Error ? error.message : \"Unknown error\"}`);\n      return;\n    }\n    const loader = new BorderedLoader(this.ui, theme, \"Creating gist...\");\n    this.editorContainer.clear();\n    this.editorContainer.addChild(loader);\n    this.ui.setFocus(loader);\n    this.ui.requestRender();\n    const restoreEditor = () => {\n      loader.dispose();\n      this.editorContainer.clear();\n      this.editorContainer.addChild(this.editor);\n      this.ui.setFocus(this.editor);\n      try {\n        fs6.unlinkSync(tmpFile);\n      } catch {\n      }\n    };\n    let proc = null;\n    loader.onAbort = () => {\n      proc?.kill();\n      restoreEditor();\n      this.showStatus(\"Share cancelled\");\n    };\n    try {\n      const result = await new Promise((resolve15) => {\n        proc = spawn9(\"gh\", [\"gist\", \"create\", \"--public=false\", tmpFile]);\n        let stdout = \"\";\n        let stderr = \"\";\n        proc.stdout?.on(\"data\", (data) => {\n          stdout += data.toString();\n        });\n        proc.stderr?.on(\"data\", (data) => {\n          stderr += data.toString();\n        });\n        proc.on(\"close\", (code) => resolve15({ stdout, stderr, code }));\n      });\n      if (loader.signal.aborted)\n        return;\n      restoreEditor();\n      if (result.code !== 0) {\n        const errorMsg = result.stderr?.trim() || \"Unknown error\";\n        this.showError(`Failed to create gist: ${errorMsg}`);\n        return;\n      }\n      const gistUrl = result.stdout?.trim();\n      const gistId = gistUrl?.split(\"/\").pop();\n      if (!gistId) {\n        this.showError(\"Failed to parse gist ID from gh output\");\n        return;\n      }\n      const previewUrl = getShareViewerUrl(gistId);\n      this.showStatus(`Share URL: ${previewUrl}\nGist: ${gistUrl}`);\n    } catch (error) {\n      if (!loader.signal.aborted) {\n        restoreEditor();\n        this.showError(`Failed to create gist: ${error instanceof Error ? error.message : \"Unknown error\"}`);\n      }\n    }\n  }\n  async handleCopyCommand(options = {}) {\n    const text = this.session.getLastAssistantText();\n    if (!text) {\n      this.showError(\"No agent messages to copy yet.\");\n      return;\n    }\n    try {\n      await copyToClipboard(text);\n      if (options.flashConfirmation && this.ui instanceof TuiAltScreen) {\n        this.ui.flash(\"Copied!\");\n      } else {\n        this.showStatus(\"Copied last agent message to clipboard\");\n      }\n    } catch (error) {\n      this.showError(error instanceof Error ? error.message : String(error));\n    }\n  }\n  handleNameCommand(text) {\n    const name = text.replace(/^\\/name\\s*/, \"\").trim();\n    if (!name) {\n      const currentName = this.sessionManager.getSessionName();\n      if (currentName) {\n        this.chatContainer.addChild(new Spacer(1));\n        this.chatContainer.addChild(new Text(theme.fg(\"dim\", `Session name: ${currentName}`), 1, 0));\n      } else {\n        this.showWarning(\"Usage: /name <name>\");\n      }\n      this.ui.requestRender();\n      return;\n    }\n    this.session.setSessionName(name);\n    const sessionName = this.sessionManager.getSessionName();\n    if (sessionName !== name) {\n      this.showWarning(`Session name was normalized from ${JSON.stringify(name)} to ${JSON.stringify(sessionName)}`);\n    }\n    this.chatContainer.addChild(new Spacer(1));\n    this.chatContainer.addChild(new Text(theme.fg(\"dim\", `Session name set: ${sessionName ?? name}`), 1, 0));\n    this.ui.requestRender();\n  }\n  handleSessionCommand() {\n    const stats = this.session.getSessionStats();\n    const sessionName = this.sessionManager.getSessionName();\n    const entries = this.sessionManager.getEntries();\n    const cacheWaste = computeCacheWaste(entries, this.session.modelRuntime);\n    const usageBreakdown = getUsageCostBreakdown(entries);\n    let info = `${theme.bold(\"Session Info\")}\n\n`;\n    if (sessionName) {\n      info += `${theme.fg(\"dim\", \"Name:\")} ${sessionName}\n`;\n    }\n    info += `${theme.fg(\"dim\", \"File:\")} ${stats.sessionFile ?? \"In-memory\"}\n`;\n    info += `${theme.fg(\"dim\", \"ID:\")} ${stats.sessionId}\n\n`;\n    info += `${theme.bold(\"Messages\")}\n`;\n    info += `${theme.fg(\"dim\", \"Total:\")} ${stats.totalMessages}\n`;\n    info += `${theme.fg(\"dim\", \"User:\")} ${stats.userMessages}\n`;\n    info += `${theme.fg(\"dim\", \"Assistant:\")} ${stats.assistantMessages}\n`;\n    info += `${theme.fg(\"dim\", \"Tools:\")} ${stats.toolCalls} calls, ${stats.toolResults} results\n\n`;\n    info += `${theme.bold(\"Tokens\")}\n`;\n    const { input, cacheRead, cacheWrite } = stats.tokens;\n    const promptTokens = input + cacheRead + cacheWrite;\n    info += `${theme.fg(\"dim\", \"Input:\")} ${promptTokens.toLocaleString()}\n`;\n    if (promptTokens > 0 && (cacheRead > 0 || cacheWrite > 0)) {\n      const hitRate = theme.fg(\"dim\", `(${(cacheRead / promptTokens * 100).toFixed(1)}%)`);\n      info += `  ${theme.fg(\"dim\", \"Cached:\")} ${cacheRead.toLocaleString()} ${hitRate}\n`;\n      const written = cacheWrite > 0 ? ` ${theme.fg(\"dim\", `(${cacheWrite.toLocaleString()} written to cache)`)}` : \"\";\n      info += `  ${theme.fg(\"dim\", \"Uncached:\")} ${(input + cacheWrite).toLocaleString()}${written}\n`;\n    }\n    info += `${theme.fg(\"dim\", \"Output:\")} ${stats.tokens.output.toLocaleString()}\n`;\n    info += `${theme.fg(\"dim\", \"Total:\")} ${stats.tokens.total.toLocaleString()}\n`;\n    if (stats.cost > 0 || cacheWaste.missedTokens > 0) {\n      info += `\n${theme.bold(\"Cost\")}\n`;\n      info += `${theme.fg(\"dim\", \"Total:\")} $${stats.cost.toFixed(3)}`;\n      if (usageBreakdown.length > 1) {\n        for (const entry of usageBreakdown) {\n          info += `\n  ${theme.fg(\"dim\", `${entry.key}:`)} $${entry.cost.toFixed(3)} ${theme.fg(\"dim\", `(${formatTokens(entry.tokens)} tokens)`)}`;\n        }\n      }\n      if (cacheWaste.missedTokens > 0) {\n        const missLabel = cacheWaste.missCount === 1 ? \"1 miss\" : `${cacheWaste.missCount} misses`;\n        const detail = `${cacheWaste.missedTokens.toLocaleString()} tokens, ${missLabel}`;\n        info += cacheWaste.missedCost >= 1e-4 ? `\n${theme.fg(\"dim\", \"Cache Re-billed:\")} $${cacheWaste.missedCost.toFixed(3)} ${theme.fg(\"dim\", `(${detail})`)}` : `\n${theme.fg(\"dim\", \"Cache Re-billed:\")} ${detail}`;\n      }\n    }\n    this.chatContainer.addChild(new Spacer(1));\n    this.chatContainer.addChild(new Text(info, 1, 0));\n    this.ui.requestRender();\n  }\n  handleChangelogCommand() {\n    const changelogPath = getChangelogPath();\n    const allEntries = parseChangelog(changelogPath);\n    const changelogMarkdown = allEntries.length > 0 ? allEntries.reverse().map((e) => normalizeChangelogLinks(e.content, e)).join(\"\\n\\n\") : \"No changelog entries found.\";\n    this.chatContainer.addChild(new Spacer(1));\n    this.chatContainer.addChild(new DynamicBorder());\n    this.chatContainer.addChild(new Text(theme.bold(theme.fg(\"accent\", \"What's New\")), 1, 0));\n    this.chatContainer.addChild(new Spacer(1));\n    this.chatContainer.addChild(new Markdown(changelogMarkdown, 1, 1, this.getMarkdownThemeWithSettings()));\n    this.chatContainer.addChild(new DynamicBorder());\n    this.ui.requestRender();\n  }\n  /**\n   * Get capitalized display string for an app keybinding action.\n   */\n  getAppKeyDisplay(action) {\n    return keyDisplayText(action);\n  }\n  /**\n   * Get capitalized display string for an editor keybinding action.\n   */\n  getEditorKeyDisplay(action) {\n    return keyDisplayText(action);\n  }\n  handleHotkeysCommand() {\n    const cursorUp = this.getEditorKeyDisplay(\"tui.editor.cursorUp\");\n    const cursorDown = this.getEditorKeyDisplay(\"tui.editor.cursorDown\");\n    const cursorLeft = this.getEditorKeyDisplay(\"tui.editor.cursorLeft\");\n    const cursorRight = this.getEditorKeyDisplay(\"tui.editor.cursorRight\");\n    const cursorWordLeft = this.getEditorKeyDisplay(\"tui.editor.cursorWordLeft\");\n    const cursorWordRight = this.getEditorKeyDisplay(\"tui.editor.cursorWordRight\");\n    const cursorLineStart = this.getEditorKeyDisplay(\"tui.editor.cursorLineStart\");\n    const cursorLineEnd = this.getEditorKeyDisplay(\"tui.editor.cursorLineEnd\");\n    const jumpForward = this.getEditorKeyDisplay(\"tui.editor.jumpForward\");\n    const jumpBackward = this.getEditorKeyDisplay(\"tui.editor.jumpBackward\");\n    const pageUp = this.getEditorKeyDisplay(\"tui.editor.pageUp\");\n    const pageDown = this.getEditorKeyDisplay(\"tui.editor.pageDown\");\n    const submit = this.getEditorKeyDisplay(\"tui.input.submit\");\n    const newLine = this.getEditorKeyDisplay(\"tui.input.newLine\");\n    const deleteWordBackward = this.getEditorKeyDisplay(\"tui.editor.deleteWordBackward\");\n    const deleteWordForward = this.getEditorKeyDisplay(\"tui.editor.deleteWordForward\");\n    const deleteToLineStart = this.getEditorKeyDisplay(\"tui.editor.deleteToLineStart\");\n    const deleteToLineEnd = this.getEditorKeyDisplay(\"tui.editor.deleteToLineEnd\");\n    const yank = this.getEditorKeyDisplay(\"tui.editor.yank\");\n    const yankPop = this.getEditorKeyDisplay(\"tui.editor.yankPop\");\n    const undo = this.getEditorKeyDisplay(\"tui.editor.undo\");\n    const tab = this.getEditorKeyDisplay(\"tui.input.tab\");\n    const interrupt = this.getAppKeyDisplay(\"app.interrupt\");\n    const clear = this.getAppKeyDisplay(\"app.clear\");\n    const exit = this.getAppKeyDisplay(\"app.exit\");\n    const suspend = this.getAppKeyDisplay(\"app.suspend\");\n    const cycleThinkingLevel = this.getAppKeyDisplay(\"app.thinking.cycle\");\n    const cycleModelForward = this.getAppKeyDisplay(\"app.model.cycleForward\");\n    const selectModel = this.getAppKeyDisplay(\"app.model.select\");\n    const expandTools = this.getAppKeyDisplay(\"app.tools.expand\");\n    const toggleThinking = this.getAppKeyDisplay(\"app.thinking.toggle\");\n    const externalEditor = this.getAppKeyDisplay(\"app.editor.external\");\n    const cycleModelBackward = this.getAppKeyDisplay(\"app.model.cycleBackward\");\n    const copyMessage = this.getAppKeyDisplay(\"app.message.copy\");\n    const followUp = this.getAppKeyDisplay(\"app.message.followUp\");\n    const dequeue = this.getAppKeyDisplay(\"app.message.dequeue\");\n    const pasteImage = this.getAppKeyDisplay(\"app.clipboard.pasteImage\");\n    let hotkeys = `\n**Navigation**\n| Key | Action |\n|-----|--------|\n| \\`${cursorUp}\\` / \\`${cursorDown}\\` / \\`${cursorLeft}\\` / \\`${cursorRight}\\` | Move cursor / browse history |\n| \\`${cursorWordLeft}\\` / \\`${cursorWordRight}\\` | Move by word |\n| \\`${cursorLineStart}\\` | Start of line |\n| \\`${cursorLineEnd}\\` | End of line |\n| \\`${jumpForward}\\` | Jump forward to character |\n| \\`${jumpBackward}\\` | Jump backward to character |\n| \\`${pageUp}\\` / \\`${pageDown}\\` | Scroll by page |\n\n**Editing**\n| Key | Action |\n|-----|--------|\n| \\`${submit}\\` | Send message |\n| \\`${newLine}\\` | New line${process.platform === \"win32\" ? \" (Ctrl+Enter on Windows Terminal)\" : \"\"} |\n| \\`${deleteWordBackward}\\` | Delete word backwards |\n| \\`${deleteWordForward}\\` | Delete word forwards |\n| \\`${deleteToLineStart}\\` | Delete to start of line |\n| \\`${deleteToLineEnd}\\` | Delete to end of line |\n| \\`${yank}\\` | Paste the most-recently-deleted text |\n| \\`${yankPop}\\` | Cycle through the deleted text after pasting |\n| \\`${undo}\\` | Undo |\n\n**Other**\n| Key | Action |\n|-----|--------|\n| \\`${tab}\\` | Path completion / accept autocomplete |\n| \\`${interrupt}\\` | Cancel autocomplete / abort streaming |\n| \\`${clear}\\` | Clear editor (first) / exit (second) |\n| \\`${exit}\\` | Exit (when editor is empty) |\n| \\`${suspend}\\` | Suspend to background |\n| \\`${cycleThinkingLevel}\\` | Cycle thinking level |\n| \\`${cycleModelForward}\\` / \\`${cycleModelBackward}\\` | Cycle models |\n| \\`${selectModel}\\` | Open model selector |\n| \\`${expandTools}\\` | Toggle tool output expansion |\n| \\`${toggleThinking}\\` | Toggle thinking block visibility |\n| \\`${externalEditor}\\` | Edit message in external editor |\n| \\`${copyMessage}\\` | Copy last assistant message |\n| \\`${followUp}\\` | Queue follow-up message |\n| \\`${dequeue}\\` | Restore queued messages |\n| \\`${pasteImage}\\` | Paste image or text from clipboard |\n| \\`/\\` | Slash commands |\n| \\`!\\` | Run bash command |\n| \\`!!\\` | Run bash command (excluded from context) |\n`;\n    const extensionRunner = this.session.extensionRunner;\n    const shortcuts = extensionRunner.getShortcuts(this.keybindings.getEffectiveConfig());\n    if (shortcuts.size > 0) {\n      hotkeys += `\n**Extensions**\n| Key | Action |\n|-----|--------|\n`;\n      for (const [key, shortcut] of shortcuts) {\n        const description = shortcut.description ?? shortcut.extensionPath;\n        const keyDisplay = formatKeyText(key, { capitalize: true });\n        hotkeys += `| \\`${keyDisplay}\\` | ${description} |\n`;\n      }\n    }\n    this.chatContainer.addChild(new Spacer(1));\n    this.chatContainer.addChild(new DynamicBorder());\n    this.chatContainer.addChild(new Text(theme.bold(theme.fg(\"accent\", \"Keyboard Shortcuts\")), 1, 0));\n    this.chatContainer.addChild(new Spacer(1));\n    this.chatContainer.addChild(new Markdown(hotkeys.trim(), 1, 1, this.getMarkdownThemeWithSettings()));\n    this.chatContainer.addChild(new DynamicBorder());\n    this.ui.requestRender();\n  }\n  async handleClearCommand() {\n    this.clearStatusIndicator();\n    try {\n      const result = await this.runtimeHost.newSession();\n      if (result.cancelled) {\n        return;\n      }\n      this.chatContainer.addChild(new Spacer(1));\n      this.chatContainer.addChild(new Text(`${theme.fg(\"accent\", \"\\u2713 New session started\")}`, 1, 1));\n      this.ui.requestRender();\n    } catch (error) {\n      await this.handleFatalRuntimeError(\"Failed to create session\", error);\n    }\n  }\n  handleDebugCommand() {\n    const width = this.ui.terminal.columns;\n    const height = this.ui.terminal.rows;\n    const allLines = this.ui.render(width);\n    const debugLogPath = getDebugLogPath();\n    const debugData = [\n      `Debug output at ${(/* @__PURE__ */ new Date()).toISOString()}`,\n      `Terminal: ${width}x${height}`,\n      `Total lines: ${allLines.length}`,\n      \"\",\n      \"=== All rendered lines with visible widths ===\",\n      ...allLines.map((line, idx) => {\n        const vw = visibleWidth(line);\n        const escaped = JSON.stringify(line);\n        return `[${idx}] (w=${vw}) ${escaped}`;\n      }),\n      \"\",\n      \"=== Agent messages (JSONL) ===\",\n      ...this.session.messages.map((msg) => JSON.stringify(msg)),\n      \"\"\n    ].join(\"\\n\");\n    fs6.mkdirSync(path10.dirname(debugLogPath), { recursive: true });\n    fs6.writeFileSync(debugLogPath, debugData);\n    this.chatContainer.addChild(new Spacer(1));\n    this.chatContainer.addChild(new Text(`${theme.fg(\"accent\", \"\\u2713 Debug log written\")}\n${theme.fg(\"muted\", debugLogPath)}`, 1, 1));\n    this.ui.requestRender();\n  }\n  handleArminSaysHi() {\n    this.chatContainer.addChild(new Spacer(1));\n    this.chatContainer.addChild(new ArminComponent(this.ui));\n    this.ui.requestRender();\n  }\n  handleDementedDelves() {\n    this.chatContainer.addChild(new Spacer(1));\n    this.chatContainer.addChild(new EarendilAnnouncementComponent());\n    this.ui.requestRender();\n  }\n  handleDaxnuts() {\n    this.chatContainer.addChild(new Spacer(1));\n    this.chatContainer.addChild(new DaxnutsComponent(this.ui));\n    this.ui.requestRender();\n  }\n  checkDaxnutsEasterEgg(model) {\n    if (model.provider === \"opencode\" && model.id.toLowerCase().includes(\"kimi-k2.5\")) {\n      this.handleDaxnuts();\n    }\n  }\n  async handleBashCommand(command, excludeFromContext = false) {\n    const extensionRunner = this.session.extensionRunner;\n    const eventResult = await extensionRunner.emitUserBash({\n      type: \"user_bash\",\n      command,\n      excludeFromContext,\n      cwd: this.sessionManager.getCwd()\n    });\n    if (eventResult?.result) {\n      const result = eventResult.result;\n      this.bashComponent = new BashExecutionComponent(command, this.ui, excludeFromContext);\n      if (this.session.isStreaming) {\n        this.pendingMessagesContainer.addChild(this.bashComponent);\n        this.pendingBashComponents.push(this.bashComponent);\n      } else {\n        this.chatContainer.addChild(this.bashComponent);\n      }\n      if (result.output) {\n        this.bashComponent.appendOutput(result.output);\n      }\n      this.bashComponent.setComplete(result.exitCode, result.cancelled, result.truncated ? { truncated: true, content: result.output } : void 0, result.fullOutputPath);\n      this.session.recordBashResult(command, result, { excludeFromContext });\n      this.bashComponent = void 0;\n      this.ui.requestRender();\n      return;\n    }\n    const isDeferred = this.session.isStreaming;\n    this.bashComponent = new BashExecutionComponent(command, this.ui, excludeFromContext);\n    if (isDeferred) {\n      this.pendingMessagesContainer.addChild(this.bashComponent);\n      this.pendingBashComponents.push(this.bashComponent);\n    } else {\n      this.chatContainer.addChild(this.bashComponent);\n    }\n    this.ui.requestRender();\n    try {\n      const result = await this.session.executeBash(command, (chunk) => {\n        if (this.bashComponent) {\n          this.bashComponent.appendOutput(chunk);\n          this.ui.requestRender();\n        }\n      }, { excludeFromContext, operations: eventResult?.operations });\n      if (this.bashComponent) {\n        this.bashComponent.setComplete(result.exitCode, result.cancelled, result.truncated ? { truncated: true, content: result.output } : void 0, result.fullOutputPath);\n      }\n    } catch (error) {\n      if (this.bashComponent) {\n        this.bashComponent.setComplete(void 0, false);\n      }\n      this.showError(`Bash command failed: ${error instanceof Error ? error.message : \"Unknown error\"}`);\n    }\n    this.bashComponent = void 0;\n    this.ui.requestRender();\n  }\n  async handleCompactCommand(customInstructions) {\n    this.clearStatusIndicator();\n    try {\n      await this.session.compact(customInstructions);\n    } catch {\n    }\n  }\n  stop(fullscreenExitOutput = this.settingsManager.getFullscreenExitOutput()) {\n    this.disposeActiveSelector();\n    if (this.settingsManager.getShowTerminalProgress()) {\n      this.ui.terminal.setProgress(false);\n    }\n    this.clearStatusIndicator();\n    this.themeController.disableAutoSync();\n    this.clearExtensionTerminalInputListeners();\n    this.footer.dispose();\n    this.footerDataProvider.dispose();\n    if (this.unsubscribe) {\n      this.unsubscribe();\n    }\n    if (this.isInitialized) {\n      this.stopInteractiveTui(fullscreenExitOutput);\n      this.isInitialized = false;\n    }\n    this.unregisterSignalHandlers();\n  }\n};\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/modes/json-event.js\nfunction toJsonEvent(event) {\n  if (event.type !== \"message_update\") {\n    return event;\n  }\n  if (event.message.role !== \"assistant\") {\n    throw new Error(\"message_update message is not an assistant message\");\n  }\n  const assistantMessageEvent = event.assistantMessageEvent;\n  if (!(\"partial\" in assistantMessageEvent)) {\n    return { type: \"message_update\", usage: event.message.usage, assistantMessageEvent };\n  }\n  const { partial: _partial, ...deltaEvent } = assistantMessageEvent;\n  return { type: \"message_update\", usage: event.message.usage, assistantMessageEvent: deltaEvent };\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/modes/print-mode.js\nasync function runPrintMode(runtimeHost, options) {\n  const { mode, messages = [], initialMessage, initialImages } = options;\n  let exitCode = 0;\n  let session = runtimeHost.session;\n  let unsubscribe;\n  let unsubscribeBackpressure;\n  let disposed = false;\n  const signalCleanupHandlers = [];\n  const disposeRuntime = async () => {\n    if (disposed)\n      return;\n    disposed = true;\n    unsubscribe?.();\n    unsubscribeBackpressure?.();\n    await runtimeHost.dispose();\n  };\n  const registerSignalHandlers = () => {\n    const signals = [\"SIGTERM\"];\n    if (process.platform !== \"win32\") {\n      signals.push(\"SIGHUP\");\n    }\n    for (const signal of signals) {\n      const handler = () => {\n        killTrackedDetachedChildren();\n        void disposeRuntime().finally(() => {\n          process.exit(signal === \"SIGHUP\" ? 129 : 143);\n        });\n      };\n      process.on(signal, handler);\n      signalCleanupHandlers.push(() => process.off(signal, handler));\n    }\n  };\n  registerSignalHandlers();\n  runtimeHost.setRebindSession(async () => {\n    await rebindSession();\n  });\n  const rebindSession = async () => {\n    session = runtimeHost.session;\n    await session.bindExtensions({\n      mode: mode === \"json\" ? \"json\" : \"print\",\n      commandContextActions: {\n        waitForIdle: () => session.waitForIdle(),\n        newSession: async (newSessionOptions) => runtimeHost.newSession(newSessionOptions),\n        fork: async (entryId, forkOptions) => {\n          const result = await runtimeHost.fork(entryId, forkOptions);\n          return { cancelled: result.cancelled };\n        },\n        navigateTree: async (targetId, navigateOptions) => {\n          const result = await session.navigateTree(targetId, {\n            summarize: navigateOptions?.summarize,\n            customInstructions: navigateOptions?.customInstructions,\n            replaceInstructions: navigateOptions?.replaceInstructions,\n            label: navigateOptions?.label\n          });\n          return { cancelled: result.cancelled };\n        },\n        switchSession: async (sessionPath, switchOptions) => {\n          return runtimeHost.switchSession(sessionPath, switchOptions);\n        },\n        reload: async () => {\n          await session.reload();\n        }\n      },\n      onError: (err2) => {\n        console.error(`Extension error (${err2.extensionPath}): ${err2.error}`);\n      }\n    });\n    unsubscribe?.();\n    unsubscribeBackpressure?.();\n    unsubscribe = session.subscribe((event) => {\n      if (mode === \"json\") {\n        writeRawStdout(`${JSON.stringify(toJsonEvent(event))}\n`);\n      }\n    });\n    unsubscribeBackpressure = mode === \"json\" ? session.agent.subscribe(async () => {\n      await waitForRawStdoutBackpressure();\n    }) : void 0;\n  };\n  try {\n    if (mode === \"json\") {\n      const header = session.sessionManager.getHeader();\n      if (header) {\n        writeRawStdout(`${JSON.stringify(header)}\n`);\n      }\n    }\n    await rebindSession();\n    if (initialMessage) {\n      await session.prompt(initialMessage, { images: initialImages });\n    }\n    for (const message of messages) {\n      await session.prompt(message);\n    }\n    if (mode === \"text\") {\n      const state = session.state;\n      const lastMessage = state.messages[state.messages.length - 1];\n      if (lastMessage?.role === \"assistant\") {\n        const assistantMsg = lastMessage;\n        if (assistantMsg.stopReason === \"error\" || assistantMsg.stopReason === \"aborted\") {\n          console.error(assistantMsg.errorMessage || `Request ${assistantMsg.stopReason}`);\n          exitCode = 1;\n        } else {\n          for (const content of assistantMsg.content) {\n            if (content.type === \"text\") {\n              writeRawStdout(`${content.text}\n`);\n            }\n          }\n        }\n      }\n    }\n    return exitCode;\n  } catch (error) {\n    console.error(error instanceof Error ? error.message : String(error));\n    return 1;\n  } finally {\n    for (const cleanup of signalCleanupHandlers) {\n      cleanup();\n    }\n    await disposeRuntime();\n    await flushRawStdout();\n  }\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/modes/rpc/rpc-client.js\nimport { spawn as spawn10 } from \"node:child_process\";\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/modes/rpc/jsonl.js\nimport { StringDecoder as StringDecoder2 } from \"node:string_decoder\";\nfunction serializeJsonLine(value) {\n  return `${JSON.stringify(value)}\n`;\n}\nfunction attachJsonlLineReader(stream11, onLine) {\n  const decoder = new StringDecoder2(\"utf8\");\n  let buffer = \"\";\n  const emitLine = (line) => {\n    onLine(line.endsWith(\"\\r\") ? line.slice(0, -1) : line);\n  };\n  const onData = (chunk) => {\n    buffer += typeof chunk === \"string\" ? chunk : decoder.write(chunk);\n    while (true) {\n      const newlineIndex = buffer.indexOf(\"\\n\");\n      if (newlineIndex === -1) {\n        return;\n      }\n      emitLine(buffer.slice(0, newlineIndex));\n      buffer = buffer.slice(newlineIndex + 1);\n    }\n  };\n  const onEnd = () => {\n    buffer += decoder.end();\n    if (buffer.length > 0) {\n      emitLine(buffer);\n      buffer = \"\";\n    }\n  };\n  stream11.on(\"data\", onData);\n  stream11.on(\"end\", onEnd);\n  return () => {\n    stream11.off(\"data\", onData);\n    stream11.off(\"end\", onEnd);\n  };\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/modes/rpc/rpc-client.js\nvar RpcClient = class {\n  process = null;\n  stopReadingStdout = null;\n  eventListeners = [];\n  pendingRequests = /* @__PURE__ */ new Map();\n  requestId = 0;\n  stderr = \"\";\n  exitError = null;\n  options;\n  constructor(options = {}) {\n    this.options = options;\n  }\n  /**\n   * Start the RPC agent process.\n   */\n  async start() {\n    if (this.process) {\n      throw new Error(\"Client already started\");\n    }\n    this.exitError = null;\n    const cliPath = this.options.cliPath ?? \"dist/cli.js\";\n    const args = [\"--mode\", \"rpc\"];\n    if (this.options.provider) {\n      args.push(\"--provider\", this.options.provider);\n    }\n    if (this.options.model) {\n      args.push(\"--model\", this.options.model);\n    }\n    if (this.options.args) {\n      args.push(...this.options.args);\n    }\n    const childProcess = spawn10(\"node\", [cliPath, ...args], {\n      cwd: this.options.cwd,\n      env: { ...process.env, ...this.options.env },\n      stdio: [\"pipe\", \"pipe\", \"pipe\"]\n    });\n    this.process = childProcess;\n    childProcess.stderr?.on(\"data\", (data) => {\n      this.stderr += data.toString();\n      process.stderr.write(data);\n    });\n    childProcess.once(\"exit\", (code, signal) => {\n      if (this.process !== childProcess)\n        return;\n      const error = this.createProcessExitError(code, signal);\n      this.exitError = error;\n      this.rejectPendingRequests(error);\n    });\n    childProcess.once(\"error\", (error) => {\n      if (this.process !== childProcess)\n        return;\n      const processError = new Error(`Agent process error: ${error.message}. Stderr: ${this.stderr}`);\n      this.exitError = processError;\n      this.rejectPendingRequests(processError);\n    });\n    childProcess.stdin?.on(\"error\", (error) => {\n      if (this.process !== childProcess)\n        return;\n      const stdinError = this.exitError ?? new Error(`Agent process stdin error: ${error.message}. Stderr: ${this.stderr}`);\n      this.exitError = stdinError;\n      this.rejectPendingRequests(stdinError);\n    });\n    this.stopReadingStdout = attachJsonlLineReader(childProcess.stdout, (line) => {\n      this.handleLine(line);\n    });\n    await new Promise((resolve15) => setTimeout(resolve15, 100));\n    if (this.process.exitCode !== null) {\n      const error = this.exitError ?? this.createProcessExitError(this.process.exitCode, this.process.signalCode);\n      this.exitError = error;\n      throw error;\n    }\n  }\n  /**\n   * Stop the RPC agent process.\n   */\n  async stop() {\n    if (!this.process)\n      return;\n    this.stopReadingStdout?.();\n    this.stopReadingStdout = null;\n    this.process.kill(\"SIGTERM\");\n    await new Promise((resolve15) => {\n      const timeout = setTimeout(() => {\n        this.process?.kill(\"SIGKILL\");\n        resolve15();\n      }, 1e3);\n      this.process?.on(\"exit\", () => {\n        clearTimeout(timeout);\n        resolve15();\n      });\n    });\n    this.process = null;\n    this.pendingRequests.clear();\n  }\n  /**\n   * Subscribe to agent events.\n   */\n  onEvent(listener) {\n    this.eventListeners.push(listener);\n    return () => {\n      const index = this.eventListeners.indexOf(listener);\n      if (index !== -1) {\n        this.eventListeners.splice(index, 1);\n      }\n    };\n  }\n  /**\n   * Get collected stderr output (useful for debugging).\n   */\n  getStderr() {\n    return this.stderr;\n  }\n  // =========================================================================\n  // Command Methods\n  // =========================================================================\n  /**\n   * Send a prompt to the agent.\n   * Returns immediately after sending; use onEvent() to receive streaming events.\n   * Use waitForIdle() to wait for completion.\n   */\n  async prompt(message, images) {\n    await this.send({ type: \"prompt\", message, images });\n  }\n  /**\n   * Queue a steering message to interrupt the agent mid-run.\n   */\n  async steer(message, images) {\n    await this.send({ type: \"steer\", message, images });\n  }\n  /**\n   * Queue a follow-up message to be processed after the agent finishes.\n   */\n  async followUp(message, images) {\n    await this.send({ type: \"follow_up\", message, images });\n  }\n  /**\n   * Abort current operation.\n   */\n  async abort() {\n    await this.send({ type: \"abort\" });\n  }\n  /**\n   * Start a new session, optionally with parent tracking.\n   * @param parentSession - Optional parent session path for lineage tracking\n   * @returns Object with `cancelled: true` if an extension cancelled the new session\n   */\n  async newSession(parentSession) {\n    const response = await this.send({ type: \"new_session\", parentSession });\n    return this.getData(response);\n  }\n  /**\n   * Get current session state.\n   */\n  async getState() {\n    const response = await this.send({ type: \"get_state\" });\n    return this.getData(response);\n  }\n  /**\n   * Set model by provider and ID.\n   */\n  async setModel(provider, modelId) {\n    const response = await this.send({ type: \"set_model\", provider, modelId });\n    return this.getData(response);\n  }\n  /**\n   * Cycle to next model.\n   */\n  async cycleModel() {\n    const response = await this.send({ type: \"cycle_model\" });\n    return this.getData(response);\n  }\n  /**\n   * Get list of available models.\n   */\n  async getAvailableModels() {\n    const response = await this.send({ type: \"get_available_models\" });\n    return this.getData(response).models;\n  }\n  /**\n   * Set thinking level.\n   */\n  async setThinkingLevel(level) {\n    await this.send({ type: \"set_thinking_level\", level });\n  }\n  /**\n   * Cycle thinking level.\n   */\n  async cycleThinkingLevel() {\n    const response = await this.send({ type: \"cycle_thinking_level\" });\n    return this.getData(response);\n  }\n  /**\n   * Get list of available thinking levels for the current model.\n   */\n  async getAvailableThinkingLevels() {\n    const response = await this.send({ type: \"get_available_thinking_levels\" });\n    return this.getData(response).levels;\n  }\n  /**\n   * Set steering mode.\n   */\n  async setSteeringMode(mode) {\n    await this.send({ type: \"set_steering_mode\", mode });\n  }\n  /**\n   * Set follow-up mode.\n   */\n  async setFollowUpMode(mode) {\n    await this.send({ type: \"set_follow_up_mode\", mode });\n  }\n  /**\n   * Compact session context.\n   */\n  async compact(customInstructions) {\n    const response = await this.send({ type: \"compact\", customInstructions });\n    return this.getData(response);\n  }\n  /**\n   * Set auto-compaction enabled/disabled.\n   */\n  async setAutoCompaction(enabled) {\n    await this.send({ type: \"set_auto_compaction\", enabled });\n  }\n  /**\n   * Set auto-retry enabled/disabled.\n   */\n  async setAutoRetry(enabled) {\n    await this.send({ type: \"set_auto_retry\", enabled });\n  }\n  /**\n   * Abort in-progress retry.\n   */\n  async abortRetry() {\n    await this.send({ type: \"abort_retry\" });\n  }\n  /**\n   * Execute a bash command.\n   */\n  async bash(command) {\n    const response = await this.send({ type: \"bash\", command });\n    return this.getData(response);\n  }\n  /**\n   * Abort running bash command.\n   */\n  async abortBash() {\n    await this.send({ type: \"abort_bash\" });\n  }\n  /**\n   * Get session statistics.\n   */\n  async getSessionStats() {\n    const response = await this.send({ type: \"get_session_stats\" });\n    return this.getData(response);\n  }\n  /**\n   * Export session to HTML.\n   */\n  async exportHtml(outputPath) {\n    const response = await this.send({ type: \"export_html\", outputPath });\n    return this.getData(response);\n  }\n  /**\n   * Switch to a different session file.\n   * @returns Object with `cancelled: true` if an extension cancelled the switch\n   */\n  async switchSession(sessionPath) {\n    const response = await this.send({ type: \"switch_session\", sessionPath });\n    return this.getData(response);\n  }\n  /**\n   * Fork from a specific message.\n   * @returns Object with `text` (the message text) and `cancelled` (if extension cancelled)\n   */\n  async fork(entryId) {\n    const response = await this.send({ type: \"fork\", entryId });\n    return this.getData(response);\n  }\n  /**\n   * Clone the current active branch into a new session.\n   * @returns Object with `cancelled: true` if an extension cancelled the clone\n   */\n  async clone() {\n    const response = await this.send({ type: \"clone\" });\n    return this.getData(response);\n  }\n  /**\n   * Get messages available for forking.\n   */\n  async getForkMessages() {\n    const response = await this.send({ type: \"get_fork_messages\" });\n    return this.getData(response).messages;\n  }\n  /**\n   * Get session entries in append order, optionally only those after the `since` entry id.\n   */\n  async getEntries(since) {\n    const response = await this.send({ type: \"get_entries\", since });\n    return this.getData(response);\n  }\n  /**\n   * Get the session entry tree.\n   */\n  async getTree() {\n    const response = await this.send({ type: \"get_tree\" });\n    return this.getData(response);\n  }\n  /**\n   * Get text of last assistant message.\n   */\n  async getLastAssistantText() {\n    const response = await this.send({ type: \"get_last_assistant_text\" });\n    return this.getData(response).text;\n  }\n  /**\n   * Set the session display name.\n   */\n  async setSessionName(name) {\n    await this.send({ type: \"set_session_name\", name });\n  }\n  /**\n   * Get all messages in the session.\n   */\n  async getMessages() {\n    const response = await this.send({ type: \"get_messages\" });\n    return this.getData(response).messages;\n  }\n  /**\n   * Get available commands (extension commands, prompt templates, skills).\n   */\n  async getCommands() {\n    const response = await this.send({ type: \"get_commands\" });\n    return this.getData(response).commands;\n  }\n  // =========================================================================\n  // Helpers\n  // =========================================================================\n  /**\n   * Wait for agent to become idle (no streaming).\n   * Resolves when agent_settled event is received.\n   */\n  waitForIdle(timeout = 6e4) {\n    return new Promise((resolve15, reject) => {\n      const timer = setTimeout(() => {\n        unsubscribe();\n        reject(new Error(`Timeout waiting for agent to become idle. Stderr: ${this.stderr}`));\n      }, timeout);\n      const unsubscribe = this.onEvent((event) => {\n        if (event.type === \"agent_settled\") {\n          clearTimeout(timer);\n          unsubscribe();\n          resolve15();\n        }\n      });\n    });\n  }\n  /**\n   * Collect events until agent becomes idle.\n   */\n  collectEvents(timeout = 6e4) {\n    return new Promise((resolve15, reject) => {\n      const events = [];\n      const timer = setTimeout(() => {\n        unsubscribe();\n        reject(new Error(`Timeout collecting events. Stderr: ${this.stderr}`));\n      }, timeout);\n      const unsubscribe = this.onEvent((event) => {\n        events.push(event);\n        if (event.type === \"agent_settled\") {\n          clearTimeout(timer);\n          unsubscribe();\n          resolve15(events);\n        }\n      });\n    });\n  }\n  /**\n   * Send prompt and wait for completion, returning all events.\n   */\n  async promptAndWait(message, images, timeout = 6e4) {\n    const eventsPromise = this.collectEvents(timeout);\n    await this.prompt(message, images);\n    return eventsPromise;\n  }\n  // =========================================================================\n  // Internal\n  // =========================================================================\n  handleLine(line) {\n    try {\n      const data = JSON.parse(line);\n      if (data.type === \"response\" && data.id && this.pendingRequests.has(data.id)) {\n        const pending = this.pendingRequests.get(data.id);\n        this.pendingRequests.delete(data.id);\n        pending.resolve(data);\n        return;\n      }\n      for (const listener of this.eventListeners) {\n        listener(data);\n      }\n    } catch {\n    }\n  }\n  createProcessExitError(code, signal) {\n    return new Error(`Agent process exited (code=${code} signal=${signal}). Stderr: ${this.stderr}`);\n  }\n  rejectPendingRequests(error) {\n    for (const pending of this.pendingRequests.values()) {\n      pending.reject(error);\n    }\n    this.pendingRequests.clear();\n  }\n  async send(command) {\n    const childProcess = this.process;\n    const stdin = childProcess?.stdin;\n    if (!childProcess || !stdin) {\n      throw new Error(\"Client not started\");\n    }\n    if (this.exitError) {\n      throw this.exitError;\n    }\n    if (childProcess.exitCode !== null) {\n      const error = this.createProcessExitError(childProcess.exitCode, childProcess.signalCode);\n      this.exitError = error;\n      throw error;\n    }\n    if (stdin.destroyed || !stdin.writable) {\n      const error = new Error(`Agent process stdin is not writable. Stderr: ${this.stderr}`);\n      this.exitError = error;\n      throw error;\n    }\n    const id = `req_${++this.requestId}`;\n    const fullCommand = { ...command, id };\n    return new Promise((resolve15, reject) => {\n      const timeout = setTimeout(() => {\n        this.pendingRequests.delete(id);\n        reject(new Error(`Timeout waiting for response to ${command.type}. Stderr: ${this.stderr}`));\n      }, 3e4);\n      this.pendingRequests.set(id, {\n        resolve: (response) => {\n          clearTimeout(timeout);\n          resolve15(response);\n        },\n        reject: (error) => {\n          clearTimeout(timeout);\n          reject(error);\n        }\n      });\n      try {\n        stdin.write(serializeJsonLine(fullCommand));\n      } catch (error) {\n        const writeError = error instanceof Error ? error : new Error(String(error));\n        const pending = this.pendingRequests.get(id);\n        this.pendingRequests.delete(id);\n        pending?.reject(writeError);\n      }\n    });\n  }\n  getData(response) {\n    if (!response.success) {\n      const errorResponse = response;\n      throw new Error(errorResponse.error);\n    }\n    const successResponse = response;\n    return successResponse.data;\n  }\n};\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/modes/rpc/rpc-mode.js\nimport * as crypto2 from \"node:crypto\";\nasync function runRpcMode(runtimeHost) {\n  takeOverStdout();\n  let session = runtimeHost.session;\n  let unsubscribe;\n  let unsubscribeBackpressure;\n  const output = (obj) => {\n    writeRawStdout(serializeJsonLine(obj));\n  };\n  const success = (id, command, data) => {\n    if (data === void 0) {\n      return { id, type: \"response\", command, success: true };\n    }\n    return { id, type: \"response\", command, success: true, data };\n  };\n  const error = (id, command, message) => {\n    return { id, type: \"response\", command, success: false, error: message };\n  };\n  const pendingExtensionRequests = /* @__PURE__ */ new Map();\n  let shutdownRequested = false;\n  let shuttingDown = false;\n  const signalCleanupHandlers = [];\n  function createDialogPromise(opts, defaultValue, request, parseResponse) {\n    if (opts?.signal?.aborted)\n      return Promise.resolve(defaultValue);\n    const id = crypto2.randomUUID();\n    return new Promise((resolve15, reject) => {\n      let timeoutId;\n      const cleanup = () => {\n        if (timeoutId)\n          clearTimeout(timeoutId);\n        opts?.signal?.removeEventListener(\"abort\", onAbort);\n        pendingExtensionRequests.delete(id);\n      };\n      const onAbort = () => {\n        cleanup();\n        resolve15(defaultValue);\n      };\n      opts?.signal?.addEventListener(\"abort\", onAbort, { once: true });\n      if (opts?.timeout) {\n        timeoutId = setTimeout(() => {\n          cleanup();\n          resolve15(defaultValue);\n        }, opts.timeout);\n      }\n      pendingExtensionRequests.set(id, {\n        resolve: (response) => {\n          cleanup();\n          resolve15(parseResponse(response));\n        },\n        reject\n      });\n      output({ type: \"extension_ui_request\", id, ...request });\n    });\n  }\n  const createExtensionUIContext = () => ({\n    select: (title, options, opts) => createDialogPromise(opts, void 0, { method: \"select\", title, options, timeout: opts?.timeout }, (r) => \"cancelled\" in r && r.cancelled ? void 0 : \"value\" in r ? r.value : void 0),\n    confirm: (title, message, opts) => createDialogPromise(opts, false, { method: \"confirm\", title, message, timeout: opts?.timeout }, (r) => \"cancelled\" in r && r.cancelled ? false : \"confirmed\" in r ? r.confirmed : false),\n    input: (title, placeholder, opts) => createDialogPromise(opts, void 0, { method: \"input\", title, placeholder, timeout: opts?.timeout }, (r) => \"cancelled\" in r && r.cancelled ? void 0 : \"value\" in r ? r.value : void 0),\n    notify(message, type) {\n      output({\n        type: \"extension_ui_request\",\n        id: crypto2.randomUUID(),\n        method: \"notify\",\n        message,\n        notifyType: type\n      });\n    },\n    onTerminalInput() {\n      return () => {\n      };\n    },\n    setStatus(key, text) {\n      output({\n        type: \"extension_ui_request\",\n        id: crypto2.randomUUID(),\n        method: \"setStatus\",\n        statusKey: key,\n        statusText: text\n      });\n    },\n    setWorkingMessage(_message) {\n    },\n    setWorkingVisible(_visible) {\n    },\n    setWorkingIndicator(_options) {\n    },\n    setHiddenThinkingLabel(_label) {\n    },\n    setWidget(key, content, options) {\n      if (content === void 0 || Array.isArray(content)) {\n        output({\n          type: \"extension_ui_request\",\n          id: crypto2.randomUUID(),\n          method: \"setWidget\",\n          widgetKey: key,\n          widgetLines: content,\n          widgetPlacement: options?.placement\n        });\n      }\n    },\n    setFooter(_factory) {\n    },\n    setHeader(_factory) {\n    },\n    setTitle(title) {\n      output({\n        type: \"extension_ui_request\",\n        id: crypto2.randomUUID(),\n        method: \"setTitle\",\n        title\n      });\n    },\n    async custom() {\n      return void 0;\n    },\n    pasteToEditor(text) {\n      this.setEditorText(text);\n    },\n    setEditorText(text) {\n      output({\n        type: \"extension_ui_request\",\n        id: crypto2.randomUUID(),\n        method: \"set_editor_text\",\n        text\n      });\n    },\n    getEditorText() {\n      return \"\";\n    },\n    async editor(title, prefill) {\n      const id = crypto2.randomUUID();\n      return new Promise((resolve15, reject) => {\n        pendingExtensionRequests.set(id, {\n          resolve: (response) => {\n            if (\"cancelled\" in response && response.cancelled) {\n              resolve15(void 0);\n            } else if (\"value\" in response) {\n              resolve15(response.value);\n            } else {\n              resolve15(void 0);\n            }\n          },\n          reject\n        });\n        output({ type: \"extension_ui_request\", id, method: \"editor\", title, prefill });\n      });\n    },\n    addAutocompleteProvider() {\n    },\n    setEditorComponent() {\n    },\n    getEditorComponent() {\n      return void 0;\n    },\n    get theme() {\n      return theme;\n    },\n    getAllThemes() {\n      return [];\n    },\n    getTheme(_name) {\n      return void 0;\n    },\n    setTheme(_theme) {\n      return { success: false, error: \"Theme switching not supported in RPC mode\" };\n    },\n    getToolsExpanded() {\n      return false;\n    },\n    setToolsExpanded(_expanded) {\n    }\n  });\n  runtimeHost.setRebindSession(async () => {\n    await rebindSession();\n  });\n  const rebindSession = async () => {\n    session = runtimeHost.session;\n    await session.bindExtensions({\n      uiContext: createExtensionUIContext(),\n      mode: \"rpc\",\n      commandContextActions: {\n        waitForIdle: () => session.waitForIdle(),\n        newSession: async (options) => runtimeHost.newSession(options),\n        fork: async (entryId, forkOptions) => {\n          const result = await runtimeHost.fork(entryId, forkOptions);\n          return { cancelled: result.cancelled };\n        },\n        navigateTree: async (targetId, options) => {\n          const result = await session.navigateTree(targetId, {\n            summarize: options?.summarize,\n            customInstructions: options?.customInstructions,\n            replaceInstructions: options?.replaceInstructions,\n            label: options?.label\n          });\n          return { cancelled: result.cancelled };\n        },\n        switchSession: async (sessionPath, options) => {\n          return runtimeHost.switchSession(sessionPath, options);\n        },\n        reload: async () => {\n          await session.reload();\n        }\n      },\n      shutdownHandler: () => {\n        shutdownRequested = true;\n      },\n      onError: (err2) => {\n        output({ type: \"extension_error\", extensionPath: err2.extensionPath, event: err2.event, error: err2.error });\n      }\n    });\n    unsubscribe?.();\n    unsubscribeBackpressure?.();\n    unsubscribe = session.subscribe((event) => {\n      output(toJsonEvent(event));\n      if (event.type === \"agent_settled\") {\n        void checkShutdownRequested();\n      }\n    });\n    unsubscribeBackpressure = session.agent.subscribe(async () => {\n      await waitForRawStdoutBackpressure();\n    });\n  };\n  const registerSignalHandlers = () => {\n    const signals = [\"SIGTERM\"];\n    if (process.platform !== \"win32\") {\n      signals.push(\"SIGHUP\");\n    }\n    for (const signal of signals) {\n      const handler = () => {\n        killTrackedDetachedChildren();\n        void shutdown(signal === \"SIGHUP\" ? 129 : 143, signal);\n      };\n      process.on(signal, handler);\n      signalCleanupHandlers.push(() => process.off(signal, handler));\n    }\n  };\n  await rebindSession();\n  registerSignalHandlers();\n  const handleCommand = async (command) => {\n    const id = command.id;\n    switch (command.type) {\n      // =================================================================\n      // Prompting\n      // =================================================================\n      case \"prompt\": {\n        let preflightSucceeded = false;\n        void session.prompt(command.message, {\n          images: command.images,\n          streamingBehavior: command.streamingBehavior,\n          source: \"rpc\",\n          preflightResult: (didSucceed) => {\n            if (didSucceed) {\n              preflightSucceeded = true;\n              output(success(id, \"prompt\"));\n            }\n          }\n        }).catch((e) => {\n          if (!preflightSucceeded) {\n            output(error(id, \"prompt\", e.message));\n          }\n        });\n        return void 0;\n      }\n      case \"steer\": {\n        await session.steer(command.message, command.images);\n        return success(id, \"steer\");\n      }\n      case \"follow_up\": {\n        await session.followUp(command.message, command.images);\n        return success(id, \"follow_up\");\n      }\n      case \"abort\": {\n        await session.abort();\n        return success(id, \"abort\");\n      }\n      case \"new_session\": {\n        const options = command.parentSession ? { parentSession: command.parentSession } : void 0;\n        const result = await runtimeHost.newSession(options);\n        if (!result.cancelled) {\n          await rebindSession();\n        }\n        return success(id, \"new_session\", result);\n      }\n      // =================================================================\n      // State\n      // =================================================================\n      case \"get_state\": {\n        const state = {\n          model: session.model,\n          thinkingLevel: session.thinkingLevel,\n          isStreaming: session.isStreaming,\n          isCompacting: session.isCompacting,\n          steeringMode: session.steeringMode,\n          followUpMode: session.followUpMode,\n          sessionFile: session.sessionFile,\n          sessionId: session.sessionId,\n          sessionName: session.sessionName,\n          autoCompactionEnabled: session.autoCompactionEnabled,\n          messageCount: session.messages.length,\n          pendingMessageCount: session.pendingMessageCount\n        };\n        return success(id, \"get_state\", state);\n      }\n      // =================================================================\n      // Model\n      // =================================================================\n      case \"set_model\": {\n        const models = session.modelRuntime.getAvailableSnapshot();\n        const model = models.find((m) => m.provider === command.provider && m.id === command.modelId);\n        if (!model) {\n          return error(id, \"set_model\", `Model not found: ${command.provider}/${command.modelId}`);\n        }\n        await session.setModel(model);\n        return success(id, \"set_model\", model);\n      }\n      case \"cycle_model\": {\n        const result = await session.cycleModel();\n        if (!result) {\n          return success(id, \"cycle_model\", null);\n        }\n        return success(id, \"cycle_model\", result);\n      }\n      case \"get_available_models\": {\n        const models = session.modelRuntime.getAvailableSnapshot();\n        return success(id, \"get_available_models\", { models });\n      }\n      // =================================================================\n      // Thinking\n      // =================================================================\n      case \"set_thinking_level\": {\n        session.setThinkingLevel(command.level);\n        return success(id, \"set_thinking_level\");\n      }\n      case \"cycle_thinking_level\": {\n        const level = session.cycleThinkingLevel();\n        if (!level) {\n          return success(id, \"cycle_thinking_level\", null);\n        }\n        return success(id, \"cycle_thinking_level\", { level });\n      }\n      case \"get_available_thinking_levels\": {\n        const levels = session.getAvailableThinkingLevels();\n        return success(id, \"get_available_thinking_levels\", { levels });\n      }\n      // =================================================================\n      // Queue Modes\n      // =================================================================\n      case \"set_steering_mode\": {\n        session.setSteeringMode(command.mode);\n        return success(id, \"set_steering_mode\");\n      }\n      case \"set_follow_up_mode\": {\n        session.setFollowUpMode(command.mode);\n        return success(id, \"set_follow_up_mode\");\n      }\n      // =================================================================\n      // Compaction\n      // =================================================================\n      case \"compact\": {\n        const result = await session.compact(command.customInstructions);\n        return success(id, \"compact\", result);\n      }\n      case \"set_auto_compaction\": {\n        session.setAutoCompactionEnabled(command.enabled);\n        return success(id, \"set_auto_compaction\");\n      }\n      // =================================================================\n      // Retry\n      // =================================================================\n      case \"set_auto_retry\": {\n        session.setAutoRetryEnabled(command.enabled);\n        return success(id, \"set_auto_retry\");\n      }\n      case \"abort_retry\": {\n        session.abortRetry();\n        return success(id, \"abort_retry\");\n      }\n      // =================================================================\n      // Bash\n      // =================================================================\n      case \"bash\": {\n        const eventResult = await session.extensionRunner.emitUserBash({\n          type: \"user_bash\",\n          command: command.command,\n          excludeFromContext: command.excludeFromContext ?? false,\n          cwd: session.sessionManager.getCwd()\n        });\n        if (eventResult?.result) {\n          session.recordBashResult(command.command, eventResult.result, {\n            excludeFromContext: command.excludeFromContext\n          });\n          return success(id, \"bash\", eventResult.result);\n        }\n        const result = await session.executeBash(command.command, void 0, {\n          excludeFromContext: command.excludeFromContext,\n          id,\n          operations: eventResult?.operations\n        });\n        return success(id, \"bash\", result);\n      }\n      case \"abort_bash\": {\n        session.abortBash();\n        return success(id, \"abort_bash\");\n      }\n      // =================================================================\n      // Session\n      // =================================================================\n      case \"get_session_stats\": {\n        const stats = session.getSessionStats();\n        return success(id, \"get_session_stats\", stats);\n      }\n      case \"export_html\": {\n        const path12 = await session.exportToHtml(command.outputPath);\n        return success(id, \"export_html\", { path: path12 });\n      }\n      case \"switch_session\": {\n        const result = await runtimeHost.switchSession(command.sessionPath);\n        if (!result.cancelled) {\n          await rebindSession();\n        }\n        return success(id, \"switch_session\", result);\n      }\n      case \"fork\": {\n        const result = await runtimeHost.fork(command.entryId);\n        if (!result.cancelled) {\n          await rebindSession();\n        }\n        return success(id, \"fork\", { text: result.selectedText, cancelled: result.cancelled });\n      }\n      case \"clone\": {\n        const leafId = session.sessionManager.getLeafId();\n        if (!leafId) {\n          return error(id, \"clone\", \"Cannot clone session: no current entry selected\");\n        }\n        const result = await runtimeHost.fork(leafId, { position: \"at\" });\n        if (!result.cancelled) {\n          await rebindSession();\n        }\n        return success(id, \"clone\", { cancelled: result.cancelled });\n      }\n      case \"get_fork_messages\": {\n        const messages = session.getUserMessagesForForking();\n        return success(id, \"get_fork_messages\", { messages });\n      }\n      case \"get_entries\": {\n        const sessionManager = session.sessionManager;\n        let entries = sessionManager.getEntries();\n        if (command.since !== void 0) {\n          const sinceIndex = entries.findIndex((e) => e.id === command.since);\n          if (sinceIndex === -1) {\n            return error(id, \"get_entries\", `Entry not found: ${command.since}`);\n          }\n          entries = entries.slice(sinceIndex + 1);\n        }\n        return success(id, \"get_entries\", { entries, leafId: sessionManager.getLeafId() });\n      }\n      case \"get_tree\": {\n        const sessionManager = session.sessionManager;\n        return success(id, \"get_tree\", { tree: sessionManager.getTree(), leafId: sessionManager.getLeafId() });\n      }\n      case \"get_last_assistant_text\": {\n        const text = session.getLastAssistantText();\n        return success(id, \"get_last_assistant_text\", { text });\n      }\n      case \"set_session_name\": {\n        const name = command.name.trim();\n        if (!name) {\n          return error(id, \"set_session_name\", \"Session name cannot be empty\");\n        }\n        session.setSessionName(name);\n        return success(id, \"set_session_name\");\n      }\n      // =================================================================\n      // Messages\n      // =================================================================\n      case \"get_messages\": {\n        return success(id, \"get_messages\", { messages: session.messages });\n      }\n      // =================================================================\n      // Commands (available for invocation via prompt)\n      // =================================================================\n      case \"get_commands\": {\n        const commands = [];\n        for (const command2 of session.extensionRunner.getRegisteredCommands()) {\n          commands.push({\n            name: command2.invocationName,\n            description: command2.description,\n            source: \"extension\",\n            sourceInfo: command2.sourceInfo\n          });\n        }\n        for (const template of session.promptTemplates) {\n          commands.push({\n            name: template.name,\n            description: template.description,\n            source: \"prompt\",\n            sourceInfo: template.sourceInfo\n          });\n        }\n        for (const skill of session.resourceLoader.getSkills().skills) {\n          commands.push({\n            name: `skill:${skill.name}`,\n            description: skill.description,\n            source: \"skill\",\n            sourceInfo: skill.sourceInfo\n          });\n        }\n        return success(id, \"get_commands\", { commands });\n      }\n      default: {\n        const unknownCommand = command;\n        return error(id, unknownCommand.type, `Unknown command: ${unknownCommand.type}`);\n      }\n    }\n  };\n  let detachInput = () => {\n  };\n  async function shutdown(exitCode = 0, signal) {\n    if (shuttingDown) {\n      process.exit(exitCode);\n    }\n    shuttingDown = true;\n    for (const cleanup of signalCleanupHandlers) {\n      cleanup();\n    }\n    unsubscribe?.();\n    unsubscribeBackpressure?.();\n    await runtimeHost.dispose();\n    detachInput();\n    process.stdin.pause();\n    if (signal !== \"SIGTERM\") {\n      await flushRawStdout();\n    }\n    process.exit(exitCode);\n  }\n  async function checkShutdownRequested() {\n    if (!shutdownRequested)\n      return;\n    await shutdown();\n  }\n  const handleInputLine = async (line) => {\n    let parsed;\n    try {\n      parsed = JSON.parse(line);\n    } catch (parseError) {\n      output(error(void 0, \"parse\", `Failed to parse command: ${parseError instanceof Error ? parseError.message : String(parseError)}`));\n      await waitForRawStdoutBackpressure();\n      return;\n    }\n    if (typeof parsed === \"object\" && parsed !== null && \"type\" in parsed && parsed.type === \"extension_ui_response\") {\n      const response = parsed;\n      const pending = pendingExtensionRequests.get(response.id);\n      if (pending) {\n        pendingExtensionRequests.delete(response.id);\n        pending.resolve(response);\n      }\n      return;\n    }\n    const command = parsed;\n    try {\n      const response = await handleCommand(command);\n      if (response) {\n        output(response);\n        await waitForRawStdoutBackpressure();\n      }\n      await checkShutdownRequested();\n    } catch (commandError) {\n      output(error(command.id, command.type, commandError instanceof Error ? commandError.message : String(commandError)));\n      await waitForRawStdoutBackpressure();\n    }\n  };\n  const onInputEnd = () => {\n    void shutdown();\n  };\n  process.stdin.on(\"end\", onInputEnd);\n  detachInput = (() => {\n    const detachJsonl = attachJsonlLineReader(process.stdin, (line) => {\n      void handleInputLine(line);\n    });\n    return () => {\n      detachJsonl();\n      process.stdin.off(\"end\", onInputEnd);\n    };\n  })();\n  return new Promise(() => {\n  });\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/show-images-selector.js\nvar SHOW_IMAGES_SELECT_LIST_LAYOUT = {\n  minPrimaryColumnWidth: 12,\n  maxPrimaryColumnWidth: 32\n};\nvar ShowImagesSelectorComponent = class extends Container {\n  selectList;\n  constructor(currentValue, onSelect, onCancel) {\n    super();\n    const items = [\n      { value: \"yes\", label: \"Yes\", description: \"Show images inline in terminal\" },\n      { value: \"no\", label: \"No\", description: \"Show text placeholder instead\" }\n    ];\n    this.addChild(new DynamicBorder());\n    this.selectList = new SelectList(items, 5, getSelectListTheme(), SHOW_IMAGES_SELECT_LIST_LAYOUT);\n    this.selectList.setSelectedIndex(currentValue ? 0 : 1);\n    this.selectList.onSelect = (item) => {\n      onSelect(item.value === \"yes\");\n    };\n    this.selectList.onCancel = () => {\n      onCancel();\n    };\n    this.addChild(this.selectList);\n    this.addChild(new DynamicBorder());\n  }\n  getSelectList() {\n    return this.selectList;\n  }\n};\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/theme-selector.js\nvar THEME_SELECT_LIST_LAYOUT = {\n  minPrimaryColumnWidth: 12,\n  maxPrimaryColumnWidth: 32\n};\nvar ThemeSelectorComponent = class extends Container {\n  selectList;\n  onPreview;\n  constructor(currentTheme, onSelect, onCancel, onPreview) {\n    super();\n    this.onPreview = onPreview;\n    const themes = getAvailableThemes();\n    const themeItems2 = themes.map((name) => ({\n      value: name,\n      label: name,\n      description: name === currentTheme ? \"(current)\" : void 0\n    }));\n    this.addChild(new DynamicBorder());\n    this.selectList = new SelectList(themeItems2, 10, getSelectListTheme(), THEME_SELECT_LIST_LAYOUT);\n    const currentIndex = themes.indexOf(currentTheme);\n    if (currentIndex !== -1) {\n      this.selectList.setSelectedIndex(currentIndex);\n    }\n    this.selectList.onSelect = (item) => {\n      onSelect(item.value);\n    };\n    this.selectList.onCancel = () => {\n      onCancel();\n    };\n    this.selectList.onSelectionChange = (item) => {\n      this.onPreview(item.value);\n    };\n    this.addChild(this.selectList);\n    this.addChild(new DynamicBorder());\n  }\n  getSelectList() {\n    return this.selectList;\n  }\n};\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/thinking-selector.js\nvar THINKING_SELECT_LIST_LAYOUT = {\n  minPrimaryColumnWidth: 12,\n  maxPrimaryColumnWidth: 32\n};\nvar LEVEL_DESCRIPTIONS = {\n  off: \"No reasoning\",\n  minimal: \"Very brief reasoning (~1k tokens)\",\n  low: \"Light reasoning (~2k tokens)\",\n  medium: \"Moderate reasoning (~8k tokens)\",\n  high: \"Deep reasoning (~16k tokens)\",\n  xhigh: \"Extra-high reasoning (~32k tokens)\",\n  max: \"Maximum reasoning\"\n};\nvar ThinkingSelectorComponent = class extends Container {\n  selectList;\n  constructor(currentLevel, availableLevels, onSelect, onCancel) {\n    super();\n    const thinkingLevels = availableLevels.map((level) => ({\n      value: level,\n      label: level,\n      description: LEVEL_DESCRIPTIONS[level]\n    }));\n    this.addChild(new DynamicBorder());\n    this.selectList = new SelectList(thinkingLevels, thinkingLevels.length, getSelectListTheme(), THINKING_SELECT_LIST_LAYOUT);\n    const currentIndex = thinkingLevels.findIndex((item) => item.value === currentLevel);\n    if (currentIndex !== -1) {\n      this.selectList.setSelectedIndex(currentIndex);\n    }\n    this.selectList.onSelect = (item) => {\n      onSelect(item.value);\n    };\n    this.selectList.onCancel = () => {\n      onCancel();\n    };\n    this.addChild(this.selectList);\n    this.addChild(new DynamicBorder());\n  }\n  getSelectList() {\n    return this.selectList;\n  }\n};\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/core/exec.js\nimport { spawn as spawn11 } from \"node:child_process\";\nasync function execCommand(command, args, cwd, options) {\n  return new Promise((resolve15) => {\n    const proc = spawn11(command, args, {\n      cwd,\n      shell: false,\n      stdio: [\"ignore\", \"pipe\", \"pipe\"]\n    });\n    let stdout = \"\";\n    let stderr = \"\";\n    let killed = false;\n    let timeoutId;\n    const killProcess = () => {\n      if (!killed) {\n        killed = true;\n        proc.kill(\"SIGTERM\");\n        setTimeout(() => {\n          if (!proc.killed) {\n            proc.kill(\"SIGKILL\");\n          }\n        }, 5e3);\n      }\n    };\n    if (options?.signal) {\n      if (options.signal.aborted) {\n        killProcess();\n      } else {\n        options.signal.addEventListener(\"abort\", killProcess, { once: true });\n      }\n    }\n    if (options?.timeout && options.timeout > 0) {\n      timeoutId = setTimeout(() => {\n        killProcess();\n      }, options.timeout);\n    }\n    proc.stdout?.on(\"data\", (data) => {\n      stdout += data.toString();\n    });\n    proc.stderr?.on(\"data\", (data) => {\n      stderr += data.toString();\n    });\n    waitForChildProcess(proc).then((code) => {\n      if (timeoutId)\n        clearTimeout(timeoutId);\n      if (options?.signal) {\n        options.signal.removeEventListener(\"abort\", killProcess);\n      }\n      resolve15({ stdout, stderr, code: code ?? 0, killed });\n    }).catch((_err) => {\n      if (timeoutId)\n        clearTimeout(timeoutId);\n      if (options?.signal) {\n        options.signal.removeEventListener(\"abort\", killProcess);\n      }\n      resolve15({ stdout, stderr, code: 1, killed });\n    });\n  });\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/core/extensions/loader.js\nvar VIRTUAL_MODULES = {\n  typebox: _bundledTypebox,\n  \"typebox/compile\": _bundledTypeboxCompile,\n  \"typebox/value\": _bundledTypeboxValue,\n  \"@sinclair/typebox\": _bundledTypebox,\n  \"@sinclair/typebox/compile\": _bundledTypeboxCompile,\n  \"@sinclair/typebox/value\": _bundledTypeboxValue,\n  \"@earendil-works/pi-agent-core\": dist_exports2,\n  \"@earendil-works/pi-tui\": dist_exports,\n  // Extensions resolve the pi-ai root to the compat entrypoint (a strict\n  // superset of the core entrypoint): existing extensions using the old\n  // global API keep working at runtime until compat is removed.\n  \"@earendil-works/pi-ai\": compat_exports,\n  \"@earendil-works/pi-ai/compat\": compat_exports,\n  \"@earendil-works/pi-ai/oauth\": oauth_exports,\n  \"@earendil-works/pi-ai/providers/all\": all_exports,\n  \"@earendil-works/pi-coding-agent\": index_exports,\n  \"@mariozechner/pi-agent-core\": dist_exports2,\n  \"@mariozechner/pi-tui\": dist_exports,\n  \"@mariozechner/pi-ai\": compat_exports,\n  \"@mariozechner/pi-ai/compat\": compat_exports,\n  \"@mariozechner/pi-ai/oauth\": oauth_exports,\n  \"@mariozechner/pi-ai/providers/all\": all_exports,\n  \"@mariozechner/pi-coding-agent\": index_exports\n};\nvar require3 = createRequire5(import.meta.url);\nvar isTypeScriptSourceRuntime = !isBunBinary && path11.extname(fileURLToPath6(import.meta.url)) === \".ts\";\nvar _aliases = null;\nfunction getAliases() {\n  if (_aliases)\n    return _aliases;\n  const __dirname2 = path11.dirname(fileURLToPath6(import.meta.url));\n  const packageIndex = path11.resolve(__dirname2, \"../..\", \"index.js\");\n  const typeboxEntry = require3.resolve(\"typebox\");\n  const typeboxCompileEntry = require3.resolve(\"typebox/compile\");\n  const typeboxValueEntry = require3.resolve(\"typebox/value\");\n  const packagesRoot = path11.resolve(__dirname2, \"../../../../\");\n  const resolveWorkspaceOrImport = (workspaceRelativePath, specifier) => {\n    const workspacePath = path11.join(packagesRoot, workspaceRelativePath);\n    if (fs7.existsSync(workspacePath)) {\n      return workspacePath;\n    }\n    return fileURLToPath6(import.meta.resolve(specifier));\n  };\n  const piCodingAgentEntry = packageIndex;\n  const piAgentCoreEntry = resolveWorkspaceOrImport(\"agent/dist/index.js\", \"@earendil-works/pi-agent-core\");\n  const piTuiEntry = resolveWorkspaceOrImport(\"tui/dist/index.js\", \"@earendil-works/pi-tui\");\n  const piAiCompatEntry = resolveWorkspaceOrImport(\"ai/dist/compat.js\", \"@earendil-works/pi-ai/compat\");\n  const piAiOauthEntry = resolveWorkspaceOrImport(\"ai/dist/oauth.js\", \"@earendil-works/pi-ai/oauth\");\n  const piAiProvidersEntry = resolveWorkspaceOrImport(\"ai/dist/providers/all.js\", \"@earendil-works/pi-ai/providers/all\");\n  _aliases = {\n    \"@earendil-works/pi-coding-agent\": piCodingAgentEntry,\n    \"@earendil-works/pi-agent-core\": piAgentCoreEntry,\n    \"@earendil-works/pi-tui\": piTuiEntry,\n    \"@earendil-works/pi-ai/providers/all\": piAiProvidersEntry,\n    \"@earendil-works/pi-ai/compat\": piAiCompatEntry,\n    \"@earendil-works/pi-ai/oauth\": piAiOauthEntry,\n    \"@earendil-works/pi-ai\": piAiCompatEntry,\n    \"@mariozechner/pi-coding-agent\": piCodingAgentEntry,\n    \"@mariozechner/pi-agent-core\": piAgentCoreEntry,\n    \"@mariozechner/pi-tui\": piTuiEntry,\n    \"@mariozechner/pi-ai/providers/all\": piAiProvidersEntry,\n    \"@mariozechner/pi-ai/compat\": piAiCompatEntry,\n    \"@mariozechner/pi-ai/oauth\": piAiOauthEntry,\n    \"@mariozechner/pi-ai\": piAiCompatEntry,\n    typebox: typeboxEntry,\n    \"typebox/compile\": typeboxCompileEntry,\n    \"typebox/value\": typeboxValueEntry,\n    \"@sinclair/typebox\": typeboxEntry,\n    \"@sinclair/typebox/compile\": typeboxCompileEntry,\n    \"@sinclair/typebox/value\": typeboxValueEntry\n  };\n  return _aliases;\n}\nvar extensionCacheCwd;\nvar extensionCacheGeneration = 0;\nvar extensionCache = /* @__PURE__ */ new Map();\nfunction clearExtensionCache() {\n  extensionCache.clear();\n  extensionCacheCwd = void 0;\n  extensionCacheGeneration++;\n}\nfunction useExtensionCacheCwd(cwd) {\n  const resolvedCwd = resolvePath(cwd);\n  if (extensionCacheCwd !== void 0 && extensionCacheCwd !== resolvedCwd) {\n    clearExtensionCache();\n  }\n  extensionCacheCwd = resolvedCwd;\n  return { cwd: resolvedCwd, generation: extensionCacheGeneration };\n}\nfunction createExtensionRuntime() {\n  const notInitialized = () => {\n    throw new Error(\"Extension runtime not initialized. Action methods cannot be called during extension loading.\");\n  };\n  const state = {};\n  const eventBusUnsubscribers = /* @__PURE__ */ new Set();\n  const assertActive = () => {\n    if (state.staleMessage) {\n      throw new Error(state.staleMessage);\n    }\n  };\n  const runtime = {\n    sendMessage: notInitialized,\n    sendUserMessage: notInitialized,\n    appendEntry: notInitialized,\n    setSessionName: notInitialized,\n    getSessionName: notInitialized,\n    setLabel: notInitialized,\n    getActiveTools: notInitialized,\n    getAllTools: notInitialized,\n    setActiveTools: notInitialized,\n    // registerTool() is valid during extension load; refresh is only needed post-bind.\n    refreshTools: () => {\n    },\n    getCommands: notInitialized,\n    setModel: () => Promise.reject(new Error(\"Extension runtime not initialized\")),\n    getThinkingLevel: notInitialized,\n    setThinkingLevel: notInitialized,\n    flagValues: /* @__PURE__ */ new Map(),\n    pendingProviderRegistrations: [],\n    pendingNativeProviderRegistrations: [],\n    assertActive,\n    invalidate: (message) => {\n      if (state.staleMessage)\n        return;\n      state.staleMessage = message ?? \"This extension ctx is stale after session replacement or reload. Do not use a captured pi or command ctx after ctx.newSession(), ctx.fork(), ctx.switchSession(), or ctx.reload(). For newSession, fork, and switchSession, move post-replacement work into withSession and use the ctx passed to withSession. For reload, do not use the old ctx after await ctx.reload().\";\n      for (const unsubscribe of eventBusUnsubscribers)\n        unsubscribe();\n      eventBusUnsubscribers.clear();\n    },\n    trackEventBusSubscription: (unsubscribe) => {\n      let active = true;\n      const trackedUnsubscribe = () => {\n        if (!active)\n          return;\n        active = false;\n        eventBusUnsubscribers.delete(trackedUnsubscribe);\n        unsubscribe();\n      };\n      eventBusUnsubscribers.add(trackedUnsubscribe);\n      return trackedUnsubscribe;\n    },\n    // Pre-bind: queue registrations so bindCore() can flush them once the\n    // model registry is available. bindCore() replaces both with direct calls.\n    registerProvider: (name, config, extensionPath = \"<unknown>\") => {\n      runtime.pendingProviderRegistrations.push({ name, config, extensionPath });\n    },\n    registerNativeProvider: (provider, extensionPath = \"<unknown>\") => {\n      runtime.pendingNativeProviderRegistrations.push({ provider, extensionPath });\n    },\n    unregisterProvider: (name) => {\n      runtime.pendingProviderRegistrations = runtime.pendingProviderRegistrations.filter((r) => r.name !== name);\n      runtime.pendingNativeProviderRegistrations = runtime.pendingNativeProviderRegistrations.filter((r) => r.provider.id !== name);\n    }\n  };\n  return runtime;\n}\nfunction createExtensionAPI(extension, runtime, cwd, eventBus) {\n  const api = {\n    // Registration methods - write to extension\n    on(event, handler) {\n      runtime.assertActive();\n      const list = extension.handlers.get(event) ?? [];\n      list.push(handler);\n      extension.handlers.set(event, list);\n    },\n    registerTool(tool) {\n      runtime.assertActive();\n      extension.tools.set(tool.name, {\n        definition: tool,\n        sourceInfo: extension.sourceInfo\n      });\n      runtime.refreshTools();\n    },\n    registerCommand(name, options) {\n      runtime.assertActive();\n      extension.commands.set(name, {\n        name,\n        sourceInfo: extension.sourceInfo,\n        ...options\n      });\n    },\n    registerShortcut(shortcut, options) {\n      runtime.assertActive();\n      extension.shortcuts.set(shortcut, { shortcut, extensionPath: extension.path, ...options });\n    },\n    registerFlag(name, options) {\n      runtime.assertActive();\n      extension.flags.set(name, { name, extensionPath: extension.path, ...options });\n      if (options.default !== void 0 && !runtime.flagValues.has(name)) {\n        runtime.flagValues.set(name, options.default);\n      }\n    },\n    registerMessageRenderer(customType, renderer) {\n      runtime.assertActive();\n      extension.messageRenderers.set(customType, renderer);\n    },\n    registerMarkdownTransformer(transformer) {\n      runtime.assertActive();\n      extension.markdownTransformer = transformer;\n    },\n    registerEntryRenderer(customType, renderer) {\n      runtime.assertActive();\n      extension.entryRenderers ??= /* @__PURE__ */ new Map();\n      extension.entryRenderers.set(customType, renderer);\n    },\n    // Flag access - checks extension registered it, reads from runtime\n    getFlag(name) {\n      runtime.assertActive();\n      if (!extension.flags.has(name))\n        return void 0;\n      return runtime.flagValues.get(name);\n    },\n    // Action methods - delegate to shared runtime\n    sendMessage(message, options) {\n      runtime.assertActive();\n      runtime.sendMessage(message, options);\n    },\n    sendUserMessage(content, options) {\n      runtime.assertActive();\n      runtime.sendUserMessage(content, options);\n    },\n    appendEntry(customType, data) {\n      runtime.assertActive();\n      runtime.appendEntry(customType, data);\n    },\n    setSessionName(name) {\n      runtime.assertActive();\n      runtime.setSessionName(name);\n    },\n    getSessionName() {\n      runtime.assertActive();\n      return runtime.getSessionName();\n    },\n    setLabel(entryId, label) {\n      runtime.assertActive();\n      runtime.setLabel(entryId, label);\n    },\n    exec(command, args, options) {\n      runtime.assertActive();\n      return execCommand(command, args, options?.cwd ?? cwd, options);\n    },\n    getActiveTools() {\n      runtime.assertActive();\n      return runtime.getActiveTools();\n    },\n    getAllTools() {\n      runtime.assertActive();\n      return runtime.getAllTools();\n    },\n    setActiveTools(toolNames) {\n      runtime.assertActive();\n      runtime.setActiveTools(toolNames);\n    },\n    getCommands() {\n      runtime.assertActive();\n      return runtime.getCommands();\n    },\n    setModel(model) {\n      runtime.assertActive();\n      return runtime.setModel(model);\n    },\n    getThinkingLevel() {\n      runtime.assertActive();\n      return runtime.getThinkingLevel();\n    },\n    setThinkingLevel(level) {\n      runtime.assertActive();\n      runtime.setThinkingLevel(level);\n    },\n    registerProvider(providerOrName, config) {\n      runtime.assertActive();\n      if (typeof providerOrName === \"string\") {\n        if (!config)\n          throw new Error(\"Provider config is required when registering by name\");\n        runtime.registerProvider(providerOrName, config, extension.path);\n        return;\n      }\n      runtime.registerNativeProvider(providerOrName, extension.path);\n    },\n    unregisterProvider(name) {\n      runtime.assertActive();\n      runtime.unregisterProvider(name, extension.path);\n    },\n    events: {\n      emit(channel, data) {\n        runtime.assertActive();\n        eventBus.emit(channel, data);\n      },\n      on(channel, handler) {\n        runtime.assertActive();\n        return runtime.trackEventBusSubscription(eventBus.on(channel, handler));\n      }\n    }\n  };\n  return api;\n}\nfunction isCurrentCacheToken(cacheToken) {\n  return cacheToken !== void 0 && extensionCacheCwd === cacheToken.cwd && extensionCacheGeneration === cacheToken.generation;\n}\nasync function loadExtensionModule(extensionPath, cacheToken) {\n  if (isCurrentCacheToken(cacheToken)) {\n    const cachedFactory = extensionCache.get(extensionPath);\n    if (cachedFactory) {\n      return cachedFactory;\n    }\n  }\n  const jiti = createJiti(import.meta.url, {\n    moduleCache: false,\n    // Bun uses modules embedded in the executable. Source TypeScript reuses the\n    // host-resolved modules and root tsconfig paths. Built Node uses dist aliases.\n    ...isBunBinary ? { virtualModules: VIRTUAL_MODULES, tryNative: false } : isTypeScriptSourceRuntime ? { virtualModules: VIRTUAL_MODULES, tsconfigPaths: true } : { virtualModules: VIRTUAL_MODULES, tryNative: false }\n  });\n  const module = await jiti.import(extensionPath, { default: true });\n  const factory = module;\n  if (typeof factory !== \"function\") {\n    return void 0;\n  }\n  if (isCurrentCacheToken(cacheToken)) {\n    extensionCache.set(extensionPath, factory);\n  }\n  return factory;\n}\nfunction createExtension(extensionPath, resolvedPath) {\n  const source = extensionPath.startsWith(\"<\") && extensionPath.endsWith(\">\") ? extensionPath.slice(1, -1).split(\":\")[0] || \"temporary\" : \"local\";\n  const baseDir = extensionPath.startsWith(\"<\") ? void 0 : path11.dirname(resolvedPath);\n  return {\n    path: extensionPath,\n    resolvedPath,\n    sourceInfo: createSyntheticSourceInfo(extensionPath, { source, baseDir }),\n    handlers: /* @__PURE__ */ new Map(),\n    tools: /* @__PURE__ */ new Map(),\n    messageRenderers: /* @__PURE__ */ new Map(),\n    entryRenderers: /* @__PURE__ */ new Map(),\n    commands: /* @__PURE__ */ new Map(),\n    flags: /* @__PURE__ */ new Map(),\n    shortcuts: /* @__PURE__ */ new Map()\n  };\n}\nasync function loadExtension(extensionPath, cwd, eventBus, runtime, cacheToken) {\n  const resolvedPath = resolvePath(extensionPath, cwd, { normalizeUnicodeSpaces: true });\n  try {\n    const factory = await loadExtensionModule(resolvedPath, cacheToken);\n    time(`${extensionPath} module import`, \"extensions\");\n    if (!factory) {\n      return { extension: null, error: `Extension does not export a valid factory function: ${extensionPath}` };\n    }\n    const extension = createExtension(extensionPath, resolvedPath);\n    const api = createExtensionAPI(extension, runtime, cwd, eventBus);\n    await factory(api);\n    time(`${extensionPath} factory`, \"extensions\");\n    return { extension, error: null };\n  } catch (err2) {\n    const message = err2 instanceof Error ? err2.message : String(err2);\n    return { extension: null, error: `Failed to load extension: ${message}` };\n  }\n}\nasync function loadExtensionFromFactory(factory, cwd, eventBus, runtime, extensionPath = \"<inline>\") {\n  const extension = createExtension(extensionPath, extensionPath);\n  const resolvedCwd = resolvePath(cwd);\n  const api = createExtensionAPI(extension, runtime, resolvedCwd, eventBus);\n  await factory(api);\n  time(`${extensionPath} factory`, \"extensions\");\n  return extension;\n}\nasync function loadExtensionsInternal(paths, cwd, eventBus, runtime, useCache = false) {\n  const extensions = [];\n  const errors = [];\n  const cacheToken = useCache ? useExtensionCacheCwd(cwd) : void 0;\n  const resolvedCwd = cacheToken?.cwd ?? resolvePath(cwd);\n  const resolvedEventBus = eventBus ?? createEventBus();\n  const resolvedRuntime = runtime ?? createExtensionRuntime();\n  for (const extPath of paths) {\n    const { extension, error } = await loadExtension(extPath, resolvedCwd, resolvedEventBus, resolvedRuntime, cacheToken);\n    if (error) {\n      errors.push({ path: extPath, error });\n      continue;\n    }\n    if (extension) {\n      extensions.push(extension);\n    }\n  }\n  return {\n    extensions,\n    errors,\n    runtime: resolvedRuntime\n  };\n}\nasync function loadExtensions(paths, cwd, eventBus, runtime) {\n  return loadExtensionsInternal(paths, cwd, eventBus, runtime);\n}\nasync function loadExtensionsCached(paths, cwd, eventBus, runtime) {\n  return loadExtensionsInternal(paths, cwd, eventBus, runtime, true);\n}\nfunction isExtensionFile(name) {\n  return name.endsWith(\".ts\") || name.endsWith(\".js\");\n}\nfunction resolveExtensionEntries2(dir) {\n  const packageJsonPath = path11.join(dir, \"package.json\");\n  if (fs7.existsSync(packageJsonPath)) {\n    const manifest = readPiManifest(packageJsonPath);\n    if (manifest?.extensions?.length) {\n      const entries = [];\n      for (const extPath of manifest.extensions) {\n        const resolvedExtPath = path11.resolve(dir, extPath);\n        if (fs7.existsSync(resolvedExtPath)) {\n          entries.push(resolvedExtPath);\n        }\n      }\n      if (entries.length > 0) {\n        return entries;\n      }\n    }\n  }\n  const indexTs = path11.join(dir, \"index.ts\");\n  const indexJs = path11.join(dir, \"index.js\");\n  if (fs7.existsSync(indexTs)) {\n    return [indexTs];\n  }\n  if (fs7.existsSync(indexJs)) {\n    return [indexJs];\n  }\n  return null;\n}\nfunction discoverExtensionsInDir(dir) {\n  if (!fs7.existsSync(dir)) {\n    return [];\n  }\n  const discovered = [];\n  try {\n    const entries = fs7.readdirSync(dir, { withFileTypes: true });\n    for (const entry of entries) {\n      const entryPath = path11.join(dir, entry.name);\n      if ((entry.isFile() || entry.isSymbolicLink()) && isExtensionFile(entry.name)) {\n        discovered.push(entryPath);\n        continue;\n      }\n      if (entry.isDirectory() || entry.isSymbolicLink()) {\n        const entries2 = resolveExtensionEntries2(entryPath);\n        if (entries2) {\n          discovered.push(...entries2);\n        }\n      }\n    }\n  } catch {\n    return [];\n  }\n  return discovered;\n}\nasync function discoverAndLoadExtensions(configuredPaths, cwd, agentDir = getAgentDir(), eventBus) {\n  const resolvedCwd = resolvePath(cwd);\n  const resolvedAgentDir = resolvePath(agentDir);\n  const allPaths = [];\n  const seen = /* @__PURE__ */ new Set();\n  const addPaths = (paths) => {\n    for (const p of paths) {\n      const resolved = path11.resolve(p);\n      if (!seen.has(resolved)) {\n        seen.add(resolved);\n        allPaths.push(p);\n      }\n    }\n  };\n  const localExtDir = path11.join(resolvedCwd, CONFIG_DIR_NAME, \"extensions\");\n  addPaths(discoverExtensionsInDir(localExtDir));\n  const globalExtDir = path11.join(resolvedAgentDir, \"extensions\");\n  addPaths(discoverExtensionsInDir(globalExtDir));\n  for (const p of configuredPaths) {\n    const resolved = resolvePath(p, resolvedCwd, { normalizeUnicodeSpaces: true });\n    if (fs7.existsSync(resolved) && fs7.statSync(resolved).isDirectory()) {\n      const entries = resolveExtensionEntries2(resolved);\n      if (entries) {\n        addPaths(entries);\n        continue;\n      }\n      addPaths(discoverExtensionsInDir(resolved));\n      continue;\n    }\n    addPaths([resolved]);\n  }\n  return loadExtensions(allPaths, resolvedCwd, eventBus);\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/core/resource-loader.js\nfunction resolvePromptInput(input, description) {\n  if (!input) {\n    return void 0;\n  }\n  if (existsSync22(input)) {\n    try {\n      return readFileSync18(input, \"utf-8\");\n    } catch (error) {\n      console.error(chalk8.yellow(`Warning: Could not read ${description} file ${input}: ${error}`));\n      return input;\n    }\n  }\n  return input;\n}\nfunction loadContextFileFromDir(dir) {\n  const candidates = [\"AGENTS.override.md\", \"AGENTS.md\", \"AGENTS.MD\", \"CLAUDE.md\", \"CLAUDE.MD\"];\n  for (const filename of candidates) {\n    const filePath = join32(dir, filename);\n    if (existsSync22(filePath)) {\n      try {\n        if (!statSync10(filePath).isFile()) {\n          continue;\n        }\n        return {\n          path: filePath,\n          content: readFileSync18(filePath, \"utf-8\")\n        };\n      } catch (error) {\n        console.error(chalk8.yellow(`Warning: Could not read ${filePath}: ${error}`));\n      }\n    }\n  }\n  return null;\n}\nfunction findShadowedContextFile(cwd) {\n  const gitPaths = findGitPaths(cwd);\n  if (!gitPaths)\n    return void 0;\n  const commonGitDir = canonicalizePath(gitPaths.commonGitDir);\n  const worktreeRoot = canonicalizePath(gitPaths.repoDir);\n  const mainRepoRoot = dirname21(commonGitDir);\n  if (!worktreeRoot.startsWith(`${mainRepoRoot}${sep9}`))\n    return void 0;\n  if (canonicalizePath(join32(mainRepoRoot, \".git\")) !== commonGitDir)\n    return void 0;\n  const worktreeContextFile = loadContextFileFromDir(worktreeRoot);\n  return worktreeContextFile ? join32(mainRepoRoot, basename10(worktreeContextFile.path)) : void 0;\n}\nfunction loadProjectContextFiles(options) {\n  const resolvedCwd = resolvePath(options.cwd);\n  const resolvedAgentDir = resolvePath(options.agentDir);\n  const contextFiles = [];\n  const seenPaths = /* @__PURE__ */ new Set();\n  const globalContext = loadContextFileFromDir(resolvedAgentDir);\n  if (globalContext) {\n    contextFiles.push(globalContext);\n    seenPaths.add(globalContext.path);\n  }\n  const ancestorContextFiles = [];\n  const shadowedContextFile = findShadowedContextFile(resolvedCwd);\n  let currentDir = resolvedCwd;\n  while (true) {\n    const contextFile = loadContextFileFromDir(currentDir);\n    const isShadowed = shadowedContextFile !== void 0 && canonicalizePath(contextFile?.path ?? \"\") === shadowedContextFile;\n    if (contextFile && !isShadowed && !seenPaths.has(contextFile.path)) {\n      ancestorContextFiles.unshift(contextFile);\n      seenPaths.add(contextFile.path);\n    }\n    const parentDir = dirname21(currentDir);\n    if (parentDir === currentDir)\n      break;\n    currentDir = parentDir;\n  }\n  contextFiles.push(...ancestorContextFiles);\n  return contextFiles;\n}\nvar DefaultResourceLoader = class {\n  cwd;\n  agentDir;\n  settingsManager;\n  eventBus;\n  packageManager;\n  additionalExtensionPaths;\n  additionalSkillPaths;\n  additionalPromptTemplatePaths;\n  additionalThemePaths;\n  extensionFactories;\n  noExtensions;\n  noSkills;\n  noPromptTemplates;\n  noThemes;\n  noContextFiles;\n  systemPromptSource;\n  appendSystemPromptSource;\n  extensionsOverride;\n  skillsOverride;\n  promptsOverride;\n  themesOverride;\n  agentsFilesOverride;\n  systemPromptOverride;\n  appendSystemPromptOverride;\n  extensionsResult;\n  skills;\n  skillDiagnostics;\n  prompts;\n  promptDiagnostics;\n  themes;\n  themeDiagnostics;\n  agentsFiles;\n  systemPrompt;\n  systemPromptSourcePath;\n  appendSystemPrompt;\n  appendSystemPromptSourcePaths;\n  lastSkillPaths;\n  extensionSkillSourceInfos;\n  extensionPromptSourceInfos;\n  extensionThemeSourceInfos;\n  resourceMetadataByPath;\n  lastPromptPaths;\n  lastThemePaths;\n  loaded;\n  constructor(options) {\n    this.cwd = resolvePath(options.cwd);\n    this.agentDir = resolvePath(options.agentDir);\n    this.settingsManager = options.settingsManager ?? SettingsManager.create(this.cwd, this.agentDir);\n    this.eventBus = options.eventBus ?? createEventBus();\n    this.packageManager = new DefaultPackageManager({\n      cwd: this.cwd,\n      agentDir: this.agentDir,\n      settingsManager: this.settingsManager\n    });\n    this.additionalExtensionPaths = options.additionalExtensionPaths ?? [];\n    this.additionalSkillPaths = options.additionalSkillPaths ?? [];\n    this.additionalPromptTemplatePaths = options.additionalPromptTemplatePaths ?? [];\n    this.additionalThemePaths = options.additionalThemePaths ?? [];\n    this.extensionFactories = options.extensionFactories ?? [];\n    this.noExtensions = options.noExtensions ?? false;\n    this.noSkills = options.noSkills ?? false;\n    this.noPromptTemplates = options.noPromptTemplates ?? false;\n    this.noThemes = options.noThemes ?? false;\n    this.noContextFiles = options.noContextFiles ?? false;\n    this.systemPromptSource = options.systemPrompt;\n    this.appendSystemPromptSource = options.appendSystemPrompt;\n    this.extensionsOverride = options.extensionsOverride;\n    this.skillsOverride = options.skillsOverride;\n    this.promptsOverride = options.promptsOverride;\n    this.themesOverride = options.themesOverride;\n    this.agentsFilesOverride = options.agentsFilesOverride;\n    this.systemPromptOverride = options.systemPromptOverride;\n    this.appendSystemPromptOverride = options.appendSystemPromptOverride;\n    this.extensionsResult = { extensions: [], errors: [], runtime: createExtensionRuntime() };\n    this.skills = [];\n    this.skillDiagnostics = [];\n    this.prompts = [];\n    this.promptDiagnostics = [];\n    this.themes = [];\n    this.themeDiagnostics = [];\n    this.agentsFiles = [];\n    this.appendSystemPrompt = [];\n    this.appendSystemPromptSourcePaths = [];\n    this.lastSkillPaths = [];\n    this.extensionSkillSourceInfos = /* @__PURE__ */ new Map();\n    this.extensionPromptSourceInfos = /* @__PURE__ */ new Map();\n    this.extensionThemeSourceInfos = /* @__PURE__ */ new Map();\n    this.resourceMetadataByPath = /* @__PURE__ */ new Map();\n    this.lastPromptPaths = [];\n    this.lastThemePaths = [];\n    this.loaded = false;\n  }\n  getExtensions() {\n    return this.extensionsResult;\n  }\n  getSkills() {\n    return { skills: this.skills, diagnostics: this.skillDiagnostics };\n  }\n  getPrompts() {\n    return { prompts: this.prompts, diagnostics: this.promptDiagnostics };\n  }\n  getThemes() {\n    return { themes: this.themes, diagnostics: this.themeDiagnostics };\n  }\n  getAgentsFiles() {\n    return { agentsFiles: this.agentsFiles };\n  }\n  getSystemPrompt() {\n    return this.systemPrompt;\n  }\n  getSystemPromptSource() {\n    return this.systemPromptSourcePath ? { path: this.systemPromptSourcePath } : void 0;\n  }\n  getAppendSystemPrompt() {\n    return this.appendSystemPrompt;\n  }\n  getAppendSystemPromptSources() {\n    return this.appendSystemPromptSourcePaths.map((path12) => ({ path: path12 }));\n  }\n  extendResources(paths) {\n    const skillPaths = this.normalizeExtensionPaths(paths.skillPaths ?? []);\n    const promptPaths = this.normalizeExtensionPaths(paths.promptPaths ?? []);\n    const themePaths = this.normalizeExtensionPaths(paths.themePaths ?? []);\n    for (const entry of skillPaths) {\n      this.extensionSkillSourceInfos.set(entry.path, createSourceInfo(entry.path, entry.metadata));\n    }\n    for (const entry of promptPaths) {\n      this.extensionPromptSourceInfos.set(entry.path, createSourceInfo(entry.path, entry.metadata));\n    }\n    for (const entry of themePaths) {\n      this.extensionThemeSourceInfos.set(entry.path, createSourceInfo(entry.path, entry.metadata));\n    }\n    if (skillPaths.length > 0) {\n      this.lastSkillPaths = this.mergePaths(this.lastSkillPaths, skillPaths.map((entry) => entry.path));\n      this.updateSkillsFromPaths(this.lastSkillPaths, this.resourceMetadataByPath);\n    }\n    if (promptPaths.length > 0) {\n      this.lastPromptPaths = this.mergePaths(this.lastPromptPaths, promptPaths.map((entry) => entry.path));\n      this.updatePromptsFromPaths(this.lastPromptPaths, this.resourceMetadataByPath);\n    }\n    if (themePaths.length > 0) {\n      this.lastThemePaths = this.mergePaths(this.lastThemePaths, themePaths.map((entry) => entry.path));\n      this.updateThemesFromPaths(this.lastThemePaths, this.resourceMetadataByPath);\n    }\n  }\n  async loadProjectTrustExtensions() {\n    this.settingsManager.setProjectTrusted(false);\n    await this.settingsManager.reload();\n    return this.loadCurrentExtensionSet({ includeInlineFactories: true });\n  }\n  async reload(options) {\n    resetTimings(\"extensions\");\n    if (this.loaded) {\n      clearExtensionCache();\n    }\n    let preTrustExtensions;\n    if (options?.resolveProjectTrust) {\n      preTrustExtensions = await this.loadProjectTrustExtensions();\n      const projectTrusted = await options.resolveProjectTrust({ extensionsResult: preTrustExtensions });\n      this.settingsManager.setProjectTrusted(projectTrusted);\n    }\n    await this.settingsManager.reload();\n    const resolvedPaths = await this.packageManager.resolve();\n    const cliExtensionPaths = await this.packageManager.resolveExtensionSources(this.additionalExtensionPaths, {\n      temporary: true\n    });\n    this.resourceMetadataByPath = /* @__PURE__ */ new Map();\n    const metadataByPath = this.resourceMetadataByPath;\n    this.extensionSkillSourceInfos = /* @__PURE__ */ new Map();\n    this.extensionPromptSourceInfos = /* @__PURE__ */ new Map();\n    this.extensionThemeSourceInfos = /* @__PURE__ */ new Map();\n    const getEnabledResources = (resources) => {\n      for (const r of resources) {\n        if (!metadataByPath.has(r.path)) {\n          metadataByPath.set(r.path, r.metadata);\n        }\n      }\n      return resources.filter((r) => r.enabled);\n    };\n    const getEnabledPaths = (resources) => getEnabledResources(resources).map((r) => r.path);\n    const enabledExtensions = getEnabledPaths(resolvedPaths.extensions);\n    const enabledSkillResources = getEnabledResources(resolvedPaths.skills);\n    const enabledPrompts = getEnabledPaths(resolvedPaths.prompts);\n    const enabledThemes = getEnabledPaths(resolvedPaths.themes);\n    const enabledSkills = enabledSkillResources.map((resource) => this.mapSkillPath(resource, metadataByPath));\n    for (const r of cliExtensionPaths.extensions) {\n      if (!metadataByPath.has(r.path)) {\n        metadataByPath.set(r.path, { source: \"cli\", scope: \"temporary\", origin: \"top-level\" });\n      }\n    }\n    for (const r of cliExtensionPaths.skills) {\n      if (!metadataByPath.has(r.path)) {\n        metadataByPath.set(r.path, { source: \"cli\", scope: \"temporary\", origin: \"top-level\" });\n      }\n    }\n    const cliEnabledExtensions = getEnabledPaths(cliExtensionPaths.extensions);\n    const cliEnabledSkills = getEnabledPaths(cliExtensionPaths.skills);\n    const cliEnabledPrompts = getEnabledPaths(cliExtensionPaths.prompts);\n    const cliEnabledThemes = getEnabledPaths(cliExtensionPaths.themes);\n    const extensionPaths = this.noExtensions ? cliEnabledExtensions : this.mergePaths(cliEnabledExtensions, enabledExtensions);\n    const extensionsResult = await this.loadFinalExtensionSet(extensionPaths, preTrustExtensions);\n    for (const p of this.additionalExtensionPaths) {\n      if (isLocalPath(p)) {\n        const resolved = this.resolveResourcePath(p);\n        if (!existsSync22(resolved)) {\n          extensionsResult.errors.push({ path: resolved, error: `Extension path does not exist: ${resolved}` });\n        }\n      }\n    }\n    this.extensionsResult = this.extensionsOverride ? this.extensionsOverride(extensionsResult) : extensionsResult;\n    this.applyExtensionSourceInfo(this.extensionsResult.extensions, metadataByPath);\n    const skillPaths = this.noSkills ? this.mergePaths(cliEnabledSkills, this.additionalSkillPaths) : this.mergePaths([...cliEnabledSkills, ...enabledSkills], this.additionalSkillPaths);\n    this.lastSkillPaths = skillPaths;\n    this.updateSkillsFromPaths(skillPaths, metadataByPath);\n    for (const p of this.additionalSkillPaths) {\n      if (isLocalPath(p)) {\n        const resolved = this.resolveResourcePath(p);\n        if (!existsSync22(resolved) && !this.skillDiagnostics.some((d) => d.path === resolved)) {\n          this.skillDiagnostics.push({ type: \"error\", message: \"Skill path does not exist\", path: resolved });\n        }\n      }\n    }\n    const promptPaths = this.noPromptTemplates ? this.mergePaths(cliEnabledPrompts, this.additionalPromptTemplatePaths) : this.mergePaths([...cliEnabledPrompts, ...enabledPrompts], this.additionalPromptTemplatePaths);\n    this.lastPromptPaths = promptPaths;\n    this.updatePromptsFromPaths(promptPaths, metadataByPath);\n    for (const p of this.additionalPromptTemplatePaths) {\n      if (isLocalPath(p)) {\n        const resolved = this.resolveResourcePath(p);\n        if (!existsSync22(resolved) && !this.promptDiagnostics.some((d) => d.path === resolved)) {\n          this.promptDiagnostics.push({\n            type: \"error\",\n            message: \"Prompt template path does not exist\",\n            path: resolved\n          });\n        }\n      }\n    }\n    const themePaths = this.noThemes ? this.mergePaths(cliEnabledThemes, this.additionalThemePaths) : this.mergePaths([...cliEnabledThemes, ...enabledThemes], this.additionalThemePaths);\n    this.lastThemePaths = themePaths;\n    this.updateThemesFromPaths(themePaths, metadataByPath);\n    for (const p of this.additionalThemePaths) {\n      const resolved = this.resolveResourcePath(p);\n      if (!existsSync22(resolved) && !this.themeDiagnostics.some((d) => d.path === resolved)) {\n        this.themeDiagnostics.push({ type: \"error\", message: \"Theme path does not exist\", path: resolved });\n      }\n    }\n    const agentsFiles = {\n      agentsFiles: this.noContextFiles ? [] : loadProjectContextFiles({\n        cwd: this.cwd,\n        agentDir: this.agentDir\n      })\n    };\n    const resolvedAgentsFiles = this.agentsFilesOverride ? this.agentsFilesOverride(agentsFiles) : agentsFiles;\n    this.agentsFiles = resolvedAgentsFiles.agentsFiles;\n    const systemPromptSource = this.systemPromptSource ?? this.discoverSystemPromptFile();\n    const baseSystemPrompt = resolvePromptInput(systemPromptSource, \"system prompt\");\n    this.systemPrompt = this.systemPromptOverride ? this.systemPromptOverride(baseSystemPrompt) : baseSystemPrompt;\n    this.systemPromptSourcePath = systemPromptSource && existsSync22(systemPromptSource) ? resolvePath(systemPromptSource) : void 0;\n    let appendSources = this.appendSystemPromptSource;\n    if (!appendSources) {\n      const discoveredAppendSystemPromptFile = this.discoverAppendSystemPromptFile();\n      appendSources = discoveredAppendSystemPromptFile ? [discoveredAppendSystemPromptFile] : [];\n    }\n    const baseAppend = appendSources.map((s) => resolvePromptInput(s, \"append system prompt\")).filter((s) => s !== void 0);\n    this.appendSystemPrompt = this.appendSystemPromptOverride ? this.appendSystemPromptOverride(baseAppend) : baseAppend;\n    this.appendSystemPromptSourcePaths = appendSources.filter((source) => existsSync22(source)).map((source) => resolvePath(source));\n    this.loaded = true;\n  }\n  async loadCurrentExtensionSet(options) {\n    const resolvedPaths = await this.packageManager.resolve();\n    const cliExtensionPaths = await this.packageManager.resolveExtensionSources(this.additionalExtensionPaths, {\n      temporary: true\n    });\n    const enabledExtensions = resolvedPaths.extensions.filter((r) => r.enabled).map((r) => r.path);\n    const cliEnabledExtensions = cliExtensionPaths.extensions.filter((r) => r.enabled).map((r) => r.path);\n    const extensionPaths = this.noExtensions ? cliEnabledExtensions : this.mergePaths(cliEnabledExtensions, enabledExtensions);\n    const extensionsResult = await loadExtensionsCached(extensionPaths, this.cwd, this.eventBus);\n    if (!options.includeInlineFactories) {\n      return extensionsResult;\n    }\n    const inlineExtensions = await this.loadExtensionFactories(extensionsResult.runtime);\n    extensionsResult.extensions.push(...inlineExtensions.extensions);\n    extensionsResult.errors.push(...inlineExtensions.errors);\n    return extensionsResult;\n  }\n  resolveExtensionLoadPath(path12) {\n    return resolvePath(path12, this.cwd, { normalizeUnicodeSpaces: true });\n  }\n  async loadFinalExtensionSet(extensionPaths, preTrustExtensions) {\n    if (!preTrustExtensions) {\n      const extensionsResult2 = await loadExtensionsCached(extensionPaths, this.cwd, this.eventBus);\n      const inlineExtensions2 = await this.loadExtensionFactories(extensionsResult2.runtime);\n      extensionsResult2.extensions.push(...inlineExtensions2.extensions);\n      extensionsResult2.errors.push(...inlineExtensions2.errors);\n      this.addExtensionConflictDiagnostics(extensionsResult2);\n      return extensionsResult2;\n    }\n    const preloadedByPath = new Map(preTrustExtensions.extensions.filter((extension) => !extension.path.startsWith(\"<inline:\")).map((extension) => [extension.resolvedPath, extension]));\n    const failedPreloadPaths = new Set(preTrustExtensions.errors.map((error) => this.resolveExtensionLoadPath(error.path)));\n    const remainingPaths = extensionPaths.filter((path12) => {\n      const resolvedPath = this.resolveExtensionLoadPath(path12);\n      return !preloadedByPath.has(resolvedPath) && !failedPreloadPaths.has(resolvedPath);\n    });\n    const remainingExtensions = await loadExtensionsCached(remainingPaths, this.cwd, this.eventBus, preTrustExtensions.runtime);\n    const loadedByPath = new Map(preloadedByPath);\n    for (const extension of remainingExtensions.extensions) {\n      loadedByPath.set(extension.resolvedPath, extension);\n    }\n    const inlineExtensions = preTrustExtensions.extensions.filter((extension) => extension.path.startsWith(\"<inline:\"));\n    const orderedExtensions = extensionPaths.map((path12) => loadedByPath.get(this.resolveExtensionLoadPath(path12))).filter((extension) => extension !== void 0);\n    orderedExtensions.push(...inlineExtensions);\n    const extensionsResult = {\n      extensions: orderedExtensions,\n      errors: [...preTrustExtensions.errors, ...remainingExtensions.errors],\n      runtime: preTrustExtensions.runtime\n    };\n    this.addExtensionConflictDiagnostics(extensionsResult);\n    return extensionsResult;\n  }\n  addExtensionConflictDiagnostics(extensionsResult) {\n    const conflicts = this.detectExtensionConflicts(extensionsResult.extensions);\n    for (const conflict of conflicts) {\n      extensionsResult.errors.push({ path: conflict.path, error: conflict.message });\n    }\n  }\n  mapSkillPath(resource, metadataByPath) {\n    if (resource.metadata.source !== \"auto\" && resource.metadata.origin !== \"package\") {\n      return resource.path;\n    }\n    try {\n      const stats = statSync10(resource.path);\n      if (!stats.isDirectory()) {\n        return resource.path;\n      }\n    } catch {\n      return resource.path;\n    }\n    const skillFile = join32(resource.path, \"SKILL.md\");\n    if (existsSync22(skillFile)) {\n      if (!metadataByPath.has(skillFile)) {\n        metadataByPath.set(skillFile, resource.metadata);\n      }\n      return skillFile;\n    }\n    return resource.path;\n  }\n  normalizeExtensionPaths(entries) {\n    return entries.map((entry) => {\n      const metadata = entry.metadata.baseDir ? { ...entry.metadata, baseDir: this.resolveResourcePath(entry.metadata.baseDir) } : entry.metadata;\n      return {\n        path: this.resolveResourcePath(entry.path),\n        metadata\n      };\n    });\n  }\n  updateSkillsFromPaths(skillPaths, metadataByPath) {\n    let skillsResult;\n    if (this.noSkills && skillPaths.length === 0) {\n      skillsResult = { skills: [], diagnostics: [] };\n    } else {\n      skillsResult = loadSkills2({\n        cwd: this.cwd,\n        agentDir: this.agentDir,\n        skillPaths,\n        includeDefaults: false\n      });\n    }\n    const resolvedSkills = this.skillsOverride ? this.skillsOverride(skillsResult) : skillsResult;\n    this.skills = resolvedSkills.skills.map((skill) => ({\n      ...skill,\n      sourceInfo: this.findSourceInfoForPath(skill.filePath, this.extensionSkillSourceInfos, metadataByPath) ?? skill.sourceInfo ?? this.getDefaultSourceInfoForPath(skill.filePath)\n    }));\n    this.skillDiagnostics = resolvedSkills.diagnostics;\n  }\n  updatePromptsFromPaths(promptPaths, metadataByPath) {\n    let promptsResult;\n    if (this.noPromptTemplates && promptPaths.length === 0) {\n      promptsResult = { prompts: [], diagnostics: [] };\n    } else {\n      const allPrompts = loadPromptTemplates2({\n        cwd: this.cwd,\n        agentDir: this.agentDir,\n        promptPaths,\n        includeDefaults: false\n      });\n      promptsResult = this.dedupePrompts(allPrompts);\n    }\n    const resolvedPrompts = this.promptsOverride ? this.promptsOverride(promptsResult) : promptsResult;\n    this.prompts = resolvedPrompts.prompts.map((prompt) => ({\n      ...prompt,\n      sourceInfo: this.findSourceInfoForPath(prompt.filePath, this.extensionPromptSourceInfos, metadataByPath) ?? prompt.sourceInfo ?? this.getDefaultSourceInfoForPath(prompt.filePath)\n    }));\n    this.promptDiagnostics = resolvedPrompts.diagnostics;\n  }\n  updateThemesFromPaths(themePaths, metadataByPath) {\n    let themesResult;\n    if (this.noThemes && themePaths.length === 0) {\n      themesResult = { themes: [], diagnostics: [] };\n    } else {\n      const loaded = this.loadThemes(themePaths, false);\n      const deduped = this.dedupeThemes(loaded.themes);\n      themesResult = { themes: deduped.themes, diagnostics: [...loaded.diagnostics, ...deduped.diagnostics] };\n    }\n    const resolvedThemes = this.themesOverride ? this.themesOverride(themesResult) : themesResult;\n    this.themes = resolvedThemes.themes.map((theme2) => {\n      const sourcePath = theme2.sourcePath;\n      theme2.sourceInfo = sourcePath ? this.findSourceInfoForPath(sourcePath, this.extensionThemeSourceInfos, metadataByPath) ?? theme2.sourceInfo ?? this.getDefaultSourceInfoForPath(sourcePath) : theme2.sourceInfo;\n      return theme2;\n    });\n    this.themeDiagnostics = resolvedThemes.diagnostics;\n  }\n  applyExtensionSourceInfo(extensions, metadataByPath) {\n    for (const extension of extensions) {\n      extension.sourceInfo = this.findSourceInfoForPath(extension.path, void 0, metadataByPath) ?? this.getDefaultSourceInfoForPath(extension.path);\n      for (const command of extension.commands.values()) {\n        command.sourceInfo = extension.sourceInfo;\n      }\n      for (const tool of extension.tools.values()) {\n        tool.sourceInfo = extension.sourceInfo;\n      }\n    }\n  }\n  findSourceInfoForPath(resourcePath, extraSourceInfos, metadataByPath) {\n    if (!resourcePath) {\n      return void 0;\n    }\n    if (resourcePath.startsWith(\"<\")) {\n      return this.getDefaultSourceInfoForPath(resourcePath);\n    }\n    const normalizedResourcePath = resolve12(resourcePath);\n    if (extraSourceInfos) {\n      for (const [sourcePath, sourceInfo] of extraSourceInfos.entries()) {\n        const normalizedSourcePath = resolve12(sourcePath);\n        if (normalizedResourcePath === normalizedSourcePath || normalizedResourcePath.startsWith(`${normalizedSourcePath}${sep9}`)) {\n          return { ...sourceInfo, path: resourcePath };\n        }\n      }\n    }\n    if (metadataByPath) {\n      const exact = metadataByPath.get(normalizedResourcePath) ?? metadataByPath.get(resourcePath);\n      if (exact) {\n        return createSourceInfo(resourcePath, exact);\n      }\n      for (const [sourcePath, metadata] of metadataByPath.entries()) {\n        const normalizedSourcePath = resolve12(sourcePath);\n        if (normalizedResourcePath === normalizedSourcePath || normalizedResourcePath.startsWith(`${normalizedSourcePath}${sep9}`)) {\n          return createSourceInfo(resourcePath, metadata);\n        }\n      }\n    }\n    return void 0;\n  }\n  getDefaultSourceInfoForPath(filePath) {\n    if (filePath.startsWith(\"<\") && filePath.endsWith(\">\")) {\n      return {\n        path: filePath,\n        source: filePath.slice(1, -1).split(\":\")[0] || \"temporary\",\n        scope: \"temporary\",\n        origin: \"top-level\"\n      };\n    }\n    const normalizedPath = resolve12(filePath);\n    const agentRoots = [\n      join32(this.agentDir, \"skills\"),\n      join32(this.agentDir, \"prompts\"),\n      join32(this.agentDir, \"themes\"),\n      join32(this.agentDir, \"extensions\")\n    ];\n    const projectRoots = [\n      join32(this.cwd, CONFIG_DIR_NAME, \"skills\"),\n      join32(this.cwd, CONFIG_DIR_NAME, \"prompts\"),\n      join32(this.cwd, CONFIG_DIR_NAME, \"themes\"),\n      join32(this.cwd, CONFIG_DIR_NAME, \"extensions\")\n    ];\n    for (const root of agentRoots) {\n      if (this.isUnderPath(normalizedPath, root)) {\n        return { path: filePath, source: \"local\", scope: \"user\", origin: \"top-level\", baseDir: root };\n      }\n    }\n    for (const root of projectRoots) {\n      if (this.isUnderPath(normalizedPath, root)) {\n        return { path: filePath, source: \"local\", scope: \"project\", origin: \"top-level\", baseDir: root };\n      }\n    }\n    return {\n      path: filePath,\n      source: \"local\",\n      scope: \"temporary\",\n      origin: \"top-level\",\n      baseDir: statSync10(normalizedPath).isDirectory() ? normalizedPath : resolve12(normalizedPath, \"..\")\n    };\n  }\n  mergePaths(primary, additional) {\n    const merged = [];\n    const seen = /* @__PURE__ */ new Set();\n    for (const p of [...primary, ...additional]) {\n      const resolved = this.resolveResourcePath(p);\n      const canonicalPath = canonicalizePath(resolved);\n      if (seen.has(canonicalPath))\n        continue;\n      seen.add(canonicalPath);\n      merged.push(resolved);\n    }\n    return merged;\n  }\n  resolveResourcePath(p) {\n    return resolvePath(p, this.cwd, { trim: true });\n  }\n  loadThemes(paths, includeDefaults = true) {\n    const themes = [];\n    const diagnostics = [];\n    if (includeDefaults) {\n      const defaultDirs = [join32(this.agentDir, \"themes\"), join32(this.cwd, CONFIG_DIR_NAME, \"themes\")];\n      for (const dir of defaultDirs) {\n        this.loadThemesFromDir(dir, themes, diagnostics);\n      }\n    }\n    for (const p of paths) {\n      const resolved = this.resolveResourcePath(p);\n      if (!existsSync22(resolved)) {\n        diagnostics.push({ type: \"warning\", message: \"theme path does not exist\", path: resolved });\n        continue;\n      }\n      try {\n        const stats = statSync10(resolved);\n        if (stats.isDirectory()) {\n          this.loadThemesFromDir(resolved, themes, diagnostics);\n        } else if (stats.isFile() && resolved.endsWith(\".json\")) {\n          this.loadThemeFromFile(resolved, themes, diagnostics);\n        } else {\n          diagnostics.push({ type: \"warning\", message: \"theme path is not a json file\", path: resolved });\n        }\n      } catch (error) {\n        const message = error instanceof Error ? error.message : \"failed to read theme path\";\n        diagnostics.push({ type: \"warning\", message, path: resolved });\n      }\n    }\n    return { themes, diagnostics };\n  }\n  loadThemesFromDir(dir, themes, diagnostics) {\n    if (!existsSync22(dir)) {\n      return;\n    }\n    try {\n      const entries = readdirSync9(dir, { withFileTypes: true });\n      for (const entry of entries) {\n        let isFile = entry.isFile();\n        if (entry.isSymbolicLink()) {\n          try {\n            isFile = statSync10(join32(dir, entry.name)).isFile();\n          } catch {\n            continue;\n          }\n        }\n        if (!isFile) {\n          continue;\n        }\n        if (!entry.name.endsWith(\".json\")) {\n          continue;\n        }\n        this.loadThemeFromFile(join32(dir, entry.name), themes, diagnostics);\n      }\n    } catch (error) {\n      const message = error instanceof Error ? error.message : \"failed to read theme directory\";\n      diagnostics.push({ type: \"warning\", message, path: dir });\n    }\n  }\n  loadThemeFromFile(filePath, themes, diagnostics) {\n    try {\n      themes.push(loadThemeFromPath(filePath));\n    } catch (error) {\n      const message = error instanceof Error ? error.message : \"failed to load theme\";\n      diagnostics.push({ type: \"warning\", message, path: filePath });\n    }\n  }\n  async loadExtensionFactories(runtime) {\n    const extensions = [];\n    const errors = [];\n    for (const [index, input] of this.extensionFactories.entries()) {\n      const isNamed = typeof input !== \"function\";\n      const factory = isNamed ? input.factory : input;\n      const extensionPath = `<inline:${isNamed ? input.name : index + 1}>`;\n      try {\n        const extension = await loadExtensionFromFactory(factory, this.cwd, this.eventBus, runtime, extensionPath);\n        extension.hidden = isNamed && input.hidden;\n        extensions.push(extension);\n      } catch (error) {\n        const message = error instanceof Error ? error.message : \"failed to load extension\";\n        errors.push({ path: extensionPath, error: message });\n      }\n    }\n    return { extensions, errors };\n  }\n  dedupePrompts(prompts) {\n    const seen = /* @__PURE__ */ new Map();\n    const diagnostics = [];\n    for (const prompt of prompts) {\n      const existing = seen.get(prompt.name);\n      if (existing) {\n        diagnostics.push({\n          type: \"collision\",\n          message: `name \"/${prompt.name}\" collision`,\n          path: prompt.filePath,\n          collision: {\n            resourceType: \"prompt\",\n            name: prompt.name,\n            winnerPath: existing.filePath,\n            loserPath: prompt.filePath\n          }\n        });\n      } else {\n        seen.set(prompt.name, prompt);\n      }\n    }\n    return { prompts: Array.from(seen.values()), diagnostics };\n  }\n  dedupeThemes(themes) {\n    const seen = /* @__PURE__ */ new Map();\n    const diagnostics = [];\n    for (const t of themes) {\n      const name = t.name ?? \"unnamed\";\n      const existing = seen.get(name);\n      if (existing) {\n        diagnostics.push({\n          type: \"collision\",\n          message: `name \"${name}\" collision`,\n          path: t.sourcePath,\n          collision: {\n            resourceType: \"theme\",\n            name,\n            winnerPath: existing.sourcePath ?? \"<builtin>\",\n            loserPath: t.sourcePath ?? \"<builtin>\"\n          }\n        });\n      } else {\n        seen.set(name, t);\n      }\n    }\n    return { themes: Array.from(seen.values()), diagnostics };\n  }\n  discoverSystemPromptFile() {\n    const projectPath = join32(this.cwd, CONFIG_DIR_NAME, \"SYSTEM.md\");\n    if (this.settingsManager.isProjectTrusted() && existsSync22(projectPath)) {\n      return projectPath;\n    }\n    const globalPath = join32(this.agentDir, \"SYSTEM.md\");\n    if (existsSync22(globalPath)) {\n      return globalPath;\n    }\n    return void 0;\n  }\n  discoverAppendSystemPromptFile() {\n    const projectPath = join32(this.cwd, CONFIG_DIR_NAME, \"APPEND_SYSTEM.md\");\n    if (this.settingsManager.isProjectTrusted() && existsSync22(projectPath)) {\n      return projectPath;\n    }\n    const globalPath = join32(this.agentDir, \"APPEND_SYSTEM.md\");\n    if (existsSync22(globalPath)) {\n      return globalPath;\n    }\n    return void 0;\n  }\n  isUnderPath(target, root) {\n    const normalizedRoot = resolve12(root);\n    if (target === normalizedRoot) {\n      return true;\n    }\n    const prefix = normalizedRoot.endsWith(sep9) ? normalizedRoot : `${normalizedRoot}${sep9}`;\n    return target.startsWith(prefix);\n  }\n  detectExtensionConflicts(extensions) {\n    const conflicts = [];\n    const toolOwners = /* @__PURE__ */ new Map();\n    const flagOwners = /* @__PURE__ */ new Map();\n    for (const ext of extensions) {\n      for (const toolName of ext.tools.keys()) {\n        const existingOwner = toolOwners.get(toolName);\n        if (existingOwner && existingOwner !== ext.path) {\n          conflicts.push({\n            path: ext.path,\n            message: `Tool \"${toolName}\" conflicts with ${existingOwner}`\n          });\n        } else {\n          toolOwners.set(toolName, ext.path);\n        }\n      }\n      for (const flagName of ext.flags.keys()) {\n        const existingOwner = flagOwners.get(flagName);\n        if (existingOwner && existingOwner !== ext.path) {\n          conflicts.push({\n            path: ext.path,\n            message: `Flag \"--${flagName}\" conflicts with ${existingOwner}`\n          });\n        } else {\n          flagOwners.set(flagName, ext.path);\n        }\n      }\n    }\n    return conflicts;\n  }\n};\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session-services.js\nfunction applyExtensionFlagValues(resourceLoader, extensionFlagValues) {\n  if (!extensionFlagValues) {\n    return [];\n  }\n  const diagnostics = [];\n  const extensionsResult = resourceLoader.getExtensions();\n  const registeredFlags = /* @__PURE__ */ new Map();\n  for (const extension of extensionsResult.extensions) {\n    for (const [name, flag] of extension.flags) {\n      registeredFlags.set(name, { type: flag.type });\n    }\n  }\n  const unknownFlags = [];\n  for (const [name, value] of extensionFlagValues) {\n    const flag = registeredFlags.get(name);\n    if (!flag) {\n      unknownFlags.push(name);\n      continue;\n    }\n    if (flag.type === \"boolean\") {\n      extensionsResult.runtime.flagValues.set(name, true);\n      continue;\n    }\n    if (typeof value === \"string\") {\n      extensionsResult.runtime.flagValues.set(name, value);\n      continue;\n    }\n    diagnostics.push({\n      type: \"error\",\n      message: `Extension flag \"--${name}\" requires a value`\n    });\n  }\n  if (unknownFlags.length > 0) {\n    diagnostics.push({\n      type: \"error\",\n      message: `Unknown option${unknownFlags.length === 1 ? \"\" : \"s\"}: ${unknownFlags.map((name) => `--${name}`).join(\", \")}`\n    });\n  }\n  return diagnostics;\n}\nasync function createAgentSessionServices(options) {\n  const cwd = resolvePath(options.cwd);\n  const agentDir = options.agentDir ? resolvePath(options.agentDir) : getAgentDir();\n  const modelRuntime = options.modelRuntime ?? await ModelRuntime.create({\n    authPath: join33(agentDir, \"auth.json\"),\n    modelsPath: join33(agentDir, \"models.json\"),\n    signal: options.modelRuntimeSignal\n  });\n  const settingsManager = options.settingsManager ?? SettingsManager.create(cwd, agentDir);\n  const resourceLoader = new DefaultResourceLoader({\n    ...options.resourceLoaderOptions ?? {},\n    cwd,\n    agentDir,\n    settingsManager\n  });\n  await resourceLoader.reload(options.resourceLoaderReloadOptions);\n  const diagnostics = [];\n  const extensionsResult = resourceLoader.getExtensions();\n  for (const { name, config, extensionPath } of extensionsResult.runtime.pendingProviderRegistrations) {\n    try {\n      modelRuntime.registerProvider(name, config);\n    } catch (error) {\n      const message = error instanceof Error ? error.message : String(error);\n      diagnostics.push({\n        type: \"error\",\n        message: `Extension \"${extensionPath}\" error: ${message}`\n      });\n    }\n  }\n  extensionsResult.runtime.pendingProviderRegistrations = [];\n  for (const { provider, extensionPath } of extensionsResult.runtime.pendingNativeProviderRegistrations) {\n    try {\n      modelRuntime.registerNativeProvider(provider);\n    } catch (error) {\n      const message = error instanceof Error ? error.message : String(error);\n      diagnostics.push({\n        type: \"error\",\n        message: `Extension \"${extensionPath}\" error: ${message}`\n      });\n    }\n  }\n  extensionsResult.runtime.pendingNativeProviderRegistrations = [];\n  await modelRuntime.refresh({ allowNetwork: false });\n  diagnostics.push(...applyExtensionFlagValues(resourceLoader, options.extensionFlagValues));\n  return {\n    cwd,\n    agentDir,\n    modelRuntime,\n    settingsManager,\n    resourceLoader,\n    diagnostics\n  };\n}\nasync function createAgentSessionFromServices(options) {\n  return createAgentSession({\n    cwd: options.services.cwd,\n    agentDir: options.services.agentDir,\n    modelRuntime: options.services.modelRuntime,\n    settingsManager: options.services.settingsManager,\n    resourceLoader: options.services.resourceLoader,\n    sessionManager: options.sessionManager,\n    model: options.model,\n    thinkingLevel: options.thinkingLevel,\n    scopedModels: options.scopedModels,\n    tools: options.tools,\n    excludeTools: options.excludeTools,\n    noTools: options.noTools,\n    customTools: options.customTools,\n    sessionStartEvent: options.sessionStartEvent\n  });\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session-runtime.js\nvar SessionImportFileNotFoundError = class extends Error {\n  filePath;\n  constructor(filePath) {\n    super(`File not found: ${filePath}`);\n    this.name = \"SessionImportFileNotFoundError\";\n    this.filePath = filePath;\n  }\n};\nfunction extractUserMessageText(content) {\n  if (typeof content === \"string\") {\n    return content;\n  }\n  return content.filter((part) => part.type === \"text\" && typeof part.text === \"string\").map((part) => part.text).join(\"\");\n}\nvar AgentSessionRuntime = class {\n  rebindSession;\n  beforeSessionInvalidate;\n  _session;\n  _services;\n  createRuntime;\n  _diagnostics;\n  _modelFallbackMessage;\n  constructor(_session, _services, createRuntime, _diagnostics = [], _modelFallbackMessage) {\n    this._session = _session;\n    this._services = _services;\n    this.createRuntime = createRuntime;\n    this._diagnostics = _diagnostics;\n    this._modelFallbackMessage = _modelFallbackMessage;\n  }\n  get services() {\n    return this._services;\n  }\n  get session() {\n    return this._session;\n  }\n  get cwd() {\n    return this._services.cwd;\n  }\n  get diagnostics() {\n    return this._diagnostics;\n  }\n  get modelFallbackMessage() {\n    return this._modelFallbackMessage;\n  }\n  setRebindSession(rebindSession) {\n    this.rebindSession = rebindSession;\n  }\n  /**\n   * Set a synchronous callback that runs after `session_shutdown` handlers finish\n   * but before the current session is invalidated.\n   *\n   * This is for host-owned UI teardown that must not yield to the event loop,\n   * such as detaching extension-provided TUI components before the old extension\n   * context becomes stale.\n   */\n  setBeforeSessionInvalidate(beforeSessionInvalidate) {\n    this.beforeSessionInvalidate = beforeSessionInvalidate;\n  }\n  async emitBeforeSwitch(reason, targetSessionFile) {\n    const runner = this.session.extensionRunner;\n    if (!runner.hasHandlers(\"session_before_switch\")) {\n      return { cancelled: false };\n    }\n    const result = await runner.emit({\n      type: \"session_before_switch\",\n      reason,\n      targetSessionFile\n    });\n    return { cancelled: result?.cancel === true };\n  }\n  async emitBeforeFork(entryId, options) {\n    const runner = this.session.extensionRunner;\n    if (!runner.hasHandlers(\"session_before_fork\")) {\n      return { cancelled: false };\n    }\n    const result = await runner.emit({\n      type: \"session_before_fork\",\n      entryId,\n      ...options\n    });\n    return { cancelled: result?.cancel === true };\n  }\n  async teardownCurrent(reason, targetSessionFile) {\n    await this.session.abort();\n    await emitSessionShutdownEvent(this.session.extensionRunner, {\n      type: \"session_shutdown\",\n      reason,\n      targetSessionFile\n    });\n    this.beforeSessionInvalidate?.();\n    this.session.dispose();\n  }\n  apply(result) {\n    this._session = result.session;\n    this._services = result.services;\n    this._diagnostics = result.diagnostics;\n    this._modelFallbackMessage = result.modelFallbackMessage;\n  }\n  async finishSessionReplacement(withSession) {\n    if (this.rebindSession) {\n      await this.rebindSession(this.session);\n    }\n    if (withSession) {\n      await withSession(this.session.createReplacedSessionContext());\n    }\n  }\n  async switchSession(sessionPath, options) {\n    const beforeResult = await this.emitBeforeSwitch(\"resume\", sessionPath);\n    if (beforeResult.cancelled) {\n      return beforeResult;\n    }\n    const previousSessionFile = this.session.sessionFile;\n    const sessionManager = SessionManager.open(sessionPath, void 0, options?.cwdOverride);\n    assertSessionCwdExists(sessionManager, this.cwd);\n    await this.teardownCurrent(\"resume\", sessionManager.getSessionFile());\n    this.apply(await this.createRuntime({\n      cwd: sessionManager.getCwd(),\n      agentDir: this.services.agentDir,\n      sessionManager,\n      sessionStartEvent: { type: \"session_start\", reason: \"resume\", previousSessionFile },\n      projectTrustContext: options?.projectTrustContextFactory?.(sessionManager.getCwd())\n    }));\n    await this.finishSessionReplacement(options?.withSession);\n    return { cancelled: false };\n  }\n  async newSession(options) {\n    const beforeResult = await this.emitBeforeSwitch(\"new\");\n    if (beforeResult.cancelled) {\n      return beforeResult;\n    }\n    const previousSessionFile = this.session.sessionFile;\n    const sessionDir = this.session.sessionManager.getSessionDir();\n    const sessionManager = this.session.sessionManager.isPersisted() ? SessionManager.create(this.cwd, sessionDir) : SessionManager.inMemory(this.cwd);\n    if (options?.parentSession) {\n      sessionManager.newSession({ parentSession: options.parentSession });\n    }\n    await this.teardownCurrent(\"new\", sessionManager.getSessionFile());\n    this.apply(await this.createRuntime({\n      cwd: this.cwd,\n      agentDir: this.services.agentDir,\n      sessionManager,\n      sessionStartEvent: { type: \"session_start\", reason: \"new\", previousSessionFile }\n    }));\n    if (options?.setup) {\n      await options.setup(this.session.sessionManager);\n      this.session.agent.state.messages = this.session.sessionManager.buildSessionContext().messages;\n    }\n    await this.finishSessionReplacement(options?.withSession);\n    return { cancelled: false };\n  }\n  async fork(entryId, options) {\n    const position = options?.position ?? \"before\";\n    const beforeResult = await this.emitBeforeFork(entryId, { position });\n    if (beforeResult.cancelled) {\n      return { cancelled: true };\n    }\n    let targetLeafId;\n    let selectedText;\n    const selectedEntry = this.session.sessionManager.getEntry(entryId);\n    if (!selectedEntry) {\n      throw new Error(\"Invalid entry ID for forking\");\n    }\n    if (position === \"at\") {\n      targetLeafId = selectedEntry.id;\n    } else {\n      if (selectedEntry.type !== \"message\" || selectedEntry.message.role !== \"user\") {\n        throw new Error(\"Invalid entry ID for forking\");\n      }\n      targetLeafId = selectedEntry.parentId;\n      selectedText = extractUserMessageText(selectedEntry.message.content);\n    }\n    const previousSessionFile = this.session.sessionFile;\n    if (this.session.sessionManager.isPersisted()) {\n      const currentSessionFile = this.session.sessionFile;\n      if (!currentSessionFile) {\n        throw new Error(\"Persisted session is missing a session file\");\n      }\n      const sessionDir = this.session.sessionManager.getSessionDir();\n      if (!targetLeafId) {\n        const sessionManager3 = SessionManager.create(this.cwd, sessionDir);\n        sessionManager3.newSession({ parentSession: currentSessionFile });\n        await this.teardownCurrent(\"fork\", sessionManager3.getSessionFile());\n        this.apply(await this.createRuntime({\n          cwd: this.cwd,\n          agentDir: this.services.agentDir,\n          sessionManager: sessionManager3,\n          sessionStartEvent: { type: \"session_start\", reason: \"fork\", previousSessionFile }\n        }));\n        await this.finishSessionReplacement(options?.withSession);\n        return { cancelled: false, selectedText };\n      }\n      if (!existsSync23(currentSessionFile)) {\n        throw new Error(\"This session has not been saved yet. Wait for the first assistant response before cloning or forking it.\");\n      }\n      const sessionManager2 = SessionManager.open(currentSessionFile, sessionDir);\n      const forkedSessionPath = sessionManager2.createBranchedSession(targetLeafId);\n      if (!forkedSessionPath) {\n        throw new Error(\"Failed to create forked session\");\n      }\n      await this.teardownCurrent(\"fork\", sessionManager2.getSessionFile());\n      this.apply(await this.createRuntime({\n        cwd: sessionManager2.getCwd(),\n        agentDir: this.services.agentDir,\n        sessionManager: sessionManager2,\n        sessionStartEvent: { type: \"session_start\", reason: \"fork\", previousSessionFile }\n      }));\n      await this.finishSessionReplacement(options?.withSession);\n      return { cancelled: false, selectedText };\n    }\n    const sessionManager = this.session.sessionManager;\n    if (!targetLeafId) {\n      sessionManager.newSession({ parentSession: this.session.sessionFile });\n    } else {\n      sessionManager.createBranchedSession(targetLeafId);\n    }\n    await this.teardownCurrent(\"fork\", sessionManager.getSessionFile());\n    this.apply(await this.createRuntime({\n      cwd: this.cwd,\n      agentDir: this.services.agentDir,\n      sessionManager,\n      sessionStartEvent: { type: \"session_start\", reason: \"fork\", previousSessionFile }\n    }));\n    await this.finishSessionReplacement(options?.withSession);\n    return { cancelled: false, selectedText };\n  }\n  /**\n   * Import a session JSONL file and switch runtime state to the imported session.\n   *\n   * @returns `{ cancelled: true }` when cancelled by `session_before_switch`, otherwise `{ cancelled: false }`.\n   * @throws {SessionImportFileNotFoundError} When the input path does not exist.\n   * @throws {MissingSessionCwdError} When the imported session cwd cannot be resolved and no override is provided.\n   */\n  async importFromJsonl(inputPath, cwdOverride) {\n    const resolvedPath = resolvePath(inputPath);\n    if (!existsSync23(resolvedPath)) {\n      throw new SessionImportFileNotFoundError(resolvedPath);\n    }\n    const sessionDir = this.session.sessionManager.getSessionDir();\n    if (!existsSync23(sessionDir)) {\n      mkdirSync10(sessionDir, { recursive: true });\n    }\n    const destinationPath = join34(sessionDir, basename11(resolvedPath));\n    const beforeResult = await this.emitBeforeSwitch(\"resume\", destinationPath);\n    if (beforeResult.cancelled) {\n      return beforeResult;\n    }\n    const previousSessionFile = this.session.sessionFile;\n    if (resolve13(destinationPath) !== resolvedPath) {\n      copyFileSync(resolvedPath, destinationPath);\n    }\n    const sessionManager = SessionManager.open(destinationPath, sessionDir, cwdOverride);\n    assertSessionCwdExists(sessionManager, this.cwd);\n    await this.teardownCurrent(\"resume\", sessionManager.getSessionFile());\n    this.apply(await this.createRuntime({\n      cwd: sessionManager.getCwd(),\n      agentDir: this.services.agentDir,\n      sessionManager,\n      sessionStartEvent: { type: \"session_start\", reason: \"resume\", previousSessionFile }\n    }));\n    await this.finishSessionReplacement();\n    return { cancelled: false };\n  }\n  async dispose() {\n    await emitSessionShutdownEvent(this.session.extensionRunner, {\n      type: \"session_shutdown\",\n      reason: \"quit\"\n    });\n    this.beforeSessionInvalidate?.();\n    this.session.dispose();\n  }\n};\nasync function createAgentSessionRuntime(createRuntime, options) {\n  assertSessionCwdExists(options.sessionManager, options.cwd);\n  const result = await createRuntime(options);\n  return new AgentSessionRuntime(result.session, result.services, createRuntime, result.diagnostics, result.modelFallbackMessage);\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/core/project-trust.js\nfunction formatProjectTrustPrompt(cwd) {\n  return `Trust project folder?\n${cwd}\n\nThis allows ${APP_NAME} to load ${CONFIG_DIR_NAME} settings and resources, install missing project packages, and execute project extensions.`;\n}\nasync function selectProjectTrustOption(cwd, ctx) {\n  const options = getProjectTrustOptions(cwd, { includeSessionOnly: true });\n  const selected = await ctx.ui.select(formatProjectTrustPrompt(cwd), options.map((option) => option.label));\n  return options.find((option) => option.label === selected);\n}\nfunction saveProjectTrustPromptResult(trustStore, result) {\n  if (result.updates.length > 0) {\n    trustStore.setMany(result.updates);\n  }\n}\nasync function resolveProjectTrusted(options) {\n  if (options.trustOverride !== void 0) {\n    return options.trustOverride;\n  }\n  if (!hasTrustRequiringProjectResources(options.cwd)) {\n    return true;\n  }\n  if (options.extensionsResult) {\n    const { result, errors } = await emitProjectTrustEvent(options.extensionsResult, { type: \"project_trust\", cwd: options.cwd }, options.projectTrustContext);\n    for (const error of errors) {\n      options.onExtensionError?.(`Extension \"${error.extensionPath}\" project_trust error: ${error.error}`);\n    }\n    if (result) {\n      const trusted = result.trusted === \"yes\";\n      if (result.remember === true) {\n        options.trustStore.set(options.cwd, trusted);\n      }\n      return trusted;\n    }\n  }\n  const decision = options.trustStore.get(options.cwd);\n  if (decision !== null) {\n    return decision;\n  }\n  switch (options.defaultProjectTrust ?? \"ask\") {\n    case \"always\":\n      return true;\n    case \"never\":\n      return false;\n    case \"ask\":\n      break;\n  }\n  if (!options.projectTrustContext.hasUI) {\n    return false;\n  }\n  const selected = await selectProjectTrustOption(options.cwd, options.projectTrustContext);\n  if (selected !== void 0) {\n    saveProjectTrustPromptResult(options.trustStore, selected);\n    return selected.trusted;\n  }\n  return false;\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/extensions/llama/client.js\nfunction errorMessage(payload, fallback) {\n  if (typeof payload !== \"object\" || payload === null)\n    return fallback;\n  const error = payload.error;\n  if (typeof error !== \"object\" || error === null)\n    return fallback;\n  const message = error.message;\n  return typeof message === \"string\" && message ? message : fallback;\n}\nfunction isModelInfo(value) {\n  if (typeof value !== \"object\" || value === null)\n    return false;\n  const candidate = value;\n  return typeof candidate.id === \"string\" && typeof candidate.status?.value === \"string\";\n}\nfunction linkSignal(source, target) {\n  if (!source)\n    return () => {\n    };\n  if (source.aborted) {\n    target.abort(source.reason);\n    return () => {\n    };\n  }\n  const abort = () => target.abort(source.reason);\n  source.addEventListener(\"abort\", abort, { once: true });\n  return () => source.removeEventListener(\"abort\", abort);\n}\nfunction sleep6(ms, signal) {\n  return new Promise((resolve15, reject) => {\n    if (signal?.aborted) {\n      reject(signal.reason ?? new Error(\"Cancelled\"));\n      return;\n    }\n    const abort = () => {\n      clearTimeout(timeout);\n      reject(signal?.reason ?? new Error(\"Cancelled\"));\n    };\n    const timeout = setTimeout(() => {\n      signal?.removeEventListener(\"abort\", abort);\n      resolve15();\n    }, ms);\n    signal?.addEventListener(\"abort\", abort, { once: true });\n  });\n}\nfunction parseLoadProgress(data) {\n  if (typeof data !== \"object\" || data === null)\n    return void 0;\n  const progress = data.progress;\n  if (typeof progress !== \"object\" || progress === null)\n    return void 0;\n  const value = progress;\n  const stage = typeof value.current === \"string\" ? value.current : typeof value.stage === \"string\" ? value.stage : void 0;\n  const stages = Array.isArray(value.stages) ? value.stages.filter((entry) => typeof entry === \"string\") : [];\n  const stageRatio = typeof value.value === \"number\" ? Math.max(0, Math.min(1, value.value)) : void 0;\n  let ratio = stageRatio;\n  if (stage && stages.length > 0) {\n    const index = stages.indexOf(stage);\n    if (index >= 0)\n      ratio = (index + (stageRatio ?? 0)) / stages.length;\n  }\n  return {\n    message: stage ? `Loading ${stage.replaceAll(\"_\", \" \")}` : \"Loading model\",\n    ratio\n  };\n}\nfunction parseDownloadProgress(data) {\n  if (typeof data !== \"object\" || data === null)\n    return void 0;\n  const nested = data.progress;\n  const files = typeof nested === \"object\" && nested !== null ? nested : data;\n  let done = 0;\n  let total = 0;\n  for (const value of Object.values(files)) {\n    if (typeof value !== \"object\" || value === null)\n      continue;\n    const entry = value;\n    if (typeof entry.done !== \"number\" || typeof entry.total !== \"number\")\n      continue;\n    done += entry.done;\n    total += entry.total;\n  }\n  if (total <= 0)\n    return void 0;\n  return {\n    message: \"Downloading model\",\n    ratio: done / total,\n    detail: `${formatBytes(done)} / ${formatBytes(total)}`\n  };\n}\nfunction formatBytes(bytes) {\n  if (bytes < 1024)\n    return `${bytes} B`;\n  const units = [\"KiB\", \"MiB\", \"GiB\", \"TiB\"];\n  let value = bytes / 1024;\n  let unit = units[0];\n  for (let index = 1; index < units.length && value >= 1024; index++) {\n    value /= 1024;\n    unit = units[index];\n  }\n  return `${value >= 10 ? value.toFixed(1) : value.toFixed(2)} ${unit}`;\n}\nfunction normalizeLlamaServerUrl(value) {\n  const url = new URL(value.trim());\n  if (url.protocol !== \"http:\" && url.protocol !== \"https:\") {\n    throw new Error(\"Server URL must use http or https\");\n  }\n  url.hash = \"\";\n  url.search = \"\";\n  url.pathname = url.pathname.replace(/\\/+$/u, \"\").replace(/\\/v1$/u, \"\") || \"/\";\n  return url.toString().replace(/\\/$/u, \"\");\n}\nfunction llamaInferenceUrl(serverUrl) {\n  return `${normalizeLlamaServerUrl(serverUrl)}/v1`;\n}\nvar LlamaClient = class {\n  serverUrl;\n  apiKey;\n  constructor(serverUrl, apiKey) {\n    this.serverUrl = normalizeLlamaServerUrl(serverUrl);\n    this.apiKey = apiKey;\n  }\n  async request(path12, init = {}) {\n    const headers = new Headers(init.headers);\n    if (init.body !== void 0)\n      headers.set(\"Content-Type\", \"application/json\");\n    if (this.apiKey)\n      headers.set(\"Authorization\", `Bearer ${this.apiKey}`);\n    const timeout = AbortSignal.timeout(15e3);\n    const signal = init.signal ? AbortSignal.any([init.signal, timeout]) : timeout;\n    const response = await fetch(`${this.serverUrl}${path12}`, { ...init, headers, signal });\n    let payload;\n    try {\n      payload = await response.json();\n    } catch {\n      payload = void 0;\n    }\n    if (!response.ok)\n      throw new Error(errorMessage(payload, `llama.cpp returned HTTP ${response.status}`));\n    return payload;\n  }\n  async list(options = {}) {\n    const payload = await this.request(`/models${options.reload ? \"?reload=1\" : \"\"}`, { signal: options.signal });\n    if (typeof payload !== \"object\" || payload === null || !Array.isArray(payload.data)) {\n      throw new Error(\"llama.cpp returned an invalid model catalog\");\n    }\n    const data = payload.data;\n    if (!data.every(isModelInfo))\n      throw new Error(\"Server is not running in llama.cpp router mode\");\n    return data;\n  }\n  async load(model, signal) {\n    await this.request(\"/models/load\", { method: \"POST\", body: JSON.stringify({ model }), signal });\n  }\n  async unload(model, signal) {\n    await this.request(\"/models/unload\", { method: \"POST\", body: JSON.stringify({ model }), signal });\n  }\n  async unloadAndWait(model, signal) {\n    await this.unload(model, signal);\n    while (true) {\n      const entry = (await this.list({ signal })).find((candidate) => candidate.id === model);\n      if (!entry || entry.status.value === \"unloaded\")\n        return;\n      await sleep6(100, signal);\n    }\n  }\n  async download(model, signal) {\n    await this.request(\"/models\", { method: \"POST\", body: JSON.stringify({ model }), signal });\n  }\n  async watch(onEvent, signal) {\n    const headers = new Headers();\n    if (this.apiKey)\n      headers.set(\"Authorization\", `Bearer ${this.apiKey}`);\n    const response = await fetch(`${this.serverUrl}/models/sse`, { headers, signal });\n    if (!response.ok || !response.body)\n      throw new Error(`llama.cpp SSE returned HTTP ${response.status}`);\n    const reader = response.body.getReader();\n    const decoder = new TextDecoder();\n    let buffer = \"\";\n    while (true) {\n      const chunk = await reader.read();\n      if (chunk.done)\n        break;\n      buffer += decoder.decode(chunk.value, { stream: true }).replaceAll(\"\\r\\n\", \"\\n\");\n      let boundary = buffer.indexOf(\"\\n\\n\");\n      while (boundary >= 0) {\n        const frame2 = buffer.slice(0, boundary);\n        buffer = buffer.slice(boundary + 2);\n        const data = frame2.split(\"\\n\").filter((line) => line.startsWith(\"data:\")).map((line) => line.slice(5).trimStart()).join(\"\\n\");\n        if (data) {\n          try {\n            const event = JSON.parse(data);\n            if (event && typeof event.model === \"string\" && typeof event.event === \"string\")\n              onEvent(event);\n          } catch {\n          }\n        }\n        boundary = buffer.indexOf(\"\\n\\n\");\n      }\n    }\n  }\n  async loadAndWait(model, onProgress, signal) {\n    const watcher = new AbortController();\n    const unlink2 = linkSignal(signal, watcher);\n    let eventLoaded = false;\n    let eventError;\n    void this.watch((event) => {\n      if (event.model !== model)\n        return;\n      if (event.event !== \"model_status\" && event.event !== \"status_change\")\n        return;\n      const data = event.data;\n      if (data?.status === \"loaded\")\n        eventLoaded = true;\n      if (data?.status === \"unloaded\")\n        eventError = \"Model failed to load\";\n      const progress = parseLoadProgress(event.data);\n      if (progress)\n        onProgress(progress);\n    }, watcher.signal).catch(() => {\n    });\n    try {\n      await this.load(model, signal);\n      onProgress({ message: \"Loading model\" });\n      while (true) {\n        if (signal?.aborted)\n          throw signal.reason ?? new Error(\"Cancelled\");\n        const entry = (await this.list({ signal })).find((candidate) => candidate.id === model);\n        if (entry?.status.value === \"loaded\")\n          return entry;\n        if (eventLoaded && !entry)\n          return { id: model, status: { value: \"loaded\" } };\n        if (entry?.status.failed || eventError) {\n          throw new Error(entry?.status.exit_code === void 0 ? eventError ?? \"Model failed to load\" : `Model exited with code ${entry.status.exit_code}`);\n        }\n        await sleep6(250, signal);\n      }\n    } finally {\n      unlink2();\n      watcher.abort();\n    }\n  }\n  async downloadAndWait(model, onProgress, signal) {\n    const watcher = new AbortController();\n    const unlink2 = linkSignal(signal, watcher);\n    let finished = false;\n    let failure;\n    let sawDownloading = false;\n    let polls = 0;\n    void this.watch((event) => {\n      if (event.model !== model)\n        return;\n      if (event.event === \"download_finished\")\n        finished = true;\n      if (event.event === \"download_failed\")\n        failure = errorMessage(event.data, \"Download failed\");\n      if (event.event === \"download_progress\") {\n        sawDownloading = true;\n        const progress = parseDownloadProgress(event.data);\n        if (progress)\n          onProgress(progress);\n      }\n    }, watcher.signal).catch(() => {\n    });\n    try {\n      await this.download(model, signal);\n      onProgress({ message: \"Downloading model\" });\n      while (true) {\n        if (signal?.aborted)\n          throw signal.reason ?? new Error(\"Cancelled\");\n        if (failure)\n          throw new Error(failure);\n        const models = await this.list({ signal });\n        polls++;\n        const entry = models.find((candidate) => candidate.id === model);\n        if (entry?.status.value === \"downloading\") {\n          sawDownloading = true;\n          const progress = parseDownloadProgress(entry.status.progress);\n          if (progress)\n            onProgress(progress);\n        } else if (finished || entry && (sawDownloading || polls >= 2)) {\n          return this.list({ reload: true, signal });\n        }\n        await sleep6(500, signal);\n      }\n    } finally {\n      unlink2();\n      watcher.abort();\n    }\n  }\n};\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/extensions/llama/huggingface.js\nimport { readFile as readFile4 } from \"node:fs/promises\";\nimport { homedir as homedir11 } from \"node:os\";\nimport { join as join35 } from \"node:path\";\nvar DEFAULT_HUGGING_FACE_URL = \"https://huggingface.co\";\nvar QUANTIZATION_PATTERN = /(?:^|[-_.])((?:UD-)?(?:IQ\\d(?:_[A-Z0-9]+)+|Q\\d(?:_[A-Z0-9]+)+|BF16|F16|F32|MXFP\\d(?:_[A-Z0-9]+)*))$/iu;\nvar SHARD_SUFFIX_PATTERN = /-\\d{5}-of-\\d{5}$/u;\nfunction payloadError(payload, fallback) {\n  if (typeof payload !== \"object\" || payload === null)\n    return fallback;\n  const error = payload.error;\n  return typeof error === \"string\" && error ? error : fallback;\n}\nfunction parseRateLimitDelay(value) {\n  const match = value?.match(/(?:^|;)t=(\\d+)/u);\n  return match ? Number(match[1]) : void 0;\n}\nasync function readToken(path12) {\n  try {\n    const token = (await readFile4(path12, \"utf8\")).trim();\n    return token || void 0;\n  } catch {\n    return void 0;\n  }\n}\nasync function findHuggingFaceToken(env = process.env) {\n  const fromEnvironment = env.HF_TOKEN?.trim();\n  if (fromEnvironment)\n    return fromEnvironment;\n  const paths = [\n    env.HF_TOKEN_PATH,\n    env.HF_HOME ? join35(env.HF_HOME, \"token\") : void 0,\n    env.XDG_CACHE_HOME ? join35(env.XDG_CACHE_HOME, \"huggingface\", \"token\") : void 0,\n    join35(homedir11(), \".cache\", \"huggingface\", \"token\")\n  ].filter((path12) => Boolean(path12));\n  for (const path12 of new Set(paths)) {\n    const token = await readToken(path12);\n    if (token)\n      return token;\n  }\n  return void 0;\n}\nvar HuggingFaceClient = class {\n  token;\n  baseUrl;\n  constructor(token, baseUrl = DEFAULT_HUGGING_FACE_URL) {\n    this.token = token;\n    this.baseUrl = baseUrl.replace(/\\/+$/u, \"\");\n  }\n  async request(path12, signal) {\n    const headers = new Headers();\n    if (this.token)\n      headers.set(\"Authorization\", `Bearer ${this.token}`);\n    const timeout = AbortSignal.timeout(15e3);\n    const response = await fetch(`${this.baseUrl}${path12}`, {\n      headers,\n      signal: signal ? AbortSignal.any([signal, timeout]) : timeout\n    });\n    let payload;\n    try {\n      payload = await response.json();\n    } catch {\n      payload = void 0;\n    }\n    if (!response.ok) {\n      const fallback = `Hugging Face returned HTTP ${response.status}`;\n      if (response.status === 429) {\n        const delay = Number(response.headers.get(\"retry-after\")) || parseRateLimitDelay(response.headers.get(\"ratelimit\"));\n        throw new Error(delay ? `Hugging Face rate limit reached; retry in ${delay}s` : \"Hugging Face rate limit reached\");\n      }\n      throw new Error(payloadError(payload, fallback));\n    }\n    return payload;\n  }\n  async search(query, signal) {\n    const params = new URLSearchParams({\n      search: query,\n      filter: \"gguf\",\n      sort: \"downloads\",\n      direction: \"-1\",\n      limit: \"20\"\n    });\n    const payload = await this.request(`/api/models?${params}`, signal);\n    if (!Array.isArray(payload))\n      throw new Error(\"Hugging Face returned invalid search results\");\n    return payload.flatMap((value) => {\n      if (typeof value !== \"object\" || value === null || typeof value.id !== \"string\")\n        return [];\n      const model = value;\n      return [{ id: model.id, downloads: typeof model.downloads === \"number\" ? model.downloads : 0 }];\n    });\n  }\n  async details(id, signal) {\n    const encodedId = id.split(\"/\").map(encodeURIComponent).join(\"/\");\n    const payload = await this.request(`/api/models/${encodedId}?blobs=true`, signal);\n    if (typeof payload !== \"object\" || payload === null) {\n      throw new Error(\"Hugging Face returned invalid model details\");\n    }\n    const model = payload;\n    const sizes = /* @__PURE__ */ new Map();\n    if (Array.isArray(model.siblings)) {\n      for (const value of model.siblings) {\n        if (typeof value !== \"object\" || value === null)\n          continue;\n        const file = value;\n        if (typeof file.rfilename !== \"string\" || !file.rfilename.toLowerCase().endsWith(\".gguf\"))\n          continue;\n        const filename = file.rfilename.split(\"/\").at(-1);\n        if (filename.toLowerCase().startsWith(\"mmproj\"))\n          continue;\n        const stem = filename.slice(0, -5).replace(SHARD_SUFFIX_PATTERN, \"\");\n        const quantization = stem.match(QUANTIZATION_PATTERN)?.[1]?.toUpperCase();\n        if (!quantization)\n          continue;\n        const current = sizes.get(quantization) ?? { total: 0, complete: true };\n        if (typeof file.size === \"number\")\n          current.total += file.size;\n        else\n          current.complete = false;\n        sizes.set(quantization, current);\n      }\n    }\n    const quantizations = [...sizes].map(([name, size]) => ({ name, size: size.complete ? size.total : void 0 })).sort((left, right) => {\n      if (left.name === \"Q4_K_M\")\n        return -1;\n      if (right.name === \"Q4_K_M\")\n        return 1;\n      return (left.size ?? Number.MAX_SAFE_INTEGER) - (right.size ?? Number.MAX_SAFE_INTEGER) || left.name.localeCompare(right.name);\n    });\n    return {\n      id: typeof model.id === \"string\" ? model.id : id,\n      gated: model.gated === \"auto\" || model.gated === \"manual\" ? model.gated : false,\n      quantizations\n    };\n  }\n};\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/extensions/llama/provider.js\nvar LLAMA_PROVIDER_ID = \"llama.cpp\";\nvar DEFAULT_LLAMA_SERVER_URL = \"http://127.0.0.1:8080\";\nfunction credentialServerUrl(credential) {\n  const value = credential?.env?.LLAMA_BASE_URL;\n  return typeof value === \"string\" && value.trim() ? normalizeLlamaServerUrl(value) : void 0;\n}\nasync function resolveServerUrl(ctx, credential) {\n  const configured = credentialServerUrl(credential) ?? (await ctx.env(\"LLAMA_BASE_URL\"))?.trim();\n  return configured ? normalizeLlamaServerUrl(configured) : void 0;\n}\nfunction toPiModel(model, serverUrl) {\n  const reportedContextWindow = model.meta?.n_ctx ?? model.meta?.n_ctx_train;\n  const contextWindow = reportedContextWindow && reportedContextWindow > 0 ? reportedContextWindow : 128e3;\n  return {\n    id: model.id,\n    name: model.id,\n    api: \"openai-completions\",\n    provider: LLAMA_PROVIDER_ID,\n    baseUrl: llamaInferenceUrl(serverUrl),\n    reasoning: false,\n    input: model.architecture?.input_modalities?.includes(\"image\") ? [\"text\", \"image\"] : [\"text\"],\n    cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },\n    contextWindow,\n    maxTokens: contextWindow,\n    compat: {\n      supportsStore: false,\n      supportsDeveloperRole: false,\n      supportsReasoningEffort: false,\n      supportsUsageInStreaming: true,\n      supportsStrictMode: false,\n      maxTokensField: \"max_tokens\"\n    }\n  };\n}\nfunction createLlamaProvider() {\n  let models = [];\n  const setCatalog = (catalog, serverUrl) => {\n    models = catalog.filter((model) => model.status.value === \"loaded\").map((model) => toPiModel(model, serverUrl));\n  };\n  const provider = {\n    id: LLAMA_PROVIDER_ID,\n    name: \"llama.cpp\",\n    baseUrl: llamaInferenceUrl(DEFAULT_LLAMA_SERVER_URL),\n    auth: {\n      apiKey: {\n        name: \"llama.cpp server\",\n        login: async (interaction) => {\n          const enteredUrl = await interaction.prompt({\n            type: \"text\",\n            message: \"llama.cpp server URL\",\n            placeholder: process.env.LLAMA_BASE_URL ?? DEFAULT_LLAMA_SERVER_URL\n          });\n          const serverUrl = normalizeLlamaServerUrl(enteredUrl.trim() || process.env.LLAMA_BASE_URL || DEFAULT_LLAMA_SERVER_URL);\n          const apiKey = (await interaction.prompt({\n            type: \"secret\",\n            message: \"API key (optional)\"\n          })).trim();\n          await new LlamaClient(serverUrl, apiKey || void 0).list({ signal: interaction.signal });\n          return {\n            type: \"api_key\",\n            key: apiKey || void 0,\n            env: { LLAMA_BASE_URL: serverUrl }\n          };\n        },\n        check: async ({ ctx, credential }) => {\n          const serverUrl = await resolveServerUrl(ctx, credential);\n          return serverUrl ? { type: \"api_key\", source: credential ? \"stored credential\" : \"LLAMA_BASE_URL\" } : void 0;\n        },\n        resolve: async ({ ctx, credential }) => {\n          const serverUrl = await resolveServerUrl(ctx, credential);\n          if (!serverUrl)\n            return void 0;\n          const apiKey = credential?.key ?? await ctx.env(\"LLAMA_API_KEY\") ?? \"local\";\n          return {\n            auth: { apiKey, baseUrl: llamaInferenceUrl(serverUrl) },\n            env: { ...credential?.env, LLAMA_BASE_URL: serverUrl },\n            source: credential ? \"stored credential\" : \"LLAMA_BASE_URL\"\n          };\n        }\n      }\n    },\n    getModels: () => models,\n    refreshModels: async (context) => {\n      if (context.stored) {\n        const restored = context.stored.models.filter((model) => model.provider === LLAMA_PROVIDER_ID && model.api === \"openai-completions\");\n        if (!await context.publish({\n          update: () => {\n            models = restored;\n          }\n        })) {\n          return;\n        }\n      }\n      if (!context.allowNetwork || context.signal.aborted || context.credential?.type !== \"api_key\")\n        return;\n      const serverUrl = credentialServerUrl(context.credential);\n      if (!serverUrl)\n        return;\n      const catalog = await new LlamaClient(serverUrl, context.credential.key).list({ signal: context.signal });\n      if (context.signal.aborted)\n        return;\n      const refreshed = catalog.filter((model) => model.status.value === \"loaded\").map((model) => toPiModel(model, serverUrl));\n      await context.publish({\n        persist: { models: refreshed, checkedAt: Date.now() },\n        update: () => {\n          models = refreshed;\n        }\n      });\n    },\n    stream: (model, context, options) => stream10(model, context, options),\n    streamSimple: (model, context, options) => streamSimple10(model, context, options)\n  };\n  return { provider, setCatalog };\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/extensions/llama/ui.js\nvar DOWNLOAD_VALUE = \"\\0download\";\nfunction contextLabel(model) {\n  const context = model.meta?.n_ctx ?? model.meta?.n_ctx_train;\n  if (context)\n    return context >= 1e3 ? `${Math.round(context / 1e3)}k` : String(context);\n  const args = model.status.args ?? [];\n  for (let index = 0; index < args.length - 1; index++) {\n    if (args[index] !== \"--ctx-size\" && args[index] !== \"-c\" && args[index] !== \"-ctx\")\n      continue;\n    const value = Number(args[index + 1]);\n    if (Number.isFinite(value) && value > 0)\n      return value >= 1e3 ? `${Math.round(value / 1e3)}k` : String(value);\n  }\n  return void 0;\n}\nfunction modelDescription(model) {\n  const details = [];\n  const loaded = model.status.value === \"loaded\" || model.status.value === \"sleeping\";\n  if (loaded)\n    details.push(\"loaded\");\n  else if (model.status.value !== \"unloaded\")\n    details.push(model.status.value);\n  const context = loaded ? contextLabel(model) : void 0;\n  if (context)\n    details.push(`${context} context`);\n  return details.join(\" \\xB7 \");\n}\nfunction selectTheme(theme2) {\n  return {\n    selectedPrefix: (text) => theme2.fg(\"accent\", text),\n    selectedText: (text) => theme2.fg(\"accent\", text),\n    description: (text) => theme2.fg(\"muted\", text),\n    scrollInfo: (text) => theme2.fg(\"dim\", text),\n    noMatch: (text) => theme2.fg(\"warning\", text)\n  };\n}\nfunction frame(theme2, title, body, footer) {\n  const container = new Container();\n  container.addChild(new DynamicBorder((text) => theme2.fg(\"accent\", text)));\n  container.addChild(new Text(theme2.fg(\"accent\", theme2.bold(title)), 1, 0));\n  for (const child of body)\n    container.addChild(child);\n  if (footer) {\n    container.addChild(new Spacer(1));\n    container.addChild(new Text(theme2.fg(\"dim\", footer), 1, 0));\n  }\n  container.addChild(new DynamicBorder((text) => theme2.fg(\"accent\", text)));\n  return container;\n}\nfunction compactCount(value) {\n  if (value >= 1e6)\n    return `${(value / 1e6).toFixed(value >= 1e7 ? 0 : 1)}M`;\n  if (value >= 1e3)\n    return `${(value / 1e3).toFixed(value >= 1e5 ? 0 : 1)}k`;\n  return String(value);\n}\nvar HuggingFaceSearch = class extends Container {\n  tui;\n  theme;\n  keybindings;\n  search;\n  cache;\n  onSelectModel;\n  input = new Input();\n  resultsContainer = new Container();\n  results = [];\n  filteredResults = [];\n  selectedIndex = 0;\n  query = \"\";\n  status = \"Type at least 2 characters\";\n  debounce;\n  request;\n  closed = false;\n  _focused = false;\n  constructor(tui, theme2, keybindings, search, cache, onSelectModel) {\n    super();\n    this.tui = tui;\n    this.theme = theme2;\n    this.keybindings = keybindings;\n    this.search = search;\n    this.cache = cache;\n    this.onSelectModel = onSelectModel;\n    this.addChild(new Text(theme2.fg(\"dim\", \"Model name or owner/repository[:quant]\"), 1, 0));\n    this.addChild(this.input);\n    this.addChild(new Spacer(1));\n    this.addChild(this.resultsContainer);\n    this.updateResults();\n  }\n  get focused() {\n    return this._focused;\n  }\n  set focused(value) {\n    this._focused = value;\n    this.input.focused = value;\n  }\n  updateResults() {\n    this.resultsContainer.clear();\n    const maxVisible = 10;\n    const start = Math.max(0, Math.min(this.selectedIndex - Math.floor(maxVisible / 2), this.filteredResults.length - maxVisible));\n    const end = Math.min(start + maxVisible, this.filteredResults.length);\n    for (let index = start; index < end; index++) {\n      const model = this.filteredResults[index];\n      if (!model)\n        continue;\n      const prefix = index === this.selectedIndex ? \"\\u2192 \" : \"  \";\n      const details = `${compactCount(model.downloads)} downloads`;\n      this.resultsContainer.addChild(new Text(index === this.selectedIndex ? this.theme.fg(\"accent\", `${prefix}${model.id}  ${details}`) : `${prefix}${model.id}${this.theme.fg(\"muted\", `  ${details}`)}`, 0, 0));\n    }\n    if (start > 0 || end < this.filteredResults.length) {\n      this.resultsContainer.addChild(new Text(this.theme.fg(\"dim\", `  (${this.selectedIndex + 1}/${this.filteredResults.length})`), 0, 0));\n    }\n    if (this.filteredResults.length === 0) {\n      this.resultsContainer.addChild(new Text(this.theme.fg(\"dim\", `  ${this.status}`), 0, 0));\n    } else if (this.status === \"Searching Hugging Face\\u2026\") {\n      this.resultsContainer.addChild(new Text(this.theme.fg(\"dim\", `  ${this.status}`), 0, 0));\n    }\n    this.tui.requestRender();\n  }\n  filterResults() {\n    if (this.query) {\n      const matches = new Set(fuzzyFilter(this.results, this.query, (model) => model.id).map((model) => model.id));\n      this.filteredResults = this.results.filter((model) => matches.has(model.id));\n    } else {\n      this.filteredResults = this.results;\n    }\n    this.selectedIndex = Math.min(this.selectedIndex, Math.max(0, this.filteredResults.length - 1));\n    this.updateResults();\n  }\n  scheduleSearch() {\n    if (this.debounce)\n      clearTimeout(this.debounce);\n    this.request?.abort();\n    this.request = void 0;\n    if (this.query.length < 2) {\n      this.status = \"Type at least 2 characters\";\n      this.filterResults();\n      return;\n    }\n    const cached = this.cache.get(this.query.toLowerCase());\n    if (cached) {\n      this.results = cached;\n      this.status = cached.length === 0 ? \"No GGUF models found\" : \"\";\n      this.filterResults();\n      return;\n    }\n    this.status = \"Searching Hugging Face\\u2026\";\n    this.filterResults();\n    this.debounce = setTimeout(() => void this.runSearch(this.query), 500);\n  }\n  async runSearch(query) {\n    const request = new AbortController();\n    this.request = request;\n    try {\n      const results = await this.search(query, request.signal);\n      this.cache.set(query.toLowerCase(), results);\n      if (this.closed || request.signal.aborted || this.query !== query)\n        return;\n      this.results = results;\n      this.selectedIndex = 0;\n      this.status = results.length === 0 ? \"No GGUF models found\" : \"\";\n      this.filterResults();\n    } catch (error) {\n      if (this.closed || request.signal.aborted || this.query !== query)\n        return;\n      this.results = [];\n      this.status = error instanceof Error ? error.message : String(error);\n      this.filterResults();\n    } finally {\n      if (this.request === request)\n        this.request = void 0;\n    }\n  }\n  close(model) {\n    if (this.closed)\n      return;\n    this.closed = true;\n    if (this.debounce)\n      clearTimeout(this.debounce);\n    this.request?.abort();\n    this.onSelectModel(model);\n  }\n  handleInput(data) {\n    if (this.keybindings.matches(data, \"tui.select.up\")) {\n      if (this.filteredResults.length > 0) {\n        this.selectedIndex = this.selectedIndex === 0 ? this.filteredResults.length - 1 : this.selectedIndex - 1;\n        this.updateResults();\n      }\n      return;\n    }\n    if (this.keybindings.matches(data, \"tui.select.down\")) {\n      if (this.filteredResults.length > 0) {\n        this.selectedIndex = this.selectedIndex === this.filteredResults.length - 1 ? 0 : this.selectedIndex + 1;\n        this.updateResults();\n      }\n      return;\n    }\n    if (this.keybindings.matches(data, \"tui.select.confirm\")) {\n      const exact = /^[^/\\s]+\\/[^:\\s]+(?::[^\\s:]+)?$/u.test(this.query) ? this.query : void 0;\n      const selected = exact ?? this.filteredResults[this.selectedIndex]?.id;\n      if (selected)\n        this.close(selected);\n      return;\n    }\n    if (this.keybindings.matches(data, \"tui.select.cancel\")) {\n      this.close(void 0);\n      return;\n    }\n    this.input.handleInput(data);\n    const query = this.input.getValue().trim();\n    if (query === this.query)\n      return;\n    this.query = query;\n    this.scheduleSearch();\n  }\n};\nvar LlamaView = class {\n  tui;\n  theme;\n  keybindings;\n  searchCache = /* @__PURE__ */ new Map();\n  content;\n  inputHandler;\n  inputTarget;\n  progressPromise;\n  progressResolver;\n  showingProgress = false;\n  _focused = false;\n  constructor(tui, theme2, keybindings) {\n    this.tui = tui;\n    this.theme = theme2;\n    this.keybindings = keybindings;\n    this.content = frame(theme2, \"llama.cpp models\", [new Text(theme2.fg(\"muted\", \"Loading\\u2026\"), 1, 1)]);\n  }\n  get focused() {\n    return this._focused;\n  }\n  set focused(value) {\n    this._focused = value;\n    if (this.inputTarget)\n      this.inputTarget.focused = value;\n  }\n  setContent(content, inputHandler, inputTarget) {\n    if (this.inputTarget)\n      this.inputTarget.focused = false;\n    this.progressPromise = void 0;\n    this.progressResolver = void 0;\n    this.showingProgress = false;\n    this.content = content;\n    this.inputHandler = inputHandler;\n    this.inputTarget = inputTarget;\n    if (this.inputTarget)\n      this.inputTarget.focused = this._focused;\n    this.tui.requestRender();\n  }\n  showModels(serverUrl, models) {\n    const sorted = [...models].sort((left, right) => {\n      const loaded = Number(right.status.value === \"loaded\") - Number(left.status.value === \"loaded\");\n      return loaded || left.id.localeCompare(right.id);\n    });\n    const byId = new Map(sorted.map((model) => [model.id, model]));\n    const items = [\n      ...sorted.map((model) => ({\n        value: model.id,\n        label: model.id,\n        description: modelDescription(model)\n      })),\n      { value: DOWNLOAD_VALUE, label: \"Download model\\u2026\", description: \"Hugging Face owner/repository[:quant]\" }\n    ];\n    return new Promise((resolve15) => {\n      const list = new SelectList(items, Math.min(items.length, 12), selectTheme(this.theme), {\n        minPrimaryColumnWidth: 36,\n        maxPrimaryColumnWidth: 56\n      });\n      list.onSelect = (item) => {\n        if (item.value === DOWNLOAD_VALUE)\n          resolve15({ type: \"download\" });\n        else {\n          const model = byId.get(item.value);\n          if (model)\n            resolve15({ type: \"model\", model });\n        }\n      };\n      list.onCancel = () => resolve15({ type: \"close\" });\n      this.setContent(frame(this.theme, \"llama.cpp models\", [new Text(this.theme.fg(\"dim\", serverUrl), 1, 0), new Spacer(1), list], `${keyHint(\"tui.select.confirm\", \"load/unload/download\")} \\u2022 ${keyHint(\"tui.select.cancel\", \"close\")}`), list);\n    });\n  }\n  select(title, options) {\n    return new Promise((resolve15) => {\n      const list = new SelectList(options.map((option) => ({ value: option, label: option })), Math.min(options.length, 12), selectTheme(this.theme));\n      list.onSelect = (item) => resolve15(item.value);\n      list.onCancel = () => resolve15(void 0);\n      this.setContent(frame(this.theme, title, [new Spacer(1), list], `${keyHint(\"tui.select.confirm\", \"select\")} \\u2022 ${keyHint(\"tui.select.cancel\", \"cancel\")}`), list);\n    });\n  }\n  async confirm(title, message) {\n    return await this.select(`${title}\n${message}`, [\"Yes\", \"No\"]) === \"Yes\";\n  }\n  async connectionError(serverUrl, message) {\n    const choice = await this.select(`llama.cpp unavailable\n${serverUrl}\n\n${message}`, [\"Retry\", \"Close\"]);\n    return choice === \"Retry\" ? \"retry\" : \"close\";\n  }\n  searchModels(search) {\n    return new Promise((resolve15) => {\n      const component = new HuggingFaceSearch(this.tui, this.theme, this.keybindings, search, this.searchCache, resolve15);\n      this.setContent(frame(this.theme, \"Download model\", [new Spacer(1), component], `${keyHint(\"tui.select.confirm\", \"select\")} \\u2022 ${keyHint(\"tui.select.cancel\", \"back\")}`), component, component);\n    });\n  }\n  showStatus(title, message) {\n    this.setContent(frame(this.theme, title, [new Spacer(1), new Text(this.theme.fg(\"muted\", message), 1, 0)]));\n  }\n  progress(state) {\n    if (!this.progressPromise) {\n      this.progressPromise = new Promise((resolve15) => {\n        this.progressResolver = resolve15;\n      });\n    }\n    this.showingProgress = true;\n    this.updateProgress(state);\n    return this.progressPromise;\n  }\n  updateProgress(state) {\n    if (!this.showingProgress)\n      return;\n    const body = [\n      new Text(this.theme.fg(\"text\", state.model), 1, 0),\n      new Spacer(1),\n      new Text(this.theme.fg(\"muted\", state.message), 1, 0)\n    ];\n    if (state.ratio !== void 0) {\n      const available = 40;\n      const filled = Math.round(Math.max(0, Math.min(1, state.ratio)) * available);\n      body.push(new Text(this.theme.fg(\"accent\", `${\"\\u2588\".repeat(filled)}${\"\\u2500\".repeat(available - filled)} ${Math.round(state.ratio * 100)}%`), 1, 0));\n    }\n    if (state.detail)\n      body.push(new Text(this.theme.fg(\"dim\", state.detail), 1, 0));\n    this.content = frame(this.theme, state.title, body, keyHint(\"tui.select.cancel\", \"stop\"));\n    this.inputHandler = void 0;\n    this.tui.requestRender();\n  }\n  handleInput(data) {\n    if (this.progressResolver && this.keybindings.matches(data, \"tui.select.cancel\")) {\n      const resolve15 = this.progressResolver;\n      this.progressPromise = void 0;\n      this.progressResolver = void 0;\n      resolve15();\n      return;\n    }\n    this.inputHandler?.handleInput?.(data);\n    this.tui.requestRender();\n  }\n  render(width) {\n    return this.content.render(width).map((line) => visibleWidth(line) > width ? truncateToWidth(line, width, \"\") : line);\n  }\n  invalidate() {\n    this.content.invalidate();\n  }\n};\nasync function showLlamaUi(ctx, run) {\n  await ctx.ui.custom((tui, theme2, keybindings, done) => {\n    const view = new LlamaView(tui, theme2, keybindings);\n    void run(view).then(() => done(), (error) => {\n      ctx.ui.notify(error instanceof Error ? error.message : String(error), \"error\");\n      done();\n    });\n    return view;\n  });\n}\nasync function runWithProgress(ui, options) {\n  const controller = new AbortController();\n  const state = { title: options.title, model: options.model, message: options.initialMessage };\n  const settled = options.run(controller.signal, (progress) => {\n    Object.assign(state, progress);\n    ui.updateProgress(state);\n  }).then((value) => ({ ok: true, value }), (error) => ({ ok: false, error }));\n  let completed = false;\n  settled.finally(() => {\n    completed = true;\n  });\n  while (!completed) {\n    const outcome = await Promise.race([\n      settled.then(() => \"settled\"),\n      ui.progress(state).then(() => \"stop\")\n    ]);\n    if (outcome === \"settled\")\n      break;\n    const stop = await ui.confirm(options.cancelTitle, options.cancelMessage);\n    if (!stop || completed)\n      continue;\n    try {\n      await options.cancel();\n    } finally {\n      controller.abort(new Error(\"Cancelled\"));\n    }\n    await settled;\n    return { cancelled: true };\n  }\n  const result = await settled;\n  if (!result.ok)\n    throw result.error;\n  return { cancelled: false, value: result.value };\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/extensions/llama/index.js\nfunction modelIsLoaded(model) {\n  return model.status.value === \"loaded\" || model.status.value === \"sleeping\";\n}\nfunction isConnectionError(error) {\n  if (!(error instanceof Error))\n    return false;\n  const message = `${error.name} ${error.message}`.toLowerCase();\n  return message.includes(\"fetch failed\") || message.includes(\"timeout\") || message.includes(\"network\");\n}\nfunction connectionErrorMessage(error) {\n  if (isConnectionError(error))\n    return \"Could not connect to the server.\";\n  return error instanceof Error ? error.message : String(error);\n}\nfunction parseHuggingFaceModel(value) {\n  const colon = value.indexOf(\":\", value.indexOf(\"/\") + 1);\n  return colon < 0 ? { repository: value } : { repository: value.slice(0, colon), quantization: value.slice(colon + 1) };\n}\nasync function configuredClient(ctx) {\n  const result = await ctx.modelRegistry.getProviderAuth(LLAMA_PROVIDER_ID);\n  if (!result) {\n    ctx.ui.notify(`Configure llama.cpp with /login ${LLAMA_PROVIDER_ID}`, \"warning\");\n    return void 0;\n  }\n  const configuredUrl = result.env?.LLAMA_BASE_URL;\n  const serverUrl = normalizeLlamaServerUrl(typeof configuredUrl === \"string\" && configuredUrl ? configuredUrl : result.auth.baseUrl ?? \"\");\n  return new LlamaClient(serverUrl, result.auth.apiKey);\n}\nfunction llamaExtension(pi) {\n  const provider = createLlamaProvider();\n  pi.registerProvider(provider.provider);\n  const syncCatalog = async (ctx, client, catalog) => {\n    const signal = AbortSignal.timeout(15e3);\n    const current = catalog ?? await client.list({ signal });\n    provider.setCatalog(current, client.serverUrl);\n    const result = await ctx.modelRegistry.refresh({\n      providers: [LLAMA_PROVIDER_ID],\n      signal\n    });\n    if (result.aborted)\n      throw new Error(\"Model catalog refresh timed out.\");\n    const refreshError = result.errors.get(LLAMA_PROVIDER_ID);\n    if (refreshError)\n      throw refreshError;\n    return current;\n  };\n  const loadModel = async (ctx, ui, client, catalog, target) => {\n    const loaded = catalog.filter((model) => model.id !== target.id && modelIsLoaded(model));\n    let replace = false;\n    if (loaded.length > 0) {\n      const choice = await ui.select(`${loaded.length} model${loaded.length === 1 ? \" is\" : \"s are\"} loaded`, [\n        \"Unload all and load\",\n        \"Keep loaded and load\",\n        \"Cancel\"\n      ]);\n      if (!choice || choice === \"Cancel\")\n        return;\n      replace = choice === \"Unload all and load\";\n    }\n    const restoreLoaded = async () => {\n      ctx.ui.notify(\"Restoring previously loaded models\");\n      for (const model of loaded)\n        await client.loadAndWait(model.id, () => {\n        });\n      await syncCatalog(ctx, client);\n    };\n    if (replace) {\n      for (const model of loaded)\n        await client.unloadAndWait(model.id);\n    }\n    try {\n      const result = await runWithProgress(ui, {\n        title: \"Loading model\",\n        model: target.id,\n        initialMessage: \"Starting\\u2026\",\n        cancelTitle: \"Stop loading?\",\n        cancelMessage: target.id,\n        run: (signal, update) => client.loadAndWait(target.id, update, signal),\n        cancel: () => client.unload(target.id)\n      });\n      if (result.cancelled) {\n        if (replace)\n          await restoreLoaded();\n        return;\n      }\n      const refreshed = await syncCatalog(ctx, client);\n      const loadedModel = refreshed.find((model) => model.id === target.id);\n      ctx.ui.notify(loadedModel?.status.value === \"loaded\" ? `Loaded ${target.id}` : `Load started for ${target.id}`);\n    } catch (error) {\n      if (replace) {\n        try {\n          await restoreLoaded();\n        } catch {\n        }\n      }\n      throw error;\n    }\n  };\n  const unloadModel = async (ctx, ui, client, model) => {\n    if (!await ui.confirm(\"Unload model?\", model.id))\n      return;\n    await client.unloadAndWait(model.id);\n    await syncCatalog(ctx, client);\n    ctx.ui.notify(`Unloaded ${model.id}`);\n  };\n  const downloadModel = async (ctx, ui, client) => {\n    const huggingFace = new HuggingFaceClient(await findHuggingFaceToken());\n    const selected = await ui.searchModels((query, signal) => huggingFace.search(query, signal));\n    if (!selected)\n      return;\n    const parsed = parseHuggingFaceModel(selected);\n    ui.showStatus(\"Loading model details\", parsed.repository);\n    const details = await huggingFace.details(parsed.repository);\n    if (details.gated) {\n      const approval = details.gated === \"manual\" ? \"Manual approval is required\" : \"Accept the access terms\";\n      const choice = await ui.select(`Hugging Face access required\n${details.id}\n\n${approval} at:\nhttps://huggingface.co/${details.id}\n\nThe llama.cpp server needs HF_TOKEN with access.`, [\"Continue\", \"Back\"]);\n      if (choice !== \"Continue\")\n        return;\n    }\n    let quantization = parsed.quantization;\n    if (!quantization && details.quantizations.length > 0) {\n      const options = details.quantizations.map((entry) => {\n        const detail = [\n          entry.size === void 0 ? void 0 : formatBytes(entry.size),\n          entry.name === \"Q4_K_M\" ? \"recommended\" : void 0\n        ].filter((value) => Boolean(value)).join(\" \\xB7 \");\n        return detail ? `${entry.name} \\xB7 ${detail}` : entry.name;\n      });\n      const choice = await ui.select(`Select quantization\n${details.id}`, options);\n      if (!choice)\n        return;\n      quantization = details.quantizations[options.indexOf(choice)]?.name;\n      if (!quantization)\n        return;\n    }\n    const model = quantization ? `${details.id}:${quantization}` : details.id;\n    const result = await runWithProgress(ui, {\n      title: \"Downloading model\",\n      model,\n      initialMessage: \"Starting\\u2026\",\n      cancelTitle: \"Stop download?\",\n      cancelMessage: model,\n      run: (signal, update) => client.downloadAndWait(model, update, signal),\n      cancel: () => client.unload(model)\n    });\n    if (result.cancelled)\n      return;\n    await syncCatalog(ctx, client, result.value);\n    ctx.ui.notify(`Downloaded ${model}`);\n  };\n  pi.registerCommand(\"llama\", {\n    description: \"Manage llama.cpp router models\",\n    handler: async (_args, ctx) => {\n      if (ctx.mode !== \"tui\") {\n        ctx.ui.notify(\"/llama is available in interactive mode\", \"warning\");\n        return;\n      }\n      const client = await configuredClient(ctx);\n      if (!client)\n        return;\n      await showLlamaUi(ctx, async (ui) => {\n        const readCatalog = async () => {\n          while (true) {\n            try {\n              return await syncCatalog(ctx, client);\n            } catch (error) {\n              if (await ui.connectionError(client.serverUrl, connectionErrorMessage(error)) === \"close\") {\n                return void 0;\n              }\n            }\n          }\n        };\n        let catalog = await readCatalog();\n        if (!catalog)\n          return;\n        while (true) {\n          const action = await ui.showModels(client.serverUrl, catalog);\n          if (action.type === \"close\")\n            return;\n          let actionError;\n          try {\n            if (action.type === \"download\")\n              await downloadModel(ctx, ui, client);\n            else if (modelIsLoaded(action.model))\n              await unloadModel(ctx, ui, client, action.model);\n            else if (action.model.status.value === \"unloaded\")\n              await loadModel(ctx, ui, client, catalog, action.model);\n            else\n              ctx.ui.notify(`${action.model.id} is ${action.model.status.value}`, \"warning\");\n          } catch (error) {\n            actionError = error;\n          }\n          const refreshed = await readCatalog();\n          if (!refreshed)\n            return;\n          catalog = refreshed;\n          if (actionError && !isConnectionError(actionError)) {\n            ctx.ui.notify(actionError instanceof Error ? actionError.message : String(actionError), \"error\");\n          }\n        }\n      });\n    }\n  });\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/extensions/index.js\nvar builtInExtensions = [{ name: \"llama.cpp\", factory: llamaExtension, hidden: true }];\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/migrations.js\nimport chalk9 from \"chalk\";\nimport { existsSync as existsSync24, mkdirSync as mkdirSync11, readdirSync as readdirSync10, readFileSync as readFileSync19, renameSync as renameSync2, rmSync as rmSync4, writeFileSync as writeFileSync11 } from \"fs\";\nimport { dirname as dirname22, join as join36 } from \"path\";\nvar MIGRATION_GUIDE_URL = \"https://github.com/earendil-works/pi-mono/blob/main/packages/coding-agent/CHANGELOG.md#extensions-migration\";\nvar EXTENSIONS_DOC_URL = \"https://github.com/earendil-works/pi-mono/blob/main/packages/coding-agent/docs/extensions.md\";\nfunction migrateAuthToAuthJson() {\n  const agentDir = getAgentDir();\n  const authPath = join36(agentDir, \"auth.json\");\n  const oauthPath = join36(agentDir, \"oauth.json\");\n  const settingsPath = join36(agentDir, \"settings.json\");\n  if (existsSync24(authPath))\n    return [];\n  const migrated = {};\n  const providers = [];\n  if (existsSync24(oauthPath)) {\n    try {\n      const oauth = JSON.parse(readFileSync19(oauthPath, \"utf-8\"));\n      for (const [provider, cred] of Object.entries(oauth)) {\n        migrated[provider] = { type: \"oauth\", ...cred };\n        providers.push(provider);\n      }\n      renameSync2(oauthPath, `${oauthPath}.migrated`);\n    } catch {\n    }\n  }\n  if (existsSync24(settingsPath)) {\n    try {\n      const content = readFileSync19(settingsPath, \"utf-8\");\n      const settings = JSON.parse(content);\n      if (settings.apiKeys && typeof settings.apiKeys === \"object\") {\n        for (const [provider, key] of Object.entries(settings.apiKeys)) {\n          if (!migrated[provider] && typeof key === \"string\") {\n            migrated[provider] = { type: \"api_key\", key };\n            providers.push(provider);\n          }\n        }\n        delete settings.apiKeys;\n        writeFileSync11(settingsPath, JSON.stringify(settings, null, 2));\n      }\n    } catch {\n    }\n  }\n  if (Object.keys(migrated).length > 0) {\n    mkdirSync11(dirname22(authPath), { recursive: true });\n    writeFileSync11(authPath, JSON.stringify(migrated, null, 2), { mode: 384 });\n  }\n  return providers;\n}\nfunction migrateSessionsFromAgentRoot() {\n  const agentDir = getAgentDir();\n  let files;\n  try {\n    files = readdirSync10(agentDir).filter((f) => f.endsWith(\".jsonl\")).map((f) => join36(agentDir, f));\n  } catch {\n    return;\n  }\n  if (files.length === 0)\n    return;\n  for (const file of files) {\n    try {\n      const content = readFileSync19(file, \"utf8\");\n      const firstLine = content.split(\"\\n\")[0];\n      if (!firstLine?.trim())\n        continue;\n      const header = JSON.parse(firstLine);\n      if (header.type !== \"session\" || !header.cwd)\n        continue;\n      const cwd = header.cwd;\n      const safePath = `--${cwd.replace(/^[/\\\\]/, \"\").replace(/[/\\\\:]/g, \"-\")}--`;\n      const correctDir = join36(agentDir, \"sessions\", safePath);\n      if (!existsSync24(correctDir)) {\n        mkdirSync11(correctDir, { recursive: true });\n      }\n      const fileName = file.split(\"/\").pop() || file.split(\"\\\\\").pop();\n      const newPath = join36(correctDir, fileName);\n      if (existsSync24(newPath))\n        continue;\n      renameSync2(file, newPath);\n    } catch {\n    }\n  }\n}\nfunction migrateCommandsToPrompts(baseDir, label) {\n  const commandsDir = join36(baseDir, \"commands\");\n  const promptsDir = join36(baseDir, \"prompts\");\n  if (existsSync24(commandsDir) && !existsSync24(promptsDir)) {\n    try {\n      renameSync2(commandsDir, promptsDir);\n      console.log(chalk9.green(`Migrated ${label} commands/ \\u2192 prompts/`));\n      return true;\n    } catch (err2) {\n      console.log(chalk9.yellow(`Warning: Could not migrate ${label} commands/ to prompts/: ${err2 instanceof Error ? err2.message : err2}`));\n    }\n  }\n  return false;\n}\nfunction migrateKeybindingsConfigFile() {\n  const configPath = join36(getAgentDir(), \"keybindings.json\");\n  if (!existsSync24(configPath))\n    return;\n  try {\n    const parsed = JSON.parse(readFileSync19(configPath, \"utf-8\"));\n    if (typeof parsed !== \"object\" || parsed === null || Array.isArray(parsed)) {\n      return;\n    }\n    const { config, migrated } = migrateKeybindingsConfig(parsed);\n    if (!migrated)\n      return;\n    writeFileSync11(configPath, `${JSON.stringify(config, null, 2)}\n`, \"utf-8\");\n  } catch {\n  }\n}\nfunction migrateToolsToBin() {\n  const agentDir = getAgentDir();\n  const toolsDir = join36(agentDir, \"tools\");\n  const binDir = getBinDir();\n  if (!existsSync24(toolsDir))\n    return;\n  const binaries = [\"fd\", \"rg\", \"fd.exe\", \"rg.exe\"];\n  let movedAny = false;\n  for (const bin of binaries) {\n    const oldPath = join36(toolsDir, bin);\n    const newPath = join36(binDir, bin);\n    if (existsSync24(oldPath)) {\n      if (!existsSync24(binDir)) {\n        mkdirSync11(binDir, { recursive: true });\n      }\n      if (!existsSync24(newPath)) {\n        try {\n          renameSync2(oldPath, newPath);\n          movedAny = true;\n        } catch {\n        }\n      } else {\n        try {\n          rmSync4?.(oldPath, { force: true });\n        } catch {\n        }\n      }\n    }\n  }\n  if (movedAny) {\n    console.log(chalk9.green(`Migrated managed binaries tools/ \\u2192 bin/`));\n  }\n}\nfunction checkDeprecatedExtensionDirs(baseDir, label) {\n  const hooksDir = join36(baseDir, \"hooks\");\n  const toolsDir = join36(baseDir, \"tools\");\n  const warnings = [];\n  if (existsSync24(hooksDir)) {\n    warnings.push(`${label} hooks/ directory found. Hooks have been renamed to extensions.`);\n  }\n  if (existsSync24(toolsDir)) {\n    try {\n      const entries = readdirSync10(toolsDir);\n      const customTools = entries.filter((e) => {\n        const lower = e.toLowerCase();\n        return lower !== \"fd\" && lower !== \"rg\" && lower !== \"fd.exe\" && lower !== \"rg.exe\" && !e.startsWith(\".\");\n      });\n      if (customTools.length > 0) {\n        warnings.push(`${label} tools/ directory contains custom tools. Custom tools have been merged into extensions.`);\n      }\n    } catch {\n    }\n  }\n  return warnings;\n}\nfunction migrateExtensionSystem(cwd) {\n  const agentDir = getAgentDir();\n  const projectDir = join36(cwd, CONFIG_DIR_NAME);\n  migrateCommandsToPrompts(agentDir, \"Global\");\n  migrateCommandsToPrompts(projectDir, \"Project\");\n  const warnings = [\n    ...checkDeprecatedExtensionDirs(agentDir, \"Global\"),\n    ...checkDeprecatedExtensionDirs(projectDir, \"Project\")\n  ];\n  return warnings;\n}\nasync function showDeprecationWarnings(warnings) {\n  if (warnings.length === 0)\n    return;\n  for (const warning of warnings) {\n    console.log(chalk9.yellow(`Warning: ${warning}`));\n  }\n  console.log(chalk9.yellow(`\nMove your extensions to the extensions/ directory.`));\n  console.log(chalk9.yellow(`Migration guide: ${MIGRATION_GUIDE_URL}`));\n  console.log(chalk9.yellow(`Documentation: ${EXTENSIONS_DOC_URL}`));\n  console.log(chalk9.dim(`\nPress any key to continue...`));\n  await new Promise((resolve15) => {\n    process.stdin.setRawMode?.(true);\n    process.stdin.resume();\n    process.stdin.once(\"data\", () => {\n      process.stdin.setRawMode?.(false);\n      process.stdin.pause();\n      resolve15();\n    });\n  });\n  console.log();\n}\nfunction runMigrations(cwd) {\n  const migratedAuthProviders = migrateAuthToAuthJson();\n  migrateSessionsFromAgentRoot();\n  migrateToolsToBin();\n  migrateKeybindingsConfigFile();\n  const deprecationWarnings = migrateExtensionSystem(cwd);\n  return { migratedAuthProviders, deprecationWarnings };\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/package-manager-cli.js\nimport { join as join39 } from \"node:path\";\nimport chalk10 from \"chalk\";\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/config-selector.js\nimport { homedir as homedir12 } from \"node:os\";\nimport { basename as basename12, dirname as dirname23, join as join37, relative as relative7 } from \"node:path\";\nvar RESOURCE_TYPES2 = [\"extensions\", \"skills\", \"prompts\", \"themes\"];\nvar RESOURCE_TYPE_LABELS = {\n  extensions: \"Extensions\",\n  skills: \"Skills\",\n  prompts: \"Prompts\",\n  themes: \"Themes\"\n};\nfunction formatBaseDir(baseDir) {\n  const homeDir = homedir12();\n  let displayPath;\n  if (baseDir === homeDir) {\n    displayPath = \"~\";\n  } else if (baseDir.startsWith(homeDir)) {\n    const rest = baseDir.slice(homeDir.length);\n    displayPath = `~${rest.replace(/\\\\/g, \"/\")}`;\n  } else {\n    displayPath = baseDir.replace(/\\\\/g, \"/\");\n  }\n  return displayPath.endsWith(\"/\") ? displayPath : `${displayPath}/`;\n}\nfunction getGroupLabel(metadata, agentDir) {\n  if (metadata.origin === \"package\") {\n    return `${metadata.source} (${metadata.scope})`;\n  }\n  if (metadata.source === \"auto\") {\n    if (metadata.baseDir) {\n      return metadata.scope === \"user\" ? `User (${formatBaseDir(metadata.baseDir)})` : `Project (${formatBaseDir(metadata.baseDir)})`;\n    }\n    return metadata.scope === \"user\" ? `User (${formatBaseDir(agentDir)})` : `Project (${CONFIG_DIR_NAME}/)`;\n  }\n  return metadata.scope === \"user\" ? \"User settings\" : \"Project settings\";\n}\nfunction buildGroups(resolved, agentDir) {\n  const groupMap = /* @__PURE__ */ new Map();\n  const addToGroup = (resources, resourceType) => {\n    for (const res of resources) {\n      const { path: path12, enabled, metadata } = res;\n      const groupKey = `${metadata.origin}:${metadata.scope}:${metadata.source}:${metadata.baseDir ?? \"\"}`;\n      if (!groupMap.has(groupKey)) {\n        groupMap.set(groupKey, {\n          key: groupKey,\n          label: getGroupLabel(metadata, agentDir),\n          scope: metadata.scope,\n          origin: metadata.origin,\n          source: metadata.source,\n          subgroups: []\n        });\n      }\n      const group = groupMap.get(groupKey);\n      const subgroupKey = `${groupKey}:${resourceType}`;\n      let subgroup = group.subgroups.find((sg) => sg.type === resourceType);\n      if (!subgroup) {\n        subgroup = {\n          type: resourceType,\n          label: RESOURCE_TYPE_LABELS[resourceType],\n          items: []\n        };\n        group.subgroups.push(subgroup);\n      }\n      const fileName = basename12(path12);\n      const parentFolder = basename12(dirname23(path12));\n      let displayName;\n      if (resourceType === \"extensions\" && parentFolder !== \"extensions\") {\n        displayName = `${parentFolder}/${fileName}`;\n      } else if (resourceType === \"skills\" && fileName === \"SKILL.md\") {\n        displayName = parentFolder;\n      } else {\n        displayName = fileName;\n      }\n      subgroup.items.push({\n        path: path12,\n        enabled,\n        metadata,\n        resourceType,\n        displayName,\n        groupKey,\n        subgroupKey\n      });\n    }\n  };\n  addToGroup(resolved.extensions, \"extensions\");\n  addToGroup(resolved.skills, \"skills\");\n  addToGroup(resolved.prompts, \"prompts\");\n  addToGroup(resolved.themes, \"themes\");\n  const groups = Array.from(groupMap.values());\n  groups.sort((a, b) => {\n    if (a.origin !== b.origin) {\n      return a.origin === \"package\" ? -1 : 1;\n    }\n    if (a.scope !== b.scope) {\n      return a.scope === \"user\" ? -1 : 1;\n    }\n    return a.source.localeCompare(b.source);\n  });\n  const typeOrder = { extensions: 0, skills: 1, prompts: 2, themes: 3 };\n  for (const group of groups) {\n    group.subgroups.sort((a, b) => typeOrder[a.type] - typeOrder[b.type]);\n    for (const subgroup of group.subgroups) {\n      subgroup.items.sort((a, b) => a.displayName.localeCompare(b.displayName));\n    }\n  }\n  return groups;\n}\nvar ConfigSelectorHeader = class {\n  writeScope;\n  projectModeAvailable;\n  constructor(writeScope, projectModeAvailable) {\n    this.writeScope = writeScope;\n    this.projectModeAvailable = projectModeAvailable;\n  }\n  setWriteScope(writeScope) {\n    this.writeScope = writeScope;\n  }\n  invalidate() {\n  }\n  render(width) {\n    const title = theme.bold(this.writeScope === \"project\" ? \"Project Local Resources\" : \"Global Resources\");\n    const sep10 = theme.fg(\"muted\", \" \\xB7 \");\n    const switchHint = this.projectModeAvailable ? keyHint(\"tui.input.tab\", \"switch mode\") + sep10 : \"\";\n    const actionHint = this.writeScope === \"project\" ? rawKeyHint(\"space\", \"cycle inherit/+/-\") : rawKeyHint(\"space\", \"toggle\");\n    const hint = switchHint + actionHint + sep10 + rawKeyHint(\"esc\", \"close\");\n    const spacing = Math.max(1, width - visibleWidth(title) - visibleWidth(hint));\n    const scopeHint = this.writeScope === \"project\" ? theme.fg(\"muted\", `${CONFIG_DIR_NAME}/settings.json \\xB7 inherited global resources are dimmed`) : theme.fg(\"muted\", `~/${CONFIG_DIR_NAME}/agent/settings.json`);\n    return [\n      truncateToWidth(`${title}${\" \".repeat(spacing)}${hint}`, width, \"\"),\n      truncateToWidth(scopeHint, width, \"\")\n    ];\n  }\n};\nvar ResourceList = class {\n  groupsByScope;\n  flatItems = [];\n  filteredItems = [];\n  selectedIndex = 0;\n  searchInput;\n  maxVisible;\n  settingsManager;\n  cwd;\n  agentDir;\n  writeScope;\n  inheritedEnabledByKey;\n  onCancel;\n  onExit;\n  onToggle;\n  onSwitchMode;\n  _focused = false;\n  get focused() {\n    return this._focused;\n  }\n  set focused(value) {\n    this._focused = value;\n    this.searchInput.focused = value;\n  }\n  constructor(groupsByScope, settingsManager, cwd, agentDir, terminalHeight, writeScope = \"global\") {\n    this.groupsByScope = groupsByScope;\n    this.settingsManager = settingsManager;\n    this.cwd = cwd;\n    this.agentDir = agentDir;\n    this.writeScope = writeScope;\n    this.inheritedEnabledByKey = this.buildInheritedEnabledMap(groupsByScope.global);\n    this.searchInput = new Input();\n    const chrome = 8;\n    this.maxVisible = Math.max(5, (terminalHeight ?? 24) - chrome);\n    this.buildFlatList();\n    this.filteredItems = [...this.flatItems];\n  }\n  setWriteScope(writeScope) {\n    this.writeScope = writeScope;\n    this.buildFlatList();\n    this.filterItems(this.searchInput.getValue());\n  }\n  get groups() {\n    return this.groupsByScope[this.writeScope];\n  }\n  buildInheritedEnabledMap(groups) {\n    const result = /* @__PURE__ */ new Map();\n    for (const group of groups) {\n      for (const subgroup of group.subgroups) {\n        for (const item of subgroup.items) {\n          result.set(this.getResourceItemKey(item), item.enabled);\n        }\n      }\n    }\n    return result;\n  }\n  buildFlatList() {\n    this.flatItems = [];\n    for (const group of this.groups) {\n      this.flatItems.push({ type: \"group\", group });\n      for (const subgroup of group.subgroups) {\n        this.flatItems.push({ type: \"subgroup\", subgroup, group });\n        for (const item of subgroup.items) {\n          this.flatItems.push({ type: \"item\", item });\n        }\n      }\n    }\n    this.selectedIndex = this.flatItems.findIndex((e) => e.type === \"item\");\n    if (this.selectedIndex < 0)\n      this.selectedIndex = 0;\n  }\n  findNextItem(fromIndex, direction) {\n    let idx = fromIndex + direction;\n    while (idx >= 0 && idx < this.filteredItems.length) {\n      if (this.filteredItems[idx].type === \"item\") {\n        return idx;\n      }\n      idx += direction;\n    }\n    return fromIndex;\n  }\n  filterItems(query) {\n    if (!query.trim()) {\n      this.filteredItems = [...this.flatItems];\n      this.selectFirstItem();\n      return;\n    }\n    const lowerQuery = query.toLowerCase();\n    const matchingItems = /* @__PURE__ */ new Set();\n    const matchingSubgroups = /* @__PURE__ */ new Set();\n    const matchingGroups = /* @__PURE__ */ new Set();\n    for (const entry of this.flatItems) {\n      if (entry.type === \"item\") {\n        const item = entry.item;\n        if (item.displayName.toLowerCase().includes(lowerQuery) || item.resourceType.toLowerCase().includes(lowerQuery) || item.path.toLowerCase().includes(lowerQuery)) {\n          matchingItems.add(item);\n        }\n      }\n    }\n    for (const group of this.groups) {\n      for (const subgroup of group.subgroups) {\n        for (const item of subgroup.items) {\n          if (matchingItems.has(item)) {\n            matchingSubgroups.add(subgroup);\n            matchingGroups.add(group);\n          }\n        }\n      }\n    }\n    this.filteredItems = [];\n    for (const entry of this.flatItems) {\n      if (entry.type === \"group\" && matchingGroups.has(entry.group)) {\n        this.filteredItems.push(entry);\n      } else if (entry.type === \"subgroup\" && matchingSubgroups.has(entry.subgroup)) {\n        this.filteredItems.push(entry);\n      } else if (entry.type === \"item\" && matchingItems.has(entry.item)) {\n        this.filteredItems.push(entry);\n      }\n    }\n    this.selectFirstItem();\n  }\n  selectFirstItem() {\n    const firstItemIndex = this.filteredItems.findIndex((e) => e.type === \"item\");\n    this.selectedIndex = firstItemIndex >= 0 ? firstItemIndex : 0;\n  }\n  updateItem(item, enabled) {\n    item.enabled = enabled;\n    for (const group of this.groups) {\n      for (const subgroup of group.subgroups) {\n        const found = subgroup.items.find((i) => i.path === item.path && i.resourceType === item.resourceType);\n        if (found) {\n          found.enabled = enabled;\n          return;\n        }\n      }\n    }\n  }\n  invalidate() {\n  }\n  render(width) {\n    const lines = [];\n    lines.push(...this.searchInput.render(width));\n    lines.push(\"\");\n    if (this.filteredItems.length === 0) {\n      lines.push(theme.fg(\"muted\", \"  No resources found\"));\n      return lines;\n    }\n    const startIndex = Math.max(0, Math.min(this.selectedIndex - Math.floor(this.maxVisible / 2), this.filteredItems.length - this.maxVisible));\n    const endIndex = Math.min(startIndex + this.maxVisible, this.filteredItems.length);\n    for (let i = startIndex; i < endIndex; i++) {\n      const entry = this.filteredItems[i];\n      const isSelected = i === this.selectedIndex;\n      if (entry.type === \"group\") {\n        const inherited = this.writeScope === \"project\" && entry.group.scope === \"user\";\n        const label = theme.bold(`${entry.group.label}${inherited ? \" \\xB7 inherited global\" : \"\"}`);\n        const groupLine = theme.fg(inherited ? \"dim\" : \"accent\", label);\n        lines.push(truncateToWidth(`  ${groupLine}`, width, \"\"));\n      } else if (entry.type === \"subgroup\") {\n        const color = this.writeScope === \"project\" && entry.group.scope === \"user\" ? \"dim\" : \"muted\";\n        const subgroupLine = theme.fg(color, entry.subgroup.label);\n        lines.push(truncateToWidth(`    ${subgroupLine}`, width, \"\"));\n      } else {\n        const item = entry.item;\n        const cursor = isSelected ? \"> \" : \"  \";\n        const dimmed = this.isDimmedItem(item);\n        const nameText = isSelected && !dimmed ? theme.bold(item.displayName) : item.displayName;\n        const name = dimmed ? theme.fg(\"dim\", nameText) : nameText;\n        lines.push(truncateToWidth(`${cursor}    ${this.renderCheckbox(item)} ${name}${this.getItemSuffix(item)}`, width, \"...\"));\n      }\n    }\n    if (startIndex > 0 || endIndex < this.filteredItems.length) {\n      const itemCount = this.filteredItems.filter((e) => e.type === \"item\").length;\n      const currentItemIndex = this.filteredItems.slice(0, this.selectedIndex).filter((e) => e.type === \"item\").length + 1;\n      lines.push(theme.fg(\"dim\", `  (${currentItemIndex}/${itemCount})`));\n    }\n    return lines;\n  }\n  handleInput(data) {\n    const kb = getKeybindings();\n    if (kb.matches(data, \"tui.select.up\")) {\n      this.selectedIndex = this.findNextItem(this.selectedIndex, -1);\n      return;\n    }\n    if (kb.matches(data, \"tui.select.down\")) {\n      this.selectedIndex = this.findNextItem(this.selectedIndex, 1);\n      return;\n    }\n    if (kb.matches(data, \"tui.select.pageUp\")) {\n      let target = Math.max(0, this.selectedIndex - this.maxVisible);\n      while (target < this.filteredItems.length && this.filteredItems[target].type !== \"item\") {\n        target++;\n      }\n      if (target < this.filteredItems.length) {\n        this.selectedIndex = target;\n      }\n      return;\n    }\n    if (kb.matches(data, \"tui.select.pageDown\")) {\n      let target = Math.min(this.filteredItems.length - 1, this.selectedIndex + this.maxVisible);\n      while (target >= 0 && this.filteredItems[target].type !== \"item\") {\n        target--;\n      }\n      if (target >= 0) {\n        this.selectedIndex = target;\n      }\n      return;\n    }\n    if (kb.matches(data, \"tui.select.cancel\")) {\n      this.onCancel?.();\n      return;\n    }\n    if (matchesKey(data, \"ctrl+c\")) {\n      this.onExit?.();\n      return;\n    }\n    if (kb.matches(data, \"tui.input.tab\")) {\n      this.onSwitchMode?.();\n      return;\n    }\n    if (data === \" \" || kb.matches(data, \"tui.select.confirm\")) {\n      const entry = this.filteredItems[this.selectedIndex];\n      if (entry?.type === \"item\" && (this.writeScope === \"project\" || this.getItemScope(entry.item) === \"user\")) {\n        const newEnabled = this.toggleResource(entry.item);\n        if (newEnabled !== void 0) {\n          this.updateItem(entry.item, newEnabled);\n          this.onToggle?.(entry.item, newEnabled);\n        }\n      }\n      return;\n    }\n    this.searchInput.handleInput(data);\n    this.filterItems(this.searchInput.getValue());\n  }\n  toggleResource(item) {\n    if (this.writeScope === \"project\") {\n      const state = this.getNextOverrideState(item);\n      if (!this.setProjectResourceOverride(item, state))\n        return void 0;\n      return state === \"inherit\" ? this.getInheritedEnabled(item) : state === \"load\";\n    }\n    const enabled = !item.enabled;\n    if (item.metadata.origin === \"top-level\") {\n      this.toggleTopLevelResource(item, enabled);\n    } else {\n      this.togglePackageResource(item, enabled);\n    }\n    return enabled;\n  }\n  toggleTopLevelResource(item, enabled) {\n    const scope = item.metadata.scope;\n    const settings = scope === \"project\" ? this.settingsManager.getProjectSettings() : this.settingsManager.getGlobalSettings();\n    const arrayKey = item.resourceType;\n    const current = settings[arrayKey] ?? [];\n    const pattern = this.getResourcePattern(item);\n    const disablePattern = `-${pattern}`;\n    const enablePattern = `+${pattern}`;\n    const updated = current.filter((p) => {\n      const stripped = p.startsWith(\"!\") || p.startsWith(\"+\") || p.startsWith(\"-\") ? p.slice(1) : p;\n      return stripped !== pattern;\n    });\n    if (enabled) {\n      updated.push(enablePattern);\n    } else {\n      updated.push(disablePattern);\n    }\n    if (scope === \"project\") {\n      if (arrayKey === \"extensions\") {\n        this.settingsManager.setProjectExtensionPaths(updated);\n      } else if (arrayKey === \"skills\") {\n        this.settingsManager.setProjectSkillPaths(updated);\n      } else if (arrayKey === \"prompts\") {\n        this.settingsManager.setProjectPromptTemplatePaths(updated);\n      } else if (arrayKey === \"themes\") {\n        this.settingsManager.setProjectThemePaths(updated);\n      }\n    } else {\n      if (arrayKey === \"extensions\") {\n        this.settingsManager.setExtensionPaths(updated);\n      } else if (arrayKey === \"skills\") {\n        this.settingsManager.setSkillPaths(updated);\n      } else if (arrayKey === \"prompts\") {\n        this.settingsManager.setPromptTemplatePaths(updated);\n      } else if (arrayKey === \"themes\") {\n        this.settingsManager.setThemePaths(updated);\n      }\n    }\n  }\n  togglePackageResource(item, enabled) {\n    const scope = item.metadata.scope;\n    const settings = scope === \"project\" ? this.settingsManager.getProjectSettings() : this.settingsManager.getGlobalSettings();\n    const packages = [...settings.packages ?? []];\n    const pkgIndex = packages.findIndex((pkg3) => {\n      const source = typeof pkg3 === \"string\" ? pkg3 : pkg3.source;\n      return source === item.metadata.source;\n    });\n    if (pkgIndex === -1)\n      return;\n    let pkg2 = packages[pkgIndex];\n    if (typeof pkg2 === \"string\") {\n      pkg2 = { source: pkg2 };\n      packages[pkgIndex] = pkg2;\n    }\n    const arrayKey = item.resourceType;\n    const current = pkg2[arrayKey] ?? [];\n    const pattern = this.getPackageResourcePattern(item);\n    const disablePattern = `-${pattern}`;\n    const enablePattern = `+${pattern}`;\n    const updated = current.filter((p) => {\n      const stripped = p.startsWith(\"!\") || p.startsWith(\"+\") || p.startsWith(\"-\") ? p.slice(1) : p;\n      return stripped !== pattern;\n    });\n    if (enabled) {\n      updated.push(enablePattern);\n    } else {\n      updated.push(disablePattern);\n    }\n    pkg2[arrayKey] = updated.length > 0 ? updated : void 0;\n    const hasFilters = [\"extensions\", \"skills\", \"prompts\", \"themes\"].some((k) => pkg2[k] !== void 0);\n    if (!hasFilters) {\n      packages[pkgIndex] = pkg2.source;\n    }\n    if (scope === \"project\") {\n      this.settingsManager.setProjectPackages(packages);\n    } else {\n      this.settingsManager.setPackages(packages);\n    }\n  }\n  renderCheckbox(item) {\n    if (this.writeScope === \"project\") {\n      const state = this.getProjectOverrideState(item);\n      if (state === \"load\")\n        return theme.fg(\"success\", \"[+]\");\n      if (state === \"unload\")\n        return theme.fg(\"warning\", \"[-]\");\n      return theme.fg(\"dim\", item.enabled ? \"[x]\" : \"[ ]\");\n    }\n    return item.enabled ? theme.fg(\"success\", \"[x]\") : theme.fg(\"dim\", \"[ ]\");\n  }\n  getItemSuffix(item) {\n    if (this.writeScope !== \"project\")\n      return \"\";\n    const state = this.getProjectOverrideState(item);\n    if (state === \"load\")\n      return theme.fg(\"muted\", \"  project load\");\n    if (state === \"unload\")\n      return theme.fg(\"muted\", \"  project unload\");\n    return this.isInheritedGlobalItem(item) ? theme.fg(\"dim\", \"  inherited global\") : \"\";\n  }\n  isDimmedItem(item) {\n    return this.writeScope === \"project\" && this.isInheritedGlobalItem(item) && this.getProjectOverrideState(item) === \"inherit\";\n  }\n  setProjectResourceOverride(item, state) {\n    return item.metadata.origin === \"top-level\" ? this.setProjectTopLevelOverride(item, state) : this.setProjectPackageOverride(item, state);\n  }\n  setProjectTopLevelOverride(item, state) {\n    const current = this.settingsManager.getProjectSettings()[item.resourceType] ?? [];\n    const pattern = this.isInheritedGlobalItem(item) ? item.path : this.getResourcePatternForScope(item, \"project\");\n    const patterns = this.getTopLevelOverridePatterns(item, \"project\");\n    const updated = current.filter((entry) => {\n      const target = this.getPatternEntryTarget(entry);\n      if ((entry.startsWith(\"!\") || entry.startsWith(\"+\") || entry.startsWith(\"-\")) && patterns.has(target))\n        return false;\n      return !(state === \"inherit\" && this.isInheritedGlobalItem(item) && target === pattern);\n    });\n    if (state !== \"inherit\") {\n      if (this.isInheritedGlobalItem(item) && !updated.includes(pattern))\n        updated.push(pattern);\n      updated.push(`${state === \"load\" ? \"+\" : \"-\"}${pattern}`);\n    }\n    this.setProjectTopLevelPaths(item.resourceType, updated);\n    return true;\n  }\n  setProjectTopLevelPaths(key, paths) {\n    if (key === \"extensions\")\n      this.settingsManager.setProjectExtensionPaths(paths);\n    else if (key === \"skills\")\n      this.settingsManager.setProjectSkillPaths(paths);\n    else if (key === \"prompts\")\n      this.settingsManager.setProjectPromptTemplatePaths(paths);\n    else\n      this.settingsManager.setProjectThemePaths(paths);\n  }\n  setProjectPackageOverride(item, state) {\n    const packages = [...this.settingsManager.getProjectSettings().packages ?? []];\n    let pkgIndex = packages.findIndex((pkg3) => this.packageSourceStringMatches(item.metadata.source, this.getItemScope(item), typeof pkg3 === \"string\" ? pkg3 : pkg3.source, \"project\"));\n    if (pkgIndex === -1) {\n      if (state === \"inherit\")\n        return false;\n      packages.push(this.createPackageOverrideSource(item));\n      pkgIndex = packages.length - 1;\n    }\n    let pkg2 = packages[pkgIndex];\n    if (pkg2 === void 0)\n      return false;\n    if (typeof pkg2 === \"string\") {\n      pkg2 = { source: pkg2 };\n      packages[pkgIndex] = pkg2;\n    }\n    const pattern = this.getPackageResourcePattern(item);\n    const updated = (pkg2[item.resourceType] ?? []).filter((entry) => this.getPatternEntryTarget(entry) !== pattern);\n    if (state !== \"inherit\")\n      updated.push(`${state === \"load\" ? \"+\" : \"-\"}${pattern}`);\n    pkg2[item.resourceType] = updated.length > 0 ? updated : void 0;\n    if (!RESOURCE_TYPES2.some((key) => pkg2[key] !== void 0)) {\n      if (pkg2.autoload === false)\n        packages.splice(pkgIndex, 1);\n      else\n        packages[pkgIndex] = pkg2.source;\n    }\n    this.settingsManager.setProjectPackages(packages);\n    return true;\n  }\n  getNextOverrideState(item) {\n    const state = this.getProjectOverrideState(item);\n    const inheritedEnabled = this.getInheritedEnabled(item);\n    if (state === \"inherit\")\n      return inheritedEnabled ? \"unload\" : \"load\";\n    if (state === \"unload\")\n      return inheritedEnabled ? \"load\" : \"inherit\";\n    return inheritedEnabled ? \"inherit\" : \"unload\";\n  }\n  getProjectOverrideState(item) {\n    if (this.writeScope !== \"project\")\n      return \"inherit\";\n    if (item.metadata.origin === \"top-level\") {\n      return this.getOverrideStateFromEntries(this.settingsManager.getProjectSettings()[item.resourceType] ?? [], this.getTopLevelOverridePatterns(item, \"project\"), false);\n    }\n    const pkg2 = this.findMatchingPackageSource(item, \"project\");\n    if (typeof pkg2 !== \"object\")\n      return \"inherit\";\n    const entries = pkg2[item.resourceType];\n    if (entries === void 0)\n      return \"inherit\";\n    return this.getOverrideStateFromEntries(entries, /* @__PURE__ */ new Set([this.getPackageResourcePattern(item)]), pkg2.autoload !== false);\n  }\n  getOverrideStateFromEntries(entries, patterns, emptyArrayIsUnload) {\n    if (entries.length === 0 && emptyArrayIsUnload)\n      return \"unload\";\n    let state = \"inherit\";\n    for (const entry of entries) {\n      if (!patterns.has(this.getPatternEntryTarget(entry)))\n        continue;\n      if (entry.startsWith(\"!\") || entry.startsWith(\"-\"))\n        state = \"unload\";\n      else\n        state = \"load\";\n    }\n    return state;\n  }\n  getInheritedEnabled(item) {\n    return this.inheritedEnabledByKey.get(this.getResourceItemKey(item)) ?? (this.getItemScope(item) === \"user\" ? item.enabled : true);\n  }\n  isInheritedGlobalItem(item) {\n    return this.getItemScope(item) === \"user\" || this.inheritedEnabledByKey.has(this.getResourceItemKey(item));\n  }\n  getTopLevelOverridePatterns(item, scope) {\n    const baseDir = this.getTopLevelBaseDir(scope);\n    const patterns = /* @__PURE__ */ new Set([\n      this.getResourcePatternForScope(item, scope),\n      item.path,\n      relative7(baseDir, item.path)\n    ]);\n    if (item.metadata.baseDir)\n      patterns.add(relative7(item.metadata.baseDir, item.path));\n    return patterns;\n  }\n  getResourcePatternForScope(item, scope) {\n    const sourceScope = this.getItemScope(item);\n    if (scope !== sourceScope)\n      return item.path;\n    const baseDir = item.metadata.baseDir ?? this.getTopLevelBaseDir(sourceScope);\n    return relative7(baseDir, item.path);\n  }\n  createPackageOverrideSource(item) {\n    const source = item.metadata.source;\n    if (!isLocalPath(source))\n      return { source, autoload: false };\n    const sourcePath = resolvePath(source, this.getTopLevelBaseDir(this.getItemScope(item)), { trim: true });\n    return { source: relative7(this.getTopLevelBaseDir(\"project\"), sourcePath) || \".\", autoload: false };\n  }\n  packageSourceStringMatches(leftSource, leftScope, rightSource, rightScope) {\n    if (leftSource === rightSource)\n      return true;\n    if (!isLocalPath(leftSource) || !isLocalPath(rightSource))\n      return false;\n    const left = resolvePath(leftSource, this.getTopLevelBaseDir(leftScope), { trim: true });\n    const right = resolvePath(rightSource, this.getTopLevelBaseDir(rightScope), { trim: true });\n    return left === right;\n  }\n  findMatchingPackageSource(item, targetScope) {\n    const settings = targetScope === \"project\" ? this.settingsManager.getProjectSettings() : this.settingsManager.getGlobalSettings();\n    return (settings.packages ?? []).find((pkg2) => this.packageSourceStringMatches(item.metadata.source, this.getItemScope(item), typeof pkg2 === \"string\" ? pkg2 : pkg2.source, targetScope));\n  }\n  getPatternEntryTarget(entry) {\n    return entry.startsWith(\"!\") || entry.startsWith(\"+\") || entry.startsWith(\"-\") ? entry.slice(1) : entry;\n  }\n  getResourceItemKey(item) {\n    return `${item.resourceType}:${canonicalizePath(item.path)}`;\n  }\n  getItemScope(item) {\n    return item.metadata.scope === \"project\" ? \"project\" : \"user\";\n  }\n  getTopLevelBaseDir(scope) {\n    return scope === \"project\" ? join37(this.cwd, CONFIG_DIR_NAME) : this.agentDir;\n  }\n  getResourcePattern(item) {\n    const scope = item.metadata.scope;\n    const baseDir = item.metadata.baseDir ?? this.getTopLevelBaseDir(scope);\n    return relative7(baseDir, item.path);\n  }\n  getPackageResourcePattern(item) {\n    const baseDir = item.metadata.baseDir ?? dirname23(item.path);\n    return relative7(baseDir, item.path);\n  }\n};\nvar ConfigSelectorComponent = class extends Container {\n  header;\n  resourceList;\n  writeScope;\n  _focused = false;\n  get focused() {\n    return this._focused;\n  }\n  set focused(value) {\n    this._focused = value;\n    this.resourceList.focused = value;\n  }\n  constructor(resolvedPaths, settingsManager, cwd, agentDir, onClose, onExit, requestRender, terminalHeight, writeScope = \"global\", projectModeAvailable = true) {\n    super();\n    this.writeScope = writeScope;\n    const groupsByScope = {\n      global: buildGroups(resolvedPaths.global, agentDir),\n      project: buildGroups(resolvedPaths.project, agentDir)\n    };\n    this.addChild(new Spacer(1));\n    this.addChild(new DynamicBorder());\n    this.addChild(new Spacer(1));\n    this.header = new ConfigSelectorHeader(this.writeScope, projectModeAvailable);\n    this.addChild(this.header);\n    this.addChild(new Spacer(1));\n    this.resourceList = new ResourceList(groupsByScope, settingsManager, cwd, agentDir, terminalHeight, this.writeScope);\n    this.resourceList.onCancel = onClose;\n    this.resourceList.onExit = onExit;\n    this.resourceList.onToggle = () => requestRender();\n    if (projectModeAvailable) {\n      this.resourceList.onSwitchMode = () => {\n        this.switchWriteScope();\n        requestRender();\n      };\n    }\n    this.addChild(this.resourceList);\n    this.addChild(new Spacer(1));\n    this.addChild(new DynamicBorder());\n  }\n  switchWriteScope() {\n    this.writeScope = this.writeScope === \"global\" ? \"project\" : \"global\";\n    this.header.setWriteScope(this.writeScope);\n    this.resourceList.setWriteScope(this.writeScope);\n  }\n  getResourceList() {\n    return this.resourceList;\n  }\n};\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/cli/config-selector.js\nasync function selectConfig(options) {\n  initTheme(options.settingsManager.getTheme(), true);\n  return new Promise((resolve15) => {\n    const ui = new TuiMainScreen(new ProcessTerminal(), void 0, options.agentDir);\n    let resolved = false;\n    const selector = new ConfigSelectorComponent(options.resolvedPaths, options.settingsManager, options.cwd, options.agentDir, () => {\n      if (!resolved) {\n        resolved = true;\n        ui.stop();\n        stopThemeWatcher();\n        resolve15();\n      }\n    }, () => {\n      ui.stop();\n      stopThemeWatcher();\n      process.exit(0);\n    }, () => ui.requestRender(), ui.terminal.rows, options.writeScope, options.projectModeAvailable);\n    ui.addChild(selector);\n    ui.setFocus(selector.getResourceList());\n    ui.start();\n  });\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/utils/windows-self-update.js\nimport { randomUUID as randomUUID6 } from \"node:crypto\";\nimport { copyFileSync as copyFileSync2, existsSync as existsSync25, mkdirSync as mkdirSync12, renameSync as renameSync3, rmSync as rmSync5 } from \"node:fs\";\nimport { basename as basename13, dirname as dirname24, join as join38, relative as relative8, resolve as resolve14, toNamespacedPath } from \"node:path\";\nvar QUARANTINE_DIR_NAME = \".pi-native-quarantine\";\nfunction normalizePath2(path12) {\n  return toNamespacedPath(resolve14(path12));\n}\nfunction getQuarantineRoot(packageDir) {\n  let current = resolve14(packageDir);\n  while (true) {\n    if (basename13(current).toLowerCase() === \"node_modules\") {\n      return join38(current, QUARANTINE_DIR_NAME);\n    }\n    const parent = dirname24(current);\n    if (parent === current) {\n      return void 0;\n    }\n    current = parent;\n  }\n}\nfunction getLoadedSharedObjectsInPackageDir(packageDir) {\n  const sharedObjects = process.report.getReport().sharedObjects;\n  if (!Array.isArray(sharedObjects)) {\n    return [];\n  }\n  const root = normalizePath2(packageDir).toLowerCase();\n  const seen = /* @__PURE__ */ new Set();\n  const loadedFiles = [];\n  for (const value of sharedObjects) {\n    if (typeof value !== \"string\") {\n      continue;\n    }\n    const filePath = normalizePath2(value);\n    const comparisonPath = filePath.toLowerCase();\n    if (getCwdRelativePath(comparisonPath, root) === void 0 || seen.has(comparisonPath)) {\n      continue;\n    }\n    seen.add(comparisonPath);\n    loadedFiles.push(filePath);\n  }\n  return loadedFiles;\n}\nfunction cleanupWindowsSelfUpdateQuarantine(packageDir) {\n  const quarantineRoot = getQuarantineRoot(packageDir);\n  if (!quarantineRoot) {\n    return;\n  }\n  try {\n    rmSync5(quarantineRoot, { recursive: true, force: true });\n  } catch {\n  }\n}\nfunction quarantineWindowsNativeDependencies(packageDir) {\n  const resolvedPackageDir = normalizePath2(packageDir);\n  const quarantineRoot = getQuarantineRoot(resolvedPackageDir);\n  if (!quarantineRoot) {\n    return;\n  }\n  const loadedFiles = getLoadedSharedObjectsInPackageDir(resolvedPackageDir);\n  if (loadedFiles.length === 0) {\n    return;\n  }\n  const quarantineRunDir = join38(quarantineRoot, `${Date.now()}-${process.pid}-${randomUUID6()}`);\n  for (const loadedFile of loadedFiles) {\n    if (!existsSync25(loadedFile)) {\n      continue;\n    }\n    const quarantinePath = join38(quarantineRunDir, relative8(resolvedPackageDir, loadedFile));\n    mkdirSync12(dirname24(quarantinePath), { recursive: true });\n    renameSync3(loadedFile, quarantinePath);\n    copyFileSync2(quarantinePath, loadedFile);\n  }\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/package-manager-cli.js\nvar SELF_UPDATE_NOTE_MARKDOWN_THEME = {\n  heading: (text) => chalk10.bold(chalk10.yellow(text)),\n  link: (text) => chalk10.cyan(text),\n  linkUrl: (text) => chalk10.dim(text),\n  code: (text) => chalk10.yellow(text),\n  codeBlock: (text) => chalk10.dim(text),\n  codeBlockBorder: (text) => chalk10.dim(text),\n  quote: (text) => chalk10.dim(text),\n  quoteBorder: (text) => chalk10.dim(text),\n  hr: (text) => chalk10.dim(text),\n  listBullet: (text) => chalk10.yellow(text),\n  bold: (text) => chalk10.bold(text),\n  italic: (text) => chalk10.italic(text),\n  strikethrough: (text) => chalk10.strikethrough(text),\n  underline: (text) => chalk10.underline(text)\n};\nfunction reportSettingsErrors(settingsManager, context) {\n  const errors = settingsManager.drainErrors();\n  for (const { scope, error } of errors) {\n    console.error(chalk10.yellow(`Warning (${context}, ${scope} settings): ${error.message}`));\n    if (error.stack) {\n      console.error(chalk10.dim(error.stack));\n    }\n  }\n}\nfunction getPackageCommandUsage(command) {\n  switch (command) {\n    case \"install\":\n      return `${APP_NAME} install <source> [-l] [--approve|--no-approve]`;\n    case \"remove\":\n      return `${APP_NAME} remove <source> [-l] [--approve|--no-approve]`;\n    case \"update\":\n      return `${APP_NAME} update [source|self|pi] [--self|--extensions|--models|--all] [--extension <source>] [--approve|--no-approve] [--force]`;\n    case \"list\":\n      return `${APP_NAME} list [--approve|--no-approve]`;\n  }\n}\nvar CONFIG_COMMAND_USAGE = `${APP_NAME} config [-l] [--approve|--no-approve]`;\nfunction printConfigCommandHelp() {\n  console.log(`${chalk10.bold(\"Usage:\")}\n  ${CONFIG_COMMAND_USAGE}\n\nOpen the resource configuration TUI to enable or disable package resources.\nWithout -l, starts in global settings (~/${CONFIG_DIR_NAME}/agent/settings.json).\nPress Tab in the TUI to switch between global and project-local modes.\n\nOptions:\n  -l, --local       Edit project overrides (${CONFIG_DIR_NAME}/settings.json)\n  -a, --approve     Trust project-local files for this command with -l\n  -na, --no-approve Ignore project-local files for this command with -l\n`);\n}\nfunction printPackageCommandHelp(command) {\n  switch (command) {\n    case \"install\":\n      console.log(`${chalk10.bold(\"Usage:\")}\n  ${getPackageCommandUsage(\"install\")}\n\nInstall a package and add it to settings.\n\nOptions:\n  -l, --local       Install project-locally (${CONFIG_DIR_NAME}/settings.json)\n  -a, --approve     Trust project-local files for this command\n  -na, --no-approve Ignore project-local files for this command\n\nExamples:\n  ${APP_NAME} install npm:@foo/bar\n  ${APP_NAME} install git:github.com/user/repo\n  ${APP_NAME} install git:git@github.com:user/repo\n  ${APP_NAME} install https://github.com/user/repo\n  ${APP_NAME} install ssh://git@github.com/user/repo\n  ${APP_NAME} install ./local/path\n`);\n      return;\n    case \"remove\":\n      console.log(`${chalk10.bold(\"Usage:\")}\n  ${getPackageCommandUsage(\"remove\")}\n\nRemove a package and its source from settings.\nAlias: ${APP_NAME} uninstall <source> [-l]\n\nOptions:\n  -l, --local       Remove from project settings (${CONFIG_DIR_NAME}/settings.json)\n  -a, --approve     Trust project-local files for this command\n  -na, --no-approve Ignore project-local files for this command\n\nExamples:\n  ${APP_NAME} remove npm:@foo/bar\n  ${APP_NAME} uninstall npm:@foo/bar\n`);\n      return;\n    case \"update\":\n      console.log(`${chalk10.bold(\"Usage:\")}\n  ${getPackageCommandUsage(\"update\")}\n\nUpdate pi, installed packages, or model catalogs.\n\nOptions:\n  --self                  Update pi only (default when no target is given)\n  --extensions            Update installed packages only\n  --models                Refresh model catalogs only\n  --all                   Update pi and installed packages\n  --extension <source>    Update one package only\n  -a, --approve           Trust project-local files for this command\n  -na, --no-approve       Ignore project-local files for this command\n  --force                 Reinstall pi even if the current version is latest\n\nShort forms:\n  ${APP_NAME} update                Update pi only\n  ${APP_NAME} update --all          Update pi and all extensions\n  ${APP_NAME} update --models       Refresh model catalogs only\n  ${APP_NAME} update <source>       Update one package\n  ${APP_NAME} update pi             Update pi only (self works as alias to pi)\n`);\n      return;\n    case \"list\":\n      console.log(`${chalk10.bold(\"Usage:\")}\n  ${getPackageCommandUsage(\"list\")}\n\nList installed packages from user and project settings.\n\nOptions:\n  -a, --approve      Trust project-local files for this command\n  -na, --no-approve  Ignore project-local files for this command\n`);\n      return;\n  }\n}\nfunction parsePackageCommand(args) {\n  const [rawCommand, ...rest] = args;\n  let command;\n  if (rawCommand === \"uninstall\") {\n    command = \"remove\";\n  } else if (rawCommand === \"install\" || rawCommand === \"remove\" || rawCommand === \"update\" || rawCommand === \"list\") {\n    command = rawCommand;\n  }\n  if (!command) {\n    return void 0;\n  }\n  let local = false;\n  let force = false;\n  let projectTrustOverride;\n  let help = false;\n  let invalidOption;\n  let invalidArgument;\n  let missingOptionValue;\n  let conflictingOptions;\n  let source;\n  let selfFlag = false;\n  let extensionsFlag = false;\n  let modelsFlag = false;\n  let allFlag = false;\n  let extensionFlagSource;\n  for (let index = 0; index < rest.length; index++) {\n    const arg = rest[index];\n    if (arg === \"-h\" || arg === \"--help\") {\n      help = true;\n      continue;\n    }\n    if (arg === \"-l\" || arg === \"--local\") {\n      if (command === \"install\" || command === \"remove\") {\n        local = true;\n      } else {\n        invalidOption = invalidOption ?? arg;\n      }\n      continue;\n    }\n    if (arg === \"--self\") {\n      if (command === \"update\") {\n        selfFlag = true;\n      } else {\n        invalidOption = invalidOption ?? arg;\n      }\n      continue;\n    }\n    if (arg === \"--extensions\") {\n      if (command === \"update\") {\n        extensionsFlag = true;\n      } else {\n        invalidOption = invalidOption ?? arg;\n      }\n      continue;\n    }\n    if (arg === \"--models\") {\n      if (command === \"update\") {\n        modelsFlag = true;\n      } else {\n        invalidOption = invalidOption ?? arg;\n      }\n      continue;\n    }\n    if (arg === \"--all\") {\n      if (command === \"update\") {\n        allFlag = true;\n      } else {\n        invalidOption = invalidOption ?? arg;\n      }\n      continue;\n    }\n    if (arg === \"--approve\" || arg === \"-a\") {\n      projectTrustOverride = true;\n      continue;\n    }\n    if (arg === \"--no-approve\" || arg === \"-na\") {\n      projectTrustOverride = false;\n      continue;\n    }\n    if (arg === \"--force\") {\n      if (command === \"update\") {\n        force = true;\n      } else {\n        invalidOption = invalidOption ?? arg;\n      }\n      continue;\n    }\n    if (arg === \"--extension\") {\n      if (command !== \"update\") {\n        invalidOption = invalidOption ?? arg;\n        continue;\n      }\n      const value = rest[index + 1];\n      if (!value || value.startsWith(\"-\")) {\n        missingOptionValue = missingOptionValue ?? arg;\n      } else if (extensionFlagSource) {\n        conflictingOptions = conflictingOptions ?? \"--extension can only be provided once\";\n        index++;\n      } else {\n        extensionFlagSource = value;\n        index++;\n      }\n      continue;\n    }\n    if (arg.startsWith(\"-\")) {\n      invalidOption = invalidOption ?? arg;\n      continue;\n    }\n    if (!source) {\n      source = arg;\n    } else {\n      invalidArgument = invalidArgument ?? arg;\n    }\n  }\n  let updateTarget;\n  let showExtensionsSkippedNote = false;\n  if (command === \"update\") {\n    if (allFlag && (selfFlag || extensionsFlag || modelsFlag || extensionFlagSource)) {\n      conflictingOptions = conflictingOptions ?? \"--all cannot be combined with --self, --extensions, --models, or --extension\";\n    }\n    if (allFlag && source) {\n      conflictingOptions = conflictingOptions ?? \"--all cannot be combined with a positional source\";\n    }\n    if (modelsFlag) {\n      if (selfFlag || extensionsFlag || allFlag || extensionFlagSource) {\n        conflictingOptions = conflictingOptions ?? \"--models cannot be combined with --self, --extensions, --all, or --extension\";\n      }\n      if (source) {\n        conflictingOptions = conflictingOptions ?? \"--models cannot be combined with a positional source\";\n      }\n      updateTarget = { type: \"models\" };\n    } else if (extensionFlagSource) {\n      if (selfFlag || extensionsFlag || allFlag) {\n        conflictingOptions = conflictingOptions ?? \"--extension cannot be combined with --self, --extensions, or --all\";\n      }\n      if (source) {\n        conflictingOptions = conflictingOptions ?? \"--extension cannot be combined with a positional source\";\n      }\n      updateTarget = { type: \"extensions\", source: extensionFlagSource };\n    } else if (source) {\n      const sourceIsSelf = source === \"self\" || source === \"pi\";\n      if (sourceIsSelf) {\n        updateTarget = extensionsFlag ? { type: \"all\" } : { type: \"self\" };\n      } else {\n        if (extensionsFlag || selfFlag || allFlag) {\n          conflictingOptions = conflictingOptions ?? \"positional update targets cannot be combined with --self, --extensions, or --all\";\n        }\n        updateTarget = { type: \"extensions\", source };\n      }\n    } else if (allFlag) {\n      updateTarget = { type: \"all\" };\n    } else if (selfFlag && extensionsFlag) {\n      updateTarget = { type: \"all\" };\n    } else if (selfFlag) {\n      updateTarget = { type: \"self\" };\n    } else if (extensionsFlag) {\n      updateTarget = { type: \"extensions\" };\n    } else {\n      updateTarget = { type: \"self\" };\n      showExtensionsSkippedNote = true;\n    }\n  }\n  return {\n    command,\n    source,\n    updateTarget,\n    showExtensionsSkippedNote,\n    local,\n    force,\n    projectTrustOverride,\n    help,\n    invalidOption,\n    invalidArgument,\n    missingOptionValue,\n    conflictingOptions\n  };\n}\nfunction updateTargetIncludesSelf(target) {\n  return target.type === \"all\" || target.type === \"self\";\n}\nfunction updateTargetIncludesExtensions(target) {\n  return target.type === \"all\" || target.type === \"extensions\";\n}\nasync function refreshModelCatalogs2(agentDir) {\n  const controller = new AbortController();\n  const timeout = setTimeout(() => controller.abort(), 15e3);\n  try {\n    const modelRuntime = await ModelRuntime.create({\n      authPath: join39(agentDir, \"auth.json\"),\n      modelsPath: join39(agentDir, \"models.json\"),\n      allowModelNetwork: false,\n      signal: controller.signal\n    });\n    const result = await modelRuntime.refresh({\n      allowNetwork: true,\n      force: true,\n      signal: controller.signal\n    });\n    if (result.aborted) {\n      throw new Error(\"Model catalog refresh timed out.\");\n    }\n    if (result.errors.size > 0) {\n      const details = Array.from(result.errors, ([provider, error]) => `${provider}: ${error.message}`).join(\"; \");\n      throw new Error(`Could not refresh model catalogs: ${details}`);\n    }\n  } finally {\n    clearTimeout(timeout);\n  }\n  console.log(chalk10.green(\"Model catalogs refreshed\"));\n}\nfunction printSelfUpdateUnavailable(npmCommand, updatePackageTarget = PACKAGE_NAME) {\n  console.error(`error: ${APP_NAME} cannot self-update this installation.`);\n  console.error(getSelfUpdateUnavailableInstruction(PACKAGE_NAME, npmCommand, updatePackageTarget));\n  const entrypoint = process.argv[1];\n  if (entrypoint) {\n    console.error(\"\");\n    console.error(`Location of ${APP_NAME} executable: ${entrypoint}`);\n  }\n}\nfunction printSelfUpdateFallback(command) {\n  console.error(chalk10.dim(`If this keeps failing, run this command yourself: ${command.display}`));\n}\nfunction printPnpmSelfUpdateMetadataHint() {\n  console.error(chalk10.yellow(\"If pnpm reports missing package versions, its cached registry metadata may be stale.\"));\n  console.error(chalk10.yellow(`Run \\`pnpm store prune\\` and retry \\`${APP_NAME} update --self\\`.`));\n}\nfunction printSelfUpdateNote(note) {\n  const trimmedNote = note.trim();\n  if (!trimmedNote) {\n    return;\n  }\n  console.log();\n  console.log(chalk10.bold(chalk10.yellow(\"Update note\")));\n  try {\n    const width = Math.max(20, process.stdout.columns ?? 80);\n    const renderedLines = new Markdown(trimmedNote, 0, 0, SELF_UPDATE_NOTE_MARKDOWN_THEME).render(width).map((line) => line.trimEnd());\n    console.log(renderedLines.join(\"\\n\"));\n  } catch {\n    console.log(trimmedNote);\n  }\n  console.log();\n}\nasync function getSelfUpdatePlan(force) {\n  let latestRelease;\n  try {\n    latestRelease = await getLatestPiRelease(VERSION, { retry: true });\n  } catch (error) {\n    throw new Error(`Could not determine latest ${APP_NAME} version: ${formatVersionCheckError(error)}`, {\n      cause: error\n    });\n  }\n  if (!latestRelease) {\n    throw new Error(`Could not determine latest ${APP_NAME} version.`);\n  }\n  const packageName = latestRelease.packageName ?? PACKAGE_NAME;\n  const installSpec = `${packageName}@${latestRelease.version}`;\n  if (force || packageName !== PACKAGE_NAME || isNewerPackageVersion(latestRelease.version, VERSION)) {\n    return {\n      packageName,\n      installSpec,\n      version: latestRelease.version,\n      ...latestRelease.note ? { note: latestRelease.note } : {},\n      shouldRun: true\n    };\n  }\n  console.log(chalk10.green(`${APP_NAME} is already up to date (v${VERSION})`));\n  return { packageName, installSpec, version: latestRelease.version, shouldRun: false };\n}\nasync function runSelfUpdate(command) {\n  console.log(chalk10.dim(`Updating ${APP_NAME} with ${command.display}...`));\n  for (const step of command.steps ?? [command]) {\n    await new Promise((resolve15, reject) => {\n      const child = spawnProcess(step.command, step.args, {\n        stdio: \"inherit\"\n      });\n      child.on(\"error\", (error) => {\n        reject(error);\n      });\n      child.on(\"close\", (code, signal) => {\n        if (code === 0) {\n          resolve15();\n        } else if (signal) {\n          reject(new Error(`${step.display} terminated by signal ${signal}`));\n        } else {\n          reject(new Error(`${step.display} exited with code ${code ?? \"unknown\"}`));\n        }\n      });\n    });\n  }\n}\nfunction prepareWindowsNpmSelfUpdate() {\n  if (process.platform !== \"win32\") {\n    return;\n  }\n  const packageDir = getPackageDir();\n  cleanupWindowsSelfUpdateQuarantine(packageDir);\n  quarantineWindowsNativeDependencies(packageDir);\n}\nfunction getCommandAppMode() {\n  return process.stdin.isTTY && process.stdout.isTTY ? \"interactive\" : \"print\";\n}\nfunction reportProjectTrustWarnings(warnings) {\n  for (const warning of warnings) {\n    console.error(chalk10.yellow(`Warning: ${warning}`));\n  }\n}\nasync function createCommandSettingsManager(options) {\n  const settingsManager = SettingsManager.create(options.cwd, options.agentDir, { projectTrusted: false });\n  const projectTrustWarnings = [];\n  const trustStore = new ProjectTrustStore(options.agentDir);\n  if (options.useSavedProjectTrustOnly) {\n    const savedProjectTrusted = trustStore.get(options.cwd) === true;\n    settingsManager.setProjectTrusted(options.projectTrustOverride ?? savedProjectTrusted);\n    return { settingsManager, projectTrustWarnings };\n  }\n  const appMode = getCommandAppMode();\n  const extensionsResult = options.projectTrustOverride === void 0 && hasTrustRequiringProjectResources(options.cwd) ? await new DefaultResourceLoader({\n    cwd: options.cwd,\n    agentDir: options.agentDir,\n    settingsManager,\n    extensionFactories: options.extensionFactories\n  }).loadProjectTrustExtensions() : void 0;\n  for (const error of extensionsResult?.errors ?? []) {\n    projectTrustWarnings.push(`Failed to load extension \"${error.path}\": ${error.error}`);\n  }\n  const projectTrusted = await resolveProjectTrusted({\n    cwd: options.cwd,\n    trustStore,\n    trustOverride: options.projectTrustOverride,\n    defaultProjectTrust: settingsManager.getDefaultProjectTrust(),\n    extensionsResult,\n    projectTrustContext: createProjectTrustContext({\n      cwd: options.cwd,\n      mode: appMode,\n      settingsManager,\n      hasUI: appMode === \"interactive\"\n    }),\n    onExtensionError: (message) => projectTrustWarnings.push(message)\n  });\n  settingsManager.setProjectTrusted(projectTrusted);\n  return { settingsManager, projectTrustWarnings };\n}\nasync function handleConfigCommand(args, runtimeOptions = {}) {\n  const [command, ...rest] = args;\n  if (command !== \"config\") {\n    return false;\n  }\n  if (rest.includes(\"-h\") || rest.includes(\"--help\")) {\n    printConfigCommandHelp();\n    return true;\n  }\n  let local = false;\n  let projectTrustOverride;\n  for (const arg of rest) {\n    if (arg === \"-l\" || arg === \"--local\") {\n      local = true;\n    } else if (arg === \"-a\" || arg === \"--approve\") {\n      projectTrustOverride = true;\n    } else if (arg === \"-na\" || arg === \"--no-approve\") {\n      projectTrustOverride = false;\n    } else if (arg.startsWith(\"-\")) {\n      console.error(chalk10.red(`Unknown option ${arg} for \"config\".`));\n      console.error(chalk10.dim(`Use \"${APP_NAME} --help\" or \"${CONFIG_COMMAND_USAGE}\".`));\n      process.exitCode = 1;\n      return true;\n    } else {\n      console.error(chalk10.red(`Unexpected argument ${arg}.`));\n      console.error(chalk10.dim(`Usage: ${CONFIG_COMMAND_USAGE}`));\n      process.exitCode = 1;\n      return true;\n    }\n  }\n  const cwd = process.cwd();\n  const agentDir = getAgentDir();\n  const { settingsManager, projectTrustWarnings } = await createCommandSettingsManager({\n    cwd,\n    agentDir,\n    projectTrustOverride,\n    extensionFactories: runtimeOptions.extensionFactories\n  });\n  reportProjectTrustWarnings(projectTrustWarnings);\n  if (local && !settingsManager.isProjectTrusted()) {\n    console.error(chalk10.red(\"Project is not trusted. Use --approve to modify local resource config.\"));\n    process.exitCode = 1;\n    return true;\n  }\n  reportSettingsErrors(settingsManager, \"config command\");\n  const globalSettingsManager = SettingsManager.create(cwd, agentDir, { projectTrusted: false });\n  const globalResolvedPaths = await new DefaultPackageManager({\n    cwd,\n    agentDir,\n    settingsManager: globalSettingsManager\n  }).resolve();\n  const projectResolvedPaths = settingsManager.isProjectTrusted() ? await new DefaultPackageManager({ cwd, agentDir, settingsManager }).resolve() : globalResolvedPaths;\n  await selectConfig({\n    resolvedPaths: { global: globalResolvedPaths, project: projectResolvedPaths },\n    settingsManager,\n    cwd,\n    agentDir,\n    writeScope: local ? \"project\" : \"global\",\n    projectModeAvailable: settingsManager.isProjectTrusted()\n  });\n  process.exit(0);\n}\nasync function handlePackageCommand(args, runtimeOptions = {}) {\n  const options = parsePackageCommand(args);\n  if (!options) {\n    return false;\n  }\n  if (options.help) {\n    printPackageCommandHelp(options.command);\n    return true;\n  }\n  if (options.invalidOption) {\n    console.error(chalk10.red(`Unknown option ${options.invalidOption} for \"${options.command}\".`));\n    console.error(chalk10.dim(`Use \"${APP_NAME} --help\" or \"${getPackageCommandUsage(options.command)}\".`));\n    process.exitCode = 1;\n    return true;\n  }\n  if (options.missingOptionValue) {\n    console.error(chalk10.red(`Missing value for ${options.missingOptionValue}.`));\n    console.error(chalk10.dim(`Usage: ${getPackageCommandUsage(options.command)}`));\n    process.exitCode = 1;\n    return true;\n  }\n  if (options.invalidArgument) {\n    console.error(chalk10.red(`Unexpected argument ${options.invalidArgument}.`));\n    console.error(chalk10.dim(`Usage: ${getPackageCommandUsage(options.command)}`));\n    process.exitCode = 1;\n    return true;\n  }\n  if (options.conflictingOptions) {\n    console.error(chalk10.red(options.conflictingOptions));\n    console.error(chalk10.dim(`Usage: ${getPackageCommandUsage(options.command)}`));\n    process.exitCode = 1;\n    return true;\n  }\n  const source = options.source;\n  if ((options.command === \"install\" || options.command === \"remove\") && !source) {\n    console.error(chalk10.red(`Missing ${options.command} source.`));\n    console.error(chalk10.dim(`Usage: ${getPackageCommandUsage(options.command)}`));\n    process.exitCode = 1;\n    return true;\n  }\n  if (options.command === \"update\" && options.updateTarget?.type === \"models\") {\n    try {\n      await refreshModelCatalogs2(getAgentDir());\n    } catch (error) {\n      const message = error instanceof Error ? error.message : \"Unknown model catalog refresh error\";\n      console.error(chalk10.red(`Error: ${message}`));\n      process.exitCode = 1;\n    }\n    return true;\n  }\n  const cwd = process.cwd();\n  const agentDir = getAgentDir();\n  const writesProjectPackageConfig = (options.command === \"install\" || options.command === \"remove\") && options.local;\n  const { settingsManager, projectTrustWarnings } = await createCommandSettingsManager({\n    cwd,\n    agentDir,\n    projectTrustOverride: options.projectTrustOverride,\n    useSavedProjectTrustOnly: options.command === \"update\",\n    extensionFactories: runtimeOptions.extensionFactories\n  });\n  reportProjectTrustWarnings(projectTrustWarnings);\n  if (!settingsManager.isProjectTrusted() && writesProjectPackageConfig) {\n    console.error(chalk10.red(\"Project is not trusted. Use --approve to modify local package config.\"));\n    process.exitCode = 1;\n    return true;\n  }\n  reportSettingsErrors(settingsManager, \"package command\");\n  const selfUpdateNpmCommand = settingsManager.getGlobalSettings().npmCommand;\n  const packageManager = new DefaultPackageManager({ cwd, agentDir, settingsManager });\n  packageManager.setProgressCallback((event) => {\n    if (event.type === \"start\") {\n      process.stdout.write(chalk10.dim(`${event.message}\n`));\n    }\n  });\n  try {\n    switch (options.command) {\n      case \"install\":\n        await packageManager.installAndPersist(source, { local: options.local });\n        console.log(chalk10.green(`Installed ${source}`));\n        return true;\n      case \"remove\": {\n        const removed = await packageManager.removeAndPersist(source, { local: options.local });\n        if (!removed) {\n          console.error(chalk10.red(`No matching package found for ${source}`));\n          process.exitCode = 1;\n          return true;\n        }\n        console.log(chalk10.green(`Removed ${source}`));\n        return true;\n      }\n      case \"list\": {\n        const configuredPackages = packageManager.listConfiguredPackages();\n        const userPackages = configuredPackages.filter((pkg2) => pkg2.scope === \"user\");\n        const projectPackages = configuredPackages.filter((pkg2) => pkg2.scope === \"project\");\n        if (configuredPackages.length === 0) {\n          console.log(chalk10.dim(\"No packages installed.\"));\n          return true;\n        }\n        const formatPackage = (pkg2) => {\n          const display = pkg2.filtered ? `${pkg2.source} (filtered)` : pkg2.source;\n          console.log(`  ${display}`);\n          if (pkg2.installedPath) {\n            console.log(chalk10.dim(`    ${pkg2.installedPath}`));\n          }\n        };\n        if (userPackages.length > 0) {\n          console.log(chalk10.bold(\"User packages:\"));\n          for (const pkg2 of userPackages) {\n            formatPackage(pkg2);\n          }\n        }\n        if (projectPackages.length > 0) {\n          if (userPackages.length > 0)\n            console.log();\n          console.log(chalk10.bold(\"Project packages:\"));\n          for (const pkg2 of projectPackages) {\n            formatPackage(pkg2);\n          }\n        }\n        return true;\n      }\n      case \"update\": {\n        const target = options.updateTarget ?? { type: \"self\" };\n        if (options.showExtensionsSkippedNote) {\n          console.log(chalk10.dim(`Extensions are skipped. Run ${APP_NAME} update --extensions to update extensions.`));\n        }\n        if (updateTargetIncludesExtensions(target)) {\n          const updateSource = target.type === \"extensions\" ? target.source : void 0;\n          await packageManager.update(updateSource);\n          if (updateSource) {\n            console.log(chalk10.green(`Updated ${updateSource}`));\n          } else {\n            console.log(chalk10.green(\"Updated packages\"));\n          }\n        }\n        if (updateTargetIncludesSelf(target)) {\n          const selfUpdatePlan = await getSelfUpdatePlan(options.force);\n          if (!selfUpdatePlan.shouldRun) {\n            return true;\n          }\n          const installMethod = detectInstallMethod();\n          if (process.platform === \"win32\" && installMethod !== \"npm\" && installMethod !== \"pnpm\") {\n            console.error(chalk10.red(`${APP_NAME} self-update on Windows is only supported for npm and pnpm installs.`));\n            console.error(chalk10.dim(`Detected install method: ${installMethod}. Update ${APP_NAME} manually.`));\n            process.exitCode = 1;\n            return true;\n          }\n          const selfUpdateTarget = {\n            packageName: selfUpdatePlan.packageName,\n            installSpec: selfUpdatePlan.installSpec\n          };\n          const selfUpdateCommand = getSelfUpdateCommand(PACKAGE_NAME, selfUpdateNpmCommand, selfUpdateTarget);\n          if (!selfUpdateCommand) {\n            printSelfUpdateUnavailable(selfUpdateNpmCommand, selfUpdateTarget);\n            process.exitCode = 1;\n            return true;\n          }\n          if (selfUpdatePlan.note) {\n            printSelfUpdateNote(selfUpdatePlan.note);\n          }\n          try {\n            if (installMethod === \"npm\") {\n              prepareWindowsNpmSelfUpdate();\n            }\n            await runSelfUpdate(selfUpdateCommand);\n          } catch (error) {\n            const message = error instanceof Error ? error.message : \"Unknown package command error\";\n            console.error(chalk10.red(`Error: ${message}`));\n            if (installMethod === \"pnpm\") {\n              printPnpmSelfUpdateMetadataHint();\n            }\n            printSelfUpdateFallback(selfUpdateCommand);\n            process.exitCode = 1;\n            return true;\n          }\n          console.log(chalk10.green(`Updated ${APP_NAME} from ${VERSION} to ${selfUpdatePlan.version}`));\n        }\n        return true;\n      }\n    }\n  } catch (error) {\n    const message = error instanceof Error ? error.message : \"Unknown package command error\";\n    console.error(chalk10.red(`Error: ${message}`));\n    process.exitCode = 1;\n    return true;\n  }\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/main.js\nvar EXTENSION_LOAD_FAILURE_HINT = `Hint: Start without extensions using \"${APP_NAME} -ne\".`;\nasync function readPipedStdin() {\n  if (process.stdin.isTTY) {\n    return void 0;\n  }\n  return new Promise((resolve15) => {\n    let data = \"\";\n    process.stdin.setEncoding(\"utf8\");\n    process.stdin.on(\"data\", (chunk) => {\n      data += chunk;\n    });\n    process.stdin.on(\"end\", () => {\n      resolve15(data.trim() || void 0);\n    });\n    process.stdin.resume();\n  });\n}\nfunction collectSettingsDiagnostics(settingsManager, context) {\n  return settingsManager.drainErrors().map(({ scope, error }) => ({\n    type: \"warning\",\n    message: `(${context}, ${scope} settings) ${error.message}`\n  }));\n}\nfunction reportDiagnostics(diagnostics) {\n  for (const diagnostic of diagnostics) {\n    const color = diagnostic.type === \"error\" ? chalk11.red : diagnostic.type === \"warning\" ? chalk11.yellow : chalk11.dim;\n    const prefix = diagnostic.type === \"error\" ? \"Error: \" : diagnostic.type === \"warning\" ? \"Warning: \" : \"\";\n    console.error(color(`${prefix}${diagnostic.message}`));\n  }\n}\nfunction isTruthyEnvFlag2(value) {\n  if (!value)\n    return false;\n  return value === \"1\" || value.toLowerCase() === \"true\" || value.toLowerCase() === \"yes\";\n}\nfunction resolveAppMode(parsed, stdinIsTTY, stdoutIsTTY) {\n  if (parsed.mode === \"rpc\") {\n    return \"rpc\";\n  }\n  if (parsed.mode === \"json\") {\n    return \"json\";\n  }\n  if (parsed.print || !stdinIsTTY || !stdoutIsTTY) {\n    return \"print\";\n  }\n  return \"interactive\";\n}\nfunction toPrintOutputMode(appMode) {\n  return appMode === \"json\" ? \"json\" : \"text\";\n}\nfunction isPlainRuntimeMetadataCommand(parsed) {\n  return !parsed.print && parsed.mode === void 0 && (parsed.help === true || parsed.listModels !== void 0);\n}\nasync function runAuthCommand(args) {\n  if (isAuthCommandHelp(args)) {\n    printAuthCommandHelp();\n    return true;\n  }\n  let command;\n  try {\n    command = parseAuthCommand(args);\n  } catch (error) {\n    const message = error instanceof AuthCommandError ? error.message : \"Failed to parse auth command\";\n    console.error(chalk11.red(`Error: ${message}`));\n    process.exitCode = 1;\n    return true;\n  }\n  if (!command)\n    return false;\n  const parsed = parseArgs(command.args);\n  if (parsed.unknownFlags.size > 0) {\n    const option = parsed.unknownFlags.keys().next().value;\n    console.error(chalk11.red(`Unknown option --${option} for \"${getAuthCommandName(command.kind)}\".`));\n    console.error(chalk11.dim(`Use \"${APP_NAME} --help\" or \"${getAuthCommandUsage(command.kind)}\".`));\n    process.exitCode = 1;\n    return true;\n  }\n  try {\n    if (parsed.diagnostics.length > 0) {\n      throw new AuthCommandError(parsed.diagnostics.map((diagnostic) => diagnostic.message).join(\"\\n\"));\n    }\n    if (command.kind !== \"check\") {\n      const signal = AbortSignal.timeout(15e3);\n      const modelRuntime = await ModelRuntime.create({ allowModelNetwork: false, signal });\n      const credential2 = await resolveCredentialForPrint(parsed, modelRuntime, command.kind, command.minExpiryMs, signal);\n      process.stdout.write(`${credential2}\n`);\n      return true;\n    }\n    const requestedAuth = validateAuthCommandArgs(parsed, command.kind);\n    let result;\n    let credential;\n    try {\n      const credentials = command.noRefresh ? new ReadOnlyAuthStorage() : AuthStorage.create();\n      const modelRuntime = await createAuthCheckModelRuntime(credentials);\n      result = await checkProviderAuth(parsed, modelRuntime, { refresh: !command.noRefresh });\n      if (command.credentials && result.status === \"ready\") {\n        credential = await getProviderCredential(result.provider, modelRuntime, credentials, {\n          refresh: !command.noRefresh\n        });\n        if (!credential) {\n          result = { status: \"not_ready\", provider: result.provider, reason: \"credential_not_available\" };\n        }\n      }\n    } catch {\n      result = {\n        status: \"invalid\",\n        provider: requestedAuth.provider ?? requestedAuth.model,\n        reason: \"invalid_state\"\n      };\n    }\n    const output = command.json ? JSON.stringify({ ...result, ...credential ? { credentials: credential } : {} }) : credential ?? result.status;\n    process.stdout.write(`${output}\n`);\n    process.exitCode = result.status === \"ready\" ? 0 : result.status === \"not_ready\" ? 1 : 2;\n  } catch (error) {\n    const message = error instanceof AuthCommandError ? error.message : \"Failed to resolve credential\";\n    console.error(chalk11.red(`Error: ${message}`));\n    process.exitCode = command.kind === \"check\" ? 2 : 1;\n  }\n  return true;\n}\nasync function prepareInitialMessage(parsed, autoResizeImages, stdinContent) {\n  if (parsed.fileArgs.length === 0) {\n    return buildInitialMessage({ parsed, stdinContent });\n  }\n  const { text, images } = await processFileArguments(parsed.fileArgs, { autoResizeImages });\n  return buildInitialMessage({\n    parsed,\n    fileText: text,\n    fileImages: images,\n    stdinContent\n  });\n}\nasync function findLocalSessionByExactId(sessionId, cwd, sessionDir) {\n  const localSessions = await SessionManager.list(cwd, sessionDir);\n  const localMatch = localSessions.find((s) => s.id === sessionId);\n  return localMatch ? { type: \"local\", path: localMatch.path } : void 0;\n}\nasync function resolveSessionPath(sessionArg, cwd, sessionDir) {\n  if (sessionArg.includes(\"/\") || sessionArg.includes(\"\\\\\") || sessionArg.endsWith(\".jsonl\")) {\n    return { type: \"path\", path: resolvePath(sessionArg, cwd) };\n  }\n  const localSessions = await SessionManager.list(cwd, sessionDir);\n  const localMatch = localSessions.find((s) => s.id === sessionArg) ?? localSessions.find((s) => s.id.startsWith(sessionArg));\n  if (localMatch) {\n    return { type: \"local\", path: localMatch.path };\n  }\n  const allSessions = await SessionManager.listAll(sessionDir);\n  const globalMatch = allSessions.find((s) => s.id === sessionArg) ?? allSessions.find((s) => s.id.startsWith(sessionArg));\n  if (globalMatch) {\n    return { type: \"global\", path: globalMatch.path, cwd: globalMatch.cwd };\n  }\n  return { type: \"not_found\", arg: sessionArg };\n}\nasync function promptConfirm(message) {\n  return new Promise((resolve15) => {\n    const rl = createInterface4({\n      input: process.stdin,\n      output: process.stdout\n    });\n    rl.question(`${message} [y/N] `, (answer) => {\n      rl.close();\n      resolve15(answer.toLowerCase() === \"y\" || answer.toLowerCase() === \"yes\");\n    });\n  });\n}\nfunction validateForkFlags(parsed) {\n  if (!parsed.fork)\n    return;\n  const conflictingFlags = [\n    parsed.session ? \"--session\" : void 0,\n    parsed.continue ? \"--continue\" : void 0,\n    parsed.resume ? \"--resume\" : void 0,\n    parsed.noSession ? \"--no-session\" : void 0\n  ].filter((flag) => flag !== void 0);\n  if (conflictingFlags.length > 0) {\n    console.error(chalk11.red(`Error: --fork cannot be combined with ${conflictingFlags.join(\", \")}`));\n    process.exit(1);\n  }\n}\nfunction validateSessionIdFlags(parsed) {\n  if (parsed.sessionId === void 0)\n    return;\n  const conflictingFlags = [\n    parsed.session ? \"--session\" : void 0,\n    parsed.continue ? \"--continue\" : void 0,\n    parsed.resume ? \"--resume\" : void 0\n  ].filter((flag) => flag !== void 0);\n  if (conflictingFlags.length > 0) {\n    console.error(chalk11.red(`Error: --session-id cannot be combined with ${conflictingFlags.join(\", \")}`));\n    process.exit(1);\n  }\n  try {\n    assertValidSessionId(parsed.sessionId);\n  } catch (error) {\n    const message = error instanceof Error ? error.message : String(error);\n    console.error(chalk11.red(`Error: ${message}`));\n    process.exit(1);\n  }\n}\nfunction openSessionOrExit(path12, sessionDir) {\n  try {\n    return SessionManager.open(path12, sessionDir);\n  } catch (error) {\n    const message = error instanceof Error ? error.message : String(error);\n    console.error(chalk11.red(`Error: ${message}`));\n    process.exit(1);\n  }\n}\nfunction forkSessionOrExit(sourcePath, cwd, sessionDir, sessionId) {\n  try {\n    return SessionManager.forkFrom(sourcePath, cwd, sessionDir, { id: sessionId });\n  } catch (error) {\n    const message = error instanceof Error ? error.message : String(error);\n    console.error(chalk11.red(`Error: ${message}`));\n    process.exit(1);\n  }\n}\nasync function createSessionManager(parsed, cwd, sessionDir, settingsManager) {\n  if (parsed.noSession || parsed.help || parsed.listModels !== void 0) {\n    return SessionManager.inMemory(cwd, parsed.sessionId !== void 0 ? { id: parsed.sessionId } : void 0);\n  }\n  if (parsed.fork) {\n    if (parsed.sessionId) {\n      const existingTarget = await findLocalSessionByExactId(parsed.sessionId, cwd, sessionDir);\n      if (existingTarget) {\n        console.error(chalk11.red(`Session already exists with id '${parsed.sessionId}'`));\n        process.exit(1);\n      }\n    }\n    const resolved = await resolveSessionPath(parsed.fork, cwd, sessionDir);\n    switch (resolved.type) {\n      case \"path\":\n      case \"local\":\n      case \"global\":\n        return forkSessionOrExit(resolved.path, cwd, sessionDir, parsed.sessionId);\n      case \"not_found\":\n        console.error(chalk11.red(`No session found matching '${resolved.arg}'`));\n        process.exit(1);\n    }\n  }\n  if (parsed.session) {\n    const resolved = await resolveSessionPath(parsed.session, cwd, sessionDir);\n    switch (resolved.type) {\n      case \"path\":\n      case \"local\":\n        return openSessionOrExit(resolved.path, sessionDir);\n      case \"global\": {\n        console.log(chalk11.yellow(`Session found in different project: ${resolved.cwd}`));\n        const shouldFork = await promptConfirm(\"Fork this session into current directory?\");\n        if (!shouldFork) {\n          console.log(chalk11.dim(\"Aborted.\"));\n          process.exit(0);\n        }\n        return forkSessionOrExit(resolved.path, cwd, sessionDir);\n      }\n      case \"not_found\":\n        console.error(chalk11.red(`No session found matching '${resolved.arg}'`));\n        process.exit(1);\n    }\n  }\n  if (parsed.resume) {\n    try {\n      const selectedPath = await selectSession((onProgress) => SessionManager.list(cwd, sessionDir, onProgress), (onProgress) => SessionManager.listAll(sessionDir, onProgress), settingsManager);\n      if (!selectedPath) {\n        console.log(chalk11.dim(\"No session selected\"));\n        process.exit(0);\n      }\n      return SessionManager.open(selectedPath, sessionDir);\n    } finally {\n      stopThemeWatcher();\n    }\n  }\n  if (parsed.continue) {\n    return SessionManager.continueRecent(cwd, sessionDir);\n  }\n  if (parsed.sessionId) {\n    const existingSession = await findLocalSessionByExactId(parsed.sessionId, cwd, sessionDir);\n    if (existingSession) {\n      return SessionManager.open(existingSession.path, sessionDir);\n    }\n    console.error(chalk11.yellow(`Warning: No project session found with id '${parsed.sessionId}'; creating a new session with that id.`));\n  }\n  return SessionManager.create(cwd, sessionDir, { id: parsed.sessionId });\n}\nfunction buildSessionOptions(parsed, scopedModels, hasExistingSession, modelRuntime, settingsManager) {\n  const options = {};\n  const diagnostics = [];\n  let cliThinkingFromModel = false;\n  if (parsed.model) {\n    const resolved = resolveCliModel({\n      cliProvider: parsed.provider,\n      cliModel: parsed.model,\n      cliThinking: parsed.thinking,\n      modelRuntime\n    });\n    if (resolved.warning) {\n      diagnostics.push({ type: \"warning\", message: resolved.warning });\n    }\n    if (resolved.error) {\n      diagnostics.push({ type: \"error\", message: resolved.error });\n    }\n    if (resolved.model) {\n      options.model = resolved.model;\n      if (!parsed.thinking && resolved.thinkingLevel) {\n        options.thinkingLevel = resolved.thinkingLevel;\n        cliThinkingFromModel = true;\n      }\n    }\n  }\n  if (!options.model && scopedModels.length > 0 && !hasExistingSession) {\n    const savedProvider = settingsManager.getDefaultProvider();\n    const savedModelId = settingsManager.getDefaultModel();\n    const savedModel = savedProvider && savedModelId ? modelRuntime.getModel(savedProvider, savedModelId) : void 0;\n    const savedInScope = savedModel ? scopedModels.find((sm) => modelsAreEqual(sm.model, savedModel)) : void 0;\n    if (savedInScope) {\n      options.model = savedInScope.model;\n      if (!parsed.thinking && savedInScope.thinkingLevel) {\n        options.thinkingLevel = savedInScope.thinkingLevel;\n      }\n    } else {\n      options.model = scopedModels[0].model;\n      if (!parsed.thinking && scopedModels[0].thinkingLevel) {\n        options.thinkingLevel = scopedModels[0].thinkingLevel;\n      }\n    }\n  }\n  if (parsed.thinking) {\n    options.thinkingLevel = parsed.thinking;\n  }\n  if (scopedModels.length > 0) {\n    options.scopedModels = scopedModels.map((sm) => ({\n      model: sm.model,\n      thinkingLevel: sm.thinkingLevel\n    }));\n  }\n  if (parsed.noTools) {\n    options.noTools = \"all\";\n  } else if (parsed.noBuiltinTools) {\n    options.noTools = \"builtin\";\n  }\n  if (parsed.tools) {\n    options.tools = [...parsed.tools];\n  }\n  if (parsed.excludeTools) {\n    options.excludeTools = [...parsed.excludeTools];\n  }\n  return { options, cliThinkingFromModel, diagnostics };\n}\nfunction resolveCliPaths(cwd, paths) {\n  return paths?.map((value) => isLocalPath(value) ? resolvePath(value, cwd) : value);\n}\nasync function promptForMissingSessionCwd(issue, settingsManager) {\n  return showStartupSelector(settingsManager, formatMissingSessionCwdPrompt(issue), [\n    { label: \"Continue\", value: issue.fallbackCwd },\n    { label: \"Cancel\", value: void 0 }\n  ]);\n}\nasync function main(args, options) {\n  resetTimings();\n  const extensionFactories = [...builtInExtensions, ...options?.extensionFactories ?? []];\n  const offlineMode = args.includes(\"--offline\") || isTruthyEnvFlag2(process.env.PI_OFFLINE);\n  if (offlineMode) {\n    process.env.PI_OFFLINE = \"1\";\n    process.env.PI_SKIP_VERSION_CHECK = \"1\";\n  }\n  if (await runAuthCommand(args)) {\n    return;\n  }\n  if (process.platform === \"win32\") {\n    cleanupWindowsSelfUpdateQuarantine(getPackageDir());\n  }\n  const cwd = process.cwd();\n  const agentDir = getAgentDir();\n  const bootstrapSettingsManager = SettingsManager.create(cwd, agentDir, { projectTrusted: false });\n  applyHttpProxySettings(bootstrapSettingsManager.getGlobalSettings().httpProxy);\n  configureHttpDispatcher();\n  if (await handlePackageCommand(args, { extensionFactories })) {\n    const exitCode = process.exitCode ?? 0;\n    if (process.platform === \"win32\" && exitCode === 0 && args[0] === \"update\") {\n      return;\n    }\n    process.exit(exitCode);\n    return;\n  }\n  if (await handleConfigCommand(args, { extensionFactories })) {\n    return;\n  }\n  const parsed = parseArgs(args);\n  if (parsed.diagnostics.length > 0) {\n    for (const d of parsed.diagnostics) {\n      const color = d.type === \"error\" ? chalk11.red : chalk11.yellow;\n      console.error(color(`${d.type === \"error\" ? \"Error\" : \"Warning\"}: ${d.message}`));\n    }\n    if (parsed.diagnostics.some((d) => d.type === \"error\")) {\n      process.exit(1);\n    }\n  }\n  time(\"parseArgs\");\n  if (parsed.version) {\n    console.log(VERSION);\n    process.exit(0);\n  }\n  if (parsed.export) {\n    let result;\n    try {\n      const outputPath = parsed.messages.length > 0 ? parsed.messages[0] : void 0;\n      result = await exportFromFile(parsed.export, outputPath);\n    } catch (error) {\n      const message = error instanceof Error ? error.message : \"Failed to export session\";\n      console.error(chalk11.red(`Error: ${message}`));\n      process.exit(1);\n    }\n    console.log(`Exported to: ${result}`);\n    process.exit(0);\n  }\n  let appMode = resolveAppMode(parsed, process.stdin.isTTY, process.stdout.isTTY);\n  const shouldTakeOverStdout = appMode !== \"interactive\" && !isPlainRuntimeMetadataCommand(parsed);\n  if (shouldTakeOverStdout) {\n    takeOverStdout();\n  }\n  if (parsed.mode === \"rpc\" && parsed.fileArgs.length > 0) {\n    console.error(chalk11.red(\"Error: @file arguments are not supported in RPC mode\"));\n    process.exit(1);\n  }\n  validateForkFlags(parsed);\n  validateSessionIdFlags(parsed);\n  const { migratedAuthProviders: migratedProviders, deprecationWarnings } = runMigrations(cwd);\n  time(\"runMigrations\");\n  const startupSettingsManager = SettingsManager.create(cwd, agentDir);\n  reportDiagnostics(collectSettingsDiagnostics(startupSettingsManager, \"startup session lookup\"));\n  if (appMode === \"interactive\" && !parsed.help && parsed.listModels === void 0 && shouldRunFirstTimeSetup()) {\n    await showFirstTimeSetup(startupSettingsManager);\n    time(\"firstTimeSetup\");\n  }\n  if (appMode === \"interactive\" && parsed.useTheme !== void 0) {\n    startupSettingsManager.applyOverrides({ theme: parsed.useTheme });\n  }\n  const envSessionDir = process.env[ENV_SESSION_DIR];\n  const sessionDir = (parsed.sessionDir ? normalizePath(parsed.sessionDir) : void 0) ?? (envSessionDir ? expandTildePath(envSessionDir) : void 0) ?? startupSettingsManager.getSessionDir();\n  let sessionManager = await createSessionManager(parsed, cwd, sessionDir, startupSettingsManager);\n  const missingSessionCwdIssue = getMissingSessionCwdIssue(sessionManager, cwd);\n  if (missingSessionCwdIssue) {\n    if (appMode === \"interactive\") {\n      const selectedCwd = await promptForMissingSessionCwd(missingSessionCwdIssue, startupSettingsManager);\n      if (!selectedCwd) {\n        process.exit(0);\n      }\n      sessionManager = SessionManager.open(missingSessionCwdIssue.sessionFile, sessionDir, selectedCwd);\n    } else {\n      console.error(chalk11.red(new MissingSessionCwdError(missingSessionCwdIssue).message));\n      process.exit(1);\n    }\n  }\n  if (parsed.name !== void 0) {\n    const name = parsed.name.trim();\n    if (!name) {\n      console.error(chalk11.red(\"Error: --name requires a non-empty value\"));\n      process.exit(1);\n    }\n    sessionManager.appendSessionInfo(name);\n  }\n  time(\"createSessionManager\");\n  const trustStore = new ProjectTrustStore(agentDir);\n  const sessionCwd = sessionManager.getCwd();\n  const autoTrustOnReloadCwd = parsed.projectTrustOverride === void 0 && !hasTrustRequiringProjectResources(sessionCwd) ? sessionCwd : void 0;\n  const trustPromptMode = parsed.help || parsed.listModels !== void 0 ? \"print\" : appMode;\n  const projectTrustByCwd = /* @__PURE__ */ new Map();\n  const resolvedExtensionPaths = resolveCliPaths(cwd, parsed.extensions);\n  const resolvedSkillPaths = resolveCliPaths(cwd, parsed.skills);\n  const resolvedPromptTemplatePaths = resolveCliPaths(cwd, parsed.promptTemplates);\n  const resolvedThemePaths = resolveCliPaths(cwd, parsed.themes);\n  const createRuntime = async ({ cwd: cwd2, agentDir: agentDir2, sessionManager: sessionManager2, sessionStartEvent, projectTrustContext }) => {\n    const isInitialRuntime = sessionStartEvent === void 0;\n    const projectTrustDiagnostics = [];\n    const cachedProjectTrust = projectTrustByCwd.get(cwd2);\n    const hasTrustRequiringResources = hasTrustRequiringProjectResources(cwd2);\n    const shouldResolveProjectTrust = parsed.projectTrustOverride === void 0 && cachedProjectTrust === void 0 && hasTrustRequiringResources;\n    const projectTrusted = shouldResolveProjectTrust ? false : cachedProjectTrust ?? parsed.projectTrustOverride ?? (!hasTrustRequiringResources || trustStore.get(cwd2) === true);\n    const runtimeSettingsManager = SettingsManager.create(cwd2, agentDir2, { projectTrusted });\n    const services2 = await createAgentSessionServices({\n      cwd: cwd2,\n      agentDir: agentDir2,\n      settingsManager: runtimeSettingsManager,\n      modelRuntimeSignal: AbortSignal.timeout(15e3),\n      extensionFlagValues: parsed.unknownFlags,\n      resourceLoaderReloadOptions: shouldResolveProjectTrust ? {\n        resolveProjectTrust: async ({ extensionsResult }) => {\n          const trusted = await resolveProjectTrusted({\n            cwd: cwd2,\n            trustStore,\n            trustOverride: parsed.projectTrustOverride,\n            defaultProjectTrust: startupSettingsManager.getDefaultProjectTrust(),\n            extensionsResult,\n            projectTrustContext: projectTrustContext ?? createProjectTrustContext({\n              cwd: cwd2,\n              mode: isInitialRuntime ? trustPromptMode : appMode,\n              settingsManager: startupSettingsManager,\n              hasUI: isInitialRuntime && trustPromptMode === \"interactive\"\n            }),\n            onExtensionError: (message) => projectTrustDiagnostics.push({ type: \"warning\", message })\n          });\n          projectTrustByCwd.set(cwd2, trusted);\n          return trusted;\n        }\n      } : void 0,\n      resourceLoaderOptions: {\n        additionalExtensionPaths: resolvedExtensionPaths,\n        additionalSkillPaths: resolvedSkillPaths,\n        additionalPromptTemplatePaths: resolvedPromptTemplatePaths,\n        additionalThemePaths: resolvedThemePaths,\n        noExtensions: parsed.noExtensions,\n        noSkills: parsed.noSkills,\n        noPromptTemplates: parsed.noPromptTemplates,\n        noThemes: parsed.noThemes,\n        noContextFiles: parsed.noContextFiles,\n        systemPrompt: parsed.systemPrompt,\n        appendSystemPrompt: parsed.appendSystemPrompt,\n        extensionFactories\n      }\n    });\n    const { settingsManager: settingsManager2, modelRuntime: modelRuntime2, resourceLoader: resourceLoader2 } = services2;\n    const diagnostics = [\n      ...projectTrustDiagnostics,\n      ...services2.diagnostics,\n      ...collectSettingsDiagnostics(settingsManager2, \"runtime creation\"),\n      ...resourceLoader2.getExtensions().errors.map(({ path: path12, error }) => ({\n        type: \"error\",\n        message: `Failed to load extension \"${path12}\": ${error}`\n      }))\n    ];\n    const modelPatterns = parsed.models ?? settingsManager2.getEnabledModels();\n    const scopedModels = modelPatterns && modelPatterns.length > 0 ? await resolveModelScope(modelPatterns, modelRuntime2, { signal: AbortSignal.timeout(15e3) }) : [];\n    const { options: sessionOptions, cliThinkingFromModel, diagnostics: sessionOptionDiagnostics } = buildSessionOptions(parsed, scopedModels, sessionManager2.buildSessionContext().messages.length > 0, modelRuntime2, settingsManager2);\n    diagnostics.push(...sessionOptionDiagnostics);\n    if (parsed.apiKey) {\n      if (!sessionOptions.model) {\n        diagnostics.push({\n          type: \"error\",\n          message: \"--api-key requires a model to be specified via --model, --provider/--model, or --models\"\n        });\n      } else {\n        await modelRuntime2.setRuntimeApiKey(sessionOptions.model.provider, parsed.apiKey);\n      }\n    }\n    const created = await createAgentSessionFromServices({\n      services: services2,\n      sessionManager: sessionManager2,\n      sessionStartEvent,\n      model: sessionOptions.model,\n      thinkingLevel: sessionOptions.thinkingLevel,\n      scopedModels: sessionOptions.scopedModels,\n      tools: sessionOptions.tools,\n      excludeTools: sessionOptions.excludeTools,\n      noTools: sessionOptions.noTools,\n      customTools: sessionOptions.customTools\n    });\n    const cliThinkingOverride = parsed.thinking !== void 0 || cliThinkingFromModel;\n    if (created.session.model && cliThinkingOverride) {\n      created.session.setThinkingLevel(created.session.thinkingLevel);\n    }\n    return {\n      ...created,\n      services: services2,\n      diagnostics\n    };\n  };\n  time(\"createRuntime\");\n  const runtime = await createAgentSessionRuntime(createRuntime, {\n    cwd: sessionManager.getCwd(),\n    agentDir,\n    sessionManager\n  });\n  time(\"createAgentSessionRuntime\");\n  const { services, session, modelFallbackMessage } = runtime;\n  const { settingsManager, modelRuntime, resourceLoader } = services;\n  applyHttpProxySettings(settingsManager.getGlobalSettings().httpProxy);\n  configureHttpDispatcher(settingsManager.getHttpIdleTimeoutMs());\n  if (parsed.help) {\n    const extensionFlags = resourceLoader.getExtensions().extensions.flatMap((extension) => Array.from(extension.flags.values()));\n    printHelp(extensionFlags);\n    process.exit(0);\n  }\n  if (parsed.listModels !== void 0) {\n    const searchPattern = typeof parsed.listModels === \"string\" ? parsed.listModels : void 0;\n    await listModels(modelRuntime, searchPattern, AbortSignal.timeout(15e3));\n    process.exit(0);\n  }\n  let stdinContent;\n  if (appMode !== \"rpc\") {\n    stdinContent = await readPipedStdin();\n    if (stdinContent !== void 0 && appMode === \"interactive\") {\n      appMode = \"print\";\n    }\n  }\n  time(\"readPipedStdin\");\n  const { initialMessage, initialImages } = await prepareInitialMessage(parsed, settingsManager.getImageAutoResize(), stdinContent);\n  time(\"prepareInitialMessage\");\n  initTheme(settingsManager.getTheme(), appMode === \"interactive\");\n  time(\"initTheme\");\n  if (appMode === \"interactive\" && deprecationWarnings.length > 0) {\n    await showDeprecationWarnings(deprecationWarnings);\n  }\n  time(\"resolveModelScope\");\n  reportDiagnostics(runtime.diagnostics);\n  if (runtime.diagnostics.some((diagnostic) => diagnostic.type === \"error\")) {\n    if (runtime.diagnostics.some((diagnostic) => diagnostic.message.includes(\"Failed to load extension\"))) {\n      console.error(chalk11.yellow(EXTENSION_LOAD_FAILURE_HINT));\n    }\n    process.exit(1);\n  }\n  time(\"createAgentSession\");\n  if (appMode !== \"interactive\" && !session.model) {\n    console.error(chalk11.red(formatNoModelsAvailableMessage()));\n    process.exit(1);\n  }\n  const startupBenchmark = isTruthyEnvFlag2(process.env.PI_STARTUP_BENCHMARK);\n  if (startupBenchmark && appMode !== \"interactive\") {\n    console.error(chalk11.red(\"Error: PI_STARTUP_BENCHMARK only supports interactive mode\"));\n    process.exit(1);\n  }\n  if (!offlineMode && appMode === \"rpc\") {\n    const controller = new AbortController();\n    const timeout = setTimeout(() => controller.abort(), 15e3);\n    void modelRuntime.refresh({ signal: controller.signal }).catch(() => {\n    }).finally(() => clearTimeout(timeout));\n  }\n  if (appMode === \"rpc\") {\n    printTimings();\n    await runRpcMode(runtime);\n  } else if (appMode === \"interactive\") {\n    const interactiveMode = new InteractiveMode(runtime, {\n      migratedProviders,\n      modelFallbackMessage,\n      autoTrustOnReloadCwd,\n      initialMessage,\n      initialImages,\n      initialMessages: parsed.messages,\n      verbose: parsed.verbose,\n      tuiMode: parsed.tuiMode,\n      initialThemeSetting: parsed.useTheme\n    });\n    if (startupBenchmark) {\n      await interactiveMode.init();\n      time(\"interactiveMode.init\");\n      await new Promise((resolve15) => setTimeout(resolve15, 150));\n      interactiveMode.stop();\n      stopThemeWatcher();\n      printTimings();\n      if (process.stdout.writableLength > 0) {\n        await new Promise((resolve15) => process.stdout.once(\"drain\", resolve15));\n      }\n      if (process.stderr.writableLength > 0) {\n        await new Promise((resolve15) => process.stderr.once(\"drain\", resolve15));\n      }\n      return;\n    }\n    printTimings();\n    await interactiveMode.run();\n  } else {\n    printTimings();\n    const exitCode = await runPrintMode(runtime, {\n      mode: toPrintOutputMode(appMode),\n      messages: parsed.messages,\n      initialMessage,\n      initialImages\n    });\n    stopThemeWatcher();\n    restoreStdout();\n    if (exitCode !== 0) {\n      process.exitCode = exitCode;\n    }\n    return;\n  }\n}\n\n// node_modules/.pnpm/@earendil-works+pi-coding-agent@0.84.2_ws@8.21.3/node_modules/@earendil-works/pi-coding-agent/dist/cli.js\nprocess.title = APP_NAME;\nprocess.env.PI_CODING_AGENT = \"true\";\nprocess.env.AI_AGENT = \"pi\";\nprocess.emitWarning = (() => {\n});\nconfigureHttpDispatcher();\nmain(process.argv.slice(2));\n"}},"modes":{"directory":{"interactive":{"directory":{"assets":{"directory":{"clankolas.png":{"file":{"base64":"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"}}}},"theme":{"directory":{"dark.json":{"file":{"contents":"{\n\t\"$schema\": \"https://raw.githubusercontent.com/earendil-works/pi/main/packages/coding-agent/src/modes/interactive/theme/theme-schema.json\",\n\t\"name\": \"dark\",\n\t\"vars\": {\n\t\t\"cyan\": \"#00d7ff\",\n\t\t\"blue\": \"#5f87ff\",\n\t\t\"green\": \"#b5bd68\",\n\t\t\"red\": \"#cc6666\",\n\t\t\"yellow\": \"#ffff00\",\n\t\t\"text\": \"#d4d4d4\",\n\t\t\"gray\": \"#808080\",\n\t\t\"dimGray\": \"#666666\",\n\t\t\"darkGray\": \"#505050\",\n\t\t\"accent\": \"#8abeb7\",\n\t\t\"selectedBg\": \"#3a3a4a\",\n\t\t\"userMsgBg\": \"#343541\",\n\t\t\"toolPendingBg\": \"#282832\",\n\t\t\"toolSuccessBg\": \"#283228\",\n\t\t\"toolErrorBg\": \"#3c2828\",\n\t\t\"customMsgBg\": \"#2d2838\"\n\t},\n\t\"colors\": {\n\t\t\"accent\": \"accent\",\n\t\t\"border\": \"blue\",\n\t\t\"borderAccent\": \"cyan\",\n\t\t\"borderMuted\": \"darkGray\",\n\t\t\"success\": \"green\",\n\t\t\"error\": \"red\",\n\t\t\"warning\": \"yellow\",\n\t\t\"muted\": \"gray\",\n\t\t\"dim\": \"dimGray\",\n\t\t\"text\": \"text\",\n\t\t\"thinkingText\": \"gray\",\n\n\t\t\"selectedBg\": \"selectedBg\",\n\t\t\"scrollbarThumb\": \"selectedBg\",\n\t\t\"searchMatchBg\": \"selectedBg\",\n\t\t\"searchMatchText\": \"text\",\n\t\t\"userMessageBg\": \"userMsgBg\",\n\t\t\"userMessageText\": \"text\",\n\t\t\"customMessageBg\": \"customMsgBg\",\n\t\t\"customMessageText\": \"text\",\n\t\t\"customMessageLabel\": \"#9575cd\",\n\t\t\"toolPendingBg\": \"toolPendingBg\",\n\t\t\"toolSuccessBg\": \"toolSuccessBg\",\n\t\t\"toolErrorBg\": \"toolErrorBg\",\n\t\t\"toolTitle\": \"text\",\n\t\t\"toolOutput\": \"gray\",\n\n\t\t\"mdHeading\": \"#f0c674\",\n\t\t\"mdLink\": \"#81a2be\",\n\t\t\"mdLinkUrl\": \"dimGray\",\n\t\t\"mdCode\": \"accent\",\n\t\t\"mdCodeBlock\": \"green\",\n\t\t\"mdCodeBlockBorder\": \"gray\",\n\t\t\"mdQuote\": \"gray\",\n\t\t\"mdQuoteBorder\": \"gray\",\n\t\t\"mdHr\": \"gray\",\n\t\t\"mdListBullet\": \"accent\",\n\n\t\t\"toolDiffAdded\": \"green\",\n\t\t\"toolDiffRemoved\": \"red\",\n\t\t\"toolDiffContext\": \"gray\",\n\n\t\t\"syntaxComment\": \"#6A9955\",\n\t\t\"syntaxKeyword\": \"#569CD6\",\n\t\t\"syntaxFunction\": \"#DCDCAA\",\n\t\t\"syntaxVariable\": \"#9CDCFE\",\n\t\t\"syntaxString\": \"#CE9178\",\n\t\t\"syntaxNumber\": \"#B5CEA8\",\n\t\t\"syntaxType\": \"#4EC9B0\",\n\t\t\"syntaxOperator\": \"#D4D4D4\",\n\t\t\"syntaxPunctuation\": \"#D4D4D4\",\n\n\t\t\"thinkingOff\": \"darkGray\",\n\t\t\"thinkingMinimal\": \"#6e6e6e\",\n\t\t\"thinkingLow\": \"#5f87af\",\n\t\t\"thinkingMedium\": \"#81a2be\",\n\t\t\"thinkingHigh\": \"#b294bb\",\n\t\t\"thinkingXhigh\": \"#d183e8\",\n\t\t\"thinkingMax\": \"#ff5fff\",\n\n\t\t\"bashMode\": \"green\"\n\t},\n\t\"export\": {\n\t\t\"pageBg\": \"#18181e\",\n\t\t\"cardBg\": \"#1e1e24\",\n\t\t\"infoBg\": \"#3c3728\"\n\t}\n}\n"}},"light.json":{"file":{"contents":"{\n\t\"$schema\": \"https://raw.githubusercontent.com/earendil-works/pi/main/packages/coding-agent/src/modes/interactive/theme/theme-schema.json\",\n\t\"name\": \"light\",\n\t\"vars\": {\n\t\t\"teal\": \"#5a8080\",\n\t\t\"blue\": \"#547da7\",\n\t\t\"green\": \"#588458\",\n\t\t\"red\": \"#aa5555\",\n\t\t\"yellow\": \"#9a7326\",\n\t\t\"text\": \"#1f2328\",\n\t\t\"mediumGray\": \"#6c6c6c\",\n\t\t\"dimGray\": \"#767676\",\n\t\t\"lightGray\": \"#b0b0b0\",\n\t\t\"selectedBg\": \"#d0d0e0\",\n\t\t\"userMsgBg\": \"#e8e8e8\",\n\t\t\"toolPendingBg\": \"#e8e8f0\",\n\t\t\"toolSuccessBg\": \"#e8f0e8\",\n\t\t\"toolErrorBg\": \"#f0e8e8\",\n\t\t\"customMsgBg\": \"#ede7f6\"\n\t},\n\t\"colors\": {\n\t\t\"accent\": \"teal\",\n\t\t\"border\": \"blue\",\n\t\t\"borderAccent\": \"teal\",\n\t\t\"borderMuted\": \"lightGray\",\n\t\t\"success\": \"green\",\n\t\t\"error\": \"red\",\n\t\t\"warning\": \"yellow\",\n\t\t\"muted\": \"mediumGray\",\n\t\t\"dim\": \"dimGray\",\n\t\t\"text\": \"text\",\n\t\t\"thinkingText\": \"mediumGray\",\n\n\t\t\"selectedBg\": \"selectedBg\",\n\t\t\"scrollbarThumb\": \"selectedBg\",\n\t\t\"searchMatchBg\": \"selectedBg\",\n\t\t\"searchMatchText\": \"text\",\n\t\t\"userMessageBg\": \"userMsgBg\",\n\t\t\"userMessageText\": \"text\",\n\t\t\"customMessageBg\": \"customMsgBg\",\n\t\t\"customMessageText\": \"text\",\n\t\t\"customMessageLabel\": \"#7e57c2\",\n\t\t\"toolPendingBg\": \"toolPendingBg\",\n\t\t\"toolSuccessBg\": \"toolSuccessBg\",\n\t\t\"toolErrorBg\": \"toolErrorBg\",\n\t\t\"toolTitle\": \"text\",\n\t\t\"toolOutput\": \"mediumGray\",\n\n\t\t\"mdHeading\": \"yellow\",\n\t\t\"mdLink\": \"blue\",\n\t\t\"mdLinkUrl\": \"dimGray\",\n\t\t\"mdCode\": \"teal\",\n\t\t\"mdCodeBlock\": \"green\",\n\t\t\"mdCodeBlockBorder\": \"mediumGray\",\n\t\t\"mdQuote\": \"mediumGray\",\n\t\t\"mdQuoteBorder\": \"mediumGray\",\n\t\t\"mdHr\": \"mediumGray\",\n\t\t\"mdListBullet\": \"green\",\n\n\t\t\"toolDiffAdded\": \"green\",\n\t\t\"toolDiffRemoved\": \"red\",\n\t\t\"toolDiffContext\": \"mediumGray\",\n\n\t\t\"syntaxComment\": \"#008000\",\n\t\t\"syntaxKeyword\": \"#0000FF\",\n\t\t\"syntaxFunction\": \"#795E26\",\n\t\t\"syntaxVariable\": \"#001080\",\n\t\t\"syntaxString\": \"#A31515\",\n\t\t\"syntaxNumber\": \"#098658\",\n\t\t\"syntaxType\": \"#267F99\",\n\t\t\"syntaxOperator\": \"#000000\",\n\t\t\"syntaxPunctuation\": \"#000000\",\n\n\t\t\"thinkingOff\": \"lightGray\",\n\t\t\"thinkingMinimal\": \"#767676\",\n\t\t\"thinkingLow\": \"blue\",\n\t\t\"thinkingMedium\": \"teal\",\n\t\t\"thinkingHigh\": \"#875f87\",\n\t\t\"thinkingXhigh\": \"#8b008b\",\n\t\t\"thinkingMax\": \"#af005f\",\n\n\t\t\"bashMode\": \"green\"\n\t},\n\t\"export\": {\n\t\t\"pageBg\": \"#f8f8f8\",\n\t\t\"cardBg\": \"#ffffff\",\n\t\t\"infoBg\": \"#fffae6\"\n\t}\n}\n"}},"theme-schema.json":{"file":{"contents":"{\n\t\"$schema\": \"http://json-schema.org/draft-07/schema#\",\n\t\"title\": \"Pi Coding Agent Theme\",\n\t\"description\": \"Theme schema for Pi coding agent\",\n\t\"type\": \"object\",\n\t\"required\": [\"name\", \"colors\"],\n\t\"properties\": {\n\t\t\"$schema\": {\n\t\t\t\"type\": \"string\",\n\t\t\t\"description\": \"JSON schema reference\"\n\t\t},\n\t\t\"name\": {\n\t\t\t\"type\": \"string\",\n\t\t\t\"pattern\": \"^[^/]+$\",\n\t\t\t\"description\": \"Theme name. Must not contain '/' because it is reserved for automatic light/dark theme settings.\"\n\t\t},\n\t\t\"vars\": {\n\t\t\t\"type\": \"object\",\n\t\t\t\"description\": \"Reusable color variables\",\n\t\t\t\"additionalProperties\": {\n\t\t\t\t\"oneOf\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\"description\": \"Hex color (#RRGGBB), variable reference, or empty string for terminal default\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"type\": \"integer\",\n\t\t\t\t\t\t\"minimum\": 0,\n\t\t\t\t\t\t\"maximum\": 255,\n\t\t\t\t\t\t\"description\": \"256-color palette index (0-255)\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t\"colors\": {\n\t\t\t\"type\": \"object\",\n\t\t\t\"description\": \"Theme color definitions (thinkingMax, scrollbarThumb, and search highlight colors are optional and use compatible fallbacks)\",\n\t\t\t\"required\": [\n\t\t\t\t\"accent\",\n\t\t\t\t\"border\",\n\t\t\t\t\"borderAccent\",\n\t\t\t\t\"borderMuted\",\n\t\t\t\t\"success\",\n\t\t\t\t\"error\",\n\t\t\t\t\"warning\",\n\t\t\t\t\"muted\",\n\t\t\t\t\"dim\",\n\t\t\t\t\"text\",\n\t\t\t\t\"thinkingText\",\n\t\t\t\t\"selectedBg\",\n\t\t\t\t\"userMessageBg\",\n\t\t\t\t\"userMessageText\",\n\t\t\t\t\"customMessageBg\",\n\t\t\t\t\"customMessageText\",\n\t\t\t\t\"customMessageLabel\",\n\t\t\t\t\"toolPendingBg\",\n\t\t\t\t\"toolSuccessBg\",\n\t\t\t\t\"toolErrorBg\",\n\t\t\t\t\"toolTitle\",\n\t\t\t\t\"toolOutput\",\n\t\t\t\t\"mdHeading\",\n\t\t\t\t\"mdLink\",\n\t\t\t\t\"mdLinkUrl\",\n\t\t\t\t\"mdCode\",\n\t\t\t\t\"mdCodeBlock\",\n\t\t\t\t\"mdCodeBlockBorder\",\n\t\t\t\t\"mdQuote\",\n\t\t\t\t\"mdQuoteBorder\",\n\t\t\t\t\"mdHr\",\n\t\t\t\t\"mdListBullet\",\n\t\t\t\t\"toolDiffAdded\",\n\t\t\t\t\"toolDiffRemoved\",\n\t\t\t\t\"toolDiffContext\",\n\t\t\t\t\"syntaxComment\",\n\t\t\t\t\"syntaxKeyword\",\n\t\t\t\t\"syntaxFunction\",\n\t\t\t\t\"syntaxVariable\",\n\t\t\t\t\"syntaxString\",\n\t\t\t\t\"syntaxNumber\",\n\t\t\t\t\"syntaxType\",\n\t\t\t\t\"syntaxOperator\",\n\t\t\t\t\"syntaxPunctuation\",\n\t\t\t\t\"thinkingOff\",\n\t\t\t\t\"thinkingMinimal\",\n\t\t\t\t\"thinkingLow\",\n\t\t\t\t\"thinkingMedium\",\n\t\t\t\t\"thinkingHigh\",\n\t\t\t\t\"thinkingXhigh\",\n\t\t\t\t\"bashMode\"\n\t\t\t],\n\t\t\t\"properties\": {\n\t\t\t\t\"accent\": {\n\t\t\t\t\t\"$ref\": \"#/$defs/colorValue\",\n\t\t\t\t\t\"description\": \"Primary accent color (logo, selected items, cursor)\"\n\t\t\t\t},\n\t\t\t\t\"border\": {\n\t\t\t\t\t\"$ref\": \"#/$defs/colorValue\",\n\t\t\t\t\t\"description\": \"Normal borders\"\n\t\t\t\t},\n\t\t\t\t\"borderAccent\": {\n\t\t\t\t\t\"$ref\": \"#/$defs/colorValue\",\n\t\t\t\t\t\"description\": \"Highlighted borders\"\n\t\t\t\t},\n\t\t\t\t\"borderMuted\": {\n\t\t\t\t\t\"$ref\": \"#/$defs/colorValue\",\n\t\t\t\t\t\"description\": \"Subtle borders\"\n\t\t\t\t},\n\t\t\t\t\"success\": {\n\t\t\t\t\t\"$ref\": \"#/$defs/colorValue\",\n\t\t\t\t\t\"description\": \"Success states\"\n\t\t\t\t},\n\t\t\t\t\"error\": {\n\t\t\t\t\t\"$ref\": \"#/$defs/colorValue\",\n\t\t\t\t\t\"description\": \"Error states\"\n\t\t\t\t},\n\t\t\t\t\"warning\": {\n\t\t\t\t\t\"$ref\": \"#/$defs/colorValue\",\n\t\t\t\t\t\"description\": \"Warning states\"\n\t\t\t\t},\n\t\t\t\t\"muted\": {\n\t\t\t\t\t\"$ref\": \"#/$defs/colorValue\",\n\t\t\t\t\t\"description\": \"Secondary/dimmed text\"\n\t\t\t\t},\n\t\t\t\t\"dim\": {\n\t\t\t\t\t\"$ref\": \"#/$defs/colorValue\",\n\t\t\t\t\t\"description\": \"Very dimmed text (more subtle than muted)\"\n\t\t\t\t},\n\t\t\t\t\"text\": {\n\t\t\t\t\t\"$ref\": \"#/$defs/colorValue\",\n\t\t\t\t\t\"description\": \"Default text color (usually empty string)\"\n\t\t\t\t},\n\t\t\t\t\"thinkingText\": {\n\t\t\t\t\t\"$ref\": \"#/$defs/colorValue\",\n\t\t\t\t\t\"description\": \"Thinking block text color\"\n\t\t\t\t},\n\t\t\t\t\"selectedBg\": {\n\t\t\t\t\t\"$ref\": \"#/$defs/colorValue\",\n\t\t\t\t\t\"description\": \"Selected item background\"\n\t\t\t\t},\n\t\t\t\t\"scrollbarThumb\": {\n\t\t\t\t\t\"$ref\": \"#/$defs/colorValue\",\n\t\t\t\t\t\"description\": \"Fullscreen scrollbar thumb background (falls back to selectedBg when omitted)\"\n\t\t\t\t},\n\t\t\t\t\"searchMatchBg\": {\n\t\t\t\t\t\"$ref\": \"#/$defs/colorValue\",\n\t\t\t\t\t\"description\": \"Transcript search match background and current-match text (falls back to selectedBg when omitted)\"\n\t\t\t\t},\n\t\t\t\t\"searchMatchText\": {\n\t\t\t\t\t\"$ref\": \"#/$defs/colorValue\",\n\t\t\t\t\t\"description\": \"Transcript search match text and current-match background (falls back to text when omitted)\"\n\t\t\t\t},\n\t\t\t\t\"userMessageBg\": {\n\t\t\t\t\t\"$ref\": \"#/$defs/colorValue\",\n\t\t\t\t\t\"description\": \"User message background\"\n\t\t\t\t},\n\t\t\t\t\"userMessageText\": {\n\t\t\t\t\t\"$ref\": \"#/$defs/colorValue\",\n\t\t\t\t\t\"description\": \"User message text color\"\n\t\t\t\t},\n\t\t\t\t\"customMessageBg\": {\n\t\t\t\t\t\"$ref\": \"#/$defs/colorValue\",\n\t\t\t\t\t\"description\": \"Custom message background (hook-injected messages)\"\n\t\t\t\t},\n\t\t\t\t\"customMessageText\": {\n\t\t\t\t\t\"$ref\": \"#/$defs/colorValue\",\n\t\t\t\t\t\"description\": \"Custom message text color\"\n\t\t\t\t},\n\t\t\t\t\"customMessageLabel\": {\n\t\t\t\t\t\"$ref\": \"#/$defs/colorValue\",\n\t\t\t\t\t\"description\": \"Custom message type label color\"\n\t\t\t\t},\n\t\t\t\t\"toolPendingBg\": {\n\t\t\t\t\t\"$ref\": \"#/$defs/colorValue\",\n\t\t\t\t\t\"description\": \"Tool execution box (pending state)\"\n\t\t\t\t},\n\t\t\t\t\"toolSuccessBg\": {\n\t\t\t\t\t\"$ref\": \"#/$defs/colorValue\",\n\t\t\t\t\t\"description\": \"Tool execution box (success state)\"\n\t\t\t\t},\n\t\t\t\t\"toolErrorBg\": {\n\t\t\t\t\t\"$ref\": \"#/$defs/colorValue\",\n\t\t\t\t\t\"description\": \"Tool execution box (error state)\"\n\t\t\t\t},\n\t\t\t\t\"toolTitle\": {\n\t\t\t\t\t\"$ref\": \"#/$defs/colorValue\",\n\t\t\t\t\t\"description\": \"Tool execution box title color\"\n\t\t\t\t},\n\t\t\t\t\"toolOutput\": {\n\t\t\t\t\t\"$ref\": \"#/$defs/colorValue\",\n\t\t\t\t\t\"description\": \"Tool execution box output text color\"\n\t\t\t\t},\n\t\t\t\t\"mdHeading\": {\n\t\t\t\t\t\"$ref\": \"#/$defs/colorValue\",\n\t\t\t\t\t\"description\": \"Markdown heading text\"\n\t\t\t\t},\n\t\t\t\t\"mdLink\": {\n\t\t\t\t\t\"$ref\": \"#/$defs/colorValue\",\n\t\t\t\t\t\"description\": \"Markdown link text\"\n\t\t\t\t},\n\t\t\t\t\"mdLinkUrl\": {\n\t\t\t\t\t\"$ref\": \"#/$defs/colorValue\",\n\t\t\t\t\t\"description\": \"Markdown link URL\"\n\t\t\t\t},\n\t\t\t\t\"mdCode\": {\n\t\t\t\t\t\"$ref\": \"#/$defs/colorValue\",\n\t\t\t\t\t\"description\": \"Markdown inline code\"\n\t\t\t\t},\n\t\t\t\t\"mdCodeBlock\": {\n\t\t\t\t\t\"$ref\": \"#/$defs/colorValue\",\n\t\t\t\t\t\"description\": \"Markdown code block content\"\n\t\t\t\t},\n\t\t\t\t\"mdCodeBlockBorder\": {\n\t\t\t\t\t\"$ref\": \"#/$defs/colorValue\",\n\t\t\t\t\t\"description\": \"Markdown code block fences\"\n\t\t\t\t},\n\t\t\t\t\"mdQuote\": {\n\t\t\t\t\t\"$ref\": \"#/$defs/colorValue\",\n\t\t\t\t\t\"description\": \"Markdown blockquote text\"\n\t\t\t\t},\n\t\t\t\t\"mdQuoteBorder\": {\n\t\t\t\t\t\"$ref\": \"#/$defs/colorValue\",\n\t\t\t\t\t\"description\": \"Markdown blockquote border\"\n\t\t\t\t},\n\t\t\t\t\"mdHr\": {\n\t\t\t\t\t\"$ref\": \"#/$defs/colorValue\",\n\t\t\t\t\t\"description\": \"Markdown horizontal rule\"\n\t\t\t\t},\n\t\t\t\t\"mdListBullet\": {\n\t\t\t\t\t\"$ref\": \"#/$defs/colorValue\",\n\t\t\t\t\t\"description\": \"Markdown list bullets/numbers\"\n\t\t\t\t},\n\t\t\t\t\"toolDiffAdded\": {\n\t\t\t\t\t\"$ref\": \"#/$defs/colorValue\",\n\t\t\t\t\t\"description\": \"Added lines in tool diffs\"\n\t\t\t\t},\n\t\t\t\t\"toolDiffRemoved\": {\n\t\t\t\t\t\"$ref\": \"#/$defs/colorValue\",\n\t\t\t\t\t\"description\": \"Removed lines in tool diffs\"\n\t\t\t\t},\n\t\t\t\t\"toolDiffContext\": {\n\t\t\t\t\t\"$ref\": \"#/$defs/colorValue\",\n\t\t\t\t\t\"description\": \"Context lines in tool diffs\"\n\t\t\t\t},\n\t\t\t\t\"syntaxComment\": {\n\t\t\t\t\t\"$ref\": \"#/$defs/colorValue\",\n\t\t\t\t\t\"description\": \"Syntax highlighting: comments\"\n\t\t\t\t},\n\t\t\t\t\"syntaxKeyword\": {\n\t\t\t\t\t\"$ref\": \"#/$defs/colorValue\",\n\t\t\t\t\t\"description\": \"Syntax highlighting: keywords\"\n\t\t\t\t},\n\t\t\t\t\"syntaxFunction\": {\n\t\t\t\t\t\"$ref\": \"#/$defs/colorValue\",\n\t\t\t\t\t\"description\": \"Syntax highlighting: function names\"\n\t\t\t\t},\n\t\t\t\t\"syntaxVariable\": {\n\t\t\t\t\t\"$ref\": \"#/$defs/colorValue\",\n\t\t\t\t\t\"description\": \"Syntax highlighting: variable names\"\n\t\t\t\t},\n\t\t\t\t\"syntaxString\": {\n\t\t\t\t\t\"$ref\": \"#/$defs/colorValue\",\n\t\t\t\t\t\"description\": \"Syntax highlighting: string literals\"\n\t\t\t\t},\n\t\t\t\t\"syntaxNumber\": {\n\t\t\t\t\t\"$ref\": \"#/$defs/colorValue\",\n\t\t\t\t\t\"description\": \"Syntax highlighting: number literals\"\n\t\t\t\t},\n\t\t\t\t\"syntaxType\": {\n\t\t\t\t\t\"$ref\": \"#/$defs/colorValue\",\n\t\t\t\t\t\"description\": \"Syntax highlighting: type names\"\n\t\t\t\t},\n\t\t\t\t\"syntaxOperator\": {\n\t\t\t\t\t\"$ref\": \"#/$defs/colorValue\",\n\t\t\t\t\t\"description\": \"Syntax highlighting: operators\"\n\t\t\t\t},\n\t\t\t\t\"syntaxPunctuation\": {\n\t\t\t\t\t\"$ref\": \"#/$defs/colorValue\",\n\t\t\t\t\t\"description\": \"Syntax highlighting: punctuation\"\n\t\t\t\t},\n\t\t\t\t\"thinkingOff\": {\n\t\t\t\t\t\"$ref\": \"#/$defs/colorValue\",\n\t\t\t\t\t\"description\": \"Thinking level border: off\"\n\t\t\t\t},\n\t\t\t\t\"thinkingMinimal\": {\n\t\t\t\t\t\"$ref\": \"#/$defs/colorValue\",\n\t\t\t\t\t\"description\": \"Thinking level border: minimal\"\n\t\t\t\t},\n\t\t\t\t\"thinkingLow\": {\n\t\t\t\t\t\"$ref\": \"#/$defs/colorValue\",\n\t\t\t\t\t\"description\": \"Thinking level border: low\"\n\t\t\t\t},\n\t\t\t\t\"thinkingMedium\": {\n\t\t\t\t\t\"$ref\": \"#/$defs/colorValue\",\n\t\t\t\t\t\"description\": \"Thinking level border: medium\"\n\t\t\t\t},\n\t\t\t\t\"thinkingHigh\": {\n\t\t\t\t\t\"$ref\": \"#/$defs/colorValue\",\n\t\t\t\t\t\"description\": \"Thinking level border: high\"\n\t\t\t\t},\n\t\t\t\t\"thinkingXhigh\": {\n\t\t\t\t\t\"$ref\": \"#/$defs/colorValue\",\n\t\t\t\t\t\"description\": \"Thinking level border: xhigh\"\n\t\t\t\t},\n\t\t\t\t\"thinkingMax\": {\n\t\t\t\t\t\"$ref\": \"#/$defs/colorValue\",\n\t\t\t\t\t\"description\": \"Thinking level border: max (falls back to thinkingXhigh when omitted)\"\n\t\t\t\t},\n\t\t\t\t\"bashMode\": {\n\t\t\t\t\t\"$ref\": \"#/$defs/colorValue\",\n\t\t\t\t\t\"description\": \"Editor border color in bash mode\"\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"additionalProperties\": false\n\t\t},\n\t\t\"export\": {\n\t\t\t\"type\": \"object\",\n\t\t\t\"description\": \"Optional colors for HTML export (defaults derived from userMessageBg if not specified)\",\n\t\t\t\"properties\": {\n\t\t\t\t\"pageBg\": {\n\t\t\t\t\t\"$ref\": \"#/$defs/colorValue\",\n\t\t\t\t\t\"description\": \"Page background color\"\n\t\t\t\t},\n\t\t\t\t\"cardBg\": {\n\t\t\t\t\t\"$ref\": \"#/$defs/colorValue\",\n\t\t\t\t\t\"description\": \"Card/container background color\"\n\t\t\t\t},\n\t\t\t\t\"infoBg\": {\n\t\t\t\t\t\"$ref\": \"#/$defs/colorValue\",\n\t\t\t\t\t\"description\": \"Info sections background (system prompt, notices)\"\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"additionalProperties\": false\n\t\t}\n\t},\n\t\"additionalProperties\": false,\n\t\"$defs\": {\n\t\t\"colorValue\": {\n\t\t\t\"oneOf\": [\n\t\t\t\t{\n\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\"description\": \"Hex color (#RRGGBB), variable reference, or empty string for terminal default\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"type\": \"integer\",\n\t\t\t\t\t\"minimum\": 0,\n\t\t\t\t\t\"maximum\": 255,\n\t\t\t\t\t\"description\": \"256-color palette index (0-255)\"\n\t\t\t\t}\n\t\t\t]\n\t\t}\n\t}\n}\n"}}}}}}}}}},"package.json":{"file":{"contents":"{\n  \"name\": \"@earendil-works/pi-coding-agent\",\n  \"version\": \"0.84.2\",\n  \"type\": \"module\",\n  \"bin\": {\n    \"pi\": \"dist/cli.js\"\n  },\n  \"piConfig\": {\n    \"configDir\": \".pi\"\n  }\n}\n"}}}}}