{"version":3,"file":"index.mjs","names":[],"sources":["../../shared/editor-border-resolver.ts","../index.ts"],"sourcesContent":["export type Colorize = (text: string) => string;\n\nexport type EditorBorderMode = \"default\" | \"plan\";\n\nexport type EditorBorderResolverOptions = {\n  text: string;\n  mode?: EditorBorderMode;\n  baseBorder: Colorize;\n  bashBorder: Colorize;\n  planBorder?: Colorize;\n};\n\n/** Match Pi core's manual bash detection: leading whitespace is ignored. */\nexport const isBashInput = (text: string): boolean => text.trimStart().startsWith(\"!\");\n\n/** Resolve editor border color by visual priority. Bash input always wins. */\nexport const resolveEditorBorder = ({\n  text,\n  mode,\n  baseBorder,\n  bashBorder,\n  planBorder,\n}: EditorBorderResolverOptions): Colorize => {\n  if (isBashInput(text)) return bashBorder;\n  if (mode === \"plan\" && planBorder) return planBorder;\n  return baseBorder;\n};\n","import type { Component, EditorTheme, TUI } from \"@earendil-works/pi-tui\";\nimport { truncateToWidth, visibleWidth } from \"@earendil-works/pi-tui\";\nimport { spinners } from \"unicode-animations\";\nimport { complete } from \"@earendil-works/pi-ai\";\nimport type { Model, Api } from \"@earendil-works/pi-ai\";\nimport {\n  CustomEditor,\n  type ExtensionAPI,\n  type ExtensionContext,\n  type KeybindingsManager,\n} from \"@earendil-works/pi-coding-agent\";\nimport { isBashInput, resolveEditorBorder } from \"../shared/editor-border-resolver\";\n\ntype FooterMode = \"zen\" | \"dev\";\ntype PiThinkingLevel = \"off\" | \"minimal\" | \"low\" | \"medium\" | \"high\" | \"xhigh\";\ntype CodexLimitUsage = {\n  provider?: string;\n  fiveHour?: {\n    usedPercent?: number;\n    windowSeconds?: number;\n    resetAt?: number;\n  };\n  weekly?: {\n    usedPercent?: number;\n    windowSeconds?: number;\n    resetAt?: number;\n  };\n  fetchedAt?: number;\n};\n\n/** Snapshot of the repository state shown in the dev footer. */\ntype GitInfo = {\n  branch?: string;\n  changedFiles: number;\n  isRepo: boolean;\n};\n\ndeclare global {\n  // eslint-disable-next-line no-var\n  var piCodexLimit: CodexLimitUsage | undefined;\n}\n\nconst STATE_TYPE = \"footer-mode-state\";\nconst SHORTCUT = \"alt+f\";\nconst TURN_DURATION_UPDATE_INTERVAL_MS = 250;\nconst WORKING_SPINNER = spinners.columns;\n\n/** Hides Pi's default footer while keeping the custom below-editor widgets active. */\nconst createEmptyFooter = (): Component => ({\n  render: () => [],\n  invalidate: () => {},\n});\n\n/**\n * Keeps the editor border color stable across renders while highlighting bash mode.\n *\n * When the prompt starts with `!`, Pi will run it as a bash command. This wrapper\n * uses the warning/yellow border and input text in that state, and falls back to\n * the muted base border with normal input rendering otherwise.\n */\nconst createBashAwareBorderEditor = (\n  tui: TUI,\n  theme: EditorTheme,\n  keybindings: KeybindingsManager,\n  baseBorder: (text: string) => string,\n  bashBorder: (text: string) => string,\n  bashInput: (text: string) => string,\n): CustomEditor => {\n  const editor = new CustomEditor(tui, { ...theme, borderColor: baseBorder }, keybindings);\n  const isBashMode = (): boolean => isBashInput(editor.getText());\n  const getBorderColor = (): ((text: string) => string) =>\n    resolveEditorBorder({\n      text: editor.getText(),\n      baseBorder,\n      bashBorder,\n    });\n\n  const originalHandleInput = editor.handleInput.bind(editor);\n  editor.handleInput = (data: string): void => {\n    originalHandleInput(data);\n    editor.borderColor = getBorderColor();\n  };\n\n  const originalSetText = editor.setText.bind(editor);\n  editor.setText = (text: string): void => {\n    originalSetText(text);\n    editor.borderColor = getBorderColor();\n  };\n\n  const originalInsertTextAtCursor = editor.insertTextAtCursor.bind(editor);\n  editor.insertTextAtCursor = (text: string): void => {\n    originalInsertTextAtCursor(text);\n    editor.borderColor = getBorderColor();\n  };\n\n  const originalRender = editor.render.bind(editor);\n  editor.render = (width: number): string[] => {\n    editor.borderColor = getBorderColor();\n    const lines = originalRender(width);\n\n    if (!isBashMode() || lines.length <= 2) return lines;\n\n    const lastEditorLineIndex = lines.length - 1;\n    return lines.map((line, index) => {\n      const isEditorBorder = index === 0 || index === lastEditorLineIndex;\n      return isEditorBorder ? line : bashInput(line);\n    });\n  };\n\n  return editor;\n};\n\nconst isFooterMode = (value: unknown): value is FooterMode => {\n  return value === \"zen\" || value === \"dev\";\n};\n\nconst getStoredMode = (data: unknown): FooterMode | undefined => {\n  if (!data || typeof data !== \"object\" || !(\"mode\" in data)) return undefined;\n  const value = (data as { mode?: unknown }).mode;\n  return isFooterMode(value) ? value : undefined;\n};\n\n/** Compact cwd for narrow footer space while preserving the useful tail path. */\nconst formatCwd = (cwd: string): string => {\n  const home = process.env.HOME;\n  const compact = home && cwd.startsWith(home) ? `~${cwd.slice(home.length)}` : cwd;\n  const parts = compact.split(\"/\").filter(Boolean);\n  if (compact.startsWith(\"~/\") && parts.length > 2) return `~/${parts.slice(-2).join(\"/\")}`;\n  if (!compact.startsWith(\"~\") && parts.length > 3) return `…/${parts.slice(-3).join(\"/\")}`;\n  return compact;\n};\n\n/** Format Unix reset timestamps into short quota-reset labels. */\nconst formatResetShort = (resetAt: number | undefined): string => {\n  if (!resetAt) return \"unknown\";\n\n  const minutes = Math.max(0, Math.round((resetAt * 1000 - Date.now()) / 60000));\n  const days = Math.floor(minutes / (60 * 24));\n  const hours = Math.floor((minutes % (60 * 24)) / 60);\n  const mins = minutes % 60;\n\n  if (days > 0) return `${days}d ${hours}h`;\n  if (hours > 0) return `${hours}h ${mins}m`;\n  return `${mins}m`;\n};\n\nconst formatDuration = (ms: number): string => {\n  const totalSeconds = Math.floor(ms / 1000);\n  const seconds = totalSeconds % 60;\n  const totalMinutes = Math.floor(totalSeconds / 60);\n  const minutes = totalMinutes % 60;\n  const hours = Math.floor(totalMinutes / 60);\n\n  if (hours > 0) return `${hours}h ${minutes}m ${seconds}s`;\n  if (minutes > 0) return `${minutes}m ${seconds}s`;\n  return `${seconds}s`;\n};\n\nconst formatTokensPerSecond = (tokensPerSecond: number): string => {\n  if (tokensPerSecond >= 100) return `${Math.round(tokensPerSecond)} tok/s`;\n  return `${tokensPerSecond.toFixed(1)} tok/s`;\n};\n\nconst isOpenAICodexProvider = (provider: string | undefined): boolean => {\n  return /^openai-codex(-\\d+)?$/.test(provider ?? \"\");\n};\n\nconst formatCompactTokens = (count: number): string => {\n  const abs = Math.abs(count);\n  if (abs >= 1_000_000) return `${Number((count / 1_000_000).toFixed(1))}m`;\n  if (abs >= 1_000) return `${Number((count / 1_000).toFixed(1))}k`;\n  return `${Math.round(count)}`;\n};\n\nconst formatEstimatedCost = (cost: number): string => {\n  if (cost >= 10) return `$${cost.toFixed(1)}`;\n  if (cost >= 1) return `$${cost.toFixed(2)}`;\n  return `$${cost.toFixed(2)}`;\n};\n\nconst formatSessionTokenTotals = (\n  ctx: ExtensionContext,\n  colorToken: (text: string) => string,\n): string => {\n  let input = 0;\n  let output = 0;\n  let cost = 0;\n\n  for (const entry of ctx.sessionManager.getBranch()) {\n    if (entry.type !== \"message\" || entry.message.role !== \"assistant\") continue;\n    input += entry.message.usage?.input ?? 0;\n    output += entry.message.usage?.output ?? 0;\n    cost += entry.message.usage?.cost?.total ?? 0;\n  }\n\n  return colorToken(\n    `↑${formatCompactTokens(input)} ↓${formatCompactTokens(output)}  ${formatEstimatedCost(cost)}`,\n  );\n};\n\n/** Compact braille-style bar showing the context window percentage already filled. */\nconst formatContextBar = (\n  ctx: ExtensionContext,\n  modelConfig: ExtensionContext[\"model\"],\n  colorToken: (text: string) => string,\n  colorBar: (percentUsed: number, text: string) => string,\n): string => {\n  const usage = ctx.getContextUsage();\n  const contextWindow = usage?.contextWindow ?? modelConfig?.contextWindow ?? 0;\n  const usedTokens = usage?.tokens ?? 0;\n  const usedPercent =\n    usage?.percent ?? (contextWindow > 0 ? (usedTokens / contextWindow) * 100 : null);\n  const tokenTotals = formatSessionTokenTotals(ctx, colorToken);\n  const tokenLabel = `${formatCompactTokens(usedTokens)}/${formatCompactTokens(contextWindow)}`;\n  const prefix = tokenTotals + colorToken(\" · \") + colorToken(tokenLabel) + colorToken(\" · \");\n\n  if (usedPercent === null) return prefix + colorToken(\"[??????????] ?%\");\n\n  const percentUsed = Math.max(0, Math.min(100, usedPercent));\n  const totalCells = 10;\n  const filledCells = Math.round((percentUsed / 100) * totalCells);\n  const bar = `${\"⣿\".repeat(filledCells)}${\"⣀\".repeat(totalCells - filledCells)}`;\n  return prefix + colorBar(percentUsed, `[${bar}] ${Math.round(percentUsed)}%`);\n};\n\n/** Build the right-side model/footer payload from Pi model state and optional Codex quota globals. */\nconst formatModelInfo = (\n  pi: ExtensionAPI,\n  modelConfig: ExtensionContext[\"model\"],\n): {\n  provider: string;\n  model: string;\n  thinking?: PiThinkingLevel;\n  usage?: CodexLimitUsage[\"fiveHour\"];\n} => {\n  const provider = modelConfig?.provider ?? \"no-provider\";\n  const model = modelConfig?.id ?? \"no-model\";\n  const thinking = pi.getThinkingLevel() as PiThinkingLevel;\n  const codexLimit = globalThis.piCodexLimit;\n  return {\n    provider,\n    model,\n    thinking: thinking === \"off\" ? undefined : thinking,\n    usage:\n      isOpenAICodexProvider(provider) && codexLimit?.provider === provider\n        ? codexLimit.fiveHour\n        : undefined,\n  };\n};\n\nconst TITLE_GENERATION_PROMPT =\n  \"Generate a very short title (max 6 words, no quotes, no punctuation) for a coding session that starts with this message. Reply with ONLY the title:\";\n\nconst MAX_TITLE_LENGTH = 50;\n\n/** Extract the first user message text from the session branch. */\nconst getFirstUserMessage = (\n  entries: Iterable<{ type: string; message?: { role?: string; content?: unknown } }>,\n): string | undefined => {\n  for (const entry of entries) {\n    if (entry.type !== \"message\" || entry.message?.role !== \"user\") continue;\n    const content = entry.message.content;\n    if (typeof content === \"string\") return content;\n    if (!Array.isArray(content)) continue;\n    for (const block of content) {\n      if (\n        block &&\n        typeof block === \"object\" &&\n        block.type === \"text\" &&\n        typeof block.text === \"string\"\n      )\n        return block.text;\n    }\n  }\n  return undefined;\n};\n\nexport default (pi: ExtensionAPI): void => {\n  let mode: FooterMode = \"zen\";\n  let activeTui: TUI | undefined;\n  let currentCtx: ExtensionContext | undefined;\n  let currentModel: ExtensionContext[\"model\"];\n  let gitInfo: GitInfo = { changedFiles: 0, isRepo: false };\n  let turnStartedAt: number | undefined;\n  let turnDurationTimer: ReturnType<typeof setInterval> | undefined;\n  let lastTurnDuration: number | undefined;\n  let lastTurnTokensPerSecond: number | undefined;\n  let sessionTitle: string | undefined;\n  let titleGenerationStarted = false;\n\n  const rememberMode = () => {\n    pi.appendEntry(STATE_TYPE, { mode });\n  };\n\n  const requestRender = () => {\n    activeTui?.requestRender();\n  };\n\n  const clearTurnDurationTimer = () => {\n    if (!turnDurationTimer) return;\n    clearInterval(turnDurationTimer);\n    turnDurationTimer = undefined;\n  };\n\n  const renderTurnDuration = () => {\n    const elapsed = turnStartedAt ? Date.now() - turnStartedAt : lastTurnDuration;\n    return elapsed === undefined ? \"\" : formatDuration(elapsed);\n  };\n\n  const updateTurnDurationDisplay = (ctx: ExtensionContext) => {\n    if (!ctx.hasUI) return;\n\n    ctx.ui.setWorkingVisible(true);\n    ctx.ui.setWorkingMessage(renderTurnDuration());\n  };\n\n  const startTurnDuration = (ctx: ExtensionContext) => {\n    clearTurnDurationTimer();\n    turnStartedAt = Date.now();\n    lastTurnDuration = undefined;\n    lastTurnTokensPerSecond = undefined;\n    requestRender();\n    updateTurnDurationDisplay(ctx);\n\n    turnDurationTimer = setInterval(() => {\n      updateTurnDurationDisplay(ctx);\n    }, TURN_DURATION_UPDATE_INTERVAL_MS);\n  };\n\n  const stopTurnDuration = (ctx: ExtensionContext): number | undefined => {\n    if (turnStartedAt === undefined) return undefined;\n\n    lastTurnDuration = Date.now() - turnStartedAt;\n    turnStartedAt = undefined;\n    clearTurnDurationTimer();\n\n    ctx.ui.setWorkingMessage();\n    updateTurnDurationDisplay(ctx);\n    requestRender();\n    return lastTurnDuration;\n  };\n\n  /** Replace the editor with a border-stable wrapper once a TUI is available. */\n  const installStableEditor = (ctx: ExtensionContext) => {\n    if (!ctx.hasUI) return;\n\n    ctx.ui.setEditorComponent((tui, theme, keybindings) => {\n      activeTui = tui;\n      return createBashAwareBorderEditor(\n        tui,\n        theme,\n        keybindings,\n        (text) => ctx.ui.theme.fg(\"borderMuted\", text),\n        (text) => ctx.ui.theme.fg(\"warning\", text),\n        (text) => ctx.ui.theme.fg(\"warning\", text),\n      );\n    });\n  };\n\n  /**\n   * Refresh branch and changed-file count for the dev footer.\n   *\n   * `git status --porcelain=v1` emits one line per changed path, including\n   * staged, unstaged, deleted, renamed, and untracked files.\n   */\n  const refreshGitInfo = async (ctx: ExtensionContext) => {\n    const [branchResult, statusResult] = await Promise.all([\n      pi.exec(\"git\", [\"branch\", \"--show-current\"], { cwd: ctx.cwd }).catch(() => undefined),\n      pi.exec(\"git\", [\"status\", \"--porcelain=v1\"], { cwd: ctx.cwd }).catch(() => undefined),\n    ]);\n\n    const branch = branchResult?.stdout.trim();\n    const changedFiles =\n      statusResult?.stdout.split(\"\\n\").filter((line) => line.trim().length > 0).length ?? 0;\n\n    gitInfo = {\n      branch: branch && branch.length > 0 ? branch : undefined,\n      changedFiles,\n      isRepo: statusResult !== undefined,\n    };\n    requestRender();\n  };\n\n  /** Avoid paying for git status when the dev footer is hidden. */\n  const refreshGitInfoIfVisible = () => {\n    if (mode === \"dev\" && currentCtx) void refreshGitInfo(currentCtx);\n  };\n\n  const applyWorkingIndicator = (ctx: ExtensionContext) => {\n    ctx.ui.setWorkingIndicator({\n      frames: WORKING_SPINNER.frames.map((frame) => ctx.ui.theme.fg(\"accent\", frame)),\n      intervalMs: WORKING_SPINNER.interval,\n    });\n  };\n\n  /** Apply zen/dev UI wiring, including widgets that are only present in dev mode. */\n  const applyMode = (ctx: ExtensionContext, notify = false) => {\n    if (!ctx.hasUI) return;\n\n    applyWorkingIndicator(ctx);\n    ctx.ui.setWorkingVisible(mode === \"dev\");\n\n    ctx.ui.setWidget(\"footer-mode-context-bar\", undefined);\n    ctx.ui.setWidget(\"footer-mode-dev-info\", undefined);\n    ctx.ui.setWidget(\"footer-mode-model-info\", undefined);\n    ctx.ui.setWidget(\"footer-mode-session-title\", undefined);\n\n    if (mode === \"zen\") {\n      ctx.ui.setFooter(createEmptyFooter);\n    } else {\n      void refreshGitInfo(ctx);\n      ctx.ui.setWidget(\"footer-mode-dev-info\", (tui, theme) => {\n        activeTui = tui;\n        return {\n          invalidate() {},\n          render(width: number): string[] {\n            const changeCount = theme.fg(\n              gitInfo.changedFiles > 0 ? \"warning\" : \"dim\",\n              `(${gitInfo.changedFiles}) `,\n            );\n            const branchLabel = gitInfo.isRepo ? (gitInfo.branch ?? \"no branch\") : \"no git\";\n            const branch = theme.fg(\"accent\", branchLabel);\n            const separator = theme.fg(\"dim\", \" · \");\n            const directory = theme.fg(\"dim\", formatCwd(ctx.cwd));\n            const left = changeCount + branch + separator + directory;\n            const displayTitle = pi.getSessionName() ?? sessionTitle;\n            const right = displayTitle ? theme.fg(\"muted\", displayTitle) : \"\";\n            if (!right) return [truncateToWidth(left, width)];\n            const gap = Math.max(1, width - visibleWidth(left) - visibleWidth(right));\n            return [truncateToWidth(left + \" \".repeat(gap) + right, width)];\n          },\n        };\n      });\n\n      ctx.ui.setWidget(\n        \"footer-mode-model-info\",\n        (tui, theme) => {\n          activeTui = tui;\n          return {\n            invalidate() {},\n            render(width: number): string[] {\n              const info = formatModelInfo(pi, currentModel);\n              const speed = lastTurnTokensPerSecond\n                ? theme.fg(\"dim\", `${formatTokensPerSecond(lastTurnTokensPerSecond)} · `)\n                : \"\";\n              const duration = lastTurnDuration\n                ? theme.fg(\"dim\", `took ${formatDuration(lastTurnDuration)} · `)\n                : \"\";\n              const provider = theme.fg(\"dim\", info.provider);\n              const slash = theme.fg(\"dim\", \"/\");\n              const model = theme.fg(\"muted\", info.model);\n              const usagePercent = info.usage?.usedPercent;\n              const usage =\n                usagePercent === undefined\n                  ? \"\"\n                  : usagePercent >= 100\n                    ? theme.fg(\"dim\", \" · resets in \") +\n                      theme.fg(\"error\", formatResetShort(info.usage?.resetAt))\n                    : theme.fg(\"dim\", \" · \") +\n                      (usagePercent >= 80\n                        ? theme.fg(\"error\", `${Math.round(usagePercent)}%`)\n                        : usagePercent >= 50\n                          ? theme.fg(\"warning\", `${Math.round(usagePercent)}%`)\n                          : theme.fg(\"muted\", `${Math.round(usagePercent)}%`));\n              const thinking = info.thinking\n                ? theme.fg(\"dim\", \" · \") +\n                  theme.getThinkingBorderColor(info.thinking)(info.thinking)\n                : \"\";\n              const left = speed + duration + provider + slash + model + usage + thinking;\n              const contextBar = formatContextBar(\n                ctx,\n                currentModel,\n                (text) => theme.fg(\"dim\", text),\n                (percentUsed, text) => {\n                  if (percentUsed >= 90) return theme.fg(\"error\", text);\n                  if (percentUsed >= 70) return theme.fg(\"warning\", text);\n                  return theme.fg(\"accent\", text);\n                },\n              );\n              const gap = Math.max(1, width - visibleWidth(left) - visibleWidth(contextBar));\n              return [truncateToWidth(left + \" \".repeat(gap) + contextBar, width)];\n            },\n          };\n        },\n        { placement: \"belowEditor\" },\n      );\n\n      ctx.ui.setFooter(createEmptyFooter);\n    }\n\n    requestRender();\n    if (notify) ctx.ui.notify(`Footer mode: ${mode}`, \"info\");\n  };\n\n  const setMode = (ctx: ExtensionContext, nextMode: FooterMode, notify = false) => {\n    mode = nextMode;\n    rememberMode();\n    applyMode(ctx, notify);\n  };\n\n  pi.on(\"session_start\", (_event, ctx) => {\n    mode = \"zen\";\n    currentCtx = ctx;\n    currentModel = ctx.model;\n    installStableEditor(ctx);\n    for (const entry of ctx.sessionManager.getEntries()) {\n      if (entry.type !== \"custom\" || entry.customType !== STATE_TYPE) continue;\n      mode = getStoredMode(entry.data) ?? mode;\n    }\n\n    applyMode(ctx);\n  });\n\n  pi.on(\"session_shutdown\", (_event, ctx) => {\n    clearTurnDurationTimer();\n    ctx.ui.setWorkingMessage();\n    ctx.ui.setWorkingIndicator();\n    ctx.ui.setWidget(\"footer-mode-session-title\", undefined);\n    turnStartedAt = undefined;\n    lastTurnDuration = undefined;\n    lastTurnTokensPerSecond = undefined;\n    sessionTitle = undefined;\n    titleGenerationStarted = false;\n    activeTui = undefined;\n    currentCtx = undefined;\n    currentModel = undefined;\n    gitInfo = { changedFiles: 0, isRepo: false };\n  });\n\n  pi.on(\"input\", (_event, ctx) => {\n    startTurnDuration(ctx);\n  });\n\n  pi.on(\"agent_start\", async (_event, ctx) => {\n    requestRender();\n\n    if (titleGenerationStarted || pi.getSessionName()) return;\n\n    const userMessage = getFirstUserMessage(ctx.sessionManager.getBranch());\n    if (!userMessage?.trim()) return;\n\n    // Skip slash commands\n    if (userMessage.trim().startsWith(\"/\")) return;\n\n    const model = currentModel as Model<Api> | undefined;\n    if (!model) return;\n\n    try {\n      const auth = await ctx.modelRegistry.getApiKeyAndHeaders(model);\n      if (!auth?.ok || !auth.apiKey) return;\n\n      titleGenerationStarted = true;\n\n      const response = await complete(\n        model,\n        {\n          messages: [\n            {\n              role: \"user\",\n              content: [\n                {\n                  type: \"text\",\n                  text: `${TITLE_GENERATION_PROMPT}\\n\\n${userMessage.slice(0, 500)}`,\n                },\n              ],\n              timestamp: Date.now(),\n            },\n          ],\n        },\n        { apiKey: auth.apiKey, headers: auth.headers },\n      );\n\n      const title = response.content\n        .filter((c): c is { type: \"text\"; text: string } => c.type === \"text\")\n        .map((c) => c.text)\n        .join(\"\")\n        .trim()\n        .replace(/^[\"']+|[\"']+$/g, \"\")\n        .replace(/[.!?;:]+$/, \"\")\n        .slice(0, MAX_TITLE_LENGTH);\n\n      if (title) {\n        sessionTitle = title;\n        pi.setSessionName(title);\n        if (currentCtx) applyMode(currentCtx);\n        requestRender();\n      }\n    } catch {\n      // Silently fail — the session simply won't get a title\n    } finally {\n      titleGenerationStarted = false;\n    }\n  });\n  pi.on(\"message_update\", requestRender);\n  pi.on(\"message_end\", requestRender);\n  pi.on(\"agent_end\", (event, ctx) => {\n    const elapsed = stopTurnDuration(ctx);\n    const outputTokens = event.messages.reduce((total, message) => {\n      if (message.role !== \"assistant\") return total;\n      return total + (message.usage?.output ?? 0);\n    }, 0);\n\n    lastTurnTokensPerSecond =\n      elapsed && outputTokens > 0 ? outputTokens / (elapsed / 1000) : undefined;\n    refreshGitInfoIfVisible();\n  });\n  pi.on(\"turn_end\", () => {\n    requestRender();\n    refreshGitInfoIfVisible();\n  });\n  pi.on(\"model_select\", (event) => {\n    currentModel = event.model;\n    requestRender();\n  });\n  pi.on(\"thinking_level_select\", requestRender);\n\n  pi.registerShortcut(SHORTCUT, {\n    description: \"Toggle footer mode between zen and dev\",\n    handler: async (ctx) => {\n      setMode(ctx, mode === \"zen\" ? \"dev\" : \"zen\");\n    },\n  });\n\n  pi.registerCommand(\"footer\", {\n    description: `Switch footer mode: /footer [zen|dev|toggle] (${SHORTCUT})`,\n    handler: async (args, ctx) => {\n      const requested = args.trim().toLowerCase();\n\n      if (requested === \"\" || requested === \"toggle\") {\n        setMode(ctx, mode === \"zen\" ? \"dev\" : \"zen\");\n        return;\n      }\n\n      if (isFooterMode(requested)) {\n        setMode(ctx, requested);\n        return;\n      }\n\n      ctx.ui.notify(\"Usage: /footer [zen|dev|toggle]\", \"warning\");\n    },\n  });\n};\n"],"mappings":";;;;;;AAaA,MAAa,eAAe,SAA0B,KAAK,WAAW,CAAC,WAAW,IAAI;;AAGtF,MAAa,uBAAuB,EAClC,MACA,MACA,YACA,YACA,iBAC2C;CAC3C,IAAI,YAAY,KAAK,EAAE,OAAO;CAC9B,IAAI,SAAS,UAAU,YAAY,OAAO;CAC1C,OAAO;;;;ACiBT,MAAM,aAAa;AACnB,MAAM,WAAW;AACjB,MAAM,mCAAmC;AACzC,MAAM,kBAAkB,SAAS;;AAGjC,MAAM,2BAAsC;CAC1C,cAAc,EAAE;CAChB,kBAAkB;CACnB;;;;;;;;AASD,MAAM,+BACJ,KACA,OACA,aACA,YACA,YACA,cACiB;CACjB,MAAM,SAAS,IAAI,aAAa,KAAK;EAAE,GAAG;EAAO,aAAa;EAAY,EAAE,YAAY;CACxF,MAAM,mBAA4B,YAAY,OAAO,SAAS,CAAC;CAC/D,MAAM,uBACJ,oBAAoB;EAClB,MAAM,OAAO,SAAS;EACtB;EACA;EACD,CAAC;CAEJ,MAAM,sBAAsB,OAAO,YAAY,KAAK,OAAO;CAC3D,OAAO,eAAe,SAAuB;EAC3C,oBAAoB,KAAK;EACzB,OAAO,cAAc,gBAAgB;;CAGvC,MAAM,kBAAkB,OAAO,QAAQ,KAAK,OAAO;CACnD,OAAO,WAAW,SAAuB;EACvC,gBAAgB,KAAK;EACrB,OAAO,cAAc,gBAAgB;;CAGvC,MAAM,6BAA6B,OAAO,mBAAmB,KAAK,OAAO;CACzE,OAAO,sBAAsB,SAAuB;EAClD,2BAA2B,KAAK;EAChC,OAAO,cAAc,gBAAgB;;CAGvC,MAAM,iBAAiB,OAAO,OAAO,KAAK,OAAO;CACjD,OAAO,UAAU,UAA4B;EAC3C,OAAO,cAAc,gBAAgB;EACrC,MAAM,QAAQ,eAAe,MAAM;EAEnC,IAAI,CAAC,YAAY,IAAI,MAAM,UAAU,GAAG,OAAO;EAE/C,MAAM,sBAAsB,MAAM,SAAS;EAC3C,OAAO,MAAM,KAAK,MAAM,UAAU;GAEhC,OADuB,UAAU,KAAK,UAAU,sBACxB,OAAO,UAAU,KAAK;IAC9C;;CAGJ,OAAO;;AAGT,MAAM,gBAAgB,UAAwC;CAC5D,OAAO,UAAU,SAAS,UAAU;;AAGtC,MAAM,iBAAiB,SAA0C;CAC/D,IAAI,CAAC,QAAQ,OAAO,SAAS,YAAY,EAAE,UAAU,OAAO,OAAO,KAAA;CACnE,MAAM,QAAS,KAA4B;CAC3C,OAAO,aAAa,MAAM,GAAG,QAAQ,KAAA;;;AAIvC,MAAM,aAAa,QAAwB;CACzC,MAAM,OAAO,QAAQ,IAAI;CACzB,MAAM,UAAU,QAAQ,IAAI,WAAW,KAAK,GAAG,IAAI,IAAI,MAAM,KAAK,OAAO,KAAK;CAC9E,MAAM,QAAQ,QAAQ,MAAM,IAAI,CAAC,OAAO,QAAQ;CAChD,IAAI,QAAQ,WAAW,KAAK,IAAI,MAAM,SAAS,GAAG,OAAO,KAAK,MAAM,MAAM,GAAG,CAAC,KAAK,IAAI;CACvF,IAAI,CAAC,QAAQ,WAAW,IAAI,IAAI,MAAM,SAAS,GAAG,OAAO,KAAK,MAAM,MAAM,GAAG,CAAC,KAAK,IAAI;CACvF,OAAO;;;AAIT,MAAM,oBAAoB,YAAwC;CAChE,IAAI,CAAC,SAAS,OAAO;CAErB,MAAM,UAAU,KAAK,IAAI,GAAG,KAAK,OAAO,UAAU,MAAO,KAAK,KAAK,IAAI,IAAM,CAAC;CAC9E,MAAM,OAAO,KAAK,MAAM,UAAW,KAAS;CAC5C,MAAM,QAAQ,KAAK,MAAO,UAAW,OAAY,GAAG;CACpD,MAAM,OAAO,UAAU;CAEvB,IAAI,OAAO,GAAG,OAAO,GAAG,KAAK,IAAI,MAAM;CACvC,IAAI,QAAQ,GAAG,OAAO,GAAG,MAAM,IAAI,KAAK;CACxC,OAAO,GAAG,KAAK;;AAGjB,MAAM,kBAAkB,OAAuB;CAC7C,MAAM,eAAe,KAAK,MAAM,KAAK,IAAK;CAC1C,MAAM,UAAU,eAAe;CAC/B,MAAM,eAAe,KAAK,MAAM,eAAe,GAAG;CAClD,MAAM,UAAU,eAAe;CAC/B,MAAM,QAAQ,KAAK,MAAM,eAAe,GAAG;CAE3C,IAAI,QAAQ,GAAG,OAAO,GAAG,MAAM,IAAI,QAAQ,IAAI,QAAQ;CACvD,IAAI,UAAU,GAAG,OAAO,GAAG,QAAQ,IAAI,QAAQ;CAC/C,OAAO,GAAG,QAAQ;;AAGpB,MAAM,yBAAyB,oBAAoC;CACjE,IAAI,mBAAmB,KAAK,OAAO,GAAG,KAAK,MAAM,gBAAgB,CAAC;CAClE,OAAO,GAAG,gBAAgB,QAAQ,EAAE,CAAC;;AAGvC,MAAM,yBAAyB,aAA0C;CACvE,OAAO,wBAAwB,KAAK,YAAY,GAAG;;AAGrD,MAAM,uBAAuB,UAA0B;CACrD,MAAM,MAAM,KAAK,IAAI,MAAM;CAC3B,IAAI,OAAO,KAAW,OAAO,GAAG,QAAQ,QAAQ,KAAW,QAAQ,EAAE,CAAC,CAAC;CACvE,IAAI,OAAO,KAAO,OAAO,GAAG,QAAQ,QAAQ,KAAO,QAAQ,EAAE,CAAC,CAAC;CAC/D,OAAO,GAAG,KAAK,MAAM,MAAM;;AAG7B,MAAM,uBAAuB,SAAyB;CACpD,IAAI,QAAQ,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE;CAC1C,IAAI,QAAQ,GAAG,OAAO,IAAI,KAAK,QAAQ,EAAE;CACzC,OAAO,IAAI,KAAK,QAAQ,EAAE;;AAG5B,MAAM,4BACJ,KACA,eACW;CACX,IAAI,QAAQ;CACZ,IAAI,SAAS;CACb,IAAI,OAAO;CAEX,KAAK,MAAM,SAAS,IAAI,eAAe,WAAW,EAAE;EAClD,IAAI,MAAM,SAAS,aAAa,MAAM,QAAQ,SAAS,aAAa;EACpE,SAAS,MAAM,QAAQ,OAAO,SAAS;EACvC,UAAU,MAAM,QAAQ,OAAO,UAAU;EACzC,QAAQ,MAAM,QAAQ,OAAO,MAAM,SAAS;;CAG9C,OAAO,WACL,IAAI,oBAAoB,MAAM,CAAC,IAAI,oBAAoB,OAAO,CAAC,IAAI,oBAAoB,KAAK,GAC7F;;;AAIH,MAAM,oBACJ,KACA,aACA,YACA,aACW;CACX,MAAM,QAAQ,IAAI,iBAAiB;CACnC,MAAM,gBAAgB,OAAO,iBAAiB,aAAa,iBAAiB;CAC5E,MAAM,aAAa,OAAO,UAAU;CACpC,MAAM,cACJ,OAAO,YAAY,gBAAgB,IAAK,aAAa,gBAAiB,MAAM;CAC9E,MAAM,cAAc,yBAAyB,KAAK,WAAW;CAC7D,MAAM,aAAa,GAAG,oBAAoB,WAAW,CAAC,GAAG,oBAAoB,cAAc;CAC3F,MAAM,SAAS,cAAc,WAAW,MAAM,GAAG,WAAW,WAAW,GAAG,WAAW,MAAM;CAE3F,IAAI,gBAAgB,MAAM,OAAO,SAAS,WAAW,kBAAkB;CAEvE,MAAM,cAAc,KAAK,IAAI,GAAG,KAAK,IAAI,KAAK,YAAY,CAAC;CAC3D,MAAM,aAAa;CACnB,MAAM,cAAc,KAAK,MAAO,cAAc,MAAO,WAAW;CAEhE,OAAO,SAAS,SAAS,aAAa,IAAI,GAD3B,IAAI,OAAO,YAAY,GAAG,IAAI,OAAO,aAAa,YAAY,GAC/B,IAAI,KAAK,MAAM,YAAY,CAAC,GAAG;;;AAI/E,MAAM,mBACJ,IACA,gBAMG;CACH,MAAM,WAAW,aAAa,YAAY;CAC1C,MAAM,QAAQ,aAAa,MAAM;CACjC,MAAM,WAAW,GAAG,kBAAkB;CACtC,MAAM,aAAa,WAAW;CAC9B,OAAO;EACL;EACA;EACA,UAAU,aAAa,QAAQ,KAAA,IAAY;EAC3C,OACE,sBAAsB,SAAS,IAAI,YAAY,aAAa,WACxD,WAAW,WACX,KAAA;EACP;;AAGH,MAAM,0BACJ;AAEF,MAAM,mBAAmB;;AAGzB,MAAM,uBACJ,YACuB;CACvB,KAAK,MAAM,SAAS,SAAS;EAC3B,IAAI,MAAM,SAAS,aAAa,MAAM,SAAS,SAAS,QAAQ;EAChE,MAAM,UAAU,MAAM,QAAQ;EAC9B,IAAI,OAAO,YAAY,UAAU,OAAO;EACxC,IAAI,CAAC,MAAM,QAAQ,QAAQ,EAAE;EAC7B,KAAK,MAAM,SAAS,SAClB,IACE,SACA,OAAO,UAAU,YACjB,MAAM,SAAS,UACf,OAAO,MAAM,SAAS,UAEtB,OAAO,MAAM;;;AAMrB,IAAA,uBAAgB,OAA2B;CACzC,IAAI,OAAmB;CACvB,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI,UAAmB;EAAE,cAAc;EAAG,QAAQ;EAAO;CACzD,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI,yBAAyB;CAE7B,MAAM,qBAAqB;EACzB,GAAG,YAAY,YAAY,EAAE,MAAM,CAAC;;CAGtC,MAAM,sBAAsB;EAC1B,WAAW,eAAe;;CAG5B,MAAM,+BAA+B;EACnC,IAAI,CAAC,mBAAmB;EACxB,cAAc,kBAAkB;EAChC,oBAAoB,KAAA;;CAGtB,MAAM,2BAA2B;EAC/B,MAAM,UAAU,gBAAgB,KAAK,KAAK,GAAG,gBAAgB;EAC7D,OAAO,YAAY,KAAA,IAAY,KAAK,eAAe,QAAQ;;CAG7D,MAAM,6BAA6B,QAA0B;EAC3D,IAAI,CAAC,IAAI,OAAO;EAEhB,IAAI,GAAG,kBAAkB,KAAK;EAC9B,IAAI,GAAG,kBAAkB,oBAAoB,CAAC;;CAGhD,MAAM,qBAAqB,QAA0B;EACnD,wBAAwB;EACxB,gBAAgB,KAAK,KAAK;EAC1B,mBAAmB,KAAA;EACnB,0BAA0B,KAAA;EAC1B,eAAe;EACf,0BAA0B,IAAI;EAE9B,oBAAoB,kBAAkB;GACpC,0BAA0B,IAAI;KAC7B,iCAAiC;;CAGtC,MAAM,oBAAoB,QAA8C;EACtE,IAAI,kBAAkB,KAAA,GAAW,OAAO,KAAA;EAExC,mBAAmB,KAAK,KAAK,GAAG;EAChC,gBAAgB,KAAA;EAChB,wBAAwB;EAExB,IAAI,GAAG,mBAAmB;EAC1B,0BAA0B,IAAI;EAC9B,eAAe;EACf,OAAO;;;CAIT,MAAM,uBAAuB,QAA0B;EACrD,IAAI,CAAC,IAAI,OAAO;EAEhB,IAAI,GAAG,oBAAoB,KAAK,OAAO,gBAAgB;GACrD,YAAY;GACZ,OAAO,4BACL,KACA,OACA,cACC,SAAS,IAAI,GAAG,MAAM,GAAG,eAAe,KAAK,GAC7C,SAAS,IAAI,GAAG,MAAM,GAAG,WAAW,KAAK,GACzC,SAAS,IAAI,GAAG,MAAM,GAAG,WAAW,KAAK,CAC3C;IACD;;;;;;;;CASJ,MAAM,iBAAiB,OAAO,QAA0B;EACtD,MAAM,CAAC,cAAc,gBAAgB,MAAM,QAAQ,IAAI,CACrD,GAAG,KAAK,OAAO,CAAC,UAAU,iBAAiB,EAAE,EAAE,KAAK,IAAI,KAAK,CAAC,CAAC,YAAY,KAAA,EAAU,EACrF,GAAG,KAAK,OAAO,CAAC,UAAU,iBAAiB,EAAE,EAAE,KAAK,IAAI,KAAK,CAAC,CAAC,YAAY,KAAA,EAAU,CACtF,CAAC;EAEF,MAAM,SAAS,cAAc,OAAO,MAAM;EAC1C,MAAM,eACJ,cAAc,OAAO,MAAM,KAAK,CAAC,QAAQ,SAAS,KAAK,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU;EAEtF,UAAU;GACR,QAAQ,UAAU,OAAO,SAAS,IAAI,SAAS,KAAA;GAC/C;GACA,QAAQ,iBAAiB,KAAA;GAC1B;EACD,eAAe;;;CAIjB,MAAM,gCAAgC;EACpC,IAAI,SAAS,SAAS,YAAY,eAAoB,WAAW;;CAGnE,MAAM,yBAAyB,QAA0B;EACvD,IAAI,GAAG,oBAAoB;GACzB,QAAQ,gBAAgB,OAAO,KAAK,UAAU,IAAI,GAAG,MAAM,GAAG,UAAU,MAAM,CAAC;GAC/E,YAAY,gBAAgB;GAC7B,CAAC;;;CAIJ,MAAM,aAAa,KAAuB,SAAS,UAAU;EAC3D,IAAI,CAAC,IAAI,OAAO;EAEhB,sBAAsB,IAAI;EAC1B,IAAI,GAAG,kBAAkB,SAAS,MAAM;EAExC,IAAI,GAAG,UAAU,2BAA2B,KAAA,EAAU;EACtD,IAAI,GAAG,UAAU,wBAAwB,KAAA,EAAU;EACnD,IAAI,GAAG,UAAU,0BAA0B,KAAA,EAAU;EACrD,IAAI,GAAG,UAAU,6BAA6B,KAAA,EAAU;EAExD,IAAI,SAAS,OACX,IAAI,GAAG,UAAU,kBAAkB;OAC9B;GACL,eAAoB,IAAI;GACxB,IAAI,GAAG,UAAU,yBAAyB,KAAK,UAAU;IACvD,YAAY;IACZ,OAAO;KACL,aAAa;KACb,OAAO,OAAyB;MAC9B,MAAM,cAAc,MAAM,GACxB,QAAQ,eAAe,IAAI,YAAY,OACvC,IAAI,QAAQ,aAAa,IAC1B;MACD,MAAM,cAAc,QAAQ,SAAU,QAAQ,UAAU,cAAe;MACvE,MAAM,SAAS,MAAM,GAAG,UAAU,YAAY;MAC9C,MAAM,YAAY,MAAM,GAAG,OAAO,MAAM;MACxC,MAAM,YAAY,MAAM,GAAG,OAAO,UAAU,IAAI,IAAI,CAAC;MACrD,MAAM,OAAO,cAAc,SAAS,YAAY;MAChD,MAAM,eAAe,GAAG,gBAAgB,IAAI;MAC5C,MAAM,QAAQ,eAAe,MAAM,GAAG,SAAS,aAAa,GAAG;MAC/D,IAAI,CAAC,OAAO,OAAO,CAAC,gBAAgB,MAAM,MAAM,CAAC;MACjD,MAAM,MAAM,KAAK,IAAI,GAAG,QAAQ,aAAa,KAAK,GAAG,aAAa,MAAM,CAAC;MACzE,OAAO,CAAC,gBAAgB,OAAO,IAAI,OAAO,IAAI,GAAG,OAAO,MAAM,CAAC;;KAElE;KACD;GAEF,IAAI,GAAG,UACL,2BACC,KAAK,UAAU;IACd,YAAY;IACZ,OAAO;KACL,aAAa;KACb,OAAO,OAAyB;MAC9B,MAAM,OAAO,gBAAgB,IAAI,aAAa;MAC9C,MAAM,QAAQ,0BACV,MAAM,GAAG,OAAO,GAAG,sBAAsB,wBAAwB,CAAC,KAAK,GACvE;MACJ,MAAM,WAAW,mBACb,MAAM,GAAG,OAAO,QAAQ,eAAe,iBAAiB,CAAC,KAAK,GAC9D;MACJ,MAAM,WAAW,MAAM,GAAG,OAAO,KAAK,SAAS;MAC/C,MAAM,QAAQ,MAAM,GAAG,OAAO,IAAI;MAClC,MAAM,QAAQ,MAAM,GAAG,SAAS,KAAK,MAAM;MAC3C,MAAM,eAAe,KAAK,OAAO;MACjC,MAAM,QACJ,iBAAiB,KAAA,IACb,KACA,gBAAgB,MACd,MAAM,GAAG,OAAO,gBAAgB,GAChC,MAAM,GAAG,SAAS,iBAAiB,KAAK,OAAO,QAAQ,CAAC,GACxD,MAAM,GAAG,OAAO,MAAM,IACrB,gBAAgB,KACb,MAAM,GAAG,SAAS,GAAG,KAAK,MAAM,aAAa,CAAC,GAAG,GACjD,gBAAgB,KACd,MAAM,GAAG,WAAW,GAAG,KAAK,MAAM,aAAa,CAAC,GAAG,GACnD,MAAM,GAAG,SAAS,GAAG,KAAK,MAAM,aAAa,CAAC,GAAG;MAC/D,MAAM,WAAW,KAAK,WAClB,MAAM,GAAG,OAAO,MAAM,GACtB,MAAM,uBAAuB,KAAK,SAAS,CAAC,KAAK,SAAS,GAC1D;MACJ,MAAM,OAAO,QAAQ,WAAW,WAAW,QAAQ,QAAQ,QAAQ;MACnE,MAAM,aAAa,iBACjB,KACA,eACC,SAAS,MAAM,GAAG,OAAO,KAAK,GAC9B,aAAa,SAAS;OACrB,IAAI,eAAe,IAAI,OAAO,MAAM,GAAG,SAAS,KAAK;OACrD,IAAI,eAAe,IAAI,OAAO,MAAM,GAAG,WAAW,KAAK;OACvD,OAAO,MAAM,GAAG,UAAU,KAAK;QAElC;MACD,MAAM,MAAM,KAAK,IAAI,GAAG,QAAQ,aAAa,KAAK,GAAG,aAAa,WAAW,CAAC;MAC9E,OAAO,CAAC,gBAAgB,OAAO,IAAI,OAAO,IAAI,GAAG,YAAY,MAAM,CAAC;;KAEvE;MAEH,EAAE,WAAW,eAAe,CAC7B;GAED,IAAI,GAAG,UAAU,kBAAkB;;EAGrC,eAAe;EACf,IAAI,QAAQ,IAAI,GAAG,OAAO,gBAAgB,QAAQ,OAAO;;CAG3D,MAAM,WAAW,KAAuB,UAAsB,SAAS,UAAU;EAC/E,OAAO;EACP,cAAc;EACd,UAAU,KAAK,OAAO;;CAGxB,GAAG,GAAG,kBAAkB,QAAQ,QAAQ;EACtC,OAAO;EACP,aAAa;EACb,eAAe,IAAI;EACnB,oBAAoB,IAAI;EACxB,KAAK,MAAM,SAAS,IAAI,eAAe,YAAY,EAAE;GACnD,IAAI,MAAM,SAAS,YAAY,MAAM,eAAe,YAAY;GAChE,OAAO,cAAc,MAAM,KAAK,IAAI;;EAGtC,UAAU,IAAI;GACd;CAEF,GAAG,GAAG,qBAAqB,QAAQ,QAAQ;EACzC,wBAAwB;EACxB,IAAI,GAAG,mBAAmB;EAC1B,IAAI,GAAG,qBAAqB;EAC5B,IAAI,GAAG,UAAU,6BAA6B,KAAA,EAAU;EACxD,gBAAgB,KAAA;EAChB,mBAAmB,KAAA;EACnB,0BAA0B,KAAA;EAC1B,eAAe,KAAA;EACf,yBAAyB;EACzB,YAAY,KAAA;EACZ,aAAa,KAAA;EACb,eAAe,KAAA;EACf,UAAU;GAAE,cAAc;GAAG,QAAQ;GAAO;GAC5C;CAEF,GAAG,GAAG,UAAU,QAAQ,QAAQ;EAC9B,kBAAkB,IAAI;GACtB;CAEF,GAAG,GAAG,eAAe,OAAO,QAAQ,QAAQ;EAC1C,eAAe;EAEf,IAAI,0BAA0B,GAAG,gBAAgB,EAAE;EAEnD,MAAM,cAAc,oBAAoB,IAAI,eAAe,WAAW,CAAC;EACvE,IAAI,CAAC,aAAa,MAAM,EAAE;EAG1B,IAAI,YAAY,MAAM,CAAC,WAAW,IAAI,EAAE;EAExC,MAAM,QAAQ;EACd,IAAI,CAAC,OAAO;EAEZ,IAAI;GACF,MAAM,OAAO,MAAM,IAAI,cAAc,oBAAoB,MAAM;GAC/D,IAAI,CAAC,MAAM,MAAM,CAAC,KAAK,QAAQ;GAE/B,yBAAyB;GAqBzB,MAAM,SAAQ,MAnBS,SACrB,OACA,EACE,UAAU,CACR;IACE,MAAM;IACN,SAAS,CACP;KACE,MAAM;KACN,MAAM,GAAG,wBAAwB,MAAM,YAAY,MAAM,GAAG,IAAI;KACjE,CACF;IACD,WAAW,KAAK,KAAK;IACtB,CACF,EACF,EACD;IAAE,QAAQ,KAAK;IAAQ,SAAS,KAAK;IAAS,CAC/C,EAEsB,QACpB,QAAQ,MAA2C,EAAE,SAAS,OAAO,CACrE,KAAK,MAAM,EAAE,KAAK,CAClB,KAAK,GAAG,CACR,MAAM,CACN,QAAQ,kBAAkB,GAAG,CAC7B,QAAQ,aAAa,GAAG,CACxB,MAAM,GAAG,iBAAiB;GAE7B,IAAI,OAAO;IACT,eAAe;IACf,GAAG,eAAe,MAAM;IACxB,IAAI,YAAY,UAAU,WAAW;IACrC,eAAe;;UAEX,WAEE;GACR,yBAAyB;;GAE3B;CACF,GAAG,GAAG,kBAAkB,cAAc;CACtC,GAAG,GAAG,eAAe,cAAc;CACnC,GAAG,GAAG,cAAc,OAAO,QAAQ;EACjC,MAAM,UAAU,iBAAiB,IAAI;EACrC,MAAM,eAAe,MAAM,SAAS,QAAQ,OAAO,YAAY;GAC7D,IAAI,QAAQ,SAAS,aAAa,OAAO;GACzC,OAAO,SAAS,QAAQ,OAAO,UAAU;KACxC,EAAE;EAEL,0BACE,WAAW,eAAe,IAAI,gBAAgB,UAAU,OAAQ,KAAA;EAClE,yBAAyB;GACzB;CACF,GAAG,GAAG,kBAAkB;EACtB,eAAe;EACf,yBAAyB;GACzB;CACF,GAAG,GAAG,iBAAiB,UAAU;EAC/B,eAAe,MAAM;EACrB,eAAe;GACf;CACF,GAAG,GAAG,yBAAyB,cAAc;CAE7C,GAAG,iBAAiB,UAAU;EAC5B,aAAa;EACb,SAAS,OAAO,QAAQ;GACtB,QAAQ,KAAK,SAAS,QAAQ,QAAQ,MAAM;;EAE/C,CAAC;CAEF,GAAG,gBAAgB,UAAU;EAC3B,aAAa,iDAAiD,SAAS;EACvE,SAAS,OAAO,MAAM,QAAQ;GAC5B,MAAM,YAAY,KAAK,MAAM,CAAC,aAAa;GAE3C,IAAI,cAAc,MAAM,cAAc,UAAU;IAC9C,QAAQ,KAAK,SAAS,QAAQ,QAAQ,MAAM;IAC5C;;GAGF,IAAI,aAAa,UAAU,EAAE;IAC3B,QAAQ,KAAK,UAAU;IACvB;;GAGF,IAAI,GAAG,OAAO,mCAAmC,UAAU;;EAE9D,CAAC"}