@agimon-ai/doompi-mcp 0.0.1-alpha.89 → 0.0.1-alpha.90

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/dist/extensions/pi.cjs +10 -6
  2. package/dist/extensions/pi.cjs.map +1 -1
  3. package/dist/extensions/pi.mjs +8 -5
  4. package/dist/extensions/pi.mjs.map +1 -1
  5. package/dist/extensions/server.cjs +57 -14
  6. package/dist/extensions/server.cjs.map +1 -1
  7. package/dist/extensions/server.mjs +52 -10
  8. package/dist/extensions/server.mjs.map +1 -1
  9. package/dist/index.cjs +1 -1
  10. package/dist/index.d.mts.map +1 -1
  11. package/dist/index.mjs +1 -1
  12. package/dist/{keyringTokenStore-BwvTXKvD.cjs → keyringTokenStore-LBsDb_eC.cjs} +3 -3
  13. package/dist/{keyringTokenStore-BwvTXKvD.cjs.map → keyringTokenStore-LBsDb_eC.cjs.map} +1 -1
  14. package/dist/{mcpCatalog-nbZdP5rF.cjs → mcpCatalog-Bnkul3t_.cjs} +10 -49
  15. package/dist/mcpCatalog-Bnkul3t_.cjs.map +1 -0
  16. package/dist/{mcpCatalog-zoD27CZd.mjs → mcpCatalog-laXfwecc.mjs} +4 -1
  17. package/dist/mcpCatalog-laXfwecc.mjs.map +1 -0
  18. package/dist/{mcpCommand-btmh62JV.cjs → mcpCommand-BARs6Y1N.cjs} +14 -5
  19. package/dist/mcpCommand-BARs6Y1N.cjs.map +1 -0
  20. package/dist/{mcpCommand-CIkm3j9w.mjs → mcpCommand-BaJXXphd.mjs} +14 -5
  21. package/dist/mcpCommand-BaJXXphd.mjs.map +1 -0
  22. package/dist/projection-gyAA2jRB.mjs +43 -0
  23. package/dist/projection-gyAA2jRB.mjs.map +1 -0
  24. package/dist/projection-w3XxXmVi.cjs +51 -0
  25. package/dist/projection-w3XxXmVi.cjs.map +1 -0
  26. package/dist/projection.cjs +1 -1
  27. package/dist/projection.d.mts +3 -5
  28. package/dist/projection.d.mts.map +1 -1
  29. package/dist/projection.mjs +1 -1
  30. package/dist/rolldown-runtime-C0BPl7ul.cjs +43 -0
  31. package/package.json +8 -8
  32. package/dist/mcpCatalog-nbZdP5rF.cjs.map +0 -1
  33. package/dist/mcpCatalog-zoD27CZd.mjs.map +0 -1
  34. package/dist/mcpCommand-CIkm3j9w.mjs.map +0 -1
  35. package/dist/mcpCommand-btmh62JV.cjs.map +0 -1
  36. package/dist/projection-BJEX-pTt.mjs +0 -24
  37. package/dist/projection-BJEX-pTt.mjs.map +0 -1
  38. package/dist/projection-ZDNTQ3iE.cjs +0 -29
  39. package/dist/projection-ZDNTQ3iE.cjs.map +0 -1
