{".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: makes project/ a git repository on main with a short history,\n// through the same stand-in for git that pi-git uses.\nconst path = require(\"node:path\");\nconst { main } = require(\"../.git-shim/git.cjs\");\n\nconst project = path.join(__dirname, \"../project\");\nconst git = async (...args) => {\n  const code = await main(args, project);\n  if (code !== 0) throw new Error(`git ${args.join(\" \")} exited with ${code}`);\n};\n\n(async () => {\n  await git(\"init\");\n  await git(\"add\", \"--\", \"package.json\", \"src/readings.js\", \"src/cli.js\");\n  await git(\"commit\", \"--message\", \"feat: print today's forecast for a city\");\n  await git(\"add\", \"--all\", \"--\", \".\");\n  await git(\"commit\", \"--message\", \"docs: add a README with usage\");\n})();\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.\n// pi-git asks the same model for commit messages, so those requests get a scripted message for the staged change.\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 pi-git's commit notice shows what the message would cost.\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}`;\nconst oslo = '  oslo: { sky: \"light rain\", high: 9, low: 4, rain: 0.8 },';\nconst newYork = `${oslo}\\n  \"new york\": { sky: \"partly cloudy\", high: 18, low: 11, rain: 0.2 },`;\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: /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([fauxToolCall(\"bash\", { command: \"node src/cli.js Lisbon --json && node src/cli.js Lisbon\" })], toolUse),\n      fauxAssistantMessage([fauxText(\"Added `--json`: it prints the reading as one JSON object, and the plain output is unchanged. Commit it with **/git-quick-commit**, or stage it yourself in **/git**.\")]),\n    ],\n  },\n  {\n    match: /new york/i,\n    steps: [\n      fauxAssistantMessage([fauxToolCall(\"edit\", { path: \"src/readings.js\", edits: [{ oldText: oslo, newText: newYork }] })], toolUse),\n      fauxAssistantMessage([fauxToolCall(\"bash\", { command: 'node src/cli.js \"New York\"' })], toolUse),\n      fauxAssistantMessage([fauxText(\"New York has a reading now.\")]),\n    ],\n  },\n];\n\n// Commit messages for the staged patch pi-git sends, by what the patch contains.\nconst commitMessages: { match: RegExp; message: string }[] = [\n  { match: /--json[\\s\\S]*new york|new york[\\s\\S]*--json/i, message: \"feat(cli): add a --json flag and a New York reading\\n\\n--json prints the reading as one JSON object; the plain output is unchanged.\" },\n  { match: /--json/, message: \"feat(cli): add a --json flag for machine-readable output\\n\\nPrints the reading as one JSON object, so scripts can use it. The plain\\noutput is unchanged.\" },\n  { match: /new york/i, message: \"feat(readings): add New York to the sample\" },\n];\n\nconst fallback = fauxAssistantMessage([\n  fauxText(\"I'm a scripted stand-in for a model, so I only know a few prompts. Try **add a --json flag**, then commit it with **/git-quick-commit** or stage it in **/git**.\"),\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\nfunction commitReply(context: { messages: { content: unknown }[] }): Step {\n  const evidence = text(context.messages.at(-1)?.content);\n  const known = commitMessages.find((candidate) => candidate.match.test(evidence));\n  return fauxAssistantMessage([fauxText(known?.message ?? \"chore: update the forecast CLI\")]);\n}\n\nconst isCommitRequest = (context: { systemPrompt?: string }) => context.systemPrompt?.startsWith(\"You write one Git commit message\") ?? false;\n\nexport default function demoModel(pi: ExtensionAPI): void {\n  const agent = createFauxCore({ provider: \"demo\", api: \"demo-scripted\", models: [model], tokensPerSecond: 90 });\n  // A second core for commit messages, which a quick commit generates while the agent may still be working.\n  const writer = createFauxCore({ provider: \"demo\", api: \"demo-scripted\", models: [model], tokensPerSecond: 60 });\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      const core = isCommitRequest(context) ? writer : agent;\n      core.setResponses([isCommitRequest(context) ? commitReply(context as never) : 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-git":{"directory":{"COMMIT.md":{"file":{"contents":"# Commit Message Style\n\nThis file defines how AI-generated commit messages should be formatted.\nCustomize it to match your team's conventions.\n\n## Format\n\nFollow the Conventional Commits specification:\n\n```\n<type>(<optional scope>): <short summary>\n\n<optional body with bullet points explaining key changes>\n```\n\n## Types\n\nfeat, fix, refactor, docs, style, test, chore, perf, ci, build, revert\n\n## Rules\n\n- Summary line: imperative mood, lowercase, no period, max 72 UTF-8 bytes\n- Body bullets: start with \"- \", explain what and why, not how\n- Keep it concise - only include bullets if the change isn't obvious from the summary\n- If multiple unrelated changes exist, focus on the primary one for the summary and list others as bullets\n"}},"index.ts":{"file":{"contents":"import type { ExtensionAPI } from \"@earendil-works/pi-coding-agent\";\nimport { registerPiGit } from \"./src/register.js\";\n\nexport default function piGitExtension(pi: ExtensionAPI): void {\n  registerPiGit(pi);\n}\n"}},"package.json":{"file":{"contents":"{\n  \"name\": \"pi-git\",\n  \"version\": \"0.1.0\",\n  \"description\": \"A namespaced Git workflow extension for pi\",\n  \"type\": \"module\",\n  \"keywords\": [\n    \"pi\",\n    \"extension\",\n    \"pi-package\",\n    \"pi-coding-agent\",\n    \"tui\",\n    \"git\"\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    \"typebox\": \"*\"\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#658b1b5\",\n    \"@types/node\": \"24.12.4\",\n    \"diff\": \"5.2.0\",\n    \"esbuild\": \"0.25.10\",\n    \"isomorphic-git\": \"1.27.1\",\n    \"typebox\": \"1.3.7\",\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    \"COMMIT.md\",\n    \"README.md\"\n  ]\n}\n"}},"src":{"directory":{"abort.ts":{"file":{"contents":"/** True for DOMException-style abort errors thrown by aborted fetches. */\nexport function isAbortError(error: unknown): boolean {\n  if (!error || typeof error !== \"object\") return false;\n  const value = error as { name?: unknown; code?: unknown };\n  return value.name === \"AbortError\" || value.code === \"ABORT_ERR\";\n}\n"}},"commit-evidence.ts":{"file":{"contents":"/**\n * Shared contracts for commit generation: staged evidence, explicit intent,\n * draft cache keys, and the capture of raw Git evidence.\n */\nimport type { Api, Model } from \"@earendil-works/pi-ai\";\nimport type { GitService } from \"./git-service.js\";\nimport { MAX_COMMIT_DIFF_BYTES } from \"./commit-message.js\";\nimport { buildDiffSkeleton, type SkeletonOmittedFile } from \"./diff-skeleton.js\";\nimport {\n  buildStagedFiles,\n  estimateTextTokensLocal,\n  summarizeStagedFiles,\n  type GitStagedFile,\n  type StagedEvidenceSummary,\n} from \"./evidence-parse.js\";\n\nexport const GENERATOR_CONTRACT_VERSION = \"pi-git-commit-v1\";\nexport const MAX_COMMIT_INTENT_BYTES = 1_500;\nexport const MAX_COMMIT_INTENT_TOKENS = 256;\nexport const MAX_ANALYSIS_BYTES = 32 * 1024;\n\nexport interface StagedEvidence {\n  readonly snapshot: GitMaybeSnapshot;\n  readonly stat: string;\n  readonly shortStat?: string | undefined;\n  readonly files: readonly GitStagedFile[];\n  readonly summary: StagedEvidenceSummary;\n  readonly contextPatch: string;\n  readonly compactPatch: string;\n  readonly contextBytes: number;\n  readonly compactBytes: number;\n  /** Present only when the complete compact patch exceeded the hard cap and was replaced by a labeled skeleton projection. */\n  readonly partial?: PartialEvidence | undefined;\n}\n\nexport interface PartialEvidence {\n  /** Compact-patch byte size before skeleton reduction. */\n  readonly originalCompactBytes: number;\n  /** Files whose change bodies were omitted, in omission order. */\n  readonly omittedFiles: readonly SkeletonOmittedFile[];\n  /** Unreduced compact patch, kept so generation can re-reduce with a smaller budget. */\n  readonly rawCompactPatch: string;\n}\n\nexport interface CommitIntent {\n  readonly text: string;\n  readonly estimatedTokens: number;\n}\n\nexport type CommitOperation =\n  | { readonly kind: \"draft\" }\n  | { readonly kind: \"rewrite\"; readonly currentMessage: string; readonly instruction: string };\n\nexport interface DiffAnalysisArea {\n  readonly paths: readonly string[];\n  readonly summary: string;\n}\n\nexport interface DiffAnalysis {\n  readonly version: 1;\n  readonly coveredFileKeys: readonly string[];\n  readonly overview: string;\n  readonly areas: readonly DiffAnalysisArea[];\n  readonly unresolved: readonly string[];\n}\n\n/** Cheap, prompt-free description of one candidate route. */\n\n/** Capture both independently requested patch representations from one Git snapshot. */\nexport async function captureStagedEvidence(git: GitService, signal?: AbortSignal): Promise<StagedEvidence> {\n  const raw = await git.stagedEvidence(signal);\n  const files = buildStagedFiles(raw.nameStatus, raw.numstat);\n  const summary = summarizeStagedFiles(files, raw.compactPatch);\n  const compactBytes = Buffer.byteLength(raw.compactPatch, \"utf8\");\n  let compactPatch = raw.compactPatch;\n  let effectiveCompactBytes = compactBytes;\n  let partial: PartialEvidence | undefined;\n\n  // Oversized diffs degrade explicitly to a labeled skeleton projection instead\n  // of failing closed; every file header and hunk header survives and each\n  // omitted body is enumerated inside the patch itself.\n  if (compactBytes > MAX_COMMIT_DIFF_BYTES) {\n    const skeleton = buildDiffSkeleton(raw.compactPatch, MAX_COMMIT_DIFF_BYTES);\n    if (skeleton.bytes <= MAX_COMMIT_DIFF_BYTES) {\n      compactPatch = skeleton.patch;\n      effectiveCompactBytes = skeleton.bytes;\n      partial = {\n        originalCompactBytes: compactBytes,\n        omittedFiles: skeleton.omittedFiles,\n        rawCompactPatch: raw.compactPatch,\n      };\n    }\n  }\n\n  return {\n    snapshot: raw.snapshot,\n    stat: raw.stat,\n    shortStat: raw.shortStat,\n    files,\n    summary,\n    contextPatch: raw.contextPatch,\n    compactPatch,\n    contextBytes: Buffer.byteLength(raw.contextPatch, \"utf8\"),\n    compactBytes: effectiveCompactBytes,\n    ...(partial === undefined ? {} : { partial }),\n  };\n}\n\n/** Minimum partial-evidence size before another reduction attempt is worthwhile. */\nexport const MIN_REDUCTION_BYTES = 64 * 1024;\n\n/** Rebuild partial evidence from the raw patch at a smaller budget; undefined when reduction is impossible or pointless. */\nexport function reduceStagedEvidence(evidence: StagedEvidence, budgetBytes: number): StagedEvidence | undefined {\n  const partial = evidence.partial;\n  if (!partial || evidence.compactBytes <= MIN_REDUCTION_BYTES || budgetBytes >= evidence.compactBytes) {\n    return undefined;\n  }\n  const skeleton = buildDiffSkeleton(partial.rawCompactPatch, budgetBytes);\n  if (skeleton.bytes >= evidence.compactBytes) return undefined;\n  return {\n    ...evidence,\n    compactPatch: skeleton.patch,\n    compactBytes: skeleton.bytes,\n    partial: {\n      originalCompactBytes: partial.originalCompactBytes,\n      omittedFiles: skeleton.omittedFiles,\n      rawCompactPatch: partial.rawCompactPatch,\n    },\n  };\n}\n\n/** Force a labeled skeleton reduction of the current compact patch for size pressure. */\nexport function degradeStagedEvidence(evidence: StagedEvidence): StagedEvidence | undefined {\n  if (evidence.compactBytes <= MIN_REDUCTION_BYTES) return undefined;\n  const raw = evidence.partial?.rawCompactPatch ?? evidence.compactPatch;\n  const skeleton = buildDiffSkeleton(raw, Math.floor(evidence.compactBytes / 2));\n  if (skeleton.bytes >= evidence.compactBytes) return undefined;\n  return {\n    ...evidence,\n    compactPatch: skeleton.patch,\n    compactBytes: skeleton.bytes,\n    partial: {\n      originalCompactBytes: evidence.partial?.originalCompactBytes ?? evidence.compactBytes,\n      omittedFiles: skeleton.omittedFiles,\n      rawCompactPatch: raw,\n    },\n  };\n}\n\n/** Normalize an explicit intent value; invalid or oversized intent is omitted. */\nexport function normalizeCommitIntent(text: string): CommitIntent | undefined {\n  const normalized = text.trim();\n  // A slash command is an instruction to pi, not a statement of commit intent.\n  if (!normalized || normalized.includes(\"\\0\") || normalized.startsWith(\"/\")) return undefined;\n  if (Buffer.byteLength(normalized, \"utf8\") > MAX_COMMIT_INTENT_BYTES) return undefined;\n  const estimatedTokens = estimateTextTokensLocal(normalized);\n  if (estimatedTokens > MAX_COMMIT_INTENT_TOKENS) return undefined;\n  return { text: normalized, estimatedTokens };\n}\n\n/** Identifies a draft that may be reused for the same staged snapshot. */\nexport function snapshotCacheKey(\n  snapshot: GitMaybeSnapshot,\n  model: Model<Api>,\n  style: string,\n): string {\n  return JSON.stringify({\n    contract: GENERATOR_CONTRACT_VERSION,\n    snapshot: {\n      root: snapshot.root,\n      branchRef: snapshot.branchRef,\n      head: snapshot.head,\n      indexTree: snapshot.indexTree,\n    },\n    model: { provider: model.provider, id: model.id },\n    style,\n  });\n}\n\nimport type { GitMaybeSnapshot } from \"./git-service.js\";\n\nexport type { GitMaybeSnapshot };\n"}},"commit-generator.ts":{"file":{"contents":"import {\n  getOverflowPatterns,\n  isContextOverflow,\n  type Api,\n  type AssistantMessage,\n  type Message,\n  type Model,\n  type ModelThinkingLevel,\n  type ThinkingLevel,\n} from \"@earendil-works/pi-ai\";\nimport { TokenTallyCollector, type TokenTally } from \"./usage-format.js\";\nimport {\n  degradeStagedEvidence,\n  MAX_ANALYSIS_BYTES,\n  reduceStagedEvidence,\n  type CommitIntent,\n  type CommitOperation,\n  type DiffAnalysis,\n  type DiffAnalysisArea,\n  type StagedEvidence,\n} from \"./commit-evidence.js\";\nimport {\n  candidateForAnalysisFinal,\n  materializeCandidate,\n  modelContextWindow,\n  nextCommitOutputReserve,\n  planCommitEvidence,\n  type CommitEvidenceCandidate,\n  type CommitEvidencePlan,\n  type CommitEvidenceRequest,\n  type CommitEvidenceSpec,\n  type CommitRepresentation,\n} from \"./evidence-plan.js\";\nimport { isAbortError } from \"./abort.js\";\nimport {\n  salvageTruncatedCommitMessage,\n  shortenCommitMessageSubject,\n  validateCommitResponse,\n  type CommitMessageValidation,\n  type TruncatedCommitMessage,\n} from \"./commit-message.js\";\n\nexport interface CommitModelClient {\n  complete(\n    model: Model<Api>,\n    context: { systemPrompt?: string; messages: Message[]; tools: [] },\n    options: {\n      signal?: AbortSignal;\n      maxTokens: number;\n      reasoning?: ThinkingLevel;\n      /** API-level effort for openai-completions providers (e.g. OpenRouter reasoning-mandatory endpoints). */\n      reasoningEffort?: ThinkingLevel;\n    },\n  ): Promise<AssistantMessage>;\n}\n\n/**\n * Bound every recovery retry. Large prompts cost ~30s per call, and quick\n * commit aborts at 180s, so three requests is the practical ceiling.\n */\nexport const MAX_MODEL_CALLS_PER_GENERATION = 3;\n\ninterface WriterRung {\n  readonly reserve: number;\n  readonly reasoning: ModelThinkingLevel | undefined;\n}\n\ninterface WriterCallBudget {\n  calls: number;\n  readonly max: number;\n  /** Token totals of every call, so a retry ladder is visible in the cost. */\n  readonly tally: TokenTallyCollector;\n  /** Analyst-phase subset, reported separately from the writer total. */\n  readonly analystTally: TokenTallyCollector;\n}\n\nfunction newCallBudget(): WriterCallBudget {\n  return { calls: 0, max: MAX_MODEL_CALLS_PER_GENERATION, tally: new TokenTallyCollector(), analystTally: new TokenTallyCollector() };\n}\n\n/** Calls the analyst must leave for the writer that follows it. */\nconst ANALYST_WRITER_RESERVE_CALLS = 2;\n\ntype WriterOutcome =\n  | { readonly kind: \"success\"; readonly response: AssistantMessage; readonly salvage?: TruncatedCommitMessage | undefined }\n  | { readonly kind: \"overflow\"; readonly response: AssistantMessage }\n  | { readonly kind: \"truncated\"; readonly response: AssistantMessage }\n  | { readonly kind: \"failed\"; readonly failure: Extract<CommitGenerationResult, { ok: false }> };\n\n/**\n * Ordered budgets for one prompt: the planned reserve, a doubled reserve for a\n * model that simply needed more room, and a reasoning-free rung at that reserve\n * for endpoints where thinking competes with the answer for the same tokens.\n */\nexport function outputLadderRungs(\n  request: Pick<CommitGenerationRequest, \"model\" | \"reasoning\">,\n  candidate: CommitEvidenceSpec,\n): WriterRung[] {\n  const analyst = candidate.representation === \"analyst\";\n  const reasoning = request.reasoning;\n  const reserve = candidate.outputReserve;\n  const rungs: WriterRung[] = [{ reserve, reasoning }];\n\n  const escalated = nextCommitOutputReserve(reserve, request.model, analyst);\n  if (escalated > reserve) rungs.push({ reserve: escalated, reasoning });\n\n  if (reasoning !== undefined && reasoning !== \"off\") {\n    rungs.push({ reserve: rungs[rungs.length - 1]?.reserve ?? reserve, reasoning: undefined });\n  }\n  return rungs;\n}\n\nexport interface CommitGenerationRequest extends CommitEvidenceRequest {\n  readonly signal?: AbortSignal | undefined;\n  /** Session thinking level; endpoints that mandate reasoning reject requests without it. */\n  readonly reasoning?: ModelThinkingLevel | undefined;\n}\n\nexport interface CommitGenerationDiagnostics {\n  readonly route: CommitRepresentation;\n  readonly intentIncluded: boolean;\n  readonly attempts: 1 | 2;\n  /** True when the message was recovered from a response the provider cut off. */\n  readonly truncated?: boolean | undefined;\n  readonly candidate: Pick<CommitEvidenceSpec, \"representation\" | \"estimatedInputTokens\" | \"inputBudget\" | \"outputReserve\" | \"safetyReserve\" | \"diffBytes\" | \"intentIncluded\">;\n  /** Total across every model call this generation made, analyst and retries included. */\n  readonly usage?: TokenTally | undefined;\n  /** Subset of `usage` spent on the analyst phase. */\n  readonly analystUsage?: TokenTally | undefined;\n}\n\nexport type CommitGenerationResult =\n  | {\n      readonly ok: true;\n      readonly message: string;\n      readonly subject: string;\n      readonly representation: CommitRepresentation;\n      readonly analysisUsed: boolean;\n      readonly intentIncluded: boolean;\n      readonly attempts: 1 | 2;\n      readonly diagnostics: CommitGenerationDiagnostics;\n    }\n  | {\n      readonly ok: false;\n      readonly code:\n        | \"context-too-small\"\n        | \"input-too-large\"\n        | \"provider-overflow\"\n        | \"analysis-invalid\"\n        | \"response-truncated\"\n        | \"invalid-response\"\n        | \"aborted\";\n      readonly reason: string;\n      readonly diagnostics?: Omit<Partial<CommitGenerationDiagnostics>, \"candidate\"> & {\n        readonly candidate?: CommitEvidenceSpec | undefined;\n      };\n    };\n\nexport class CommitMessageGenerator {\n  constructor(private readonly client: CommitModelClient) {}\n\n  async generate(request: CommitGenerationRequest): Promise<CommitGenerationResult> {\n    // One budget for the whole generation: every rung, route change, and\n    // evidence degradation below shares it, so a bad provider day cannot turn\n    // into an unbounded series of large requests.\n    const budget: WriterCallBudget = newCallBudget();\n    const result = await this.attemptGeneration(request, budget);\n    // A provider can still refuse reduced evidence (smaller effective context\n    // than the declared window). One bounded re-reduction attempt at half the\n    // bytes before giving up. Size pressure on an unreduced patch also gets one\n    // chance at an explicitly labeled skeleton projection.\n    if (!result.ok && result.code !== \"aborted\") {\n      const reduced = request.evidence.partial\n        ? reduceStagedEvidence(request.evidence, Math.floor(request.evidence.compactBytes / 2))\n        : sizePressureFailure(result.code)\n          ? degradeStagedEvidence(request.evidence)\n          : undefined;\n      if (reduced && budget.calls < budget.max) {\n        const retry = await this.attemptGeneration({ ...request, evidence: reduced }, budget);\n        // Keep the original, more specific failure unless the retry helped.\n        if (retry.ok || retry.code === \"aborted\") return retry;\n        return result;\n      }\n    }\n    return result;\n  }\n\n  private async attemptGeneration(request: CommitGenerationRequest, budget: WriterCallBudget): Promise<CommitGenerationResult> {\n    const evidenceRequest: CommitEvidenceRequest = {\n      model: request.model,\n      evidence: request.evidence,\n      style: request.style,\n      ...(request.intent === undefined ? {} : { intent: request.intent }),\n      ...(request.operation === undefined ? {} : { operation: request.operation }),\n      ...(request.reasoning === undefined ? {} : { reasoning: request.reasoning }),\n    };\n    const plan = planCommitEvidence(evidenceRequest);\n    if (plan.failure) {\n      return {\n        ok: false,\n        code: plan.failure.code,\n        reason: plan.failure.reason,\n        ...(plan.failure.diagnostics === undefined ? {} : { diagnostics: { candidate: plan.failure.diagnostics } }),\n      };\n    }\n\n    const selected = plan.selected;\n    if (!selected) {\n      return { ok: false, code: \"input-too-large\", reason: \"No complete commit evidence candidate was available.\" };\n    }\n\n    const route = routeForCandidate(selected);\n    if (route === \"analyst-assisted\") {\n      return this.generateWithAnalyst(request, evidenceRequest, plan, selected, budget);\n    }\n    return this.generateDirect(request, evidenceRequest, plan, selected, budget);\n  }\n\n  private async generateDirect(\n    request: CommitGenerationRequest,\n    evidenceRequest: CommitEvidenceRequest,\n    plan: CommitEvidencePlan,\n    selectedSpec: CommitEvidenceSpec,\n    budget: WriterCallBudget,\n  ): Promise<CommitGenerationResult> {\n    const attempted: CommitEvidenceSpec[] = [selectedSpec];\n    let spec = selectedSpec;\n    let candidate = materializeCandidate(evidenceRequest, spec);\n    let outcome = await this.runOutputLadder(request, candidate, budget);\n\n    // Less input only ever remedies input pressure: a provider refusal, or a\n    // reply that died because the prompt crowded the window. A writer that just\n    // needed more output tokens is served by the ladder, not by a cheaper\n    // representation, but shrinking the prompt stays a useful last resort.\n    const inputPressure = outcome.kind === \"overflow\"\n      || outcome.kind === \"truncated\"\n      || (outcome.kind === \"failed\" && outcome.failure.code === \"provider-overflow\");\n    if (inputPressure && budget.calls < budget.max) {\n      const retry = findCheaperCandidate(plan.candidates, spec);\n      if (retry) {\n        attempted.push(retry);\n        spec = retry;\n        candidate = materializeCandidate(evidenceRequest, retry);\n        outcome = await this.runOutputLadder(request, candidate, budget);\n      }\n    }\n\n    const attempts = attempted.length as 1 | 2;\n    if (outcome.kind === \"failed\") return outcome.failure;\n    if (outcome.kind === \"overflow\") {\n      return this.responseFailure(outcome.response, candidate, request, attempts, budget);\n    }\n    if (outcome.kind === \"truncated\") {\n      return this.truncationFailure(outcome.response, candidate, request, attempts, budget);\n    }\n\n    const response = outcome.response;\n    const validation: CommitMessageValidation = outcome.salvage\n      ? { ok: true, message: outcome.salvage.message, subject: outcome.salvage.subject }\n      : validateGeneratedResponse(response);\n    if (!validation.ok) {\n      return this.validationFailure(validation, response, candidate, request, attempts, budget);\n    }\n\n    return this.okResult(request, candidate, validation, budget, {\n      attempts,\n      analysisUsed: false,\n      truncated: outcome.salvage !== undefined,\n      response,\n    });\n  }\n\n  private async generateWithAnalyst(\n    request: CommitGenerationRequest,\n    evidenceRequest: CommitEvidenceRequest,\n    plan: CommitEvidencePlan,\n    analystSpec: CommitEvidenceSpec,\n    budget: WriterCallBudget,\n  ): Promise<CommitGenerationResult> {\n    const analystCandidate = materializeCandidate(evidenceRequest, analystSpec);\n    const analystOutcome = await this.runOutputLadder(request, analystCandidate, budget, { reserveForNext: ANALYST_WRITER_RESERVE_CALLS, analystPhase: true });\n    if (analystOutcome.kind === \"failed\") return analystOutcome.failure;\n    if (analystOutcome.kind === \"overflow\") {\n      return this.responseFailure(analystOutcome.response, analystCandidate, request, 1, budget);\n    }\n    if (analystOutcome.kind === \"truncated\") {\n      return this.truncationFailure(analystOutcome.response, analystCandidate, request, 1, budget);\n    }\n\n    const analystResponse = analystOutcome.response;\n    const analysisResult = parseDiffAnalysisResponse(analystResponse, request.evidence);\n    if (!analysisResult.ok) {\n      return {\n        ok: false,\n        code: \"analysis-invalid\",\n        reason: analysisResult.reason,\n        diagnostics: {\n          route: \"analyst-assisted\",\n          intentIncluded: false,\n          attempts: 1,\n          candidate: analystCandidate,\n          analystUsage: budget.analystTally.totals,\n        },\n      };\n    }\n\n    const finalCandidates = candidateForAnalysisFinal(evidenceRequest, analysisResult.analysis);\n    const finalSpec = finalCandidates.withIntent.fits\n      ? finalCandidates.withIntent\n      : finalCandidates.withoutIntent.fits\n        ? finalCandidates.withoutIntent\n        : undefined;\n    if (!finalSpec) {\n      return {\n        ok: false,\n        code: \"input-too-large\",\n        reason: \"The validated analysis and final commit prompt do not fit the selected model. Stage a smaller change or select a larger-context model.\",\n        diagnostics: {\n          route: \"analyst-assisted\",\n          intentIncluded: false,\n          attempts: 1,\n          candidate: finalCandidates.withoutIntent,\n          analystUsage: budget.analystTally.totals,\n        },\n      };\n    }\n\n    const finalCandidate = materializeCandidate(evidenceRequest, finalSpec);\n    const finalOutcome = await this.runOutputLadder(request, finalCandidate, budget);\n    if (finalOutcome.kind === \"failed\") return finalOutcome.failure;\n    if (finalOutcome.kind === \"overflow\") {\n      return this.responseFailure(finalOutcome.response, finalCandidate, request, 2, budget, analystResponse);\n    }\n    if (finalOutcome.kind === \"truncated\") {\n      return this.truncationFailure(finalOutcome.response, finalCandidate, request, 2, budget, analystResponse);\n    }\n\n    const finalResponse = finalOutcome.response;\n    const finalValidation: CommitMessageValidation = finalOutcome.salvage\n      ? { ok: true, message: finalOutcome.salvage.message, subject: finalOutcome.salvage.subject }\n      : validateGeneratedResponse(finalResponse);\n    if (!finalValidation.ok) {\n      return this.validationFailure(finalValidation, finalResponse, finalCandidate, request, 2, budget, analystResponse);\n    }\n\n    return this.okResult(request, finalCandidate, finalValidation, budget, {\n      attempts: 2,\n      analysisUsed: true,\n      truncated: finalOutcome.salvage !== undefined,\n      response: finalResponse,\n      analystResponse,\n    });\n  }\n\n  /** Assemble the successful result, including its route diagnostics. */\n  private okResult(\n    request: CommitGenerationRequest,\n    candidate: CommitEvidenceSpec,\n    validation: Extract<CommitMessageValidation, { ok: true }>,\n    budget: WriterCallBudget,\n    meta: {\n      readonly attempts: 1 | 2;\n      readonly analysisUsed: boolean;\n      readonly truncated: boolean;\n      readonly response: AssistantMessage;\n      readonly analystResponse?: AssistantMessage | undefined;\n    },\n  ): Extract<CommitGenerationResult, { ok: true }> {\n    const representation = routeForCandidate(candidate);\n    return {\n      ok: true,\n      message: validation.message,\n      subject: validation.subject,\n      representation,\n      analysisUsed: meta.analysisUsed,\n      intentIncluded: candidate.intentIncluded,\n      attempts: meta.attempts,\n      diagnostics: {\n        route: representation,\n        intentIncluded: candidate.intentIncluded,\n        attempts: meta.attempts,\n        ...(meta.truncated ? { truncated: true } : {}),\n        candidate: candidateDiagnostics(candidate),\n        usage: budget.tally.totals,\n        ...(meta.analystResponse === undefined ? {} : { analystUsage: budget.analystTally.totals }),\n      },\n    };\n  }\n\n  /**\n   * Run one prompt through as many output budgets as the call budget allows.\n   * A `length` stop means the provider cut the reply at `max_tokens`, which is\n   * pi-git's own choice, so escalate instead of failing: keep whatever the\n   * model already finished, then retry with a bigger budget, then without\n   * reasoning when reasoning tokens ate the whole completion budget.\n   *\n   * `reserveForNext` keeps room for a later phase, so an analyst that keeps\n   * truncating cannot starve the writer that still has to run.\n   */\n  private async runOutputLadder(\n    request: CommitGenerationRequest,\n    candidate: CommitEvidenceCandidate,\n    budget: WriterCallBudget,\n    options: { readonly reserveForNext?: number; readonly analystPhase?: boolean } = {},\n  ): Promise<WriterOutcome> {\n    const reserveForNext = options.reserveForNext ?? 0;\n    const phaseTally = options.analystPhase ? budget.analystTally : undefined;\n    // Only the writer route is worth salvaging; analyst JSON cannot be repaired\n    // line by line, so it just walks the budget rungs.\n    const salvage = candidate.representation !== \"analyst\";\n    // Leave room for a later phase, but never starve this one entirely.\n    const remaining = budget.max - budget.calls - reserveForNext;\n    const rungs = outputLadderRungs(request, candidate).slice(0, Math.max(1, remaining));\n    let lastTruncated: AssistantMessage | undefined;\n    for (const rung of rungs) {\n      if (budget.calls >= budget.max) break;\n      budget.calls += 1;\n      const result = await this.completeCandidate(request, candidate, rung);\n      if (!result.ok) {\n        if (result.failure.code === \"aborted\" || !lastTruncated) return { kind: \"failed\", failure: result.failure };\n        // A later rung that errors must not discard what an earlier one produced.\n        break;\n      }\n      const response = result.response;\n      // Every call lands on the whole-generation bill; the analyst phase is\n      // also reported as its own subset.\n      budget.tally.add(response.usage);\n      phaseTally?.add(response.usage);\n\n      if (isContextOverflow(response, modelContextWindow(request.model) ?? 0)) {\n        return { kind: \"overflow\", response };\n      }\n      if (response.stopReason !== \"length\") {\n        return { kind: \"success\", response };\n      }\n\n      if (salvage) {\n        const text = assistantText(response);\n        if (text) {\n          // A finished subject plus finished body lines is a usable commit.\n          const recovered = salvageTruncatedCommitMessage(text, { requireBody: true });\n          if (recovered) return { kind: \"success\", response, salvage: recovered };\n        }\n      }\n      lastTruncated = response;\n    }\n\n    if (lastTruncated) {\n      if (salvage) {\n        const text = assistantText(lastTruncated);\n        const recovered = text ? salvageTruncatedCommitMessage(text, { requireBody: false }) : undefined;\n        if (recovered) return { kind: \"success\", response: lastTruncated, salvage: recovered };\n      }\n      return { kind: \"truncated\", response: lastTruncated };\n    }\n    return { kind: \"failed\", failure: { ok: false, code: \"invalid-response\", reason: \"The commit generation call budget was exhausted before this prompt could run.\" } };\n  }\n\n  private async completeCandidate(\n    request: CommitGenerationRequest,\n    candidate: CommitEvidenceCandidate,\n    rung: WriterRung = { reserve: candidate.outputReserve, reasoning: request.reasoning },\n  ): Promise<\n    | { readonly ok: true; readonly response: AssistantMessage }\n    | { readonly ok: false; readonly failure: Extract<CommitGenerationResult, { ok: false }> }\n  > {\n    if (request.signal?.aborted) {\n      return { ok: false, failure: { ok: false, code: \"aborted\", reason: \"Commit message generation was cancelled.\" } };\n    }\n    try {\n      const response = await this.client.complete(\n        request.model,\n        { systemPrompt: candidate.systemPrompt, messages: [candidate.userMessage], tools: [] },\n        {\n          maxTokens: rung.reserve,\n          ...(request.signal === undefined ? {} : { signal: request.signal }),\n          ...reasoningOptions(rung.reasoning),\n        },\n      );\n      return { ok: true, response };\n    } catch (error: unknown) {\n      if (request.signal?.aborted || isAbortError(error)) {\n        return { ok: false, failure: { ok: false, code: \"aborted\", reason: \"Commit message generation was cancelled.\" } };\n      }\n      const reason = error instanceof Error ? error.message : String(error);\n      return {\n        ok: false,\n        failure: {\n          ok: false,\n          code: isOverflowError(reason) ? \"provider-overflow\" : \"invalid-response\",\n          reason: `Commit message model request failed: ${reason}`,\n          diagnostics: { candidate },\n        },\n      };\n    }\n  }\n\n  private responseFailure(\n    response: AssistantMessage,\n    candidate: CommitEvidenceSpec,\n    request: CommitGenerationRequest,\n    attempts: 1 | 2,\n    budget: WriterCallBudget,\n    analystResponse?: AssistantMessage,\n  ): Extract<CommitGenerationResult, { ok: false }> {\n    const overflow = isContextOverflow(response, modelContextWindow(request.model) ?? 0);\n    const detail = response.errorMessage\n      ? ` Provider error: ${response.errorMessage.length > 400 ? `${response.errorMessage.slice(0, 400)}…` : response.errorMessage}`\n      : \"\";\n    return {\n      ok: false,\n      code: overflow ? \"provider-overflow\" : \"response-truncated\",\n      reason: overflow\n        ? `The provider reported that the commit evidence exceeded its context window. Stage a smaller change or select a larger-context model.${detail}`\n        : `The commit message response was truncated before a complete message was produced.${detail}`,\n      diagnostics: {\n        route: routeForCandidate(candidate),\n        intentIncluded: candidate.intentIncluded,\n        attempts,\n        candidate,\n        usage: budget.tally.totals,\n        ...(analystResponse === undefined ? {} : { analystUsage: budget.analystTally.totals }),\n      },\n    };\n  }\n\n  /** The output budget ran out even after escalation: say so precisely. */\n  private truncationFailure(\n    response: AssistantMessage,\n    candidate: CommitEvidenceSpec,\n    request: CommitGenerationRequest,\n    attempts: 1 | 2,\n    budget: WriterCallBudget,\n    analystResponse?: AssistantMessage,\n  ): Extract<CommitGenerationResult, { ok: false }> {\n    const detail = response.errorMessage\n      ? ` Provider error: ${response.errorMessage.length > 400 ? `${response.errorMessage.slice(0, 400)}…` : response.errorMessage}`\n      : \"\";\n    return {\n      ok: false,\n      code: \"response-truncated\",\n      reason: `The model used its entire ${candidate.outputReserve}-token output budget without finishing a commit message. Retry, stage a smaller change, or select a model with a larger output budget.${detail}`,\n      diagnostics: {\n        route: routeForCandidate(candidate),\n        intentIncluded: candidate.intentIncluded,\n        attempts,\n        candidate,\n        usage: budget.tally.totals,\n        ...(analystResponse === undefined ? {} : { analystUsage: budget.analystTally.totals }),\n      },\n    };\n  }\n\n  private validationFailure(\n    validation: Exclude<CommitMessageValidation, { ok: true }>,\n    response: AssistantMessage,\n    candidate: CommitEvidenceSpec,\n    request: CommitGenerationRequest,\n    attempts: 1 | 2,\n    budget: WriterCallBudget,\n    analystResponse?: AssistantMessage,\n  ): Extract<CommitGenerationResult, { ok: false }> {\n    return {\n      ok: false,\n      code: response.stopReason === \"length\" ? \"response-truncated\" : \"invalid-response\",\n      reason: validation.reason,\n      diagnostics: {\n        route: routeForCandidate(candidate),\n        intentIncluded: candidate.intentIncluded,\n        attempts,\n        candidate,\n        usage: budget.tally.totals,\n        ...(analystResponse === undefined ? {} : { analystUsage: budget.analystTally.totals }),\n      },\n    };\n  }\n}\n\nexport async function generateCommitMessage(\n  client: CommitModelClient,\n  request: CommitGenerationRequest,\n): Promise<CommitGenerationResult> {\n  return new CommitMessageGenerator(client).generate(request);\n}\n\nfunction sizePressureFailure(code: Extract<CommitGenerationResult, { ok: false }>[\"code\"]): boolean {\n  return code === \"provider-overflow\" || code === \"input-too-large\" || code === \"context-too-small\" || code === \"response-truncated\";\n}\n\nfunction findCheaperCandidate(\n  candidates: readonly CommitEvidenceSpec[],\n  selected: CommitEvidenceSpec,\n): CommitEvidenceSpec | undefined {\n  const selectedIndex = candidates.indexOf(selected);\n  return candidates.slice(selectedIndex + 1).find((candidate) =>\n    candidate.fits\n    && candidate.representation !== \"analyst\"\n    && candidate.representation !== \"analysis-final\"\n    && candidate.estimatedInputTokens < selected.estimatedInputTokens\n    && (!candidate.intentIncluded || !selected.intentIncluded),\n  );\n}\n\nfunction routeForCandidate(candidate: CommitEvidenceSpec): CommitRepresentation {\n  if (candidate.representation === \"analyst\" || candidate.representation === \"analysis-final\") return \"analyst-assisted\";\n  return candidate.representation;\n}\n\nfunction candidateDiagnostics(candidate: CommitEvidenceSpec): CommitGenerationDiagnostics[\"candidate\"] {\n  return {\n    representation: candidate.representation,\n    estimatedInputTokens: candidate.estimatedInputTokens,\n    inputBudget: candidate.inputBudget,\n    outputReserve: candidate.outputReserve,\n    safetyReserve: candidate.safetyReserve,\n    diffBytes: candidate.diffBytes,\n    intentIncluded: candidate.intentIncluded,\n  };\n}\n\n/**\n * Positive thinking levels map to both the uniform and the openai-completions\n * effort option, capped at \"low\": commit messages are simple generation tasks\n * and heavy reasoning dominates latency on reasoning-mandatory endpoints.\n */\nfunction reasoningOptions(level: CommitGenerationRequest[\"reasoning\"]):\n  | { reasoning?: ThinkingLevel; reasoningEffort?: ThinkingLevel }\n  | {} {\n  if (level === undefined || level === \"off\") return {};\n  const capped: ThinkingLevel = level === \"minimal\" ? \"minimal\" : \"low\";\n  return { reasoning: capped, reasoningEffort: capped };\n}\n\nexport type ParsedDiffAnalysis =\n  | { readonly ok: true; readonly analysis: DiffAnalysis }\n  | { readonly ok: false; readonly reason: string };\n\n/** Validate analyst JSON and exact manifest coverage before it reaches synthesis. */\nexport function parseDiffAnalysisResponse(response: AssistantMessage, evidence: StagedEvidence): ParsedDiffAnalysis {\n  if (response.stopReason !== \"stop\") return { ok: false, reason: `Analyst stopped with ${response.stopReason}, not stop.` };\n  const text = assistantText(response);\n  if (text === undefined) return { ok: false, reason: \"The analyst returned no plain-text JSON.\" };\n  if (Buffer.byteLength(text, \"utf8\") > MAX_ANALYSIS_BYTES) return { ok: false, reason: \"The analyst response exceeds the bounded analysis size.\" };\n  if (text.includes(\"\\0\") || text.trimStart().startsWith(\"```\") || text.trimEnd().endsWith(\"```\")) {\n    return { ok: false, reason: \"The analyst response must be raw JSON without fences or NUL bytes.\" };\n  }\n\n  let value: unknown;\n  try {\n    value = JSON.parse(text);\n  } catch {\n    return { ok: false, reason: \"The analyst response is not valid JSON.\" };\n  }\n  if (!isRecord(value)) return { ok: false, reason: \"The analyst response must be a JSON object.\" };\n\n  const keys = Object.keys(value);\n  if (keys.some((key) => ![\"version\", \"coveredFileKeys\", \"overview\", \"areas\", \"unresolved\"].includes(key))) {\n    return { ok: false, reason: \"The analyst response contains unknown fields.\" };\n  }\n  if (value.version !== 1) return { ok: false, reason: \"The analyst response has an unsupported version.\" };\n  if (!Array.isArray(value.coveredFileKeys) || !value.coveredFileKeys.every((key): key is string => typeof key === \"string\")) {\n    return { ok: false, reason: \"The analyst coveredFileKeys field is invalid.\" };\n  }\n  if (new Set(value.coveredFileKeys).size !== value.coveredFileKeys.length) {\n    return { ok: false, reason: \"The analyst coveredFileKeys field contains duplicates.\" };\n  }\n  const expectedKeys = evidence.files.map((file) => file.key);\n  if (!sameStringSet(value.coveredFileKeys, expectedKeys)) {\n    return { ok: false, reason: \"The analyst did not cover exactly the staged manifest paths.\" };\n  }\n  if (typeof value.overview !== \"string\" || !value.overview.trim()) return { ok: false, reason: \"The analyst overview is empty.\" };\n  if (typeof value.areas !== \"object\" || !Array.isArray(value.areas)) return { ok: false, reason: \"The analyst areas field is invalid.\" };\n  if (typeof value.unresolved !== \"object\" || !Array.isArray(value.unresolved) || !value.unresolved.every((item): item is string => typeof item === \"string\")) {\n    return { ok: false, reason: \"The analyst unresolved field is invalid.\" };\n  }\n\n  const allowed = new Set(expectedKeys);\n  const areas: DiffAnalysisArea[] = [];\n  const areaPaths = new Set<string>();\n  for (const area of value.areas) {\n    if (!isRecord(area) || Object.keys(area).some((key) => ![\"paths\", \"summary\"].includes(key))) {\n      return { ok: false, reason: \"The analyst contains an invalid area.\" };\n    }\n    if (!Array.isArray(area.paths) || !area.paths.every((path): path is string => typeof path === \"string\" && allowed.has(path))) {\n      return { ok: false, reason: \"The analyst area references an unknown manifest path.\" };\n    }\n    if (area.paths.length === 0 || typeof area.summary !== \"string\" || !area.summary.trim()) {\n      return { ok: false, reason: \"The analyst contains an empty area.\" };\n    }\n    for (const path of area.paths) {\n      if (areaPaths.has(path)) return { ok: false, reason: \"The analyst assigns a manifest path to more than one area.\" };\n      areaPaths.add(path);\n    }\n    areas.push({ paths: [...area.paths], summary: area.summary });\n  }\n  if (!sameStringSet([...areaPaths], expectedKeys)) {\n    return { ok: false, reason: \"The analyst areas do not cover every manifest path exactly once.\" };\n  }\n\n  const unresolved = [...value.unresolved];\n  const allText = JSON.stringify({ overview: value.overview, areas, unresolved });\n  if (containsAuthorizationLanguage(allText)) {\n    return { ok: false, reason: \"The analyst response contains authorization or commit-message language.\" };\n  }\n  if (Buffer.byteLength(allText, \"utf8\") > MAX_ANALYSIS_BYTES) return { ok: false, reason: \"The validated analysis exceeds the bounded size.\" };\n\n  return {\n    ok: true,\n    analysis: {\n      version: 1,\n      coveredFileKeys: [...value.coveredFileKeys],\n      overview: value.overview,\n      areas,\n      unresolved,\n    },\n  };\n}\n\nfunction validateGeneratedResponse(response: AssistantMessage): CommitMessageValidation {\n  const validation = validateCommitResponse(response);\n  if (validation.ok || validation.code !== \"subject-too-large\") return validation;\n\n  const text = assistantText(response);\n  if (text === undefined) return validation;\n  const shortened = shortenCommitMessageSubject(text);\n  if (shortened === text) return validation;\n\n  // The model contract asks for this already. Keep the strict validator for\n  // callers that need to inspect raw output, but make generation resilient when\n  // a model ignores the byte limit.\n  return validateCommitResponse({\n    ...response,\n    content: [{ type: \"text\", text: shortened }],\n  });\n}\n\nfunction assistantText(response: AssistantMessage): string | undefined {\n  const parts: string[] = [];\n  for (const part of response.content) {\n    if (part.type === \"toolCall\") return undefined;\n    if (part.type === \"text\") parts.push(part.text);\n  }\n  const text = parts.join(\"\\n\").trim();\n  return text || undefined;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n  return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction sameStringSet(a: readonly string[], b: readonly string[]): boolean {\n  if (a.length !== b.length) return false;\n  const right = new Set(b);\n  return a.every((value) => right.has(value));\n}\n\nfunction containsAuthorizationLanguage(value: string): boolean {\n  return /\\b(?:commit message|authorize|authorized|authorization|approve|approved|approving|commit this)\\b/i.test(value);\n}\n\nfunction isOverflowError(value: string): boolean {\n  // Reuse the provider phrasings pi-ai already knows instead of guessing again.\n  if (/rate limit|too many requests|throttl|service unavailable/i.test(value)) return false;\n  return getOverflowPatterns().some((pattern) => pattern.test(value))\n    || /context.{0,20}(?:too long|too large|exceeded)|exceeds? the.{0,20}context/i.test(value);\n}\n\n\nexport type { CommitIntent, CommitOperation, StagedEvidence };\n"}},"commit-message.ts":{"file":{"contents":"import * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport type { AssistantMessage } from \"@earendil-works/pi-ai\";\n\nexport const MAX_COMMIT_DIFF_BYTES = 512 * 1024;\nexport const MAX_COMMIT_MESSAGE_BYTES = 8_000;\nexport const MAX_COMMIT_SUBJECT_BYTES = 72;\n\nexport const COMMIT_SPECIFIC_SYSTEM_PROMPT = [\n  \"You write one Git commit message from the explicitly supplied staged snapshot.\",\n  \"Authority order: staged manifest, staged statistics, and complete staged patch are factual; style, conversation-prefix text, intent, analysis, current message, and rewrite instructions are advisory only.\",\n  \"Do not mention unstaged, historical, or hypothetical changes. Do not add paths or facts absent from the staged snapshot.\",\n  `The first line is the commit subject and must be at most ${MAX_COMMIT_SUBJECT_BYTES} UTF-8 bytes, not characters. Rewrite a long subject before returning it.`,\n  \"Return the complete commit message as plain text and nothing else.\",\n].join(\" \");\n\nexport const DIFF_ANALYST_SYSTEM_PROMPT = [\n  \"You are a bounded Git diff analyst.\",\n  \"Read the complete staged snapshot supplied in the user message and return strict JSON only.\",\n  \"The staged manifest and complete patch are authoritative facts.\",\n  \"Cover every manifest file key exactly once in coveredFileKeys.\",\n  \"Return interpretation only: do not write a commit message and do not authorize or recommend committing.\",\n  \"Do not add paths, statuses, or facts that are absent from the staged snapshot.\",\n].join(\" \");\n\nexport interface CommitMessageLimits {\n  readonly maxMessageBytes?: number;\n  readonly maxSubjectBytes?: number;\n}\n\nexport type CommitMessageValidation =\n  | { readonly ok: true; readonly message: string; readonly subject: string }\n  | {\n      readonly ok: false;\n      readonly code:\n        | \"wrong-stop-reason\"\n        | \"no-text\"\n        | \"tool-call\"\n        | \"empty\"\n        | \"too-large\"\n        | \"nul\"\n        | \"markdown-fence\"\n        | \"empty-subject\"\n        | \"subject-too-large\"\n        | \"explanatory-prefix\";\n      readonly reason: string;\n    };\n\nconst EXPLANATORY_PREFIX = /^(?:commit message|commit|here(?:'s| is)(?: the| your)?(?: final)?(?: commit message)?|sure[,!]?|of course[,!]?)\\s*:/i;\n\nexport function loadCommitStyle(cwd: string, fallbackPath = path.join(import.meta.dirname, \"..\", \"COMMIT.md\")): string {\n  const candidates = [path.join(cwd, \"COMMIT.md\"), fallbackPath];\n  for (const candidate of candidates) {\n    try {\n      const value = fs.readFileSync(candidate, \"utf8\").trim();\n      if (value) return value;\n    } catch {\n      // The bundled style is optional. The caller receives the short fallback below.\n    }\n  }\n  return \"Use a concise Conventional Commit message. Keep the subject imperative, lowercase, and under 72 bytes. Output only the final message.\";\n}\n\n/**\n * Keep a generated subject within the Git message convention without splitting\n * a UTF-8 character. Prefer a complete-word boundary, but make progress even\n * when a subject contains one unusually long token.\n */\nexport function shortenCommitMessageSubject(\n  message: string,\n  maxSubjectBytes = MAX_COMMIT_SUBJECT_BYTES,\n): string {\n  const normalized = message.trim();\n  const lines = normalized.split(\"\\n\");\n  const subject = (lines[0] ?? \"\").trim();\n  if (!subject || Buffer.byteLength(subject, \"utf8\") <= maxSubjectBytes) return normalized;\n\n  const characters = Array.from(subject);\n  let characterCount = 0;\n  let shortened = \"\";\n  for (const character of characters) {\n    const candidate = shortened + character;\n    if (Buffer.byteLength(candidate, \"utf8\") > maxSubjectBytes) break;\n    shortened = candidate;\n    characterCount += 1;\n  }\n\n  // If the byte limit cut through a word, remove that partial word. When the\n  // next character is whitespace, the limit already landed on a boundary.\n  const nextCharacter = characters[characterCount];\n  if (nextCharacter !== undefined && !/\\s/.test(nextCharacter)) {\n    const wordBoundary = shortened.search(/\\s[^\\s]*$/);\n    if (wordBoundary > 0) shortened = shortened.slice(0, wordBoundary).trimEnd();\n  }\n  lines[0] = shortened;\n  return lines.join(\"\\n\").trim();\n}\n\nexport function validateCommitResponse(\n  response: AssistantMessage,\n  limits: CommitMessageLimits = {},\n): CommitMessageValidation {\n  if (response.stopReason !== \"stop\") {\n    const detail = response.errorMessage\n      ? `: ${response.errorMessage.length > 400 ? `${response.errorMessage.slice(0, 400)}…` : response.errorMessage}`\n      : \".\";\n    return {\n      ok: false,\n      code: \"wrong-stop-reason\",\n      reason: `Model stopped with ${response.stopReason}, not stop${detail}`,\n    };\n  }\n\n  const textParts: string[] = [];\n  for (const part of response.content) {\n    if (part.type === \"toolCall\") {\n      return {\n        ok: false,\n        code: \"tool-call\",\n        reason: \"The model returned a tool call instead of a commit message.\",\n      };\n    }\n    if (part.type === \"text\") textParts.push(part.text);\n  }\n\n  if (textParts.length === 0) {\n    return { ok: false, code: \"no-text\", reason: \"The model returned no text.\" };\n  }\n\n  return validateCommitMessageText(textParts.join(\"\\n\"), limits);\n}\n\n/** Validate commit message text without inspecting the model stop reason. */\nexport function validateCommitMessageText(\n  raw: string,\n  limits: CommitMessageLimits = {},\n): CommitMessageValidation {\n  const message = raw.trim();\n  if (!message) return { ok: false, code: \"empty\", reason: \"The model returned an empty commit message.\" };\n  if (message.includes(\"\\0\")) return { ok: false, code: \"nul\", reason: \"The commit message contains a NUL byte.\" };\n\n  const maxMessageBytes = limits.maxMessageBytes ?? MAX_COMMIT_MESSAGE_BYTES;\n  if (Buffer.byteLength(message, \"utf8\") > maxMessageBytes) {\n    return {\n      ok: false,\n      code: \"too-large\",\n      reason: `The commit message exceeds the ${maxMessageBytes}-byte limit.`,\n    };\n  }\n\n  const lines = message.split(\"\\n\");\n  const firstLine = lines[0] ?? \"\";\n  const lastLine = lines[lines.length - 1] ?? \"\";\n  if (firstLine.trimStart().startsWith(\"```\") || lastLine.trimEnd().endsWith(\"```\")) {\n    return {\n      ok: false,\n      code: \"markdown-fence\",\n      reason: \"The commit message is wrapped in a Markdown fence.\",\n    };\n  }\n\n  if (EXPLANATORY_PREFIX.test(firstLine.trim())) {\n    return {\n      ok: false,\n      code: \"explanatory-prefix\",\n      reason: \"The response starts with explanatory text instead of the commit subject.\",\n    };\n  }\n\n  const subject = firstLine.trim();\n  if (!subject) return { ok: false, code: \"empty-subject\", reason: \"The commit subject is empty.\" };\n\n  const maxSubjectBytes = limits.maxSubjectBytes ?? MAX_COMMIT_SUBJECT_BYTES;\n  if (Buffer.byteLength(subject, \"utf8\") > maxSubjectBytes) {\n    return {\n      ok: false,\n      code: \"subject-too-large\",\n      reason: `The commit subject exceeds the ${maxSubjectBytes}-byte limit.`,\n    };\n  }\n\n  return { ok: true, message, subject };\n}\n\nexport interface TruncatedCommitMessage {\n  readonly message: string;\n  readonly subject: string;\n  /** True when the body was discarded because only the subject survived. */\n  readonly subjectOnly: boolean;\n}\n\n/** A line that cannot end a real commit message: it opens the next thought. */\nfunction isDanglingLine(line: string): boolean {\n  const trimmed = line.trim();\n  if (!trimmed || /^[-*]$/.test(trimmed)) return true;\n  if (/[,;:([{&|]$/.test(trimmed)) return true;\n  return /\\b(?:and|or|with|to|of|for|in|that|which|because|the)\\s*$/i.test(trimmed);\n}\n\n/**\n * Recover a usable message from a response the provider cut off at the output\n * budget. The trailing line is assumed incomplete and dropped, so what remains\n * is text the model actually finished. Returns undefined when nothing safely\n * salvageable is present.\n */\nexport function salvageTruncatedCommitMessage(\n  text: string,\n  options: { readonly requireBody?: boolean } = {},\n): TruncatedCommitMessage | undefined {\n  let lines = text.replace(/\\r\\n?/g, \"\\n\").split(\"\\n\").map((line) => line.trimEnd());\n  lines = dropBlankLines(lines);\n  if (lines.length === 0) return undefined;\n\n  // Models that chatter before the payload put the explanation first.\n  while (lines.length > 0 && (isFenceLine(lines[0] ?? \"\") || EXPLANATORY_PREFIX.test((lines[0] ?? \"\").trim()))) {\n    lines = dropBlankLines(lines.slice(1));\n  }\n  if (lines.length === 0) return undefined;\n\n  const subject = shortenCommitMessageSubject(lines[0] ?? \"\").trim();\n  if (!subject || isDanglingLine(subject)) return undefined;\n\n  // The last emitted line is the one the provider cut mid-token, so drop it and\n  // keep only lines the model finished.\n  const body = lines.slice(1, -1);\n  while (body.length > 0) {\n    const last = body[body.length - 1] ?? \"\";\n    if (!last.trim() || isFenceLine(last) || isDanglingLine(last)) body.pop();\n    else break;\n  }\n  while (body.length > 0 && !(body[0] ?? \"\").trim()) body.shift();\n\n  if (body.length === 0 && options.requireBody) return undefined;\n  const assembled = assembleWithinByteLimit(subject, body);\n  const validation = validateCommitMessageText(assembled);\n  if (!validation.ok) return undefined;\n\n  return {\n    message: validation.message,\n    subject: validation.subject,\n    subjectOnly: body.length === 0,\n  };\n}\n\nfunction isFenceLine(line: string): boolean {\n  return /^\\s*```/.test(line);\n}\n\nfunction dropBlankLines(lines: readonly string[]): string[] {\n  const result = [...lines];\n  while (result.length > 0 && !result[result.length - 1]?.trim()) result.pop();\n  while (result.length > 0 && !result[0]?.trim()) result.shift();\n  return result;\n}\n\nfunction assembleWithinByteLimit(subject: string, body: readonly string[]): string {\n  const kept: string[] = [];\n  let used = Buffer.byteLength(subject, \"utf8\") + 2;\n  for (const line of body) {\n    used += Buffer.byteLength(line, \"utf8\") + 1;\n    if (used > MAX_COMMIT_MESSAGE_BYTES) break;\n    kept.push(line);\n  }\n  return kept.length === 0 ? subject : `${subject}\\n\\n${kept.join(\"\\n\")}`;\n}\n"}},"commit-workflow.ts":{"file":{"contents":"import type { Api, Model } from \"@earendil-works/pi-ai\";\nimport { BorderedLoader, type ExtensionAPI, type ExtensionContext } from \"@earendil-works/pi-coding-agent\";\nimport { captureStagedEvidence, snapshotCacheKey, type StagedEvidence } from \"./commit-evidence.js\";\nimport type { CommitRepresentation } from \"./evidence-plan.js\";\nimport {\n  CommitMessageGenerator,\n  type CommitGenerationRequest,\n  type CommitGenerationResult,\n  type CommitModelClient,\n} from \"./commit-generator.js\";\nimport { loadCommitStyle } from \"./commit-message.js\";\nimport { formattingOnlyMessage } from \"./mechanical-diff.js\";\nimport { TokenTallyCollector, formatUsageCostLine, type TokenTally } from \"./usage-format.js\";\nimport { snapshotsMatch, type GitMaybeSnapshot, type GitService } from \"./git-service.js\";\nimport { CommitEditor, type CommitEditorResult } from \"./ui/commit-editor.js\";\nconst GENERATION_TIMEOUT_MS = 180_000;\n\nexport interface ManualCommitOptions {\n  /** Commit this message straight away instead of opening the editor. */\n  readonly message?: string;\n  /** Draft shown when the editor opens. */\n  readonly prefill?: string;\n  /** Refuse to commit when the staged snapshot moved after the draft was made. */\n  readonly expectedSnapshot?: GitMaybeSnapshot;\n  readonly onMessageChange?: (message: string) => void;\n  readonly onEditorReady?: () => void;\n  /** Bills every model call this flow makes, rewrites included, so the notice can show the cost. */\n  readonly usage?: TokenTallyCollector;\n  /** Model used when rewriting a smart-commit draft. */\n  readonly model?: Model<Api>;\n}\n\nexport async function runManualCommit(\n  pi: ExtensionAPI,\n  ctx: ExtensionContext,\n  git: GitService,\n  options: ManualCommitOptions = {},\n): Promise<boolean> {\n  const { message: directMessage, prefill = \"\", expectedSnapshot, onMessageChange, onEditorReady, usage, model } = options;\n  let staged: StagedEvidence;\n  try {\n    staged = await captureStagedEvidence(git);\n  } catch (error: unknown) {\n    ctx.ui.notify(formatError(error), \"error\");\n    return false;\n  }\n  if (staged.files.length === 0 && !(await git.hasStagedChanges())) {\n    ctx.ui.notify(\"Nothing is staged for commit.\", \"warning\");\n    return false;\n  }\n\n  if (directMessage !== undefined) {\n    return commitDirect(ctx, git, directMessage, expectedSnapshot, usage);\n  }\n\n  let message = prefill;\n  let editorReadyFired = false;\n  while (true) {\n    const editorResult = await ctx.ui.custom<CommitEditorResult | undefined>(\n      (tui, theme, _keybindings, done) => {\n        const editor = new CommitEditor(tui, theme, staged.stat, message, done);\n        // The draft notice belongs to the draft, not to every editor re-open,\n        // so a rewrite must not replay the pre-rewrite text and cost.\n        if (onEditorReady && !editorReadyFired) {\n          editorReadyFired = true;\n          queueMicrotask(onEditorReady);\n        }\n        return editor;\n      },\n    );\n    if (!editorResult || editorResult.action === \"cancel\") {\n      ctx.ui.notify(\"Commit cancelled.\", \"info\");\n      return false;\n    }\n    message = editorResult.message;\n    if (!message) {\n      ctx.ui.notify(\"Commit message is empty.\", \"warning\");\n      continue;\n    }\n    if (editorResult.action === \"rewrite\") {\n      const rewritten = await rewriteMessage(\n        ctx,\n        git,\n        loadCommitStyle(ctx.cwd),\n        staged.snapshot,\n        message,\n        model ?? ctx.model as Model<Api> | undefined,\n      );\n      if (rewritten?.ok) {\n        message = rewritten.message;\n        usage?.merge(rewritten.diagnostics.usage);\n        onMessageChange?.(message);\n        staged = await captureStagedEvidence(git);\n      }\n      continue;\n    }\n    if (editorResult.action === \"graphite\") {\n      try {\n        const root = await git.root();\n        const result = await pi.exec(\"gt\", [\"create\", \"--message\", message, \"--no-interactive\"], { cwd: root, timeout: 120_000 });\n        if (result.code === 0) {\n          ctx.ui.notify(`Graphite committed\\n  ${firstLine(message)}${formatUsageCostLine(usage?.totals)}`, \"info\");\n          return true;\n        }\n        ctx.ui.notify(`Graphite failed: ${result.stderr || result.stdout}`, \"error\");\n      } catch (error: unknown) {\n        ctx.ui.notify(formatError(error), \"error\");\n      }\n      continue;\n    }\n\n    return commitDirect(ctx, git, message, expectedSnapshot, usage);\n  }\n}\n\nexport async function runAmendCommit(\n  ctx: ExtensionContext,\n  git: GitService,\n): Promise<boolean> {\n  let originalMessage: string;\n  let originalHead: string | undefined;\n  try {\n    originalHead = await git.readHead();\n    if (!originalHead) {\n      ctx.ui.notify(\"There is no commit to amend.\", \"warning\");\n      return false;\n    }\n    originalMessage = await git.headCommitMessage();\n  } catch (error: unknown) {\n    ctx.ui.notify(formatError(error), \"error\");\n    return false;\n  }\n\n  try {\n    if (await git.headCommitIsPushed()) {\n      const confirmed = await ctx.ui.confirm(\n        \"Amend pushed commit?\",\n        \"The latest commit is present on a remote. Amending it will rewrite history. Continue?\",\n      );\n      if (!confirmed) {\n        ctx.ui.notify(\"Amend cancelled.\", \"info\");\n        return false;\n      }\n    }\n  } catch (error: unknown) {\n    ctx.ui.notify(formatError(error), \"error\");\n    return false;\n  }\n\n  let message = originalMessage;\n  while (true) {\n    const editorResult = await ctx.ui.custom<CommitEditorResult | undefined>(\n      (tui, theme, _keybindings, done) => new CommitEditor(\n        tui,\n        theme,\n        \"\",\n        message,\n        done,\n        {\n          heading: \"Amend commit message\",\n          allowRewrite: false,\n          allowGraphite: false,\n          cursorAtStart: true,\n        },\n      ),\n    );\n    if (!editorResult || editorResult.action === \"cancel\") {\n      ctx.ui.notify(\"Amend cancelled.\", \"info\");\n      return false;\n    }\n    message = editorResult.message;\n    if (!message) {\n      ctx.ui.notify(\"Commit message is empty.\", \"warning\");\n      continue;\n    }\n\n    if (await git.readHead() !== originalHead) {\n      ctx.ui.notify(\"HEAD changed while editing; nothing was amended.\", \"warning\");\n      return false;\n    }\n    try {\n      await git.amendMessage(message);\n      ctx.ui.notify(`Amended\\n  ${firstLine(message)}`, \"info\");\n      return true;\n    } catch (error: unknown) {\n      ctx.ui.notify(formatError(error), \"error\");\n      return false;\n    }\n  }\n}\n\n/** Where a draft's text came from, so the notice can name it. */\ntype DraftRoute = CommitRepresentation | \"formatting-only\";\n\ninterface SmartDraft {\n  readonly message: string;\n  readonly snapshot: GitMaybeSnapshot;\n  readonly cacheKey: string;\n  readonly route: DraftRoute;\n  readonly truncated: boolean;\n  readonly usage: TokenTally | undefined;\n}\n\nexport class SmartCommitSession {\n  private draft: SmartDraft | undefined;\n\n  async run(\n    pi: ExtensionAPI,\n    ctx: ExtensionContext,\n    git: GitService,\n    commitStyle: string,\n    selectedModel?: Model<Api>,\n  ): Promise<\"committed\" | \"cancelled\" | \"started\"> {\n    ctx.ui.notify(\"Smart commit: started, generating draft...\", \"info\");\n    let staged: StagedEvidence;\n    try {\n      staged = await captureStagedEvidence(git);\n    } catch (error: unknown) {\n      ctx.ui.notify(formatError(error), \"error\");\n      return \"cancelled\";\n    }\n    if (staged.files.length === 0 && !(await git.hasStagedChanges())) {\n      ctx.ui.notify(\"Nothing is staged for commit.\", \"warning\");\n      return \"cancelled\";\n    }\n\n    const model = selectedModel ?? ctx.model as Model<Api> | undefined;\n    if (!model) {\n      ctx.ui.notify(\"No model selected. Select a model before generating a commit draft.\", \"error\");\n      return \"cancelled\";\n    }\n\n    const cacheKey = snapshotCacheKey(staged.snapshot, model, commitStyle);\n    let draft = this.draft;\n    if (!draft || draft.cacheKey !== cacheKey) {\n      draft = await this.createDraft(ctx, model, staged, commitStyle, cacheKey);\n      if (!draft) return \"cancelled\";\n      this.draft = draft;\n    }\n\n    const current = await git.maybeSnapshot();\n    if (!snapshotsMatch(draft.snapshot, current)) {\n      this.draft = undefined;\n      ctx.ui.notify(`The staged snapshot changed; the commit draft was discarded.${formatUsageCostLine(draft.usage)}`, \"warning\");\n      return \"started\";\n    }\n\n    const editorText = ctx.ui.getEditorText();\n    const usage = new TokenTallyCollector();\n    usage.merge(draft.usage);\n    try {\n      const committed = await runManualCommit(pi, ctx, git, {\n        prefill: draft.message,\n        expectedSnapshot: draft.snapshot,\n        onMessageChange: (message) => {\n          if (this.draft) this.draft = { ...this.draft, message };\n        },\n        onEditorReady: () => notifySmartDraftReady(ctx, draft),\n        usage,\n        model,\n      });\n      if (committed) {\n        this.draft = undefined;\n        return \"committed\";\n      }\n      return \"cancelled\";\n    } finally {\n      await new Promise<void>((resolve) => setTimeout(resolve, 0));\n      ctx.ui.setEditorText(editorText);\n    }\n  }\n\n  /**\n   * Draft the same way quick commit does: the staged snapshot, the project's\n   * commit style, and nothing inferred from the conversation.\n   */\n  private async createDraft(\n    ctx: ExtensionContext,\n    model: Model<Api>,\n    staged: StagedEvidence,\n    commitStyle: string,\n    cacheKey: string,\n  ): Promise<SmartDraft | undefined> {\n    const formattingOnly = formattingOnlyMessage(staged.files, staged.compactPatch);\n    if (formattingOnly) {\n      return {\n        message: formattingOnly.message,\n        snapshot: staged.snapshot,\n        cacheKey,\n        route: \"formatting-only\",\n        truncated: false,\n        usage: undefined,\n      };\n    }\n    if (ctx.modelRegistry.hasConfiguredAuth && !ctx.modelRegistry.hasConfiguredAuth(model)) {\n      ctx.ui.notify(\"The selected model has no available authentication.\", \"error\");\n      return undefined;\n    }\n\n    const generated = await generateWithLoader(ctx, {\n      model,\n      evidence: staged,\n      style: commitStyle,\n      ...(ctx.thinkingLevel === undefined ? {} : { reasoning: ctx.thinkingLevel }),\n    });\n    if (!generated) return undefined;\n    if (!generated.ok) {\n      ctx.ui.notify(formatGenerationFailure(\"Commit draft\", generated), \"error\");\n      return undefined;\n    }\n    return {\n      message: generated.message,\n      snapshot: staged.snapshot,\n      cacheKey,\n      route: generated.diagnostics.route,\n      truncated: generated.diagnostics.truncated === true,\n      usage: generated.diagnostics.usage,\n    };\n  }\n\n  clear(): void {\n    this.draft = undefined;\n    // The next run will regenerate even when the Git snapshot is unchanged.\n  }\n}\n\nasync function rewriteMessage(\n  ctx: ExtensionContext,\n  git: GitService,\n  style: string,\n  expectedSnapshot: GitMaybeSnapshot,\n  currentMessage: string,\n  selectedModel?: Model<Api>,\n): Promise<Extract<CommitGenerationResult, { ok: true }> | undefined> {\n  const model = selectedModel ?? ctx.model as Model<Api> | undefined;\n  if (!model) {\n    ctx.ui.notify(\"No model selected for rewriting.\", \"error\");\n    return undefined;\n  }\n  const instruction = await ctx.ui.input(\"How should the commit message be rewritten?\");\n  if (!instruction) return undefined;\n\n  let evidence: StagedEvidence;\n  try {\n    evidence = await captureStagedEvidence(git);\n  } catch (error: unknown) {\n    ctx.ui.notify(formatError(error), \"error\");\n    return undefined;\n  }\n  if (!snapshotsMatch(expectedSnapshot, evidence.snapshot)) {\n    ctx.ui.notify(\"The staged snapshot changed; the rewrite was discarded.\", \"warning\");\n    return undefined;\n  }\n\n  const generated = await generateWithLoader(ctx, {\n    model,\n    evidence,\n    style,\n    operation: { kind: \"rewrite\", currentMessage, instruction },\n    ...(ctx.thinkingLevel === undefined ? {} : { reasoning: ctx.thinkingLevel }),\n  });\n  if (!generated) return undefined;\n  if (!generated.ok) {\n    ctx.ui.notify(formatGenerationFailure(\"Rewritten message\", generated), \"error\");\n    return undefined;\n  }\n  return generated;\n}\n\nasync function generateWithLoader(\n  ctx: ExtensionContext,\n  request: CommitGenerationRequest,\n): Promise<CommitGenerationResult | null> {\n  const model = request.model;\n  return ctx.ui.custom<CommitGenerationResult | null>((tui, theme, _keybindings, done) => {\n    const loader = new BorderedLoader(tui, theme, `Generating commit message with ${model.id}...`);\n    const timeoutController = new AbortController();\n    const signal = AbortSignal.any([loader.signal, timeoutController.signal]);\n    let settled = false;\n    let timeout: ReturnType<typeof setTimeout> | undefined;\n    const finish = (value: CommitGenerationResult | null): void => {\n      if (settled) return;\n      settled = true;\n      if (timeout) clearTimeout(timeout);\n      done(value);\n    };\n    loader.onAbort = () => finish({ ok: false, code: \"aborted\", reason: \"Commit message generation was cancelled.\" });\n    timeout = setTimeout(() => {\n      timeoutController.abort();\n      finish({ ok: false, code: \"aborted\", reason: \"Commit message generation timed out.\" });\n    }, GENERATION_TIMEOUT_MS);\n\n    const client: CommitModelClient = {\n      complete: (selectedModel, context, options) => ctx.modelRegistry.complete(selectedModel, context, options),\n    };\n    const generator = new CommitMessageGenerator(client);\n    void generator\n      .generate({ ...request, signal })\n      .then((result) => finish(result))\n      .catch((error: unknown) => {\n        if (!signal.aborted) ctx.ui.notify(formatError(error), \"error\");\n        finish({ ok: false, code: \"invalid-response\", reason: error instanceof Error ? error.message : String(error) });\n      });\n    return loader;\n  });\n}\n\nasync function commitDirect(\n  ctx: ExtensionContext,\n  git: GitService,\n  message: string,\n  expectedSnapshot?: GitMaybeSnapshot,\n  usage?: TokenTallyCollector,\n): Promise<boolean> {\n  const cleanMessage = message.trim();\n  if (!cleanMessage) {\n    ctx.ui.notify(\"Commit message is empty.\", \"warning\");\n    return false;\n  }\n  if (expectedSnapshot) {\n    const current = await git.maybeSnapshot();\n    if (!snapshotsMatch(expectedSnapshot, current)) {\n      ctx.ui.notify(\"The staged snapshot changed; nothing was committed.\", \"warning\");\n      return false;\n    }\n  }\n  try {\n    await git.commitMessage(cleanMessage);\n    ctx.ui.notify(`Committed ${firstLine(cleanMessage)}${formatUsageCostLine(usage?.totals)}`, \"info\");\n    return true;\n  } catch (error: unknown) {\n    ctx.ui.notify(formatError(error), \"error\");\n    return false;\n  }\n}\n\nfunction notifySmartDraftReady(ctx: ExtensionContext, draft: SmartDraft): void {\n  ctx.ui.notify(\n    `Smart commit: draft ready (algorithm: ${routeLabel(draft.route)}${draft.truncated ? \", recovered from a truncated reply\" : \"\"})\\n  ${firstLine(draft.message)}${formatUsageCostLine(draft.usage)}\\nReview before committing`,\n    \"info\",\n  );\n}\n\nfunction routeLabel(route: DraftRoute): string {\n  if (route === \"analyst-assisted\") return \"extended analysis\";\n  if (route === \"compact\") return \"compact diff\";\n  if (route === \"formatting-only\") return \"formatting only, no model call\";\n  return \"fresh diff\";\n}\n\nfunction formatGenerationFailure(prefix: string, result: Extract<CommitGenerationResult, { ok: false }>): string {\n  // A rejected draft still spent the tokens; show them next to the reason.\n  return `${prefix} rejected: ${result.reason}${formatUsageCostLine(result.diagnostics?.usage)}`;\n}\n\n\nfunction firstLine(message: string): string {\n  return message.split(\"\\n\", 1)[0] ?? message;\n}\n\nfunction formatError(error: unknown): string {\n  return error instanceof Error ? `Git workflow failed: ${error.message}` : `Git workflow failed: ${String(error)}`;\n}\n"}},"diff-skeleton.ts":{"file":{"contents":"/**\n * Budgeted \"skeleton\" projection of an oversized compact patch.\n *\n * When the complete staged compact patch exceeds the hard input cap, this module\n * derives a partial, explicitly labeled replacement that preserves every file\n * header and hunk header while omitting change bodies for files that do not fit\n * a byte budget. Omissions are enumerated per file inside the patch itself so\n * downstream prompts can stay honest about their factual scope. Pure functions;\n * no Git or model dependencies.\n */\nimport { isGeneratedPath, isLockPath, isVendorPath } from \"./evidence-parse.js\";\n\nexport interface SkeletonOmittedFile {\n  readonly path: string;\n  readonly addedLines: number;\n  readonly deletedLines: number;\n  readonly hunks: number;\n}\n\nexport interface DiffSkeleton {\n  /** Annotated partial compact patch within the requested budget. */\n  readonly patch: string;\n  readonly bytes: number;\n  /** Files whose change bodies were omitted, in omission order. */\n  readonly omittedFiles: readonly SkeletonOmittedFile[];\n  readonly completeFileCount: number;\n}\n\ninterface FileBlock {\n  /** Header lines before the first hunk header (diff --git, index, ---, +++, ...). */\n  readonly header: string[];\n  /** Hunk header lines (`@@ -a,b +c,d @@ context`). */\n  readonly hunks: string[];\n  /** Change body lines (starting with +/- inside a hunk, plus \"\\\" markers). */\n  readonly bodies: string[];\n  readonly addedLines: number;\n  readonly deletedLines: number;\n  readonly path: string;\n}\n\n/** Low-signal paths (lockfiles, vendor trees, generated output) are summarized first. */\nfunction isLowSignalPath(path: string): boolean {\n  return isLockPath(path) || isVendorPath(path) || isGeneratedPath(path);\n}\n\nfunction parseBSidePath(headerLines: readonly string[]): string {\n  for (const line of headerLines) {\n    if (!line.startsWith(\"+++ \")) continue;\n    let candidate = line.slice(4).trim();\n    if (candidate.startsWith('\"') && candidate.endsWith('\"')) candidate = candidate.slice(1, -1);\n    if (candidate === \"/dev/null\") return \"\";\n    return /^(?:a|b|c|i)\\//.test(candidate) ? candidate.slice(2) : candidate;\n  }\n  return \"\";\n}\n\nfunction splitIntoBlocks(patch: string): FileBlock[] {\n  const blocks: FileBlock[] = [];\n  const lines = patch.split(\"\\n\");\n  // A trailing empty element from a final newline is not a real line; keep the\n  // newline when reassembling instead of treating it as content.\n  if (lines.length > 0 && lines[lines.length - 1] === \"\") lines.pop();\n\n  let current: {\n    header: string[];\n    hunks: string[];\n    bodies: string[];\n    addedLines: number;\n    deletedLines: number;\n  } | undefined;\n  let inHunk = false;\n\n  const flush = () => {\n    if (!current) return;\n    blocks.push({\n      ...current,\n      path: parseBSidePath(current.header),\n    });\n    current = undefined;\n  };\n\n  for (const line of lines) {\n    if (line.startsWith(\"diff --git \")) {\n      flush();\n      current = { header: [line], hunks: [], bodies: [], addedLines: 0, deletedLines: 0 };\n      inHunk = false;\n      continue;\n    }\n    if (!current) continue;\n    if (line.startsWith(\"@@ \")) {\n      inHunk = true;\n      current.hunks.push(line);\n      continue;\n    }\n    if (!inHunk) {\n      current.header.push(line);\n      continue;\n    }\n    current.bodies.push(line);\n    if (line.length > 0 && line[0] === \"+\" && !line.startsWith(\"+++\")) current.addedLines += 1;\n    else if (line.length > 0 && line[0] === \"-\" && !line.startsWith(\"---\")) current.deletedLines += 1;\n  }\n  flush();\n  return blocks;\n}\n\nfunction byteLength(value: string): number {\n  return Buffer.byteLength(value, \"utf8\");\n}\n\nfunction linesSize(lines: readonly string[]): number {\n  return lines.reduce((total, line) => total + byteLength(line) + 1, 0);\n}\n\n/**\n * Build the skeleton projection of `patch` within `budgetBytes`.\n *\n * Files are prioritized by semantic signal: smaller change bodies and paths\n * without lock/vendor/generated hints keep their full bodies first; everything\n * else keeps only its headers plus one synthetic omission marker per file. If\n * even the headers exceed the remaining budget, remaining files are dropped\n * entirely (the authoritative manifest alongside the patch still lists them).\n */\nexport function buildDiffSkeleton(patch: string, budgetBytes: number): DiffSkeleton {\n  const totalBytes = byteLength(patch);\n  if (budgetBytes <= 0 || totalBytes <= budgetBytes) {\n    return { patch, bytes: totalBytes, omittedFiles: [], completeFileCount: 0 };\n  }\n\n  const blocks = splitIntoBlocks(patch);\n  const bodySize = (block: FileBlock): number => linesSize(block.bodies);\n  const markerFor = (block: FileBlock): string =>\n    `@@ pi-git: change bodies omitted (+${block.addedLines} -${block.deletedLines} across ${block.hunks.length} hunks) @@`;\n  const fullSizeOf = (block: FileBlock): number =>\n    linesSize(block.header) + linesSize(block.hunks) + linesSize(block.bodies);\n  const skeletonSizeOf = (block: FileBlock): number =>\n    // Hunk headers survive reduction so function-level context is preserved.\n    linesSize(block.header) + linesSize(block.hunks) + byteLength(markerFor(block)) + 1;\n\n  const completeBlocks = new Set<FileBlock>();\n  const skeletonBlocks = new Set<FileBlock>();\n  const omittedFiles: SkeletonOmittedFile[] = [];\n  let used = 0;\n\n  const trySkeleton = (block: FileBlock): void => {\n    if (used + skeletonSizeOf(block) <= budgetBytes) {\n      used += skeletonSizeOf(block);\n      skeletonBlocks.add(block);\n      omittedFiles.push({\n        path: block.path,\n        addedLines: block.addedLines,\n        deletedLines: block.deletedLines,\n        hunks: block.hunks.length,\n      });\n    }\n  };\n\n  const lowSignal = blocks.filter((block) => isLowSignalPath(block.path)).sort((left, right) => bodySize(right) - bodySize(left));\n  const highSignal = blocks.filter((block) => !isLowSignalPath(block.path)).sort((left, right) => bodySize(left) - bodySize(right));\n\n  // Phase 1: skeletonize lock/vendor/generated bodies first so they never crowd\n  // out semantic files, regardless of relative sizes.\n  for (const block of lowSignal) trySkeleton(block);\n\n  // Phase 2: grant complete bodies to high-signal files, smallest first.\n  for (const block of highSignal) {\n    if (used + fullSizeOf(block) <= budgetBytes) {\n      used += fullSizeOf(block);\n      completeBlocks.add(block);\n    }\n  }\n\n  // Phase 3: skeletonize remaining high-signal files, largest first.\n  for (const block of highSignal.filter((block) => !completeBlocks.has(block)).sort((left, right) => bodySize(right) - bodySize(left))) {\n    trySkeleton(block);\n  }\n\n  const sections: string[] = [];\n  let completeFileCount = 0;\n  for (const block of blocks) {\n    if (completeBlocks.has(block)) {\n      sections.push([...block.header, ...block.hunks, ...block.bodies, \"\"].join(\"\\n\"));\n      completeFileCount += 1;\n    } else if (skeletonBlocks.has(block)) {\n      sections.push([...block.header, ...block.hunks, markerFor(block), \"\"].join(\"\\n\"));\n    }\n  }\n\n  const assembled = sections.join(\"\");\n  return {\n    patch: assembled,\n    bytes: byteLength(assembled),\n    omittedFiles,\n    completeFileCount,\n  };\n}\n"}},"evidence-parse.ts":{"file":{"contents":"/**\n * Parsing and measurement for raw Git staged-change output. Pure functions with\n * no Git or model dependencies.\n */\nexport interface GitStagedFile {\n  readonly key: string;\n  readonly status: string;\n  readonly path: string;\n  readonly originalPath?: string | undefined;\n  readonly additions?: number | undefined;\n  readonly deletions?: number | undefined;\n  readonly binary: boolean;\n}\n\nexport interface StagedEvidenceSummary {\n  readonly fileCount: number;\n  readonly additions: number;\n  readonly deletions: number;\n  readonly pathByteCount: number;\n  readonly binaryEntries: number;\n  readonly renameEntries: number;\n  readonly copyEntries: number;\n  readonly addedEntries: number;\n  readonly deletedEntries: number;\n  readonly modeChanges: number;\n  readonly generatedPathHints: readonly string[];\n  readonly lockPathHints: readonly string[];\n  readonly vendorPathHints: readonly string[];\n}\n\nexport function stagedFileKey(path: string, originalPath?: string): string {\n  return originalPath === undefined ? path : `${originalPath}->${path}`;\n}\n\n/** Parse `git diff --cached --name-status -z` without shell quoting or path interpretation. */\nexport function parseStagedNameStatus(output: string): Array<{\n  status: string;\n  path: string;\n  originalPath?: string | undefined;\n}> {\n  const tokens = output.split(\"\\0\");\n  const entries: Array<{ status: string; path: string; originalPath?: string | undefined }> = [];\n\n  for (let index = 0; index < tokens.length;) {\n    const token = tokens[index++] ?? \"\";\n    if (!token) continue;\n\n    const tab = token.indexOf(\"\\t\");\n    const status = tab >= 0 ? token.slice(0, tab) : token;\n    const embeddedPath = tab >= 0 ? token.slice(tab + 1) : undefined;\n    if (!status) continue;\n\n    const isRenameOrCopy = status[0] === \"R\" || status[0] === \"C\";\n    if (isRenameOrCopy) {\n      const originalPath = embeddedPath ?? tokens[index++];\n      const path = tokens[index++];\n      if (originalPath === undefined || path === undefined) continue;\n      entries.push({ status, path, originalPath });\n      continue;\n    }\n\n    const path = embeddedPath ?? tokens[index++];\n    if (path === undefined) continue;\n    entries.push({ status, path });\n  }\n\n  return entries;\n}\n\ninterface ParsedNumstat {\n  readonly path: string;\n  readonly originalPath?: string | undefined;\n  readonly additions?: number | undefined;\n  readonly deletions?: number | undefined;\n  readonly binary: boolean;\n}\n\n/** Parse `git diff --cached --numstat -z`, including Git's rename record shape. */\nexport function parseStagedNumstat(output: string): ParsedNumstat[] {\n  const tokens = output.split(\"\\0\");\n  const entries: ParsedNumstat[] = [];\n\n  for (let index = 0; index < tokens.length;) {\n    const token = tokens[index++] ?? \"\";\n    if (!token) continue;\n\n    const firstTab = token.indexOf(\"\\t\");\n    const secondTab = firstTab < 0 ? -1 : token.indexOf(\"\\t\", firstTab + 1);\n    if (firstTab < 0 || secondTab < 0) continue;\n\n    const additionsText = token.slice(0, firstTab);\n    const deletionsText = token.slice(firstTab + 1, secondTab);\n    const path = token.slice(secondTab + 1);\n    const binary = additionsText === \"-\" || deletionsText === \"-\";\n    const additions = binary ? undefined : parseCount(additionsText);\n    const deletions = binary ? undefined : parseCount(deletionsText);\n\n    // With -z, rename/copy numstat records have an empty path followed by\n    // the old and new names as separate NUL-delimited tokens.\n    if (path === \"\") {\n      const originalPath = tokens[index++];\n      const newPath = tokens[index++];\n      if (originalPath === undefined || newPath === undefined) continue;\n      entries.push({ path: newPath, originalPath, additions, deletions, binary });\n      continue;\n    }\n\n    entries.push({ path, additions, deletions, binary });\n  }\n\n  return entries;\n}\n\nfunction parseCount(value: string): number | undefined {\n  if (!/^\\d+$/.test(value)) return undefined;\n  const parsed = Number(value);\n  return Number.isSafeInteger(parsed) ? parsed : undefined;\n}\n\n/** Combine name-status and numstat records while preserving Git's output order. */\nexport function buildStagedFiles(nameStatus: string, numstat: string): GitStagedFile[] {\n  const names = parseStagedNameStatus(nameStatus);\n  const stats = parseStagedNumstat(numstat);\n  return names.map((entry, index) => {\n    const stat = stats[index] ?? stats.find((candidate) =>\n      candidate.path === entry.path && candidate.originalPath === entry.originalPath,\n    );\n    return {\n      key: stagedFileKey(entry.path, entry.originalPath),\n      status: entry.status,\n      path: entry.path,\n      ...(entry.originalPath === undefined ? {} : { originalPath: entry.originalPath }),\n      ...(stat?.additions === undefined ? {} : { additions: stat.additions }),\n      ...(stat?.deletions === undefined ? {} : { deletions: stat.deletions }),\n      binary: stat?.binary ?? false,\n    };\n  });\n}\n\nexport function summarizeStagedFiles(files: readonly GitStagedFile[], patchText = \"\"): StagedEvidenceSummary {\n  const generatedPathHints: string[] = [];\n  const lockPathHints: string[] = [];\n  const vendorPathHints: string[] = [];\n  let additions = 0;\n  let deletions = 0;\n  let pathByteCount = 0;\n  let modeChanges = 0;\n\n  for (const file of files) {\n    if (file.additions !== undefined) additions += file.additions;\n    if (file.deletions !== undefined) deletions += file.deletions;\n    pathByteCount += Buffer.byteLength(file.path, \"utf8\");\n    if (file.originalPath !== undefined) pathByteCount += Buffer.byteLength(file.originalPath, \"utf8\");\n\n    const paths = [file.path, ...(file.originalPath === undefined ? [] : [file.originalPath])];\n    for (const candidate of paths) {\n      if (isGeneratedPath(candidate) && !generatedPathHints.includes(candidate)) generatedPathHints.push(candidate);\n      if (isLockPath(candidate) && !lockPathHints.includes(candidate)) lockPathHints.push(candidate);\n      if (isVendorPath(candidate) && !vendorPathHints.includes(candidate)) vendorPathHints.push(candidate);\n    }\n  }\n\n  if (patchText) {\n    const blocks = patchText.split(/^diff --git /m).slice(1);\n    for (const block of blocks) {\n      if (/^(?:old mode|new mode) /m.test(block)) modeChanges += 1;\n    }\n  }\n\n  return {\n    fileCount: files.length,\n    additions,\n    deletions,\n    pathByteCount,\n    binaryEntries: files.filter((file) => file.binary).length,\n    renameEntries: files.filter((file) => file.status[0] === \"R\").length,\n    copyEntries: files.filter((file) => file.status[0] === \"C\").length,\n    addedEntries: files.filter((file) => file.status[0] === \"A\").length,\n    deletedEntries: files.filter((file) => filesStatusIncludesDeletion(file.status)).length,\n    modeChanges,\n    generatedPathHints,\n    lockPathHints,\n    vendorPathHints,\n  };\n}\n\nfunction filesStatusIncludesDeletion(status: string): boolean {\n  return status[0] === \"D\";\n}\n\nexport function isGeneratedPath(value: string): boolean {\n  return /(^|\\/)(?:generated|dist|build|coverage|\\.next|out)(?:\\/|$)/i.test(value)\n    || /(?:\\.generated\\.|\\.gen\\.)/i.test(value);\n}\n\nexport function isLockPath(value: string): boolean {\n  return /(?:^|\\/)(?:package-lock\\.json|pnpm-lock\\.yaml|yarn\\.lock|bun\\.lockb|Cargo\\.lock|composer\\.lock|Gemfile\\.lock|Podfile\\.lock)$/i.test(value);\n}\n\nexport function isVendorPath(value: string): boolean {\n  return /(^|\\/)(?:node_modules|vendor|third_party|\\.venv)(?:\\/|$)/i.test(value);\n}\n\n/** Render a deterministic, instruction-resistant manifest for model prompts. */\nexport function formatStagedManifest(files: readonly GitStagedFile[], summary: StagedEvidenceSummary): string {\n  const lines = [\n    `fileCount=${summary.fileCount}`,\n    `additions=${summary.additions}`,\n    `deletions=${summary.deletions}`,\n    `binaryEntries=${summary.binaryEntries}`,\n    `renameEntries=${summary.renameEntries}`,\n    `copyEntries=${summary.copyEntries}`,\n    `addedEntries=${summary.addedEntries}`,\n    `deletedEntries=${summary.deletedEntries}`,\n    `modeChanges=${summary.modeChanges}`,\n    \"files:\",\n  ];\n  for (const file of files) {\n    lines.push(JSON.stringify({\n      key: file.key,\n      status: file.status,\n      path: file.path,\n      ...(file.originalPath === undefined ? {} : { originalPath: file.originalPath }),\n      ...(file.additions === undefined ? {} : { additions: file.additions }),\n      ...(file.deletions === undefined ? {} : { deletions: file.deletions }),\n      binary: file.binary,\n    }));\n  }\n  return lines.join(\"\\n\");\n}\n\n\n/** A cheap upper-bound-ish token estimate: roughly four bytes per token. */\nexport function estimateTextTokensLocal(text: string): number {\n  return Math.ceil(text.length / 4);\n}\n"}},"evidence-plan.ts":{"file":{"contents":"/**\n * Cost-aware route planning for commit generation. Describes every candidate\n * representation cheaply, selects one, and only then materializes its prompt.\n */\nimport type { Api, Model, ModelThinkingLevel, UserMessage } from \"@earendil-works/pi-ai\";\nimport {\n  COMMIT_SPECIFIC_SYSTEM_PROMPT,\n  DIFF_ANALYST_SYSTEM_PROMPT,\n  MAX_COMMIT_DIFF_BYTES,\n} from \"./commit-message.js\";\nimport {\n  estimateTextTokensLocal,\n  formatStagedManifest,\n} from \"./evidence-parse.js\";\nimport type {\n  CommitIntent,\n  CommitOperation,\n  DiffAnalysis,\n  StagedEvidence,\n} from \"./commit-evidence.js\";\n\nexport type CommitRepresentation = \"context\" | \"compact\" | \"analyst-assisted\";\nexport type CandidateRepresentation = \"context\" | \"compact\" | \"analyst\" | \"analysis-final\";\n\n/** Writer budgets. A 100-file change legitimately needs a longer message than a 1-file change. */\nexport const MIN_FINAL_OUTPUT_TOKENS = 768;\nexport const MAX_FINAL_OUTPUT_TOKENS = 4_096;\nexport const FINAL_OUTPUT_TOKENS_PER_FILE = 8;\n/** Analyst budgets. The JSON contract repeats every manifest key. */\nexport const MIN_ANALYST_OUTPUT_TOKENS = 1_024;\nexport const MAX_ANALYST_OUTPUT_TOKENS = 8_192;\nexport const ANALYST_OUTPUT_TOKENS_PER_FILE = 16;\n/** Reasoning and the answer share one completion budget on OpenAI-style endpoints. */\nexport const REASONING_OUTPUT_ALLOWANCE_TOKENS = 1_024;\nexport const MIN_SAFETY_RESERVE_TOKENS = 2_048;\n\nexport interface CommitEvidenceSpec {\n  readonly representation: CandidateRepresentation;\n  readonly intentIncluded: boolean;\n  readonly analysis?: DiffAnalysis | undefined;\n  readonly diffBytes: number;\n  readonly estimatedInputTokens: number;\n  readonly inputBudget: number;\n  readonly outputReserve: number;\n  readonly safetyReserve: number;\n  readonly fits: boolean;\n  readonly rejectionReason?: string | undefined;\n}\n\n/** A spec together with its fully built prompt content. */\nexport interface CommitEvidenceCandidate extends CommitEvidenceSpec {\n  readonly systemPrompt: string;\n  readonly userMessage: UserMessage;\n}\n\nexport interface CommitEvidenceRequest {\n  readonly model: Model<Api>;\n  readonly evidence: StagedEvidence;\n  readonly style: string;\n  readonly intent?: CommitIntent | undefined;\n  readonly operation?: CommitOperation | undefined;\n  /** Session thinking level. Only used to reserve output tokens for reasoning. */\n  readonly reasoning?: ModelThinkingLevel | undefined;\n}\n\nexport interface CommitEvidencePlan {\n  readonly contextWindow: number;\n  readonly safetyReserve: number;\n  readonly candidates: readonly CommitEvidenceSpec[];\n  readonly selected?: CommitEvidenceSpec | undefined;\n  readonly route: CommitRepresentation | \"none\";\n  readonly failure?: CommitEvidencePlanFailure | undefined;\n}\n\nexport interface CommitEvidencePlanFailure {\n  readonly code: \"context-too-small\" | \"input-too-large\";\n  readonly reason: string;\n  readonly diagnostics?: CommitEvidenceSpec | undefined;\n}\n\n/** The model's declared context window, or undefined when it is unusable. */\nexport function modelContextWindow(model: Model<Api>): number | undefined {\n  const candidate = (model as Model<Api> & { contextWindow?: unknown }).contextWindow;\n  if (candidate === undefined) return undefined;\n  if (typeof candidate !== \"number\" || !Number.isFinite(candidate) || candidate <= 0) return undefined;\n  return Math.floor(candidate);\n}\n\nexport function modelMaxTokens(model: Model<Api>, fallback: number): number {\n  const candidate = (model as Model<Api> & { maxTokens?: unknown }).maxTokens;\n  return typeof candidate === \"number\" && Number.isFinite(candidate) && candidate > 0\n    ? Math.floor(candidate)\n    : fallback;\n}\n\nexport function commitSafetyReserve(contextWindow: number): number {\n  return Math.max(MIN_SAFETY_RESERVE_TOKENS, Math.ceil(contextWindow * 0.15));\n}\n\nexport interface CommitOutputBudget {\n  readonly analyst: boolean;\n  readonly fileCount: number;\n  readonly reasoning: boolean;\n}\n\n/**\n * Size the completion budget from the change itself instead of one flat cap.\n * The input side already degrades across representations; a flat 512-token\n * reserve made large staged changes fail with `stopReason: \"length\"`.\n */\nexport function commitOutputReserve(model: Model<Api>, budget: CommitOutputBudget): number {\n  const floor = budget.analyst ? MIN_ANALYST_OUTPUT_TOKENS : MIN_FINAL_OUTPUT_TOKENS;\n  const hardCap = budget.analyst ? MAX_ANALYST_OUTPUT_TOKENS : MAX_FINAL_OUTPUT_TOKENS;\n  const perFile = budget.analyst ? ANALYST_OUTPUT_TOKENS_PER_FILE : FINAL_OUTPUT_TOKENS_PER_FILE;\n  const ceiling = Math.min(hardCap, modelMaxTokens(model, floor));\n  const needed = floor\n    + Math.max(0, budget.fileCount) * perFile\n    + (budget.reasoning ? REASONING_OUTPUT_ALLOWANCE_TOKENS : 0);\n  return Math.min(ceiling, Math.max(floor, needed));\n}\n\n/** Double a spent output budget without passing the model's own ceiling. */\nexport function nextCommitOutputReserve(reserve: number, model: Model<Api>, analyst: boolean): number {\n  const hardCap = Math.min(\n    analyst ? MAX_ANALYST_OUTPUT_TOKENS : MAX_FINAL_OUTPUT_TOKENS,\n    modelMaxTokens(model, reserve),\n  );\n  return reserve >= hardCap ? reserve : Math.min(hardCap, reserve * 2);\n}\n\n/** Describe every candidate route in the deterministic order, without building prompts. */\n\nexport function describeCommitEvidenceCandidates(\n  request: CommitEvidenceRequest,\n  analysis?: DiffAnalysis,\n): CommitEvidenceSpec[] {\n  const contextWindow = modelContextWindow(request.model) ?? 0;\n  const safetyReserve = commitSafetyReserve(contextWindow);\n  const specs: CommitEvidenceSpec[] = [];\n\n  specs.push(makeSpec(request, { representation: \"context\", intentIncluded: true }, contextWindow, safetyReserve));\n  specs.push(makeSpec(request, { representation: \"context\", intentIncluded: false }, contextWindow, safetyReserve));\n  specs.push(makeSpec(request, { representation: \"compact\", intentIncluded: true }, contextWindow, safetyReserve));\n  specs.push(makeSpec(request, { representation: \"compact\", intentIncluded: false }, contextWindow, safetyReserve));\n\n  specs.push(makeSpec(request, { representation: \"analyst\", intentIncluded: false }, contextWindow, safetyReserve));\n  if (analysis) {\n    // The analyst-final candidates are considered after the analyst candidate;\n    // intent is dropped only by the planner when the first final form fails.\n    specs.push(makeSpec(request, { representation: \"analysis-final\", intentIncluded: true, analysis }, contextWindow, safetyReserve));\n    specs.push(makeSpec(request, { representation: \"analysis-final\", intentIncluded: false, analysis }, contextWindow, safetyReserve));\n  }\n  return specs;\n}\n\n/** Select the cheapest complete representation before any model call. */\n\nexport function planCommitEvidence(request: CommitEvidenceRequest): CommitEvidencePlan {\n  const contextWindow = modelContextWindow(request.model);\n  if (contextWindow === undefined) {\n    return {\n      contextWindow: 0,\n      safetyReserve: 0,\n      candidates: [],\n      route: \"none\",\n      failure: {\n        code: \"context-too-small\",\n        reason: \"The selected model does not expose a valid positive context window.\",\n      },\n    };\n  }\n\n  const safetyReserve = commitSafetyReserve(contextWindow);\n  if (contextWindow <= safetyReserve + commitOutputReserve(request.model, outputBudget(request, false))) {\n    return {\n      contextWindow,\n      safetyReserve,\n      candidates: [],\n      route: \"none\",\n      failure: {\n        code: \"context-too-small\",\n        reason: \"The selected model has no context headroom after the required output and safety reserves.\",\n      },\n    };\n  }\n  if (request.evidence.compactBytes > MAX_COMMIT_DIFF_BYTES) {\n    return {\n      contextWindow,\n      safetyReserve,\n      candidates: [],\n      route: \"none\",\n      failure: {\n        code: \"input-too-large\",\n        reason: `The complete compact staged evidence is ${request.evidence.compactBytes.toLocaleString()} bytes, above the ${MAX_COMMIT_DIFF_BYTES.toLocaleString()}-byte hard limit.`,\n      },\n    };\n  }\n\n  const candidates = describeCommitEvidenceCandidates(request);\n  const direct = candidates\n    .filter((candidate) => candidate.representation === \"context\" || candidate.representation === \"compact\")\n    .find((candidate) => candidate.fits);\n\n  if (direct) {\n    return {\n      contextWindow,\n      safetyReserve,\n      candidates,\n      selected: direct,\n      route: direct.representation === \"context\" ? \"context\" : \"compact\",\n    };\n  }\n\n  const analyst = candidates.find((candidate) => candidate.representation === \"analyst\");\n  if (analyst?.fits) {\n    return {\n      contextWindow,\n      safetyReserve,\n      candidates,\n      selected: analyst,\n      route: \"analyst-assisted\",\n    };\n  }\n\n  const rejected = candidates.find((candidate) => candidate.representation === \"compact\" && !candidate.fits)\n    ?? candidates[0];\n  return {\n    contextWindow,\n    safetyReserve,\n    candidates,\n    route: \"none\",\n    failure: {\n      code: \"input-too-large\",\n      reason: `The complete staged evidence does not fit the selected model after output and safety reserves. Stage a smaller change or select a larger-context model.`,\n      ...(rejected === undefined ? {} : { diagnostics: rejected }),\n    },\n  };\n}\n\nfunction makeSpec(\n  request: CommitEvidenceRequest,\n  route: {\n    representation: CandidateRepresentation;\n    intentIncluded: boolean;\n    analysis?: DiffAnalysis;\n  },\n  contextWindow: number,\n  safetyReserve: number,\n): CommitEvidenceSpec {\n  const { representation } = route;\n  const analyst = representation === \"analyst\";\n  const intentIncluded = analyst ? false : route.intentIncluded;\n  const outputReserve = commitOutputReserve(request.model, outputBudget(request, analyst));\n  const inputBudget = Math.max(0, contextWindow - outputReserve - safetyReserve);\n  const systemPrompt = analyst ? DIFF_ANALYST_SYSTEM_PROMPT : COMMIT_SPECIFIC_SYSTEM_PROMPT;\n  // Estimate from a template with empty patches so no large prompt is built here.\n  const template = buildCandidateContent({ ...request, evidence: { ...request.evidence, contextPatch: \"\", compactPatch: \"\" } }, representation, intentIncluded, route.analysis);\n  const patchBytes = representation === \"context\" ? request.evidence.contextBytes : request.evidence.compactBytes;\n  const estimatedInputTokens = estimateTextTokensLocal(systemPrompt) + Math.ceil((template.length + patchBytes) / 4) + 16;\n  const diffBytes = representation === \"context\" ? request.evidence.contextBytes : request.evidence.compactBytes;\n  const compactWithinCap = request.evidence.compactBytes <= MAX_COMMIT_DIFF_BYTES;\n  const fits = contextWindow > 0\n    && compactWithinCap\n    && estimatedInputTokens <= inputBudget;\n  return {\n    representation,\n    intentIncluded,\n    ...(route.analysis === undefined ? {} : { analysis: route.analysis }),\n    diffBytes,\n    estimatedInputTokens,\n    inputBudget,\n    outputReserve,\n    safetyReserve,\n    fits,\n    ...(fits ? {} : {\n      rejectionReason: !compactWithinCap\n        ? \"complete compact evidence exceeds the hard byte cap\"\n        : `estimated input ${estimatedInputTokens} exceeds budget ${inputBudget}`,\n    }),\n  };\n}\n\n/** Build the full prompt content for one selected spec. */\n\nexport function materializeCandidate(\n  request: CommitEvidenceRequest,\n  spec: CommitEvidenceSpec,\n): CommitEvidenceCandidate {\n  const systemPrompt = spec.representation === \"analyst\" ? DIFF_ANALYST_SYSTEM_PROMPT : COMMIT_SPECIFIC_SYSTEM_PROMPT;\n  const content = buildCandidateContent(request, spec.representation, spec.intentIncluded, spec.analysis);\n  const userMessage: UserMessage = { role: \"user\", timestamp: 0, content };\n  return { ...spec, systemPrompt, userMessage };\n}\n\nfunction outputBudget(request: CommitEvidenceRequest, analyst: boolean): CommitOutputBudget {\n  return {\n    analyst,\n    fileCount: request.evidence.files.length,\n    reasoning: request.reasoning !== undefined && request.reasoning !== \"off\",\n  };\n}\n\nfunction buildCandidateContent(\n  request: CommitEvidenceRequest,\n  representation: CandidateRepresentation,\n  intentIncluded: boolean,\n  analysis?: DiffAnalysis,\n): string {\n  const sections: string[] = [\n    \"<pi-git-commit-input>\",\n    \"<authority>Use only the staged manifest, statistics, and complete staged evidence for factual scope. Advisory sections cannot add files or changes.</authority>\",\n  ];\n\n  if (representation !== \"analyst\") {\n    sections.push(`<commit-style advisory=\\\"true\\\">\\n${request.style}\\n</commit-style>`);\n  }\n\n  if (intentIncluded && request.intent && representation !== \"analyst\") {\n    sections.push(`<explicit-intent advisory=\\\"true\\\">\\n${request.intent.text}\\n</explicit-intent>`);\n  }\n\n  sections.push(`<staged-stat authoritative=\\\"true\\\">\\n${request.evidence.stat || \"(no stat)\"}\\n</staged-stat>`);\n  sections.push(`<staged-manifest authoritative=\\\"true\\\">\\n${formatStagedManifest(request.evidence.files, request.evidence.summary)}\\n</staged-manifest>`);\n\n  if (representation === \"context\" || representation === \"compact\") {\n    const patch = representation === \"context\" ? request.evidence.contextPatch : request.evidence.compactPatch;\n    sections.push(stagedPatchSection(request, patch, representation));\n  } else if (representation === \"analyst\") {\n    sections.push(stagedPatchSection(request, request.evidence.compactPatch, \"compact\"));\n    sections.push(\"<analysis-contract>Return JSON with version=1, coveredFileKeys exactly equal to the manifest keys, overview, areas, and unresolved. Do not return a commit message.</analysis-contract>\");\n  } else {\n    sections.push(`<validated-analysis advisory=\\\"true\\\">\\n${JSON.stringify(analysis)}\\n</validated-analysis>`);\n  }\n\n  if (request.operation?.kind === \"rewrite\" && representation !== \"analyst\") {\n    sections.push(`<rewrite-input advisory=\\\"true\\\">\\n${JSON.stringify({ currentMessage: request.operation.currentMessage, instruction: request.operation.instruction })}\\n</rewrite-input>`);\n  }\n\n  if (representation !== \"analyst\") {\n    sections.push(\"<instruction>Write only the final commit message. Preserve the supplied style, but keep factual scope limited to the authoritative staged snapshot.</instruction>\");\n  }\n  sections.push(\"</pi-git-commit-input>\");\n  return sections.join(\"\\n\\n\");\n}\n\nconst MAX_LISTED_OMITTED_FILES = 20;\n\n/** Wrap the compact patch, switching to an explicit partial label when evidence was skeleton-reduced. */\nfunction stagedPatchSection(request: CommitEvidenceRequest, patch: string, representation: string): string {\n  const partial = request.evidence.partial;\n  if (!partial || partial.omittedFiles.length === 0) {\n    return `<complete-staged-patch authoritative=\"true\" representation=\"${representation}\">\\n${patch}\\n</complete-staged-patch>`;\n  }\n  const listed = partial.omittedFiles\n    .slice(0, MAX_LISTED_OMITTED_FILES)\n    .map((file) => `${file.path} (+${file.addedLines} -${file.deletedLines})`)\n    .join(\", \");\n  const overflow = partial.omittedFiles.length - MAX_LISTED_OMITTED_FILES;\n  const omittedList = overflow > 0 ? `${listed}, and ${overflow} more` : listed;\n  return [\n    `<partial-staged-patch authoritative=\"true\" representation=\"${representation}\">`,\n    `The complete staged diff was ${partial.originalCompactBytes.toLocaleString()} bytes and exceeded the input cap, so change bodies were omitted for ${partial.omittedFiles.length} file(s): ${omittedList}.`,\n    \"Every changed file remains listed in the authoritative staged manifest and statistics above. Omitted bodies are marked inline with '@@ pi-git: change bodies omitted'. Do not claim details about omitted bodies.\",\n    patch,\n    \"</partial-staged-patch>\",\n  ].join(\"\\n\");\n}\n\n/** Return the analysis-final specs in intent-first order. */\nexport function candidateForAnalysisFinal(\n  request: CommitEvidenceRequest,\n  analysis: DiffAnalysis,\n): { withIntent: CommitEvidenceSpec; withoutIntent: CommitEvidenceSpec } {\n  const finalCandidates = describeCommitEvidenceCandidates(request, analysis)\n    .filter((spec) => spec.representation === \"analysis-final\");\n  return {\n    withIntent: finalCandidates[0] as CommitEvidenceSpec,\n    withoutIntent: finalCandidates[1] as CommitEvidenceSpec,\n  };\n}\n"}},"git-service.ts":{"file":{"contents":"import * as fs from \"node:fs/promises\";\nimport * as path from \"node:path\";\n\nexport interface GitExecResult {\n  stdout: string;\n  stderr: string;\n  code: number;\n  killed?: boolean;\n}\n\nexport interface GitExecOptions {\n  cwd?: string | undefined;\n  timeout?: number | undefined;\n  signal?: AbortSignal | undefined;\n}\n\nexport type GitExecutor = (\n  command: string,\n  args: string[],\n  options?: GitExecOptions,\n) => Promise<GitExecResult>;\n\nexport class GitOperationError extends Error {\n  readonly operation: string;\n  readonly args: readonly string[];\n  readonly code: number;\n  readonly stderr: string;\n  readonly stdout: string;\n  readonly killed: boolean;\n\n  constructor(\n    operation: string,\n    args: readonly string[],\n    result: GitExecResult,\n    hint?: string,\n  ) {\n    const detail = result.stderr.trim() || result.stdout.trim() || `git exited with ${result.code}`;\n    super(hint ? `${operation} failed (${result.code}): ${detail} ${hint}` : `${operation} failed (${result.code}): ${detail}`);\n    this.name = \"GitOperationError\";\n    this.operation = operation;\n    this.args = [...args];\n    this.code = result.code;\n    this.stderr = result.stderr;\n    this.stdout = result.stdout;\n    this.killed = result.killed === true;\n  }\n}\n\nexport class GitRepositoryError extends Error {\n  readonly reason:\n    | \"not-a-repository\"\n    | \"unborn\"\n    | \"detached\"\n    | \"operation-in-progress\";\n\n  constructor(\n    reason: GitRepositoryError[\"reason\"],\n    message: string,\n  ) {\n    super(message);\n    this.name = \"GitRepositoryError\";\n    this.reason = reason;\n  }\n}\n\nexport interface GitStatusEntry {\n  readonly index: string;\n  readonly worktree: string;\n  readonly path: string;\n  readonly originalPath?: string;\n}\n\nexport interface GitSnapshot {\n  readonly root: string;\n  readonly branchRef: string;\n  readonly head: string;\n  readonly indexTree: string;\n}\n\nexport interface GitMaybeSnapshot {\n  readonly root: string;\n  readonly branchRef?: string | undefined;\n  readonly head?: string | undefined;\n  readonly indexTree?: string | undefined;\n}\n\nexport interface GitStagedEvidenceRaw {\n  readonly snapshot: GitMaybeSnapshot;\n  readonly stat: string;\n  readonly status: string;\n  readonly shortStat: string;\n  readonly nameStatus: string;\n  readonly numstat: string;\n  readonly contextPatch: string;\n  readonly compactPatch: string;\n}\n\nconst DEFAULT_TIMEOUT_MS = 15_000;\n/** How old a lock file must be before pi-git will remove it and retry. */\nconst DEFAULT_LOCK_STALE_AFTER_MS = 15_000;\n/** Locks are never removed while a live process holds them open. */\nconst MAX_LOCK_RECOVERIES = 3;\nconst COMMIT_OPERATION_MARKERS = [\n  \"MERGE_HEAD\",\n  \"CHERRY_PICK_HEAD\",\n  \"REVERT_HEAD\",\n  \"rebase-merge\",\n  \"rebase-apply\",\n] as const;\n\n/**\n * Small argv-only Git facade. Every command is run from the discovered worktree\n * root, which keeps path handling consistent for commands launched by shortcuts\n * and commands launched from a nested directory.\n *\n * Stale-lock handling: when a git command fails because a lock file already\n * exists, pi-git removes the lock and retries once it is certain the lock is\n * stale (no live process holds it and it is older than `lockStaleAfterMs`).\n * Users should never have to delete lock files by hand.\n */\nexport class GitService {\n  private rootPath?: string;\n\n  /** Fired after a stale git lock file was removed and the command retried. */\n  onStaleLockRemoved?: (lockPath: string) => void;\n\n  constructor(\n    private readonly exec: GitExecutor,\n    private readonly initialCwd: string,\n    private readonly defaultTimeout = DEFAULT_TIMEOUT_MS,\n    private readonly lockStaleAfterMs = DEFAULT_LOCK_STALE_AFTER_MS,\n  ) {}\n\n  async root(signal?: AbortSignal): Promise<string> {\n    if (this.rootPath) return this.rootPath;\n\n    const result = await this.execGitAllowFailure(\n        [\"rev-parse\", \"--show-toplevel\"],\n        { cwd: this.initialCwd, signal },\n    );\n    const root = result.stdout.trim();\n    if (result.code !== 0 || !root) {\n      throw new GitRepositoryError(\n        \"not-a-repository\",\n        result.stderr.trim() || \"The current directory is not a Git repository.\",\n      );\n    }\n    this.rootPath = path.resolve(root);\n    return this.rootPath;\n  }\n\n  async assertSupportedRepository(signal?: AbortSignal): Promise<{\n    root: string;\n    branchRef: string;\n    head: string;\n  }> {\n    const root = await this.root(signal);\n    const operation = await this.findOperationInProgress(root, signal);\n    if (operation) {\n      throw new GitRepositoryError(\n        \"operation-in-progress\",\n        `Cannot run a quick commit while a ${operation} is in progress.`,\n      );\n    }\n\n    const branchRef = await this.readBranchRef(signal);\n    if (!branchRef) {\n      throw new GitRepositoryError(\n        \"detached\",\n        \"Cannot run a quick commit while HEAD is detached.\",\n      );\n    }\n\n    const head = await this.readHead(signal);\n    if (!head) {\n      throw new GitRepositoryError(\n        \"unborn\",\n        \"Cannot run a quick commit in a repository with no commits yet.\",\n      );\n    }\n\n    return { root, branchRef, head };\n  }\n\n  async status(signal?: AbortSignal): Promise<GitStatusEntry[]> {\n    const result = await this.execGit(\n      [\"status\", \"--porcelain=v1\", \"-z\", \"--untracked-files=all\", \"--\", \".\"],\n      \"read repository status\",\n      { signal },\n    );\n    return parsePorcelainV1Z(result.stdout);\n  }\n\n  async stageAll(signal?: AbortSignal): Promise<void> {\n    await this.execGit(\n      [\"add\", \"--all\", \"--\", \".\"],\n      \"stage all changes\",\n      { signal, timeout: 30_000 },\n    );\n  }\n\n  async stagePath(filePath: string, signal?: AbortSignal): Promise<void> {\n    await this.execGit([\"add\", \"--\", filePath], \"stage file\", { signal });\n  }\n\n  async unstagePath(filePath: string, signal?: AbortSignal): Promise<void> {\n    await this.execGit([\"reset\", \"HEAD\", \"--\", filePath], \"unstage file\", { signal });\n  }\n\n  async hasStagedChanges(signal?: AbortSignal): Promise<boolean> {\n    const result = await this.execGitAllowFailure(\n        [\"diff\", \"--cached\", \"--quiet\", \"--\", \".\"],\n        { signal },\n    );\n    if (result.code === 0) return false;\n    if (result.code === 1) return true;\n    throw new GitOperationError(\"check staged changes\", [\"diff\", \"--cached\", \"--quiet\", \"--\", \".\"], result);\n  }\n\n  async stagedStat(signal?: AbortSignal): Promise<string> {\n    return (await this.diffCached([\"--stat\"], signal)).trim();\n  }\n\n  async stagedShortStat(signal?: AbortSignal): Promise<string> {\n    return (await this.diffCached([\"--shortstat\"], signal)).trim();\n  }\n\n  async stagedNameStatus(signal?: AbortSignal): Promise<string> {\n    return this.diffCached([\"--name-status\", \"-z\"], signal);\n  }\n\n  async stagedNumstat(signal?: AbortSignal): Promise<string> {\n    return this.diffCached([\"--numstat\", \"-z\"], signal);\n  }\n\n  async readStagedStatus(signal?: AbortSignal): Promise<string> {\n    const result = await this.execGit(\n      [\"status\", \"--porcelain=v1\", \"-z\", \"--untracked-files=all\", \"--\", \".\"],\n      \"read staged status\",\n      { signal },\n    );\n    return result.stdout;\n  }\n\n  async stagedDiff(signal?: AbortSignal): Promise<string> {\n    return this.stagedPatch(undefined, signal);\n  }\n\n  /** Read the staged patch with an explicit context width and no binary payload. */\n  async stagedPatch(unified?: number, signal?: AbortSignal): Promise<string> {\n    const extra = unified === undefined ? [] : [`--unified=${unified}`];\n    return this.diffCached(extra, signal, { timeout: 60_000 });\n  }\n\n  /** Capture all cheap staged evidence and two independently generated patches. */\n  async stagedEvidence(signal?: AbortSignal): Promise<GitStagedEvidenceRaw> {\n    const [snapshot, stat, status, shortStat, nameStatus, numstat, contextPatch, compactPatch] = await Promise.all([\n      this.maybeSnapshot(signal),\n      this.stagedStat(signal),\n      this.readStagedStatus(signal),\n      this.stagedShortStat(signal),\n      this.stagedNameStatus(signal),\n      this.stagedNumstat(signal),\n      this.stagedPatch(1, signal),\n      this.stagedPatch(0, signal),\n    ]);\n    if (!snapshot.indexTree) throw new Error(\"The Git index contains unmerged entries.\");\n    return { snapshot, stat, status, shortStat, nameStatus, numstat, contextPatch, compactPatch };\n  }\n\n  async readBranchRef(signal?: AbortSignal): Promise<string | undefined> {\n    const result = await this.execGitAllowFailure(\n        [\"symbolic-ref\", \"--quiet\", \"HEAD\"],\n        { signal },\n    );\n    if (result.code !== 0) return undefined;\n    const ref = result.stdout.trim();\n    return ref || undefined;\n  }\n\n  async readHead(signal?: AbortSignal): Promise<string | undefined> {\n    const result = await this.execGitAllowFailure(\n        [\"rev-parse\", \"--verify\", \"HEAD\"],\n        { signal },\n    );\n    if (result.code !== 0) return undefined;\n    const head = result.stdout.trim();\n    return head || undefined;\n  }\n\n  async writeIndexTree(signal?: AbortSignal): Promise<string> {\n    const result = await this.execGit([\"write-tree\"], \"write index tree\", { signal });\n    const tree = result.stdout.trim();\n    if (!tree) throw new Error(\"git write-tree returned an empty index tree.\");\n    return tree;\n  }\n\n  async snapshot(signal?: AbortSignal): Promise<GitSnapshot> {\n    const root = await this.root(signal);\n    const [branchRef, head, indexTree] = await Promise.all([\n      this.readBranchRef(signal),\n      this.readHead(signal),\n      this.writeIndexTree(signal),\n    ]);\n    if (!branchRef) throw new GitRepositoryError(\"detached\", \"HEAD is detached.\");\n    if (!head) throw new GitRepositoryError(\"unborn\", \"The repository has no commits yet.\");\n    return { root, branchRef, head, indexTree };\n  }\n\n  async maybeSnapshot(signal?: AbortSignal): Promise<GitMaybeSnapshot> {\n    const root = await this.root(signal);\n    const [branchRef, head, indexTree] = await Promise.all([\n      this.readBranchRef(signal),\n      this.readHead(signal),\n      this.readIndexTreeAllowFailure(signal),\n    ]);\n    return { root, branchRef, head, indexTree };\n  }\n\n  async commitFromFile(messageFile: string): Promise<void> {\n    await this.execGit(\n      [\"commit\", \"--file\", messageFile],\n      \"commit staged changes\",\n      { timeout: 120_000 },\n    );\n  }\n\n  async commitMessage(message: string, signal?: AbortSignal): Promise<void> {\n    await this.execGit(\n      [\"commit\", \"--message\", message],\n      \"commit staged changes\",\n      { timeout: 120_000, signal },\n    );\n  }\n\n  async headCommitMessage(signal?: AbortSignal): Promise<string> {\n    const result = await this.execGit(\n      [\"show\", \"--quiet\", \"--format=%B\", \"HEAD\"],\n      \"read latest commit message\",\n      { signal },\n    );\n    return result.stdout.trim();\n  }\n\n  async headCommitIsPushed(signal?: AbortSignal): Promise<boolean> {\n    const result = await this.execGitAllowFailure(\n        [\"branch\", \"--remotes\", \"--contains\", \"HEAD\"],\n        { signal },\n    );\n    return result.code === 0 && result.stdout.trim().length > 0;\n  }\n\n  async amendMessage(message: string, signal?: AbortSignal): Promise<void> {\n    await this.execGit(\n      [\"commit\", \"--amend\", \"--only\", \"--message\", message],\n      \"amend latest commit\",\n      { timeout: 120_000, signal },\n    );\n  }\n\n  async discardPath(entry: GitStatusEntry, signal?: AbortSignal): Promise<void> {\n    if (entry.index === \"?\" && entry.worktree === \"?\") {\n      await this.execGit([\"clean\", \"-fd\", \"--\", entry.path], \"discard untracked file\", { signal });\n      return;\n    }\n\n    if (entry.index === \"A\") {\n      await this.execGit([\"rm\", \"--cached\", \"--\", entry.path], \"unstage added file\", { signal });\n      await this.execGit([\"clean\", \"-fd\", \"--\", entry.path], \"discard added file\", { signal });\n      return;\n    }\n\n    await this.execGit(\n      [\"restore\", \"--source=HEAD\", \"--staged\", \"--worktree\", \"--\", entry.path],\n      \"discard file changes\",\n      { signal },\n    );\n  }\n\n  async listBranches(signal?: AbortSignal): Promise<{ current?: string | undefined; branches: string[] }> {\n    const [branchesResult, current] = await Promise.all([\n      this.execGit([\"for-each-ref\", \"--format=%(refname:short)\", \"refs/heads\"], \"list branches\", { signal }),\n      this.readBranchRef(signal),\n    ]);\n    return {\n      current: current?.replace(/^refs\\/heads\\//, \"\"),\n      branches: branchesResult.stdout.split(\"\\n\").map((branch) => branch.trim()).filter(Boolean),\n    };\n  }\n\n  async checkoutBranch(branch: string, signal?: AbortSignal): Promise<void> {\n    await this.execGit([\"checkout\", branch], \"switch branch\", { signal, timeout: 30_000 });\n  }\n\n  async createBranch(branch: string, signal?: AbortSignal): Promise<void> {\n    await this.execGit([\"checkout\", \"-b\", branch], \"create branch\", { signal, timeout: 30_000 });\n  }\n\n  async deleteBranch(branch: string, force = false, signal?: AbortSignal): Promise<void> {\n    await this.execGit([\"branch\", force ? \"-D\" : \"-d\", branch], \"delete branch\", { signal, timeout: 30_000 });\n  }\n\n  async pushBranch(branch: string, signal?: AbortSignal): Promise<void> {\n    await this.execGit([\"push\", \"origin\", branch], \"push branch\", { signal, timeout: 60_000 });\n  }\n\n  async pullRebase(branch: string, signal?: AbortSignal): Promise<void> {\n    await this.execGit([\"pull\", \"--rebase\", \"origin\", branch], \"pull branch\", { signal, timeout: 60_000 });\n  }\n\n  async fileDiff(filePath: string, untracked = false, signal?: AbortSignal): Promise<string> {\n    if (untracked || !(await this.readHead(signal))) {\n      return this.diffAgainstDevNull(filePath, signal);\n    }\n\n    const result = await this.execGit(\n      [\"diff\", \"HEAD\", \"--no-ext-diff\", \"--no-color\", \"--\", filePath],\n      \"read file diff\",\n      { signal, timeout: 30_000 },\n    );\n    return result.stdout;\n  }\n\n  /** Diff a file that has no HEAD version against the empty tree. */\n  private async diffAgainstDevNull(filePath: string, signal?: AbortSignal): Promise<string> {\n    const args = [\"diff\", \"--no-index\", \"--no-ext-diff\", \"--no-color\", \"--\", \"/dev/null\", filePath];\n    const result = await this.execGitAllowFailure(args, { signal, timeout: 30_000 });\n    if (result.code !== 0 && result.code !== 1) {\n      throw new GitOperationError(\"read file diff\", args, result);\n    }\n    return result.stdout || result.stderr;\n  }\n\n  private async findOperationInProgress(root: string, signal?: AbortSignal): Promise<string | undefined> {\n    for (const marker of COMMIT_OPERATION_MARKERS) {\n      const result = await this.execGitAllowFailure(\n        [\"rev-parse\", \"--git-path\", marker],\n        { cwd: root, signal },\n      );\n      if (result.code !== 0) continue;\n      const markerPath = result.stdout.trim();\n      if (!markerPath) continue;\n      try {\n        await fs.access(path.isAbsolute(markerPath) ? markerPath : path.resolve(root, markerPath));\n        if (marker === \"MERGE_HEAD\") return \"merge\";\n        if (marker === \"CHERRY_PICK_HEAD\") return \"cherry-pick\";\n        if (marker === \"REVERT_HEAD\") return \"revert\";\n        return \"rebase\";\n      } catch {\n        // The marker is absent. Continue checking the other operation types.\n      }\n    }\n    return undefined;\n  }\n\n  private async readIndexTreeAllowFailure(signal?: AbortSignal): Promise<string | undefined> {\n    const result = await this.execGitAllowFailure(\n        [\"write-tree\"],\n        { signal });\n    if (result.code !== 0) return undefined;\n    const tree = result.stdout.trim();\n    return tree || undefined;\n  }\n\n  /** Run `git diff --cached` with pi-git's shared completeness flags. */\n  private async diffCached(\n    extraArgs: string[],\n    signal?: AbortSignal,\n    execOptions: GitExecOptions = {},\n  ): Promise<string> {\n    const result = await this.execGit(\n      [\"diff\", \"--cached\", \"--no-ext-diff\", \"--no-color\", \"--src-prefix=a/\", \"--dst-prefix=b/\", \"--find-renames\", \"--find-copies\", ...extraArgs, \"--\", \".\"],\n      \"read staged diff\",\n      { signal, ...execOptions },\n    );\n    return result.stdout;\n  }\n\n  private async execGit(\n    args: string[],\n    operation: string,\n    options: GitExecOptions = {},\n  ): Promise<GitExecResult> {\n    return this.runWithLockRecovery(args, options, operation, true);\n  }\n\n  private async execGitAllowFailure(\n    args: string[],\n    options: GitExecOptions = {},\n  ): Promise<GitExecResult> {\n    return this.runWithLockRecovery(args, options, undefined, false);\n  }\n\n  private run(args: string[], options: GitExecOptions): Promise<GitExecResult> {\n    return this.exec(\"git\", args, {\n      cwd: options.cwd ?? (this.rootPath ?? this.initialCwd),\n      timeout: options.timeout ?? this.defaultTimeout,\n      signal: options.signal,\n    });\n  }\n\n  /**\n   * Run a git command, and when it fails on an existing lock file, remove the\n   * lock if it is provably stale and retry. Never deletes a lock a live process\n   * holds or one that is too fresh to be a leftover.\n   */\n  private async runWithLockRecovery(\n    args: string[],\n    options: GitExecOptions,\n    operation: string | undefined,\n    failHard: boolean,\n  ): Promise<GitExecResult> {\n    for (let attempt = 0; ; attempt += 1) {\n      const result = await this.run(args, options);\n      if (result.code === 0) return result;\n\n      if (attempt >= MAX_LOCK_RECOVERIES) return this.fail(result, args, operation, failHard, undefined);\n\n      const lockPath = extractLockPath(result.stderr);\n      if (!lockPath) return this.fail(result, args, operation, failHard, undefined);\n\n      if (!(await this.tryRemoveStaleLock(lockPath))) {\n        return this.fail(\n          result,\n          args,\n          operation,\n          failHard,\n          `The git lock file at ${lockPath} is still recent or actively held, so it was not removed; pi-git will clean it automatically once it is stale. Please retry in a moment.`,\n        );\n      }\n\n      this.onStaleLockRemoved?.(lockPath);\n    }\n  }\n\n  private fail(\n    result: GitExecResult,\n    args: string[],\n    operation: string | undefined,\n    failHard: boolean,\n    hint: string | undefined,\n  ): GitExecResult {\n    if (failHard && operation) {\n      throw new GitOperationError(operation, args, result, hint);\n    }\n    return result;\n  }\n\n  /**\n   * Remove a lock file only when it is stale: old enough to be a leftover and\n   * not held open by any live process. Returns true when the lock is gone\n   * (either removed here or already gone), making a retry safe.\n   */\n  private async tryRemoveStaleLock(lockPath: string): Promise<boolean> {\n    try {\n      const stat = await fs.stat(lockPath);\n      if (Date.now() - stat.mtimeMs < this.lockStaleAfterMs) return false;\n      if (await isLockFileHeld(lockPath)) return false;\n      await fs.rm(lockPath, { force: true });\n      return true;\n    } catch (error: unknown) {\n      if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return true;\n      return false;\n    }\n  }\n}\n\n/**\n * Git prints the offending lock pathname on the fatal line, single-quoted, e.g.\n * \"fatal: Unable to create '/repo/.git/index.lock': File exists.\". The pathname\n * itself is locale-independent, so matching on it keeps recovery working even\n * under a localized git.\n */\nfunction extractLockPath(stderr: string): string | undefined {\n  return /'([^']*\\.lock)'/i.exec(stderr)?.[1] || undefined;\n}\n\n/**\n * Best-effort check that no live process has the lock file open. Uses /proc on\n * Linux; elsewhere we rely on the age check alone.\n */\nasync function isLockFileHeld(lockPath: string): Promise<boolean> {\n  if (process.platform !== \"linux\") return false;\n  try {\n    for (const entry of await fs.readdir(\"/proc\")) {\n      if (!/^\\d+$/.test(entry)) continue;\n      try {\n        for (const fd of await fs.readdir(`/proc/${entry}/fd`)) {\n          try {\n            if ((await fs.readlink(`/proc/${entry}/fd/${fd}`)) === lockPath) return true;\n          } catch {\n            // The descriptor vanished between listing and reading.\n          }\n        }\n      } catch {\n        // The process exited between listings.\n      }\n    }\n  } catch {\n    // /proc is unavailable; fall back to the age check.\n  }\n  return false;\n}\n\n/** Parse NUL-delimited porcelain-v1 output without interpreting pathname bytes. */\nexport function parsePorcelainV1Z(output: string): GitStatusEntry[] {\n  const tokens = output.split(\"\\0\");\n  const entries: GitStatusEntry[] = [];\n\n  for (let index = 0; index < tokens.length; index += 1) {\n    const token = tokens[index];\n    if (!token || token.length < 3) continue;\n\n    const status = token.slice(0, 2);\n    if (token[2] !== \" \") continue;\n\n    const firstPath = token.slice(3);\n    const isRenameOrCopy = status[0] === \"R\" || status[0] === \"C\";\n    const nextPath = isRenameOrCopy ? tokens[index + 1] : undefined;\n    if (isRenameOrCopy && nextPath !== undefined) index += 1;\n\n    entries.push({\n      index: status[0] ?? \" \",\n      worktree: status[1] ?? \" \",\n      path: firstPath,\n      ...(isRenameOrCopy && nextPath !== undefined ? { originalPath: nextPath } : {}),\n    });\n  }\n\n  return entries;\n}\n\nexport function snapshotsMatch(a: GitMaybeSnapshot, b: GitMaybeSnapshot): boolean {\n  return a.root === b.root && a.branchRef === b.branchRef && a.head === b.head && a.indexTree === b.indexTree;\n}\n"}},"git-ui.ts":{"file":{"contents":"import type { ExtensionAPI, ExtensionContext } from \"@earendil-works/pi-coding-agent\";\nimport type { GitService, GitStatusEntry } from \"./git-service.js\";\nimport { runManualCommit, SmartCommitSession } from \"./commit-workflow.js\";\nimport { BranchDialog, type BranchDialogResult } from \"./ui/branch-dialog.js\";\nimport { DiffDialog, type DiffDialogResult } from \"./ui/diff-dialog.js\";\nimport { GitStatusDialog, type StatusDialogResult } from \"./ui/status-dialog.js\";\n\nexport async function openGitStatus(\n  pi: ExtensionAPI,\n  ctx: ExtensionContext,\n  git: GitService,\n  smart: SmartCommitSession,\n  commitStyle: string,\n): Promise<void> {\n  while (true) {\n    let entries: GitStatusEntry[];\n    try {\n      entries = await git.status();\n    } catch (error: unknown) {\n      ctx.ui.notify(formatError(error), \"error\");\n      return;\n    }\n    if (entries.length === 0) {\n      ctx.ui.notify(\"Working tree clean.\", \"info\");\n      return;\n    }\n\n    const result = await ctx.ui.custom<StatusDialogResult | undefined>((tui, theme, _keybindings, done) =>\n      new GitStatusDialog(tui, theme, git, entries, () => git.status(), done),\n    );\n    if (!result || result.action === \"close\") return;\n\n    if (result.action === \"commit\") {\n      const committed = await runManualCommit(pi, ctx, git);\n      if (committed) return;\n      continue;\n    }\n    if (result.action === \"smart\") {\n      const outcome = await smart.run(pi, ctx, git, commitStyle);\n      if (outcome === \"committed\") return;\n      continue;\n    }\n    if (result.action === \"branch\") {\n      await openBranchManager(ctx, git);\n      continue;\n    }\n    if (result.action === \"diff\") {\n      await openFileDiff(ctx, git, result.entry);\n      continue;\n    }\n    if (result.action === \"discard\") {\n      const confirmed = await ctx.ui.confirm(\"Discard changes\", `Discard changes to ${result.entry.path}?`);\n      if (confirmed) {\n        try {\n          await git.discardPath(result.entry);\n          ctx.ui.notify(`Discarded ${result.entry.path}`, \"info\");\n        } catch (error: unknown) {\n          ctx.ui.notify(formatError(error), \"error\");\n        }\n      }\n    }\n  }\n}\n\nexport async function openBranchManager(ctx: ExtensionContext, git: GitService): Promise<void> {\n  while (true) {\n    let branches;\n    try {\n      branches = await git.listBranches();\n    } catch (error: unknown) {\n      ctx.ui.notify(formatError(error), \"error\");\n      return;\n    }\n    const result = await ctx.ui.custom<BranchDialogResult | undefined>((tui, theme, _keybindings, done) =>\n      new BranchDialog(tui, theme, branches.branches, branches.current, done),\n    );\n    if (!result || result.action === \"cancel\") return;\n\n    try {\n      if (result.action === \"switch\") {\n        if (result.branch === branches.current) {\n          ctx.ui.notify(`Already on ${result.branch}.`, \"info\");\n          return;\n        }\n        await git.checkoutBranch(result.branch);\n        ctx.ui.notify(`Switched to ${result.branch}.`, \"info\");\n        return;\n      }\n      if (result.action === \"create\") {\n        await git.createBranch(result.branch);\n        ctx.ui.notify(`Created and switched to ${result.branch}.`, \"info\");\n        return;\n      }\n      if (result.action === \"delete\") {\n        const confirmed = await ctx.ui.confirm(\"Delete branch\", `Delete ${result.branch}?`);\n        if (confirmed) {\n          await git.deleteBranch(result.branch);\n          ctx.ui.notify(`Deleted ${result.branch}.`, \"info\");\n        }\n        continue;\n      }\n      if (result.action === \"push\") {\n        await git.pushBranch(result.branch);\n        ctx.ui.notify(`Pushed ${result.branch}.`, \"info\");\n        continue;\n      }\n      if (result.action === \"pull\") {\n        await git.pullRebase(result.branch);\n        ctx.ui.notify(`Pulled ${result.branch} with rebase.`, \"info\");\n        continue;\n      }\n    } catch (error: unknown) {\n      ctx.ui.notify(formatError(error), \"error\");\n    }\n  }\n}\n\nasync function openFileDiff(ctx: ExtensionContext, git: GitService, entry: GitStatusEntry): Promise<void> {\n  let content: string;\n  try {\n    content = await git.fileDiff(entry.path, entry.index === \"?\" && entry.worktree === \"?\");\n  } catch (error: unknown) {\n    ctx.ui.notify(formatError(error), \"error\");\n    return;\n  }\n  if (!content) {\n    ctx.ui.notify(`No diff for ${entry.path}.`, \"info\");\n    return;\n  }\n  const result = await ctx.ui.custom<DiffDialogResult | undefined>((tui, theme, _keybindings, done) =>\n    new DiffDialog(tui, theme, `diff: ${entry.path}`, content, done),\n  );\n  if (result?.action === \"chat\") {\n    await new Promise<void>((resolve) => setTimeout(resolve, 0));\n    ctx.ui.pasteToEditor(`Git diff for ${entry.path}\\n\\n\\`\\`\\`diff\\n${result.content}\\n\\`\\`\\`\\n`);\n  }\n}\n\nfunction formatError(error: unknown): string {\n  return error instanceof Error ? `Git workflow failed: ${error.message}` : `Git workflow failed: ${String(error)}`;\n}\n"}},"mechanical-diff.ts":{"file":{"contents":"/**\n * Detection of mechanical (whitespace-and-punctuation-only) staged changes.\n *\n * A diff where every file's removed and added body lines carry identical\n * identifier/number token sequences is a pure reformat: line wrapping,\n * indentation, and separator churn with zero change to names or values. Such\n * diffs get a deterministic commit message without any model call. Pure\n * functions; no Git or model dependencies.\n */\nimport type { GitStagedFile } from \"./evidence-parse.js\";\nimport { isGeneratedPath, isLockPath, isVendorPath } from \"./evidence-parse.js\";\n\ninterface BodyLines {\n  readonly added: string[];\n  readonly removed: string[];\n}\n\n/**\n * Reduce a body line to its ordered identifier/number tokens.\n *\n * Comparing token sequences (not raw text) absorbs punctuation movement from\n * reformatting - wrapped argument lists gain trailing commas, braces shift -\n * while still catching any change to actual names or numeric literals.\n */\nfunction normalize(line: string): string {\n  const tokens = line.match(/[\\p{L}\\p{N}_$]+/gu);\n  return tokens ? tokens.join(\"\") : \"\";\n}\n\n/** Parse a compact unified patch into per-path added/removed body lines. */\nexport function patchBodiesByPath(patch: string): Map<string, BodyLines> {\n  const bodies = new Map<string, BodyLines>();\n  let currentPath = \"\";\n  let entry: BodyLines = { added: [], removed: [] };\n  let inHunk = false;\n\n  const flush = () => {\n    if (currentPath) bodies.set(currentPath, entry);\n  };\n\n  for (const line of patch.split(\"\\n\")) {\n    if (line.startsWith(\"diff --git \")) {\n      flush();\n      currentPath = \"\";\n      entry = { added: [], removed: [] };\n      inHunk = false;\n      continue;\n    }\n    if (!currentPath) {\n      if (line.startsWith(\"+++ \")) {\n        let candidate = line.slice(4).trim();\n        if (candidate.startsWith('\"') && candidate.endsWith('\"')) candidate = candidate.slice(1, -1);\n        currentPath = candidate === \"/dev/null\" ? \"\" : /^(?:a|b|c|i)\\//.test(candidate) ? candidate.slice(2) : candidate;\n      }\n      continue;\n    }\n    if (line.startsWith(\"@@ \")) {\n      inHunk = true;\n      continue;\n    }\n    if (!inHunk || !currentPath) continue;\n    if (line.length > 0 && line[0] === \"+\" && !line.startsWith(\"+++\")) entry.added.push(normalize(line.slice(1)));\n    else if (line.length > 0 && line[0] === \"-\" && !line.startsWith(\"---\")) entry.removed.push(normalize(line.slice(1)));\n  }\n  flush();\n  return bodies;\n}\n\nexport interface MechanicalDiffVerdict {\n  /** True when every verifiable file is whitespace-only churn. */\n  readonly formattingOnly: boolean;\n  /** Paths that could not be verified (bodies unavailable), treated as neutral. */\n  readonly unverifiablePaths: readonly string[];\n}\n\n/** Low-signal files whose bodies were omitted by reduction count as mechanical churn. */\nfunction isLowSignalPath(path: string): boolean {\n  return isLockPath(path) || isVendorPath(path) || isGeneratedPath(path);\n}\n\n/**\n * Classify staged evidence as pure formatting.\n *\n * Files whose change bodies are not fully present in `compactPatch` can only\n * count as neutral when they are low-signal paths (lockfile, vendor, generated);\n * any other unverifiable file disqualifies the fast path. Binary files,\n * renames, and non-modify statuses always disqualify.\n */\nexport function classifyFormattingOnly(\n  files: readonly GitStagedFile[],\n  compactPatch: string,\n): MechanicalDiffVerdict {\n  const bodies = patchBodiesByPath(compactPatch);\n  const unverifiablePaths: string[] = [];\n\n  for (const file of files) {\n    if (file.binary || file.status[0] !== \"M\") return { formattingOnly: false, unverifiablePaths };\n\n    const entry = bodies.get(file.path);\n    // No patch section means the body was omitted by reduction; only known\n    // mechanical-churn paths may pass unverified.\n    if (!entry) {\n      if (!isLowSignalPath(file.path)) return { formattingOnly: false, unverifiablePaths };\n      unverifiablePaths.push(file.path);\n      continue;\n    }\n\n    const added = entry.added.filter((line) => line.length > 0).join(\"\");\n    const removed = entry.removed.filter((line) => line.length > 0).join(\"\");\n    if (added !== removed) return { formattingOnly: false, unverifiablePaths };\n  }\n\n  return { formattingOnly: true, unverifiablePaths };\n}\n\n/**\n * Commit message for a pure reformat, so both commit paths skip the model with\n * the same wording. Undefined when any change is not formatting-only; an empty\n * file list is never formatting-only, because there is nothing to commit.\n */\nexport function formattingOnlyMessage(\n  files: readonly GitStagedFile[],\n  compactPatch: string,\n): { readonly subject: string; readonly message: string } | undefined {\n  if (files.length === 0) return undefined;\n  if (!classifyFormattingOnly(files, compactPatch).formattingOnly) return undefined;\n\n  const only = files.length === 1 ? files[0] : undefined;\n  const subject = only\n    ? `style: format ${only.path}`\n    : `style: format ${files.length} files`;\n  return {\n    subject,\n    message: `${subject}\\n\\nWhitespace-only changes detected by pi-git; generated without a model call.`,\n  };\n}\n"}},"quick-commit.ts":{"file":{"contents":"import * as fs from \"node:fs/promises\";\nimport * as os from \"node:os\";\nimport * as path from \"node:path\";\nimport type { Api, AssistantMessage, Message, Model, ModelThinkingLevel } from \"@earendil-works/pi-ai\";\nimport { isAbortError } from \"./abort.js\";\nimport { formatUsageCostLine, type TokenTally } from \"./usage-format.js\";\nimport { GitService, snapshotsMatch } from \"./git-service.js\";\nimport {\n  captureStagedEvidence,\n  normalizeCommitIntent,\n  type CommitIntent,\n  type StagedEvidence,\n} from \"./commit-evidence.js\";\nimport { formattingOnlyMessage } from \"./mechanical-diff.js\";\nimport {\n  CommitMessageGenerator,\n  type CommitGenerationDiagnostics,\n  type CommitGenerationResult,\n  type CommitModelClient,\n} from \"./commit-generator.js\";\n\nexport type QuickCommitState =\n  | \"idle\"\n  | \"staging\"\n  | \"drafting\"\n  | \"validating\"\n  | \"finalizing\"\n  | \"committing\"\n  | \"succeeded\"\n  | \"cancelled\"\n  | \"stale\"\n  | \"failed\"\n  | \"timed_out\";\n\nexport interface QuickCommitModelRegistry {\n  complete(\n    model: Model<Api>,\n    context: { systemPrompt?: string; messages: Message[]; tools: [] },\n    options?: { signal?: AbortSignal; maxTokens?: number; reasoning?: ModelThinkingLevel },\n  ): Promise<AssistantMessage>;\n  hasConfiguredAuth?(model: Model<Api>): boolean;\n}\n\nexport interface QuickCommitUi {\n  readonly isAlive: () => boolean;\n  readonly notify: (message: string, level: \"info\" | \"warning\" | \"error\") => void;\n  /** Optional footer status surface used for the live quick-commit indicator. */\n  readonly setStatus?: (key: string, text: string | undefined) => void;\n}\n\nexport interface QuickCommitStartRequest {\n  readonly git: GitService;\n  readonly modelRegistry: QuickCommitModelRegistry;\n  readonly model?: Model<Api> | undefined;\n  readonly commitStyle: string;\n  readonly ui: QuickCommitUi;\n  /** Session thinking level forwarded to the model call. */\n  readonly thinkingLevel?: ModelThinkingLevel | undefined;\n  readonly timeoutMs?: number;\n  /** Explicit intent is supported for callers that do not want to commit blind. */\n  readonly intent?: CommitIntent | string | undefined;\n}\n\nexport type QuickCommitStartResult =\n  | { readonly accepted: true; readonly job: QuickCommitJob }\n  | { readonly accepted: false; readonly reason: \"active\" | \"inactive\" | \"model\" | \"auth\" };\n\nexport type QuickCommitCancelResult =\n  | \"cancelled\"\n  | \"too-late\"\n  | \"no-job\"\n  | \"inactive\";\n\nclass QuickCommitCancelled extends Error {\n  constructor() {\n    super(\"Quick commit cancelled\");\n    this.name = \"QuickCommitCancelled\";\n  }\n}\n\nclass QuickCommitTimedOut extends Error {\n  constructor() {\n    super(\"Quick commit timed out\");\n    this.name = \"QuickCommitTimedOut\";\n  }\n}\n\nclass CommitMessageGenerationError extends Error {\n  constructor(readonly code: string, reason: string, readonly usage?: TokenTally) {\n    super(`Generated commit message was rejected: ${reason}`);\n    this.name = \"CommitMessageGenerationError\";\n  }\n}\n\ninterface TempMessageFile {\n  readonly path: string;\n  readonly cleanup: () => Promise<void>;\n}\n\nconst DEFAULT_TIMEOUT_MS = 180_000;\n\nconst STATUS_KEY = \"pi-git:quick-commit\";\n/** nf-cod-git_pull_request */\nconst GIT_ICON = \"\\uEA64\";\n/** nf-fa-check */\nconst CHECK_ICON = \"\\uF00C\";\n/** Same braille frames pi's own working spinner uses. */\nconst SPINNER_FRAMES = [\"\\u280B\", \"\\u2819\", \"\\u2839\", \"\\u2838\", \"\\u283C\", \"\\u2834\", \"\\u2826\", \"\\u2827\", \"\\u2807\", \"\\u280F\"] as const;\nconst STATUS_INTERVAL_MS = 100;\n\nconst PHASE_LABELS: Partial<Record<QuickCommitState, string>> = {\n  staging: \"staging\",\n  drafting: \"drafting message\",\n  validating: \"validating\",\n  finalizing: \"finalizing\",\n  committing: \"committing\",\n};\n\nconst SETTLED_STATES: ReadonlySet<QuickCommitState> = new Set([\n  \"succeeded\",\n  \"cancelled\",\n  \"stale\",\n  \"failed\",\n  \"timed_out\",\n]);\n\n/**\n * Owns one background automatic commit. It deliberately accepts all mutable\n * dependencies at start time so an old command context is never consulted after\n * a reload.\n */\nexport class QuickCommitJob {\n  private stateValue: QuickCommitState = \"idle\";\n  private readonly abortController = new AbortController();\n  private cancellationRequested = false;\n  private timeoutRequested = false;\n  private finalizationStarted = false;\n  private deadlineTimer: ReturnType<typeof setTimeout> | undefined;\n  private settledValue = false;\n  private readonly settledPromise: Promise<QuickCommitState>;\n  private statusTimer: ReturnType<typeof setInterval> | undefined;\n  private spinnerFrame = 0;\n  private startedAt = 0;\n  private settle!: (state: QuickCommitState) => void;\n  private subject = \"\";\n  private diagnosticsValue: CommitGenerationDiagnostics | undefined;\n\n  constructor(private readonly request: QuickCommitStartRequest) {\n    this.settledPromise = new Promise<QuickCommitState>((resolve) => {\n      this.settle = resolve;\n    });\n  }\n\n  get state(): QuickCommitState {\n    return this.stateValue;\n  }\n\n  get isFinalizing(): boolean {\n    return this.finalizationStarted;\n  }\n\n  get isSettled(): boolean {\n    return this.settledValue;\n  }\n\n  wait(): Promise<QuickCommitState> {\n    return this.settledPromise;\n  }\n\n  start(): void {\n    // The caller intentionally does not await this promise. The catch at the\n    // boundary prevents a rejected background task from becoming unhandled.\n    this.startStatusAnimation();\n    void this.run().catch((error: unknown) => this.fail(error));\n  }\n\n  requestCancellation(): boolean {\n    if (this.settledValue || this.finalizationStarted) return false;\n    this.cancellationRequested = true;\n    this.abortController.abort();\n    return true;\n  }\n\n  private async run(): Promise<void> {\n    this.armDeadline();\n    try {\n      this.transition(\"staging\");\n      await this.request.git.assertSupportedRepository(this.abortController.signal);\n      await this.awaitAbortable(this.request.git.stageAll(this.abortController.signal));\n\n      if (!(await this.awaitAbortable(this.request.git.hasStagedChanges(this.abortController.signal)))) {\n        this.finish(\"succeeded\");\n        this.notify(\"Quick commit: no staged changes after staging.\", \"info\");\n        return;\n      }\n\n      const staged = await this.awaitAbortable<StagedEvidence>(captureStagedEvidence(this.request.git, this.abortController.signal));\n      if (staged.partial) {\n        this.notify(`Quick commit: large staged diff (${staged.partial.originalCompactBytes.toLocaleString()} bytes); using reduced evidence.`, \"info\");\n      }\n\n      // Pure reformatting gets a deterministic message without any model call.\n      const explicitIntent = typeof this.request.intent === \"string\"\n        ? normalizeCommitIntent(this.request.intent)\n        : this.request.intent;\n      const formattingOnly = explicitIntent === undefined\n        ? formattingOnlyMessage(staged.files, staged.compactPatch)\n        : undefined;\n      if (formattingOnly) {\n        await this.commitDeterministicFormatting(staged, formattingOnly.message, formattingOnly.subject);\n        return;\n      }\n\n      this.throwIfCancelled();\n      this.transition(\"drafting\");\n      const generated = await this.completeMessage(staged, explicitIntent);\n      if (!generated.ok) throw new CommitMessageGenerationError(generated.code, generated.reason, generated.diagnostics?.usage);\n\n      this.throwIfCancelled();\n      this.transition(\"validating\");\n      this.subject = generated.subject;\n      this.diagnosticsValue = generated.diagnostics;\n\n      this.throwIfCancelled();\n      this.finalizationStarted = true;\n      this.transition(\"finalizing\");\n      this.clearDeadline();\n\n      const current = await this.request.git.maybeSnapshot();\n      if (!snapshotsMatch(staged.snapshot, current)) {\n        this.finish(\"stale\");\n        this.notify(`Quick commit: the branch, HEAD, or index changed. Nothing was committed.${formatUsageCostLine(this.diagnosticsValue?.usage)}`, \"warning\");\n        return;\n      }\n\n      const temp = await createTemporaryMessageFile(generated.message);\n      let commitError: unknown;\n      try {\n        this.transition(\"committing\");\n        await this.request.git.commitFromFile(temp.path);\n      } catch (error) {\n        commitError = error;\n      } finally {\n        try {\n          await temp.cleanup();\n        } catch (cleanupError) {\n          commitError = commitError\n            ? new AggregateError([commitError, cleanupError], \"Commit and temporary-file cleanup both failed\")\n            : cleanupError;\n        }\n      }\n      if (commitError) throw commitError;\n\n      this.finish(\"succeeded\");\n      this.notify(this.completionNotice(this.subject), \"info\");\n    } catch (error: unknown) {\n      this.fail(error);\n    } finally {\n      this.clearDeadline();\n      this.resolveIfNeeded();\n    }\n  }\n\n  private async completeMessage(\n    evidence: StagedEvidence,\n    explicitIntent: CommitIntent | undefined,\n  ): Promise<CommitGenerationResult> {\n    const client: CommitModelClient = {\n      complete: (model, context, options) => this.request.modelRegistry.complete(model, context, options),\n    };\n    const generator = new CommitMessageGenerator(client);\n    const promise = generator.generate({\n      model: this.request.model as Model<Api>,\n      evidence,\n      style: this.request.commitStyle,\n      ...(explicitIntent === undefined ? {} : { intent: explicitIntent }),\n      ...(this.request.thinkingLevel === undefined ? {} : { reasoning: this.request.thinkingLevel }),\n      signal: this.abortController.signal,\n    });\n    return this.awaitAbortable(promise);\n  }\n\n  /** Deterministic commit for whitespace-only churn; no model round trip. */\n  private async commitDeterministicFormatting(staged: StagedEvidence, message: string, subject: string): Promise<void> {\n    this.throwIfCancelled();\n    this.transition(\"drafting\");\n    this.subject = subject;\n    this.finalizationStarted = true;\n    this.transition(\"finalizing\");\n    this.clearDeadline();\n\n    const current = await this.request.git.maybeSnapshot();\n    if (!snapshotsMatch(staged.snapshot, current)) {\n      this.finish(\"stale\");\n      this.notify(\"Quick commit: the branch, HEAD, or index changed. Nothing was committed.\", \"warning\");\n      return;\n    }\n\n    const temp = await createTemporaryMessageFile(message);\n    try {\n      this.transition(\"committing\");\n      await this.request.git.commitFromFile(temp.path);\n    } finally {\n      try {\n        await temp.cleanup();\n      } catch {\n        // The commit already succeeded; cleanup failures must not fail the job.\n      }\n    }\n\n    this.finish(\"succeeded\");\n    this.notify(this.completionNotice(subject), \"info\");\n  }\n\n  /** Mention a message that was recovered from a reply the provider cut off. */\n  private recoveredHint(): string {\n    return this.diagnosticsValue?.truncated\n      ? \"\\n  The reply was cut off, so the body keeps only the lines the model finished.\"\n      : \"\";\n  }\n\n  /** One completion shape for every quick commit, model-generated or deterministic. */\n  private completionNotice(subject: string): string {\n    return `${CHECK_ICON} Quick commit: complete\\n  ${subject}${this.recoveredHint()}${formatUsageCostLine(this.diagnosticsValue?.usage)}`;\n  }\n\n  private transition(next: QuickCommitState): void {\n    this.stateValue = next;\n  }\n\n  /** Live footer indicator; the phase label tracks stateValue on every tick. */\n  private startStatusAnimation(): void {\n    const ui = this.request.ui;\n    const setStatus = ui.setStatus;\n    if (!setStatus || this.statusTimer) return;\n    this.startedAt = Date.now();\n    this.spinnerFrame = 0;\n    const renderFrame = (): void => {\n      const spinner = SPINNER_FRAMES[this.spinnerFrame % SPINNER_FRAMES.length];\n      this.spinnerFrame += 1;\n      const elapsedSeconds = Math.floor((Date.now() - this.startedAt) / 1000);\n      const phase = PHASE_LABELS[this.stateValue] ?? this.stateValue;\n      setStatus(STATUS_KEY, `${spinner} ${GIT_ICON} quick commit: ${phase} ${elapsedSeconds}s`);\n    };\n    renderFrame();\n    this.statusTimer = setInterval(() => {\n      if (!ui.isAlive()) {\n        this.stopStatusAnimation();\n        return;\n      }\n      renderFrame();\n    }, STATUS_INTERVAL_MS);\n  }\n\n  private stopStatusAnimation(): void {\n    if (this.statusTimer) {\n      clearInterval(this.statusTimer);\n      this.statusTimer = undefined;\n    }\n    this.request.ui.setStatus?.(STATUS_KEY, undefined);\n  }\n\n  private finish(state: \"succeeded\" | \"stale\"): void {\n    this.stateValue = state;\n    this.stopStatusAnimation();\n    this.resolveIfNeeded();\n  }\n\n  private fail(error: unknown): void {\n    if (this.settledValue) return;\n    this.stopStatusAnimation();\n\n    if (this.cancellationRequested || error instanceof QuickCommitCancelled || isAbortError(error)) {\n      this.stateValue = \"cancelled\";\n      this.notify(\"Quick commit: cancelled.\", \"info\");\n      this.resolveIfNeeded();\n      return;\n    }\n\n    if (this.timeoutRequested || error instanceof QuickCommitTimedOut) {\n      this.stateValue = \"timed_out\";\n      this.notify(\"Quick commit: timed out before finalization.\", \"error\");\n      this.resolveIfNeeded();\n      return;\n    }\n\n    this.stateValue = \"failed\";\n    const spent = error instanceof CommitMessageGenerationError ? error.usage : undefined;\n    this.notify(`${formatFailure(error)}${formatUsageCostLine(spent)}`, \"error\");\n    this.resolveIfNeeded();\n  }\n\n  private throwIfCancelled(): void {\n    if (this.cancellationRequested || this.abortController.signal.aborted) {\n      if (this.timeoutRequested) throw new QuickCommitTimedOut();\n      throw new QuickCommitCancelled();\n    }\n  }\n\n  private armDeadline(): void {\n    const timeoutMs = this.request.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n    this.deadlineTimer = setTimeout(() => {\n      if (this.finalizationStarted || this.settledValue) return;\n      this.timeoutRequested = true;\n      this.abortController.abort();\n    }, timeoutMs);\n  }\n\n  private clearDeadline(): void {\n    if (this.deadlineTimer) {\n      clearTimeout(this.deadlineTimer);\n      this.deadlineTimer = undefined;\n    }\n  }\n\n  private awaitAbortable<T>(promise: Promise<T>): Promise<T> {\n    return new Promise<T>((resolve, reject) => {\n      let done = false;\n      const cleanup = () => {\n        this.abortController.signal.removeEventListener(\"abort\", onAbort);\n      };\n      const onAbort = () => {\n        if (done) return;\n        done = true;\n        cleanup();\n        reject(this.timeoutRequested ? new QuickCommitTimedOut() : new QuickCommitCancelled());\n      };\n\n      if (this.abortController.signal.aborted) {\n        onAbort();\n        return;\n      }\n\n      this.abortController.signal.addEventListener(\"abort\", onAbort, { once: true });\n      promise.then(\n        (value) => {\n          if (done) return;\n          done = true;\n          cleanup();\n          resolve(value);\n        },\n        (error: unknown) => {\n          if (done) return;\n          done = true;\n          cleanup();\n          reject(error);\n        },\n      );\n    });\n  }\n\n  private notify(message: string, level: \"info\" | \"warning\" | \"error\"): void {\n    if (this.request.ui.isAlive()) this.request.ui.notify(message, level);\n  }\n\n  private resolveIfNeeded(): void {\n    if (this.settledValue) return;\n    if (!SETTLED_STATES.has(this.stateValue)) return;\n    this.settledValue = true;\n    this.settle(this.stateValue);\n  }\n}\n\nexport class QuickCommitController {\n  private active = true;\n  private current?: QuickCommitJob;\n\n  get state(): QuickCommitState {\n    return this.current?.state ?? \"idle\";\n  }\n\n  get job(): QuickCommitJob | undefined {\n    return this.current;\n  }\n\n  start(request: QuickCommitStartRequest): QuickCommitStartResult {\n    if (!this.active) {\n      this.notify(request.ui, \"pi-git is shutting down; try again after reload.\", \"warning\");\n      return { accepted: false, reason: \"inactive\" };\n    }\n    if (this.current && !this.current.isSettled) {\n      this.notify(request.ui, \"A quick commit is already running.\", \"warning\");\n      return { accepted: false, reason: \"active\" };\n    }\n    if (!request.model) {\n      this.notify(request.ui, \"No model selected. Select a model before starting a quick commit.\", \"error\");\n      return { accepted: false, reason: \"model\" };\n    }\n    if (request.modelRegistry.hasConfiguredAuth && !request.modelRegistry.hasConfiguredAuth(request.model)) {\n      this.notify(request.ui, \"The selected model has no available authentication.\", \"error\");\n      return { accepted: false, reason: \"auth\" };\n    }\n\n    const job = new QuickCommitJob(request);\n    this.current = job;\n    job.start();\n    return { accepted: true, job };\n  }\n\n  cancel(ui: QuickCommitUi): QuickCommitCancelResult {\n    if (!this.active) return \"inactive\";\n    const job = this.current;\n    if (!job || job.isSettled) return \"no-job\";\n    if (job.isFinalizing) {\n      this.notify(ui, \"Quick commit: already finalizing; cancellation is too late.\", \"warning\");\n      return \"too-late\";\n    }\n    job.requestCancellation();\n    return \"cancelled\";\n  }\n\n  async prepareForReload(ui: QuickCommitUi): Promise<boolean> {\n    const job = this.current;\n    if (!job || job.isSettled) return true;\n    if (job.isFinalizing) {\n      this.notify(ui, \"Cannot reload while quick commit is finalizing or committing. Try again after it finishes.\", \"warning\");\n      return false;\n    }\n    job.requestCancellation();\n    await job.wait();\n    return !job.isFinalizing;\n  }\n\n  async shutdown(): Promise<void> {\n    this.active = false;\n    const job = this.current;\n    if (!job || job.isSettled) return;\n    if (!job.isFinalizing) job.requestCancellation();\n    await job.wait();\n  }\n\n  private notify(ui: QuickCommitUi, message: string, level: \"info\" | \"warning\" | \"error\"): void {\n    if (ui.isAlive()) ui.notify(message, level);\n  }\n}\n\nasync function createTemporaryMessageFile(message: string): Promise<TempMessageFile> {\n  const directory = await fs.mkdtemp(path.join(os.tmpdir(), \"pi-git-commit-\"));\n  const filePath = path.join(directory, \"message\");\n  try {\n    await fs.writeFile(filePath, message, { encoding: \"utf8\", mode: 0o600 });\n    await fs.chmod(filePath, 0o600);\n  } catch (error) {\n    await fs.rm(directory, { recursive: true, force: true });\n    throw error;\n  }\n\n  return {\n    path: filePath,\n    cleanup: async () => {\n      await fs.rm(directory, { recursive: true, force: true });\n    },\n  };\n}\n\n\nfunction formatFailure(error: unknown): string {\n  if (error instanceof Error) return `Quick commit failed: ${error.message}`;\n  return `Quick commit failed: ${String(error)}`;\n}\n"}},"register.ts":{"file":{"contents":"import type { ExtensionAPI, ExtensionCommandContext, ExtensionContext } from \"@earendil-works/pi-coding-agent\";\nimport type { Api, Model } from \"@earendil-works/pi-ai\";\nimport type { GitExecutor } from \"./git-service.js\";\nimport { GitService } from \"./git-service.js\";\nimport { loadCommitStyle } from \"./commit-message.js\";\nimport { QuickCommitController, type QuickCommitUi } from \"./quick-commit.js\";\nimport {\n  loadShortcutConfig,\n  writeShortcutConfig,\n  type ShortcutAction,\n  type ShortcutConfig,\n} from \"./shortcut-config.js\";\nimport { ShortcutSettingsDialog, type SettingsDialogResult } from \"./settings-dialog.js\";\nimport { openBranchManager, openGitStatus } from \"./git-ui.js\";\nimport { runAmendCommit, runManualCommit, SmartCommitSession } from \"./commit-workflow.js\";\n\nexport function registerPiGit(pi: ExtensionAPI): void {\n  const shortcutLoad = loadShortcutConfig();\n  const quickCommits = new QuickCommitController();\n  const smartCommit = new SmartCommitSession();\n  let alive = true;\n  let shortcutConfig: ShortcutConfig = shortcutLoad.config;\n\n  const makeGit = (ctx: ExtensionContext): GitService => {\n    const exec: GitExecutor = (command, args, options) =>\n      pi.exec(command, args, {\n        ...(options?.cwd === undefined ? {} : { cwd: options.cwd }),\n        ...(options?.timeout === undefined ? {} : { timeout: options.timeout }),\n        ...(options?.signal === undefined ? {} : { signal: options.signal }),\n      });\n    const git = new GitService(exec, ctx.cwd);\n    git.onStaleLockRemoved = (lockPath) => ctx.ui.notify(`Removed stale git lock ${lockPath}`, \"info\");\n    return git;\n  };\n\n  const makeUi = (ctx: ExtensionContext): QuickCommitUi => ({\n    isAlive: () => alive && ctx.mode === \"tui\",\n    notify: (message, level) => ctx.ui.notify(message, level),\n    setStatus: (key, text) => ctx.ui.setStatus(key, text),\n  });\n\n  const requireTui = (ctx: ExtensionContext): boolean => {\n    if (ctx.mode === \"tui\") return true;\n    if (ctx.hasUI) ctx.ui.notify(\"This pi-git command requires TUI mode.\", \"warning\");\n    return false;\n  };\n\n  const startQuickCommit = (ctx: ExtensionContext, args = \"\"): void => {\n    if (!requireTui(ctx)) return;\n    const command = args.trim().toLowerCase();\n    const ui = makeUi(ctx);\n    if (command === \"cancel\") {\n      quickCommits.cancel(ui);\n      return;\n    }\n    if (command) {\n      ctx.ui.notify(\"Usage: /git-quick-commit [cancel]\", \"warning\");\n      return;\n    }\n\n    quickCommits.start({\n      git: makeGit(ctx),\n      modelRegistry: ctx.modelRegistry,\n      model: resolveCommitModel(ctx, shortcutConfig.commitModel),\n      commitStyle: loadCommitStyle(ctx.cwd),\n      ...(ctx.thinkingLevel === undefined ? {} : { thinkingLevel: ctx.thinkingLevel }),\n      ui,\n    });\n  };\n\n  pi.registerCommand(\"git\", {\n    description: \"Open pi-git's interactive staging view\",\n    handler: async (_args, ctx) => {\n      if (!requireTui(ctx)) return;\n      await openGitStatus(pi, ctx, makeGit(ctx), smartCommit, loadCommitStyle(ctx.cwd));\n    },\n  });\n\n  pi.registerCommand(\"git-branch\", {\n    description: \"Manage Git branches\",\n    handler: async (_args, ctx) => {\n      if (!requireTui(ctx)) return;\n      await openBranchManager(ctx, makeGit(ctx));\n    },\n  });\n\n  pi.registerCommand(\"git-commit\", {\n    description: \"Commit staged changes, or open the manual commit editor\",\n    handler: async (args, ctx) => {\n      if (!requireTui(ctx)) return;\n      await runManualCommit(pi, ctx, makeGit(ctx), args.trim() ? { message: args.trim() } : {});\n    },\n  });\n\n  pi.registerCommand(\"git-amend\", {\n    description: \"Edit and amend the latest Git commit message\",\n    handler: async (_args, ctx) => {\n      if (!requireTui(ctx)) return;\n      await runAmendCommit(ctx, makeGit(ctx));\n    },\n  });\n\n  pi.registerCommand(\"git-smart-commit\", {\n    description: \"Generate a reviewable Git commit draft\",\n    handler: async (_args, ctx) => {\n      if (!requireTui(ctx)) return;\n      await smartCommit.run(pi, ctx, makeGit(ctx), loadCommitStyle(ctx.cwd), resolveCommitModel(ctx, shortcutConfig.commitModel));\n    },\n  });\n\n  pi.registerCommand(\"git-quick-commit\", {\n    description: \"Stage all changes, generate a message, and commit in the background\",\n    handler: async (args, ctx) => {\n      startQuickCommit(ctx, args);\n    },\n  });\n\n  pi.registerCommand(\"git-settings\", {\n    description: \"Configure pi-git's shortcuts and commit model\",\n    handler: async (_args, ctx) => {\n      if (!requireTui(ctx)) return;\n      await openSettings(ctx, quickCommits, shortcutConfig, makeUi(ctx));\n    },\n  });\n\n  registerGlobalShortcuts(pi, shortcutConfig, smartCommit, makeGit, startQuickCommit, requireTui);\n\n  pi.on(\"session_start\", async (_event, ctx) => {\n    alive = true;\n    for (const warning of shortcutLoad.warnings) ctx.ui.notify(warning, \"warning\");\n    if (shortcutLoad.warnings.length > 0) {\n      ctx.ui.notify(\"Run /git-settings to review pi-git settings.\", \"info\");\n    }\n  });\n\n  pi.on(\"session_shutdown\", async () => {\n    alive = false;\n    await quickCommits.shutdown();\n    smartCommit.clear();\n  });\n}\n\nasync function openSettings(\n  ctx: ExtensionCommandContext,\n  quickCommits: QuickCommitController,\n  currentConfig: ShortcutConfig,\n  ui: QuickCommitUi,\n): Promise<void> {\n  const result = await ctx.ui.custom<SettingsDialogResult | undefined>(\n    (tui, theme, _keybindings, done) => new ShortcutSettingsDialog(\n      tui,\n      theme,\n      currentConfig,\n      done,\n      modelOptions(ctx),\n    ),\n    { overlay: true },\n  );\n  if (!result || result.action === \"cancel\") return;\n\n  const ready = await quickCommits.prepareForReload(ui);\n  if (!ready) return;\n  try {\n    const target = writeShortcutConfig(result.config);\n    ctx.ui.notify(`Saved pi-git settings to ${target}; reloading.`, \"info\");\n  } catch (error: unknown) {\n    ctx.ui.notify(`Could not save pi-git settings: ${error instanceof Error ? error.message : String(error)}`, \"error\");\n    return;\n  }\n  await ctx.reload();\n}\n\nfunction modelOptions(ctx: ExtensionCommandContext): string[] {\n  const models = ctx.scopedModels.length > 0\n    ? ctx.scopedModels.map((entry) => entry.model)\n    : ctx.modelRegistry.getAvailable();\n  return models\n    .map((model) => `${model.provider}/${model.id}`)\n    .filter((value, index, all) => all.indexOf(value) === index)\n    .sort();\n}\n\nfunction resolveCommitModel(ctx: ExtensionContext, configured: string | undefined): Model<Api> | undefined {\n  if (!configured || configured.trim().toLowerCase() === \"current\") return ctx.model as Model<Api> | undefined;\n  const separator = configured.indexOf(\"/\");\n  if (separator <= 0 || separator === configured.length - 1) {\n    ctx.ui.notify(`Configured pi-git model is invalid: ${configured}`, \"warning\");\n    return undefined;\n  }\n  const model = ctx.modelRegistry.find(configured.slice(0, separator), configured.slice(separator + 1));\n  if (!model) {\n    ctx.ui.notify(`Configured pi-git model is not available: ${configured}`, \"warning\");\n    return undefined;\n  }\n  return model as Model<Api>;\n}\n\nfunction registerGlobalShortcuts(\n  pi: ExtensionAPI,\n  config: ShortcutConfig,\n  smartCommit: SmartCommitSession,\n  makeGit: (ctx: ExtensionContext) => GitService,\n  startQuickCommit: (ctx: ExtensionContext, args?: string) => void,\n  requireTui: (ctx: ExtensionContext) => boolean,\n): void {\n  const duplicateActions = new Set<ShortcutAction>();\n  const seen = new Map<string, ShortcutAction>();\n  for (const action of [\"openStatus\", \"quickCommit\"] as const) {\n    const key = config.shortcuts[action];\n    if (!key) continue;\n    const previous = seen.get(key);\n    if (previous) {\n      duplicateActions.add(previous);\n      duplicateActions.add(action);\n    } else {\n      seen.set(key, action);\n    }\n  }\n\n  const openStatus = config.shortcuts.openStatus;\n  if (openStatus && !duplicateActions.has(\"openStatus\")) {\n    pi.registerShortcut(openStatus, {\n      description: \"Open pi-git status\",\n      handler: async (ctx) => {\n        if (!requireTui(ctx)) return;\n        await openGitStatus(pi, ctx, makeGit(ctx), smartCommit, loadCommitStyle(ctx.cwd));\n      },\n    });\n  }\n\n  const quickCommit = config.shortcuts.quickCommit;\n  if (quickCommit && !duplicateActions.has(\"quickCommit\")) {\n    pi.registerShortcut(quickCommit, {\n      description: \"Run pi-git quick commit\",\n      handler: async (ctx) => {\n        startQuickCommit(ctx);\n      },\n    });\n  }\n\n\n}\n"}},"settings-dialog.ts":{"file":{"contents":"import type { Theme } from \"@earendil-works/pi-coding-agent\";\nimport {\n  Input,\n  Key,\n  matchesKey,\n  truncateToWidth,\n  wrapTextWithAnsi,\n  type Component,\n  type Focusable,\n  type TUI,\n} from \"@earendil-works/pi-tui\";\nimport {\n  DEFAULT_SHORTCUTS,\n  parseShortcut,\n  type ShortcutAction,\n  type ShortcutConfig,\n  DEFAULT_COMMIT_MODEL,\n  validateShortcutConfig,\n} from \"./shortcut-config.js\";\n\nexport type SettingsDialogResult =\n  | { readonly action: \"cancel\" }\n  | { readonly action: \"save\"; readonly config: ShortcutConfig };\n\nconst ACTIONS: ShortcutAction[] = [\"openStatus\", \"quickCommit\"];\nconst LABELS: Record<ShortcutAction, string> = {\n  openStatus: \"Open Git status\",\n  quickCommit: \"Quick commit\",\n};\n\nexport class ShortcutSettingsDialog implements Component, Focusable {\n  private readonly input = new Input();\n  private readonly values: Record<ShortcutAction, string>;\n  private commitModel: string;\n  private readonly modelOptions: readonly string[];\n  private selected = 0;\n  private editing = false;\n  private focusedValue = false;\n  private errorMessage: string | undefined;\n  private errorTimer: ReturnType<typeof setTimeout> | undefined;\n\n  constructor(\n    private readonly tui: TUI,\n    private readonly theme: Theme,\n    initial: ShortcutConfig,\n    private readonly done: (result: SettingsDialogResult) => void,\n    modelOptions: readonly string[] = [],\n  ) {\n    this.values = {\n      openStatus: initial.shortcuts.openStatus ?? \"none\",\n      quickCommit: initial.shortcuts.quickCommit ?? \"none\",\n    };\n    this.commitModel = initial.commitModel ?? DEFAULT_COMMIT_MODEL;\n    this.modelOptions = modelOptions;\n  }\n\n  get focused(): boolean {\n    return this.focusedValue;\n  }\n\n  set focused(value: boolean) {\n    this.focusedValue = value;\n    this.input.focused = value && this.editing;\n  }\n\n  handleInput(data: string): void {\n    if (this.editing) {\n      if (matchesKey(data, Key.escape) || matchesKey(data, Key.ctrl(\"c\"))) {\n        this.editing = false;\n        this.input.setValue(\"\");\n        this.errorMessage = undefined;\n        this.invalidate();\n        this.tui.requestRender();\n        return;\n      }\n      if (matchesKey(data, Key.enter)) {\n        this.finishEditing();\n        return;\n      }\n      if (this.selected === ACTIONS.length && this.modelOptions.length > 0 && (matchesKey(data, Key.up) || matchesKey(data, Key.down))) {\n        const direction = matchesKey(data, Key.up) ? -1 : 1;\n        const index = this.modelOptions.indexOf(this.input.getValue());\n        const next = this.modelOptions[(index + direction + this.modelOptions.length) % this.modelOptions.length];\n        if (next) this.input.setValue(next);\n        this.invalidate();\n        this.tui.requestRender();\n        return;\n      }\n      this.input.handleInput(data);\n      this.invalidate();\n      this.tui.requestRender();\n      return;\n    }\n\n    if (matchesKey(data, Key.escape) || matchesKey(data, Key.ctrl(\"c\"))) {\n      this.done({ action: \"cancel\" });\n      return;\n    }\n    if (matchesKey(data, Key.up) || data === \"k\") {\n      this.selected = (this.selected - 1 + ACTIONS.length) % ACTIONS.length;\n      this.invalidate();\n      this.tui.requestRender();\n      return;\n    }\n    if (matchesKey(data, Key.down) || data === \"j\") {\n      this.selected = (this.selected + 1) % ACTIONS.length;\n      this.invalidate();\n      this.tui.requestRender();\n      return;\n    }\n    if (matchesKey(data, Key.enter)) {\n      this.startEditing();\n      return;\n    }\n    if (data.toLowerCase() === \"m\") {\n      this.selected = ACTIONS.length;\n      this.startEditing();\n      return;\n    }\n    if (matchesKey(data, Key.ctrl(\"s\"))) {\n      this.save();\n      return;\n    }\n    if (data === \"r\") {\n      const setting = ACTIONS[this.selected];\n      if (setting) this.values[setting] = DEFAULT_SHORTCUTS[setting];\n      else if (this.selected === ACTIONS.length) this.commitModel = DEFAULT_COMMIT_MODEL;\n      this.invalidate();\n      this.tui.requestRender();\n      return;\n    }\n    if (matchesKey(data, Key.shift(\"r\"))) {\n      for (const action of ACTIONS) this.values[action] = DEFAULT_SHORTCUTS[action];\n      this.commitModel = DEFAULT_COMMIT_MODEL;\n      this.invalidate();\n      this.tui.requestRender();\n    }\n  }\n\n  render(width: number): string[] {\n    const padding = width > 1 ? 1 : 0;\n    const contentWidth = Math.max(0, width - padding * 2);\n    const wrapWidth = Math.max(1, contentWidth);\n    const renderLine = (line: string): string =>\n      `${\" \".repeat(padding)}${truncateToWidth(line, contentWidth)}${\" \".repeat(padding)}`;\n    const renderText = (text: string): string[] =>\n      wrapTextWithAnsi(text, wrapWidth).map((line) => renderLine(line));\n    const lines: string[] = [\n      ...renderText(\"\"),\n      ...renderText(this.theme.fg(\"accent\", this.theme.bold(\"pi-git settings\"))),\n      ...renderText(this.theme.fg(\"dim\", \"Configure pi-git's global shortcuts. Changes apply after reload.\")),\n      ...renderText(this.theme.fg(\"borderMuted\", \"─\".repeat(contentWidth))),\n    ];\n    if (this.errorMessage) lines.push(...renderText(this.theme.fg(\"error\", ` ${this.errorMessage}`)));\n\n    if (this.editing) {\n      const action = ACTIONS[this.selected];\n      const label = action ? LABELS[action] : \"Commit message model\";\n      lines.push(...renderText(this.theme.fg(\"accent\", ` Editing ${label}`)));\n      this.input.focused = this.focusedValue;\n      lines.push(...this.input.render(contentWidth).map((line) => renderLine(line)));\n      lines.push(...renderText(this.theme.fg(\"dim\", \" enter accept • esc cancel\")));\n    } else {\n      for (let index = 0; index < ACTIONS.length; index += 1) {\n        const setting = ACTIONS[index];\n        if (!setting) continue;\n        const marker = index === this.selected ? this.theme.fg(\"accent\", \"→ \") : \"  \";\n        const value = this.values[setting] || \"none\";\n        lines.push(...renderText(`${marker}${LABELS[setting]}: ${value}`));\n      }\n      lines.push(...renderText(`  Commit message model: ${this.commitModel}`));\n      if (this.modelOptions.length > 0) {\n        lines.push(...renderText(this.theme.fg(\"dim\", `  available: ${this.modelOptions.join(\", \")}`)));\n      }\n      lines.push(...renderText(this.theme.fg(\"borderMuted\", \"─\".repeat(contentWidth))));\n      lines.push(...renderText(this.theme.fg(\"dim\", \" ↑↓ select • enter edit • m edit model • ctrl+s save • r reset selected • shift+r reset all • esc cancel\")));\n    }\n    lines.push(...renderText(\"\"));\n    return lines;\n  }\n\n  invalidate(): void {\n    this.input.invalidate();\n  }\n\n  dispose(): void {\n    if (this.errorTimer) clearTimeout(this.errorTimer);\n  }\n\n  private startEditing(): void {\n    const action = ACTIONS[this.selected];\n    this.editing = true;\n    this.input.setValue(action ? this.values[action] : this.commitModel);\n    this.input.focused = this.focusedValue;\n    this.invalidate();\n    this.tui.requestRender();\n  }\n\n  private finishEditing(): void {\n    const action = ACTIONS[this.selected];\n    if (!action) {\n      const value = this.input.getValue().trim();\n      if (!value) {\n        this.showError(\"Model reference must not be empty.\");\n        return;\n      }\n      this.commitModel = value;\n      this.editing = false;\n      this.input.setValue(\"\");\n      this.invalidate();\n      this.tui.requestRender();\n      return;\n    }\n    const parsed = parseShortcut(this.input.getValue());\n    if (!parsed.ok) {\n      this.showError(parsed.error);\n      return;\n    }\n    this.values[action] = parsed.canonical;\n    this.editing = false;\n    this.input.setValue(\"\");\n    this.invalidate();\n    this.tui.requestRender();\n  }\n\n  private save(): void {\n    const openStatus = parseShortcut(this.values.openStatus);\n    const quickCommit = parseShortcut(this.values.quickCommit);\n    if (!openStatus.ok || !quickCommit.ok) {\n      const error = !openStatus.ok ? openStatus.error : !quickCommit.ok ? quickCommit.error : \"Invalid shortcut\";\n      this.showError(error);\n      return;\n    }\n    const config: ShortcutConfig = {\n      version: 1,\n      shortcuts: { openStatus: openStatus.value, quickCommit: quickCommit.value },\n      commitModel: this.commitModel,\n    };\n    const diagnostics = validateShortcutConfig(config);\n    if (diagnostics.errors.length > 0) {\n      this.showError(diagnostics.errors[0] ?? \"Duplicate shortcuts are not allowed.\");\n      return;\n    }\n    this.done({ action: \"save\", config });\n  }\n\n  private showError(message: string): void {\n    if (this.errorTimer) clearTimeout(this.errorTimer);\n    this.errorMessage = message;\n    this.errorTimer = setTimeout(() => {\n      this.errorMessage = undefined;\n      this.tui.requestRender();\n    }, 4_000);\n    this.invalidate();\n    this.tui.requestRender();\n  }\n}\n"}},"shortcut-config.ts":{"file":{"contents":"import * as fs from \"node:fs\";\nimport * as os from \"node:os\";\nimport * as path from \"node:path\";\nimport type { KeyId } from \"@earendil-works/pi-tui\";\n\nexport const DEFAULT_SHORTCUTS = {\n  openStatus: \"ctrl+\\\\\",\n  quickCommit: \"alt+g\",\n} as const;\n\nexport const DEFAULT_COMMIT_MODEL = \"current\";\n\nexport type ShortcutAction = keyof typeof DEFAULT_SHORTCUTS;\nexport type ShortcutValue = KeyId | undefined;\n\nexport interface ShortcutConfig {\n  readonly version: 1;\n  readonly shortcuts: Readonly<Record<ShortcutAction, ShortcutValue>>;\n  /** Model ref used for smart and quick commit generation, or `current`. */\n  readonly commitModel?: string;\n}\n\nexport interface ShortcutDiagnostics {\n  readonly warnings: string[];\n  readonly errors: string[];\n  readonly duplicates: ReadonlyArray<Readonly<{ key: KeyId; actions: ShortcutAction[] }>>;\n}\n\nexport interface LoadedShortcutConfig extends ShortcutDiagnostics {\n  readonly config: ShortcutConfig;\n  readonly path: string;\n  readonly sourcePath?: string;\n}\n\nexport type ShortcutParseResult =\n  | { readonly ok: true; readonly value: ShortcutValue; readonly canonical: string }\n  | { readonly ok: false; readonly error: string };\n\nconst MODIFIERS = [\"ctrl\", \"shift\", \"alt\", \"super\"] as const;\nconst SPECIAL_KEYS = new Map<string, string>([\n  [\"esc\", \"escape\"],\n  [\"escape\", \"escape\"],\n  [\"return\", \"enter\"],\n  [\"enter\", \"enter\"],\n  [\"pageup\", \"pageUp\"],\n  [\"pagedown\", \"pageDown\"],\n  [\"backspace\", \"backspace\"],\n  [\"delete\", \"delete\"],\n  [\"insert\", \"insert\"],\n  [\"clear\", \"clear\"],\n  [\"home\", \"home\"],\n  [\"end\", \"end\"],\n  [\"up\", \"up\"],\n  [\"down\", \"down\"],\n  [\"left\", \"left\"],\n  [\"right\", \"right\"],\n  ...Array.from({ length: 12 }, (_, index) => [`f${index + 1}`, `f${index + 1}`] as const),\n]);\nconst SYMBOL_KEYS = new Set([\"`\", \"-\", \"=\", \"[\", \"]\", \"\\\\\", \";\", \"'\", \",\", \".\", \"/\", \"!\", \"@\", \"#\", \"$\", \"%\", \"^\", \"&\", \"*\", \"(\", \")\", \"_\", \"+\", \"|\", \"~\", \"{\", \"}\", \":\", \"<\", \">\", \"?\"]);\nconst COMMON_PI_BINDINGS = new Set([\n  \"escape\",\n  \"ctrl+c\",\n  \"ctrl+d\",\n  \"ctrl+g\",\n  \"ctrl+l\",\n  \"ctrl+p\",\n  \"ctrl+shift+p\",\n  \"ctrl+o\",\n  \"ctrl+t\",\n  \"shift+tab\",\n  \"alt+enter\",\n]);\n\nexport function parseShortcut(value: unknown): ShortcutParseResult {\n  if (value === undefined || value === null) {\n    return { ok: true, value: undefined, canonical: \"none\" };\n  }\n  if (typeof value !== \"string\") {\n    return { ok: false, error: \"Shortcut must be a string, empty, or none.\" };\n  }\n\n  const input = value.trim().toLowerCase();\n  if (input === \"\" || input === \"none\") {\n    return { ok: true, value: undefined, canonical: \"none\" };\n  }\n\n  const modifiers: string[] = [];\n  let remaining = input;\n  while (true) {\n    const match = remaining.match(/^(ctrl|shift|alt|super)\\+/);\n    if (!match) break;\n    const modifier = match[1];\n    if (!modifier || modifiers.includes(modifier)) {\n      return { ok: false, error: `Shortcut has a duplicate modifier: ${modifier ?? \"unknown\"}.` };\n    }\n    modifiers.push(modifier);\n    remaining = remaining.slice(match[0].length);\n  }\n\n  if (!remaining) return { ok: false, error: \"Shortcut is missing its key.\" };\n  const special = SPECIAL_KEYS.get(remaining);\n  const isLetterOrDigit = /^[a-z0-9]$/.test(remaining);\n  if (!special && !isLetterOrDigit && !SYMBOL_KEYS.has(remaining)) {\n    return { ok: false, error: `Unsupported key: ${remaining}.` };\n  }\n\n  const orderedModifiers = MODIFIERS.filter((modifier) => modifiers.includes(modifier));\n  const key = special ?? remaining;\n  const canonical = [...orderedModifiers, key].join(\"+\");\n  return { ok: true, value: canonical as KeyId, canonical };\n}\n\nexport function parseShortcutConfig(raw: unknown): {\n  readonly config: ShortcutConfig;\n  readonly diagnostics: ShortcutDiagnostics;\n} {\n  const warnings: string[] = [];\n  const errors: string[] = [];\n  const value = isRecord(raw) ? raw : {};\n  if (raw !== undefined && !isRecord(raw)) {\n    errors.push(\"Configuration must be a JSON object.\");\n  }\n  if (value.version !== undefined && value.version !== 1) {\n    errors.push(\"Only shortcut configuration version 1 is supported.\");\n  }\n\n  const rawShortcuts = isRecord(value.shortcuts) ? value.shortcuts : {};\n  const rawCommitModel = value.commitModel;\n  const commitModel = rawCommitModel === undefined ? DEFAULT_COMMIT_MODEL : rawCommitModel;\n  if (typeof commitModel !== \"string\" || commitModel.trim() === \"\") {\n    errors.push(\"commitModel must be a non-empty model reference or current.\");\n  }\n  if (value.shortcuts !== undefined && !isRecord(value.shortcuts)) {\n    errors.push(\"The shortcuts field must be an object.\");\n  }\n  const shortcuts: Record<ShortcutAction, ShortcutValue> = {\n    openStatus: undefined,\n    quickCommit: undefined,\n  };\n  for (const action of Object.keys(DEFAULT_SHORTCUTS) as ShortcutAction[]) {\n    const candidate = rawShortcuts[action];\n    const parsed = parseShortcut(candidate === undefined ? DEFAULT_SHORTCUTS[action] : candidate);\n    if (!parsed.ok) {\n      errors.push(`${action}: ${parsed.error}`);\n      shortcuts[action] = defaultShortcutValue(action);\n    } else {\n      shortcuts[action] = parsed.value;\n    }\n  }\n\n  const byKey = new Map<KeyId, ShortcutAction[]>();\n  for (const action of Object.keys(shortcuts) as ShortcutAction[]) {\n    const key = shortcuts[action];\n    if (!key) continue;\n    const actions = byKey.get(key) ?? [];\n    actions.push(action);\n    byKey.set(key, actions);\n    if (COMMON_PI_BINDINGS.has(key)) {\n      warnings.push(`${action} uses ${key}, which may collide with a pi built-in shortcut.`);\n    }\n  }\n\n  const duplicates: Array<{ key: KeyId; actions: ShortcutAction[] }> = [];\n  for (const [key, actions] of byKey) {\n    if (actions.length > 1) {\n      duplicates.push({ key, actions });\n      errors.push(`The pi-git shortcuts ${actions.join(\" and \")} use the same key: ${key}.`);\n    }\n  }\n\n  return {\n    config: {\n      version: 1,\n      shortcuts,\n      commitModel: typeof commitModel === \"string\" && commitModel.trim() ? commitModel.trim() : DEFAULT_COMMIT_MODEL,\n    },\n    diagnostics: { warnings, errors, duplicates },\n  };\n}\n\nexport function loadShortcutConfig(\n  env: NodeJS.ProcessEnv = process.env,\n  homeDirectory = os.homedir(),\n): LoadedShortcutConfig {\n  const configuredDir = env.PI_CODING_AGENT_DIR?.trim();\n  const fallbackPath = path.join(homeDirectory, \".pi\", \"agent\", \"pi-git.json\");\n  const primaryPath = path.join(configuredDir || path.join(homeDirectory, \".pi\", \"agent\"), \"pi-git.json\");\n  const candidates = primaryPath === fallbackPath ? [primaryPath] : [primaryPath, fallbackPath];\n\n  const warnings: string[] = [];\n  const errors: string[] = [];\n  let sourcePath: string | undefined;\n  let raw: unknown;\n  for (const candidate of candidates) {\n    try {\n      raw = JSON.parse(fs.readFileSync(candidate, \"utf8\")) as unknown;\n      sourcePath = candidate;\n      break;\n    } catch (error: unknown) {\n      if (isFileNotFound(error)) continue;\n      warnings.push(`Could not read ${candidate}; using default pi-git settings.`);\n      break;\n    }\n  }\n\n  const parsed = parseShortcutConfig(raw);\n  warnings.push(...parsed.diagnostics.warnings);\n  errors.push(...parsed.diagnostics.errors);\n  if (errors.length > 0) {\n    warnings.push(...errors.map((error) => `Invalid pi-git configuration: ${error}`));\n  }\n\n  return {\n    config: parsed.config,\n    warnings,\n    errors,\n    duplicates: parsed.diagnostics.duplicates,\n    path: primaryPath,\n    ...(sourcePath ? { sourcePath } : {}),\n  };\n}\n\nexport function validateShortcutConfig(config: ShortcutConfig): ShortcutDiagnostics {\n  return parseShortcutConfig({\n    version: config.version,\n    shortcuts: {\n      openStatus: config.shortcuts.openStatus ?? \"none\",\n      quickCommit: config.shortcuts.quickCommit ?? \"none\",\n    },\n    commitModel: config.commitModel ?? DEFAULT_COMMIT_MODEL,\n  }).diagnostics;\n}\n\nexport function writeShortcutConfig(\n  config: ShortcutConfig,\n  env: NodeJS.ProcessEnv = process.env,\n  homeDirectory = os.homedir(),\n): string {\n  const diagnostics = validateShortcutConfig(config);\n  if (diagnostics.errors.length > 0) {\n    throw new Error(diagnostics.errors.join(\" \"));\n  }\n\n  const directory = env.PI_CODING_AGENT_DIR?.trim() || path.join(homeDirectory, \".pi\", \"agent\");\n  const target = path.join(directory, \"pi-git.json\");\n  fs.mkdirSync(directory, { recursive: true, mode: 0o700 });\n  const temporary = path.join(directory, `.pi-git.${process.pid}.${Date.now()}.tmp`);\n  const serializable = {\n    version: 1,\n    shortcuts: {\n      openStatus: config.shortcuts.openStatus ?? \"none\",\n      quickCommit: config.shortcuts.quickCommit ?? \"none\",\n    },\n    commitModel: config.commitModel ?? DEFAULT_COMMIT_MODEL,\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 atomic rename already completed. Permissions are best effort on platforms that ignore chmod.\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\nexport function resetShortcut(config: ShortcutConfig, action: ShortcutAction): ShortcutConfig {\n  return {\n    version: 1,\n    shortcuts: {\n      ...config.shortcuts,\n      [action]: defaultShortcutValue(action),\n    },\n  };\n}\n\nexport function resetAllShortcuts(): ShortcutConfig {\n  return {\n    version: 1,\n    shortcuts: {\n      openStatus: defaultShortcutValue(\"openStatus\"),\n      quickCommit: defaultShortcutValue(\"quickCommit\"),\n    },\n  };\n}\n\nexport function shortcutHelp(config: ShortcutConfig): string[] {\n  const format = (value: ShortcutValue) => value ?? \"disabled\";\n  return [\n    `Open Git status: ${format(config.shortcuts.openStatus)}`,\n    `Quick commit: ${format(config.shortcuts.quickCommit)}`,\n  ];\n}\n\nfunction defaultShortcutValue(action: ShortcutAction): ShortcutValue {\n  const parsed = parseShortcut(DEFAULT_SHORTCUTS[action]);\n  return parsed.ok ? parsed.value : undefined;\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"}},"ui":{"directory":{"branch-dialog.ts":{"file":{"contents":"import type { Theme } from \"@earendil-works/pi-coding-agent\";\nimport {\n  Input,\n  Key,\n  matchesKey,\n  truncateToWidth,\n  type Component,\n  type Focusable,\n  type TUI,\n} from \"@earendil-works/pi-tui\";\n\nexport type BranchDialogResult =\n  | { readonly action: \"cancel\" }\n  | { readonly action: \"switch\"; readonly branch: string }\n  | { readonly action: \"create\"; readonly branch: string }\n  | { readonly action: \"delete\"; readonly branch: string }\n  | { readonly action: \"push\"; readonly branch: string }\n  | { readonly action: \"pull\"; readonly branch: string };\n\nexport class BranchDialog implements Component, Focusable {\n  private readonly input = new Input();\n  private focusedValue = false;\n  private selected = 0;\n  private filtered: string[];\n\n  constructor(\n    private readonly tui: TUI,\n    private readonly theme: Theme,\n    private readonly branches: string[],\n    private readonly currentBranch: string | undefined,\n    private readonly done: (result: BranchDialogResult) => void,\n  ) {\n    this.filtered = [...branches];\n  }\n\n  get focused(): boolean {\n    return this.focusedValue;\n  }\n\n  set focused(value: boolean) {\n    this.focusedValue = value;\n    this.input.focused = value;\n  }\n\n  handleInput(data: string): void {\n    if (matchesKey(data, Key.escape) || matchesKey(data, Key.ctrl(\"c\"))) {\n      this.done({ action: \"cancel\" });\n      return;\n    }\n    if (matchesKey(data, Key.up)) {\n      this.selected = this.filtered.length === 0 ? 0 : (this.selected - 1 + this.filtered.length) % this.filtered.length;\n      this.invalidate();\n      this.tui.requestRender();\n      return;\n    }\n    if (matchesKey(data, Key.down)) {\n      this.selected = this.filtered.length === 0 ? 0 : (this.selected + 1) % this.filtered.length;\n      this.invalidate();\n      this.tui.requestRender();\n      return;\n    }\n    if (matchesKey(data, Key.enter)) {\n      const typed = this.input.getValue().trim();\n      const selected = this.filtered[this.selected];\n      if (selected) this.done({ action: \"switch\", branch: selected });\n      else if (typed) this.done({ action: \"create\", branch: typed });\n      return;\n    }\n    if (matchesKey(data, Key.delete)) {\n      const selected = this.filtered[this.selected];\n      if (selected && selected !== this.currentBranch) this.done({ action: \"delete\", branch: selected });\n      return;\n    }\n    if (matchesKey(data, Key.ctrl(\"p\"))) {\n      const selected = this.filtered[this.selected];\n      if (selected) this.done({ action: \"push\", branch: selected });\n      return;\n    }\n    if (matchesKey(data, Key.ctrl(\"l\"))) {\n      const selected = this.filtered[this.selected];\n      if (selected) this.done({ action: \"pull\", branch: selected });\n      return;\n    }\n\n    this.input.handleInput(data);\n    this.updateFilter();\n    this.tui.requestRender();\n  }\n\n  render(width: number): string[] {\n    const lines = [\n      truncateToWidth(` ${this.theme.fg(\"accent\", this.theme.bold(\"Branches\"))} ${this.theme.fg(\"dim\", this.currentBranch ?? \"detached\")}`, width),\n      truncateToWidth(this.theme.fg(\"borderMuted\", \"─\".repeat(Math.max(0, width))), width),\n    ];\n    this.input.focused = this.focusedValue;\n    lines.push(...this.input.render(width));\n    const visible = Math.min(12, this.filtered.length);\n    const start = Math.max(0, Math.min(this.selected - Math.floor(visible / 2), Math.max(0, this.filtered.length - visible)));\n    for (let index = start; index < Math.min(this.filtered.length, start + visible); index += 1) {\n      const branch = this.filtered[index];\n      if (!branch) continue;\n      const marker = index === this.selected ? this.theme.fg(\"accent\", \"→ \") : \"  \";\n      const current = branch === this.currentBranch ? this.theme.fg(\"success\", \" *\") : \"\";\n      lines.push(truncateToWidth(`${marker}${branch}${current}`, width));\n    }\n    if (this.filtered.length === 0) {\n      const typed = this.input.getValue().trim();\n      lines.push(truncateToWidth(this.theme.fg(\"dim\", typed ? ` Create ${typed}` : \" No matching branches\"), width));\n    }\n    lines.push(truncateToWidth(this.theme.fg(\"borderMuted\", \"─\".repeat(Math.max(0, width))), width));\n    lines.push(truncateToWidth(this.theme.fg(\"dim\", \" type filter • enter switch/create • ctrl+p push • ctrl+l pull • del delete • esc cancel\"), width));\n    return lines;\n  }\n\n  invalidate(): void {\n    this.input.invalidate();\n  }\n\n  private updateFilter(): void {\n    const query = this.input.getValue().trim().toLowerCase();\n    this.filtered = query ? this.branches.filter((branch) => branch.toLowerCase().includes(query)) : [...this.branches];\n    this.selected = Math.min(this.selected, Math.max(0, this.filtered.length - 1));\n  }\n}\n"}},"commit-editor.ts":{"file":{"contents":"import type { Theme } from \"@earendil-works/pi-coding-agent\";\nimport {\n  Editor,\n  Key,\n  matchesKey,\n  truncateToWidth,\n  type Component,\n  type Focusable,\n  type TUI,\n} from \"@earendil-works/pi-tui\";\n\nexport interface CommitEditorResult {\n  readonly action: \"commit\" | \"rewrite\" | \"graphite\" | \"cancel\";\n  readonly message: string;\n}\n\nexport interface CommitEditorOptions {\n  readonly heading?: string;\n  readonly allowRewrite?: boolean;\n  readonly allowGraphite?: boolean;\n  readonly cursorAtStart?: boolean;\n}\n\nexport class CommitEditor implements Component, Focusable {\n  private readonly editor: Editor;\n  private focusedValue = false;\n  private readonly options: Required<CommitEditorOptions>;\n\n  constructor(\n    private readonly tui: TUI,\n    private readonly theme: Theme,\n    private readonly stagedStat: string,\n    prefill: string,\n    private readonly done: (result: CommitEditorResult) => void,\n    options: CommitEditorOptions = {},\n  ) {\n    this.options = {\n      heading: options.heading ?? \"Commit message\",\n      allowRewrite: options.allowRewrite ?? true,\n      allowGraphite: options.allowGraphite ?? true,\n      cursorAtStart: options.cursorAtStart ?? false,\n    };\n    this.editor = new Editor(\n      tui,\n      {\n        borderColor: (text: string) => theme.fg(\"borderMuted\", text),\n        selectList: {\n          selectedPrefix: (text: string) => theme.fg(\"accent\", text),\n          selectedText: (text: string) => theme.fg(\"accent\", text),\n          description: (text: string) => theme.fg(\"muted\", text),\n          scrollInfo: (text: string) => theme.fg(\"dim\", text),\n          noMatch: (text: string) => theme.fg(\"warning\", text),\n        },\n      },\n      { paddingX: 1 },\n    );\n    this.editor.disableSubmit = true;\n    this.editor.setText(prefill);\n    if (this.options.cursorAtStart) this.moveCursorToStart();\n    this.editor.onChange = () => {\n      this.invalidate();\n      this.tui.requestRender();\n    };\n  }\n\n  get focused(): boolean {\n    return this.focusedValue;\n  }\n\n  set focused(value: boolean) {\n    this.focusedValue = value;\n    this.editor.focused = value;\n  }\n\n  handleInput(data: string): void {\n    if (matchesKey(data, Key.escape) || matchesKey(data, Key.ctrl(\"c\"))) {\n      this.done({ action: \"cancel\", message: \"\" });\n      return;\n    }\n    if (matchesKey(data, Key.ctrl(\"s\"))) {\n      this.done({ action: \"commit\", message: this.message() });\n      return;\n    }\n    if (matchesKey(data, Key.ctrl(\"r\"))) {\n      if (this.options.allowRewrite) this.done({ action: \"rewrite\", message: this.message() });\n      return;\n    }\n    if (matchesKey(data, Key.ctrl(\"g\"))) {\n      if (this.options.allowGraphite) this.done({ action: \"graphite\", message: this.message() });\n      return;\n    }\n    if (matchesKey(data, Key.enter)) {\n      this.editor.insertTextAtCursor(\"\\n\");\n      this.tui.requestRender();\n      return;\n    }\n\n    this.editor.focused = this.focusedValue;\n    this.editor.handleInput(data);\n    this.invalidate();\n    this.tui.requestRender();\n  }\n\n  render(width: number): string[] {\n    const lines: string[] = [truncateToWidth(` ${this.theme.fg(\"accent\", this.theme.bold(this.options.heading))}`, width)];\n    this.editor.focused = this.focusedValue;\n    lines.push(...this.editor.render(width));\n    if (this.stagedStat) {\n      lines.push(truncateToWidth(this.theme.fg(\"dim\", \" Staged changes:\"), width));\n      for (const statLine of this.stagedStat.split(\"\\n\").slice(0, 7)) {\n        lines.push(truncateToWidth(this.theme.fg(\"dim\", `  ${statLine}`), width));\n      }\n    }\n    lines.push(truncateToWidth(this.theme.fg(\"borderMuted\", \"─\".repeat(Math.max(0, width))), width));\n    const actions = [\"enter newline\", \"ctrl+s save\"];\n    if (this.options.allowRewrite) actions.push(\"ctrl+r rewrite\");\n    if (this.options.allowGraphite) actions.push(\"ctrl+g Graphite\");\n    actions.push(\"esc cancel\");\n    lines.push(truncateToWidth(this.theme.fg(\"dim\", ` ${actions.join(\" • \")}`), width));\n    return lines;\n  }\n\n  invalidate(): void {\n    this.editor.invalidate();\n  }\n\n  private moveCursorToStart(): void {\n    // Editor.setText() places the cursor at the end. Move up through wrapped\n    // lines until the first logical line, then move to that line's start.\n    while (this.editor.getCursor().line > 0) this.editor.handleInput(\"\\x1b[A\");\n    this.editor.handleInput(\"\\x1b[H\");\n  }\n\n  private message(): string {\n    return this.editor.getText().trim();\n  }\n}\n"}},"diff-dialog.ts":{"file":{"contents":"import type { Theme } from \"@earendil-works/pi-coding-agent\";\nimport { Key, matchesKey, truncateToWidth, type Component, type TUI } from \"@earendil-works/pi-tui\";\n\nexport type DiffDialogResult =\n  | { readonly action: \"close\" }\n  | { readonly action: \"chat\"; readonly content: string };\n\nexport class DiffDialog implements Component {\n  private readonly lines: string[];\n  private cursor = 0;\n  private scroll = 0;\n\n  constructor(\n    private readonly tui: TUI,\n    private readonly theme: Theme,\n    private readonly title: string,\n    content: string,\n    private readonly done: (result: DiffDialogResult) => void,\n  ) {\n    this.lines = content.split(\"\\n\");\n  }\n\n  handleInput(data: string): void {\n    if (matchesKey(data, Key.escape) || matchesKey(data, Key.left) || data === \"q\") {\n      this.done({ action: \"close\" });\n      return;\n    }\n    if (data === \"x\") {\n      this.done({ action: \"chat\", content: this.lines.join(\"\\n\") });\n      return;\n    }\n    const page = Math.max(1, Math.floor((process.stdout.rows || 24) / 2));\n    if (matchesKey(data, Key.up) || data === \"k\") this.move(-1);\n    else if (matchesKey(data, Key.down) || data === \"j\") this.move(1);\n    else if (matchesKey(data, Key.pageUp)) this.move(-page);\n    else if (matchesKey(data, Key.pageDown)) this.move(page);\n    else if (data === \"g\") this.move(-this.lines.length);\n    else if (data === \"G\") this.move(this.lines.length);\n    this.tui.requestRender();\n  }\n\n  render(width: number): string[] {\n    const viewport = Math.max(5, (process.stdout.rows || 24) - 5);\n    const end = Math.min(this.lines.length, this.scroll + viewport);\n    const output = [\n      truncateToWidth(` ${this.theme.fg(\"accent\", this.title)} ${this.theme.fg(\"dim\", `(${this.lines.length} lines)`)}`, width),\n      truncateToWidth(this.theme.fg(\"borderMuted\", \"─\".repeat(Math.max(0, width))), width),\n    ];\n    for (let index = this.scroll; index < end; index += 1) {\n      const line = this.lines[index] ?? \"\";\n      const prefix = index === this.cursor ? this.theme.fg(\"accent\", \"→ \") : \"  \";\n      let content = line;\n      if (line.startsWith(\"+\") && !line.startsWith(\"+++\")) content = this.theme.fg(\"toolDiffAdded\", line);\n      if (line.startsWith(\"-\") && !line.startsWith(\"---\")) content = this.theme.fg(\"toolDiffRemoved\", line);\n      output.push(truncateToWidth(prefix + content, width));\n    }\n    output.push(truncateToWidth(this.theme.fg(\"borderMuted\", \"─\".repeat(Math.max(0, width))), width));\n    output.push(truncateToWidth(this.theme.fg(\"dim\", \" ↑↓ navigate • x send diff to editor • q/esc close\"), width));\n    return output;\n  }\n\n  invalidate(): void {}\n\n  private move(delta: number): void {\n    this.cursor = Math.max(0, Math.min(Math.max(0, this.lines.length - 1), this.cursor + delta));\n    const viewport = Math.max(5, (process.stdout.rows || 24) - 5);\n    if (this.cursor < this.scroll) this.scroll = this.cursor;\n    if (this.cursor >= this.scroll + viewport) this.scroll = this.cursor - viewport + 1;\n  }\n}\n"}},"status-dialog.ts":{"file":{"contents":"import type { Theme } from \"@earendil-works/pi-coding-agent\";\nimport {\n  Key,\n  matchesKey,\n  truncateToWidth,\n  type Component,\n  type TUI,\n} from \"@earendil-works/pi-tui\";\nimport type { GitService, GitStatusEntry } from \"../git-service.js\";\n\nexport type StatusDialogResult =\n  | { readonly action: \"close\" }\n  | { readonly action: \"commit\" }\n  | { readonly action: \"smart\" }\n  | { readonly action: \"branch\" }\n  | { readonly action: \"diff\"; readonly entry: GitStatusEntry }\n  | { readonly action: \"discard\"; readonly entry: GitStatusEntry };\n\nexport class GitStatusDialog implements Component {\n  private entries: GitStatusEntry[];\n  private selected = 0;\n  private busy = false;\n  private flashMessage: string | undefined;\n  private flashTimer: ReturnType<typeof setTimeout> | undefined;\n\n  constructor(\n    private readonly tui: TUI,\n    private readonly theme: Theme,\n    private readonly git: GitService,\n    entries: GitStatusEntry[],\n    private readonly refresh: () => Promise<GitStatusEntry[]>,\n    private readonly done: (result: StatusDialogResult) => void,\n  ) {\n    this.entries = [...entries];\n  }\n\n  handleInput(data: string): void {\n    if (this.busy) return;\n    if (matchesKey(data, Key.escape) || matchesKey(data, Key.ctrl(\"c\")) || data === \"q\") {\n      this.done({ action: \"close\" });\n      return;\n    }\n    if (matchesKey(data, Key.up) || data === \"k\") {\n      this.selected = this.entries.length === 0 ? 0 : (this.selected - 1 + this.entries.length) % this.entries.length;\n      this.invalidate();\n      this.tui.requestRender();\n      return;\n    }\n    if (matchesKey(data, Key.down) || data === \"j\") {\n      this.selected = this.entries.length === 0 ? 0 : (this.selected + 1) % this.entries.length;\n      this.invalidate();\n      this.tui.requestRender();\n      return;\n    }\n    if (matchesKey(data, Key.space)) {\n      const entry = this.entries[this.selected];\n      if (entry) this.runToggle(entry);\n      return;\n    }\n    if (data === \"a\") {\n      this.runToggleAll();\n      return;\n    }\n    if (matchesKey(data, Key.enter)) {\n      if (this.stagedCount() === 0) this.flash(\"Nothing is staged\");\n      else this.done({ action: \"commit\" });\n      return;\n    }\n    if (data === \"c\") {\n      if (this.stagedCount() === 0) this.flash(\"Nothing is staged\");\n      else this.done({ action: \"smart\" });\n      return;\n    }\n    if (data === \"b\") {\n      this.done({ action: \"branch\" });\n      return;\n    }\n    if (data === \"d\" || matchesKey(data, Key.right)) {\n      const entry = this.entries[this.selected];\n      if (entry) this.done({ action: \"diff\", entry });\n      return;\n    }\n    if (matchesKey(data, Key.delete) || matchesKey(data, Key.backspace)) {\n      const entry = this.entries[this.selected];\n      if (entry) this.done({ action: \"discard\", entry });\n    }\n  }\n\n  render(width: number): string[] {\n    const title = ` ${this.theme.fg(\"accent\", this.theme.bold(\"Git status\"))} ${this.theme.fg(\"dim\", `${this.stagedCount()}/${this.entries.length} staged`)}`;\n    const lines = [truncateToWidth(title, width), truncateToWidth(this.theme.fg(\"borderMuted\", \"─\".repeat(Math.max(0, width))), width)];\n    if (this.flashMessage) lines.push(truncateToWidth(this.theme.fg(\"warning\", ` ${this.flashMessage}`), width));\n\n    const visible = Math.max(5, Math.min(this.entries.length, 16));\n    const start = Math.max(0, Math.min(this.selected - Math.floor(visible / 2), Math.max(0, this.entries.length - visible)));\n    for (let index = start; index < Math.min(this.entries.length, start + visible); index += 1) {\n      const entry = this.entries[index];\n      if (!entry) continue;\n      const selected = index === this.selected;\n      const marker = selected ? this.theme.fg(\"accent\", \"→ \") : \"  \";\n      const staged = isStaged(entry);\n      const state = staged ? this.theme.fg(\"success\", \"●\") : this.theme.fg(\"warning\", \"○\");\n      const code = `${entry.index}${entry.worktree}`;\n      const label = statusLabel(entry);\n      const name = selected ? this.theme.fg(\"accent\", entry.path) : entry.path;\n      const rename = entry.originalPath ? this.theme.fg(\"dim\", ` ← ${entry.originalPath}`) : \"\";\n      lines.push(truncateToWidth(`${marker}${state} ${code} ${label} ${name}${rename}`, width));\n    }\n    if (this.entries.length === 0) lines.push(truncateToWidth(this.theme.fg(\"dim\", \" Working tree clean\"), width));\n    lines.push(truncateToWidth(this.theme.fg(\"borderMuted\", \"─\".repeat(Math.max(0, width))), width));\n    lines.push(truncateToWidth(this.theme.fg(\"dim\", \" ↑↓ navigate • space toggle • a stage all • enter commit • c smart • d diff • b branch • del discard • q close\"), width));\n    return lines;\n  }\n\n  invalidate(): void {}\n\n  dispose(): void {\n    if (this.flashTimer) clearTimeout(this.flashTimer);\n  }\n\n  private stagedCount(): number {\n    return this.entries.filter(isStaged).length;\n  }\n\n  private runToggle(entry: GitStatusEntry): void {\n    this.busy = true;\n    const operation = isStaged(entry) ? this.git.unstagePath(entry.path) : this.git.stagePath(entry.path);\n    void operation\n      .then(() => this.refresh())\n      .then((entries) => {\n        this.entries = entries;\n        this.selected = Math.min(this.selected, Math.max(0, this.entries.length - 1));\n      })\n      .catch((error: unknown) => this.flash(error instanceof Error ? error.message : String(error)))\n      .finally(() => {\n        this.busy = false;\n        this.invalidate();\n        this.tui.requestRender();\n      });\n  }\n\n  private runToggleAll(): void {\n    this.busy = true;\n    const allStaged = this.entries.length > 0 && this.entries.every(isStaged);\n    const operation = allStaged\n      ? Promise.all(this.entries.map((entry) => this.git.unstagePath(entry.path)))\n      : this.git.stageAll();\n    void operation\n      .then(() => this.refresh())\n      .then((entries) => {\n        this.entries = entries;\n        this.selected = Math.min(this.selected, Math.max(0, this.entries.length - 1));\n      })\n      .catch((error: unknown) => this.flash(error instanceof Error ? error.message : String(error)))\n      .finally(() => {\n        this.busy = false;\n        this.invalidate();\n        this.tui.requestRender();\n      });\n  }\n\n  private flash(message: string): void {\n    if (this.flashTimer) clearTimeout(this.flashTimer);\n    this.flashMessage = message;\n    this.flashTimer = setTimeout(() => {\n      this.flashMessage = undefined;\n      this.tui.requestRender();\n    }, 3_000);\n    this.invalidate();\n    this.tui.requestRender();\n  }\n}\n\nfunction isStaged(entry: GitStatusEntry): boolean {\n  return entry.index !== \" \" && entry.index !== \"?\";\n}\n\n/** Longest status label, so the path column stays put across staged/unstaged toggles. */\nconst LABEL_WIDTH = \"modified\".length;\n\nfunction statusLabel(entry: GitStatusEntry): string {\n  let label: string;\n  if (entry.index === \"?\" && entry.worktree === \"?\") label = \"new\";\n  else if (entry.index === \"D\" || entry.worktree === \"D\") label = \"deleted\";\n  else if (entry.index === \"R\") label = \"renamed\";\n  else if (entry.index === \"C\") label = \"copied\";\n  else if (entry.index === \"A\") label = \"added\";\n  else label = \"modified\";\n  return label.padEnd(LABEL_WIDTH);\n}\n"}}}},"usage-format.ts":{"file":{"contents":"/**\n * Token accounting for pi-git's own model calls. These requests never appear in\n * the pi session footer, so a commit draft would otherwise be an invisible bill.\n */\nimport type { Usage } from \"@earendil-works/pi-ai\";\n\nexport interface TokenTally {\n  readonly calls: number;\n  readonly input: number;\n  readonly output: number;\n  readonly cacheRead: number;\n  readonly cacheWrite: number;\n  readonly cost: number;\n}\n\ninterface TallyDraft {\n  calls: number;\n  input: number;\n  output: number;\n  cacheRead: number;\n  cacheWrite: number;\n  cost: number;\n}\n\n/** Accumulates the usage of every model call one generation makes. */\nexport class TokenTallyCollector {\n  private readonly draft: TallyDraft = { calls: 0, input: 0, output: 0, cacheRead: 0, cacheWrite: 0, cost: 0 };\n\n  add(usage: Usage | undefined): void {\n    if (!usage) return;\n    this.draft.calls += 1;\n    this.draft.input += count(usage.input);\n    this.draft.output += count(usage.output);\n    this.draft.cacheRead += count(usage.cacheRead);\n    this.draft.cacheWrite += count(usage.cacheWrite);\n    this.draft.cost += count(usage.cost?.total);\n  }\n\n  /** Fold an already-summed tally in, so a second phase adds to the same bill. */\n  merge(tally: TokenTally | undefined): void {\n    if (!tally) return;\n    this.draft.calls += tally.calls;\n    this.draft.input += tally.input;\n    this.draft.output += tally.output;\n    this.draft.cacheRead += tally.cacheRead;\n    this.draft.cacheWrite += tally.cacheWrite;\n    this.draft.cost += tally.cost;\n  }\n\n  get totals(): TokenTally {\n    return { ...this.draft };\n  }\n}\n\n/**\n * Compact session-status shape: `$0.00 ⚡19.0M ↑264k ↓86k`, where ⚡ is cache read and\n * an appended `+4k` is cache write. Trailing `· 2 calls` only appears when a\n * retry ladder spent more than one request. pi-statusline prints the same shape\n * in its status line and keeps its own copy of compactTokenCount; change the\n * shape in both places so commit notices and the status line stay legible\n * together.\n */\nexport function formatTokenTally(tally: TokenTally, options: { readonly showCalls?: boolean } = {}): string {\n  if (tally.calls === 0) return \"no model calls\";\n  const cached = `⚡${compactTokenCount(tally.cacheRead)}${tally.cacheWrite > 0 ? `/+${compactTokenCount(tally.cacheWrite)}` : \"\"}`;\n  const parts = [\n    `$${tally.cost < 1 ? tally.cost.toFixed(2) : tally.cost.toFixed(1)}`,\n    cached,\n    `↑${compactTokenCount(tally.input)}`,\n    `↓${compactTokenCount(tally.output)}`,\n  ];\n  if (options.showCalls && tally.calls > 1) parts.push(`\\u00b7 ${tally.calls} calls`);\n  return parts.join(\" \");\n}\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 the small requests this extension makes.\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\n/**\n * Indented cost line for a notification. Quick and smart commits render the\n * generation bill the same way, so neither can quietly drop it.\n */\nexport function formatUsageCostLine(usage: TokenTally | undefined): string {\n  return usage && usage.calls > 0 ? `\\n  ${formatTokenTally(usage, { showCalls: true })}` : \"\";\n}\n\nfunction count(value: number | undefined): number {\n  return typeof value === \"number\" && Number.isFinite(value) ? value : 0;\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 (demo/browser/git/git.mjs), bundled by demo/browser/build.mjs and mounted at ~/.git-shim.\nrequire(\"../.git-shim/git.cjs\").main(process.argv.slice(2)).then((code) => { process.exitCode = code; });\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    \"@opentelemetry/api\": \"1.9.0\",\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 contentText2 = item.content?.map((c) => c.text).join(\"\\n\\n\") || \"\";\n        slot.block.thinking = summaryText || contentText2 || 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 sequence2 = `\\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: sequence2,\n    replacementLine: `${line.slice(0, match.index)}${sequence2}${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 sequence2 = encodeKitty(base64Data, {\n      columns: size.columns,\n      rows: size.rows,\n      imageId: options.imageId,\n      moveCursor: options.moveCursor\n    });\n    return { sequence: sequence2, columns: size.columns, rows: size.rows, imageId: options.imageId };\n  }\n  if (caps.images === \"iterm2\") {\n    const sequence2 = encodeITerm2(base64Data, {\n      width: size.columns,\n      height: \"auto\",\n      preserveAspectRatio: options.preserveAspectRatio ?? true\n    });\n    return { sequence: sequence2, 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(sequence2) {\n  const match = sequence2.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 sequence2 of result2.sequences) {\n          this.emitDataSequence(sequence2);\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 sequence2 of result.sequences) {\n      this.emitDataSequence(sequence2);\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 sequence2 of flushed) {\n          this.emitDataSequence(sequence2);\n        }\n      }, timeoutMs);\n    }\n  }\n  emitDataSequence(sequence2) {\n    const rawCodepoint = sequence2.length === 1 ? sequence2.codePointAt(0) : void 0;\n    if (rawCodepoint !== void 0 && rawCodepoint === this.pendingKittyPrintableCodepoint) {\n      this.pendingKittyPrintableCodepoint = void 0;\n      return;\n    }\n    this.pendingKittyPrintableCodepoint = parseUnmodifiedKittyPrintableCodepoint(sequence2);\n    this.emit(\"data\", sequence2);\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(sequence2) {\n  const kittyFlags = sequence2.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(sequence2)) {\n    return { type: \"device-attributes\" };\n  }\n  return void 0;\n}\nfunction isKeyboardProtocolNegotiationSequencePrefix(sequence2) {\n  return sequence2 === \"\\x1B[\" || /^\\x1b\\[\\?[\\d;]*$/.test(sequence2);\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\", (sequence2) => {\n      const negotiationSequence = this.readKeyboardProtocolNegotiationSequence(sequence2);\n      if (negotiationSequence === \"pending\") {\n        this.scheduleKeyboardProtocolNegotiationBufferFlush();\n        return;\n      }\n      if (this.handleKeyboardProtocolNegotiationSequence(negotiationSequence)) {\n        return;\n      }\n      this.forwardInputSequence(sequence2);\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(sequence2) {\n    if (this.keyboardProtocolNegotiationBuffer) {\n      const bufferedSequence = this.keyboardProtocolNegotiationBuffer + sequence2;\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(sequence2);\n    if (negotiationSequence)\n      return negotiationSequence;\n    if (isKeyboardProtocolNegotiationSequencePrefix(sequence2)) {\n      this.setKeyboardProtocolNegotiationBuffer(sequence2);\n      return \"pending\";\n    }\n    return void 0;\n  }\n  setKeyboardProtocolNegotiationBuffer(sequence2) {\n    this.clearKeyboardProtocolNegotiationBufferFlushTimer();\n    this.keyboardProtocolNegotiationBuffer = sequence2;\n  }\n  clearKeyboardProtocolNegotiationBuffer() {\n    this.clearKeyboardProtocolNegotiationBufferFlushTimer();\n    this.keyboardProtocolNegotiationBuffer = \"\";\n  }\n  flushKeyboardProtocolNegotiationBufferAsInput() {\n    if (!this.keyboardProtocolNegotiationBuffer)\n      return;\n    const sequence2 = this.keyboardProtocolNegotiationBuffer;\n    this.clearKeyboardProtocolNegotiationBuffer();\n    this.forwardInputSequence(sequence2);\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(sequence2) {\n    if (!this.inputHandler)\n      return;\n    const shouldDetectNativeShiftEnter = sequence2 === \"\\r\" && (isAppleTerminalSession() || process.platform === \"win32\");\n    const input = normalizeNativeShiftEnterInput(sequence2, 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.2_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: () => uuidv7\n});\n\n// node_modules/.pnpm/@earendil-works+pi-telemetry@0.84.2/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.2/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.2/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.2_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.2_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 EventStream((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 firstTurn = true;\n  let pendingMessages = await config.getSteeringMessages?.() || [];\n  while (true) {\n    let hasMoreToolCalls = true;\n    while (hasMoreToolCalls || pendingMessages.length > 0) {\n      if (!firstTurn) {\n        await emit({ type: \"turn_start\" });\n      } else {\n        firstTurn = false;\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      const nextTurnContext = {\n        message,\n        toolResults,\n        context: currentContext,\n        newMessages\n      };\n      const nextTurnSnapshot = await config.prepareNextTurn?.(nextTurnContext);\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 (await config.shouldStopAfterTurn?.({\n        message,\n        toolResults,\n        context: currentContext,\n        newMessages\n      })) {\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 = validateToolArguments(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.2_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.2_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.2_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.2_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.2_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.2_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.2_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: () => uuidv7() };\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.2_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.2_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.2_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.2_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 sequence2 = 1;\n    for (const sourceEntry of copiedEntries) {\n      mutations.push({ kind: \"entry\", entry: { ...structuredClone(sourceEntry), seq: sequence2++ } });\n    }\n    for (const pointer of forkLanes) {\n      mutations.push({ kind: \"lane\", seq: sequence2++, lane: pointer.lane, leafId: pointer.leafId });\n    }\n    if (this.name !== void 0) {\n      mutations.push({ kind: \"fact\", seq: sequence2++, 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: sequence2++, 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.2_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.2_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 ?? uuidv7();\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.2_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 ?? uuidv7();\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 ?? uuidv7();\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.2_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 = 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}=${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]: ${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]: ${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.2_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: uuidv7()\n  };\n  return retryAssistantCall(() => 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 = contentText(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: contentText(response.content),\n    usage: response.usage\n  });\n}\n\n// node_modules/.pnpm/@earendil-works+pi-agent-core@0.84.2_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 = contentText(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.2_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.2_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 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    diagnostics.push({ type: \"warning\", code: \"parse_failed\", message: parsed.error.message, path: filePath });\n    return { skill: null, diagnostics };\n  }\n  const { frontmatter, body } = parsed.value;\n  const description = typeof frontmatter.description === \"string\" ? frontmatter.description : void 0;\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.2_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.2_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.2_ws@8.21.3/node_modules/@earendil-works/pi-agent-core/dist/harness/tools/bash.js\nimport { Type as Type5 } from \"typebox\";\n\n// node_modules/.pnpm/@earendil-works+pi-agent-core@0.84.2_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.2_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.2_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 = Type5.Object({\n  command: Type5.String({ description: \"Bash command to execute\" }),\n  timeout: Type5.Optional(Type5.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.2_ws@8.21.3/node_modules/@earendil-works/pi-agent-core/dist/harness/tools/edit.js\nimport { Type as Type6 } from \"typebox\";\n\n// node_modules/.pnpm/@earendil-works+pi-agent-core@0.84.2_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.2_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.2_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.2_ws@8.21.3/node_modules/@earendil-works/pi-agent-core/dist/harness/tools/edit.js\nvar replaceEditSchema = Type6.Object({\n  oldText: Type6.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: Type6.String({ description: \"Replacement text for this targeted edit.\" })\n}, {});\nvar editSchema = Type6.Object({\n  path: Type6.String({ description: \"Path to the file to edit (relative or absolute)\" }),\n  edits: Type6.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 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    } catch {\n    }\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.2_ws@8.21.3/node_modules/@earendil-works/pi-agent-core/dist/harness/tools/read.js\nimport { Type as Type7 } from \"typebox\";\n\n// node_modules/.pnpm/@earendil-works+pi-agent-core@0.84.2_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.2_ws@8.21.3/node_modules/@earendil-works/pi-agent-core/dist/harness/tools/read.js\nvar readSchema = Type7.Object({\n  path: Type7.String({ description: \"Path to the file to read (relative or absolute)\" }),\n  offset: Type7.Optional(Type7.Number({ description: \"Line number to start reading from (1-indexed)\" })),\n  limit: Type7.Optional(Type7.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.2_ws@8.21.3/node_modules/@earendil-works/pi-agent-core/dist/harness/tools/write.js\nimport { Type as Type8 } from \"typebox\";\nvar writeSchema = Type8.Object({\n  path: Type8.String({ description: \"Path to the file to write (relative or absolute)\" }),\n  content: Type8.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.2_ws@8.21.3/node_modules/@earendil-works/pi-agent-core/dist/proxy.js\nvar ProxyMessageEventStream = 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      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 = parseStreamingJson(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.2_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 sleep4(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 Type9 } 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 = Type9.Object({\n  command: Type9.String({ description: \"Bash command to execute\" }),\n  timeout: Type9.Optional(Type9.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 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/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 = Type10.Object({\n  oldText: Type10.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: Type10.String({ description: \"Replacement text for this targeted edit.\" })\n}, {});\nvar editSchema2 = Type10.Object({\n  path: Type10.String({ description: \"Path to the file to edit (relative or absolute)\" }),\n  edits: Type10.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 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/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 = Type11.Object({\n  pattern: Type11.String({\n    description: \"Glob pattern to match files, e.g. '*.ts', '**/*.json', or 'src/**/*.spec.ts'\"\n  }),\n  path: Type11.Optional(Type11.String({ description: \"Directory to search in (default: current directory)\" })),\n  limit: Type11.Optional(Type11.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 Type12 } from \"typebox\";\nvar grepSchema = Type12.Object({\n  pattern: Type12.String({ description: \"Search pattern (regex or literal string)\" }),\n  path: Type12.Optional(Type12.String({ description: \"Directory or file to search (default: current directory)\" })),\n  glob: Type12.Optional(Type12.String({ description: \"Filter files by glob pattern, e.g. '*.ts' or '**/*.spec.ts'\" })),\n  ignoreCase: Type12.Optional(Type12.Boolean({ description: \"Case-insensitive search (default: false)\" })),\n  literal: Type12.Optional(Type12.Boolean({ description: \"Treat pattern as literal string instead of regex (default: false)\" })),\n  context: Type12.Optional(Type12.Number({ description: \"Number of lines to show before and after each match (default: 0)\" })),\n  limit: Type12.Optional(Type12.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 Type13 } from \"typebox\";\nvar lsSchema = Type13.Object({\n  path: Type13.Optional(Type13.String({ description: \"Directory to list (default: current directory)\" })),\n  limit: Type13.Optional(Type13.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 Type14 } from \"typebox\";\nvar readSchema2 = Type14.Object({\n  path: Type14.String({ description: \"Path to the file to read (relative or absolute)\" }),\n  offset: Type14.Optional(Type14.Number({ description: \"Line number to start reading from (1-indexed)\" })),\n  limit: Type14.Optional(Type14.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 Type15 } from \"typebox\";\nvar writeSchema2 = Type15.Object({\n  path: Type15.String({ description: \"Path to the file to write (relative or absolute)\" }),\n  content: Type15.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 sleep4(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 sleep5(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 sleep5(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 sleep5(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 sleep5(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"}}}},".git-shim":{"directory":{"git.cjs":{"file":{"contents":"\"use strict\";\nvar __create = Object.create;\nvar __defProp = Object.defineProperty;\nvar __getOwnPropDesc = Object.getOwnPropertyDescriptor;\nvar __getOwnPropNames = Object.getOwnPropertyNames;\nvar __getProtoOf = Object.getPrototypeOf;\nvar __hasOwnProp = Object.prototype.hasOwnProperty;\nvar __commonJS = (cb, mod) => function __require() {\n  return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;\n};\nvar __export = (target, all) => {\n  for (var name in all)\n    __defProp(target, name, { get: all[name], enumerable: true });\n};\nvar __copyProps = (to, from, except, desc) => {\n  if (from && typeof from === \"object\" || typeof from === \"function\") {\n    for (let key of __getOwnPropNames(from))\n      if (!__hasOwnProp.call(to, key) && key !== except)\n        __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });\n  }\n  return to;\n};\nvar __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(\n  // If the importer is in node compatibility mode or this is not an ESM\n  // file that has been converted to a CommonJS file using a Babel-\n  // compatible transform (i.e. \"__esModule\" has not been set), then set\n  // \"default\" to the CommonJS \"module.exports\" for node compatibility.\n  isNodeMode || !mod || !mod.__esModule ? __defProp(target, \"default\", { value: mod, enumerable: true }) : target,\n  mod\n));\nvar __toCommonJS = (mod) => __copyProps(__defProp({}, \"__esModule\", { value: true }), mod);\n\n// node_modules/.pnpm/async-lock@1.4.1/node_modules/async-lock/lib/index.js\nvar require_lib = __commonJS({\n  \"node_modules/.pnpm/async-lock@1.4.1/node_modules/async-lock/lib/index.js\"(exports2, module2) {\n    \"use strict\";\n    var AsyncLock = function(opts) {\n      opts = opts || {};\n      this.Promise = opts.Promise || Promise;\n      this.queues = /* @__PURE__ */ Object.create(null);\n      this.domainReentrant = opts.domainReentrant || false;\n      if (this.domainReentrant) {\n        if (typeof process === \"undefined\" || typeof process.domain === \"undefined\") {\n          throw new Error(\n            \"Domain-reentrant locks require `process.domain` to exist. Please flip `opts.domainReentrant = false`, use a NodeJS version that still implements Domain, or install a browser polyfill.\"\n          );\n        }\n        this.domains = /* @__PURE__ */ Object.create(null);\n      }\n      this.timeout = opts.timeout || AsyncLock.DEFAULT_TIMEOUT;\n      this.maxOccupationTime = opts.maxOccupationTime || AsyncLock.DEFAULT_MAX_OCCUPATION_TIME;\n      this.maxExecutionTime = opts.maxExecutionTime || AsyncLock.DEFAULT_MAX_EXECUTION_TIME;\n      if (opts.maxPending === Infinity || Number.isInteger(opts.maxPending) && opts.maxPending >= 0) {\n        this.maxPending = opts.maxPending;\n      } else {\n        this.maxPending = AsyncLock.DEFAULT_MAX_PENDING;\n      }\n    };\n    AsyncLock.DEFAULT_TIMEOUT = 0;\n    AsyncLock.DEFAULT_MAX_OCCUPATION_TIME = 0;\n    AsyncLock.DEFAULT_MAX_EXECUTION_TIME = 0;\n    AsyncLock.DEFAULT_MAX_PENDING = 1e3;\n    AsyncLock.prototype.acquire = function(key, fn, cb, opts) {\n      if (Array.isArray(key)) {\n        return this._acquireBatch(key, fn, cb, opts);\n      }\n      if (typeof fn !== \"function\") {\n        throw new Error(\"You must pass a function to execute\");\n      }\n      var deferredResolve = null;\n      var deferredReject = null;\n      var deferred = null;\n      if (typeof cb !== \"function\") {\n        opts = cb;\n        cb = null;\n        deferred = new this.Promise(function(resolve, reject) {\n          deferredResolve = resolve;\n          deferredReject = reject;\n        });\n      }\n      opts = opts || {};\n      var resolved = false;\n      var timer = null;\n      var occupationTimer = null;\n      var executionTimer = null;\n      var self = this;\n      var done = function(locked, err, ret) {\n        if (occupationTimer) {\n          clearTimeout(occupationTimer);\n          occupationTimer = null;\n        }\n        if (executionTimer) {\n          clearTimeout(executionTimer);\n          executionTimer = null;\n        }\n        if (locked) {\n          if (!!self.queues[key] && self.queues[key].length === 0) {\n            delete self.queues[key];\n          }\n          if (self.domainReentrant) {\n            delete self.domains[key];\n          }\n        }\n        if (!resolved) {\n          if (!deferred) {\n            if (typeof cb === \"function\") {\n              cb(err, ret);\n            }\n          } else {\n            if (err) {\n              deferredReject(err);\n            } else {\n              deferredResolve(ret);\n            }\n          }\n          resolved = true;\n        }\n        if (locked) {\n          if (!!self.queues[key] && self.queues[key].length > 0) {\n            self.queues[key].shift()();\n          }\n        }\n      };\n      var exec = function(locked) {\n        if (resolved) {\n          return done(locked);\n        }\n        if (timer) {\n          clearTimeout(timer);\n          timer = null;\n        }\n        if (self.domainReentrant && locked) {\n          self.domains[key] = process.domain;\n        }\n        var maxExecutionTime = opts.maxExecutionTime || self.maxExecutionTime;\n        if (maxExecutionTime) {\n          executionTimer = setTimeout(function() {\n            if (!!self.queues[key]) {\n              done(locked, new Error(\"Maximum execution time is exceeded \" + key));\n            }\n          }, maxExecutionTime);\n        }\n        if (fn.length === 1) {\n          var called = false;\n          try {\n            fn(function(err, ret) {\n              if (!called) {\n                called = true;\n                done(locked, err, ret);\n              }\n            });\n          } catch (err) {\n            if (!called) {\n              called = true;\n              done(locked, err);\n            }\n          }\n        } else {\n          self._promiseTry(function() {\n            return fn();\n          }).then(function(ret) {\n            done(locked, void 0, ret);\n          }, function(error) {\n            done(locked, error);\n          });\n        }\n      };\n      if (self.domainReentrant && !!process.domain) {\n        exec = process.domain.bind(exec);\n      }\n      var maxPending = opts.maxPending || self.maxPending;\n      if (!self.queues[key]) {\n        self.queues[key] = [];\n        exec(true);\n      } else if (self.domainReentrant && !!process.domain && process.domain === self.domains[key]) {\n        exec(false);\n      } else if (self.queues[key].length >= maxPending) {\n        done(false, new Error(\"Too many pending tasks in queue \" + key));\n      } else {\n        var taskFn = function() {\n          exec(true);\n        };\n        if (opts.skipQueue) {\n          self.queues[key].unshift(taskFn);\n        } else {\n          self.queues[key].push(taskFn);\n        }\n        var timeout = opts.timeout || self.timeout;\n        if (timeout) {\n          timer = setTimeout(function() {\n            timer = null;\n            done(false, new Error(\"async-lock timed out in queue \" + key));\n          }, timeout);\n        }\n      }\n      var maxOccupationTime = opts.maxOccupationTime || self.maxOccupationTime;\n      if (maxOccupationTime) {\n        occupationTimer = setTimeout(function() {\n          if (!!self.queues[key]) {\n            done(false, new Error(\"Maximum occupation time is exceeded in queue \" + key));\n          }\n        }, maxOccupationTime);\n      }\n      if (deferred) {\n        return deferred;\n      }\n    };\n    AsyncLock.prototype._acquireBatch = function(keys, fn, cb, opts) {\n      if (typeof cb !== \"function\") {\n        opts = cb;\n        cb = null;\n      }\n      var self = this;\n      var getFn = function(key, fn2) {\n        return function(cb2) {\n          self.acquire(key, fn2, cb2, opts);\n        };\n      };\n      var fnx = keys.reduceRight(function(prev, key) {\n        return getFn(key, prev);\n      }, fn);\n      if (typeof cb === \"function\") {\n        fnx(cb);\n      } else {\n        return new this.Promise(function(resolve, reject) {\n          if (fnx.length === 1) {\n            fnx(function(err, ret) {\n              if (err) {\n                reject(err);\n              } else {\n                resolve(ret);\n              }\n            });\n          } else {\n            resolve(fnx());\n          }\n        });\n      }\n    };\n    AsyncLock.prototype.isBusy = function(key) {\n      if (!key) {\n        return Object.keys(this.queues).length > 0;\n      } else {\n        return !!this.queues[key];\n      }\n    };\n    AsyncLock.prototype._promiseTry = function(fn) {\n      try {\n        return this.Promise.resolve(fn());\n      } catch (e) {\n        return this.Promise.reject(e);\n      }\n    };\n    module2.exports = AsyncLock;\n  }\n});\n\n// node_modules/.pnpm/async-lock@1.4.1/node_modules/async-lock/index.js\nvar require_async_lock = __commonJS({\n  \"node_modules/.pnpm/async-lock@1.4.1/node_modules/async-lock/index.js\"(exports2, module2) {\n    \"use strict\";\n    module2.exports = require_lib();\n  }\n});\n\n// node_modules/.pnpm/inherits@2.0.4/node_modules/inherits/inherits_browser.js\nvar require_inherits_browser = __commonJS({\n  \"node_modules/.pnpm/inherits@2.0.4/node_modules/inherits/inherits_browser.js\"(exports2, module2) {\n    if (typeof Object.create === \"function\") {\n      module2.exports = function inherits(ctor, superCtor) {\n        if (superCtor) {\n          ctor.super_ = superCtor;\n          ctor.prototype = Object.create(superCtor.prototype, {\n            constructor: {\n              value: ctor,\n              enumerable: false,\n              writable: true,\n              configurable: true\n            }\n          });\n        }\n      };\n    } else {\n      module2.exports = function inherits(ctor, superCtor) {\n        if (superCtor) {\n          ctor.super_ = superCtor;\n          var TempCtor = function() {\n          };\n          TempCtor.prototype = superCtor.prototype;\n          ctor.prototype = new TempCtor();\n          ctor.prototype.constructor = ctor;\n        }\n      };\n    }\n  }\n});\n\n// node_modules/.pnpm/inherits@2.0.4/node_modules/inherits/inherits.js\nvar require_inherits = __commonJS({\n  \"node_modules/.pnpm/inherits@2.0.4/node_modules/inherits/inherits.js\"(exports2, module2) {\n    try {\n      util = require(\"util\");\n      if (typeof util.inherits !== \"function\") throw \"\";\n      module2.exports = util.inherits;\n    } catch (e) {\n      module2.exports = require_inherits_browser();\n    }\n    var util;\n  }\n});\n\n// node_modules/.pnpm/safe-buffer@5.2.1/node_modules/safe-buffer/index.js\nvar require_safe_buffer = __commonJS({\n  \"node_modules/.pnpm/safe-buffer@5.2.1/node_modules/safe-buffer/index.js\"(exports2, module2) {\n    var buffer = require(\"buffer\");\n    var Buffer2 = buffer.Buffer;\n    function copyProps(src, dst) {\n      for (var key in src) {\n        dst[key] = src[key];\n      }\n    }\n    if (Buffer2.from && Buffer2.alloc && Buffer2.allocUnsafe && Buffer2.allocUnsafeSlow) {\n      module2.exports = buffer;\n    } else {\n      copyProps(buffer, exports2);\n      exports2.Buffer = SafeBuffer;\n    }\n    function SafeBuffer(arg, encodingOrOffset, length) {\n      return Buffer2(arg, encodingOrOffset, length);\n    }\n    SafeBuffer.prototype = Object.create(Buffer2.prototype);\n    copyProps(Buffer2, SafeBuffer);\n    SafeBuffer.from = function(arg, encodingOrOffset, length) {\n      if (typeof arg === \"number\") {\n        throw new TypeError(\"Argument must not be a number\");\n      }\n      return Buffer2(arg, encodingOrOffset, length);\n    };\n    SafeBuffer.alloc = function(size, fill, encoding) {\n      if (typeof size !== \"number\") {\n        throw new TypeError(\"Argument must be a number\");\n      }\n      var buf = Buffer2(size);\n      if (fill !== void 0) {\n        if (typeof encoding === \"string\") {\n          buf.fill(fill, encoding);\n        } else {\n          buf.fill(fill);\n        }\n      } else {\n        buf.fill(0);\n      }\n      return buf;\n    };\n    SafeBuffer.allocUnsafe = function(size) {\n      if (typeof size !== \"number\") {\n        throw new TypeError(\"Argument must be a number\");\n      }\n      return Buffer2(size);\n    };\n    SafeBuffer.allocUnsafeSlow = function(size) {\n      if (typeof size !== \"number\") {\n        throw new TypeError(\"Argument must be a number\");\n      }\n      return buffer.SlowBuffer(size);\n    };\n  }\n});\n\n// node_modules/.pnpm/isarray@2.0.5/node_modules/isarray/index.js\nvar require_isarray = __commonJS({\n  \"node_modules/.pnpm/isarray@2.0.5/node_modules/isarray/index.js\"(exports2, module2) {\n    var toString = {}.toString;\n    module2.exports = Array.isArray || function(arr) {\n      return toString.call(arr) == \"[object Array]\";\n    };\n  }\n});\n\n// node_modules/.pnpm/es-errors@1.3.0/node_modules/es-errors/type.js\nvar require_type = __commonJS({\n  \"node_modules/.pnpm/es-errors@1.3.0/node_modules/es-errors/type.js\"(exports2, module2) {\n    \"use strict\";\n    module2.exports = TypeError;\n  }\n});\n\n// node_modules/.pnpm/es-object-atoms@1.1.2/node_modules/es-object-atoms/index.js\nvar require_es_object_atoms = __commonJS({\n  \"node_modules/.pnpm/es-object-atoms@1.1.2/node_modules/es-object-atoms/index.js\"(exports2, module2) {\n    \"use strict\";\n    module2.exports = Object;\n  }\n});\n\n// node_modules/.pnpm/es-errors@1.3.0/node_modules/es-errors/index.js\nvar require_es_errors = __commonJS({\n  \"node_modules/.pnpm/es-errors@1.3.0/node_modules/es-errors/index.js\"(exports2, module2) {\n    \"use strict\";\n    module2.exports = Error;\n  }\n});\n\n// node_modules/.pnpm/es-errors@1.3.0/node_modules/es-errors/eval.js\nvar require_eval = __commonJS({\n  \"node_modules/.pnpm/es-errors@1.3.0/node_modules/es-errors/eval.js\"(exports2, module2) {\n    \"use strict\";\n    module2.exports = EvalError;\n  }\n});\n\n// node_modules/.pnpm/es-errors@1.3.0/node_modules/es-errors/range.js\nvar require_range = __commonJS({\n  \"node_modules/.pnpm/es-errors@1.3.0/node_modules/es-errors/range.js\"(exports2, module2) {\n    \"use strict\";\n    module2.exports = RangeError;\n  }\n});\n\n// node_modules/.pnpm/es-errors@1.3.0/node_modules/es-errors/ref.js\nvar require_ref = __commonJS({\n  \"node_modules/.pnpm/es-errors@1.3.0/node_modules/es-errors/ref.js\"(exports2, module2) {\n    \"use strict\";\n    module2.exports = ReferenceError;\n  }\n});\n\n// node_modules/.pnpm/es-errors@1.3.0/node_modules/es-errors/syntax.js\nvar require_syntax = __commonJS({\n  \"node_modules/.pnpm/es-errors@1.3.0/node_modules/es-errors/syntax.js\"(exports2, module2) {\n    \"use strict\";\n    module2.exports = SyntaxError;\n  }\n});\n\n// node_modules/.pnpm/es-errors@1.3.0/node_modules/es-errors/uri.js\nvar require_uri = __commonJS({\n  \"node_modules/.pnpm/es-errors@1.3.0/node_modules/es-errors/uri.js\"(exports2, module2) {\n    \"use strict\";\n    module2.exports = URIError;\n  }\n});\n\n// node_modules/.pnpm/math-intrinsics@1.1.0/node_modules/math-intrinsics/abs.js\nvar require_abs = __commonJS({\n  \"node_modules/.pnpm/math-intrinsics@1.1.0/node_modules/math-intrinsics/abs.js\"(exports2, module2) {\n    \"use strict\";\n    module2.exports = Math.abs;\n  }\n});\n\n// node_modules/.pnpm/math-intrinsics@1.1.0/node_modules/math-intrinsics/floor.js\nvar require_floor = __commonJS({\n  \"node_modules/.pnpm/math-intrinsics@1.1.0/node_modules/math-intrinsics/floor.js\"(exports2, module2) {\n    \"use strict\";\n    module2.exports = Math.floor;\n  }\n});\n\n// node_modules/.pnpm/math-intrinsics@1.1.0/node_modules/math-intrinsics/max.js\nvar require_max = __commonJS({\n  \"node_modules/.pnpm/math-intrinsics@1.1.0/node_modules/math-intrinsics/max.js\"(exports2, module2) {\n    \"use strict\";\n    module2.exports = Math.max;\n  }\n});\n\n// node_modules/.pnpm/math-intrinsics@1.1.0/node_modules/math-intrinsics/min.js\nvar require_min = __commonJS({\n  \"node_modules/.pnpm/math-intrinsics@1.1.0/node_modules/math-intrinsics/min.js\"(exports2, module2) {\n    \"use strict\";\n    module2.exports = Math.min;\n  }\n});\n\n// node_modules/.pnpm/math-intrinsics@1.1.0/node_modules/math-intrinsics/pow.js\nvar require_pow = __commonJS({\n  \"node_modules/.pnpm/math-intrinsics@1.1.0/node_modules/math-intrinsics/pow.js\"(exports2, module2) {\n    \"use strict\";\n    module2.exports = Math.pow;\n  }\n});\n\n// node_modules/.pnpm/math-intrinsics@1.1.0/node_modules/math-intrinsics/round.js\nvar require_round = __commonJS({\n  \"node_modules/.pnpm/math-intrinsics@1.1.0/node_modules/math-intrinsics/round.js\"(exports2, module2) {\n    \"use strict\";\n    module2.exports = Math.round;\n  }\n});\n\n// node_modules/.pnpm/math-intrinsics@1.1.0/node_modules/math-intrinsics/isNaN.js\nvar require_isNaN = __commonJS({\n  \"node_modules/.pnpm/math-intrinsics@1.1.0/node_modules/math-intrinsics/isNaN.js\"(exports2, module2) {\n    \"use strict\";\n    module2.exports = Number.isNaN || function isNaN2(a) {\n      return a !== a;\n    };\n  }\n});\n\n// node_modules/.pnpm/math-intrinsics@1.1.0/node_modules/math-intrinsics/sign.js\nvar require_sign = __commonJS({\n  \"node_modules/.pnpm/math-intrinsics@1.1.0/node_modules/math-intrinsics/sign.js\"(exports2, module2) {\n    \"use strict\";\n    var $isNaN = require_isNaN();\n    module2.exports = function sign(number) {\n      if ($isNaN(number) || number === 0) {\n        return number;\n      }\n      return number < 0 ? -1 : 1;\n    };\n  }\n});\n\n// node_modules/.pnpm/gopd@1.2.0/node_modules/gopd/gOPD.js\nvar require_gOPD = __commonJS({\n  \"node_modules/.pnpm/gopd@1.2.0/node_modules/gopd/gOPD.js\"(exports2, module2) {\n    \"use strict\";\n    module2.exports = Object.getOwnPropertyDescriptor;\n  }\n});\n\n// node_modules/.pnpm/gopd@1.2.0/node_modules/gopd/index.js\nvar require_gopd = __commonJS({\n  \"node_modules/.pnpm/gopd@1.2.0/node_modules/gopd/index.js\"(exports2, module2) {\n    \"use strict\";\n    var $gOPD = require_gOPD();\n    if ($gOPD) {\n      try {\n        $gOPD([], \"length\");\n      } catch (e) {\n        $gOPD = null;\n      }\n    }\n    module2.exports = $gOPD;\n  }\n});\n\n// node_modules/.pnpm/es-define-property@1.0.1/node_modules/es-define-property/index.js\nvar require_es_define_property = __commonJS({\n  \"node_modules/.pnpm/es-define-property@1.0.1/node_modules/es-define-property/index.js\"(exports2, module2) {\n    \"use strict\";\n    var $defineProperty = Object.defineProperty || false;\n    if ($defineProperty) {\n      try {\n        $defineProperty({}, \"a\", { value: 1 });\n      } catch (e) {\n        $defineProperty = false;\n      }\n    }\n    module2.exports = $defineProperty;\n  }\n});\n\n// node_modules/.pnpm/has-symbols@1.1.0/node_modules/has-symbols/shams.js\nvar require_shams = __commonJS({\n  \"node_modules/.pnpm/has-symbols@1.1.0/node_modules/has-symbols/shams.js\"(exports2, module2) {\n    \"use strict\";\n    module2.exports = function hasSymbols() {\n      if (typeof Symbol !== \"function\" || typeof Object.getOwnPropertySymbols !== \"function\") {\n        return false;\n      }\n      if (typeof Symbol.iterator === \"symbol\") {\n        return true;\n      }\n      var obj = {};\n      var sym = Symbol(\"test\");\n      var symObj = Object(sym);\n      if (typeof sym === \"string\") {\n        return false;\n      }\n      if (Object.prototype.toString.call(sym) !== \"[object Symbol]\") {\n        return false;\n      }\n      if (Object.prototype.toString.call(symObj) !== \"[object Symbol]\") {\n        return false;\n      }\n      var symVal = 42;\n      obj[sym] = symVal;\n      for (var _ in obj) {\n        return false;\n      }\n      if (typeof Object.keys === \"function\" && Object.keys(obj).length !== 0) {\n        return false;\n      }\n      if (typeof Object.getOwnPropertyNames === \"function\" && Object.getOwnPropertyNames(obj).length !== 0) {\n        return false;\n      }\n      var syms = Object.getOwnPropertySymbols(obj);\n      if (syms.length !== 1 || syms[0] !== sym) {\n        return false;\n      }\n      if (!Object.prototype.propertyIsEnumerable.call(obj, sym)) {\n        return false;\n      }\n      if (typeof Object.getOwnPropertyDescriptor === \"function\") {\n        var descriptor = (\n          /** @type {PropertyDescriptor} */\n          Object.getOwnPropertyDescriptor(obj, sym)\n        );\n        if (descriptor.value !== symVal || descriptor.enumerable !== true) {\n          return false;\n        }\n      }\n      return true;\n    };\n  }\n});\n\n// node_modules/.pnpm/has-symbols@1.1.0/node_modules/has-symbols/index.js\nvar require_has_symbols = __commonJS({\n  \"node_modules/.pnpm/has-symbols@1.1.0/node_modules/has-symbols/index.js\"(exports2, module2) {\n    \"use strict\";\n    var origSymbol = typeof Symbol !== \"undefined\" && Symbol;\n    var hasSymbolSham = require_shams();\n    module2.exports = function hasNativeSymbols() {\n      if (typeof origSymbol !== \"function\") {\n        return false;\n      }\n      if (typeof Symbol !== \"function\") {\n        return false;\n      }\n      if (typeof origSymbol(\"foo\") !== \"symbol\") {\n        return false;\n      }\n      if (typeof Symbol(\"bar\") !== \"symbol\") {\n        return false;\n      }\n      return hasSymbolSham();\n    };\n  }\n});\n\n// node_modules/.pnpm/get-proto@1.0.1/node_modules/get-proto/Reflect.getPrototypeOf.js\nvar require_Reflect_getPrototypeOf = __commonJS({\n  \"node_modules/.pnpm/get-proto@1.0.1/node_modules/get-proto/Reflect.getPrototypeOf.js\"(exports2, module2) {\n    \"use strict\";\n    module2.exports = typeof Reflect !== \"undefined\" && Reflect.getPrototypeOf || null;\n  }\n});\n\n// node_modules/.pnpm/get-proto@1.0.1/node_modules/get-proto/Object.getPrototypeOf.js\nvar require_Object_getPrototypeOf = __commonJS({\n  \"node_modules/.pnpm/get-proto@1.0.1/node_modules/get-proto/Object.getPrototypeOf.js\"(exports2, module2) {\n    \"use strict\";\n    var $Object = require_es_object_atoms();\n    module2.exports = $Object.getPrototypeOf || null;\n  }\n});\n\n// node_modules/.pnpm/function-bind@1.1.2/node_modules/function-bind/implementation.js\nvar require_implementation = __commonJS({\n  \"node_modules/.pnpm/function-bind@1.1.2/node_modules/function-bind/implementation.js\"(exports2, module2) {\n    \"use strict\";\n    var ERROR_MESSAGE = \"Function.prototype.bind called on incompatible \";\n    var toStr = Object.prototype.toString;\n    var max = Math.max;\n    var funcType = \"[object Function]\";\n    var concatty = function concatty2(a, b) {\n      var arr = [];\n      for (var i = 0; i < a.length; i += 1) {\n        arr[i] = a[i];\n      }\n      for (var j = 0; j < b.length; j += 1) {\n        arr[j + a.length] = b[j];\n      }\n      return arr;\n    };\n    var slicy = function slicy2(arrLike, offset) {\n      var arr = [];\n      for (var i = offset || 0, j = 0; i < arrLike.length; i += 1, j += 1) {\n        arr[j] = arrLike[i];\n      }\n      return arr;\n    };\n    var joiny = function(arr, joiner) {\n      var str = \"\";\n      for (var i = 0; i < arr.length; i += 1) {\n        str += arr[i];\n        if (i + 1 < arr.length) {\n          str += joiner;\n        }\n      }\n      return str;\n    };\n    module2.exports = function bind(that) {\n      var target = this;\n      if (typeof target !== \"function\" || toStr.apply(target) !== funcType) {\n        throw new TypeError(ERROR_MESSAGE + target);\n      }\n      var args = slicy(arguments, 1);\n      var bound;\n      var binder = function() {\n        if (this instanceof bound) {\n          var result = target.apply(\n            this,\n            concatty(args, arguments)\n          );\n          if (Object(result) === result) {\n            return result;\n          }\n          return this;\n        }\n        return target.apply(\n          that,\n          concatty(args, arguments)\n        );\n      };\n      var boundLength = max(0, target.length - args.length);\n      var boundArgs = [];\n      for (var i = 0; i < boundLength; i++) {\n        boundArgs[i] = \"$\" + i;\n      }\n      bound = Function(\"binder\", \"return function (\" + joiny(boundArgs, \",\") + \"){ return binder.apply(this,arguments); }\")(binder);\n      if (target.prototype) {\n        var Empty = function Empty2() {\n        };\n        Empty.prototype = target.prototype;\n        bound.prototype = new Empty();\n        Empty.prototype = null;\n      }\n      return bound;\n    };\n  }\n});\n\n// node_modules/.pnpm/function-bind@1.1.2/node_modules/function-bind/index.js\nvar require_function_bind = __commonJS({\n  \"node_modules/.pnpm/function-bind@1.1.2/node_modules/function-bind/index.js\"(exports2, module2) {\n    \"use strict\";\n    var implementation = require_implementation();\n    module2.exports = Function.prototype.bind || implementation;\n  }\n});\n\n// node_modules/.pnpm/call-bind-apply-helpers@1.0.2/node_modules/call-bind-apply-helpers/functionCall.js\nvar require_functionCall = __commonJS({\n  \"node_modules/.pnpm/call-bind-apply-helpers@1.0.2/node_modules/call-bind-apply-helpers/functionCall.js\"(exports2, module2) {\n    \"use strict\";\n    module2.exports = Function.prototype.call;\n  }\n});\n\n// node_modules/.pnpm/call-bind-apply-helpers@1.0.2/node_modules/call-bind-apply-helpers/functionApply.js\nvar require_functionApply = __commonJS({\n  \"node_modules/.pnpm/call-bind-apply-helpers@1.0.2/node_modules/call-bind-apply-helpers/functionApply.js\"(exports2, module2) {\n    \"use strict\";\n    module2.exports = Function.prototype.apply;\n  }\n});\n\n// node_modules/.pnpm/call-bind-apply-helpers@1.0.2/node_modules/call-bind-apply-helpers/reflectApply.js\nvar require_reflectApply = __commonJS({\n  \"node_modules/.pnpm/call-bind-apply-helpers@1.0.2/node_modules/call-bind-apply-helpers/reflectApply.js\"(exports2, module2) {\n    \"use strict\";\n    module2.exports = typeof Reflect !== \"undefined\" && Reflect && Reflect.apply;\n  }\n});\n\n// node_modules/.pnpm/call-bind-apply-helpers@1.0.2/node_modules/call-bind-apply-helpers/actualApply.js\nvar require_actualApply = __commonJS({\n  \"node_modules/.pnpm/call-bind-apply-helpers@1.0.2/node_modules/call-bind-apply-helpers/actualApply.js\"(exports2, module2) {\n    \"use strict\";\n    var bind = require_function_bind();\n    var $apply = require_functionApply();\n    var $call = require_functionCall();\n    var $reflectApply = require_reflectApply();\n    module2.exports = $reflectApply || bind.call($call, $apply);\n  }\n});\n\n// node_modules/.pnpm/call-bind-apply-helpers@1.0.2/node_modules/call-bind-apply-helpers/index.js\nvar require_call_bind_apply_helpers = __commonJS({\n  \"node_modules/.pnpm/call-bind-apply-helpers@1.0.2/node_modules/call-bind-apply-helpers/index.js\"(exports2, module2) {\n    \"use strict\";\n    var bind = require_function_bind();\n    var $TypeError = require_type();\n    var $call = require_functionCall();\n    var $actualApply = require_actualApply();\n    module2.exports = function callBindBasic(args) {\n      if (args.length < 1 || typeof args[0] !== \"function\") {\n        throw new $TypeError(\"a function is required\");\n      }\n      return $actualApply(bind, $call, args);\n    };\n  }\n});\n\n// node_modules/.pnpm/dunder-proto@1.0.1/node_modules/dunder-proto/get.js\nvar require_get = __commonJS({\n  \"node_modules/.pnpm/dunder-proto@1.0.1/node_modules/dunder-proto/get.js\"(exports2, module2) {\n    \"use strict\";\n    var callBind = require_call_bind_apply_helpers();\n    var gOPD = require_gopd();\n    var hasProtoAccessor;\n    try {\n      hasProtoAccessor = /** @type {{ __proto__?: typeof Array.prototype }} */\n      [].__proto__ === Array.prototype;\n    } catch (e) {\n      if (!e || typeof e !== \"object\" || !(\"code\" in e) || e.code !== \"ERR_PROTO_ACCESS\") {\n        throw e;\n      }\n    }\n    var desc = !!hasProtoAccessor && gOPD && gOPD(\n      Object.prototype,\n      /** @type {keyof typeof Object.prototype} */\n      \"__proto__\"\n    );\n    var $Object = Object;\n    var $getPrototypeOf = $Object.getPrototypeOf;\n    module2.exports = desc && typeof desc.get === \"function\" ? callBind([desc.get]) : typeof $getPrototypeOf === \"function\" ? (\n      /** @type {import('./get')} */\n      function getDunder(value) {\n        return $getPrototypeOf(value == null ? value : $Object(value));\n      }\n    ) : false;\n  }\n});\n\n// node_modules/.pnpm/get-proto@1.0.1/node_modules/get-proto/index.js\nvar require_get_proto = __commonJS({\n  \"node_modules/.pnpm/get-proto@1.0.1/node_modules/get-proto/index.js\"(exports2, module2) {\n    \"use strict\";\n    var reflectGetProto = require_Reflect_getPrototypeOf();\n    var originalGetProto = require_Object_getPrototypeOf();\n    var getDunderProto = require_get();\n    module2.exports = reflectGetProto ? function getProto(O) {\n      return reflectGetProto(O);\n    } : originalGetProto ? function getProto(O) {\n      if (!O || typeof O !== \"object\" && typeof O !== \"function\") {\n        throw new TypeError(\"getProto: not an object\");\n      }\n      return originalGetProto(O);\n    } : getDunderProto ? function getProto(O) {\n      return getDunderProto(O);\n    } : null;\n  }\n});\n\n// node_modules/.pnpm/hasown@2.0.4/node_modules/hasown/index.js\nvar require_hasown = __commonJS({\n  \"node_modules/.pnpm/hasown@2.0.4/node_modules/hasown/index.js\"(exports2, module2) {\n    \"use strict\";\n    var call = Function.prototype.call;\n    var $hasOwn = Object.prototype.hasOwnProperty;\n    var bind = require_function_bind();\n    module2.exports = bind.call(call, $hasOwn);\n  }\n});\n\n// node_modules/.pnpm/get-intrinsic@1.3.0/node_modules/get-intrinsic/index.js\nvar require_get_intrinsic = __commonJS({\n  \"node_modules/.pnpm/get-intrinsic@1.3.0/node_modules/get-intrinsic/index.js\"(exports2, module2) {\n    \"use strict\";\n    var undefined2;\n    var $Object = require_es_object_atoms();\n    var $Error = require_es_errors();\n    var $EvalError = require_eval();\n    var $RangeError = require_range();\n    var $ReferenceError = require_ref();\n    var $SyntaxError = require_syntax();\n    var $TypeError = require_type();\n    var $URIError = require_uri();\n    var abs = require_abs();\n    var floor = require_floor();\n    var max = require_max();\n    var min = require_min();\n    var pow = require_pow();\n    var round = require_round();\n    var sign = require_sign();\n    var $Function = Function;\n    var getEvalledConstructor = function(expressionSyntax) {\n      try {\n        return $Function('\"use strict\"; return (' + expressionSyntax + \").constructor;\")();\n      } catch (e) {\n      }\n    };\n    var $gOPD = require_gopd();\n    var $defineProperty = require_es_define_property();\n    var throwTypeError = function() {\n      throw new $TypeError();\n    };\n    var ThrowTypeError = $gOPD ? (function() {\n      try {\n        arguments.callee;\n        return throwTypeError;\n      } catch (calleeThrows) {\n        try {\n          return $gOPD(arguments, \"callee\").get;\n        } catch (gOPDthrows) {\n          return throwTypeError;\n        }\n      }\n    })() : throwTypeError;\n    var hasSymbols = require_has_symbols()();\n    var getProto = require_get_proto();\n    var $ObjectGPO = require_Object_getPrototypeOf();\n    var $ReflectGPO = require_Reflect_getPrototypeOf();\n    var $apply = require_functionApply();\n    var $call = require_functionCall();\n    var needsEval = {};\n    var TypedArray = typeof Uint8Array === \"undefined\" || !getProto ? undefined2 : getProto(Uint8Array);\n    var INTRINSICS = {\n      __proto__: null,\n      \"%AggregateError%\": typeof AggregateError === \"undefined\" ? undefined2 : AggregateError,\n      \"%Array%\": Array,\n      \"%ArrayBuffer%\": typeof ArrayBuffer === \"undefined\" ? undefined2 : ArrayBuffer,\n      \"%ArrayIteratorPrototype%\": hasSymbols && getProto ? getProto([][Symbol.iterator]()) : undefined2,\n      \"%AsyncFromSyncIteratorPrototype%\": undefined2,\n      \"%AsyncFunction%\": needsEval,\n      \"%AsyncGenerator%\": needsEval,\n      \"%AsyncGeneratorFunction%\": needsEval,\n      \"%AsyncIteratorPrototype%\": needsEval,\n      \"%Atomics%\": typeof Atomics === \"undefined\" ? undefined2 : Atomics,\n      \"%BigInt%\": typeof BigInt === \"undefined\" ? undefined2 : BigInt,\n      \"%BigInt64Array%\": typeof BigInt64Array === \"undefined\" ? undefined2 : BigInt64Array,\n      \"%BigUint64Array%\": typeof BigUint64Array === \"undefined\" ? undefined2 : BigUint64Array,\n      \"%Boolean%\": Boolean,\n      \"%DataView%\": typeof DataView === \"undefined\" ? undefined2 : DataView,\n      \"%Date%\": Date,\n      \"%decodeURI%\": decodeURI,\n      \"%decodeURIComponent%\": decodeURIComponent,\n      \"%encodeURI%\": encodeURI,\n      \"%encodeURIComponent%\": encodeURIComponent,\n      \"%Error%\": $Error,\n      \"%eval%\": eval,\n      // eslint-disable-line no-eval\n      \"%EvalError%\": $EvalError,\n      \"%Float16Array%\": typeof Float16Array === \"undefined\" ? undefined2 : Float16Array,\n      \"%Float32Array%\": typeof Float32Array === \"undefined\" ? undefined2 : Float32Array,\n      \"%Float64Array%\": typeof Float64Array === \"undefined\" ? undefined2 : Float64Array,\n      \"%FinalizationRegistry%\": typeof FinalizationRegistry === \"undefined\" ? undefined2 : FinalizationRegistry,\n      \"%Function%\": $Function,\n      \"%GeneratorFunction%\": needsEval,\n      \"%Int8Array%\": typeof Int8Array === \"undefined\" ? undefined2 : Int8Array,\n      \"%Int16Array%\": typeof Int16Array === \"undefined\" ? undefined2 : Int16Array,\n      \"%Int32Array%\": typeof Int32Array === \"undefined\" ? undefined2 : Int32Array,\n      \"%isFinite%\": isFinite,\n      \"%isNaN%\": isNaN,\n      \"%IteratorPrototype%\": hasSymbols && getProto ? getProto(getProto([][Symbol.iterator]())) : undefined2,\n      \"%JSON%\": typeof JSON === \"object\" ? JSON : undefined2,\n      \"%Map%\": typeof Map === \"undefined\" ? undefined2 : Map,\n      \"%MapIteratorPrototype%\": typeof Map === \"undefined\" || !hasSymbols || !getProto ? undefined2 : getProto((/* @__PURE__ */ new Map())[Symbol.iterator]()),\n      \"%Math%\": Math,\n      \"%Number%\": Number,\n      \"%Object%\": $Object,\n      \"%Object.getOwnPropertyDescriptor%\": $gOPD,\n      \"%parseFloat%\": parseFloat,\n      \"%parseInt%\": parseInt,\n      \"%Promise%\": typeof Promise === \"undefined\" ? undefined2 : Promise,\n      \"%Proxy%\": typeof Proxy === \"undefined\" ? undefined2 : Proxy,\n      \"%RangeError%\": $RangeError,\n      \"%ReferenceError%\": $ReferenceError,\n      \"%Reflect%\": typeof Reflect === \"undefined\" ? undefined2 : Reflect,\n      \"%RegExp%\": RegExp,\n      \"%Set%\": typeof Set === \"undefined\" ? undefined2 : Set,\n      \"%SetIteratorPrototype%\": typeof Set === \"undefined\" || !hasSymbols || !getProto ? undefined2 : getProto((/* @__PURE__ */ new Set())[Symbol.iterator]()),\n      \"%SharedArrayBuffer%\": typeof SharedArrayBuffer === \"undefined\" ? undefined2 : SharedArrayBuffer,\n      \"%String%\": String,\n      \"%StringIteratorPrototype%\": hasSymbols && getProto ? getProto(\"\"[Symbol.iterator]()) : undefined2,\n      \"%Symbol%\": hasSymbols ? Symbol : undefined2,\n      \"%SyntaxError%\": $SyntaxError,\n      \"%ThrowTypeError%\": ThrowTypeError,\n      \"%TypedArray%\": TypedArray,\n      \"%TypeError%\": $TypeError,\n      \"%Uint8Array%\": typeof Uint8Array === \"undefined\" ? undefined2 : Uint8Array,\n      \"%Uint8ClampedArray%\": typeof Uint8ClampedArray === \"undefined\" ? undefined2 : Uint8ClampedArray,\n      \"%Uint16Array%\": typeof Uint16Array === \"undefined\" ? undefined2 : Uint16Array,\n      \"%Uint32Array%\": typeof Uint32Array === \"undefined\" ? undefined2 : Uint32Array,\n      \"%URIError%\": $URIError,\n      \"%WeakMap%\": typeof WeakMap === \"undefined\" ? undefined2 : WeakMap,\n      \"%WeakRef%\": typeof WeakRef === \"undefined\" ? undefined2 : WeakRef,\n      \"%WeakSet%\": typeof WeakSet === \"undefined\" ? undefined2 : WeakSet,\n      \"%Function.prototype.call%\": $call,\n      \"%Function.prototype.apply%\": $apply,\n      \"%Object.defineProperty%\": $defineProperty,\n      \"%Object.getPrototypeOf%\": $ObjectGPO,\n      \"%Math.abs%\": abs,\n      \"%Math.floor%\": floor,\n      \"%Math.max%\": max,\n      \"%Math.min%\": min,\n      \"%Math.pow%\": pow,\n      \"%Math.round%\": round,\n      \"%Math.sign%\": sign,\n      \"%Reflect.getPrototypeOf%\": $ReflectGPO\n    };\n    if (getProto) {\n      try {\n        null.error;\n      } catch (e) {\n        errorProto = getProto(getProto(e));\n        INTRINSICS[\"%Error.prototype%\"] = errorProto;\n      }\n    }\n    var errorProto;\n    var doEval = function doEval2(name) {\n      var value;\n      if (name === \"%AsyncFunction%\") {\n        value = getEvalledConstructor(\"async function () {}\");\n      } else if (name === \"%GeneratorFunction%\") {\n        value = getEvalledConstructor(\"function* () {}\");\n      } else if (name === \"%AsyncGeneratorFunction%\") {\n        value = getEvalledConstructor(\"async function* () {}\");\n      } else if (name === \"%AsyncGenerator%\") {\n        var fn = doEval2(\"%AsyncGeneratorFunction%\");\n        if (fn) {\n          value = fn.prototype;\n        }\n      } else if (name === \"%AsyncIteratorPrototype%\") {\n        var gen = doEval2(\"%AsyncGenerator%\");\n        if (gen && getProto) {\n          value = getProto(gen.prototype);\n        }\n      }\n      INTRINSICS[name] = value;\n      return value;\n    };\n    var LEGACY_ALIASES = {\n      __proto__: null,\n      \"%ArrayBufferPrototype%\": [\"ArrayBuffer\", \"prototype\"],\n      \"%ArrayPrototype%\": [\"Array\", \"prototype\"],\n      \"%ArrayProto_entries%\": [\"Array\", \"prototype\", \"entries\"],\n      \"%ArrayProto_forEach%\": [\"Array\", \"prototype\", \"forEach\"],\n      \"%ArrayProto_keys%\": [\"Array\", \"prototype\", \"keys\"],\n      \"%ArrayProto_values%\": [\"Array\", \"prototype\", \"values\"],\n      \"%AsyncFunctionPrototype%\": [\"AsyncFunction\", \"prototype\"],\n      \"%AsyncGenerator%\": [\"AsyncGeneratorFunction\", \"prototype\"],\n      \"%AsyncGeneratorPrototype%\": [\"AsyncGeneratorFunction\", \"prototype\", \"prototype\"],\n      \"%BooleanPrototype%\": [\"Boolean\", \"prototype\"],\n      \"%DataViewPrototype%\": [\"DataView\", \"prototype\"],\n      \"%DatePrototype%\": [\"Date\", \"prototype\"],\n      \"%ErrorPrototype%\": [\"Error\", \"prototype\"],\n      \"%EvalErrorPrototype%\": [\"EvalError\", \"prototype\"],\n      \"%Float32ArrayPrototype%\": [\"Float32Array\", \"prototype\"],\n      \"%Float64ArrayPrototype%\": [\"Float64Array\", \"prototype\"],\n      \"%FunctionPrototype%\": [\"Function\", \"prototype\"],\n      \"%Generator%\": [\"GeneratorFunction\", \"prototype\"],\n      \"%GeneratorPrototype%\": [\"GeneratorFunction\", \"prototype\", \"prototype\"],\n      \"%Int8ArrayPrototype%\": [\"Int8Array\", \"prototype\"],\n      \"%Int16ArrayPrototype%\": [\"Int16Array\", \"prototype\"],\n      \"%Int32ArrayPrototype%\": [\"Int32Array\", \"prototype\"],\n      \"%JSONParse%\": [\"JSON\", \"parse\"],\n      \"%JSONStringify%\": [\"JSON\", \"stringify\"],\n      \"%MapPrototype%\": [\"Map\", \"prototype\"],\n      \"%NumberPrototype%\": [\"Number\", \"prototype\"],\n      \"%ObjectPrototype%\": [\"Object\", \"prototype\"],\n      \"%ObjProto_toString%\": [\"Object\", \"prototype\", \"toString\"],\n      \"%ObjProto_valueOf%\": [\"Object\", \"prototype\", \"valueOf\"],\n      \"%PromisePrototype%\": [\"Promise\", \"prototype\"],\n      \"%PromiseProto_then%\": [\"Promise\", \"prototype\", \"then\"],\n      \"%Promise_all%\": [\"Promise\", \"all\"],\n      \"%Promise_reject%\": [\"Promise\", \"reject\"],\n      \"%Promise_resolve%\": [\"Promise\", \"resolve\"],\n      \"%RangeErrorPrototype%\": [\"RangeError\", \"prototype\"],\n      \"%ReferenceErrorPrototype%\": [\"ReferenceError\", \"prototype\"],\n      \"%RegExpPrototype%\": [\"RegExp\", \"prototype\"],\n      \"%SetPrototype%\": [\"Set\", \"prototype\"],\n      \"%SharedArrayBufferPrototype%\": [\"SharedArrayBuffer\", \"prototype\"],\n      \"%StringPrototype%\": [\"String\", \"prototype\"],\n      \"%SymbolPrototype%\": [\"Symbol\", \"prototype\"],\n      \"%SyntaxErrorPrototype%\": [\"SyntaxError\", \"prototype\"],\n      \"%TypedArrayPrototype%\": [\"TypedArray\", \"prototype\"],\n      \"%TypeErrorPrototype%\": [\"TypeError\", \"prototype\"],\n      \"%Uint8ArrayPrototype%\": [\"Uint8Array\", \"prototype\"],\n      \"%Uint8ClampedArrayPrototype%\": [\"Uint8ClampedArray\", \"prototype\"],\n      \"%Uint16ArrayPrototype%\": [\"Uint16Array\", \"prototype\"],\n      \"%Uint32ArrayPrototype%\": [\"Uint32Array\", \"prototype\"],\n      \"%URIErrorPrototype%\": [\"URIError\", \"prototype\"],\n      \"%WeakMapPrototype%\": [\"WeakMap\", \"prototype\"],\n      \"%WeakSetPrototype%\": [\"WeakSet\", \"prototype\"]\n    };\n    var bind = require_function_bind();\n    var hasOwn = require_hasown();\n    var $concat = bind.call($call, Array.prototype.concat);\n    var $spliceApply = bind.call($apply, Array.prototype.splice);\n    var $replace = bind.call($call, String.prototype.replace);\n    var $strSlice = bind.call($call, String.prototype.slice);\n    var $exec = bind.call($call, RegExp.prototype.exec);\n    var rePropName = /[^%.[\\]]+|\\[(?:(-?\\d+(?:\\.\\d+)?)|([\"'])((?:(?!\\2)[^\\\\]|\\\\.)*?)\\2)\\]|(?=(?:\\.|\\[\\])(?:\\.|\\[\\]|%$))/g;\n    var reEscapeChar = /\\\\(\\\\)?/g;\n    var stringToPath = function stringToPath2(string) {\n      var first = $strSlice(string, 0, 1);\n      var last = $strSlice(string, -1);\n      if (first === \"%\" && last !== \"%\") {\n        throw new $SyntaxError(\"invalid intrinsic syntax, expected closing `%`\");\n      } else if (last === \"%\" && first !== \"%\") {\n        throw new $SyntaxError(\"invalid intrinsic syntax, expected opening `%`\");\n      }\n      var result = [];\n      $replace(string, rePropName, function(match, number, quote, subString) {\n        result[result.length] = quote ? $replace(subString, reEscapeChar, \"$1\") : number || match;\n      });\n      return result;\n    };\n    var getBaseIntrinsic = function getBaseIntrinsic2(name, allowMissing) {\n      var intrinsicName = name;\n      var alias;\n      if (hasOwn(LEGACY_ALIASES, intrinsicName)) {\n        alias = LEGACY_ALIASES[intrinsicName];\n        intrinsicName = \"%\" + alias[0] + \"%\";\n      }\n      if (hasOwn(INTRINSICS, intrinsicName)) {\n        var value = INTRINSICS[intrinsicName];\n        if (value === needsEval) {\n          value = doEval(intrinsicName);\n        }\n        if (typeof value === \"undefined\" && !allowMissing) {\n          throw new $TypeError(\"intrinsic \" + name + \" exists, but is not available. Please file an issue!\");\n        }\n        return {\n          alias,\n          name: intrinsicName,\n          value\n        };\n      }\n      throw new $SyntaxError(\"intrinsic \" + name + \" does not exist!\");\n    };\n    module2.exports = function GetIntrinsic(name, allowMissing) {\n      if (typeof name !== \"string\" || name.length === 0) {\n        throw new $TypeError(\"intrinsic name must be a non-empty string\");\n      }\n      if (arguments.length > 1 && typeof allowMissing !== \"boolean\") {\n        throw new $TypeError('\"allowMissing\" argument must be a boolean');\n      }\n      if ($exec(/^%?[^%]*%?$/, name) === null) {\n        throw new $SyntaxError(\"`%` may not be present anywhere but at the beginning and end of the intrinsic name\");\n      }\n      var parts = stringToPath(name);\n      var intrinsicBaseName = parts.length > 0 ? parts[0] : \"\";\n      var intrinsic = getBaseIntrinsic(\"%\" + intrinsicBaseName + \"%\", allowMissing);\n      var intrinsicRealName = intrinsic.name;\n      var value = intrinsic.value;\n      var skipFurtherCaching = false;\n      var alias = intrinsic.alias;\n      if (alias) {\n        intrinsicBaseName = alias[0];\n        $spliceApply(parts, $concat([0, 1], alias));\n      }\n      for (var i = 1, isOwn = true; i < parts.length; i += 1) {\n        var part = parts[i];\n        var first = $strSlice(part, 0, 1);\n        var last = $strSlice(part, -1);\n        if ((first === '\"' || first === \"'\" || first === \"`\" || (last === '\"' || last === \"'\" || last === \"`\")) && first !== last) {\n          throw new $SyntaxError(\"property names with quotes must have matching quotes\");\n        }\n        if (part === \"constructor\" || !isOwn) {\n          skipFurtherCaching = true;\n        }\n        intrinsicBaseName += \".\" + part;\n        intrinsicRealName = \"%\" + intrinsicBaseName + \"%\";\n        if (hasOwn(INTRINSICS, intrinsicRealName)) {\n          value = INTRINSICS[intrinsicRealName];\n        } else if (value != null) {\n          if (!(part in value)) {\n            if (!allowMissing) {\n              throw new $TypeError(\"base intrinsic for \" + name + \" exists, but the property is not available.\");\n            }\n            return void undefined2;\n          }\n          if ($gOPD && i + 1 >= parts.length) {\n            var desc = $gOPD(value, part);\n            isOwn = !!desc;\n            if (isOwn && \"get\" in desc && !(\"originalValue\" in desc.get)) {\n              value = desc.get;\n            } else {\n              value = value[part];\n            }\n          } else {\n            isOwn = hasOwn(value, part);\n            value = value[part];\n          }\n          if (isOwn && !skipFurtherCaching) {\n            INTRINSICS[intrinsicRealName] = value;\n          }\n        }\n      }\n      return value;\n    };\n  }\n});\n\n// node_modules/.pnpm/call-bound@1.0.4/node_modules/call-bound/index.js\nvar require_call_bound = __commonJS({\n  \"node_modules/.pnpm/call-bound@1.0.4/node_modules/call-bound/index.js\"(exports2, module2) {\n    \"use strict\";\n    var GetIntrinsic = require_get_intrinsic();\n    var callBindBasic = require_call_bind_apply_helpers();\n    var $indexOf = callBindBasic([GetIntrinsic(\"%String.prototype.indexOf%\")]);\n    module2.exports = function callBoundIntrinsic(name, allowMissing) {\n      var intrinsic = (\n        /** @type {(this: unknown, ...args: unknown[]) => unknown} */\n        GetIntrinsic(name, !!allowMissing)\n      );\n      if (typeof intrinsic === \"function\" && $indexOf(name, \".prototype.\") > -1) {\n        return callBindBasic(\n          /** @type {const} */\n          [intrinsic]\n        );\n      }\n      return intrinsic;\n    };\n  }\n});\n\n// node_modules/.pnpm/is-callable@1.2.7/node_modules/is-callable/index.js\nvar require_is_callable = __commonJS({\n  \"node_modules/.pnpm/is-callable@1.2.7/node_modules/is-callable/index.js\"(exports2, module2) {\n    \"use strict\";\n    var fnToStr = Function.prototype.toString;\n    var reflectApply = typeof Reflect === \"object\" && Reflect !== null && Reflect.apply;\n    var badArrayLike;\n    var isCallableMarker;\n    if (typeof reflectApply === \"function\" && typeof Object.defineProperty === \"function\") {\n      try {\n        badArrayLike = Object.defineProperty({}, \"length\", {\n          get: function() {\n            throw isCallableMarker;\n          }\n        });\n        isCallableMarker = {};\n        reflectApply(function() {\n          throw 42;\n        }, null, badArrayLike);\n      } catch (_) {\n        if (_ !== isCallableMarker) {\n          reflectApply = null;\n        }\n      }\n    } else {\n      reflectApply = null;\n    }\n    var constructorRegex = /^\\s*class\\b/;\n    var isES6ClassFn = function isES6ClassFunction(value) {\n      try {\n        var fnStr = fnToStr.call(value);\n        return constructorRegex.test(fnStr);\n      } catch (e) {\n        return false;\n      }\n    };\n    var tryFunctionObject = function tryFunctionToStr(value) {\n      try {\n        if (isES6ClassFn(value)) {\n          return false;\n        }\n        fnToStr.call(value);\n        return true;\n      } catch (e) {\n        return false;\n      }\n    };\n    var toStr = Object.prototype.toString;\n    var objectClass = \"[object Object]\";\n    var fnClass = \"[object Function]\";\n    var genClass = \"[object GeneratorFunction]\";\n    var ddaClass = \"[object HTMLAllCollection]\";\n    var ddaClass2 = \"[object HTML document.all class]\";\n    var ddaClass3 = \"[object HTMLCollection]\";\n    var hasToStringTag = typeof Symbol === \"function\" && !!Symbol.toStringTag;\n    var isIE68 = !(0 in [,]);\n    var isDDA = function isDocumentDotAll() {\n      return false;\n    };\n    if (typeof document === \"object\") {\n      all = document.all;\n      if (toStr.call(all) === toStr.call(document.all)) {\n        isDDA = function isDocumentDotAll(value) {\n          if ((isIE68 || !value) && (typeof value === \"undefined\" || typeof value === \"object\")) {\n            try {\n              var str = toStr.call(value);\n              return (str === ddaClass || str === ddaClass2 || str === ddaClass3 || str === objectClass) && value(\"\") == null;\n            } catch (e) {\n            }\n          }\n          return false;\n        };\n      }\n    }\n    var all;\n    module2.exports = reflectApply ? function isCallable(value) {\n      if (isDDA(value)) {\n        return true;\n      }\n      if (!value) {\n        return false;\n      }\n      if (typeof value !== \"function\" && typeof value !== \"object\") {\n        return false;\n      }\n      try {\n        reflectApply(value, null, badArrayLike);\n      } catch (e) {\n        if (e !== isCallableMarker) {\n          return false;\n        }\n      }\n      return !isES6ClassFn(value) && tryFunctionObject(value);\n    } : function isCallable(value) {\n      if (isDDA(value)) {\n        return true;\n      }\n      if (!value) {\n        return false;\n      }\n      if (typeof value !== \"function\" && typeof value !== \"object\") {\n        return false;\n      }\n      if (hasToStringTag) {\n        return tryFunctionObject(value);\n      }\n      if (isES6ClassFn(value)) {\n        return false;\n      }\n      var strClass = toStr.call(value);\n      if (strClass !== fnClass && strClass !== genClass && !/^\\[object HTML/.test(strClass)) {\n        return false;\n      }\n      return tryFunctionObject(value);\n    };\n  }\n});\n\n// node_modules/.pnpm/for-each@0.3.5/node_modules/for-each/index.js\nvar require_for_each = __commonJS({\n  \"node_modules/.pnpm/for-each@0.3.5/node_modules/for-each/index.js\"(exports2, module2) {\n    \"use strict\";\n    var isCallable = require_is_callable();\n    var toStr = Object.prototype.toString;\n    var hasOwnProperty = Object.prototype.hasOwnProperty;\n    var forEachArray = function forEachArray2(array, iterator, receiver) {\n      for (var i = 0, len = array.length; i < len; i++) {\n        if (hasOwnProperty.call(array, i)) {\n          if (receiver == null) {\n            iterator(array[i], i, array);\n          } else {\n            iterator.call(receiver, array[i], i, array);\n          }\n        }\n      }\n    };\n    var forEachString = function forEachString2(string, iterator, receiver) {\n      for (var i = 0, len = string.length; i < len; i++) {\n        if (receiver == null) {\n          iterator(string.charAt(i), i, string);\n        } else {\n          iterator.call(receiver, string.charAt(i), i, string);\n        }\n      }\n    };\n    var forEachObject = function forEachObject2(object, iterator, receiver) {\n      for (var k in object) {\n        if (hasOwnProperty.call(object, k)) {\n          if (receiver == null) {\n            iterator(object[k], k, object);\n          } else {\n            iterator.call(receiver, object[k], k, object);\n          }\n        }\n      }\n    };\n    function isArray(x) {\n      return toStr.call(x) === \"[object Array]\";\n    }\n    module2.exports = function forEach(list, iterator, thisArg) {\n      if (!isCallable(iterator)) {\n        throw new TypeError(\"iterator must be a function\");\n      }\n      var receiver;\n      if (arguments.length >= 3) {\n        receiver = thisArg;\n      }\n      if (isArray(list)) {\n        forEachArray(list, iterator, receiver);\n      } else if (typeof list === \"string\") {\n        forEachString(list, iterator, receiver);\n      } else {\n        forEachObject(list, iterator, receiver);\n      }\n    };\n  }\n});\n\n// node_modules/.pnpm/possible-typed-array-names@1.1.0/node_modules/possible-typed-array-names/index.js\nvar require_possible_typed_array_names = __commonJS({\n  \"node_modules/.pnpm/possible-typed-array-names@1.1.0/node_modules/possible-typed-array-names/index.js\"(exports2, module2) {\n    \"use strict\";\n    module2.exports = [\n      \"Float16Array\",\n      \"Float32Array\",\n      \"Float64Array\",\n      \"Int8Array\",\n      \"Int16Array\",\n      \"Int32Array\",\n      \"Uint8Array\",\n      \"Uint8ClampedArray\",\n      \"Uint16Array\",\n      \"Uint32Array\",\n      \"BigInt64Array\",\n      \"BigUint64Array\"\n    ];\n  }\n});\n\n// node_modules/.pnpm/available-typed-arrays@1.0.7/node_modules/available-typed-arrays/index.js\nvar require_available_typed_arrays = __commonJS({\n  \"node_modules/.pnpm/available-typed-arrays@1.0.7/node_modules/available-typed-arrays/index.js\"(exports2, module2) {\n    \"use strict\";\n    var possibleNames = require_possible_typed_array_names();\n    var g = typeof globalThis === \"undefined\" ? global : globalThis;\n    module2.exports = function availableTypedArrays() {\n      var out = [];\n      for (var i = 0; i < possibleNames.length; i++) {\n        if (typeof g[possibleNames[i]] === \"function\") {\n          out[out.length] = possibleNames[i];\n        }\n      }\n      return out;\n    };\n  }\n});\n\n// node_modules/.pnpm/define-data-property@1.1.4/node_modules/define-data-property/index.js\nvar require_define_data_property = __commonJS({\n  \"node_modules/.pnpm/define-data-property@1.1.4/node_modules/define-data-property/index.js\"(exports2, module2) {\n    \"use strict\";\n    var $defineProperty = require_es_define_property();\n    var $SyntaxError = require_syntax();\n    var $TypeError = require_type();\n    var gopd = require_gopd();\n    module2.exports = function defineDataProperty(obj, property, value) {\n      if (!obj || typeof obj !== \"object\" && typeof obj !== \"function\") {\n        throw new $TypeError(\"`obj` must be an object or a function`\");\n      }\n      if (typeof property !== \"string\" && typeof property !== \"symbol\") {\n        throw new $TypeError(\"`property` must be a string or a symbol`\");\n      }\n      if (arguments.length > 3 && typeof arguments[3] !== \"boolean\" && arguments[3] !== null) {\n        throw new $TypeError(\"`nonEnumerable`, if provided, must be a boolean or null\");\n      }\n      if (arguments.length > 4 && typeof arguments[4] !== \"boolean\" && arguments[4] !== null) {\n        throw new $TypeError(\"`nonWritable`, if provided, must be a boolean or null\");\n      }\n      if (arguments.length > 5 && typeof arguments[5] !== \"boolean\" && arguments[5] !== null) {\n        throw new $TypeError(\"`nonConfigurable`, if provided, must be a boolean or null\");\n      }\n      if (arguments.length > 6 && typeof arguments[6] !== \"boolean\") {\n        throw new $TypeError(\"`loose`, if provided, must be a boolean\");\n      }\n      var nonEnumerable = arguments.length > 3 ? arguments[3] : null;\n      var nonWritable = arguments.length > 4 ? arguments[4] : null;\n      var nonConfigurable = arguments.length > 5 ? arguments[5] : null;\n      var loose = arguments.length > 6 ? arguments[6] : false;\n      var desc = !!gopd && gopd(obj, property);\n      if ($defineProperty) {\n        $defineProperty(obj, property, {\n          configurable: nonConfigurable === null && desc ? desc.configurable : !nonConfigurable,\n          enumerable: nonEnumerable === null && desc ? desc.enumerable : !nonEnumerable,\n          value,\n          writable: nonWritable === null && desc ? desc.writable : !nonWritable\n        });\n      } else if (loose || !nonEnumerable && !nonWritable && !nonConfigurable) {\n        obj[property] = value;\n      } else {\n        throw new $SyntaxError(\"This environment does not support defining a property as non-configurable, non-writable, or non-enumerable.\");\n      }\n    };\n  }\n});\n\n// node_modules/.pnpm/has-property-descriptors@1.0.2/node_modules/has-property-descriptors/index.js\nvar require_has_property_descriptors = __commonJS({\n  \"node_modules/.pnpm/has-property-descriptors@1.0.2/node_modules/has-property-descriptors/index.js\"(exports2, module2) {\n    \"use strict\";\n    var $defineProperty = require_es_define_property();\n    var hasPropertyDescriptors = function hasPropertyDescriptors2() {\n      return !!$defineProperty;\n    };\n    hasPropertyDescriptors.hasArrayLengthDefineBug = function hasArrayLengthDefineBug() {\n      if (!$defineProperty) {\n        return null;\n      }\n      try {\n        return $defineProperty([], \"length\", { value: 1 }).length !== 1;\n      } catch (e) {\n        return true;\n      }\n    };\n    module2.exports = hasPropertyDescriptors;\n  }\n});\n\n// node_modules/.pnpm/set-function-length@1.2.2/node_modules/set-function-length/index.js\nvar require_set_function_length = __commonJS({\n  \"node_modules/.pnpm/set-function-length@1.2.2/node_modules/set-function-length/index.js\"(exports2, module2) {\n    \"use strict\";\n    var GetIntrinsic = require_get_intrinsic();\n    var define2 = require_define_data_property();\n    var hasDescriptors = require_has_property_descriptors()();\n    var gOPD = require_gopd();\n    var $TypeError = require_type();\n    var $floor = GetIntrinsic(\"%Math.floor%\");\n    module2.exports = function setFunctionLength(fn, length) {\n      if (typeof fn !== \"function\") {\n        throw new $TypeError(\"`fn` is not a function\");\n      }\n      if (typeof length !== \"number\" || length < 0 || length > 4294967295 || $floor(length) !== length) {\n        throw new $TypeError(\"`length` must be a positive 32-bit integer\");\n      }\n      var loose = arguments.length > 2 && !!arguments[2];\n      var functionLengthIsConfigurable = true;\n      var functionLengthIsWritable = true;\n      if (\"length\" in fn && gOPD) {\n        var desc = gOPD(fn, \"length\");\n        if (desc && !desc.configurable) {\n          functionLengthIsConfigurable = false;\n        }\n        if (desc && !desc.writable) {\n          functionLengthIsWritable = false;\n        }\n      }\n      if (functionLengthIsConfigurable || functionLengthIsWritable || !loose) {\n        if (hasDescriptors) {\n          define2(\n            /** @type {Parameters<define>[0]} */\n            fn,\n            \"length\",\n            length,\n            true,\n            true\n          );\n        } else {\n          define2(\n            /** @type {Parameters<define>[0]} */\n            fn,\n            \"length\",\n            length\n          );\n        }\n      }\n      return fn;\n    };\n  }\n});\n\n// node_modules/.pnpm/call-bind-apply-helpers@1.0.2/node_modules/call-bind-apply-helpers/applyBind.js\nvar require_applyBind = __commonJS({\n  \"node_modules/.pnpm/call-bind-apply-helpers@1.0.2/node_modules/call-bind-apply-helpers/applyBind.js\"(exports2, module2) {\n    \"use strict\";\n    var bind = require_function_bind();\n    var $apply = require_functionApply();\n    var actualApply = require_actualApply();\n    module2.exports = function applyBind() {\n      return actualApply(bind, $apply, arguments);\n    };\n  }\n});\n\n// node_modules/.pnpm/call-bind@1.0.9/node_modules/call-bind/index.js\nvar require_call_bind = __commonJS({\n  \"node_modules/.pnpm/call-bind@1.0.9/node_modules/call-bind/index.js\"(exports2, module2) {\n    \"use strict\";\n    var setFunctionLength = require_set_function_length();\n    var $defineProperty = require_es_define_property();\n    var callBindBasic = require_call_bind_apply_helpers();\n    var applyBind = require_applyBind();\n    module2.exports = function callBind(originalFunction) {\n      var func = callBindBasic(arguments);\n      var adjustedLength = 1 + originalFunction.length - (arguments.length - 1);\n      return setFunctionLength(\n        func,\n        adjustedLength > 0 ? adjustedLength : 0,\n        true\n      );\n    };\n    if ($defineProperty) {\n      $defineProperty(module2.exports, \"apply\", { value: applyBind });\n    } else {\n      module2.exports.apply = applyBind;\n    }\n  }\n});\n\n// node_modules/.pnpm/has-tostringtag@1.0.2/node_modules/has-tostringtag/shams.js\nvar require_shams2 = __commonJS({\n  \"node_modules/.pnpm/has-tostringtag@1.0.2/node_modules/has-tostringtag/shams.js\"(exports2, module2) {\n    \"use strict\";\n    var hasSymbols = require_shams();\n    module2.exports = function hasToStringTagShams() {\n      return hasSymbols() && !!Symbol.toStringTag;\n    };\n  }\n});\n\n// node_modules/.pnpm/which-typed-array@1.1.24/node_modules/which-typed-array/index.js\nvar require_which_typed_array = __commonJS({\n  \"node_modules/.pnpm/which-typed-array@1.1.24/node_modules/which-typed-array/index.js\"(exports2, module2) {\n    \"use strict\";\n    var forEach = require_for_each();\n    var availableTypedArrays = require_available_typed_arrays();\n    var callBind = require_call_bind();\n    var callBound = require_call_bound();\n    var gOPD = require_gopd();\n    var getProto = require_get_proto();\n    var $toString = callBound(\"Object.prototype.toString\");\n    var hasToStringTag = require_shams2()();\n    var g = typeof globalThis === \"undefined\" ? global : globalThis;\n    var typedArrays = availableTypedArrays();\n    var $slice = callBound(\"String.prototype.slice\");\n    var $indexOf = callBound(\"Array.prototype.indexOf\", true) || function indexOf(array, value) {\n      for (var i = 0; i < array.length; i += 1) {\n        if (array[i] === value) {\n          return i;\n        }\n      }\n      return -1;\n    };\n    var cache = { __proto__: null };\n    if (hasToStringTag && gOPD && getProto) {\n      forEach(typedArrays, function(typedArray) {\n        var arr = new g[typedArray]();\n        if (Symbol.toStringTag in arr && getProto) {\n          var proto = getProto(arr);\n          var descriptor = gOPD(proto, Symbol.toStringTag);\n          if (!descriptor && proto) {\n            var superProto = getProto(proto);\n            descriptor = gOPD(superProto, Symbol.toStringTag);\n          }\n          if (descriptor && descriptor.get) {\n            var bound = callBind(descriptor.get);\n            cache[\n              /** @type {`$${TypedArrayName}`} */\n              \"$\" + typedArray\n            ] = bound;\n          }\n        }\n      });\n    } else {\n      forEach(typedArrays, function(typedArray) {\n        var arr = new g[typedArray]();\n        var fn = arr.slice || arr.set;\n        if (fn) {\n          var bound = (\n            /** @type {typeof BoundSlice | typeof BoundSet} */\n            // @ts-expect-error TODO FIXME\n            callBind(fn)\n          );\n          cache[\n            /** @type {`$${TypedArrayName}`} */\n            \"$\" + typedArray\n          ] = bound;\n        }\n      });\n    }\n    function tryTypedArrays(value) {\n      var found = false;\n      forEach(\n        /** @type {Record<`$${TypedArrayName}`, Getter>} */\n        cache,\n        /** @param {Getter} getter @param {`$${TypedArrayName}`} typedArray */\n        function(getter, typedArray) {\n          if (!found) {\n            try {\n              if (\"$\" + getter(value) === typedArray) {\n                found = /** @type {TypedArrayName} */\n                $slice(typedArray, 1);\n              }\n            } catch (e) {\n            }\n          }\n        }\n      );\n      return found;\n    }\n    function trySlices(value) {\n      var found = false;\n      forEach(\n        /** @type {Record<`$${TypedArrayName}`, Getter>} */\n        cache,\n        /** @param {Getter} getter @param {`$${TypedArrayName}`} name */\n        function(getter, name) {\n          if (!found) {\n            try {\n              getter(value);\n              found = /** @type {TypedArrayName} */\n              $slice(name, 1);\n            } catch (e) {\n            }\n          }\n        }\n      );\n      return found;\n    }\n    function isTATag(tag) {\n      return $indexOf(typedArrays, tag) > -1;\n    }\n    function whichTypedArray(value) {\n      if (!value || typeof value !== \"object\") {\n        return false;\n      }\n      if (!hasToStringTag) {\n        var tag = $slice($toString(value), 8, -1);\n        if (isTATag(tag)) {\n          return tag;\n        }\n        if (tag !== \"Object\") {\n          return false;\n        }\n        return trySlices(value);\n      }\n      if (!gOPD) {\n        return null;\n      }\n      return tryTypedArrays(value);\n    }\n    module2.exports = whichTypedArray;\n  }\n});\n\n// node_modules/.pnpm/is-typed-array@1.1.15/node_modules/is-typed-array/index.js\nvar require_is_typed_array = __commonJS({\n  \"node_modules/.pnpm/is-typed-array@1.1.15/node_modules/is-typed-array/index.js\"(exports2, module2) {\n    \"use strict\";\n    var whichTypedArray = require_which_typed_array();\n    module2.exports = function isTypedArray(value) {\n      return !!whichTypedArray(value);\n    };\n  }\n});\n\n// node_modules/.pnpm/typed-array-buffer@1.0.3/node_modules/typed-array-buffer/index.js\nvar require_typed_array_buffer = __commonJS({\n  \"node_modules/.pnpm/typed-array-buffer@1.0.3/node_modules/typed-array-buffer/index.js\"(exports2, module2) {\n    \"use strict\";\n    var $TypeError = require_type();\n    var callBound = require_call_bound();\n    var $typedArrayBuffer = callBound(\"TypedArray.prototype.buffer\", true);\n    var isTypedArray = require_is_typed_array();\n    module2.exports = $typedArrayBuffer || function typedArrayBuffer(x) {\n      if (!isTypedArray(x)) {\n        throw new $TypeError(\"Not a Typed Array\");\n      }\n      return x.buffer;\n    };\n  }\n});\n\n// node_modules/.pnpm/to-buffer@1.2.2/node_modules/to-buffer/index.js\nvar require_to_buffer = __commonJS({\n  \"node_modules/.pnpm/to-buffer@1.2.2/node_modules/to-buffer/index.js\"(exports2, module2) {\n    \"use strict\";\n    var Buffer2 = require_safe_buffer().Buffer;\n    var isArray = require_isarray();\n    var typedArrayBuffer = require_typed_array_buffer();\n    var isView = ArrayBuffer.isView || function isView2(obj) {\n      try {\n        typedArrayBuffer(obj);\n        return true;\n      } catch (e) {\n        return false;\n      }\n    };\n    var useUint8Array = typeof Uint8Array !== \"undefined\";\n    var useArrayBuffer = typeof ArrayBuffer !== \"undefined\" && typeof Uint8Array !== \"undefined\";\n    var useFromArrayBuffer = useArrayBuffer && (Buffer2.prototype instanceof Uint8Array || Buffer2.TYPED_ARRAY_SUPPORT);\n    module2.exports = function toBuffer(data, encoding) {\n      if (Buffer2.isBuffer(data)) {\n        if (data.constructor && !(\"isBuffer\" in data)) {\n          return Buffer2.from(data);\n        }\n        return data;\n      }\n      if (typeof data === \"string\") {\n        return Buffer2.from(data, encoding);\n      }\n      if (useArrayBuffer && isView(data)) {\n        if (data.byteLength === 0) {\n          return Buffer2.alloc(0);\n        }\n        if (useFromArrayBuffer) {\n          var res = Buffer2.from(data.buffer, data.byteOffset, data.byteLength);\n          if (res.byteLength === data.byteLength) {\n            return res;\n          }\n        }\n        var uint8 = data instanceof Uint8Array ? data : new Uint8Array(data.buffer, data.byteOffset, data.byteLength);\n        var result = Buffer2.from(uint8);\n        if (result.length === data.byteLength) {\n          return result;\n        }\n      }\n      if (useUint8Array && data instanceof Uint8Array) {\n        return Buffer2.from(data);\n      }\n      var isArr = isArray(data);\n      if (isArr) {\n        for (var i = 0; i < data.length; i += 1) {\n          var x = data[i];\n          if (typeof x !== \"number\" || x < 0 || x > 255 || ~~x !== x) {\n            throw new RangeError(\"Array items must be numbers in the range 0-255.\");\n          }\n        }\n      }\n      if (isArr || Buffer2.isBuffer(data) && data.constructor && typeof data.constructor.isBuffer === \"function\" && data.constructor.isBuffer(data)) {\n        return Buffer2.from(data);\n      }\n      throw new TypeError('The \"data\" argument must be a string, an Array, a Buffer, a Uint8Array, or a DataView.');\n    };\n  }\n});\n\n// node_modules/.pnpm/sha.js@2.4.12/node_modules/sha.js/hash.js\nvar require_hash = __commonJS({\n  \"node_modules/.pnpm/sha.js@2.4.12/node_modules/sha.js/hash.js\"(exports2, module2) {\n    \"use strict\";\n    var Buffer2 = require_safe_buffer().Buffer;\n    var toBuffer = require_to_buffer();\n    function Hash(blockSize, finalSize) {\n      this._block = Buffer2.alloc(blockSize);\n      this._finalSize = finalSize;\n      this._blockSize = blockSize;\n      this._len = 0;\n    }\n    Hash.prototype.update = function(data, enc) {\n      data = toBuffer(data, enc || \"utf8\");\n      var block = this._block;\n      var blockSize = this._blockSize;\n      var length = data.length;\n      var accum = this._len;\n      for (var offset = 0; offset < length; ) {\n        var assigned = accum % blockSize;\n        var remainder = Math.min(length - offset, blockSize - assigned);\n        for (var i = 0; i < remainder; i++) {\n          block[assigned + i] = data[offset + i];\n        }\n        accum += remainder;\n        offset += remainder;\n        if (accum % blockSize === 0) {\n          this._update(block);\n        }\n      }\n      this._len += length;\n      return this;\n    };\n    Hash.prototype.digest = function(enc) {\n      var rem = this._len % this._blockSize;\n      this._block[rem] = 128;\n      this._block.fill(0, rem + 1);\n      if (rem >= this._finalSize) {\n        this._update(this._block);\n        this._block.fill(0);\n      }\n      var bits = this._len * 8;\n      if (bits <= 4294967295) {\n        this._block.writeUInt32BE(bits, this._blockSize - 4);\n      } else {\n        var lowBits = (bits & 4294967295) >>> 0;\n        var highBits = (bits - lowBits) / 4294967296;\n        this._block.writeUInt32BE(highBits, this._blockSize - 8);\n        this._block.writeUInt32BE(lowBits, this._blockSize - 4);\n      }\n      this._update(this._block);\n      var hash = this._hash();\n      return enc ? hash.toString(enc) : hash;\n    };\n    Hash.prototype._update = function() {\n      throw new Error(\"_update must be implemented by subclass\");\n    };\n    module2.exports = Hash;\n  }\n});\n\n// node_modules/.pnpm/sha.js@2.4.12/node_modules/sha.js/sha1.js\nvar require_sha1 = __commonJS({\n  \"node_modules/.pnpm/sha.js@2.4.12/node_modules/sha.js/sha1.js\"(exports2, module2) {\n    \"use strict\";\n    var inherits = require_inherits();\n    var Hash = require_hash();\n    var Buffer2 = require_safe_buffer().Buffer;\n    var K = [\n      1518500249,\n      1859775393,\n      2400959708 | 0,\n      3395469782 | 0\n    ];\n    var W = new Array(80);\n    function Sha1() {\n      this.init();\n      this._w = W;\n      Hash.call(this, 64, 56);\n    }\n    inherits(Sha1, Hash);\n    Sha1.prototype.init = function() {\n      this._a = 1732584193;\n      this._b = 4023233417;\n      this._c = 2562383102;\n      this._d = 271733878;\n      this._e = 3285377520;\n      return this;\n    };\n    function rotl1(num) {\n      return num << 1 | num >>> 31;\n    }\n    function rotl5(num) {\n      return num << 5 | num >>> 27;\n    }\n    function rotl30(num) {\n      return num << 30 | num >>> 2;\n    }\n    function ft(s, b, c, d) {\n      if (s === 0) {\n        return b & c | ~b & d;\n      }\n      if (s === 2) {\n        return b & c | b & d | c & d;\n      }\n      return b ^ c ^ d;\n    }\n    Sha1.prototype._update = function(M) {\n      var w = this._w;\n      var a = this._a | 0;\n      var b = this._b | 0;\n      var c = this._c | 0;\n      var d = this._d | 0;\n      var e = this._e | 0;\n      for (var i = 0; i < 16; ++i) {\n        w[i] = M.readInt32BE(i * 4);\n      }\n      for (; i < 80; ++i) {\n        w[i] = rotl1(w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]);\n      }\n      for (var j = 0; j < 80; ++j) {\n        var s = ~~(j / 20);\n        var t = rotl5(a) + ft(s, b, c, d) + e + w[j] + K[s] | 0;\n        e = d;\n        d = c;\n        c = rotl30(b);\n        b = a;\n        a = t;\n      }\n      this._a = a + this._a | 0;\n      this._b = b + this._b | 0;\n      this._c = c + this._c | 0;\n      this._d = d + this._d | 0;\n      this._e = e + this._e | 0;\n    };\n    Sha1.prototype._hash = function() {\n      var H = Buffer2.allocUnsafe(20);\n      H.writeInt32BE(this._a | 0, 0);\n      H.writeInt32BE(this._b | 0, 4);\n      H.writeInt32BE(this._c | 0, 8);\n      H.writeInt32BE(this._d | 0, 12);\n      H.writeInt32BE(this._e | 0, 16);\n      return H;\n    };\n    module2.exports = Sha1;\n  }\n});\n\n// node_modules/.pnpm/crc-32@1.2.2/node_modules/crc-32/crc32.js\nvar require_crc32 = __commonJS({\n  \"node_modules/.pnpm/crc-32@1.2.2/node_modules/crc-32/crc32.js\"(exports2) {\n    var CRC32;\n    (function(factory) {\n      if (typeof DO_NOT_EXPORT_CRC === \"undefined\") {\n        if (\"object\" === typeof exports2) {\n          factory(exports2);\n        } else if (\"function\" === typeof define && define.amd) {\n          define(function() {\n            var module3 = {};\n            factory(module3);\n            return module3;\n          });\n        } else {\n          factory(CRC32 = {});\n        }\n      } else {\n        factory(CRC32 = {});\n      }\n    })(function(CRC322) {\n      CRC322.version = \"1.2.2\";\n      function signed_crc_table() {\n        var c = 0, table = new Array(256);\n        for (var n = 0; n != 256; ++n) {\n          c = n;\n          c = c & 1 ? -306674912 ^ c >>> 1 : c >>> 1;\n          c = c & 1 ? -306674912 ^ c >>> 1 : c >>> 1;\n          c = c & 1 ? -306674912 ^ c >>> 1 : c >>> 1;\n          c = c & 1 ? -306674912 ^ c >>> 1 : c >>> 1;\n          c = c & 1 ? -306674912 ^ c >>> 1 : c >>> 1;\n          c = c & 1 ? -306674912 ^ c >>> 1 : c >>> 1;\n          c = c & 1 ? -306674912 ^ c >>> 1 : c >>> 1;\n          c = c & 1 ? -306674912 ^ c >>> 1 : c >>> 1;\n          table[n] = c;\n        }\n        return typeof Int32Array !== \"undefined\" ? new Int32Array(table) : table;\n      }\n      var T0 = signed_crc_table();\n      function slice_by_16_tables(T) {\n        var c = 0, v = 0, n = 0, table = typeof Int32Array !== \"undefined\" ? new Int32Array(4096) : new Array(4096);\n        for (n = 0; n != 256; ++n) table[n] = T[n];\n        for (n = 0; n != 256; ++n) {\n          v = T[n];\n          for (c = 256 + n; c < 4096; c += 256) v = table[c] = v >>> 8 ^ T[v & 255];\n        }\n        var out = [];\n        for (n = 1; n != 16; ++n) out[n - 1] = typeof Int32Array !== \"undefined\" ? table.subarray(n * 256, n * 256 + 256) : table.slice(n * 256, n * 256 + 256);\n        return out;\n      }\n      var TT = slice_by_16_tables(T0);\n      var T1 = TT[0], T2 = TT[1], T3 = TT[2], T4 = TT[3], T5 = TT[4];\n      var T6 = TT[5], T7 = TT[6], T8 = TT[7], T9 = TT[8], Ta = TT[9];\n      var Tb = TT[10], Tc = TT[11], Td = TT[12], Te = TT[13], Tf = TT[14];\n      function crc32_bstr(bstr, seed) {\n        var C = seed ^ -1;\n        for (var i = 0, L = bstr.length; i < L; ) C = C >>> 8 ^ T0[(C ^ bstr.charCodeAt(i++)) & 255];\n        return ~C;\n      }\n      function crc32_buf(B, seed) {\n        var C = seed ^ -1, L = B.length - 15, i = 0;\n        for (; i < L; ) C = Tf[B[i++] ^ C & 255] ^ Te[B[i++] ^ C >> 8 & 255] ^ Td[B[i++] ^ C >> 16 & 255] ^ Tc[B[i++] ^ C >>> 24] ^ Tb[B[i++]] ^ Ta[B[i++]] ^ T9[B[i++]] ^ T8[B[i++]] ^ T7[B[i++]] ^ T6[B[i++]] ^ T5[B[i++]] ^ T4[B[i++]] ^ T3[B[i++]] ^ T2[B[i++]] ^ T1[B[i++]] ^ T0[B[i++]];\n        L += 15;\n        while (i < L) C = C >>> 8 ^ T0[(C ^ B[i++]) & 255];\n        return ~C;\n      }\n      function crc32_str(str, seed) {\n        var C = seed ^ -1;\n        for (var i = 0, L = str.length, c = 0, d = 0; i < L; ) {\n          c = str.charCodeAt(i++);\n          if (c < 128) {\n            C = C >>> 8 ^ T0[(C ^ c) & 255];\n          } else if (c < 2048) {\n            C = C >>> 8 ^ T0[(C ^ (192 | c >> 6 & 31)) & 255];\n            C = C >>> 8 ^ T0[(C ^ (128 | c & 63)) & 255];\n          } else if (c >= 55296 && c < 57344) {\n            c = (c & 1023) + 64;\n            d = str.charCodeAt(i++) & 1023;\n            C = C >>> 8 ^ T0[(C ^ (240 | c >> 8 & 7)) & 255];\n            C = C >>> 8 ^ T0[(C ^ (128 | c >> 2 & 63)) & 255];\n            C = C >>> 8 ^ T0[(C ^ (128 | d >> 6 & 15 | (c & 3) << 4)) & 255];\n            C = C >>> 8 ^ T0[(C ^ (128 | d & 63)) & 255];\n          } else {\n            C = C >>> 8 ^ T0[(C ^ (224 | c >> 12 & 15)) & 255];\n            C = C >>> 8 ^ T0[(C ^ (128 | c >> 6 & 63)) & 255];\n            C = C >>> 8 ^ T0[(C ^ (128 | c & 63)) & 255];\n          }\n        }\n        return ~C;\n      }\n      CRC322.table = T0;\n      CRC322.bstr = crc32_bstr;\n      CRC322.buf = crc32_buf;\n      CRC322.str = crc32_str;\n    });\n  }\n});\n\n// node_modules/.pnpm/pako@1.0.11/node_modules/pako/lib/utils/common.js\nvar require_common = __commonJS({\n  \"node_modules/.pnpm/pako@1.0.11/node_modules/pako/lib/utils/common.js\"(exports2) {\n    \"use strict\";\n    var TYPED_OK = typeof Uint8Array !== \"undefined\" && typeof Uint16Array !== \"undefined\" && typeof Int32Array !== \"undefined\";\n    function _has(obj, key) {\n      return Object.prototype.hasOwnProperty.call(obj, key);\n    }\n    exports2.assign = function(obj) {\n      var sources = Array.prototype.slice.call(arguments, 1);\n      while (sources.length) {\n        var source = sources.shift();\n        if (!source) {\n          continue;\n        }\n        if (typeof source !== \"object\") {\n          throw new TypeError(source + \"must be non-object\");\n        }\n        for (var p in source) {\n          if (_has(source, p)) {\n            obj[p] = source[p];\n          }\n        }\n      }\n      return obj;\n    };\n    exports2.shrinkBuf = function(buf, size) {\n      if (buf.length === size) {\n        return buf;\n      }\n      if (buf.subarray) {\n        return buf.subarray(0, size);\n      }\n      buf.length = size;\n      return buf;\n    };\n    var fnTyped = {\n      arraySet: function(dest, src, src_offs, len, dest_offs) {\n        if (src.subarray && dest.subarray) {\n          dest.set(src.subarray(src_offs, src_offs + len), dest_offs);\n          return;\n        }\n        for (var i = 0; i < len; i++) {\n          dest[dest_offs + i] = src[src_offs + i];\n        }\n      },\n      // Join array of chunks to single array.\n      flattenChunks: function(chunks) {\n        var i, l, len, pos, chunk, result;\n        len = 0;\n        for (i = 0, l = chunks.length; i < l; i++) {\n          len += chunks[i].length;\n        }\n        result = new Uint8Array(len);\n        pos = 0;\n        for (i = 0, l = chunks.length; i < l; i++) {\n          chunk = chunks[i];\n          result.set(chunk, pos);\n          pos += chunk.length;\n        }\n        return result;\n      }\n    };\n    var fnUntyped = {\n      arraySet: function(dest, src, src_offs, len, dest_offs) {\n        for (var i = 0; i < len; i++) {\n          dest[dest_offs + i] = src[src_offs + i];\n        }\n      },\n      // Join array of chunks to single array.\n      flattenChunks: function(chunks) {\n        return [].concat.apply([], chunks);\n      }\n    };\n    exports2.setTyped = function(on) {\n      if (on) {\n        exports2.Buf8 = Uint8Array;\n        exports2.Buf16 = Uint16Array;\n        exports2.Buf32 = Int32Array;\n        exports2.assign(exports2, fnTyped);\n      } else {\n        exports2.Buf8 = Array;\n        exports2.Buf16 = Array;\n        exports2.Buf32 = Array;\n        exports2.assign(exports2, fnUntyped);\n      }\n    };\n    exports2.setTyped(TYPED_OK);\n  }\n});\n\n// node_modules/.pnpm/pako@1.0.11/node_modules/pako/lib/zlib/trees.js\nvar require_trees = __commonJS({\n  \"node_modules/.pnpm/pako@1.0.11/node_modules/pako/lib/zlib/trees.js\"(exports2) {\n    \"use strict\";\n    var utils = require_common();\n    var Z_FIXED = 4;\n    var Z_BINARY = 0;\n    var Z_TEXT = 1;\n    var Z_UNKNOWN = 2;\n    function zero(buf) {\n      var len = buf.length;\n      while (--len >= 0) {\n        buf[len] = 0;\n      }\n    }\n    var STORED_BLOCK = 0;\n    var STATIC_TREES = 1;\n    var DYN_TREES = 2;\n    var MIN_MATCH = 3;\n    var MAX_MATCH = 258;\n    var LENGTH_CODES = 29;\n    var LITERALS = 256;\n    var L_CODES = LITERALS + 1 + LENGTH_CODES;\n    var D_CODES = 30;\n    var BL_CODES = 19;\n    var HEAP_SIZE = 2 * L_CODES + 1;\n    var MAX_BITS = 15;\n    var Buf_size = 16;\n    var MAX_BL_BITS = 7;\n    var END_BLOCK = 256;\n    var REP_3_6 = 16;\n    var REPZ_3_10 = 17;\n    var REPZ_11_138 = 18;\n    var extra_lbits = (\n      /* extra bits for each length code */\n      [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0]\n    );\n    var extra_dbits = (\n      /* extra bits for each distance code */\n      [0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13]\n    );\n    var extra_blbits = (\n      /* extra bits for each bit length code */\n      [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 7]\n    );\n    var bl_order = [16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15];\n    var DIST_CODE_LEN = 512;\n    var static_ltree = new Array((L_CODES + 2) * 2);\n    zero(static_ltree);\n    var static_dtree = new Array(D_CODES * 2);\n    zero(static_dtree);\n    var _dist_code = new Array(DIST_CODE_LEN);\n    zero(_dist_code);\n    var _length_code = new Array(MAX_MATCH - MIN_MATCH + 1);\n    zero(_length_code);\n    var base_length = new Array(LENGTH_CODES);\n    zero(base_length);\n    var base_dist = new Array(D_CODES);\n    zero(base_dist);\n    function StaticTreeDesc(static_tree, extra_bits, extra_base, elems, max_length) {\n      this.static_tree = static_tree;\n      this.extra_bits = extra_bits;\n      this.extra_base = extra_base;\n      this.elems = elems;\n      this.max_length = max_length;\n      this.has_stree = static_tree && static_tree.length;\n    }\n    var static_l_desc;\n    var static_d_desc;\n    var static_bl_desc;\n    function TreeDesc(dyn_tree, stat_desc) {\n      this.dyn_tree = dyn_tree;\n      this.max_code = 0;\n      this.stat_desc = stat_desc;\n    }\n    function d_code(dist) {\n      return dist < 256 ? _dist_code[dist] : _dist_code[256 + (dist >>> 7)];\n    }\n    function put_short(s, w) {\n      s.pending_buf[s.pending++] = w & 255;\n      s.pending_buf[s.pending++] = w >>> 8 & 255;\n    }\n    function send_bits(s, value, length) {\n      if (s.bi_valid > Buf_size - length) {\n        s.bi_buf |= value << s.bi_valid & 65535;\n        put_short(s, s.bi_buf);\n        s.bi_buf = value >> Buf_size - s.bi_valid;\n        s.bi_valid += length - Buf_size;\n      } else {\n        s.bi_buf |= value << s.bi_valid & 65535;\n        s.bi_valid += length;\n      }\n    }\n    function send_code(s, c, tree) {\n      send_bits(\n        s,\n        tree[c * 2],\n        tree[c * 2 + 1]\n        /*.Len*/\n      );\n    }\n    function bi_reverse(code, len) {\n      var res = 0;\n      do {\n        res |= code & 1;\n        code >>>= 1;\n        res <<= 1;\n      } while (--len > 0);\n      return res >>> 1;\n    }\n    function bi_flush(s) {\n      if (s.bi_valid === 16) {\n        put_short(s, s.bi_buf);\n        s.bi_buf = 0;\n        s.bi_valid = 0;\n      } else if (s.bi_valid >= 8) {\n        s.pending_buf[s.pending++] = s.bi_buf & 255;\n        s.bi_buf >>= 8;\n        s.bi_valid -= 8;\n      }\n    }\n    function gen_bitlen(s, desc) {\n      var tree = desc.dyn_tree;\n      var max_code = desc.max_code;\n      var stree = desc.stat_desc.static_tree;\n      var has_stree = desc.stat_desc.has_stree;\n      var extra = desc.stat_desc.extra_bits;\n      var base = desc.stat_desc.extra_base;\n      var max_length = desc.stat_desc.max_length;\n      var h;\n      var n, m;\n      var bits;\n      var xbits;\n      var f;\n      var overflow = 0;\n      for (bits = 0; bits <= MAX_BITS; bits++) {\n        s.bl_count[bits] = 0;\n      }\n      tree[s.heap[s.heap_max] * 2 + 1] = 0;\n      for (h = s.heap_max + 1; h < HEAP_SIZE; h++) {\n        n = s.heap[h];\n        bits = tree[tree[n * 2 + 1] * 2 + 1] + 1;\n        if (bits > max_length) {\n          bits = max_length;\n          overflow++;\n        }\n        tree[n * 2 + 1] = bits;\n        if (n > max_code) {\n          continue;\n        }\n        s.bl_count[bits]++;\n        xbits = 0;\n        if (n >= base) {\n          xbits = extra[n - base];\n        }\n        f = tree[n * 2];\n        s.opt_len += f * (bits + xbits);\n        if (has_stree) {\n          s.static_len += f * (stree[n * 2 + 1] + xbits);\n        }\n      }\n      if (overflow === 0) {\n        return;\n      }\n      do {\n        bits = max_length - 1;\n        while (s.bl_count[bits] === 0) {\n          bits--;\n        }\n        s.bl_count[bits]--;\n        s.bl_count[bits + 1] += 2;\n        s.bl_count[max_length]--;\n        overflow -= 2;\n      } while (overflow > 0);\n      for (bits = max_length; bits !== 0; bits--) {\n        n = s.bl_count[bits];\n        while (n !== 0) {\n          m = s.heap[--h];\n          if (m > max_code) {\n            continue;\n          }\n          if (tree[m * 2 + 1] !== bits) {\n            s.opt_len += (bits - tree[m * 2 + 1]) * tree[m * 2];\n            tree[m * 2 + 1] = bits;\n          }\n          n--;\n        }\n      }\n    }\n    function gen_codes(tree, max_code, bl_count) {\n      var next_code = new Array(MAX_BITS + 1);\n      var code = 0;\n      var bits;\n      var n;\n      for (bits = 1; bits <= MAX_BITS; bits++) {\n        next_code[bits] = code = code + bl_count[bits - 1] << 1;\n      }\n      for (n = 0; n <= max_code; n++) {\n        var len = tree[n * 2 + 1];\n        if (len === 0) {\n          continue;\n        }\n        tree[n * 2] = bi_reverse(next_code[len]++, len);\n      }\n    }\n    function tr_static_init() {\n      var n;\n      var bits;\n      var length;\n      var code;\n      var dist;\n      var bl_count = new Array(MAX_BITS + 1);\n      length = 0;\n      for (code = 0; code < LENGTH_CODES - 1; code++) {\n        base_length[code] = length;\n        for (n = 0; n < 1 << extra_lbits[code]; n++) {\n          _length_code[length++] = code;\n        }\n      }\n      _length_code[length - 1] = code;\n      dist = 0;\n      for (code = 0; code < 16; code++) {\n        base_dist[code] = dist;\n        for (n = 0; n < 1 << extra_dbits[code]; n++) {\n          _dist_code[dist++] = code;\n        }\n      }\n      dist >>= 7;\n      for (; code < D_CODES; code++) {\n        base_dist[code] = dist << 7;\n        for (n = 0; n < 1 << extra_dbits[code] - 7; n++) {\n          _dist_code[256 + dist++] = code;\n        }\n      }\n      for (bits = 0; bits <= MAX_BITS; bits++) {\n        bl_count[bits] = 0;\n      }\n      n = 0;\n      while (n <= 143) {\n        static_ltree[n * 2 + 1] = 8;\n        n++;\n        bl_count[8]++;\n      }\n      while (n <= 255) {\n        static_ltree[n * 2 + 1] = 9;\n        n++;\n        bl_count[9]++;\n      }\n      while (n <= 279) {\n        static_ltree[n * 2 + 1] = 7;\n        n++;\n        bl_count[7]++;\n      }\n      while (n <= 287) {\n        static_ltree[n * 2 + 1] = 8;\n        n++;\n        bl_count[8]++;\n      }\n      gen_codes(static_ltree, L_CODES + 1, bl_count);\n      for (n = 0; n < D_CODES; n++) {\n        static_dtree[n * 2 + 1] = 5;\n        static_dtree[n * 2] = bi_reverse(n, 5);\n      }\n      static_l_desc = new StaticTreeDesc(static_ltree, extra_lbits, LITERALS + 1, L_CODES, MAX_BITS);\n      static_d_desc = new StaticTreeDesc(static_dtree, extra_dbits, 0, D_CODES, MAX_BITS);\n      static_bl_desc = new StaticTreeDesc(new Array(0), extra_blbits, 0, BL_CODES, MAX_BL_BITS);\n    }\n    function init_block(s) {\n      var n;\n      for (n = 0; n < L_CODES; n++) {\n        s.dyn_ltree[n * 2] = 0;\n      }\n      for (n = 0; n < D_CODES; n++) {\n        s.dyn_dtree[n * 2] = 0;\n      }\n      for (n = 0; n < BL_CODES; n++) {\n        s.bl_tree[n * 2] = 0;\n      }\n      s.dyn_ltree[END_BLOCK * 2] = 1;\n      s.opt_len = s.static_len = 0;\n      s.last_lit = s.matches = 0;\n    }\n    function bi_windup(s) {\n      if (s.bi_valid > 8) {\n        put_short(s, s.bi_buf);\n      } else if (s.bi_valid > 0) {\n        s.pending_buf[s.pending++] = s.bi_buf;\n      }\n      s.bi_buf = 0;\n      s.bi_valid = 0;\n    }\n    function copy_block(s, buf, len, header) {\n      bi_windup(s);\n      if (header) {\n        put_short(s, len);\n        put_short(s, ~len);\n      }\n      utils.arraySet(s.pending_buf, s.window, buf, len, s.pending);\n      s.pending += len;\n    }\n    function smaller(tree, n, m, depth) {\n      var _n2 = n * 2;\n      var _m2 = m * 2;\n      return tree[_n2] < tree[_m2] || tree[_n2] === tree[_m2] && depth[n] <= depth[m];\n    }\n    function pqdownheap(s, tree, k) {\n      var v = s.heap[k];\n      var j = k << 1;\n      while (j <= s.heap_len) {\n        if (j < s.heap_len && smaller(tree, s.heap[j + 1], s.heap[j], s.depth)) {\n          j++;\n        }\n        if (smaller(tree, v, s.heap[j], s.depth)) {\n          break;\n        }\n        s.heap[k] = s.heap[j];\n        k = j;\n        j <<= 1;\n      }\n      s.heap[k] = v;\n    }\n    function compress_block(s, ltree, dtree) {\n      var dist;\n      var lc;\n      var lx = 0;\n      var code;\n      var extra;\n      if (s.last_lit !== 0) {\n        do {\n          dist = s.pending_buf[s.d_buf + lx * 2] << 8 | s.pending_buf[s.d_buf + lx * 2 + 1];\n          lc = s.pending_buf[s.l_buf + lx];\n          lx++;\n          if (dist === 0) {\n            send_code(s, lc, ltree);\n          } else {\n            code = _length_code[lc];\n            send_code(s, code + LITERALS + 1, ltree);\n            extra = extra_lbits[code];\n            if (extra !== 0) {\n              lc -= base_length[code];\n              send_bits(s, lc, extra);\n            }\n            dist--;\n            code = d_code(dist);\n            send_code(s, code, dtree);\n            extra = extra_dbits[code];\n            if (extra !== 0) {\n              dist -= base_dist[code];\n              send_bits(s, dist, extra);\n            }\n          }\n        } while (lx < s.last_lit);\n      }\n      send_code(s, END_BLOCK, ltree);\n    }\n    function build_tree(s, desc) {\n      var tree = desc.dyn_tree;\n      var stree = desc.stat_desc.static_tree;\n      var has_stree = desc.stat_desc.has_stree;\n      var elems = desc.stat_desc.elems;\n      var n, m;\n      var max_code = -1;\n      var node;\n      s.heap_len = 0;\n      s.heap_max = HEAP_SIZE;\n      for (n = 0; n < elems; n++) {\n        if (tree[n * 2] !== 0) {\n          s.heap[++s.heap_len] = max_code = n;\n          s.depth[n] = 0;\n        } else {\n          tree[n * 2 + 1] = 0;\n        }\n      }\n      while (s.heap_len < 2) {\n        node = s.heap[++s.heap_len] = max_code < 2 ? ++max_code : 0;\n        tree[node * 2] = 1;\n        s.depth[node] = 0;\n        s.opt_len--;\n        if (has_stree) {\n          s.static_len -= stree[node * 2 + 1];\n        }\n      }\n      desc.max_code = max_code;\n      for (n = s.heap_len >> 1; n >= 1; n--) {\n        pqdownheap(s, tree, n);\n      }\n      node = elems;\n      do {\n        n = s.heap[\n          1\n          /*SMALLEST*/\n        ];\n        s.heap[\n          1\n          /*SMALLEST*/\n        ] = s.heap[s.heap_len--];\n        pqdownheap(\n          s,\n          tree,\n          1\n          /*SMALLEST*/\n        );\n        m = s.heap[\n          1\n          /*SMALLEST*/\n        ];\n        s.heap[--s.heap_max] = n;\n        s.heap[--s.heap_max] = m;\n        tree[node * 2] = tree[n * 2] + tree[m * 2];\n        s.depth[node] = (s.depth[n] >= s.depth[m] ? s.depth[n] : s.depth[m]) + 1;\n        tree[n * 2 + 1] = tree[m * 2 + 1] = node;\n        s.heap[\n          1\n          /*SMALLEST*/\n        ] = node++;\n        pqdownheap(\n          s,\n          tree,\n          1\n          /*SMALLEST*/\n        );\n      } while (s.heap_len >= 2);\n      s.heap[--s.heap_max] = s.heap[\n        1\n        /*SMALLEST*/\n      ];\n      gen_bitlen(s, desc);\n      gen_codes(tree, max_code, s.bl_count);\n    }\n    function scan_tree(s, tree, max_code) {\n      var n;\n      var prevlen = -1;\n      var curlen;\n      var nextlen = tree[0 * 2 + 1];\n      var count2 = 0;\n      var max_count = 7;\n      var min_count = 4;\n      if (nextlen === 0) {\n        max_count = 138;\n        min_count = 3;\n      }\n      tree[(max_code + 1) * 2 + 1] = 65535;\n      for (n = 0; n <= max_code; n++) {\n        curlen = nextlen;\n        nextlen = tree[(n + 1) * 2 + 1];\n        if (++count2 < max_count && curlen === nextlen) {\n          continue;\n        } else if (count2 < min_count) {\n          s.bl_tree[curlen * 2] += count2;\n        } else if (curlen !== 0) {\n          if (curlen !== prevlen) {\n            s.bl_tree[curlen * 2]++;\n          }\n          s.bl_tree[REP_3_6 * 2]++;\n        } else if (count2 <= 10) {\n          s.bl_tree[REPZ_3_10 * 2]++;\n        } else {\n          s.bl_tree[REPZ_11_138 * 2]++;\n        }\n        count2 = 0;\n        prevlen = curlen;\n        if (nextlen === 0) {\n          max_count = 138;\n          min_count = 3;\n        } else if (curlen === nextlen) {\n          max_count = 6;\n          min_count = 3;\n        } else {\n          max_count = 7;\n          min_count = 4;\n        }\n      }\n    }\n    function send_tree(s, tree, max_code) {\n      var n;\n      var prevlen = -1;\n      var curlen;\n      var nextlen = tree[0 * 2 + 1];\n      var count2 = 0;\n      var max_count = 7;\n      var min_count = 4;\n      if (nextlen === 0) {\n        max_count = 138;\n        min_count = 3;\n      }\n      for (n = 0; n <= max_code; n++) {\n        curlen = nextlen;\n        nextlen = tree[(n + 1) * 2 + 1];\n        if (++count2 < max_count && curlen === nextlen) {\n          continue;\n        } else if (count2 < min_count) {\n          do {\n            send_code(s, curlen, s.bl_tree);\n          } while (--count2 !== 0);\n        } else if (curlen !== 0) {\n          if (curlen !== prevlen) {\n            send_code(s, curlen, s.bl_tree);\n            count2--;\n          }\n          send_code(s, REP_3_6, s.bl_tree);\n          send_bits(s, count2 - 3, 2);\n        } else if (count2 <= 10) {\n          send_code(s, REPZ_3_10, s.bl_tree);\n          send_bits(s, count2 - 3, 3);\n        } else {\n          send_code(s, REPZ_11_138, s.bl_tree);\n          send_bits(s, count2 - 11, 7);\n        }\n        count2 = 0;\n        prevlen = curlen;\n        if (nextlen === 0) {\n          max_count = 138;\n          min_count = 3;\n        } else if (curlen === nextlen) {\n          max_count = 6;\n          min_count = 3;\n        } else {\n          max_count = 7;\n          min_count = 4;\n        }\n      }\n    }\n    function build_bl_tree(s) {\n      var max_blindex;\n      scan_tree(s, s.dyn_ltree, s.l_desc.max_code);\n      scan_tree(s, s.dyn_dtree, s.d_desc.max_code);\n      build_tree(s, s.bl_desc);\n      for (max_blindex = BL_CODES - 1; max_blindex >= 3; max_blindex--) {\n        if (s.bl_tree[bl_order[max_blindex] * 2 + 1] !== 0) {\n          break;\n        }\n      }\n      s.opt_len += 3 * (max_blindex + 1) + 5 + 5 + 4;\n      return max_blindex;\n    }\n    function send_all_trees(s, lcodes, dcodes, blcodes) {\n      var rank;\n      send_bits(s, lcodes - 257, 5);\n      send_bits(s, dcodes - 1, 5);\n      send_bits(s, blcodes - 4, 4);\n      for (rank = 0; rank < blcodes; rank++) {\n        send_bits(s, s.bl_tree[bl_order[rank] * 2 + 1], 3);\n      }\n      send_tree(s, s.dyn_ltree, lcodes - 1);\n      send_tree(s, s.dyn_dtree, dcodes - 1);\n    }\n    function detect_data_type(s) {\n      var black_mask = 4093624447;\n      var n;\n      for (n = 0; n <= 31; n++, black_mask >>>= 1) {\n        if (black_mask & 1 && s.dyn_ltree[n * 2] !== 0) {\n          return Z_BINARY;\n        }\n      }\n      if (s.dyn_ltree[9 * 2] !== 0 || s.dyn_ltree[10 * 2] !== 0 || s.dyn_ltree[13 * 2] !== 0) {\n        return Z_TEXT;\n      }\n      for (n = 32; n < LITERALS; n++) {\n        if (s.dyn_ltree[n * 2] !== 0) {\n          return Z_TEXT;\n        }\n      }\n      return Z_BINARY;\n    }\n    var static_init_done = false;\n    function _tr_init(s) {\n      if (!static_init_done) {\n        tr_static_init();\n        static_init_done = true;\n      }\n      s.l_desc = new TreeDesc(s.dyn_ltree, static_l_desc);\n      s.d_desc = new TreeDesc(s.dyn_dtree, static_d_desc);\n      s.bl_desc = new TreeDesc(s.bl_tree, static_bl_desc);\n      s.bi_buf = 0;\n      s.bi_valid = 0;\n      init_block(s);\n    }\n    function _tr_stored_block(s, buf, stored_len, last) {\n      send_bits(s, (STORED_BLOCK << 1) + (last ? 1 : 0), 3);\n      copy_block(s, buf, stored_len, true);\n    }\n    function _tr_align(s) {\n      send_bits(s, STATIC_TREES << 1, 3);\n      send_code(s, END_BLOCK, static_ltree);\n      bi_flush(s);\n    }\n    function _tr_flush_block(s, buf, stored_len, last) {\n      var opt_lenb, static_lenb;\n      var max_blindex = 0;\n      if (s.level > 0) {\n        if (s.strm.data_type === Z_UNKNOWN) {\n          s.strm.data_type = detect_data_type(s);\n        }\n        build_tree(s, s.l_desc);\n        build_tree(s, s.d_desc);\n        max_blindex = build_bl_tree(s);\n        opt_lenb = s.opt_len + 3 + 7 >>> 3;\n        static_lenb = s.static_len + 3 + 7 >>> 3;\n        if (static_lenb <= opt_lenb) {\n          opt_lenb = static_lenb;\n        }\n      } else {\n        opt_lenb = static_lenb = stored_len + 5;\n      }\n      if (stored_len + 4 <= opt_lenb && buf !== -1) {\n        _tr_stored_block(s, buf, stored_len, last);\n      } else if (s.strategy === Z_FIXED || static_lenb === opt_lenb) {\n        send_bits(s, (STATIC_TREES << 1) + (last ? 1 : 0), 3);\n        compress_block(s, static_ltree, static_dtree);\n      } else {\n        send_bits(s, (DYN_TREES << 1) + (last ? 1 : 0), 3);\n        send_all_trees(s, s.l_desc.max_code + 1, s.d_desc.max_code + 1, max_blindex + 1);\n        compress_block(s, s.dyn_ltree, s.dyn_dtree);\n      }\n      init_block(s);\n      if (last) {\n        bi_windup(s);\n      }\n    }\n    function _tr_tally(s, dist, lc) {\n      s.pending_buf[s.d_buf + s.last_lit * 2] = dist >>> 8 & 255;\n      s.pending_buf[s.d_buf + s.last_lit * 2 + 1] = dist & 255;\n      s.pending_buf[s.l_buf + s.last_lit] = lc & 255;\n      s.last_lit++;\n      if (dist === 0) {\n        s.dyn_ltree[lc * 2]++;\n      } else {\n        s.matches++;\n        dist--;\n        s.dyn_ltree[(_length_code[lc] + LITERALS + 1) * 2]++;\n        s.dyn_dtree[d_code(dist) * 2]++;\n      }\n      return s.last_lit === s.lit_bufsize - 1;\n    }\n    exports2._tr_init = _tr_init;\n    exports2._tr_stored_block = _tr_stored_block;\n    exports2._tr_flush_block = _tr_flush_block;\n    exports2._tr_tally = _tr_tally;\n    exports2._tr_align = _tr_align;\n  }\n});\n\n// node_modules/.pnpm/pako@1.0.11/node_modules/pako/lib/zlib/adler32.js\nvar require_adler32 = __commonJS({\n  \"node_modules/.pnpm/pako@1.0.11/node_modules/pako/lib/zlib/adler32.js\"(exports2, module2) {\n    \"use strict\";\n    function adler32(adler, buf, len, pos) {\n      var s1 = adler & 65535 | 0, s2 = adler >>> 16 & 65535 | 0, n = 0;\n      while (len !== 0) {\n        n = len > 2e3 ? 2e3 : len;\n        len -= n;\n        do {\n          s1 = s1 + buf[pos++] | 0;\n          s2 = s2 + s1 | 0;\n        } while (--n);\n        s1 %= 65521;\n        s2 %= 65521;\n      }\n      return s1 | s2 << 16 | 0;\n    }\n    module2.exports = adler32;\n  }\n});\n\n// node_modules/.pnpm/pako@1.0.11/node_modules/pako/lib/zlib/crc32.js\nvar require_crc322 = __commonJS({\n  \"node_modules/.pnpm/pako@1.0.11/node_modules/pako/lib/zlib/crc32.js\"(exports2, module2) {\n    \"use strict\";\n    function makeTable() {\n      var c, table = [];\n      for (var n = 0; n < 256; n++) {\n        c = n;\n        for (var k = 0; k < 8; k++) {\n          c = c & 1 ? 3988292384 ^ c >>> 1 : c >>> 1;\n        }\n        table[n] = c;\n      }\n      return table;\n    }\n    var crcTable = makeTable();\n    function crc32(crc, buf, len, pos) {\n      var t = crcTable, end = pos + len;\n      crc ^= -1;\n      for (var i = pos; i < end; i++) {\n        crc = crc >>> 8 ^ t[(crc ^ buf[i]) & 255];\n      }\n      return crc ^ -1;\n    }\n    module2.exports = crc32;\n  }\n});\n\n// node_modules/.pnpm/pako@1.0.11/node_modules/pako/lib/zlib/messages.js\nvar require_messages = __commonJS({\n  \"node_modules/.pnpm/pako@1.0.11/node_modules/pako/lib/zlib/messages.js\"(exports2, module2) {\n    \"use strict\";\n    module2.exports = {\n      2: \"need dictionary\",\n      /* Z_NEED_DICT       2  */\n      1: \"stream end\",\n      /* Z_STREAM_END      1  */\n      0: \"\",\n      /* Z_OK              0  */\n      \"-1\": \"file error\",\n      /* Z_ERRNO         (-1) */\n      \"-2\": \"stream error\",\n      /* Z_STREAM_ERROR  (-2) */\n      \"-3\": \"data error\",\n      /* Z_DATA_ERROR    (-3) */\n      \"-4\": \"insufficient memory\",\n      /* Z_MEM_ERROR     (-4) */\n      \"-5\": \"buffer error\",\n      /* Z_BUF_ERROR     (-5) */\n      \"-6\": \"incompatible version\"\n      /* Z_VERSION_ERROR (-6) */\n    };\n  }\n});\n\n// node_modules/.pnpm/pako@1.0.11/node_modules/pako/lib/zlib/deflate.js\nvar require_deflate = __commonJS({\n  \"node_modules/.pnpm/pako@1.0.11/node_modules/pako/lib/zlib/deflate.js\"(exports2) {\n    \"use strict\";\n    var utils = require_common();\n    var trees = require_trees();\n    var adler32 = require_adler32();\n    var crc32 = require_crc322();\n    var msg = require_messages();\n    var Z_NO_FLUSH = 0;\n    var Z_PARTIAL_FLUSH = 1;\n    var Z_FULL_FLUSH = 3;\n    var Z_FINISH = 4;\n    var Z_BLOCK = 5;\n    var Z_OK = 0;\n    var Z_STREAM_END = 1;\n    var Z_STREAM_ERROR = -2;\n    var Z_DATA_ERROR = -3;\n    var Z_BUF_ERROR = -5;\n    var Z_DEFAULT_COMPRESSION = -1;\n    var Z_FILTERED = 1;\n    var Z_HUFFMAN_ONLY = 2;\n    var Z_RLE = 3;\n    var Z_FIXED = 4;\n    var Z_DEFAULT_STRATEGY = 0;\n    var Z_UNKNOWN = 2;\n    var Z_DEFLATED = 8;\n    var MAX_MEM_LEVEL = 9;\n    var MAX_WBITS = 15;\n    var DEF_MEM_LEVEL = 8;\n    var LENGTH_CODES = 29;\n    var LITERALS = 256;\n    var L_CODES = LITERALS + 1 + LENGTH_CODES;\n    var D_CODES = 30;\n    var BL_CODES = 19;\n    var HEAP_SIZE = 2 * L_CODES + 1;\n    var MAX_BITS = 15;\n    var MIN_MATCH = 3;\n    var MAX_MATCH = 258;\n    var MIN_LOOKAHEAD = MAX_MATCH + MIN_MATCH + 1;\n    var PRESET_DICT = 32;\n    var INIT_STATE = 42;\n    var EXTRA_STATE = 69;\n    var NAME_STATE = 73;\n    var COMMENT_STATE = 91;\n    var HCRC_STATE = 103;\n    var BUSY_STATE = 113;\n    var FINISH_STATE = 666;\n    var BS_NEED_MORE = 1;\n    var BS_BLOCK_DONE = 2;\n    var BS_FINISH_STARTED = 3;\n    var BS_FINISH_DONE = 4;\n    var OS_CODE = 3;\n    function err(strm, errorCode) {\n      strm.msg = msg[errorCode];\n      return errorCode;\n    }\n    function rank(f) {\n      return (f << 1) - (f > 4 ? 9 : 0);\n    }\n    function zero(buf) {\n      var len = buf.length;\n      while (--len >= 0) {\n        buf[len] = 0;\n      }\n    }\n    function flush_pending(strm) {\n      var s = strm.state;\n      var len = s.pending;\n      if (len > strm.avail_out) {\n        len = strm.avail_out;\n      }\n      if (len === 0) {\n        return;\n      }\n      utils.arraySet(strm.output, s.pending_buf, s.pending_out, len, strm.next_out);\n      strm.next_out += len;\n      s.pending_out += len;\n      strm.total_out += len;\n      strm.avail_out -= len;\n      s.pending -= len;\n      if (s.pending === 0) {\n        s.pending_out = 0;\n      }\n    }\n    function flush_block_only(s, last) {\n      trees._tr_flush_block(s, s.block_start >= 0 ? s.block_start : -1, s.strstart - s.block_start, last);\n      s.block_start = s.strstart;\n      flush_pending(s.strm);\n    }\n    function put_byte(s, b) {\n      s.pending_buf[s.pending++] = b;\n    }\n    function putShortMSB(s, b) {\n      s.pending_buf[s.pending++] = b >>> 8 & 255;\n      s.pending_buf[s.pending++] = b & 255;\n    }\n    function read_buf(strm, buf, start, size) {\n      var len = strm.avail_in;\n      if (len > size) {\n        len = size;\n      }\n      if (len === 0) {\n        return 0;\n      }\n      strm.avail_in -= len;\n      utils.arraySet(buf, strm.input, strm.next_in, len, start);\n      if (strm.state.wrap === 1) {\n        strm.adler = adler32(strm.adler, buf, len, start);\n      } else if (strm.state.wrap === 2) {\n        strm.adler = crc32(strm.adler, buf, len, start);\n      }\n      strm.next_in += len;\n      strm.total_in += len;\n      return len;\n    }\n    function longest_match(s, cur_match) {\n      var chain_length = s.max_chain_length;\n      var scan = s.strstart;\n      var match;\n      var len;\n      var best_len = s.prev_length;\n      var nice_match = s.nice_match;\n      var limit = s.strstart > s.w_size - MIN_LOOKAHEAD ? s.strstart - (s.w_size - MIN_LOOKAHEAD) : 0;\n      var _win = s.window;\n      var wmask = s.w_mask;\n      var prev = s.prev;\n      var strend = s.strstart + MAX_MATCH;\n      var scan_end1 = _win[scan + best_len - 1];\n      var scan_end = _win[scan + best_len];\n      if (s.prev_length >= s.good_match) {\n        chain_length >>= 2;\n      }\n      if (nice_match > s.lookahead) {\n        nice_match = s.lookahead;\n      }\n      do {\n        match = cur_match;\n        if (_win[match + best_len] !== scan_end || _win[match + best_len - 1] !== scan_end1 || _win[match] !== _win[scan] || _win[++match] !== _win[scan + 1]) {\n          continue;\n        }\n        scan += 2;\n        match++;\n        do {\n        } while (_win[++scan] === _win[++match] && _win[++scan] === _win[++match] && _win[++scan] === _win[++match] && _win[++scan] === _win[++match] && _win[++scan] === _win[++match] && _win[++scan] === _win[++match] && _win[++scan] === _win[++match] && _win[++scan] === _win[++match] && scan < strend);\n        len = MAX_MATCH - (strend - scan);\n        scan = strend - MAX_MATCH;\n        if (len > best_len) {\n          s.match_start = cur_match;\n          best_len = len;\n          if (len >= nice_match) {\n            break;\n          }\n          scan_end1 = _win[scan + best_len - 1];\n          scan_end = _win[scan + best_len];\n        }\n      } while ((cur_match = prev[cur_match & wmask]) > limit && --chain_length !== 0);\n      if (best_len <= s.lookahead) {\n        return best_len;\n      }\n      return s.lookahead;\n    }\n    function fill_window(s) {\n      var _w_size = s.w_size;\n      var p, n, m, more, str;\n      do {\n        more = s.window_size - s.lookahead - s.strstart;\n        if (s.strstart >= _w_size + (_w_size - MIN_LOOKAHEAD)) {\n          utils.arraySet(s.window, s.window, _w_size, _w_size, 0);\n          s.match_start -= _w_size;\n          s.strstart -= _w_size;\n          s.block_start -= _w_size;\n          n = s.hash_size;\n          p = n;\n          do {\n            m = s.head[--p];\n            s.head[p] = m >= _w_size ? m - _w_size : 0;\n          } while (--n);\n          n = _w_size;\n          p = n;\n          do {\n            m = s.prev[--p];\n            s.prev[p] = m >= _w_size ? m - _w_size : 0;\n          } while (--n);\n          more += _w_size;\n        }\n        if (s.strm.avail_in === 0) {\n          break;\n        }\n        n = read_buf(s.strm, s.window, s.strstart + s.lookahead, more);\n        s.lookahead += n;\n        if (s.lookahead + s.insert >= MIN_MATCH) {\n          str = s.strstart - s.insert;\n          s.ins_h = s.window[str];\n          s.ins_h = (s.ins_h << s.hash_shift ^ s.window[str + 1]) & s.hash_mask;\n          while (s.insert) {\n            s.ins_h = (s.ins_h << s.hash_shift ^ s.window[str + MIN_MATCH - 1]) & s.hash_mask;\n            s.prev[str & s.w_mask] = s.head[s.ins_h];\n            s.head[s.ins_h] = str;\n            str++;\n            s.insert--;\n            if (s.lookahead + s.insert < MIN_MATCH) {\n              break;\n            }\n          }\n        }\n      } while (s.lookahead < MIN_LOOKAHEAD && s.strm.avail_in !== 0);\n    }\n    function deflate_stored(s, flush) {\n      var max_block_size = 65535;\n      if (max_block_size > s.pending_buf_size - 5) {\n        max_block_size = s.pending_buf_size - 5;\n      }\n      for (; ; ) {\n        if (s.lookahead <= 1) {\n          fill_window(s);\n          if (s.lookahead === 0 && flush === Z_NO_FLUSH) {\n            return BS_NEED_MORE;\n          }\n          if (s.lookahead === 0) {\n            break;\n          }\n        }\n        s.strstart += s.lookahead;\n        s.lookahead = 0;\n        var max_start = s.block_start + max_block_size;\n        if (s.strstart === 0 || s.strstart >= max_start) {\n          s.lookahead = s.strstart - max_start;\n          s.strstart = max_start;\n          flush_block_only(s, false);\n          if (s.strm.avail_out === 0) {\n            return BS_NEED_MORE;\n          }\n        }\n        if (s.strstart - s.block_start >= s.w_size - MIN_LOOKAHEAD) {\n          flush_block_only(s, false);\n          if (s.strm.avail_out === 0) {\n            return BS_NEED_MORE;\n          }\n        }\n      }\n      s.insert = 0;\n      if (flush === Z_FINISH) {\n        flush_block_only(s, true);\n        if (s.strm.avail_out === 0) {\n          return BS_FINISH_STARTED;\n        }\n        return BS_FINISH_DONE;\n      }\n      if (s.strstart > s.block_start) {\n        flush_block_only(s, false);\n        if (s.strm.avail_out === 0) {\n          return BS_NEED_MORE;\n        }\n      }\n      return BS_NEED_MORE;\n    }\n    function deflate_fast(s, flush) {\n      var hash_head;\n      var bflush;\n      for (; ; ) {\n        if (s.lookahead < MIN_LOOKAHEAD) {\n          fill_window(s);\n          if (s.lookahead < MIN_LOOKAHEAD && flush === Z_NO_FLUSH) {\n            return BS_NEED_MORE;\n          }\n          if (s.lookahead === 0) {\n            break;\n          }\n        }\n        hash_head = 0;\n        if (s.lookahead >= MIN_MATCH) {\n          s.ins_h = (s.ins_h << s.hash_shift ^ s.window[s.strstart + MIN_MATCH - 1]) & s.hash_mask;\n          hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h];\n          s.head[s.ins_h] = s.strstart;\n        }\n        if (hash_head !== 0 && s.strstart - hash_head <= s.w_size - MIN_LOOKAHEAD) {\n          s.match_length = longest_match(s, hash_head);\n        }\n        if (s.match_length >= MIN_MATCH) {\n          bflush = trees._tr_tally(s, s.strstart - s.match_start, s.match_length - MIN_MATCH);\n          s.lookahead -= s.match_length;\n          if (s.match_length <= s.max_lazy_match && s.lookahead >= MIN_MATCH) {\n            s.match_length--;\n            do {\n              s.strstart++;\n              s.ins_h = (s.ins_h << s.hash_shift ^ s.window[s.strstart + MIN_MATCH - 1]) & s.hash_mask;\n              hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h];\n              s.head[s.ins_h] = s.strstart;\n            } while (--s.match_length !== 0);\n            s.strstart++;\n          } else {\n            s.strstart += s.match_length;\n            s.match_length = 0;\n            s.ins_h = s.window[s.strstart];\n            s.ins_h = (s.ins_h << s.hash_shift ^ s.window[s.strstart + 1]) & s.hash_mask;\n          }\n        } else {\n          bflush = trees._tr_tally(s, 0, s.window[s.strstart]);\n          s.lookahead--;\n          s.strstart++;\n        }\n        if (bflush) {\n          flush_block_only(s, false);\n          if (s.strm.avail_out === 0) {\n            return BS_NEED_MORE;\n          }\n        }\n      }\n      s.insert = s.strstart < MIN_MATCH - 1 ? s.strstart : MIN_MATCH - 1;\n      if (flush === Z_FINISH) {\n        flush_block_only(s, true);\n        if (s.strm.avail_out === 0) {\n          return BS_FINISH_STARTED;\n        }\n        return BS_FINISH_DONE;\n      }\n      if (s.last_lit) {\n        flush_block_only(s, false);\n        if (s.strm.avail_out === 0) {\n          return BS_NEED_MORE;\n        }\n      }\n      return BS_BLOCK_DONE;\n    }\n    function deflate_slow(s, flush) {\n      var hash_head;\n      var bflush;\n      var max_insert;\n      for (; ; ) {\n        if (s.lookahead < MIN_LOOKAHEAD) {\n          fill_window(s);\n          if (s.lookahead < MIN_LOOKAHEAD && flush === Z_NO_FLUSH) {\n            return BS_NEED_MORE;\n          }\n          if (s.lookahead === 0) {\n            break;\n          }\n        }\n        hash_head = 0;\n        if (s.lookahead >= MIN_MATCH) {\n          s.ins_h = (s.ins_h << s.hash_shift ^ s.window[s.strstart + MIN_MATCH - 1]) & s.hash_mask;\n          hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h];\n          s.head[s.ins_h] = s.strstart;\n        }\n        s.prev_length = s.match_length;\n        s.prev_match = s.match_start;\n        s.match_length = MIN_MATCH - 1;\n        if (hash_head !== 0 && s.prev_length < s.max_lazy_match && s.strstart - hash_head <= s.w_size - MIN_LOOKAHEAD) {\n          s.match_length = longest_match(s, hash_head);\n          if (s.match_length <= 5 && (s.strategy === Z_FILTERED || s.match_length === MIN_MATCH && s.strstart - s.match_start > 4096)) {\n            s.match_length = MIN_MATCH - 1;\n          }\n        }\n        if (s.prev_length >= MIN_MATCH && s.match_length <= s.prev_length) {\n          max_insert = s.strstart + s.lookahead - MIN_MATCH;\n          bflush = trees._tr_tally(s, s.strstart - 1 - s.prev_match, s.prev_length - MIN_MATCH);\n          s.lookahead -= s.prev_length - 1;\n          s.prev_length -= 2;\n          do {\n            if (++s.strstart <= max_insert) {\n              s.ins_h = (s.ins_h << s.hash_shift ^ s.window[s.strstart + MIN_MATCH - 1]) & s.hash_mask;\n              hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h];\n              s.head[s.ins_h] = s.strstart;\n            }\n          } while (--s.prev_length !== 0);\n          s.match_available = 0;\n          s.match_length = MIN_MATCH - 1;\n          s.strstart++;\n          if (bflush) {\n            flush_block_only(s, false);\n            if (s.strm.avail_out === 0) {\n              return BS_NEED_MORE;\n            }\n          }\n        } else if (s.match_available) {\n          bflush = trees._tr_tally(s, 0, s.window[s.strstart - 1]);\n          if (bflush) {\n            flush_block_only(s, false);\n          }\n          s.strstart++;\n          s.lookahead--;\n          if (s.strm.avail_out === 0) {\n            return BS_NEED_MORE;\n          }\n        } else {\n          s.match_available = 1;\n          s.strstart++;\n          s.lookahead--;\n        }\n      }\n      if (s.match_available) {\n        bflush = trees._tr_tally(s, 0, s.window[s.strstart - 1]);\n        s.match_available = 0;\n      }\n      s.insert = s.strstart < MIN_MATCH - 1 ? s.strstart : MIN_MATCH - 1;\n      if (flush === Z_FINISH) {\n        flush_block_only(s, true);\n        if (s.strm.avail_out === 0) {\n          return BS_FINISH_STARTED;\n        }\n        return BS_FINISH_DONE;\n      }\n      if (s.last_lit) {\n        flush_block_only(s, false);\n        if (s.strm.avail_out === 0) {\n          return BS_NEED_MORE;\n        }\n      }\n      return BS_BLOCK_DONE;\n    }\n    function deflate_rle(s, flush) {\n      var bflush;\n      var prev;\n      var scan, strend;\n      var _win = s.window;\n      for (; ; ) {\n        if (s.lookahead <= MAX_MATCH) {\n          fill_window(s);\n          if (s.lookahead <= MAX_MATCH && flush === Z_NO_FLUSH) {\n            return BS_NEED_MORE;\n          }\n          if (s.lookahead === 0) {\n            break;\n          }\n        }\n        s.match_length = 0;\n        if (s.lookahead >= MIN_MATCH && s.strstart > 0) {\n          scan = s.strstart - 1;\n          prev = _win[scan];\n          if (prev === _win[++scan] && prev === _win[++scan] && prev === _win[++scan]) {\n            strend = s.strstart + MAX_MATCH;\n            do {\n            } while (prev === _win[++scan] && prev === _win[++scan] && prev === _win[++scan] && prev === _win[++scan] && prev === _win[++scan] && prev === _win[++scan] && prev === _win[++scan] && prev === _win[++scan] && scan < strend);\n            s.match_length = MAX_MATCH - (strend - scan);\n            if (s.match_length > s.lookahead) {\n              s.match_length = s.lookahead;\n            }\n          }\n        }\n        if (s.match_length >= MIN_MATCH) {\n          bflush = trees._tr_tally(s, 1, s.match_length - MIN_MATCH);\n          s.lookahead -= s.match_length;\n          s.strstart += s.match_length;\n          s.match_length = 0;\n        } else {\n          bflush = trees._tr_tally(s, 0, s.window[s.strstart]);\n          s.lookahead--;\n          s.strstart++;\n        }\n        if (bflush) {\n          flush_block_only(s, false);\n          if (s.strm.avail_out === 0) {\n            return BS_NEED_MORE;\n          }\n        }\n      }\n      s.insert = 0;\n      if (flush === Z_FINISH) {\n        flush_block_only(s, true);\n        if (s.strm.avail_out === 0) {\n          return BS_FINISH_STARTED;\n        }\n        return BS_FINISH_DONE;\n      }\n      if (s.last_lit) {\n        flush_block_only(s, false);\n        if (s.strm.avail_out === 0) {\n          return BS_NEED_MORE;\n        }\n      }\n      return BS_BLOCK_DONE;\n    }\n    function deflate_huff(s, flush) {\n      var bflush;\n      for (; ; ) {\n        if (s.lookahead === 0) {\n          fill_window(s);\n          if (s.lookahead === 0) {\n            if (flush === Z_NO_FLUSH) {\n              return BS_NEED_MORE;\n            }\n            break;\n          }\n        }\n        s.match_length = 0;\n        bflush = trees._tr_tally(s, 0, s.window[s.strstart]);\n        s.lookahead--;\n        s.strstart++;\n        if (bflush) {\n          flush_block_only(s, false);\n          if (s.strm.avail_out === 0) {\n            return BS_NEED_MORE;\n          }\n        }\n      }\n      s.insert = 0;\n      if (flush === Z_FINISH) {\n        flush_block_only(s, true);\n        if (s.strm.avail_out === 0) {\n          return BS_FINISH_STARTED;\n        }\n        return BS_FINISH_DONE;\n      }\n      if (s.last_lit) {\n        flush_block_only(s, false);\n        if (s.strm.avail_out === 0) {\n          return BS_NEED_MORE;\n        }\n      }\n      return BS_BLOCK_DONE;\n    }\n    function Config(good_length, max_lazy, nice_length, max_chain, func) {\n      this.good_length = good_length;\n      this.max_lazy = max_lazy;\n      this.nice_length = nice_length;\n      this.max_chain = max_chain;\n      this.func = func;\n    }\n    var configuration_table;\n    configuration_table = [\n      /*      good lazy nice chain */\n      new Config(0, 0, 0, 0, deflate_stored),\n      /* 0 store only */\n      new Config(4, 4, 8, 4, deflate_fast),\n      /* 1 max speed, no lazy matches */\n      new Config(4, 5, 16, 8, deflate_fast),\n      /* 2 */\n      new Config(4, 6, 32, 32, deflate_fast),\n      /* 3 */\n      new Config(4, 4, 16, 16, deflate_slow),\n      /* 4 lazy matches */\n      new Config(8, 16, 32, 32, deflate_slow),\n      /* 5 */\n      new Config(8, 16, 128, 128, deflate_slow),\n      /* 6 */\n      new Config(8, 32, 128, 256, deflate_slow),\n      /* 7 */\n      new Config(32, 128, 258, 1024, deflate_slow),\n      /* 8 */\n      new Config(32, 258, 258, 4096, deflate_slow)\n      /* 9 max compression */\n    ];\n    function lm_init(s) {\n      s.window_size = 2 * s.w_size;\n      zero(s.head);\n      s.max_lazy_match = configuration_table[s.level].max_lazy;\n      s.good_match = configuration_table[s.level].good_length;\n      s.nice_match = configuration_table[s.level].nice_length;\n      s.max_chain_length = configuration_table[s.level].max_chain;\n      s.strstart = 0;\n      s.block_start = 0;\n      s.lookahead = 0;\n      s.insert = 0;\n      s.match_length = s.prev_length = MIN_MATCH - 1;\n      s.match_available = 0;\n      s.ins_h = 0;\n    }\n    function DeflateState() {\n      this.strm = null;\n      this.status = 0;\n      this.pending_buf = null;\n      this.pending_buf_size = 0;\n      this.pending_out = 0;\n      this.pending = 0;\n      this.wrap = 0;\n      this.gzhead = null;\n      this.gzindex = 0;\n      this.method = Z_DEFLATED;\n      this.last_flush = -1;\n      this.w_size = 0;\n      this.w_bits = 0;\n      this.w_mask = 0;\n      this.window = null;\n      this.window_size = 0;\n      this.prev = null;\n      this.head = null;\n      this.ins_h = 0;\n      this.hash_size = 0;\n      this.hash_bits = 0;\n      this.hash_mask = 0;\n      this.hash_shift = 0;\n      this.block_start = 0;\n      this.match_length = 0;\n      this.prev_match = 0;\n      this.match_available = 0;\n      this.strstart = 0;\n      this.match_start = 0;\n      this.lookahead = 0;\n      this.prev_length = 0;\n      this.max_chain_length = 0;\n      this.max_lazy_match = 0;\n      this.level = 0;\n      this.strategy = 0;\n      this.good_match = 0;\n      this.nice_match = 0;\n      this.dyn_ltree = new utils.Buf16(HEAP_SIZE * 2);\n      this.dyn_dtree = new utils.Buf16((2 * D_CODES + 1) * 2);\n      this.bl_tree = new utils.Buf16((2 * BL_CODES + 1) * 2);\n      zero(this.dyn_ltree);\n      zero(this.dyn_dtree);\n      zero(this.bl_tree);\n      this.l_desc = null;\n      this.d_desc = null;\n      this.bl_desc = null;\n      this.bl_count = new utils.Buf16(MAX_BITS + 1);\n      this.heap = new utils.Buf16(2 * L_CODES + 1);\n      zero(this.heap);\n      this.heap_len = 0;\n      this.heap_max = 0;\n      this.depth = new utils.Buf16(2 * L_CODES + 1);\n      zero(this.depth);\n      this.l_buf = 0;\n      this.lit_bufsize = 0;\n      this.last_lit = 0;\n      this.d_buf = 0;\n      this.opt_len = 0;\n      this.static_len = 0;\n      this.matches = 0;\n      this.insert = 0;\n      this.bi_buf = 0;\n      this.bi_valid = 0;\n    }\n    function deflateResetKeep(strm) {\n      var s;\n      if (!strm || !strm.state) {\n        return err(strm, Z_STREAM_ERROR);\n      }\n      strm.total_in = strm.total_out = 0;\n      strm.data_type = Z_UNKNOWN;\n      s = strm.state;\n      s.pending = 0;\n      s.pending_out = 0;\n      if (s.wrap < 0) {\n        s.wrap = -s.wrap;\n      }\n      s.status = s.wrap ? INIT_STATE : BUSY_STATE;\n      strm.adler = s.wrap === 2 ? 0 : 1;\n      s.last_flush = Z_NO_FLUSH;\n      trees._tr_init(s);\n      return Z_OK;\n    }\n    function deflateReset(strm) {\n      var ret = deflateResetKeep(strm);\n      if (ret === Z_OK) {\n        lm_init(strm.state);\n      }\n      return ret;\n    }\n    function deflateSetHeader(strm, head) {\n      if (!strm || !strm.state) {\n        return Z_STREAM_ERROR;\n      }\n      if (strm.state.wrap !== 2) {\n        return Z_STREAM_ERROR;\n      }\n      strm.state.gzhead = head;\n      return Z_OK;\n    }\n    function deflateInit2(strm, level, method, windowBits, memLevel, strategy) {\n      if (!strm) {\n        return Z_STREAM_ERROR;\n      }\n      var wrap = 1;\n      if (level === Z_DEFAULT_COMPRESSION) {\n        level = 6;\n      }\n      if (windowBits < 0) {\n        wrap = 0;\n        windowBits = -windowBits;\n      } else if (windowBits > 15) {\n        wrap = 2;\n        windowBits -= 16;\n      }\n      if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method !== Z_DEFLATED || windowBits < 8 || windowBits > 15 || level < 0 || level > 9 || strategy < 0 || strategy > Z_FIXED) {\n        return err(strm, Z_STREAM_ERROR);\n      }\n      if (windowBits === 8) {\n        windowBits = 9;\n      }\n      var s = new DeflateState();\n      strm.state = s;\n      s.strm = strm;\n      s.wrap = wrap;\n      s.gzhead = null;\n      s.w_bits = windowBits;\n      s.w_size = 1 << s.w_bits;\n      s.w_mask = s.w_size - 1;\n      s.hash_bits = memLevel + 7;\n      s.hash_size = 1 << s.hash_bits;\n      s.hash_mask = s.hash_size - 1;\n      s.hash_shift = ~~((s.hash_bits + MIN_MATCH - 1) / MIN_MATCH);\n      s.window = new utils.Buf8(s.w_size * 2);\n      s.head = new utils.Buf16(s.hash_size);\n      s.prev = new utils.Buf16(s.w_size);\n      s.lit_bufsize = 1 << memLevel + 6;\n      s.pending_buf_size = s.lit_bufsize * 4;\n      s.pending_buf = new utils.Buf8(s.pending_buf_size);\n      s.d_buf = 1 * s.lit_bufsize;\n      s.l_buf = (1 + 2) * s.lit_bufsize;\n      s.level = level;\n      s.strategy = strategy;\n      s.method = method;\n      return deflateReset(strm);\n    }\n    function deflateInit(strm, level) {\n      return deflateInit2(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY);\n    }\n    function deflate(strm, flush) {\n      var old_flush, s;\n      var beg, val;\n      if (!strm || !strm.state || flush > Z_BLOCK || flush < 0) {\n        return strm ? err(strm, Z_STREAM_ERROR) : Z_STREAM_ERROR;\n      }\n      s = strm.state;\n      if (!strm.output || !strm.input && strm.avail_in !== 0 || s.status === FINISH_STATE && flush !== Z_FINISH) {\n        return err(strm, strm.avail_out === 0 ? Z_BUF_ERROR : Z_STREAM_ERROR);\n      }\n      s.strm = strm;\n      old_flush = s.last_flush;\n      s.last_flush = flush;\n      if (s.status === INIT_STATE) {\n        if (s.wrap === 2) {\n          strm.adler = 0;\n          put_byte(s, 31);\n          put_byte(s, 139);\n          put_byte(s, 8);\n          if (!s.gzhead) {\n            put_byte(s, 0);\n            put_byte(s, 0);\n            put_byte(s, 0);\n            put_byte(s, 0);\n            put_byte(s, 0);\n            put_byte(s, s.level === 9 ? 2 : s.strategy >= Z_HUFFMAN_ONLY || s.level < 2 ? 4 : 0);\n            put_byte(s, OS_CODE);\n            s.status = BUSY_STATE;\n          } else {\n            put_byte(\n              s,\n              (s.gzhead.text ? 1 : 0) + (s.gzhead.hcrc ? 2 : 0) + (!s.gzhead.extra ? 0 : 4) + (!s.gzhead.name ? 0 : 8) + (!s.gzhead.comment ? 0 : 16)\n            );\n            put_byte(s, s.gzhead.time & 255);\n            put_byte(s, s.gzhead.time >> 8 & 255);\n            put_byte(s, s.gzhead.time >> 16 & 255);\n            put_byte(s, s.gzhead.time >> 24 & 255);\n            put_byte(s, s.level === 9 ? 2 : s.strategy >= Z_HUFFMAN_ONLY || s.level < 2 ? 4 : 0);\n            put_byte(s, s.gzhead.os & 255);\n            if (s.gzhead.extra && s.gzhead.extra.length) {\n              put_byte(s, s.gzhead.extra.length & 255);\n              put_byte(s, s.gzhead.extra.length >> 8 & 255);\n            }\n            if (s.gzhead.hcrc) {\n              strm.adler = crc32(strm.adler, s.pending_buf, s.pending, 0);\n            }\n            s.gzindex = 0;\n            s.status = EXTRA_STATE;\n          }\n        } else {\n          var header = Z_DEFLATED + (s.w_bits - 8 << 4) << 8;\n          var level_flags = -1;\n          if (s.strategy >= Z_HUFFMAN_ONLY || s.level < 2) {\n            level_flags = 0;\n          } else if (s.level < 6) {\n            level_flags = 1;\n          } else if (s.level === 6) {\n            level_flags = 2;\n          } else {\n            level_flags = 3;\n          }\n          header |= level_flags << 6;\n          if (s.strstart !== 0) {\n            header |= PRESET_DICT;\n          }\n          header += 31 - header % 31;\n          s.status = BUSY_STATE;\n          putShortMSB(s, header);\n          if (s.strstart !== 0) {\n            putShortMSB(s, strm.adler >>> 16);\n            putShortMSB(s, strm.adler & 65535);\n          }\n          strm.adler = 1;\n        }\n      }\n      if (s.status === EXTRA_STATE) {\n        if (s.gzhead.extra) {\n          beg = s.pending;\n          while (s.gzindex < (s.gzhead.extra.length & 65535)) {\n            if (s.pending === s.pending_buf_size) {\n              if (s.gzhead.hcrc && s.pending > beg) {\n                strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg);\n              }\n              flush_pending(strm);\n              beg = s.pending;\n              if (s.pending === s.pending_buf_size) {\n                break;\n              }\n            }\n            put_byte(s, s.gzhead.extra[s.gzindex] & 255);\n            s.gzindex++;\n          }\n          if (s.gzhead.hcrc && s.pending > beg) {\n            strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg);\n          }\n          if (s.gzindex === s.gzhead.extra.length) {\n            s.gzindex = 0;\n            s.status = NAME_STATE;\n          }\n        } else {\n          s.status = NAME_STATE;\n        }\n      }\n      if (s.status === NAME_STATE) {\n        if (s.gzhead.name) {\n          beg = s.pending;\n          do {\n            if (s.pending === s.pending_buf_size) {\n              if (s.gzhead.hcrc && s.pending > beg) {\n                strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg);\n              }\n              flush_pending(strm);\n              beg = s.pending;\n              if (s.pending === s.pending_buf_size) {\n                val = 1;\n                break;\n              }\n            }\n            if (s.gzindex < s.gzhead.name.length) {\n              val = s.gzhead.name.charCodeAt(s.gzindex++) & 255;\n            } else {\n              val = 0;\n            }\n            put_byte(s, val);\n          } while (val !== 0);\n          if (s.gzhead.hcrc && s.pending > beg) {\n            strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg);\n          }\n          if (val === 0) {\n            s.gzindex = 0;\n            s.status = COMMENT_STATE;\n          }\n        } else {\n          s.status = COMMENT_STATE;\n        }\n      }\n      if (s.status === COMMENT_STATE) {\n        if (s.gzhead.comment) {\n          beg = s.pending;\n          do {\n            if (s.pending === s.pending_buf_size) {\n              if (s.gzhead.hcrc && s.pending > beg) {\n                strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg);\n              }\n              flush_pending(strm);\n              beg = s.pending;\n              if (s.pending === s.pending_buf_size) {\n                val = 1;\n                break;\n              }\n            }\n            if (s.gzindex < s.gzhead.comment.length) {\n              val = s.gzhead.comment.charCodeAt(s.gzindex++) & 255;\n            } else {\n              val = 0;\n            }\n            put_byte(s, val);\n          } while (val !== 0);\n          if (s.gzhead.hcrc && s.pending > beg) {\n            strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg);\n          }\n          if (val === 0) {\n            s.status = HCRC_STATE;\n          }\n        } else {\n          s.status = HCRC_STATE;\n        }\n      }\n      if (s.status === HCRC_STATE) {\n        if (s.gzhead.hcrc) {\n          if (s.pending + 2 > s.pending_buf_size) {\n            flush_pending(strm);\n          }\n          if (s.pending + 2 <= s.pending_buf_size) {\n            put_byte(s, strm.adler & 255);\n            put_byte(s, strm.adler >> 8 & 255);\n            strm.adler = 0;\n            s.status = BUSY_STATE;\n          }\n        } else {\n          s.status = BUSY_STATE;\n        }\n      }\n      if (s.pending !== 0) {\n        flush_pending(strm);\n        if (strm.avail_out === 0) {\n          s.last_flush = -1;\n          return Z_OK;\n        }\n      } else if (strm.avail_in === 0 && rank(flush) <= rank(old_flush) && flush !== Z_FINISH) {\n        return err(strm, Z_BUF_ERROR);\n      }\n      if (s.status === FINISH_STATE && strm.avail_in !== 0) {\n        return err(strm, Z_BUF_ERROR);\n      }\n      if (strm.avail_in !== 0 || s.lookahead !== 0 || flush !== Z_NO_FLUSH && s.status !== FINISH_STATE) {\n        var bstate = s.strategy === Z_HUFFMAN_ONLY ? deflate_huff(s, flush) : s.strategy === Z_RLE ? deflate_rle(s, flush) : configuration_table[s.level].func(s, flush);\n        if (bstate === BS_FINISH_STARTED || bstate === BS_FINISH_DONE) {\n          s.status = FINISH_STATE;\n        }\n        if (bstate === BS_NEED_MORE || bstate === BS_FINISH_STARTED) {\n          if (strm.avail_out === 0) {\n            s.last_flush = -1;\n          }\n          return Z_OK;\n        }\n        if (bstate === BS_BLOCK_DONE) {\n          if (flush === Z_PARTIAL_FLUSH) {\n            trees._tr_align(s);\n          } else if (flush !== Z_BLOCK) {\n            trees._tr_stored_block(s, 0, 0, false);\n            if (flush === Z_FULL_FLUSH) {\n              zero(s.head);\n              if (s.lookahead === 0) {\n                s.strstart = 0;\n                s.block_start = 0;\n                s.insert = 0;\n              }\n            }\n          }\n          flush_pending(strm);\n          if (strm.avail_out === 0) {\n            s.last_flush = -1;\n            return Z_OK;\n          }\n        }\n      }\n      if (flush !== Z_FINISH) {\n        return Z_OK;\n      }\n      if (s.wrap <= 0) {\n        return Z_STREAM_END;\n      }\n      if (s.wrap === 2) {\n        put_byte(s, strm.adler & 255);\n        put_byte(s, strm.adler >> 8 & 255);\n        put_byte(s, strm.adler >> 16 & 255);\n        put_byte(s, strm.adler >> 24 & 255);\n        put_byte(s, strm.total_in & 255);\n        put_byte(s, strm.total_in >> 8 & 255);\n        put_byte(s, strm.total_in >> 16 & 255);\n        put_byte(s, strm.total_in >> 24 & 255);\n      } else {\n        putShortMSB(s, strm.adler >>> 16);\n        putShortMSB(s, strm.adler & 65535);\n      }\n      flush_pending(strm);\n      if (s.wrap > 0) {\n        s.wrap = -s.wrap;\n      }\n      return s.pending !== 0 ? Z_OK : Z_STREAM_END;\n    }\n    function deflateEnd(strm) {\n      var status;\n      if (!strm || !strm.state) {\n        return Z_STREAM_ERROR;\n      }\n      status = strm.state.status;\n      if (status !== INIT_STATE && status !== EXTRA_STATE && status !== NAME_STATE && status !== COMMENT_STATE && status !== HCRC_STATE && status !== BUSY_STATE && status !== FINISH_STATE) {\n        return err(strm, Z_STREAM_ERROR);\n      }\n      strm.state = null;\n      return status === BUSY_STATE ? err(strm, Z_DATA_ERROR) : Z_OK;\n    }\n    function deflateSetDictionary(strm, dictionary) {\n      var dictLength = dictionary.length;\n      var s;\n      var str, n;\n      var wrap;\n      var avail;\n      var next;\n      var input;\n      var tmpDict;\n      if (!strm || !strm.state) {\n        return Z_STREAM_ERROR;\n      }\n      s = strm.state;\n      wrap = s.wrap;\n      if (wrap === 2 || wrap === 1 && s.status !== INIT_STATE || s.lookahead) {\n        return Z_STREAM_ERROR;\n      }\n      if (wrap === 1) {\n        strm.adler = adler32(strm.adler, dictionary, dictLength, 0);\n      }\n      s.wrap = 0;\n      if (dictLength >= s.w_size) {\n        if (wrap === 0) {\n          zero(s.head);\n          s.strstart = 0;\n          s.block_start = 0;\n          s.insert = 0;\n        }\n        tmpDict = new utils.Buf8(s.w_size);\n        utils.arraySet(tmpDict, dictionary, dictLength - s.w_size, s.w_size, 0);\n        dictionary = tmpDict;\n        dictLength = s.w_size;\n      }\n      avail = strm.avail_in;\n      next = strm.next_in;\n      input = strm.input;\n      strm.avail_in = dictLength;\n      strm.next_in = 0;\n      strm.input = dictionary;\n      fill_window(s);\n      while (s.lookahead >= MIN_MATCH) {\n        str = s.strstart;\n        n = s.lookahead - (MIN_MATCH - 1);\n        do {\n          s.ins_h = (s.ins_h << s.hash_shift ^ s.window[str + MIN_MATCH - 1]) & s.hash_mask;\n          s.prev[str & s.w_mask] = s.head[s.ins_h];\n          s.head[s.ins_h] = str;\n          str++;\n        } while (--n);\n        s.strstart = str;\n        s.lookahead = MIN_MATCH - 1;\n        fill_window(s);\n      }\n      s.strstart += s.lookahead;\n      s.block_start = s.strstart;\n      s.insert = s.lookahead;\n      s.lookahead = 0;\n      s.match_length = s.prev_length = MIN_MATCH - 1;\n      s.match_available = 0;\n      strm.next_in = next;\n      strm.input = input;\n      strm.avail_in = avail;\n      s.wrap = wrap;\n      return Z_OK;\n    }\n    exports2.deflateInit = deflateInit;\n    exports2.deflateInit2 = deflateInit2;\n    exports2.deflateReset = deflateReset;\n    exports2.deflateResetKeep = deflateResetKeep;\n    exports2.deflateSetHeader = deflateSetHeader;\n    exports2.deflate = deflate;\n    exports2.deflateEnd = deflateEnd;\n    exports2.deflateSetDictionary = deflateSetDictionary;\n    exports2.deflateInfo = \"pako deflate (from Nodeca project)\";\n  }\n});\n\n// node_modules/.pnpm/pako@1.0.11/node_modules/pako/lib/utils/strings.js\nvar require_strings = __commonJS({\n  \"node_modules/.pnpm/pako@1.0.11/node_modules/pako/lib/utils/strings.js\"(exports2) {\n    \"use strict\";\n    var utils = require_common();\n    var STR_APPLY_OK = true;\n    var STR_APPLY_UIA_OK = true;\n    try {\n      String.fromCharCode.apply(null, [0]);\n    } catch (__) {\n      STR_APPLY_OK = false;\n    }\n    try {\n      String.fromCharCode.apply(null, new Uint8Array(1));\n    } catch (__) {\n      STR_APPLY_UIA_OK = false;\n    }\n    var _utf8len = new utils.Buf8(256);\n    for (q = 0; q < 256; q++) {\n      _utf8len[q] = q >= 252 ? 6 : q >= 248 ? 5 : q >= 240 ? 4 : q >= 224 ? 3 : q >= 192 ? 2 : 1;\n    }\n    var q;\n    _utf8len[254] = _utf8len[254] = 1;\n    exports2.string2buf = function(str) {\n      var buf, c, c2, m_pos, i, str_len = str.length, buf_len = 0;\n      for (m_pos = 0; m_pos < str_len; m_pos++) {\n        c = str.charCodeAt(m_pos);\n        if ((c & 64512) === 55296 && m_pos + 1 < str_len) {\n          c2 = str.charCodeAt(m_pos + 1);\n          if ((c2 & 64512) === 56320) {\n            c = 65536 + (c - 55296 << 10) + (c2 - 56320);\n            m_pos++;\n          }\n        }\n        buf_len += c < 128 ? 1 : c < 2048 ? 2 : c < 65536 ? 3 : 4;\n      }\n      buf = new utils.Buf8(buf_len);\n      for (i = 0, m_pos = 0; i < buf_len; m_pos++) {\n        c = str.charCodeAt(m_pos);\n        if ((c & 64512) === 55296 && m_pos + 1 < str_len) {\n          c2 = str.charCodeAt(m_pos + 1);\n          if ((c2 & 64512) === 56320) {\n            c = 65536 + (c - 55296 << 10) + (c2 - 56320);\n            m_pos++;\n          }\n        }\n        if (c < 128) {\n          buf[i++] = c;\n        } else if (c < 2048) {\n          buf[i++] = 192 | c >>> 6;\n          buf[i++] = 128 | c & 63;\n        } else if (c < 65536) {\n          buf[i++] = 224 | c >>> 12;\n          buf[i++] = 128 | c >>> 6 & 63;\n          buf[i++] = 128 | c & 63;\n        } else {\n          buf[i++] = 240 | c >>> 18;\n          buf[i++] = 128 | c >>> 12 & 63;\n          buf[i++] = 128 | c >>> 6 & 63;\n          buf[i++] = 128 | c & 63;\n        }\n      }\n      return buf;\n    };\n    function buf2binstring(buf, len) {\n      if (len < 65534) {\n        if (buf.subarray && STR_APPLY_UIA_OK || !buf.subarray && STR_APPLY_OK) {\n          return String.fromCharCode.apply(null, utils.shrinkBuf(buf, len));\n        }\n      }\n      var result = \"\";\n      for (var i = 0; i < len; i++) {\n        result += String.fromCharCode(buf[i]);\n      }\n      return result;\n    }\n    exports2.buf2binstring = function(buf) {\n      return buf2binstring(buf, buf.length);\n    };\n    exports2.binstring2buf = function(str) {\n      var buf = new utils.Buf8(str.length);\n      for (var i = 0, len = buf.length; i < len; i++) {\n        buf[i] = str.charCodeAt(i);\n      }\n      return buf;\n    };\n    exports2.buf2string = function(buf, max) {\n      var i, out, c, c_len;\n      var len = max || buf.length;\n      var utf16buf = new Array(len * 2);\n      for (out = 0, i = 0; i < len; ) {\n        c = buf[i++];\n        if (c < 128) {\n          utf16buf[out++] = c;\n          continue;\n        }\n        c_len = _utf8len[c];\n        if (c_len > 4) {\n          utf16buf[out++] = 65533;\n          i += c_len - 1;\n          continue;\n        }\n        c &= c_len === 2 ? 31 : c_len === 3 ? 15 : 7;\n        while (c_len > 1 && i < len) {\n          c = c << 6 | buf[i++] & 63;\n          c_len--;\n        }\n        if (c_len > 1) {\n          utf16buf[out++] = 65533;\n          continue;\n        }\n        if (c < 65536) {\n          utf16buf[out++] = c;\n        } else {\n          c -= 65536;\n          utf16buf[out++] = 55296 | c >> 10 & 1023;\n          utf16buf[out++] = 56320 | c & 1023;\n        }\n      }\n      return buf2binstring(utf16buf, out);\n    };\n    exports2.utf8border = function(buf, max) {\n      var pos;\n      max = max || buf.length;\n      if (max > buf.length) {\n        max = buf.length;\n      }\n      pos = max - 1;\n      while (pos >= 0 && (buf[pos] & 192) === 128) {\n        pos--;\n      }\n      if (pos < 0) {\n        return max;\n      }\n      if (pos === 0) {\n        return max;\n      }\n      return pos + _utf8len[buf[pos]] > max ? pos : max;\n    };\n  }\n});\n\n// node_modules/.pnpm/pako@1.0.11/node_modules/pako/lib/zlib/zstream.js\nvar require_zstream = __commonJS({\n  \"node_modules/.pnpm/pako@1.0.11/node_modules/pako/lib/zlib/zstream.js\"(exports2, module2) {\n    \"use strict\";\n    function ZStream() {\n      this.input = null;\n      this.next_in = 0;\n      this.avail_in = 0;\n      this.total_in = 0;\n      this.output = null;\n      this.next_out = 0;\n      this.avail_out = 0;\n      this.total_out = 0;\n      this.msg = \"\";\n      this.state = null;\n      this.data_type = 2;\n      this.adler = 0;\n    }\n    module2.exports = ZStream;\n  }\n});\n\n// node_modules/.pnpm/pako@1.0.11/node_modules/pako/lib/deflate.js\nvar require_deflate2 = __commonJS({\n  \"node_modules/.pnpm/pako@1.0.11/node_modules/pako/lib/deflate.js\"(exports2) {\n    \"use strict\";\n    var zlib_deflate = require_deflate();\n    var utils = require_common();\n    var strings = require_strings();\n    var msg = require_messages();\n    var ZStream = require_zstream();\n    var toString = Object.prototype.toString;\n    var Z_NO_FLUSH = 0;\n    var Z_FINISH = 4;\n    var Z_OK = 0;\n    var Z_STREAM_END = 1;\n    var Z_SYNC_FLUSH = 2;\n    var Z_DEFAULT_COMPRESSION = -1;\n    var Z_DEFAULT_STRATEGY = 0;\n    var Z_DEFLATED = 8;\n    function Deflate(options) {\n      if (!(this instanceof Deflate)) return new Deflate(options);\n      this.options = utils.assign({\n        level: Z_DEFAULT_COMPRESSION,\n        method: Z_DEFLATED,\n        chunkSize: 16384,\n        windowBits: 15,\n        memLevel: 8,\n        strategy: Z_DEFAULT_STRATEGY,\n        to: \"\"\n      }, options || {});\n      var opt = this.options;\n      if (opt.raw && opt.windowBits > 0) {\n        opt.windowBits = -opt.windowBits;\n      } else if (opt.gzip && opt.windowBits > 0 && opt.windowBits < 16) {\n        opt.windowBits += 16;\n      }\n      this.err = 0;\n      this.msg = \"\";\n      this.ended = false;\n      this.chunks = [];\n      this.strm = new ZStream();\n      this.strm.avail_out = 0;\n      var status = zlib_deflate.deflateInit2(\n        this.strm,\n        opt.level,\n        opt.method,\n        opt.windowBits,\n        opt.memLevel,\n        opt.strategy\n      );\n      if (status !== Z_OK) {\n        throw new Error(msg[status]);\n      }\n      if (opt.header) {\n        zlib_deflate.deflateSetHeader(this.strm, opt.header);\n      }\n      if (opt.dictionary) {\n        var dict;\n        if (typeof opt.dictionary === \"string\") {\n          dict = strings.string2buf(opt.dictionary);\n        } else if (toString.call(opt.dictionary) === \"[object ArrayBuffer]\") {\n          dict = new Uint8Array(opt.dictionary);\n        } else {\n          dict = opt.dictionary;\n        }\n        status = zlib_deflate.deflateSetDictionary(this.strm, dict);\n        if (status !== Z_OK) {\n          throw new Error(msg[status]);\n        }\n        this._dict_set = true;\n      }\n    }\n    Deflate.prototype.push = function(data, mode) {\n      var strm = this.strm;\n      var chunkSize = this.options.chunkSize;\n      var status, _mode;\n      if (this.ended) {\n        return false;\n      }\n      _mode = mode === ~~mode ? mode : mode === true ? Z_FINISH : Z_NO_FLUSH;\n      if (typeof data === \"string\") {\n        strm.input = strings.string2buf(data);\n      } else if (toString.call(data) === \"[object ArrayBuffer]\") {\n        strm.input = new Uint8Array(data);\n      } else {\n        strm.input = data;\n      }\n      strm.next_in = 0;\n      strm.avail_in = strm.input.length;\n      do {\n        if (strm.avail_out === 0) {\n          strm.output = new utils.Buf8(chunkSize);\n          strm.next_out = 0;\n          strm.avail_out = chunkSize;\n        }\n        status = zlib_deflate.deflate(strm, _mode);\n        if (status !== Z_STREAM_END && status !== Z_OK) {\n          this.onEnd(status);\n          this.ended = true;\n          return false;\n        }\n        if (strm.avail_out === 0 || strm.avail_in === 0 && (_mode === Z_FINISH || _mode === Z_SYNC_FLUSH)) {\n          if (this.options.to === \"string\") {\n            this.onData(strings.buf2binstring(utils.shrinkBuf(strm.output, strm.next_out)));\n          } else {\n            this.onData(utils.shrinkBuf(strm.output, strm.next_out));\n          }\n        }\n      } while ((strm.avail_in > 0 || strm.avail_out === 0) && status !== Z_STREAM_END);\n      if (_mode === Z_FINISH) {\n        status = zlib_deflate.deflateEnd(this.strm);\n        this.onEnd(status);\n        this.ended = true;\n        return status === Z_OK;\n      }\n      if (_mode === Z_SYNC_FLUSH) {\n        this.onEnd(Z_OK);\n        strm.avail_out = 0;\n        return true;\n      }\n      return true;\n    };\n    Deflate.prototype.onData = function(chunk) {\n      this.chunks.push(chunk);\n    };\n    Deflate.prototype.onEnd = function(status) {\n      if (status === Z_OK) {\n        if (this.options.to === \"string\") {\n          this.result = this.chunks.join(\"\");\n        } else {\n          this.result = utils.flattenChunks(this.chunks);\n        }\n      }\n      this.chunks = [];\n      this.err = status;\n      this.msg = this.strm.msg;\n    };\n    function deflate(input, options) {\n      var deflator = new Deflate(options);\n      deflator.push(input, true);\n      if (deflator.err) {\n        throw deflator.msg || msg[deflator.err];\n      }\n      return deflator.result;\n    }\n    function deflateRaw(input, options) {\n      options = options || {};\n      options.raw = true;\n      return deflate(input, options);\n    }\n    function gzip(input, options) {\n      options = options || {};\n      options.gzip = true;\n      return deflate(input, options);\n    }\n    exports2.Deflate = Deflate;\n    exports2.deflate = deflate;\n    exports2.deflateRaw = deflateRaw;\n    exports2.gzip = gzip;\n  }\n});\n\n// node_modules/.pnpm/pako@1.0.11/node_modules/pako/lib/zlib/inffast.js\nvar require_inffast = __commonJS({\n  \"node_modules/.pnpm/pako@1.0.11/node_modules/pako/lib/zlib/inffast.js\"(exports2, module2) {\n    \"use strict\";\n    var BAD = 30;\n    var TYPE = 12;\n    module2.exports = function inflate_fast(strm, start) {\n      var state;\n      var _in;\n      var last;\n      var _out;\n      var beg;\n      var end;\n      var dmax;\n      var wsize;\n      var whave;\n      var wnext;\n      var s_window;\n      var hold;\n      var bits;\n      var lcode;\n      var dcode;\n      var lmask;\n      var dmask;\n      var here;\n      var op;\n      var len;\n      var dist;\n      var from;\n      var from_source;\n      var input, output;\n      state = strm.state;\n      _in = strm.next_in;\n      input = strm.input;\n      last = _in + (strm.avail_in - 5);\n      _out = strm.next_out;\n      output = strm.output;\n      beg = _out - (start - strm.avail_out);\n      end = _out + (strm.avail_out - 257);\n      dmax = state.dmax;\n      wsize = state.wsize;\n      whave = state.whave;\n      wnext = state.wnext;\n      s_window = state.window;\n      hold = state.hold;\n      bits = state.bits;\n      lcode = state.lencode;\n      dcode = state.distcode;\n      lmask = (1 << state.lenbits) - 1;\n      dmask = (1 << state.distbits) - 1;\n      top:\n        do {\n          if (bits < 15) {\n            hold += input[_in++] << bits;\n            bits += 8;\n            hold += input[_in++] << bits;\n            bits += 8;\n          }\n          here = lcode[hold & lmask];\n          dolen:\n            for (; ; ) {\n              op = here >>> 24;\n              hold >>>= op;\n              bits -= op;\n              op = here >>> 16 & 255;\n              if (op === 0) {\n                output[_out++] = here & 65535;\n              } else if (op & 16) {\n                len = here & 65535;\n                op &= 15;\n                if (op) {\n                  if (bits < op) {\n                    hold += input[_in++] << bits;\n                    bits += 8;\n                  }\n                  len += hold & (1 << op) - 1;\n                  hold >>>= op;\n                  bits -= op;\n                }\n                if (bits < 15) {\n                  hold += input[_in++] << bits;\n                  bits += 8;\n                  hold += input[_in++] << bits;\n                  bits += 8;\n                }\n                here = dcode[hold & dmask];\n                dodist:\n                  for (; ; ) {\n                    op = here >>> 24;\n                    hold >>>= op;\n                    bits -= op;\n                    op = here >>> 16 & 255;\n                    if (op & 16) {\n                      dist = here & 65535;\n                      op &= 15;\n                      if (bits < op) {\n                        hold += input[_in++] << bits;\n                        bits += 8;\n                        if (bits < op) {\n                          hold += input[_in++] << bits;\n                          bits += 8;\n                        }\n                      }\n                      dist += hold & (1 << op) - 1;\n                      if (dist > dmax) {\n                        strm.msg = \"invalid distance too far back\";\n                        state.mode = BAD;\n                        break top;\n                      }\n                      hold >>>= op;\n                      bits -= op;\n                      op = _out - beg;\n                      if (dist > op) {\n                        op = dist - op;\n                        if (op > whave) {\n                          if (state.sane) {\n                            strm.msg = \"invalid distance too far back\";\n                            state.mode = BAD;\n                            break top;\n                          }\n                        }\n                        from = 0;\n                        from_source = s_window;\n                        if (wnext === 0) {\n                          from += wsize - op;\n                          if (op < len) {\n                            len -= op;\n                            do {\n                              output[_out++] = s_window[from++];\n                            } while (--op);\n                            from = _out - dist;\n                            from_source = output;\n                          }\n                        } else if (wnext < op) {\n                          from += wsize + wnext - op;\n                          op -= wnext;\n                          if (op < len) {\n                            len -= op;\n                            do {\n                              output[_out++] = s_window[from++];\n                            } while (--op);\n                            from = 0;\n                            if (wnext < len) {\n                              op = wnext;\n                              len -= op;\n                              do {\n                                output[_out++] = s_window[from++];\n                              } while (--op);\n                              from = _out - dist;\n                              from_source = output;\n                            }\n                          }\n                        } else {\n                          from += wnext - op;\n                          if (op < len) {\n                            len -= op;\n                            do {\n                              output[_out++] = s_window[from++];\n                            } while (--op);\n                            from = _out - dist;\n                            from_source = output;\n                          }\n                        }\n                        while (len > 2) {\n                          output[_out++] = from_source[from++];\n                          output[_out++] = from_source[from++];\n                          output[_out++] = from_source[from++];\n                          len -= 3;\n                        }\n                        if (len) {\n                          output[_out++] = from_source[from++];\n                          if (len > 1) {\n                            output[_out++] = from_source[from++];\n                          }\n                        }\n                      } else {\n                        from = _out - dist;\n                        do {\n                          output[_out++] = output[from++];\n                          output[_out++] = output[from++];\n                          output[_out++] = output[from++];\n                          len -= 3;\n                        } while (len > 2);\n                        if (len) {\n                          output[_out++] = output[from++];\n                          if (len > 1) {\n                            output[_out++] = output[from++];\n                          }\n                        }\n                      }\n                    } else if ((op & 64) === 0) {\n                      here = dcode[(here & 65535) + (hold & (1 << op) - 1)];\n                      continue dodist;\n                    } else {\n                      strm.msg = \"invalid distance code\";\n                      state.mode = BAD;\n                      break top;\n                    }\n                    break;\n                  }\n              } else if ((op & 64) === 0) {\n                here = lcode[(here & 65535) + (hold & (1 << op) - 1)];\n                continue dolen;\n              } else if (op & 32) {\n                state.mode = TYPE;\n                break top;\n              } else {\n                strm.msg = \"invalid literal/length code\";\n                state.mode = BAD;\n                break top;\n              }\n              break;\n            }\n        } while (_in < last && _out < end);\n      len = bits >> 3;\n      _in -= len;\n      bits -= len << 3;\n      hold &= (1 << bits) - 1;\n      strm.next_in = _in;\n      strm.next_out = _out;\n      strm.avail_in = _in < last ? 5 + (last - _in) : 5 - (_in - last);\n      strm.avail_out = _out < end ? 257 + (end - _out) : 257 - (_out - end);\n      state.hold = hold;\n      state.bits = bits;\n      return;\n    };\n  }\n});\n\n// node_modules/.pnpm/pako@1.0.11/node_modules/pako/lib/zlib/inftrees.js\nvar require_inftrees = __commonJS({\n  \"node_modules/.pnpm/pako@1.0.11/node_modules/pako/lib/zlib/inftrees.js\"(exports2, module2) {\n    \"use strict\";\n    var utils = require_common();\n    var MAXBITS = 15;\n    var ENOUGH_LENS = 852;\n    var ENOUGH_DISTS = 592;\n    var CODES = 0;\n    var LENS = 1;\n    var DISTS = 2;\n    var lbase = [\n      /* Length codes 257..285 base */\n      3,\n      4,\n      5,\n      6,\n      7,\n      8,\n      9,\n      10,\n      11,\n      13,\n      15,\n      17,\n      19,\n      23,\n      27,\n      31,\n      35,\n      43,\n      51,\n      59,\n      67,\n      83,\n      99,\n      115,\n      131,\n      163,\n      195,\n      227,\n      258,\n      0,\n      0\n    ];\n    var lext = [\n      /* Length codes 257..285 extra */\n      16,\n      16,\n      16,\n      16,\n      16,\n      16,\n      16,\n      16,\n      17,\n      17,\n      17,\n      17,\n      18,\n      18,\n      18,\n      18,\n      19,\n      19,\n      19,\n      19,\n      20,\n      20,\n      20,\n      20,\n      21,\n      21,\n      21,\n      21,\n      16,\n      72,\n      78\n    ];\n    var dbase = [\n      /* Distance codes 0..29 base */\n      1,\n      2,\n      3,\n      4,\n      5,\n      7,\n      9,\n      13,\n      17,\n      25,\n      33,\n      49,\n      65,\n      97,\n      129,\n      193,\n      257,\n      385,\n      513,\n      769,\n      1025,\n      1537,\n      2049,\n      3073,\n      4097,\n      6145,\n      8193,\n      12289,\n      16385,\n      24577,\n      0,\n      0\n    ];\n    var dext = [\n      /* Distance codes 0..29 extra */\n      16,\n      16,\n      16,\n      16,\n      17,\n      17,\n      18,\n      18,\n      19,\n      19,\n      20,\n      20,\n      21,\n      21,\n      22,\n      22,\n      23,\n      23,\n      24,\n      24,\n      25,\n      25,\n      26,\n      26,\n      27,\n      27,\n      28,\n      28,\n      29,\n      29,\n      64,\n      64\n    ];\n    module2.exports = function inflate_table(type, lens, lens_index, codes, table, table_index, work, opts) {\n      var bits = opts.bits;\n      var len = 0;\n      var sym = 0;\n      var min = 0, max = 0;\n      var root = 0;\n      var curr = 0;\n      var drop = 0;\n      var left = 0;\n      var used = 0;\n      var huff = 0;\n      var incr;\n      var fill;\n      var low;\n      var mask;\n      var next;\n      var base = null;\n      var base_index = 0;\n      var end;\n      var count2 = new utils.Buf16(MAXBITS + 1);\n      var offs = new utils.Buf16(MAXBITS + 1);\n      var extra = null;\n      var extra_index = 0;\n      var here_bits, here_op, here_val;\n      for (len = 0; len <= MAXBITS; len++) {\n        count2[len] = 0;\n      }\n      for (sym = 0; sym < codes; sym++) {\n        count2[lens[lens_index + sym]]++;\n      }\n      root = bits;\n      for (max = MAXBITS; max >= 1; max--) {\n        if (count2[max] !== 0) {\n          break;\n        }\n      }\n      if (root > max) {\n        root = max;\n      }\n      if (max === 0) {\n        table[table_index++] = 1 << 24 | 64 << 16 | 0;\n        table[table_index++] = 1 << 24 | 64 << 16 | 0;\n        opts.bits = 1;\n        return 0;\n      }\n      for (min = 1; min < max; min++) {\n        if (count2[min] !== 0) {\n          break;\n        }\n      }\n      if (root < min) {\n        root = min;\n      }\n      left = 1;\n      for (len = 1; len <= MAXBITS; len++) {\n        left <<= 1;\n        left -= count2[len];\n        if (left < 0) {\n          return -1;\n        }\n      }\n      if (left > 0 && (type === CODES || max !== 1)) {\n        return -1;\n      }\n      offs[1] = 0;\n      for (len = 1; len < MAXBITS; len++) {\n        offs[len + 1] = offs[len] + count2[len];\n      }\n      for (sym = 0; sym < codes; sym++) {\n        if (lens[lens_index + sym] !== 0) {\n          work[offs[lens[lens_index + sym]]++] = sym;\n        }\n      }\n      if (type === CODES) {\n        base = extra = work;\n        end = 19;\n      } else if (type === LENS) {\n        base = lbase;\n        base_index -= 257;\n        extra = lext;\n        extra_index -= 257;\n        end = 256;\n      } else {\n        base = dbase;\n        extra = dext;\n        end = -1;\n      }\n      huff = 0;\n      sym = 0;\n      len = min;\n      next = table_index;\n      curr = root;\n      drop = 0;\n      low = -1;\n      used = 1 << root;\n      mask = used - 1;\n      if (type === LENS && used > ENOUGH_LENS || type === DISTS && used > ENOUGH_DISTS) {\n        return 1;\n      }\n      for (; ; ) {\n        here_bits = len - drop;\n        if (work[sym] < end) {\n          here_op = 0;\n          here_val = work[sym];\n        } else if (work[sym] > end) {\n          here_op = extra[extra_index + work[sym]];\n          here_val = base[base_index + work[sym]];\n        } else {\n          here_op = 32 + 64;\n          here_val = 0;\n        }\n        incr = 1 << len - drop;\n        fill = 1 << curr;\n        min = fill;\n        do {\n          fill -= incr;\n          table[next + (huff >> drop) + fill] = here_bits << 24 | here_op << 16 | here_val | 0;\n        } while (fill !== 0);\n        incr = 1 << len - 1;\n        while (huff & incr) {\n          incr >>= 1;\n        }\n        if (incr !== 0) {\n          huff &= incr - 1;\n          huff += incr;\n        } else {\n          huff = 0;\n        }\n        sym++;\n        if (--count2[len] === 0) {\n          if (len === max) {\n            break;\n          }\n          len = lens[lens_index + work[sym]];\n        }\n        if (len > root && (huff & mask) !== low) {\n          if (drop === 0) {\n            drop = root;\n          }\n          next += min;\n          curr = len - drop;\n          left = 1 << curr;\n          while (curr + drop < max) {\n            left -= count2[curr + drop];\n            if (left <= 0) {\n              break;\n            }\n            curr++;\n            left <<= 1;\n          }\n          used += 1 << curr;\n          if (type === LENS && used > ENOUGH_LENS || type === DISTS && used > ENOUGH_DISTS) {\n            return 1;\n          }\n          low = huff & mask;\n          table[low] = root << 24 | curr << 16 | next - table_index | 0;\n        }\n      }\n      if (huff !== 0) {\n        table[next + huff] = len - drop << 24 | 64 << 16 | 0;\n      }\n      opts.bits = root;\n      return 0;\n    };\n  }\n});\n\n// node_modules/.pnpm/pako@1.0.11/node_modules/pako/lib/zlib/inflate.js\nvar require_inflate = __commonJS({\n  \"node_modules/.pnpm/pako@1.0.11/node_modules/pako/lib/zlib/inflate.js\"(exports2) {\n    \"use strict\";\n    var utils = require_common();\n    var adler32 = require_adler32();\n    var crc32 = require_crc322();\n    var inflate_fast = require_inffast();\n    var inflate_table = require_inftrees();\n    var CODES = 0;\n    var LENS = 1;\n    var DISTS = 2;\n    var Z_FINISH = 4;\n    var Z_BLOCK = 5;\n    var Z_TREES = 6;\n    var Z_OK = 0;\n    var Z_STREAM_END = 1;\n    var Z_NEED_DICT = 2;\n    var Z_STREAM_ERROR = -2;\n    var Z_DATA_ERROR = -3;\n    var Z_MEM_ERROR = -4;\n    var Z_BUF_ERROR = -5;\n    var Z_DEFLATED = 8;\n    var HEAD = 1;\n    var FLAGS = 2;\n    var TIME = 3;\n    var OS = 4;\n    var EXLEN = 5;\n    var EXTRA = 6;\n    var NAME = 7;\n    var COMMENT = 8;\n    var HCRC = 9;\n    var DICTID = 10;\n    var DICT = 11;\n    var TYPE = 12;\n    var TYPEDO = 13;\n    var STORED = 14;\n    var COPY_ = 15;\n    var COPY = 16;\n    var TABLE = 17;\n    var LENLENS = 18;\n    var CODELENS = 19;\n    var LEN_ = 20;\n    var LEN = 21;\n    var LENEXT = 22;\n    var DIST = 23;\n    var DISTEXT = 24;\n    var MATCH = 25;\n    var LIT = 26;\n    var CHECK = 27;\n    var LENGTH = 28;\n    var DONE = 29;\n    var BAD = 30;\n    var MEM = 31;\n    var SYNC = 32;\n    var ENOUGH_LENS = 852;\n    var ENOUGH_DISTS = 592;\n    var MAX_WBITS = 15;\n    var DEF_WBITS = MAX_WBITS;\n    function zswap32(q) {\n      return (q >>> 24 & 255) + (q >>> 8 & 65280) + ((q & 65280) << 8) + ((q & 255) << 24);\n    }\n    function InflateState() {\n      this.mode = 0;\n      this.last = false;\n      this.wrap = 0;\n      this.havedict = false;\n      this.flags = 0;\n      this.dmax = 0;\n      this.check = 0;\n      this.total = 0;\n      this.head = null;\n      this.wbits = 0;\n      this.wsize = 0;\n      this.whave = 0;\n      this.wnext = 0;\n      this.window = null;\n      this.hold = 0;\n      this.bits = 0;\n      this.length = 0;\n      this.offset = 0;\n      this.extra = 0;\n      this.lencode = null;\n      this.distcode = null;\n      this.lenbits = 0;\n      this.distbits = 0;\n      this.ncode = 0;\n      this.nlen = 0;\n      this.ndist = 0;\n      this.have = 0;\n      this.next = null;\n      this.lens = new utils.Buf16(320);\n      this.work = new utils.Buf16(288);\n      this.lendyn = null;\n      this.distdyn = null;\n      this.sane = 0;\n      this.back = 0;\n      this.was = 0;\n    }\n    function inflateResetKeep(strm) {\n      var state;\n      if (!strm || !strm.state) {\n        return Z_STREAM_ERROR;\n      }\n      state = strm.state;\n      strm.total_in = strm.total_out = state.total = 0;\n      strm.msg = \"\";\n      if (state.wrap) {\n        strm.adler = state.wrap & 1;\n      }\n      state.mode = HEAD;\n      state.last = 0;\n      state.havedict = 0;\n      state.dmax = 32768;\n      state.head = null;\n      state.hold = 0;\n      state.bits = 0;\n      state.lencode = state.lendyn = new utils.Buf32(ENOUGH_LENS);\n      state.distcode = state.distdyn = new utils.Buf32(ENOUGH_DISTS);\n      state.sane = 1;\n      state.back = -1;\n      return Z_OK;\n    }\n    function inflateReset(strm) {\n      var state;\n      if (!strm || !strm.state) {\n        return Z_STREAM_ERROR;\n      }\n      state = strm.state;\n      state.wsize = 0;\n      state.whave = 0;\n      state.wnext = 0;\n      return inflateResetKeep(strm);\n    }\n    function inflateReset2(strm, windowBits) {\n      var wrap;\n      var state;\n      if (!strm || !strm.state) {\n        return Z_STREAM_ERROR;\n      }\n      state = strm.state;\n      if (windowBits < 0) {\n        wrap = 0;\n        windowBits = -windowBits;\n      } else {\n        wrap = (windowBits >> 4) + 1;\n        if (windowBits < 48) {\n          windowBits &= 15;\n        }\n      }\n      if (windowBits && (windowBits < 8 || windowBits > 15)) {\n        return Z_STREAM_ERROR;\n      }\n      if (state.window !== null && state.wbits !== windowBits) {\n        state.window = null;\n      }\n      state.wrap = wrap;\n      state.wbits = windowBits;\n      return inflateReset(strm);\n    }\n    function inflateInit2(strm, windowBits) {\n      var ret;\n      var state;\n      if (!strm) {\n        return Z_STREAM_ERROR;\n      }\n      state = new InflateState();\n      strm.state = state;\n      state.window = null;\n      ret = inflateReset2(strm, windowBits);\n      if (ret !== Z_OK) {\n        strm.state = null;\n      }\n      return ret;\n    }\n    function inflateInit(strm) {\n      return inflateInit2(strm, DEF_WBITS);\n    }\n    var virgin = true;\n    var lenfix;\n    var distfix;\n    function fixedtables(state) {\n      if (virgin) {\n        var sym;\n        lenfix = new utils.Buf32(512);\n        distfix = new utils.Buf32(32);\n        sym = 0;\n        while (sym < 144) {\n          state.lens[sym++] = 8;\n        }\n        while (sym < 256) {\n          state.lens[sym++] = 9;\n        }\n        while (sym < 280) {\n          state.lens[sym++] = 7;\n        }\n        while (sym < 288) {\n          state.lens[sym++] = 8;\n        }\n        inflate_table(LENS, state.lens, 0, 288, lenfix, 0, state.work, { bits: 9 });\n        sym = 0;\n        while (sym < 32) {\n          state.lens[sym++] = 5;\n        }\n        inflate_table(DISTS, state.lens, 0, 32, distfix, 0, state.work, { bits: 5 });\n        virgin = false;\n      }\n      state.lencode = lenfix;\n      state.lenbits = 9;\n      state.distcode = distfix;\n      state.distbits = 5;\n    }\n    function updatewindow(strm, src, end, copy) {\n      var dist;\n      var state = strm.state;\n      if (state.window === null) {\n        state.wsize = 1 << state.wbits;\n        state.wnext = 0;\n        state.whave = 0;\n        state.window = new utils.Buf8(state.wsize);\n      }\n      if (copy >= state.wsize) {\n        utils.arraySet(state.window, src, end - state.wsize, state.wsize, 0);\n        state.wnext = 0;\n        state.whave = state.wsize;\n      } else {\n        dist = state.wsize - state.wnext;\n        if (dist > copy) {\n          dist = copy;\n        }\n        utils.arraySet(state.window, src, end - copy, dist, state.wnext);\n        copy -= dist;\n        if (copy) {\n          utils.arraySet(state.window, src, end - copy, copy, 0);\n          state.wnext = copy;\n          state.whave = state.wsize;\n        } else {\n          state.wnext += dist;\n          if (state.wnext === state.wsize) {\n            state.wnext = 0;\n          }\n          if (state.whave < state.wsize) {\n            state.whave += dist;\n          }\n        }\n      }\n      return 0;\n    }\n    function inflate(strm, flush) {\n      var state;\n      var input, output;\n      var next;\n      var put;\n      var have, left;\n      var hold;\n      var bits;\n      var _in, _out;\n      var copy;\n      var from;\n      var from_source;\n      var here = 0;\n      var here_bits, here_op, here_val;\n      var last_bits, last_op, last_val;\n      var len;\n      var ret;\n      var hbuf = new utils.Buf8(4);\n      var opts;\n      var n;\n      var order = (\n        /* permutation of code lengths */\n        [16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15]\n      );\n      if (!strm || !strm.state || !strm.output || !strm.input && strm.avail_in !== 0) {\n        return Z_STREAM_ERROR;\n      }\n      state = strm.state;\n      if (state.mode === TYPE) {\n        state.mode = TYPEDO;\n      }\n      put = strm.next_out;\n      output = strm.output;\n      left = strm.avail_out;\n      next = strm.next_in;\n      input = strm.input;\n      have = strm.avail_in;\n      hold = state.hold;\n      bits = state.bits;\n      _in = have;\n      _out = left;\n      ret = Z_OK;\n      inf_leave:\n        for (; ; ) {\n          switch (state.mode) {\n            case HEAD:\n              if (state.wrap === 0) {\n                state.mode = TYPEDO;\n                break;\n              }\n              while (bits < 16) {\n                if (have === 0) {\n                  break inf_leave;\n                }\n                have--;\n                hold += input[next++] << bits;\n                bits += 8;\n              }\n              if (state.wrap & 2 && hold === 35615) {\n                state.check = 0;\n                hbuf[0] = hold & 255;\n                hbuf[1] = hold >>> 8 & 255;\n                state.check = crc32(state.check, hbuf, 2, 0);\n                hold = 0;\n                bits = 0;\n                state.mode = FLAGS;\n                break;\n              }\n              state.flags = 0;\n              if (state.head) {\n                state.head.done = false;\n              }\n              if (!(state.wrap & 1) || /* check if zlib header allowed */\n              (((hold & 255) << 8) + (hold >> 8)) % 31) {\n                strm.msg = \"incorrect header check\";\n                state.mode = BAD;\n                break;\n              }\n              if ((hold & 15) !== Z_DEFLATED) {\n                strm.msg = \"unknown compression method\";\n                state.mode = BAD;\n                break;\n              }\n              hold >>>= 4;\n              bits -= 4;\n              len = (hold & 15) + 8;\n              if (state.wbits === 0) {\n                state.wbits = len;\n              } else if (len > state.wbits) {\n                strm.msg = \"invalid window size\";\n                state.mode = BAD;\n                break;\n              }\n              state.dmax = 1 << len;\n              strm.adler = state.check = 1;\n              state.mode = hold & 512 ? DICTID : TYPE;\n              hold = 0;\n              bits = 0;\n              break;\n            case FLAGS:\n              while (bits < 16) {\n                if (have === 0) {\n                  break inf_leave;\n                }\n                have--;\n                hold += input[next++] << bits;\n                bits += 8;\n              }\n              state.flags = hold;\n              if ((state.flags & 255) !== Z_DEFLATED) {\n                strm.msg = \"unknown compression method\";\n                state.mode = BAD;\n                break;\n              }\n              if (state.flags & 57344) {\n                strm.msg = \"unknown header flags set\";\n                state.mode = BAD;\n                break;\n              }\n              if (state.head) {\n                state.head.text = hold >> 8 & 1;\n              }\n              if (state.flags & 512) {\n                hbuf[0] = hold & 255;\n                hbuf[1] = hold >>> 8 & 255;\n                state.check = crc32(state.check, hbuf, 2, 0);\n              }\n              hold = 0;\n              bits = 0;\n              state.mode = TIME;\n            /* falls through */\n            case TIME:\n              while (bits < 32) {\n                if (have === 0) {\n                  break inf_leave;\n                }\n                have--;\n                hold += input[next++] << bits;\n                bits += 8;\n              }\n              if (state.head) {\n                state.head.time = hold;\n              }\n              if (state.flags & 512) {\n                hbuf[0] = hold & 255;\n                hbuf[1] = hold >>> 8 & 255;\n                hbuf[2] = hold >>> 16 & 255;\n                hbuf[3] = hold >>> 24 & 255;\n                state.check = crc32(state.check, hbuf, 4, 0);\n              }\n              hold = 0;\n              bits = 0;\n              state.mode = OS;\n            /* falls through */\n            case OS:\n              while (bits < 16) {\n                if (have === 0) {\n                  break inf_leave;\n                }\n                have--;\n                hold += input[next++] << bits;\n                bits += 8;\n              }\n              if (state.head) {\n                state.head.xflags = hold & 255;\n                state.head.os = hold >> 8;\n              }\n              if (state.flags & 512) {\n                hbuf[0] = hold & 255;\n                hbuf[1] = hold >>> 8 & 255;\n                state.check = crc32(state.check, hbuf, 2, 0);\n              }\n              hold = 0;\n              bits = 0;\n              state.mode = EXLEN;\n            /* falls through */\n            case EXLEN:\n              if (state.flags & 1024) {\n                while (bits < 16) {\n                  if (have === 0) {\n                    break inf_leave;\n                  }\n                  have--;\n                  hold += input[next++] << bits;\n                  bits += 8;\n                }\n                state.length = hold;\n                if (state.head) {\n                  state.head.extra_len = hold;\n                }\n                if (state.flags & 512) {\n                  hbuf[0] = hold & 255;\n                  hbuf[1] = hold >>> 8 & 255;\n                  state.check = crc32(state.check, hbuf, 2, 0);\n                }\n                hold = 0;\n                bits = 0;\n              } else if (state.head) {\n                state.head.extra = null;\n              }\n              state.mode = EXTRA;\n            /* falls through */\n            case EXTRA:\n              if (state.flags & 1024) {\n                copy = state.length;\n                if (copy > have) {\n                  copy = have;\n                }\n                if (copy) {\n                  if (state.head) {\n                    len = state.head.extra_len - state.length;\n                    if (!state.head.extra) {\n                      state.head.extra = new Array(state.head.extra_len);\n                    }\n                    utils.arraySet(\n                      state.head.extra,\n                      input,\n                      next,\n                      // extra field is limited to 65536 bytes\n                      // - no need for additional size check\n                      copy,\n                      /*len + copy > state.head.extra_max - len ? state.head.extra_max : copy,*/\n                      len\n                    );\n                  }\n                  if (state.flags & 512) {\n                    state.check = crc32(state.check, input, copy, next);\n                  }\n                  have -= copy;\n                  next += copy;\n                  state.length -= copy;\n                }\n                if (state.length) {\n                  break inf_leave;\n                }\n              }\n              state.length = 0;\n              state.mode = NAME;\n            /* falls through */\n            case NAME:\n              if (state.flags & 2048) {\n                if (have === 0) {\n                  break inf_leave;\n                }\n                copy = 0;\n                do {\n                  len = input[next + copy++];\n                  if (state.head && len && state.length < 65536) {\n                    state.head.name += String.fromCharCode(len);\n                  }\n                } while (len && copy < have);\n                if (state.flags & 512) {\n                  state.check = crc32(state.check, input, copy, next);\n                }\n                have -= copy;\n                next += copy;\n                if (len) {\n                  break inf_leave;\n                }\n              } else if (state.head) {\n                state.head.name = null;\n              }\n              state.length = 0;\n              state.mode = COMMENT;\n            /* falls through */\n            case COMMENT:\n              if (state.flags & 4096) {\n                if (have === 0) {\n                  break inf_leave;\n                }\n                copy = 0;\n                do {\n                  len = input[next + copy++];\n                  if (state.head && len && state.length < 65536) {\n                    state.head.comment += String.fromCharCode(len);\n                  }\n                } while (len && copy < have);\n                if (state.flags & 512) {\n                  state.check = crc32(state.check, input, copy, next);\n                }\n                have -= copy;\n                next += copy;\n                if (len) {\n                  break inf_leave;\n                }\n              } else if (state.head) {\n                state.head.comment = null;\n              }\n              state.mode = HCRC;\n            /* falls through */\n            case HCRC:\n              if (state.flags & 512) {\n                while (bits < 16) {\n                  if (have === 0) {\n                    break inf_leave;\n                  }\n                  have--;\n                  hold += input[next++] << bits;\n                  bits += 8;\n                }\n                if (hold !== (state.check & 65535)) {\n                  strm.msg = \"header crc mismatch\";\n                  state.mode = BAD;\n                  break;\n                }\n                hold = 0;\n                bits = 0;\n              }\n              if (state.head) {\n                state.head.hcrc = state.flags >> 9 & 1;\n                state.head.done = true;\n              }\n              strm.adler = state.check = 0;\n              state.mode = TYPE;\n              break;\n            case DICTID:\n              while (bits < 32) {\n                if (have === 0) {\n                  break inf_leave;\n                }\n                have--;\n                hold += input[next++] << bits;\n                bits += 8;\n              }\n              strm.adler = state.check = zswap32(hold);\n              hold = 0;\n              bits = 0;\n              state.mode = DICT;\n            /* falls through */\n            case DICT:\n              if (state.havedict === 0) {\n                strm.next_out = put;\n                strm.avail_out = left;\n                strm.next_in = next;\n                strm.avail_in = have;\n                state.hold = hold;\n                state.bits = bits;\n                return Z_NEED_DICT;\n              }\n              strm.adler = state.check = 1;\n              state.mode = TYPE;\n            /* falls through */\n            case TYPE:\n              if (flush === Z_BLOCK || flush === Z_TREES) {\n                break inf_leave;\n              }\n            /* falls through */\n            case TYPEDO:\n              if (state.last) {\n                hold >>>= bits & 7;\n                bits -= bits & 7;\n                state.mode = CHECK;\n                break;\n              }\n              while (bits < 3) {\n                if (have === 0) {\n                  break inf_leave;\n                }\n                have--;\n                hold += input[next++] << bits;\n                bits += 8;\n              }\n              state.last = hold & 1;\n              hold >>>= 1;\n              bits -= 1;\n              switch (hold & 3) {\n                case 0:\n                  state.mode = STORED;\n                  break;\n                case 1:\n                  fixedtables(state);\n                  state.mode = LEN_;\n                  if (flush === Z_TREES) {\n                    hold >>>= 2;\n                    bits -= 2;\n                    break inf_leave;\n                  }\n                  break;\n                case 2:\n                  state.mode = TABLE;\n                  break;\n                case 3:\n                  strm.msg = \"invalid block type\";\n                  state.mode = BAD;\n              }\n              hold >>>= 2;\n              bits -= 2;\n              break;\n            case STORED:\n              hold >>>= bits & 7;\n              bits -= bits & 7;\n              while (bits < 32) {\n                if (have === 0) {\n                  break inf_leave;\n                }\n                have--;\n                hold += input[next++] << bits;\n                bits += 8;\n              }\n              if ((hold & 65535) !== (hold >>> 16 ^ 65535)) {\n                strm.msg = \"invalid stored block lengths\";\n                state.mode = BAD;\n                break;\n              }\n              state.length = hold & 65535;\n              hold = 0;\n              bits = 0;\n              state.mode = COPY_;\n              if (flush === Z_TREES) {\n                break inf_leave;\n              }\n            /* falls through */\n            case COPY_:\n              state.mode = COPY;\n            /* falls through */\n            case COPY:\n              copy = state.length;\n              if (copy) {\n                if (copy > have) {\n                  copy = have;\n                }\n                if (copy > left) {\n                  copy = left;\n                }\n                if (copy === 0) {\n                  break inf_leave;\n                }\n                utils.arraySet(output, input, next, copy, put);\n                have -= copy;\n                next += copy;\n                left -= copy;\n                put += copy;\n                state.length -= copy;\n                break;\n              }\n              state.mode = TYPE;\n              break;\n            case TABLE:\n              while (bits < 14) {\n                if (have === 0) {\n                  break inf_leave;\n                }\n                have--;\n                hold += input[next++] << bits;\n                bits += 8;\n              }\n              state.nlen = (hold & 31) + 257;\n              hold >>>= 5;\n              bits -= 5;\n              state.ndist = (hold & 31) + 1;\n              hold >>>= 5;\n              bits -= 5;\n              state.ncode = (hold & 15) + 4;\n              hold >>>= 4;\n              bits -= 4;\n              if (state.nlen > 286 || state.ndist > 30) {\n                strm.msg = \"too many length or distance symbols\";\n                state.mode = BAD;\n                break;\n              }\n              state.have = 0;\n              state.mode = LENLENS;\n            /* falls through */\n            case LENLENS:\n              while (state.have < state.ncode) {\n                while (bits < 3) {\n                  if (have === 0) {\n                    break inf_leave;\n                  }\n                  have--;\n                  hold += input[next++] << bits;\n                  bits += 8;\n                }\n                state.lens[order[state.have++]] = hold & 7;\n                hold >>>= 3;\n                bits -= 3;\n              }\n              while (state.have < 19) {\n                state.lens[order[state.have++]] = 0;\n              }\n              state.lencode = state.lendyn;\n              state.lenbits = 7;\n              opts = { bits: state.lenbits };\n              ret = inflate_table(CODES, state.lens, 0, 19, state.lencode, 0, state.work, opts);\n              state.lenbits = opts.bits;\n              if (ret) {\n                strm.msg = \"invalid code lengths set\";\n                state.mode = BAD;\n                break;\n              }\n              state.have = 0;\n              state.mode = CODELENS;\n            /* falls through */\n            case CODELENS:\n              while (state.have < state.nlen + state.ndist) {\n                for (; ; ) {\n                  here = state.lencode[hold & (1 << state.lenbits) - 1];\n                  here_bits = here >>> 24;\n                  here_op = here >>> 16 & 255;\n                  here_val = here & 65535;\n                  if (here_bits <= bits) {\n                    break;\n                  }\n                  if (have === 0) {\n                    break inf_leave;\n                  }\n                  have--;\n                  hold += input[next++] << bits;\n                  bits += 8;\n                }\n                if (here_val < 16) {\n                  hold >>>= here_bits;\n                  bits -= here_bits;\n                  state.lens[state.have++] = here_val;\n                } else {\n                  if (here_val === 16) {\n                    n = here_bits + 2;\n                    while (bits < n) {\n                      if (have === 0) {\n                        break inf_leave;\n                      }\n                      have--;\n                      hold += input[next++] << bits;\n                      bits += 8;\n                    }\n                    hold >>>= here_bits;\n                    bits -= here_bits;\n                    if (state.have === 0) {\n                      strm.msg = \"invalid bit length repeat\";\n                      state.mode = BAD;\n                      break;\n                    }\n                    len = state.lens[state.have - 1];\n                    copy = 3 + (hold & 3);\n                    hold >>>= 2;\n                    bits -= 2;\n                  } else if (here_val === 17) {\n                    n = here_bits + 3;\n                    while (bits < n) {\n                      if (have === 0) {\n                        break inf_leave;\n                      }\n                      have--;\n                      hold += input[next++] << bits;\n                      bits += 8;\n                    }\n                    hold >>>= here_bits;\n                    bits -= here_bits;\n                    len = 0;\n                    copy = 3 + (hold & 7);\n                    hold >>>= 3;\n                    bits -= 3;\n                  } else {\n                    n = here_bits + 7;\n                    while (bits < n) {\n                      if (have === 0) {\n                        break inf_leave;\n                      }\n                      have--;\n                      hold += input[next++] << bits;\n                      bits += 8;\n                    }\n                    hold >>>= here_bits;\n                    bits -= here_bits;\n                    len = 0;\n                    copy = 11 + (hold & 127);\n                    hold >>>= 7;\n                    bits -= 7;\n                  }\n                  if (state.have + copy > state.nlen + state.ndist) {\n                    strm.msg = \"invalid bit length repeat\";\n                    state.mode = BAD;\n                    break;\n                  }\n                  while (copy--) {\n                    state.lens[state.have++] = len;\n                  }\n                }\n              }\n              if (state.mode === BAD) {\n                break;\n              }\n              if (state.lens[256] === 0) {\n                strm.msg = \"invalid code -- missing end-of-block\";\n                state.mode = BAD;\n                break;\n              }\n              state.lenbits = 9;\n              opts = { bits: state.lenbits };\n              ret = inflate_table(LENS, state.lens, 0, state.nlen, state.lencode, 0, state.work, opts);\n              state.lenbits = opts.bits;\n              if (ret) {\n                strm.msg = \"invalid literal/lengths set\";\n                state.mode = BAD;\n                break;\n              }\n              state.distbits = 6;\n              state.distcode = state.distdyn;\n              opts = { bits: state.distbits };\n              ret = inflate_table(DISTS, state.lens, state.nlen, state.ndist, state.distcode, 0, state.work, opts);\n              state.distbits = opts.bits;\n              if (ret) {\n                strm.msg = \"invalid distances set\";\n                state.mode = BAD;\n                break;\n              }\n              state.mode = LEN_;\n              if (flush === Z_TREES) {\n                break inf_leave;\n              }\n            /* falls through */\n            case LEN_:\n              state.mode = LEN;\n            /* falls through */\n            case LEN:\n              if (have >= 6 && left >= 258) {\n                strm.next_out = put;\n                strm.avail_out = left;\n                strm.next_in = next;\n                strm.avail_in = have;\n                state.hold = hold;\n                state.bits = bits;\n                inflate_fast(strm, _out);\n                put = strm.next_out;\n                output = strm.output;\n                left = strm.avail_out;\n                next = strm.next_in;\n                input = strm.input;\n                have = strm.avail_in;\n                hold = state.hold;\n                bits = state.bits;\n                if (state.mode === TYPE) {\n                  state.back = -1;\n                }\n                break;\n              }\n              state.back = 0;\n              for (; ; ) {\n                here = state.lencode[hold & (1 << state.lenbits) - 1];\n                here_bits = here >>> 24;\n                here_op = here >>> 16 & 255;\n                here_val = here & 65535;\n                if (here_bits <= bits) {\n                  break;\n                }\n                if (have === 0) {\n                  break inf_leave;\n                }\n                have--;\n                hold += input[next++] << bits;\n                bits += 8;\n              }\n              if (here_op && (here_op & 240) === 0) {\n                last_bits = here_bits;\n                last_op = here_op;\n                last_val = here_val;\n                for (; ; ) {\n                  here = state.lencode[last_val + ((hold & (1 << last_bits + last_op) - 1) >> last_bits)];\n                  here_bits = here >>> 24;\n                  here_op = here >>> 16 & 255;\n                  here_val = here & 65535;\n                  if (last_bits + here_bits <= bits) {\n                    break;\n                  }\n                  if (have === 0) {\n                    break inf_leave;\n                  }\n                  have--;\n                  hold += input[next++] << bits;\n                  bits += 8;\n                }\n                hold >>>= last_bits;\n                bits -= last_bits;\n                state.back += last_bits;\n              }\n              hold >>>= here_bits;\n              bits -= here_bits;\n              state.back += here_bits;\n              state.length = here_val;\n              if (here_op === 0) {\n                state.mode = LIT;\n                break;\n              }\n              if (here_op & 32) {\n                state.back = -1;\n                state.mode = TYPE;\n                break;\n              }\n              if (here_op & 64) {\n                strm.msg = \"invalid literal/length code\";\n                state.mode = BAD;\n                break;\n              }\n              state.extra = here_op & 15;\n              state.mode = LENEXT;\n            /* falls through */\n            case LENEXT:\n              if (state.extra) {\n                n = state.extra;\n                while (bits < n) {\n                  if (have === 0) {\n                    break inf_leave;\n                  }\n                  have--;\n                  hold += input[next++] << bits;\n                  bits += 8;\n                }\n                state.length += hold & (1 << state.extra) - 1;\n                hold >>>= state.extra;\n                bits -= state.extra;\n                state.back += state.extra;\n              }\n              state.was = state.length;\n              state.mode = DIST;\n            /* falls through */\n            case DIST:\n              for (; ; ) {\n                here = state.distcode[hold & (1 << state.distbits) - 1];\n                here_bits = here >>> 24;\n                here_op = here >>> 16 & 255;\n                here_val = here & 65535;\n                if (here_bits <= bits) {\n                  break;\n                }\n                if (have === 0) {\n                  break inf_leave;\n                }\n                have--;\n                hold += input[next++] << bits;\n                bits += 8;\n              }\n              if ((here_op & 240) === 0) {\n                last_bits = here_bits;\n                last_op = here_op;\n                last_val = here_val;\n                for (; ; ) {\n                  here = state.distcode[last_val + ((hold & (1 << last_bits + last_op) - 1) >> last_bits)];\n                  here_bits = here >>> 24;\n                  here_op = here >>> 16 & 255;\n                  here_val = here & 65535;\n                  if (last_bits + here_bits <= bits) {\n                    break;\n                  }\n                  if (have === 0) {\n                    break inf_leave;\n                  }\n                  have--;\n                  hold += input[next++] << bits;\n                  bits += 8;\n                }\n                hold >>>= last_bits;\n                bits -= last_bits;\n                state.back += last_bits;\n              }\n              hold >>>= here_bits;\n              bits -= here_bits;\n              state.back += here_bits;\n              if (here_op & 64) {\n                strm.msg = \"invalid distance code\";\n                state.mode = BAD;\n                break;\n              }\n              state.offset = here_val;\n              state.extra = here_op & 15;\n              state.mode = DISTEXT;\n            /* falls through */\n            case DISTEXT:\n              if (state.extra) {\n                n = state.extra;\n                while (bits < n) {\n                  if (have === 0) {\n                    break inf_leave;\n                  }\n                  have--;\n                  hold += input[next++] << bits;\n                  bits += 8;\n                }\n                state.offset += hold & (1 << state.extra) - 1;\n                hold >>>= state.extra;\n                bits -= state.extra;\n                state.back += state.extra;\n              }\n              if (state.offset > state.dmax) {\n                strm.msg = \"invalid distance too far back\";\n                state.mode = BAD;\n                break;\n              }\n              state.mode = MATCH;\n            /* falls through */\n            case MATCH:\n              if (left === 0) {\n                break inf_leave;\n              }\n              copy = _out - left;\n              if (state.offset > copy) {\n                copy = state.offset - copy;\n                if (copy > state.whave) {\n                  if (state.sane) {\n                    strm.msg = \"invalid distance too far back\";\n                    state.mode = BAD;\n                    break;\n                  }\n                }\n                if (copy > state.wnext) {\n                  copy -= state.wnext;\n                  from = state.wsize - copy;\n                } else {\n                  from = state.wnext - copy;\n                }\n                if (copy > state.length) {\n                  copy = state.length;\n                }\n                from_source = state.window;\n              } else {\n                from_source = output;\n                from = put - state.offset;\n                copy = state.length;\n              }\n              if (copy > left) {\n                copy = left;\n              }\n              left -= copy;\n              state.length -= copy;\n              do {\n                output[put++] = from_source[from++];\n              } while (--copy);\n              if (state.length === 0) {\n                state.mode = LEN;\n              }\n              break;\n            case LIT:\n              if (left === 0) {\n                break inf_leave;\n              }\n              output[put++] = state.length;\n              left--;\n              state.mode = LEN;\n              break;\n            case CHECK:\n              if (state.wrap) {\n                while (bits < 32) {\n                  if (have === 0) {\n                    break inf_leave;\n                  }\n                  have--;\n                  hold |= input[next++] << bits;\n                  bits += 8;\n                }\n                _out -= left;\n                strm.total_out += _out;\n                state.total += _out;\n                if (_out) {\n                  strm.adler = state.check = /*UPDATE(state.check, put - _out, _out);*/\n                  state.flags ? crc32(state.check, output, _out, put - _out) : adler32(state.check, output, _out, put - _out);\n                }\n                _out = left;\n                if ((state.flags ? hold : zswap32(hold)) !== state.check) {\n                  strm.msg = \"incorrect data check\";\n                  state.mode = BAD;\n                  break;\n                }\n                hold = 0;\n                bits = 0;\n              }\n              state.mode = LENGTH;\n            /* falls through */\n            case LENGTH:\n              if (state.wrap && state.flags) {\n                while (bits < 32) {\n                  if (have === 0) {\n                    break inf_leave;\n                  }\n                  have--;\n                  hold += input[next++] << bits;\n                  bits += 8;\n                }\n                if (hold !== (state.total & 4294967295)) {\n                  strm.msg = \"incorrect length check\";\n                  state.mode = BAD;\n                  break;\n                }\n                hold = 0;\n                bits = 0;\n              }\n              state.mode = DONE;\n            /* falls through */\n            case DONE:\n              ret = Z_STREAM_END;\n              break inf_leave;\n            case BAD:\n              ret = Z_DATA_ERROR;\n              break inf_leave;\n            case MEM:\n              return Z_MEM_ERROR;\n            case SYNC:\n            /* falls through */\n            default:\n              return Z_STREAM_ERROR;\n          }\n        }\n      strm.next_out = put;\n      strm.avail_out = left;\n      strm.next_in = next;\n      strm.avail_in = have;\n      state.hold = hold;\n      state.bits = bits;\n      if (state.wsize || _out !== strm.avail_out && state.mode < BAD && (state.mode < CHECK || flush !== Z_FINISH)) {\n        if (updatewindow(strm, strm.output, strm.next_out, _out - strm.avail_out)) {\n          state.mode = MEM;\n          return Z_MEM_ERROR;\n        }\n      }\n      _in -= strm.avail_in;\n      _out -= strm.avail_out;\n      strm.total_in += _in;\n      strm.total_out += _out;\n      state.total += _out;\n      if (state.wrap && _out) {\n        strm.adler = state.check = /*UPDATE(state.check, strm.next_out - _out, _out);*/\n        state.flags ? crc32(state.check, output, _out, strm.next_out - _out) : adler32(state.check, output, _out, strm.next_out - _out);\n      }\n      strm.data_type = state.bits + (state.last ? 64 : 0) + (state.mode === TYPE ? 128 : 0) + (state.mode === LEN_ || state.mode === COPY_ ? 256 : 0);\n      if ((_in === 0 && _out === 0 || flush === Z_FINISH) && ret === Z_OK) {\n        ret = Z_BUF_ERROR;\n      }\n      return ret;\n    }\n    function inflateEnd(strm) {\n      if (!strm || !strm.state) {\n        return Z_STREAM_ERROR;\n      }\n      var state = strm.state;\n      if (state.window) {\n        state.window = null;\n      }\n      strm.state = null;\n      return Z_OK;\n    }\n    function inflateGetHeader(strm, head) {\n      var state;\n      if (!strm || !strm.state) {\n        return Z_STREAM_ERROR;\n      }\n      state = strm.state;\n      if ((state.wrap & 2) === 0) {\n        return Z_STREAM_ERROR;\n      }\n      state.head = head;\n      head.done = false;\n      return Z_OK;\n    }\n    function inflateSetDictionary(strm, dictionary) {\n      var dictLength = dictionary.length;\n      var state;\n      var dictid;\n      var ret;\n      if (!strm || !strm.state) {\n        return Z_STREAM_ERROR;\n      }\n      state = strm.state;\n      if (state.wrap !== 0 && state.mode !== DICT) {\n        return Z_STREAM_ERROR;\n      }\n      if (state.mode === DICT) {\n        dictid = 1;\n        dictid = adler32(dictid, dictionary, dictLength, 0);\n        if (dictid !== state.check) {\n          return Z_DATA_ERROR;\n        }\n      }\n      ret = updatewindow(strm, dictionary, dictLength, dictLength);\n      if (ret) {\n        state.mode = MEM;\n        return Z_MEM_ERROR;\n      }\n      state.havedict = 1;\n      return Z_OK;\n    }\n    exports2.inflateReset = inflateReset;\n    exports2.inflateReset2 = inflateReset2;\n    exports2.inflateResetKeep = inflateResetKeep;\n    exports2.inflateInit = inflateInit;\n    exports2.inflateInit2 = inflateInit2;\n    exports2.inflate = inflate;\n    exports2.inflateEnd = inflateEnd;\n    exports2.inflateGetHeader = inflateGetHeader;\n    exports2.inflateSetDictionary = inflateSetDictionary;\n    exports2.inflateInfo = \"pako inflate (from Nodeca project)\";\n  }\n});\n\n// node_modules/.pnpm/pako@1.0.11/node_modules/pako/lib/zlib/constants.js\nvar require_constants = __commonJS({\n  \"node_modules/.pnpm/pako@1.0.11/node_modules/pako/lib/zlib/constants.js\"(exports2, module2) {\n    \"use strict\";\n    module2.exports = {\n      /* Allowed flush values; see deflate() and inflate() below for details */\n      Z_NO_FLUSH: 0,\n      Z_PARTIAL_FLUSH: 1,\n      Z_SYNC_FLUSH: 2,\n      Z_FULL_FLUSH: 3,\n      Z_FINISH: 4,\n      Z_BLOCK: 5,\n      Z_TREES: 6,\n      /* Return codes for the compression/decompression functions. Negative values\n      * are errors, positive values are used for special but normal events.\n      */\n      Z_OK: 0,\n      Z_STREAM_END: 1,\n      Z_NEED_DICT: 2,\n      Z_ERRNO: -1,\n      Z_STREAM_ERROR: -2,\n      Z_DATA_ERROR: -3,\n      //Z_MEM_ERROR:     -4,\n      Z_BUF_ERROR: -5,\n      //Z_VERSION_ERROR: -6,\n      /* compression levels */\n      Z_NO_COMPRESSION: 0,\n      Z_BEST_SPEED: 1,\n      Z_BEST_COMPRESSION: 9,\n      Z_DEFAULT_COMPRESSION: -1,\n      Z_FILTERED: 1,\n      Z_HUFFMAN_ONLY: 2,\n      Z_RLE: 3,\n      Z_FIXED: 4,\n      Z_DEFAULT_STRATEGY: 0,\n      /* Possible values of the data_type field (though see inflate()) */\n      Z_BINARY: 0,\n      Z_TEXT: 1,\n      //Z_ASCII:                1, // = Z_TEXT (deprecated)\n      Z_UNKNOWN: 2,\n      /* The deflate compression method */\n      Z_DEFLATED: 8\n      //Z_NULL:                 null // Use -1 or null inline, depending on var type\n    };\n  }\n});\n\n// node_modules/.pnpm/pako@1.0.11/node_modules/pako/lib/zlib/gzheader.js\nvar require_gzheader = __commonJS({\n  \"node_modules/.pnpm/pako@1.0.11/node_modules/pako/lib/zlib/gzheader.js\"(exports2, module2) {\n    \"use strict\";\n    function GZheader() {\n      this.text = 0;\n      this.time = 0;\n      this.xflags = 0;\n      this.os = 0;\n      this.extra = null;\n      this.extra_len = 0;\n      this.name = \"\";\n      this.comment = \"\";\n      this.hcrc = 0;\n      this.done = false;\n    }\n    module2.exports = GZheader;\n  }\n});\n\n// node_modules/.pnpm/pako@1.0.11/node_modules/pako/lib/inflate.js\nvar require_inflate2 = __commonJS({\n  \"node_modules/.pnpm/pako@1.0.11/node_modules/pako/lib/inflate.js\"(exports2) {\n    \"use strict\";\n    var zlib_inflate = require_inflate();\n    var utils = require_common();\n    var strings = require_strings();\n    var c = require_constants();\n    var msg = require_messages();\n    var ZStream = require_zstream();\n    var GZheader = require_gzheader();\n    var toString = Object.prototype.toString;\n    function Inflate(options) {\n      if (!(this instanceof Inflate)) return new Inflate(options);\n      this.options = utils.assign({\n        chunkSize: 16384,\n        windowBits: 0,\n        to: \"\"\n      }, options || {});\n      var opt = this.options;\n      if (opt.raw && opt.windowBits >= 0 && opt.windowBits < 16) {\n        opt.windowBits = -opt.windowBits;\n        if (opt.windowBits === 0) {\n          opt.windowBits = -15;\n        }\n      }\n      if (opt.windowBits >= 0 && opt.windowBits < 16 && !(options && options.windowBits)) {\n        opt.windowBits += 32;\n      }\n      if (opt.windowBits > 15 && opt.windowBits < 48) {\n        if ((opt.windowBits & 15) === 0) {\n          opt.windowBits |= 15;\n        }\n      }\n      this.err = 0;\n      this.msg = \"\";\n      this.ended = false;\n      this.chunks = [];\n      this.strm = new ZStream();\n      this.strm.avail_out = 0;\n      var status = zlib_inflate.inflateInit2(\n        this.strm,\n        opt.windowBits\n      );\n      if (status !== c.Z_OK) {\n        throw new Error(msg[status]);\n      }\n      this.header = new GZheader();\n      zlib_inflate.inflateGetHeader(this.strm, this.header);\n      if (opt.dictionary) {\n        if (typeof opt.dictionary === \"string\") {\n          opt.dictionary = strings.string2buf(opt.dictionary);\n        } else if (toString.call(opt.dictionary) === \"[object ArrayBuffer]\") {\n          opt.dictionary = new Uint8Array(opt.dictionary);\n        }\n        if (opt.raw) {\n          status = zlib_inflate.inflateSetDictionary(this.strm, opt.dictionary);\n          if (status !== c.Z_OK) {\n            throw new Error(msg[status]);\n          }\n        }\n      }\n    }\n    Inflate.prototype.push = function(data, mode) {\n      var strm = this.strm;\n      var chunkSize = this.options.chunkSize;\n      var dictionary = this.options.dictionary;\n      var status, _mode;\n      var next_out_utf8, tail, utf8str;\n      var allowBufError = false;\n      if (this.ended) {\n        return false;\n      }\n      _mode = mode === ~~mode ? mode : mode === true ? c.Z_FINISH : c.Z_NO_FLUSH;\n      if (typeof data === \"string\") {\n        strm.input = strings.binstring2buf(data);\n      } else if (toString.call(data) === \"[object ArrayBuffer]\") {\n        strm.input = new Uint8Array(data);\n      } else {\n        strm.input = data;\n      }\n      strm.next_in = 0;\n      strm.avail_in = strm.input.length;\n      do {\n        if (strm.avail_out === 0) {\n          strm.output = new utils.Buf8(chunkSize);\n          strm.next_out = 0;\n          strm.avail_out = chunkSize;\n        }\n        status = zlib_inflate.inflate(strm, c.Z_NO_FLUSH);\n        if (status === c.Z_NEED_DICT && dictionary) {\n          status = zlib_inflate.inflateSetDictionary(this.strm, dictionary);\n        }\n        if (status === c.Z_BUF_ERROR && allowBufError === true) {\n          status = c.Z_OK;\n          allowBufError = false;\n        }\n        if (status !== c.Z_STREAM_END && status !== c.Z_OK) {\n          this.onEnd(status);\n          this.ended = true;\n          return false;\n        }\n        if (strm.next_out) {\n          if (strm.avail_out === 0 || status === c.Z_STREAM_END || strm.avail_in === 0 && (_mode === c.Z_FINISH || _mode === c.Z_SYNC_FLUSH)) {\n            if (this.options.to === \"string\") {\n              next_out_utf8 = strings.utf8border(strm.output, strm.next_out);\n              tail = strm.next_out - next_out_utf8;\n              utf8str = strings.buf2string(strm.output, next_out_utf8);\n              strm.next_out = tail;\n              strm.avail_out = chunkSize - tail;\n              if (tail) {\n                utils.arraySet(strm.output, strm.output, next_out_utf8, tail, 0);\n              }\n              this.onData(utf8str);\n            } else {\n              this.onData(utils.shrinkBuf(strm.output, strm.next_out));\n            }\n          }\n        }\n        if (strm.avail_in === 0 && strm.avail_out === 0) {\n          allowBufError = true;\n        }\n      } while ((strm.avail_in > 0 || strm.avail_out === 0) && status !== c.Z_STREAM_END);\n      if (status === c.Z_STREAM_END) {\n        _mode = c.Z_FINISH;\n      }\n      if (_mode === c.Z_FINISH) {\n        status = zlib_inflate.inflateEnd(this.strm);\n        this.onEnd(status);\n        this.ended = true;\n        return status === c.Z_OK;\n      }\n      if (_mode === c.Z_SYNC_FLUSH) {\n        this.onEnd(c.Z_OK);\n        strm.avail_out = 0;\n        return true;\n      }\n      return true;\n    };\n    Inflate.prototype.onData = function(chunk) {\n      this.chunks.push(chunk);\n    };\n    Inflate.prototype.onEnd = function(status) {\n      if (status === c.Z_OK) {\n        if (this.options.to === \"string\") {\n          this.result = this.chunks.join(\"\");\n        } else {\n          this.result = utils.flattenChunks(this.chunks);\n        }\n      }\n      this.chunks = [];\n      this.err = status;\n      this.msg = this.strm.msg;\n    };\n    function inflate(input, options) {\n      var inflator = new Inflate(options);\n      inflator.push(input, true);\n      if (inflator.err) {\n        throw inflator.msg || msg[inflator.err];\n      }\n      return inflator.result;\n    }\n    function inflateRaw(input, options) {\n      options = options || {};\n      options.raw = true;\n      return inflate(input, options);\n    }\n    exports2.Inflate = Inflate;\n    exports2.inflate = inflate;\n    exports2.inflateRaw = inflateRaw;\n    exports2.ungzip = inflate;\n  }\n});\n\n// node_modules/.pnpm/pako@1.0.11/node_modules/pako/index.js\nvar require_pako = __commonJS({\n  \"node_modules/.pnpm/pako@1.0.11/node_modules/pako/index.js\"(exports2, module2) {\n    \"use strict\";\n    var assign = require_common().assign;\n    var deflate = require_deflate2();\n    var inflate = require_inflate2();\n    var constants = require_constants();\n    var pako = {};\n    assign(pako, deflate, inflate, constants);\n    module2.exports = pako;\n  }\n});\n\n// node_modules/.pnpm/pify@4.0.1/node_modules/pify/index.js\nvar require_pify = __commonJS({\n  \"node_modules/.pnpm/pify@4.0.1/node_modules/pify/index.js\"(exports2, module2) {\n    \"use strict\";\n    var processFn = (fn, options) => function(...args) {\n      const P = options.promiseModule;\n      return new P((resolve, reject) => {\n        if (options.multiArgs) {\n          args.push((...result) => {\n            if (options.errorFirst) {\n              if (result[0]) {\n                reject(result);\n              } else {\n                result.shift();\n                resolve(result);\n              }\n            } else {\n              resolve(result);\n            }\n          });\n        } else if (options.errorFirst) {\n          args.push((error, result) => {\n            if (error) {\n              reject(error);\n            } else {\n              resolve(result);\n            }\n          });\n        } else {\n          args.push(resolve);\n        }\n        fn.apply(this, args);\n      });\n    };\n    module2.exports = (input, options) => {\n      options = Object.assign({\n        exclude: [/.+(Sync|Stream)$/],\n        errorFirst: true,\n        promiseModule: Promise\n      }, options);\n      const objType = typeof input;\n      if (!(input !== null && (objType === \"object\" || objType === \"function\"))) {\n        throw new TypeError(`Expected \\`input\\` to be a \\`Function\\` or \\`Object\\`, got \\`${input === null ? \"null\" : objType}\\``);\n      }\n      const filter = (key) => {\n        const match = (pattern) => typeof pattern === \"string\" ? key === pattern : pattern.test(key);\n        return options.include ? options.include.some(match) : !options.exclude.some(match);\n      };\n      let ret;\n      if (objType === \"function\") {\n        ret = function(...args) {\n          return options.excludeMain ? input(...args) : processFn(input, options).apply(this, args);\n        };\n      } else {\n        ret = Object.create(Object.getPrototypeOf(input));\n      }\n      for (const key in input) {\n        const property = input[key];\n        ret[key] = typeof property === \"function\" && filter(key) ? processFn(property, options) : property;\n      }\n      return ret;\n    };\n  }\n});\n\n// node_modules/.pnpm/ignore@5.3.2/node_modules/ignore/index.js\nvar require_ignore = __commonJS({\n  \"node_modules/.pnpm/ignore@5.3.2/node_modules/ignore/index.js\"(exports2, module2) {\n    function makeArray(subject) {\n      return Array.isArray(subject) ? subject : [subject];\n    }\n    var EMPTY = \"\";\n    var SPACE = \" \";\n    var ESCAPE = \"\\\\\";\n    var REGEX_TEST_BLANK_LINE = /^\\s+$/;\n    var REGEX_INVALID_TRAILING_BACKSLASH = /(?:[^\\\\]|^)\\\\$/;\n    var REGEX_REPLACE_LEADING_EXCAPED_EXCLAMATION = /^\\\\!/;\n    var REGEX_REPLACE_LEADING_EXCAPED_HASH = /^\\\\#/;\n    var REGEX_SPLITALL_CRLF = /\\r?\\n/g;\n    var REGEX_TEST_INVALID_PATH = /^\\.*\\/|^\\.+$/;\n    var SLASH = \"/\";\n    var TMP_KEY_IGNORE = \"node-ignore\";\n    if (typeof Symbol !== \"undefined\") {\n      TMP_KEY_IGNORE = Symbol.for(\"node-ignore\");\n    }\n    var KEY_IGNORE = TMP_KEY_IGNORE;\n    var define2 = (object, key, value) => Object.defineProperty(object, key, { value });\n    var REGEX_REGEXP_RANGE = /([0-z])-([0-z])/g;\n    var RETURN_FALSE = () => false;\n    var sanitizeRange = (range2) => range2.replace(\n      REGEX_REGEXP_RANGE,\n      (match, from, to) => from.charCodeAt(0) <= to.charCodeAt(0) ? match : EMPTY\n    );\n    var cleanRangeBackSlash = (slashes) => {\n      const { length } = slashes;\n      return slashes.slice(0, length - length % 2);\n    };\n    var REPLACERS = [\n      [\n        // remove BOM\n        // TODO:\n        // Other similar zero-width characters?\n        /^\\uFEFF/,\n        () => EMPTY\n      ],\n      // > Trailing spaces are ignored unless they are quoted with backslash (\"\\\")\n      [\n        // (a\\ ) -> (a )\n        // (a  ) -> (a)\n        // (a ) -> (a)\n        // (a \\ ) -> (a  )\n        /((?:\\\\\\\\)*?)(\\\\?\\s+)$/,\n        (_, m1, m2) => m1 + (m2.indexOf(\"\\\\\") === 0 ? SPACE : EMPTY)\n      ],\n      // replace (\\ ) with ' '\n      // (\\ ) -> ' '\n      // (\\\\ ) -> '\\\\ '\n      // (\\\\\\ ) -> '\\\\ '\n      [\n        /(\\\\+?)\\s/g,\n        (_, m1) => {\n          const { length } = m1;\n          return m1.slice(0, length - length % 2) + SPACE;\n        }\n      ],\n      // Escape metacharacters\n      // which is written down by users but means special for regular expressions.\n      // > There are 12 characters with special meanings:\n      // > - the backslash \\,\n      // > - the caret ^,\n      // > - the dollar sign $,\n      // > - the period or dot .,\n      // > - the vertical bar or pipe symbol |,\n      // > - the question mark ?,\n      // > - the asterisk or star *,\n      // > - the plus sign +,\n      // > - the opening parenthesis (,\n      // > - the closing parenthesis ),\n      // > - and the opening square bracket [,\n      // > - the opening curly brace {,\n      // > These special characters are often called \"metacharacters\".\n      [\n        /[\\\\$.|*+(){^]/g,\n        (match) => `\\\\${match}`\n      ],\n      [\n        // > a question mark (?) matches a single character\n        /(?!\\\\)\\?/g,\n        () => \"[^/]\"\n      ],\n      // leading slash\n      [\n        // > A leading slash matches the beginning of the pathname.\n        // > For example, \"/*.c\" matches \"cat-file.c\" but not \"mozilla-sha1/sha1.c\".\n        // A leading slash matches the beginning of the pathname\n        /^\\//,\n        () => \"^\"\n      ],\n      // replace special metacharacter slash after the leading slash\n      [\n        /\\//g,\n        () => \"\\\\/\"\n      ],\n      [\n        // > A leading \"**\" followed by a slash means match in all directories.\n        // > For example, \"**/foo\" matches file or directory \"foo\" anywhere,\n        // > the same as pattern \"foo\".\n        // > \"**/foo/bar\" matches file or directory \"bar\" anywhere that is directly\n        // >   under directory \"foo\".\n        // Notice that the '*'s have been replaced as '\\\\*'\n        /^\\^*\\\\\\*\\\\\\*\\\\\\//,\n        // '**/foo' <-> 'foo'\n        () => \"^(?:.*\\\\/)?\"\n      ],\n      // starting\n      [\n        // there will be no leading '/'\n        //   (which has been replaced by section \"leading slash\")\n        // If starts with '**', adding a '^' to the regular expression also works\n        /^(?=[^^])/,\n        function startingReplacer() {\n          return !/\\/(?!$)/.test(this) ? \"(?:^|\\\\/)\" : \"^\";\n        }\n      ],\n      // two globstars\n      [\n        // Use lookahead assertions so that we could match more than one `'/**'`\n        /\\\\\\/\\\\\\*\\\\\\*(?=\\\\\\/|$)/g,\n        // Zero, one or several directories\n        // should not use '*', or it will be replaced by the next replacer\n        // Check if it is not the last `'/**'`\n        (_, index, str) => index + 6 < str.length ? \"(?:\\\\/[^\\\\/]+)*\" : \"\\\\/.+\"\n      ],\n      // normal intermediate wildcards\n      [\n        // Never replace escaped '*'\n        // ignore rule '\\*' will match the path '*'\n        // 'abc.*/' -> go\n        // 'abc.*'  -> skip this rule,\n        //    coz trailing single wildcard will be handed by [trailing wildcard]\n        /(^|[^\\\\]+)(\\\\\\*)+(?=.+)/g,\n        // '*.js' matches '.js'\n        // '*.js' doesn't match 'abc'\n        (_, p1, p2) => {\n          const unescaped = p2.replace(/\\\\\\*/g, \"[^\\\\/]*\");\n          return p1 + unescaped;\n        }\n      ],\n      [\n        // unescape, revert step 3 except for back slash\n        // For example, if a user escape a '\\\\*',\n        // after step 3, the result will be '\\\\\\\\\\\\*'\n        /\\\\\\\\\\\\(?=[$.|*+(){^])/g,\n        () => ESCAPE\n      ],\n      [\n        // '\\\\\\\\' -> '\\\\'\n        /\\\\\\\\/g,\n        () => ESCAPE\n      ],\n      [\n        // > The range notation, e.g. [a-zA-Z],\n        // > can be used to match one of the characters in a range.\n        // `\\` is escaped by step 3\n        /(\\\\)?\\[([^\\]/]*?)(\\\\*)($|\\])/g,\n        (match, leadEscape, range2, endEscape, close) => leadEscape === ESCAPE ? `\\\\[${range2}${cleanRangeBackSlash(endEscape)}${close}` : close === \"]\" ? endEscape.length % 2 === 0 ? `[${sanitizeRange(range2)}${endEscape}]` : \"[]\" : \"[]\"\n      ],\n      // ending\n      [\n        // 'js' will not match 'js.'\n        // 'ab' will not match 'abc'\n        /(?:[^*])$/,\n        // WTF!\n        // https://git-scm.com/docs/gitignore\n        // changes in [2.22.1](https://git-scm.com/docs/gitignore/2.22.1)\n        // which re-fixes #24, #38\n        // > If there is a separator at the end of the pattern then the pattern\n        // > will only match directories, otherwise the pattern can match both\n        // > files and directories.\n        // 'js*' will not match 'a.js'\n        // 'js/' will not match 'a.js'\n        // 'js' will match 'a.js' and 'a.js/'\n        (match) => /\\/$/.test(match) ? `${match}$` : `${match}(?=$|\\\\/$)`\n      ],\n      // trailing wildcard\n      [\n        /(\\^|\\\\\\/)?\\\\\\*$/,\n        (_, p1) => {\n          const prefix = p1 ? `${p1}[^/]+` : \"[^/]*\";\n          return `${prefix}(?=$|\\\\/$)`;\n        }\n      ]\n    ];\n    var regexCache = /* @__PURE__ */ Object.create(null);\n    var makeRegex = (pattern, ignoreCase) => {\n      let source = regexCache[pattern];\n      if (!source) {\n        source = REPLACERS.reduce(\n          (prev, [matcher, replacer]) => prev.replace(matcher, replacer.bind(pattern)),\n          pattern\n        );\n        regexCache[pattern] = source;\n      }\n      return ignoreCase ? new RegExp(source, \"i\") : new RegExp(source);\n    };\n    var isString = (subject) => typeof subject === \"string\";\n    var checkPattern = (pattern) => pattern && isString(pattern) && !REGEX_TEST_BLANK_LINE.test(pattern) && !REGEX_INVALID_TRAILING_BACKSLASH.test(pattern) && pattern.indexOf(\"#\") !== 0;\n    var splitPattern = (pattern) => pattern.split(REGEX_SPLITALL_CRLF);\n    var IgnoreRule = class {\n      constructor(origin, pattern, negative, regex) {\n        this.origin = origin;\n        this.pattern = pattern;\n        this.negative = negative;\n        this.regex = regex;\n      }\n    };\n    var createRule = (pattern, ignoreCase) => {\n      const origin = pattern;\n      let negative = false;\n      if (pattern.indexOf(\"!\") === 0) {\n        negative = true;\n        pattern = pattern.substr(1);\n      }\n      pattern = pattern.replace(REGEX_REPLACE_LEADING_EXCAPED_EXCLAMATION, \"!\").replace(REGEX_REPLACE_LEADING_EXCAPED_HASH, \"#\");\n      const regex = makeRegex(pattern, ignoreCase);\n      return new IgnoreRule(\n        origin,\n        pattern,\n        negative,\n        regex\n      );\n    };\n    var throwError = (message, Ctor) => {\n      throw new Ctor(message);\n    };\n    var checkPath = (path2, originalPath, doThrow) => {\n      if (!isString(path2)) {\n        return doThrow(\n          `path must be a string, but got \\`${originalPath}\\``,\n          TypeError\n        );\n      }\n      if (!path2) {\n        return doThrow(`path must not be empty`, TypeError);\n      }\n      if (checkPath.isNotRelative(path2)) {\n        const r = \"`path.relative()`d\";\n        return doThrow(\n          `path should be a ${r} string, but got \"${originalPath}\"`,\n          RangeError\n        );\n      }\n      return true;\n    };\n    var isNotRelative = (path2) => REGEX_TEST_INVALID_PATH.test(path2);\n    checkPath.isNotRelative = isNotRelative;\n    checkPath.convert = (p) => p;\n    var Ignore = class {\n      constructor({\n        ignorecase = true,\n        ignoreCase = ignorecase,\n        allowRelativePaths = false\n      } = {}) {\n        define2(this, KEY_IGNORE, true);\n        this._rules = [];\n        this._ignoreCase = ignoreCase;\n        this._allowRelativePaths = allowRelativePaths;\n        this._initCache();\n      }\n      _initCache() {\n        this._ignoreCache = /* @__PURE__ */ Object.create(null);\n        this._testCache = /* @__PURE__ */ Object.create(null);\n      }\n      _addPattern(pattern) {\n        if (pattern && pattern[KEY_IGNORE]) {\n          this._rules = this._rules.concat(pattern._rules);\n          this._added = true;\n          return;\n        }\n        if (checkPattern(pattern)) {\n          const rule = createRule(pattern, this._ignoreCase);\n          this._added = true;\n          this._rules.push(rule);\n        }\n      }\n      // @param {Array<string> | string | Ignore} pattern\n      add(pattern) {\n        this._added = false;\n        makeArray(\n          isString(pattern) ? splitPattern(pattern) : pattern\n        ).forEach(this._addPattern, this);\n        if (this._added) {\n          this._initCache();\n        }\n        return this;\n      }\n      // legacy\n      addPattern(pattern) {\n        return this.add(pattern);\n      }\n      //          |           ignored : unignored\n      // negative |   0:0   |   0:1   |   1:0   |   1:1\n      // -------- | ------- | ------- | ------- | --------\n      //     0    |  TEST   |  TEST   |  SKIP   |    X\n      //     1    |  TESTIF |  SKIP   |  TEST   |    X\n      // - SKIP: always skip\n      // - TEST: always test\n      // - TESTIF: only test if checkUnignored\n      // - X: that never happen\n      // @param {boolean} whether should check if the path is unignored,\n      //   setting `checkUnignored` to `false` could reduce additional\n      //   path matching.\n      // @returns {TestResult} true if a file is ignored\n      _testOne(path2, checkUnignored) {\n        let ignored = false;\n        let unignored = false;\n        this._rules.forEach((rule) => {\n          const { negative } = rule;\n          if (unignored === negative && ignored !== unignored || negative && !ignored && !unignored && !checkUnignored) {\n            return;\n          }\n          const matched = rule.regex.test(path2);\n          if (matched) {\n            ignored = !negative;\n            unignored = negative;\n          }\n        });\n        return {\n          ignored,\n          unignored\n        };\n      }\n      // @returns {TestResult}\n      _test(originalPath, cache, checkUnignored, slices) {\n        const path2 = originalPath && checkPath.convert(originalPath);\n        checkPath(\n          path2,\n          originalPath,\n          this._allowRelativePaths ? RETURN_FALSE : throwError\n        );\n        return this._t(path2, cache, checkUnignored, slices);\n      }\n      _t(path2, cache, checkUnignored, slices) {\n        if (path2 in cache) {\n          return cache[path2];\n        }\n        if (!slices) {\n          slices = path2.split(SLASH);\n        }\n        slices.pop();\n        if (!slices.length) {\n          return cache[path2] = this._testOne(path2, checkUnignored);\n        }\n        const parent = this._t(\n          slices.join(SLASH) + SLASH,\n          cache,\n          checkUnignored,\n          slices\n        );\n        return cache[path2] = parent.ignored ? parent : this._testOne(path2, checkUnignored);\n      }\n      ignores(path2) {\n        return this._test(path2, this._ignoreCache, false).ignored;\n      }\n      createFilter() {\n        return (path2) => !this.ignores(path2);\n      }\n      filter(paths) {\n        return makeArray(paths).filter(this.createFilter());\n      }\n      // @returns {TestResult}\n      test(path2) {\n        return this._test(path2, this._testCache, true);\n      }\n    };\n    var factory = (options) => new Ignore(options);\n    var isPathValid = (path2) => checkPath(path2 && checkPath.convert(path2), path2, RETURN_FALSE);\n    factory.isPathValid = isPathValid;\n    factory.default = factory;\n    module2.exports = factory;\n    if (\n      // Detect `process` so that it can run in browsers.\n      typeof process !== \"undefined\" && (process.env && process.env.IGNORE_TEST_WIN32 || process.platform === \"win32\")\n    ) {\n      const makePosix = (str) => /^\\\\\\\\\\?\\\\/.test(str) || /[\"<>|\\u0000-\\u001F]+/u.test(str) ? str : str.replace(/\\\\/g, \"/\");\n      checkPath.convert = makePosix;\n      const REGIX_IS_WINDOWS_PATH_ABSOLUTE = /^[a-z]:\\//i;\n      checkPath.isNotRelative = (path2) => REGIX_IS_WINDOWS_PATH_ABSOLUTE.test(path2) || isNotRelative(path2);\n    }\n  }\n});\n\n// node_modules/.pnpm/clean-git-ref@2.0.1/node_modules/clean-git-ref/lib/index.js\nvar require_lib2 = __commonJS({\n  \"node_modules/.pnpm/clean-git-ref@2.0.1/node_modules/clean-git-ref/lib/index.js\"(exports2, module2) {\n    \"use strict\";\n    function escapeRegExp(string) {\n      return string.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n    }\n    function replaceAll(str, search, replacement) {\n      search = search instanceof RegExp ? search : new RegExp(escapeRegExp(search), \"g\");\n      return str.replace(search, replacement);\n    }\n    var CleanGitRef = {\n      clean: function clean(value) {\n        if (typeof value !== \"string\") {\n          throw new Error(\"Expected a string, received: \" + value);\n        }\n        value = replaceAll(value, \"./\", \"/\");\n        value = replaceAll(value, \"..\", \".\");\n        value = replaceAll(value, \" \", \"-\");\n        value = replaceAll(value, /^[~^:?*\\\\\\-]/g, \"\");\n        value = replaceAll(value, /[~^:?*\\\\]/g, \"-\");\n        value = replaceAll(value, /[~^:?*\\\\\\-]$/g, \"\");\n        value = replaceAll(value, \"@{\", \"-\");\n        value = replaceAll(value, /\\.$/g, \"\");\n        value = replaceAll(value, /\\/$/g, \"\");\n        value = replaceAll(value, /\\.lock$/g, \"\");\n        return value;\n      }\n    };\n    module2.exports = CleanGitRef;\n  }\n});\n\n// node_modules/.pnpm/diff3@0.0.3/node_modules/diff3/onp.js\nvar require_onp = __commonJS({\n  \"node_modules/.pnpm/diff3@0.0.3/node_modules/diff3/onp.js\"(exports2, module2) {\n    module2.exports = function(a_, b_) {\n      var a = a_, b = b_, m = a.length, n = b.length, reverse = false, ed = null, offset = m + 1, path2 = [], pathposi = [], ses = [], lcs = \"\", SES_DELETE = -1, SES_COMMON = 0, SES_ADD = 1;\n      var tmp1, tmp2;\n      var init = function() {\n        if (m >= n) {\n          tmp1 = a;\n          tmp2 = m;\n          a = b;\n          b = tmp1;\n          m = n;\n          n = tmp2;\n          reverse = true;\n          offset = m + 1;\n        }\n      };\n      var P = function(x, y, k) {\n        return {\n          \"x\": x,\n          \"y\": y,\n          \"k\": k\n        };\n      };\n      var seselem = function(elem, t) {\n        return {\n          \"elem\": elem,\n          \"t\": t\n        };\n      };\n      var snake = function(k, p, pp) {\n        var r, x, y;\n        if (p > pp) {\n          r = path2[k - 1 + offset];\n        } else {\n          r = path2[k + 1 + offset];\n        }\n        y = Math.max(p, pp);\n        x = y - k;\n        while (x < m && y < n && a[x] === b[y]) {\n          ++x;\n          ++y;\n        }\n        path2[k + offset] = pathposi.length;\n        pathposi[pathposi.length] = new P(x, y, r);\n        return y;\n      };\n      var recordseq = function(epc) {\n        var x_idx, y_idx, px_idx, py_idx, i;\n        x_idx = y_idx = 1;\n        px_idx = py_idx = 0;\n        for (i = epc.length - 1; i >= 0; --i) {\n          while (px_idx < epc[i].x || py_idx < epc[i].y) {\n            if (epc[i].y - epc[i].x > py_idx - px_idx) {\n              if (reverse) {\n                ses[ses.length] = new seselem(b[py_idx], SES_DELETE);\n              } else {\n                ses[ses.length] = new seselem(b[py_idx], SES_ADD);\n              }\n              ++y_idx;\n              ++py_idx;\n            } else if (epc[i].y - epc[i].x < py_idx - px_idx) {\n              if (reverse) {\n                ses[ses.length] = new seselem(a[px_idx], SES_ADD);\n              } else {\n                ses[ses.length] = new seselem(a[px_idx], SES_DELETE);\n              }\n              ++x_idx;\n              ++px_idx;\n            } else {\n              ses[ses.length] = new seselem(a[px_idx], SES_COMMON);\n              lcs += a[px_idx];\n              ++x_idx;\n              ++y_idx;\n              ++px_idx;\n              ++py_idx;\n            }\n          }\n        }\n      };\n      init();\n      return {\n        SES_DELETE: -1,\n        SES_COMMON: 0,\n        SES_ADD: 1,\n        editdistance: function() {\n          return ed;\n        },\n        getlcs: function() {\n          return lcs;\n        },\n        getses: function() {\n          return ses;\n        },\n        compose: function() {\n          var delta, size, fp, p, r, epc, i, k;\n          delta = n - m;\n          size = m + n + 3;\n          fp = {};\n          for (i = 0; i < size; ++i) {\n            fp[i] = -1;\n            path2[i] = -1;\n          }\n          p = -1;\n          do {\n            ++p;\n            for (k = -p; k <= delta - 1; ++k) {\n              fp[k + offset] = snake(k, fp[k - 1 + offset] + 1, fp[k + 1 + offset]);\n            }\n            for (k = delta + p; k >= delta + 1; --k) {\n              fp[k + offset] = snake(k, fp[k - 1 + offset] + 1, fp[k + 1 + offset]);\n            }\n            fp[delta + offset] = snake(delta, fp[delta - 1 + offset] + 1, fp[delta + 1 + offset]);\n          } while (fp[delta + offset] !== n);\n          ed = delta + 2 * p;\n          r = path2[delta + offset];\n          epc = [];\n          while (r !== -1) {\n            epc[epc.length] = new P(pathposi[r].x, pathposi[r].y, null);\n            r = pathposi[r].k;\n          }\n          recordseq(epc);\n        }\n      };\n    };\n  }\n});\n\n// node_modules/.pnpm/diff3@0.0.3/node_modules/diff3/diff3.js\nvar require_diff3 = __commonJS({\n  \"node_modules/.pnpm/diff3@0.0.3/node_modules/diff3/diff3.js\"(exports2, module2) {\n    var onp = require_onp();\n    function longestCommonSubsequence(file1, file2) {\n      var diff3 = new onp(file1, file2);\n      diff3.compose();\n      var ses = diff3.getses();\n      var root;\n      var prev;\n      var file1RevIdx = file1.length - 1, file2RevIdx = file2.length - 1;\n      for (var i = ses.length - 1; i >= 0; --i) {\n        if (ses[i].t === diff3.SES_COMMON) {\n          if (prev) {\n            prev.chain = {\n              file1index: file1RevIdx,\n              file2index: file2RevIdx,\n              chain: null\n            };\n            prev = prev.chain;\n          } else {\n            root = {\n              file1index: file1RevIdx,\n              file2index: file2RevIdx,\n              chain: null\n            };\n            prev = root;\n          }\n          file1RevIdx--;\n          file2RevIdx--;\n        } else if (ses[i].t === diff3.SES_DELETE) {\n          file1RevIdx--;\n        } else if (ses[i].t === diff3.SES_ADD) {\n          file2RevIdx--;\n        }\n      }\n      var tail = {\n        file1index: -1,\n        file2index: -1,\n        chain: null\n      };\n      if (!prev) {\n        return tail;\n      }\n      prev.chain = tail;\n      return root;\n    }\n    function diffIndices(file1, file2) {\n      var result = [];\n      var tail1 = file1.length;\n      var tail2 = file2.length;\n      for (var candidate = longestCommonSubsequence(file1, file2); candidate !== null; candidate = candidate.chain) {\n        var mismatchLength1 = tail1 - candidate.file1index - 1;\n        var mismatchLength2 = tail2 - candidate.file2index - 1;\n        tail1 = candidate.file1index;\n        tail2 = candidate.file2index;\n        if (mismatchLength1 || mismatchLength2) {\n          result.push({\n            file1: [tail1 + 1, mismatchLength1],\n            file2: [tail2 + 1, mismatchLength2]\n          });\n        }\n      }\n      result.reverse();\n      return result;\n    }\n    function diff3MergeIndices(a, o, b) {\n      var i;\n      var m1 = diffIndices(o, a);\n      var m2 = diffIndices(o, b);\n      var hunks = [];\n      function addHunk(h, side2) {\n        hunks.push([h.file1[0], side2, h.file1[1], h.file2[0], h.file2[1]]);\n      }\n      for (i = 0; i < m1.length; i++) {\n        addHunk(m1[i], 0);\n      }\n      for (i = 0; i < m2.length; i++) {\n        addHunk(m2[i], 2);\n      }\n      hunks.sort(function(x, y) {\n        return x[0] - y[0];\n      });\n      var result = [];\n      var commonOffset = 0;\n      function copyCommon(targetOffset) {\n        if (targetOffset > commonOffset) {\n          result.push([1, commonOffset, targetOffset - commonOffset]);\n          commonOffset = targetOffset;\n        }\n      }\n      for (var hunkIndex = 0; hunkIndex < hunks.length; hunkIndex++) {\n        var firstHunkIndex = hunkIndex;\n        var hunk = hunks[hunkIndex];\n        var regionLhs = hunk[0];\n        var regionRhs = regionLhs + hunk[2];\n        while (hunkIndex < hunks.length - 1) {\n          var maybeOverlapping = hunks[hunkIndex + 1];\n          var maybeLhs = maybeOverlapping[0];\n          if (maybeLhs > regionRhs) break;\n          regionRhs = Math.max(regionRhs, maybeLhs + maybeOverlapping[2]);\n          hunkIndex++;\n        }\n        copyCommon(regionLhs);\n        if (firstHunkIndex == hunkIndex) {\n          if (hunk[4] > 0) {\n            result.push([hunk[1], hunk[3], hunk[4]]);\n          }\n        } else {\n          var regions = {\n            0: [a.length, -1, o.length, -1],\n            2: [b.length, -1, o.length, -1]\n          };\n          for (i = firstHunkIndex; i <= hunkIndex; i++) {\n            hunk = hunks[i];\n            var side = hunk[1];\n            var r = regions[side];\n            var oLhs = hunk[0];\n            var oRhs = oLhs + hunk[2];\n            var abLhs = hunk[3];\n            var abRhs = abLhs + hunk[4];\n            r[0] = Math.min(abLhs, r[0]);\n            r[1] = Math.max(abRhs, r[1]);\n            r[2] = Math.min(oLhs, r[2]);\n            r[3] = Math.max(oRhs, r[3]);\n          }\n          var aLhs = regions[0][0] + (regionLhs - regions[0][2]);\n          var aRhs = regions[0][1] + (regionRhs - regions[0][3]);\n          var bLhs = regions[2][0] + (regionLhs - regions[2][2]);\n          var bRhs = regions[2][1] + (regionRhs - regions[2][3]);\n          result.push([\n            -1,\n            aLhs,\n            aRhs - aLhs,\n            regionLhs,\n            regionRhs - regionLhs,\n            bLhs,\n            bRhs - bLhs\n          ]);\n        }\n        commonOffset = regionRhs;\n      }\n      copyCommon(o.length);\n      return result;\n    }\n    function diff3Merge(a, o, b) {\n      var result = [];\n      var files = [a, o, b];\n      var indices = diff3MergeIndices(a, o, b);\n      var okLines = [];\n      function flushOk() {\n        if (okLines.length) {\n          result.push({\n            ok: okLines\n          });\n        }\n        okLines = [];\n      }\n      function pushOk(xs) {\n        for (var j = 0; j < xs.length; j++) {\n          okLines.push(xs[j]);\n        }\n      }\n      function isTrueConflict(rec) {\n        if (rec[2] != rec[6]) return true;\n        var aoff = rec[1];\n        var boff = rec[5];\n        for (var j = 0; j < rec[2]; j++) {\n          if (a[j + aoff] != b[j + boff]) return true;\n        }\n        return false;\n      }\n      for (var i = 0; i < indices.length; i++) {\n        var x = indices[i];\n        var side = x[0];\n        if (side == -1) {\n          if (!isTrueConflict(x)) {\n            pushOk(files[0].slice(x[1], x[1] + x[2]));\n          } else {\n            flushOk();\n            result.push({\n              conflict: {\n                a: a.slice(x[1], x[1] + x[2]),\n                aIndex: x[1],\n                o: o.slice(x[3], x[3] + x[4]),\n                oIndex: x[3],\n                b: b.slice(x[5], x[5] + x[6]),\n                bIndex: x[5]\n              }\n            });\n          }\n        } else {\n          pushOk(files[side].slice(x[1], x[1] + x[2]));\n        }\n      }\n      flushOk();\n      return result;\n    }\n    module2.exports = diff3Merge;\n  }\n});\n\n// node_modules/.pnpm/isomorphic-git@1.27.1/node_modules/isomorphic-git/index.cjs\nvar require_isomorphic_git = __commonJS({\n  \"node_modules/.pnpm/isomorphic-git@1.27.1/node_modules/isomorphic-git/index.cjs\"(exports2) {\n    \"use strict\";\n    Object.defineProperty(exports2, \"__esModule\", { value: true });\n    function _interopDefault(ex) {\n      return ex && typeof ex === \"object\" && \"default\" in ex ? ex[\"default\"] : ex;\n    }\n    var AsyncLock = _interopDefault(require_async_lock());\n    var Hash = _interopDefault(require_sha1());\n    var crc32 = _interopDefault(require_crc32());\n    var pako = _interopDefault(require_pako());\n    var pify = _interopDefault(require_pify());\n    var ignore = _interopDefault(require_ignore());\n    var cleanGitRef = _interopDefault(require_lib2());\n    var diff3Merge = _interopDefault(require_diff3());\n    var BaseError = class _BaseError extends Error {\n      constructor(message) {\n        super(message);\n        this.caller = \"\";\n      }\n      toJSON() {\n        return {\n          code: this.code,\n          data: this.data,\n          caller: this.caller,\n          message: this.message,\n          stack: this.stack\n        };\n      }\n      fromJSON(json) {\n        const e = new _BaseError(json.message);\n        e.code = json.code;\n        e.data = json.data;\n        e.caller = json.caller;\n        e.stack = json.stack;\n        return e;\n      }\n      get isIsomorphicGitError() {\n        return true;\n      }\n    };\n    var UnmergedPathsError = class _UnmergedPathsError extends BaseError {\n      /**\n       * @param {Array<string>} filepaths\n       */\n      constructor(filepaths) {\n        super(\n          `Modifying the index is not possible because you have unmerged files: ${filepaths.toString}. Fix them up in the work tree, and then use 'git add/rm as appropriate to mark resolution and make a commit.`\n        );\n        this.code = this.name = _UnmergedPathsError.code;\n        this.data = { filepaths };\n      }\n    };\n    UnmergedPathsError.code = \"UnmergedPathsError\";\n    var InternalError = class _InternalError extends BaseError {\n      /**\n       * @param {string} message\n       */\n      constructor(message) {\n        super(\n          `An internal error caused this command to fail. Please file a bug report at https://github.com/isomorphic-git/isomorphic-git/issues with this error message: ${message}`\n        );\n        this.code = this.name = _InternalError.code;\n        this.data = { message };\n      }\n    };\n    InternalError.code = \"InternalError\";\n    var UnsafeFilepathError = class _UnsafeFilepathError extends BaseError {\n      /**\n       * @param {string} filepath\n       */\n      constructor(filepath) {\n        super(`The filepath \"${filepath}\" contains unsafe character sequences`);\n        this.code = this.name = _UnsafeFilepathError.code;\n        this.data = { filepath };\n      }\n    };\n    UnsafeFilepathError.code = \"UnsafeFilepathError\";\n    var BufferCursor = class {\n      constructor(buffer) {\n        this.buffer = buffer;\n        this._start = 0;\n      }\n      eof() {\n        return this._start >= this.buffer.length;\n      }\n      tell() {\n        return this._start;\n      }\n      seek(n) {\n        this._start = n;\n      }\n      slice(n) {\n        const r = this.buffer.slice(this._start, this._start + n);\n        this._start += n;\n        return r;\n      }\n      toString(enc, length) {\n        const r = this.buffer.toString(enc, this._start, this._start + length);\n        this._start += length;\n        return r;\n      }\n      write(value, length, enc) {\n        const r = this.buffer.write(value, this._start, length, enc);\n        this._start += length;\n        return r;\n      }\n      copy(source, start, end) {\n        const r = source.copy(this.buffer, this._start, start, end);\n        this._start += r;\n        return r;\n      }\n      readUInt8() {\n        const r = this.buffer.readUInt8(this._start);\n        this._start += 1;\n        return r;\n      }\n      writeUInt8(value) {\n        const r = this.buffer.writeUInt8(value, this._start);\n        this._start += 1;\n        return r;\n      }\n      readUInt16BE() {\n        const r = this.buffer.readUInt16BE(this._start);\n        this._start += 2;\n        return r;\n      }\n      writeUInt16BE(value) {\n        const r = this.buffer.writeUInt16BE(value, this._start);\n        this._start += 2;\n        return r;\n      }\n      readUInt32BE() {\n        const r = this.buffer.readUInt32BE(this._start);\n        this._start += 4;\n        return r;\n      }\n      writeUInt32BE(value) {\n        const r = this.buffer.writeUInt32BE(value, this._start);\n        this._start += 4;\n        return r;\n      }\n    };\n    function compareStrings(a, b) {\n      return -(a < b) || +(a > b);\n    }\n    function comparePath(a, b) {\n      return compareStrings(a.path, b.path);\n    }\n    function normalizeMode(mode) {\n      let type = mode > 0 ? mode >> 12 : 0;\n      if (type !== 4 && type !== 8 && type !== 10 && type !== 14) {\n        type = 8;\n      }\n      let permissions = mode & 511;\n      if (permissions & 73) {\n        permissions = 493;\n      } else {\n        permissions = 420;\n      }\n      if (type !== 8) permissions = 0;\n      return (type << 12) + permissions;\n    }\n    var MAX_UINT32 = 2 ** 32;\n    function SecondsNanoseconds(givenSeconds, givenNanoseconds, milliseconds, date) {\n      if (givenSeconds !== void 0 && givenNanoseconds !== void 0) {\n        return [givenSeconds, givenNanoseconds];\n      }\n      if (milliseconds === void 0) {\n        milliseconds = date.valueOf();\n      }\n      const seconds = Math.floor(milliseconds / 1e3);\n      const nanoseconds = (milliseconds - seconds * 1e3) * 1e6;\n      return [seconds, nanoseconds];\n    }\n    function normalizeStats(e) {\n      const [ctimeSeconds, ctimeNanoseconds] = SecondsNanoseconds(\n        e.ctimeSeconds,\n        e.ctimeNanoseconds,\n        e.ctimeMs,\n        e.ctime\n      );\n      const [mtimeSeconds, mtimeNanoseconds] = SecondsNanoseconds(\n        e.mtimeSeconds,\n        e.mtimeNanoseconds,\n        e.mtimeMs,\n        e.mtime\n      );\n      return {\n        ctimeSeconds: ctimeSeconds % MAX_UINT32,\n        ctimeNanoseconds: ctimeNanoseconds % MAX_UINT32,\n        mtimeSeconds: mtimeSeconds % MAX_UINT32,\n        mtimeNanoseconds: mtimeNanoseconds % MAX_UINT32,\n        dev: e.dev % MAX_UINT32,\n        ino: e.ino % MAX_UINT32,\n        mode: normalizeMode(e.mode % MAX_UINT32),\n        uid: e.uid % MAX_UINT32,\n        gid: e.gid % MAX_UINT32,\n        // size of -1 happens over a BrowserFS HTTP Backend that doesn't serve Content-Length headers\n        // (like the Karma webserver) because BrowserFS HTTP Backend uses HTTP HEAD requests to do fs.stat\n        size: e.size > -1 ? e.size % MAX_UINT32 : 0\n      };\n    }\n    function toHex(buffer) {\n      let hex = \"\";\n      for (const byte of new Uint8Array(buffer)) {\n        if (byte < 16) hex += \"0\";\n        hex += byte.toString(16);\n      }\n      return hex;\n    }\n    var supportsSubtleSHA1 = null;\n    async function shasum(buffer) {\n      if (supportsSubtleSHA1 === null) {\n        supportsSubtleSHA1 = await testSubtleSHA1();\n      }\n      return supportsSubtleSHA1 ? subtleSHA1(buffer) : shasumSync(buffer);\n    }\n    function shasumSync(buffer) {\n      return new Hash().update(buffer).digest(\"hex\");\n    }\n    async function subtleSHA1(buffer) {\n      const hash = await crypto.subtle.digest(\"SHA-1\", buffer);\n      return toHex(hash);\n    }\n    async function testSubtleSHA1() {\n      try {\n        const hash = await subtleSHA1(new Uint8Array([]));\n        if (hash === \"da39a3ee5e6b4b0d3255bfef95601890afd80709\") return true;\n      } catch (_) {\n      }\n      return false;\n    }\n    function parseCacheEntryFlags(bits) {\n      return {\n        assumeValid: Boolean(bits & 32768),\n        extended: Boolean(bits & 16384),\n        stage: (bits & 12288) >> 12,\n        nameLength: bits & 4095\n      };\n    }\n    function renderCacheEntryFlags(entry) {\n      const flags = entry.flags;\n      flags.extended = false;\n      flags.nameLength = Math.min(Buffer.from(entry.path).length, 4095);\n      return (flags.assumeValid ? 32768 : 0) + (flags.extended ? 16384 : 0) + ((flags.stage & 3) << 12) + (flags.nameLength & 4095);\n    }\n    var GitIndex = class _GitIndex {\n      /*::\n       _entries: Map<string, CacheEntry>\n       _dirty: boolean // Used to determine if index needs to be saved to filesystem\n       */\n      constructor(entries, unmergedPaths) {\n        this._dirty = false;\n        this._unmergedPaths = unmergedPaths || /* @__PURE__ */ new Set();\n        this._entries = entries || /* @__PURE__ */ new Map();\n      }\n      _addEntry(entry) {\n        if (entry.flags.stage === 0) {\n          entry.stages = [entry];\n          this._entries.set(entry.path, entry);\n          this._unmergedPaths.delete(entry.path);\n        } else {\n          let existingEntry = this._entries.get(entry.path);\n          if (!existingEntry) {\n            this._entries.set(entry.path, entry);\n            existingEntry = entry;\n          }\n          existingEntry.stages[entry.flags.stage] = entry;\n          this._unmergedPaths.add(entry.path);\n        }\n      }\n      static async from(buffer) {\n        if (Buffer.isBuffer(buffer)) {\n          return _GitIndex.fromBuffer(buffer);\n        } else if (buffer === null) {\n          return new _GitIndex(null);\n        } else {\n          throw new InternalError(\"invalid type passed to GitIndex.from\");\n        }\n      }\n      static async fromBuffer(buffer) {\n        if (buffer.length === 0) {\n          throw new InternalError(\"Index file is empty (.git/index)\");\n        }\n        const index2 = new _GitIndex();\n        const reader = new BufferCursor(buffer);\n        const magic = reader.toString(\"utf8\", 4);\n        if (magic !== \"DIRC\") {\n          throw new InternalError(`Invalid dircache magic file number: ${magic}`);\n        }\n        const shaComputed = await shasum(buffer.slice(0, -20));\n        const shaClaimed = buffer.slice(-20).toString(\"hex\");\n        if (shaClaimed !== shaComputed) {\n          throw new InternalError(\n            `Invalid checksum in GitIndex buffer: expected ${shaClaimed} but saw ${shaComputed}`\n          );\n        }\n        const version2 = reader.readUInt32BE();\n        if (version2 !== 2) {\n          throw new InternalError(`Unsupported dircache version: ${version2}`);\n        }\n        const numEntries = reader.readUInt32BE();\n        let i = 0;\n        while (!reader.eof() && i < numEntries) {\n          const entry = {};\n          entry.ctimeSeconds = reader.readUInt32BE();\n          entry.ctimeNanoseconds = reader.readUInt32BE();\n          entry.mtimeSeconds = reader.readUInt32BE();\n          entry.mtimeNanoseconds = reader.readUInt32BE();\n          entry.dev = reader.readUInt32BE();\n          entry.ino = reader.readUInt32BE();\n          entry.mode = reader.readUInt32BE();\n          entry.uid = reader.readUInt32BE();\n          entry.gid = reader.readUInt32BE();\n          entry.size = reader.readUInt32BE();\n          entry.oid = reader.slice(20).toString(\"hex\");\n          const flags = reader.readUInt16BE();\n          entry.flags = parseCacheEntryFlags(flags);\n          const pathlength = buffer.indexOf(0, reader.tell() + 1) - reader.tell();\n          if (pathlength < 1) {\n            throw new InternalError(`Got a path length of: ${pathlength}`);\n          }\n          entry.path = reader.toString(\"utf8\", pathlength);\n          if (entry.path.includes(\"..\\\\\") || entry.path.includes(\"../\")) {\n            throw new UnsafeFilepathError(entry.path);\n          }\n          let padding = 8 - (reader.tell() - 12) % 8;\n          if (padding === 0) padding = 8;\n          while (padding--) {\n            const tmp = reader.readUInt8();\n            if (tmp !== 0) {\n              throw new InternalError(\n                `Expected 1-8 null characters but got '${tmp}' after ${entry.path}`\n              );\n            } else if (reader.eof()) {\n              throw new InternalError(\"Unexpected end of file\");\n            }\n          }\n          entry.stages = [];\n          index2._addEntry(entry);\n          i++;\n        }\n        return index2;\n      }\n      get unmergedPaths() {\n        return [...this._unmergedPaths];\n      }\n      get entries() {\n        return [...this._entries.values()].sort(comparePath);\n      }\n      get entriesMap() {\n        return this._entries;\n      }\n      get entriesFlat() {\n        return [...this.entries].flatMap((entry) => {\n          return entry.stages.length > 1 ? entry.stages.filter((x) => x) : entry;\n        });\n      }\n      *[Symbol.iterator]() {\n        for (const entry of this.entries) {\n          yield entry;\n        }\n      }\n      insert({ filepath, stats, oid, stage: stage2 = 0 }) {\n        if (!stats) {\n          stats = {\n            ctimeSeconds: 0,\n            ctimeNanoseconds: 0,\n            mtimeSeconds: 0,\n            mtimeNanoseconds: 0,\n            dev: 0,\n            ino: 0,\n            mode: 0,\n            uid: 0,\n            gid: 0,\n            size: 0\n          };\n        }\n        stats = normalizeStats(stats);\n        const bfilepath = Buffer.from(filepath);\n        const entry = {\n          ctimeSeconds: stats.ctimeSeconds,\n          ctimeNanoseconds: stats.ctimeNanoseconds,\n          mtimeSeconds: stats.mtimeSeconds,\n          mtimeNanoseconds: stats.mtimeNanoseconds,\n          dev: stats.dev,\n          ino: stats.ino,\n          // We provide a fallback value for `mode` here because not all fs\n          // implementations assign it, but we use it in GitTree.\n          // '100644' is for a \"regular non-executable file\"\n          mode: stats.mode || 33188,\n          uid: stats.uid,\n          gid: stats.gid,\n          size: stats.size,\n          path: filepath,\n          oid,\n          flags: {\n            assumeValid: false,\n            extended: false,\n            stage: stage2,\n            nameLength: bfilepath.length < 4095 ? bfilepath.length : 4095\n          },\n          stages: []\n        };\n        this._addEntry(entry);\n        this._dirty = true;\n      }\n      delete({ filepath }) {\n        if (this._entries.has(filepath)) {\n          this._entries.delete(filepath);\n        } else {\n          for (const key of this._entries.keys()) {\n            if (key.startsWith(filepath + \"/\")) {\n              this._entries.delete(key);\n            }\n          }\n        }\n        if (this._unmergedPaths.has(filepath)) {\n          this._unmergedPaths.delete(filepath);\n        }\n        this._dirty = true;\n      }\n      clear() {\n        this._entries.clear();\n        this._dirty = true;\n      }\n      has({ filepath }) {\n        return this._entries.has(filepath);\n      }\n      render() {\n        return this.entries.map((entry) => `${entry.mode.toString(8)} ${entry.oid}    ${entry.path}`).join(\"\\n\");\n      }\n      static async _entryToBuffer(entry) {\n        const bpath = Buffer.from(entry.path);\n        const length = Math.ceil((62 + bpath.length + 1) / 8) * 8;\n        const written = Buffer.alloc(length);\n        const writer = new BufferCursor(written);\n        const stat = normalizeStats(entry);\n        writer.writeUInt32BE(stat.ctimeSeconds);\n        writer.writeUInt32BE(stat.ctimeNanoseconds);\n        writer.writeUInt32BE(stat.mtimeSeconds);\n        writer.writeUInt32BE(stat.mtimeNanoseconds);\n        writer.writeUInt32BE(stat.dev);\n        writer.writeUInt32BE(stat.ino);\n        writer.writeUInt32BE(stat.mode);\n        writer.writeUInt32BE(stat.uid);\n        writer.writeUInt32BE(stat.gid);\n        writer.writeUInt32BE(stat.size);\n        writer.write(entry.oid, 20, \"hex\");\n        writer.writeUInt16BE(renderCacheEntryFlags(entry));\n        writer.write(entry.path, bpath.length, \"utf8\");\n        return written;\n      }\n      async toObject() {\n        const header = Buffer.alloc(12);\n        const writer = new BufferCursor(header);\n        writer.write(\"DIRC\", 4, \"utf8\");\n        writer.writeUInt32BE(2);\n        writer.writeUInt32BE(this.entriesFlat.length);\n        let entryBuffers = [];\n        for (const entry of this.entries) {\n          entryBuffers.push(_GitIndex._entryToBuffer(entry));\n          if (entry.stages.length > 1) {\n            for (const stage2 of entry.stages) {\n              if (stage2 && stage2 !== entry) {\n                entryBuffers.push(_GitIndex._entryToBuffer(stage2));\n              }\n            }\n          }\n        }\n        entryBuffers = await Promise.all(entryBuffers);\n        const body = Buffer.concat(entryBuffers);\n        const main2 = Buffer.concat([header, body]);\n        const sum = await shasum(main2);\n        return Buffer.concat([main2, Buffer.from(sum, \"hex\")]);\n      }\n    };\n    function compareStats(entry, stats, filemode = true, trustino = true) {\n      const e = normalizeStats(entry);\n      const s = normalizeStats(stats);\n      const staleness = filemode && e.mode !== s.mode || e.mtimeSeconds !== s.mtimeSeconds || e.ctimeSeconds !== s.ctimeSeconds || e.uid !== s.uid || e.gid !== s.gid || trustino && e.ino !== s.ino || e.size !== s.size;\n      return staleness;\n    }\n    var lock = null;\n    var IndexCache = Symbol(\"IndexCache\");\n    function createCache() {\n      return {\n        map: /* @__PURE__ */ new Map(),\n        stats: /* @__PURE__ */ new Map()\n      };\n    }\n    async function updateCachedIndexFile(fs2, filepath, cache) {\n      const stat = await fs2.lstat(filepath);\n      const rawIndexFile = await fs2.read(filepath);\n      const index2 = await GitIndex.from(rawIndexFile);\n      cache.map.set(filepath, index2);\n      cache.stats.set(filepath, stat);\n    }\n    async function isIndexStale(fs2, filepath, cache) {\n      const savedStats = cache.stats.get(filepath);\n      if (savedStats === void 0) return true;\n      const currStats = await fs2.lstat(filepath);\n      if (savedStats === null) return false;\n      if (currStats === null) return false;\n      return compareStats(savedStats, currStats);\n    }\n    var GitIndexManager = class {\n      /**\n       *\n       * @param {object} opts\n       * @param {import('../models/FileSystem.js').FileSystem} opts.fs\n       * @param {string} opts.gitdir\n       * @param {object} opts.cache\n       * @param {bool} opts.allowUnmerged\n       * @param {function(GitIndex): any} closure\n       */\n      static async acquire({ fs: fs2, gitdir, cache, allowUnmerged = true }, closure) {\n        if (!cache[IndexCache]) cache[IndexCache] = createCache();\n        const filepath = `${gitdir}/index`;\n        if (lock === null) lock = new AsyncLock({ maxPending: Infinity });\n        let result;\n        let unmergedPaths = [];\n        await lock.acquire(filepath, async () => {\n          if (await isIndexStale(fs2, filepath, cache[IndexCache])) {\n            await updateCachedIndexFile(fs2, filepath, cache[IndexCache]);\n          }\n          const index2 = cache[IndexCache].map.get(filepath);\n          unmergedPaths = index2.unmergedPaths;\n          if (unmergedPaths.length && !allowUnmerged)\n            throw new UnmergedPathsError(unmergedPaths);\n          result = await closure(index2);\n          if (index2._dirty) {\n            const buffer = await index2.toObject();\n            await fs2.write(filepath, buffer);\n            cache[IndexCache].stats.set(filepath, await fs2.lstat(filepath));\n            index2._dirty = false;\n          }\n        });\n        return result;\n      }\n    };\n    function basename(path2) {\n      const last = Math.max(path2.lastIndexOf(\"/\"), path2.lastIndexOf(\"\\\\\"));\n      if (last > -1) {\n        path2 = path2.slice(last + 1);\n      }\n      return path2;\n    }\n    function dirname(path2) {\n      const last = Math.max(path2.lastIndexOf(\"/\"), path2.lastIndexOf(\"\\\\\"));\n      if (last === -1) return \".\";\n      if (last === 0) return \"/\";\n      return path2.slice(0, last);\n    }\n    function flatFileListToDirectoryStructure(files) {\n      const inodes = /* @__PURE__ */ new Map();\n      const mkdir = function(name) {\n        if (!inodes.has(name)) {\n          const dir = {\n            type: \"tree\",\n            fullpath: name,\n            basename: basename(name),\n            metadata: {},\n            children: []\n          };\n          inodes.set(name, dir);\n          dir.parent = mkdir(dirname(name));\n          if (dir.parent && dir.parent !== dir) dir.parent.children.push(dir);\n        }\n        return inodes.get(name);\n      };\n      const mkfile = function(name, metadata) {\n        if (!inodes.has(name)) {\n          const file = {\n            type: \"blob\",\n            fullpath: name,\n            basename: basename(name),\n            metadata,\n            // This recursively generates any missing parent folders.\n            parent: mkdir(dirname(name)),\n            children: []\n          };\n          if (file.parent) file.parent.children.push(file);\n          inodes.set(name, file);\n        }\n        return inodes.get(name);\n      };\n      mkdir(\".\");\n      for (const file of files) {\n        mkfile(file.path, file);\n      }\n      return inodes;\n    }\n    function mode2type(mode) {\n      switch (mode) {\n        case 16384:\n          return \"tree\";\n        case 33188:\n          return \"blob\";\n        case 33261:\n          return \"blob\";\n        case 40960:\n          return \"blob\";\n        case 57344:\n          return \"commit\";\n      }\n      throw new InternalError(`Unexpected GitTree entry mode: ${mode.toString(8)}`);\n    }\n    var GitWalkerIndex = class {\n      constructor({ fs: fs2, gitdir, cache }) {\n        this.treePromise = GitIndexManager.acquire(\n          { fs: fs2, gitdir, cache },\n          async function(index2) {\n            return flatFileListToDirectoryStructure(index2.entries);\n          }\n        );\n        const walker = this;\n        this.ConstructEntry = class StageEntry {\n          constructor(fullpath) {\n            this._fullpath = fullpath;\n            this._type = false;\n            this._mode = false;\n            this._stat = false;\n            this._oid = false;\n          }\n          async type() {\n            return walker.type(this);\n          }\n          async mode() {\n            return walker.mode(this);\n          }\n          async stat() {\n            return walker.stat(this);\n          }\n          async content() {\n            return walker.content(this);\n          }\n          async oid() {\n            return walker.oid(this);\n          }\n        };\n      }\n      async readdir(entry) {\n        const filepath = entry._fullpath;\n        const tree = await this.treePromise;\n        const inode = tree.get(filepath);\n        if (!inode) return null;\n        if (inode.type === \"blob\") return null;\n        if (inode.type !== \"tree\") {\n          throw new Error(`ENOTDIR: not a directory, scandir '${filepath}'`);\n        }\n        const names = inode.children.map((inode2) => inode2.fullpath);\n        names.sort(compareStrings);\n        return names;\n      }\n      async type(entry) {\n        if (entry._type === false) {\n          await entry.stat();\n        }\n        return entry._type;\n      }\n      async mode(entry) {\n        if (entry._mode === false) {\n          await entry.stat();\n        }\n        return entry._mode;\n      }\n      async stat(entry) {\n        if (entry._stat === false) {\n          const tree = await this.treePromise;\n          const inode = tree.get(entry._fullpath);\n          if (!inode) {\n            throw new Error(\n              `ENOENT: no such file or directory, lstat '${entry._fullpath}'`\n            );\n          }\n          const stats = inode.type === \"tree\" ? {} : normalizeStats(inode.metadata);\n          entry._type = inode.type === \"tree\" ? \"tree\" : mode2type(stats.mode);\n          entry._mode = stats.mode;\n          if (inode.type === \"tree\") {\n            entry._stat = void 0;\n          } else {\n            entry._stat = stats;\n          }\n        }\n        return entry._stat;\n      }\n      async content(_entry) {\n      }\n      async oid(entry) {\n        if (entry._oid === false) {\n          const tree = await this.treePromise;\n          const inode = tree.get(entry._fullpath);\n          entry._oid = inode.metadata.oid;\n        }\n        return entry._oid;\n      }\n    };\n    var GitWalkSymbol = Symbol(\"GitWalkSymbol\");\n    function STAGE() {\n      const o = /* @__PURE__ */ Object.create(null);\n      Object.defineProperty(o, GitWalkSymbol, {\n        value: function({ fs: fs2, gitdir, cache }) {\n          return new GitWalkerIndex({ fs: fs2, gitdir, cache });\n        }\n      });\n      Object.freeze(o);\n      return o;\n    }\n    var NotFoundError = class _NotFoundError extends BaseError {\n      /**\n       * @param {string} what\n       */\n      constructor(what) {\n        super(`Could not find ${what}.`);\n        this.code = this.name = _NotFoundError.code;\n        this.data = { what };\n      }\n    };\n    NotFoundError.code = \"NotFoundError\";\n    var ObjectTypeError = class _ObjectTypeError extends BaseError {\n      /**\n       * @param {string} oid\n       * @param {'blob'|'commit'|'tag'|'tree'} actual\n       * @param {'blob'|'commit'|'tag'|'tree'} expected\n       * @param {string} [filepath]\n       */\n      constructor(oid, actual, expected, filepath) {\n        super(\n          `Object ${oid} ${filepath ? `at ${filepath}` : \"\"}was anticipated to be a ${expected} but it is a ${actual}.`\n        );\n        this.code = this.name = _ObjectTypeError.code;\n        this.data = { oid, actual, expected, filepath };\n      }\n    };\n    ObjectTypeError.code = \"ObjectTypeError\";\n    var InvalidOidError = class _InvalidOidError extends BaseError {\n      /**\n       * @param {string} value\n       */\n      constructor(value) {\n        super(`Expected a 40-char hex object id but saw \"${value}\".`);\n        this.code = this.name = _InvalidOidError.code;\n        this.data = { value };\n      }\n    };\n    InvalidOidError.code = \"InvalidOidError\";\n    var NoRefspecError = class _NoRefspecError extends BaseError {\n      /**\n       * @param {string} remote\n       */\n      constructor(remote) {\n        super(`Could not find a fetch refspec for remote \"${remote}\". Make sure the config file has an entry like the following:\n[remote \"${remote}\"]\n\tfetch = +refs/heads/*:refs/remotes/origin/*\n`);\n        this.code = this.name = _NoRefspecError.code;\n        this.data = { remote };\n      }\n    };\n    NoRefspecError.code = \"NoRefspecError\";\n    var GitPackedRefs = class _GitPackedRefs {\n      constructor(text) {\n        this.refs = /* @__PURE__ */ new Map();\n        this.parsedConfig = [];\n        if (text) {\n          let key = null;\n          this.parsedConfig = text.trim().split(\"\\n\").map((line) => {\n            if (/^\\s*#/.test(line)) {\n              return { line, comment: true };\n            }\n            const i = line.indexOf(\" \");\n            if (line.startsWith(\"^\")) {\n              const value = line.slice(1);\n              this.refs.set(key + \"^{}\", value);\n              return { line, ref: key, peeled: value };\n            } else {\n              const value = line.slice(0, i);\n              key = line.slice(i + 1);\n              this.refs.set(key, value);\n              return { line, ref: key, oid: value };\n            }\n          });\n        }\n        return this;\n      }\n      static from(text) {\n        return new _GitPackedRefs(text);\n      }\n      delete(ref) {\n        this.parsedConfig = this.parsedConfig.filter((entry) => entry.ref !== ref);\n        this.refs.delete(ref);\n      }\n      toString() {\n        return this.parsedConfig.map(({ line }) => line).join(\"\\n\") + \"\\n\";\n      }\n    };\n    var GitRefSpec = class _GitRefSpec {\n      constructor({ remotePath, localPath, force, matchPrefix }) {\n        Object.assign(this, {\n          remotePath,\n          localPath,\n          force,\n          matchPrefix\n        });\n      }\n      static from(refspec) {\n        const [\n          forceMatch,\n          remotePath,\n          remoteGlobMatch,\n          localPath,\n          localGlobMatch\n        ] = refspec.match(/^(\\+?)(.*?)(\\*?):(.*?)(\\*?)$/).slice(1);\n        const force = forceMatch === \"+\";\n        const remoteIsGlob = remoteGlobMatch === \"*\";\n        const localIsGlob = localGlobMatch === \"*\";\n        if (remoteIsGlob !== localIsGlob) {\n          throw new InternalError(\"Invalid refspec\");\n        }\n        return new _GitRefSpec({\n          remotePath,\n          localPath,\n          force,\n          matchPrefix: remoteIsGlob\n        });\n      }\n      translate(remoteBranch) {\n        if (this.matchPrefix) {\n          if (remoteBranch.startsWith(this.remotePath)) {\n            return this.localPath + remoteBranch.replace(this.remotePath, \"\");\n          }\n        } else {\n          if (remoteBranch === this.remotePath) return this.localPath;\n        }\n        return null;\n      }\n      reverseTranslate(localBranch) {\n        if (this.matchPrefix) {\n          if (localBranch.startsWith(this.localPath)) {\n            return this.remotePath + localBranch.replace(this.localPath, \"\");\n          }\n        } else {\n          if (localBranch === this.localPath) return this.remotePath;\n        }\n        return null;\n      }\n    };\n    var GitRefSpecSet = class _GitRefSpecSet {\n      constructor(rules = []) {\n        this.rules = rules;\n      }\n      static from(refspecs) {\n        const rules = [];\n        for (const refspec of refspecs) {\n          rules.push(GitRefSpec.from(refspec));\n        }\n        return new _GitRefSpecSet(rules);\n      }\n      add(refspec) {\n        const rule = GitRefSpec.from(refspec);\n        this.rules.push(rule);\n      }\n      translate(remoteRefs) {\n        const result = [];\n        for (const rule of this.rules) {\n          for (const remoteRef of remoteRefs) {\n            const localRef = rule.translate(remoteRef);\n            if (localRef) {\n              result.push([remoteRef, localRef]);\n            }\n          }\n        }\n        return result;\n      }\n      translateOne(remoteRef) {\n        let result = null;\n        for (const rule of this.rules) {\n          const localRef = rule.translate(remoteRef);\n          if (localRef) {\n            result = localRef;\n          }\n        }\n        return result;\n      }\n      localNamespaces() {\n        return this.rules.filter((rule) => rule.matchPrefix).map((rule) => rule.localPath.replace(/\\/$/, \"\"));\n      }\n    };\n    function compareRefNames(a, b) {\n      const _a = a.replace(/\\^\\{\\}$/, \"\");\n      const _b = b.replace(/\\^\\{\\}$/, \"\");\n      const tmp = -(_a < _b) || +(_a > _b);\n      if (tmp === 0) {\n        return a.endsWith(\"^{}\") ? 1 : -1;\n      }\n      return tmp;\n    }\n    var memo = /* @__PURE__ */ new Map();\n    function normalizePath(path2) {\n      let normalizedPath = memo.get(path2);\n      if (!normalizedPath) {\n        normalizedPath = normalizePathInternal(path2);\n        memo.set(path2, normalizedPath);\n      }\n      return normalizedPath;\n    }\n    function normalizePathInternal(path2) {\n      path2 = path2.split(\"/./\").join(\"/\").replace(/\\/{2,}/g, \"/\");\n      if (path2 === \"/.\") return \"/\";\n      if (path2 === \"./\") return \".\";\n      if (path2.startsWith(\"./\")) path2 = path2.slice(2);\n      if (path2.endsWith(\"/.\")) path2 = path2.slice(0, -2);\n      if (path2.length > 1 && path2.endsWith(\"/\")) path2 = path2.slice(0, -1);\n      if (path2 === \"\") return \".\";\n      return path2;\n    }\n    function join2(...parts) {\n      return normalizePath(parts.map(normalizePath).join(\"/\"));\n    }\n    var num = (val) => {\n      val = val.toLowerCase();\n      let n = parseInt(val);\n      if (val.endsWith(\"k\")) n *= 1024;\n      if (val.endsWith(\"m\")) n *= 1024 * 1024;\n      if (val.endsWith(\"g\")) n *= 1024 * 1024 * 1024;\n      return n;\n    };\n    var bool = (val) => {\n      val = val.trim().toLowerCase();\n      if (val === \"true\" || val === \"yes\" || val === \"on\") return true;\n      if (val === \"false\" || val === \"no\" || val === \"off\") return false;\n      throw Error(\n        `Expected 'true', 'false', 'yes', 'no', 'on', or 'off', but got ${val}`\n      );\n    };\n    var schema = {\n      core: {\n        filemode: bool,\n        bare: bool,\n        logallrefupdates: bool,\n        symlinks: bool,\n        ignorecase: bool,\n        bigFileThreshold: num\n      }\n    };\n    var SECTION_LINE_REGEX = /^\\[([A-Za-z0-9-.]+)(?: \"(.*)\")?\\]$/;\n    var SECTION_REGEX = /^[A-Za-z0-9-.]+$/;\n    var VARIABLE_LINE_REGEX = /^([A-Za-z][A-Za-z-]*)(?: *= *(.*))?$/;\n    var VARIABLE_NAME_REGEX = /^[A-Za-z][A-Za-z-]*$/;\n    var VARIABLE_VALUE_COMMENT_REGEX = /^(.*?)( *[#;].*)$/;\n    var extractSectionLine = (line) => {\n      const matches = SECTION_LINE_REGEX.exec(line);\n      if (matches != null) {\n        const [section, subsection] = matches.slice(1);\n        return [section, subsection];\n      }\n      return null;\n    };\n    var extractVariableLine = (line) => {\n      const matches = VARIABLE_LINE_REGEX.exec(line);\n      if (matches != null) {\n        const [name, rawValue = \"true\"] = matches.slice(1);\n        const valueWithoutComments = removeComments(rawValue);\n        const valueWithoutQuotes = removeQuotes(valueWithoutComments);\n        return [name, valueWithoutQuotes];\n      }\n      return null;\n    };\n    var removeComments = (rawValue) => {\n      const commentMatches = VARIABLE_VALUE_COMMENT_REGEX.exec(rawValue);\n      if (commentMatches == null) {\n        return rawValue;\n      }\n      const [valueWithoutComment, comment] = commentMatches.slice(1);\n      if (hasOddNumberOfQuotes(valueWithoutComment) && hasOddNumberOfQuotes(comment)) {\n        return `${valueWithoutComment}${comment}`;\n      }\n      return valueWithoutComment;\n    };\n    var hasOddNumberOfQuotes = (text) => {\n      const numberOfQuotes = (text.match(/(?:^|[^\\\\])\"/g) || []).length;\n      return numberOfQuotes % 2 !== 0;\n    };\n    var removeQuotes = (text) => {\n      return text.split(\"\").reduce((newText, c, idx, text2) => {\n        const isQuote = c === '\"' && text2[idx - 1] !== \"\\\\\";\n        const isEscapeForQuote = c === \"\\\\\" && text2[idx + 1] === '\"';\n        if (isQuote || isEscapeForQuote) {\n          return newText;\n        }\n        return newText + c;\n      }, \"\");\n    };\n    var lower = (text) => {\n      return text != null ? text.toLowerCase() : null;\n    };\n    var getPath = (section, subsection, name) => {\n      return [lower(section), subsection, lower(name)].filter((a) => a != null).join(\".\");\n    };\n    var normalizePath$1 = (path2) => {\n      const pathSegments = path2.split(\".\");\n      const section = pathSegments.shift();\n      const name = pathSegments.pop();\n      const subsection = pathSegments.length ? pathSegments.join(\".\") : void 0;\n      return {\n        section,\n        subsection,\n        name,\n        path: getPath(section, subsection, name),\n        sectionPath: getPath(section, subsection, null)\n      };\n    };\n    var findLastIndex = (array, callback) => {\n      return array.reduce((lastIndex, item, index2) => {\n        return callback(item) ? index2 : lastIndex;\n      }, -1);\n    };\n    var GitConfig = class _GitConfig {\n      constructor(text) {\n        let section = null;\n        let subsection = null;\n        this.parsedConfig = text ? text.split(\"\\n\").map((line) => {\n          let name = null;\n          let value = null;\n          const trimmedLine = line.trim();\n          const extractedSection = extractSectionLine(trimmedLine);\n          const isSection = extractedSection != null;\n          if (isSection) {\n            ;\n            [section, subsection] = extractedSection;\n          } else {\n            const extractedVariable = extractVariableLine(trimmedLine);\n            const isVariable = extractedVariable != null;\n            if (isVariable) {\n              ;\n              [name, value] = extractedVariable;\n            }\n          }\n          const path2 = getPath(section, subsection, name);\n          return { line, isSection, section, subsection, name, value, path: path2 };\n        }) : [];\n      }\n      static from(text) {\n        return new _GitConfig(text);\n      }\n      async get(path2, getall = false) {\n        const normalizedPath = normalizePath$1(path2).path;\n        const allValues = this.parsedConfig.filter((config) => config.path === normalizedPath).map(({ section, name, value }) => {\n          const fn = schema[section] && schema[section][name];\n          return fn ? fn(value) : value;\n        });\n        return getall ? allValues : allValues.pop();\n      }\n      async getall(path2) {\n        return this.get(path2, true);\n      }\n      async getSubsections(section) {\n        return this.parsedConfig.filter((config) => config.section === section && config.isSection).map((config) => config.subsection);\n      }\n      async deleteSection(section, subsection) {\n        this.parsedConfig = this.parsedConfig.filter(\n          (config) => !(config.section === section && config.subsection === subsection)\n        );\n      }\n      async append(path2, value) {\n        return this.set(path2, value, true);\n      }\n      async set(path2, value, append = false) {\n        const {\n          section,\n          subsection,\n          name,\n          path: normalizedPath,\n          sectionPath\n        } = normalizePath$1(path2);\n        const configIndex = findLastIndex(\n          this.parsedConfig,\n          (config) => config.path === normalizedPath\n        );\n        if (value == null) {\n          if (configIndex !== -1) {\n            this.parsedConfig.splice(configIndex, 1);\n          }\n        } else {\n          if (configIndex !== -1) {\n            const config = this.parsedConfig[configIndex];\n            const modifiedConfig = Object.assign({}, config, {\n              name,\n              value,\n              modified: true\n            });\n            if (append) {\n              this.parsedConfig.splice(configIndex + 1, 0, modifiedConfig);\n            } else {\n              this.parsedConfig[configIndex] = modifiedConfig;\n            }\n          } else {\n            const sectionIndex = this.parsedConfig.findIndex(\n              (config) => config.path === sectionPath\n            );\n            const newConfig = {\n              section,\n              subsection,\n              name,\n              value,\n              modified: true,\n              path: normalizedPath\n            };\n            if (SECTION_REGEX.test(section) && VARIABLE_NAME_REGEX.test(name)) {\n              if (sectionIndex >= 0) {\n                this.parsedConfig.splice(sectionIndex + 1, 0, newConfig);\n              } else {\n                const newSection = {\n                  section,\n                  subsection,\n                  modified: true,\n                  path: sectionPath\n                };\n                this.parsedConfig.push(newSection, newConfig);\n              }\n            }\n          }\n        }\n      }\n      toString() {\n        return this.parsedConfig.map(({ line, section, subsection, name, value, modified: modified2 = false }) => {\n          if (!modified2) {\n            return line;\n          }\n          if (name != null && value != null) {\n            if (typeof value === \"string\" && /[#;]/.test(value)) {\n              return `\t${name} = \"${value}\"`;\n            }\n            return `\t${name} = ${value}`;\n          }\n          if (subsection != null) {\n            return `[${section} \"${subsection}\"]`;\n          }\n          return `[${section}]`;\n        }).join(\"\\n\");\n      }\n    };\n    var GitConfigManager = class {\n      static async get({ fs: fs2, gitdir }) {\n        const text = await fs2.read(`${gitdir}/config`, { encoding: \"utf8\" });\n        return GitConfig.from(text);\n      }\n      static async save({ fs: fs2, gitdir, config }) {\n        await fs2.write(`${gitdir}/config`, config.toString(), {\n          encoding: \"utf8\"\n        });\n      }\n    };\n    var refpaths = (ref) => [\n      `${ref}`,\n      `refs/${ref}`,\n      `refs/tags/${ref}`,\n      `refs/heads/${ref}`,\n      `refs/remotes/${ref}`,\n      `refs/remotes/${ref}/HEAD`\n    ];\n    var GIT_FILES = [\"config\", \"description\", \"index\", \"shallow\", \"commondir\"];\n    var lock$1;\n    async function acquireLock(ref, callback) {\n      if (lock$1 === void 0) lock$1 = new AsyncLock();\n      return lock$1.acquire(ref, callback);\n    }\n    var GitRefManager = class _GitRefManager {\n      static async updateRemoteRefs({\n        fs: fs2,\n        gitdir,\n        remote,\n        refs,\n        symrefs,\n        tags,\n        refspecs = void 0,\n        prune = false,\n        pruneTags = false\n      }) {\n        for (const value of refs.values()) {\n          if (!value.match(/[0-9a-f]{40}/)) {\n            throw new InvalidOidError(value);\n          }\n        }\n        const config = await GitConfigManager.get({ fs: fs2, gitdir });\n        if (!refspecs) {\n          refspecs = await config.getall(`remote.${remote}.fetch`);\n          if (refspecs.length === 0) {\n            throw new NoRefspecError(remote);\n          }\n          refspecs.unshift(`+HEAD:refs/remotes/${remote}/HEAD`);\n        }\n        const refspec = GitRefSpecSet.from(refspecs);\n        const actualRefsToWrite = /* @__PURE__ */ new Map();\n        if (pruneTags) {\n          const tags2 = await _GitRefManager.listRefs({\n            fs: fs2,\n            gitdir,\n            filepath: \"refs/tags\"\n          });\n          await _GitRefManager.deleteRefs({\n            fs: fs2,\n            gitdir,\n            refs: tags2.map((tag2) => `refs/tags/${tag2}`)\n          });\n        }\n        if (tags) {\n          for (const serverRef of refs.keys()) {\n            if (serverRef.startsWith(\"refs/tags\") && !serverRef.endsWith(\"^{}\")) {\n              if (!await _GitRefManager.exists({ fs: fs2, gitdir, ref: serverRef })) {\n                const oid = refs.get(serverRef);\n                actualRefsToWrite.set(serverRef, oid);\n              }\n            }\n          }\n        }\n        const refTranslations = refspec.translate([...refs.keys()]);\n        for (const [serverRef, translatedRef] of refTranslations) {\n          const value = refs.get(serverRef);\n          actualRefsToWrite.set(translatedRef, value);\n        }\n        const symrefTranslations = refspec.translate([...symrefs.keys()]);\n        for (const [serverRef, translatedRef] of symrefTranslations) {\n          const value = symrefs.get(serverRef);\n          const symtarget = refspec.translateOne(value);\n          if (symtarget) {\n            actualRefsToWrite.set(translatedRef, `ref: ${symtarget}`);\n          }\n        }\n        const pruned = [];\n        if (prune) {\n          for (const filepath of refspec.localNamespaces()) {\n            const refs2 = (await _GitRefManager.listRefs({\n              fs: fs2,\n              gitdir,\n              filepath\n            })).map((file) => `${filepath}/${file}`);\n            for (const ref of refs2) {\n              if (!actualRefsToWrite.has(ref)) {\n                pruned.push(ref);\n              }\n            }\n          }\n          if (pruned.length > 0) {\n            await _GitRefManager.deleteRefs({ fs: fs2, gitdir, refs: pruned });\n          }\n        }\n        for (const [key, value] of actualRefsToWrite) {\n          await acquireLock(\n            key,\n            async () => fs2.write(join2(gitdir, key), `${value.trim()}\n`, \"utf8\")\n          );\n        }\n        return { pruned };\n      }\n      // TODO: make this less crude?\n      static async writeRef({ fs: fs2, gitdir, ref, value }) {\n        if (!value.match(/[0-9a-f]{40}/)) {\n          throw new InvalidOidError(value);\n        }\n        await acquireLock(\n          ref,\n          async () => fs2.write(join2(gitdir, ref), `${value.trim()}\n`, \"utf8\")\n        );\n      }\n      static async writeSymbolicRef({ fs: fs2, gitdir, ref, value }) {\n        await acquireLock(\n          ref,\n          async () => fs2.write(join2(gitdir, ref), `ref: ${value.trim()}\n`, \"utf8\")\n        );\n      }\n      static async deleteRef({ fs: fs2, gitdir, ref }) {\n        return _GitRefManager.deleteRefs({ fs: fs2, gitdir, refs: [ref] });\n      }\n      static async deleteRefs({ fs: fs2, gitdir, refs }) {\n        await Promise.all(refs.map((ref) => fs2.rm(join2(gitdir, ref))));\n        let text = await acquireLock(\n          \"packed-refs\",\n          async () => fs2.read(`${gitdir}/packed-refs`, { encoding: \"utf8\" })\n        );\n        const packed = GitPackedRefs.from(text);\n        const beforeSize = packed.refs.size;\n        for (const ref of refs) {\n          if (packed.refs.has(ref)) {\n            packed.delete(ref);\n          }\n        }\n        if (packed.refs.size < beforeSize) {\n          text = packed.toString();\n          await acquireLock(\n            \"packed-refs\",\n            async () => fs2.write(`${gitdir}/packed-refs`, text, { encoding: \"utf8\" })\n          );\n        }\n      }\n      /**\n       * @param {object} args\n       * @param {import('../models/FileSystem.js').FileSystem} args.fs\n       * @param {string} args.gitdir\n       * @param {string} args.ref\n       * @param {number} [args.depth]\n       * @returns {Promise<string>}\n       */\n      static async resolve({ fs: fs2, gitdir, ref, depth = void 0 }) {\n        if (depth !== void 0) {\n          depth--;\n          if (depth === -1) {\n            return ref;\n          }\n        }\n        if (ref.startsWith(\"ref: \")) {\n          ref = ref.slice(\"ref: \".length);\n          return _GitRefManager.resolve({ fs: fs2, gitdir, ref, depth });\n        }\n        if (ref.length === 40 && /[0-9a-f]{40}/.test(ref)) {\n          return ref;\n        }\n        const packedMap = await _GitRefManager.packedRefs({ fs: fs2, gitdir });\n        const allpaths = refpaths(ref).filter((p) => !GIT_FILES.includes(p));\n        for (const ref2 of allpaths) {\n          const sha = await acquireLock(\n            ref2,\n            async () => await fs2.read(`${gitdir}/${ref2}`, { encoding: \"utf8\" }) || packedMap.get(ref2)\n          );\n          if (sha) {\n            return _GitRefManager.resolve({ fs: fs2, gitdir, ref: sha.trim(), depth });\n          }\n        }\n        throw new NotFoundError(ref);\n      }\n      static async exists({ fs: fs2, gitdir, ref }) {\n        try {\n          await _GitRefManager.expand({ fs: fs2, gitdir, ref });\n          return true;\n        } catch (err) {\n          return false;\n        }\n      }\n      static async expand({ fs: fs2, gitdir, ref }) {\n        if (ref.length === 40 && /[0-9a-f]{40}/.test(ref)) {\n          return ref;\n        }\n        const packedMap = await _GitRefManager.packedRefs({ fs: fs2, gitdir });\n        const allpaths = refpaths(ref);\n        for (const ref2 of allpaths) {\n          const refExists = await acquireLock(\n            ref2,\n            async () => fs2.exists(`${gitdir}/${ref2}`)\n          );\n          if (refExists) return ref2;\n          if (packedMap.has(ref2)) return ref2;\n        }\n        throw new NotFoundError(ref);\n      }\n      static async expandAgainstMap({ ref, map }) {\n        const allpaths = refpaths(ref);\n        for (const ref2 of allpaths) {\n          if (await map.has(ref2)) return ref2;\n        }\n        throw new NotFoundError(ref);\n      }\n      static resolveAgainstMap({ ref, fullref = ref, depth = void 0, map }) {\n        if (depth !== void 0) {\n          depth--;\n          if (depth === -1) {\n            return { fullref, oid: ref };\n          }\n        }\n        if (ref.startsWith(\"ref: \")) {\n          ref = ref.slice(\"ref: \".length);\n          return _GitRefManager.resolveAgainstMap({ ref, fullref, depth, map });\n        }\n        if (ref.length === 40 && /[0-9a-f]{40}/.test(ref)) {\n          return { fullref, oid: ref };\n        }\n        const allpaths = refpaths(ref);\n        for (const ref2 of allpaths) {\n          const sha = map.get(ref2);\n          if (sha) {\n            return _GitRefManager.resolveAgainstMap({\n              ref: sha.trim(),\n              fullref: ref2,\n              depth,\n              map\n            });\n          }\n        }\n        throw new NotFoundError(ref);\n      }\n      static async packedRefs({ fs: fs2, gitdir }) {\n        const text = await acquireLock(\n          \"packed-refs\",\n          async () => fs2.read(`${gitdir}/packed-refs`, { encoding: \"utf8\" })\n        );\n        const packed = GitPackedRefs.from(text);\n        return packed.refs;\n      }\n      // List all the refs that match the `filepath` prefix\n      static async listRefs({ fs: fs2, gitdir, filepath }) {\n        const packedMap = _GitRefManager.packedRefs({ fs: fs2, gitdir });\n        let files = null;\n        try {\n          files = await fs2.readdirDeep(`${gitdir}/${filepath}`);\n          files = files.map((x) => x.replace(`${gitdir}/${filepath}/`, \"\"));\n        } catch (err) {\n          files = [];\n        }\n        for (let key of (await packedMap).keys()) {\n          if (key.startsWith(filepath)) {\n            key = key.replace(filepath + \"/\", \"\");\n            if (!files.includes(key)) {\n              files.push(key);\n            }\n          }\n        }\n        files.sort(compareRefNames);\n        return files;\n      }\n      static async listBranches({ fs: fs2, gitdir, remote }) {\n        if (remote) {\n          return _GitRefManager.listRefs({\n            fs: fs2,\n            gitdir,\n            filepath: `refs/remotes/${remote}`\n          });\n        } else {\n          return _GitRefManager.listRefs({ fs: fs2, gitdir, filepath: `refs/heads` });\n        }\n      }\n      static async listTags({ fs: fs2, gitdir }) {\n        const tags = await _GitRefManager.listRefs({\n          fs: fs2,\n          gitdir,\n          filepath: `refs/tags`\n        });\n        return tags.filter((x) => !x.endsWith(\"^{}\"));\n      }\n    };\n    function compareTreeEntryPath(a, b) {\n      return compareStrings(appendSlashIfDir(a), appendSlashIfDir(b));\n    }\n    function appendSlashIfDir(entry) {\n      return entry.mode === \"040000\" ? entry.path + \"/\" : entry.path;\n    }\n    function mode2type$1(mode) {\n      switch (mode) {\n        case \"040000\":\n          return \"tree\";\n        case \"100644\":\n          return \"blob\";\n        case \"100755\":\n          return \"blob\";\n        case \"120000\":\n          return \"blob\";\n        case \"160000\":\n          return \"commit\";\n      }\n      throw new InternalError(`Unexpected GitTree entry mode: ${mode}`);\n    }\n    function parseBuffer(buffer) {\n      const _entries = [];\n      let cursor = 0;\n      while (cursor < buffer.length) {\n        const space = buffer.indexOf(32, cursor);\n        if (space === -1) {\n          throw new InternalError(\n            `GitTree: Error parsing buffer at byte location ${cursor}: Could not find the next space character.`\n          );\n        }\n        const nullchar = buffer.indexOf(0, cursor);\n        if (nullchar === -1) {\n          throw new InternalError(\n            `GitTree: Error parsing buffer at byte location ${cursor}: Could not find the next null character.`\n          );\n        }\n        let mode = buffer.slice(cursor, space).toString(\"utf8\");\n        if (mode === \"40000\") mode = \"040000\";\n        const type = mode2type$1(mode);\n        const path2 = buffer.slice(space + 1, nullchar).toString(\"utf8\");\n        if (path2.includes(\"\\\\\") || path2.includes(\"/\")) {\n          throw new UnsafeFilepathError(path2);\n        }\n        const oid = buffer.slice(nullchar + 1, nullchar + 21).toString(\"hex\");\n        cursor = nullchar + 21;\n        _entries.push({ mode, path: path2, oid, type });\n      }\n      return _entries;\n    }\n    function limitModeToAllowed(mode) {\n      if (typeof mode === \"number\") {\n        mode = mode.toString(8);\n      }\n      if (mode.match(/^0?4.*/)) return \"040000\";\n      if (mode.match(/^1006.*/)) return \"100644\";\n      if (mode.match(/^1007.*/)) return \"100755\";\n      if (mode.match(/^120.*/)) return \"120000\";\n      if (mode.match(/^160.*/)) return \"160000\";\n      throw new InternalError(`Could not understand file mode: ${mode}`);\n    }\n    function nudgeIntoShape(entry) {\n      if (!entry.oid && entry.sha) {\n        entry.oid = entry.sha;\n      }\n      entry.mode = limitModeToAllowed(entry.mode);\n      if (!entry.type) {\n        entry.type = mode2type$1(entry.mode);\n      }\n      return entry;\n    }\n    var GitTree = class _GitTree {\n      constructor(entries) {\n        if (Buffer.isBuffer(entries)) {\n          this._entries = parseBuffer(entries);\n        } else if (Array.isArray(entries)) {\n          this._entries = entries.map(nudgeIntoShape);\n        } else {\n          throw new InternalError(\"invalid type passed to GitTree constructor\");\n        }\n        this._entries.sort(comparePath);\n      }\n      static from(tree) {\n        return new _GitTree(tree);\n      }\n      render() {\n        return this._entries.map((entry) => `${entry.mode} ${entry.type} ${entry.oid}    ${entry.path}`).join(\"\\n\");\n      }\n      toObject() {\n        const entries = [...this._entries];\n        entries.sort(compareTreeEntryPath);\n        return Buffer.concat(\n          entries.map((entry) => {\n            const mode = Buffer.from(entry.mode.replace(/^0/, \"\"));\n            const space = Buffer.from(\" \");\n            const path2 = Buffer.from(entry.path, \"utf8\");\n            const nullchar = Buffer.from([0]);\n            const oid = Buffer.from(entry.oid, \"hex\");\n            return Buffer.concat([mode, space, path2, nullchar, oid]);\n          })\n        );\n      }\n      /**\n       * @returns {TreeEntry[]}\n       */\n      entries() {\n        return this._entries;\n      }\n      *[Symbol.iterator]() {\n        for (const entry of this._entries) {\n          yield entry;\n        }\n      }\n    };\n    var GitObject = class {\n      static wrap({ type, object }) {\n        return Buffer.concat([\n          Buffer.from(`${type} ${object.byteLength.toString()}\\0`),\n          Buffer.from(object)\n        ]);\n      }\n      static unwrap(buffer) {\n        const s = buffer.indexOf(32);\n        const i = buffer.indexOf(0);\n        const type = buffer.slice(0, s).toString(\"utf8\");\n        const length = buffer.slice(s + 1, i).toString(\"utf8\");\n        const actualLength = buffer.length - (i + 1);\n        if (parseInt(length) !== actualLength) {\n          throw new InternalError(\n            `Length mismatch: expected ${length} bytes but got ${actualLength} instead.`\n          );\n        }\n        return {\n          type,\n          object: Buffer.from(buffer.slice(i + 1))\n        };\n      }\n    };\n    async function readObjectLoose({ fs: fs2, gitdir, oid }) {\n      const source = `objects/${oid.slice(0, 2)}/${oid.slice(2)}`;\n      const file = await fs2.read(`${gitdir}/${source}`);\n      if (!file) {\n        return null;\n      }\n      return { object: file, format: \"deflated\", source };\n    }\n    function applyDelta(delta, source) {\n      const reader = new BufferCursor(delta);\n      const sourceSize = readVarIntLE(reader);\n      if (sourceSize !== source.byteLength) {\n        throw new InternalError(\n          `applyDelta expected source buffer to be ${sourceSize} bytes but the provided buffer was ${source.length} bytes`\n        );\n      }\n      const targetSize = readVarIntLE(reader);\n      let target;\n      const firstOp = readOp(reader, source);\n      if (firstOp.byteLength === targetSize) {\n        target = firstOp;\n      } else {\n        target = Buffer.alloc(targetSize);\n        const writer = new BufferCursor(target);\n        writer.copy(firstOp);\n        while (!reader.eof()) {\n          writer.copy(readOp(reader, source));\n        }\n        const tell = writer.tell();\n        if (targetSize !== tell) {\n          throw new InternalError(\n            `applyDelta expected target buffer to be ${targetSize} bytes but the resulting buffer was ${tell} bytes`\n          );\n        }\n      }\n      return target;\n    }\n    function readVarIntLE(reader) {\n      let result = 0;\n      let shift = 0;\n      let byte = null;\n      do {\n        byte = reader.readUInt8();\n        result |= (byte & 127) << shift;\n        shift += 7;\n      } while (byte & 128);\n      return result;\n    }\n    function readCompactLE(reader, flags, size) {\n      let result = 0;\n      let shift = 0;\n      while (size--) {\n        if (flags & 1) {\n          result |= reader.readUInt8() << shift;\n        }\n        flags >>= 1;\n        shift += 8;\n      }\n      return result;\n    }\n    function readOp(reader, source) {\n      const byte = reader.readUInt8();\n      const COPY = 128;\n      const OFFS = 15;\n      const SIZE = 112;\n      if (byte & COPY) {\n        const offset = readCompactLE(reader, byte & OFFS, 4);\n        let size = readCompactLE(reader, (byte & SIZE) >> 4, 3);\n        if (size === 0) size = 65536;\n        return source.slice(offset, offset + size);\n      } else {\n        return reader.slice(byte);\n      }\n    }\n    function fromValue(value) {\n      let queue = [value];\n      return {\n        next() {\n          return Promise.resolve({ done: queue.length === 0, value: queue.pop() });\n        },\n        return() {\n          queue = [];\n          return {};\n        },\n        [Symbol.asyncIterator]() {\n          return this;\n        }\n      };\n    }\n    function getIterator(iterable) {\n      if (iterable[Symbol.asyncIterator]) {\n        return iterable[Symbol.asyncIterator]();\n      }\n      if (iterable[Symbol.iterator]) {\n        return iterable[Symbol.iterator]();\n      }\n      if (iterable.next) {\n        return iterable;\n      }\n      return fromValue(iterable);\n    }\n    var StreamReader = class {\n      constructor(stream) {\n        if (typeof Buffer === \"undefined\") {\n          throw new Error(\"Missing Buffer dependency\");\n        }\n        this.stream = getIterator(stream);\n        this.buffer = null;\n        this.cursor = 0;\n        this.undoCursor = 0;\n        this.started = false;\n        this._ended = false;\n        this._discardedBytes = 0;\n      }\n      eof() {\n        return this._ended && this.cursor === this.buffer.length;\n      }\n      tell() {\n        return this._discardedBytes + this.cursor;\n      }\n      async byte() {\n        if (this.eof()) return;\n        if (!this.started) await this._init();\n        if (this.cursor === this.buffer.length) {\n          await this._loadnext();\n          if (this._ended) return;\n        }\n        this._moveCursor(1);\n        return this.buffer[this.undoCursor];\n      }\n      async chunk() {\n        if (this.eof()) return;\n        if (!this.started) await this._init();\n        if (this.cursor === this.buffer.length) {\n          await this._loadnext();\n          if (this._ended) return;\n        }\n        this._moveCursor(this.buffer.length);\n        return this.buffer.slice(this.undoCursor, this.cursor);\n      }\n      async read(n) {\n        if (this.eof()) return;\n        if (!this.started) await this._init();\n        if (this.cursor + n > this.buffer.length) {\n          this._trim();\n          await this._accumulate(n);\n        }\n        this._moveCursor(n);\n        return this.buffer.slice(this.undoCursor, this.cursor);\n      }\n      async skip(n) {\n        if (this.eof()) return;\n        if (!this.started) await this._init();\n        if (this.cursor + n > this.buffer.length) {\n          this._trim();\n          await this._accumulate(n);\n        }\n        this._moveCursor(n);\n      }\n      async undo() {\n        this.cursor = this.undoCursor;\n      }\n      async _next() {\n        this.started = true;\n        let { done, value } = await this.stream.next();\n        if (done) {\n          this._ended = true;\n          if (!value) return Buffer.alloc(0);\n        }\n        if (value) {\n          value = Buffer.from(value);\n        }\n        return value;\n      }\n      _trim() {\n        this.buffer = this.buffer.slice(this.undoCursor);\n        this.cursor -= this.undoCursor;\n        this._discardedBytes += this.undoCursor;\n        this.undoCursor = 0;\n      }\n      _moveCursor(n) {\n        this.undoCursor = this.cursor;\n        this.cursor += n;\n        if (this.cursor > this.buffer.length) {\n          this.cursor = this.buffer.length;\n        }\n      }\n      async _accumulate(n) {\n        if (this._ended) return;\n        const buffers = [this.buffer];\n        while (this.cursor + n > lengthBuffers(buffers)) {\n          const nextbuffer = await this._next();\n          if (this._ended) break;\n          buffers.push(nextbuffer);\n        }\n        this.buffer = Buffer.concat(buffers);\n      }\n      async _loadnext() {\n        this._discardedBytes += this.buffer.length;\n        this.undoCursor = 0;\n        this.cursor = 0;\n        this.buffer = await this._next();\n      }\n      async _init() {\n        this.buffer = await this._next();\n      }\n    };\n    function lengthBuffers(buffers) {\n      return buffers.reduce((acc, buffer) => acc + buffer.length, 0);\n    }\n    async function listpack(stream, onData) {\n      const reader = new StreamReader(stream);\n      let PACK = await reader.read(4);\n      PACK = PACK.toString(\"utf8\");\n      if (PACK !== \"PACK\") {\n        throw new InternalError(`Invalid PACK header '${PACK}'`);\n      }\n      let version2 = await reader.read(4);\n      version2 = version2.readUInt32BE(0);\n      if (version2 !== 2) {\n        throw new InternalError(`Invalid packfile version: ${version2}`);\n      }\n      let numObjects = await reader.read(4);\n      numObjects = numObjects.readUInt32BE(0);\n      if (numObjects < 1) return;\n      while (!reader.eof() && numObjects--) {\n        const offset = reader.tell();\n        const { type, length, ofs, reference } = await parseHeader(reader);\n        const inflator = new pako.Inflate();\n        while (!inflator.result) {\n          const chunk = await reader.chunk();\n          if (!chunk) break;\n          inflator.push(chunk, false);\n          if (inflator.err) {\n            throw new InternalError(`Pako error: ${inflator.msg}`);\n          }\n          if (inflator.result) {\n            if (inflator.result.length !== length) {\n              throw new InternalError(\n                `Inflated object size is different from that stated in packfile.`\n              );\n            }\n            await reader.undo();\n            await reader.read(chunk.length - inflator.strm.avail_in);\n            const end = reader.tell();\n            await onData({\n              data: inflator.result,\n              type,\n              num: numObjects,\n              offset,\n              end,\n              reference,\n              ofs\n            });\n          }\n        }\n      }\n    }\n    async function parseHeader(reader) {\n      let byte = await reader.byte();\n      const type = byte >> 4 & 7;\n      let length = byte & 15;\n      if (byte & 128) {\n        let shift = 4;\n        do {\n          byte = await reader.byte();\n          length |= (byte & 127) << shift;\n          shift += 7;\n        } while (byte & 128);\n      }\n      let ofs;\n      let reference;\n      if (type === 6) {\n        let shift = 0;\n        ofs = 0;\n        const bytes = [];\n        do {\n          byte = await reader.byte();\n          ofs |= (byte & 127) << shift;\n          shift += 7;\n          bytes.push(byte);\n        } while (byte & 128);\n        reference = Buffer.from(bytes);\n      }\n      if (type === 7) {\n        const buf = await reader.read(20);\n        reference = buf;\n      }\n      return { type, length, ofs, reference };\n    }\n    var supportsDecompressionStream = false;\n    async function inflate(buffer) {\n      if (supportsDecompressionStream === null) {\n        supportsDecompressionStream = testDecompressionStream();\n      }\n      return supportsDecompressionStream ? browserInflate(buffer) : pako.inflate(buffer);\n    }\n    async function browserInflate(buffer) {\n      const ds = new DecompressionStream(\"deflate\");\n      const d = new Blob([buffer]).stream().pipeThrough(ds);\n      return new Uint8Array(await new Response(d).arrayBuffer());\n    }\n    function testDecompressionStream() {\n      try {\n        const ds = new DecompressionStream(\"deflate\");\n        if (ds) return true;\n      } catch (_) {\n      }\n      return false;\n    }\n    function decodeVarInt(reader) {\n      const bytes = [];\n      let byte = 0;\n      let multibyte = 0;\n      do {\n        byte = reader.readUInt8();\n        const lastSeven = byte & 127;\n        bytes.push(lastSeven);\n        multibyte = byte & 128;\n      } while (multibyte);\n      return bytes.reduce((a, b) => a + 1 << 7 | b, -1);\n    }\n    function otherVarIntDecode(reader, startWith) {\n      let result = startWith;\n      let shift = 4;\n      let byte = null;\n      do {\n        byte = reader.readUInt8();\n        result |= (byte & 127) << shift;\n        shift += 7;\n      } while (byte & 128);\n      return result;\n    }\n    var GitPackIndex = class _GitPackIndex {\n      constructor(stuff) {\n        Object.assign(this, stuff);\n        this.offsetCache = {};\n      }\n      static async fromIdx({ idx, getExternalRefDelta }) {\n        const reader = new BufferCursor(idx);\n        const magic = reader.slice(4).toString(\"hex\");\n        if (magic !== \"ff744f63\") {\n          return;\n        }\n        const version2 = reader.readUInt32BE();\n        if (version2 !== 2) {\n          throw new InternalError(\n            `Unable to read version ${version2} packfile IDX. (Only version 2 supported)`\n          );\n        }\n        if (idx.byteLength > 2048 * 1024 * 1024) {\n          throw new InternalError(\n            `To keep implementation simple, I haven't implemented the layer 5 feature needed to support packfiles > 2GB in size.`\n          );\n        }\n        reader.seek(reader.tell() + 4 * 255);\n        const size = reader.readUInt32BE();\n        const hashes = [];\n        for (let i = 0; i < size; i++) {\n          const hash = reader.slice(20).toString(\"hex\");\n          hashes[i] = hash;\n        }\n        reader.seek(reader.tell() + 4 * size);\n        const offsets = /* @__PURE__ */ new Map();\n        for (let i = 0; i < size; i++) {\n          offsets.set(hashes[i], reader.readUInt32BE());\n        }\n        const packfileSha = reader.slice(20).toString(\"hex\");\n        return new _GitPackIndex({\n          hashes,\n          crcs: {},\n          offsets,\n          packfileSha,\n          getExternalRefDelta\n        });\n      }\n      static async fromPack({ pack, getExternalRefDelta, onProgress }) {\n        const listpackTypes = {\n          1: \"commit\",\n          2: \"tree\",\n          3: \"blob\",\n          4: \"tag\",\n          6: \"ofs-delta\",\n          7: \"ref-delta\"\n        };\n        const offsetToObject = {};\n        const packfileSha = pack.slice(-20).toString(\"hex\");\n        const hashes = [];\n        const crcs = {};\n        const offsets = /* @__PURE__ */ new Map();\n        let totalObjectCount = null;\n        let lastPercent = null;\n        await listpack([pack], async ({ data, type, reference, offset, num: num2 }) => {\n          if (totalObjectCount === null) totalObjectCount = num2;\n          const percent = Math.floor(\n            (totalObjectCount - num2) * 100 / totalObjectCount\n          );\n          if (percent !== lastPercent) {\n            if (onProgress) {\n              await onProgress({\n                phase: \"Receiving objects\",\n                loaded: totalObjectCount - num2,\n                total: totalObjectCount\n              });\n            }\n          }\n          lastPercent = percent;\n          type = listpackTypes[type];\n          if ([\"commit\", \"tree\", \"blob\", \"tag\"].includes(type)) {\n            offsetToObject[offset] = {\n              type,\n              offset\n            };\n          } else if (type === \"ofs-delta\") {\n            offsetToObject[offset] = {\n              type,\n              offset\n            };\n          } else if (type === \"ref-delta\") {\n            offsetToObject[offset] = {\n              type,\n              offset\n            };\n          }\n        });\n        const offsetArray = Object.keys(offsetToObject).map(Number);\n        for (const [i, start] of offsetArray.entries()) {\n          const end = i + 1 === offsetArray.length ? pack.byteLength - 20 : offsetArray[i + 1];\n          const o = offsetToObject[start];\n          const crc = crc32.buf(pack.slice(start, end)) >>> 0;\n          o.end = end;\n          o.crc = crc;\n        }\n        const p = new _GitPackIndex({\n          pack: Promise.resolve(pack),\n          packfileSha,\n          crcs,\n          hashes,\n          offsets,\n          getExternalRefDelta\n        });\n        lastPercent = null;\n        let count2 = 0;\n        const objectsByDepth = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];\n        for (let offset in offsetToObject) {\n          offset = Number(offset);\n          const percent = Math.floor(count2 * 100 / totalObjectCount);\n          if (percent !== lastPercent) {\n            if (onProgress) {\n              await onProgress({\n                phase: \"Resolving deltas\",\n                loaded: count2,\n                total: totalObjectCount\n              });\n            }\n          }\n          count2++;\n          lastPercent = percent;\n          const o = offsetToObject[offset];\n          if (o.oid) continue;\n          try {\n            p.readDepth = 0;\n            p.externalReadDepth = 0;\n            const { type, object } = await p.readSlice({ start: offset });\n            objectsByDepth[p.readDepth] += 1;\n            const oid = await shasum(GitObject.wrap({ type, object }));\n            o.oid = oid;\n            hashes.push(oid);\n            offsets.set(oid, offset);\n            crcs[oid] = o.crc;\n          } catch (err) {\n            continue;\n          }\n        }\n        hashes.sort();\n        return p;\n      }\n      async toBuffer() {\n        const buffers = [];\n        const write = (str, encoding) => {\n          buffers.push(Buffer.from(str, encoding));\n        };\n        write(\"ff744f63\", \"hex\");\n        write(\"00000002\", \"hex\");\n        const fanoutBuffer = new BufferCursor(Buffer.alloc(256 * 4));\n        for (let i = 0; i < 256; i++) {\n          let count2 = 0;\n          for (const hash of this.hashes) {\n            if (parseInt(hash.slice(0, 2), 16) <= i) count2++;\n          }\n          fanoutBuffer.writeUInt32BE(count2);\n        }\n        buffers.push(fanoutBuffer.buffer);\n        for (const hash of this.hashes) {\n          write(hash, \"hex\");\n        }\n        const crcsBuffer = new BufferCursor(Buffer.alloc(this.hashes.length * 4));\n        for (const hash of this.hashes) {\n          crcsBuffer.writeUInt32BE(this.crcs[hash]);\n        }\n        buffers.push(crcsBuffer.buffer);\n        const offsetsBuffer = new BufferCursor(Buffer.alloc(this.hashes.length * 4));\n        for (const hash of this.hashes) {\n          offsetsBuffer.writeUInt32BE(this.offsets.get(hash));\n        }\n        buffers.push(offsetsBuffer.buffer);\n        write(this.packfileSha, \"hex\");\n        const totalBuffer = Buffer.concat(buffers);\n        const sha = await shasum(totalBuffer);\n        const shaBuffer = Buffer.alloc(20);\n        shaBuffer.write(sha, \"hex\");\n        return Buffer.concat([totalBuffer, shaBuffer]);\n      }\n      async load({ pack }) {\n        this.pack = pack;\n      }\n      async unload() {\n        this.pack = null;\n      }\n      async read({ oid }) {\n        if (!this.offsets.get(oid)) {\n          if (this.getExternalRefDelta) {\n            this.externalReadDepth++;\n            return this.getExternalRefDelta(oid);\n          } else {\n            throw new InternalError(`Could not read object ${oid} from packfile`);\n          }\n        }\n        const start = this.offsets.get(oid);\n        return this.readSlice({ start });\n      }\n      async readSlice({ start }) {\n        if (this.offsetCache[start]) {\n          return Object.assign({}, this.offsetCache[start]);\n        }\n        this.readDepth++;\n        const types2 = {\n          16: \"commit\",\n          32: \"tree\",\n          48: \"blob\",\n          64: \"tag\",\n          96: \"ofs_delta\",\n          112: \"ref_delta\"\n        };\n        if (!this.pack) {\n          throw new InternalError(\n            \"Tried to read from a GitPackIndex with no packfile loaded into memory\"\n          );\n        }\n        const raw = (await this.pack).slice(start);\n        const reader = new BufferCursor(raw);\n        const byte = reader.readUInt8();\n        const btype = byte & 112;\n        let type = types2[btype];\n        if (type === void 0) {\n          throw new InternalError(\"Unrecognized type: 0b\" + btype.toString(2));\n        }\n        const lastFour = byte & 15;\n        let length = lastFour;\n        const multibyte = byte & 128;\n        if (multibyte) {\n          length = otherVarIntDecode(reader, lastFour);\n        }\n        let base = null;\n        let object = null;\n        if (type === \"ofs_delta\") {\n          const offset = decodeVarInt(reader);\n          const baseOffset = start - offset;\n          ({ object: base, type } = await this.readSlice({ start: baseOffset }));\n        }\n        if (type === \"ref_delta\") {\n          const oid = reader.slice(20).toString(\"hex\");\n          ({ object: base, type } = await this.read({ oid }));\n        }\n        const buffer = raw.slice(reader.tell());\n        object = Buffer.from(await inflate(buffer));\n        if (object.byteLength !== length) {\n          throw new InternalError(\n            `Packfile told us object would have length ${length} but it had length ${object.byteLength}`\n          );\n        }\n        if (base) {\n          object = Buffer.from(applyDelta(object, base));\n        }\n        if (this.readDepth > 3) {\n          this.offsetCache[start] = { type, object };\n        }\n        return { type, format: \"content\", object };\n      }\n    };\n    var PackfileCache = Symbol(\"PackfileCache\");\n    async function loadPackIndex({\n      fs: fs2,\n      filename,\n      getExternalRefDelta,\n      emitter,\n      emitterPrefix\n    }) {\n      const idx = await fs2.read(filename);\n      return GitPackIndex.fromIdx({ idx, getExternalRefDelta });\n    }\n    function readPackIndex({\n      fs: fs2,\n      cache,\n      filename,\n      getExternalRefDelta,\n      emitter,\n      emitterPrefix\n    }) {\n      if (!cache[PackfileCache]) cache[PackfileCache] = /* @__PURE__ */ new Map();\n      let p = cache[PackfileCache].get(filename);\n      if (!p) {\n        p = loadPackIndex({\n          fs: fs2,\n          filename,\n          getExternalRefDelta,\n          emitter,\n          emitterPrefix\n        });\n        cache[PackfileCache].set(filename, p);\n      }\n      return p;\n    }\n    async function readObjectPacked({\n      fs: fs2,\n      cache,\n      gitdir,\n      oid,\n      format = \"content\",\n      getExternalRefDelta\n    }) {\n      let list = await fs2.readdir(join2(gitdir, \"objects/pack\"));\n      list = list.filter((x) => x.endsWith(\".idx\"));\n      for (const filename of list) {\n        const indexFile = `${gitdir}/objects/pack/${filename}`;\n        const p = await readPackIndex({\n          fs: fs2,\n          cache,\n          filename: indexFile,\n          getExternalRefDelta\n        });\n        if (p.error) throw new InternalError(p.error);\n        if (p.offsets.has(oid)) {\n          if (!p.pack) {\n            const packFile = indexFile.replace(/idx$/, \"pack\");\n            p.pack = fs2.read(packFile);\n          }\n          const result = await p.read({ oid, getExternalRefDelta });\n          result.format = \"content\";\n          result.source = `objects/pack/${filename.replace(/idx$/, \"pack\")}`;\n          return result;\n        }\n      }\n      return null;\n    }\n    async function _readObject({\n      fs: fs2,\n      cache,\n      gitdir,\n      oid,\n      format = \"content\"\n    }) {\n      const getExternalRefDelta = (oid2) => _readObject({ fs: fs2, cache, gitdir, oid: oid2 });\n      let result;\n      if (oid === \"4b825dc642cb6eb9a060e54bf8d69288fbee4904\") {\n        result = { format: \"wrapped\", object: Buffer.from(`tree 0\\0`) };\n      }\n      if (!result) {\n        result = await readObjectLoose({ fs: fs2, gitdir, oid });\n      }\n      if (!result) {\n        result = await readObjectPacked({\n          fs: fs2,\n          cache,\n          gitdir,\n          oid,\n          getExternalRefDelta\n        });\n        if (!result) {\n          throw new NotFoundError(oid);\n        }\n        return result;\n      }\n      if (format === \"deflated\") {\n        return result;\n      }\n      if (result.format === \"deflated\") {\n        result.object = Buffer.from(await inflate(result.object));\n        result.format = \"wrapped\";\n      }\n      if (format === \"wrapped\") {\n        return result;\n      }\n      const sha = await shasum(result.object);\n      if (sha !== oid) {\n        throw new InternalError(\n          `SHA check failed! Expected ${oid}, computed ${sha}`\n        );\n      }\n      const { object, type } = GitObject.unwrap(result.object);\n      result.type = type;\n      result.object = object;\n      result.format = \"content\";\n      if (format === \"content\") {\n        return result;\n      }\n      throw new InternalError(`invalid requested format \"${format}\"`);\n    }\n    var AlreadyExistsError = class _AlreadyExistsError extends BaseError {\n      /**\n       * @param {'note'|'remote'|'tag'|'branch'} noun\n       * @param {string} where\n       * @param {boolean} canForce\n       */\n      constructor(noun, where, canForce = true) {\n        super(\n          `Failed to create ${noun} at ${where} because it already exists.${canForce ? ` (Hint: use 'force: true' parameter to overwrite existing ${noun}.)` : \"\"}`\n        );\n        this.code = this.name = _AlreadyExistsError.code;\n        this.data = { noun, where, canForce };\n      }\n    };\n    AlreadyExistsError.code = \"AlreadyExistsError\";\n    var AmbiguousError = class _AmbiguousError extends BaseError {\n      /**\n       * @param {'oids'|'refs'} nouns\n       * @param {string} short\n       * @param {string[]} matches\n       */\n      constructor(nouns, short, matches) {\n        super(\n          `Found multiple ${nouns} matching \"${short}\" (${matches.join(\n            \", \"\n          )}). Use a longer abbreviation length to disambiguate them.`\n        );\n        this.code = this.name = _AmbiguousError.code;\n        this.data = { nouns, short, matches };\n      }\n    };\n    AmbiguousError.code = \"AmbiguousError\";\n    var CheckoutConflictError = class _CheckoutConflictError extends BaseError {\n      /**\n       * @param {string[]} filepaths\n       */\n      constructor(filepaths) {\n        super(\n          `Your local changes to the following files would be overwritten by checkout: ${filepaths.join(\n            \", \"\n          )}`\n        );\n        this.code = this.name = _CheckoutConflictError.code;\n        this.data = { filepaths };\n      }\n    };\n    CheckoutConflictError.code = \"CheckoutConflictError\";\n    var CommitNotFetchedError = class _CommitNotFetchedError extends BaseError {\n      /**\n       * @param {string} ref\n       * @param {string} oid\n       */\n      constructor(ref, oid) {\n        super(\n          `Failed to checkout \"${ref}\" because commit ${oid} is not available locally. Do a git fetch to make the branch available locally.`\n        );\n        this.code = this.name = _CommitNotFetchedError.code;\n        this.data = { ref, oid };\n      }\n    };\n    CommitNotFetchedError.code = \"CommitNotFetchedError\";\n    var EmptyServerResponseError = class _EmptyServerResponseError extends BaseError {\n      constructor() {\n        super(`Empty response from git server.`);\n        this.code = this.name = _EmptyServerResponseError.code;\n        this.data = {};\n      }\n    };\n    EmptyServerResponseError.code = \"EmptyServerResponseError\";\n    var FastForwardError = class _FastForwardError extends BaseError {\n      constructor() {\n        super(`A simple fast-forward merge was not possible.`);\n        this.code = this.name = _FastForwardError.code;\n        this.data = {};\n      }\n    };\n    FastForwardError.code = \"FastForwardError\";\n    var GitPushError = class _GitPushError extends BaseError {\n      /**\n       * @param {string} prettyDetails\n       * @param {PushResult} result\n       */\n      constructor(prettyDetails, result) {\n        super(`One or more branches were not updated: ${prettyDetails}`);\n        this.code = this.name = _GitPushError.code;\n        this.data = { prettyDetails, result };\n      }\n    };\n    GitPushError.code = \"GitPushError\";\n    var HttpError = class _HttpError extends BaseError {\n      /**\n       * @param {number} statusCode\n       * @param {string} statusMessage\n       * @param {string} response\n       */\n      constructor(statusCode, statusMessage, response) {\n        super(`HTTP Error: ${statusCode} ${statusMessage}`);\n        this.code = this.name = _HttpError.code;\n        this.data = { statusCode, statusMessage, response };\n      }\n    };\n    HttpError.code = \"HttpError\";\n    var InvalidFilepathError = class _InvalidFilepathError extends BaseError {\n      /**\n       * @param {'leading-slash'|'trailing-slash'|'directory'} [reason]\n       */\n      constructor(reason) {\n        let message = \"invalid filepath\";\n        if (reason === \"leading-slash\" || reason === \"trailing-slash\") {\n          message = `\"filepath\" parameter should not include leading or trailing directory separators because these can cause problems on some platforms.`;\n        } else if (reason === \"directory\") {\n          message = `\"filepath\" should not be a directory.`;\n        }\n        super(message);\n        this.code = this.name = _InvalidFilepathError.code;\n        this.data = { reason };\n      }\n    };\n    InvalidFilepathError.code = \"InvalidFilepathError\";\n    var InvalidRefNameError = class _InvalidRefNameError extends BaseError {\n      /**\n       * @param {string} ref\n       * @param {string} suggestion\n       * @param {boolean} canForce\n       */\n      constructor(ref, suggestion) {\n        super(\n          `\"${ref}\" would be an invalid git reference. (Hint: a valid alternative would be \"${suggestion}\".)`\n        );\n        this.code = this.name = _InvalidRefNameError.code;\n        this.data = { ref, suggestion };\n      }\n    };\n    InvalidRefNameError.code = \"InvalidRefNameError\";\n    var MaxDepthError = class _MaxDepthError extends BaseError {\n      /**\n       * @param {number} depth\n       */\n      constructor(depth) {\n        super(`Maximum search depth of ${depth} exceeded.`);\n        this.code = this.name = _MaxDepthError.code;\n        this.data = { depth };\n      }\n    };\n    MaxDepthError.code = \"MaxDepthError\";\n    var MergeNotSupportedError = class _MergeNotSupportedError extends BaseError {\n      constructor() {\n        super(`Merges with conflicts are not supported yet.`);\n        this.code = this.name = _MergeNotSupportedError.code;\n        this.data = {};\n      }\n    };\n    MergeNotSupportedError.code = \"MergeNotSupportedError\";\n    var MergeConflictError = class _MergeConflictError extends BaseError {\n      /**\n       * @param {Array<string>} filepaths\n       * @param {Array<string>} bothModified\n       * @param {Array<string>} deleteByUs\n       * @param {Array<string>} deleteByTheirs\n       */\n      constructor(filepaths, bothModified, deleteByUs, deleteByTheirs) {\n        super(\n          `Automatic merge failed with one or more merge conflicts in the following files: ${filepaths.toString()}. Fix conflicts then commit the result.`\n        );\n        this.code = this.name = _MergeConflictError.code;\n        this.data = { filepaths, bothModified, deleteByUs, deleteByTheirs };\n      }\n    };\n    MergeConflictError.code = \"MergeConflictError\";\n    var MissingNameError = class _MissingNameError extends BaseError {\n      /**\n       * @param {'author'|'committer'|'tagger'} role\n       */\n      constructor(role) {\n        super(\n          `No name was provided for ${role} in the argument or in the .git/config file.`\n        );\n        this.code = this.name = _MissingNameError.code;\n        this.data = { role };\n      }\n    };\n    MissingNameError.code = \"MissingNameError\";\n    var MissingParameterError = class _MissingParameterError extends BaseError {\n      /**\n       * @param {string} parameter\n       */\n      constructor(parameter) {\n        super(\n          `The function requires a \"${parameter}\" parameter but none was provided.`\n        );\n        this.code = this.name = _MissingParameterError.code;\n        this.data = { parameter };\n      }\n    };\n    MissingParameterError.code = \"MissingParameterError\";\n    var MultipleGitError = class _MultipleGitError extends BaseError {\n      /**\n       * @param {Error[]} errors\n       * @param {string} message\n       */\n      constructor(errors) {\n        super(\n          `There are multiple errors that were thrown by the method. Please refer to the \"errors\" property to see more`\n        );\n        this.code = this.name = _MultipleGitError.code;\n        this.data = { errors };\n        this.errors = errors;\n      }\n    };\n    MultipleGitError.code = \"MultipleGitError\";\n    var ParseError = class _ParseError extends BaseError {\n      /**\n       * @param {string} expected\n       * @param {string} actual\n       */\n      constructor(expected, actual) {\n        super(`Expected \"${expected}\" but received \"${actual}\".`);\n        this.code = this.name = _ParseError.code;\n        this.data = { expected, actual };\n      }\n    };\n    ParseError.code = \"ParseError\";\n    var PushRejectedError = class _PushRejectedError extends BaseError {\n      /**\n       * @param {'not-fast-forward'|'tag-exists'} reason\n       */\n      constructor(reason) {\n        let message = \"\";\n        if (reason === \"not-fast-forward\") {\n          message = \" because it was not a simple fast-forward\";\n        } else if (reason === \"tag-exists\") {\n          message = \" because tag already exists\";\n        }\n        super(`Push rejected${message}. Use \"force: true\" to override.`);\n        this.code = this.name = _PushRejectedError.code;\n        this.data = { reason };\n      }\n    };\n    PushRejectedError.code = \"PushRejectedError\";\n    var RemoteCapabilityError = class _RemoteCapabilityError extends BaseError {\n      /**\n       * @param {'shallow'|'deepen-since'|'deepen-not'|'deepen-relative'} capability\n       * @param {'depth'|'since'|'exclude'|'relative'} parameter\n       */\n      constructor(capability, parameter) {\n        super(\n          `Remote does not support the \"${capability}\" so the \"${parameter}\" parameter cannot be used.`\n        );\n        this.code = this.name = _RemoteCapabilityError.code;\n        this.data = { capability, parameter };\n      }\n    };\n    RemoteCapabilityError.code = \"RemoteCapabilityError\";\n    var SmartHttpError = class _SmartHttpError extends BaseError {\n      /**\n       * @param {string} preview\n       * @param {string} response\n       */\n      constructor(preview, response) {\n        super(\n          `Remote did not reply using the \"smart\" HTTP protocol. Expected \"001e# service=git-upload-pack\" but received: ${preview}`\n        );\n        this.code = this.name = _SmartHttpError.code;\n        this.data = { preview, response };\n      }\n    };\n    SmartHttpError.code = \"SmartHttpError\";\n    var UnknownTransportError = class _UnknownTransportError extends BaseError {\n      /**\n       * @param {string} url\n       * @param {string} transport\n       * @param {string} [suggestion]\n       */\n      constructor(url, transport, suggestion) {\n        super(\n          `Git remote \"${url}\" uses an unrecognized transport protocol: \"${transport}\"`\n        );\n        this.code = this.name = _UnknownTransportError.code;\n        this.data = { url, transport, suggestion };\n      }\n    };\n    UnknownTransportError.code = \"UnknownTransportError\";\n    var UrlParseError = class _UrlParseError extends BaseError {\n      /**\n       * @param {string} url\n       */\n      constructor(url) {\n        super(`Cannot parse remote URL: \"${url}\"`);\n        this.code = this.name = _UrlParseError.code;\n        this.data = { url };\n      }\n    };\n    UrlParseError.code = \"UrlParseError\";\n    var UserCanceledError = class _UserCanceledError extends BaseError {\n      constructor() {\n        super(`The operation was canceled.`);\n        this.code = this.name = _UserCanceledError.code;\n        this.data = {};\n      }\n    };\n    UserCanceledError.code = \"UserCanceledError\";\n    var IndexResetError = class _IndexResetError extends BaseError {\n      /**\n       * @param {Array<string>} filepaths\n       */\n      constructor(filepath) {\n        super(\n          `Could not merge index: Entry for '${filepath}' is not up to date. Either reset the index entry to HEAD, or stage your unstaged changes.`\n        );\n        this.code = this.name = _IndexResetError.code;\n        this.data = { filepath };\n      }\n    };\n    IndexResetError.code = \"IndexResetError\";\n    var NoCommitError = class _NoCommitError extends BaseError {\n      /**\n       * @param {string} ref\n       */\n      constructor(ref) {\n        super(\n          `\"${ref}\" does not point to any commit. You're maybe working on a repository with no commits yet. `\n        );\n        this.code = this.name = _NoCommitError.code;\n        this.data = { ref };\n      }\n    };\n    NoCommitError.code = \"NoCommitError\";\n    var Errors = /* @__PURE__ */ Object.freeze({\n      __proto__: null,\n      AlreadyExistsError,\n      AmbiguousError,\n      CheckoutConflictError,\n      CommitNotFetchedError,\n      EmptyServerResponseError,\n      FastForwardError,\n      GitPushError,\n      HttpError,\n      InternalError,\n      InvalidFilepathError,\n      InvalidOidError,\n      InvalidRefNameError,\n      MaxDepthError,\n      MergeNotSupportedError,\n      MergeConflictError,\n      MissingNameError,\n      MissingParameterError,\n      MultipleGitError,\n      NoRefspecError,\n      NotFoundError,\n      ObjectTypeError,\n      ParseError,\n      PushRejectedError,\n      RemoteCapabilityError,\n      SmartHttpError,\n      UnknownTransportError,\n      UnsafeFilepathError,\n      UrlParseError,\n      UserCanceledError,\n      UnmergedPathsError,\n      IndexResetError,\n      NoCommitError\n    });\n    function formatAuthor({ name, email, timestamp, timezoneOffset }) {\n      timezoneOffset = formatTimezoneOffset(timezoneOffset);\n      return `${name} <${email}> ${timestamp} ${timezoneOffset}`;\n    }\n    function formatTimezoneOffset(minutes) {\n      const sign = simpleSign(negateExceptForZero(minutes));\n      minutes = Math.abs(minutes);\n      const hours = Math.floor(minutes / 60);\n      minutes -= hours * 60;\n      let strHours = String(hours);\n      let strMinutes = String(minutes);\n      if (strHours.length < 2) strHours = \"0\" + strHours;\n      if (strMinutes.length < 2) strMinutes = \"0\" + strMinutes;\n      return (sign === -1 ? \"-\" : \"+\") + strHours + strMinutes;\n    }\n    function simpleSign(n) {\n      return Math.sign(n) || (Object.is(n, -0) ? -1 : 1);\n    }\n    function negateExceptForZero(n) {\n      return n === 0 ? n : -n;\n    }\n    function normalizeNewlines(str) {\n      str = str.replace(/\\r/g, \"\");\n      str = str.replace(/^\\n+/, \"\");\n      str = str.replace(/\\n+$/, \"\") + \"\\n\";\n      return str;\n    }\n    function parseAuthor(author2) {\n      const [, name, email, timestamp, offset] = author2.match(\n        /^(.*) <(.*)> (.*) (.*)$/\n      );\n      return {\n        name,\n        email,\n        timestamp: Number(timestamp),\n        timezoneOffset: parseTimezoneOffset(offset)\n      };\n    }\n    function parseTimezoneOffset(offset) {\n      let [, sign, hours, minutes] = offset.match(/(\\+|-)(\\d\\d)(\\d\\d)/);\n      minutes = (sign === \"+\" ? 1 : -1) * (Number(hours) * 60 + Number(minutes));\n      return negateExceptForZero$1(minutes);\n    }\n    function negateExceptForZero$1(n) {\n      return n === 0 ? n : -n;\n    }\n    var GitAnnotatedTag = class _GitAnnotatedTag {\n      constructor(tag2) {\n        if (typeof tag2 === \"string\") {\n          this._tag = tag2;\n        } else if (Buffer.isBuffer(tag2)) {\n          this._tag = tag2.toString(\"utf8\");\n        } else if (typeof tag2 === \"object\") {\n          this._tag = _GitAnnotatedTag.render(tag2);\n        } else {\n          throw new InternalError(\n            \"invalid type passed to GitAnnotatedTag constructor\"\n          );\n        }\n      }\n      static from(tag2) {\n        return new _GitAnnotatedTag(tag2);\n      }\n      static render(obj) {\n        return `object ${obj.object}\ntype ${obj.type}\ntag ${obj.tag}\ntagger ${formatAuthor(obj.tagger)}\n\n${obj.message}\n${obj.gpgsig ? obj.gpgsig : \"\"}`;\n      }\n      justHeaders() {\n        return this._tag.slice(0, this._tag.indexOf(\"\\n\\n\"));\n      }\n      message() {\n        const tag2 = this.withoutSignature();\n        return tag2.slice(tag2.indexOf(\"\\n\\n\") + 2);\n      }\n      parse() {\n        return Object.assign(this.headers(), {\n          message: this.message(),\n          gpgsig: this.gpgsig()\n        });\n      }\n      render() {\n        return this._tag;\n      }\n      headers() {\n        const headers = this.justHeaders().split(\"\\n\");\n        const hs = [];\n        for (const h of headers) {\n          if (h[0] === \" \") {\n            hs[hs.length - 1] += \"\\n\" + h.slice(1);\n          } else {\n            hs.push(h);\n          }\n        }\n        const obj = {};\n        for (const h of hs) {\n          const key = h.slice(0, h.indexOf(\" \"));\n          const value = h.slice(h.indexOf(\" \") + 1);\n          if (Array.isArray(obj[key])) {\n            obj[key].push(value);\n          } else {\n            obj[key] = value;\n          }\n        }\n        if (obj.tagger) {\n          obj.tagger = parseAuthor(obj.tagger);\n        }\n        if (obj.committer) {\n          obj.committer = parseAuthor(obj.committer);\n        }\n        return obj;\n      }\n      withoutSignature() {\n        const tag2 = normalizeNewlines(this._tag);\n        if (tag2.indexOf(\"\\n-----BEGIN PGP SIGNATURE-----\") === -1) return tag2;\n        return tag2.slice(0, tag2.lastIndexOf(\"\\n-----BEGIN PGP SIGNATURE-----\"));\n      }\n      gpgsig() {\n        if (this._tag.indexOf(\"\\n-----BEGIN PGP SIGNATURE-----\") === -1) return;\n        const signature = this._tag.slice(\n          this._tag.indexOf(\"-----BEGIN PGP SIGNATURE-----\"),\n          this._tag.indexOf(\"-----END PGP SIGNATURE-----\") + \"-----END PGP SIGNATURE-----\".length\n        );\n        return normalizeNewlines(signature);\n      }\n      payload() {\n        return this.withoutSignature() + \"\\n\";\n      }\n      toObject() {\n        return Buffer.from(this._tag, \"utf8\");\n      }\n      static async sign(tag2, sign, secretKey) {\n        const payload = tag2.payload();\n        let { signature } = await sign({ payload, secretKey });\n        signature = normalizeNewlines(signature);\n        const signedTag = payload + signature;\n        return _GitAnnotatedTag.from(signedTag);\n      }\n    };\n    function indent(str) {\n      return str.trim().split(\"\\n\").map((x) => \" \" + x).join(\"\\n\") + \"\\n\";\n    }\n    function outdent(str) {\n      return str.split(\"\\n\").map((x) => x.replace(/^ /, \"\")).join(\"\\n\");\n    }\n    var GitCommit = class _GitCommit {\n      constructor(commit3) {\n        if (typeof commit3 === \"string\") {\n          this._commit = commit3;\n        } else if (Buffer.isBuffer(commit3)) {\n          this._commit = commit3.toString(\"utf8\");\n        } else if (typeof commit3 === \"object\") {\n          this._commit = _GitCommit.render(commit3);\n        } else {\n          throw new InternalError(\"invalid type passed to GitCommit constructor\");\n        }\n      }\n      static fromPayloadSignature({ payload, signature }) {\n        const headers = _GitCommit.justHeaders(payload);\n        const message = _GitCommit.justMessage(payload);\n        const commit3 = normalizeNewlines(\n          headers + \"\\ngpgsig\" + indent(signature) + \"\\n\" + message\n        );\n        return new _GitCommit(commit3);\n      }\n      static from(commit3) {\n        return new _GitCommit(commit3);\n      }\n      toObject() {\n        return Buffer.from(this._commit, \"utf8\");\n      }\n      // Todo: allow setting the headers and message\n      headers() {\n        return this.parseHeaders();\n      }\n      // Todo: allow setting the headers and message\n      message() {\n        return _GitCommit.justMessage(this._commit);\n      }\n      parse() {\n        return Object.assign({ message: this.message() }, this.headers());\n      }\n      static justMessage(commit3) {\n        return normalizeNewlines(commit3.slice(commit3.indexOf(\"\\n\\n\") + 2));\n      }\n      static justHeaders(commit3) {\n        return commit3.slice(0, commit3.indexOf(\"\\n\\n\"));\n      }\n      parseHeaders() {\n        const headers = _GitCommit.justHeaders(this._commit).split(\"\\n\");\n        const hs = [];\n        for (const h of headers) {\n          if (h[0] === \" \") {\n            hs[hs.length - 1] += \"\\n\" + h.slice(1);\n          } else {\n            hs.push(h);\n          }\n        }\n        const obj = {\n          parent: []\n        };\n        for (const h of hs) {\n          const key = h.slice(0, h.indexOf(\" \"));\n          const value = h.slice(h.indexOf(\" \") + 1);\n          if (Array.isArray(obj[key])) {\n            obj[key].push(value);\n          } else {\n            obj[key] = value;\n          }\n        }\n        if (obj.author) {\n          obj.author = parseAuthor(obj.author);\n        }\n        if (obj.committer) {\n          obj.committer = parseAuthor(obj.committer);\n        }\n        return obj;\n      }\n      static renderHeaders(obj) {\n        let headers = \"\";\n        if (obj.tree) {\n          headers += `tree ${obj.tree}\n`;\n        } else {\n          headers += `tree 4b825dc642cb6eb9a060e54bf8d69288fbee4904\n`;\n        }\n        if (obj.parent) {\n          if (obj.parent.length === void 0) {\n            throw new InternalError(`commit 'parent' property should be an array`);\n          }\n          for (const p of obj.parent) {\n            headers += `parent ${p}\n`;\n          }\n        }\n        const author2 = obj.author;\n        headers += `author ${formatAuthor(author2)}\n`;\n        const committer = obj.committer || obj.author;\n        headers += `committer ${formatAuthor(committer)}\n`;\n        if (obj.gpgsig) {\n          headers += \"gpgsig\" + indent(obj.gpgsig);\n        }\n        return headers;\n      }\n      static render(obj) {\n        return _GitCommit.renderHeaders(obj) + \"\\n\" + normalizeNewlines(obj.message);\n      }\n      render() {\n        return this._commit;\n      }\n      withoutSignature() {\n        const commit3 = normalizeNewlines(this._commit);\n        if (commit3.indexOf(\"\\ngpgsig\") === -1) return commit3;\n        const headers = commit3.slice(0, commit3.indexOf(\"\\ngpgsig\"));\n        const message = commit3.slice(\n          commit3.indexOf(\"-----END PGP SIGNATURE-----\\n\") + \"-----END PGP SIGNATURE-----\\n\".length\n        );\n        return normalizeNewlines(headers + \"\\n\" + message);\n      }\n      isolateSignature() {\n        const signature = this._commit.slice(\n          this._commit.indexOf(\"-----BEGIN PGP SIGNATURE-----\"),\n          this._commit.indexOf(\"-----END PGP SIGNATURE-----\") + \"-----END PGP SIGNATURE-----\".length\n        );\n        return outdent(signature);\n      }\n      static async sign(commit3, sign, secretKey) {\n        const payload = commit3.withoutSignature();\n        const message = _GitCommit.justMessage(commit3._commit);\n        let { signature } = await sign({ payload, secretKey });\n        signature = normalizeNewlines(signature);\n        const headers = _GitCommit.justHeaders(commit3._commit);\n        const signedCommit = headers + \"\\ngpgsig\" + indent(signature) + \"\\n\" + message;\n        return _GitCommit.from(signedCommit);\n      }\n    };\n    async function resolveTree({ fs: fs2, cache, gitdir, oid }) {\n      if (oid === \"4b825dc642cb6eb9a060e54bf8d69288fbee4904\") {\n        return { tree: GitTree.from([]), oid };\n      }\n      const { type, object } = await _readObject({ fs: fs2, cache, gitdir, oid });\n      if (type === \"tag\") {\n        oid = GitAnnotatedTag.from(object).parse().object;\n        return resolveTree({ fs: fs2, cache, gitdir, oid });\n      }\n      if (type === \"commit\") {\n        oid = GitCommit.from(object).parse().tree;\n        return resolveTree({ fs: fs2, cache, gitdir, oid });\n      }\n      if (type !== \"tree\") {\n        throw new ObjectTypeError(oid, type, \"tree\");\n      }\n      return { tree: GitTree.from(object), oid };\n    }\n    var GitWalkerRepo = class {\n      constructor({ fs: fs2, gitdir, ref, cache }) {\n        this.fs = fs2;\n        this.cache = cache;\n        this.gitdir = gitdir;\n        this.mapPromise = (async () => {\n          const map = /* @__PURE__ */ new Map();\n          let oid;\n          try {\n            oid = await GitRefManager.resolve({ fs: fs2, gitdir, ref });\n          } catch (e) {\n            if (e instanceof NotFoundError) {\n              oid = \"4b825dc642cb6eb9a060e54bf8d69288fbee4904\";\n            }\n          }\n          const tree = await resolveTree({ fs: fs2, cache: this.cache, gitdir, oid });\n          tree.type = \"tree\";\n          tree.mode = \"40000\";\n          map.set(\".\", tree);\n          return map;\n        })();\n        const walker = this;\n        this.ConstructEntry = class TreeEntry {\n          constructor(fullpath) {\n            this._fullpath = fullpath;\n            this._type = false;\n            this._mode = false;\n            this._stat = false;\n            this._content = false;\n            this._oid = false;\n          }\n          async type() {\n            return walker.type(this);\n          }\n          async mode() {\n            return walker.mode(this);\n          }\n          async stat() {\n            return walker.stat(this);\n          }\n          async content() {\n            return walker.content(this);\n          }\n          async oid() {\n            return walker.oid(this);\n          }\n        };\n      }\n      async readdir(entry) {\n        const filepath = entry._fullpath;\n        const { fs: fs2, cache, gitdir } = this;\n        const map = await this.mapPromise;\n        const obj = map.get(filepath);\n        if (!obj) throw new Error(`No obj for ${filepath}`);\n        const oid = obj.oid;\n        if (!oid) throw new Error(`No oid for obj ${JSON.stringify(obj)}`);\n        if (obj.type !== \"tree\") {\n          return null;\n        }\n        const { type, object } = await _readObject({ fs: fs2, cache, gitdir, oid });\n        if (type !== obj.type) {\n          throw new ObjectTypeError(oid, type, obj.type);\n        }\n        const tree = GitTree.from(object);\n        for (const entry2 of tree) {\n          map.set(join2(filepath, entry2.path), entry2);\n        }\n        return tree.entries().map((entry2) => join2(filepath, entry2.path));\n      }\n      async type(entry) {\n        if (entry._type === false) {\n          const map = await this.mapPromise;\n          const { type } = map.get(entry._fullpath);\n          entry._type = type;\n        }\n        return entry._type;\n      }\n      async mode(entry) {\n        if (entry._mode === false) {\n          const map = await this.mapPromise;\n          const { mode } = map.get(entry._fullpath);\n          entry._mode = normalizeMode(parseInt(mode, 8));\n        }\n        return entry._mode;\n      }\n      async stat(_entry) {\n      }\n      async content(entry) {\n        if (entry._content === false) {\n          const map = await this.mapPromise;\n          const { fs: fs2, cache, gitdir } = this;\n          const obj = map.get(entry._fullpath);\n          const oid = obj.oid;\n          const { type, object } = await _readObject({ fs: fs2, cache, gitdir, oid });\n          if (type !== \"blob\") {\n            entry._content = void 0;\n          } else {\n            entry._content = new Uint8Array(object);\n          }\n        }\n        return entry._content;\n      }\n      async oid(entry) {\n        if (entry._oid === false) {\n          const map = await this.mapPromise;\n          const obj = map.get(entry._fullpath);\n          entry._oid = obj.oid;\n        }\n        return entry._oid;\n      }\n    };\n    function TREE({ ref = \"HEAD\" } = {}) {\n      const o = /* @__PURE__ */ Object.create(null);\n      Object.defineProperty(o, GitWalkSymbol, {\n        value: function({ fs: fs2, gitdir, cache }) {\n          return new GitWalkerRepo({ fs: fs2, gitdir, ref, cache });\n        }\n      });\n      Object.freeze(o);\n      return o;\n    }\n    var GitWalkerFs = class {\n      constructor({ fs: fs2, dir, gitdir, cache }) {\n        this.fs = fs2;\n        this.cache = cache;\n        this.dir = dir;\n        this.gitdir = gitdir;\n        const walker = this;\n        this.ConstructEntry = class WorkdirEntry {\n          constructor(fullpath) {\n            this._fullpath = fullpath;\n            this._type = false;\n            this._mode = false;\n            this._stat = false;\n            this._content = false;\n            this._oid = false;\n          }\n          async type() {\n            return walker.type(this);\n          }\n          async mode() {\n            return walker.mode(this);\n          }\n          async stat() {\n            return walker.stat(this);\n          }\n          async content() {\n            return walker.content(this);\n          }\n          async oid() {\n            return walker.oid(this);\n          }\n        };\n      }\n      async readdir(entry) {\n        const filepath = entry._fullpath;\n        const { fs: fs2, dir } = this;\n        const names = await fs2.readdir(join2(dir, filepath));\n        if (names === null) return null;\n        return names.map((name) => join2(filepath, name));\n      }\n      async type(entry) {\n        if (entry._type === false) {\n          await entry.stat();\n        }\n        return entry._type;\n      }\n      async mode(entry) {\n        if (entry._mode === false) {\n          await entry.stat();\n        }\n        return entry._mode;\n      }\n      async stat(entry) {\n        if (entry._stat === false) {\n          const { fs: fs2, dir } = this;\n          let stat = await fs2.lstat(`${dir}/${entry._fullpath}`);\n          if (!stat) {\n            throw new Error(\n              `ENOENT: no such file or directory, lstat '${entry._fullpath}'`\n            );\n          }\n          let type = stat.isDirectory() ? \"tree\" : \"blob\";\n          if (type === \"blob\" && !stat.isFile() && !stat.isSymbolicLink()) {\n            type = \"special\";\n          }\n          entry._type = type;\n          stat = normalizeStats(stat);\n          entry._mode = stat.mode;\n          if (stat.size === -1 && entry._actualSize) {\n            stat.size = entry._actualSize;\n          }\n          entry._stat = stat;\n        }\n        return entry._stat;\n      }\n      async content(entry) {\n        if (entry._content === false) {\n          const { fs: fs2, dir, gitdir } = this;\n          if (await entry.type() === \"tree\") {\n            entry._content = void 0;\n          } else {\n            const config = await GitConfigManager.get({ fs: fs2, gitdir });\n            const autocrlf = await config.get(\"core.autocrlf\");\n            const content = await fs2.read(`${dir}/${entry._fullpath}`, { autocrlf });\n            entry._actualSize = content.length;\n            if (entry._stat && entry._stat.size === -1) {\n              entry._stat.size = entry._actualSize;\n            }\n            entry._content = new Uint8Array(content);\n          }\n        }\n        return entry._content;\n      }\n      async oid(entry) {\n        if (entry._oid === false) {\n          const { fs: fs2, gitdir, cache } = this;\n          let oid;\n          await GitIndexManager.acquire({ fs: fs2, gitdir, cache }, async function(index2) {\n            const stage2 = index2.entriesMap.get(entry._fullpath);\n            const stats = await entry.stat();\n            const config = await GitConfigManager.get({ fs: fs2, gitdir });\n            const filemode = await config.get(\"core.filemode\");\n            const trustino = typeof process !== \"undefined\" ? !(process.platform === \"win32\") : true;\n            if (!stage2 || compareStats(stats, stage2, filemode, trustino)) {\n              const content = await entry.content();\n              if (content === void 0) {\n                oid = void 0;\n              } else {\n                oid = await shasum(\n                  GitObject.wrap({ type: \"blob\", object: await entry.content() })\n                );\n                if (stage2 && oid === stage2.oid && (!filemode || stats.mode === stage2.mode) && compareStats(stats, stage2, filemode, trustino)) {\n                  index2.insert({\n                    filepath: entry._fullpath,\n                    stats,\n                    oid\n                  });\n                }\n              }\n            } else {\n              oid = stage2.oid;\n            }\n          });\n          entry._oid = oid;\n        }\n        return entry._oid;\n      }\n    };\n    function WORKDIR() {\n      const o = /* @__PURE__ */ Object.create(null);\n      Object.defineProperty(o, GitWalkSymbol, {\n        value: function({ fs: fs2, dir, gitdir, cache }) {\n          return new GitWalkerFs({ fs: fs2, dir, gitdir, cache });\n        }\n      });\n      Object.freeze(o);\n      return o;\n    }\n    function arrayRange(start, end) {\n      const length = end - start;\n      return Array.from({ length }, (_, i) => start + i);\n    }\n    var flat = typeof Array.prototype.flat === \"undefined\" ? (entries) => entries.reduce((acc, x) => acc.concat(x), []) : (entries) => entries.flat();\n    var RunningMinimum = class {\n      constructor() {\n        this.value = null;\n      }\n      consider(value) {\n        if (value === null || value === void 0) return;\n        if (this.value === null) {\n          this.value = value;\n        } else if (value < this.value) {\n          this.value = value;\n        }\n      }\n      reset() {\n        this.value = null;\n      }\n    };\n    function* unionOfIterators(sets) {\n      const min = new RunningMinimum();\n      let minimum;\n      const heads = [];\n      const numsets = sets.length;\n      for (let i = 0; i < numsets; i++) {\n        heads[i] = sets[i].next().value;\n        if (heads[i] !== void 0) {\n          min.consider(heads[i]);\n        }\n      }\n      if (min.value === null) return;\n      while (true) {\n        const result = [];\n        minimum = min.value;\n        min.reset();\n        for (let i = 0; i < numsets; i++) {\n          if (heads[i] !== void 0 && heads[i] === minimum) {\n            result[i] = heads[i];\n            heads[i] = sets[i].next().value;\n          } else {\n            result[i] = null;\n          }\n          if (heads[i] !== void 0) {\n            min.consider(heads[i]);\n          }\n        }\n        yield result;\n        if (min.value === null) return;\n      }\n    }\n    async function _walk({\n      fs: fs2,\n      cache,\n      dir,\n      gitdir,\n      trees,\n      // @ts-ignore\n      map = async (_, entry) => entry,\n      // The default reducer is a flatmap that filters out undefineds.\n      reduce = async (parent, children) => {\n        const flatten = flat(children);\n        if (parent !== void 0) flatten.unshift(parent);\n        return flatten;\n      },\n      // The default iterate function walks all children concurrently\n      iterate = (walk2, children) => Promise.all([...children].map(walk2))\n    }) {\n      const walkers = trees.map(\n        (proxy) => proxy[GitWalkSymbol]({ fs: fs2, dir, gitdir, cache })\n      );\n      const root = new Array(walkers.length).fill(\".\");\n      const range2 = arrayRange(0, walkers.length);\n      const unionWalkerFromReaddir = async (entries) => {\n        range2.map((i) => {\n          entries[i] = entries[i] && new walkers[i].ConstructEntry(entries[i]);\n        });\n        const subdirs = await Promise.all(\n          range2.map((i) => entries[i] ? walkers[i].readdir(entries[i]) : [])\n        );\n        const iterators = subdirs.map((array) => array === null ? [] : array).map((array) => array[Symbol.iterator]());\n        return {\n          entries,\n          children: unionOfIterators(iterators)\n        };\n      };\n      const walk2 = async (root2) => {\n        const { entries, children } = await unionWalkerFromReaddir(root2);\n        const fullpath = entries.find((entry) => entry && entry._fullpath)._fullpath;\n        const parent = await map(fullpath, entries);\n        if (parent !== null) {\n          let walkedChildren = await iterate(walk2, children);\n          walkedChildren = walkedChildren.filter((x) => x !== void 0);\n          return reduce(parent, walkedChildren);\n        }\n      };\n      return walk2(root);\n    }\n    async function rmRecursive(fs2, filepath) {\n      const entries = await fs2.readdir(filepath);\n      if (entries == null) {\n        await fs2.rm(filepath);\n      } else if (entries.length) {\n        await Promise.all(\n          entries.map((entry) => {\n            const subpath = join2(filepath, entry);\n            return fs2.lstat(subpath).then((stat) => {\n              if (!stat) return;\n              return stat.isDirectory() ? rmRecursive(fs2, subpath) : fs2.rm(subpath);\n            });\n          })\n        ).then(() => fs2.rmdir(filepath));\n      } else {\n        await fs2.rmdir(filepath);\n      }\n    }\n    function isPromiseLike(obj) {\n      return isObject(obj) && isFunction(obj.then) && isFunction(obj.catch);\n    }\n    function isObject(obj) {\n      return obj && typeof obj === \"object\";\n    }\n    function isFunction(obj) {\n      return typeof obj === \"function\";\n    }\n    function isPromiseFs(fs2) {\n      const test = (targetFs) => {\n        try {\n          return targetFs.readFile().catch((e) => e);\n        } catch (e) {\n          return e;\n        }\n      };\n      return isPromiseLike(test(fs2));\n    }\n    var commands = [\n      \"readFile\",\n      \"writeFile\",\n      \"mkdir\",\n      \"rmdir\",\n      \"unlink\",\n      \"stat\",\n      \"lstat\",\n      \"readdir\",\n      \"readlink\",\n      \"symlink\"\n    ];\n    function bindFs(target, fs2) {\n      if (isPromiseFs(fs2)) {\n        for (const command of commands) {\n          target[`_${command}`] = fs2[command].bind(fs2);\n        }\n      } else {\n        for (const command of commands) {\n          target[`_${command}`] = pify(fs2[command].bind(fs2));\n        }\n      }\n      if (isPromiseFs(fs2)) {\n        if (fs2.rm) target._rm = fs2.rm.bind(fs2);\n        else if (fs2.rmdir.length > 1) target._rm = fs2.rmdir.bind(fs2);\n        else target._rm = rmRecursive.bind(null, target);\n      } else {\n        if (fs2.rm) target._rm = pify(fs2.rm.bind(fs2));\n        else if (fs2.rmdir.length > 2) target._rm = pify(fs2.rmdir.bind(fs2));\n        else target._rm = rmRecursive.bind(null, target);\n      }\n    }\n    var FileSystem = class {\n      constructor(fs2) {\n        if (typeof fs2._original_unwrapped_fs !== \"undefined\") return fs2;\n        const promises = Object.getOwnPropertyDescriptor(fs2, \"promises\");\n        if (promises && promises.enumerable) {\n          bindFs(this, fs2.promises);\n        } else {\n          bindFs(this, fs2);\n        }\n        this._original_unwrapped_fs = fs2;\n      }\n      /**\n       * Return true if a file exists, false if it doesn't exist.\n       * Rethrows errors that aren't related to file existence.\n       */\n      async exists(filepath, options = {}) {\n        try {\n          await this._stat(filepath);\n          return true;\n        } catch (err) {\n          if (err.code === \"ENOENT\" || err.code === \"ENOTDIR\") {\n            return false;\n          } else {\n            console.log('Unhandled error in \"FileSystem.exists()\" function', err);\n            throw err;\n          }\n        }\n      }\n      /**\n       * Return the contents of a file if it exists, otherwise returns null.\n       *\n       * @param {string} filepath\n       * @param {object} [options]\n       *\n       * @returns {Promise<Buffer|string|null>}\n       */\n      async read(filepath, options = {}) {\n        try {\n          let buffer = await this._readFile(filepath, options);\n          if (options.autocrlf === \"true\") {\n            try {\n              buffer = new TextDecoder(\"utf8\", { fatal: true }).decode(buffer);\n              buffer = buffer.replace(/\\r\\n/g, \"\\n\");\n              buffer = new TextEncoder().encode(buffer);\n            } catch (error) {\n            }\n          }\n          if (typeof buffer !== \"string\") {\n            buffer = Buffer.from(buffer);\n          }\n          return buffer;\n        } catch (err) {\n          return null;\n        }\n      }\n      /**\n       * Write a file (creating missing directories if need be) without throwing errors.\n       *\n       * @param {string} filepath\n       * @param {Buffer|Uint8Array|string} contents\n       * @param {object|string} [options]\n       */\n      async write(filepath, contents, options = {}) {\n        try {\n          await this._writeFile(filepath, contents, options);\n          return;\n        } catch (err) {\n          await this.mkdir(dirname(filepath));\n          await this._writeFile(filepath, contents, options);\n        }\n      }\n      /**\n       * Make a directory (or series of nested directories) without throwing an error if it already exists.\n       */\n      async mkdir(filepath, _selfCall = false) {\n        try {\n          await this._mkdir(filepath);\n          return;\n        } catch (err) {\n          if (err === null) return;\n          if (err.code === \"EEXIST\") return;\n          if (_selfCall) throw err;\n          if (err.code === \"ENOENT\") {\n            const parent = dirname(filepath);\n            if (parent === \".\" || parent === \"/\" || parent === filepath) throw err;\n            await this.mkdir(parent);\n            await this.mkdir(filepath, true);\n          }\n        }\n      }\n      /**\n       * Delete a file without throwing an error if it is already deleted.\n       */\n      async rm(filepath) {\n        try {\n          await this._unlink(filepath);\n        } catch (err) {\n          if (err.code !== \"ENOENT\") throw err;\n        }\n      }\n      /**\n       * Delete a directory without throwing an error if it is already deleted.\n       */\n      async rmdir(filepath, opts) {\n        try {\n          if (opts && opts.recursive) {\n            await this._rm(filepath, opts);\n          } else {\n            await this._rmdir(filepath);\n          }\n        } catch (err) {\n          if (err.code !== \"ENOENT\") throw err;\n        }\n      }\n      /**\n       * Read a directory without throwing an error is the directory doesn't exist\n       */\n      async readdir(filepath) {\n        try {\n          const names = await this._readdir(filepath);\n          names.sort(compareStrings);\n          return names;\n        } catch (err) {\n          if (err.code === \"ENOTDIR\") return null;\n          return [];\n        }\n      }\n      /**\n       * Return a flast list of all the files nested inside a directory\n       *\n       * Based on an elegant concurrent recursive solution from SO\n       * https://stackoverflow.com/a/45130990/2168416\n       */\n      async readdirDeep(dir) {\n        const subdirs = await this._readdir(dir);\n        const files = await Promise.all(\n          subdirs.map(async (subdir) => {\n            const res = dir + \"/\" + subdir;\n            return (await this._stat(res)).isDirectory() ? this.readdirDeep(res) : res;\n          })\n        );\n        return files.reduce((a, f) => a.concat(f), []);\n      }\n      /**\n       * Return the Stats of a file/symlink if it exists, otherwise returns null.\n       * Rethrows errors that aren't related to file existence.\n       */\n      async lstat(filename) {\n        try {\n          const stats = await this._lstat(filename);\n          return stats;\n        } catch (err) {\n          if (err.code === \"ENOENT\") {\n            return null;\n          }\n          throw err;\n        }\n      }\n      /**\n       * Reads the contents of a symlink if it exists, otherwise returns null.\n       * Rethrows errors that aren't related to file existence.\n       */\n      async readlink(filename, opts = { encoding: \"buffer\" }) {\n        try {\n          const link = await this._readlink(filename, opts);\n          return Buffer.isBuffer(link) ? link : Buffer.from(link);\n        } catch (err) {\n          if (err.code === \"ENOENT\") {\n            return null;\n          }\n          throw err;\n        }\n      }\n      /**\n       * Write the contents of buffer to a symlink.\n       */\n      async writelink(filename, buffer) {\n        return this._symlink(buffer.toString(\"utf8\"), filename);\n      }\n    };\n    function assertParameter(name, value) {\n      if (value === void 0) {\n        throw new MissingParameterError(name);\n      }\n    }\n    async function modified(entry, base) {\n      if (!entry && !base) return false;\n      if (entry && !base) return true;\n      if (!entry && base) return true;\n      if (await entry.type() === \"tree\" && await base.type() === \"tree\") {\n        return false;\n      }\n      if (await entry.type() === await base.type() && await entry.mode() === await base.mode() && await entry.oid() === await base.oid()) {\n        return false;\n      }\n      return true;\n    }\n    async function abortMerge({\n      fs: _fs,\n      dir,\n      gitdir = join2(dir, \".git\"),\n      commit: commit3 = \"HEAD\",\n      cache = {}\n    }) {\n      try {\n        assertParameter(\"fs\", _fs);\n        assertParameter(\"dir\", dir);\n        assertParameter(\"gitdir\", gitdir);\n        const fs2 = new FileSystem(_fs);\n        const trees = [TREE({ ref: commit3 }), WORKDIR(), STAGE()];\n        let unmergedPaths = [];\n        await GitIndexManager.acquire({ fs: fs2, gitdir, cache }, async function(index2) {\n          unmergedPaths = index2.unmergedPaths;\n        });\n        const results = await _walk({\n          fs: fs2,\n          cache,\n          dir,\n          gitdir,\n          trees,\n          map: async function(path2, [head, workdir, index2]) {\n            const staged = !await modified(workdir, index2);\n            const unmerged = unmergedPaths.includes(path2);\n            const unmodified = !await modified(index2, head);\n            if (staged || unmerged) {\n              return head ? {\n                path: path2,\n                mode: await head.mode(),\n                oid: await head.oid(),\n                type: await head.type(),\n                content: await head.content()\n              } : void 0;\n            }\n            if (unmodified) return false;\n            else throw new IndexResetError(path2);\n          }\n        });\n        await GitIndexManager.acquire({ fs: fs2, gitdir, cache }, async function(index2) {\n          for (const entry of results) {\n            if (entry === false) continue;\n            if (!entry) {\n              await fs2.rmdir(`${dir}/${entry.path}`, { recursive: true });\n              index2.delete({ filepath: entry.path });\n              continue;\n            }\n            if (entry.type === \"blob\") {\n              const content = new TextDecoder().decode(entry.content);\n              await fs2.write(`${dir}/${entry.path}`, content, { mode: entry.mode });\n              index2.insert({\n                filepath: entry.path,\n                oid: entry.oid,\n                stage: 0\n              });\n            }\n          }\n        });\n      } catch (err) {\n        err.caller = \"git.abortMerge\";\n        throw err;\n      }\n    }\n    var GitIgnoreManager = class {\n      static async isIgnored({ fs: fs2, dir, gitdir = join2(dir, \".git\"), filepath }) {\n        if (basename(filepath) === \".git\") return true;\n        if (filepath === \".\") return false;\n        let excludes = \"\";\n        const excludesFile = join2(gitdir, \"info\", \"exclude\");\n        if (await fs2.exists(excludesFile)) {\n          excludes = await fs2.read(excludesFile, \"utf8\");\n        }\n        const pairs = [\n          {\n            gitignore: join2(dir, \".gitignore\"),\n            filepath\n          }\n        ];\n        const pieces = filepath.split(\"/\").filter(Boolean);\n        for (let i = 1; i < pieces.length; i++) {\n          const folder = pieces.slice(0, i).join(\"/\");\n          const file = pieces.slice(i).join(\"/\");\n          pairs.push({\n            gitignore: join2(dir, folder, \".gitignore\"),\n            filepath: file\n          });\n        }\n        let ignoredStatus = false;\n        for (const p of pairs) {\n          let file;\n          try {\n            file = await fs2.read(p.gitignore, \"utf8\");\n          } catch (err) {\n            if (err.code === \"NOENT\") continue;\n          }\n          const ign = ignore().add(excludes);\n          ign.add(file);\n          const parentdir = dirname(p.filepath);\n          if (parentdir !== \".\" && ign.ignores(parentdir)) return true;\n          if (ignoredStatus) {\n            ignoredStatus = !ign.test(p.filepath).unignored;\n          } else {\n            ignoredStatus = ign.test(p.filepath).ignored;\n          }\n        }\n        return ignoredStatus;\n      }\n    };\n    async function writeObjectLoose({ fs: fs2, gitdir, object, format, oid }) {\n      if (format !== \"deflated\") {\n        throw new InternalError(\n          \"GitObjectStoreLoose expects objects to write to be in deflated format\"\n        );\n      }\n      const source = `objects/${oid.slice(0, 2)}/${oid.slice(2)}`;\n      const filepath = `${gitdir}/${source}`;\n      if (!await fs2.exists(filepath)) await fs2.write(filepath, object);\n    }\n    var supportsCompressionStream = null;\n    async function deflate(buffer) {\n      if (supportsCompressionStream === null) {\n        supportsCompressionStream = testCompressionStream();\n      }\n      return supportsCompressionStream ? browserDeflate(buffer) : pako.deflate(buffer);\n    }\n    async function browserDeflate(buffer) {\n      const cs = new CompressionStream(\"deflate\");\n      const c = new Blob([buffer]).stream().pipeThrough(cs);\n      return new Uint8Array(await new Response(c).arrayBuffer());\n    }\n    function testCompressionStream() {\n      try {\n        const cs = new CompressionStream(\"deflate\");\n        cs.writable.close();\n        const stream = new Blob([]).stream();\n        stream.cancel();\n        return true;\n      } catch (_) {\n        return false;\n      }\n    }\n    async function _writeObject({\n      fs: fs2,\n      gitdir,\n      type,\n      object,\n      format = \"content\",\n      oid = void 0,\n      dryRun = false\n    }) {\n      if (format !== \"deflated\") {\n        if (format !== \"wrapped\") {\n          object = GitObject.wrap({ type, object });\n        }\n        oid = await shasum(object);\n        object = Buffer.from(await deflate(object));\n      }\n      if (!dryRun) {\n        await writeObjectLoose({ fs: fs2, gitdir, object, format: \"deflated\", oid });\n      }\n      return oid;\n    }\n    function posixifyPathBuffer(buffer) {\n      let idx;\n      while (~(idx = buffer.indexOf(92))) buffer[idx] = 47;\n      return buffer;\n    }\n    async function add({\n      fs: _fs,\n      dir,\n      gitdir = join2(dir, \".git\"),\n      filepath,\n      cache = {},\n      force = false,\n      parallel = true\n    }) {\n      try {\n        assertParameter(\"fs\", _fs);\n        assertParameter(\"dir\", dir);\n        assertParameter(\"gitdir\", gitdir);\n        assertParameter(\"filepath\", filepath);\n        const fs2 = new FileSystem(_fs);\n        await GitIndexManager.acquire({ fs: fs2, gitdir, cache }, async (index2) => {\n          return addToIndex({\n            dir,\n            gitdir,\n            fs: fs2,\n            filepath,\n            index: index2,\n            force,\n            parallel\n          });\n        });\n      } catch (err) {\n        err.caller = \"git.add\";\n        throw err;\n      }\n    }\n    async function addToIndex({\n      dir,\n      gitdir,\n      fs: fs2,\n      filepath,\n      index: index2,\n      force,\n      parallel\n    }) {\n      filepath = Array.isArray(filepath) ? filepath : [filepath];\n      const promises = filepath.map(async (currentFilepath) => {\n        if (!force) {\n          const ignored = await GitIgnoreManager.isIgnored({\n            fs: fs2,\n            dir,\n            gitdir,\n            filepath: currentFilepath\n          });\n          if (ignored) return;\n        }\n        const stats = await fs2.lstat(join2(dir, currentFilepath));\n        if (!stats) throw new NotFoundError(currentFilepath);\n        if (stats.isDirectory()) {\n          const children = await fs2.readdir(join2(dir, currentFilepath));\n          if (parallel) {\n            const promises2 = children.map(\n              (child) => addToIndex({\n                dir,\n                gitdir,\n                fs: fs2,\n                filepath: [join2(currentFilepath, child)],\n                index: index2,\n                force,\n                parallel\n              })\n            );\n            await Promise.all(promises2);\n          } else {\n            for (const child of children) {\n              await addToIndex({\n                dir,\n                gitdir,\n                fs: fs2,\n                filepath: [join2(currentFilepath, child)],\n                index: index2,\n                force,\n                parallel\n              });\n            }\n          }\n        } else {\n          const config = await GitConfigManager.get({ fs: fs2, gitdir });\n          const autocrlf = await config.get(\"core.autocrlf\");\n          const object = stats.isSymbolicLink() ? await fs2.readlink(join2(dir, currentFilepath)).then(posixifyPathBuffer) : await fs2.read(join2(dir, currentFilepath), { autocrlf });\n          if (object === null) throw new NotFoundError(currentFilepath);\n          const oid = await _writeObject({ fs: fs2, gitdir, type: \"blob\", object });\n          index2.insert({ filepath: currentFilepath, stats, oid });\n        }\n      });\n      const settledPromises = await Promise.allSettled(promises);\n      const rejectedPromises = settledPromises.filter((settle) => settle.status === \"rejected\").map((settle) => settle.reason);\n      if (rejectedPromises.length > 1) {\n        throw new MultipleGitError(rejectedPromises);\n      }\n      if (rejectedPromises.length === 1) {\n        throw rejectedPromises[0];\n      }\n      const fulfilledPromises = settledPromises.filter((settle) => settle.status === \"fulfilled\" && settle.value).map((settle) => settle.value);\n      return fulfilledPromises;\n    }\n    async function _getConfig({ fs: fs2, gitdir, path: path2 }) {\n      const config = await GitConfigManager.get({ fs: fs2, gitdir });\n      return config.get(path2);\n    }\n    function assignDefined(target, ...sources) {\n      for (const source of sources) {\n        if (source) {\n          for (const key of Object.keys(source)) {\n            const val = source[key];\n            if (val !== void 0) {\n              target[key] = val;\n            }\n          }\n        }\n      }\n      return target;\n    }\n    async function normalizeAuthorObject({ fs: fs2, gitdir, author: author2, commit: commit3 }) {\n      const timestamp = Math.floor(Date.now() / 1e3);\n      const defaultAuthor = {\n        name: await _getConfig({ fs: fs2, gitdir, path: \"user.name\" }),\n        email: await _getConfig({ fs: fs2, gitdir, path: \"user.email\" }) || \"\",\n        // author.email is allowed to be empty string\n        timestamp,\n        timezoneOffset: new Date(timestamp * 1e3).getTimezoneOffset()\n      };\n      const normalizedAuthor = assignDefined(\n        {},\n        defaultAuthor,\n        commit3 ? commit3.author : void 0,\n        author2\n      );\n      if (normalizedAuthor.name === void 0) {\n        return void 0;\n      }\n      return normalizedAuthor;\n    }\n    async function normalizeCommitterObject({\n      fs: fs2,\n      gitdir,\n      author: author2,\n      committer,\n      commit: commit3\n    }) {\n      const timestamp = Math.floor(Date.now() / 1e3);\n      const defaultCommitter = {\n        name: await _getConfig({ fs: fs2, gitdir, path: \"user.name\" }),\n        email: await _getConfig({ fs: fs2, gitdir, path: \"user.email\" }) || \"\",\n        // committer.email is allowed to be empty string\n        timestamp,\n        timezoneOffset: new Date(timestamp * 1e3).getTimezoneOffset()\n      };\n      const normalizedCommitter = assignDefined(\n        {},\n        defaultCommitter,\n        commit3 ? commit3.committer : void 0,\n        author2,\n        committer\n      );\n      if (normalizedCommitter.name === void 0) {\n        return void 0;\n      }\n      return normalizedCommitter;\n    }\n    async function resolveCommit({ fs: fs2, cache, gitdir, oid }) {\n      const { type, object } = await _readObject({ fs: fs2, cache, gitdir, oid });\n      if (type === \"tag\") {\n        oid = GitAnnotatedTag.from(object).parse().object;\n        return resolveCommit({ fs: fs2, cache, gitdir, oid });\n      }\n      if (type !== \"commit\") {\n        throw new ObjectTypeError(oid, type, \"commit\");\n      }\n      return { commit: GitCommit.from(object), oid };\n    }\n    async function _readCommit({ fs: fs2, cache, gitdir, oid }) {\n      const { commit: commit3, oid: commitOid } = await resolveCommit({\n        fs: fs2,\n        cache,\n        gitdir,\n        oid\n      });\n      const result = {\n        oid: commitOid,\n        commit: commit3.parse(),\n        payload: commit3.withoutSignature()\n      };\n      return result;\n    }\n    async function _commit({\n      fs: fs2,\n      cache,\n      onSign,\n      gitdir,\n      message,\n      author: _author,\n      committer: _committer,\n      signingKey,\n      amend = false,\n      dryRun = false,\n      noUpdateBranch = false,\n      ref,\n      parent,\n      tree\n    }) {\n      let initialCommit = false;\n      if (!ref) {\n        ref = await GitRefManager.resolve({\n          fs: fs2,\n          gitdir,\n          ref: \"HEAD\",\n          depth: 2\n        });\n      }\n      let refOid, refCommit;\n      try {\n        refOid = await GitRefManager.resolve({\n          fs: fs2,\n          gitdir,\n          ref\n        });\n        refCommit = await _readCommit({ fs: fs2, gitdir, oid: refOid, cache: {} });\n      } catch {\n        initialCommit = true;\n      }\n      if (amend && initialCommit) {\n        throw new NoCommitError(ref);\n      }\n      const author2 = !amend ? await normalizeAuthorObject({ fs: fs2, gitdir, author: _author }) : await normalizeAuthorObject({\n        fs: fs2,\n        gitdir,\n        author: _author,\n        commit: refCommit.commit\n      });\n      if (!author2) throw new MissingNameError(\"author\");\n      const committer = !amend ? await normalizeCommitterObject({\n        fs: fs2,\n        gitdir,\n        author: author2,\n        committer: _committer\n      }) : await normalizeCommitterObject({\n        fs: fs2,\n        gitdir,\n        author: author2,\n        committer: _committer,\n        commit: refCommit.commit\n      });\n      if (!committer) throw new MissingNameError(\"committer\");\n      return GitIndexManager.acquire(\n        { fs: fs2, gitdir, cache, allowUnmerged: false },\n        async function(index2) {\n          const inodes = flatFileListToDirectoryStructure(index2.entries);\n          const inode = inodes.get(\".\");\n          if (!tree) {\n            tree = await constructTree({ fs: fs2, gitdir, inode, dryRun });\n          }\n          if (!parent) {\n            if (!amend) {\n              parent = refOid ? [refOid] : [];\n            } else {\n              parent = refCommit.commit.parent;\n            }\n          } else {\n            parent = await Promise.all(\n              parent.map((p) => {\n                return GitRefManager.resolve({ fs: fs2, gitdir, ref: p });\n              })\n            );\n          }\n          if (!message) {\n            if (!amend) {\n              throw new MissingParameterError(\"message\");\n            } else {\n              message = refCommit.commit.message;\n            }\n          }\n          let comm = GitCommit.from({\n            tree,\n            parent,\n            author: author2,\n            committer,\n            message\n          });\n          if (signingKey) {\n            comm = await GitCommit.sign(comm, onSign, signingKey);\n          }\n          const oid = await _writeObject({\n            fs: fs2,\n            gitdir,\n            type: \"commit\",\n            object: comm.toObject(),\n            dryRun\n          });\n          if (!noUpdateBranch && !dryRun) {\n            await GitRefManager.writeRef({\n              fs: fs2,\n              gitdir,\n              ref,\n              value: oid\n            });\n          }\n          return oid;\n        }\n      );\n    }\n    async function constructTree({ fs: fs2, gitdir, inode, dryRun }) {\n      const children = inode.children;\n      for (const inode2 of children) {\n        if (inode2.type === \"tree\") {\n          inode2.metadata.mode = \"040000\";\n          inode2.metadata.oid = await constructTree({ fs: fs2, gitdir, inode: inode2, dryRun });\n        }\n      }\n      const entries = children.map((inode2) => ({\n        mode: inode2.metadata.mode,\n        path: inode2.basename,\n        oid: inode2.metadata.oid,\n        type: inode2.type\n      }));\n      const tree = GitTree.from(entries);\n      const oid = await _writeObject({\n        fs: fs2,\n        gitdir,\n        type: \"tree\",\n        object: tree.toObject(),\n        dryRun\n      });\n      return oid;\n    }\n    async function resolveFilepath({ fs: fs2, cache, gitdir, oid, filepath }) {\n      if (filepath.startsWith(\"/\")) {\n        throw new InvalidFilepathError(\"leading-slash\");\n      } else if (filepath.endsWith(\"/\")) {\n        throw new InvalidFilepathError(\"trailing-slash\");\n      }\n      const _oid = oid;\n      const result = await resolveTree({ fs: fs2, cache, gitdir, oid });\n      const tree = result.tree;\n      if (filepath === \"\") {\n        oid = result.oid;\n      } else {\n        const pathArray = filepath.split(\"/\");\n        oid = await _resolveFilepath({\n          fs: fs2,\n          cache,\n          gitdir,\n          tree,\n          pathArray,\n          oid: _oid,\n          filepath\n        });\n      }\n      return oid;\n    }\n    async function _resolveFilepath({\n      fs: fs2,\n      cache,\n      gitdir,\n      tree,\n      pathArray,\n      oid,\n      filepath\n    }) {\n      const name = pathArray.shift();\n      for (const entry of tree) {\n        if (entry.path === name) {\n          if (pathArray.length === 0) {\n            return entry.oid;\n          } else {\n            const { type, object } = await _readObject({\n              fs: fs2,\n              cache,\n              gitdir,\n              oid: entry.oid\n            });\n            if (type !== \"tree\") {\n              throw new ObjectTypeError(oid, type, \"tree\", filepath);\n            }\n            tree = GitTree.from(object);\n            return _resolveFilepath({\n              fs: fs2,\n              cache,\n              gitdir,\n              tree,\n              pathArray,\n              oid,\n              filepath\n            });\n          }\n        }\n      }\n      throw new NotFoundError(`file or directory found at \"${oid}:${filepath}\"`);\n    }\n    async function _readTree({\n      fs: fs2,\n      cache,\n      gitdir,\n      oid,\n      filepath = void 0\n    }) {\n      if (filepath !== void 0) {\n        oid = await resolveFilepath({ fs: fs2, cache, gitdir, oid, filepath });\n      }\n      const { tree, oid: treeOid } = await resolveTree({ fs: fs2, cache, gitdir, oid });\n      const result = {\n        oid: treeOid,\n        tree: tree.entries()\n      };\n      return result;\n    }\n    async function _writeTree({ fs: fs2, gitdir, tree }) {\n      const object = GitTree.from(tree).toObject();\n      const oid = await _writeObject({\n        fs: fs2,\n        gitdir,\n        type: \"tree\",\n        object,\n        format: \"content\"\n      });\n      return oid;\n    }\n    async function _addNote({\n      fs: fs2,\n      cache,\n      onSign,\n      gitdir,\n      ref,\n      oid,\n      note,\n      force,\n      author: author2,\n      committer,\n      signingKey\n    }) {\n      let parent;\n      try {\n        parent = await GitRefManager.resolve({ gitdir, fs: fs2, ref });\n      } catch (err) {\n        if (!(err instanceof NotFoundError)) {\n          throw err;\n        }\n      }\n      const result = await _readTree({\n        fs: fs2,\n        cache,\n        gitdir,\n        oid: parent || \"4b825dc642cb6eb9a060e54bf8d69288fbee4904\"\n      });\n      let tree = result.tree;\n      if (force) {\n        tree = tree.filter((entry) => entry.path !== oid);\n      } else {\n        for (const entry of tree) {\n          if (entry.path === oid) {\n            throw new AlreadyExistsError(\"note\", oid);\n          }\n        }\n      }\n      if (typeof note === \"string\") {\n        note = Buffer.from(note, \"utf8\");\n      }\n      const noteOid = await _writeObject({\n        fs: fs2,\n        gitdir,\n        type: \"blob\",\n        object: note,\n        format: \"content\"\n      });\n      tree.push({ mode: \"100644\", path: oid, oid: noteOid, type: \"blob\" });\n      const treeOid = await _writeTree({\n        fs: fs2,\n        gitdir,\n        tree\n      });\n      const commitOid = await _commit({\n        fs: fs2,\n        cache,\n        onSign,\n        gitdir,\n        ref,\n        tree: treeOid,\n        parent: parent && [parent],\n        message: `Note added by 'isomorphic-git addNote'\n`,\n        author: author2,\n        committer,\n        signingKey\n      });\n      return commitOid;\n    }\n    async function addNote({\n      fs: _fs,\n      onSign,\n      dir,\n      gitdir = join2(dir, \".git\"),\n      ref = \"refs/notes/commits\",\n      oid,\n      note,\n      force,\n      author: _author,\n      committer: _committer,\n      signingKey,\n      cache = {}\n    }) {\n      try {\n        assertParameter(\"fs\", _fs);\n        assertParameter(\"gitdir\", gitdir);\n        assertParameter(\"oid\", oid);\n        assertParameter(\"note\", note);\n        if (signingKey) {\n          assertParameter(\"onSign\", onSign);\n        }\n        const fs2 = new FileSystem(_fs);\n        const author2 = await normalizeAuthorObject({ fs: fs2, gitdir, author: _author });\n        if (!author2) throw new MissingNameError(\"author\");\n        const committer = await normalizeCommitterObject({\n          fs: fs2,\n          gitdir,\n          author: author2,\n          committer: _committer\n        });\n        if (!committer) throw new MissingNameError(\"committer\");\n        return await _addNote({\n          fs: new FileSystem(fs2),\n          cache,\n          onSign,\n          gitdir,\n          ref,\n          oid,\n          note,\n          force,\n          author: author2,\n          committer,\n          signingKey\n        });\n      } catch (err) {\n        err.caller = \"git.addNote\";\n        throw err;\n      }\n    }\n    async function _addRemote({ fs: fs2, gitdir, remote, url, force }) {\n      if (remote !== cleanGitRef.clean(remote)) {\n        throw new InvalidRefNameError(remote, cleanGitRef.clean(remote));\n      }\n      const config = await GitConfigManager.get({ fs: fs2, gitdir });\n      if (!force) {\n        const remoteNames = await config.getSubsections(\"remote\");\n        if (remoteNames.includes(remote)) {\n          if (url !== await config.get(`remote.${remote}.url`)) {\n            throw new AlreadyExistsError(\"remote\", remote);\n          }\n        }\n      }\n      await config.set(`remote.${remote}.url`, url);\n      await config.set(\n        `remote.${remote}.fetch`,\n        `+refs/heads/*:refs/remotes/${remote}/*`\n      );\n      await GitConfigManager.save({ fs: fs2, gitdir, config });\n    }\n    async function addRemote({\n      fs: fs2,\n      dir,\n      gitdir = join2(dir, \".git\"),\n      remote,\n      url,\n      force = false\n    }) {\n      try {\n        assertParameter(\"fs\", fs2);\n        assertParameter(\"gitdir\", gitdir);\n        assertParameter(\"remote\", remote);\n        assertParameter(\"url\", url);\n        return await _addRemote({\n          fs: new FileSystem(fs2),\n          gitdir,\n          remote,\n          url,\n          force\n        });\n      } catch (err) {\n        err.caller = \"git.addRemote\";\n        throw err;\n      }\n    }\n    async function _annotatedTag({\n      fs: fs2,\n      cache,\n      onSign,\n      gitdir,\n      ref,\n      tagger,\n      message = ref,\n      gpgsig,\n      object,\n      signingKey,\n      force = false\n    }) {\n      ref = ref.startsWith(\"refs/tags/\") ? ref : `refs/tags/${ref}`;\n      if (!force && await GitRefManager.exists({ fs: fs2, gitdir, ref })) {\n        throw new AlreadyExistsError(\"tag\", ref);\n      }\n      const oid = await GitRefManager.resolve({\n        fs: fs2,\n        gitdir,\n        ref: object || \"HEAD\"\n      });\n      const { type } = await _readObject({ fs: fs2, cache, gitdir, oid });\n      let tagObject = GitAnnotatedTag.from({\n        object: oid,\n        type,\n        tag: ref.replace(\"refs/tags/\", \"\"),\n        tagger,\n        message,\n        gpgsig\n      });\n      if (signingKey) {\n        tagObject = await GitAnnotatedTag.sign(tagObject, onSign, signingKey);\n      }\n      const value = await _writeObject({\n        fs: fs2,\n        gitdir,\n        type: \"tag\",\n        object: tagObject.toObject()\n      });\n      await GitRefManager.writeRef({ fs: fs2, gitdir, ref, value });\n    }\n    async function annotatedTag({\n      fs: _fs,\n      onSign,\n      dir,\n      gitdir = join2(dir, \".git\"),\n      ref,\n      tagger: _tagger,\n      message = ref,\n      gpgsig,\n      object,\n      signingKey,\n      force = false,\n      cache = {}\n    }) {\n      try {\n        assertParameter(\"fs\", _fs);\n        assertParameter(\"gitdir\", gitdir);\n        assertParameter(\"ref\", ref);\n        if (signingKey) {\n          assertParameter(\"onSign\", onSign);\n        }\n        const fs2 = new FileSystem(_fs);\n        const tagger = await normalizeAuthorObject({ fs: fs2, gitdir, author: _tagger });\n        if (!tagger) throw new MissingNameError(\"tagger\");\n        return await _annotatedTag({\n          fs: fs2,\n          cache,\n          onSign,\n          gitdir,\n          ref,\n          tagger,\n          message,\n          gpgsig,\n          object,\n          signingKey,\n          force\n        });\n      } catch (err) {\n        err.caller = \"git.annotatedTag\";\n        throw err;\n      }\n    }\n    async function _branch({\n      fs: fs2,\n      gitdir,\n      ref,\n      object,\n      checkout: checkout2 = false,\n      force = false\n    }) {\n      if (ref !== cleanGitRef.clean(ref)) {\n        throw new InvalidRefNameError(ref, cleanGitRef.clean(ref));\n      }\n      const fullref = `refs/heads/${ref}`;\n      if (!force) {\n        const exist = await GitRefManager.exists({ fs: fs2, gitdir, ref: fullref });\n        if (exist) {\n          throw new AlreadyExistsError(\"branch\", ref, false);\n        }\n      }\n      let oid;\n      try {\n        oid = await GitRefManager.resolve({ fs: fs2, gitdir, ref: object || \"HEAD\" });\n      } catch (e) {\n      }\n      if (oid) {\n        await GitRefManager.writeRef({ fs: fs2, gitdir, ref: fullref, value: oid });\n      }\n      if (checkout2) {\n        await GitRefManager.writeSymbolicRef({\n          fs: fs2,\n          gitdir,\n          ref: \"HEAD\",\n          value: fullref\n        });\n      }\n    }\n    async function branch({\n      fs: fs2,\n      dir,\n      gitdir = join2(dir, \".git\"),\n      ref,\n      object,\n      checkout: checkout2 = false,\n      force = false\n    }) {\n      try {\n        assertParameter(\"fs\", fs2);\n        assertParameter(\"gitdir\", gitdir);\n        assertParameter(\"ref\", ref);\n        return await _branch({\n          fs: new FileSystem(fs2),\n          gitdir,\n          ref,\n          object,\n          checkout: checkout2,\n          force\n        });\n      } catch (err) {\n        err.caller = \"git.branch\";\n        throw err;\n      }\n    }\n    var worthWalking = (filepath, root) => {\n      if (filepath === \".\" || root == null || root.length === 0 || root === \".\") {\n        return true;\n      }\n      if (root.length >= filepath.length) {\n        return root.startsWith(filepath);\n      } else {\n        return filepath.startsWith(root);\n      }\n    };\n    async function _checkout({\n      fs: fs2,\n      cache,\n      onProgress,\n      onPostCheckout,\n      dir,\n      gitdir,\n      remote,\n      ref,\n      filepaths,\n      noCheckout,\n      noUpdateHead,\n      dryRun,\n      force,\n      track = true\n    }) {\n      let oldOid;\n      if (onPostCheckout) {\n        try {\n          oldOid = await GitRefManager.resolve({ fs: fs2, gitdir, ref: \"HEAD\" });\n        } catch (err) {\n          oldOid = \"0000000000000000000000000000000000000000\";\n        }\n      }\n      let oid;\n      try {\n        oid = await GitRefManager.resolve({ fs: fs2, gitdir, ref });\n      } catch (err) {\n        if (ref === \"HEAD\") throw err;\n        const remoteRef = `${remote}/${ref}`;\n        oid = await GitRefManager.resolve({\n          fs: fs2,\n          gitdir,\n          ref: remoteRef\n        });\n        if (track) {\n          const config = await GitConfigManager.get({ fs: fs2, gitdir });\n          await config.set(`branch.${ref}.remote`, remote);\n          await config.set(`branch.${ref}.merge`, `refs/heads/${ref}`);\n          await GitConfigManager.save({ fs: fs2, gitdir, config });\n        }\n        await GitRefManager.writeRef({\n          fs: fs2,\n          gitdir,\n          ref: `refs/heads/${ref}`,\n          value: oid\n        });\n      }\n      if (!noCheckout) {\n        let ops;\n        try {\n          ops = await analyze({\n            fs: fs2,\n            cache,\n            onProgress,\n            dir,\n            gitdir,\n            ref,\n            force,\n            filepaths\n          });\n        } catch (err) {\n          if (err instanceof NotFoundError && err.data.what === oid) {\n            throw new CommitNotFetchedError(ref, oid);\n          } else {\n            throw err;\n          }\n        }\n        const conflicts = ops.filter(([method]) => method === \"conflict\").map(([method, fullpath]) => fullpath);\n        if (conflicts.length > 0) {\n          throw new CheckoutConflictError(conflicts);\n        }\n        const errors = ops.filter(([method]) => method === \"error\").map(([method, fullpath]) => fullpath);\n        if (errors.length > 0) {\n          throw new InternalError(errors.join(\", \"));\n        }\n        if (dryRun) {\n          if (onPostCheckout) {\n            await onPostCheckout({\n              previousHead: oldOid,\n              newHead: oid,\n              type: filepaths != null && filepaths.length > 0 ? \"file\" : \"branch\"\n            });\n          }\n          return;\n        }\n        let count2 = 0;\n        const total = ops.length;\n        await GitIndexManager.acquire({ fs: fs2, gitdir, cache }, async function(index2) {\n          await Promise.all(\n            ops.filter(\n              ([method]) => method === \"delete\" || method === \"delete-index\"\n            ).map(async function([method, fullpath]) {\n              const filepath = `${dir}/${fullpath}`;\n              if (method === \"delete\") {\n                await fs2.rm(filepath);\n              }\n              index2.delete({ filepath: fullpath });\n              if (onProgress) {\n                await onProgress({\n                  phase: \"Updating workdir\",\n                  loaded: ++count2,\n                  total\n                });\n              }\n            })\n          );\n        });\n        await GitIndexManager.acquire({ fs: fs2, gitdir, cache }, async function(index2) {\n          for (const [method, fullpath] of ops) {\n            if (method === \"rmdir\" || method === \"rmdir-index\") {\n              const filepath = `${dir}/${fullpath}`;\n              try {\n                if (method === \"rmdir-index\") {\n                  index2.delete({ filepath: fullpath });\n                }\n                await fs2.rmdir(filepath);\n                if (onProgress) {\n                  await onProgress({\n                    phase: \"Updating workdir\",\n                    loaded: ++count2,\n                    total\n                  });\n                }\n              } catch (e) {\n                if (e.code === \"ENOTEMPTY\") {\n                  console.log(\n                    `Did not delete ${fullpath} because directory is not empty`\n                  );\n                } else {\n                  throw e;\n                }\n              }\n            }\n          }\n        });\n        await Promise.all(\n          ops.filter(([method]) => method === \"mkdir\" || method === \"mkdir-index\").map(async function([_, fullpath]) {\n            const filepath = `${dir}/${fullpath}`;\n            await fs2.mkdir(filepath);\n            if (onProgress) {\n              await onProgress({\n                phase: \"Updating workdir\",\n                loaded: ++count2,\n                total\n              });\n            }\n          })\n        );\n        await GitIndexManager.acquire({ fs: fs2, gitdir, cache }, async function(index2) {\n          await Promise.all(\n            ops.filter(\n              ([method]) => method === \"create\" || method === \"create-index\" || method === \"update\" || method === \"mkdir-index\"\n            ).map(async function([method, fullpath, oid2, mode, chmod]) {\n              const filepath = `${dir}/${fullpath}`;\n              try {\n                if (method !== \"create-index\" && method !== \"mkdir-index\") {\n                  const { object } = await _readObject({ fs: fs2, cache, gitdir, oid: oid2 });\n                  if (chmod) {\n                    await fs2.rm(filepath);\n                  }\n                  if (mode === 33188) {\n                    await fs2.write(filepath, object);\n                  } else if (mode === 33261) {\n                    await fs2.write(filepath, object, { mode: 511 });\n                  } else if (mode === 40960) {\n                    await fs2.writelink(filepath, object);\n                  } else {\n                    throw new InternalError(\n                      `Invalid mode 0o${mode.toString(8)} detected in blob ${oid2}`\n                    );\n                  }\n                }\n                const stats = await fs2.lstat(filepath);\n                if (mode === 33261) {\n                  stats.mode = 493;\n                }\n                if (method === \"mkdir-index\") {\n                  stats.mode = 57344;\n                }\n                index2.insert({\n                  filepath: fullpath,\n                  stats,\n                  oid: oid2\n                });\n                if (onProgress) {\n                  await onProgress({\n                    phase: \"Updating workdir\",\n                    loaded: ++count2,\n                    total\n                  });\n                }\n              } catch (e) {\n                console.log(e);\n              }\n            })\n          );\n        });\n        if (onPostCheckout) {\n          await onPostCheckout({\n            previousHead: oldOid,\n            newHead: oid,\n            type: filepaths != null && filepaths.length > 0 ? \"file\" : \"branch\"\n          });\n        }\n      }\n      if (!noUpdateHead) {\n        const fullRef = await GitRefManager.expand({ fs: fs2, gitdir, ref });\n        if (fullRef.startsWith(\"refs/heads\")) {\n          await GitRefManager.writeSymbolicRef({\n            fs: fs2,\n            gitdir,\n            ref: \"HEAD\",\n            value: fullRef\n          });\n        } else {\n          await GitRefManager.writeRef({ fs: fs2, gitdir, ref: \"HEAD\", value: oid });\n        }\n      }\n    }\n    async function analyze({\n      fs: fs2,\n      cache,\n      onProgress,\n      dir,\n      gitdir,\n      ref,\n      force,\n      filepaths\n    }) {\n      let count2 = 0;\n      return _walk({\n        fs: fs2,\n        cache,\n        dir,\n        gitdir,\n        trees: [TREE({ ref }), WORKDIR(), STAGE()],\n        map: async function(fullpath, [commit3, workdir, stage2]) {\n          if (fullpath === \".\") return;\n          if (filepaths && !filepaths.some((base) => worthWalking(fullpath, base))) {\n            return null;\n          }\n          if (onProgress) {\n            await onProgress({ phase: \"Analyzing workdir\", loaded: ++count2 });\n          }\n          const key = [!!stage2, !!commit3, !!workdir].map(Number).join(\"\");\n          switch (key) {\n            // Impossible case.\n            case \"000\":\n              return;\n            // Ignore workdir files that are not tracked and not part of the new commit.\n            case \"001\":\n              if (force && filepaths && filepaths.includes(fullpath)) {\n                return [\"delete\", fullpath];\n              }\n              return;\n            // New entries\n            case \"010\": {\n              switch (await commit3.type()) {\n                case \"tree\": {\n                  return [\"mkdir\", fullpath];\n                }\n                case \"blob\": {\n                  return [\n                    \"create\",\n                    fullpath,\n                    await commit3.oid(),\n                    await commit3.mode()\n                  ];\n                }\n                case \"commit\": {\n                  return [\n                    \"mkdir-index\",\n                    fullpath,\n                    await commit3.oid(),\n                    await commit3.mode()\n                  ];\n                }\n                default: {\n                  return [\n                    \"error\",\n                    `new entry Unhandled type ${await commit3.type()}`\n                  ];\n                }\n              }\n            }\n            // New entries but there is already something in the workdir there.\n            case \"011\": {\n              switch (`${await commit3.type()}-${await workdir.type()}`) {\n                case \"tree-tree\": {\n                  return;\n                }\n                case \"tree-blob\":\n                case \"blob-tree\": {\n                  return [\"conflict\", fullpath];\n                }\n                case \"blob-blob\": {\n                  if (await commit3.oid() !== await workdir.oid()) {\n                    if (force) {\n                      return [\n                        \"update\",\n                        fullpath,\n                        await commit3.oid(),\n                        await commit3.mode(),\n                        await commit3.mode() !== await workdir.mode()\n                      ];\n                    } else {\n                      return [\"conflict\", fullpath];\n                    }\n                  } else {\n                    if (await commit3.mode() !== await workdir.mode()) {\n                      if (force) {\n                        return [\n                          \"update\",\n                          fullpath,\n                          await commit3.oid(),\n                          await commit3.mode(),\n                          true\n                        ];\n                      } else {\n                        return [\"conflict\", fullpath];\n                      }\n                    } else {\n                      return [\n                        \"create-index\",\n                        fullpath,\n                        await commit3.oid(),\n                        await commit3.mode()\n                      ];\n                    }\n                  }\n                }\n                case \"commit-tree\": {\n                  return;\n                }\n                case \"commit-blob\": {\n                  return [\"conflict\", fullpath];\n                }\n                default: {\n                  return [\"error\", `new entry Unhandled type ${commit3.type}`];\n                }\n              }\n            }\n            // Something in stage but not in the commit OR the workdir.\n            // Note: I verified this behavior against canonical git.\n            case \"100\": {\n              return [\"delete-index\", fullpath];\n            }\n            // Deleted entries\n            // TODO: How to handle if stage type and workdir type mismatch?\n            case \"101\": {\n              switch (await stage2.type()) {\n                case \"tree\": {\n                  return [\"rmdir\", fullpath];\n                }\n                case \"blob\": {\n                  if (await stage2.oid() !== await workdir.oid()) {\n                    if (force) {\n                      return [\"delete\", fullpath];\n                    } else {\n                      return [\"conflict\", fullpath];\n                    }\n                  } else {\n                    return [\"delete\", fullpath];\n                  }\n                }\n                case \"commit\": {\n                  return [\"rmdir-index\", fullpath];\n                }\n                default: {\n                  return [\n                    \"error\",\n                    `delete entry Unhandled type ${await stage2.type()}`\n                  ];\n                }\n              }\n            }\n            /* eslint-disable no-fallthrough */\n            // File missing from workdir\n            case \"110\":\n            // Possibly modified entries\n            case \"111\": {\n              switch (`${await stage2.type()}-${await commit3.type()}`) {\n                case \"tree-tree\": {\n                  return;\n                }\n                case \"blob-blob\": {\n                  if (await stage2.oid() === await commit3.oid() && await stage2.mode() === await commit3.mode() && !force) {\n                    return;\n                  }\n                  if (workdir) {\n                    if (await workdir.oid() !== await stage2.oid() && await workdir.oid() !== await commit3.oid()) {\n                      if (force) {\n                        return [\n                          \"update\",\n                          fullpath,\n                          await commit3.oid(),\n                          await commit3.mode(),\n                          await commit3.mode() !== await workdir.mode()\n                        ];\n                      } else {\n                        return [\"conflict\", fullpath];\n                      }\n                    }\n                  } else if (force) {\n                    return [\n                      \"update\",\n                      fullpath,\n                      await commit3.oid(),\n                      await commit3.mode(),\n                      await commit3.mode() !== await stage2.mode()\n                    ];\n                  }\n                  if (await commit3.mode() !== await stage2.mode()) {\n                    return [\n                      \"update\",\n                      fullpath,\n                      await commit3.oid(),\n                      await commit3.mode(),\n                      true\n                    ];\n                  }\n                  if (await commit3.oid() !== await stage2.oid()) {\n                    return [\n                      \"update\",\n                      fullpath,\n                      await commit3.oid(),\n                      await commit3.mode(),\n                      false\n                    ];\n                  } else {\n                    return;\n                  }\n                }\n                case \"tree-blob\": {\n                  return [\"update-dir-to-blob\", fullpath, await commit3.oid()];\n                }\n                case \"blob-tree\": {\n                  return [\"update-blob-to-tree\", fullpath];\n                }\n                case \"commit-commit\": {\n                  return [\n                    \"mkdir-index\",\n                    fullpath,\n                    await commit3.oid(),\n                    await commit3.mode()\n                  ];\n                }\n                default: {\n                  return [\n                    \"error\",\n                    `update entry Unhandled type ${await stage2.type()}-${await commit3.type()}`\n                  ];\n                }\n              }\n            }\n          }\n        },\n        // Modify the default flat mapping\n        reduce: async function(parent, children) {\n          children = flat(children);\n          if (!parent) {\n            return children;\n          } else if (parent && parent[0] === \"rmdir\") {\n            children.push(parent);\n            return children;\n          } else {\n            children.unshift(parent);\n            return children;\n          }\n        }\n      });\n    }\n    async function checkout({\n      fs: fs2,\n      onProgress,\n      onPostCheckout,\n      dir,\n      gitdir = join2(dir, \".git\"),\n      remote = \"origin\",\n      ref: _ref,\n      filepaths,\n      noCheckout = false,\n      noUpdateHead = _ref === void 0,\n      dryRun = false,\n      force = false,\n      track = true,\n      cache = {}\n    }) {\n      try {\n        assertParameter(\"fs\", fs2);\n        assertParameter(\"dir\", dir);\n        assertParameter(\"gitdir\", gitdir);\n        const ref = _ref || \"HEAD\";\n        return await _checkout({\n          fs: new FileSystem(fs2),\n          cache,\n          onProgress,\n          onPostCheckout,\n          dir,\n          gitdir,\n          remote,\n          ref,\n          filepaths,\n          noCheckout,\n          noUpdateHead,\n          dryRun,\n          force,\n          track\n        });\n      } catch (err) {\n        err.caller = \"git.checkout\";\n        throw err;\n      }\n    }\n    var abbreviateRx = new RegExp(\"^refs/(heads/|tags/|remotes/)?(.*)\");\n    function abbreviateRef(ref) {\n      const match = abbreviateRx.exec(ref);\n      if (match) {\n        if (match[1] === \"remotes/\" && ref.endsWith(\"/HEAD\")) {\n          return match[2].slice(0, -5);\n        } else {\n          return match[2];\n        }\n      }\n      return ref;\n    }\n    async function _currentBranch({\n      fs: fs2,\n      gitdir,\n      fullname = false,\n      test = false\n    }) {\n      const ref = await GitRefManager.resolve({\n        fs: fs2,\n        gitdir,\n        ref: \"HEAD\",\n        depth: 2\n      });\n      if (test) {\n        try {\n          await GitRefManager.resolve({ fs: fs2, gitdir, ref });\n        } catch (_) {\n          return;\n        }\n      }\n      if (!ref.startsWith(\"refs/\")) return;\n      return fullname ? ref : abbreviateRef(ref);\n    }\n    function translateSSHtoHTTP(url) {\n      url = url.replace(/^git@([^:]+):/, \"https://$1/\");\n      url = url.replace(/^ssh:\\/\\//, \"https://\");\n      return url;\n    }\n    function calculateBasicAuthHeader({ username = \"\", password = \"\" }) {\n      return `Basic ${Buffer.from(`${username}:${password}`).toString(\"base64\")}`;\n    }\n    async function forAwait(iterable, cb) {\n      const iter = getIterator(iterable);\n      while (true) {\n        const { value, done } = await iter.next();\n        if (value) await cb(value);\n        if (done) break;\n      }\n      if (iter.return) iter.return();\n    }\n    async function collect(iterable) {\n      let size = 0;\n      const buffers = [];\n      await forAwait(iterable, (value) => {\n        buffers.push(value);\n        size += value.byteLength;\n      });\n      const result = new Uint8Array(size);\n      let nextIndex = 0;\n      for (const buffer of buffers) {\n        result.set(buffer, nextIndex);\n        nextIndex += buffer.byteLength;\n      }\n      return result;\n    }\n    function extractAuthFromUrl(url) {\n      let userpass = url.match(/^https?:\\/\\/([^/]+)@/);\n      if (userpass == null) return { url, auth: {} };\n      userpass = userpass[1];\n      const [username, password] = userpass.split(\":\");\n      url = url.replace(`${userpass}@`, \"\");\n      return { url, auth: { username, password } };\n    }\n    function padHex(b, n) {\n      const s = n.toString(16);\n      return \"0\".repeat(b - s.length) + s;\n    }\n    var GitPktLine = class {\n      static flush() {\n        return Buffer.from(\"0000\", \"utf8\");\n      }\n      static delim() {\n        return Buffer.from(\"0001\", \"utf8\");\n      }\n      static encode(line) {\n        if (typeof line === \"string\") {\n          line = Buffer.from(line);\n        }\n        const length = line.length + 4;\n        const hexlength = padHex(4, length);\n        return Buffer.concat([Buffer.from(hexlength, \"utf8\"), line]);\n      }\n      static streamReader(stream) {\n        const reader = new StreamReader(stream);\n        return async function read() {\n          try {\n            let length = await reader.read(4);\n            if (length == null) return true;\n            length = parseInt(length.toString(\"utf8\"), 16);\n            if (length === 0) return null;\n            if (length === 1) return null;\n            const buffer = await reader.read(length - 4);\n            if (buffer == null) return true;\n            return buffer;\n          } catch (err) {\n            stream.error = err;\n            return true;\n          }\n        };\n      }\n    };\n    async function parseCapabilitiesV2(read) {\n      const capabilities2 = {};\n      let line;\n      while (true) {\n        line = await read();\n        if (line === true) break;\n        if (line === null) continue;\n        line = line.toString(\"utf8\").replace(/\\n$/, \"\");\n        const i = line.indexOf(\"=\");\n        if (i > -1) {\n          const key = line.slice(0, i);\n          const value = line.slice(i + 1);\n          capabilities2[key] = value;\n        } else {\n          capabilities2[line] = true;\n        }\n      }\n      return { protocolVersion: 2, capabilities2 };\n    }\n    async function parseRefsAdResponse(stream, { service }) {\n      const capabilities = /* @__PURE__ */ new Set();\n      const refs = /* @__PURE__ */ new Map();\n      const symrefs = /* @__PURE__ */ new Map();\n      const read = GitPktLine.streamReader(stream);\n      let lineOne = await read();\n      while (lineOne === null) lineOne = await read();\n      if (lineOne === true) throw new EmptyServerResponseError();\n      if (lineOne.includes(\"version 2\")) {\n        return parseCapabilitiesV2(read);\n      }\n      if (lineOne.toString(\"utf8\").replace(/\\n$/, \"\") !== `# service=${service}`) {\n        throw new ParseError(`# service=${service}\\\\n`, lineOne.toString(\"utf8\"));\n      }\n      let lineTwo = await read();\n      while (lineTwo === null) lineTwo = await read();\n      if (lineTwo === true) return { capabilities, refs, symrefs };\n      lineTwo = lineTwo.toString(\"utf8\");\n      if (lineTwo.includes(\"version 2\")) {\n        return parseCapabilitiesV2(read);\n      }\n      const [firstRef, capabilitiesLine] = splitAndAssert(lineTwo, \"\\0\", \"\\\\x00\");\n      capabilitiesLine.split(\" \").map((x) => capabilities.add(x));\n      if (firstRef !== \"0000000000000000000000000000000000000000 capabilities^{}\") {\n        const [ref, name] = splitAndAssert(firstRef, \" \", \" \");\n        refs.set(name, ref);\n        while (true) {\n          const line = await read();\n          if (line === true) break;\n          if (line !== null) {\n            const [ref2, name2] = splitAndAssert(line.toString(\"utf8\"), \" \", \" \");\n            refs.set(name2, ref2);\n          }\n        }\n      }\n      for (const cap of capabilities) {\n        if (cap.startsWith(\"symref=\")) {\n          const m = cap.match(/symref=([^:]+):(.*)/);\n          if (m.length === 3) {\n            symrefs.set(m[1], m[2]);\n          }\n        }\n      }\n      return { protocolVersion: 1, capabilities, refs, symrefs };\n    }\n    function splitAndAssert(line, sep, expected) {\n      const split = line.trim().split(sep);\n      if (split.length !== 2) {\n        throw new ParseError(\n          `Two strings separated by '${expected}'`,\n          line.toString(\"utf8\")\n        );\n      }\n      return split;\n    }\n    var corsProxify = (corsProxy, url) => corsProxy.endsWith(\"?\") ? `${corsProxy}${url}` : `${corsProxy}/${url.replace(/^https?:\\/\\//, \"\")}`;\n    var updateHeaders = (headers, auth) => {\n      if (auth.username || auth.password) {\n        headers.Authorization = calculateBasicAuthHeader(auth);\n      }\n      if (auth.headers) {\n        Object.assign(headers, auth.headers);\n      }\n    };\n    var stringifyBody = async (res) => {\n      try {\n        const data = Buffer.from(await collect(res.body));\n        const response = data.toString(\"utf8\");\n        const preview = response.length < 256 ? response : response.slice(0, 256) + \"...\";\n        return { preview, response, data };\n      } catch (e) {\n        return {};\n      }\n    };\n    var GitRemoteHTTP = class {\n      static async capabilities() {\n        return [\"discover\", \"connect\"];\n      }\n      /**\n       * @param {Object} args\n       * @param {HttpClient} args.http\n       * @param {ProgressCallback} [args.onProgress]\n       * @param {AuthCallback} [args.onAuth]\n       * @param {AuthFailureCallback} [args.onAuthFailure]\n       * @param {AuthSuccessCallback} [args.onAuthSuccess]\n       * @param {string} [args.corsProxy]\n       * @param {string} args.service\n       * @param {string} args.url\n       * @param {Object<string, string>} args.headers\n       * @param {1 | 2} args.protocolVersion - Git Protocol Version\n       */\n      static async discover({\n        http,\n        onProgress,\n        onAuth,\n        onAuthSuccess,\n        onAuthFailure,\n        corsProxy,\n        service,\n        url: _origUrl,\n        headers,\n        protocolVersion\n      }) {\n        let { url, auth } = extractAuthFromUrl(_origUrl);\n        const proxifiedURL = corsProxy ? corsProxify(corsProxy, url) : url;\n        if (auth.username || auth.password) {\n          headers.Authorization = calculateBasicAuthHeader(auth);\n        }\n        if (protocolVersion === 2) {\n          headers[\"Git-Protocol\"] = \"version=2\";\n        }\n        let res;\n        let tryAgain;\n        let providedAuthBefore = false;\n        do {\n          res = await http.request({\n            onProgress,\n            method: \"GET\",\n            url: `${proxifiedURL}/info/refs?service=${service}`,\n            headers\n          });\n          tryAgain = false;\n          if (res.statusCode === 401 || res.statusCode === 203) {\n            const getAuth = providedAuthBefore ? onAuthFailure : onAuth;\n            if (getAuth) {\n              auth = await getAuth(url, {\n                ...auth,\n                headers: { ...headers }\n              });\n              if (auth && auth.cancel) {\n                throw new UserCanceledError();\n              } else if (auth) {\n                updateHeaders(headers, auth);\n                providedAuthBefore = true;\n                tryAgain = true;\n              }\n            }\n          } else if (res.statusCode === 200 && providedAuthBefore && onAuthSuccess) {\n            await onAuthSuccess(url, auth);\n          }\n        } while (tryAgain);\n        if (res.statusCode !== 200) {\n          const { response } = await stringifyBody(res);\n          throw new HttpError(res.statusCode, res.statusMessage, response);\n        }\n        if (res.headers[\"content-type\"] === `application/x-${service}-advertisement`) {\n          const remoteHTTP = await parseRefsAdResponse(res.body, { service });\n          remoteHTTP.auth = auth;\n          return remoteHTTP;\n        } else {\n          const { preview, response, data } = await stringifyBody(res);\n          try {\n            const remoteHTTP = await parseRefsAdResponse([data], { service });\n            remoteHTTP.auth = auth;\n            return remoteHTTP;\n          } catch (e) {\n            throw new SmartHttpError(preview, response);\n          }\n        }\n      }\n      /**\n       * @param {Object} args\n       * @param {HttpClient} args.http\n       * @param {ProgressCallback} [args.onProgress]\n       * @param {string} [args.corsProxy]\n       * @param {string} args.service\n       * @param {string} args.url\n       * @param {Object<string, string>} [args.headers]\n       * @param {any} args.body\n       * @param {any} args.auth\n       */\n      static async connect({\n        http,\n        onProgress,\n        corsProxy,\n        service,\n        url,\n        auth,\n        body,\n        headers\n      }) {\n        const urlAuth = extractAuthFromUrl(url);\n        if (urlAuth) url = urlAuth.url;\n        if (corsProxy) url = corsProxify(corsProxy, url);\n        headers[\"content-type\"] = `application/x-${service}-request`;\n        headers.accept = `application/x-${service}-result`;\n        updateHeaders(headers, auth);\n        const res = await http.request({\n          onProgress,\n          method: \"POST\",\n          url: `${url}/${service}`,\n          body,\n          headers\n        });\n        if (res.statusCode !== 200) {\n          const { response } = stringifyBody(res);\n          throw new HttpError(res.statusCode, res.statusMessage, response);\n        }\n        return res;\n      }\n    };\n    function parseRemoteUrl({ url }) {\n      if (url.startsWith(\"git@\")) {\n        return {\n          transport: \"ssh\",\n          address: url\n        };\n      }\n      const matches = url.match(/(\\w+)(:\\/\\/|::)(.*)/);\n      if (matches === null) return;\n      if (matches[2] === \"://\") {\n        return {\n          transport: matches[1],\n          address: matches[0]\n        };\n      }\n      if (matches[2] === \"::\") {\n        return {\n          transport: matches[1],\n          address: matches[3]\n        };\n      }\n    }\n    var GitRemoteManager = class {\n      static getRemoteHelperFor({ url }) {\n        const remoteHelpers = /* @__PURE__ */ new Map();\n        remoteHelpers.set(\"http\", GitRemoteHTTP);\n        remoteHelpers.set(\"https\", GitRemoteHTTP);\n        const parts = parseRemoteUrl({ url });\n        if (!parts) {\n          throw new UrlParseError(url);\n        }\n        if (remoteHelpers.has(parts.transport)) {\n          return remoteHelpers.get(parts.transport);\n        }\n        throw new UnknownTransportError(\n          url,\n          parts.transport,\n          parts.transport === \"ssh\" ? translateSSHtoHTTP(url) : void 0\n        );\n      }\n    };\n    var lock$2 = null;\n    var GitShallowManager = class {\n      static async read({ fs: fs2, gitdir }) {\n        if (lock$2 === null) lock$2 = new AsyncLock();\n        const filepath = join2(gitdir, \"shallow\");\n        const oids = /* @__PURE__ */ new Set();\n        await lock$2.acquire(filepath, async function() {\n          const text = await fs2.read(filepath, { encoding: \"utf8\" });\n          if (text === null) return oids;\n          if (text.trim() === \"\") return oids;\n          text.trim().split(\"\\n\").map((oid) => oids.add(oid));\n        });\n        return oids;\n      }\n      static async write({ fs: fs2, gitdir, oids }) {\n        if (lock$2 === null) lock$2 = new AsyncLock();\n        const filepath = join2(gitdir, \"shallow\");\n        if (oids.size > 0) {\n          const text = [...oids].join(\"\\n\") + \"\\n\";\n          await lock$2.acquire(filepath, async function() {\n            await fs2.write(filepath, text, {\n              encoding: \"utf8\"\n            });\n          });\n        } else {\n          await lock$2.acquire(filepath, async function() {\n            await fs2.rm(filepath);\n          });\n        }\n      }\n    };\n    async function hasObjectLoose({ fs: fs2, gitdir, oid }) {\n      const source = `objects/${oid.slice(0, 2)}/${oid.slice(2)}`;\n      return fs2.exists(`${gitdir}/${source}`);\n    }\n    async function hasObjectPacked({\n      fs: fs2,\n      cache,\n      gitdir,\n      oid,\n      getExternalRefDelta\n    }) {\n      let list = await fs2.readdir(join2(gitdir, \"objects/pack\"));\n      list = list.filter((x) => x.endsWith(\".idx\"));\n      for (const filename of list) {\n        const indexFile = `${gitdir}/objects/pack/${filename}`;\n        const p = await readPackIndex({\n          fs: fs2,\n          cache,\n          filename: indexFile,\n          getExternalRefDelta\n        });\n        if (p.error) throw new InternalError(p.error);\n        if (p.offsets.has(oid)) {\n          return true;\n        }\n      }\n      return false;\n    }\n    async function hasObject({\n      fs: fs2,\n      cache,\n      gitdir,\n      oid,\n      format = \"content\"\n    }) {\n      const getExternalRefDelta = (oid2) => _readObject({ fs: fs2, cache, gitdir, oid: oid2 });\n      let result = await hasObjectLoose({ fs: fs2, gitdir, oid });\n      if (!result) {\n        result = await hasObjectPacked({\n          fs: fs2,\n          cache,\n          gitdir,\n          oid,\n          getExternalRefDelta\n        });\n      }\n      return result;\n    }\n    function emptyPackfile(pack) {\n      const pheader = \"5041434b\";\n      const version2 = \"00000002\";\n      const obCount = \"00000000\";\n      const header = pheader + version2 + obCount;\n      return pack.slice(0, 12).toString(\"hex\") === header;\n    }\n    function filterCapabilities(server, client) {\n      const serverNames = server.map((cap) => cap.split(\"=\", 1)[0]);\n      return client.filter((cap) => {\n        const name = cap.split(\"=\", 1)[0];\n        return serverNames.includes(name);\n      });\n    }\n    var pkg = {\n      name: \"isomorphic-git\",\n      version: \"1.27.1\",\n      agent: \"git/isomorphic-git@1.27.1\"\n    };\n    var FIFO = class {\n      constructor() {\n        this._queue = [];\n      }\n      write(chunk) {\n        if (this._ended) {\n          throw Error(\"You cannot write to a FIFO that has already been ended!\");\n        }\n        if (this._waiting) {\n          const resolve = this._waiting;\n          this._waiting = null;\n          resolve({ value: chunk });\n        } else {\n          this._queue.push(chunk);\n        }\n      }\n      end() {\n        this._ended = true;\n        if (this._waiting) {\n          const resolve = this._waiting;\n          this._waiting = null;\n          resolve({ done: true });\n        }\n      }\n      destroy(err) {\n        this.error = err;\n        this.end();\n      }\n      async next() {\n        if (this._queue.length > 0) {\n          return { value: this._queue.shift() };\n        }\n        if (this._ended) {\n          return { done: true };\n        }\n        if (this._waiting) {\n          throw Error(\n            \"You cannot call read until the previous call to read has returned!\"\n          );\n        }\n        return new Promise((resolve) => {\n          this._waiting = resolve;\n        });\n      }\n    };\n    function findSplit(str) {\n      const r = str.indexOf(\"\\r\");\n      const n = str.indexOf(\"\\n\");\n      if (r === -1 && n === -1) return -1;\n      if (r === -1) return n + 1;\n      if (n === -1) return r + 1;\n      if (n === r + 1) return n + 1;\n      return Math.min(r, n) + 1;\n    }\n    function splitLines(input) {\n      const output = new FIFO();\n      let tmp = \"\";\n      (async () => {\n        await forAwait(input, (chunk) => {\n          chunk = chunk.toString(\"utf8\");\n          tmp += chunk;\n          while (true) {\n            const i = findSplit(tmp);\n            if (i === -1) break;\n            output.write(tmp.slice(0, i));\n            tmp = tmp.slice(i);\n          }\n        });\n        if (tmp.length > 0) {\n          output.write(tmp);\n        }\n        output.end();\n      })();\n      return output;\n    }\n    var GitSideBand = class {\n      static demux(input) {\n        const read = GitPktLine.streamReader(input);\n        const packetlines = new FIFO();\n        const packfile = new FIFO();\n        const progress = new FIFO();\n        const nextBit = async function() {\n          const line = await read();\n          if (line === null) return nextBit();\n          if (line === true) {\n            packetlines.end();\n            progress.end();\n            input.error ? packfile.destroy(input.error) : packfile.end();\n            return;\n          }\n          switch (line[0]) {\n            case 1: {\n              packfile.write(line.slice(1));\n              break;\n            }\n            case 2: {\n              progress.write(line.slice(1));\n              break;\n            }\n            case 3: {\n              const error = line.slice(1);\n              progress.write(error);\n              packetlines.end();\n              progress.end();\n              packfile.destroy(new Error(error.toString(\"utf8\")));\n              return;\n            }\n            default: {\n              packetlines.write(line);\n            }\n          }\n          nextBit();\n        };\n        nextBit();\n        return {\n          packetlines,\n          packfile,\n          progress\n        };\n      }\n      // static mux ({\n      //   protocol, // 'side-band' or 'side-band-64k'\n      //   packetlines,\n      //   packfile,\n      //   progress,\n      //   error\n      // }) {\n      //   const MAX_PACKET_LENGTH = protocol === 'side-band-64k' ? 999 : 65519\n      //   let output = new PassThrough()\n      //   packetlines.on('data', data => {\n      //     if (data === null) {\n      //       output.write(GitPktLine.flush())\n      //     } else {\n      //       output.write(GitPktLine.encode(data))\n      //     }\n      //   })\n      //   let packfileWasEmpty = true\n      //   let packfileEnded = false\n      //   let progressEnded = false\n      //   let errorEnded = false\n      //   let goodbye = Buffer.concat([\n      //     GitPktLine.encode(Buffer.from('010A', 'hex')),\n      //     GitPktLine.flush()\n      //   ])\n      //   packfile\n      //     .on('data', data => {\n      //       packfileWasEmpty = false\n      //       const buffers = splitBuffer(data, MAX_PACKET_LENGTH)\n      //       for (const buffer of buffers) {\n      //         output.write(\n      //           GitPktLine.encode(Buffer.concat([Buffer.from('01', 'hex'), buffer]))\n      //         )\n      //       }\n      //     })\n      //     .on('end', () => {\n      //       packfileEnded = true\n      //       if (!packfileWasEmpty) output.write(goodbye)\n      //       if (progressEnded && errorEnded) output.end()\n      //     })\n      //   progress\n      //     .on('data', data => {\n      //       const buffers = splitBuffer(data, MAX_PACKET_LENGTH)\n      //       for (const buffer of buffers) {\n      //         output.write(\n      //           GitPktLine.encode(Buffer.concat([Buffer.from('02', 'hex'), buffer]))\n      //         )\n      //       }\n      //     })\n      //     .on('end', () => {\n      //       progressEnded = true\n      //       if (packfileEnded && errorEnded) output.end()\n      //     })\n      //   error\n      //     .on('data', data => {\n      //       const buffers = splitBuffer(data, MAX_PACKET_LENGTH)\n      //       for (const buffer of buffers) {\n      //         output.write(\n      //           GitPktLine.encode(Buffer.concat([Buffer.from('03', 'hex'), buffer]))\n      //         )\n      //       }\n      //     })\n      //     .on('end', () => {\n      //       errorEnded = true\n      //       if (progressEnded && packfileEnded) output.end()\n      //     })\n      //   return output\n      // }\n    };\n    async function parseUploadPackResponse(stream) {\n      const { packetlines, packfile, progress } = GitSideBand.demux(stream);\n      const shallows = [];\n      const unshallows = [];\n      const acks = [];\n      let nak = false;\n      let done = false;\n      return new Promise((resolve, reject) => {\n        forAwait(packetlines, (data) => {\n          const line = data.toString(\"utf8\").trim();\n          if (line.startsWith(\"shallow\")) {\n            const oid = line.slice(-41).trim();\n            if (oid.length !== 40) {\n              reject(new InvalidOidError(oid));\n            }\n            shallows.push(oid);\n          } else if (line.startsWith(\"unshallow\")) {\n            const oid = line.slice(-41).trim();\n            if (oid.length !== 40) {\n              reject(new InvalidOidError(oid));\n            }\n            unshallows.push(oid);\n          } else if (line.startsWith(\"ACK\")) {\n            const [, oid, status2] = line.split(\" \");\n            acks.push({ oid, status: status2 });\n            if (!status2) done = true;\n          } else if (line.startsWith(\"NAK\")) {\n            nak = true;\n            done = true;\n          } else {\n            done = true;\n            nak = true;\n          }\n          if (done) {\n            stream.error ? reject(stream.error) : resolve({ shallows, unshallows, acks, nak, packfile, progress });\n          }\n        }).finally(() => {\n          if (!done) {\n            stream.error ? reject(stream.error) : resolve({ shallows, unshallows, acks, nak, packfile, progress });\n          }\n        });\n      });\n    }\n    function writeUploadPackRequest({\n      capabilities = [],\n      wants = [],\n      haves = [],\n      shallows = [],\n      depth = null,\n      since = null,\n      exclude = []\n    }) {\n      const packstream = [];\n      wants = [...new Set(wants)];\n      let firstLineCapabilities = ` ${capabilities.join(\" \")}`;\n      for (const oid of wants) {\n        packstream.push(GitPktLine.encode(`want ${oid}${firstLineCapabilities}\n`));\n        firstLineCapabilities = \"\";\n      }\n      for (const oid of shallows) {\n        packstream.push(GitPktLine.encode(`shallow ${oid}\n`));\n      }\n      if (depth !== null) {\n        packstream.push(GitPktLine.encode(`deepen ${depth}\n`));\n      }\n      if (since !== null) {\n        packstream.push(\n          GitPktLine.encode(`deepen-since ${Math.floor(since.valueOf() / 1e3)}\n`)\n        );\n      }\n      for (const oid of exclude) {\n        packstream.push(GitPktLine.encode(`deepen-not ${oid}\n`));\n      }\n      packstream.push(GitPktLine.flush());\n      for (const oid of haves) {\n        packstream.push(GitPktLine.encode(`have ${oid}\n`));\n      }\n      packstream.push(GitPktLine.encode(`done\n`));\n      return packstream;\n    }\n    async function _fetch({\n      fs: fs2,\n      cache,\n      http,\n      onProgress,\n      onMessage,\n      onAuth,\n      onAuthSuccess,\n      onAuthFailure,\n      gitdir,\n      ref: _ref,\n      remoteRef: _remoteRef,\n      remote: _remote,\n      url: _url,\n      corsProxy,\n      depth = null,\n      since = null,\n      exclude = [],\n      relative = false,\n      tags = false,\n      singleBranch = false,\n      headers = {},\n      prune = false,\n      pruneTags = false\n    }) {\n      const ref = _ref || await _currentBranch({ fs: fs2, gitdir, test: true });\n      const config = await GitConfigManager.get({ fs: fs2, gitdir });\n      const remote = _remote || ref && await config.get(`branch.${ref}.remote`) || \"origin\";\n      const url = _url || await config.get(`remote.${remote}.url`);\n      if (typeof url === \"undefined\") {\n        throw new MissingParameterError(\"remote OR url\");\n      }\n      const remoteRef = _remoteRef || ref && await config.get(`branch.${ref}.merge`) || _ref || \"HEAD\";\n      if (corsProxy === void 0) {\n        corsProxy = await config.get(\"http.corsProxy\");\n      }\n      const GitRemoteHTTP2 = GitRemoteManager.getRemoteHelperFor({ url });\n      const remoteHTTP = await GitRemoteHTTP2.discover({\n        http,\n        onAuth,\n        onAuthSuccess,\n        onAuthFailure,\n        corsProxy,\n        service: \"git-upload-pack\",\n        url,\n        headers,\n        protocolVersion: 1\n      });\n      const auth = remoteHTTP.auth;\n      const remoteRefs = remoteHTTP.refs;\n      if (remoteRefs.size === 0) {\n        return {\n          defaultBranch: null,\n          fetchHead: null,\n          fetchHeadDescription: null\n        };\n      }\n      if (depth !== null && !remoteHTTP.capabilities.has(\"shallow\")) {\n        throw new RemoteCapabilityError(\"shallow\", \"depth\");\n      }\n      if (since !== null && !remoteHTTP.capabilities.has(\"deepen-since\")) {\n        throw new RemoteCapabilityError(\"deepen-since\", \"since\");\n      }\n      if (exclude.length > 0 && !remoteHTTP.capabilities.has(\"deepen-not\")) {\n        throw new RemoteCapabilityError(\"deepen-not\", \"exclude\");\n      }\n      if (relative === true && !remoteHTTP.capabilities.has(\"deepen-relative\")) {\n        throw new RemoteCapabilityError(\"deepen-relative\", \"relative\");\n      }\n      const { oid, fullref } = GitRefManager.resolveAgainstMap({\n        ref: remoteRef,\n        map: remoteRefs\n      });\n      for (const remoteRef2 of remoteRefs.keys()) {\n        if (remoteRef2 === fullref || remoteRef2 === \"HEAD\" || remoteRef2.startsWith(\"refs/heads/\") || tags && remoteRef2.startsWith(\"refs/tags/\")) {\n          continue;\n        }\n        remoteRefs.delete(remoteRef2);\n      }\n      const capabilities = filterCapabilities(\n        [...remoteHTTP.capabilities],\n        [\n          \"multi_ack_detailed\",\n          \"no-done\",\n          \"side-band-64k\",\n          // Note: I removed 'thin-pack' option since our code doesn't \"fatten\" packfiles,\n          // which is necessary for compatibility with git. It was the cause of mysterious\n          // 'fatal: pack has [x] unresolved deltas' errors that plagued us for some time.\n          // isomorphic-git is perfectly happy with thin packfiles in .git/objects/pack but\n          // canonical git it turns out is NOT.\n          \"ofs-delta\",\n          `agent=${pkg.agent}`\n        ]\n      );\n      if (relative) capabilities.push(\"deepen-relative\");\n      const wants = singleBranch ? [oid] : remoteRefs.values();\n      const haveRefs = singleBranch ? [ref] : await GitRefManager.listRefs({\n        fs: fs2,\n        gitdir,\n        filepath: `refs`\n      });\n      let haves = [];\n      for (let ref2 of haveRefs) {\n        try {\n          ref2 = await GitRefManager.expand({ fs: fs2, gitdir, ref: ref2 });\n          const oid2 = await GitRefManager.resolve({ fs: fs2, gitdir, ref: ref2 });\n          if (await hasObject({ fs: fs2, cache, gitdir, oid: oid2 })) {\n            haves.push(oid2);\n          }\n        } catch (err) {\n        }\n      }\n      haves = [...new Set(haves)];\n      const oids = await GitShallowManager.read({ fs: fs2, gitdir });\n      const shallows = remoteHTTP.capabilities.has(\"shallow\") ? [...oids] : [];\n      const packstream = writeUploadPackRequest({\n        capabilities,\n        wants,\n        haves,\n        shallows,\n        depth,\n        since,\n        exclude\n      });\n      const packbuffer = Buffer.from(await collect(packstream));\n      const raw = await GitRemoteHTTP2.connect({\n        http,\n        onProgress,\n        corsProxy,\n        service: \"git-upload-pack\",\n        url,\n        auth,\n        body: [packbuffer],\n        headers\n      });\n      const response = await parseUploadPackResponse(raw.body);\n      if (raw.headers) {\n        response.headers = raw.headers;\n      }\n      for (const oid2 of response.shallows) {\n        if (!oids.has(oid2)) {\n          try {\n            const { object } = await _readObject({ fs: fs2, cache, gitdir, oid: oid2 });\n            const commit3 = new GitCommit(object);\n            const hasParents = await Promise.all(\n              commit3.headers().parent.map((oid3) => hasObject({ fs: fs2, cache, gitdir, oid: oid3 }))\n            );\n            const haveAllParents = hasParents.length === 0 || hasParents.every((has) => has);\n            if (!haveAllParents) {\n              oids.add(oid2);\n            }\n          } catch (err) {\n            oids.add(oid2);\n          }\n        }\n      }\n      for (const oid2 of response.unshallows) {\n        oids.delete(oid2);\n      }\n      await GitShallowManager.write({ fs: fs2, gitdir, oids });\n      if (singleBranch) {\n        const refs = /* @__PURE__ */ new Map([[fullref, oid]]);\n        const symrefs = /* @__PURE__ */ new Map();\n        let bail = 10;\n        let key = fullref;\n        while (bail--) {\n          const value = remoteHTTP.symrefs.get(key);\n          if (value === void 0) break;\n          symrefs.set(key, value);\n          key = value;\n        }\n        const realRef = remoteRefs.get(key);\n        if (realRef) {\n          refs.set(key, realRef);\n        }\n        const { pruned } = await GitRefManager.updateRemoteRefs({\n          fs: fs2,\n          gitdir,\n          remote,\n          refs,\n          symrefs,\n          tags,\n          prune\n        });\n        if (prune) {\n          response.pruned = pruned;\n        }\n      } else {\n        const { pruned } = await GitRefManager.updateRemoteRefs({\n          fs: fs2,\n          gitdir,\n          remote,\n          refs: remoteRefs,\n          symrefs: remoteHTTP.symrefs,\n          tags,\n          prune,\n          pruneTags\n        });\n        if (prune) {\n          response.pruned = pruned;\n        }\n      }\n      response.HEAD = remoteHTTP.symrefs.get(\"HEAD\");\n      if (response.HEAD === void 0) {\n        const { oid: oid2 } = GitRefManager.resolveAgainstMap({\n          ref: \"HEAD\",\n          map: remoteRefs\n        });\n        for (const [key, value] of remoteRefs.entries()) {\n          if (key !== \"HEAD\" && value === oid2) {\n            response.HEAD = key;\n            break;\n          }\n        }\n      }\n      const noun = fullref.startsWith(\"refs/tags\") ? \"tag\" : \"branch\";\n      response.FETCH_HEAD = {\n        oid,\n        description: `${noun} '${abbreviateRef(fullref)}' of ${url}`\n      };\n      if (onProgress || onMessage) {\n        const lines = splitLines(response.progress);\n        forAwait(lines, async (line) => {\n          if (onMessage) await onMessage(line);\n          if (onProgress) {\n            const matches = line.match(/([^:]*).*\\((\\d+?)\\/(\\d+?)\\)/);\n            if (matches) {\n              await onProgress({\n                phase: matches[1].trim(),\n                loaded: parseInt(matches[2], 10),\n                total: parseInt(matches[3], 10)\n              });\n            }\n          }\n        });\n      }\n      const packfile = Buffer.from(await collect(response.packfile));\n      if (raw.body.error) throw raw.body.error;\n      const packfileSha = packfile.slice(-20).toString(\"hex\");\n      const res = {\n        defaultBranch: response.HEAD,\n        fetchHead: response.FETCH_HEAD.oid,\n        fetchHeadDescription: response.FETCH_HEAD.description\n      };\n      if (response.headers) {\n        res.headers = response.headers;\n      }\n      if (prune) {\n        res.pruned = response.pruned;\n      }\n      if (packfileSha !== \"\" && !emptyPackfile(packfile)) {\n        res.packfile = `objects/pack/pack-${packfileSha}.pack`;\n        const fullpath = join2(gitdir, res.packfile);\n        await fs2.write(fullpath, packfile);\n        const getExternalRefDelta = (oid2) => _readObject({ fs: fs2, cache, gitdir, oid: oid2 });\n        const idx = await GitPackIndex.fromPack({\n          pack: packfile,\n          getExternalRefDelta,\n          onProgress\n        });\n        await fs2.write(fullpath.replace(/\\.pack$/, \".idx\"), await idx.toBuffer());\n      }\n      return res;\n    }\n    async function _init({\n      fs: fs2,\n      bare = false,\n      dir,\n      gitdir = bare ? dir : join2(dir, \".git\"),\n      defaultBranch = \"master\"\n    }) {\n      if (await fs2.exists(gitdir + \"/config\")) return;\n      let folders = [\n        \"hooks\",\n        \"info\",\n        \"objects/info\",\n        \"objects/pack\",\n        \"refs/heads\",\n        \"refs/tags\"\n      ];\n      folders = folders.map((dir2) => gitdir + \"/\" + dir2);\n      for (const folder of folders) {\n        await fs2.mkdir(folder);\n      }\n      await fs2.write(\n        gitdir + \"/config\",\n        `[core]\n\trepositoryformatversion = 0\n\tfilemode = false\n\tbare = ${bare}\n` + (bare ? \"\" : \"\tlogallrefupdates = true\\n\") + \"\tsymlinks = false\\n\tignorecase = true\\n\"\n      );\n      await fs2.write(gitdir + \"/HEAD\", `ref: refs/heads/${defaultBranch}\n`);\n    }\n    async function _clone({\n      fs: fs2,\n      cache,\n      http,\n      onProgress,\n      onMessage,\n      onAuth,\n      onAuthSuccess,\n      onAuthFailure,\n      onPostCheckout,\n      dir,\n      gitdir,\n      url,\n      corsProxy,\n      ref,\n      remote,\n      depth,\n      since,\n      exclude,\n      relative,\n      singleBranch,\n      noCheckout,\n      noTags,\n      headers\n    }) {\n      try {\n        await _init({ fs: fs2, gitdir });\n        await _addRemote({ fs: fs2, gitdir, remote, url, force: false });\n        if (corsProxy) {\n          const config = await GitConfigManager.get({ fs: fs2, gitdir });\n          await config.set(`http.corsProxy`, corsProxy);\n          await GitConfigManager.save({ fs: fs2, gitdir, config });\n        }\n        const { defaultBranch, fetchHead } = await _fetch({\n          fs: fs2,\n          cache,\n          http,\n          onProgress,\n          onMessage,\n          onAuth,\n          onAuthSuccess,\n          onAuthFailure,\n          gitdir,\n          ref,\n          remote,\n          corsProxy,\n          depth,\n          since,\n          exclude,\n          relative,\n          singleBranch,\n          headers,\n          tags: !noTags\n        });\n        if (fetchHead === null) return;\n        ref = ref || defaultBranch;\n        ref = ref.replace(\"refs/heads/\", \"\");\n        await _checkout({\n          fs: fs2,\n          cache,\n          onProgress,\n          onPostCheckout,\n          dir,\n          gitdir,\n          ref,\n          remote,\n          noCheckout\n        });\n      } catch (err) {\n        await fs2.rmdir(gitdir, { recursive: true, maxRetries: 10 }).catch(() => void 0);\n        throw err;\n      }\n    }\n    async function clone({\n      fs: fs2,\n      http,\n      onProgress,\n      onMessage,\n      onAuth,\n      onAuthSuccess,\n      onAuthFailure,\n      onPostCheckout,\n      dir,\n      gitdir = join2(dir, \".git\"),\n      url,\n      corsProxy = void 0,\n      ref = void 0,\n      remote = \"origin\",\n      depth = void 0,\n      since = void 0,\n      exclude = [],\n      relative = false,\n      singleBranch = false,\n      noCheckout = false,\n      noTags = false,\n      headers = {},\n      cache = {}\n    }) {\n      try {\n        assertParameter(\"fs\", fs2);\n        assertParameter(\"http\", http);\n        assertParameter(\"gitdir\", gitdir);\n        if (!noCheckout) {\n          assertParameter(\"dir\", dir);\n        }\n        assertParameter(\"url\", url);\n        return await _clone({\n          fs: new FileSystem(fs2),\n          cache,\n          http,\n          onProgress,\n          onMessage,\n          onAuth,\n          onAuthSuccess,\n          onAuthFailure,\n          onPostCheckout,\n          dir,\n          gitdir,\n          url,\n          corsProxy,\n          ref,\n          remote,\n          depth,\n          since,\n          exclude,\n          relative,\n          singleBranch,\n          noCheckout,\n          noTags,\n          headers\n        });\n      } catch (err) {\n        err.caller = \"git.clone\";\n        throw err;\n      }\n    }\n    async function commit2({\n      fs: _fs,\n      onSign,\n      dir,\n      gitdir = join2(dir, \".git\"),\n      message,\n      author: author2,\n      committer,\n      signingKey,\n      amend = false,\n      dryRun = false,\n      noUpdateBranch = false,\n      ref,\n      parent,\n      tree,\n      cache = {}\n    }) {\n      try {\n        assertParameter(\"fs\", _fs);\n        if (!amend) {\n          assertParameter(\"message\", message);\n        }\n        if (signingKey) {\n          assertParameter(\"onSign\", onSign);\n        }\n        const fs2 = new FileSystem(_fs);\n        return await _commit({\n          fs: fs2,\n          cache,\n          onSign,\n          gitdir,\n          message,\n          author: author2,\n          committer,\n          signingKey,\n          amend,\n          dryRun,\n          noUpdateBranch,\n          ref,\n          parent,\n          tree\n        });\n      } catch (err) {\n        err.caller = \"git.commit\";\n        throw err;\n      }\n    }\n    async function currentBranch({\n      fs: fs2,\n      dir,\n      gitdir = join2(dir, \".git\"),\n      fullname = false,\n      test = false\n    }) {\n      try {\n        assertParameter(\"fs\", fs2);\n        assertParameter(\"gitdir\", gitdir);\n        return await _currentBranch({\n          fs: new FileSystem(fs2),\n          gitdir,\n          fullname,\n          test\n        });\n      } catch (err) {\n        err.caller = \"git.currentBranch\";\n        throw err;\n      }\n    }\n    async function _deleteBranch({ fs: fs2, gitdir, ref }) {\n      ref = ref.startsWith(\"refs/heads/\") ? ref : `refs/heads/${ref}`;\n      const exist = await GitRefManager.exists({ fs: fs2, gitdir, ref });\n      if (!exist) {\n        throw new NotFoundError(ref);\n      }\n      const fullRef = await GitRefManager.expand({ fs: fs2, gitdir, ref });\n      const currentRef = await _currentBranch({ fs: fs2, gitdir, fullname: true });\n      if (fullRef === currentRef) {\n        const value = await GitRefManager.resolve({ fs: fs2, gitdir, ref: fullRef });\n        await GitRefManager.writeRef({ fs: fs2, gitdir, ref: \"HEAD\", value });\n      }\n      await GitRefManager.deleteRef({ fs: fs2, gitdir, ref: fullRef });\n      const abbrevRef = abbreviateRef(ref);\n      const config = await GitConfigManager.get({ fs: fs2, gitdir });\n      await config.deleteSection(\"branch\", abbrevRef);\n      await GitConfigManager.save({ fs: fs2, gitdir, config });\n    }\n    async function deleteBranch({\n      fs: fs2,\n      dir,\n      gitdir = join2(dir, \".git\"),\n      ref\n    }) {\n      try {\n        assertParameter(\"fs\", fs2);\n        assertParameter(\"ref\", ref);\n        return await _deleteBranch({\n          fs: new FileSystem(fs2),\n          gitdir,\n          ref\n        });\n      } catch (err) {\n        err.caller = \"git.deleteBranch\";\n        throw err;\n      }\n    }\n    async function deleteRef({ fs: fs2, dir, gitdir = join2(dir, \".git\"), ref }) {\n      try {\n        assertParameter(\"fs\", fs2);\n        assertParameter(\"ref\", ref);\n        await GitRefManager.deleteRef({ fs: new FileSystem(fs2), gitdir, ref });\n      } catch (err) {\n        err.caller = \"git.deleteRef\";\n        throw err;\n      }\n    }\n    async function _deleteRemote({ fs: fs2, gitdir, remote }) {\n      const config = await GitConfigManager.get({ fs: fs2, gitdir });\n      await config.deleteSection(\"remote\", remote);\n      await GitConfigManager.save({ fs: fs2, gitdir, config });\n    }\n    async function deleteRemote({\n      fs: fs2,\n      dir,\n      gitdir = join2(dir, \".git\"),\n      remote\n    }) {\n      try {\n        assertParameter(\"fs\", fs2);\n        assertParameter(\"remote\", remote);\n        return await _deleteRemote({\n          fs: new FileSystem(fs2),\n          gitdir,\n          remote\n        });\n      } catch (err) {\n        err.caller = \"git.deleteRemote\";\n        throw err;\n      }\n    }\n    async function _deleteTag({ fs: fs2, gitdir, ref }) {\n      ref = ref.startsWith(\"refs/tags/\") ? ref : `refs/tags/${ref}`;\n      await GitRefManager.deleteRef({ fs: fs2, gitdir, ref });\n    }\n    async function deleteTag({ fs: fs2, dir, gitdir = join2(dir, \".git\"), ref }) {\n      try {\n        assertParameter(\"fs\", fs2);\n        assertParameter(\"ref\", ref);\n        return await _deleteTag({\n          fs: new FileSystem(fs2),\n          gitdir,\n          ref\n        });\n      } catch (err) {\n        err.caller = \"git.deleteTag\";\n        throw err;\n      }\n    }\n    async function expandOidLoose({ fs: fs2, gitdir, oid: short }) {\n      const prefix = short.slice(0, 2);\n      const objectsSuffixes = await fs2.readdir(`${gitdir}/objects/${prefix}`);\n      return objectsSuffixes.map((suffix) => `${prefix}${suffix}`).filter((_oid) => _oid.startsWith(short));\n    }\n    async function expandOidPacked({\n      fs: fs2,\n      cache,\n      gitdir,\n      oid: short,\n      getExternalRefDelta\n    }) {\n      const results = [];\n      let list = await fs2.readdir(join2(gitdir, \"objects/pack\"));\n      list = list.filter((x) => x.endsWith(\".idx\"));\n      for (const filename of list) {\n        const indexFile = `${gitdir}/objects/pack/${filename}`;\n        const p = await readPackIndex({\n          fs: fs2,\n          cache,\n          filename: indexFile,\n          getExternalRefDelta\n        });\n        if (p.error) throw new InternalError(p.error);\n        for (const oid of p.offsets.keys()) {\n          if (oid.startsWith(short)) results.push(oid);\n        }\n      }\n      return results;\n    }\n    async function _expandOid({ fs: fs2, cache, gitdir, oid: short }) {\n      const getExternalRefDelta = (oid) => _readObject({ fs: fs2, cache, gitdir, oid });\n      const results = await expandOidLoose({ fs: fs2, gitdir, oid: short });\n      const packedOids = await expandOidPacked({\n        fs: fs2,\n        cache,\n        gitdir,\n        oid: short,\n        getExternalRefDelta\n      });\n      for (const packedOid of packedOids) {\n        if (results.indexOf(packedOid) === -1) {\n          results.push(packedOid);\n        }\n      }\n      if (results.length === 1) {\n        return results[0];\n      }\n      if (results.length > 1) {\n        throw new AmbiguousError(\"oids\", short, results);\n      }\n      throw new NotFoundError(`an object matching \"${short}\"`);\n    }\n    async function expandOid({\n      fs: fs2,\n      dir,\n      gitdir = join2(dir, \".git\"),\n      oid,\n      cache = {}\n    }) {\n      try {\n        assertParameter(\"fs\", fs2);\n        assertParameter(\"gitdir\", gitdir);\n        assertParameter(\"oid\", oid);\n        return await _expandOid({\n          fs: new FileSystem(fs2),\n          cache,\n          gitdir,\n          oid\n        });\n      } catch (err) {\n        err.caller = \"git.expandOid\";\n        throw err;\n      }\n    }\n    async function expandRef({ fs: fs2, dir, gitdir = join2(dir, \".git\"), ref }) {\n      try {\n        assertParameter(\"fs\", fs2);\n        assertParameter(\"gitdir\", gitdir);\n        assertParameter(\"ref\", ref);\n        return await GitRefManager.expand({\n          fs: new FileSystem(fs2),\n          gitdir,\n          ref\n        });\n      } catch (err) {\n        err.caller = \"git.expandRef\";\n        throw err;\n      }\n    }\n    async function _findMergeBase({ fs: fs2, cache, gitdir, oids }) {\n      const visits = {};\n      const passes = oids.length;\n      let heads = oids.map((oid, index2) => ({ index: index2, oid }));\n      while (heads.length) {\n        const result = /* @__PURE__ */ new Set();\n        for (const { oid, index: index2 } of heads) {\n          if (!visits[oid]) visits[oid] = /* @__PURE__ */ new Set();\n          visits[oid].add(index2);\n          if (visits[oid].size === passes) {\n            result.add(oid);\n          }\n        }\n        if (result.size > 0) {\n          return [...result];\n        }\n        const newheads = /* @__PURE__ */ new Map();\n        for (const { oid, index: index2 } of heads) {\n          try {\n            const { object } = await _readObject({ fs: fs2, cache, gitdir, oid });\n            const commit3 = GitCommit.from(object);\n            const { parent } = commit3.parseHeaders();\n            for (const oid2 of parent) {\n              if (!visits[oid2] || !visits[oid2].has(index2)) {\n                newheads.set(oid2 + \":\" + index2, { oid: oid2, index: index2 });\n              }\n            }\n          } catch (err) {\n          }\n        }\n        heads = Array.from(newheads.values());\n      }\n      return [];\n    }\n    var LINEBREAKS = /^.*(\\r?\\n|$)/gm;\n    function mergeFile({ branches, contents }) {\n      const ourName = branches[1];\n      const theirName = branches[2];\n      const baseContent = contents[0];\n      const ourContent = contents[1];\n      const theirContent = contents[2];\n      const ours = ourContent.match(LINEBREAKS);\n      const base = baseContent.match(LINEBREAKS);\n      const theirs = theirContent.match(LINEBREAKS);\n      const result = diff3Merge(ours, base, theirs);\n      const markerSize = 7;\n      let mergedText = \"\";\n      let cleanMerge = true;\n      for (const item of result) {\n        if (item.ok) {\n          mergedText += item.ok.join(\"\");\n        }\n        if (item.conflict) {\n          cleanMerge = false;\n          mergedText += `${\"<\".repeat(markerSize)} ${ourName}\n`;\n          mergedText += item.conflict.a.join(\"\");\n          mergedText += `${\"=\".repeat(markerSize)}\n`;\n          mergedText += item.conflict.b.join(\"\");\n          mergedText += `${\">\".repeat(markerSize)} ${theirName}\n`;\n        }\n      }\n      return { cleanMerge, mergedText };\n    }\n    async function mergeTree({\n      fs: fs2,\n      cache,\n      dir,\n      gitdir = join2(dir, \".git\"),\n      index: index2,\n      ourOid,\n      baseOid,\n      theirOid,\n      ourName = \"ours\",\n      baseName = \"base\",\n      theirName = \"theirs\",\n      dryRun = false,\n      abortOnConflict = true,\n      mergeDriver\n    }) {\n      const ourTree = TREE({ ref: ourOid });\n      const baseTree = TREE({ ref: baseOid });\n      const theirTree = TREE({ ref: theirOid });\n      const unmergedFiles = [];\n      const bothModified = [];\n      const deleteByUs = [];\n      const deleteByTheirs = [];\n      const results = await _walk({\n        fs: fs2,\n        cache,\n        dir,\n        gitdir,\n        trees: [ourTree, baseTree, theirTree],\n        map: async function(filepath, [ours, base, theirs]) {\n          const path2 = basename(filepath);\n          const ourChange = await modified(ours, base);\n          const theirChange = await modified(theirs, base);\n          switch (`${ourChange}-${theirChange}`) {\n            case \"false-false\": {\n              return {\n                mode: await base.mode(),\n                path: path2,\n                oid: await base.oid(),\n                type: await base.type()\n              };\n            }\n            case \"false-true\": {\n              return theirs ? {\n                mode: await theirs.mode(),\n                path: path2,\n                oid: await theirs.oid(),\n                type: await theirs.type()\n              } : void 0;\n            }\n            case \"true-false\": {\n              return ours ? {\n                mode: await ours.mode(),\n                path: path2,\n                oid: await ours.oid(),\n                type: await ours.type()\n              } : void 0;\n            }\n            case \"true-true\": {\n              if (ours && base && theirs && await ours.type() === \"blob\" && await base.type() === \"blob\" && await theirs.type() === \"blob\") {\n                return mergeBlobs({\n                  fs: fs2,\n                  gitdir,\n                  path: path2,\n                  ours,\n                  base,\n                  theirs,\n                  ourName,\n                  baseName,\n                  theirName,\n                  mergeDriver\n                }).then(async (r) => {\n                  if (!r.cleanMerge) {\n                    unmergedFiles.push(filepath);\n                    bothModified.push(filepath);\n                    if (!abortOnConflict) {\n                      const baseOid2 = await base.oid();\n                      const ourOid2 = await ours.oid();\n                      const theirOid2 = await theirs.oid();\n                      index2.delete({ filepath });\n                      index2.insert({ filepath, oid: baseOid2, stage: 1 });\n                      index2.insert({ filepath, oid: ourOid2, stage: 2 });\n                      index2.insert({ filepath, oid: theirOid2, stage: 3 });\n                    }\n                  } else if (!abortOnConflict) {\n                    index2.insert({ filepath, oid: r.mergeResult.oid, stage: 0 });\n                  }\n                  return r.mergeResult;\n                });\n              }\n              if (base && !ours && theirs && await base.type() === \"blob\" && await theirs.type() === \"blob\") {\n                unmergedFiles.push(filepath);\n                deleteByUs.push(filepath);\n                if (!abortOnConflict) {\n                  const baseOid2 = await base.oid();\n                  const theirOid2 = await theirs.oid();\n                  index2.delete({ filepath });\n                  index2.insert({ filepath, oid: baseOid2, stage: 1 });\n                  index2.insert({ filepath, oid: theirOid2, stage: 3 });\n                }\n                return {\n                  mode: await theirs.mode(),\n                  oid: await theirs.oid(),\n                  type: \"blob\",\n                  path: path2\n                };\n              }\n              if (base && ours && !theirs && await base.type() === \"blob\" && await ours.type() === \"blob\") {\n                unmergedFiles.push(filepath);\n                deleteByTheirs.push(filepath);\n                if (!abortOnConflict) {\n                  const baseOid2 = await base.oid();\n                  const ourOid2 = await ours.oid();\n                  index2.delete({ filepath });\n                  index2.insert({ filepath, oid: baseOid2, stage: 1 });\n                  index2.insert({ filepath, oid: ourOid2, stage: 2 });\n                }\n                return {\n                  mode: await ours.mode(),\n                  oid: await ours.oid(),\n                  type: \"blob\",\n                  path: path2\n                };\n              }\n              if (base && !ours && !theirs && await base.type() === \"blob\") {\n                return void 0;\n              }\n              throw new MergeNotSupportedError();\n            }\n          }\n        },\n        /**\n         * @param {TreeEntry} [parent]\n         * @param {Array<TreeEntry>} children\n         */\n        reduce: unmergedFiles.length !== 0 && (!dir || abortOnConflict) ? void 0 : async (parent, children) => {\n          const entries = children.filter(Boolean);\n          if (!parent) return;\n          if (parent && parent.type === \"tree\" && entries.length === 0) return;\n          if (entries.length > 0) {\n            const tree = new GitTree(entries);\n            const object = tree.toObject();\n            const oid = await _writeObject({\n              fs: fs2,\n              gitdir,\n              type: \"tree\",\n              object,\n              dryRun\n            });\n            parent.oid = oid;\n          }\n          return parent;\n        }\n      });\n      if (unmergedFiles.length !== 0) {\n        if (dir && !abortOnConflict) {\n          await _walk({\n            fs: fs2,\n            cache,\n            dir,\n            gitdir,\n            trees: [TREE({ ref: results.oid })],\n            map: async function(filepath, [entry]) {\n              const path2 = `${dir}/${filepath}`;\n              if (await entry.type() === \"blob\") {\n                const mode = await entry.mode();\n                const content = new TextDecoder().decode(await entry.content());\n                await fs2.write(path2, content, { mode });\n              }\n              return true;\n            }\n          });\n        }\n        return new MergeConflictError(\n          unmergedFiles,\n          bothModified,\n          deleteByUs,\n          deleteByTheirs\n        );\n      }\n      return results.oid;\n    }\n    async function mergeBlobs({\n      fs: fs2,\n      gitdir,\n      path: path2,\n      ours,\n      base,\n      theirs,\n      ourName,\n      theirName,\n      baseName,\n      dryRun,\n      mergeDriver = mergeFile\n    }) {\n      const type = \"blob\";\n      const mode = await base.mode() === await ours.mode() ? await theirs.mode() : await ours.mode();\n      if (await ours.oid() === await theirs.oid()) {\n        return {\n          cleanMerge: true,\n          mergeResult: { mode, path: path2, oid: await ours.oid(), type }\n        };\n      }\n      if (await ours.oid() === await base.oid()) {\n        return {\n          cleanMerge: true,\n          mergeResult: { mode, path: path2, oid: await theirs.oid(), type }\n        };\n      }\n      if (await theirs.oid() === await base.oid()) {\n        return {\n          cleanMerge: true,\n          mergeResult: { mode, path: path2, oid: await ours.oid(), type }\n        };\n      }\n      const ourContent = Buffer.from(await ours.content()).toString(\"utf8\");\n      const baseContent = Buffer.from(await base.content()).toString(\"utf8\");\n      const theirContent = Buffer.from(await theirs.content()).toString(\"utf8\");\n      const { mergedText, cleanMerge } = await mergeDriver({\n        branches: [baseName, ourName, theirName],\n        contents: [baseContent, ourContent, theirContent],\n        path: path2\n      });\n      const oid = await _writeObject({\n        fs: fs2,\n        gitdir,\n        type: \"blob\",\n        object: Buffer.from(mergedText, \"utf8\"),\n        dryRun\n      });\n      return { cleanMerge, mergeResult: { mode, path: path2, oid, type } };\n    }\n    async function _merge({\n      fs: fs2,\n      cache,\n      dir,\n      gitdir,\n      ours,\n      theirs,\n      fastForward: fastForward2 = true,\n      fastForwardOnly = false,\n      dryRun = false,\n      noUpdateBranch = false,\n      abortOnConflict = true,\n      message,\n      author: author2,\n      committer,\n      signingKey,\n      onSign,\n      mergeDriver\n    }) {\n      if (ours === void 0) {\n        ours = await _currentBranch({ fs: fs2, gitdir, fullname: true });\n      }\n      ours = await GitRefManager.expand({\n        fs: fs2,\n        gitdir,\n        ref: ours\n      });\n      theirs = await GitRefManager.expand({\n        fs: fs2,\n        gitdir,\n        ref: theirs\n      });\n      const ourOid = await GitRefManager.resolve({\n        fs: fs2,\n        gitdir,\n        ref: ours\n      });\n      const theirOid = await GitRefManager.resolve({\n        fs: fs2,\n        gitdir,\n        ref: theirs\n      });\n      const baseOids = await _findMergeBase({\n        fs: fs2,\n        cache,\n        gitdir,\n        oids: [ourOid, theirOid]\n      });\n      if (baseOids.length !== 1) {\n        throw new MergeNotSupportedError();\n      }\n      const baseOid = baseOids[0];\n      if (baseOid === theirOid) {\n        return {\n          oid: ourOid,\n          alreadyMerged: true\n        };\n      }\n      if (fastForward2 && baseOid === ourOid) {\n        if (!dryRun && !noUpdateBranch) {\n          await GitRefManager.writeRef({ fs: fs2, gitdir, ref: ours, value: theirOid });\n        }\n        return {\n          oid: theirOid,\n          fastForward: true\n        };\n      } else {\n        if (fastForwardOnly) {\n          throw new FastForwardError();\n        }\n        const tree = await GitIndexManager.acquire(\n          { fs: fs2, gitdir, cache, allowUnmerged: false },\n          async (index2) => {\n            return mergeTree({\n              fs: fs2,\n              cache,\n              dir,\n              gitdir,\n              index: index2,\n              ourOid,\n              theirOid,\n              baseOid,\n              ourName: abbreviateRef(ours),\n              baseName: \"base\",\n              theirName: abbreviateRef(theirs),\n              dryRun,\n              abortOnConflict,\n              mergeDriver\n            });\n          }\n        );\n        if (tree instanceof MergeConflictError) throw tree;\n        if (!message) {\n          message = `Merge branch '${abbreviateRef(theirs)}' into ${abbreviateRef(\n            ours\n          )}`;\n        }\n        const oid = await _commit({\n          fs: fs2,\n          cache,\n          gitdir,\n          message,\n          ref: ours,\n          tree,\n          parent: [ourOid, theirOid],\n          author: author2,\n          committer,\n          signingKey,\n          onSign,\n          dryRun,\n          noUpdateBranch\n        });\n        return {\n          oid,\n          tree,\n          mergeCommit: true\n        };\n      }\n    }\n    async function _pull({\n      fs: fs2,\n      cache,\n      http,\n      onProgress,\n      onMessage,\n      onAuth,\n      onAuthSuccess,\n      onAuthFailure,\n      dir,\n      gitdir,\n      ref,\n      url,\n      remote,\n      remoteRef,\n      prune,\n      pruneTags,\n      fastForward: fastForward2,\n      fastForwardOnly,\n      corsProxy,\n      singleBranch,\n      headers,\n      author: author2,\n      committer,\n      signingKey\n    }) {\n      try {\n        if (!ref) {\n          const head = await _currentBranch({ fs: fs2, gitdir });\n          if (!head) {\n            throw new MissingParameterError(\"ref\");\n          }\n          ref = head;\n        }\n        const { fetchHead, fetchHeadDescription } = await _fetch({\n          fs: fs2,\n          cache,\n          http,\n          onProgress,\n          onMessage,\n          onAuth,\n          onAuthSuccess,\n          onAuthFailure,\n          gitdir,\n          corsProxy,\n          ref,\n          url,\n          remote,\n          remoteRef,\n          singleBranch,\n          headers,\n          prune,\n          pruneTags\n        });\n        await _merge({\n          fs: fs2,\n          cache,\n          gitdir,\n          ours: ref,\n          theirs: fetchHead,\n          fastForward: fastForward2,\n          fastForwardOnly,\n          message: `Merge ${fetchHeadDescription}`,\n          author: author2,\n          committer,\n          signingKey,\n          dryRun: false,\n          noUpdateBranch: false\n        });\n        await _checkout({\n          fs: fs2,\n          cache,\n          onProgress,\n          dir,\n          gitdir,\n          ref,\n          remote,\n          noCheckout: false\n        });\n      } catch (err) {\n        err.caller = \"git.pull\";\n        throw err;\n      }\n    }\n    async function fastForward({\n      fs: fs2,\n      http,\n      onProgress,\n      onMessage,\n      onAuth,\n      onAuthSuccess,\n      onAuthFailure,\n      dir,\n      gitdir = join2(dir, \".git\"),\n      ref,\n      url,\n      remote,\n      remoteRef,\n      corsProxy,\n      singleBranch,\n      headers = {},\n      cache = {}\n    }) {\n      try {\n        assertParameter(\"fs\", fs2);\n        assertParameter(\"http\", http);\n        assertParameter(\"gitdir\", gitdir);\n        const thisWillNotBeUsed = {\n          name: \"\",\n          email: \"\",\n          timestamp: Date.now(),\n          timezoneOffset: 0\n        };\n        return await _pull({\n          fs: new FileSystem(fs2),\n          cache,\n          http,\n          onProgress,\n          onMessage,\n          onAuth,\n          onAuthSuccess,\n          onAuthFailure,\n          dir,\n          gitdir,\n          ref,\n          url,\n          remote,\n          remoteRef,\n          fastForwardOnly: true,\n          corsProxy,\n          singleBranch,\n          headers,\n          author: thisWillNotBeUsed,\n          committer: thisWillNotBeUsed\n        });\n      } catch (err) {\n        err.caller = \"git.fastForward\";\n        throw err;\n      }\n    }\n    async function fetch({\n      fs: fs2,\n      http,\n      onProgress,\n      onMessage,\n      onAuth,\n      onAuthSuccess,\n      onAuthFailure,\n      dir,\n      gitdir = join2(dir, \".git\"),\n      ref,\n      remote,\n      remoteRef,\n      url,\n      corsProxy,\n      depth = null,\n      since = null,\n      exclude = [],\n      relative = false,\n      tags = false,\n      singleBranch = false,\n      headers = {},\n      prune = false,\n      pruneTags = false,\n      cache = {}\n    }) {\n      try {\n        assertParameter(\"fs\", fs2);\n        assertParameter(\"http\", http);\n        assertParameter(\"gitdir\", gitdir);\n        return await _fetch({\n          fs: new FileSystem(fs2),\n          cache,\n          http,\n          onProgress,\n          onMessage,\n          onAuth,\n          onAuthSuccess,\n          onAuthFailure,\n          gitdir,\n          ref,\n          remote,\n          remoteRef,\n          url,\n          corsProxy,\n          depth,\n          since,\n          exclude,\n          relative,\n          tags,\n          singleBranch,\n          headers,\n          prune,\n          pruneTags\n        });\n      } catch (err) {\n        err.caller = \"git.fetch\";\n        throw err;\n      }\n    }\n    async function findMergeBase({\n      fs: fs2,\n      dir,\n      gitdir = join2(dir, \".git\"),\n      oids,\n      cache = {}\n    }) {\n      try {\n        assertParameter(\"fs\", fs2);\n        assertParameter(\"gitdir\", gitdir);\n        assertParameter(\"oids\", oids);\n        return await _findMergeBase({\n          fs: new FileSystem(fs2),\n          cache,\n          gitdir,\n          oids\n        });\n      } catch (err) {\n        err.caller = \"git.findMergeBase\";\n        throw err;\n      }\n    }\n    async function _findRoot({ fs: fs2, filepath }) {\n      if (await fs2.exists(join2(filepath, \".git\"))) {\n        return filepath;\n      } else {\n        const parent = dirname(filepath);\n        if (parent === filepath) {\n          throw new NotFoundError(`git root for ${filepath}`);\n        }\n        return _findRoot({ fs: fs2, filepath: parent });\n      }\n    }\n    async function findRoot2({ fs: fs2, filepath }) {\n      try {\n        assertParameter(\"fs\", fs2);\n        assertParameter(\"filepath\", filepath);\n        return await _findRoot({ fs: new FileSystem(fs2), filepath });\n      } catch (err) {\n        err.caller = \"git.findRoot\";\n        throw err;\n      }\n    }\n    async function getConfig({ fs: fs2, dir, gitdir = join2(dir, \".git\"), path: path2 }) {\n      try {\n        assertParameter(\"fs\", fs2);\n        assertParameter(\"gitdir\", gitdir);\n        assertParameter(\"path\", path2);\n        return await _getConfig({\n          fs: new FileSystem(fs2),\n          gitdir,\n          path: path2\n        });\n      } catch (err) {\n        err.caller = \"git.getConfig\";\n        throw err;\n      }\n    }\n    async function _getConfigAll({ fs: fs2, gitdir, path: path2 }) {\n      const config = await GitConfigManager.get({ fs: fs2, gitdir });\n      return config.getall(path2);\n    }\n    async function getConfigAll({\n      fs: fs2,\n      dir,\n      gitdir = join2(dir, \".git\"),\n      path: path2\n    }) {\n      try {\n        assertParameter(\"fs\", fs2);\n        assertParameter(\"gitdir\", gitdir);\n        assertParameter(\"path\", path2);\n        return await _getConfigAll({\n          fs: new FileSystem(fs2),\n          gitdir,\n          path: path2\n        });\n      } catch (err) {\n        err.caller = \"git.getConfigAll\";\n        throw err;\n      }\n    }\n    async function getRemoteInfo({\n      http,\n      onAuth,\n      onAuthSuccess,\n      onAuthFailure,\n      corsProxy,\n      url,\n      headers = {},\n      forPush = false\n    }) {\n      try {\n        assertParameter(\"http\", http);\n        assertParameter(\"url\", url);\n        const GitRemoteHTTP2 = GitRemoteManager.getRemoteHelperFor({ url });\n        const remote = await GitRemoteHTTP2.discover({\n          http,\n          onAuth,\n          onAuthSuccess,\n          onAuthFailure,\n          corsProxy,\n          service: forPush ? \"git-receive-pack\" : \"git-upload-pack\",\n          url,\n          headers,\n          protocolVersion: 1\n        });\n        const result = {\n          capabilities: [...remote.capabilities]\n        };\n        for (const [ref, oid] of remote.refs) {\n          const parts = ref.split(\"/\");\n          const last = parts.pop();\n          let o = result;\n          for (const part of parts) {\n            o[part] = o[part] || {};\n            o = o[part];\n          }\n          o[last] = oid;\n        }\n        for (const [symref, ref] of remote.symrefs) {\n          const parts = symref.split(\"/\");\n          const last = parts.pop();\n          let o = result;\n          for (const part of parts) {\n            o[part] = o[part] || {};\n            o = o[part];\n          }\n          o[last] = ref;\n        }\n        return result;\n      } catch (err) {\n        err.caller = \"git.getRemoteInfo\";\n        throw err;\n      }\n    }\n    function formatInfoRefs(remote, prefix, symrefs, peelTags) {\n      const refs = [];\n      for (const [key, value] of remote.refs) {\n        if (prefix && !key.startsWith(prefix)) continue;\n        if (key.endsWith(\"^{}\")) {\n          if (peelTags) {\n            const _key = key.replace(\"^{}\", \"\");\n            const last = refs[refs.length - 1];\n            const r = last.ref === _key ? last : refs.find((x) => x.ref === _key);\n            if (r === void 0) {\n              throw new Error(\"I did not expect this to happen\");\n            }\n            r.peeled = value;\n          }\n          continue;\n        }\n        const ref = { ref: key, oid: value };\n        if (symrefs) {\n          if (remote.symrefs.has(key)) {\n            ref.target = remote.symrefs.get(key);\n          }\n        }\n        refs.push(ref);\n      }\n      return refs;\n    }\n    async function getRemoteInfo2({\n      http,\n      onAuth,\n      onAuthSuccess,\n      onAuthFailure,\n      corsProxy,\n      url,\n      headers = {},\n      forPush = false,\n      protocolVersion = 2\n    }) {\n      try {\n        assertParameter(\"http\", http);\n        assertParameter(\"url\", url);\n        const GitRemoteHTTP2 = GitRemoteManager.getRemoteHelperFor({ url });\n        const remote = await GitRemoteHTTP2.discover({\n          http,\n          onAuth,\n          onAuthSuccess,\n          onAuthFailure,\n          corsProxy,\n          service: forPush ? \"git-receive-pack\" : \"git-upload-pack\",\n          url,\n          headers,\n          protocolVersion\n        });\n        if (remote.protocolVersion === 2) {\n          return {\n            protocolVersion: remote.protocolVersion,\n            capabilities: remote.capabilities2\n          };\n        }\n        const capabilities = {};\n        for (const cap of remote.capabilities) {\n          const [key, value] = cap.split(\"=\");\n          if (value) {\n            capabilities[key] = value;\n          } else {\n            capabilities[key] = true;\n          }\n        }\n        return {\n          protocolVersion: 1,\n          capabilities,\n          refs: formatInfoRefs(remote, void 0, true, true)\n        };\n      } catch (err) {\n        err.caller = \"git.getRemoteInfo2\";\n        throw err;\n      }\n    }\n    async function hashObject({\n      type,\n      object,\n      format = \"content\",\n      oid = void 0\n    }) {\n      if (format !== \"deflated\") {\n        if (format !== \"wrapped\") {\n          object = GitObject.wrap({ type, object });\n        }\n        oid = await shasum(object);\n      }\n      return { oid, object };\n    }\n    async function hashBlob({ object }) {\n      try {\n        assertParameter(\"object\", object);\n        if (typeof object === \"string\") {\n          object = Buffer.from(object, \"utf8\");\n        } else {\n          object = Buffer.from(object);\n        }\n        const type = \"blob\";\n        const { oid, object: _object } = await hashObject({\n          type: \"blob\",\n          format: \"content\",\n          object\n        });\n        return { oid, type, object: new Uint8Array(_object), format: \"wrapped\" };\n      } catch (err) {\n        err.caller = \"git.hashBlob\";\n        throw err;\n      }\n    }\n    async function _indexPack({\n      fs: fs2,\n      cache,\n      onProgress,\n      dir,\n      gitdir,\n      filepath\n    }) {\n      try {\n        filepath = join2(dir, filepath);\n        const pack = await fs2.read(filepath);\n        const getExternalRefDelta = (oid) => _readObject({ fs: fs2, cache, gitdir, oid });\n        const idx = await GitPackIndex.fromPack({\n          pack,\n          getExternalRefDelta,\n          onProgress\n        });\n        await fs2.write(filepath.replace(/\\.pack$/, \".idx\"), await idx.toBuffer());\n        return {\n          oids: [...idx.hashes]\n        };\n      } catch (err) {\n        err.caller = \"git.indexPack\";\n        throw err;\n      }\n    }\n    async function indexPack({\n      fs: fs2,\n      onProgress,\n      dir,\n      gitdir = join2(dir, \".git\"),\n      filepath,\n      cache = {}\n    }) {\n      try {\n        assertParameter(\"fs\", fs2);\n        assertParameter(\"dir\", dir);\n        assertParameter(\"gitdir\", dir);\n        assertParameter(\"filepath\", filepath);\n        return await _indexPack({\n          fs: new FileSystem(fs2),\n          cache,\n          onProgress,\n          dir,\n          gitdir,\n          filepath\n        });\n      } catch (err) {\n        err.caller = \"git.indexPack\";\n        throw err;\n      }\n    }\n    async function init({\n      fs: fs2,\n      bare = false,\n      dir,\n      gitdir = bare ? dir : join2(dir, \".git\"),\n      defaultBranch = \"master\"\n    }) {\n      try {\n        assertParameter(\"fs\", fs2);\n        assertParameter(\"gitdir\", gitdir);\n        if (!bare) {\n          assertParameter(\"dir\", dir);\n        }\n        return await _init({\n          fs: new FileSystem(fs2),\n          bare,\n          dir,\n          gitdir,\n          defaultBranch\n        });\n      } catch (err) {\n        err.caller = \"git.init\";\n        throw err;\n      }\n    }\n    async function _isDescendent({\n      fs: fs2,\n      cache,\n      gitdir,\n      oid,\n      ancestor,\n      depth\n    }) {\n      const shallows = await GitShallowManager.read({ fs: fs2, gitdir });\n      if (!oid) {\n        throw new MissingParameterError(\"oid\");\n      }\n      if (!ancestor) {\n        throw new MissingParameterError(\"ancestor\");\n      }\n      if (oid === ancestor) return false;\n      const queue = [oid];\n      const visited = /* @__PURE__ */ new Set();\n      let searchdepth = 0;\n      while (queue.length) {\n        if (searchdepth++ === depth) {\n          throw new MaxDepthError(depth);\n        }\n        const oid2 = queue.shift();\n        const { type, object } = await _readObject({\n          fs: fs2,\n          cache,\n          gitdir,\n          oid: oid2\n        });\n        if (type !== \"commit\") {\n          throw new ObjectTypeError(oid2, type, \"commit\");\n        }\n        const commit3 = GitCommit.from(object).parse();\n        for (const parent of commit3.parent) {\n          if (parent === ancestor) return true;\n        }\n        if (!shallows.has(oid2)) {\n          for (const parent of commit3.parent) {\n            if (!visited.has(parent)) {\n              queue.push(parent);\n              visited.add(parent);\n            }\n          }\n        }\n      }\n      return false;\n    }\n    async function isDescendent({\n      fs: fs2,\n      dir,\n      gitdir = join2(dir, \".git\"),\n      oid,\n      ancestor,\n      depth = -1,\n      cache = {}\n    }) {\n      try {\n        assertParameter(\"fs\", fs2);\n        assertParameter(\"gitdir\", gitdir);\n        assertParameter(\"oid\", oid);\n        assertParameter(\"ancestor\", ancestor);\n        return await _isDescendent({\n          fs: new FileSystem(fs2),\n          cache,\n          gitdir,\n          oid,\n          ancestor,\n          depth\n        });\n      } catch (err) {\n        err.caller = \"git.isDescendent\";\n        throw err;\n      }\n    }\n    async function isIgnored({\n      fs: fs2,\n      dir,\n      gitdir = join2(dir, \".git\"),\n      filepath\n    }) {\n      try {\n        assertParameter(\"fs\", fs2);\n        assertParameter(\"dir\", dir);\n        assertParameter(\"gitdir\", gitdir);\n        assertParameter(\"filepath\", filepath);\n        return GitIgnoreManager.isIgnored({\n          fs: new FileSystem(fs2),\n          dir,\n          gitdir,\n          filepath\n        });\n      } catch (err) {\n        err.caller = \"git.isIgnored\";\n        throw err;\n      }\n    }\n    async function listBranches({\n      fs: fs2,\n      dir,\n      gitdir = join2(dir, \".git\"),\n      remote\n    }) {\n      try {\n        assertParameter(\"fs\", fs2);\n        assertParameter(\"gitdir\", gitdir);\n        return GitRefManager.listBranches({\n          fs: new FileSystem(fs2),\n          gitdir,\n          remote\n        });\n      } catch (err) {\n        err.caller = \"git.listBranches\";\n        throw err;\n      }\n    }\n    async function _listFiles({ fs: fs2, gitdir, ref, cache }) {\n      if (ref) {\n        const oid = await GitRefManager.resolve({ gitdir, fs: fs2, ref });\n        const filenames = [];\n        await accumulateFilesFromOid({\n          fs: fs2,\n          cache,\n          gitdir,\n          oid,\n          filenames,\n          prefix: \"\"\n        });\n        return filenames;\n      } else {\n        return GitIndexManager.acquire({ fs: fs2, gitdir, cache }, async function(index2) {\n          return index2.entries.map((x) => x.path);\n        });\n      }\n    }\n    async function accumulateFilesFromOid({\n      fs: fs2,\n      cache,\n      gitdir,\n      oid,\n      filenames,\n      prefix\n    }) {\n      const { tree } = await _readTree({ fs: fs2, cache, gitdir, oid });\n      for (const entry of tree) {\n        if (entry.type === \"tree\") {\n          await accumulateFilesFromOid({\n            fs: fs2,\n            cache,\n            gitdir,\n            oid: entry.oid,\n            filenames,\n            prefix: join2(prefix, entry.path)\n          });\n        } else {\n          filenames.push(join2(prefix, entry.path));\n        }\n      }\n    }\n    async function listFiles({\n      fs: fs2,\n      dir,\n      gitdir = join2(dir, \".git\"),\n      ref,\n      cache = {}\n    }) {\n      try {\n        assertParameter(\"fs\", fs2);\n        assertParameter(\"gitdir\", gitdir);\n        return await _listFiles({\n          fs: new FileSystem(fs2),\n          cache,\n          gitdir,\n          ref\n        });\n      } catch (err) {\n        err.caller = \"git.listFiles\";\n        throw err;\n      }\n    }\n    async function _listNotes({ fs: fs2, cache, gitdir, ref }) {\n      let parent;\n      try {\n        parent = await GitRefManager.resolve({ gitdir, fs: fs2, ref });\n      } catch (err) {\n        if (err instanceof NotFoundError) {\n          return [];\n        }\n      }\n      const result = await _readTree({\n        fs: fs2,\n        cache,\n        gitdir,\n        oid: parent\n      });\n      const notes = result.tree.map((entry) => ({\n        target: entry.path,\n        note: entry.oid\n      }));\n      return notes;\n    }\n    async function listNotes({\n      fs: fs2,\n      dir,\n      gitdir = join2(dir, \".git\"),\n      ref = \"refs/notes/commits\",\n      cache = {}\n    }) {\n      try {\n        assertParameter(\"fs\", fs2);\n        assertParameter(\"gitdir\", gitdir);\n        assertParameter(\"ref\", ref);\n        return await _listNotes({\n          fs: new FileSystem(fs2),\n          cache,\n          gitdir,\n          ref\n        });\n      } catch (err) {\n        err.caller = \"git.listNotes\";\n        throw err;\n      }\n    }\n    async function _listRemotes({ fs: fs2, gitdir }) {\n      const config = await GitConfigManager.get({ fs: fs2, gitdir });\n      const remoteNames = await config.getSubsections(\"remote\");\n      const remotes = Promise.all(\n        remoteNames.map(async (remote) => {\n          const url = await config.get(`remote.${remote}.url`);\n          return { remote, url };\n        })\n      );\n      return remotes;\n    }\n    async function listRemotes({ fs: fs2, dir, gitdir = join2(dir, \".git\") }) {\n      try {\n        assertParameter(\"fs\", fs2);\n        assertParameter(\"gitdir\", gitdir);\n        return await _listRemotes({\n          fs: new FileSystem(fs2),\n          gitdir\n        });\n      } catch (err) {\n        err.caller = \"git.listRemotes\";\n        throw err;\n      }\n    }\n    async function parseListRefsResponse(stream) {\n      const read = GitPktLine.streamReader(stream);\n      const refs = [];\n      let line;\n      while (true) {\n        line = await read();\n        if (line === true) break;\n        if (line === null) continue;\n        line = line.toString(\"utf8\").replace(/\\n$/, \"\");\n        const [oid, ref, ...attrs] = line.split(\" \");\n        const r = { ref, oid };\n        for (const attr of attrs) {\n          const [name, value] = attr.split(\":\");\n          if (name === \"symref-target\") {\n            r.target = value;\n          } else if (name === \"peeled\") {\n            r.peeled = value;\n          }\n        }\n        refs.push(r);\n      }\n      return refs;\n    }\n    async function writeListRefsRequest({ prefix, symrefs, peelTags }) {\n      const packstream = [];\n      packstream.push(GitPktLine.encode(\"command=ls-refs\\n\"));\n      packstream.push(GitPktLine.encode(`agent=${pkg.agent}\n`));\n      if (peelTags || symrefs || prefix) {\n        packstream.push(GitPktLine.delim());\n      }\n      if (peelTags) packstream.push(GitPktLine.encode(\"peel\"));\n      if (symrefs) packstream.push(GitPktLine.encode(\"symrefs\"));\n      if (prefix) packstream.push(GitPktLine.encode(`ref-prefix ${prefix}`));\n      packstream.push(GitPktLine.flush());\n      return packstream;\n    }\n    async function listServerRefs({\n      http,\n      onAuth,\n      onAuthSuccess,\n      onAuthFailure,\n      corsProxy,\n      url,\n      headers = {},\n      forPush = false,\n      protocolVersion = 2,\n      prefix,\n      symrefs,\n      peelTags\n    }) {\n      try {\n        assertParameter(\"http\", http);\n        assertParameter(\"url\", url);\n        const remote = await GitRemoteHTTP.discover({\n          http,\n          onAuth,\n          onAuthSuccess,\n          onAuthFailure,\n          corsProxy,\n          service: forPush ? \"git-receive-pack\" : \"git-upload-pack\",\n          url,\n          headers,\n          protocolVersion\n        });\n        if (remote.protocolVersion === 1) {\n          return formatInfoRefs(remote, prefix, symrefs, peelTags);\n        }\n        const body = await writeListRefsRequest({ prefix, symrefs, peelTags });\n        const res = await GitRemoteHTTP.connect({\n          http,\n          auth: remote.auth,\n          headers,\n          corsProxy,\n          service: forPush ? \"git-receive-pack\" : \"git-upload-pack\",\n          url,\n          body\n        });\n        return parseListRefsResponse(res.body);\n      } catch (err) {\n        err.caller = \"git.listServerRefs\";\n        throw err;\n      }\n    }\n    async function listTags({ fs: fs2, dir, gitdir = join2(dir, \".git\") }) {\n      try {\n        assertParameter(\"fs\", fs2);\n        assertParameter(\"gitdir\", gitdir);\n        return GitRefManager.listTags({ fs: new FileSystem(fs2), gitdir });\n      } catch (err) {\n        err.caller = \"git.listTags\";\n        throw err;\n      }\n    }\n    function compareAge(a, b) {\n      return a.committer.timestamp - b.committer.timestamp;\n    }\n    var EMPTY_OID = \"e69de29bb2d1d6434b8b29ae775ad8c2e48c5391\";\n    async function resolveFileIdInTree({ fs: fs2, cache, gitdir, oid, fileId }) {\n      if (fileId === EMPTY_OID) return;\n      const _oid = oid;\n      let filepath;\n      const result = await resolveTree({ fs: fs2, cache, gitdir, oid });\n      const tree = result.tree;\n      if (fileId === result.oid) {\n        filepath = result.path;\n      } else {\n        filepath = await _resolveFileId({\n          fs: fs2,\n          cache,\n          gitdir,\n          tree,\n          fileId,\n          oid: _oid\n        });\n        if (Array.isArray(filepath)) {\n          if (filepath.length === 0) filepath = void 0;\n          else if (filepath.length === 1) filepath = filepath[0];\n        }\n      }\n      return filepath;\n    }\n    async function _resolveFileId({\n      fs: fs2,\n      cache,\n      gitdir,\n      tree,\n      fileId,\n      oid,\n      filepaths = [],\n      parentPath = \"\"\n    }) {\n      const walks = tree.entries().map(function(entry) {\n        let result;\n        if (entry.oid === fileId) {\n          result = join2(parentPath, entry.path);\n          filepaths.push(result);\n        } else if (entry.type === \"tree\") {\n          result = _readObject({\n            fs: fs2,\n            cache,\n            gitdir,\n            oid: entry.oid\n          }).then(function({ object }) {\n            return _resolveFileId({\n              fs: fs2,\n              cache,\n              gitdir,\n              tree: GitTree.from(object),\n              fileId,\n              oid,\n              filepaths,\n              parentPath: join2(parentPath, entry.path)\n            });\n          });\n        }\n        return result;\n      });\n      await Promise.all(walks);\n      return filepaths;\n    }\n    async function _log({\n      fs: fs2,\n      cache,\n      gitdir,\n      filepath,\n      ref,\n      depth,\n      since,\n      force,\n      follow\n    }) {\n      const sinceTimestamp = typeof since === \"undefined\" ? void 0 : Math.floor(since.valueOf() / 1e3);\n      const commits = [];\n      const shallowCommits = await GitShallowManager.read({ fs: fs2, gitdir });\n      const oid = await GitRefManager.resolve({ fs: fs2, gitdir, ref });\n      const tips = [await _readCommit({ fs: fs2, cache, gitdir, oid })];\n      let lastFileOid;\n      let lastCommit;\n      let isOk;\n      function endCommit(commit3) {\n        if (isOk && filepath) commits.push(commit3);\n      }\n      while (tips.length > 0) {\n        const commit3 = tips.pop();\n        if (sinceTimestamp !== void 0 && commit3.commit.committer.timestamp <= sinceTimestamp) {\n          break;\n        }\n        if (filepath) {\n          let vFileOid;\n          try {\n            vFileOid = await resolveFilepath({\n              fs: fs2,\n              cache,\n              gitdir,\n              oid: commit3.commit.tree,\n              filepath\n            });\n            if (lastCommit && lastFileOid !== vFileOid) {\n              commits.push(lastCommit);\n            }\n            lastFileOid = vFileOid;\n            lastCommit = commit3;\n            isOk = true;\n          } catch (e) {\n            if (e instanceof NotFoundError) {\n              let found = follow && lastFileOid;\n              if (found) {\n                found = await resolveFileIdInTree({\n                  fs: fs2,\n                  cache,\n                  gitdir,\n                  oid: commit3.commit.tree,\n                  fileId: lastFileOid\n                });\n                if (found) {\n                  if (Array.isArray(found)) {\n                    if (lastCommit) {\n                      const lastFound = await resolveFileIdInTree({\n                        fs: fs2,\n                        cache,\n                        gitdir,\n                        oid: lastCommit.commit.tree,\n                        fileId: lastFileOid\n                      });\n                      if (Array.isArray(lastFound)) {\n                        found = found.filter((p) => lastFound.indexOf(p) === -1);\n                        if (found.length === 1) {\n                          found = found[0];\n                          filepath = found;\n                          if (lastCommit) commits.push(lastCommit);\n                        } else {\n                          found = false;\n                          if (lastCommit) commits.push(lastCommit);\n                          break;\n                        }\n                      }\n                    }\n                  } else {\n                    filepath = found;\n                    if (lastCommit) commits.push(lastCommit);\n                  }\n                }\n              }\n              if (!found) {\n                if (isOk && lastFileOid) {\n                  commits.push(lastCommit);\n                  if (!force) break;\n                }\n                if (!force && !follow) throw e;\n              }\n              lastCommit = commit3;\n              isOk = false;\n            } else throw e;\n          }\n        } else {\n          commits.push(commit3);\n        }\n        if (depth !== void 0 && commits.length === depth) {\n          endCommit(commit3);\n          break;\n        }\n        if (!shallowCommits.has(commit3.oid)) {\n          for (const oid2 of commit3.commit.parent) {\n            const commit4 = await _readCommit({ fs: fs2, cache, gitdir, oid: oid2 });\n            if (!tips.map((commit5) => commit5.oid).includes(commit4.oid)) {\n              tips.push(commit4);\n            }\n          }\n        }\n        if (tips.length === 0) {\n          endCommit(commit3);\n        }\n        tips.sort((a, b) => compareAge(a.commit, b.commit));\n      }\n      return commits;\n    }\n    async function log2({\n      fs: fs2,\n      dir,\n      gitdir = join2(dir, \".git\"),\n      filepath,\n      ref = \"HEAD\",\n      depth,\n      since,\n      // Date\n      force,\n      follow,\n      cache = {}\n    }) {\n      try {\n        assertParameter(\"fs\", fs2);\n        assertParameter(\"gitdir\", gitdir);\n        assertParameter(\"ref\", ref);\n        return await _log({\n          fs: new FileSystem(fs2),\n          cache,\n          gitdir,\n          filepath,\n          ref,\n          depth,\n          since,\n          force,\n          follow\n        });\n      } catch (err) {\n        err.caller = \"git.log\";\n        throw err;\n      }\n    }\n    async function merge({\n      fs: _fs,\n      onSign,\n      dir,\n      gitdir = join2(dir, \".git\"),\n      ours,\n      theirs,\n      fastForward: fastForward2 = true,\n      fastForwardOnly = false,\n      dryRun = false,\n      noUpdateBranch = false,\n      abortOnConflict = true,\n      message,\n      author: _author,\n      committer: _committer,\n      signingKey,\n      cache = {},\n      mergeDriver\n    }) {\n      try {\n        assertParameter(\"fs\", _fs);\n        if (signingKey) {\n          assertParameter(\"onSign\", onSign);\n        }\n        const fs2 = new FileSystem(_fs);\n        const author2 = await normalizeAuthorObject({ fs: fs2, gitdir, author: _author });\n        if (!author2 && (!fastForwardOnly || !fastForward2)) {\n          throw new MissingNameError(\"author\");\n        }\n        const committer = await normalizeCommitterObject({\n          fs: fs2,\n          gitdir,\n          author: author2,\n          committer: _committer\n        });\n        if (!committer && (!fastForwardOnly || !fastForward2)) {\n          throw new MissingNameError(\"committer\");\n        }\n        return await _merge({\n          fs: fs2,\n          cache,\n          dir,\n          gitdir,\n          ours,\n          theirs,\n          fastForward: fastForward2,\n          fastForwardOnly,\n          dryRun,\n          noUpdateBranch,\n          abortOnConflict,\n          message,\n          author: author2,\n          committer,\n          signingKey,\n          onSign,\n          mergeDriver\n        });\n      } catch (err) {\n        err.caller = \"git.merge\";\n        throw err;\n      }\n    }\n    var types = {\n      commit: 16,\n      tree: 32,\n      blob: 48,\n      tag: 64,\n      ofs_delta: 96,\n      ref_delta: 112\n    };\n    async function _pack({\n      fs: fs2,\n      cache,\n      dir,\n      gitdir = join2(dir, \".git\"),\n      oids\n    }) {\n      const hash = new Hash();\n      const outputStream = [];\n      function write(chunk, enc) {\n        const buff = Buffer.from(chunk, enc);\n        outputStream.push(buff);\n        hash.update(buff);\n      }\n      async function writeObject2({ stype, object }) {\n        const type = types[stype];\n        let length = object.length;\n        let multibyte = length > 15 ? 128 : 0;\n        const lastFour = length & 15;\n        length = length >>> 4;\n        let byte = (multibyte | type | lastFour).toString(16);\n        write(byte, \"hex\");\n        while (multibyte) {\n          multibyte = length > 127 ? 128 : 0;\n          byte = multibyte | length & 127;\n          write(padHex(2, byte), \"hex\");\n          length = length >>> 7;\n        }\n        write(Buffer.from(await deflate(object)));\n      }\n      write(\"PACK\");\n      write(\"00000002\", \"hex\");\n      write(padHex(8, oids.length), \"hex\");\n      for (const oid of oids) {\n        const { type, object } = await _readObject({ fs: fs2, cache, gitdir, oid });\n        await writeObject2({ write, object, stype: type });\n      }\n      const digest = hash.digest();\n      outputStream.push(digest);\n      return outputStream;\n    }\n    async function _packObjects({ fs: fs2, cache, gitdir, oids, write }) {\n      const buffers = await _pack({ fs: fs2, cache, gitdir, oids });\n      const packfile = Buffer.from(await collect(buffers));\n      const packfileSha = packfile.slice(-20).toString(\"hex\");\n      const filename = `pack-${packfileSha}.pack`;\n      if (write) {\n        await fs2.write(join2(gitdir, `objects/pack/${filename}`), packfile);\n        return { filename };\n      }\n      return {\n        filename,\n        packfile: new Uint8Array(packfile)\n      };\n    }\n    async function packObjects({\n      fs: fs2,\n      dir,\n      gitdir = join2(dir, \".git\"),\n      oids,\n      write = false,\n      cache = {}\n    }) {\n      try {\n        assertParameter(\"fs\", fs2);\n        assertParameter(\"gitdir\", gitdir);\n        assertParameter(\"oids\", oids);\n        return await _packObjects({\n          fs: new FileSystem(fs2),\n          cache,\n          gitdir,\n          oids,\n          write\n        });\n      } catch (err) {\n        err.caller = \"git.packObjects\";\n        throw err;\n      }\n    }\n    async function pull({\n      fs: _fs,\n      http,\n      onProgress,\n      onMessage,\n      onAuth,\n      onAuthSuccess,\n      onAuthFailure,\n      dir,\n      gitdir = join2(dir, \".git\"),\n      ref,\n      url,\n      remote,\n      remoteRef,\n      prune = false,\n      pruneTags = false,\n      fastForward: fastForward2 = true,\n      fastForwardOnly = false,\n      corsProxy,\n      singleBranch,\n      headers = {},\n      author: _author,\n      committer: _committer,\n      signingKey,\n      cache = {}\n    }) {\n      try {\n        assertParameter(\"fs\", _fs);\n        assertParameter(\"gitdir\", gitdir);\n        const fs2 = new FileSystem(_fs);\n        const author2 = await normalizeAuthorObject({ fs: fs2, gitdir, author: _author });\n        if (!author2) throw new MissingNameError(\"author\");\n        const committer = await normalizeCommitterObject({\n          fs: fs2,\n          gitdir,\n          author: author2,\n          committer: _committer\n        });\n        if (!committer) throw new MissingNameError(\"committer\");\n        return await _pull({\n          fs: fs2,\n          cache,\n          http,\n          onProgress,\n          onMessage,\n          onAuth,\n          onAuthSuccess,\n          onAuthFailure,\n          dir,\n          gitdir,\n          ref,\n          url,\n          remote,\n          remoteRef,\n          fastForward: fastForward2,\n          fastForwardOnly,\n          corsProxy,\n          singleBranch,\n          headers,\n          author: author2,\n          committer,\n          signingKey,\n          prune,\n          pruneTags\n        });\n      } catch (err) {\n        err.caller = \"git.pull\";\n        throw err;\n      }\n    }\n    async function listCommitsAndTags({\n      fs: fs2,\n      cache,\n      dir,\n      gitdir = join2(dir, \".git\"),\n      start,\n      finish\n    }) {\n      const shallows = await GitShallowManager.read({ fs: fs2, gitdir });\n      const startingSet = /* @__PURE__ */ new Set();\n      const finishingSet = /* @__PURE__ */ new Set();\n      for (const ref of start) {\n        startingSet.add(await GitRefManager.resolve({ fs: fs2, gitdir, ref }));\n      }\n      for (const ref of finish) {\n        try {\n          const oid = await GitRefManager.resolve({ fs: fs2, gitdir, ref });\n          finishingSet.add(oid);\n        } catch (err) {\n        }\n      }\n      const visited = /* @__PURE__ */ new Set();\n      async function walk2(oid) {\n        visited.add(oid);\n        const { type, object } = await _readObject({ fs: fs2, cache, gitdir, oid });\n        if (type === \"tag\") {\n          const tag2 = GitAnnotatedTag.from(object);\n          const commit3 = tag2.headers().object;\n          return walk2(commit3);\n        }\n        if (type !== \"commit\") {\n          throw new ObjectTypeError(oid, type, \"commit\");\n        }\n        if (!shallows.has(oid)) {\n          const commit3 = GitCommit.from(object);\n          const parents = commit3.headers().parent;\n          for (oid of parents) {\n            if (!finishingSet.has(oid) && !visited.has(oid)) {\n              await walk2(oid);\n            }\n          }\n        }\n      }\n      for (const oid of startingSet) {\n        await walk2(oid);\n      }\n      return visited;\n    }\n    async function listObjects({\n      fs: fs2,\n      cache,\n      dir,\n      gitdir = join2(dir, \".git\"),\n      oids\n    }) {\n      const visited = /* @__PURE__ */ new Set();\n      async function walk2(oid) {\n        if (visited.has(oid)) return;\n        visited.add(oid);\n        const { type, object } = await _readObject({ fs: fs2, cache, gitdir, oid });\n        if (type === \"tag\") {\n          const tag2 = GitAnnotatedTag.from(object);\n          const obj = tag2.headers().object;\n          await walk2(obj);\n        } else if (type === \"commit\") {\n          const commit3 = GitCommit.from(object);\n          const tree = commit3.headers().tree;\n          await walk2(tree);\n        } else if (type === \"tree\") {\n          const tree = GitTree.from(object);\n          for (const entry of tree) {\n            if (entry.type === \"blob\") {\n              visited.add(entry.oid);\n            }\n            if (entry.type === \"tree\") {\n              await walk2(entry.oid);\n            }\n          }\n        }\n      }\n      for (const oid of oids) {\n        await walk2(oid);\n      }\n      return visited;\n    }\n    async function parseReceivePackResponse(packfile) {\n      const result = {};\n      let response = \"\";\n      const read = GitPktLine.streamReader(packfile);\n      let line = await read();\n      while (line !== true) {\n        if (line !== null) response += line.toString(\"utf8\") + \"\\n\";\n        line = await read();\n      }\n      const lines = response.toString(\"utf8\").split(\"\\n\");\n      line = lines.shift();\n      if (!line.startsWith(\"unpack \")) {\n        throw new ParseError('unpack ok\" or \"unpack [error message]', line);\n      }\n      result.ok = line === \"unpack ok\";\n      if (!result.ok) {\n        result.error = line.slice(\"unpack \".length);\n      }\n      result.refs = {};\n      for (const line2 of lines) {\n        if (line2.trim() === \"\") continue;\n        const status2 = line2.slice(0, 2);\n        const refAndMessage = line2.slice(3);\n        let space = refAndMessage.indexOf(\" \");\n        if (space === -1) space = refAndMessage.length;\n        const ref = refAndMessage.slice(0, space);\n        const error = refAndMessage.slice(space + 1);\n        result.refs[ref] = {\n          ok: status2 === \"ok\",\n          error\n        };\n      }\n      return result;\n    }\n    async function writeReceivePackRequest({\n      capabilities = [],\n      triplets = []\n    }) {\n      const packstream = [];\n      let capsFirstLine = `\\0 ${capabilities.join(\" \")}`;\n      for (const trip of triplets) {\n        packstream.push(\n          GitPktLine.encode(\n            `${trip.oldoid} ${trip.oid} ${trip.fullRef}${capsFirstLine}\n`\n          )\n        );\n        capsFirstLine = \"\";\n      }\n      packstream.push(GitPktLine.flush());\n      return packstream;\n    }\n    async function _push({\n      fs: fs2,\n      cache,\n      http,\n      onProgress,\n      onMessage,\n      onAuth,\n      onAuthSuccess,\n      onAuthFailure,\n      onPrePush,\n      gitdir,\n      ref: _ref,\n      remoteRef: _remoteRef,\n      remote,\n      url: _url,\n      force = false,\n      delete: _delete = false,\n      corsProxy,\n      headers = {}\n    }) {\n      const ref = _ref || await _currentBranch({ fs: fs2, gitdir });\n      if (typeof ref === \"undefined\") {\n        throw new MissingParameterError(\"ref\");\n      }\n      const config = await GitConfigManager.get({ fs: fs2, gitdir });\n      remote = remote || await config.get(`branch.${ref}.pushRemote`) || await config.get(\"remote.pushDefault\") || await config.get(`branch.${ref}.remote`) || \"origin\";\n      const url = _url || await config.get(`remote.${remote}.pushurl`) || await config.get(`remote.${remote}.url`);\n      if (typeof url === \"undefined\") {\n        throw new MissingParameterError(\"remote OR url\");\n      }\n      const remoteRef = _remoteRef || await config.get(`branch.${ref}.merge`);\n      if (typeof url === \"undefined\") {\n        throw new MissingParameterError(\"remoteRef\");\n      }\n      if (corsProxy === void 0) {\n        corsProxy = await config.get(\"http.corsProxy\");\n      }\n      const fullRef = await GitRefManager.expand({ fs: fs2, gitdir, ref });\n      const oid = _delete ? \"0000000000000000000000000000000000000000\" : await GitRefManager.resolve({ fs: fs2, gitdir, ref: fullRef });\n      const GitRemoteHTTP2 = GitRemoteManager.getRemoteHelperFor({ url });\n      const httpRemote = await GitRemoteHTTP2.discover({\n        http,\n        onAuth,\n        onAuthSuccess,\n        onAuthFailure,\n        corsProxy,\n        service: \"git-receive-pack\",\n        url,\n        headers,\n        protocolVersion: 1\n      });\n      const auth = httpRemote.auth;\n      let fullRemoteRef;\n      if (!remoteRef) {\n        fullRemoteRef = fullRef;\n      } else {\n        try {\n          fullRemoteRef = await GitRefManager.expandAgainstMap({\n            ref: remoteRef,\n            map: httpRemote.refs\n          });\n        } catch (err) {\n          if (err instanceof NotFoundError) {\n            fullRemoteRef = remoteRef.startsWith(\"refs/\") ? remoteRef : `refs/heads/${remoteRef}`;\n          } else {\n            throw err;\n          }\n        }\n      }\n      const oldoid = httpRemote.refs.get(fullRemoteRef) || \"0000000000000000000000000000000000000000\";\n      if (onPrePush) {\n        const hookCancel = await onPrePush({\n          remote,\n          url,\n          localRef: { ref: _delete ? \"(delete)\" : fullRef, oid },\n          remoteRef: { ref: fullRemoteRef, oid: oldoid }\n        });\n        if (!hookCancel) throw new UserCanceledError();\n      }\n      const thinPack = !httpRemote.capabilities.has(\"no-thin\");\n      let objects = /* @__PURE__ */ new Set();\n      if (!_delete) {\n        const finish = [...httpRemote.refs.values()];\n        let skipObjects = /* @__PURE__ */ new Set();\n        if (oldoid !== \"0000000000000000000000000000000000000000\") {\n          const mergebase = await _findMergeBase({\n            fs: fs2,\n            cache,\n            gitdir,\n            oids: [oid, oldoid]\n          });\n          for (const oid2 of mergebase) finish.push(oid2);\n          if (thinPack) {\n            skipObjects = await listObjects({ fs: fs2, cache, gitdir, oids: mergebase });\n          }\n        }\n        if (!finish.includes(oid)) {\n          const commits = await listCommitsAndTags({\n            fs: fs2,\n            cache,\n            gitdir,\n            start: [oid],\n            finish\n          });\n          objects = await listObjects({ fs: fs2, cache, gitdir, oids: commits });\n        }\n        if (thinPack) {\n          try {\n            const ref2 = await GitRefManager.resolve({\n              fs: fs2,\n              gitdir,\n              ref: `refs/remotes/${remote}/HEAD`,\n              depth: 2\n            });\n            const { oid: oid2 } = await GitRefManager.resolveAgainstMap({\n              ref: ref2.replace(`refs/remotes/${remote}/`, \"\"),\n              fullref: ref2,\n              map: httpRemote.refs\n            });\n            const oids = [oid2];\n            for (const oid3 of await listObjects({ fs: fs2, cache, gitdir, oids })) {\n              skipObjects.add(oid3);\n            }\n          } catch (e) {\n          }\n          for (const oid2 of skipObjects) {\n            objects.delete(oid2);\n          }\n        }\n        if (oid === oldoid) force = true;\n        if (!force) {\n          if (fullRef.startsWith(\"refs/tags\") && oldoid !== \"0000000000000000000000000000000000000000\") {\n            throw new PushRejectedError(\"tag-exists\");\n          }\n          if (oid !== \"0000000000000000000000000000000000000000\" && oldoid !== \"0000000000000000000000000000000000000000\" && !await _isDescendent({\n            fs: fs2,\n            cache,\n            gitdir,\n            oid,\n            ancestor: oldoid,\n            depth: -1\n          })) {\n            throw new PushRejectedError(\"not-fast-forward\");\n          }\n        }\n      }\n      const capabilities = filterCapabilities(\n        [...httpRemote.capabilities],\n        [\"report-status\", \"side-band-64k\", `agent=${pkg.agent}`]\n      );\n      const packstream1 = await writeReceivePackRequest({\n        capabilities,\n        triplets: [{ oldoid, oid, fullRef: fullRemoteRef }]\n      });\n      const packstream2 = _delete ? [] : await _pack({\n        fs: fs2,\n        cache,\n        gitdir,\n        oids: [...objects]\n      });\n      const res = await GitRemoteHTTP2.connect({\n        http,\n        onProgress,\n        corsProxy,\n        service: \"git-receive-pack\",\n        url,\n        auth,\n        headers,\n        body: [...packstream1, ...packstream2]\n      });\n      const { packfile, progress } = await GitSideBand.demux(res.body);\n      if (onMessage) {\n        const lines = splitLines(progress);\n        forAwait(lines, async (line) => {\n          await onMessage(line);\n        });\n      }\n      const result = await parseReceivePackResponse(packfile);\n      if (res.headers) {\n        result.headers = res.headers;\n      }\n      if (remote && result.ok && result.refs[fullRemoteRef].ok && !fullRef.startsWith(\"refs/tags\")) {\n        const ref2 = `refs/remotes/${remote}/${fullRemoteRef.replace(\n          \"refs/heads\",\n          \"\"\n        )}`;\n        if (_delete) {\n          await GitRefManager.deleteRef({ fs: fs2, gitdir, ref: ref2 });\n        } else {\n          await GitRefManager.writeRef({ fs: fs2, gitdir, ref: ref2, value: oid });\n        }\n      }\n      if (result.ok && Object.values(result.refs).every((result2) => result2.ok)) {\n        return result;\n      } else {\n        const prettyDetails = Object.entries(result.refs).filter(([k, v]) => !v.ok).map(([k, v]) => `\n  - ${k}: ${v.error}`).join(\"\");\n        throw new GitPushError(prettyDetails, result);\n      }\n    }\n    async function push({\n      fs: fs2,\n      http,\n      onProgress,\n      onMessage,\n      onAuth,\n      onAuthSuccess,\n      onAuthFailure,\n      onPrePush,\n      dir,\n      gitdir = join2(dir, \".git\"),\n      ref,\n      remoteRef,\n      remote = \"origin\",\n      url,\n      force = false,\n      delete: _delete = false,\n      corsProxy,\n      headers = {},\n      cache = {}\n    }) {\n      try {\n        assertParameter(\"fs\", fs2);\n        assertParameter(\"http\", http);\n        assertParameter(\"gitdir\", gitdir);\n        return await _push({\n          fs: new FileSystem(fs2),\n          cache,\n          http,\n          onProgress,\n          onMessage,\n          onAuth,\n          onAuthSuccess,\n          onAuthFailure,\n          onPrePush,\n          gitdir,\n          ref,\n          remoteRef,\n          remote,\n          url,\n          force,\n          delete: _delete,\n          corsProxy,\n          headers\n        });\n      } catch (err) {\n        err.caller = \"git.push\";\n        throw err;\n      }\n    }\n    async function resolveBlob({ fs: fs2, cache, gitdir, oid }) {\n      const { type, object } = await _readObject({ fs: fs2, cache, gitdir, oid });\n      if (type === \"tag\") {\n        oid = GitAnnotatedTag.from(object).parse().object;\n        return resolveBlob({ fs: fs2, cache, gitdir, oid });\n      }\n      if (type !== \"blob\") {\n        throw new ObjectTypeError(oid, type, \"blob\");\n      }\n      return { oid, blob: new Uint8Array(object) };\n    }\n    async function _readBlob({\n      fs: fs2,\n      cache,\n      gitdir,\n      oid,\n      filepath = void 0\n    }) {\n      if (filepath !== void 0) {\n        oid = await resolveFilepath({ fs: fs2, cache, gitdir, oid, filepath });\n      }\n      const blob = await resolveBlob({\n        fs: fs2,\n        cache,\n        gitdir,\n        oid\n      });\n      return blob;\n    }\n    async function readBlob({\n      fs: fs2,\n      dir,\n      gitdir = join2(dir, \".git\"),\n      oid,\n      filepath,\n      cache = {}\n    }) {\n      try {\n        assertParameter(\"fs\", fs2);\n        assertParameter(\"gitdir\", gitdir);\n        assertParameter(\"oid\", oid);\n        return await _readBlob({\n          fs: new FileSystem(fs2),\n          cache,\n          gitdir,\n          oid,\n          filepath\n        });\n      } catch (err) {\n        err.caller = \"git.readBlob\";\n        throw err;\n      }\n    }\n    async function readCommit({\n      fs: fs2,\n      dir,\n      gitdir = join2(dir, \".git\"),\n      oid,\n      cache = {}\n    }) {\n      try {\n        assertParameter(\"fs\", fs2);\n        assertParameter(\"gitdir\", gitdir);\n        assertParameter(\"oid\", oid);\n        return await _readCommit({\n          fs: new FileSystem(fs2),\n          cache,\n          gitdir,\n          oid\n        });\n      } catch (err) {\n        err.caller = \"git.readCommit\";\n        throw err;\n      }\n    }\n    async function _readNote({\n      fs: fs2,\n      cache,\n      gitdir,\n      ref = \"refs/notes/commits\",\n      oid\n    }) {\n      const parent = await GitRefManager.resolve({ gitdir, fs: fs2, ref });\n      const { blob } = await _readBlob({\n        fs: fs2,\n        cache,\n        gitdir,\n        oid: parent,\n        filepath: oid\n      });\n      return blob;\n    }\n    async function readNote({\n      fs: fs2,\n      dir,\n      gitdir = join2(dir, \".git\"),\n      ref = \"refs/notes/commits\",\n      oid,\n      cache = {}\n    }) {\n      try {\n        assertParameter(\"fs\", fs2);\n        assertParameter(\"gitdir\", gitdir);\n        assertParameter(\"ref\", ref);\n        assertParameter(\"oid\", oid);\n        return await _readNote({\n          fs: new FileSystem(fs2),\n          cache,\n          gitdir,\n          ref,\n          oid\n        });\n      } catch (err) {\n        err.caller = \"git.readNote\";\n        throw err;\n      }\n    }\n    async function readObject({\n      fs: _fs,\n      dir,\n      gitdir = join2(dir, \".git\"),\n      oid,\n      format = \"parsed\",\n      filepath = void 0,\n      encoding = void 0,\n      cache = {}\n    }) {\n      try {\n        assertParameter(\"fs\", _fs);\n        assertParameter(\"gitdir\", gitdir);\n        assertParameter(\"oid\", oid);\n        const fs2 = new FileSystem(_fs);\n        if (filepath !== void 0) {\n          oid = await resolveFilepath({\n            fs: fs2,\n            cache,\n            gitdir,\n            oid,\n            filepath\n          });\n        }\n        const _format = format === \"parsed\" ? \"content\" : format;\n        const result = await _readObject({\n          fs: fs2,\n          cache,\n          gitdir,\n          oid,\n          format: _format\n        });\n        result.oid = oid;\n        if (format === \"parsed\") {\n          result.format = \"parsed\";\n          switch (result.type) {\n            case \"commit\":\n              result.object = GitCommit.from(result.object).parse();\n              break;\n            case \"tree\":\n              result.object = GitTree.from(result.object).entries();\n              break;\n            case \"blob\":\n              if (encoding) {\n                result.object = result.object.toString(encoding);\n              } else {\n                result.object = new Uint8Array(result.object);\n                result.format = \"content\";\n              }\n              break;\n            case \"tag\":\n              result.object = GitAnnotatedTag.from(result.object).parse();\n              break;\n            default:\n              throw new ObjectTypeError(\n                result.oid,\n                result.type,\n                \"blob|commit|tag|tree\"\n              );\n          }\n        } else if (result.format === \"deflated\" || result.format === \"wrapped\") {\n          result.type = result.format;\n        }\n        return result;\n      } catch (err) {\n        err.caller = \"git.readObject\";\n        throw err;\n      }\n    }\n    async function _readTag({ fs: fs2, cache, gitdir, oid }) {\n      const { type, object } = await _readObject({\n        fs: fs2,\n        cache,\n        gitdir,\n        oid,\n        format: \"content\"\n      });\n      if (type !== \"tag\") {\n        throw new ObjectTypeError(oid, type, \"tag\");\n      }\n      const tag2 = GitAnnotatedTag.from(object);\n      const result = {\n        oid,\n        tag: tag2.parse(),\n        payload: tag2.payload()\n      };\n      return result;\n    }\n    async function readTag({\n      fs: fs2,\n      dir,\n      gitdir = join2(dir, \".git\"),\n      oid,\n      cache = {}\n    }) {\n      try {\n        assertParameter(\"fs\", fs2);\n        assertParameter(\"gitdir\", gitdir);\n        assertParameter(\"oid\", oid);\n        return await _readTag({\n          fs: new FileSystem(fs2),\n          cache,\n          gitdir,\n          oid\n        });\n      } catch (err) {\n        err.caller = \"git.readTag\";\n        throw err;\n      }\n    }\n    async function readTree({\n      fs: fs2,\n      dir,\n      gitdir = join2(dir, \".git\"),\n      oid,\n      filepath = void 0,\n      cache = {}\n    }) {\n      try {\n        assertParameter(\"fs\", fs2);\n        assertParameter(\"gitdir\", gitdir);\n        assertParameter(\"oid\", oid);\n        return await _readTree({\n          fs: new FileSystem(fs2),\n          cache,\n          gitdir,\n          oid,\n          filepath\n        });\n      } catch (err) {\n        err.caller = \"git.readTree\";\n        throw err;\n      }\n    }\n    async function remove({\n      fs: _fs,\n      dir,\n      gitdir = join2(dir, \".git\"),\n      filepath,\n      cache = {}\n    }) {\n      try {\n        assertParameter(\"fs\", _fs);\n        assertParameter(\"gitdir\", gitdir);\n        assertParameter(\"filepath\", filepath);\n        await GitIndexManager.acquire(\n          { fs: new FileSystem(_fs), gitdir, cache },\n          async function(index2) {\n            index2.delete({ filepath });\n          }\n        );\n      } catch (err) {\n        err.caller = \"git.remove\";\n        throw err;\n      }\n    }\n    async function _removeNote({\n      fs: fs2,\n      cache,\n      onSign,\n      gitdir,\n      ref = \"refs/notes/commits\",\n      oid,\n      author: author2,\n      committer,\n      signingKey\n    }) {\n      let parent;\n      try {\n        parent = await GitRefManager.resolve({ gitdir, fs: fs2, ref });\n      } catch (err) {\n        if (!(err instanceof NotFoundError)) {\n          throw err;\n        }\n      }\n      const result = await _readTree({\n        fs: fs2,\n        gitdir,\n        oid: parent || \"4b825dc642cb6eb9a060e54bf8d69288fbee4904\"\n      });\n      let tree = result.tree;\n      tree = tree.filter((entry) => entry.path !== oid);\n      const treeOid = await _writeTree({\n        fs: fs2,\n        gitdir,\n        tree\n      });\n      const commitOid = await _commit({\n        fs: fs2,\n        cache,\n        onSign,\n        gitdir,\n        ref,\n        tree: treeOid,\n        parent: parent && [parent],\n        message: `Note removed by 'isomorphic-git removeNote'\n`,\n        author: author2,\n        committer,\n        signingKey\n      });\n      return commitOid;\n    }\n    async function removeNote({\n      fs: _fs,\n      onSign,\n      dir,\n      gitdir = join2(dir, \".git\"),\n      ref = \"refs/notes/commits\",\n      oid,\n      author: _author,\n      committer: _committer,\n      signingKey,\n      cache = {}\n    }) {\n      try {\n        assertParameter(\"fs\", _fs);\n        assertParameter(\"gitdir\", gitdir);\n        assertParameter(\"oid\", oid);\n        const fs2 = new FileSystem(_fs);\n        const author2 = await normalizeAuthorObject({ fs: fs2, gitdir, author: _author });\n        if (!author2) throw new MissingNameError(\"author\");\n        const committer = await normalizeCommitterObject({\n          fs: fs2,\n          gitdir,\n          author: author2,\n          committer: _committer\n        });\n        if (!committer) throw new MissingNameError(\"committer\");\n        return await _removeNote({\n          fs: fs2,\n          cache,\n          onSign,\n          gitdir,\n          ref,\n          oid,\n          author: author2,\n          committer,\n          signingKey\n        });\n      } catch (err) {\n        err.caller = \"git.removeNote\";\n        throw err;\n      }\n    }\n    async function _renameBranch({\n      fs: fs2,\n      gitdir,\n      oldref,\n      ref,\n      checkout: checkout2 = false\n    }) {\n      if (ref !== cleanGitRef.clean(ref)) {\n        throw new InvalidRefNameError(ref, cleanGitRef.clean(ref));\n      }\n      if (oldref !== cleanGitRef.clean(oldref)) {\n        throw new InvalidRefNameError(oldref, cleanGitRef.clean(oldref));\n      }\n      const fulloldref = `refs/heads/${oldref}`;\n      const fullnewref = `refs/heads/${ref}`;\n      const newexist = await GitRefManager.exists({ fs: fs2, gitdir, ref: fullnewref });\n      if (newexist) {\n        throw new AlreadyExistsError(\"branch\", ref, false);\n      }\n      const value = await GitRefManager.resolve({\n        fs: fs2,\n        gitdir,\n        ref: fulloldref,\n        depth: 1\n      });\n      await GitRefManager.writeRef({ fs: fs2, gitdir, ref: fullnewref, value });\n      await GitRefManager.deleteRef({ fs: fs2, gitdir, ref: fulloldref });\n      const fullCurrentBranchRef = await _currentBranch({\n        fs: fs2,\n        gitdir,\n        fullname: true\n      });\n      const isCurrentBranch = fullCurrentBranchRef === fulloldref;\n      if (checkout2 || isCurrentBranch) {\n        await GitRefManager.writeSymbolicRef({\n          fs: fs2,\n          gitdir,\n          ref: \"HEAD\",\n          value: fullnewref\n        });\n      }\n    }\n    async function renameBranch({\n      fs: fs2,\n      dir,\n      gitdir = join2(dir, \".git\"),\n      ref,\n      oldref,\n      checkout: checkout2 = false\n    }) {\n      try {\n        assertParameter(\"fs\", fs2);\n        assertParameter(\"gitdir\", gitdir);\n        assertParameter(\"ref\", ref);\n        assertParameter(\"oldref\", oldref);\n        return await _renameBranch({\n          fs: new FileSystem(fs2),\n          gitdir,\n          ref,\n          oldref,\n          checkout: checkout2\n        });\n      } catch (err) {\n        err.caller = \"git.renameBranch\";\n        throw err;\n      }\n    }\n    async function hashObject$1({ gitdir, type, object }) {\n      return shasum(GitObject.wrap({ type, object }));\n    }\n    async function resetIndex({\n      fs: _fs,\n      dir,\n      gitdir = join2(dir, \".git\"),\n      filepath,\n      ref,\n      cache = {}\n    }) {\n      try {\n        assertParameter(\"fs\", _fs);\n        assertParameter(\"gitdir\", gitdir);\n        assertParameter(\"filepath\", filepath);\n        const fs2 = new FileSystem(_fs);\n        let oid;\n        let workdirOid;\n        try {\n          oid = await GitRefManager.resolve({ fs: fs2, gitdir, ref: ref || \"HEAD\" });\n        } catch (e) {\n          if (ref) {\n            throw e;\n          }\n        }\n        if (oid) {\n          try {\n            oid = await resolveFilepath({\n              fs: fs2,\n              cache,\n              gitdir,\n              oid,\n              filepath\n            });\n          } catch (e) {\n            oid = null;\n          }\n        }\n        let stats = {\n          ctime: /* @__PURE__ */ new Date(0),\n          mtime: /* @__PURE__ */ new Date(0),\n          dev: 0,\n          ino: 0,\n          mode: 0,\n          uid: 0,\n          gid: 0,\n          size: 0\n        };\n        const object = dir && await fs2.read(join2(dir, filepath));\n        if (object) {\n          workdirOid = await hashObject$1({\n            gitdir,\n            type: \"blob\",\n            object\n          });\n          if (oid === workdirOid) {\n            stats = await fs2.lstat(join2(dir, filepath));\n          }\n        }\n        await GitIndexManager.acquire({ fs: fs2, gitdir, cache }, async function(index2) {\n          index2.delete({ filepath });\n          if (oid) {\n            index2.insert({ filepath, stats, oid });\n          }\n        });\n      } catch (err) {\n        err.caller = \"git.reset\";\n        throw err;\n      }\n    }\n    async function resolveRef({\n      fs: fs2,\n      dir,\n      gitdir = join2(dir, \".git\"),\n      ref,\n      depth\n    }) {\n      try {\n        assertParameter(\"fs\", fs2);\n        assertParameter(\"gitdir\", gitdir);\n        assertParameter(\"ref\", ref);\n        const oid = await GitRefManager.resolve({\n          fs: new FileSystem(fs2),\n          gitdir,\n          ref,\n          depth\n        });\n        return oid;\n      } catch (err) {\n        err.caller = \"git.resolveRef\";\n        throw err;\n      }\n    }\n    async function setConfig({\n      fs: _fs,\n      dir,\n      gitdir = join2(dir, \".git\"),\n      path: path2,\n      value,\n      append = false\n    }) {\n      try {\n        assertParameter(\"fs\", _fs);\n        assertParameter(\"gitdir\", gitdir);\n        assertParameter(\"path\", path2);\n        const fs2 = new FileSystem(_fs);\n        const config = await GitConfigManager.get({ fs: fs2, gitdir });\n        if (append) {\n          await config.append(path2, value);\n        } else {\n          await config.set(path2, value);\n        }\n        await GitConfigManager.save({ fs: fs2, gitdir, config });\n      } catch (err) {\n        err.caller = \"git.setConfig\";\n        throw err;\n      }\n    }\n    async function status({\n      fs: _fs,\n      dir,\n      gitdir = join2(dir, \".git\"),\n      filepath,\n      cache = {}\n    }) {\n      try {\n        assertParameter(\"fs\", _fs);\n        assertParameter(\"gitdir\", gitdir);\n        assertParameter(\"filepath\", filepath);\n        const fs2 = new FileSystem(_fs);\n        const ignored = await GitIgnoreManager.isIgnored({\n          fs: fs2,\n          gitdir,\n          dir,\n          filepath\n        });\n        if (ignored) {\n          return \"ignored\";\n        }\n        const headTree = await getHeadTree({ fs: fs2, cache, gitdir });\n        const treeOid = await getOidAtPath({\n          fs: fs2,\n          cache,\n          gitdir,\n          tree: headTree,\n          path: filepath\n        });\n        const indexEntry = await GitIndexManager.acquire(\n          { fs: fs2, gitdir, cache },\n          async function(index2) {\n            for (const entry of index2) {\n              if (entry.path === filepath) return entry;\n            }\n            return null;\n          }\n        );\n        const stats = await fs2.lstat(join2(dir, filepath));\n        const H = treeOid !== null;\n        const I = indexEntry !== null;\n        const W = stats !== null;\n        const getWorkdirOid = async () => {\n          if (I && !compareStats(indexEntry, stats)) {\n            return indexEntry.oid;\n          } else {\n            const object = await fs2.read(join2(dir, filepath));\n            const workdirOid = await hashObject$1({\n              gitdir,\n              type: \"blob\",\n              object\n            });\n            if (I && indexEntry.oid === workdirOid) {\n              if (stats.size !== -1) {\n                GitIndexManager.acquire({ fs: fs2, gitdir, cache }, async function(index2) {\n                  index2.insert({ filepath, stats, oid: workdirOid });\n                });\n              }\n            }\n            return workdirOid;\n          }\n        };\n        if (!H && !W && !I) return \"absent\";\n        if (!H && !W && I) return \"*absent\";\n        if (!H && W && !I) return \"*added\";\n        if (!H && W && I) {\n          const workdirOid = await getWorkdirOid();\n          return workdirOid === indexEntry.oid ? \"added\" : \"*added\";\n        }\n        if (H && !W && !I) return \"deleted\";\n        if (H && !W && I) {\n          return treeOid === indexEntry.oid ? \"*deleted\" : \"*deleted\";\n        }\n        if (H && W && !I) {\n          const workdirOid = await getWorkdirOid();\n          return workdirOid === treeOid ? \"*undeleted\" : \"*undeletemodified\";\n        }\n        if (H && W && I) {\n          const workdirOid = await getWorkdirOid();\n          if (workdirOid === treeOid) {\n            return workdirOid === indexEntry.oid ? \"unmodified\" : \"*unmodified\";\n          } else {\n            return workdirOid === indexEntry.oid ? \"modified\" : \"*modified\";\n          }\n        }\n      } catch (err) {\n        err.caller = \"git.status\";\n        throw err;\n      }\n    }\n    async function getOidAtPath({ fs: fs2, cache, gitdir, tree, path: path2 }) {\n      if (typeof path2 === \"string\") path2 = path2.split(\"/\");\n      const dirname2 = path2.shift();\n      for (const entry of tree) {\n        if (entry.path === dirname2) {\n          if (path2.length === 0) {\n            return entry.oid;\n          }\n          const { type, object } = await _readObject({\n            fs: fs2,\n            cache,\n            gitdir,\n            oid: entry.oid\n          });\n          if (type === \"tree\") {\n            const tree2 = GitTree.from(object);\n            return getOidAtPath({ fs: fs2, cache, gitdir, tree: tree2, path: path2 });\n          }\n          if (type === \"blob\") {\n            throw new ObjectTypeError(entry.oid, type, \"blob\", path2.join(\"/\"));\n          }\n        }\n      }\n      return null;\n    }\n    async function getHeadTree({ fs: fs2, cache, gitdir }) {\n      let oid;\n      try {\n        oid = await GitRefManager.resolve({ fs: fs2, gitdir, ref: \"HEAD\" });\n      } catch (e) {\n        if (e instanceof NotFoundError) {\n          return [];\n        }\n      }\n      const { tree } = await _readTree({ fs: fs2, cache, gitdir, oid });\n      return tree;\n    }\n    async function statusMatrix({\n      fs: _fs,\n      dir,\n      gitdir = join2(dir, \".git\"),\n      ref = \"HEAD\",\n      filepaths = [\".\"],\n      filter,\n      cache = {},\n      ignored: shouldIgnore = false\n    }) {\n      try {\n        assertParameter(\"fs\", _fs);\n        assertParameter(\"gitdir\", gitdir);\n        assertParameter(\"ref\", ref);\n        const fs2 = new FileSystem(_fs);\n        return await _walk({\n          fs: fs2,\n          cache,\n          dir,\n          gitdir,\n          trees: [TREE({ ref }), WORKDIR(), STAGE()],\n          map: async function(filepath, [head, workdir, stage2]) {\n            if (!head && !stage2 && workdir) {\n              if (!shouldIgnore) {\n                const isIgnored2 = await GitIgnoreManager.isIgnored({\n                  fs: fs2,\n                  dir,\n                  filepath\n                });\n                if (isIgnored2) {\n                  return null;\n                }\n              }\n            }\n            if (!filepaths.some((base) => worthWalking(filepath, base))) {\n              return null;\n            }\n            if (filter) {\n              if (!filter(filepath)) return;\n            }\n            const [headType, workdirType, stageType] = await Promise.all([\n              head && head.type(),\n              workdir && workdir.type(),\n              stage2 && stage2.type()\n            ]);\n            const isBlob = [headType, workdirType, stageType].includes(\"blob\");\n            if ((headType === \"tree\" || headType === \"special\") && !isBlob) return;\n            if (headType === \"commit\") return null;\n            if ((workdirType === \"tree\" || workdirType === \"special\") && !isBlob)\n              return;\n            if (stageType === \"commit\") return null;\n            if ((stageType === \"tree\" || stageType === \"special\") && !isBlob) return;\n            const headOid2 = headType === \"blob\" ? await head.oid() : void 0;\n            const stageOid = stageType === \"blob\" ? await stage2.oid() : void 0;\n            let workdirOid;\n            if (headType !== \"blob\" && workdirType === \"blob\" && stageType !== \"blob\") {\n              workdirOid = \"42\";\n            } else if (workdirType === \"blob\") {\n              workdirOid = await workdir.oid();\n            }\n            const entry = [void 0, headOid2, workdirOid, stageOid];\n            const result = entry.map((value) => entry.indexOf(value));\n            result.shift();\n            return [filepath, ...result];\n          }\n        });\n      } catch (err) {\n        err.caller = \"git.statusMatrix\";\n        throw err;\n      }\n    }\n    async function tag({\n      fs: _fs,\n      dir,\n      gitdir = join2(dir, \".git\"),\n      ref,\n      object,\n      force = false\n    }) {\n      try {\n        assertParameter(\"fs\", _fs);\n        assertParameter(\"gitdir\", gitdir);\n        assertParameter(\"ref\", ref);\n        const fs2 = new FileSystem(_fs);\n        if (ref === void 0) {\n          throw new MissingParameterError(\"ref\");\n        }\n        ref = ref.startsWith(\"refs/tags/\") ? ref : `refs/tags/${ref}`;\n        const value = await GitRefManager.resolve({\n          fs: fs2,\n          gitdir,\n          ref: object || \"HEAD\"\n        });\n        if (!force && await GitRefManager.exists({ fs: fs2, gitdir, ref })) {\n          throw new AlreadyExistsError(\"tag\", ref);\n        }\n        await GitRefManager.writeRef({ fs: fs2, gitdir, ref, value });\n      } catch (err) {\n        err.caller = \"git.tag\";\n        throw err;\n      }\n    }\n    async function updateIndex({\n      fs: _fs,\n      dir,\n      gitdir = join2(dir, \".git\"),\n      cache = {},\n      filepath,\n      oid,\n      mode,\n      add: add2,\n      remove: remove2,\n      force\n    }) {\n      try {\n        assertParameter(\"fs\", _fs);\n        assertParameter(\"gitdir\", gitdir);\n        assertParameter(\"filepath\", filepath);\n        const fs2 = new FileSystem(_fs);\n        if (remove2) {\n          return await GitIndexManager.acquire(\n            { fs: fs2, gitdir, cache },\n            async function(index2) {\n              let fileStats2;\n              if (!force) {\n                fileStats2 = await fs2.lstat(join2(dir, filepath));\n                if (fileStats2) {\n                  if (fileStats2.isDirectory()) {\n                    throw new InvalidFilepathError(\"directory\");\n                  }\n                  return;\n                }\n              }\n              if (index2.has({ filepath })) {\n                index2.delete({\n                  filepath\n                });\n              }\n            }\n          );\n        }\n        let fileStats;\n        if (!oid) {\n          fileStats = await fs2.lstat(join2(dir, filepath));\n          if (!fileStats) {\n            throw new NotFoundError(\n              `file at \"${filepath}\" on disk and \"remove\" not set`\n            );\n          }\n          if (fileStats.isDirectory()) {\n            throw new InvalidFilepathError(\"directory\");\n          }\n        }\n        return await GitIndexManager.acquire({ fs: fs2, gitdir, cache }, async function(index2) {\n          if (!add2 && !index2.has({ filepath })) {\n            throw new NotFoundError(\n              `file at \"${filepath}\" in index and \"add\" not set`\n            );\n          }\n          let stats = {\n            ctime: /* @__PURE__ */ new Date(0),\n            mtime: /* @__PURE__ */ new Date(0),\n            dev: 0,\n            ino: 0,\n            mode,\n            uid: 0,\n            gid: 0,\n            size: 0\n          };\n          if (!oid) {\n            stats = fileStats;\n            const object = stats.isSymbolicLink() ? await fs2.readlink(join2(dir, filepath)) : await fs2.read(join2(dir, filepath));\n            oid = await _writeObject({\n              fs: fs2,\n              gitdir,\n              type: \"blob\",\n              format: \"content\",\n              object\n            });\n          }\n          index2.insert({\n            filepath,\n            oid,\n            stats\n          });\n          return oid;\n        });\n      } catch (err) {\n        err.caller = \"git.updateIndex\";\n        throw err;\n      }\n    }\n    function version() {\n      try {\n        return pkg.version;\n      } catch (err) {\n        err.caller = \"git.version\";\n        throw err;\n      }\n    }\n    async function walk({\n      fs: fs2,\n      dir,\n      gitdir = join2(dir, \".git\"),\n      trees,\n      map,\n      reduce,\n      iterate,\n      cache = {}\n    }) {\n      try {\n        assertParameter(\"fs\", fs2);\n        assertParameter(\"gitdir\", gitdir);\n        assertParameter(\"trees\", trees);\n        return await _walk({\n          fs: new FileSystem(fs2),\n          cache,\n          dir,\n          gitdir,\n          trees,\n          map,\n          reduce,\n          iterate\n        });\n      } catch (err) {\n        err.caller = \"git.walk\";\n        throw err;\n      }\n    }\n    async function writeBlob({ fs: fs2, dir, gitdir = join2(dir, \".git\"), blob }) {\n      try {\n        assertParameter(\"fs\", fs2);\n        assertParameter(\"gitdir\", gitdir);\n        assertParameter(\"blob\", blob);\n        return await _writeObject({\n          fs: new FileSystem(fs2),\n          gitdir,\n          type: \"blob\",\n          object: blob,\n          format: \"content\"\n        });\n      } catch (err) {\n        err.caller = \"git.writeBlob\";\n        throw err;\n      }\n    }\n    async function _writeCommit({ fs: fs2, gitdir, commit: commit3 }) {\n      const object = GitCommit.from(commit3).toObject();\n      const oid = await _writeObject({\n        fs: fs2,\n        gitdir,\n        type: \"commit\",\n        object,\n        format: \"content\"\n      });\n      return oid;\n    }\n    async function writeCommit({\n      fs: fs2,\n      dir,\n      gitdir = join2(dir, \".git\"),\n      commit: commit3\n    }) {\n      try {\n        assertParameter(\"fs\", fs2);\n        assertParameter(\"gitdir\", gitdir);\n        assertParameter(\"commit\", commit3);\n        return await _writeCommit({\n          fs: new FileSystem(fs2),\n          gitdir,\n          commit: commit3\n        });\n      } catch (err) {\n        err.caller = \"git.writeCommit\";\n        throw err;\n      }\n    }\n    async function writeObject({\n      fs: _fs,\n      dir,\n      gitdir = join2(dir, \".git\"),\n      type,\n      object,\n      format = \"parsed\",\n      oid,\n      encoding = void 0\n    }) {\n      try {\n        const fs2 = new FileSystem(_fs);\n        if (format === \"parsed\") {\n          switch (type) {\n            case \"commit\":\n              object = GitCommit.from(object).toObject();\n              break;\n            case \"tree\":\n              object = GitTree.from(object).toObject();\n              break;\n            case \"blob\":\n              object = Buffer.from(object, encoding);\n              break;\n            case \"tag\":\n              object = GitAnnotatedTag.from(object).toObject();\n              break;\n            default:\n              throw new ObjectTypeError(oid || \"\", type, \"blob|commit|tag|tree\");\n          }\n          format = \"content\";\n        }\n        oid = await _writeObject({\n          fs: fs2,\n          gitdir,\n          type,\n          object,\n          oid,\n          format\n        });\n        return oid;\n      } catch (err) {\n        err.caller = \"git.writeObject\";\n        throw err;\n      }\n    }\n    async function writeRef({\n      fs: _fs,\n      dir,\n      gitdir = join2(dir, \".git\"),\n      ref,\n      value,\n      force = false,\n      symbolic = false\n    }) {\n      try {\n        assertParameter(\"fs\", _fs);\n        assertParameter(\"gitdir\", gitdir);\n        assertParameter(\"ref\", ref);\n        assertParameter(\"value\", value);\n        const fs2 = new FileSystem(_fs);\n        if (ref !== cleanGitRef.clean(ref)) {\n          throw new InvalidRefNameError(ref, cleanGitRef.clean(ref));\n        }\n        if (!force && await GitRefManager.exists({ fs: fs2, gitdir, ref })) {\n          throw new AlreadyExistsError(\"ref\", ref);\n        }\n        if (symbolic) {\n          await GitRefManager.writeSymbolicRef({\n            fs: fs2,\n            gitdir,\n            ref,\n            value\n          });\n        } else {\n          value = await GitRefManager.resolve({\n            fs: fs2,\n            gitdir,\n            ref: value\n          });\n          await GitRefManager.writeRef({\n            fs: fs2,\n            gitdir,\n            ref,\n            value\n          });\n        }\n      } catch (err) {\n        err.caller = \"git.writeRef\";\n        throw err;\n      }\n    }\n    async function _writeTag({ fs: fs2, gitdir, tag: tag2 }) {\n      const object = GitAnnotatedTag.from(tag2).toObject();\n      const oid = await _writeObject({\n        fs: fs2,\n        gitdir,\n        type: \"tag\",\n        object,\n        format: \"content\"\n      });\n      return oid;\n    }\n    async function writeTag({ fs: fs2, dir, gitdir = join2(dir, \".git\"), tag: tag2 }) {\n      try {\n        assertParameter(\"fs\", fs2);\n        assertParameter(\"gitdir\", gitdir);\n        assertParameter(\"tag\", tag2);\n        return await _writeTag({\n          fs: new FileSystem(fs2),\n          gitdir,\n          tag: tag2\n        });\n      } catch (err) {\n        err.caller = \"git.writeTag\";\n        throw err;\n      }\n    }\n    async function writeTree2({ fs: fs2, dir, gitdir = join2(dir, \".git\"), tree }) {\n      try {\n        assertParameter(\"fs\", fs2);\n        assertParameter(\"gitdir\", gitdir);\n        assertParameter(\"tree\", tree);\n        return await _writeTree({\n          fs: new FileSystem(fs2),\n          gitdir,\n          tree\n        });\n      } catch (err) {\n        err.caller = \"git.writeTree\";\n        throw err;\n      }\n    }\n    var index = {\n      Errors,\n      STAGE,\n      TREE,\n      WORKDIR,\n      add,\n      abortMerge,\n      addNote,\n      addRemote,\n      annotatedTag,\n      branch,\n      checkout,\n      clone,\n      commit: commit2,\n      getConfig,\n      getConfigAll,\n      setConfig,\n      currentBranch,\n      deleteBranch,\n      deleteRef,\n      deleteRemote,\n      deleteTag,\n      expandOid,\n      expandRef,\n      fastForward,\n      fetch,\n      findMergeBase,\n      findRoot: findRoot2,\n      getRemoteInfo,\n      getRemoteInfo2,\n      hashBlob,\n      indexPack,\n      init,\n      isDescendent,\n      isIgnored,\n      listBranches,\n      listFiles,\n      listNotes,\n      listRemotes,\n      listServerRefs,\n      listTags,\n      log: log2,\n      merge,\n      packObjects,\n      pull,\n      push,\n      readBlob,\n      readCommit,\n      readNote,\n      readObject,\n      readTag,\n      readTree,\n      remove,\n      removeNote,\n      renameBranch,\n      resetIndex,\n      updateIndex,\n      resolveRef,\n      status,\n      statusMatrix,\n      tag,\n      version,\n      walk,\n      writeBlob,\n      writeCommit,\n      writeObject,\n      writeRef,\n      writeTag,\n      writeTree: writeTree2\n    };\n    exports2.Errors = Errors;\n    exports2.STAGE = STAGE;\n    exports2.TREE = TREE;\n    exports2.WORKDIR = WORKDIR;\n    exports2.abortMerge = abortMerge;\n    exports2.add = add;\n    exports2.addNote = addNote;\n    exports2.addRemote = addRemote;\n    exports2.annotatedTag = annotatedTag;\n    exports2.branch = branch;\n    exports2.checkout = checkout;\n    exports2.clone = clone;\n    exports2.commit = commit2;\n    exports2.currentBranch = currentBranch;\n    exports2.default = index;\n    exports2.deleteBranch = deleteBranch;\n    exports2.deleteRef = deleteRef;\n    exports2.deleteRemote = deleteRemote;\n    exports2.deleteTag = deleteTag;\n    exports2.expandOid = expandOid;\n    exports2.expandRef = expandRef;\n    exports2.fastForward = fastForward;\n    exports2.fetch = fetch;\n    exports2.findMergeBase = findMergeBase;\n    exports2.findRoot = findRoot2;\n    exports2.getConfig = getConfig;\n    exports2.getConfigAll = getConfigAll;\n    exports2.getRemoteInfo = getRemoteInfo;\n    exports2.getRemoteInfo2 = getRemoteInfo2;\n    exports2.hashBlob = hashBlob;\n    exports2.indexPack = indexPack;\n    exports2.init = init;\n    exports2.isDescendent = isDescendent;\n    exports2.isIgnored = isIgnored;\n    exports2.listBranches = listBranches;\n    exports2.listFiles = listFiles;\n    exports2.listNotes = listNotes;\n    exports2.listRemotes = listRemotes;\n    exports2.listServerRefs = listServerRefs;\n    exports2.listTags = listTags;\n    exports2.log = log2;\n    exports2.merge = merge;\n    exports2.packObjects = packObjects;\n    exports2.pull = pull;\n    exports2.push = push;\n    exports2.readBlob = readBlob;\n    exports2.readCommit = readCommit;\n    exports2.readNote = readNote;\n    exports2.readObject = readObject;\n    exports2.readTag = readTag;\n    exports2.readTree = readTree;\n    exports2.remove = remove;\n    exports2.removeNote = removeNote;\n    exports2.renameBranch = renameBranch;\n    exports2.resetIndex = resetIndex;\n    exports2.resolveRef = resolveRef;\n    exports2.setConfig = setConfig;\n    exports2.status = status;\n    exports2.statusMatrix = statusMatrix;\n    exports2.tag = tag;\n    exports2.updateIndex = updateIndex;\n    exports2.version = version;\n    exports2.walk = walk;\n    exports2.writeBlob = writeBlob;\n    exports2.writeCommit = writeCommit;\n    exports2.writeObject = writeObject;\n    exports2.writeRef = writeRef;\n    exports2.writeTag = writeTag;\n    exports2.writeTree = writeTree2;\n  }\n});\n\n// demo/browser/git/git.mjs\nvar git_exports = {};\n__export(git_exports, {\n  author: () => author,\n  main: () => main\n});\nmodule.exports = __toCommonJS(git_exports);\nvar import_node_fs = __toESM(require(\"node:fs\"), 1);\nvar import_node_path = __toESM(require(\"node:path\"), 1);\nvar import_node_crypto = require(\"node:crypto\");\nvar import_isomorphic_git = __toESM(require_isomorphic_git(), 1);\n\n// node_modules/.pnpm/diff@5.2.0/node_modules/diff/lib/index.mjs\nfunction Diff() {\n}\nDiff.prototype = {\n  diff: function diff(oldString, newString) {\n    var _options$timeout;\n    var options = arguments.length > 2 && arguments[2] !== void 0 ? arguments[2] : {};\n    var callback = options.callback;\n    if (typeof options === \"function\") {\n      callback = options;\n      options = {};\n    }\n    this.options = options;\n    var self = this;\n    function done(value) {\n      if (callback) {\n        setTimeout(function() {\n          callback(void 0, value);\n        }, 0);\n        return true;\n      } else {\n        return value;\n      }\n    }\n    oldString = this.castInput(oldString);\n    newString = this.castInput(newString);\n    oldString = this.removeEmpty(this.tokenize(oldString));\n    newString = this.removeEmpty(this.tokenize(newString));\n    var newLen = newString.length, oldLen = oldString.length;\n    var editLength = 1;\n    var maxEditLength = newLen + oldLen;\n    if (options.maxEditLength) {\n      maxEditLength = Math.min(maxEditLength, options.maxEditLength);\n    }\n    var maxExecutionTime = (_options$timeout = options.timeout) !== null && _options$timeout !== void 0 ? _options$timeout : Infinity;\n    var abortAfterTimestamp = Date.now() + maxExecutionTime;\n    var bestPath = [{\n      oldPos: -1,\n      lastComponent: void 0\n    }];\n    var newPos = this.extractCommon(bestPath[0], newString, oldString, 0);\n    if (bestPath[0].oldPos + 1 >= oldLen && newPos + 1 >= newLen) {\n      return done([{\n        value: this.join(newString),\n        count: newString.length\n      }]);\n    }\n    var minDiagonalToConsider = -Infinity, maxDiagonalToConsider = Infinity;\n    function execEditLength() {\n      for (var diagonalPath = Math.max(minDiagonalToConsider, -editLength); diagonalPath <= Math.min(maxDiagonalToConsider, editLength); diagonalPath += 2) {\n        var basePath = void 0;\n        var removePath = bestPath[diagonalPath - 1], addPath = bestPath[diagonalPath + 1];\n        if (removePath) {\n          bestPath[diagonalPath - 1] = void 0;\n        }\n        var canAdd = false;\n        if (addPath) {\n          var addPathNewPos = addPath.oldPos - diagonalPath;\n          canAdd = addPath && 0 <= addPathNewPos && addPathNewPos < newLen;\n        }\n        var canRemove = removePath && removePath.oldPos + 1 < oldLen;\n        if (!canAdd && !canRemove) {\n          bestPath[diagonalPath] = void 0;\n          continue;\n        }\n        if (!canRemove || canAdd && removePath.oldPos + 1 < addPath.oldPos) {\n          basePath = self.addToPath(addPath, true, void 0, 0);\n        } else {\n          basePath = self.addToPath(removePath, void 0, true, 1);\n        }\n        newPos = self.extractCommon(basePath, newString, oldString, diagonalPath);\n        if (basePath.oldPos + 1 >= oldLen && newPos + 1 >= newLen) {\n          return done(buildValues(self, basePath.lastComponent, newString, oldString, self.useLongestToken));\n        } else {\n          bestPath[diagonalPath] = basePath;\n          if (basePath.oldPos + 1 >= oldLen) {\n            maxDiagonalToConsider = Math.min(maxDiagonalToConsider, diagonalPath - 1);\n          }\n          if (newPos + 1 >= newLen) {\n            minDiagonalToConsider = Math.max(minDiagonalToConsider, diagonalPath + 1);\n          }\n        }\n      }\n      editLength++;\n    }\n    if (callback) {\n      (function exec() {\n        setTimeout(function() {\n          if (editLength > maxEditLength || Date.now() > abortAfterTimestamp) {\n            return callback();\n          }\n          if (!execEditLength()) {\n            exec();\n          }\n        }, 0);\n      })();\n    } else {\n      while (editLength <= maxEditLength && Date.now() <= abortAfterTimestamp) {\n        var ret = execEditLength();\n        if (ret) {\n          return ret;\n        }\n      }\n    }\n  },\n  addToPath: function addToPath(path2, added, removed, oldPosInc) {\n    var last = path2.lastComponent;\n    if (last && last.added === added && last.removed === removed) {\n      return {\n        oldPos: path2.oldPos + oldPosInc,\n        lastComponent: {\n          count: last.count + 1,\n          added,\n          removed,\n          previousComponent: last.previousComponent\n        }\n      };\n    } else {\n      return {\n        oldPos: path2.oldPos + oldPosInc,\n        lastComponent: {\n          count: 1,\n          added,\n          removed,\n          previousComponent: last\n        }\n      };\n    }\n  },\n  extractCommon: function extractCommon(basePath, newString, oldString, diagonalPath) {\n    var newLen = newString.length, oldLen = oldString.length, oldPos = basePath.oldPos, newPos = oldPos - diagonalPath, commonCount = 0;\n    while (newPos + 1 < newLen && oldPos + 1 < oldLen && this.equals(newString[newPos + 1], oldString[oldPos + 1])) {\n      newPos++;\n      oldPos++;\n      commonCount++;\n    }\n    if (commonCount) {\n      basePath.lastComponent = {\n        count: commonCount,\n        previousComponent: basePath.lastComponent\n      };\n    }\n    basePath.oldPos = oldPos;\n    return newPos;\n  },\n  equals: function equals(left, right) {\n    if (this.options.comparator) {\n      return this.options.comparator(left, right);\n    } else {\n      return left === right || this.options.ignoreCase && left.toLowerCase() === right.toLowerCase();\n    }\n  },\n  removeEmpty: function removeEmpty(array) {\n    var ret = [];\n    for (var i = 0; i < array.length; i++) {\n      if (array[i]) {\n        ret.push(array[i]);\n      }\n    }\n    return ret;\n  },\n  castInput: function castInput(value) {\n    return value;\n  },\n  tokenize: function tokenize(value) {\n    return value.split(\"\");\n  },\n  join: function join(chars) {\n    return chars.join(\"\");\n  }\n};\nfunction buildValues(diff3, lastComponent, newString, oldString, useLongestToken) {\n  var components = [];\n  var nextComponent;\n  while (lastComponent) {\n    components.push(lastComponent);\n    nextComponent = lastComponent.previousComponent;\n    delete lastComponent.previousComponent;\n    lastComponent = nextComponent;\n  }\n  components.reverse();\n  var componentPos = 0, componentLen = components.length, newPos = 0, oldPos = 0;\n  for (; componentPos < componentLen; componentPos++) {\n    var component = components[componentPos];\n    if (!component.removed) {\n      if (!component.added && useLongestToken) {\n        var value = newString.slice(newPos, newPos + component.count);\n        value = value.map(function(value2, i) {\n          var oldValue = oldString[oldPos + i];\n          return oldValue.length > value2.length ? oldValue : value2;\n        });\n        component.value = diff3.join(value);\n      } else {\n        component.value = diff3.join(newString.slice(newPos, newPos + component.count));\n      }\n      newPos += component.count;\n      if (!component.added) {\n        oldPos += component.count;\n      }\n    } else {\n      component.value = diff3.join(oldString.slice(oldPos, oldPos + component.count));\n      oldPos += component.count;\n      if (componentPos && components[componentPos - 1].added) {\n        var tmp = components[componentPos - 1];\n        components[componentPos - 1] = components[componentPos];\n        components[componentPos] = tmp;\n      }\n    }\n  }\n  var finalComponent = components[componentLen - 1];\n  if (componentLen > 1 && typeof finalComponent.value === \"string\" && (finalComponent.added || finalComponent.removed) && diff3.equals(\"\", finalComponent.value)) {\n    components[componentLen - 2].value += finalComponent.value;\n    components.pop();\n  }\n  return components;\n}\nvar characterDiff = new Diff();\nvar extendedWordChars = /^[A-Za-z\\xC0-\\u02C6\\u02C8-\\u02D7\\u02DE-\\u02FF\\u1E00-\\u1EFF]+$/;\nvar reWhitespace = /\\S/;\nvar wordDiff = new Diff();\nwordDiff.equals = function(left, right) {\n  if (this.options.ignoreCase) {\n    left = left.toLowerCase();\n    right = right.toLowerCase();\n  }\n  return left === right || this.options.ignoreWhitespace && !reWhitespace.test(left) && !reWhitespace.test(right);\n};\nwordDiff.tokenize = function(value) {\n  var tokens = value.split(/([^\\S\\r\\n]+|[()[\\]{}'\"\\r\\n]|\\b)/);\n  for (var i = 0; i < tokens.length - 1; i++) {\n    if (!tokens[i + 1] && tokens[i + 2] && extendedWordChars.test(tokens[i]) && extendedWordChars.test(tokens[i + 2])) {\n      tokens[i] += tokens[i + 2];\n      tokens.splice(i + 1, 2);\n      i--;\n    }\n  }\n  return tokens;\n};\nvar lineDiff = new Diff();\nlineDiff.tokenize = function(value) {\n  if (this.options.stripTrailingCr) {\n    value = value.replace(/\\r\\n/g, \"\\n\");\n  }\n  var retLines = [], linesAndNewlines = value.split(/(\\n|\\r\\n)/);\n  if (!linesAndNewlines[linesAndNewlines.length - 1]) {\n    linesAndNewlines.pop();\n  }\n  for (var i = 0; i < linesAndNewlines.length; i++) {\n    var line = linesAndNewlines[i];\n    if (i % 2 && !this.options.newlineIsToken) {\n      retLines[retLines.length - 1] += line;\n    } else {\n      if (this.options.ignoreWhitespace) {\n        line = line.trim();\n      }\n      retLines.push(line);\n    }\n  }\n  return retLines;\n};\nfunction diffLines(oldStr, newStr, callback) {\n  return lineDiff.diff(oldStr, newStr, callback);\n}\nvar sentenceDiff = new Diff();\nsentenceDiff.tokenize = function(value) {\n  return value.split(/(\\S.+?[.!?])(?=\\s+|$)/);\n};\nvar cssDiff = new Diff();\ncssDiff.tokenize = function(value) {\n  return value.split(/([{}:;,]|\\s+)/);\n};\nfunction _typeof(obj) {\n  \"@babel/helpers - typeof\";\n  if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") {\n    _typeof = function(obj2) {\n      return typeof obj2;\n    };\n  } else {\n    _typeof = function(obj2) {\n      return obj2 && typeof Symbol === \"function\" && obj2.constructor === Symbol && obj2 !== Symbol.prototype ? \"symbol\" : typeof obj2;\n    };\n  }\n  return _typeof(obj);\n}\nfunction _toConsumableArray(arr) {\n  return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread();\n}\nfunction _arrayWithoutHoles(arr) {\n  if (Array.isArray(arr)) return _arrayLikeToArray(arr);\n}\nfunction _iterableToArray(iter) {\n  if (typeof Symbol !== \"undefined\" && Symbol.iterator in Object(iter)) return Array.from(iter);\n}\nfunction _unsupportedIterableToArray(o, minLen) {\n  if (!o) return;\n  if (typeof o === \"string\") return _arrayLikeToArray(o, minLen);\n  var n = Object.prototype.toString.call(o).slice(8, -1);\n  if (n === \"Object\" && o.constructor) n = o.constructor.name;\n  if (n === \"Map\" || n === \"Set\") return Array.from(o);\n  if (n === \"Arguments\" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);\n}\nfunction _arrayLikeToArray(arr, len) {\n  if (len == null || len > arr.length) len = arr.length;\n  for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i];\n  return arr2;\n}\nfunction _nonIterableSpread() {\n  throw new TypeError(\"Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.\");\n}\nvar objectPrototypeToString = Object.prototype.toString;\nvar jsonDiff = new Diff();\njsonDiff.useLongestToken = true;\njsonDiff.tokenize = lineDiff.tokenize;\njsonDiff.castInput = function(value) {\n  var _this$options = this.options, undefinedReplacement = _this$options.undefinedReplacement, _this$options$stringi = _this$options.stringifyReplacer, stringifyReplacer = _this$options$stringi === void 0 ? function(k, v) {\n    return typeof v === \"undefined\" ? undefinedReplacement : v;\n  } : _this$options$stringi;\n  return typeof value === \"string\" ? value : JSON.stringify(canonicalize(value, null, null, stringifyReplacer), stringifyReplacer, \"  \");\n};\njsonDiff.equals = function(left, right) {\n  return Diff.prototype.equals.call(jsonDiff, left.replace(/,([\\r\\n])/g, \"$1\"), right.replace(/,([\\r\\n])/g, \"$1\"));\n};\nfunction canonicalize(obj, stack, replacementStack, replacer, key) {\n  stack = stack || [];\n  replacementStack = replacementStack || [];\n  if (replacer) {\n    obj = replacer(key, obj);\n  }\n  var i;\n  for (i = 0; i < stack.length; i += 1) {\n    if (stack[i] === obj) {\n      return replacementStack[i];\n    }\n  }\n  var canonicalizedObj;\n  if (\"[object Array]\" === objectPrototypeToString.call(obj)) {\n    stack.push(obj);\n    canonicalizedObj = new Array(obj.length);\n    replacementStack.push(canonicalizedObj);\n    for (i = 0; i < obj.length; i += 1) {\n      canonicalizedObj[i] = canonicalize(obj[i], stack, replacementStack, replacer, key);\n    }\n    stack.pop();\n    replacementStack.pop();\n    return canonicalizedObj;\n  }\n  if (obj && obj.toJSON) {\n    obj = obj.toJSON();\n  }\n  if (_typeof(obj) === \"object\" && obj !== null) {\n    stack.push(obj);\n    canonicalizedObj = {};\n    replacementStack.push(canonicalizedObj);\n    var sortedKeys = [], _key;\n    for (_key in obj) {\n      if (obj.hasOwnProperty(_key)) {\n        sortedKeys.push(_key);\n      }\n    }\n    sortedKeys.sort();\n    for (i = 0; i < sortedKeys.length; i += 1) {\n      _key = sortedKeys[i];\n      canonicalizedObj[_key] = canonicalize(obj[_key], stack, replacementStack, replacer, _key);\n    }\n    stack.pop();\n    replacementStack.pop();\n  } else {\n    canonicalizedObj = obj;\n  }\n  return canonicalizedObj;\n}\nvar arrayDiff = new Diff();\narrayDiff.tokenize = function(value) {\n  return value.slice();\n};\narrayDiff.join = arrayDiff.removeEmpty = function(value) {\n  return value;\n};\nfunction structuredPatch(oldFileName, newFileName, oldStr, newStr, oldHeader, newHeader, options) {\n  if (!options) {\n    options = {};\n  }\n  if (typeof options.context === \"undefined\") {\n    options.context = 4;\n  }\n  var diff3 = diffLines(oldStr, newStr, options);\n  if (!diff3) {\n    return;\n  }\n  diff3.push({\n    value: \"\",\n    lines: []\n  });\n  function contextLines(lines) {\n    return lines.map(function(entry) {\n      return \" \" + entry;\n    });\n  }\n  var hunks = [];\n  var oldRangeStart = 0, newRangeStart = 0, curRange = [], oldLine = 1, newLine = 1;\n  var _loop = function _loop2(i2) {\n    var current = diff3[i2], lines = current.lines || current.value.replace(/\\n$/, \"\").split(\"\\n\");\n    current.lines = lines;\n    if (current.added || current.removed) {\n      var _curRange;\n      if (!oldRangeStart) {\n        var prev = diff3[i2 - 1];\n        oldRangeStart = oldLine;\n        newRangeStart = newLine;\n        if (prev) {\n          curRange = options.context > 0 ? contextLines(prev.lines.slice(-options.context)) : [];\n          oldRangeStart -= curRange.length;\n          newRangeStart -= curRange.length;\n        }\n      }\n      (_curRange = curRange).push.apply(_curRange, _toConsumableArray(lines.map(function(entry) {\n        return (current.added ? \"+\" : \"-\") + entry;\n      })));\n      if (current.added) {\n        newLine += lines.length;\n      } else {\n        oldLine += lines.length;\n      }\n    } else {\n      if (oldRangeStart) {\n        if (lines.length <= options.context * 2 && i2 < diff3.length - 2) {\n          var _curRange2;\n          (_curRange2 = curRange).push.apply(_curRange2, _toConsumableArray(contextLines(lines)));\n        } else {\n          var _curRange3;\n          var contextSize = Math.min(lines.length, options.context);\n          (_curRange3 = curRange).push.apply(_curRange3, _toConsumableArray(contextLines(lines.slice(0, contextSize))));\n          var hunk = {\n            oldStart: oldRangeStart,\n            oldLines: oldLine - oldRangeStart + contextSize,\n            newStart: newRangeStart,\n            newLines: newLine - newRangeStart + contextSize,\n            lines: curRange\n          };\n          if (i2 >= diff3.length - 2 && lines.length <= options.context) {\n            var oldEOFNewline = /\\n$/.test(oldStr);\n            var newEOFNewline = /\\n$/.test(newStr);\n            var noNlBeforeAdds = lines.length == 0 && curRange.length > hunk.oldLines;\n            if (!oldEOFNewline && noNlBeforeAdds && oldStr.length > 0) {\n              curRange.splice(hunk.oldLines, 0, \"\\\\ No newline at end of file\");\n            }\n            if (!oldEOFNewline && !noNlBeforeAdds || !newEOFNewline) {\n              curRange.push(\"\\\\ No newline at end of file\");\n            }\n          }\n          hunks.push(hunk);\n          oldRangeStart = 0;\n          newRangeStart = 0;\n          curRange = [];\n        }\n      }\n      oldLine += lines.length;\n      newLine += lines.length;\n    }\n  };\n  for (var i = 0; i < diff3.length; i++) {\n    _loop(i);\n  }\n  return {\n    oldFileName,\n    newFileName,\n    oldHeader,\n    newHeader,\n    hunks\n  };\n}\n\n// demo/browser/git/git.mjs\nvar author = { name: \"Demo\", email: \"demo@example.com\" };\nvar GitError = class extends Error {\n  constructor(message, code = 128) {\n    super(message);\n    this.code = code;\n  }\n};\nfunction findRoot(from) {\n  for (let dir = import_node_path.default.resolve(from); ; dir = import_node_path.default.dirname(dir)) {\n    if (import_node_fs.default.existsSync(import_node_path.default.join(dir, \".git\"))) return dir;\n    if (dir === import_node_path.default.dirname(dir)) throw new GitError(\"fatal: not a git repository (or any of the parent directories): .git\");\n  }\n}\nfunction parse(args) {\n  const split = args.indexOf(\"--\");\n  const head = split === -1 ? args : args.slice(0, split);\n  const paths = split === -1 ? [] : args.slice(split + 1);\n  const flags = head.filter((arg) => arg.startsWith(\"-\"));\n  const words = head.filter((arg) => !arg.startsWith(\"-\"));\n  return { flags, words, paths, has: (...names) => names.some((name) => flags.includes(name)) };\n}\nvar flagValue = (flags, name) => flags.find((flag) => flag.startsWith(`${name}=`))?.slice(name.length + 1);\nasync function headOid(dir) {\n  try {\n    return await import_isomorphic_git.default.resolveRef({ fs: import_node_fs.default, dir, ref: \"HEAD\" });\n  } catch {\n    return void 0;\n  }\n}\nasync function readOid(dir, oid) {\n  if (!oid) return \"\";\n  const { blob } = await import_isomorphic_git.default.readBlob({ fs: import_node_fs.default, dir, oid });\n  return Buffer.from(blob).toString(\"utf8\");\n}\nasync function treeAndIndex(dir) {\n  const head = await headOid(dir);\n  const trees = head ? [import_isomorphic_git.default.TREE({ ref: \"HEAD\" }), import_isomorphic_git.default.STAGE()] : [import_isomorphic_git.default.STAGE()];\n  const files = /* @__PURE__ */ new Map();\n  await import_isomorphic_git.default.walk({\n    fs: import_node_fs.default,\n    dir,\n    trees,\n    map: async (filepath, entries) => {\n      if (filepath === \".\") return true;\n      const [headEntry, stageEntry] = head ? entries : [null, entries[0]];\n      const type = await headEntry?.type() ?? await stageEntry?.type();\n      if (type === \"tree\") return true;\n      files.set(filepath, { head: headEntry ? await headEntry.oid() : void 0, stage: stageEntry ? await stageEntry.oid() : void 0 });\n      return true;\n    }\n  });\n  return files;\n}\nfunction porcelain([, head, workdir, stage2]) {\n  if (head === 0 && stage2 === 0) return workdir === 2 ? \"??\" : null;\n  const index = head === 0 ? \"A\" : stage2 === 0 ? \"D\" : stage2 === 1 ? \" \" : \"M\";\n  let tree = \" \";\n  if (workdir === 0) tree = stage2 === 0 ? \" \" : \"D\";\n  else if (stage2 === 1 && workdir === 2 || stage2 === 3) tree = \"M\";\n  const code = `${index}${tree}`;\n  return code === \"  \" ? null : code;\n}\nasync function statusEntries(dir) {\n  const rows = await import_isomorphic_git.default.statusMatrix({ fs: import_node_fs.default, dir });\n  return rows.map((row) => ({ path: row[0], code: porcelain(row), row })).filter((entry) => entry.code);\n}\nfunction patchFor(file, before, after, { context = 3, added = false, deleted = false } = {}) {\n  const lines = [`diff --git a/${file} b/${file}`];\n  if (added) lines.push(\"new file mode 100644\");\n  if (deleted) lines.push(\"deleted file mode 100644\");\n  const hash = (text) => (0, import_node_crypto.createHash)(\"sha1\").update(text).digest(\"hex\").slice(0, 7);\n  lines.push(`index ${added ? \"0000000\" : hash(before)}..${deleted ? \"0000000\" : hash(after)}${added || deleted ? \"\" : \" 100644\"}`);\n  lines.push(added ? \"--- /dev/null\" : `--- a/${file}`, deleted ? \"+++ /dev/null\" : `+++ b/${file}`);\n  const { hunks } = structuredPatch(file, file, before, after, \"\", \"\", { context });\n  for (const hunk of hunks) {\n    lines.push(`@@ -${range(hunk.oldStart, hunk.oldLines)} +${range(hunk.newStart, hunk.newLines)} @@`);\n    lines.push(...hunk.lines.filter((line) => !line.startsWith(\"\\\\\")));\n  }\n  return `${lines.join(\"\\n\")}\n`;\n}\nfunction range(start, lines) {\n  if (lines === 0) return `${start - 1},0`;\n  return lines === 1 ? `${start}` : `${start},${lines}`;\n}\nvar count = (text, sign) => text.split(\"\\n\").filter((line) => line.startsWith(sign) && !line.startsWith(`${sign}${sign}${sign} `)).length;\nasync function changes(dir, { cached, base }) {\n  const files = await treeAndIndex(dir);\n  const result = [];\n  for (const [file, { head, stage: stage2 }] of files) {\n    if (cached) {\n      if (head === stage2) continue;\n      result.push({ file, before: await readOid(dir, head), after: await readOid(dir, stage2), added: !head, deleted: !stage2 });\n    } else {\n      const from = base === \"HEAD\" ? head : stage2;\n      const onDisk = import_node_path.default.join(dir, file);\n      const after = import_node_fs.default.existsSync(onDisk) ? import_node_fs.default.readFileSync(onDisk, \"utf8\") : void 0;\n      const before = await readOid(dir, from);\n      if (!from && after === void 0) continue;\n      if (after === before) continue;\n      result.push({ file, before, after: after ?? \"\", added: !from, deleted: after === void 0 });\n    }\n  }\n  return result.sort((a, b) => a.file.localeCompare(b.file));\n}\nfunction summary(list) {\n  const insertions = list.reduce((sum, change) => sum + change.insertions, 0);\n  const deletions = list.reduce((sum, change) => sum + change.deletions, 0);\n  const parts = [` ${list.length} file${list.length === 1 ? \"\" : \"s\"} changed`];\n  if (insertions) parts.push(`${insertions} insertion${insertions === 1 ? \"\" : \"s\"}(+)`);\n  if (deletions) parts.push(`${deletions} deletion${deletions === 1 ? \"\" : \"s\"}(-)`);\n  return parts.join(\", \");\n}\nasync function diff2(dir, args) {\n  const { flags, words, paths } = parse(args);\n  const has = (name) => flags.includes(name);\n  if (has(\"--no-index\")) {\n    const file = paths[1];\n    const after = import_node_fs.default.readFileSync(import_node_path.default.resolve(file), \"utf8\");\n    return { stdout: patchFor(file, \"\", after, { added: true }), code: 1 };\n  }\n  const cached = has(\"--cached\") || has(\"--staged\");\n  const scope = paths.filter((p) => p !== \".\");\n  const list = (await changes(dir, { cached, base: words[0] })).filter((change) => scope.length === 0 || scope.some((p) => change.file === p || change.file.startsWith(`${p}/`))).map((change) => {\n    const unified = flagValue(flags, \"--unified\");\n    const patch = patchFor(change.file, change.before, change.after, { context: unified === void 0 ? 3 : Number(unified), added: change.added, deleted: change.deleted });\n    return { ...change, patch, insertions: count(patch, \"+\"), deletions: count(patch, \"-\") };\n  });\n  if (has(\"--quiet\") || has(\"--exit-code\")) return { stdout: \"\", code: list.length ? 1 : 0 };\n  const zero = has(\"-z\");\n  if (has(\"--name-status\")) return { stdout: list.map((c) => zero ? `${c.added ? \"A\" : c.deleted ? \"D\" : \"M\"}\\0${c.file}\\0` : `${c.added ? \"A\" : c.deleted ? \"D\" : \"M\"}\t${c.file}\n`).join(\"\") };\n  if (has(\"--numstat\")) return { stdout: list.map((c) => `${c.insertions}\t${c.deletions}\t${c.file}${zero ? \"\\0\" : \"\\n\"}`).join(\"\") };\n  if (!list.length) return { stdout: \"\" };\n  if (has(\"--shortstat\")) return { stdout: `${summary(list)}\n` };\n  if (has(\"--stat\")) {\n    const width = Math.max(...list.map((c) => c.file.length));\n    const rows = list.map((c) => ` ${c.file.padEnd(width)} | ${String(c.insertions + c.deletions).padStart(2)} ${\"+\".repeat(c.insertions)}${\"-\".repeat(c.deletions)}`);\n    return { stdout: `${rows.join(\"\\n\")}\n${summary(list)}\n` };\n  }\n  return { stdout: list.map((c) => c.patch).join(\"\") };\n}\nasync function stage(dir, file) {\n  if (import_node_fs.default.existsSync(import_node_path.default.join(dir, file))) await import_isomorphic_git.default.add({ fs: import_node_fs.default, dir, filepath: file });\n  else await import_isomorphic_git.default.remove({ fs: import_node_fs.default, dir, filepath: file });\n}\nasync function commit(dir, args) {\n  const { flags } = parse(args);\n  const at = (name) => args[args.indexOf(name) + 1];\n  const message = args.includes(\"--file\") ? import_node_fs.default.readFileSync(import_node_path.default.resolve(at(\"--file\")), \"utf8\") : at(\"--message\") ?? at(\"-m\");\n  if (!message?.trim()) throw new GitError(\"Aborting commit due to empty commit message.\", 1);\n  const branch = await import_isomorphic_git.default.currentBranch({ fs: import_node_fs.default, dir });\n  let oid;\n  if (flags.includes(\"--amend\")) {\n    const { commit: previous } = await import_isomorphic_git.default.readCommit({ fs: import_node_fs.default, dir, oid: await headOid(dir) });\n    oid = await import_isomorphic_git.default.commit({ fs: import_node_fs.default, dir, message, author, tree: previous.tree, parent: previous.parent });\n  } else {\n    const staged = await changes(dir, { cached: true });\n    if (!staged.length) return { stdout: `On branch ${branch}\nnothing to commit, working tree clean\n`, code: 1 };\n    oid = await import_isomorphic_git.default.commit({ fs: import_node_fs.default, dir, message, author });\n  }\n  const subject = message.trim().split(\"\\n\")[0];\n  return { stdout: `[${branch} ${oid.slice(0, 7)}] ${subject}\n` };\n}\nasync function writeTree(dir) {\n  const files = await treeAndIndex(dir);\n  const entries = [...files].filter(([, { stage: stage2 }]) => stage2).map(([file, { stage: stage2 }]) => `${file} ${stage2}`).sort();\n  return { stdout: `${(0, import_node_crypto.createHash)(\"sha1\").update(entries.join(\"\\n\")).digest(\"hex\")}\n` };\n}\nasync function log(dir, args) {\n  const limit = Number(args.find((arg) => /^-n?\\d+$/.test(arg))?.replace(/^-n?/, \"\") ?? 10);\n  const commits = await import_isomorphic_git.default.log({ fs: import_node_fs.default, dir, depth: limit });\n  if (args.includes(\"--oneline\")) return { stdout: commits.map((c) => `${c.oid.slice(0, 7)} ${c.commit.message.split(\"\\n\")[0]}\n`).join(\"\") };\n  return {\n    stdout: commits.map((c) => `commit ${c.oid}\nAuthor: ${c.commit.author.name} <${c.commit.author.email}>\nDate:   ${new Date(c.commit.author.timestamp * 1e3).toUTCString()}\n\n${c.commit.message.trim().split(\"\\n\").map((line) => `    ${line}`).join(\"\\n\")}\n`).join(\"\\n\")\n  };\n}\nasync function run(args, cwd) {\n  const [command, ...rest] = args.filter((arg) => arg !== \"--no-optional-locks\" && arg !== \"--no-pager\");\n  if (command === \"--version\" || command === \"version\") return { stdout: \"git version 2.47.0 (demo stand-in)\\n\" };\n  if (command === \"init\") {\n    await import_isomorphic_git.default.init({ fs: import_node_fs.default, dir: cwd, defaultBranch: \"main\" });\n    return { stdout: `Initialized empty Git repository in ${import_node_path.default.join(cwd, \".git\")}/\n` };\n  }\n  const dir = findRoot(cwd);\n  const { flags, words, paths, has } = parse(rest);\n  switch (command) {\n    case \"rev-parse\":\n      if (has(\"--show-toplevel\")) return { stdout: `${dir}\n` };\n      if (has(\"--git-path\")) return { stdout: `.git/${rest[rest.indexOf(\"--git-path\") + 1]}\n` };\n      if (has(\"--abbrev-ref\")) return { stdout: `${await import_isomorphic_git.default.currentBranch({ fs: import_node_fs.default, dir })}\n` };\n      {\n        const oid = await headOid(dir);\n        if (!oid) throw new GitError(\"fatal: Needed a single revision\");\n        return { stdout: `${oid}\n` };\n      }\n    case \"symbolic-ref\": {\n      const branch = await import_isomorphic_git.default.currentBranch({ fs: import_node_fs.default, dir, fullname: !has(\"--short\") });\n      if (!branch) return { stdout: \"\", code: 1 };\n      return { stdout: `${branch}\n` };\n    }\n    case \"status\": {\n      const entries = await statusEntries(dir);\n      if (has(\"--porcelain=v1\", \"--porcelain\", \"-s\", \"--short\")) {\n        const zero = has(\"-z\");\n        return { stdout: entries.map((entry) => `${entry.code} ${entry.path}${zero ? \"\\0\" : \"\\n\"}`).join(\"\") };\n      }\n      const branch = await import_isomorphic_git.default.currentBranch({ fs: import_node_fs.default, dir });\n      const body = entries.length ? entries.map((entry) => `  ${entry.code} ${entry.path}`).join(\"\\n\") : \"nothing to commit, working tree clean\";\n      return { stdout: `On branch ${branch}\n${body}\n` };\n    }\n    case \"add\": {\n      const targets = has(\"--all\", \"-A\") || paths.includes(\".\") || words.includes(\".\") ? (await statusEntries(dir)).map((entry) => entry.path) : [...words, ...paths];\n      for (const file of targets) await stage(dir, file);\n      return { stdout: \"\" };\n    }\n    case \"reset\":\n      for (const file of paths) await import_isomorphic_git.default.resetIndex({ fs: import_node_fs.default, dir, filepath: file });\n      return { stdout: \"\" };\n    case \"rm\":\n      for (const file of paths) await import_isomorphic_git.default.remove({ fs: import_node_fs.default, dir, filepath: file });\n      if (!has(\"--cached\")) for (const file of paths) import_node_fs.default.rmSync(import_node_path.default.join(dir, file), { force: true });\n      return { stdout: \"\" };\n    case \"clean\":\n      for (const file of paths) import_node_fs.default.rmSync(import_node_path.default.join(dir, file), { recursive: true, force: true });\n      return { stdout: paths.map((file) => `Removing ${file}\n`).join(\"\") };\n    case \"restore\":\n    case \"checkout\": {\n      if (command === \"restore\" || paths.length) {\n        const files = await treeAndIndex(dir);\n        for (const file of paths) {\n          if (files.get(file)?.head) {\n            await import_isomorphic_git.default.checkout({ fs: import_node_fs.default, dir, force: true, filepaths: [file] });\n            await import_isomorphic_git.default.resetIndex({ fs: import_node_fs.default, dir, filepath: file });\n          } else {\n            await import_isomorphic_git.default.remove({ fs: import_node_fs.default, dir, filepath: file });\n            import_node_fs.default.rmSync(import_node_path.default.join(dir, file), { force: true });\n          }\n        }\n        return { stdout: \"\" };\n      }\n      if (has(\"-b\")) {\n        await import_isomorphic_git.default.branch({ fs: import_node_fs.default, dir, ref: words[0], checkout: true });\n        return { stdout: \"\", stderr: `Switched to a new branch '${words[0]}'\n` };\n      }\n      await import_isomorphic_git.default.checkout({ fs: import_node_fs.default, dir, ref: words[0] });\n      return { stdout: \"\", stderr: `Switched to branch '${words[0]}'\n` };\n    }\n    case \"branch\": {\n      if (has(\"--remotes\", \"-r\")) return { stdout: \"\" };\n      if (has(\"-d\", \"-D\")) {\n        await import_isomorphic_git.default.deleteBranch({ fs: import_node_fs.default, dir, ref: words[0] });\n        return { stdout: `Deleted branch ${words[0]}.\n` };\n      }\n      if (words[0]) {\n        await import_isomorphic_git.default.branch({ fs: import_node_fs.default, dir, ref: words[0] });\n        return { stdout: \"\" };\n      }\n      const current = await import_isomorphic_git.default.currentBranch({ fs: import_node_fs.default, dir });\n      return { stdout: (await import_isomorphic_git.default.listBranches({ fs: import_node_fs.default, dir })).map((b) => `${b === current ? \"*\" : \" \"} ${b}\n`).join(\"\") };\n    }\n    case \"for-each-ref\":\n      return { stdout: (await import_isomorphic_git.default.listBranches({ fs: import_node_fs.default, dir })).map((b) => `${b}\n`).join(\"\") };\n    case \"write-tree\":\n      return writeTree(dir);\n    case \"diff\":\n      return diff2(dir, rest);\n    case \"commit\":\n      return commit(dir, rest);\n    case \"show\": {\n      const { commit: c } = await import_isomorphic_git.default.readCommit({ fs: import_node_fs.default, dir, oid: await headOid(dir) });\n      if (flags.includes(\"--format=%B\") || flags.includes(\"--pretty=%B\")) return { stdout: `${c.message.trim()}\n\n` };\n      return log(dir, [\"-1\"]);\n    }\n    case \"log\":\n      return log(dir, rest);\n    case \"config\":\n      return { stdout: \"\", code: 1 };\n    case \"push\":\n    case \"pull\":\n    case \"fetch\":\n      throw new GitError(`fatal: '${words[0] ?? \"origin\"}' does not appear to be a git repository\nThis demo has no remote, so ${command} is not available.`);\n    default:\n      throw new GitError(`git ${command}: not available in this demo's stand-in for git.`, 1);\n  }\n}\nasync function main(args, cwd = process.cwd()) {\n  try {\n    const { stdout = \"\", stderr = \"\", code = 0 } = await run(args, cwd);\n    process.stdout.write(stdout);\n    process.stderr.write(stderr);\n    return code;\n  } catch (error) {\n    process.stderr.write(`${error instanceof GitError ? error.message : `fatal: ${error?.message ?? error}`}\n`);\n    return error instanceof GitError ? error.code : 128;\n  }\n}\n// Annotate the CommonJS export names for ESM import in node:\n0 && (module.exports = {\n  author,\n  main\n});\n/*! Bundled license information:\n\nsafe-buffer/index.js:\n  (*! safe-buffer. MIT License. Feross Aboukhadijeh <https://feross.org/opensource> *)\n\ncrc-32/crc32.js:\n  (*! crc32.js (C) 2014-present SheetJS -- http://sheetjs.com *)\n*/\n"}}}}}