@agimon-ai/doompi-core 0.0.1-alpha.82 → 0.0.1-alpha.83

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.
@@ -309,6 +309,7 @@ function createSessionMcpRoutes(options) {
309
309
  if (options.registrationStore === void 0) return;
310
310
  const active = target(workspaceId, sessionId);
311
311
  if (active === void 0 || grant.sessionGeneration !== active.generation || grant.clientId === "") throw new Error("The session grant is no longer active.");
312
+ if (authorization.readClient(grant.clientId)?.tokenEndpointAuthMethod === "api_key") return;
312
313
  const registration = authorization.persistentRegistration(grant.clientId, workspaceId, Date.now());
313
314
  if (registration === void 0 || !options.registrationStore.save(registration)) throw new Error("The verified Session MCP client could not be saved.");
314
315
  },
@@ -353,7 +354,7 @@ function createSessionMcpRoutes(options) {
353
354
  const client = authorization.readClient(clientId);
354
355
  const binding = authorization.readAuthorizationBinding(clientId);
355
356
  const redirectUri = url.searchParams.get("redirect_uri") ?? "";
356
- if (client === void 0 || binding === void 0 || redirectUri !== client.redirectUri) return oauthError(new require_index$1.SessionMcpOAuthError("invalid_client", "Unknown client or callback."));
357
+ if (client === void 0 || client.tokenEndpointAuthMethod !== "client_secret_post" || binding === void 0 || redirectUri !== client.redirectUri) return oauthError(new require_index$1.SessionMcpOAuthError("invalid_client", "Unknown client or callback."));
357
358
  const callback = new URL(client.redirectUri);
358
359
  const state = url.searchParams.get("state");
359
360
  try {
@@ -507,7 +508,10 @@ function createSessionMcpRoutes(options) {
507
508
  const hasSkills = Object.hasOwn(input, "skills");
508
509
  const tools = parseStringArray(input.tools);
509
510
  const skills = parseStringArray(input.skills);
510
- if (typeof input.redirectUri !== "string") return json(400, { error: "A redirectUri is required." });
511
+ const apiKey = input.authMethod === "api_key";
512
+ if (input.authMethod !== void 0 && input.authMethod !== "oauth" && !apiKey) return json(400, { error: "Authentication method is not supported." });
513
+ if (apiKey && (scope !== "session" || Object.hasOwn(input, "redirectUri"))) return json(400, { error: "API keys require session scope and no redirectUri." });
514
+ if (!apiKey && typeof input.redirectUri !== "string") return json(400, { error: "A redirectUri is required." });
511
515
  if (scope === "session" && (hasTools || hasSkills)) return json(400, { error: "Session scope cannot include capability grants." });
512
516
  if (scope === "restricted" && (typeof input.name !== "string" || !tools || !skills)) return json(400, { error: "Restricted scope requires a name, tools, and skills." });
513
517
  if (scope === "restricted") {
@@ -522,13 +526,16 @@ function createSessionMcpRoutes(options) {
522
526
  if (tools.some((name) => !activeTools.has(name)) || skills.some((name) => !activeSkills.has(name))) return json(400, { error: "Every requested grant must be active in the session." });
523
527
  }
524
528
  try {
525
- const client = authorization.createClient({
529
+ const client = authorization.createClient(apiKey ? {
530
+ name: typeof input.name === "string" ? input.name : "API key",
531
+ authMethod: "api_key"
532
+ } : {
526
533
  name: scope === "session" ? defaultClientName(configuredOrigin) : input.name,
527
534
  redirectUri: input.redirectUri
528
535
  });
529
536
  const audience = `${configuredOrigin}${sessionPath(workspaceId, sessionId)}`;
530
537
  try {
531
- return json(201, { client: publicClient(client, scope === "session" ? authorization.createAuthorizationBinding({
538
+ const binding = scope === "session" ? authorization.createAuthorizationBinding({
532
539
  clientId: client.clientId,
533
540
  sessionId,
534
541
  sessionGeneration: resolved.generation,
@@ -544,7 +551,18 @@ function createSessionMcpRoutes(options) {
544
551
  routing,
545
552
  tools: [...new Set(tools)],
546
553
  skills: [...new Set(skills)]
547
- })) });
554
+ });
555
+ if (apiKey) {
556
+ const registration = authorization.persistentRegistration(client.clientId, workspaceId, Date.now());
557
+ if (registration === void 0 || !options.registrationStore.save(registration)) {
558
+ authorization.revokeClient(client.clientId);
559
+ return json(500, { error: "API key could not be saved." });
560
+ }
561
+ }
562
+ return json(201, { client: {
563
+ ...publicClient(client, binding),
564
+ clientSecret: client.clientSecret
565
+ } });
548
566
  } catch (error) {
549
567
  authorization.revokeClient(client.clientId);
550
568
  throw error;
@@ -1 +1 @@
1
- {"version":3,"file":"sessionMcpRoutes.cjs","names":["SessionMcpOAuthError","sessionMcpRouting","path","SessionMcpConversationError","fs","createSessionMcpAuthorizationService","createSessionMcpHttpHandler"],"sources":["../../../src/server/sessionMcpRoutes.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\n\nimport type { DoomHubSessionReservations, DoomHubSessionScope } from '../schemas/hubChannel';\nimport {\n createSessionMcpAuthorizationService,\n SessionMcpOAuthError,\n sessionMcpRouting,\n type SessionMcpAuthorizationBinding,\n type SessionMcpAuthorizationService,\n type SessionMcpClient,\n} from '../services/sessionMcpAuthorization';\nimport { SessionMcpConversationError, type SessionMcpConversationStore } from '../services/sessionMcpConversations';\nimport type { SessionMcpRegistrationStore } from '../services/sessionMcpRegistrationStore';\nimport type { HeadlessHub, HeadlessHubSession } from './headlessHub';\nimport { createSessionMcpHttpHandler, type SessionMcpHttpHandler } from './sessionMcpHandler';\n\nconst AUTHORIZATION_SERVER_DISCOVERY = '/.well-known/oauth-authorization-server';\nconst AUTHORIZE_ROUTE = '/oauth/authorize';\nconst TOKEN_ROUTE = '/oauth/token';\nconst SESSION_MCP_PATTERN = /^\\/api\\/workspaces\\/([^/]+)\\/sessions\\/([^/]+)\\/mcp$/u;\nconst SESSION_MCP_CONFIG_PATTERN = /^\\/api\\/workspaces\\/([^/]+)\\/sessions\\/([^/]+)\\/mcp\\/config$/u;\nconst SESSION_MCP_CLIENTS_PATTERN = /^\\/api\\/workspaces\\/([^/]+)\\/sessions\\/([^/]+)\\/mcp\\/clients(?:\\/([^/]+))?$/u;\nconst SESSION_MCP_CONVERSATIONS_PATTERN =\n /^\\/api\\/workspaces\\/([^/]+)\\/sessions\\/([^/]+)\\/mcp\\/conversations(?:\\/([^/]+))?$/u;\nconst PROTECTED_RESOURCE_PATTERN =\n /^\\/\\.well-known\\/oauth-protected-resource(\\/api\\/workspaces\\/[^/]+\\/sessions\\/[^/]+\\/mcp)$/u;\n\nexport interface SessionMcpRoutesOptions {\n readonly headlessHub: HeadlessHub;\n readonly publicOrigin: () => string | undefined;\n readonly publicOriginRevision?: () => number;\n readonly authorization?: SessionMcpAuthorizationService;\n readonly registrationStore?: SessionMcpRegistrationStore;\n readonly conversationStore?: SessionMcpConversationStore;\n readonly isSessionPersisted?: (sessionId: string, cwd: string) => boolean;\n readonly onNotice?: (message: string) => void;\n}\n\nexport interface SessionMcpRoutes {\n handlePublic(request: Request): Promise<Response | undefined>;\n handleHost(request: Request): Promise<Response | undefined>;\n readonly reservations: DoomHubSessionReservations;\n closeSessionBinding(sessionId: string): void;\n close(): void;\n}\n\nfunction json(status: number, value: unknown): Response {\n return Response.json(value, { status, headers: { 'cache-control': 'no-store' } });\n}\n\nfunction oauthError(error: unknown): Response {\n if (error instanceof SessionMcpOAuthError)\n return json(error.code === 'invalid_client' ? 401 : 400, {\n error: error.code,\n error_description: error.message,\n });\n return json(400, { error: 'invalid_request', error_description: 'The OAuth request was invalid.' });\n}\n\nfunction trustedOrigin(value: string | undefined): string | undefined {\n if (value === undefined) return undefined;\n try {\n const url = new URL(value);\n return url.protocol === 'https:' && url.pathname === '/' && url.search === '' && url.hash === ''\n ? url.origin\n : undefined;\n } catch {\n return undefined;\n }\n}\n\nfunction sessionPath(workspaceId: string, sessionId: string): string {\n return `/api/workspaces/${encodeURIComponent(workspaceId)}/sessions/${encodeURIComponent(sessionId)}/mcp`;\n}\n\nfunction parseStringArray(value: unknown): readonly string[] | undefined {\n return Array.isArray(value) && value.every((entry) => typeof entry === 'string') ? value : undefined;\n}\n\nfunction defaultClientName(origin: string): string {\n return `ChatGPT · ${new URL(origin).hostname}`;\n}\n\nfunction formString(form: FormData, name: string): string {\n const value = form.get(name);\n return typeof value === 'string' ? value : '';\n}\n\nfunction publicClient(client: SessionMcpClient, binding: SessionMcpAuthorizationBinding): Record<string, unknown> {\n return {\n ...client,\n scope: binding.scope,\n routing: sessionMcpRouting(binding.routing),\n tools: binding.tools,\n skills: binding.skills,\n audience: binding.audience,\n };\n}\n\n/** Canonicalizes an intended directory without creating it or accepting symlink aliases. */\nfunction executionDirectory(value: string): string {\n if (!path.isAbsolute(value) || value.includes('\\0') || value.length > 4096)\n throw new SessionMcpConversationError('INVALID_EXECUTION_DIRECTORY', 'Choose an absolute execution directory.');\n let ancestor = path.resolve(value);\n const suffix: string[] = [];\n for (;;) {\n try {\n return path.join(fs.realpathSync(ancestor), ...suffix);\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== 'ENOENT' || path.dirname(ancestor) === ancestor)\n throw new SessionMcpConversationError(\n 'INVALID_EXECUTION_DIRECTORY',\n 'The execution directory cannot be resolved.',\n );\n suffix.unshift(path.basename(ancestor));\n ancestor = path.dirname(ancestor);\n }\n }\n}\n\nfunction overlappingDirectories(left: string, right: string): boolean {\n const contained = (root: string, target: string): boolean => {\n const relative = path.relative(root, target);\n return (\n relative === '' || (!path.isAbsolute(relative) && relative !== '..' && !relative.startsWith(`..${path.sep}`))\n );\n };\n return contained(left, right) || contained(right, left);\n}\n\n/** Routes the process-local session MCP authority and revokes every grant with its live incarnation. */\nexport function createSessionMcpRoutes(options: SessionMcpRoutesOptions): SessionMcpRoutes {\n const authorization = options.authorization ?? createSessionMcpAuthorizationService();\n const incarnations = new Map<\n string,\n { host: HeadlessHubSession['host']; generation: number; handlers: Map<string, SessionMcpHttpHandler> }\n >();\n let nextGeneration = 1;\n let publishPending = (): void => {};\n\n const revokeIncarnation = (sessionId: string, generation: number): void => {\n authorization.revokeSessionGeneration(sessionId, generation);\n };\n const register = (session: HeadlessHubSession): void => {\n const current = incarnations.get(session.id);\n if (current?.host === session.host) return;\n if (current !== undefined) revokeIncarnation(session.id, current.generation);\n incarnations.set(session.id, { host: session.host, generation: nextGeneration++, handlers: new Map() });\n };\n for (const session of options.headlessHub.snapshot()) register(session);\n const unsubscribe = options.headlessHub.onEvent((event) => {\n if (event.kind === 'upsert') {\n register(event.session);\n publishPending();\n }\n if (event.kind === 'removed') {\n const current = incarnations.get(event.sessionId);\n if (current !== undefined) revokeIncarnation(event.sessionId, current.generation);\n incarnations.delete(event.sessionId);\n }\n });\n\n let observedOrigin: string | undefined;\n let observedOriginRevision: number | undefined;\n let originObserved = false;\n const origin = (): string | undefined => {\n const current = trustedOrigin(options.publicOrigin());\n const revision = options.publicOriginRevision?.();\n if (\n (originObserved && current !== observedOrigin) ||\n (revision !== undefined && observedOriginRevision !== undefined && revision !== observedOriginRevision)\n ) {\n for (const client of authorization.listClients()) {\n authorization.revokeClient(client.clientId);\n options.registrationStore?.remove(client.clientId);\n }\n for (const incarnation of incarnations.values()) incarnation.handlers.clear();\n }\n observedOrigin = current;\n observedOriginRevision = revision;\n originObserved = true;\n restorePersistedRegistrations(current);\n return current;\n };\n const target = (workspaceId: string, sessionId: string) => {\n const session = options.headlessHub.session(sessionId);\n const incarnation = incarnations.get(sessionId);\n return session !== undefined && session.workspaceId === workspaceId && incarnation?.host === session.host\n ? { session, generation: incarnation.generation }\n : undefined;\n };\n const restorePersistedRegistrations = (configuredOrigin: string | undefined): void => {\n if (configuredOrigin === undefined) return;\n for (const registration of options.registrationStore?.registrations() ?? []) {\n const audience = `${configuredOrigin}${sessionPath(registration.workspaceId, registration.binding.sessionId)}`;\n if (registration.binding.audience !== audience) {\n options.registrationStore?.remove(registration.client.clientId);\n continue;\n }\n const resolved = target(registration.workspaceId, registration.binding.sessionId);\n if (resolved !== undefined) authorization.restorePersistentRegistration(registration, resolved.generation);\n }\n };\n\n const requireStore = (): SessionMcpConversationStore => {\n if (!options.conversationStore)\n throw new SessionMcpConversationError(\n 'CONVERSATION_ROUTING_UNAVAILABLE',\n 'Persistent conversation routing is unavailable.',\n );\n return options.conversationStore;\n };\n publishPending = () => {\n if (!options.conversationStore) return;\n try {\n const records = options.conversationStore.list();\n for (const parent of options.headlessHub.snapshot())\n options.headlessHub.setPendingSessionSetups?.(\n parent.id,\n records\n .filter((record) => record.parentSessionId === parent.id && record.state === 'pending')\n .map((record) => ({\n id: record.id,\n name: `conversation ${record.id.slice(0, 8)}`,\n createdAt: record.createdAt,\n ...(record.cwd === undefined ? {} : { cwd: record.cwd }),\n })),\n );\n } catch (error) {\n options.onNotice?.(error instanceof Error ? error.message : 'Conversation bindings are unavailable.');\n }\n };\n const readReservation = (id: string, parentSessionId: string) => {\n origin();\n const record = requireStore().get(id, parentSessionId);\n const binding = authorization.readAuthorizationBinding(record.clientId);\n const parent = target(record.parentWorkspaceId, parentSessionId);\n if (\n !parent ||\n binding?.routing !== 'conversation' ||\n binding.sessionId !== parentSessionId ||\n binding.sessionGeneration !== parent.generation\n )\n throw new SessionMcpConversationError(\n 'SESSION_UNAVAILABLE',\n 'The connection that owns this setup is no longer active.',\n id,\n );\n return { record, parent };\n };\n const reservations: DoomHubSessionReservations = {\n read(id, parentSessionId) {\n const { record } = readReservation(id, parentSessionId);\n return { sessionId: record.id, ...(record.cwd === undefined ? {} : { cwd: record.cwd }) };\n },\n async prepare(id, parentSessionId, suppliedDirectory) {\n const { record, parent } = readReservation(id, parentSessionId);\n const cwd = executionDirectory(suppliedDirectory);\n const parentRoot =\n options.headlessHub.workspaces().find((workspace) => workspace.id === parent.session.workspaceId)?.root ??\n parent.session.cwd;\n const occupied = [\n parentRoot,\n ...options.headlessHub\n .snapshot()\n .filter((session) => session.id !== id)\n .map((session) => session.cwd),\n ...requireStore()\n .list()\n .filter((entry) => entry.id !== id && entry.state !== 'closed' && entry.cwd !== undefined)\n .map((entry) => entry.cwd!),\n ];\n if (occupied.some((directory) => overlappingDirectories(cwd, executionDirectory(directory))))\n throw new SessionMcpConversationError(\n 'EXECUTION_DIRECTORY_SHARED',\n 'Choose a separate checkout, not a directory shared with another session.',\n id,\n );\n if (record.state === 'bound' && record.cwd !== cwd)\n throw new SessionMcpConversationError(\n 'SESSION_TARGET_FIXED',\n 'An initialized session cannot change its directory.',\n id,\n );\n requireStore().prepare(id, parentSessionId, cwd);\n publishPending();\n return { sessionId: id, cwd };\n },\n async complete(id, parentSessionId): Promise<DoomHubSessionScope> {\n const { record } = readReservation(id, parentSessionId);\n const child = options.headlessHub.session(id);\n if (\n !record.cwd ||\n !child?.workspaceId ||\n child.parentSessionId !== parentSessionId ||\n executionDirectory(child.cwd) !== record.cwd ||\n options.isSessionPersisted?.(id, child.cwd) === false\n )\n throw new SessionMcpConversationError(\n 'SESSION_SETUP_INCOMPLETE',\n 'The reserved session is not durably ready. Recover the existing setup instead of creating another checkout.',\n id,\n );\n requireStore().bind(id, parentSessionId, child.workspaceId);\n publishPending();\n return { sessionId: id, workspaceId: child.workspaceId, cwd: child.cwd };\n },\n };\n const provision = new Map<string, Promise<DoomHubSessionScope>>();\n const setupDirectory = async (\n id: string,\n parentSessionId: string,\n directory: string,\n ): Promise<DoomHubSessionScope> => {\n // A mistyped existing-directory choice must not permanently reserve a nonexistent path.\n const canonical = executionDirectory(directory);\n if (!fs.statSync(canonical).isDirectory()) throw new Error('The execution directory is not a directory.');\n const prepared = await reservations.prepare(id, parentSessionId, canonical);\n const pending = provision.get(id);\n if (pending) return pending;\n const setup = (async () => {\n if (!options.headlessHub.session(id)) {\n const record = requireStore().get(id, parentSessionId);\n if (record.state === 'bound' || options.isSessionPersisted?.(id, prepared.cwd))\n throw new SessionMcpConversationError(\n 'SESSION_UNAVAILABLE',\n 'Resume the existing session in DoomPi. It will not be recreated automatically.',\n id,\n );\n if (!fs.statSync(prepared.cwd).isDirectory()) throw new Error('The execution directory is not a directory.');\n await options.headlessHub.sessionService.create({\n cwd: prepared.cwd,\n name: `conversation ${id.slice(0, 8)}`,\n parentSessionId,\n sessionProvenance: 'remote-conversation',\n reservationId: id,\n });\n }\n return reservations.complete(id, parentSessionId);\n })();\n provision.set(id, setup);\n try {\n return await setup;\n } finally {\n if (provision.get(id) === setup) provision.delete(id);\n }\n };\n const provisionConversationWorktree = async (\n record: ReturnType<SessionMcpConversationStore['reserve']>,\n signal?: AbortSignal,\n ): Promise<DoomHubSessionScope> => {\n const pending = provision.get(record.id);\n if (pending) return pending;\n const setup = (async () => {\n try {\n const child = await options.headlessHub.sessionService.provisionReservedWorktree?.({\n reservationId: record.id,\n parentSessionId: record.parentSessionId,\n signal,\n });\n if (child === undefined || child.sessionId !== record.id)\n throw new Error('Automatic worktree provisioning did not create the reserved session.');\n return child;\n } catch (error) {\n if (error instanceof SessionMcpConversationError) throw error;\n throw new SessionMcpConversationError(\n 'SESSION_WORKTREE_PROVISION_FAILED',\n 'An automatic worktree could not be created for this conversation. Resolve the host Git setup, then retry.',\n record.id,\n );\n }\n })();\n provision.set(record.id, setup);\n try {\n return await setup;\n } finally {\n if (provision.get(record.id) === setup) provision.delete(record.id);\n }\n };\n const publicRoutes = async (request: Request): Promise<Response | undefined> => {\n const url = new URL(request.url);\n const configuredOrigin = origin();\n const mcpMatch = SESSION_MCP_PATTERN.exec(url.pathname);\n if (mcpMatch !== null) {\n if (configuredOrigin === undefined) return json(503, { error: 'Session MCP public origin is unavailable.' });\n const workspaceId = decodeURIComponent(mcpMatch[1]);\n const sessionId = decodeURIComponent(mcpMatch[2]);\n const exactPath = sessionPath(workspaceId, sessionId);\n if (url.pathname !== exactPath || url.search !== '') return json(404, { error: 'Not found.' });\n const audience = `${configuredOrigin}${exactPath}`;\n const handlers = target(workspaceId, sessionId) === undefined ? undefined : incarnations.get(sessionId)?.handlers;\n const handler =\n handlers?.get(audience) ??\n createSessionMcpHttpHandler({\n audience,\n authorization,\n onNotice: options.onNotice,\n resolveConversation: async (grant, digest, reserve, signal) => {\n const store = requireStore();\n let record = reserve\n ? store.reserve(grant.clientId, sessionId, workspaceId, digest)\n : store.find(grant.clientId, sessionId, digest);\n if (!record || record.state === 'closed')\n throw new SessionMcpConversationError(\n 'SESSION_UNAVAILABLE',\n 'This conversation binding is unavailable. It will not be recreated automatically.',\n );\n if (record.state === 'pending') {\n publishPending();\n await provisionConversationWorktree(record, signal);\n record = store.find(grant.clientId, sessionId, digest);\n if (!record || record.state !== 'bound')\n throw new SessionMcpConversationError(\n 'SESSION_WORKTREE_PROVISION_FAILED',\n 'The automatic worktree setup did not complete. Retry after resolving the host Git setup.',\n );\n }\n const child = record.workspaceId === undefined ? undefined : target(record.workspaceId, record.id);\n if (\n !child ||\n child.session.parentSessionId !== sessionId ||\n executionDirectory(child.session.cwd) !== record.cwd ||\n !fs.existsSync(child.session.cwd)\n )\n throw new SessionMcpConversationError(\n 'SESSION_UNAVAILABLE',\n 'The bound session is unavailable. Resume it in DoomPi; no other session will be used.',\n record.id,\n );\n return { sessionId: record.id, generation: child.generation, toolSurface: child.session.host.mcpSurface };\n },\n onVerified: (grant) => {\n if (options.registrationStore === undefined) return;\n const active = target(workspaceId, sessionId);\n if (active === undefined || grant.sessionGeneration !== active.generation || grant.clientId === '') {\n throw new Error('The session grant is no longer active.');\n }\n const registration = authorization.persistentRegistration(grant.clientId, workspaceId, Date.now());\n if (registration === undefined || !options.registrationStore.save(registration)) {\n throw new Error('The verified Session MCP client could not be saved.');\n }\n },\n resourceMetadataUrl: `${configuredOrigin}/.well-known/oauth-protected-resource${exactPath}`,\n resolveSession: (grantedSessionId) => {\n if (grantedSessionId !== sessionId) return undefined;\n const resolved = target(workspaceId, sessionId);\n return resolved === undefined\n ? undefined\n : { sessionId, generation: resolved.generation, toolSurface: resolved.session.host.mcpSurface };\n },\n });\n handlers?.set(audience, handler);\n return handler(new Request(audience, request));\n }\n\n const protectedMatch = PROTECTED_RESOURCE_PATTERN.exec(url.pathname);\n if (protectedMatch !== null && request.method === 'GET') {\n if (configuredOrigin === undefined) return json(503, { error: 'Session MCP public origin is unavailable.' });\n return json(200, {\n resource: `${configuredOrigin}${protectedMatch[1]}`,\n authorization_servers: [configuredOrigin],\n bearer_methods_supported: ['header'],\n });\n }\n if (url.pathname === AUTHORIZATION_SERVER_DISCOVERY && request.method === 'GET') {\n if (configuredOrigin === undefined) return json(503, { error: 'Session MCP public origin is unavailable.' });\n return json(200, {\n issuer: configuredOrigin,\n authorization_endpoint: `${configuredOrigin}${AUTHORIZE_ROUTE}`,\n token_endpoint: `${configuredOrigin}${TOKEN_ROUTE}`,\n response_types_supported: ['code'],\n grant_types_supported: ['authorization_code', 'refresh_token'],\n code_challenge_methods_supported: ['S256'],\n token_endpoint_auth_methods_supported: ['client_secret_post'],\n });\n }\n if (url.pathname === AUTHORIZE_ROUTE && request.method === 'GET') {\n if (configuredOrigin === undefined) return json(503, { error: 'Session MCP public origin is unavailable.' });\n const clientId = url.searchParams.get('client_id') ?? '';\n const client = authorization.readClient(clientId);\n const binding = authorization.readAuthorizationBinding(clientId);\n const redirectUri = url.searchParams.get('redirect_uri') ?? '';\n if (client === undefined || binding === undefined || redirectUri !== client.redirectUri) {\n return oauthError(new SessionMcpOAuthError('invalid_client', 'Unknown client or callback.'));\n }\n const callback = new URL(client.redirectUri);\n const state = url.searchParams.get('state');\n try {\n const boundSession = options.headlessHub.session(binding.sessionId);\n const boundIncarnation = incarnations.get(binding.sessionId);\n const expectedAudience =\n boundSession?.workspaceId === undefined\n ? undefined\n : `${configuredOrigin}${sessionPath(boundSession.workspaceId, binding.sessionId)}`;\n if (\n expectedAudience === undefined ||\n binding.audience !== expectedAudience ||\n boundIncarnation?.host !== boundSession?.host ||\n binding.sessionGeneration !== boundIncarnation?.generation\n ) {\n authorization.revokeClient(clientId);\n throw new SessionMcpOAuthError('invalid_grant', 'The preauthorized session is no longer active.');\n }\n if (url.searchParams.get('response_type') !== 'code')\n throw new SessionMcpOAuthError('invalid_request', 'Only the code response type is supported.');\n if (url.searchParams.get('resource') !== null && url.searchParams.get('resource') !== binding.audience)\n throw new SessionMcpOAuthError('invalid_request', 'The requested resource is not preauthorized.');\n const code = authorization.issueAuthorizationCode({\n clientId,\n redirectUri,\n codeChallenge: url.searchParams.get('code_challenge') ?? '',\n codeChallengeMethod: url.searchParams.get('code_challenge_method') as 'S256',\n });\n callback.searchParams.set('code', code.code);\n } catch (error) {\n callback.searchParams.set('error', error instanceof SessionMcpOAuthError ? error.code : 'invalid_request');\n callback.searchParams.set(\n 'error_description',\n error instanceof Error ? error.message : 'The OAuth request was invalid.',\n );\n }\n if (state !== null) callback.searchParams.set('state', state);\n return new Response(null, { status: 302, headers: { location: callback.href, 'cache-control': 'no-store' } });\n }\n if (url.pathname === TOKEN_ROUTE && request.method === 'POST') {\n try {\n const form = await request.formData();\n const grantType = formString(form, 'grant_type');\n const clientId = formString(form, 'client_id');\n const clientSecret = formString(form, 'client_secret');\n const result =\n grantType === 'authorization_code'\n ? authorization.exchangeToken({\n grantType,\n clientId,\n clientSecret,\n code: formString(form, 'code'),\n redirectUri: formString(form, 'redirect_uri'),\n codeVerifier: formString(form, 'code_verifier'),\n })\n : grantType === 'refresh_token'\n ? authorization.exchangeToken({\n grantType,\n clientId,\n clientSecret,\n refreshToken: formString(form, 'refresh_token'),\n })\n : (() => {\n throw new SessionMcpOAuthError('unsupported_grant_type', 'The grant type is not supported.');\n })();\n return json(200, {\n access_token: result.accessToken,\n refresh_token: result.refreshToken,\n token_type: result.tokenType,\n expires_in: result.expiresIn,\n });\n } catch (error) {\n return oauthError(error);\n }\n }\n return undefined;\n };\n\n publishPending();\n return {\n reservations,\n closeSessionBinding(sessionId) {\n options.conversationStore?.closeSession(sessionId);\n publishPending();\n },\n handlePublic: publicRoutes,\n async handleHost(request) {\n const url = new URL(request.url);\n origin();\n const configMatch = SESSION_MCP_CONFIG_PATTERN.exec(url.pathname);\n const match = SESSION_MCP_CLIENTS_PATTERN.exec(url.pathname);\n const conversationMatch = SESSION_MCP_CONVERSATIONS_PATTERN.exec(url.pathname);\n if (configMatch === null && match === null && conversationMatch === null) return undefined;\n const routeMatch = configMatch ?? match ?? conversationMatch!;\n const workspaceId = decodeURIComponent(routeMatch[1]);\n const sessionId = decodeURIComponent(routeMatch[2]);\n const clientId = match?.[3] === undefined ? undefined : decodeURIComponent(match[3]);\n const resolved = target(workspaceId, sessionId);\n if (resolved === undefined) return json(404, { error: 'Session not found.' });\n if (conversationMatch !== null) {\n const id = conversationMatch[3] === undefined ? undefined : decodeURIComponent(conversationMatch[3]);\n try {\n if (request.method === 'GET' && id === undefined)\n return json(200, {\n conversations: requireStore()\n .list()\n .filter((record) => record.parentSessionId === sessionId && record.state !== 'closed')\n .map(({ conversationDigest: _digest, clientId: _clientId, ...record }) => record),\n });\n if (id !== undefined && request.method === 'DELETE') {\n const record = requireStore().get(id, sessionId);\n if (record.state !== 'pending' || options.headlessHub.session(id))\n return json(409, { error: 'Remove the existing session instead.' });\n requireStore().closeSession(id);\n publishPending();\n return json(200, { ok: true });\n }\n if (id !== undefined && request.method === 'POST') {\n const body: unknown = await request.json();\n if (typeof body !== 'object' || body === null || !('cwd' in body) || typeof body.cwd !== 'string')\n return json(400, { error: 'An execution directory is required.' });\n return json(200, { session: await setupDirectory(id, sessionId, body.cwd) });\n }\n return json(405, { error: 'Method not allowed.' });\n } catch (error) {\n return json(409, {\n error:\n error instanceof SessionMcpConversationError\n ? error.message\n : 'Session setup failed. Recover the existing setup before retrying.',\n ...(error instanceof SessionMcpConversationError ? { code: error.code } : {}),\n });\n }\n }\n if (configMatch !== null) {\n if (request.method !== 'GET') return json(405, { error: 'Method not allowed.' });\n const configuredOrigin = origin();\n if (configuredOrigin === undefined) return json(503, { error: 'Session MCP public origin is unavailable.' });\n let surface;\n try {\n surface = resolved.session.host.mcpSurface.readSurface();\n } catch {\n return json(409, { error: 'The session capability surface is not ready.' });\n }\n return json(200, {\n audience: `${configuredOrigin}${sessionPath(workspaceId, sessionId)}`,\n authorizationEndpoint: `${configuredOrigin}${AUTHORIZE_ROUTE}`,\n tokenEndpoint: `${configuredOrigin}${TOKEN_ROUTE}`,\n tools: surface.tools.map(({ name, label, description }) => ({ name, label, description })),\n skills: surface.skills,\n });\n }\n if (clientId === undefined && request.method === 'GET') {\n return json(200, {\n clients: authorization.listClients().flatMap((client) => {\n const binding = authorization.readAuthorizationBinding(client.clientId);\n return binding?.sessionId === sessionId ? [publicClient(client, binding)] : [];\n }),\n });\n }\n if (clientId === undefined && request.method === 'POST') {\n const configuredOrigin = origin();\n if (configuredOrigin === undefined) return json(503, { error: 'Session MCP public origin is unavailable.' });\n let body: unknown;\n try {\n body = await request.json();\n } catch {\n return json(400, { error: 'Invalid client request.' });\n }\n if (typeof body !== 'object' || body === null) return json(400, { error: 'Invalid client request.' });\n const input = body as Record<string, unknown>;\n if (!options.conversationStore || !options.registrationStore)\n return json(503, { error: 'Mandatory conversation routing requires persistent host state.' });\n if (input.routing !== undefined && input.routing !== 'session' && input.routing !== 'conversation')\n return json(400, { error: 'Session MCP routing is not supported.' });\n const routing = sessionMcpRouting(input.routing);\n const requestedScope = input.scope;\n if (requestedScope !== undefined && requestedScope !== 'session' && requestedScope !== 'restricted') {\n return json(400, { error: 'Authorization scope is not supported.' });\n }\n const scope = requestedScope === 'session' ? 'session' : 'restricted';\n const hasTools = Object.hasOwn(input, 'tools');\n const hasSkills = Object.hasOwn(input, 'skills');\n const tools = parseStringArray(input.tools);\n const skills = parseStringArray(input.skills);\n if (typeof input.redirectUri !== 'string') return json(400, { error: 'A redirectUri is required.' });\n if (scope === 'session' && (hasTools || hasSkills)) {\n return json(400, { error: 'Session scope cannot include capability grants.' });\n }\n if (scope === 'restricted' && (typeof input.name !== 'string' || !tools || !skills)) {\n return json(400, { error: 'Restricted scope requires a name, tools, and skills.' });\n }\n if (scope === 'restricted') {\n let surface;\n try {\n surface = resolved.session.host.mcpSurface.readSurface();\n } catch {\n return json(409, { error: 'The session capability surface is not ready.' });\n }\n const activeTools = new Set(surface.tools.map((tool) => tool.name));\n const activeSkills = new Set(surface.skills.map((skill) => skill.name));\n if (tools!.some((name) => !activeTools.has(name)) || skills!.some((name) => !activeSkills.has(name)))\n return json(400, { error: 'Every requested grant must be active in the session.' });\n }\n try {\n const client = authorization.createClient({\n name: scope === 'session' ? defaultClientName(configuredOrigin) : (input.name as string),\n redirectUri: input.redirectUri,\n });\n const audience = `${configuredOrigin}${sessionPath(workspaceId, sessionId)}`;\n try {\n const binding =\n scope === 'session'\n ? authorization.createAuthorizationBinding({\n clientId: client.clientId,\n sessionId,\n sessionGeneration: resolved.generation,\n audience,\n scope: 'session',\n routing,\n })\n : authorization.createAuthorizationBinding({\n clientId: client.clientId,\n sessionId,\n sessionGeneration: resolved.generation,\n audience,\n scope: 'restricted',\n routing,\n tools: [...new Set(tools!)],\n skills: [...new Set(skills!)],\n });\n return json(201, { client: publicClient(client, binding) });\n } catch (error) {\n authorization.revokeClient(client.clientId);\n throw error;\n }\n } catch (error) {\n return oauthError(error);\n }\n }\n if (clientId !== undefined && request.method === 'DELETE') {\n const binding = authorization.readAuthorizationBinding(clientId);\n if (binding?.sessionId !== sessionId) return json(404, { error: 'Client not found.' });\n if (options.registrationStore !== undefined && !options.registrationStore.remove(clientId)) {\n return json(500, { error: 'Client revocation could not be saved.' });\n }\n authorization.revokeClient(clientId);\n options.conversationStore?.closeClient(clientId);\n publishPending();\n return json(200, { ok: true });\n }\n return json(405, { error: 'Method not allowed.' });\n },\n close() {\n unsubscribe();\n for (const [sessionId, incarnation] of incarnations) revokeIncarnation(sessionId, incarnation.generation);\n incarnations.clear();\n },\n };\n}\n\nexport function isPublicSessionMcpRoute(method: string, pathname: string): boolean {\n return (\n SESSION_MCP_PATTERN.test(pathname) ||\n (method === 'GET' && PROTECTED_RESOURCE_PATTERN.test(pathname)) ||\n (method === 'GET' && (pathname === AUTHORIZATION_SERVER_DISCOVERY || pathname === AUTHORIZE_ROUTE)) ||\n (method === 'POST' && pathname === TOKEN_ROUTE)\n );\n}\n\nexport function isSessionMcpHostRoute(pathname: string): boolean {\n return (\n SESSION_MCP_CONFIG_PATTERN.test(pathname) ||\n SESSION_MCP_CLIENTS_PATTERN.test(pathname) ||\n SESSION_MCP_CONVERSATIONS_PATTERN.test(pathname)\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"sessionMcpRoutes.cjs","names":["SessionMcpOAuthError","sessionMcpRouting","path","SessionMcpConversationError","fs","createSessionMcpAuthorizationService","createSessionMcpHttpHandler"],"sources":["../../../src/server/sessionMcpRoutes.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\n\nimport type { DoomHubSessionReservations, DoomHubSessionScope } from '../schemas/hubChannel';\nimport {\n createSessionMcpAuthorizationService,\n SessionMcpOAuthError,\n sessionMcpRouting,\n type SessionMcpAuthorizationBinding,\n type SessionMcpAuthorizationService,\n type SessionMcpClient,\n} from '../services/sessionMcpAuthorization';\nimport { SessionMcpConversationError, type SessionMcpConversationStore } from '../services/sessionMcpConversations';\nimport type { SessionMcpRegistrationStore } from '../services/sessionMcpRegistrationStore';\nimport type { HeadlessHub, HeadlessHubSession } from './headlessHub';\nimport { createSessionMcpHttpHandler, type SessionMcpHttpHandler } from './sessionMcpHandler';\n\nconst AUTHORIZATION_SERVER_DISCOVERY = '/.well-known/oauth-authorization-server';\nconst AUTHORIZE_ROUTE = '/oauth/authorize';\nconst TOKEN_ROUTE = '/oauth/token';\nconst SESSION_MCP_PATTERN = /^\\/api\\/workspaces\\/([^/]+)\\/sessions\\/([^/]+)\\/mcp$/u;\nconst SESSION_MCP_CONFIG_PATTERN = /^\\/api\\/workspaces\\/([^/]+)\\/sessions\\/([^/]+)\\/mcp\\/config$/u;\nconst SESSION_MCP_CLIENTS_PATTERN = /^\\/api\\/workspaces\\/([^/]+)\\/sessions\\/([^/]+)\\/mcp\\/clients(?:\\/([^/]+))?$/u;\nconst SESSION_MCP_CONVERSATIONS_PATTERN =\n /^\\/api\\/workspaces\\/([^/]+)\\/sessions\\/([^/]+)\\/mcp\\/conversations(?:\\/([^/]+))?$/u;\nconst PROTECTED_RESOURCE_PATTERN =\n /^\\/\\.well-known\\/oauth-protected-resource(\\/api\\/workspaces\\/[^/]+\\/sessions\\/[^/]+\\/mcp)$/u;\n\nexport interface SessionMcpRoutesOptions {\n readonly headlessHub: HeadlessHub;\n readonly publicOrigin: () => string | undefined;\n readonly publicOriginRevision?: () => number;\n readonly authorization?: SessionMcpAuthorizationService;\n readonly registrationStore?: SessionMcpRegistrationStore;\n readonly conversationStore?: SessionMcpConversationStore;\n readonly isSessionPersisted?: (sessionId: string, cwd: string) => boolean;\n readonly onNotice?: (message: string) => void;\n}\n\nexport interface SessionMcpRoutes {\n handlePublic(request: Request): Promise<Response | undefined>;\n handleHost(request: Request): Promise<Response | undefined>;\n readonly reservations: DoomHubSessionReservations;\n closeSessionBinding(sessionId: string): void;\n close(): void;\n}\n\nfunction json(status: number, value: unknown): Response {\n return Response.json(value, { status, headers: { 'cache-control': 'no-store' } });\n}\n\nfunction oauthError(error: unknown): Response {\n if (error instanceof SessionMcpOAuthError)\n return json(error.code === 'invalid_client' ? 401 : 400, {\n error: error.code,\n error_description: error.message,\n });\n return json(400, { error: 'invalid_request', error_description: 'The OAuth request was invalid.' });\n}\n\nfunction trustedOrigin(value: string | undefined): string | undefined {\n if (value === undefined) return undefined;\n try {\n const url = new URL(value);\n return url.protocol === 'https:' && url.pathname === '/' && url.search === '' && url.hash === ''\n ? url.origin\n : undefined;\n } catch {\n return undefined;\n }\n}\n\nfunction sessionPath(workspaceId: string, sessionId: string): string {\n return `/api/workspaces/${encodeURIComponent(workspaceId)}/sessions/${encodeURIComponent(sessionId)}/mcp`;\n}\n\nfunction parseStringArray(value: unknown): readonly string[] | undefined {\n return Array.isArray(value) && value.every((entry) => typeof entry === 'string') ? value : undefined;\n}\n\nfunction defaultClientName(origin: string): string {\n return `ChatGPT · ${new URL(origin).hostname}`;\n}\n\nfunction formString(form: FormData, name: string): string {\n const value = form.get(name);\n return typeof value === 'string' ? value : '';\n}\n\nfunction publicClient(client: SessionMcpClient, binding: SessionMcpAuthorizationBinding): Record<string, unknown> {\n return {\n ...client,\n scope: binding.scope,\n routing: sessionMcpRouting(binding.routing),\n tools: binding.tools,\n skills: binding.skills,\n audience: binding.audience,\n };\n}\n\n/** Canonicalizes an intended directory without creating it or accepting symlink aliases. */\nfunction executionDirectory(value: string): string {\n if (!path.isAbsolute(value) || value.includes('\\0') || value.length > 4096)\n throw new SessionMcpConversationError('INVALID_EXECUTION_DIRECTORY', 'Choose an absolute execution directory.');\n let ancestor = path.resolve(value);\n const suffix: string[] = [];\n for (;;) {\n try {\n return path.join(fs.realpathSync(ancestor), ...suffix);\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== 'ENOENT' || path.dirname(ancestor) === ancestor)\n throw new SessionMcpConversationError(\n 'INVALID_EXECUTION_DIRECTORY',\n 'The execution directory cannot be resolved.',\n );\n suffix.unshift(path.basename(ancestor));\n ancestor = path.dirname(ancestor);\n }\n }\n}\n\nfunction overlappingDirectories(left: string, right: string): boolean {\n const contained = (root: string, target: string): boolean => {\n const relative = path.relative(root, target);\n return (\n relative === '' || (!path.isAbsolute(relative) && relative !== '..' && !relative.startsWith(`..${path.sep}`))\n );\n };\n return contained(left, right) || contained(right, left);\n}\n\n/** Routes the process-local session MCP authority and revokes every grant with its live incarnation. */\nexport function createSessionMcpRoutes(options: SessionMcpRoutesOptions): SessionMcpRoutes {\n const authorization = options.authorization ?? createSessionMcpAuthorizationService();\n const incarnations = new Map<\n string,\n { host: HeadlessHubSession['host']; generation: number; handlers: Map<string, SessionMcpHttpHandler> }\n >();\n let nextGeneration = 1;\n let publishPending = (): void => {};\n\n const revokeIncarnation = (sessionId: string, generation: number): void => {\n authorization.revokeSessionGeneration(sessionId, generation);\n };\n const register = (session: HeadlessHubSession): void => {\n const current = incarnations.get(session.id);\n if (current?.host === session.host) return;\n if (current !== undefined) revokeIncarnation(session.id, current.generation);\n incarnations.set(session.id, { host: session.host, generation: nextGeneration++, handlers: new Map() });\n };\n for (const session of options.headlessHub.snapshot()) register(session);\n const unsubscribe = options.headlessHub.onEvent((event) => {\n if (event.kind === 'upsert') {\n register(event.session);\n publishPending();\n }\n if (event.kind === 'removed') {\n const current = incarnations.get(event.sessionId);\n if (current !== undefined) revokeIncarnation(event.sessionId, current.generation);\n incarnations.delete(event.sessionId);\n }\n });\n\n let observedOrigin: string | undefined;\n let observedOriginRevision: number | undefined;\n let originObserved = false;\n const origin = (): string | undefined => {\n const current = trustedOrigin(options.publicOrigin());\n const revision = options.publicOriginRevision?.();\n if (\n (originObserved && current !== observedOrigin) ||\n (revision !== undefined && observedOriginRevision !== undefined && revision !== observedOriginRevision)\n ) {\n for (const client of authorization.listClients()) {\n authorization.revokeClient(client.clientId);\n options.registrationStore?.remove(client.clientId);\n }\n for (const incarnation of incarnations.values()) incarnation.handlers.clear();\n }\n observedOrigin = current;\n observedOriginRevision = revision;\n originObserved = true;\n restorePersistedRegistrations(current);\n return current;\n };\n const target = (workspaceId: string, sessionId: string) => {\n const session = options.headlessHub.session(sessionId);\n const incarnation = incarnations.get(sessionId);\n return session !== undefined && session.workspaceId === workspaceId && incarnation?.host === session.host\n ? { session, generation: incarnation.generation }\n : undefined;\n };\n const restorePersistedRegistrations = (configuredOrigin: string | undefined): void => {\n if (configuredOrigin === undefined) return;\n for (const registration of options.registrationStore?.registrations() ?? []) {\n const audience = `${configuredOrigin}${sessionPath(registration.workspaceId, registration.binding.sessionId)}`;\n if (registration.binding.audience !== audience) {\n options.registrationStore?.remove(registration.client.clientId);\n continue;\n }\n const resolved = target(registration.workspaceId, registration.binding.sessionId);\n if (resolved !== undefined) authorization.restorePersistentRegistration(registration, resolved.generation);\n }\n };\n\n const requireStore = (): SessionMcpConversationStore => {\n if (!options.conversationStore)\n throw new SessionMcpConversationError(\n 'CONVERSATION_ROUTING_UNAVAILABLE',\n 'Persistent conversation routing is unavailable.',\n );\n return options.conversationStore;\n };\n publishPending = () => {\n if (!options.conversationStore) return;\n try {\n const records = options.conversationStore.list();\n for (const parent of options.headlessHub.snapshot())\n options.headlessHub.setPendingSessionSetups?.(\n parent.id,\n records\n .filter((record) => record.parentSessionId === parent.id && record.state === 'pending')\n .map((record) => ({\n id: record.id,\n name: `conversation ${record.id.slice(0, 8)}`,\n createdAt: record.createdAt,\n ...(record.cwd === undefined ? {} : { cwd: record.cwd }),\n })),\n );\n } catch (error) {\n options.onNotice?.(error instanceof Error ? error.message : 'Conversation bindings are unavailable.');\n }\n };\n const readReservation = (id: string, parentSessionId: string) => {\n origin();\n const record = requireStore().get(id, parentSessionId);\n const binding = authorization.readAuthorizationBinding(record.clientId);\n const parent = target(record.parentWorkspaceId, parentSessionId);\n if (\n !parent ||\n binding?.routing !== 'conversation' ||\n binding.sessionId !== parentSessionId ||\n binding.sessionGeneration !== parent.generation\n )\n throw new SessionMcpConversationError(\n 'SESSION_UNAVAILABLE',\n 'The connection that owns this setup is no longer active.',\n id,\n );\n return { record, parent };\n };\n const reservations: DoomHubSessionReservations = {\n read(id, parentSessionId) {\n const { record } = readReservation(id, parentSessionId);\n return { sessionId: record.id, ...(record.cwd === undefined ? {} : { cwd: record.cwd }) };\n },\n async prepare(id, parentSessionId, suppliedDirectory) {\n const { record, parent } = readReservation(id, parentSessionId);\n const cwd = executionDirectory(suppliedDirectory);\n const parentRoot =\n options.headlessHub.workspaces().find((workspace) => workspace.id === parent.session.workspaceId)?.root ??\n parent.session.cwd;\n const occupied = [\n parentRoot,\n ...options.headlessHub\n .snapshot()\n .filter((session) => session.id !== id)\n .map((session) => session.cwd),\n ...requireStore()\n .list()\n .filter((entry) => entry.id !== id && entry.state !== 'closed' && entry.cwd !== undefined)\n .map((entry) => entry.cwd!),\n ];\n if (occupied.some((directory) => overlappingDirectories(cwd, executionDirectory(directory))))\n throw new SessionMcpConversationError(\n 'EXECUTION_DIRECTORY_SHARED',\n 'Choose a separate checkout, not a directory shared with another session.',\n id,\n );\n if (record.state === 'bound' && record.cwd !== cwd)\n throw new SessionMcpConversationError(\n 'SESSION_TARGET_FIXED',\n 'An initialized session cannot change its directory.',\n id,\n );\n requireStore().prepare(id, parentSessionId, cwd);\n publishPending();\n return { sessionId: id, cwd };\n },\n async complete(id, parentSessionId): Promise<DoomHubSessionScope> {\n const { record } = readReservation(id, parentSessionId);\n const child = options.headlessHub.session(id);\n if (\n !record.cwd ||\n !child?.workspaceId ||\n child.parentSessionId !== parentSessionId ||\n executionDirectory(child.cwd) !== record.cwd ||\n options.isSessionPersisted?.(id, child.cwd) === false\n )\n throw new SessionMcpConversationError(\n 'SESSION_SETUP_INCOMPLETE',\n 'The reserved session is not durably ready. Recover the existing setup instead of creating another checkout.',\n id,\n );\n requireStore().bind(id, parentSessionId, child.workspaceId);\n publishPending();\n return { sessionId: id, workspaceId: child.workspaceId, cwd: child.cwd };\n },\n };\n const provision = new Map<string, Promise<DoomHubSessionScope>>();\n const setupDirectory = async (\n id: string,\n parentSessionId: string,\n directory: string,\n ): Promise<DoomHubSessionScope> => {\n // A mistyped existing-directory choice must not permanently reserve a nonexistent path.\n const canonical = executionDirectory(directory);\n if (!fs.statSync(canonical).isDirectory()) throw new Error('The execution directory is not a directory.');\n const prepared = await reservations.prepare(id, parentSessionId, canonical);\n const pending = provision.get(id);\n if (pending) return pending;\n const setup = (async () => {\n if (!options.headlessHub.session(id)) {\n const record = requireStore().get(id, parentSessionId);\n if (record.state === 'bound' || options.isSessionPersisted?.(id, prepared.cwd))\n throw new SessionMcpConversationError(\n 'SESSION_UNAVAILABLE',\n 'Resume the existing session in DoomPi. It will not be recreated automatically.',\n id,\n );\n if (!fs.statSync(prepared.cwd).isDirectory()) throw new Error('The execution directory is not a directory.');\n await options.headlessHub.sessionService.create({\n cwd: prepared.cwd,\n name: `conversation ${id.slice(0, 8)}`,\n parentSessionId,\n sessionProvenance: 'remote-conversation',\n reservationId: id,\n });\n }\n return reservations.complete(id, parentSessionId);\n })();\n provision.set(id, setup);\n try {\n return await setup;\n } finally {\n if (provision.get(id) === setup) provision.delete(id);\n }\n };\n const provisionConversationWorktree = async (\n record: ReturnType<SessionMcpConversationStore['reserve']>,\n signal?: AbortSignal,\n ): Promise<DoomHubSessionScope> => {\n const pending = provision.get(record.id);\n if (pending) return pending;\n const setup = (async () => {\n try {\n const child = await options.headlessHub.sessionService.provisionReservedWorktree?.({\n reservationId: record.id,\n parentSessionId: record.parentSessionId,\n signal,\n });\n if (child === undefined || child.sessionId !== record.id)\n throw new Error('Automatic worktree provisioning did not create the reserved session.');\n return child;\n } catch (error) {\n if (error instanceof SessionMcpConversationError) throw error;\n throw new SessionMcpConversationError(\n 'SESSION_WORKTREE_PROVISION_FAILED',\n 'An automatic worktree could not be created for this conversation. Resolve the host Git setup, then retry.',\n record.id,\n );\n }\n })();\n provision.set(record.id, setup);\n try {\n return await setup;\n } finally {\n if (provision.get(record.id) === setup) provision.delete(record.id);\n }\n };\n const publicRoutes = async (request: Request): Promise<Response | undefined> => {\n const url = new URL(request.url);\n const configuredOrigin = origin();\n const mcpMatch = SESSION_MCP_PATTERN.exec(url.pathname);\n if (mcpMatch !== null) {\n if (configuredOrigin === undefined) return json(503, { error: 'Session MCP public origin is unavailable.' });\n const workspaceId = decodeURIComponent(mcpMatch[1]);\n const sessionId = decodeURIComponent(mcpMatch[2]);\n const exactPath = sessionPath(workspaceId, sessionId);\n if (url.pathname !== exactPath || url.search !== '') return json(404, { error: 'Not found.' });\n const audience = `${configuredOrigin}${exactPath}`;\n const handlers = target(workspaceId, sessionId) === undefined ? undefined : incarnations.get(sessionId)?.handlers;\n const handler =\n handlers?.get(audience) ??\n createSessionMcpHttpHandler({\n audience,\n authorization,\n onNotice: options.onNotice,\n resolveConversation: async (grant, digest, reserve, signal) => {\n const store = requireStore();\n let record = reserve\n ? store.reserve(grant.clientId, sessionId, workspaceId, digest)\n : store.find(grant.clientId, sessionId, digest);\n if (!record || record.state === 'closed')\n throw new SessionMcpConversationError(\n 'SESSION_UNAVAILABLE',\n 'This conversation binding is unavailable. It will not be recreated automatically.',\n );\n if (record.state === 'pending') {\n publishPending();\n await provisionConversationWorktree(record, signal);\n record = store.find(grant.clientId, sessionId, digest);\n if (!record || record.state !== 'bound')\n throw new SessionMcpConversationError(\n 'SESSION_WORKTREE_PROVISION_FAILED',\n 'The automatic worktree setup did not complete. Retry after resolving the host Git setup.',\n );\n }\n const child = record.workspaceId === undefined ? undefined : target(record.workspaceId, record.id);\n if (\n !child ||\n child.session.parentSessionId !== sessionId ||\n executionDirectory(child.session.cwd) !== record.cwd ||\n !fs.existsSync(child.session.cwd)\n )\n throw new SessionMcpConversationError(\n 'SESSION_UNAVAILABLE',\n 'The bound session is unavailable. Resume it in DoomPi; no other session will be used.',\n record.id,\n );\n return { sessionId: record.id, generation: child.generation, toolSurface: child.session.host.mcpSurface };\n },\n onVerified: (grant) => {\n if (options.registrationStore === undefined) return;\n const active = target(workspaceId, sessionId);\n if (active === undefined || grant.sessionGeneration !== active.generation || grant.clientId === '') {\n throw new Error('The session grant is no longer active.');\n }\n if (authorization.readClient(grant.clientId)?.tokenEndpointAuthMethod === 'api_key') return;\n const registration = authorization.persistentRegistration(grant.clientId, workspaceId, Date.now());\n if (registration === undefined || !options.registrationStore.save(registration)) {\n throw new Error('The verified Session MCP client could not be saved.');\n }\n },\n resourceMetadataUrl: `${configuredOrigin}/.well-known/oauth-protected-resource${exactPath}`,\n resolveSession: (grantedSessionId) => {\n if (grantedSessionId !== sessionId) return undefined;\n const resolved = target(workspaceId, sessionId);\n return resolved === undefined\n ? undefined\n : { sessionId, generation: resolved.generation, toolSurface: resolved.session.host.mcpSurface };\n },\n });\n handlers?.set(audience, handler);\n return handler(new Request(audience, request));\n }\n\n const protectedMatch = PROTECTED_RESOURCE_PATTERN.exec(url.pathname);\n if (protectedMatch !== null && request.method === 'GET') {\n if (configuredOrigin === undefined) return json(503, { error: 'Session MCP public origin is unavailable.' });\n return json(200, {\n resource: `${configuredOrigin}${protectedMatch[1]}`,\n authorization_servers: [configuredOrigin],\n bearer_methods_supported: ['header'],\n });\n }\n if (url.pathname === AUTHORIZATION_SERVER_DISCOVERY && request.method === 'GET') {\n if (configuredOrigin === undefined) return json(503, { error: 'Session MCP public origin is unavailable.' });\n return json(200, {\n issuer: configuredOrigin,\n authorization_endpoint: `${configuredOrigin}${AUTHORIZE_ROUTE}`,\n token_endpoint: `${configuredOrigin}${TOKEN_ROUTE}`,\n response_types_supported: ['code'],\n grant_types_supported: ['authorization_code', 'refresh_token'],\n code_challenge_methods_supported: ['S256'],\n token_endpoint_auth_methods_supported: ['client_secret_post'],\n });\n }\n if (url.pathname === AUTHORIZE_ROUTE && request.method === 'GET') {\n if (configuredOrigin === undefined) return json(503, { error: 'Session MCP public origin is unavailable.' });\n const clientId = url.searchParams.get('client_id') ?? '';\n const client = authorization.readClient(clientId);\n const binding = authorization.readAuthorizationBinding(clientId);\n const redirectUri = url.searchParams.get('redirect_uri') ?? '';\n if (\n client === undefined ||\n client.tokenEndpointAuthMethod !== 'client_secret_post' ||\n binding === undefined ||\n redirectUri !== client.redirectUri\n ) {\n return oauthError(new SessionMcpOAuthError('invalid_client', 'Unknown client or callback.'));\n }\n const callback = new URL(client.redirectUri);\n const state = url.searchParams.get('state');\n try {\n const boundSession = options.headlessHub.session(binding.sessionId);\n const boundIncarnation = incarnations.get(binding.sessionId);\n const expectedAudience =\n boundSession?.workspaceId === undefined\n ? undefined\n : `${configuredOrigin}${sessionPath(boundSession.workspaceId, binding.sessionId)}`;\n if (\n expectedAudience === undefined ||\n binding.audience !== expectedAudience ||\n boundIncarnation?.host !== boundSession?.host ||\n binding.sessionGeneration !== boundIncarnation?.generation\n ) {\n authorization.revokeClient(clientId);\n throw new SessionMcpOAuthError('invalid_grant', 'The preauthorized session is no longer active.');\n }\n if (url.searchParams.get('response_type') !== 'code')\n throw new SessionMcpOAuthError('invalid_request', 'Only the code response type is supported.');\n if (url.searchParams.get('resource') !== null && url.searchParams.get('resource') !== binding.audience)\n throw new SessionMcpOAuthError('invalid_request', 'The requested resource is not preauthorized.');\n const code = authorization.issueAuthorizationCode({\n clientId,\n redirectUri,\n codeChallenge: url.searchParams.get('code_challenge') ?? '',\n codeChallengeMethod: url.searchParams.get('code_challenge_method') as 'S256',\n });\n callback.searchParams.set('code', code.code);\n } catch (error) {\n callback.searchParams.set('error', error instanceof SessionMcpOAuthError ? error.code : 'invalid_request');\n callback.searchParams.set(\n 'error_description',\n error instanceof Error ? error.message : 'The OAuth request was invalid.',\n );\n }\n if (state !== null) callback.searchParams.set('state', state);\n return new Response(null, { status: 302, headers: { location: callback.href, 'cache-control': 'no-store' } });\n }\n if (url.pathname === TOKEN_ROUTE && request.method === 'POST') {\n try {\n const form = await request.formData();\n const grantType = formString(form, 'grant_type');\n const clientId = formString(form, 'client_id');\n const clientSecret = formString(form, 'client_secret');\n const result =\n grantType === 'authorization_code'\n ? authorization.exchangeToken({\n grantType,\n clientId,\n clientSecret,\n code: formString(form, 'code'),\n redirectUri: formString(form, 'redirect_uri'),\n codeVerifier: formString(form, 'code_verifier'),\n })\n : grantType === 'refresh_token'\n ? authorization.exchangeToken({\n grantType,\n clientId,\n clientSecret,\n refreshToken: formString(form, 'refresh_token'),\n })\n : (() => {\n throw new SessionMcpOAuthError('unsupported_grant_type', 'The grant type is not supported.');\n })();\n return json(200, {\n access_token: result.accessToken,\n refresh_token: result.refreshToken,\n token_type: result.tokenType,\n expires_in: result.expiresIn,\n });\n } catch (error) {\n return oauthError(error);\n }\n }\n return undefined;\n };\n\n publishPending();\n return {\n reservations,\n closeSessionBinding(sessionId) {\n options.conversationStore?.closeSession(sessionId);\n publishPending();\n },\n handlePublic: publicRoutes,\n async handleHost(request) {\n const url = new URL(request.url);\n origin();\n const configMatch = SESSION_MCP_CONFIG_PATTERN.exec(url.pathname);\n const match = SESSION_MCP_CLIENTS_PATTERN.exec(url.pathname);\n const conversationMatch = SESSION_MCP_CONVERSATIONS_PATTERN.exec(url.pathname);\n if (configMatch === null && match === null && conversationMatch === null) return undefined;\n const routeMatch = configMatch ?? match ?? conversationMatch!;\n const workspaceId = decodeURIComponent(routeMatch[1]);\n const sessionId = decodeURIComponent(routeMatch[2]);\n const clientId = match?.[3] === undefined ? undefined : decodeURIComponent(match[3]);\n const resolved = target(workspaceId, sessionId);\n if (resolved === undefined) return json(404, { error: 'Session not found.' });\n if (conversationMatch !== null) {\n const id = conversationMatch[3] === undefined ? undefined : decodeURIComponent(conversationMatch[3]);\n try {\n if (request.method === 'GET' && id === undefined)\n return json(200, {\n conversations: requireStore()\n .list()\n .filter((record) => record.parentSessionId === sessionId && record.state !== 'closed')\n .map(({ conversationDigest: _digest, clientId: _clientId, ...record }) => record),\n });\n if (id !== undefined && request.method === 'DELETE') {\n const record = requireStore().get(id, sessionId);\n if (record.state !== 'pending' || options.headlessHub.session(id))\n return json(409, { error: 'Remove the existing session instead.' });\n requireStore().closeSession(id);\n publishPending();\n return json(200, { ok: true });\n }\n if (id !== undefined && request.method === 'POST') {\n const body: unknown = await request.json();\n if (typeof body !== 'object' || body === null || !('cwd' in body) || typeof body.cwd !== 'string')\n return json(400, { error: 'An execution directory is required.' });\n return json(200, { session: await setupDirectory(id, sessionId, body.cwd) });\n }\n return json(405, { error: 'Method not allowed.' });\n } catch (error) {\n return json(409, {\n error:\n error instanceof SessionMcpConversationError\n ? error.message\n : 'Session setup failed. Recover the existing setup before retrying.',\n ...(error instanceof SessionMcpConversationError ? { code: error.code } : {}),\n });\n }\n }\n if (configMatch !== null) {\n if (request.method !== 'GET') return json(405, { error: 'Method not allowed.' });\n const configuredOrigin = origin();\n if (configuredOrigin === undefined) return json(503, { error: 'Session MCP public origin is unavailable.' });\n let surface;\n try {\n surface = resolved.session.host.mcpSurface.readSurface();\n } catch {\n return json(409, { error: 'The session capability surface is not ready.' });\n }\n return json(200, {\n audience: `${configuredOrigin}${sessionPath(workspaceId, sessionId)}`,\n authorizationEndpoint: `${configuredOrigin}${AUTHORIZE_ROUTE}`,\n tokenEndpoint: `${configuredOrigin}${TOKEN_ROUTE}`,\n tools: surface.tools.map(({ name, label, description }) => ({ name, label, description })),\n skills: surface.skills,\n });\n }\n if (clientId === undefined && request.method === 'GET') {\n return json(200, {\n clients: authorization.listClients().flatMap((client) => {\n const binding = authorization.readAuthorizationBinding(client.clientId);\n return binding?.sessionId === sessionId ? [publicClient(client, binding)] : [];\n }),\n });\n }\n if (clientId === undefined && request.method === 'POST') {\n const configuredOrigin = origin();\n if (configuredOrigin === undefined) return json(503, { error: 'Session MCP public origin is unavailable.' });\n let body: unknown;\n try {\n body = await request.json();\n } catch {\n return json(400, { error: 'Invalid client request.' });\n }\n if (typeof body !== 'object' || body === null) return json(400, { error: 'Invalid client request.' });\n const input = body as Record<string, unknown>;\n if (!options.conversationStore || !options.registrationStore)\n return json(503, { error: 'Mandatory conversation routing requires persistent host state.' });\n if (input.routing !== undefined && input.routing !== 'session' && input.routing !== 'conversation')\n return json(400, { error: 'Session MCP routing is not supported.' });\n const routing = sessionMcpRouting(input.routing);\n const requestedScope = input.scope;\n if (requestedScope !== undefined && requestedScope !== 'session' && requestedScope !== 'restricted') {\n return json(400, { error: 'Authorization scope is not supported.' });\n }\n const scope = requestedScope === 'session' ? 'session' : 'restricted';\n const hasTools = Object.hasOwn(input, 'tools');\n const hasSkills = Object.hasOwn(input, 'skills');\n const tools = parseStringArray(input.tools);\n const skills = parseStringArray(input.skills);\n const apiKey = input.authMethod === 'api_key';\n if (input.authMethod !== undefined && input.authMethod !== 'oauth' && !apiKey)\n return json(400, { error: 'Authentication method is not supported.' });\n if (apiKey && (scope !== 'session' || Object.hasOwn(input, 'redirectUri')))\n return json(400, { error: 'API keys require session scope and no redirectUri.' });\n if (!apiKey && typeof input.redirectUri !== 'string') return json(400, { error: 'A redirectUri is required.' });\n if (scope === 'session' && (hasTools || hasSkills)) {\n return json(400, { error: 'Session scope cannot include capability grants.' });\n }\n if (scope === 'restricted' && (typeof input.name !== 'string' || !tools || !skills)) {\n return json(400, { error: 'Restricted scope requires a name, tools, and skills.' });\n }\n if (scope === 'restricted') {\n let surface;\n try {\n surface = resolved.session.host.mcpSurface.readSurface();\n } catch {\n return json(409, { error: 'The session capability surface is not ready.' });\n }\n const activeTools = new Set(surface.tools.map((tool) => tool.name));\n const activeSkills = new Set(surface.skills.map((skill) => skill.name));\n if (tools!.some((name) => !activeTools.has(name)) || skills!.some((name) => !activeSkills.has(name)))\n return json(400, { error: 'Every requested grant must be active in the session.' });\n }\n try {\n const client = authorization.createClient(\n apiKey\n ? { name: typeof input.name === 'string' ? input.name : 'API key', authMethod: 'api_key' }\n : {\n name: scope === 'session' ? defaultClientName(configuredOrigin) : (input.name as string),\n redirectUri: input.redirectUri as string,\n },\n );\n const audience = `${configuredOrigin}${sessionPath(workspaceId, sessionId)}`;\n try {\n const binding =\n scope === 'session'\n ? authorization.createAuthorizationBinding({\n clientId: client.clientId,\n sessionId,\n sessionGeneration: resolved.generation,\n audience,\n scope: 'session',\n routing,\n })\n : authorization.createAuthorizationBinding({\n clientId: client.clientId,\n sessionId,\n sessionGeneration: resolved.generation,\n audience,\n scope: 'restricted',\n routing,\n tools: [...new Set(tools!)],\n skills: [...new Set(skills!)],\n });\n if (apiKey) {\n const registration = authorization.persistentRegistration(client.clientId, workspaceId, Date.now());\n if (registration === undefined || !options.registrationStore.save(registration)) {\n authorization.revokeClient(client.clientId);\n return json(500, { error: 'API key could not be saved.' });\n }\n }\n return json(201, { client: { ...publicClient(client, binding), clientSecret: client.clientSecret } });\n } catch (error) {\n authorization.revokeClient(client.clientId);\n throw error;\n }\n } catch (error) {\n return oauthError(error);\n }\n }\n if (clientId !== undefined && request.method === 'DELETE') {\n const binding = authorization.readAuthorizationBinding(clientId);\n if (binding?.sessionId !== sessionId) return json(404, { error: 'Client not found.' });\n if (options.registrationStore !== undefined && !options.registrationStore.remove(clientId)) {\n return json(500, { error: 'Client revocation could not be saved.' });\n }\n authorization.revokeClient(clientId);\n options.conversationStore?.closeClient(clientId);\n publishPending();\n return json(200, { ok: true });\n }\n return json(405, { error: 'Method not allowed.' });\n },\n close() {\n unsubscribe();\n for (const [sessionId, incarnation] of incarnations) revokeIncarnation(sessionId, incarnation.generation);\n incarnations.clear();\n },\n };\n}\n\nexport function isPublicSessionMcpRoute(method: string, pathname: string): boolean {\n return (\n SESSION_MCP_PATTERN.test(pathname) ||\n (method === 'GET' && PROTECTED_RESOURCE_PATTERN.test(pathname)) ||\n (method === 'GET' && (pathname === AUTHORIZATION_SERVER_DISCOVERY || pathname === AUTHORIZE_ROUTE)) ||\n (method === 'POST' && pathname === TOKEN_ROUTE)\n );\n}\n\nexport function isSessionMcpHostRoute(pathname: string): boolean {\n return (\n SESSION_MCP_CONFIG_PATTERN.test(pathname) ||\n SESSION_MCP_CLIENTS_PATTERN.test(pathname) ||\n SESSION_MCP_CONVERSATIONS_PATTERN.test(pathname)\n );\n}\n"],"mappings":"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"}
@@ -306,6 +306,7 @@ function createSessionMcpRoutes(options) {
306
306
  if (options.registrationStore === void 0) return;
307
307
  const active = target(workspaceId, sessionId);
308
308
  if (active === void 0 || grant.sessionGeneration !== active.generation || grant.clientId === "") throw new Error("The session grant is no longer active.");
309
+ if (authorization.readClient(grant.clientId)?.tokenEndpointAuthMethod === "api_key") return;
309
310
  const registration = authorization.persistentRegistration(grant.clientId, workspaceId, Date.now());
310
311
  if (registration === void 0 || !options.registrationStore.save(registration)) throw new Error("The verified Session MCP client could not be saved.");
311
312
  },
@@ -350,7 +351,7 @@ function createSessionMcpRoutes(options) {
350
351
  const client = authorization.readClient(clientId);
351
352
  const binding = authorization.readAuthorizationBinding(clientId);
352
353
  const redirectUri = url.searchParams.get("redirect_uri") ?? "";
353
- if (client === void 0 || binding === void 0 || redirectUri !== client.redirectUri) return oauthError(new SessionMcpOAuthError("invalid_client", "Unknown client or callback."));
354
+ if (client === void 0 || client.tokenEndpointAuthMethod !== "client_secret_post" || binding === void 0 || redirectUri !== client.redirectUri) return oauthError(new SessionMcpOAuthError("invalid_client", "Unknown client or callback."));
354
355
  const callback = new URL(client.redirectUri);
355
356
  const state = url.searchParams.get("state");
356
357
  try {
@@ -504,7 +505,10 @@ function createSessionMcpRoutes(options) {
504
505
  const hasSkills = Object.hasOwn(input, "skills");
505
506
  const tools = parseStringArray(input.tools);
506
507
  const skills = parseStringArray(input.skills);
507
- if (typeof input.redirectUri !== "string") return json(400, { error: "A redirectUri is required." });
508
+ const apiKey = input.authMethod === "api_key";
509
+ if (input.authMethod !== void 0 && input.authMethod !== "oauth" && !apiKey) return json(400, { error: "Authentication method is not supported." });
510
+ if (apiKey && (scope !== "session" || Object.hasOwn(input, "redirectUri"))) return json(400, { error: "API keys require session scope and no redirectUri." });
511
+ if (!apiKey && typeof input.redirectUri !== "string") return json(400, { error: "A redirectUri is required." });
508
512
  if (scope === "session" && (hasTools || hasSkills)) return json(400, { error: "Session scope cannot include capability grants." });
509
513
  if (scope === "restricted" && (typeof input.name !== "string" || !tools || !skills)) return json(400, { error: "Restricted scope requires a name, tools, and skills." });
510
514
  if (scope === "restricted") {
@@ -519,13 +523,16 @@ function createSessionMcpRoutes(options) {
519
523
  if (tools.some((name) => !activeTools.has(name)) || skills.some((name) => !activeSkills.has(name))) return json(400, { error: "Every requested grant must be active in the session." });
520
524
  }
521
525
  try {
522
- const client = authorization.createClient({
526
+ const client = authorization.createClient(apiKey ? {
527
+ name: typeof input.name === "string" ? input.name : "API key",
528
+ authMethod: "api_key"
529
+ } : {
523
530
  name: scope === "session" ? defaultClientName(configuredOrigin) : input.name,
524
531
  redirectUri: input.redirectUri
525
532
  });
526
533
  const audience = `${configuredOrigin}${sessionPath(workspaceId, sessionId)}`;
527
534
  try {
528
- return json(201, { client: publicClient(client, scope === "session" ? authorization.createAuthorizationBinding({
535
+ const binding = scope === "session" ? authorization.createAuthorizationBinding({
529
536
  clientId: client.clientId,
530
537
  sessionId,
531
538
  sessionGeneration: resolved.generation,
@@ -541,7 +548,18 @@ function createSessionMcpRoutes(options) {
541
548
  routing,
542
549
  tools: [...new Set(tools)],
543
550
  skills: [...new Set(skills)]
544
- })) });
551
+ });
552
+ if (apiKey) {
553
+ const registration = authorization.persistentRegistration(client.clientId, workspaceId, Date.now());
554
+ if (registration === void 0 || !options.registrationStore.save(registration)) {
555
+ authorization.revokeClient(client.clientId);
556
+ return json(500, { error: "API key could not be saved." });
557
+ }
558
+ }
559
+ return json(201, { client: {
560
+ ...publicClient(client, binding),
561
+ clientSecret: client.clientSecret
562
+ } });
545
563
  } catch (error) {
546
564
  authorization.revokeClient(client.clientId);
547
565
  throw error;