@@ -2,11 +2,12 @@ Object.defineProperties(exports, {
2
2
  __esModule: { value: true },
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
- const require_mcpCatalog = require("../mcpCatalog-nbZdP5rF.cjs");
6
- const require_projection = require("../projection-ZDNTQ3iE.cjs");
7
- const require_mcpCommand = require("../mcpCommand-btmh62JV.cjs");
5
+ const require_rolldown_runtime = require("../rolldown-runtime-C0BPl7ul.cjs");
6
+ const require_mcpCatalog = require("../mcpCatalog-Bnkul3t_.cjs");
7
+ const require_projection = require("../projection-w3XxXmVi.cjs");
8
+ const require_mcpCommand = require("../mcpCommand-BARs6Y1N.cjs");
8
9
  let node_path = require("node:path");
9
- node_path = require_mcpCatalog.__toESM(node_path, 1);
10
+ node_path = require_rolldown_runtime.__toESM(node_path, 1);
10
11
  let _agimon_ai_doompi_core_mcpProjection = require("@agimon-ai/doompi-core/mcpProjection");
11
12
  let _agimon_ai_doompi_core_piExtension = require("@agimon-ai/doompi-core/piExtension");
12
13
  let _agimon_ai_doompi_core_extensionFile = require("@agimon-ai/doompi-core/extensionFile");
@@ -83,7 +84,7 @@ function createMcpPiRuntime(runtime) {
83
84
  };
84
85
  const stopPublishing = session.onChange(publishServerStatus);
85
86
  publishServerStatus();
86
- if (mode === "standalone") await session.reconfigure(require_mcpCatalog.readSessionConfig(process.env, context.cwd));
87
+ if (mode === "standalone") await session.reconfigure(require_mcpCatalog.readSessionConfig(process.env, context.cwd), context.cwd);
87
88
  else {
88
89
  await session.reconfigure(failClosedSessionConfig(context.cwd));
89
90
  sessionContext.inject([_agimon_ai_doompi_core_mcpProjection.DOOM_MCP_PROJECTION_SERVICE], async (projectionContext) => {
@@ -91,7 +92,10 @@ function createMcpPiRuntime(runtime) {
91
92
  if (!projection || projection.sessionId !== expectedSessionId) {
92
93
  await session.reconfigure(failClosedSessionConfig(context.cwd));
93
94
  if (projection && sessionActive && !disposed) context.ui?.notify(`The Doom MCP projection belongs to session "${projection.sessionId}", not "${expectedSessionId}"; MCP is disabled.`, WARNING);
94
- } else await session.reconfigure(require_projection.mcpSessionConfigFromProjection(projection.getSnapshot()));
95
+ } else {
96
+ const snapshot = projection.getSnapshot();
97
+ await session.reconfigure(require_projection.mcpSessionConfigFromProjection(snapshot, context.cwd), context.cwd, snapshot.repoRoot);
98
+ }
95
99
  return async () => {
96
100
  if (sessionActive && !disposed) await session.reconfigure(failClosedSessionConfig(context.cwd));
97
101
  };
@@ -1 +1 @@
1
- {"version":3,"file":"pi.cjs","names":["PACKAGE_SOURCE","LEADER_BINDING_PREFIX","LEADER_GROUP","LEADER_DETAIL","path","McpSession","DOOM_UI_HUB_SERVICE","requireDoomUiHub","DOOM_TOOL_SURFACE_SERVICE","requireDoomToolSurface","DOOM_CORDIS_SESSION_SERVICE","MCP_STATUS_KEY","MCP_SESSION_AUTH_STATUS_KEY","formatMcpSessionAuthStatus","readSessionConfig","DOOM_MCP_PROJECTION_SERVICE","readDoomMcpProjectionService","mcpSessionConfigFromProjection","createMcpSessionToolsService","createMcpChildTool","DOOM_MCP_STATUS_SERVICE","DOOM_MCP_TOOL_RESOLVER_SERVICE","MCP_SESSION_TOOLS_SERVICE","DOOM_CHILD_SESSION_MCP_TOOL_SERVICE","defineRoot","defineRoutedContribution","createMcpCommand","defineResource","createMcpTool","wrapTextWithAnsi","truncateToWidth","renderToolHeading","DoomToolCall","defineRoutedContribution","definePiExtension","rootSession","composeRootHooks","commandMcp","resourceDoompiUseMcp","piToolContributions","toolMcp"],"sources":["../../src/services/leader/index.ts","../../src/services/piRuntime/index.ts","../../src/extensions/workspaces/sessions/(backend)/_lib/piRoot.ts","../../src/extensions/workspaces/sessions/(backend)/root.cli.ts","../../src/extensions/workspaces/sessions/(backend)/command/mcp.cli.ts","../../src/extensions/workspaces/sessions/(backend)/resource/doompi-use-mcp.cli.ts","../../src/services/mcpToolCollection/index.ts","../../src/tui/mcpToolRender.ts","../../src/extensions/workspaces/sessions/(backend)/tool/mcp.cli.ts","../../generated/pi.ts"],"sourcesContent":["import type { DoomUiHubService } from '@agimon-ai/doompi-core/uiHub';\n\nimport { COMMAND_NAME } from '../../constants/mcp';\nimport {\n LEADER_BINDING_PREFIX,\n LEADER_DETAIL,\n LEADER_GROUP,\n LEADER_KEY,\n LEADER_LABEL,\n PACKAGE_SOURCE,\n} from '../../constants/piMcp';\n\nexport function registerLeaderContribution(hub: DoomUiHubService): () => void {\n const contribution = hub.registerLeader({\n source: PACKAGE_SOURCE,\n bindings: [\n {\n id: `${LEADER_BINDING_PREFIX}.open`,\n path: [LEADER_GROUP, { key: LEADER_KEY, label: LEADER_LABEL, detail: LEADER_DETAIL }],\n command: { name: COMMAND_NAME },\n },\n ],\n });\n return () => contribution.dispose();\n}\n","import path from 'node:path';\n\nimport { DOOM_CHILD_SESSION_MCP_TOOL_SERVICE } from '@agimon-ai/doompi-core/childSession';\nimport type { DoomCordisRuntimeService } from '@agimon-ai/doompi-core/cordisHost';\nimport { DOOM_CORDIS_SESSION_SERVICE, type DoomCordisSessionService } from '@agimon-ai/doompi-core/cordisHost';\nimport { DOOM_MCP_PROJECTION_SERVICE, readDoomMcpProjectionService } from '@agimon-ai/doompi-core/mcpProjection';\nimport { DOOM_MCP_STATUS_SERVICE, type DoomMcpStatusService } from '@agimon-ai/doompi-core/mcpStatus';\nimport {\n DOOM_MCP_TOOL_RESOLVER_SERVICE,\n type DoomMcpToolResolverService,\n} from '@agimon-ai/doompi-core/mcpToolResolver';\nimport { DOOM_TOOL_SURFACE_SERVICE, requireDoomToolSurface } from '@agimon-ai/doompi-core/toolSurface';\nimport { DOOM_UI_HUB_SERVICE, requireDoomUiHub } from '@agimon-ai/doompi-core/uiHub';\nimport type { Context } from '@deepseek-ai/cordis';\nimport type { ExtensionContext } from '@earendil-works/pi-coding-agent';\n\nimport { MCP_STATUS_KEY } from '../../constants/piMcp';\nimport { McpSession } from '../../services/mcpSession';\nimport { mcpSessionConfigFromProjection } from '../../services/projection';\nimport { readSessionConfig } from '../../services/sessionConfig';\nimport type { McpSessionConfig } from '../../types/mcpConfig';\nimport { formatMcpSessionAuthStatus, MCP_SESSION_AUTH_STATUS_KEY } from '../../types/webMcp';\nimport { registerLeaderContribution } from '../leader';\nimport { createMcpChildTool, createMcpSessionToolsService, MCP_SESSION_TOOLS_SERVICE } from '../mcpSessionTools';\n\nconst INFO = 'info';\nconst WARNING = 'warning';\n\nfunction failClosedSessionConfig(cwd: string): McpSessionConfig {\n return {\n enabled: false,\n repoRoot: cwd,\n stagingDirectory: path.join(cwd, '.doom', 'mcp-disabled'),\n sources: [],\n };\n}\n\nexport function createMcpPiRuntime(runtime: DoomCordisRuntimeService) {\n const mode = runtime.mode;\n let activeContext: ExtensionContext | undefined;\n let disposed = false;\n const session = new McpSession({\n onAuthorizationUrl: async (url, serverName, { openBrowser }) => {\n const context = activeContext;\n if (context?.mode === 'tui') {\n if (!openBrowser) return;\n try {\n const { default: open } = await import('open');\n await open(url.toString());\n } catch (error) {\n context.ui.notify(\n `Could not open the authorization page for ${serverName}: ${error instanceof Error ? error.message : String(error)}. Press a in the MCP overlay to retry.`,\n WARNING,\n );\n throw error;\n }\n return;\n }\n context?.ui?.notify(`Authorize ${serverName} by opening:\\n${url.toString()}`, INFO);\n },\n });\n\n return {\n session,\n services: [\n (cordis: Context) => {\n cordis.inject([DOOM_UI_HUB_SERVICE], (uiContext) => registerLeaderContribution(requireDoomUiHub(uiContext)));\n // The surface lives on the session fiber, so this resolves after install has\n // already registered the cached wrappers: binding is what first hides the ones\n // no server has confirmed.\n cordis.inject([DOOM_TOOL_SURFACE_SERVICE], (surfaceContext) =>\n session.bindToolSurface(requireDoomToolSurface(surfaceContext)),\n );\n cordis.inject([DOOM_CORDIS_SESSION_SERVICE], async (sessionContext) => {\n const hostSession = sessionContext.get(DOOM_CORDIS_SESSION_SERVICE) as DoomCordisSessionService;\n const context = hostSession.context;\n const expectedSessionId = hostSession.sessionId;\n let sessionActive = true;\n activeContext = context;\n // The legacy server-name status remains available to every UI. The compact\n // authorization status is browser-only so the TUI footer stays unchanged.\n const publishServerStatus = (): void => {\n const servers = session.getSnapshot().servers;\n const names = servers.map((server) => server.name).join(',');\n context.ui?.setStatus(MCP_STATUS_KEY, names);\n if (context.mode !== 'tui') {\n context.ui?.setStatus(MCP_SESSION_AUTH_STATUS_KEY, formatMcpSessionAuthStatus(session.getServers()));\n }\n };\n const stopPublishing = session.onChange(publishServerStatus);\n publishServerStatus();\n\n if (mode === 'standalone') {\n await session.reconfigure(readSessionConfig(process.env, context.cwd));\n } else {\n await session.reconfigure(failClosedSessionConfig(context.cwd));\n sessionContext.inject([DOOM_MCP_PROJECTION_SERVICE], async (projectionContext) => {\n const projection = readDoomMcpProjectionService(projectionContext);\n if (!projection || projection.sessionId !== expectedSessionId) {\n await session.reconfigure(failClosedSessionConfig(context.cwd));\n if (projection && sessionActive && !disposed) {\n context.ui?.notify(\n `The Doom MCP projection belongs to session \"${projection.sessionId}\", not \"${expectedSessionId}\"; MCP is disabled.`,\n WARNING,\n );\n }\n } else {\n await session.reconfigure(mcpSessionConfigFromProjection(projection.getSnapshot()));\n }\n return async () => {\n if (sessionActive && !disposed) await session.reconfigure(failClosedSessionConfig(context.cwd));\n };\n });\n }\n\n const status: DoomMcpStatusService = Object.freeze({\n generation: `${hostSession.generation}:mcp-status`,\n getSnapshot: () => session.getSnapshot(),\n onChange: (listener: () => void) => session.onChange(listener),\n });\n const toolResolver: DoomMcpToolResolverService = Object.freeze({\n generation: `${hostSession.generation}:mcp-tool-resolver`,\n resolve: (selectors: readonly string[]) => session.resolveToolSelectors(selectors),\n });\n const sessionTools = createMcpSessionToolsService(session, `${hostSession.generation}:mcp-tools`);\n const childTool = createMcpChildTool(async (parameters, signal) => {\n if (!sessionActive || disposed) throw new Error('The parent MCP session is no longer available.');\n const tool = sessionTools\n .snapshot()\n .find(\n (candidate) => candidate.serverName === parameters.server && candidate.toolName === parameters.tool,\n );\n if (!tool)\n throw new Error(\n `MCP tool ${parameters.server}/${parameters.tool} is not available in the current session configuration.`,\n );\n return sessionTools.invoke(tool.piName, parameters.arguments ?? {}, signal);\n });\n sessionContext.plugin((providerContext) => {\n providerContext.provide(DOOM_MCP_STATUS_SERVICE, status);\n providerContext.provide(DOOM_MCP_TOOL_RESOLVER_SERVICE, toolResolver);\n providerContext.provide(MCP_SESSION_TOOLS_SERVICE, sessionTools);\n providerContext.provide(DOOM_CHILD_SESSION_MCP_TOOL_SERVICE, childTool);\n });\n for (const diagnostic of session.getDiagnostics()) context.ui?.notify(diagnostic, WARNING);\n return async () => {\n sessionActive = false;\n stopPublishing();\n context.ui?.setStatus(MCP_STATUS_KEY, undefined);\n if (context.mode !== 'tui') context.ui?.setStatus(MCP_SESSION_AUTH_STATUS_KEY, undefined);\n if (activeContext === context) activeContext = undefined;\n if (!disposed) await session.reconfigure(failClosedSessionConfig(context.cwd));\n };\n });\n },\n ],\n async onDispose() {\n disposed = true;\n activeContext = undefined;\n await session.dispose();\n },\n };\n}\n","import type { PiPluginContext } from '@agimon-ai/doompi-core/piExtension';\n\nimport { createMcpPiRuntime } from '../../../../../services/piRuntime';\nexport const createMcpPiRoot = ({ runtime }: PiPluginContext) => {\n if (!runtime) throw new Error('MCP requires the Cordis runtime mode.');\n const state = createMcpPiRuntime(runtime);\n return { value: state, services: state.services, onDispose: () => state.onDispose() };\n};\nexport type McpPiScope = Awaited<ReturnType<typeof createMcpPiRoot>>['value'];\n","import { defineRoot } from '@agimon-ai/doompi-core/extensionFile';\n\nimport { createMcpPiRoot } from './_lib/piRoot';\n\nexport default defineRoot(createMcpPiRoot);\n","import { defineRoutedContribution, type WithRoot } from '@agimon-ai/doompi-core/extensionFile';\nimport type { PiPluginContext } from '@agimon-ai/doompi-core/piExtension';\n\nimport { createMcpCommand } from '../../../../../services/mcpCommand';\nimport type { McpPiScope } from '../_lib/piRoot';\nexport default defineRoutedContribution(\n (context: WithRoot<PiPluginContext<unknown>, McpPiScope>) =>\n [\n createMcpCommand(context.root.session, {\n openOverlay: async (ctx) => {\n const { openMcpOverlay } = await import('../../../../../tui/mcpOverlay');\n return openMcpOverlay(ctx, context.root.session);\n },\n }),\n ] as const,\n { cardinality: 'many' },\n);\n","import { defineResource } from '@agimon-ai/doompi-core/extensionFile';\n\nexport default defineResource({\n source: '@agimon-ai/doompi-mcp',\n moduleUrl: import.meta.url,\n skills: [\n {\n name: 'doompi-use-mcp',\n description:\n 'Use Doom Pi MCP to inspect domain-scoped servers, authenticate, reload configuration, and troubleshoot tool availability.',\n },\n ],\n});\n","import type { PiToolCollection, PiToolDeclaration } from '@agimon-ai/doompi-core/piExtension';\n\nimport type { CatalogTool } from '../../services/mcpCatalog';\nimport type { McpSession } from '../../services/mcpSession';\nimport { createMcpTool, type McpToolRenderers } from '../mcpTools';\nexport function createMcpToolCollection(\n session: McpSession,\n renderers: (tool: CatalogTool) => McpToolRenderers = () => ({}),\n): PiToolCollection {\n const declarations = new Map<CatalogTool, PiToolDeclaration>();\n return {\n snapshot: (): readonly PiToolDeclaration[] =>\n session.toolDefinitions().map((tool) => {\n let declaration = declarations.get(tool);\n if (!declaration) {\n declaration = createMcpTool(\n session.getClientManager,\n tool,\n (candidate) => session.isToolAvailable(candidate),\n renderers(tool),\n );\n declarations.set(tool, declaration);\n }\n return declaration;\n }),\n subscribe: (listener: () => void) => session.onChange(listener),\n };\n}\n","import { DoomToolCall, renderToolHeading } from '@agimon-ai/doompi-ui/toolChrome';\nimport type { Theme } from '@earendil-works/pi-coding-agent';\nimport { type Component, truncateToWidth, wrapTextWithAnsi } from '@earendil-works/pi-tui';\n\nconst COLLAPSED_RESULT_LINES = 12;\nconst MAX_ARGUMENTS = 3;\nconst ELLIPSIS = '…';\n\ninterface McpToolTextLayout {\n wrap: boolean;\n separator: boolean;\n trailingBlank: boolean;\n}\n\n/** Bash-compatible width budget, horizontal inset, and structural result divider. */\nclass McpToolText implements Component {\n constructor(\n private readonly lines: readonly string[],\n private readonly layout: McpToolTextLayout,\n private readonly theme: Theme,\n ) {}\n\n render(width: number): string[] {\n if (width <= 0) return [];\n const contentWidth = Math.max(1, width - 2);\n const rendered = this.layout.wrap\n ? this.lines.flatMap((line) => wrapTextWithAnsi(line, contentWidth))\n : this.lines.map((line) => truncateToWidth(line, contentWidth, ELLIPSIS));\n if (this.layout.separator) {\n rendered.unshift(this.theme.fg('borderMuted', '─'.repeat(contentWidth)));\n }\n const padded = rendered.map((line) => ` ${line}`);\n if (this.layout.trailingBlank) padded.push('');\n return padded;\n }\n\n invalidate(): void {\n // Content is immutable and reflows from the current width on every render.\n }\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\nfunction argumentSummary(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 interface McpToolIdentity {\n serverName: string;\n toolName: string;\n}\n\nexport function renderMcpCall(tool: McpToolIdentity, params: Record<string, unknown>, theme: Theme): Component {\n const heading = renderToolHeading('mcp', tool.serverName, theme, 'muted');\n const toolName = theme.fg('accent', tool.toolName);\n const argumentsText = argumentSummary(params);\n const text = `${heading}${theme.fg('muted', ' / ')}${toolName}${\n argumentsText ? ` ${theme.fg('muted', `· ${argumentsText}`)}` : ''\n }`;\n return new DoomToolCall(text);\n}\n\nexport interface McpToolResultLike {\n content?: Array<{ type: string; text?: string }>;\n}\n\nexport interface McpToolResultOptions {\n expanded: boolean;\n isPartial: boolean;\n isError: boolean;\n}\n\nfunction resultLines(result: McpToolResultLike): string[] {\n const text = (result.content ?? []).map((block) => block.text ?? '').join('');\n const lines = text.split('\\n');\n while (lines.length > 0 && lines.at(-1)?.trim() === '') lines.pop();\n return lines;\n}\n\nexport function renderMcpResult(result: McpToolResultLike, options: McpToolResultOptions, theme: Theme): Component {\n const all = resultLines(result);\n const shown = options.expanded ? all : all.slice(0, COLLAPSED_RESULT_LINES);\n const body = shown.map((line) => theme.fg('toolOutput', line));\n\n if (options.isPartial) {\n body.push(theme.fg('warning', '◐') + theme.fg('dim', ' running'));\n } else if (options.isError) {\n body.push(theme.fg('error', '✗') + theme.fg('dim', ' failed'));\n } else if (!options.expanded && all.length > shown.length) {\n body.push(theme.fg('dim', '… ctrl+o'));\n } else if (body.length === 0) {\n body.push(theme.fg('success', '✓') + theme.fg('dim', ' done'));\n }\n\n return new McpToolText(body, { wrap: options.expanded, separator: true, trailingBlank: true }, theme);\n}\n","import { defineRoutedContribution, type WithRoot } from '@agimon-ai/doompi-core/extensionFile';\nimport type { PiPluginContext, PiToolCollection } from '@agimon-ai/doompi-core/piExtension';\n\nimport { createMcpToolCollection } from '../../../../../services/mcpToolCollection';\nimport { renderMcpCall, renderMcpResult } from '../../../../../tui/mcpToolRender';\nimport type { McpPiScope } from '../_lib/piRoot';\n\nexport default defineRoutedContribution(\n (context: WithRoot<PiPluginContext<unknown>, McpPiScope>): PiToolCollection =>\n createMcpToolCollection(context.root.session, (tool) => ({\n renderCall: (params, theme) => renderMcpCall(tool, params as Record<string, unknown>, theme),\n renderResult: (result, options, theme, execution) =>\n renderMcpResult(result, { ...options, isError: execution.isError }, theme),\n })),\n { cardinality: 'collection' },\n);\n","// Generated by @agimon-ai/doompi-build. Do not edit by hand.\nimport { definePiExtension, piToolContributions, type PiPluginContext, type PiPluginContributions } from '@agimon-ai/doompi-core/piExtension';\nimport { composeRootHooks } from '@agimon-ai/doompi-core/extensionFile';\n\nimport rootSession from '../src/extensions/workspaces/sessions/(backend)/root.cli';\nimport commandMcp from '../src/extensions/workspaces/sessions/(backend)/command/mcp.cli';\nimport resourceDoompiUseMcp from '../src/extensions/workspaces/sessions/(backend)/resource/doompi-use-mcp.cli';\nimport toolMcp from '../src/extensions/workspaces/sessions/(backend)/tool/mcp.cli';\n\ntype OptionsOf<T> = T extends (context: PiPluginContext<infer Options>) => unknown ? Options : never;\ntype InferredOptions = Exclude<OptionsOf<typeof rootSession> | OptionsOf<typeof commandMcp> | OptionsOf<typeof resourceDoompiUseMcp> | OptionsOf<typeof toolMcp>, undefined>;\ntype Intersect<Union> =\n (Union extends unknown ? (value: Union) => void : never) extends (value: infer Value) => void ? Value : never;\ntype ExtensionOptions = [InferredOptions] extends [never] ? undefined : Intersect<InferredOptions>;\n\ntype Factory<T, C> = (context: C) => T;\nconst at = <T, C>(value: T | Factory<T, C>, context: C): T =>\n typeof value === 'function' ? (value as Factory<T, C>)(context) : value;\ntype ManyFactory<T, C> = (context: C) => T | readonly T[];\nconst many = <T, C>(value: T | readonly T[] | ManyFactory<T, C>, context: C): readonly T[] => {\n const resolved = typeof value === 'function' ? (value as ManyFactory<T, C>)(context) : value;\n return Array.isArray(resolved) ? resolved : [resolved as T];\n};\n\nexport const extension = definePiExtension<ExtensionOptions>('@agimon-ai/doompi-mcp', async (context) => {\n const scopeSession = await rootSession(context);\n const contextSession = { ...context, root: scopeSession.value };\n return {\n ...composeRootHooks(scopeSession),\n get commands(): PiPluginContributions['commands'] { return [...many(commandMcp, contextSession)]; },\n get resources(): PiPluginContributions['resources'] { return [at(resourceDoompiUseMcp, contextSession)]; },\n ...piToolContributions('@agimon-ai/doompi-mcp', at(toolMcp, contextSession)),\n services: [...(scopeSession.services ?? [])],\n };\n});\n\nexport default extension;\n"],"mappings":"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"}
1
+ {"version":3,"file":"pi.cjs","names":["PACKAGE_SOURCE","LEADER_BINDING_PREFIX","LEADER_GROUP","LEADER_DETAIL","path","McpSession","DOOM_UI_HUB_SERVICE","requireDoomUiHub","DOOM_TOOL_SURFACE_SERVICE","requireDoomToolSurface","DOOM_CORDIS_SESSION_SERVICE","MCP_STATUS_KEY","MCP_SESSION_AUTH_STATUS_KEY","formatMcpSessionAuthStatus","readSessionConfig","DOOM_MCP_PROJECTION_SERVICE","readDoomMcpProjectionService","mcpSessionConfigFromProjection","createMcpSessionToolsService","createMcpChildTool","DOOM_MCP_STATUS_SERVICE","DOOM_MCP_TOOL_RESOLVER_SERVICE","MCP_SESSION_TOOLS_SERVICE","DOOM_CHILD_SESSION_MCP_TOOL_SERVICE","defineRoot","defineRoutedContribution","createMcpCommand","defineResource","createMcpTool","wrapTextWithAnsi","truncateToWidth","renderToolHeading","DoomToolCall","defineRoutedContribution","definePiExtension","rootSession","composeRootHooks","commandMcp","resourceDoompiUseMcp","piToolContributions","toolMcp"],"sources":["../../src/services/leader/index.ts","../../src/services/piRuntime/index.ts","../../src/extensions/workspaces/sessions/(backend)/_lib/piRoot.ts","../../src/extensions/workspaces/sessions/(backend)/root.cli.ts","../../src/extensions/workspaces/sessions/(backend)/command/mcp.cli.ts","../../src/extensions/workspaces/sessions/(backend)/resource/doompi-use-mcp.cli.ts","../../src/services/mcpToolCollection/index.ts","../../src/tui/mcpToolRender.ts","../../src/extensions/workspaces/sessions/(backend)/tool/mcp.cli.ts","../../generated/pi.ts"],"sourcesContent":["import type { DoomUiHubService } from '@agimon-ai/doompi-core/uiHub';\n\nimport { COMMAND_NAME } from '../../constants/mcp';\nimport {\n LEADER_BINDING_PREFIX,\n LEADER_DETAIL,\n LEADER_GROUP,\n LEADER_KEY,\n LEADER_LABEL,\n PACKAGE_SOURCE,\n} from '../../constants/piMcp';\n\nexport function registerLeaderContribution(hub: DoomUiHubService): () => void {\n const contribution = hub.registerLeader({\n source: PACKAGE_SOURCE,\n bindings: [\n {\n id: `${LEADER_BINDING_PREFIX}.open`,\n path: [LEADER_GROUP, { key: LEADER_KEY, label: LEADER_LABEL, detail: LEADER_DETAIL }],\n command: { name: COMMAND_NAME },\n },\n ],\n });\n return () => contribution.dispose();\n}\n","import path from 'node:path';\n\nimport { DOOM_CHILD_SESSION_MCP_TOOL_SERVICE } from '@agimon-ai/doompi-core/childSession';\nimport type { DoomCordisRuntimeService } from '@agimon-ai/doompi-core/cordisHost';\nimport { DOOM_CORDIS_SESSION_SERVICE, type DoomCordisSessionService } from '@agimon-ai/doompi-core/cordisHost';\nimport { DOOM_MCP_PROJECTION_SERVICE, readDoomMcpProjectionService } from '@agimon-ai/doompi-core/mcpProjection';\nimport { DOOM_MCP_STATUS_SERVICE, type DoomMcpStatusService } from '@agimon-ai/doompi-core/mcpStatus';\nimport {\n DOOM_MCP_TOOL_RESOLVER_SERVICE,\n type DoomMcpToolResolverService,\n} from '@agimon-ai/doompi-core/mcpToolResolver';\nimport { DOOM_TOOL_SURFACE_SERVICE, requireDoomToolSurface } from '@agimon-ai/doompi-core/toolSurface';\nimport { DOOM_UI_HUB_SERVICE, requireDoomUiHub } from '@agimon-ai/doompi-core/uiHub';\nimport type { Context } from '@deepseek-ai/cordis';\nimport type { ExtensionContext } from '@earendil-works/pi-coding-agent';\n\nimport { MCP_STATUS_KEY } from '../../constants/piMcp';\nimport { McpSession } from '../../services/mcpSession';\nimport { mcpSessionConfigFromProjection } from '../../services/projection';\nimport { readSessionConfig } from '../../services/sessionConfig';\nimport type { McpSessionConfig } from '../../types/mcpConfig';\nimport { formatMcpSessionAuthStatus, MCP_SESSION_AUTH_STATUS_KEY } from '../../types/webMcp';\nimport { registerLeaderContribution } from '../leader';\nimport { createMcpChildTool, createMcpSessionToolsService, MCP_SESSION_TOOLS_SERVICE } from '../mcpSessionTools';\n\nconst INFO = 'info';\nconst WARNING = 'warning';\n\nfunction failClosedSessionConfig(cwd: string): McpSessionConfig {\n return {\n enabled: false,\n repoRoot: cwd,\n stagingDirectory: path.join(cwd, '.doom', 'mcp-disabled'),\n sources: [],\n };\n}\n\nexport function createMcpPiRuntime(runtime: DoomCordisRuntimeService) {\n const mode = runtime.mode;\n let activeContext: ExtensionContext | undefined;\n let disposed = false;\n const session = new McpSession({\n onAuthorizationUrl: async (url, serverName, { openBrowser }) => {\n const context = activeContext;\n if (context?.mode === 'tui') {\n if (!openBrowser) return;\n try {\n const { default: open } = await import('open');\n await open(url.toString());\n } catch (error) {\n context.ui.notify(\n `Could not open the authorization page for ${serverName}: ${error instanceof Error ? error.message : String(error)}. Press a in the MCP overlay to retry.`,\n WARNING,\n );\n throw error;\n }\n return;\n }\n context?.ui?.notify(`Authorize ${serverName} by opening:\\n${url.toString()}`, INFO);\n },\n });\n\n return {\n session,\n services: [\n (cordis: Context) => {\n cordis.inject([DOOM_UI_HUB_SERVICE], (uiContext) => registerLeaderContribution(requireDoomUiHub(uiContext)));\n // The surface lives on the session fiber, so this resolves after install has\n // already registered the cached wrappers: binding is what first hides the ones\n // no server has confirmed.\n cordis.inject([DOOM_TOOL_SURFACE_SERVICE], (surfaceContext) =>\n session.bindToolSurface(requireDoomToolSurface(surfaceContext)),\n );\n cordis.inject([DOOM_CORDIS_SESSION_SERVICE], async (sessionContext) => {\n const hostSession = sessionContext.get(DOOM_CORDIS_SESSION_SERVICE) as DoomCordisSessionService;\n const context = hostSession.context;\n const expectedSessionId = hostSession.sessionId;\n let sessionActive = true;\n activeContext = context;\n // The legacy server-name status remains available to every UI. The compact\n // authorization status is browser-only so the TUI footer stays unchanged.\n const publishServerStatus = (): void => {\n const servers = session.getSnapshot().servers;\n const names = servers.map((server) => server.name).join(',');\n context.ui?.setStatus(MCP_STATUS_KEY, names);\n if (context.mode !== 'tui') {\n context.ui?.setStatus(MCP_SESSION_AUTH_STATUS_KEY, formatMcpSessionAuthStatus(session.getServers()));\n }\n };\n const stopPublishing = session.onChange(publishServerStatus);\n publishServerStatus();\n\n if (mode === 'standalone') {\n await session.reconfigure(readSessionConfig(process.env, context.cwd), context.cwd);\n } else {\n await session.reconfigure(failClosedSessionConfig(context.cwd));\n sessionContext.inject([DOOM_MCP_PROJECTION_SERVICE], async (projectionContext) => {\n const projection = readDoomMcpProjectionService(projectionContext);\n if (!projection || projection.sessionId !== expectedSessionId) {\n await session.reconfigure(failClosedSessionConfig(context.cwd));\n if (projection && sessionActive && !disposed) {\n context.ui?.notify(\n `The Doom MCP projection belongs to session \"${projection.sessionId}\", not \"${expectedSessionId}\"; MCP is disabled.`,\n WARNING,\n );\n }\n } else {\n const snapshot = projection.getSnapshot();\n await session.reconfigure(\n mcpSessionConfigFromProjection(snapshot, context.cwd),\n context.cwd,\n snapshot.repoRoot,\n );\n }\n return async () => {\n if (sessionActive && !disposed) await session.reconfigure(failClosedSessionConfig(context.cwd));\n };\n });\n }\n\n const status: DoomMcpStatusService = Object.freeze({\n generation: `${hostSession.generation}:mcp-status`,\n getSnapshot: () => session.getSnapshot(),\n onChange: (listener: () => void) => session.onChange(listener),\n });\n const toolResolver: DoomMcpToolResolverService = Object.freeze({\n generation: `${hostSession.generation}:mcp-tool-resolver`,\n resolve: (selectors: readonly string[]) => session.resolveToolSelectors(selectors),\n });\n const sessionTools = createMcpSessionToolsService(session, `${hostSession.generation}:mcp-tools`);\n const childTool = createMcpChildTool(async (parameters, signal) => {\n if (!sessionActive || disposed) throw new Error('The parent MCP session is no longer available.');\n const tool = sessionTools\n .snapshot()\n .find(\n (candidate) => candidate.serverName === parameters.server && candidate.toolName === parameters.tool,\n );\n if (!tool)\n throw new Error(\n `MCP tool ${parameters.server}/${parameters.tool} is not available in the current session configuration.`,\n );\n return sessionTools.invoke(tool.piName, parameters.arguments ?? {}, signal);\n });\n sessionContext.plugin((providerContext) => {\n providerContext.provide(DOOM_MCP_STATUS_SERVICE, status);\n providerContext.provide(DOOM_MCP_TOOL_RESOLVER_SERVICE, toolResolver);\n providerContext.provide(MCP_SESSION_TOOLS_SERVICE, sessionTools);\n providerContext.provide(DOOM_CHILD_SESSION_MCP_TOOL_SERVICE, childTool);\n });\n for (const diagnostic of session.getDiagnostics()) context.ui?.notify(diagnostic, WARNING);\n return async () => {\n sessionActive = false;\n stopPublishing();\n context.ui?.setStatus(MCP_STATUS_KEY, undefined);\n if (context.mode !== 'tui') context.ui?.setStatus(MCP_SESSION_AUTH_STATUS_KEY, undefined);\n if (activeContext === context) activeContext = undefined;\n if (!disposed) await session.reconfigure(failClosedSessionConfig(context.cwd));\n };\n });\n },\n ],\n async onDispose() {\n disposed = true;\n activeContext = undefined;\n await session.dispose();\n },\n };\n}\n","import type { PiPluginContext } from '@agimon-ai/doompi-core/piExtension';\n\nimport { createMcpPiRuntime } from '../../../../../services/piRuntime';\nexport const createMcpPiRoot = ({ runtime }: PiPluginContext) => {\n if (!runtime) throw new Error('MCP requires the Cordis runtime mode.');\n const state = createMcpPiRuntime(runtime);\n return { value: state, services: state.services, onDispose: () => state.onDispose() };\n};\nexport type McpPiScope = Awaited<ReturnType<typeof createMcpPiRoot>>['value'];\n","import { defineRoot } from '@agimon-ai/doompi-core/extensionFile';\n\nimport { createMcpPiRoot } from './_lib/piRoot';\n\nexport default defineRoot(createMcpPiRoot);\n","import { defineRoutedContribution, type WithRoot } from '@agimon-ai/doompi-core/extensionFile';\nimport type { PiPluginContext } from '@agimon-ai/doompi-core/piExtension';\n\nimport { createMcpCommand } from '../../../../../services/mcpCommand';\nimport type { McpPiScope } from '../_lib/piRoot';\nexport default defineRoutedContribution(\n (context: WithRoot<PiPluginContext<unknown>, McpPiScope>) =>\n [\n createMcpCommand(context.root.session, {\n openOverlay: async (ctx) => {\n const { openMcpOverlay } = await import('../../../../../tui/mcpOverlay');\n return openMcpOverlay(ctx, context.root.session);\n },\n }),\n ] as const,\n { cardinality: 'many' },\n);\n","import { defineResource } from '@agimon-ai/doompi-core/extensionFile';\n\nexport default defineResource({\n source: '@agimon-ai/doompi-mcp',\n moduleUrl: import.meta.url,\n skills: [\n {\n name: 'doompi-use-mcp',\n description:\n 'Use Doom Pi MCP to inspect domain-scoped servers, authenticate, reload configuration, and troubleshoot tool availability.',\n },\n ],\n});\n","import type { PiToolCollection, PiToolDeclaration } from '@agimon-ai/doompi-core/piExtension';\n\nimport type { CatalogTool } from '../../services/mcpCatalog';\nimport type { McpSession } from '../../services/mcpSession';\nimport { createMcpTool, type McpToolRenderers } from '../mcpTools';\nexport function createMcpToolCollection(\n session: McpSession,\n renderers: (tool: CatalogTool) => McpToolRenderers = () => ({}),\n): PiToolCollection {\n const declarations = new Map<CatalogTool, PiToolDeclaration>();\n return {\n snapshot: (): readonly PiToolDeclaration[] =>\n session.toolDefinitions().map((tool) => {\n let declaration = declarations.get(tool);\n if (!declaration) {\n declaration = createMcpTool(\n session.getClientManager,\n tool,\n (candidate) => session.isToolAvailable(candidate),\n renderers(tool),\n );\n declarations.set(tool, declaration);\n }\n return declaration;\n }),\n subscribe: (listener: () => void) => session.onChange(listener),\n };\n}\n","import { DoomToolCall, renderToolHeading } from '@agimon-ai/doompi-ui/toolChrome';\nimport type { Theme } from '@earendil-works/pi-coding-agent';\nimport { type Component, truncateToWidth, wrapTextWithAnsi } from '@earendil-works/pi-tui';\n\nconst COLLAPSED_RESULT_LINES = 12;\nconst MAX_ARGUMENTS = 3;\nconst ELLIPSIS = '…';\n\ninterface McpToolTextLayout {\n wrap: boolean;\n separator: boolean;\n trailingBlank: boolean;\n}\n\n/** Bash-compatible width budget, horizontal inset, and structural result divider. */\nclass McpToolText implements Component {\n constructor(\n private readonly lines: readonly string[],\n private readonly layout: McpToolTextLayout,\n private readonly theme: Theme,\n ) {}\n\n render(width: number): string[] {\n if (width <= 0) return [];\n const contentWidth = Math.max(1, width - 2);\n const rendered = this.layout.wrap\n ? this.lines.flatMap((line) => wrapTextWithAnsi(line, contentWidth))\n : this.lines.map((line) => truncateToWidth(line, contentWidth, ELLIPSIS));\n if (this.layout.separator) {\n rendered.unshift(this.theme.fg('borderMuted', '─'.repeat(contentWidth)));\n }\n const padded = rendered.map((line) => ` ${line}`);\n if (this.layout.trailingBlank) padded.push('');\n return padded;\n }\n\n invalidate(): void {\n // Content is immutable and reflows from the current width on every render.\n }\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\nfunction argumentSummary(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 interface McpToolIdentity {\n serverName: string;\n toolName: string;\n}\n\nexport function renderMcpCall(tool: McpToolIdentity, params: Record<string, unknown>, theme: Theme): Component {\n const heading = renderToolHeading('mcp', tool.serverName, theme, 'muted');\n const toolName = theme.fg('accent', tool.toolName);\n const argumentsText = argumentSummary(params);\n const text = `${heading}${theme.fg('muted', ' / ')}${toolName}${\n argumentsText ? ` ${theme.fg('muted', `· ${argumentsText}`)}` : ''\n }`;\n return new DoomToolCall(text);\n}\n\nexport interface McpToolResultLike {\n content?: Array<{ type: string; text?: string }>;\n}\n\nexport interface McpToolResultOptions {\n expanded: boolean;\n isPartial: boolean;\n isError: boolean;\n}\n\nfunction resultLines(result: McpToolResultLike): string[] {\n const text = (result.content ?? []).map((block) => block.text ?? '').join('');\n const lines = text.split('\\n');\n while (lines.length > 0 && lines.at(-1)?.trim() === '') lines.pop();\n return lines;\n}\n\nexport function renderMcpResult(result: McpToolResultLike, options: McpToolResultOptions, theme: Theme): Component {\n const all = resultLines(result);\n const shown = options.expanded ? all : all.slice(0, COLLAPSED_RESULT_LINES);\n const body = shown.map((line) => theme.fg('toolOutput', line));\n\n if (options.isPartial) {\n body.push(theme.fg('warning', '◐') + theme.fg('dim', ' running'));\n } else if (options.isError) {\n body.push(theme.fg('error', '✗') + theme.fg('dim', ' failed'));\n } else if (!options.expanded && all.length > shown.length) {\n body.push(theme.fg('dim', '… ctrl+o'));\n } else if (body.length === 0) {\n body.push(theme.fg('success', '✓') + theme.fg('dim', ' done'));\n }\n\n return new McpToolText(body, { wrap: options.expanded, separator: true, trailingBlank: true }, theme);\n}\n","import { defineRoutedContribution, type WithRoot } from '@agimon-ai/doompi-core/extensionFile';\nimport type { PiPluginContext, PiToolCollection } from '@agimon-ai/doompi-core/piExtension';\n\nimport { createMcpToolCollection } from '../../../../../services/mcpToolCollection';\nimport { renderMcpCall, renderMcpResult } from '../../../../../tui/mcpToolRender';\nimport type { McpPiScope } from '../_lib/piRoot';\n\nexport default defineRoutedContribution(\n (context: WithRoot<PiPluginContext<unknown>, McpPiScope>): PiToolCollection =>\n createMcpToolCollection(context.root.session, (tool) => ({\n renderCall: (params, theme) => renderMcpCall(tool, params as Record<string, unknown>, theme),\n renderResult: (result, options, theme, execution) =>\n renderMcpResult(result, { ...options, isError: execution.isError }, theme),\n })),\n { cardinality: 'collection' },\n);\n","// Generated by @agimon-ai/doompi-build. Do not edit by hand.\nimport { definePiExtension, piToolContributions, type PiPluginContext, type PiPluginContributions } from '@agimon-ai/doompi-core/piExtension';\nimport { composeRootHooks } from '@agimon-ai/doompi-core/extensionFile';\n\nimport rootSession from '../src/extensions/workspaces/sessions/(backend)/root.cli';\nimport commandMcp from '../src/extensions/workspaces/sessions/(backend)/command/mcp.cli';\nimport resourceDoompiUseMcp from '../src/extensions/workspaces/sessions/(backend)/resource/doompi-use-mcp.cli';\nimport toolMcp from '../src/extensions/workspaces/sessions/(backend)/tool/mcp.cli';\n\ntype OptionsOf<T> = T extends (context: PiPluginContext<infer Options>) => unknown ? Options : never;\ntype InferredOptions = Exclude<OptionsOf<typeof rootSession> | OptionsOf<typeof commandMcp> | OptionsOf<typeof resourceDoompiUseMcp> | OptionsOf<typeof toolMcp>, undefined>;\ntype Intersect<Union> =\n (Union extends unknown ? (value: Union) => void : never) extends (value: infer Value) => void ? Value : never;\ntype ExtensionOptions = [InferredOptions] extends [never] ? undefined : Intersect<InferredOptions>;\n\ntype Factory<T, C> = (context: C) => T;\nconst at = <T, C>(value: T | Factory<T, C>, context: C): T =>\n typeof value === 'function' ? (value as Factory<T, C>)(context) : value;\ntype ManyFactory<T, C> = (context: C) => T | readonly T[];\nconst many = <T, C>(value: T | readonly T[] | ManyFactory<T, C>, context: C): readonly T[] => {\n const resolved = typeof value === 'function' ? (value as ManyFactory<T, C>)(context) : value;\n return Array.isArray(resolved) ? resolved : [resolved as T];\n};\n\nexport const extension = definePiExtension<ExtensionOptions>('@agimon-ai/doompi-mcp', async (context) => {\n const scopeSession = await rootSession(context);\n const contextSession = { ...context, root: scopeSession.value };\n return {\n ...composeRootHooks(scopeSession),\n get commands(): PiPluginContributions['commands'] { return [...many(commandMcp, contextSession)]; },\n get resources(): PiPluginContributions['resources'] { return [at(resourceDoompiUseMcp, contextSession)]; },\n ...piToolContributions('@agimon-ai/doompi-mcp', at(toolMcp, contextSession)),\n services: [...(scopeSession.services ?? [])],\n };\n});\n\nexport default extension;\n"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
- import { a as readSessionConfig } from "../mcpCatalog-zoD27CZd.mjs";
2
- import { t as mcpSessionConfigFromProjection } from "../projection-BJEX-pTt.mjs";
3
- import { _ as LEADER_BINDING_PREFIX, a as createMcpSessionToolsService, b as MCP_STATUS_KEY, g as createMcpTool, h as McpSession, i as createMcpChildTool, m as formatMcpSessionAuthStatus, p as MCP_SESSION_AUTH_STATUS_KEY, r as MCP_SESSION_TOOLS_SERVICE, t as createMcpCommand, v as LEADER_DETAIL, x as PACKAGE_SOURCE, y as LEADER_GROUP } from "../mcpCommand-CIkm3j9w.mjs";
1
+ import { a as readSessionConfig } from "../mcpCatalog-laXfwecc.mjs";
2
+ import { t as mcpSessionConfigFromProjection } from "../projection-gyAA2jRB.mjs";
3
+ import { _ as LEADER_BINDING_PREFIX, a as createMcpSessionToolsService, b as MCP_STATUS_KEY, g as createMcpTool, h as McpSession, i as createMcpChildTool, m as formatMcpSessionAuthStatus, p as MCP_SESSION_AUTH_STATUS_KEY, r as MCP_SESSION_TOOLS_SERVICE, t as createMcpCommand, v as LEADER_DETAIL, x as PACKAGE_SOURCE, y as LEADER_GROUP } from "../mcpCommand-BaJXXphd.mjs";
4
4
  import path from "node:path";
5
5
  import { DOOM_MCP_PROJECTION_SERVICE, readDoomMcpProjectionService } from "@agimon-ai/doompi-core/mcpProjection";
6
6
  import { definePiExtension, piToolContributions } from "@agimon-ai/doompi-core/piExtension";
@@ -78,7 +78,7 @@ function createMcpPiRuntime(runtime) {
78
78
  };
79
79
  const stopPublishing = session.onChange(publishServerStatus);
80
80
  publishServerStatus();
81
- if (mode === "standalone") await session.reconfigure(readSessionConfig(process.env, context.cwd));
81
+ if (mode === "standalone") await session.reconfigure(readSessionConfig(process.env, context.cwd), context.cwd);
82
82
  else {
83
83
  await session.reconfigure(failClosedSessionConfig(context.cwd));
84
84
  sessionContext.inject([DOOM_MCP_PROJECTION_SERVICE], async (projectionContext) => {
@@ -86,7 +86,10 @@ function createMcpPiRuntime(runtime) {
86
86
  if (!projection || projection.sessionId !== expectedSessionId) {
87
87
  await session.reconfigure(failClosedSessionConfig(context.cwd));
88
88
  if (projection && sessionActive && !disposed) context.ui?.notify(`The Doom MCP projection belongs to session "${projection.sessionId}", not "${expectedSessionId}"; MCP is disabled.`, WARNING);
89
- } else await session.reconfigure(mcpSessionConfigFromProjection(projection.getSnapshot()));
89
+ } else {
90
+ const snapshot = projection.getSnapshot();
91
+ await session.reconfigure(mcpSessionConfigFromProjection(snapshot, context.cwd), context.cwd, snapshot.repoRoot);
92
+ }
90
93
  return async () => {
91
94
  if (sessionActive && !disposed) await session.reconfigure(failClosedSessionConfig(context.cwd));
92
95
  };
@@ -1 +1 @@
1
- {"version":3,"file":"pi.mjs","names":["rootSession","commandMcp","resourceDoompiUseMcp","toolMcp"],"sources":["../../src/services/leader/index.ts","../../src/services/piRuntime/index.ts","../../src/extensions/workspaces/sessions/(backend)/_lib/piRoot.ts","../../src/extensions/workspaces/sessions/(backend)/root.cli.ts","../../src/extensions/workspaces/sessions/(backend)/command/mcp.cli.ts","../../src/extensions/workspaces/sessions/(backend)/resource/doompi-use-mcp.cli.ts","../../src/services/mcpToolCollection/index.ts","../../src/tui/mcpToolRender.ts","../../src/extensions/workspaces/sessions/(backend)/tool/mcp.cli.ts","../../generated/pi.ts"],"sourcesContent":["import type { DoomUiHubService } from '@agimon-ai/doompi-core/uiHub';\n\nimport { COMMAND_NAME } from '../../constants/mcp';\nimport {\n LEADER_BINDING_PREFIX,\n LEADER_DETAIL,\n LEADER_GROUP,\n LEADER_KEY,\n LEADER_LABEL,\n PACKAGE_SOURCE,\n} from '../../constants/piMcp';\n\nexport function registerLeaderContribution(hub: DoomUiHubService): () => void {\n const contribution = hub.registerLeader({\n source: PACKAGE_SOURCE,\n bindings: [\n {\n id: `${LEADER_BINDING_PREFIX}.open`,\n path: [LEADER_GROUP, { key: LEADER_KEY, label: LEADER_LABEL, detail: LEADER_DETAIL }],\n command: { name: COMMAND_NAME },\n },\n ],\n });\n return () => contribution.dispose();\n}\n","import path from 'node:path';\n\nimport { DOOM_CHILD_SESSION_MCP_TOOL_SERVICE } from '@agimon-ai/doompi-core/childSession';\nimport type { DoomCordisRuntimeService } from '@agimon-ai/doompi-core/cordisHost';\nimport { DOOM_CORDIS_SESSION_SERVICE, type DoomCordisSessionService } from '@agimon-ai/doompi-core/cordisHost';\nimport { DOOM_MCP_PROJECTION_SERVICE, readDoomMcpProjectionService } from '@agimon-ai/doompi-core/mcpProjection';\nimport { DOOM_MCP_STATUS_SERVICE, type DoomMcpStatusService } from '@agimon-ai/doompi-core/mcpStatus';\nimport {\n DOOM_MCP_TOOL_RESOLVER_SERVICE,\n type DoomMcpToolResolverService,\n} from '@agimon-ai/doompi-core/mcpToolResolver';\nimport { DOOM_TOOL_SURFACE_SERVICE, requireDoomToolSurface } from '@agimon-ai/doompi-core/toolSurface';\nimport { DOOM_UI_HUB_SERVICE, requireDoomUiHub } from '@agimon-ai/doompi-core/uiHub';\nimport type { Context } from '@deepseek-ai/cordis';\nimport type { ExtensionContext } from '@earendil-works/pi-coding-agent';\n\nimport { MCP_STATUS_KEY } from '../../constants/piMcp';\nimport { McpSession } from '../../services/mcpSession';\nimport { mcpSessionConfigFromProjection } from '../../services/projection';\nimport { readSessionConfig } from '../../services/sessionConfig';\nimport type { McpSessionConfig } from '../../types/mcpConfig';\nimport { formatMcpSessionAuthStatus, MCP_SESSION_AUTH_STATUS_KEY } from '../../types/webMcp';\nimport { registerLeaderContribution } from '../leader';\nimport { createMcpChildTool, createMcpSessionToolsService, MCP_SESSION_TOOLS_SERVICE } from '../mcpSessionTools';\n\nconst INFO = 'info';\nconst WARNING = 'warning';\n\nfunction failClosedSessionConfig(cwd: string): McpSessionConfig {\n return {\n enabled: false,\n repoRoot: cwd,\n stagingDirectory: path.join(cwd, '.doom', 'mcp-disabled'),\n sources: [],\n };\n}\n\nexport function createMcpPiRuntime(runtime: DoomCordisRuntimeService) {\n const mode = runtime.mode;\n let activeContext: ExtensionContext | undefined;\n let disposed = false;\n const session = new McpSession({\n onAuthorizationUrl: async (url, serverName, { openBrowser }) => {\n const context = activeContext;\n if (context?.mode === 'tui') {\n if (!openBrowser) return;\n try {\n const { default: open } = await import('open');\n await open(url.toString());\n } catch (error) {\n context.ui.notify(\n `Could not open the authorization page for ${serverName}: ${error instanceof Error ? error.message : String(error)}. Press a in the MCP overlay to retry.`,\n WARNING,\n );\n throw error;\n }\n return;\n }\n context?.ui?.notify(`Authorize ${serverName} by opening:\\n${url.toString()}`, INFO);\n },\n });\n\n return {\n session,\n services: [\n (cordis: Context) => {\n cordis.inject([DOOM_UI_HUB_SERVICE], (uiContext) => registerLeaderContribution(requireDoomUiHub(uiContext)));\n // The surface lives on the session fiber, so this resolves after install has\n // already registered the cached wrappers: binding is what first hides the ones\n // no server has confirmed.\n cordis.inject([DOOM_TOOL_SURFACE_SERVICE], (surfaceContext) =>\n session.bindToolSurface(requireDoomToolSurface(surfaceContext)),\n );\n cordis.inject([DOOM_CORDIS_SESSION_SERVICE], async (sessionContext) => {\n const hostSession = sessionContext.get(DOOM_CORDIS_SESSION_SERVICE) as DoomCordisSessionService;\n const context = hostSession.context;\n const expectedSessionId = hostSession.sessionId;\n let sessionActive = true;\n activeContext = context;\n // The legacy server-name status remains available to every UI. The compact\n // authorization status is browser-only so the TUI footer stays unchanged.\n const publishServerStatus = (): void => {\n const servers = session.getSnapshot().servers;\n const names = servers.map((server) => server.name).join(',');\n context.ui?.setStatus(MCP_STATUS_KEY, names);\n if (context.mode !== 'tui') {\n context.ui?.setStatus(MCP_SESSION_AUTH_STATUS_KEY, formatMcpSessionAuthStatus(session.getServers()));\n }\n };\n const stopPublishing = session.onChange(publishServerStatus);\n publishServerStatus();\n\n if (mode === 'standalone') {\n await session.reconfigure(readSessionConfig(process.env, context.cwd));\n } else {\n await session.reconfigure(failClosedSessionConfig(context.cwd));\n sessionContext.inject([DOOM_MCP_PROJECTION_SERVICE], async (projectionContext) => {\n const projection = readDoomMcpProjectionService(projectionContext);\n if (!projection || projection.sessionId !== expectedSessionId) {\n await session.reconfigure(failClosedSessionConfig(context.cwd));\n if (projection && sessionActive && !disposed) {\n context.ui?.notify(\n `The Doom MCP projection belongs to session \"${projection.sessionId}\", not \"${expectedSessionId}\"; MCP is disabled.`,\n WARNING,\n );\n }\n } else {\n await session.reconfigure(mcpSessionConfigFromProjection(projection.getSnapshot()));\n }\n return async () => {\n if (sessionActive && !disposed) await session.reconfigure(failClosedSessionConfig(context.cwd));\n };\n });\n }\n\n const status: DoomMcpStatusService = Object.freeze({\n generation: `${hostSession.generation}:mcp-status`,\n getSnapshot: () => session.getSnapshot(),\n onChange: (listener: () => void) => session.onChange(listener),\n });\n const toolResolver: DoomMcpToolResolverService = Object.freeze({\n generation: `${hostSession.generation}:mcp-tool-resolver`,\n resolve: (selectors: readonly string[]) => session.resolveToolSelectors(selectors),\n });\n const sessionTools = createMcpSessionToolsService(session, `${hostSession.generation}:mcp-tools`);\n const childTool = createMcpChildTool(async (parameters, signal) => {\n if (!sessionActive || disposed) throw new Error('The parent MCP session is no longer available.');\n const tool = sessionTools\n .snapshot()\n .find(\n (candidate) => candidate.serverName === parameters.server && candidate.toolName === parameters.tool,\n );\n if (!tool)\n throw new Error(\n `MCP tool ${parameters.server}/${parameters.tool} is not available in the current session configuration.`,\n );\n return sessionTools.invoke(tool.piName, parameters.arguments ?? {}, signal);\n });\n sessionContext.plugin((providerContext) => {\n providerContext.provide(DOOM_MCP_STATUS_SERVICE, status);\n providerContext.provide(DOOM_MCP_TOOL_RESOLVER_SERVICE, toolResolver);\n providerContext.provide(MCP_SESSION_TOOLS_SERVICE, sessionTools);\n providerContext.provide(DOOM_CHILD_SESSION_MCP_TOOL_SERVICE, childTool);\n });\n for (const diagnostic of session.getDiagnostics()) context.ui?.notify(diagnostic, WARNING);\n return async () => {\n sessionActive = false;\n stopPublishing();\n context.ui?.setStatus(MCP_STATUS_KEY, undefined);\n if (context.mode !== 'tui') context.ui?.setStatus(MCP_SESSION_AUTH_STATUS_KEY, undefined);\n if (activeContext === context) activeContext = undefined;\n if (!disposed) await session.reconfigure(failClosedSessionConfig(context.cwd));\n };\n });\n },\n ],\n async onDispose() {\n disposed = true;\n activeContext = undefined;\n await session.dispose();\n },\n };\n}\n","import type { PiPluginContext } from '@agimon-ai/doompi-core/piExtension';\n\nimport { createMcpPiRuntime } from '../../../../../services/piRuntime';\nexport const createMcpPiRoot = ({ runtime }: PiPluginContext) => {\n if (!runtime) throw new Error('MCP requires the Cordis runtime mode.');\n const state = createMcpPiRuntime(runtime);\n return { value: state, services: state.services, onDispose: () => state.onDispose() };\n};\nexport type McpPiScope = Awaited<ReturnType<typeof createMcpPiRoot>>['value'];\n","import { defineRoot } from '@agimon-ai/doompi-core/extensionFile';\n\nimport { createMcpPiRoot } from './_lib/piRoot';\n\nexport default defineRoot(createMcpPiRoot);\n","import { defineRoutedContribution, type WithRoot } from '@agimon-ai/doompi-core/extensionFile';\nimport type { PiPluginContext } from '@agimon-ai/doompi-core/piExtension';\n\nimport { createMcpCommand } from '../../../../../services/mcpCommand';\nimport type { McpPiScope } from '../_lib/piRoot';\nexport default defineRoutedContribution(\n (context: WithRoot<PiPluginContext<unknown>, McpPiScope>) =>\n [\n createMcpCommand(context.root.session, {\n openOverlay: async (ctx) => {\n const { openMcpOverlay } = await import('../../../../../tui/mcpOverlay');\n return openMcpOverlay(ctx, context.root.session);\n },\n }),\n ] as const,\n { cardinality: 'many' },\n);\n","import { defineResource } from '@agimon-ai/doompi-core/extensionFile';\n\nexport default defineResource({\n source: '@agimon-ai/doompi-mcp',\n moduleUrl: import.meta.url,\n skills: [\n {\n name: 'doompi-use-mcp',\n description:\n 'Use Doom Pi MCP to inspect domain-scoped servers, authenticate, reload configuration, and troubleshoot tool availability.',\n },\n ],\n});\n","import type { PiToolCollection, PiToolDeclaration } from '@agimon-ai/doompi-core/piExtension';\n\nimport type { CatalogTool } from '../../services/mcpCatalog';\nimport type { McpSession } from '../../services/mcpSession';\nimport { createMcpTool, type McpToolRenderers } from '../mcpTools';\nexport function createMcpToolCollection(\n session: McpSession,\n renderers: (tool: CatalogTool) => McpToolRenderers = () => ({}),\n): PiToolCollection {\n const declarations = new Map<CatalogTool, PiToolDeclaration>();\n return {\n snapshot: (): readonly PiToolDeclaration[] =>\n session.toolDefinitions().map((tool) => {\n let declaration = declarations.get(tool);\n if (!declaration) {\n declaration = createMcpTool(\n session.getClientManager,\n tool,\n (candidate) => session.isToolAvailable(candidate),\n renderers(tool),\n );\n declarations.set(tool, declaration);\n }\n return declaration;\n }),\n subscribe: (listener: () => void) => session.onChange(listener),\n };\n}\n","import { DoomToolCall, renderToolHeading } from '@agimon-ai/doompi-ui/toolChrome';\nimport type { Theme } from '@earendil-works/pi-coding-agent';\nimport { type Component, truncateToWidth, wrapTextWithAnsi } from '@earendil-works/pi-tui';\n\nconst COLLAPSED_RESULT_LINES = 12;\nconst MAX_ARGUMENTS = 3;\nconst ELLIPSIS = '…';\n\ninterface McpToolTextLayout {\n wrap: boolean;\n separator: boolean;\n trailingBlank: boolean;\n}\n\n/** Bash-compatible width budget, horizontal inset, and structural result divider. */\nclass McpToolText implements Component {\n constructor(\n private readonly lines: readonly string[],\n private readonly layout: McpToolTextLayout,\n private readonly theme: Theme,\n ) {}\n\n render(width: number): string[] {\n if (width <= 0) return [];\n const contentWidth = Math.max(1, width - 2);\n const rendered = this.layout.wrap\n ? this.lines.flatMap((line) => wrapTextWithAnsi(line, contentWidth))\n : this.lines.map((line) => truncateToWidth(line, contentWidth, ELLIPSIS));\n if (this.layout.separator) {\n rendered.unshift(this.theme.fg('borderMuted', '─'.repeat(contentWidth)));\n }\n const padded = rendered.map((line) => ` ${line}`);\n if (this.layout.trailingBlank) padded.push('');\n return padded;\n }\n\n invalidate(): void {\n // Content is immutable and reflows from the current width on every render.\n }\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\nfunction argumentSummary(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 interface McpToolIdentity {\n serverName: string;\n toolName: string;\n}\n\nexport function renderMcpCall(tool: McpToolIdentity, params: Record<string, unknown>, theme: Theme): Component {\n const heading = renderToolHeading('mcp', tool.serverName, theme, 'muted');\n const toolName = theme.fg('accent', tool.toolName);\n const argumentsText = argumentSummary(params);\n const text = `${heading}${theme.fg('muted', ' / ')}${toolName}${\n argumentsText ? ` ${theme.fg('muted', `· ${argumentsText}`)}` : ''\n }`;\n return new DoomToolCall(text);\n}\n\nexport interface McpToolResultLike {\n content?: Array<{ type: string; text?: string }>;\n}\n\nexport interface McpToolResultOptions {\n expanded: boolean;\n isPartial: boolean;\n isError: boolean;\n}\n\nfunction resultLines(result: McpToolResultLike): string[] {\n const text = (result.content ?? []).map((block) => block.text ?? '').join('');\n const lines = text.split('\\n');\n while (lines.length > 0 && lines.at(-1)?.trim() === '') lines.pop();\n return lines;\n}\n\nexport function renderMcpResult(result: McpToolResultLike, options: McpToolResultOptions, theme: Theme): Component {\n const all = resultLines(result);\n const shown = options.expanded ? all : all.slice(0, COLLAPSED_RESULT_LINES);\n const body = shown.map((line) => theme.fg('toolOutput', line));\n\n if (options.isPartial) {\n body.push(theme.fg('warning', '◐') + theme.fg('dim', ' running'));\n } else if (options.isError) {\n body.push(theme.fg('error', '✗') + theme.fg('dim', ' failed'));\n } else if (!options.expanded && all.length > shown.length) {\n body.push(theme.fg('dim', '… ctrl+o'));\n } else if (body.length === 0) {\n body.push(theme.fg('success', '✓') + theme.fg('dim', ' done'));\n }\n\n return new McpToolText(body, { wrap: options.expanded, separator: true, trailingBlank: true }, theme);\n}\n","import { defineRoutedContribution, type WithRoot } from '@agimon-ai/doompi-core/extensionFile';\nimport type { PiPluginContext, PiToolCollection } from '@agimon-ai/doompi-core/piExtension';\n\nimport { createMcpToolCollection } from '../../../../../services/mcpToolCollection';\nimport { renderMcpCall, renderMcpResult } from '../../../../../tui/mcpToolRender';\nimport type { McpPiScope } from '../_lib/piRoot';\n\nexport default defineRoutedContribution(\n (context: WithRoot<PiPluginContext<unknown>, McpPiScope>): PiToolCollection =>\n createMcpToolCollection(context.root.session, (tool) => ({\n renderCall: (params, theme) => renderMcpCall(tool, params as Record<string, unknown>, theme),\n renderResult: (result, options, theme, execution) =>\n renderMcpResult(result, { ...options, isError: execution.isError }, theme),\n })),\n { cardinality: 'collection' },\n);\n","// Generated by @agimon-ai/doompi-build. Do not edit by hand.\nimport { definePiExtension, piToolContributions, type PiPluginContext, type PiPluginContributions } from '@agimon-ai/doompi-core/piExtension';\nimport { composeRootHooks } from '@agimon-ai/doompi-core/extensionFile';\n\nimport rootSession from '../src/extensions/workspaces/sessions/(backend)/root.cli';\nimport commandMcp from '../src/extensions/workspaces/sessions/(backend)/command/mcp.cli';\nimport resourceDoompiUseMcp from '../src/extensions/workspaces/sessions/(backend)/resource/doompi-use-mcp.cli';\nimport toolMcp from '../src/extensions/workspaces/sessions/(backend)/tool/mcp.cli';\n\ntype OptionsOf<T> = T extends (context: PiPluginContext<infer Options>) => unknown ? Options : never;\ntype InferredOptions = Exclude<OptionsOf<typeof rootSession> | OptionsOf<typeof commandMcp> | OptionsOf<typeof resourceDoompiUseMcp> | OptionsOf<typeof toolMcp>, undefined>;\ntype Intersect<Union> =\n (Union extends unknown ? (value: Union) => void : never) extends (value: infer Value) => void ? Value : never;\ntype ExtensionOptions = [InferredOptions] extends [never] ? undefined : Intersect<InferredOptions>;\n\ntype Factory<T, C> = (context: C) => T;\nconst at = <T, C>(value: T | Factory<T, C>, context: C): T =>\n typeof value === 'function' ? (value as Factory<T, C>)(context) : value;\ntype ManyFactory<T, C> = (context: C) => T | readonly T[];\nconst many = <T, C>(value: T | readonly T[] | ManyFactory<T, C>, context: C): readonly T[] => {\n const resolved = typeof value === 'function' ? (value as ManyFactory<T, C>)(context) : value;\n return Array.isArray(resolved) ? resolved : [resolved as T];\n};\n\nexport const extension = definePiExtension<ExtensionOptions>('@agimon-ai/doompi-mcp', async (context) => {\n const scopeSession = await rootSession(context);\n const contextSession = { ...context, root: scopeSession.value };\n return {\n ...composeRootHooks(scopeSession),\n get commands(): PiPluginContributions['commands'] { return [...many(commandMcp, contextSession)]; },\n get resources(): PiPluginContributions['resources'] { return [at(resourceDoompiUseMcp, contextSession)]; },\n ...piToolContributions('@agimon-ai/doompi-mcp', at(toolMcp, contextSession)),\n services: [...(scopeSession.services ?? [])],\n };\n});\n\nexport default extension;\n"],"mappings":"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"}
1
+ {"version":3,"file":"pi.mjs","names":["rootSession","commandMcp","resourceDoompiUseMcp","toolMcp"],"sources":["../../src/services/leader/index.ts","../../src/services/piRuntime/index.ts","../../src/extensions/workspaces/sessions/(backend)/_lib/piRoot.ts","../../src/extensions/workspaces/sessions/(backend)/root.cli.ts","../../src/extensions/workspaces/sessions/(backend)/command/mcp.cli.ts","../../src/extensions/workspaces/sessions/(backend)/resource/doompi-use-mcp.cli.ts","../../src/services/mcpToolCollection/index.ts","../../src/tui/mcpToolRender.ts","../../src/extensions/workspaces/sessions/(backend)/tool/mcp.cli.ts","../../generated/pi.ts"],"sourcesContent":["import type { DoomUiHubService } from '@agimon-ai/doompi-core/uiHub';\n\nimport { COMMAND_NAME } from '../../constants/mcp';\nimport {\n LEADER_BINDING_PREFIX,\n LEADER_DETAIL,\n LEADER_GROUP,\n LEADER_KEY,\n LEADER_LABEL,\n PACKAGE_SOURCE,\n} from '../../constants/piMcp';\n\nexport function registerLeaderContribution(hub: DoomUiHubService): () => void {\n const contribution = hub.registerLeader({\n source: PACKAGE_SOURCE,\n bindings: [\n {\n id: `${LEADER_BINDING_PREFIX}.open`,\n path: [LEADER_GROUP, { key: LEADER_KEY, label: LEADER_LABEL, detail: LEADER_DETAIL }],\n command: { name: COMMAND_NAME },\n },\n ],\n });\n return () => contribution.dispose();\n}\n","import path from 'node:path';\n\nimport { DOOM_CHILD_SESSION_MCP_TOOL_SERVICE } from '@agimon-ai/doompi-core/childSession';\nimport type { DoomCordisRuntimeService } from '@agimon-ai/doompi-core/cordisHost';\nimport { DOOM_CORDIS_SESSION_SERVICE, type DoomCordisSessionService } from '@agimon-ai/doompi-core/cordisHost';\nimport { DOOM_MCP_PROJECTION_SERVICE, readDoomMcpProjectionService } from '@agimon-ai/doompi-core/mcpProjection';\nimport { DOOM_MCP_STATUS_SERVICE, type DoomMcpStatusService } from '@agimon-ai/doompi-core/mcpStatus';\nimport {\n DOOM_MCP_TOOL_RESOLVER_SERVICE,\n type DoomMcpToolResolverService,\n} from '@agimon-ai/doompi-core/mcpToolResolver';\nimport { DOOM_TOOL_SURFACE_SERVICE, requireDoomToolSurface } from '@agimon-ai/doompi-core/toolSurface';\nimport { DOOM_UI_HUB_SERVICE, requireDoomUiHub } from '@agimon-ai/doompi-core/uiHub';\nimport type { Context } from '@deepseek-ai/cordis';\nimport type { ExtensionContext } from '@earendil-works/pi-coding-agent';\n\nimport { MCP_STATUS_KEY } from '../../constants/piMcp';\nimport { McpSession } from '../../services/mcpSession';\nimport { mcpSessionConfigFromProjection } from '../../services/projection';\nimport { readSessionConfig } from '../../services/sessionConfig';\nimport type { McpSessionConfig } from '../../types/mcpConfig';\nimport { formatMcpSessionAuthStatus, MCP_SESSION_AUTH_STATUS_KEY } from '../../types/webMcp';\nimport { registerLeaderContribution } from '../leader';\nimport { createMcpChildTool, createMcpSessionToolsService, MCP_SESSION_TOOLS_SERVICE } from '../mcpSessionTools';\n\nconst INFO = 'info';\nconst WARNING = 'warning';\n\nfunction failClosedSessionConfig(cwd: string): McpSessionConfig {\n return {\n enabled: false,\n repoRoot: cwd,\n stagingDirectory: path.join(cwd, '.doom', 'mcp-disabled'),\n sources: [],\n };\n}\n\nexport function createMcpPiRuntime(runtime: DoomCordisRuntimeService) {\n const mode = runtime.mode;\n let activeContext: ExtensionContext | undefined;\n let disposed = false;\n const session = new McpSession({\n onAuthorizationUrl: async (url, serverName, { openBrowser }) => {\n const context = activeContext;\n if (context?.mode === 'tui') {\n if (!openBrowser) return;\n try {\n const { default: open } = await import('open');\n await open(url.toString());\n } catch (error) {\n context.ui.notify(\n `Could not open the authorization page for ${serverName}: ${error instanceof Error ? error.message : String(error)}. Press a in the MCP overlay to retry.`,\n WARNING,\n );\n throw error;\n }\n return;\n }\n context?.ui?.notify(`Authorize ${serverName} by opening:\\n${url.toString()}`, INFO);\n },\n });\n\n return {\n session,\n services: [\n (cordis: Context) => {\n cordis.inject([DOOM_UI_HUB_SERVICE], (uiContext) => registerLeaderContribution(requireDoomUiHub(uiContext)));\n // The surface lives on the session fiber, so this resolves after install has\n // already registered the cached wrappers: binding is what first hides the ones\n // no server has confirmed.\n cordis.inject([DOOM_TOOL_SURFACE_SERVICE], (surfaceContext) =>\n session.bindToolSurface(requireDoomToolSurface(surfaceContext)),\n );\n cordis.inject([DOOM_CORDIS_SESSION_SERVICE], async (sessionContext) => {\n const hostSession = sessionContext.get(DOOM_CORDIS_SESSION_SERVICE) as DoomCordisSessionService;\n const context = hostSession.context;\n const expectedSessionId = hostSession.sessionId;\n let sessionActive = true;\n activeContext = context;\n // The legacy server-name status remains available to every UI. The compact\n // authorization status is browser-only so the TUI footer stays unchanged.\n const publishServerStatus = (): void => {\n const servers = session.getSnapshot().servers;\n const names = servers.map((server) => server.name).join(',');\n context.ui?.setStatus(MCP_STATUS_KEY, names);\n if (context.mode !== 'tui') {\n context.ui?.setStatus(MCP_SESSION_AUTH_STATUS_KEY, formatMcpSessionAuthStatus(session.getServers()));\n }\n };\n const stopPublishing = session.onChange(publishServerStatus);\n publishServerStatus();\n\n if (mode === 'standalone') {\n await session.reconfigure(readSessionConfig(process.env, context.cwd), context.cwd);\n } else {\n await session.reconfigure(failClosedSessionConfig(context.cwd));\n sessionContext.inject([DOOM_MCP_PROJECTION_SERVICE], async (projectionContext) => {\n const projection = readDoomMcpProjectionService(projectionContext);\n if (!projection || projection.sessionId !== expectedSessionId) {\n await session.reconfigure(failClosedSessionConfig(context.cwd));\n if (projection && sessionActive && !disposed) {\n context.ui?.notify(\n `The Doom MCP projection belongs to session \"${projection.sessionId}\", not \"${expectedSessionId}\"; MCP is disabled.`,\n WARNING,\n );\n }\n } else {\n const snapshot = projection.getSnapshot();\n await session.reconfigure(\n mcpSessionConfigFromProjection(snapshot, context.cwd),\n context.cwd,\n snapshot.repoRoot,\n );\n }\n return async () => {\n if (sessionActive && !disposed) await session.reconfigure(failClosedSessionConfig(context.cwd));\n };\n });\n }\n\n const status: DoomMcpStatusService = Object.freeze({\n generation: `${hostSession.generation}:mcp-status`,\n getSnapshot: () => session.getSnapshot(),\n onChange: (listener: () => void) => session.onChange(listener),\n });\n const toolResolver: DoomMcpToolResolverService = Object.freeze({\n generation: `${hostSession.generation}:mcp-tool-resolver`,\n resolve: (selectors: readonly string[]) => session.resolveToolSelectors(selectors),\n });\n const sessionTools = createMcpSessionToolsService(session, `${hostSession.generation}:mcp-tools`);\n const childTool = createMcpChildTool(async (parameters, signal) => {\n if (!sessionActive || disposed) throw new Error('The parent MCP session is no longer available.');\n const tool = sessionTools\n .snapshot()\n .find(\n (candidate) => candidate.serverName === parameters.server && candidate.toolName === parameters.tool,\n );\n if (!tool)\n throw new Error(\n `MCP tool ${parameters.server}/${parameters.tool} is not available in the current session configuration.`,\n );\n return sessionTools.invoke(tool.piName, parameters.arguments ?? {}, signal);\n });\n sessionContext.plugin((providerContext) => {\n providerContext.provide(DOOM_MCP_STATUS_SERVICE, status);\n providerContext.provide(DOOM_MCP_TOOL_RESOLVER_SERVICE, toolResolver);\n providerContext.provide(MCP_SESSION_TOOLS_SERVICE, sessionTools);\n providerContext.provide(DOOM_CHILD_SESSION_MCP_TOOL_SERVICE, childTool);\n });\n for (const diagnostic of session.getDiagnostics()) context.ui?.notify(diagnostic, WARNING);\n return async () => {\n sessionActive = false;\n stopPublishing();\n context.ui?.setStatus(MCP_STATUS_KEY, undefined);\n if (context.mode !== 'tui') context.ui?.setStatus(MCP_SESSION_AUTH_STATUS_KEY, undefined);\n if (activeContext === context) activeContext = undefined;\n if (!disposed) await session.reconfigure(failClosedSessionConfig(context.cwd));\n };\n });\n },\n ],\n async onDispose() {\n disposed = true;\n activeContext = undefined;\n await session.dispose();\n },\n };\n}\n","import type { PiPluginContext } from '@agimon-ai/doompi-core/piExtension';\n\nimport { createMcpPiRuntime } from '../../../../../services/piRuntime';\nexport const createMcpPiRoot = ({ runtime }: PiPluginContext) => {\n if (!runtime) throw new Error('MCP requires the Cordis runtime mode.');\n const state = createMcpPiRuntime(runtime);\n return { value: state, services: state.services, onDispose: () => state.onDispose() };\n};\nexport type McpPiScope = Awaited<ReturnType<typeof createMcpPiRoot>>['value'];\n","import { defineRoot } from '@agimon-ai/doompi-core/extensionFile';\n\nimport { createMcpPiRoot } from './_lib/piRoot';\n\nexport default defineRoot(createMcpPiRoot);\n","import { defineRoutedContribution, type WithRoot } from '@agimon-ai/doompi-core/extensionFile';\nimport type { PiPluginContext } from '@agimon-ai/doompi-core/piExtension';\n\nimport { createMcpCommand } from '../../../../../services/mcpCommand';\nimport type { McpPiScope } from '../_lib/piRoot';\nexport default defineRoutedContribution(\n (context: WithRoot<PiPluginContext<unknown>, McpPiScope>) =>\n [\n createMcpCommand(context.root.session, {\n openOverlay: async (ctx) => {\n const { openMcpOverlay } = await import('../../../../../tui/mcpOverlay');\n return openMcpOverlay(ctx, context.root.session);\n },\n }),\n ] as const,\n { cardinality: 'many' },\n);\n","import { defineResource } from '@agimon-ai/doompi-core/extensionFile';\n\nexport default defineResource({\n source: '@agimon-ai/doompi-mcp',\n moduleUrl: import.meta.url,\n skills: [\n {\n name: 'doompi-use-mcp',\n description:\n 'Use Doom Pi MCP to inspect domain-scoped servers, authenticate, reload configuration, and troubleshoot tool availability.',\n },\n ],\n});\n","import type { PiToolCollection, PiToolDeclaration } from '@agimon-ai/doompi-core/piExtension';\n\nimport type { CatalogTool } from '../../services/mcpCatalog';\nimport type { McpSession } from '../../services/mcpSession';\nimport { createMcpTool, type McpToolRenderers } from '../mcpTools';\nexport function createMcpToolCollection(\n session: McpSession,\n renderers: (tool: CatalogTool) => McpToolRenderers = () => ({}),\n): PiToolCollection {\n const declarations = new Map<CatalogTool, PiToolDeclaration>();\n return {\n snapshot: (): readonly PiToolDeclaration[] =>\n session.toolDefinitions().map((tool) => {\n let declaration = declarations.get(tool);\n if (!declaration) {\n declaration = createMcpTool(\n session.getClientManager,\n tool,\n (candidate) => session.isToolAvailable(candidate),\n renderers(tool),\n );\n declarations.set(tool, declaration);\n }\n return declaration;\n }),\n subscribe: (listener: () => void) => session.onChange(listener),\n };\n}\n","import { DoomToolCall, renderToolHeading } from '@agimon-ai/doompi-ui/toolChrome';\nimport type { Theme } from '@earendil-works/pi-coding-agent';\nimport { type Component, truncateToWidth, wrapTextWithAnsi } from '@earendil-works/pi-tui';\n\nconst COLLAPSED_RESULT_LINES = 12;\nconst MAX_ARGUMENTS = 3;\nconst ELLIPSIS = '…';\n\ninterface McpToolTextLayout {\n wrap: boolean;\n separator: boolean;\n trailingBlank: boolean;\n}\n\n/** Bash-compatible width budget, horizontal inset, and structural result divider. */\nclass McpToolText implements Component {\n constructor(\n private readonly lines: readonly string[],\n private readonly layout: McpToolTextLayout,\n private readonly theme: Theme,\n ) {}\n\n render(width: number): string[] {\n if (width <= 0) return [];\n const contentWidth = Math.max(1, width - 2);\n const rendered = this.layout.wrap\n ? this.lines.flatMap((line) => wrapTextWithAnsi(line, contentWidth))\n : this.lines.map((line) => truncateToWidth(line, contentWidth, ELLIPSIS));\n if (this.layout.separator) {\n rendered.unshift(this.theme.fg('borderMuted', '─'.repeat(contentWidth)));\n }\n const padded = rendered.map((line) => ` ${line}`);\n if (this.layout.trailingBlank) padded.push('');\n return padded;\n }\n\n invalidate(): void {\n // Content is immutable and reflows from the current width on every render.\n }\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\nfunction argumentSummary(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 interface McpToolIdentity {\n serverName: string;\n toolName: string;\n}\n\nexport function renderMcpCall(tool: McpToolIdentity, params: Record<string, unknown>, theme: Theme): Component {\n const heading = renderToolHeading('mcp', tool.serverName, theme, 'muted');\n const toolName = theme.fg('accent', tool.toolName);\n const argumentsText = argumentSummary(params);\n const text = `${heading}${theme.fg('muted', ' / ')}${toolName}${\n argumentsText ? ` ${theme.fg('muted', `· ${argumentsText}`)}` : ''\n }`;\n return new DoomToolCall(text);\n}\n\nexport interface McpToolResultLike {\n content?: Array<{ type: string; text?: string }>;\n}\n\nexport interface McpToolResultOptions {\n expanded: boolean;\n isPartial: boolean;\n isError: boolean;\n}\n\nfunction resultLines(result: McpToolResultLike): string[] {\n const text = (result.content ?? []).map((block) => block.text ?? '').join('');\n const lines = text.split('\\n');\n while (lines.length > 0 && lines.at(-1)?.trim() === '') lines.pop();\n return lines;\n}\n\nexport function renderMcpResult(result: McpToolResultLike, options: McpToolResultOptions, theme: Theme): Component {\n const all = resultLines(result);\n const shown = options.expanded ? all : all.slice(0, COLLAPSED_RESULT_LINES);\n const body = shown.map((line) => theme.fg('toolOutput', line));\n\n if (options.isPartial) {\n body.push(theme.fg('warning', '◐') + theme.fg('dim', ' running'));\n } else if (options.isError) {\n body.push(theme.fg('error', '✗') + theme.fg('dim', ' failed'));\n } else if (!options.expanded && all.length > shown.length) {\n body.push(theme.fg('dim', '… ctrl+o'));\n } else if (body.length === 0) {\n body.push(theme.fg('success', '✓') + theme.fg('dim', ' done'));\n }\n\n return new McpToolText(body, { wrap: options.expanded, separator: true, trailingBlank: true }, theme);\n}\n","import { defineRoutedContribution, type WithRoot } from '@agimon-ai/doompi-core/extensionFile';\nimport type { PiPluginContext, PiToolCollection } from '@agimon-ai/doompi-core/piExtension';\n\nimport { createMcpToolCollection } from '../../../../../services/mcpToolCollection';\nimport { renderMcpCall, renderMcpResult } from '../../../../../tui/mcpToolRender';\nimport type { McpPiScope } from '../_lib/piRoot';\n\nexport default defineRoutedContribution(\n (context: WithRoot<PiPluginContext<unknown>, McpPiScope>): PiToolCollection =>\n createMcpToolCollection(context.root.session, (tool) => ({\n renderCall: (params, theme) => renderMcpCall(tool, params as Record<string, unknown>, theme),\n renderResult: (result, options, theme, execution) =>\n renderMcpResult(result, { ...options, isError: execution.isError }, theme),\n })),\n { cardinality: 'collection' },\n);\n","// Generated by @agimon-ai/doompi-build. Do not edit by hand.\nimport { definePiExtension, piToolContributions, type PiPluginContext, type PiPluginContributions } from '@agimon-ai/doompi-core/piExtension';\nimport { composeRootHooks } from '@agimon-ai/doompi-core/extensionFile';\n\nimport rootSession from '../src/extensions/workspaces/sessions/(backend)/root.cli';\nimport commandMcp from '../src/extensions/workspaces/sessions/(backend)/command/mcp.cli';\nimport resourceDoompiUseMcp from '../src/extensions/workspaces/sessions/(backend)/resource/doompi-use-mcp.cli';\nimport toolMcp from '../src/extensions/workspaces/sessions/(backend)/tool/mcp.cli';\n\ntype OptionsOf<T> = T extends (context: PiPluginContext<infer Options>) => unknown ? Options : never;\ntype InferredOptions = Exclude<OptionsOf<typeof rootSession> | OptionsOf<typeof commandMcp> | OptionsOf<typeof resourceDoompiUseMcp> | OptionsOf<typeof toolMcp>, undefined>;\ntype Intersect<Union> =\n (Union extends unknown ? (value: Union) => void : never) extends (value: infer Value) => void ? Value : never;\ntype ExtensionOptions = [InferredOptions] extends [never] ? undefined : Intersect<InferredOptions>;\n\ntype Factory<T, C> = (context: C) => T;\nconst at = <T, C>(value: T | Factory<T, C>, context: C): T =>\n typeof value === 'function' ? (value as Factory<T, C>)(context) : value;\ntype ManyFactory<T, C> = (context: C) => T | readonly T[];\nconst many = <T, C>(value: T | readonly T[] | ManyFactory<T, C>, context: C): readonly T[] => {\n const resolved = typeof value === 'function' ? (value as ManyFactory<T, C>)(context) : value;\n return Array.isArray(resolved) ? resolved : [resolved as T];\n};\n\nexport const extension = definePiExtension<ExtensionOptions>('@agimon-ai/doompi-mcp', async (context) => {\n const scopeSession = await rootSession(context);\n const contextSession = { ...context, root: scopeSession.value };\n return {\n ...composeRootHooks(scopeSession),\n get commands(): PiPluginContributions['commands'] { return [...many(commandMcp, contextSession)]; },\n get resources(): PiPluginContributions['resources'] { return [at(resourceDoompiUseMcp, contextSession)]; },\n ...piToolContributions('@agimon-ai/doompi-mcp', at(toolMcp, contextSession)),\n services: [...(scopeSession.services ?? [])],\n };\n});\n\nexport default extension;\n"],"mappings":"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"}
@@ -2,22 +2,26 @@ Object.defineProperties(exports, {
2
2
  __esModule: { value: true },
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
- const require_mcpCatalog = require("../mcpCatalog-nbZdP5rF.cjs");
6
- const require_projection = require("../projection-ZDNTQ3iE.cjs");
7
- const require_mcpCommand = require("../mcpCommand-btmh62JV.cjs");
8
- const require_keyringTokenStore = require("../keyringTokenStore-BwvTXKvD.cjs");
5
+ const require_rolldown_runtime = require("../rolldown-runtime-C0BPl7ul.cjs");
6
+ const require_mcpCatalog = require("../mcpCatalog-Bnkul3t_.cjs");
7
+ const require_projection = require("../projection-w3XxXmVi.cjs");
8
+ const require_mcpCommand = require("../mcpCommand-BARs6Y1N.cjs");
9
+ const require_keyringTokenStore = require("../keyringTokenStore-LBsDb_eC.cjs");
9
10
  let node_crypto = require("node:crypto");
10
11
  let node_fs = require("node:fs");
11
- node_fs = require_mcpCatalog.__toESM(node_fs, 1);
12
+ node_fs = require_rolldown_runtime.__toESM(node_fs, 1);
12
13
  let node_path = require("node:path");
13
- node_path = require_mcpCatalog.__toESM(node_path, 1);
14
+ node_path = require_rolldown_runtime.__toESM(node_path, 1);
14
15
  let node_os = require("node:os");
15
- node_os = require_mcpCatalog.__toESM(node_os, 1);
16
+ node_os = require_rolldown_runtime.__toESM(node_os, 1);
17
+ let _agimon_ai_doompi_core_mcpProjection = require("@agimon-ai/doompi-core/mcpProjection");
16
18
  let _agimon_ai_doompi_core_extensionFile = require("@agimon-ai/doompi-core/extensionFile");
17
19
  let _agimon_ai_doompi_core_childSession = require("@agimon-ai/doompi-core/childSession");
18
20
  let _agimon_ai_doompi_core_mcpStatus = require("@agimon-ai/doompi-core/mcpStatus");
19
21
  let _agimon_ai_doompi_core_mcpToolResolver = require("@agimon-ai/doompi-core/mcpToolResolver");
20
22
  let _agimon_ai_doompi_core_serverFacet = require("@agimon-ai/doompi-core/serverFacet");
23
+ let _agimon_ai_doompi_core_headless = require("@agimon-ai/doompi-core/headless");
24
+ let _agimon_ai_doompi_config_harnessStore = require("@agimon-ai/doompi-config/harnessStore");
21
25
  let _agimon_ai_doompi_core_web = require("@agimon-ai/doompi-core/web");
22
26
  //#region src/services/mcpHeadlessTools/index.ts
23
27
  const MCP_HEADLESS_TOOLS_SERVICE = "doom/mcp-headless-tools";
@@ -30,8 +34,23 @@ function mountMcpHeadlessTools(tools) {
30
34
  }
31
35
  //#endregion
32
36
  //#region src/services/serverRuntime/index.ts
33
- function createMcpServerRuntime(environment = {}) {
37
+ function sessionConfiguration(execution, workspaceRoot) {
38
+ if (workspaceRoot !== void 0) {
39
+ const loaded = (0, _agimon_ai_doompi_config_harnessStore.loadHarnessState)({ ...execution.environment });
40
+ const projection = loaded.state.mcpProjection;
41
+ if (loaded.filePath && loaded.state.root === workspaceRoot && execution.repoRoot === workspaceRoot && loaded.state.mcp && loaded.state.majorMode === execution.selection.majorMode && JSON.stringify(loaded.state.domains) === JSON.stringify(execution.selection.domains) && JSON.stringify(loaded.state.layers) === JSON.stringify(execution.selection.activeLayers) && (0, _agimon_ai_doompi_core_mcpProjection.isDoomMcpProjection)(projection) && projection.repoRoot === workspaceRoot) return require_projection.mcpSessionConfigFromProjection(projection, execution.cwd);
42
+ return {
43
+ enabled: false,
44
+ repoRoot: execution.cwd,
45
+ stagingDirectory: node_path.default.join(execution.cwd, ".doom", "mcp-disabled"),
46
+ sources: []
47
+ };
48
+ }
49
+ return require_mcpCatalog.readSessionConfig(execution.environment, execution.cwd);
50
+ }
51
+ function createMcpServerRuntime(environment = {}, workspaceRoot) {
34
52
  let active;
53
+ let staleSelection = false;
35
54
  const authorizing = /* @__PURE__ */ new Map();
36
55
  const session = new require_mcpCommand.McpSession({
37
56
  environment: { ...environment },
@@ -47,6 +66,7 @@ function createMcpServerRuntime(environment = {}) {
47
66
  name: "doompi-mcp-runtime",
48
67
  async start(execution) {
49
68
  active = execution;
69
+ staleSelection = false;
50
70
  const reported = /* @__PURE__ */ new Set();
51
71
  const publish = () => {
52
72
  execution.client.setStatus(require_mcpCommand.MCP_STATUS_KEY, session.getServers().map((server) => server.name).join(","));
@@ -63,7 +83,7 @@ function createMcpServerRuntime(environment = {}) {
63
83
  };
64
84
  const stopPublishing = session.onChange(publish);
65
85
  try {
66
- await session.reconfigure(require_mcpCatalog.readSessionConfig(execution.environment, execution.cwd));
86
+ await session.reconfigure(sessionConfiguration(execution, workspaceRoot), execution.cwd, execution.repoRoot);
67
87
  publish();
68
88
  } catch (error) {
69
89
  await execution.client.notify({
@@ -76,6 +96,7 @@ function createMcpServerRuntime(environment = {}) {
76
96
  stopPublishing();
77
97
  if (active !== execution) return;
78
98
  active = void 0;
99
+ staleSelection = false;
79
100
  authorizing.clear();
80
101
  try {
81
102
  await session.dispose();
@@ -93,6 +114,7 @@ function createMcpServerRuntime(environment = {}) {
93
114
  };
94
115
  const invoke = async (parameters, signal) => {
95
116
  if (!active) throw new Error("The MCP runtime has not started yet.");
117
+ if (staleSelection) throw new Error("The MCP projection is stale for the current selection.");
96
118
  const selected = session.activeToolDefinitions().find((candidate) => candidate.serverName === parameters.server && candidate.toolName === parameters.tool);
97
119
  if (!selected) throw new Error(`MCP tool ${parameters.server}/${parameters.tool} is not available in this session.`);
98
120
  return session.invokeTool(selected.piName, parameters.arguments ?? {}, signal);
@@ -118,6 +140,7 @@ function createMcpServerRuntime(environment = {}) {
118
140
  return;
119
141
  }
120
142
  if (!active) throw new Error("The MCP runtime has not started yet.");
143
+ if (staleSelection) throw new Error("The MCP projection is stale for the current selection.");
121
144
  if (subcommand === "auth" || subcommand === "disconnect") {
122
145
  if (!serverName) throw new Error(`Name the server, for example /mcp ${subcommand} <server>.`);
123
146
  const server = session.getServers().find((candidate) => candidate.name === serverName);
@@ -158,7 +181,7 @@ function createMcpServerRuntime(environment = {}) {
158
181
  stagingDirectory: execution.cwd
159
182
  });
160
183
  }
161
- await session.reconfigure(require_mcpCatalog.readSessionConfig(execution.environment, execution.cwd));
184
+ await session.reconfigure(sessionConfiguration(execution, workspaceRoot), execution.cwd, execution.repoRoot);
162
185
  await notify("Reconnecting MCP servers.");
163
186
  return;
164
187
  }
@@ -188,16 +211,32 @@ function createMcpServerRuntime(environment = {}) {
188
211
  }
189
212
  }
190
213
  }],
191
- childTool
214
+ childTool,
215
+ async onSelectionChange(selection) {
216
+ if (!active || workspaceRoot === void 0) return;
217
+ const initial = active.selection;
218
+ if (!initial || JSON.stringify(initial.domains) === JSON.stringify(selection.domains)) return;
219
+ staleSelection = true;
220
+ authorizing.clear();
221
+ await session.reconfigure({
222
+ enabled: false,
223
+ repoRoot: active.cwd,
224
+ stagingDirectory: node_path.default.join(active.cwd, ".doom", "mcp-disabled"),
225
+ sources: []
226
+ });
227
+ }
192
228
  };
193
229
  }
194
230
  //#endregion
195
231
  //#region src/extensions/workspaces/sessions/(backend)/_lib/serverRoot.ts
196
232
  const createMcpServerRoot = (context) => {
197
- const runtime = createMcpServerRuntime(context?.agent?.context?.environment);
233
+ const runtime = createMcpServerRuntime(context?.agent?.context?.environment, context?.host.context.workspaceRoot);
198
234
  const generation = `${context?.agent?.context?.sessionId ?? crypto.randomUUID()}:mcp-server`;
199
235
  const { session } = runtime;
200
236
  const mountSession = (cordis) => {
237
+ cordis.inject([_agimon_ai_doompi_core_headless.DOOM_HEADLESS_HOST_SERVICE], (hostContext) => {
238
+ return hostContext.get(_agimon_ai_doompi_core_headless.DOOM_HEADLESS_HOST_SERVICE).subscribeSelection((selection) => runtime.onSelectionChange(selection));
239
+ });
201
240
  cordis.plugin((provider) => {
202
241
  provider.provide(_agimon_ai_doompi_core_mcpStatus.DOOM_MCP_STATUS_SERVICE, {
203
242
  generation,
@@ -418,6 +457,8 @@ var McpSettingsManager = class {
418
457
  try {
419
458
  const handle = await owner.start({
420
459
  configSources: prepared.configSources,
460
+ workspaceRoot: repositoryRoot,
461
+ executionCwd: repositoryRoot,
421
462
  tokenStore: await this.tokenStore(),
422
463
  onAuthorizationUrl: (_url, serverName) => {
423
464
  liveStates.set(serverName, {
@@ -479,7 +520,7 @@ var McpSettingsManager = class {
479
520
  };
480
521
  this.flows.set(flow.id, flow);
481
522
  this.busyRepositories.add(repositoryId);
482
- this.runAuthorization(flow, prepared.configSources, redirect);
523
+ this.runAuthorization(flow, prepared.configSources, repositoryRoot, redirect);
483
524
  return publicFlow(flow);
484
525
  }
485
526
  getAuthorization(flowId, repositoryId) {
@@ -496,7 +537,7 @@ var McpSettingsManager = class {
496
537
  }
497
538
  return publicFlow(flow);
498
539
  }
499
- async runAuthorization(flow, sources, redirect) {
540
+ async runAuthorization(flow, sources, repositoryRoot, redirect) {
500
541
  const owner = new require_mcpCatalog.McpRuntimeOwner();
501
542
  flow.owner = owner;
502
543
  flow.timeout = setTimeout(() => {
@@ -508,6 +549,8 @@ var McpSettingsManager = class {
508
549
  try {
509
550
  const handle = await owner.start({
510
551
  configSources: sources,
552
+ workspaceRoot: repositoryRoot,
553
+ executionCwd: repositoryRoot,
511
554
  tokenStore: await this.tokenStore(),
512
555
  ...redirect ? { callbackServer: require_mcpCatalog.hubCallbackSink(redirect) } : {},
513
556
  onAuthorizationUrl: (url, serverName) => {