{"version":3,"file":"web.mjs","names":["routes","isRecord","repositorySettingsPanelMcp","fillMcpAuth","toolMcp"],"sources":["../../src/types/webMcp.ts","../../src/types/apiRoutes.ts","../../generated/client.ts","../../src/extensions/workspaces/(frontend)/repository-settings-panel/_lib/mcpSettingsApi.ts","../../src/extensions/workspaces/(frontend)/repository-settings-panel/_lib/mcpSettingsStore.ts","../../src/extensions/workspaces/(frontend)/repository-settings-panel/_components/McpRepositorySettingsPanel.tsx","../../src/extensions/workspaces/(frontend)/repository-settings-panel/mcp.web.tsx","../../src/extensions/workspaces/sessions/(frontend)/fill/_components/McpSessionAuthSection.tsx","../../src/extensions/workspaces/sessions/(frontend)/fill/McpAuth.context.web.tsx","../../src/extensions/workspaces/sessions/(frontend)/tool/_lib/mcpToolMatch.ts","../../src/extensions/workspaces/sessions/(frontend)/tool/_components/McpToolMessage.tsx","../../src/extensions/workspaces/sessions/(frontend)/tool/mcp.web.tsx","../../generated/web.ts"],"sourcesContent":["/**\n * What an MCP tool result carries beyond its text, shared by this package's\n * Pi adapter (which attaches it as the result's details) and its web plugin\n * (which renders it). Wire JSON only: images ride Pi's own content blocks,\n * so they are not repeated here.\n */\n\nexport type McpResultBlock =\n  | { type: 'audio'; data: string; mimeType: string }\n  | { type: 'resource_link'; uri: string; name: string; title?: string; description?: string; mimeType?: string }\n  | { type: 'resource'; uri: string; mimeType?: string; text?: string; blob?: string }\n  | { type: 'structured'; value: Record<string, unknown> };\n\nexport interface McpToolDetails {\n  server: string;\n  tool: string;\n  /** Present only when the downstream result carried something beyond text and images. */\n  blocks?: McpResultBlock[];\n}\n\nexport const MCP_SESSION_AUTH_STATUS_KEY = 'doom-mcp-session-auth';\n\nconst ANSI_ESCAPE_PATTERN = new RegExp(`${String.fromCharCode(27)}\\\\[[0-?]*[ -/]*[@-~]`, 'gu');\nconst MAX_SESSION_AUTH_SERVERS = 128;\nconst MAX_AUTHORIZATION_URL_LENGTH = 8192;\nconst SESSION_AUTH_STATES = [\n  'not-connected',\n  'connecting',\n  'connected',\n  'degraded',\n  'needs-auth',\n  'failed',\n  'closed',\n  'disabled',\n] as const;\nexport type McpSessionAuthState = (typeof SESSION_AUTH_STATES)[number];\n\nfunction isSessionAuthState(value: unknown): value is McpSessionAuthState {\n  return SESSION_AUTH_STATES.some((state) => state === value);\n}\n\nexport interface McpSessionAuthStatusItem {\n  readonly name: string;\n  readonly state: McpSessionAuthState;\n  readonly authorizationUrl?: string;\n}\n\ninterface McpSessionServerStatusSource {\n  readonly name: string;\n  readonly state: string;\n  readonly authorizationUrl?: unknown;\n}\n\n/** Keeps servers visible before discovery and after failures, without diagnostics or credentials. */\nexport function formatMcpSessionAuthStatus<T extends McpSessionServerStatusSource>(\n  servers: readonly T[],\n): string | undefined {\n  const items: McpSessionAuthStatusItem[] = servers.flatMap((server) => {\n    if (!isSessionAuthState(server.state)) return [];\n    const item: McpSessionAuthStatusItem = {\n      name: server.name,\n      state: server.state,\n      ...(isAuthorizationUrl(server.authorizationUrl) ? { authorizationUrl: server.authorizationUrl } : {}),\n    };\n    return [item];\n  });\n  return items.length === 0 ? undefined : JSON.stringify(items);\n}\n\n/** Reads the live-session status defensively. Empty is the browser's active-session clear value. */\nexport function parseMcpSessionAuthStatus(raw: string | undefined): McpSessionAuthStatusItem[] | undefined {\n  if (raw === undefined || raw.trim() === '') return undefined;\n  try {\n    const value: unknown = JSON.parse(raw.replace(ANSI_ESCAPE_PATTERN, ''));\n    if (!Array.isArray(value) || value.length === 0 || value.length > MAX_SESSION_AUTH_SERVERS) return undefined;\n\n    const names = new Set<string>();\n    for (const item of value) {\n      if (!isSessionAuthStatusItem(item) || names.has(item.name)) return undefined;\n      names.add(item.name);\n    }\n    return value;\n  } catch {\n    return undefined;\n  }\n}\n\nfunction hasControlCharacter(value: string): boolean {\n  for (const character of value) {\n    const codePoint = character.codePointAt(0);\n    if (codePoint !== undefined && (codePoint < 32 || (codePoint >= 127 && codePoint <= 159))) return true;\n  }\n  return false;\n}\n\nfunction isAuthorizationUrl(value: unknown): value is string {\n  if (typeof value !== 'string' || value.length > MAX_AUTHORIZATION_URL_LENGTH || hasControlCharacter(value)) {\n    return false;\n  }\n  try {\n    const url = new URL(value);\n    return (url.protocol === 'http:' || url.protocol === 'https:') && url.username === '' && url.password === '';\n  } catch {\n    return false;\n  }\n}\n\nfunction isSessionAuthStatusItem(value: unknown): value is McpSessionAuthStatusItem {\n  if (!value || typeof value !== 'object' || Array.isArray(value)) return false;\n  const record = value as Record<string, unknown>;\n  return (\n    Object.keys(record).every((key) => key === 'name' || key === 'state' || key === 'authorizationUrl') &&\n    (!('authorizationUrl' in record) || isAuthorizationUrl(record.authorizationUrl)) &&\n    typeof record.name === 'string' &&\n    record.name.trim() !== '' &&\n    !hasControlCharacter(record.name) &&\n    isSessionAuthState(record.state)\n  );\n}\n\n/** Hub API paths for repository-scoped MCP management. */\nexport const MCP_REPOSITORY_API_PATH = '/repository';\nexport const MCP_DISCOVERY_API_PATH = '/repository/discover';\nexport const MCP_AUTHORIZATION_API_PATH = '/repository/authorize';\n/** The repository every route is asked about, and the flow segment the two flow routes carry. */\nexport const MCP_REPOSITORY_ID_QUERY = 'repositoryId';\nexport const MCP_FLOW_ID_PARAM = 'flowId';\n\nexport type McpRepositoryServerState =\n  | 'not-connected'\n  | 'connecting'\n  | 'connected'\n  | 'degraded'\n  | 'needs-auth'\n  | 'failed'\n  | 'closed';\n\nexport interface McpRepositoryTool {\n  name: string;\n  piName: string;\n  description?: string;\n}\n\nexport interface McpRepositoryServer {\n  name: string;\n  state: McpRepositoryServerState;\n  source: 'cached' | 'live' | 'configured';\n  credentialPresent: boolean;\n  tools: McpRepositoryTool[];\n  error?: string;\n}\n\nexport interface McpRepositoryCatalog {\n  repositoryId: string;\n  sync: {\n    fresh: boolean;\n    reasons: string[];\n  };\n  servers: McpRepositoryServer[];\n  droppedServers: string[];\n  diagnostics: string[];\n}\n\nexport type McpAuthorizationStatus = 'starting' | 'waiting' | 'completed' | 'failed' | 'cancelled' | 'expired';\n\nexport interface McpAuthorizationFlow {\n  id: string;\n  repositoryId: string;\n  serverName: string;\n  status: McpAuthorizationStatus;\n  authorizationUrl?: string;\n  error?: string;\n  expiresAt: number;\n}\n","import { apiResponse, defineApiRoutes } from '@agimon-ai/doompi-core/web';\n\nimport {\n  MCP_AUTHORIZATION_API_PATH,\n  MCP_DISCOVERY_API_PATH,\n  MCP_FLOW_ID_PARAM,\n  MCP_REPOSITORY_API_PATH,\n  MCP_REPOSITORY_ID_QUERY,\n  type McpAuthorizationFlow,\n  type McpRepositoryCatalog,\n} from './webMcp';\n\n/** One authorization flow, addressed by id below the flow collection. */\nconst AUTHORIZATION_FLOW_PATH = `${MCP_AUTHORIZATION_API_PATH}/:${MCP_FLOW_ID_PARAM}`;\n\n/**\n * This package's routes, as data.\n *\n * No scope and no base path. The build reads both off\n * `src/extensions/(backend)/api/mcp/`, so the mount is stated once, by the\n * folder that creates it. The sub-paths come from `webMcp`, which already owned\n * them, so this table names where a route sits and nothing else.\n *\n * This is the one file the hub handler and the settings panel both read, so a\n * path cannot move on one side alone. The handler matches on these strings\n * rather than parsing its own copies of them.\n *\n * `:flowId` is the client's parameter syntax; the handler reads the segment off\n * the same path, so the two cannot disagree about where the id sits.\n */\nexport default defineApiRoutes({\n  catalog: {\n    method: 'GET',\n    path: MCP_REPOSITORY_API_PATH,\n    query: [MCP_REPOSITORY_ID_QUERY],\n    response: apiResponse<McpRepositoryCatalog>(),\n  },\n  discover: {\n    method: 'POST',\n    path: MCP_DISCOVERY_API_PATH,\n    response: apiResponse<McpRepositoryCatalog>(),\n  },\n  authorize: {\n    method: 'POST',\n    path: MCP_AUTHORIZATION_API_PATH,\n    response: apiResponse<McpAuthorizationFlow>(),\n  },\n  readAuthorization: {\n    method: 'GET',\n    path: AUTHORIZATION_FLOW_PATH,\n    query: [MCP_REPOSITORY_ID_QUERY],\n    response: apiResponse<McpAuthorizationFlow>(),\n  },\n  /** The same path as `readAuthorization`; the method is the whole of the difference. */\n  cancelAuthorization: {\n    method: 'DELETE',\n    path: AUTHORIZATION_FLOW_PATH,\n    query: [MCP_REPOSITORY_ID_QUERY],\n    response: apiResponse<McpAuthorizationFlow>(),\n  },\n});\n","// Generated by @agimon-ai/doompi-build. Do not edit by hand.\nimport { createApiClient, sessionApiAddress } from '@agimon-ai/doompi-core/web';\nimport { sealedTransport } from '@agimon-ai/doompi-web-security/browser';\n\nimport routes from '../src/types/apiRoutes';\n\n/** Scopes the tree mounts 'mcp' at. */\nexport const apiScopes = ['global', 'workspace', 'session'] as const;\n\nexport const api = createApiClient(routes, {\n  scopes: apiScopes,\n  basePath: 'mcp',\n  transport: (input, init) => sealedTransport.fetch(input, init),\n  sessionAddress: sessionApiAddress,\n});\n","import { api } from '../../../../../../generated/client';\nimport {\n  MCP_FLOW_ID_PARAM,\n  MCP_REPOSITORY_ID_QUERY,\n  type McpAuthorizationFlow,\n  type McpRepositoryCatalog,\n} from '../../../../../types/webMcp';\n\n/**\n * The panel's half of this package's repository API.\n *\n * The generated client owns every URL, addressed at the workspace scope the\n * repository names, so nothing here spells a mount. The workspace prefix, the\n * plugins segment and the base path used to be concatenated at the top of this\n * file, the only copy of that shape outside the host, and it agreed with the\n * route by inspection alone.\n *\n * The transport stays injected, which is the one way this package differs from\n * its siblings. Every write here is step-up gated: the panel passes the\n * elevated request for discovery, authorization and cancellation and the plain\n * one for reads, and that choice belongs to the caller. So the client is asked\n * for the URL and the method, and the caller's own request issues them.\n */\n\nconst JSON_HEADERS = { 'content-type': 'application/json' };\n\nexport type McpRequest = (input: string, init?: RequestInit) => Promise<Response>;\nexport type McpApiResult<T> = { value: T } | { error: string };\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n  return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nasync function resultOf<T>(response: Response, fallback: string): Promise<McpApiResult<T>> {\n  let body: unknown;\n  try {\n    body = (await response.json()) as unknown;\n  } catch {\n    body = undefined;\n  }\n  if (!response.ok) {\n    return { error: isRecord(body) && typeof body.error === 'string' ? body.error : fallback };\n  }\n  return { value: body as T };\n}\n\nexport async function readMcpCatalog(\n  request: McpRequest,\n  repositoryId: string,\n): Promise<McpApiResult<McpRepositoryCatalog>> {\n  const route = api.workspace(repositoryId).catalog;\n  const response = await request(route.url({ query: { [MCP_REPOSITORY_ID_QUERY]: repositoryId } }));\n  return await resultOf(response, 'The synced MCP catalog could not be read.');\n}\n\nexport async function discoverMcpCatalog(\n  requestWithStepUp: McpRequest,\n  repositoryId: string,\n): Promise<McpApiResult<McpRepositoryCatalog>> {\n  const route = api.workspace(repositoryId).discover;\n  const response = await requestWithStepUp(route.url(), {\n    method: route.spec.method,\n    headers: JSON_HEADERS,\n    body: JSON.stringify({ repositoryId }),\n  });\n  return await resultOf(response, 'MCP discovery could not be completed.');\n}\n\nexport async function startMcpAuthorization(\n  requestWithStepUp: McpRequest,\n  repositoryId: string,\n  serverName: string,\n): Promise<McpApiResult<McpAuthorizationFlow>> {\n  const route = api.workspace(repositoryId).authorize;\n  const response = await requestWithStepUp(route.url(), {\n    method: route.spec.method,\n    headers: JSON_HEADERS,\n    body: JSON.stringify({ repositoryId, serverName }),\n  });\n  return await resultOf(response, 'MCP authorization could not be started.');\n}\n\nexport async function readMcpAuthorization(\n  request: McpRequest,\n  repositoryId: string,\n  flowId: string,\n): Promise<McpApiResult<McpAuthorizationFlow>> {\n  const route = api.workspace(repositoryId).readAuthorization;\n  const response = await request(\n    route.url({ params: { [MCP_FLOW_ID_PARAM]: flowId }, query: { [MCP_REPOSITORY_ID_QUERY]: repositoryId } }),\n  );\n  return await resultOf(response, 'The authorization state could not be read.');\n}\n\nexport async function cancelMcpAuthorization(\n  requestWithStepUp: McpRequest,\n  repositoryId: string,\n  flowId: string,\n): Promise<McpApiResult<McpAuthorizationFlow>> {\n  const route = api.workspace(repositoryId).cancelAuthorization;\n  const response = await requestWithStepUp(\n    route.url({ params: { [MCP_FLOW_ID_PARAM]: flowId }, query: { [MCP_REPOSITORY_ID_QUERY]: repositoryId } }),\n    { method: route.spec.method },\n  );\n  return await resultOf(response, 'The authorization flow could not be cancelled.');\n}\n","import { Store } from '@tanstack/store';\n\nimport type { McpAuthorizationFlow, McpRepositoryCatalog } from '../../../../../types/webMcp';\nimport {\n  cancelMcpAuthorization,\n  discoverMcpCatalog,\n  type McpRequest,\n  readMcpAuthorization,\n  readMcpCatalog,\n  startMcpAuthorization,\n} from './mcpSettingsApi';\n\nexport interface McpSettingsState {\n  repositoryId: string | undefined;\n  catalog: McpRepositoryCatalog | undefined;\n  authorization: McpAuthorizationFlow | undefined;\n  busy: 'loading' | 'discovering' | 'authorizing' | 'cancelling' | undefined;\n  error: string | undefined;\n}\n\nexport const mcpSettings = new Store<McpSettingsState>({\n  repositoryId: undefined,\n  catalog: undefined,\n  authorization: undefined,\n  busy: undefined,\n  error: undefined,\n});\n\nfunction selectRepository(repositoryId: string): void {\n  if (mcpSettings.state.repositoryId === repositoryId) return;\n  mcpSettings.setState(() => ({\n    repositoryId,\n    catalog: undefined,\n    authorization: undefined,\n    busy: undefined,\n    error: undefined,\n  }));\n}\n\nfunction applyFor(repositoryId: string, update: (current: McpSettingsState) => McpSettingsState): void {\n  if (mcpSettings.state.repositoryId !== repositoryId) return;\n  mcpSettings.setState(update);\n}\n\nexport async function loadMcpSettings(request: McpRequest, repositoryId: string): Promise<void> {\n  selectRepository(repositoryId);\n  mcpSettings.setState((current) => ({ ...current, busy: 'loading', error: undefined }));\n  try {\n    const result = await readMcpCatalog(request, repositoryId);\n    applyFor(repositoryId, (current) =>\n      'error' in result\n        ? { ...current, busy: undefined, error: result.error }\n        : { ...current, busy: undefined, catalog: result.value, error: undefined },\n    );\n  } catch {\n    applyFor(repositoryId, (current) => ({ ...current, busy: undefined, error: 'The cockpit hub is unreachable.' }));\n  }\n}\n\nexport async function discoverMcpSettings(requestWithStepUp: McpRequest, repositoryId: string): Promise<void> {\n  selectRepository(repositoryId);\n  mcpSettings.setState((current) => ({ ...current, busy: 'discovering', error: undefined }));\n  try {\n    const result = await discoverMcpCatalog(requestWithStepUp, repositoryId);\n    applyFor(repositoryId, (current) =>\n      'error' in result\n        ? { ...current, busy: undefined, error: result.error }\n        : { ...current, busy: undefined, catalog: result.value, error: undefined },\n    );\n  } catch {\n    applyFor(repositoryId, (current) => ({ ...current, busy: undefined, error: 'The cockpit hub is unreachable.' }));\n  }\n}\n\nexport async function authorizeMcpServer(\n  requestWithStepUp: McpRequest,\n  repositoryId: string,\n  serverName: string,\n): Promise<void> {\n  selectRepository(repositoryId);\n  mcpSettings.setState((current) => ({ ...current, busy: 'authorizing', error: undefined }));\n  try {\n    const result = await startMcpAuthorization(requestWithStepUp, repositoryId, serverName);\n    applyFor(repositoryId, (current) =>\n      'error' in result\n        ? { ...current, busy: undefined, error: result.error }\n        : { ...current, busy: undefined, authorization: result.value, error: undefined },\n    );\n  } catch {\n    applyFor(repositoryId, (current) => ({ ...current, busy: undefined, error: 'The cockpit hub is unreachable.' }));\n  }\n}\n\nexport function followMcpAuthorization(\n  request: McpRequest,\n  repositoryId: string,\n  flowId: string,\n  onCompleted: () => void,\n): () => void {\n  let stopped = false;\n  let timer: ReturnType<typeof setTimeout> | undefined;\n  const poll = async (): Promise<void> => {\n    if (stopped) return;\n    try {\n      const result = await readMcpAuthorization(request, repositoryId, flowId);\n      if (stopped) return;\n      if ('error' in result) {\n        applyFor(repositoryId, (current) => ({ ...current, error: result.error }));\n        return;\n      }\n      applyFor(repositoryId, (current) => ({ ...current, authorization: result.value, error: undefined }));\n      if (result.value.status === 'completed') {\n        onCompleted();\n        return;\n      }\n      if (['failed', 'cancelled', 'expired'].includes(result.value.status)) return;\n      timer = setTimeout(() => void poll(), 1000);\n    } catch {\n      applyFor(repositoryId, (current) => ({ ...current, error: 'The authorization status could not be refreshed.' }));\n    }\n  };\n  void poll();\n  return () => {\n    stopped = true;\n    if (timer) clearTimeout(timer);\n  };\n}\n\nexport async function cancelMcpFlow(\n  requestWithStepUp: McpRequest,\n  repositoryId: string,\n  flowId: string,\n): Promise<void> {\n  mcpSettings.setState((current) => ({ ...current, busy: 'cancelling', error: undefined }));\n  try {\n    const result = await cancelMcpAuthorization(requestWithStepUp, repositoryId, flowId);\n    applyFor(repositoryId, (current) =>\n      'error' in result\n        ? { ...current, busy: undefined, error: result.error }\n        : { ...current, busy: undefined, authorization: result.value, error: undefined },\n    );\n  } catch {\n    applyFor(repositoryId, (current) => ({ ...current, busy: undefined, error: 'The cockpit hub is unreachable.' }));\n  }\n}\n","import type { RepositorySettingsPanelProps } from '@agimon-ai/doompi-core/web';\nimport { Badge, Button } from '@agimon-ai/doompi-web-components';\nimport { useStore } from '@tanstack/react-store';\nimport { useEffect, useState } from 'react';\n\nimport {\n  authorizeMcpServer,\n  cancelMcpFlow,\n  discoverMcpSettings,\n  followMcpAuthorization,\n  loadMcpSettings,\n  mcpSettings,\n} from '../_lib/mcpSettingsStore';\n\nconst TERMINAL_AUTHORIZATION = new Set(['completed', 'failed', 'cancelled', 'expired']);\n\nfunction syncReason(reason: string): string {\n  const labels: Record<string, string> = {\n    'never-synced': 'never synced',\n    'configuration-changed': 'configuration changed',\n    'cockpit-bundle-missing': 'cockpit bundle missing',\n    'package-apis-missing': 'package APIs missing',\n  };\n  return labels[reason] ?? reason;\n}\n\nexport function McpRepositorySettingsPanel({ repository, request, requestWithStepUp }: RepositorySettingsPanelProps) {\n  const state = useStore(mcpSettings);\n  const [confirmDiscovery, setConfirmDiscovery] = useState(false);\n  const [confirmAuthorization, setConfirmAuthorization] = useState<string | undefined>();\n  const repositoryId = repository?.id;\n\n  useEffect(() => {\n    // Loading a repository's catalog is the external sync; the two resets clear the\n    // confirmations that belonged to the repository being navigated away from.\n    // oxlint-disable-next-line react/set-state-in-effect\n    setConfirmDiscovery(false);\n    setConfirmAuthorization(undefined);\n    if (repositoryId) void loadMcpSettings(request, repositoryId);\n  }, [repositoryId, request]);\n\n  const authorization = state.repositoryId === repositoryId ? state.authorization : undefined;\n  // Only the id and status decide the subscription, so the effect reads those two\n  // primitives rather than the authorization object it belongs to.\n  const authorizationId = authorization?.id;\n  const authorizationStatus = authorization?.status;\n  useEffect(() => {\n    if (!repositoryId || authorizationId === undefined) return;\n    if (authorizationStatus !== undefined && TERMINAL_AUTHORIZATION.has(authorizationStatus)) return;\n    return followMcpAuthorization(request, repositoryId, authorizationId, () => {\n      void loadMcpSettings(request, repositoryId);\n    });\n  }, [authorizationId, authorizationStatus, repositoryId, request]);\n\n  if (!repository) {\n    return <p className=\"py-3 text-xs text-doom-faint\">Select a repository to inspect its synced MCP catalog.</p>;\n  }\n\n  const catalog = state.repositoryId === repository.id ? state.catalog : undefined;\n  const busy = state.repositoryId === repository.id ? state.busy : undefined;\n  const error = state.repositoryId === repository.id ? state.error : undefined;\n\n  return (\n    <div className=\"flex flex-col gap-3\" data-testid=\"mcp-repository-settings\">\n      <div className=\"flex flex-col items-stretch gap-2 rounded border border-doom-border bg-doom-panel px-3 py-2 min-[560px]:flex-row min-[560px]:items-center\">\n        <Badge>{catalog?.sync.fresh ? 'synced' : 'sync required'}</Badge>\n        <span className=\"min-w-0 text-xs leading-relaxed text-doom-dim min-[560px]:flex-1\">\n          {catalog?.sync.fresh\n            ? 'Cached inspection is local. Discovery contacts the configured servers.'\n            : catalog\n              ? catalog.sync.reasons.map(syncReason).join(', ')\n              : 'Reading the last synced projection.'}\n        </span>\n        <Button\n          variant=\"outline\"\n          size=\"xs\"\n          loading={busy === 'loading'}\n          disabled={busy !== undefined}\n          onClick={() => void loadMcpSettings(request, repository.id)}\n          className=\"w-full text-xs min-[560px]:w-auto\"\n        >\n          refresh cache\n        </Button>\n        <Button\n          variant=\"outline\"\n          size=\"xs\"\n          loading={busy === 'discovering'}\n          disabled={busy !== undefined || !catalog?.sync.fresh}\n          onClick={() => setConfirmDiscovery(true)}\n          className=\"w-full text-xs min-[560px]:w-auto\"\n        >\n          discover live\n        </Button>\n      </div>\n\n      {!confirmDiscovery ? null : (\n        <div className=\"flex flex-col items-stretch gap-2 rounded border border-doom-blue/50 bg-doom-blue/5 px-3 py-2 min-[560px]:flex-row min-[560px]:items-center\">\n          <span className=\"min-w-0 text-xs leading-relaxed text-doom-hi min-[560px]:flex-1\">\n            Discovery starts configured processes and contacts remote MCP servers. Continue?\n          </span>\n          <Button\n            size=\"xs\"\n            disabled={busy !== undefined}\n            onClick={() => {\n              setConfirmDiscovery(false);\n              void discoverMcpSettings(requestWithStepUp, repository.id);\n            }}\n            className=\"w-full text-xs min-[560px]:w-auto\"\n          >\n            confirm discovery\n          </Button>\n          <Button\n            variant=\"ghost\"\n            size=\"xs\"\n            onClick={() => setConfirmDiscovery(false)}\n            className=\"w-full text-xs min-[560px]:w-auto\"\n          >\n            cancel\n          </Button>\n        </div>\n      )}\n\n      {!error ? null : <p className=\"rounded border border-doom-red/40 px-3 py-2 text-xs text-doom-red\">{error}</p>}\n\n      {authorization ? (\n        <div className=\"flex flex-col gap-2 rounded border border-doom-border bg-doom-panel px-3 py-2\">\n          <div className=\"flex flex-wrap items-center gap-2\">\n            <span className=\"min-w-0 basis-full text-xs font-bold text-doom-hi min-[560px]:basis-auto\">\n              {authorization.serverName}\n            </span>\n            <Badge>{authorization.status}</Badge>\n            <span className=\"min-w-0 flex-1 text-2xs text-doom-faint\">authorization flow</span>\n            {TERMINAL_AUTHORIZATION.has(authorization.status) ? null : (\n              <Button\n                variant=\"ghost\"\n                size=\"xs\"\n                loading={busy === 'cancelling'}\n                disabled={busy !== undefined}\n                onClick={() => void cancelMcpFlow(requestWithStepUp, repository.id, authorization.id)}\n                className=\"w-full text-xs min-[560px]:w-auto\"\n              >\n                cancel\n              </Button>\n            )}\n          </div>\n          {!authorization.authorizationUrl ? null : (\n            <a\n              href={authorization.authorizationUrl}\n              target=\"_blank\"\n              rel=\"noreferrer noopener\"\n              className=\"w-fit text-xs text-doom-blue underline underline-offset-2\"\n            >\n              open authorization page\n            </a>\n          )}\n          {!authorization.error ? null : <p className=\"text-2xs text-doom-red\">{authorization.error}</p>}\n        </div>\n      ) : null}\n\n      {!catalog || catalog.servers.length === 0 ? (\n        <p className=\"rounded border border-dashed border-doom-border px-3 py-4 text-xs text-doom-faint\">\n          {busy === 'loading' ? 'Reading the cached catalog.' : 'No MCP servers are enabled in the synced selection.'}\n        </p>\n      ) : (\n        <div className=\"flex flex-col gap-2\">\n          {catalog.servers.map((server) => (\n            <div\n              key={server.name}\n              className=\"flex flex-col gap-2 rounded border border-doom-border bg-doom-panel px-3 py-2\"\n            >\n              <div className=\"flex flex-wrap items-center gap-2\">\n                <span className=\"min-w-0 basis-full truncate text-sm font-bold text-doom-hi min-[560px]:basis-auto min-[560px]:flex-1\">\n                  {server.name}\n                </span>\n                <Badge>{server.state}</Badge>\n                <Badge>{server.source}</Badge>\n                <Badge>{server.credentialPresent ? 'credential present' : 'no credential'}</Badge>\n                <Button\n                  variant=\"outline\"\n                  size=\"xs\"\n                  disabled={busy !== undefined || !catalog.sync.fresh}\n                  onClick={() => setConfirmAuthorization(server.name)}\n                  className=\"w-full text-xs min-[560px]:w-auto\"\n                >\n                  authorize\n                </Button>\n              </div>\n              {confirmAuthorization !== server.name ? null : (\n                <div className=\"flex flex-col items-stretch gap-2 border-t border-doom-border pt-2 min-[560px]:flex-row min-[560px]:items-center\">\n                  <span className=\"min-w-0 text-2xs leading-relaxed text-doom-dim min-[560px]:flex-1\">\n                    Start a bounded OAuth attempt for this server? A passkey may be required.\n                  </span>\n                  <Button\n                    size=\"xs\"\n                    disabled={busy !== undefined}\n                    onClick={() => {\n                      setConfirmAuthorization(undefined);\n                      void authorizeMcpServer(requestWithStepUp, repository.id, server.name);\n                    }}\n                    className=\"w-full text-xs min-[560px]:w-auto\"\n                  >\n                    continue\n                  </Button>\n                  <Button\n                    variant=\"ghost\"\n                    size=\"xs\"\n                    onClick={() => setConfirmAuthorization(undefined)}\n                    className=\"w-full text-xs min-[560px]:w-auto\"\n                  >\n                    cancel\n                  </Button>\n                </div>\n              )}\n              <details>\n                <summary className=\"cursor-pointer text-2xs text-doom-dim\">\n                  {String(server.tools.length)} cached {server.tools.length === 1 ? 'tool' : 'tools'}\n                </summary>\n                <div className=\"mt-2 flex flex-col gap-1 border-t border-doom-border pt-2\">\n                  {server.tools.length === 0 ? (\n                    <span className=\"text-2xs text-doom-faint\">Run discovery to populate capabilities.</span>\n                  ) : (\n                    server.tools.map((tool) => (\n                      <div key={tool.piName} className=\"flex min-w-0 gap-2 text-2xs\">\n                        <code className=\"shrink-0 text-doom-hi\">{tool.name}</code>\n                        <span className=\"truncate text-doom-faint\">{tool.description ?? tool.piName}</span>\n                      </div>\n                    ))\n                  )}\n                </div>\n              </details>\n              {!server.error ? null : <p className=\"text-2xs text-doom-red\">{server.error}</p>}\n            </div>\n          ))}\n        </div>\n      )}\n\n      {catalog?.droppedServers.length ? (\n        <p className=\"text-2xs text-doom-faint\">\n          Policy omitted {String(catalog.droppedServers.length)} configured servers.\n        </p>\n      ) : null}\n      {catalog?.diagnostics.map((diagnostic) => (\n        <p key={diagnostic} className=\"text-2xs text-doom-red\">\n          {diagnostic}\n        </p>\n      ))}\n    </div>\n  );\n}\n","import { defineRepositorySettingsPanel } from '@agimon-ai/doompi-core/web';\n\nimport { McpRepositorySettingsPanel } from './_components/McpRepositorySettingsPanel';\nexport default defineRepositorySettingsPanel({\n  label: 'MCP servers',\n  detail: 'inspect cached capabilities, discover live servers, and complete OAuth authorization.',\n  order: 100,\n  component: McpRepositorySettingsPanel,\n});\n","import type { SessionFrameSender, WebPluginSlotProps } from '@agimon-ai/doompi-core/web';\nimport {\n  Button,\n  Dialog,\n  DialogBody,\n  DialogContent,\n  DialogDescription,\n  DialogFooter,\n  DialogHeader,\n  DialogTitle,\n  Input,\n} from '@agimon-ai/doompi-web-components';\nimport { useEffect, useRef, useState } from 'react';\n\nimport { MCP_SESSION_AUTH_STATUS_KEY, parseMcpSessionAuthStatus } from '../../../../../../types/webMcp';\n\n/** Requests authorization through Pi's command frame, never through a shell. */\nexport function requestMcpSessionAuthorization(\n  sendSessionFrame: SessionFrameSender,\n  sessionId: string,\n  serverName: string,\n): void {\n  sendSessionFrame(sessionId, { type: 'prompt', message: `/mcp auth ${serverName}` });\n}\n\nfunction tokenEstimate(value: number | null): string {\n  return value === null ? '—' : `~${value.toLocaleString()}`;\n}\n\n/** Keep configured servers actionable even before they have discovered any tools. */\nexport function McpSessionAuthSection({\n  sessionId,\n  statuses,\n  sendSessionFrame,\n  contextInventory = [],\n}: WebPluginSlotProps) {\n  const servers = parseMcpSessionAuthStatus(statuses[MCP_SESSION_AUTH_STATUS_KEY]) ?? [];\n  const [target, setTarget] = useState<{ sessionId: string; name: string } | null>(null);\n  const [copyFeedback, setCopyFeedback] = useState('');\n  const [popupBlocked, setPopupBlocked] = useState(false);\n  // Only retain a tab while it is our blank placeholder. Never close the provider's page.\n  const pendingTab = useRef<Window | null>(null);\n  const selected = target?.sessionId === sessionId ? target : null;\n  const server = servers.find((item) => item.name === selected?.name);\n  const authorizationUrl = server?.authorizationUrl;\n\n  const closePendingTab = () => {\n    pendingTab.current?.close();\n    pendingTab.current = null;\n  };\n\n  useEffect(() => {\n    const tab = pendingTab.current;\n    if (!selected || !authorizationUrl || !tab || tab.closed) return;\n    tab.location.replace(authorizationUrl);\n    pendingTab.current = null;\n  }, [selected, authorizationUrl]);\n\n  useEffect(\n    () => () => {\n      pendingTab.current?.close();\n      pendingTab.current = null;\n    },\n    [sessionId],\n  );\n\n  const authorize = (name: string) => {\n    if (sessionId === null) return;\n    const current = servers.find((item) => item.name === name);\n    closePendingTab();\n    setTarget({ sessionId, name });\n    setCopyFeedback('');\n    // Reserve the tab during the click. Opening it after asynchronous discovery is blocked by browsers.\n    const tab = window.open('about:blank', '_blank');\n    setPopupBlocked(tab === null);\n    if (tab) {\n      tab.opener = null;\n      if (current?.authorizationUrl) {\n        tab.location.replace(current.authorizationUrl);\n      } else {\n        tab.document.title = 'MCP authorization';\n        tab.document.body.textContent = 'Preparing authorization. Return to DoomPi for progress or manual sign-in.';\n        pendingTab.current = tab;\n      }\n    }\n    if (!current?.authorizationUrl && current?.state !== 'connecting') {\n      requestMcpSessionAuthorization(sendSessionFrame, sessionId, name);\n    }\n  };\n\n  const copyLink = async () => {\n    if (!authorizationUrl) return;\n    try {\n      await navigator.clipboard.writeText(authorizationUrl);\n      setCopyFeedback('Link copied.');\n    } catch {\n      setCopyFeedback('Clipboard unavailable. Select the link above and copy it manually.');\n    }\n  };\n\n  return (\n    <>\n      {servers.length === 0 ? null : (\n        <section data-testid=\"context-mcp-auth\" className=\"flex flex-col gap-2 border-b border-doom-border px-3 py-3\">\n          <div className=\"flex flex-col gap-0.5\">\n            <p className=\"text-2xs font-bold uppercase tracking-wide text-doom-faint\">MCP servers</p>\n            <p className=\"text-2xs leading-relaxed text-doom-dim\">\n              Open sign-in in a new tab, or copy the link from the authorization dialog.\n            </p>\n          </div>\n          <ul aria-label=\"MCP servers\" className=\"flex flex-col gap-2\">\n            {servers.map((item) => {\n              const tools = contextInventory.filter(\n                (inventoryItem) => inventoryItem.source === 'mcp' && inventoryItem.owner === item.name,\n              );\n              return (\n                <li key={item.name} className=\"flex min-w-0 flex-col gap-1 px-1 py-0.5\">\n                  <div className=\"flex min-w-0 items-center gap-2\">\n                    <span className=\"min-w-0 flex-1 truncate text-xs text-doom-hi\">{item.name}</span>\n                    <span className=\"text-2xs text-doom-dim\">{item.state.replace(/-/g, ' ')}</span>\n                    <Button\n                      variant=\"subtle\"\n                      size=\"xs\"\n                      data-testid={`context-mcp-auth-${item.name}`}\n                      aria-label={`${item.state === 'connected' ? 'Manage' : 'Authorize'} ${item.name}`}\n                      disabled={sessionId === null || item.state === 'disabled'}\n                      onClick={() => {\n                        if (item.state !== 'connected') {\n                          authorize(item.name);\n                        } else if (sessionId !== null) {\n                          closePendingTab();\n                          setCopyFeedback('');\n                          setPopupBlocked(false);\n                          setTarget({ sessionId, name: item.name });\n                        }\n                      }}\n                      className=\"shrink-0 text-2xs font-bold\"\n                    >\n                      {item.state === 'connected' ? 'manage' : 'authorize'}\n                    </Button>\n                  </div>\n                  {tools.length === 0 ? (\n                    <p className=\"pl-3 text-2xs text-doom-faint\">no tools reported</p>\n                  ) : (\n                    <ul aria-label={`${item.name} tools`} className=\"flex flex-col\">\n                      {tools.map((tool) => (\n                        <li key={tool.name} className=\"flex min-w-0 items-center gap-2 py-px pl-3\">\n                          <span\n                            className={`min-w-0 flex-1 truncate text-2xs ${tool.active ? 'text-doom-dim' : 'text-doom-faint'}`}\n                          >\n                            {tool.name}\n                          </span>\n                          <span className=\"w-14 shrink-0 text-right text-2xs text-doom-faint\">\n                            {tool.active ? tokenEstimate(tool.tokens) : `(${tokenEstimate(tool.tokens)})`}\n                          </span>\n                        </li>\n                      ))}\n                    </ul>\n                  )}\n                </li>\n              );\n            })}\n          </ul>\n        </section>\n      )}\n      <Dialog\n        open={selected !== null}\n        onOpenChange={(open) => {\n          if (!open) {\n            closePendingTab();\n            setTarget(null);\n          }\n        }}\n      >\n        <DialogContent data-testid=\"mcp-authorization-dialog\" onInteractOutside={(event) => event.preventDefault()}>\n          <DialogHeader className=\"items-start px-4 py-4 sm:px-5\">\n            <div className=\"flex min-w-0 flex-1 flex-col gap-1.5\">\n              <DialogTitle className=\"break-words text-base leading-snug\">\n                {server?.state === 'connected' ? 'Manage' : 'Authorize'} {selected?.name}\n              </DialogTitle>\n              <DialogDescription className=\"max-w-2xl\">\n                {server?.state === 'connected'\n                  ? 'Disconnect this session without deleting saved credentials, or reauthorize to sign in again.'\n                  : \"Complete sign-in in the provider's tab. You can also open or copy the link below.\"}\n              </DialogDescription>\n            </div>\n          </DialogHeader>\n          <DialogBody className=\"px-4 py-4 sm:px-5 sm:py-5\">\n            <output className=\"text-sm text-doom-dim\">\n              {server?.state === 'connected'\n                ? 'Authorization complete. This server is connected.'\n                : server?.state === 'closed'\n                  ? 'Disconnected from this session. Saved credentials were kept.'\n                  : authorizationUrl\n                    ? 'Waiting for you to complete authorization.'\n                    : server?.state === 'failed'\n                      ? 'Connection failed. Retry authorization; details are in the session transcript.'\n                      : server\n                        ? 'Preparing the authorization link...'\n                        : 'This server is no longer available in the session.'}\n            </output>\n            {popupBlocked ? (\n              <p className=\"text-xs text-doom-dim\">\n                The browser blocked the new tab. Open the link below when it is ready.\n              </p>\n            ) : null}\n            {authorizationUrl ? (\n              <div className=\"flex flex-col gap-2\">\n                <Input\n                  aria-label=\"OAuth authorization URL\"\n                  readOnly\n                  value={authorizationUrl}\n                  onFocus={(event) => event.currentTarget.select()}\n                />\n                <a\n                  href={authorizationUrl}\n                  target=\"_blank\"\n                  rel=\"noopener noreferrer\"\n                  className=\"text-sm text-doom-blue underline underline-offset-2\"\n                >\n                  open authorization page\n                </a>\n                <Button variant=\"outline\" size=\"xs\" onClick={() => void copyLink()}>\n                  copy link\n                </Button>\n              </div>\n            ) : null}\n            {copyFeedback ? <output className=\"text-xs text-doom-dim\">{copyFeedback}</output> : null}\n          </DialogBody>\n          <DialogFooter className=\"flex-wrap justify-end border-t border-doom-border-soft px-4 py-3 sm:px-5\">\n            {server?.state === 'connected' && selected ? (\n              <Button\n                variant=\"outline\"\n                size=\"md\"\n                onClick={() => {\n                  closePendingTab();\n                  setCopyFeedback('');\n                  setPopupBlocked(false);\n                  sendSessionFrame(selected.sessionId, { type: 'prompt', message: `/mcp disconnect ${selected.name}` });\n                }}\n              >\n                disconnect\n              </Button>\n            ) : null}\n            {(server?.state === 'failed' || server?.state === 'connected' || server?.state === 'closed') && selected ? (\n              <Button size=\"md\" onClick={() => authorize(selected.name)}>\n                {server.state === 'failed' ? 'retry authorization' : 'reauthorize'}\n              </Button>\n            ) : null}\n            <Button\n              variant=\"ghost\"\n              size=\"md\"\n              onClick={() => {\n                closePendingTab();\n                setTarget(null);\n              }}\n            >\n              close\n            </Button>\n          </DialogFooter>\n        </DialogContent>\n      </Dialog>\n    </>\n  );\n}\n","import { defineFill } from '@agimon-ai/doompi-core/web';\n\nimport { McpSessionAuthSection } from './_components/McpSessionAuthSection';\nexport default defineFill({ component: McpSessionAuthSection });\n","import type { McpResultBlock } from '../../../../../../types/webMcp';\n\n/**\n * Pure view logic for MCP tool cards, the browser counterpart of\n * src/tui/mcpToolRender.ts. MCP tools are registered under `<server>_<tool>`,\n * so the plugin recognises a call by the server names the session publishes.\n */\n\n/**\n * The footer status the session half publishes (src/constants/piMcp.ts\n * MCP_STATUS_KEY). Duplicated because the browser half may import only\n * src/types and src/constants; a test keeps the two literals equal.\n */\nexport const MCP_STATUS_KEY = 'doom-mcp';\nconst SERVER_SEPARATOR = ',';\nconst PI_NAME_SEPARATOR = '_';\nconst MAX_ARGUMENTS = 3;\n/** Text lines kept in the collapsed result, before the card is expanded. */\nconst COLLAPSED_RESULT_LINES = 12;\n\nexport interface McpToolIdentity {\n  server: string;\n  tool: string;\n}\n\n/** The server names the session reports, in the order it listed them. */\nexport function mcpServers(statuses: Readonly<Record<string, string>>): string[] {\n  const raw = statuses[MCP_STATUS_KEY];\n  if (raw === undefined) return [];\n  return raw\n    .split(SERVER_SEPARATOR)\n    .map((name) => name.trim())\n    .filter((name) => name.length > 0);\n}\n\n/**\n * Splits a Pi tool name into its MCP server and tool. The longest server\n * prefix wins so `github_enterprise_search` belongs to `github_enterprise`\n * when both it and `github` are configured.\n */\nexport function matchMcpTool(toolName: string, statuses: Readonly<Record<string, string>>): McpToolIdentity | null {\n  let best: McpToolIdentity | null = null;\n  for (const server of mcpServers(statuses)) {\n    const prefix = `${server}${PI_NAME_SEPARATOR}`;\n    if (!toolName.startsWith(prefix) || toolName.length === prefix.length) continue;\n    if (best === null || server.length > best.server.length) {\n      best = { server, tool: toolName.slice(prefix.length) };\n    }\n  }\n  return best;\n}\n\n/** The identity the result details carry, which the tool wrote itself and is exact. */\nexport function mcpIdentityFromDetails(details: unknown): McpToolIdentity | null {\n  if (typeof details !== 'object' || details === null) return null;\n  const record = details as { server?: unknown; tool?: unknown };\n  if (typeof record.server !== 'string' || typeof record.tool !== 'string') return null;\n  return { server: record.server, tool: record.tool };\n}\n\nfunction argumentValue(value: unknown): string {\n  if (typeof value === 'string') return value;\n  if (typeof value === 'number' || typeof value === 'boolean') return String(value);\n  if (value === null) return 'null';\n  if (Array.isArray(value)) return `[${value.length}]`;\n  return '{…}';\n}\n\n/** The first few arguments as `key=value`, with a count for the rest. */\nexport function mcpArgumentSummary(params: Record<string, unknown>): string {\n  const entries = Object.entries(params);\n  const shown = entries.slice(0, MAX_ARGUMENTS).map(([key, value]) => `${key}=${argumentValue(value)}`);\n  if (entries.length > shown.length) shown.push(`+${entries.length - shown.length}`);\n  return shown.join(' · ');\n}\n\nexport type McpStatusTone = 'running' | 'ok' | 'error' | 'hint';\n\nexport interface McpResultView {\n  lines: string[];\n  status: { glyph: string; tone: McpStatusTone; text: string } | null;\n}\n\n/** The result body as renderMcpResult lays it out: text lines, then one status line. */\nexport function mcpResultView(input: {\n  output: string;\n  expanded: boolean;\n  isPartial: boolean;\n  isError: boolean;\n}): McpResultView {\n  const all = input.output.split('\\n');\n  while (all.length > 0 && all.at(-1)?.trim() === '') all.pop();\n  const lines = input.expanded ? all : all.slice(0, COLLAPSED_RESULT_LINES);\n\n  if (input.isPartial) return { lines, status: { glyph: '◐', tone: 'running', text: 'running' } };\n  if (input.isError) return { lines, status: { glyph: '✗', tone: 'error', text: 'failed' } };\n  if (!input.expanded && all.length > lines.length) {\n    return { lines, status: { glyph: '…', tone: 'hint', text: `${all.length - lines.length} more line(s)` } };\n  }\n  if (lines.length === 0) return { lines, status: { glyph: '✓', tone: 'ok', text: 'done' } };\n  return { lines, status: null };\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n  return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\n/** One block of the result's details, kept only when its required fields are the strings the adapter wrote. */\nfunction mcpResultBlock(entry: unknown): McpResultBlock | null {\n  if (!isRecord(entry)) return null;\n  const text = (key: string): string | undefined => (typeof entry[key] === 'string' ? entry[key] : undefined);\n  switch (entry.type) {\n    case 'audio': {\n      const data = text('data');\n      const mimeType = text('mimeType');\n      return data !== undefined && mimeType !== undefined ? { type: 'audio', data, mimeType } : null;\n    }\n    case 'resource_link': {\n      const uri = text('uri');\n      const name = text('name');\n      if (uri === undefined || name === undefined) return null;\n      const title = text('title');\n      const description = text('description');\n      const mimeType = text('mimeType');\n      return {\n        type: 'resource_link',\n        uri,\n        name,\n        ...(title === undefined ? {} : { title }),\n        ...(description === undefined ? {} : { description }),\n        ...(mimeType === undefined ? {} : { mimeType }),\n      };\n    }\n    case 'resource': {\n      const uri = text('uri');\n      if (uri === undefined) return null;\n      const mimeType = text('mimeType');\n      const content = text('text');\n      const blob = text('blob');\n      return {\n        type: 'resource',\n        uri,\n        ...(mimeType === undefined ? {} : { mimeType }),\n        ...(content === undefined ? {} : { text: content }),\n        ...(blob === undefined ? {} : { blob }),\n      };\n    }\n    case 'structured':\n      return isRecord(entry.value) ? { type: 'structured', value: entry.value } : null;\n    default:\n      return null;\n  }\n}\n\n/** The blocks beyond text the adapter attached to the result's details; malformed entries are dropped. */\nexport function mcpResultBlocks(details: unknown): McpResultBlock[] {\n  if (!isRecord(details) || !Array.isArray(details.blocks)) return [];\n  return details.blocks.flatMap((entry) => {\n    const block = mcpResultBlock(entry);\n    return block === null ? [] : [block];\n  });\n}\n\nexport interface McpImageBlock {\n  data: string;\n  mimeType: string;\n}\n\n/** The image blocks of a result's content, which Pi carries beside the text. */\nexport function mcpImageBlocks(content: readonly unknown[]): McpImageBlock[] {\n  return content.flatMap((block) => {\n    if (!isRecord(block) || block.type !== 'image') return [];\n    return typeof block.data === 'string' && typeof block.mimeType === 'string'\n      ? [{ data: block.data, mimeType: block.mimeType }]\n      : [];\n  });\n}\n","import type { ToolMessageRenderProps } from '@agimon-ai/doompi-core/web';\nimport {\n  MessageItem,\n  MessageItemBody,\n  MessageItemHeader,\n  MessageItemStatus,\n  type StatusTone,\n  SyntaxText,\n  toolTone,\n} from '@agimon-ai/doompi-web-components';\n\nimport type { McpResultBlock } from '../../../../../../types/webMcp';\nimport {\n  type McpStatusTone,\n  matchMcpTool,\n  mcpArgumentSummary,\n  mcpIdentityFromDetails,\n  mcpImageBlocks,\n  mcpResultBlocks,\n  mcpResultView,\n} from '../_lib/mcpToolMatch';\n\nconst STATUS_TONE: Record<McpStatusTone, StatusTone> = {\n  running: 'running',\n  ok: 'ok',\n  error: 'error',\n  hint: 'neutral',\n};\n\n/** The Pi name split on its first underscore, for a call whose server the session has not named. */\nfunction fallbackIdentity(toolName: string): { server: string; tool: string } {\n  const separator = toolName.indexOf('_');\n  if (separator <= 0) return { server: toolName, tool: '' };\n  return { server: toolName.slice(0, separator), tool: toolName.slice(separator + 1) };\n}\n\n/** One block beyond text the result carried: a link, an embedded resource, structured content, or audio. */\nfunction McpBlock({ block }: { block: McpResultBlock }) {\n  switch (block.type) {\n    case 'resource_link':\n      return (\n        <a\n          href={block.uri}\n          target=\"_blank\"\n          rel=\"noreferrer\"\n          data-testid=\"tool-result-mcp-link\"\n          className=\"truncate text-doom-blue hover:underline\"\n          title={block.description ?? block.uri}\n        >\n          {block.title ?? block.name}\n        </a>\n      );\n    case 'resource':\n      return block.text !== undefined ? (\n        // A resource arrives without a name, so its grammar is whatever the\n        // text itself gives away; anything unrecognised stays plain.\n        <SyntaxText data-testid=\"tool-result-mcp-resource\" className=\"text-doom-dim\" text={block.text} />\n      ) : (\n        <span data-testid=\"tool-result-mcp-resource\" className=\"truncate text-doom-faint\">\n          binary {block.mimeType ?? 'resource'} · {block.uri}\n        </span>\n      );\n    case 'structured':\n      return (\n        <SyntaxText\n          data-testid=\"tool-result-mcp-structured\"\n          className=\"text-doom-dim\"\n          grammar=\"json\"\n          text={JSON.stringify(block.value, null, 2)}\n        />\n      );\n    case 'audio':\n      return (\n        <span data-testid=\"tool-result-mcp-audio\" className=\"text-doom-faint\">\n          audio · {block.mimeType}\n        </span>\n      );\n  }\n}\n\n/**\n * The MCP tool's timeline item, the web half of renderMcpCall and\n * renderMcpResult: `mcp | server / tool · k=v` in the header; the text lines,\n * collapsed to twelve, then the images Pi carries beside the text, the\n * blocks the adapter put in the details, and one status line in the body.\n */\nexport function McpToolMessage({ toolName, args, result, output, running, isError, statuses }: ToolMessageRenderProps) {\n  const identity =\n    mcpIdentityFromDetails(result?.details) ?? matchMcpTool(toolName, statuses) ?? fallbackIdentity(toolName);\n  const summary = mcpArgumentSummary(args);\n  const collapsed = mcpResultView({ output, expanded: false, isPartial: running, isError });\n  const images = mcpImageBlocks(result?.content ?? []);\n  const blocks = mcpResultBlocks(result?.details);\n\n  return (\n    <MessageItem tone={toolTone({ running, isError })} expandable={collapsed.status?.tone === 'hint'}>\n      {({ expanded }) => {\n        const view = expanded ? mcpResultView({ output, expanded: true, isPartial: running, isError }) : collapsed;\n        const hint = view.status?.tone === 'hint';\n        return (\n          <>\n            <MessageItemHeader title=\"mcp\">\n              <span data-testid=\"tool-call-mcp\" className=\"flex min-w-0 flex-1 items-center gap-1.5\">\n                <span className=\"shrink-0 text-doom-dim\">{identity.server}</span>\n                <span className=\"shrink-0 text-doom-faint\">/</span>\n                <span className=\"shrink-0 text-doom-blue\">{identity.tool}</span>\n                {summary ? <span className=\"min-w-0 flex-1 truncate text-doom-faint\">· {summary}</span> : null}\n              </span>\n            </MessageItemHeader>\n            {view.lines.length > 0 || view.status !== null || images.length > 0 || blocks.length > 0 ? (\n              <MessageItemBody\n                data-testid=\"tool-result-mcp\"\n                data-mcp-server={identity.server}\n                className=\"flex flex-col gap-1\"\n              >\n                {view.lines.length > 0 ? (\n                  <pre className=\"whitespace-pre-wrap break-words font-mono text-doom-dim\">{view.lines.join('\\n')}</pre>\n                ) : null}\n                {images.map((image, index) => (\n                  <img\n                    key={`${String(index)}-${image.mimeType}`}\n                    data-testid=\"tool-result-mcp-image\"\n                    src={`data:${image.mimeType};base64,${image.data}`}\n                    alt={`${identity.tool} result ${String(index + 1)}`}\n                    className=\"max-h-60 max-w-full self-start rounded border border-doom-border-soft\"\n                  />\n                ))}\n                {blocks.map((block, index) => (\n                  <McpBlock key={`${String(index)}-${block.type}`} block={block} />\n                ))}\n                {view.status ? (\n                  <MessageItemStatus\n                    data-testid=\"tool-result-mcp-status\"\n                    tone={STATUS_TONE[view.status.tone]}\n                    glyph={view.status.glyph}\n                    expands={hint}\n                  >\n                    {view.status.text}\n                  </MessageItemStatus>\n                ) : null}\n              </MessageItemBody>\n            ) : null}\n          </>\n        );\n      }}\n    </MessageItem>\n  );\n}\n","import { defineToolRenderer } from '@agimon-ai/doompi-core/web';\n\nimport { McpToolMessage } from './_components/McpToolMessage';\nimport { matchMcpTool } from './_lib/mcpToolMatch';\nexport default defineToolRenderer({\n  tools: [],\n  matches: (toolName, statuses) => matchMcpTool(toolName, statuses) !== null,\n  message: McpToolMessage,\n});\n","// Generated by @agimon-ai/doompi-build. Do not edit by hand.\nimport { defineWebPlugin, type WebPluginContributions } from '@agimon-ai/doompi-core/web';\n\nimport repositorySettingsPanelMcp from '../src/extensions/workspaces/(frontend)/repository-settings-panel/mcp.web';\nimport fillMcpAuth from '../src/extensions/workspaces/sessions/(frontend)/fill/McpAuth.context.web';\nimport toolMcp from '../src/extensions/workspaces/sessions/(frontend)/tool/mcp.web';\n\nconst via = <T>(identity: Record<string, unknown>, value: unknown): T =>\n  (value === undefined ? undefined : { ...identity, ...(value as object) }) as T;\n\nexport const webPlugin = defineWebPlugin({\n  id: 'mcp',\n  workspace: {\n    get repositorySettingsPanel(): WebPluginContributions['repositorySettingsPanel'] { return repositorySettingsPanelMcp; },\n  },\n  session: {\n    get fills(): WebPluginContributions['fills'] { return [via({ slot: 'context', id: 'mcp-auth' }, fillMcpAuth)]; },\n    get toolRenderers(): WebPluginContributions['toolRenderers'] { return [via({ tools: ['mcp'] }, toolMcp)]; },\n  },\n});\n"],"mappings":"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"}