{"version":3,"file":"mcpOverlay-DpLcSgu0.mjs","names":[],"sources":["../src/tui/mcpOverlay.ts"],"sourcesContent":["/**\n * MCP browser: the `SPC e m` overlay.\n *\n * A roster of this session's MCP servers on the left, and on the right what the\n * selected one offers plus the controls that act on it. It replaces a `/mcp status`\n * text blob that could be read but not acted on.\n *\n * DESIGN PATTERNS:\n * - Controls always list every action, unavailable ones dimmed rather than hidden,\n *   so the key map never shifts under the user\n * - Every collaborator arrives through `McpOverlayTarget`, so the component renders\n *   and dispatches in a test with no terminal and no session behind it\n *\n * The roster stays a flat list and the detail pane a tab strip rather than a second\n * navigation level: selection is one index, and every row is assertable as a string.\n *\n * Repainting is driven by `target.onChange`, not a timer. Servers connect on their\n * own schedule and the session already announces each one as it folds in, so a poll\n * here would only be sampling an event that had already fired.\n *\n * Disabling is a visibility control, not a permission boundary: Pi 0.84 cannot\n * unregister a tool, so a disabled server's tools leave the active list but stay\n * registered and callable. `DirectToolFilter` has the same property.\n */\n\nimport {\n  DOOM_FULLSCREEN_UI_OPTIONS,\n  DOOM_NAVIGATION_KEYS,\n  DOOM_OVERLAY_ACCENT,\n  DoomOverlay,\n  type DoomOverlayChrome,\n  type DoomOverlayTui,\n} from '@agimon-ai/doompi-ui/doomOverlay';\nimport type { ExtensionContext, Theme } from '@earendil-works/pi-coding-agent';\nimport { Key, matchesKey, truncateToWidth, visibleWidth } from '@earendil-works/pi-tui';\n\nimport type { McpOverlayTarget, McpResourceView, McpServerView } from '../types/mcp';\n\nconst TITLE = 'MCP';\nconst BREADCRUMB = 'SPC › e / m · mcp';\n/**\n * Ordered by what a user reaches for first, because the chrome drops trailing\n * hints rather than shrinking them when the terminal is narrow.\n *\n * Scrolling earns a slot: a long tool list is the common case (the proxy alone\n * carries twelve), and without a legend entry the keys that reach the rest of it\n * are undiscoverable.\n */\nconst HINTS: readonly (readonly [string, string])[] = [\n  [DOOM_NAVIGATION_KEYS.list, 'server'],\n  [DOOM_NAVIGATION_KEYS.detail, 'scroll'],\n  ['tab', 'pane'],\n  ['a', 'auth'],\n  ['d', 'disable'],\n  ['e', 'enable'],\n  ['r', 'reload'],\n  ['esc', 'close'],\n];\n/** Derived so the plain-text fallback cannot drift from the caps above it. */\nconst FOOTER_FALLBACK = HINTS.map(([key, label]) => `${key} ${label}`).join(' · ');\n/** Matches the chrome's spacing between footer caps, so both legends read alike. */\nconst CAP_SEPARATOR = '   ';\n\nconst MIN_WIDTH = 48;\n/** A third for the roster, two thirds for what the server offers. */\nconst ROSTER_PANE_RATIO = 1 / 3;\nconst PANE_GUTTER = 1;\nconst MIN_PANE_WIDTH = 18;\nconst ELLIPSIS = '…';\nconst LABEL_COLUMN = 10;\nconst FIELD_FALLBACK = '—';\nconst EMPTY_MESSAGE = 'No MCP servers are configured for this session.';\nconst TOOL_INDENT = '  ';\nconst OSC_LINK_OPEN = '\\u001B]8;;';\nconst OSC_LINK_SEPARATOR = '\\u0007';\nconst OSC_LINK_CLOSE = `${OSC_LINK_OPEN}${OSC_LINK_SEPARATOR}`;\n\nexport type McpDetailTab = 'tools' | 'resources';\nconst DETAIL_TABS: readonly McpDetailTab[] = ['tools', 'resources'];\n\ntype McpActionName = 'auth' | 'disable' | 'enable';\n\nconst CONTROL_ORDER: readonly McpActionName[] = ['auth', 'disable', 'enable'];\nconst CONTROL_KEY: Record<McpActionName, string> = { auth: 'a', disable: 'd', enable: 'e' };\n/** Short qualifier where the verb alone would understate what the key does. */\nconst CONTROL_HINT: Record<McpActionName, string | undefined> = {\n  auth: 'reconnect',\n  disable: 'session',\n  enable: undefined,\n};\nconst CONTROL_BY_KEY = new Map<string, McpActionName>(CONTROL_ORDER.map((action) => [CONTROL_KEY[action], action]));\n\n/**\n * What each control can do to a server in its current condition.\n *\n * `auth` reconnects wherever that is meaningful, including a server that has not\n * been dialled yet. Mid-connect it is withheld until the flow has a reserved URL;\n * from then on the same key safely reopens that page without reconnecting.\n */\nfunction controlAvailability(server: McpServerView | undefined): Record<McpActionName, boolean> {\n  if (!server) return { auth: false, disable: false, enable: false };\n  if (!server.enabled) return { auth: false, disable: false, enable: true };\n  return { auth: server.authorizationUrl !== undefined || server.state !== 'connecting', disable: true, enable: false };\n}\n\nfunction unavailableReason(action: McpActionName, server: McpServerView | undefined): string {\n  if (!server) return `${action} unavailable · no server is selected`;\n  if (!server.enabled) return `${action} unavailable · ${server.name} is disabled for this session`;\n  if (action === 'enable') return `enable unavailable · ${server.name} is already enabled`;\n  return `${action} unavailable · ${server.name} is ${server.state}`;\n}\n\nfunction statusGlyph(server: McpServerView, theme: Theme): string {\n  if (!server.enabled) return theme.fg('dim', '■');\n  if (server.state === 'connected') return theme.fg('success', '●');\n  if (server.state === 'connecting') return theme.fg('accent', '◐');\n  if (server.state === 'degraded') return theme.fg('warning', '▲');\n  if (server.state === 'needs-auth') return theme.fg('warning', '✗');\n  if (server.state === 'failed') return theme.fg('error', '✗');\n  return theme.fg('muted', '◦');\n}\n\n/** What the roster row and the detail header both call the server's condition. */\nfunction stateLabel(server: McpServerView): string {\n  return server.enabled ? server.state : 'disabled';\n}\n\nfunction fit(text: string, width: number): string {\n  const clipped = truncateToWidth(text, Math.max(0, width), ELLIPSIS);\n  return clipped + ' '.repeat(Math.max(0, width - visibleWidth(clipped)));\n}\n\nfunction rightAligned(left: string, right: string, width: number): string {\n  const rightWidth = visibleWidth(right);\n  const leftWidth = Math.max(0, width - rightWidth - 1);\n  return fit(left, leftWidth) + ' '.repeat(Math.max(1, width - leftWidth - rightWidth)) + fit(right, rightWidth);\n}\n\nfunction wrap(text: string, width: number): string[] {\n  if (width <= 0) return [];\n  const lines: string[] = [];\n  let current = '';\n  for (const word of text.split(/\\s+/).filter(Boolean)) {\n    if (current.length === 0) current = word;\n    else if (current.length + 1 + word.length <= width) current += ` ${word}`;\n    else {\n      lines.push(current);\n      current = word;\n    }\n  }\n  if (current.length > 0) lines.push(current);\n  return lines;\n}\n\n/** A compact clickable fallback whose visible width does not include its target URL. */\nfunction terminalLink(label: string, url: string): string {\n  return `${OSC_LINK_OPEN}${url}${OSC_LINK_SEPARATOR}${label}${OSC_LINK_CLOSE}`;\n}\n\n/** What the resources pane knows about one server. Absent until the pane asks. */\ninterface ResourcePane {\n  status: 'loading' | 'ready' | 'error';\n  items?: readonly McpResourceView[];\n  error?: string;\n}\n\nexport class McpOverlayComponent extends DoomOverlay {\n  private servers: readonly McpServerView[] = [];\n  private selected = 0;\n  private selectedName: string | undefined;\n  private detailTab: McpDetailTab = 'tools';\n  private detailScroll = 0;\n  private detailLineCount = 0;\n  private detailViewportHeight = 8;\n  private bodyHeight = 8;\n  private actionNotice: string | undefined;\n  private disposed = false;\n  private readonly resourcePanes = new Map<string, ResourcePane>();\n  private readonly unsubscribe: () => void;\n\n  constructor(\n    tui: DoomOverlayTui,\n    theme: Theme,\n    private readonly target: McpOverlayTarget,\n    private readonly done: (result: undefined) => void,\n  ) {\n    super(tui, theme);\n    this.refresh();\n    this.unsubscribe = this.target.onChange(() => {\n      if (this.disposed) return;\n      this.refresh();\n      // A flow that has surfaced its URL is no longer dispatching. Explicit auth\n      // opens it automatically, while the same key now reopens the reserved page.\n      const server = this.current();\n      if (server?.authorizationUrl) this.actionNotice = `auth ${server.name} · page ready · a reopens browser`;\n      this.tui.requestRender();\n    });\n  }\n\n  dispose(): void {\n    this.disposed = true;\n    this.unsubscribe();\n  }\n\n  /** Re-reads the roster, keeping the cursor on the server it was already on. */\n  private refresh(): void {\n    const previousName = this.servers[this.selected]?.name ?? this.selectedName;\n    this.servers = this.target.getServers();\n    const preserved = previousName ? this.servers.findIndex((server) => server.name === previousName) : -1;\n    this.selected = preserved >= 0 ? preserved : Math.min(this.selected, Math.max(0, this.servers.length - 1));\n    this.selectedName = this.servers[this.selected]?.name;\n  }\n\n  private current(): McpServerView | undefined {\n    return this.servers[this.selected];\n  }\n\n  handleInput(data: string): void {\n    if (matchesKey(data, 'escape') || matchesKey(data, 'ctrl+c') || matchesKey(data, 'q')) {\n      this.done(undefined);\n      return;\n    }\n    if (matchesKey(data, Key.shift('k'))) {\n      this.scrollDetail(-1);\n      return;\n    }\n    if (matchesKey(data, Key.shift('j'))) {\n      this.scrollDetail(1);\n      return;\n    }\n    if (matchesKey(data, 'up') || matchesKey(data, 'k')) {\n      this.moveSelection(-1);\n      return;\n    }\n    if (matchesKey(data, 'down') || matchesKey(data, 'j')) {\n      this.moveSelection(1);\n      return;\n    }\n    if (matchesKey(data, 'pageUp')) {\n      this.scrollDetail(-this.detailViewportHeight);\n      return;\n    }\n    if (matchesKey(data, 'pageDown')) {\n      this.scrollDetail(this.detailViewportHeight);\n      return;\n    }\n    if (matchesKey(data, 'tab')) {\n      this.toggleTab();\n      return;\n    }\n    // Checked before the single-letter controls: ctrl+r is the deliberate path that\n    // discards what a server said about its resources and asks again.\n    if (matchesKey(data, 'ctrl+r')) {\n      this.loadResources({ refresh: true });\n      return;\n    }\n    if (matchesKey(data, 'r')) {\n      this.reload();\n      return;\n    }\n    const action = CONTROL_BY_KEY.get(data.toLowerCase());\n    if (action) this.triggerControl(action);\n  }\n\n  private moveSelection(delta: number): void {\n    if (this.servers.length === 0) return;\n    this.selected = Math.max(0, Math.min(this.servers.length - 1, this.selected + delta));\n    this.selectedName = this.servers[this.selected]?.name;\n    this.detailScroll = 0;\n    this.maybeLoadResources();\n    this.tui.requestRender();\n  }\n\n  private scrollDetail(delta: number): void {\n    const maxScroll = Math.max(0, this.detailLineCount - this.detailViewportHeight);\n    this.detailScroll = Math.max(0, Math.min(maxScroll, this.detailScroll + delta));\n    this.tui.requestRender();\n  }\n\n  private toggleTab(): void {\n    this.detailTab = this.detailTab === 'tools' ? 'resources' : 'tools';\n    this.detailScroll = 0;\n    this.maybeLoadResources();\n    this.tui.requestRender();\n  }\n\n  private reload(): void {\n    this.setNotice('reload · dispatching…');\n    // Not awaited: a server that never answers must not wedge the overlay. The\n    // roster repaints through onChange as each one lands.\n    void this.target\n      .start()\n      .then(() => {\n        if (!this.disposed) this.setNotice('reload · reconnecting');\n      })\n      .catch((cause: unknown) => {\n        if (!this.disposed) this.setNotice(`reload · failed · ${message(cause)}`);\n      });\n  }\n\n  /**\n   * Lists the selected server's resources, but only where a listing is meaningful.\n   *\n   * A server that has not connected is left alone: turning a `tab` keypress into a\n   * silent dial-out is not what switching panes should mean.\n   */\n  private maybeLoadResources(): void {\n    if (this.detailTab !== 'resources') return;\n    const server = this.current();\n    if (!server || !server.enabled || server.state !== 'connected') return;\n    if (this.resourcePanes.has(server.name)) return;\n    this.loadResources();\n  }\n\n  private loadResources(options: { refresh?: boolean } = {}): void {\n    const server = this.current();\n    if (!server) return;\n    this.resourcePanes.set(server.name, { status: 'loading' });\n    this.tui.requestRender();\n    void this.target\n      .listResources(server.name, options)\n      .then((items) => {\n        if (this.disposed) return;\n        this.resourcePanes.set(server.name, { status: 'ready', items });\n        this.tui.requestRender();\n      })\n      .catch((cause: unknown) => {\n        if (this.disposed) return;\n        this.resourcePanes.set(server.name, { status: 'error', error: message(cause) });\n        this.tui.requestRender();\n      });\n  }\n\n  private triggerControl(action: McpActionName): void {\n    const server = this.current();\n    if (!controlAvailability(server)[action]) {\n      this.setNotice(unavailableReason(action, server));\n      return;\n    }\n    if (!server) return;\n    if (action === 'auth') {\n      if (server.authorizationUrl) void this.openAuthorizationPage(server.name);\n      else void this.authorize(server.name);\n      return;\n    }\n    const enabled = action === 'enable';\n    try {\n      this.target.setEnabled(server.name, enabled);\n      this.refresh();\n      this.setNotice(`${action} ${server.name} · ${enabled ? 'tools restored' : 'tools withheld for this session'}`);\n    } catch (cause) {\n      this.setNotice(`${action} ${server.name} · failed · ${message(cause)}`);\n    }\n  }\n\n  private async authorize(serverName: string): Promise<void> {\n    this.setNotice(`auth ${serverName} · dispatching…`);\n    try {\n      await this.target.reauthorize(serverName);\n      if (this.disposed) return;\n      // The listing is about whatever the reconnect just settled on.\n      this.resourcePanes.delete(serverName);\n      this.refresh();\n      this.setNotice(`auth ${serverName} · authorized`);\n    } catch (cause) {\n      if (this.disposed) return;\n      this.setNotice(`auth ${serverName} · failed · ${message(cause)}`);\n    }\n  }\n\n  private async openAuthorizationPage(serverName: string): Promise<void> {\n    this.setNotice(`auth ${serverName} · opening browser…`);\n    try {\n      await this.target.openAuthorizationPage(serverName);\n      if (!this.disposed) this.setNotice(`auth ${serverName} · browser opened · waiting for approval`);\n    } catch (cause) {\n      if (!this.disposed) this.setNotice(`auth ${serverName} · browser failed · ${message(cause)}`);\n    }\n  }\n\n  private setNotice(notice: string): void {\n    this.actionNotice = notice;\n    this.tui.requestRender();\n  }\n\n  private rosterLines(width: number): string[] {\n    if (this.servers.length === 0) return [this.theme.fg('dim', 'No servers')];\n    const start = Math.max(\n      0,\n      Math.min(this.selected - this.bodyHeight + 1, Math.max(0, this.servers.length - this.bodyHeight)),\n    );\n    return this.servers.slice(start, start + this.bodyHeight).map((server, offset) => {\n      const index = start + offset;\n      const marker = index === this.selected ? this.theme.fg('accent', '›') : ' ';\n      // Dimming a disabled server states in the roster what the detail pane would\n      // otherwise have to be visited to learn.\n      const name = server.enabled\n        ? index === this.selected\n          ? this.theme.bold(server.name)\n          : server.name\n        : this.theme.fg('dim', server.name);\n      const left = `${marker} ${statusGlyph(server, this.theme)} ${name}`;\n      return rightAligned(left, this.theme.fg('dim', stateLabel(server)), width);\n    });\n  }\n\n  /**\n   * A single-line fallback for the page that explicit auth already opened.\n   *\n   * The full URL lives in an OSC 8 target rather than printable layout cells, so a\n   * long OAuth state token cannot wrap through pane borders and become corrupted.\n   * Terminals without clickable links still have the same `a` key to reopen it.\n   */\n  private authorizationLines(url: string, width: number): string[] {\n    return [\n      this.theme.fg('accent', fit(`${TOOL_INDENT}Authorization page ready`, width)),\n      this.theme.fg('text', fit(`${TOOL_INDENT}${terminalLink('Open authorization page', url)} · a reopens`, width)),\n    ];\n  }\n\n  private field(label: string, value: string, width: number): string[] {\n    const valueWidth = Math.max(1, width - LABEL_COLUMN);\n    return wrap(value, valueWidth).map(\n      (line, index) => `${this.theme.fg('dim', fit(index === 0 ? label : '', LABEL_COLUMN))}${fit(line, valueWidth)}`,\n    );\n  }\n\n  /**\n   * Runtime controls as filled key caps, matching the footer legend.\n   *\n   * Every action is always listed; an unavailable one loses its cap fill rather\n   * than its place, so the key map never shifts under the user and a control that\n   * cannot act still reads as a key rather than as prose.\n   */\n  private controlLine(server: McpServerView | undefined, width: number): string {\n    const availability = controlAvailability(server);\n    const parts = CONTROL_ORDER.map((action) => {\n      const hint = action === 'auth' && server?.authorizationUrl ? 'reopen' : CONTROL_HINT[action];\n      const label = `${action}${hint ? ` (${hint})` : ''}`;\n      return this.keyCap(CONTROL_KEY[action], label, availability[action]);\n    });\n    return truncateToWidth(`  ${parts.join(CAP_SEPARATOR)}`, width);\n  }\n\n  /** One filled key cap and its label. Unfilled when the key would do nothing. */\n  private keyCap(key: string, label: string, enabled = true): string {\n    const cap = enabled\n      ? this.theme.bg('selectedBg', this.theme.fg('text', ` ${key} `))\n      : this.theme.fg('dim', ` ${key} `);\n    return `${cap}${this.theme.fg('dim', ` ${label}`)}`;\n  }\n\n  private tabStrip(server: McpServerView | undefined, width: number): string {\n    const label = (name: McpDetailTab): string =>\n      name === this.detailTab\n        ? this.theme.fg('accent', this.theme.bold(`[ ${name} ]`))\n        : this.theme.fg('dim', `  ${name}  `);\n    const counts =\n      server && this.detailTab === 'tools'\n        ? `${server.tools.filter((tool) => tool.active).length}/${server.tools.length}`\n        : 'ctrl+r refresh';\n    return rightAligned(`  ${DETAIL_TABS.map(label).join('')}`, this.theme.fg('dim', counts), width);\n  }\n\n  private toolLines(server: McpServerView, width: number): string[] {\n    if (server.tools.length === 0) return [this.theme.fg('dim', `${TOOL_INDENT}No tools`)];\n    const lines: string[] = [];\n    for (const tool of server.tools) {\n      // Colour separates what the model can call from what is merely registered,\n      // so a withheld tool never has to be selected to be recognised.\n      const usable = tool.active && server.enabled;\n      lines.push(this.theme.fg(usable ? 'text' : 'dim', fit(`${TOOL_INDENT}${tool.toolName}`, width)));\n      if (tool.description) {\n        for (const line of wrap(tool.description, Math.max(1, width - TOOL_INDENT.length * 2))) {\n          lines.push(this.theme.fg('dim', `${TOOL_INDENT}${TOOL_INDENT}${line}`));\n        }\n      }\n    }\n    return lines;\n  }\n\n  private resourceLines(server: McpServerView, width: number): string[] {\n    const pane = this.resourcePanes.get(server.name);\n    if (!pane) {\n      return [\n        this.theme.fg(\n          'dim',\n          `${TOOL_INDENT}${server.state === 'connected' && server.enabled ? 'Press ctrl+r to list resources' : `${server.name} is ${stateLabel(server)} · press ctrl+r to try anyway`}`,\n        ),\n      ];\n    }\n    if (pane.status === 'loading') return [this.theme.fg('dim', `${TOOL_INDENT}Listing resources…`)];\n    if (pane.status === 'error') {\n      return wrap(\n        `Could not list resources: ${pane.error ?? 'unknown error'}`,\n        Math.max(1, width - TOOL_INDENT.length),\n      ).map((line) => this.theme.fg('warning', `${TOOL_INDENT}${line}`));\n    }\n    const items = pane.items ?? [];\n    if (items.length === 0) return [this.theme.fg('dim', `${TOOL_INDENT}No resources`)];\n    return items.flatMap((resource) => {\n      const lines = [\n        rightAligned(\n          `${TOOL_INDENT}${resource.name ?? resource.uri}`,\n          this.theme.fg('dim', resource.mimeType ?? ''),\n          width,\n        ),\n      ];\n      if (resource.name) lines.push(this.theme.fg('dim', fit(`${TOOL_INDENT}${TOOL_INDENT}${resource.uri}`, width)));\n      if (resource.description) {\n        for (const line of wrap(resource.description, Math.max(1, width - TOOL_INDENT.length * 2))) {\n          lines.push(this.theme.fg('dim', `${TOOL_INDENT}${TOOL_INDENT}${line}`));\n        }\n      }\n      return lines;\n    });\n  }\n\n  private detailLines(width: number, height: number): string[] {\n    const server = this.current();\n    if (!server) return [this.theme.fg('dim', EMPTY_MESSAGE)];\n\n    const summary = [\n      stateLabel(server),\n      `${server.tools.length} ${server.tools.length === 1 ? 'tool' : 'tools'}`,\n      `${server.resourceCount} res`,\n    ].join(' · ');\n    const header = [\n      this.theme.bold(server.name),\n      '',\n      ...this.field('State', summary, width),\n      ...this.field('Error', server.error ?? FIELD_FALLBACK, width),\n      // The compact label is clickable, while `a` reopens the same reserved URL.\n      ...(server.authorizationUrl ? ['', ...this.authorizationLines(server.authorizationUrl, width)] : []),\n      '',\n      this.controlLine(server, width),\n      '',\n      this.tabStrip(server, width),\n      '',\n    ];\n\n    const body = this.detailTab === 'tools' ? this.toolLines(server, width) : this.resourceLines(server, width);\n    this.detailLineCount = body.length;\n    this.detailViewportHeight = Math.max(1, height - header.length);\n    const start = Math.min(this.detailScroll, Math.max(0, body.length - this.detailViewportHeight));\n    return [...header, ...body.slice(start, start + this.detailViewportHeight)];\n  }\n\n  protected getChrome(): DoomOverlayChrome {\n    const connected = this.servers.filter((server) => server.enabled && server.state === 'connected').length;\n    return {\n      title: TITLE,\n      accent: DOOM_OVERLAY_ACCENT,\n      breadcrumb: BREADCRUMB,\n      headerRight: `${connected}/${this.servers.length} connected · esc close`,\n      // The chrome renders the caps and decides what fits; `footer` is only the\n      // plain-sentence fallback it uses when hints are absent.\n      footer: FOOTER_FALLBACK,\n      footerHints: HINTS,\n    };\n  }\n\n  /**\n   * The notice line, on its own full-width row at the foot of the body.\n   *\n   * Not `footerRight`: the chrome drops a right-hand status whole when the row\n   * cannot spare the columns, and the hint legend always claims them, so an action's\n   * only feedback would be silently discarded on every terminal.\n   */\n  private noticeRow(width: number): string {\n    return this.theme.fg('warning', fit(`  ${this.actionNotice ?? ''}`, width));\n  }\n\n  protected renderBody(width: number, height: number): string[] {\n    const paneHeight = this.actionNotice ? Math.max(1, height - 1) : height;\n    const notice = this.actionNotice ? [this.noticeRow(width)] : [];\n    this.bodyHeight = paneHeight;\n    if (width < MIN_WIDTH) return [...this.renderStacked(width, paneHeight), ...notice];\n\n    const leftWidth = Math.max(MIN_PANE_WIDTH, Math.floor((width - 1) * ROSTER_PANE_RATIO));\n    const rightWidth = Math.max(1, width - leftWidth - 1);\n    const leftContent = Math.max(1, leftWidth - PANE_GUTTER);\n    const rightContent = Math.max(1, rightWidth - PANE_GUTTER);\n    const left = this.rosterLines(leftContent);\n    const right = this.detailLines(rightContent, paneHeight);\n\n    const divider = this.theme.fg('borderMuted', '│');\n    const rows = Array.from({ length: paneHeight }, (_, index) => {\n      const row = `${fit(left[index] ?? '', leftContent)} ${divider} ${fit(right[index] ?? '', rightContent)}`;\n      return truncateToWidth(row, width, ELLIPSIS);\n    });\n    return [...rows, ...notice];\n  }\n\n  private renderStacked(width: number, height: number): string[] {\n    const topHeight = Math.max(1, Math.floor((height - 1) / 2));\n    const bottomHeight = Math.max(0, height - topHeight - 1);\n    this.bodyHeight = topHeight;\n    const top = this.rosterLines(width);\n    const bottom = this.detailLines(width, bottomHeight);\n    return [\n      ...top.slice(0, topHeight),\n      ...Array.from({ length: Math.max(0, topHeight - top.length) }, () => ''),\n      this.theme.fg('borderMuted', '─'.repeat(width)),\n      ...bottom.slice(0, bottomHeight),\n    ];\n  }\n}\n\nfunction message(cause: unknown): string {\n  return cause instanceof Error ? cause.message : String(cause);\n}\n\nexport async function openMcpOverlay(ctx: ExtensionContext, target: McpOverlayTarget): Promise<void> {\n  await ctx.ui.custom<undefined>(\n    (tui, theme, _keybindings, done) => new McpOverlayComponent(tui, theme, target, done),\n    DOOM_FULLSCREEN_UI_OPTIONS,\n  );\n}\n"],"mappings":"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"}