{"version":3,"file":"mcpCatalog-laXfwecc.mjs","names":["parseYaml","stringifyYaml"],"sources":["../src/services/configSources/index.ts","../src/services/mcpRuntime/index.ts","../src/services/sessionConfig/index.ts","../src/schemas/directTools.ts","../src/services/mcpCatalog/index.ts"],"sourcesContent":["import { createHash } from 'node:crypto';\nimport fs from 'node:fs';\nimport path from 'node:path';\n\nimport { normalizeAgentPluginMcpSource } from '@agimon-ai/doompi-config/agentPluginMcp';\nimport type { DoomMcpNativeProjectionSource } from '@agimon-ai/doompi-core/mcpProjection';\nimport { parse as parseYaml, stringify as stringifyYaml } from 'yaml';\n\nimport type { McpConfigGroups, McpConfigGroupsInput, McpConfigSource } from '../../types/mcpConfig';\n\n/** Wrapper entry used by non-Doom clients to expose `mcp-config.yaml` as one MCP. */\nexport const PROXY_SERVER_NAME = 'mcp-proxy';\n\nconst PROXY_SERVER_ALIASES = new Set([PROXY_SERVER_NAME, 'agiflow-proxy']);\nconst PRIVATE_FILE_MODE = 0o600;\nconst PRIVATE_DIRECTORY_MODE = 0o700;\nconst DEFAULT_UPSTREAM_CONFIG = 'mcp-config.yaml';\nconst CONFIG_ARGUMENT = '--config';\n\ntype JsonObject = Record<string, unknown>;\n\ninterface FilteredLayer {\n  source: McpConfigSource;\n  kept: string[];\n  dropped: string[];\n}\n\ninterface ConfigDocument {\n  config: JsonObject;\n  contents: string;\n}\n\nfunction isObject(value: unknown): value is JsonObject {\n  return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction isYamlPath(filePath: string): boolean {\n  const extension = path.extname(filePath).toLowerCase();\n  return extension === '.yaml' || extension === '.yml';\n}\n\nfunction readConfigDocument(filePath: string): ConfigDocument | undefined {\n  try {\n    const contents = fs.readFileSync(filePath, 'utf8');\n    const parsed: unknown = isYamlPath(filePath) ? parseYaml(contents) : JSON.parse(contents);\n    return isObject(parsed) ? { config: parsed, contents } : undefined;\n  } catch {\n    return undefined;\n  }\n}\n\nfunction readConfigObject(filePath: string): JsonObject | undefined {\n  return readConfigDocument(filePath)?.config;\n}\n\nfunction serverDefinitions(config: JsonObject | undefined): Record<string, unknown> {\n  return isObject(config?.mcpServers) ? config.mcpServers : {};\n}\n\nfunction isEnabledDefinition(definition: unknown): boolean {\n  return !isObject(definition) || definition.disabled !== true;\n}\n\nfunction isProxyWrapper(name: string): boolean {\n  return PROXY_SERVER_ALIASES.has(name);\n}\n\n/**\n * Resolves the upstream config referenced by the repository proxy wrapper.\n *\n * The wrapper remains useful to Claude, Codex, and other external clients. Doom\n * embeds the same client/runtime code, so it reads this path and connects each\n * declared server itself instead of starting the wrapper as a nested MCP.\n */\nfunction resolveSharedConfigPathFrom(repoRoot: string, repositoryConfigPath: string): string | undefined {\n  const servers = serverDefinitions(readConfigObject(repositoryConfigPath));\n  const proxy = [...PROXY_SERVER_ALIASES]\n    .map((name) => servers[name])\n    .find((definition): definition is JsonObject => isObject(definition));\n  const rawArgs: unknown = proxy?.args;\n  const args = Array.isArray(rawArgs) ? (rawArgs as unknown[]) : [];\n  const configArgumentIndex = args.indexOf(CONFIG_ARGUMENT);\n  const declared = args[configArgumentIndex + 1];\n  const candidate =\n    configArgumentIndex >= 0 && typeof declared === 'string'\n      ? path.resolve(repoRoot, declared)\n      : path.join(repoRoot, DEFAULT_UPSTREAM_CONFIG);\n  return fs.existsSync(candidate) ? candidate : undefined;\n}\n\nexport function resolveSharedConfigPath(repoRoot: string): string | undefined {\n  return resolveSharedConfigPathFrom(repoRoot, path.join(repoRoot, '.mcp.json'));\n}\n\n/** Empty and absent allowlists both mean \"keep everything\". */\nfunction isAllowed(name: string, allowed: string[] | undefined): boolean {\n  return !allowed || allowed.length === 0 || allowed.includes(name);\n}\n\nfunction stagedPath(filePath: string, contents: string, stagingDirectory: string): string {\n  // The filtered bytes are part of the identity because two live sessions can\n  // select different domains. Sharing a path would let the later one rewrite the\n  // configuration underneath the first one's deferred startup.\n  const digest = createHash('sha256').update(filePath).update('\\0').update(contents).digest('hex').slice(0, 16);\n  const extension = isYamlPath(filePath) ? '.yaml' : '.json';\n  return path.join(stagingDirectory, `mcp-${digest}${extension}`);\n}\n\nfunction serializeConfig(filePath: string, config: JsonObject): string {\n  return isYamlPath(filePath) ? stringifyYaml(config) : `${JSON.stringify(config, null, 2)}\\n`;\n}\n\nfunction layerCacheKey(\n  filePath: string,\n  format: McpConfigSource['format'],\n  originalContents: string,\n  effectiveContents: string,\n  sourceIdentity?: string,\n): string {\n  return createHash('sha256')\n    .update(format)\n    .update('\\0')\n    .update(fs.realpathSync(filePath))\n    .update('\\0')\n    .update(sourceIdentity ?? 'unprojected')\n    .update('\\0')\n    .update(originalContents)\n    .update('\\0')\n    .update(effectiveContents)\n    .digest('hex');\n}\n\n/**\n * Rewrites one config layer with disallowed servers removed.\n *\n * Proxy wrapper entries are stripped from `.mcp.json` layers because Doom reaches\n * their upstream config directly. Entries are removed rather than marked disabled,\n * so a filtered stdio server is never spawned at all.\n */\nfunction filterLayer(\n  filePath: string,\n  allowed: string[] | undefined,\n  stagingDirectory: string,\n  options: { stripProxyWrappers: boolean; sourceIdentity?: string },\n): FilteredLayer | undefined {\n  const document = readConfigDocument(filePath);\n  if (!document) return undefined;\n  const { config, contents: originalContents } = document;\n  const servers = serverDefinitions(config);\n  const kept: Record<string, unknown> = {};\n  const dropped: string[] = [];\n\n  for (const [name, definition] of Object.entries(servers)) {\n    const shouldDrop = (options.stripProxyWrappers && isProxyWrapper(name)) || !isAllowed(name, allowed);\n    if (shouldDrop) dropped.push(name);\n    else kept[name] = definition;\n  }\n\n  const keptNames = Object.entries(kept)\n    .filter(([, definition]) => isEnabledDefinition(definition))\n    .map(([name]) => name);\n  if (dropped.length === 0) {\n    return {\n      source: {\n        path: filePath,\n        format: 'claude',\n        cacheKey: layerCacheKey(filePath, 'claude', originalContents, originalContents, options.sourceIdentity),\n      },\n      kept: keptNames,\n      dropped,\n    };\n  }\n\n  fs.mkdirSync(stagingDirectory, { mode: PRIVATE_DIRECTORY_MODE, recursive: true });\n  const contents = serializeConfig(filePath, { ...config, mcpServers: kept });\n  const target = stagedPath(filePath, contents, stagingDirectory);\n  fs.writeFileSync(target, contents, { mode: PRIVATE_FILE_MODE });\n  return {\n    source: {\n      path: target,\n      format: 'claude',\n      cacheKey: layerCacheKey(filePath, 'claude', originalContents, contents, options.sourceIdentity),\n    },\n    kept: keptNames,\n    dropped,\n  };\n}\n\nfunction digestMatches(source: DoomMcpNativeProjectionSource): boolean {\n  try {\n    const digest = createHash('sha256').update(fs.readFileSync(source.configPath)).digest('hex');\n    return digest === source.contentDigest;\n  } catch {\n    return false;\n  }\n}\n\nfunction emptyGroups(diagnostics: string[] = []): McpConfigGroups {\n  return {\n    shared: { configSources: [], configPaths: [], serverNames: [] },\n    sessionLocal: { configSources: [], configPaths: [], serverNames: [] },\n    droppedServers: [],\n    diagnostics,\n  };\n}\n\n/**\n * Resolves every config layer for this session and applies its domain allowlist.\n *\n * All returned layers go into one embedded `@agimon-ai/mcp-proxy` client container.\n * The package is used as a library only: its wrapper MCP never becomes a Doom MCP\n * server, so status, enable/disable, resources, and OAuth stay attached to each\n * actual downstream server.\n */\nexport function buildMcpConfigGroups(input: McpConfigGroupsInput): McpConfigGroups {\n  if (input.enabled === false) return emptyGroups();\n\n  const projectedSources = input.sources;\n  const legacyLayers = projectedSources\n    ? []\n    : [\n        path.join(input.repoRoot, '.mcp.json'),\n        ...(input.pluginConfigPaths ?? []).map((candidate) => path.resolve(input.repoRoot, candidate)),\n      ].filter((candidate) => fs.existsSync(candidate));\n\n  const configSources: McpConfigSource[] = [];\n  const serverNames: string[] = [];\n  const droppedServers: string[] = [];\n  const diagnostics: string[] = [];\n  for (const layer of legacyLayers) {\n    const filtered = filterLayer(layer, input.allowlist?.servers, input.stagingDirectory, {\n      stripProxyWrappers: true,\n    });\n    if (!filtered) continue;\n    configSources.push(filtered.source);\n    serverNames.push(...filtered.kept);\n    droppedServers.push(...filtered.dropped);\n  }\n\n  for (const source of projectedSources ?? []) {\n    if (source.format === 'agent-plugin-v1') {\n      const normalized = normalizeAgentPluginMcpSource(source, {\n        stagingDirectory: input.stagingDirectory,\n        allowedServers: input.allowlist?.servers,\n      });\n      if (normalized.configSource) configSources.push(normalized.configSource);\n      serverNames.push(...normalized.serverNames);\n      droppedServers.push(...normalized.droppedServers);\n      diagnostics.push(...normalized.diagnostics);\n      continue;\n    }\n\n    if (!digestMatches(source)) {\n      diagnostics.push(\n        `Native MCP source \"${source.sourceId}\" was disabled: the file is missing or its content digest changed.`,\n      );\n      continue;\n    }\n    const filtered = filterLayer(source.configPath, input.allowlist?.servers, input.stagingDirectory, {\n      stripProxyWrappers: true,\n      sourceIdentity: `${source.sourceId}:${source.contentDigest}`,\n    });\n    if (!filtered) {\n      diagnostics.push(`Native MCP source \"${source.sourceId}\" was disabled: the config could not be parsed.`);\n      continue;\n    }\n    configSources.push(filtered.source);\n    serverNames.push(...filtered.kept);\n    droppedServers.push(...filtered.dropped);\n  }\n\n  const repositorySource = projectedSources?.find(\n    (source): source is DoomMcpNativeProjectionSource => source.format === 'native' && source.owner === 'repository',\n  );\n  const upstreamPath = projectedSources\n    ? repositorySource && digestMatches(repositorySource)\n      ? resolveSharedConfigPathFrom(input.repoRoot, repositorySource.configPath)\n      : undefined\n    : resolveSharedConfigPath(input.repoRoot);\n  const upstream = upstreamPath\n    ? filterLayer(upstreamPath, input.allowlist?.proxy, input.stagingDirectory, { stripProxyWrappers: true })\n    : undefined;\n  if (upstream) droppedServers.push(...upstream.dropped);\n\n  return {\n    shared: {\n      configSources: upstream ? [upstream.source] : [],\n      configPaths: upstream ? [upstream.source.path] : [],\n      serverNames: upstream ? upstream.kept : [],\n    },\n    // A later layer overriding an earlier one contributes the same name twice.\n    sessionLocal: {\n      configSources,\n      configPaths: configSources.map((source) => source.path),\n      serverNames: [...new Set(serverNames)],\n    },\n    droppedServers: [...new Set(droppedServers)],\n    diagnostics,\n  };\n}\n","import { createHash } from 'node:crypto';\nimport { readFileSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\n\nimport type { DoomOAuthRedirect } from '@agimon-ai/doompi-core/packageApi';\nimport type {\n  ConfigSource,\n  McpServerStateChange,\n  McpToolInfo,\n  OAuthCallbackSink,\n  SharedServices,\n  TokenStore,\n} from '@agimon-ai/mcp-proxy';\nimport mcpProxyPackage from '@agimon-ai/mcp-proxy/package.json' with { type: 'json' };\n\nimport type { McpConfigSource } from '../../types/mcpConfig';\nimport type { CachedCatalog } from '../../types/mcpRuntime';\n\n/**\n * Presents the hub's redirect surface as the proxy's callback collaborator.\n *\n * `listen` binds nothing: the hub already serves the address this advertises,\n * so opening a loopback port would only create one nobody redirects to.\n */\nexport function hubCallbackSink(redirect: DoomOAuthRedirect): OAuthCallbackSink {\n  return {\n    redirectUri: () => redirect.redirectUri,\n    getPort: () => undefined,\n    listen: (preferredPort) => Promise.resolve(preferredPort),\n    reserve: (state, timeoutMs) => redirect.reserve(state, timeoutMs),\n    waitForCallback: (state, timeoutMs) => redirect.wait(state, timeoutMs),\n    cancel: (state) => redirect.cancel(state),\n  };\n}\n\nexport interface McpRuntimeOptions {\n  /** Ordered config layers. Later layers override earlier ones. */\n  configSources: McpConfigSource[];\n  workspaceRoot?: string;\n  /** Exact session directory, independent of the checkout used for configuration. */\n  executionCwd?: string;\n  environment?: Readonly<Record<string, string | undefined>>;\n  tokenStore?: TokenStore;\n  /**\n   * Where OAuth redirects are received. Omitted, the proxy binds its own\n   * loopback listener, which only a browser on this machine can reach.\n   */\n  callbackServer?: OAuthCallbackSink;\n  onAuthorizationUrl?: (url: URL, serverName: string) => void;\n  onServerStateChange?: (change: McpServerStateChange) => void;\n}\n\nexport interface McpRuntimeHandle {\n  generation: number;\n  services: SharedServices;\n  /** Resolves once the first connection pass settles. Never rejects. */\n  connectionsSettled: Promise<void>;\n}\n\ninterface DefinitionsCacheFile {\n  oneMcpVersion?: string;\n  servers?: Record<string, { serverName: string; tools?: McpToolInfo[] }>;\n}\n\n/**\n * Definitions cache path shared by Doom's synchronous warm reader and mcp-proxy.\n *\n * Generated staging paths are deliberately absent: projected source content must\n * invalidate a reused path, while identical portable content must survive a new\n * private staging directory. Stable source origins are carried inside each cache\n * key; format and merge behavior remain part of the ordered identity.\n */\nexport function definitionsCachePath(configSources: readonly McpConfigSource[]): string {\n  if (configSources.length === 0) throw new Error('definitionsCachePath requires at least one config source');\n  const digest = createHash('sha256')\n    .update(\n      JSON.stringify(\n        configSources.map((source) => ({\n          cacheKey: source.cacheKey,\n          format: source.format,\n          optional: source.optional ?? false,\n          mergeStrategy: source.mergeStrategy ?? 'remote-priority',\n        })),\n      ),\n    )\n    .update('\\0')\n    .update(mcpProxyPackage.version)\n    .digest('hex');\n  return join(homedir(), '.mcp-proxy', `doompi-${digest}.definitions-cache.json`);\n}\n\n/**\n * Reads the catalog the previous run left behind.\n *\n * Synchronous on purpose: Pi has to be able to register these tools during\n * extension install, before it takes its first turn, and awaiting a file read\n * would let that turn start with an empty tool set. A miss is normal on a first\n * run and resolves to an empty catalog rather than an error.\n *\n * The file path is content-addressed from the current ordered layers, and its proxy\n * version is checked before any schema is registered. Servers filtered out of the\n * current configuration are also excluded later by `McpCatalog.seed`.\n */\nexport function readCachedCatalog(\n  configSources: readonly McpConfigSource[],\n  cachePathFor: (sources: readonly McpConfigSource[]) => string = definitionsCachePath,\n): CachedCatalog {\n  if (configSources.length === 0) return { servers: [] };\n  try {\n    const cachePath = cachePathFor(configSources);\n    const cache = JSON.parse(readFileSync(cachePath, 'utf8')) as Partial<DefinitionsCacheFile>;\n    if (cache.oneMcpVersion !== mcpProxyPackage.version) return { servers: [] };\n    const servers = Object.values(cache.servers ?? {}).map((server) => ({\n      name: server.serverName,\n      tools: server.tools ?? [],\n    }));\n    return { servers };\n  } catch {\n    return { servers: [] };\n  }\n}\n\nfunction toProxyConfigSource(source: McpConfigSource): ConfigSource {\n  return {\n    path: source.path,\n    format: source.format,\n    ...(source.optional === undefined ? {} : { optional: source.optional }),\n    ...(source.mergeStrategy === undefined ? {} : { mergeStrategy: source.mergeStrategy }),\n  };\n}\n\n/**\n * Owns the one live mcp-proxy container for this extension.\n *\n * Pi reloads extensions in process, so a connect that lands after a session restart\n * or a `/domains` switch would otherwise fold tools into a dead context. Every start\n * takes the next generation; anything an older generation produces is dropped and its\n * container disposed.\n */\nexport class McpRuntimeOwner {\n  private generation = 0;\n  private active: SharedServices | undefined;\n  private unsubscribe: (() => void) | undefined;\n\n  get currentGeneration(): number {\n    return this.generation;\n  }\n\n  /** The live container, or undefined before the first start and after dispose. */\n  getServices(): SharedServices | undefined {\n    return this.active;\n  }\n\n  /**\n   * Whether a container a caller captured earlier is still the live one.\n   *\n   * An async continuation that started under one container has to check this\n   * before writing its result, or a `/domains` switch would fold stale tools into\n   * the new session.\n   */\n  isCurrent(services: SharedServices | undefined): boolean {\n    return services !== undefined && services === this.active;\n  }\n\n  /**\n   * Starts a container for the current configuration, replacing any predecessor.\n   *\n   * Returns undefined when a newer generation started while this one was building,\n   * which is the signal for the caller to abandon its half-finished work.\n   */\n  async start(options: McpRuntimeOptions): Promise<McpRuntimeHandle | undefined> {\n    const generation = ++this.generation;\n    // Retired before the replacement is built so two containers never hold the same\n    // stdio children open at once.\n    await this.retire();\n    if (options.configSources.length === 0) return undefined;\n\n    // The proxy container pulls in transports, OAuth, schema conversion, and\n    // server implementations. Cached tool registration needs none of those, so\n    // load the runtime only after session_start has yielded control to Pi.\n    const { createProxyContainer } = await import('@agimon-ai/mcp-proxy');\n    const cachePath = definitionsCachePath(options.configSources);\n    const services = await createProxyContainer({\n      configSources: options.configSources.map(toProxyConfigSource),\n      workspaceRoot: options.workspaceRoot,\n      executionCwd: options.executionCwd,\n      environment: options.environment,\n      definitionsCachePath: cachePath,\n      // Never blocking: an unreachable server must not delay Pi's first prompt.\n      startupMode: 'background',\n      auth: {\n        tokenStore: options.tokenStore,\n        onAuthorizationUrl: options.onAuthorizationUrl,\n        ...(options.callbackServer ? { callbackServer: options.callbackServer } : {}),\n      },\n    });\n\n    if (generation !== this.generation) {\n      await services.dispose().catch(() => undefined);\n      return undefined;\n    }\n\n    this.active = services;\n    const forward = options.onServerStateChange;\n    if (forward) {\n      this.unsubscribe = services.clientManager.onServerStateChange((change) => {\n        if (generation === this.generation) forward(change);\n      });\n    }\n\n    return { generation, services, connectionsSettled: services.connectionsSettled };\n  }\n\n  /** Tears the container down and invalidates every generation still in flight. */\n  async dispose(): Promise<void> {\n    ++this.generation;\n    await this.retire();\n  }\n\n  private async retire(): Promise<void> {\n    this.unsubscribe?.();\n    this.unsubscribe = undefined;\n    const services = this.active;\n    this.active = undefined;\n    // A failed teardown must not leave the owner believing a dead container is live.\n    if (services) await services.dispose().catch(() => undefined);\n  }\n}\n","import os from 'node:os';\nimport path from 'node:path';\n\nimport {\n  DOOM_MCP_SESSION_ENV_VAR,\n  doomMcpSessionEnvironment,\n  readDoomMcpSessionConfig,\n} from '@agimon-ai/doompi-core/mcpSession';\n\nimport type { McpAllowlist, McpSessionConfig } from '../../types/mcpConfig';\n\nfunction asStringArray(value: unknown): string[] | undefined {\n  if (!Array.isArray(value)) return undefined;\n  const strings = value.filter((entry): entry is string => typeof entry === 'string' && entry.length > 0);\n  return strings.length > 0 ? strings : undefined;\n}\n\nfunction readAllowlist(value: unknown): McpAllowlist | undefined {\n  if (typeof value !== 'object' || value === null) return undefined;\n  const { servers, proxy } = value as { servers?: unknown; proxy?: unknown };\n  const allowlist: McpAllowlist = {};\n  const allowedServers = asStringArray(servers);\n  const allowedProxy = asStringArray(proxy);\n  if (allowedServers) allowlist.servers = allowedServers;\n  if (allowedProxy) allowlist.proxy = allowedProxy;\n  return allowlist.servers || allowlist.proxy ? allowlist : undefined;\n}\n\n/**\n * Resolves what this session should connect to.\n *\n * Every field falls back to a working default so the extension is usable outside\n * doom-pi: a bare Pi session in a repository still gets that repository's\n * `.mcp.json` with no allowlist. A malformed value is treated as absent rather\n * than fatal, because losing MCP is better than losing the session.\n */\nexport function readSessionConfig(\n  env: Readonly<Record<string, string | undefined>> = process.env,\n  defaultRepoRoot: string = process.cwd(),\n): McpSessionConfig {\n  const fallback: McpSessionConfig = {\n    repoRoot: defaultRepoRoot,\n    stagingDirectory: path.join(os.tmpdir(), 'doom-mcp'),\n  };\n\n  const strict = readDoomMcpSessionConfig(env);\n  if (strict) {\n    const { allowlist, pluginConfigPaths, ...required } = strict;\n    const strictAllowlist = readAllowlist(allowlist);\n    return {\n      ...required,\n      ...(pluginConfigPaths?.length ? { pluginConfigPaths: [...pluginConfigPaths] } : {}),\n      ...(strictAllowlist ? { allowlist: strictAllowlist } : {}),\n    };\n  }\n\n  const raw = env[DOOM_MCP_SESSION_ENV_VAR];\n  if (!raw) return fallback;\n\n  let parsed: unknown;\n  try {\n    parsed = JSON.parse(raw);\n  } catch {\n    return fallback;\n  }\n  if (typeof parsed !== 'object' || parsed === null) return fallback;\n\n  const { repoRoot, generatedConfigPath, pluginConfigPaths, allowlist, stagingDirectory } = parsed as Record<\n    string,\n    unknown\n  >;\n  const resolvedRoot = typeof repoRoot === 'string' && repoRoot ? repoRoot : fallback.repoRoot;\n  const generatedConfig =\n    typeof generatedConfigPath === 'string' && generatedConfigPath ? generatedConfigPath : undefined;\n  const plugins = asStringArray(pluginConfigPaths);\n  const resolvedAllowlist = readAllowlist(allowlist);\n  const staging =\n    typeof stagingDirectory === 'string' && stagingDirectory ? stagingDirectory : fallback.stagingDirectory;\n\n  return {\n    repoRoot: resolvedRoot,\n    stagingDirectory: staging,\n    ...(generatedConfig ? { generatedConfigPath: generatedConfig } : {}),\n    ...(plugins ? { pluginConfigPaths: plugins } : {}),\n    ...(resolvedAllowlist ? { allowlist: resolvedAllowlist } : {}),\n  };\n}\n\n/** Serializes the configuration for the Pi child process doom-pi launches. */\nexport function sessionConfigEnvironment(config: McpSessionConfig): Record<string, string> {\n  return doomMcpSessionEnvironment(config);\n}\n","/** Environment variable carrying a child agent's MCP tool selection. */\nexport const DIRECT_TOOLS_ENV = 'MCP_DIRECT_TOOLS';\n\n/** Explicit \"no MCP tools\", distinct from an unset variable meaning \"no limit\". */\nexport const NO_DIRECT_TOOLS = '__none__';\n","import type { DoomMcpResolvedToolSelection } from '@agimon-ai/doompi-core/mcpToolResolver';\n\nimport type { McpServerView } from '../../types/mcp';\nimport type {\n  McpCatalogSnapshot,\n  McpCatalogState,\n  McpCatalogStateChange,\n  McpCatalogToolInput,\n} from '../../types/mcpCatalog';\nimport type { CachedCatalog } from '../../types/mcpRuntime';\nimport type { DirectToolFilter } from '../directTools';\n\n/** One downstream tool, with the name Pi will know it by. */\nexport interface CatalogTool {\n  /** Name registered with Pi, prefixed by server. */\n  piName: string;\n  /** Name the downstream server knows. */\n  toolName: string;\n  serverName: string;\n  description?: string;\n  inputSchema: Record<string, unknown>;\n  annotations?: McpCatalogToolInput['annotations'];\n  outputSchema?: McpCatalogToolInput['outputSchema'];\n}\n\nexport interface CatalogEntry {\n  name: string;\n  /**\n   * The last transition the server actually reported.\n   *\n   * Never `disabled`: a session disable is an override the user applied, not\n   * something the server did, so it lives in its own field. Writing it into\n   * `state` would destroy the value re-enabling has to return to.\n   */\n  state: McpCatalogState;\n  /** Session-only override. Survives nothing; a restart returns to configuration. */\n  disabled?: boolean;\n  tools: CatalogTool[];\n  resourceCount: number;\n  error?: string;\n}\n\n/**\n * States where calling a tool cannot succeed, so its tools are withheld.\n *\n * `closed` is absent deliberately: a server closed after an idle timeout is\n * reconnected by the next call rather than gone. `disabled` is absent because it is\n * no longer a reachable transition; `entry.disabled` carries that instead.\n */\nconst UNAVAILABLE_STATES = new Set<McpCatalogState>(['failed', 'needs-auth']);\n\n/** Where a server starts: known to the session, not yet dialled. */\nconst NOT_CONNECTED: McpCatalogState = 'not-connected';\nconst DISABLED: McpCatalogState = 'disabled';\nconst ALL_SERVERS_SELECTOR = '*';\nconst SELECTOR_SEPARATOR = '/';\n\n/**\n * Pi's tool name for a downstream tool.\n *\n * Always prefixed, matching what `pi-mcp-adapter` produced by default. Tool names\n * are a contract with agent frontmatter selectors, transcripts, and user habit, so\n * they stay stable across the swap rather than following mcp-proxy's internal\n * scheme, which prefixes only on a clash.\n */\nexport function toPiToolName(serverName: string, toolName: string): string {\n  return `${serverName.replace(/[^a-zA-Z0-9]/g, '_')}_${toolName}`;\n}\n\nfunction toCatalogTool(serverName: string, tool: McpCatalogToolInput): CatalogTool {\n  return {\n    piName: toPiToolName(serverName, tool.name),\n    toolName: tool.name,\n    serverName,\n    ...(tool.description ? { description: tool.description } : {}),\n    inputSchema: tool.inputSchema,\n    ...(tool.annotations === undefined ? {} : { annotations: tool.annotations }),\n    ...(tool.outputSchema === undefined ? {} : { outputSchema: tool.outputSchema }),\n  };\n}\n\n/**\n * The session's MCP servers and the tools registered for each.\n *\n * Seeded from the previous run's catalog so tools exist before any socket opens,\n * then folded forward as servers report in. Tools are never removed: Pi 0.84 has no\n * way to unregister one, so a tool whose server later fails stays registered and is\n * simply left out of the active set.\n */\nexport class McpCatalog {\n  private readonly entries = new Map<string, CatalogEntry>();\n  private readonly diagnostics: string[] = [];\n  /** Pi names already claimed, so two servers cannot register the same one. */\n  private readonly claimed = new Map<string, string>();\n\n  /**\n   * @param directTools - A child agent's tool selection. Undefined in a normal\n   *   session, where every configured tool is available.\n   */\n  constructor(private readonly directTools?: DirectToolFilter) {}\n\n  /**\n   * Seeds the servers this session will connect to, all still `not-connected`.\n   *\n   * Configured names come first so a run with no cache still reports what it is\n   * about to reach rather than looking empty; the cache then fills in their tools.\n   * A cached server that configuration has since dropped is not seeded at all.\n   */\n  seed(catalog: CachedCatalog, configuredServers: readonly string[] = []): void {\n    for (const name of configuredServers) {\n      this.entries.set(name, { name, state: NOT_CONNECTED, tools: [], resourceCount: 0 });\n    }\n    for (const server of catalog.servers) {\n      if (configuredServers.length > 0 && !this.entries.has(server.name)) continue;\n      this.entries.set(server.name, {\n        name: server.name,\n        state: NOT_CONNECTED,\n        tools: this.claimTools(server.name, server.tools),\n        resourceCount: 0,\n      });\n    }\n  }\n\n  /**\n   * Hides or restores a server's tools for this session.\n   *\n   * Only the flag moves: `state` keeps tracking what the server reports, so\n   * re-enabling lands on the current truth rather than on a remembered value that\n   * may have gone stale while the server was hidden.\n   */\n  setDisabled(serverName: string, disabled: boolean): void {\n    const entry = this.entries.get(serverName);\n    if (entry) entry.disabled = disabled;\n    else\n      this.entries.set(serverName, { name: serverName, state: NOT_CONNECTED, disabled, tools: [], resourceCount: 0 });\n  }\n\n  /** Records how many resources a server offered the last time they were listed. */\n  setResourceCount(serverName: string, resourceCount: number): void {\n    const entry = this.entries.get(serverName);\n    if (entry) entry.resourceCount = resourceCount;\n  }\n\n  /**\n   * Folds a live server transition into the catalog.\n   *\n   * Returns the tools that are new to this catalog, which is what the caller has to\n   * register with Pi. A reconnect returns nothing, since its tools already exist.\n   */\n  applyStateChange(\n    change: McpCatalogStateChange,\n    tools?: McpCatalogToolInput[],\n    resourceCount?: number,\n  ): CatalogTool[] {\n    const entry = this.entries.get(change.serverName) ?? {\n      name: change.serverName,\n      state: change.state,\n      tools: [],\n      resourceCount: 0,\n    };\n    entry.state = change.state;\n    if (change.error) entry.error = change.error;\n    else delete entry.error;\n    if (resourceCount !== undefined) entry.resourceCount = resourceCount;\n\n    if (change.state === 'connected' && tools !== undefined) {\n      const known = new Map(entry.tools.map((tool) => [tool.toolName, tool]));\n      const next: CatalogTool[] = [];\n      const added: CatalogTool[] = [];\n      for (const tool of tools) {\n        const current = known.get(tool.name);\n        if (current !== undefined) {\n          next.push(toCatalogTool(change.serverName, tool));\n          continue;\n        }\n        const [claimed] = this.claimTools(change.serverName, [tool]);\n        if (claimed !== undefined) {\n          next.push(claimed);\n          added.push(claimed);\n        }\n      }\n      entry.tools = next;\n      this.entries.set(change.serverName, entry);\n      return added;\n    }\n    this.entries.set(change.serverName, entry);\n    return [];\n  }\n\n  /**\n   * Tool names Pi should currently expose.\n   *\n   * Optimistic: a server that has not reported yet still contributes its cached\n   * tools, because calling one connects it on demand. The live background pass can\n   * take longer than Pi startup, so requiring `connected` first would make a warm\n   * session needlessly start with no tools.\n   *\n   * Only a server that is known to be unusable, or one the user disabled, is held\n   * back.\n   */\n  activeToolNames(): string[] {\n    const names: string[] = [];\n    for (const entry of this.entries.values()) {\n      if (entry.disabled || UNAVAILABLE_STATES.has(entry.state)) continue;\n      for (const tool of entry.tools) {\n        if (this.directTools && !this.directTools.allows(entry.name, tool.toolName)) continue;\n        names.push(tool.piName);\n      }\n    }\n    return names;\n  }\n\n  /** Every tool ever registered, whether or not its server is reachable. */\n  allTools(): CatalogTool[] {\n    return [...this.entries.values()].flatMap((entry) => entry.tools);\n  }\n\n  /** Resolve configured selectors only to tool names this authoritative catalog confirms. */\n  resolveToolSelectors(selectors: readonly string[]): readonly DoomMcpResolvedToolSelection[] {\n    let allServers = false;\n    const selectedServers = new Set<string>();\n    const selectedTools = new Map<string, Set<string>>();\n    for (const selection of selectors) {\n      const item = selection.trim().replace(/\\/+$/u, '');\n      if (!item) continue;\n      if (item === ALL_SERVERS_SELECTOR) {\n        allServers = true;\n        continue;\n      }\n      const separator = item.indexOf(SELECTOR_SEPARATOR);\n      if (separator === -1) {\n        selectedServers.add(item);\n        continue;\n      }\n      const server = item.slice(0, separator);\n      const tool = item.slice(separator + 1);\n      if (!server) continue;\n      if (!tool) {\n        selectedServers.add(server);\n        continue;\n      }\n      const names = selectedTools.get(server) ?? new Set<string>();\n      names.add(tool);\n      selectedTools.set(server, names);\n    }\n\n    const resolved: DoomMcpResolvedToolSelection[] = [];\n    const seen = new Set<string>();\n    for (const tool of this.allTools()) {\n      const wholeServer = allServers || selectedServers.has(tool.serverName);\n      if (!wholeServer && !selectedTools.get(tool.serverName)?.has(tool.toolName)) continue;\n      if (seen.has(tool.piName)) continue;\n      seen.add(tool.piName);\n      resolved.push({ name: tool.piName, selector: `${tool.serverName}${SELECTOR_SEPARATOR}${tool.toolName}` });\n    }\n    return resolved;\n  }\n\n  findTool(piName: string): CatalogTool | undefined {\n    return this.allTools().find((tool) => tool.piName === piName);\n  }\n\n  /**\n   * The cross-extension status shape.\n   *\n   * A disabled server reports `disabled` as its state, because that is the one word\n   * the wire contract has for \"configured but contributing nothing\", and consumers\n   * outside this process have no use for the transition underneath it.\n   */\n  toSnapshot(): McpCatalogSnapshot {\n    return {\n      servers: [...this.entries.values()].map((entry) => ({\n        name: entry.name,\n        state: entry.disabled ? DISABLED : entry.state,\n        tools: entry.tools.map((tool) => tool.piName),\n        resourceCount: entry.resourceCount,\n        ...(entry.error ? { error: entry.error } : {}),\n      })),\n    };\n  }\n\n  /**\n   * The fuller picture the overlay renders.\n   *\n   * Carries what the snapshot cannot: each tool's downstream name and description,\n   * whether a child agent's selection withholds it, and `enabled` as its own field\n   * so the overlay can offer disable and enable against the real server state.\n   */\n  toView(): McpServerView[] {\n    return [...this.entries.values()].map((entry) => ({\n      name: entry.name,\n      state: entry.state,\n      tools: entry.tools.map((tool) => ({\n        piName: tool.piName,\n        toolName: tool.toolName,\n        ...(tool.description ? { description: tool.description } : {}),\n        active: !this.directTools || this.directTools.allows(entry.name, tool.toolName),\n      })),\n      resourceCount: entry.resourceCount,\n      enabled: !entry.disabled,\n      ...(entry.error ? { error: entry.error } : {}),\n    }));\n  }\n\n  /** Problems worth surfacing to the user. Reported, never thrown. */\n  getDiagnostics(): readonly string[] {\n    return this.diagnostics;\n  }\n\n  /**\n   * Records a problem for the user without interrupting whatever hit it.\n   *\n   * Deduplicated: a fault that recurs on every repaint would otherwise grow this\n   * list for as long as the session runs, and the second copy tells nobody\n   * anything the first did not.\n   */\n  addDiagnostic(diagnostic: string): void {\n    if (!this.diagnostics.includes(diagnostic)) this.diagnostics.push(diagnostic);\n  }\n\n  /**\n   * Assigns Pi names, dropping any that another server already owns.\n   *\n   * Two server names that normalize to the same prefix (`code-intel` and\n   * `code_intel`) would otherwise have one silently shadow the other's tool.\n   */\n  private claimTools(serverName: string, tools: McpCatalogToolInput[]): CatalogTool[] {\n    const claimed: CatalogTool[] = [];\n    for (const tool of tools) {\n      const candidate = toCatalogTool(serverName, tool);\n      const owner = this.claimed.get(candidate.piName);\n      if (owner !== undefined && owner !== serverName) {\n        this.diagnostics.push(\n          `MCP tool \"${candidate.piName}\" from \"${serverName}\" was dropped: \"${owner}\" already registered that name.`,\n        );\n        continue;\n      }\n      this.claimed.set(candidate.piName, serverName);\n      claimed.push(candidate);\n    }\n    return claimed;\n  }\n}\n"],"mappings":"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"}