@agimon-ai/po-core 0.0.0-alpha.20 → 0.0.0-alpha.21
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.
- package/LICENSE +149 -21
- package/NOTICE +41 -0
- package/dist/apiContracts.d.mts +54 -1
- package/dist/apiContracts.d.mts.map +1 -1
- package/dist/headlessHub.cjs +4 -0
- package/dist/headlessHub.cjs.map +1 -1
- package/dist/headlessHub.mjs +4 -0
- package/dist/headlessHub.mjs.map +1 -1
- package/dist/headlessServer.cjs +7 -2
- package/dist/headlessServer.cjs.map +1 -1
- package/dist/headlessServer.d.mts +2 -0
- package/dist/headlessServer.d.mts.map +1 -1
- package/dist/headlessServer.mjs +7 -2
- package/dist/headlessServer.mjs.map +1 -1
- package/dist/moduleResolution.cjs +24 -2
- package/dist/moduleResolution.cjs.map +1 -1
- package/dist/moduleResolution.d.mts +6 -0
- package/dist/moduleResolution.d.mts.map +1 -1
- package/dist/moduleResolution.mjs +24 -3
- package/dist/moduleResolution.mjs.map +1 -1
- package/dist/native.cjs +1 -0
- package/dist/native.d.mts +3 -3
- package/dist/native.mjs +2 -2
- package/dist/nodePlatform.cjs +1 -0
- package/dist/nodePlatform.cjs.map +1 -1
- package/dist/nodePlatform.d.mts +2 -0
- package/dist/nodePlatform.d.mts.map +1 -1
- package/dist/nodePlatform.mjs +1 -0
- package/dist/nodePlatform.mjs.map +1 -1
- package/dist/packageApiServer.cjs +11 -5
- package/dist/packageApiServer.cjs.map +1 -1
- package/dist/packageApiServer.d.mts.map +1 -1
- package/dist/packageApiServer.mjs +7 -1
- package/dist/packageApiServer.mjs.map +1 -1
- package/dist/platform.cjs +6 -0
- package/dist/platform.d.mts +2 -1
- package/dist/platform.mjs +2 -1
- package/dist/src/schemas/hubChannel.cjs.map +1 -1
- package/dist/src/schemas/hubChannel.d.mts +4 -0
- package/dist/src/schemas/hubChannel.d.mts.map +1 -1
- package/dist/src/schemas/hubChannel.mjs.map +1 -1
- package/dist/src/schemas/packageApi.cjs.map +1 -1
- package/dist/src/schemas/packageApi.d.mts +3 -0
- package/dist/src/schemas/packageApi.d.mts.map +1 -1
- package/dist/src/schemas/packageApi.mjs.map +1 -1
- package/dist/src/schemas/platform.cjs.map +1 -1
- package/dist/src/schemas/platform.d.mts +5 -0
- package/dist/src/schemas/platform.d.mts.map +1 -1
- package/dist/src/schemas/platform.mjs.map +1 -1
- package/dist/src/server/serverScope.cjs +4 -1
- package/dist/src/server/serverScope.cjs.map +1 -1
- package/dist/src/server/serverScope.d.mts.map +1 -1
- package/dist/src/server/serverScope.mjs +4 -1
- package/dist/src/server/serverScope.mjs.map +1 -1
- package/dist/src/services/sessionFiles/index.cjs +96 -0
- package/dist/src/services/sessionFiles/index.cjs.map +1 -0
- package/dist/src/services/sessionFiles/index.d.mts +33 -0
- package/dist/src/services/sessionFiles/index.d.mts.map +1 -0
- package/dist/src/services/sessionFiles/index.mjs +89 -0
- package/dist/src/services/sessionFiles/index.mjs.map +1 -0
- package/dist/src/services/sessionFiles/sessionDirectory.cjs +66 -0
- package/dist/src/services/sessionFiles/sessionDirectory.cjs.map +1 -0
- package/dist/src/services/sessionFiles/sessionDirectory.mjs +62 -0
- package/dist/src/services/sessionFiles/sessionDirectory.mjs.map +1 -0
- package/dist/src/systems/main/adapters/headlessSessionHost.cjs +18 -6
- package/dist/src/systems/main/adapters/headlessSessionHost.cjs.map +1 -1
- package/dist/src/systems/main/adapters/headlessSessionHost.d.mts.map +1 -1
- package/dist/src/systems/main/adapters/headlessSessionHost.mjs +16 -4
- package/dist/src/systems/main/adapters/headlessSessionHost.mjs.map +1 -1
- package/dist/src/web/types/nativeTemplate.d.mts +1 -1
- package/dist/src/web/types/nativeTemplate.d.mts.map +1 -1
- package/licenses/Codex-Apache-2.0.txt +201 -0
- package/package.json +8 -6
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"packageApiServer.cjs","names":["createPoServerHost","PoServerScope","PO_API_ROUTE_PREFIX","validatedTraceContext"],"sources":["../src/server/packageApiServer.ts"],"sourcesContent":["import type { PoTraceContext } from '@agimon-ai/po-telemetry';\nimport type { Context } from '@deepseek-ai/cordis';\n\nimport type { PoDirectEventBus, PoHubSessionPromptOptions, PoHubSessionService } from '../exports/hubChannel';\nimport { PO_API_ROUTE_PREFIX, type PoApi, type PoApiContext } from '../exports/packageApi';\nimport type { PoPlatform } from '../exports/platform';\nimport type { PoPluginRegistry } from '../exports/pluginProtocol';\nimport {\n createPoServerHost,\n type CreatePoServerHostOptions,\n type LoadedServerPackage,\n type PoServerPlugin,\n PoServerScope,\n} from '../exports/serverPlugin';\nimport { observe, type ServerTelemetry } from '../services/serverTelemetry';\nimport { validatedTraceContext } from '../services/traceContext';\n\n/**\n * A body that keeps streaming well after its headers went out is worth its own span. A fast\n * one is not: the request span already carries the duration and outcome, so emitting a second\n * span per call made package API traffic 99.65% of all spans recorded in a two hour sample.\n */\nexport const COMPLETION_SPAN_MIN_DURATION_MS = 1000;\n\nexport interface PackageApiServerOptions {\n sessionId: string;\n workspaceId?: string;\n workspaceRoot?: string;\n sessionContext?: PoApiContext['sessionContext'];\n homeDirectory?: string;\n mountChannel?: CreatePoServerHostOptions['mountChannel'];\n cwd: string;\n /** Admitted environment for APIs serving this session. */\n readonly environment: Readonly<Record<string, string | undefined>>;\n /** Lifecycle-owned direct events shared with the hub. */\n readonly directEvents: PoDirectEventBus;\n readonly computerUse?: PoApiContext['computerUse'];\n /** Bound to this session's id and cwd by the host. */\n readonly shareFile?: PoApiContext['shareFile'];\n readonly mediaArbitration?: PoApiContext['mediaArbitration'];\n readonly executionBudget?: PoApiContext['executionBudget'];\n readonly editPresence?: PoApiContext['editPresence'];\n readonly peerAgents?: PoApiContext['peerAgents'];\n readonly requestApi?: PoApiContext['requestApi'];\n /** Publishes this session's activity line through the hub; bound to this session only. */\n readonly publishActivity?: PoApiContext['publishActivity'];\n internalToken?: string;\n hubToken?: string;\n /** Shared exact-scope dispatch table, so session packages can mount plugin methods. */\n pluginRegistry?: PoPluginRegistry;\n sessionService?: PoHubSessionService;\n apis: readonly PoApi[];\n /** Server packages to install; each registers its own APIs through the host. */\n packages?: readonly (PoServerPlugin | LoadedServerPackage)[];\n /** Publishes the session's own services into its scope root before any package installs. */\n preparePackages?: (root: Context) => void | Promise<void>;\n /** The hub's workspace or global scope; the session's own scope opens below it and closes with it. */\n parentScope?: PoServerScope;\n /** Host capabilities for the session scope root, injected by the composition root. */\n platform: PoPlatform;\n activatePackages?: (installedPackages: readonly string[]) => Promise<void>;\n canDispatch?: () => boolean;\n telemetry?: ServerTelemetry;\n onNotice: (message: string) => void;\n}\n\nexport interface PackageApiServer {\n /** Dispatches an already-authenticated request without crossing a transport boundary. */\n readonly request: (request: Request) => Promise<Response>;\n close(): Promise<void>;\n}\n\nfunction describeError(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\nfunction responseWithCompletion(response: Response, complete: () => void): Response {\n if (response.body === null) {\n complete();\n return response;\n }\n const reader = response.body.getReader();\n let completed = false;\n const finish = (): void => {\n if (completed) return;\n completed = true;\n complete();\n };\n const body = new ReadableStream<Uint8Array>({\n async pull(controller) {\n try {\n const result = await reader.read();\n if (result.done) {\n finish();\n controller.close();\n } else controller.enqueue(result.value);\n } catch (error) {\n finish();\n controller.error(error);\n }\n },\n async cancel(reason) {\n finish();\n await reader.cancel(reason);\n },\n });\n return new Response(body, response);\n}\n\n/** Installs session packages and dispatches authenticated package API calls in-process. */\nexport async function serveSessionApis(options: PackageApiServerOptions): Promise<PackageApiServer> {\n if (options.environment === undefined)\n throw new Error('Session package API server requires an admitted environment.');\n if (options.directEvents === undefined) throw new Error('Session package API server requires direct events.');\n const packages = options.packages ?? [];\n // Without a level above it, a session that mounts nothing has nothing to route.\n const routesNothing = (): boolean => !options.preparePackages && options.parentScope === undefined;\n if (options.apis.length === 0 && packages.length === 0 && routesNothing()) {\n return {\n request: async () => Response.json({ error: 'No package APIs are mounted.' }, { status: 404 }),\n close: () => Promise.resolve(),\n };\n }\n\n const owningSessionService = options.sessionService;\n const communication = owningSessionService?.bindCommunication?.(options.sessionId);\n const ownedReadExecutionState = owningSessionService?.readExecutionState?.bind(owningSessionService);\n const ownedPrompt = owningSessionService?.prompt?.bind(owningSessionService);\n const ownedAbort = owningSessionService?.abort?.bind(owningSessionService);\n const ownedSteer = owningSessionService?.steer?.bind(owningSessionService);\n const ownedRelease = owningSessionService?.release?.bind(owningSessionService);\n const exposedSessionService: PoHubSessionService | undefined =\n owningSessionService === undefined\n ? undefined\n : {\n create: (request) => owningSessionService.create(request),\n close: (sessionId) => owningSessionService.close(sessionId),\n isLive: (sessionId) => owningSessionService.isLive(sessionId),\n ...(ownedReadExecutionState === undefined\n ? {}\n : {\n readExecutionState: (sessionId: string) =>\n ownedReadExecutionState(sessionId, { parentSessionId: options.sessionId }),\n }),\n // A session may drive only the children it started, never its parent or a sibling.\n ...(ownedPrompt === undefined\n ? {}\n : {\n prompt: (sessionId: string, text: string, promptOptions?: PoHubSessionPromptOptions) =>\n ownedPrompt(sessionId, text, {\n ...(promptOptions?.signal === undefined ? {} : { signal: promptOptions.signal }),\n parentSessionId: options.sessionId,\n }),\n }),\n ...(ownedAbort === undefined\n ? {}\n : {\n abort: (sessionId: string) => ownedAbort(sessionId, { parentSessionId: options.sessionId }),\n }),\n ...(ownedSteer === undefined\n ? {}\n : {\n steer: (sessionId: string, message: string) =>\n ownedSteer(sessionId, message, { parentSessionId: options.sessionId }),\n }),\n ...(ownedRelease === undefined\n ? {}\n : {\n release: (sessionId: string) => ownedRelease(sessionId, { parentSessionId: options.sessionId }),\n }),\n ...(owningSessionService.canCommunicate === undefined\n ? {}\n : {\n canCommunicate: (sourceSessionId: string, targetSessionId: string) =>\n owningSessionService.canCommunicate?.(sourceSessionId, targetSessionId) === true,\n }),\n };\n const context: PoApiContext = {\n scope: 'session',\n sessionId: options.sessionId,\n workspaceId: options.workspaceId,\n workspaceRoot: options.workspaceRoot,\n ...(options.sessionContext === undefined ? {} : { sessionContext: options.sessionContext }),\n homeDirectory: options.homeDirectory,\n cwd: options.cwd,\n environment: options.environment,\n directEvents: options.directEvents,\n ...(options.computerUse === undefined ? {} : { computerUse: options.computerUse }),\n ...(options.shareFile === undefined ? {} : { shareFile: options.shareFile }),\n ...(options.mediaArbitration === undefined ? {} : { mediaArbitration: options.mediaArbitration }),\n ...(options.executionBudget === undefined ? {} : { executionBudget: options.executionBudget }),\n ...(options.editPresence === undefined ? {} : { editPresence: options.editPresence }),\n ...(options.peerAgents === undefined ? {} : { peerAgents: options.peerAgents }),\n ...(options.requestApi === undefined ? {} : { requestApi: options.requestApi }),\n ...(options.publishActivity === undefined ? {} : { publishActivity: options.publishActivity }),\n ...(options.internalToken === undefined ? {} : { internalToken: options.internalToken }),\n ...(options.hubToken === undefined ? {} : { hubToken: options.hubToken }),\n ...(exposedSessionService === undefined ? {} : { sessionService: exposedSessionService }),\n ...(communication === undefined ? {} : { sessionCommunication: communication }),\n onNotice: options.onNotice,\n };\n const host = createPoServerHost({\n scope: 'session',\n context,\n mountChannel: options.mountChannel,\n ...(options.pluginRegistry === undefined ? {} : { pluginRegistry: options.pluginRegistry }),\n });\n let scope: PoServerScope | undefined;\n try {\n for (const api of options.apis) host.registerApi(api);\n // The session's own level of the server IoC tree; it closes with the hub level it opens below.\n scope = await PoServerScope.open('session', options.parentScope);\n await scope.serve({ host, platform: options.platform });\n await options.preparePackages?.(scope.root);\n const installed = await scope.install(packages, {\n onNotice: options.onNotice,\n onPackageSettled: (report) => {\n if (!options.telemetry) return;\n observe(\n options.telemetry.recordEvent('po_server.package_install', {\n 'package.name': report.packageName,\n 'package.outcome': report.outcome,\n duration_ms: report.durationMs,\n scope: 'session',\n }),\n options.onNotice,\n );\n },\n });\n await options.activatePackages?.(installed);\n } catch (error) {\n await scope?.dispose();\n communication?.close();\n host.dispose();\n throw error;\n }\n if (host.mounted().length === 0 && routesNothing()) {\n await scope.dispose();\n communication?.close();\n host.dispose();\n return {\n request: async () => Response.json({ error: 'No package APIs are mounted.' }, { status: 404 }),\n close: () => Promise.resolve(),\n };\n }\n const sessionScope = scope;\n\n const dispatch = async (request: Request): Promise<Response> => {\n if (options.canDispatch?.() === false)\n return Response.json({ error: 'Session selection is not ready.' }, { status: 503 });\n const url = new URL(request.url);\n if (!url.pathname.startsWith(`${PO_API_ROUTE_PREFIX}/`))\n return Response.json({ error: 'Not found.' }, { status: 404 });\n const rest = url.pathname.slice(PO_API_ROUTE_PREFIX.length + 1);\n const slash = rest.indexOf('/');\n const basePath = slash === -1 ? rest : rest.slice(0, slash);\n // The session's own API, else the nearest level above it that serves one.\n const handler = sessionScope.apiHandler(basePath);\n if (handler === undefined)\n return Response.json({ error: `No API '${basePath}' in this session.` }, { status: 404 });\n url.pathname = slash === -1 ? '/' : rest.slice(slash);\n const startedAt = performance.now();\n const parent = validatedTraceContext(request.headers.get('traceparent'));\n let childContext: PoTraceContext | undefined;\n let response: Response;\n try {\n const invoke = async (context?: PoTraceContext): Promise<Response> => {\n if (options.canDispatch?.() === false || sessionScope.apiHandler(basePath) !== handler) {\n return Response.json({ error: 'Session selection changed before dispatch.' }, { status: 503 });\n }\n childContext = context;\n return handler.fetch(new Request(url, request));\n };\n response = options.telemetry\n ? await options.telemetry.runInSpan(\n 'po_server.package_api.request',\n { api: basePath, method: request.method },\n invoke,\n parent,\n )\n : await invoke();\n } catch (error) {\n if (request.signal.aborted) return new Response(null, { status: 499 });\n options.onNotice(`package API '${basePath}' failed on ${url.pathname} (${describeError(error)})`);\n response = Response.json({ error: `The '${basePath}' API failed.` }, { status: 500 });\n }\n return responseWithCompletion(response, () => {\n if (!options.telemetry) return;\n const durationMs = Math.round(performance.now() - startedAt);\n // Keep this span only where it says something the request span cannot: a failing status,\n // or a body that took real time to flush after the headers were sent.\n if (response.status < 400 && durationMs < COMPLETION_SPAN_MIN_DURATION_MS) return;\n observe(\n options.telemetry.runInSpan(\n 'po_server.package_api.complete',\n {\n api: basePath,\n method: request.method,\n status_code: response.status,\n duration_ms: durationMs,\n },\n async () => undefined,\n childContext ?? parent,\n ),\n options.onNotice,\n );\n });\n };\n let closePromise: Promise<void> | undefined;\n\n return {\n request: dispatch,\n close: () => {\n closePromise ??= (async () => {\n await scope.dispose();\n communication?.close();\n host.dispose();\n })();\n return closePromise;\n },\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"packageApiServer.cjs","names":["prepareSessionEnvironment","createPoServerHost","PoServerScope","PO_API_ROUTE_PREFIX","validatedTraceContext"],"sources":["../src/server/packageApiServer.ts"],"sourcesContent":["import type { PoTraceContext } from '@agimon-ai/po-telemetry';\nimport type { Context } from '@deepseek-ai/cordis';\n\nimport type { PoDirectEventBus, PoHubSessionPromptOptions, PoHubSessionService } from '../exports/hubChannel';\nimport { PO_API_ROUTE_PREFIX, type PoApi, type PoApiContext } from '../exports/packageApi';\nimport type { PoPlatform } from '../exports/platform';\nimport type { PoPluginRegistry } from '../exports/pluginProtocol';\nimport {\n createPoServerHost,\n type CreatePoServerHostOptions,\n type LoadedServerPackage,\n type PoServerPlugin,\n PoServerScope,\n} from '../exports/serverPlugin';\nimport { observe, type ServerTelemetry } from '../services/serverTelemetry';\nimport { prepareSessionEnvironment } from '../services/sessionFiles';\nimport { validatedTraceContext } from '../services/traceContext';\n\n/**\n * A body that keeps streaming well after its headers went out is worth its own span. A fast\n * one is not: the request span already carries the duration and outcome, so emitting a second\n * span per call made package API traffic 99.65% of all spans recorded in a two hour sample.\n */\nexport const COMPLETION_SPAN_MIN_DURATION_MS = 1000;\n\nexport interface PackageApiServerOptions {\n sessionId: string;\n workspaceId?: string;\n workspaceRoot?: string;\n sessionContext?: PoApiContext['sessionContext'];\n homeDirectory?: string;\n mountChannel?: CreatePoServerHostOptions['mountChannel'];\n cwd: string;\n /** Admitted environment for APIs serving this session. */\n readonly environment: Readonly<Record<string, string | undefined>>;\n /** Lifecycle-owned direct events shared with the hub. */\n readonly directEvents: PoDirectEventBus;\n readonly computerUse?: PoApiContext['computerUse'];\n /** Bound to this session's id and cwd by the host. */\n readonly shareFile?: PoApiContext['shareFile'];\n readonly mediaArbitration?: PoApiContext['mediaArbitration'];\n readonly executionBudget?: PoApiContext['executionBudget'];\n readonly editPresence?: PoApiContext['editPresence'];\n readonly peerAgents?: PoApiContext['peerAgents'];\n readonly requestApi?: PoApiContext['requestApi'];\n /** Publishes this session's activity line through the hub; bound to this session only. */\n readonly publishActivity?: PoApiContext['publishActivity'];\n internalToken?: string;\n hubToken?: string;\n /** Shared exact-scope dispatch table, so session packages can mount plugin methods. */\n pluginRegistry?: PoPluginRegistry;\n sessionService?: PoHubSessionService;\n apis: readonly PoApi[];\n /** Server packages to install; each registers its own APIs through the host. */\n packages?: readonly (PoServerPlugin | LoadedServerPackage)[];\n /** Publishes the session's own services into its scope root before any package installs. */\n preparePackages?: (root: Context) => void | Promise<void>;\n /** The hub's workspace or global scope; the session's own scope opens below it and closes with it. */\n parentScope?: PoServerScope;\n /** Host capabilities for the session scope root, injected by the composition root. */\n platform: PoPlatform;\n activatePackages?: (installedPackages: readonly string[]) => Promise<void>;\n canDispatch?: () => boolean;\n telemetry?: ServerTelemetry;\n onNotice: (message: string) => void;\n}\n\nexport interface PackageApiServer {\n /** Dispatches an already-authenticated request without crossing a transport boundary. */\n readonly request: (request: Request) => Promise<Response>;\n close(): Promise<void>;\n}\n\nfunction describeError(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\nfunction responseWithCompletion(response: Response, complete: () => void): Response {\n if (response.body === null) {\n complete();\n return response;\n }\n const reader = response.body.getReader();\n let completed = false;\n const finish = (): void => {\n if (completed) return;\n completed = true;\n complete();\n };\n const body = new ReadableStream<Uint8Array>({\n async pull(controller) {\n try {\n const result = await reader.read();\n if (result.done) {\n finish();\n controller.close();\n } else controller.enqueue(result.value);\n } catch (error) {\n finish();\n controller.error(error);\n }\n },\n async cancel(reason) {\n finish();\n await reader.cancel(reason);\n },\n });\n return new Response(body, response);\n}\n\n/** Installs session packages and dispatches authenticated package API calls in-process. */\nexport async function serveSessionApis(options: PackageApiServerOptions): Promise<PackageApiServer> {\n if (options.environment === undefined)\n throw new Error('Session package API server requires an admitted environment.');\n if (options.directEvents === undefined) throw new Error('Session package API server requires direct events.');\n options = { ...options, environment: await prepareSessionEnvironment(options) };\n const packages = options.packages ?? [];\n // Without a level above it, a session that mounts nothing has nothing to route.\n const routesNothing = (): boolean => !options.preparePackages && options.parentScope === undefined;\n if (options.apis.length === 0 && packages.length === 0 && routesNothing()) {\n return {\n request: async () => Response.json({ error: 'No package APIs are mounted.' }, { status: 404 }),\n close: () => Promise.resolve(),\n };\n }\n\n const owningSessionService = options.sessionService;\n const communication = owningSessionService?.bindCommunication?.(options.sessionId);\n const ownedReadExecutionState = owningSessionService?.readExecutionState?.bind(owningSessionService);\n const ownedPrompt = owningSessionService?.prompt?.bind(owningSessionService);\n const ownedAbort = owningSessionService?.abort?.bind(owningSessionService);\n const ownedSteer = owningSessionService?.steer?.bind(owningSessionService);\n const ownedRelease = owningSessionService?.release?.bind(owningSessionService);\n const exposedSessionService: PoHubSessionService | undefined =\n owningSessionService === undefined\n ? undefined\n : {\n create: (request) => owningSessionService.create(request),\n close: (sessionId) => owningSessionService.close(sessionId),\n isLive: (sessionId) => owningSessionService.isLive(sessionId),\n ...(ownedReadExecutionState === undefined\n ? {}\n : {\n readExecutionState: (sessionId: string) =>\n ownedReadExecutionState(sessionId, { parentSessionId: options.sessionId }),\n }),\n // A session may drive only the children it started, never its parent or a sibling.\n ...(ownedPrompt === undefined\n ? {}\n : {\n prompt: (sessionId: string, text: string, promptOptions?: PoHubSessionPromptOptions) =>\n ownedPrompt(sessionId, text, {\n ...(promptOptions?.signal === undefined ? {} : { signal: promptOptions.signal }),\n parentSessionId: options.sessionId,\n }),\n }),\n ...(ownedAbort === undefined\n ? {}\n : {\n abort: (sessionId: string) => ownedAbort(sessionId, { parentSessionId: options.sessionId }),\n }),\n ...(ownedSteer === undefined\n ? {}\n : {\n steer: (sessionId: string, message: string) =>\n ownedSteer(sessionId, message, { parentSessionId: options.sessionId }),\n }),\n ...(ownedRelease === undefined\n ? {}\n : {\n release: (sessionId: string) => ownedRelease(sessionId, { parentSessionId: options.sessionId }),\n }),\n ...(owningSessionService.canCommunicate === undefined\n ? {}\n : {\n canCommunicate: (sourceSessionId: string, targetSessionId: string) =>\n owningSessionService.canCommunicate?.(sourceSessionId, targetSessionId) === true,\n }),\n };\n const context: PoApiContext = {\n scope: 'session',\n sessionId: options.sessionId,\n workspaceId: options.workspaceId,\n workspaceRoot: options.workspaceRoot,\n ...(options.sessionContext === undefined ? {} : { sessionContext: options.sessionContext }),\n homeDirectory: options.homeDirectory ?? options.platform.homeDirectory,\n sessionStorage: options.platform.sessions,\n cwd: options.cwd,\n environment: options.environment,\n directEvents: options.directEvents,\n ...(options.computerUse === undefined ? {} : { computerUse: options.computerUse }),\n ...(options.shareFile === undefined ? {} : { shareFile: options.shareFile }),\n ...(options.mediaArbitration === undefined ? {} : { mediaArbitration: options.mediaArbitration }),\n ...(options.executionBudget === undefined ? {} : { executionBudget: options.executionBudget }),\n ...(options.editPresence === undefined ? {} : { editPresence: options.editPresence }),\n ...(options.peerAgents === undefined ? {} : { peerAgents: options.peerAgents }),\n ...(options.requestApi === undefined ? {} : { requestApi: options.requestApi }),\n ...(options.publishActivity === undefined ? {} : { publishActivity: options.publishActivity }),\n ...(options.internalToken === undefined ? {} : { internalToken: options.internalToken }),\n ...(options.hubToken === undefined ? {} : { hubToken: options.hubToken }),\n ...(exposedSessionService === undefined ? {} : { sessionService: exposedSessionService }),\n ...(communication === undefined ? {} : { sessionCommunication: communication }),\n onNotice: options.onNotice,\n };\n const host = createPoServerHost({\n scope: 'session',\n context,\n mountChannel: options.mountChannel,\n ...(options.pluginRegistry === undefined ? {} : { pluginRegistry: options.pluginRegistry }),\n });\n let scope: PoServerScope | undefined;\n try {\n for (const api of options.apis) host.registerApi(api);\n // The session's own level of the server IoC tree; it closes with the hub level it opens below.\n scope = await PoServerScope.open('session', options.parentScope);\n await scope.serve({ host, platform: options.platform });\n await options.preparePackages?.(scope.root);\n const installed = await scope.install(packages, {\n onNotice: options.onNotice,\n onPackageSettled: (report) => {\n if (!options.telemetry) return;\n observe(\n options.telemetry.recordEvent('po_server.package_install', {\n 'package.name': report.packageName,\n 'package.outcome': report.outcome,\n duration_ms: report.durationMs,\n scope: 'session',\n }),\n options.onNotice,\n );\n },\n });\n await options.activatePackages?.(installed);\n } catch (error) {\n await scope?.dispose();\n communication?.close();\n host.dispose();\n throw error;\n }\n if (host.mounted().length === 0 && routesNothing()) {\n await scope.dispose();\n communication?.close();\n host.dispose();\n return {\n request: async () => Response.json({ error: 'No package APIs are mounted.' }, { status: 404 }),\n close: () => Promise.resolve(),\n };\n }\n const sessionScope = scope;\n\n const dispatch = async (request: Request): Promise<Response> => {\n if (options.canDispatch?.() === false)\n return Response.json({ error: 'Session selection is not ready.' }, { status: 503 });\n const url = new URL(request.url);\n if (!url.pathname.startsWith(`${PO_API_ROUTE_PREFIX}/`))\n return Response.json({ error: 'Not found.' }, { status: 404 });\n const rest = url.pathname.slice(PO_API_ROUTE_PREFIX.length + 1);\n const slash = rest.indexOf('/');\n const basePath = slash === -1 ? rest : rest.slice(0, slash);\n // The session's own API, else the nearest level above it that serves one.\n const handler = sessionScope.apiHandler(basePath);\n if (handler === undefined)\n return Response.json({ error: `No API '${basePath}' in this session.` }, { status: 404 });\n url.pathname = slash === -1 ? '/' : rest.slice(slash);\n const startedAt = performance.now();\n const parent = validatedTraceContext(request.headers.get('traceparent'));\n let childContext: PoTraceContext | undefined;\n let response: Response;\n try {\n const invoke = async (context?: PoTraceContext): Promise<Response> => {\n if (options.canDispatch?.() === false || sessionScope.apiHandler(basePath) !== handler) {\n return Response.json({ error: 'Session selection changed before dispatch.' }, { status: 503 });\n }\n childContext = context;\n return handler.fetch(new Request(url, request));\n };\n response = options.telemetry\n ? await options.telemetry.runInSpan(\n 'po_server.package_api.request',\n { api: basePath, method: request.method },\n invoke,\n parent,\n )\n : await invoke();\n } catch (error) {\n if (request.signal.aborted) return new Response(null, { status: 499 });\n options.onNotice(`package API '${basePath}' failed on ${url.pathname} (${describeError(error)})`);\n response = Response.json({ error: `The '${basePath}' API failed.` }, { status: 500 });\n }\n return responseWithCompletion(response, () => {\n if (!options.telemetry) return;\n const durationMs = Math.round(performance.now() - startedAt);\n // Keep this span only where it says something the request span cannot: a failing status,\n // or a body that took real time to flush after the headers were sent.\n if (response.status < 400 && durationMs < COMPLETION_SPAN_MIN_DURATION_MS) return;\n observe(\n options.telemetry.runInSpan(\n 'po_server.package_api.complete',\n {\n api: basePath,\n method: request.method,\n status_code: response.status,\n duration_ms: durationMs,\n },\n async () => undefined,\n childContext ?? parent,\n ),\n options.onNotice,\n );\n });\n };\n let closePromise: Promise<void> | undefined;\n\n return {\n request: dispatch,\n close: () => {\n closePromise ??= (async () => {\n await scope.dispose();\n communication?.close();\n host.dispose();\n })();\n return closePromise;\n },\n };\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"packageApiServer.d.mts","names":[],"sources":["../src/server/packageApiServer.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"packageApiServer.d.mts","names":[],"sources":["../src/server/packageApiServer.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;qBAuBa;iBAEI;EACf;EACA;EACA;EACA,iBAAiB;EACjB;EACA,eAAe;EACf;;WAES,aAAa,SAAS;;WAEtB,cAAc;WACd,cAAc;;WAEd,YAAY;WACZ,mBAAmB;WACnB,kBAAkB;WAClB,eAAe;WACf,aAAa;WACb,aAAa;;WAEb,kBAAkB;EAC3B;EACA;;EAEA,iBAAiB;EACjB,iBAAiB;EACjB,eAAe;;EAEf,qBAAqB,iBAAiB;;EAEtC,mBAAmB,MAAM,mBAAmB;;EAE5C,cAAc;;EAEd,UAAU;EACV,oBAAoB,yCAAyC;EAC7D;EACA,YAAY;EACZ,WAAW;;iBAGI;;WAEN,UAAU,SAAS,YAAY,QAAQ;EAChD,SAAS;;;wBAyCW,iBAAiB,SAAS,0BAA0B,QAAQ"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { observe } from "./serverTelemetry.mjs";
|
|
2
|
+
import { prepareSessionEnvironment } from "./src/services/sessionFiles/index.mjs";
|
|
2
3
|
import { PO_API_ROUTE_PREFIX } from "./src/schemas/packageApi.mjs";
|
|
3
4
|
import "./packageApi.mjs";
|
|
4
5
|
import { createPoServerHost } from "./src/services/serverHost/index.mjs";
|
|
@@ -51,6 +52,10 @@ function responseWithCompletion(response, complete) {
|
|
|
51
52
|
async function serveSessionApis(options) {
|
|
52
53
|
if (options.environment === void 0) throw new Error("Session package API server requires an admitted environment.");
|
|
53
54
|
if (options.directEvents === void 0) throw new Error("Session package API server requires direct events.");
|
|
55
|
+
options = {
|
|
56
|
+
...options,
|
|
57
|
+
environment: await prepareSessionEnvironment(options)
|
|
58
|
+
};
|
|
54
59
|
const packages = options.packages ?? [];
|
|
55
60
|
const routesNothing = () => !options.preparePackages && options.parentScope === void 0;
|
|
56
61
|
if (options.apis.length === 0 && packages.length === 0 && routesNothing()) return {
|
|
@@ -84,7 +89,8 @@ async function serveSessionApis(options) {
|
|
|
84
89
|
workspaceId: options.workspaceId,
|
|
85
90
|
workspaceRoot: options.workspaceRoot,
|
|
86
91
|
...options.sessionContext === void 0 ? {} : { sessionContext: options.sessionContext },
|
|
87
|
-
homeDirectory: options.homeDirectory,
|
|
92
|
+
homeDirectory: options.homeDirectory ?? options.platform.homeDirectory,
|
|
93
|
+
sessionStorage: options.platform.sessions,
|
|
88
94
|
cwd: options.cwd,
|
|
89
95
|
environment: options.environment,
|
|
90
96
|
directEvents: options.directEvents,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"packageApiServer.mjs","names":[],"sources":["../src/server/packageApiServer.ts"],"sourcesContent":["import type { PoTraceContext } from '@agimon-ai/po-telemetry';\nimport type { Context } from '@deepseek-ai/cordis';\n\nimport type { PoDirectEventBus, PoHubSessionPromptOptions, PoHubSessionService } from '../exports/hubChannel';\nimport { PO_API_ROUTE_PREFIX, type PoApi, type PoApiContext } from '../exports/packageApi';\nimport type { PoPlatform } from '../exports/platform';\nimport type { PoPluginRegistry } from '../exports/pluginProtocol';\nimport {\n createPoServerHost,\n type CreatePoServerHostOptions,\n type LoadedServerPackage,\n type PoServerPlugin,\n PoServerScope,\n} from '../exports/serverPlugin';\nimport { observe, type ServerTelemetry } from '../services/serverTelemetry';\nimport { validatedTraceContext } from '../services/traceContext';\n\n/**\n * A body that keeps streaming well after its headers went out is worth its own span. A fast\n * one is not: the request span already carries the duration and outcome, so emitting a second\n * span per call made package API traffic 99.65% of all spans recorded in a two hour sample.\n */\nexport const COMPLETION_SPAN_MIN_DURATION_MS = 1000;\n\nexport interface PackageApiServerOptions {\n sessionId: string;\n workspaceId?: string;\n workspaceRoot?: string;\n sessionContext?: PoApiContext['sessionContext'];\n homeDirectory?: string;\n mountChannel?: CreatePoServerHostOptions['mountChannel'];\n cwd: string;\n /** Admitted environment for APIs serving this session. */\n readonly environment: Readonly<Record<string, string | undefined>>;\n /** Lifecycle-owned direct events shared with the hub. */\n readonly directEvents: PoDirectEventBus;\n readonly computerUse?: PoApiContext['computerUse'];\n /** Bound to this session's id and cwd by the host. */\n readonly shareFile?: PoApiContext['shareFile'];\n readonly mediaArbitration?: PoApiContext['mediaArbitration'];\n readonly executionBudget?: PoApiContext['executionBudget'];\n readonly editPresence?: PoApiContext['editPresence'];\n readonly peerAgents?: PoApiContext['peerAgents'];\n readonly requestApi?: PoApiContext['requestApi'];\n /** Publishes this session's activity line through the hub; bound to this session only. */\n readonly publishActivity?: PoApiContext['publishActivity'];\n internalToken?: string;\n hubToken?: string;\n /** Shared exact-scope dispatch table, so session packages can mount plugin methods. */\n pluginRegistry?: PoPluginRegistry;\n sessionService?: PoHubSessionService;\n apis: readonly PoApi[];\n /** Server packages to install; each registers its own APIs through the host. */\n packages?: readonly (PoServerPlugin | LoadedServerPackage)[];\n /** Publishes the session's own services into its scope root before any package installs. */\n preparePackages?: (root: Context) => void | Promise<void>;\n /** The hub's workspace or global scope; the session's own scope opens below it and closes with it. */\n parentScope?: PoServerScope;\n /** Host capabilities for the session scope root, injected by the composition root. */\n platform: PoPlatform;\n activatePackages?: (installedPackages: readonly string[]) => Promise<void>;\n canDispatch?: () => boolean;\n telemetry?: ServerTelemetry;\n onNotice: (message: string) => void;\n}\n\nexport interface PackageApiServer {\n /** Dispatches an already-authenticated request without crossing a transport boundary. */\n readonly request: (request: Request) => Promise<Response>;\n close(): Promise<void>;\n}\n\nfunction describeError(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\nfunction responseWithCompletion(response: Response, complete: () => void): Response {\n if (response.body === null) {\n complete();\n return response;\n }\n const reader = response.body.getReader();\n let completed = false;\n const finish = (): void => {\n if (completed) return;\n completed = true;\n complete();\n };\n const body = new ReadableStream<Uint8Array>({\n async pull(controller) {\n try {\n const result = await reader.read();\n if (result.done) {\n finish();\n controller.close();\n } else controller.enqueue(result.value);\n } catch (error) {\n finish();\n controller.error(error);\n }\n },\n async cancel(reason) {\n finish();\n await reader.cancel(reason);\n },\n });\n return new Response(body, response);\n}\n\n/** Installs session packages and dispatches authenticated package API calls in-process. */\nexport async function serveSessionApis(options: PackageApiServerOptions): Promise<PackageApiServer> {\n if (options.environment === undefined)\n throw new Error('Session package API server requires an admitted environment.');\n if (options.directEvents === undefined) throw new Error('Session package API server requires direct events.');\n const packages = options.packages ?? [];\n // Without a level above it, a session that mounts nothing has nothing to route.\n const routesNothing = (): boolean => !options.preparePackages && options.parentScope === undefined;\n if (options.apis.length === 0 && packages.length === 0 && routesNothing()) {\n return {\n request: async () => Response.json({ error: 'No package APIs are mounted.' }, { status: 404 }),\n close: () => Promise.resolve(),\n };\n }\n\n const owningSessionService = options.sessionService;\n const communication = owningSessionService?.bindCommunication?.(options.sessionId);\n const ownedReadExecutionState = owningSessionService?.readExecutionState?.bind(owningSessionService);\n const ownedPrompt = owningSessionService?.prompt?.bind(owningSessionService);\n const ownedAbort = owningSessionService?.abort?.bind(owningSessionService);\n const ownedSteer = owningSessionService?.steer?.bind(owningSessionService);\n const ownedRelease = owningSessionService?.release?.bind(owningSessionService);\n const exposedSessionService: PoHubSessionService | undefined =\n owningSessionService === undefined\n ? undefined\n : {\n create: (request) => owningSessionService.create(request),\n close: (sessionId) => owningSessionService.close(sessionId),\n isLive: (sessionId) => owningSessionService.isLive(sessionId),\n ...(ownedReadExecutionState === undefined\n ? {}\n : {\n readExecutionState: (sessionId: string) =>\n ownedReadExecutionState(sessionId, { parentSessionId: options.sessionId }),\n }),\n // A session may drive only the children it started, never its parent or a sibling.\n ...(ownedPrompt === undefined\n ? {}\n : {\n prompt: (sessionId: string, text: string, promptOptions?: PoHubSessionPromptOptions) =>\n ownedPrompt(sessionId, text, {\n ...(promptOptions?.signal === undefined ? {} : { signal: promptOptions.signal }),\n parentSessionId: options.sessionId,\n }),\n }),\n ...(ownedAbort === undefined\n ? {}\n : {\n abort: (sessionId: string) => ownedAbort(sessionId, { parentSessionId: options.sessionId }),\n }),\n ...(ownedSteer === undefined\n ? {}\n : {\n steer: (sessionId: string, message: string) =>\n ownedSteer(sessionId, message, { parentSessionId: options.sessionId }),\n }),\n ...(ownedRelease === undefined\n ? {}\n : {\n release: (sessionId: string) => ownedRelease(sessionId, { parentSessionId: options.sessionId }),\n }),\n ...(owningSessionService.canCommunicate === undefined\n ? {}\n : {\n canCommunicate: (sourceSessionId: string, targetSessionId: string) =>\n owningSessionService.canCommunicate?.(sourceSessionId, targetSessionId) === true,\n }),\n };\n const context: PoApiContext = {\n scope: 'session',\n sessionId: options.sessionId,\n workspaceId: options.workspaceId,\n workspaceRoot: options.workspaceRoot,\n ...(options.sessionContext === undefined ? {} : { sessionContext: options.sessionContext }),\n homeDirectory: options.homeDirectory,\n cwd: options.cwd,\n environment: options.environment,\n directEvents: options.directEvents,\n ...(options.computerUse === undefined ? {} : { computerUse: options.computerUse }),\n ...(options.shareFile === undefined ? {} : { shareFile: options.shareFile }),\n ...(options.mediaArbitration === undefined ? {} : { mediaArbitration: options.mediaArbitration }),\n ...(options.executionBudget === undefined ? {} : { executionBudget: options.executionBudget }),\n ...(options.editPresence === undefined ? {} : { editPresence: options.editPresence }),\n ...(options.peerAgents === undefined ? {} : { peerAgents: options.peerAgents }),\n ...(options.requestApi === undefined ? {} : { requestApi: options.requestApi }),\n ...(options.publishActivity === undefined ? {} : { publishActivity: options.publishActivity }),\n ...(options.internalToken === undefined ? {} : { internalToken: options.internalToken }),\n ...(options.hubToken === undefined ? {} : { hubToken: options.hubToken }),\n ...(exposedSessionService === undefined ? {} : { sessionService: exposedSessionService }),\n ...(communication === undefined ? {} : { sessionCommunication: communication }),\n onNotice: options.onNotice,\n };\n const host = createPoServerHost({\n scope: 'session',\n context,\n mountChannel: options.mountChannel,\n ...(options.pluginRegistry === undefined ? {} : { pluginRegistry: options.pluginRegistry }),\n });\n let scope: PoServerScope | undefined;\n try {\n for (const api of options.apis) host.registerApi(api);\n // The session's own level of the server IoC tree; it closes with the hub level it opens below.\n scope = await PoServerScope.open('session', options.parentScope);\n await scope.serve({ host, platform: options.platform });\n await options.preparePackages?.(scope.root);\n const installed = await scope.install(packages, {\n onNotice: options.onNotice,\n onPackageSettled: (report) => {\n if (!options.telemetry) return;\n observe(\n options.telemetry.recordEvent('po_server.package_install', {\n 'package.name': report.packageName,\n 'package.outcome': report.outcome,\n duration_ms: report.durationMs,\n scope: 'session',\n }),\n options.onNotice,\n );\n },\n });\n await options.activatePackages?.(installed);\n } catch (error) {\n await scope?.dispose();\n communication?.close();\n host.dispose();\n throw error;\n }\n if (host.mounted().length === 0 && routesNothing()) {\n await scope.dispose();\n communication?.close();\n host.dispose();\n return {\n request: async () => Response.json({ error: 'No package APIs are mounted.' }, { status: 404 }),\n close: () => Promise.resolve(),\n };\n }\n const sessionScope = scope;\n\n const dispatch = async (request: Request): Promise<Response> => {\n if (options.canDispatch?.() === false)\n return Response.json({ error: 'Session selection is not ready.' }, { status: 503 });\n const url = new URL(request.url);\n if (!url.pathname.startsWith(`${PO_API_ROUTE_PREFIX}/`))\n return Response.json({ error: 'Not found.' }, { status: 404 });\n const rest = url.pathname.slice(PO_API_ROUTE_PREFIX.length + 1);\n const slash = rest.indexOf('/');\n const basePath = slash === -1 ? rest : rest.slice(0, slash);\n // The session's own API, else the nearest level above it that serves one.\n const handler = sessionScope.apiHandler(basePath);\n if (handler === undefined)\n return Response.json({ error: `No API '${basePath}' in this session.` }, { status: 404 });\n url.pathname = slash === -1 ? '/' : rest.slice(slash);\n const startedAt = performance.now();\n const parent = validatedTraceContext(request.headers.get('traceparent'));\n let childContext: PoTraceContext | undefined;\n let response: Response;\n try {\n const invoke = async (context?: PoTraceContext): Promise<Response> => {\n if (options.canDispatch?.() === false || sessionScope.apiHandler(basePath) !== handler) {\n return Response.json({ error: 'Session selection changed before dispatch.' }, { status: 503 });\n }\n childContext = context;\n return handler.fetch(new Request(url, request));\n };\n response = options.telemetry\n ? await options.telemetry.runInSpan(\n 'po_server.package_api.request',\n { api: basePath, method: request.method },\n invoke,\n parent,\n )\n : await invoke();\n } catch (error) {\n if (request.signal.aborted) return new Response(null, { status: 499 });\n options.onNotice(`package API '${basePath}' failed on ${url.pathname} (${describeError(error)})`);\n response = Response.json({ error: `The '${basePath}' API failed.` }, { status: 500 });\n }\n return responseWithCompletion(response, () => {\n if (!options.telemetry) return;\n const durationMs = Math.round(performance.now() - startedAt);\n // Keep this span only where it says something the request span cannot: a failing status,\n // or a body that took real time to flush after the headers were sent.\n if (response.status < 400 && durationMs < COMPLETION_SPAN_MIN_DURATION_MS) return;\n observe(\n options.telemetry.runInSpan(\n 'po_server.package_api.complete',\n {\n api: basePath,\n method: request.method,\n status_code: response.status,\n duration_ms: durationMs,\n },\n async () => undefined,\n childContext ?? parent,\n ),\n options.onNotice,\n );\n });\n };\n let closePromise: Promise<void> | undefined;\n\n return {\n request: dispatch,\n close: () => {\n closePromise ??= (async () => {\n await scope.dispose();\n communication?.close();\n host.dispose();\n })();\n return closePromise;\n },\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"packageApiServer.mjs","names":[],"sources":["../src/server/packageApiServer.ts"],"sourcesContent":["import type { PoTraceContext } from '@agimon-ai/po-telemetry';\nimport type { Context } from '@deepseek-ai/cordis';\n\nimport type { PoDirectEventBus, PoHubSessionPromptOptions, PoHubSessionService } from '../exports/hubChannel';\nimport { PO_API_ROUTE_PREFIX, type PoApi, type PoApiContext } from '../exports/packageApi';\nimport type { PoPlatform } from '../exports/platform';\nimport type { PoPluginRegistry } from '../exports/pluginProtocol';\nimport {\n createPoServerHost,\n type CreatePoServerHostOptions,\n type LoadedServerPackage,\n type PoServerPlugin,\n PoServerScope,\n} from '../exports/serverPlugin';\nimport { observe, type ServerTelemetry } from '../services/serverTelemetry';\nimport { prepareSessionEnvironment } from '../services/sessionFiles';\nimport { validatedTraceContext } from '../services/traceContext';\n\n/**\n * A body that keeps streaming well after its headers went out is worth its own span. A fast\n * one is not: the request span already carries the duration and outcome, so emitting a second\n * span per call made package API traffic 99.65% of all spans recorded in a two hour sample.\n */\nexport const COMPLETION_SPAN_MIN_DURATION_MS = 1000;\n\nexport interface PackageApiServerOptions {\n sessionId: string;\n workspaceId?: string;\n workspaceRoot?: string;\n sessionContext?: PoApiContext['sessionContext'];\n homeDirectory?: string;\n mountChannel?: CreatePoServerHostOptions['mountChannel'];\n cwd: string;\n /** Admitted environment for APIs serving this session. */\n readonly environment: Readonly<Record<string, string | undefined>>;\n /** Lifecycle-owned direct events shared with the hub. */\n readonly directEvents: PoDirectEventBus;\n readonly computerUse?: PoApiContext['computerUse'];\n /** Bound to this session's id and cwd by the host. */\n readonly shareFile?: PoApiContext['shareFile'];\n readonly mediaArbitration?: PoApiContext['mediaArbitration'];\n readonly executionBudget?: PoApiContext['executionBudget'];\n readonly editPresence?: PoApiContext['editPresence'];\n readonly peerAgents?: PoApiContext['peerAgents'];\n readonly requestApi?: PoApiContext['requestApi'];\n /** Publishes this session's activity line through the hub; bound to this session only. */\n readonly publishActivity?: PoApiContext['publishActivity'];\n internalToken?: string;\n hubToken?: string;\n /** Shared exact-scope dispatch table, so session packages can mount plugin methods. */\n pluginRegistry?: PoPluginRegistry;\n sessionService?: PoHubSessionService;\n apis: readonly PoApi[];\n /** Server packages to install; each registers its own APIs through the host. */\n packages?: readonly (PoServerPlugin | LoadedServerPackage)[];\n /** Publishes the session's own services into its scope root before any package installs. */\n preparePackages?: (root: Context) => void | Promise<void>;\n /** The hub's workspace or global scope; the session's own scope opens below it and closes with it. */\n parentScope?: PoServerScope;\n /** Host capabilities for the session scope root, injected by the composition root. */\n platform: PoPlatform;\n activatePackages?: (installedPackages: readonly string[]) => Promise<void>;\n canDispatch?: () => boolean;\n telemetry?: ServerTelemetry;\n onNotice: (message: string) => void;\n}\n\nexport interface PackageApiServer {\n /** Dispatches an already-authenticated request without crossing a transport boundary. */\n readonly request: (request: Request) => Promise<Response>;\n close(): Promise<void>;\n}\n\nfunction describeError(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\nfunction responseWithCompletion(response: Response, complete: () => void): Response {\n if (response.body === null) {\n complete();\n return response;\n }\n const reader = response.body.getReader();\n let completed = false;\n const finish = (): void => {\n if (completed) return;\n completed = true;\n complete();\n };\n const body = new ReadableStream<Uint8Array>({\n async pull(controller) {\n try {\n const result = await reader.read();\n if (result.done) {\n finish();\n controller.close();\n } else controller.enqueue(result.value);\n } catch (error) {\n finish();\n controller.error(error);\n }\n },\n async cancel(reason) {\n finish();\n await reader.cancel(reason);\n },\n });\n return new Response(body, response);\n}\n\n/** Installs session packages and dispatches authenticated package API calls in-process. */\nexport async function serveSessionApis(options: PackageApiServerOptions): Promise<PackageApiServer> {\n if (options.environment === undefined)\n throw new Error('Session package API server requires an admitted environment.');\n if (options.directEvents === undefined) throw new Error('Session package API server requires direct events.');\n options = { ...options, environment: await prepareSessionEnvironment(options) };\n const packages = options.packages ?? [];\n // Without a level above it, a session that mounts nothing has nothing to route.\n const routesNothing = (): boolean => !options.preparePackages && options.parentScope === undefined;\n if (options.apis.length === 0 && packages.length === 0 && routesNothing()) {\n return {\n request: async () => Response.json({ error: 'No package APIs are mounted.' }, { status: 404 }),\n close: () => Promise.resolve(),\n };\n }\n\n const owningSessionService = options.sessionService;\n const communication = owningSessionService?.bindCommunication?.(options.sessionId);\n const ownedReadExecutionState = owningSessionService?.readExecutionState?.bind(owningSessionService);\n const ownedPrompt = owningSessionService?.prompt?.bind(owningSessionService);\n const ownedAbort = owningSessionService?.abort?.bind(owningSessionService);\n const ownedSteer = owningSessionService?.steer?.bind(owningSessionService);\n const ownedRelease = owningSessionService?.release?.bind(owningSessionService);\n const exposedSessionService: PoHubSessionService | undefined =\n owningSessionService === undefined\n ? undefined\n : {\n create: (request) => owningSessionService.create(request),\n close: (sessionId) => owningSessionService.close(sessionId),\n isLive: (sessionId) => owningSessionService.isLive(sessionId),\n ...(ownedReadExecutionState === undefined\n ? {}\n : {\n readExecutionState: (sessionId: string) =>\n ownedReadExecutionState(sessionId, { parentSessionId: options.sessionId }),\n }),\n // A session may drive only the children it started, never its parent or a sibling.\n ...(ownedPrompt === undefined\n ? {}\n : {\n prompt: (sessionId: string, text: string, promptOptions?: PoHubSessionPromptOptions) =>\n ownedPrompt(sessionId, text, {\n ...(promptOptions?.signal === undefined ? {} : { signal: promptOptions.signal }),\n parentSessionId: options.sessionId,\n }),\n }),\n ...(ownedAbort === undefined\n ? {}\n : {\n abort: (sessionId: string) => ownedAbort(sessionId, { parentSessionId: options.sessionId }),\n }),\n ...(ownedSteer === undefined\n ? {}\n : {\n steer: (sessionId: string, message: string) =>\n ownedSteer(sessionId, message, { parentSessionId: options.sessionId }),\n }),\n ...(ownedRelease === undefined\n ? {}\n : {\n release: (sessionId: string) => ownedRelease(sessionId, { parentSessionId: options.sessionId }),\n }),\n ...(owningSessionService.canCommunicate === undefined\n ? {}\n : {\n canCommunicate: (sourceSessionId: string, targetSessionId: string) =>\n owningSessionService.canCommunicate?.(sourceSessionId, targetSessionId) === true,\n }),\n };\n const context: PoApiContext = {\n scope: 'session',\n sessionId: options.sessionId,\n workspaceId: options.workspaceId,\n workspaceRoot: options.workspaceRoot,\n ...(options.sessionContext === undefined ? {} : { sessionContext: options.sessionContext }),\n homeDirectory: options.homeDirectory ?? options.platform.homeDirectory,\n sessionStorage: options.platform.sessions,\n cwd: options.cwd,\n environment: options.environment,\n directEvents: options.directEvents,\n ...(options.computerUse === undefined ? {} : { computerUse: options.computerUse }),\n ...(options.shareFile === undefined ? {} : { shareFile: options.shareFile }),\n ...(options.mediaArbitration === undefined ? {} : { mediaArbitration: options.mediaArbitration }),\n ...(options.executionBudget === undefined ? {} : { executionBudget: options.executionBudget }),\n ...(options.editPresence === undefined ? {} : { editPresence: options.editPresence }),\n ...(options.peerAgents === undefined ? {} : { peerAgents: options.peerAgents }),\n ...(options.requestApi === undefined ? {} : { requestApi: options.requestApi }),\n ...(options.publishActivity === undefined ? {} : { publishActivity: options.publishActivity }),\n ...(options.internalToken === undefined ? {} : { internalToken: options.internalToken }),\n ...(options.hubToken === undefined ? {} : { hubToken: options.hubToken }),\n ...(exposedSessionService === undefined ? {} : { sessionService: exposedSessionService }),\n ...(communication === undefined ? {} : { sessionCommunication: communication }),\n onNotice: options.onNotice,\n };\n const host = createPoServerHost({\n scope: 'session',\n context,\n mountChannel: options.mountChannel,\n ...(options.pluginRegistry === undefined ? {} : { pluginRegistry: options.pluginRegistry }),\n });\n let scope: PoServerScope | undefined;\n try {\n for (const api of options.apis) host.registerApi(api);\n // The session's own level of the server IoC tree; it closes with the hub level it opens below.\n scope = await PoServerScope.open('session', options.parentScope);\n await scope.serve({ host, platform: options.platform });\n await options.preparePackages?.(scope.root);\n const installed = await scope.install(packages, {\n onNotice: options.onNotice,\n onPackageSettled: (report) => {\n if (!options.telemetry) return;\n observe(\n options.telemetry.recordEvent('po_server.package_install', {\n 'package.name': report.packageName,\n 'package.outcome': report.outcome,\n duration_ms: report.durationMs,\n scope: 'session',\n }),\n options.onNotice,\n );\n },\n });\n await options.activatePackages?.(installed);\n } catch (error) {\n await scope?.dispose();\n communication?.close();\n host.dispose();\n throw error;\n }\n if (host.mounted().length === 0 && routesNothing()) {\n await scope.dispose();\n communication?.close();\n host.dispose();\n return {\n request: async () => Response.json({ error: 'No package APIs are mounted.' }, { status: 404 }),\n close: () => Promise.resolve(),\n };\n }\n const sessionScope = scope;\n\n const dispatch = async (request: Request): Promise<Response> => {\n if (options.canDispatch?.() === false)\n return Response.json({ error: 'Session selection is not ready.' }, { status: 503 });\n const url = new URL(request.url);\n if (!url.pathname.startsWith(`${PO_API_ROUTE_PREFIX}/`))\n return Response.json({ error: 'Not found.' }, { status: 404 });\n const rest = url.pathname.slice(PO_API_ROUTE_PREFIX.length + 1);\n const slash = rest.indexOf('/');\n const basePath = slash === -1 ? rest : rest.slice(0, slash);\n // The session's own API, else the nearest level above it that serves one.\n const handler = sessionScope.apiHandler(basePath);\n if (handler === undefined)\n return Response.json({ error: `No API '${basePath}' in this session.` }, { status: 404 });\n url.pathname = slash === -1 ? '/' : rest.slice(slash);\n const startedAt = performance.now();\n const parent = validatedTraceContext(request.headers.get('traceparent'));\n let childContext: PoTraceContext | undefined;\n let response: Response;\n try {\n const invoke = async (context?: PoTraceContext): Promise<Response> => {\n if (options.canDispatch?.() === false || sessionScope.apiHandler(basePath) !== handler) {\n return Response.json({ error: 'Session selection changed before dispatch.' }, { status: 503 });\n }\n childContext = context;\n return handler.fetch(new Request(url, request));\n };\n response = options.telemetry\n ? await options.telemetry.runInSpan(\n 'po_server.package_api.request',\n { api: basePath, method: request.method },\n invoke,\n parent,\n )\n : await invoke();\n } catch (error) {\n if (request.signal.aborted) return new Response(null, { status: 499 });\n options.onNotice(`package API '${basePath}' failed on ${url.pathname} (${describeError(error)})`);\n response = Response.json({ error: `The '${basePath}' API failed.` }, { status: 500 });\n }\n return responseWithCompletion(response, () => {\n if (!options.telemetry) return;\n const durationMs = Math.round(performance.now() - startedAt);\n // Keep this span only where it says something the request span cannot: a failing status,\n // or a body that took real time to flush after the headers were sent.\n if (response.status < 400 && durationMs < COMPLETION_SPAN_MIN_DURATION_MS) return;\n observe(\n options.telemetry.runInSpan(\n 'po_server.package_api.complete',\n {\n api: basePath,\n method: request.method,\n status_code: response.status,\n duration_ms: durationMs,\n },\n async () => undefined,\n childContext ?? parent,\n ),\n options.onNotice,\n );\n });\n };\n let closePromise: Promise<void> | undefined;\n\n return {\n request: dispatch,\n close: () => {\n closePromise ??= (async () => {\n await scope.dispose();\n communication?.close();\n host.dispose();\n })();\n return closePromise;\n },\n };\n}\n"],"mappings":"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"}
|
package/dist/platform.cjs
CHANGED
|
@@ -4,6 +4,7 @@ const require_index$1 = require("./src/services/nodeHost/index.cjs");
|
|
|
4
4
|
const require_index$2 = require("./src/services/serialRunner/index.cjs");
|
|
5
5
|
const require_docs = require("./src/services/durableSession/docs.cjs");
|
|
6
6
|
const require_index$3 = require("./src/services/durableSession/index.cjs");
|
|
7
|
+
const require_index$4 = require("./src/services/sessionFiles/index.cjs");
|
|
7
8
|
const require_platform = require("./src/schemas/platform.cjs");
|
|
8
9
|
let _earendil_works_pi_durable_env = require("@earendil-works/pi-durable/env");
|
|
9
10
|
let dist_interop_chordContext_mjs = require("../dist/interop/chordContext.mjs");
|
|
@@ -26,7 +27,9 @@ Object.defineProperty(exports, "FileError", {
|
|
|
26
27
|
}
|
|
27
28
|
});
|
|
28
29
|
exports.PO_FS_SERVICE = require_platform.PO_FS_SERVICE;
|
|
30
|
+
exports.PO_SESSION_FILES_SERVICE = require_index$4.PO_SESSION_FILES_SERVICE;
|
|
29
31
|
exports.PO_SESSION_STORAGE_SERVICE = require_platform.PO_SESSION_STORAGE_SERVICE;
|
|
32
|
+
exports.PO_SESSION_TEMP_DIR = require_index$4.PO_SESSION_TEMP_DIR;
|
|
30
33
|
exports.PO_SHELL_SERVICE = require_platform.PO_SHELL_SERVICE;
|
|
31
34
|
exports.PO_SQLITE_SERVICE = require_platform.PO_SQLITE_SERVICE;
|
|
32
35
|
exports.SessionIdentityDoc = require_docs.SessionIdentityDoc;
|
|
@@ -42,11 +45,14 @@ exports.initializeSessionIdentity = require_index$3.initializeSessionIdentity;
|
|
|
42
45
|
exports.nodeHost = require_index$1.nodeHost;
|
|
43
46
|
exports.pathExists = require_index.pathExists;
|
|
44
47
|
exports.readPoFs = require_platform.readPoFs;
|
|
48
|
+
exports.readSessionFileDirectories = require_index$4.readSessionFileDirectories;
|
|
45
49
|
exports.readTextIfExists = require_index.readTextIfExists;
|
|
46
50
|
exports.removePath = require_index.removePath;
|
|
51
|
+
exports.removeSessionFiles = require_index$4.removeSessionFiles;
|
|
47
52
|
exports.requirePoFs = require_platform.requirePoFs;
|
|
48
53
|
exports.requirePoShell = require_platform.requirePoShell;
|
|
49
54
|
exports.requirePoSqlite = require_platform.requirePoSqlite;
|
|
55
|
+
exports.sessionTempDirectory = require_index$4.sessionTempDirectory;
|
|
50
56
|
Object.defineProperty(exports, "withAbortSignal", {
|
|
51
57
|
enumerable: true,
|
|
52
58
|
get: function() {
|
package/dist/platform.d.mts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { PO_FS_SERVICE, PO_SESSION_STORAGE_SERVICE, PO_SHELL_SERVICE, PO_SQLITE_SERVICE, PoPlatform, PoSessionStorage, PoSessionStorageRequest, PoSessionStorageService, PoSqliteService, PoStoredSession, readPoFs, requirePoFs, requirePoShell, requirePoSqlite } from "./src/schemas/platform.mjs";
|
|
2
|
+
import { PO_SESSION_FILES_SERVICE, PO_SESSION_TEMP_DIR, PoSessionFileDirectories, PoSessionFiles, SessionTempDirectoryOptions, readSessionFileDirectories, removeSessionFiles, sessionTempDirectory } from "./src/services/sessionFiles/index.mjs";
|
|
2
3
|
import { SerialRunner, SerialTask, createSerialRunner } from "./src/services/serialRunner/index.mjs";
|
|
3
4
|
import { initializeSessionIdentity } from "./src/services/durableSession/index.mjs";
|
|
4
5
|
import { SessionIdentityDoc, SessionMetadataDoc } from "./src/services/durableSession/docs.mjs";
|
|
@@ -6,4 +7,4 @@ import { nodeHost } from "./src/services/nodeHost/index.mjs";
|
|
|
6
7
|
import { pathExists, readTextIfExists, removePath, writeFileAtomic } from "./src/services/platformFiles/index.mjs";
|
|
7
8
|
import { ExecutionEnv, ExecutionError, FileError, FileSystem, Result, Shell, getOrThrow } from "@earendil-works/pi-durable/env";
|
|
8
9
|
import { BACKGROUND_CONTEXT, withAbortSignal } from "@earendil-works/chord/context";
|
|
9
|
-
export { BACKGROUND_CONTEXT, type ExecutionEnv, ExecutionError, FileError, type FileSystem, PO_FS_SERVICE, PO_SESSION_STORAGE_SERVICE, PO_SHELL_SERVICE, PO_SQLITE_SERVICE, type PoPlatform, type PoSessionStorage, type PoSessionStorageRequest, type PoSessionStorageService, type PoSqliteService, type PoStoredSession, type Result, type SerialRunner, type SerialTask, SessionIdentityDoc, SessionMetadataDoc, type Shell, createSerialRunner, getOrThrow, initializeSessionIdentity, nodeHost, pathExists, readPoFs, readTextIfExists, removePath, requirePoFs, requirePoShell, requirePoSqlite, withAbortSignal, writeFileAtomic };
|
|
10
|
+
export { BACKGROUND_CONTEXT, type ExecutionEnv, ExecutionError, FileError, type FileSystem, PO_FS_SERVICE, PO_SESSION_FILES_SERVICE, PO_SESSION_STORAGE_SERVICE, PO_SESSION_TEMP_DIR, PO_SHELL_SERVICE, PO_SQLITE_SERVICE, type PoPlatform, type PoSessionFileDirectories, type PoSessionFiles, type PoSessionStorage, type PoSessionStorageRequest, type PoSessionStorageService, type PoSqliteService, type PoStoredSession, type Result, type SerialRunner, type SerialTask, SessionIdentityDoc, SessionMetadataDoc, type SessionTempDirectoryOptions, type Shell, createSerialRunner, getOrThrow, initializeSessionIdentity, nodeHost, pathExists, readPoFs, readSessionFileDirectories, readTextIfExists, removePath, removeSessionFiles, requirePoFs, requirePoShell, requirePoSqlite, sessionTempDirectory, withAbortSignal, writeFileAtomic };
|
package/dist/platform.mjs
CHANGED
|
@@ -3,7 +3,8 @@ import { nodeHost } from "./src/services/nodeHost/index.mjs";
|
|
|
3
3
|
import { createSerialRunner } from "./src/services/serialRunner/index.mjs";
|
|
4
4
|
import { SessionIdentityDoc, SessionMetadataDoc } from "./src/services/durableSession/docs.mjs";
|
|
5
5
|
import { initializeSessionIdentity } from "./src/services/durableSession/index.mjs";
|
|
6
|
+
import { PO_SESSION_FILES_SERVICE, PO_SESSION_TEMP_DIR, readSessionFileDirectories, removeSessionFiles, sessionTempDirectory } from "./src/services/sessionFiles/index.mjs";
|
|
6
7
|
import { PO_FS_SERVICE, PO_SESSION_STORAGE_SERVICE, PO_SHELL_SERVICE, PO_SQLITE_SERVICE, readPoFs, requirePoFs, requirePoShell, requirePoSqlite } from "./src/schemas/platform.mjs";
|
|
7
8
|
import { ExecutionError, FileError, getOrThrow } from "@earendil-works/pi-durable/env";
|
|
8
9
|
import { BACKGROUND_CONTEXT, withAbortSignal } from "@earendil-works/chord/context";
|
|
9
|
-
export { BACKGROUND_CONTEXT, ExecutionError, FileError, PO_FS_SERVICE, PO_SESSION_STORAGE_SERVICE, PO_SHELL_SERVICE, PO_SQLITE_SERVICE, SessionIdentityDoc, SessionMetadataDoc, createSerialRunner, getOrThrow, initializeSessionIdentity, nodeHost, pathExists, readPoFs, readTextIfExists, removePath, requirePoFs, requirePoShell, requirePoSqlite, withAbortSignal, writeFileAtomic };
|
|
10
|
+
export { BACKGROUND_CONTEXT, ExecutionError, FileError, PO_FS_SERVICE, PO_SESSION_FILES_SERVICE, PO_SESSION_STORAGE_SERVICE, PO_SESSION_TEMP_DIR, PO_SHELL_SERVICE, PO_SQLITE_SERVICE, SessionIdentityDoc, SessionMetadataDoc, createSerialRunner, getOrThrow, initializeSessionIdentity, nodeHost, pathExists, readPoFs, readSessionFileDirectories, readTextIfExists, removePath, removeSessionFiles, requirePoFs, requirePoShell, requirePoSqlite, sessionTempDirectory, withAbortSignal, writeFileAtomic };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hubChannel.cjs","names":[],"sources":["../../../src/schemas/hubChannel.ts"],"sourcesContent":["import type { PoBackgroundWorkSnapshot } from './backgroundWork';\nimport type { HomeProjection } from './home';\n\nexport interface PoHubChannelFrame {\n type: string;\n sessionId: string;\n payload: unknown;\n}\n\n/** Same-process lifecycle bus shared by a host's session APIs and hub channels. */\nexport interface PoDirectEventSubscriptionOptions {\n /** Replay the most recent value published for this frame and session, when one exists. */\n readonly replayLatest?: boolean;\n}\n\nexport interface PoDirectEventBus {\n publish(frameType: string, sessionId: string, payload: unknown): void;\n subscribe(\n frameType: string,\n sessionId: string,\n listener: (payload: unknown) => void,\n options?: PoDirectEventSubscriptionOptions,\n ): () => void;\n /** Drop retained state for a session after its lifecycle ends. */\n clearSession?(sessionId: string): void;\n close(): void;\n}\n\n/**\n * The extension-agnostic baseline every surface gets for one session, computed once by the\n * session host. Extensions build on it instead of re-deriving roots and relations from cwd.\n */\nexport interface PoSessionContext {\n readonly sessionId: string;\n /** Persisted workspace id, shared by every session and member checkout of the workspace. */\n readonly workspaceId: string;\n /** The admitted workspace root. It owns configuration, composition and settings. */\n readonly workspaceRoot: string;\n /**\n * The checkout the session executes in. Equals workspaceRoot unless the session runs in a\n * member checkout, such as a worktree, which may live outside the workspace folder.\n */\n readonly checkoutRoot: string;\n readonly cwd: string;\n readonly parentSessionId?: string;\n /** The spawner's label for the session. Opaque: hosts never interpret it. */\n readonly provenance?: string;\n}\n\nexport interface PoHubSessionScope {\n sessionId: string;\n workspaceId?: string;\n cwd: string;\n /** Environment admitted for this session, when supplied by the host. */\n environment?: Readonly<Record<string, string | undefined>>;\n /** The session's baseline context, when its host knows its workspace. */\n sessionContext?: PoSessionContext;\n}\n\nexport interface PoHubReservedWorktreeRequest {\n readonly reservationId: string;\n readonly parentSessionId: string;\n readonly signal?: AbortSignal;\n}\n\nexport type PoHubReservedWorktreeProvisioner = (request: PoHubReservedWorktreeRequest) => Promise<PoHubSessionScope>;\n\n/** Selection axes a caller pins for a new session instead of the workspace defaults. */\nexport interface PoHubSessionSelection {\n readonly majorMode?: string;\n readonly minorModes?: readonly string[];\n readonly profile?: string;\n /** An empty list starts the session with no domains. */\n readonly domains?: readonly string[];\n}\n\n/**\n * Provenance of a session a workflow step opened.\n *\n * The step's conversation belongs to the workflow that ran it and is read in\n * that workflow's view, so the session rail leaves such sessions out.\n */\nexport const WORKFLOW_STEP_SESSION_PROVENANCE = 'workflow';\n\n/**\n * Provenance of a session opened to launch workflows for its parent.\n *\n * It picks and starts work, then closes; the runs it started belong to its\n * parent. Like a detached helper, it takes no row in the session rail.\n */\nexport const WORKFLOW_DISPATCHER_SESSION_PROVENANCE = 'workflow-dispatcher';\n\n/** Provenance of a conversation an external MCP client opened and drives. */\nexport const REMOTE_CONVERSATION_SESSION_PROVENANCE = 'remote-conversation';\n\nexport interface PoHubSessionCreateRequest {\n readonly cwd: string;\n readonly name: string;\n readonly parentSessionId?: string;\n readonly sessionProvenance?: string;\n readonly signal?: AbortSignal;\n /** Host-issued reservation, not a caller-chosen target session id. */\n readonly reservationId?: string;\n /** Pinned axes stay put when the workspace defaults change between turns. */\n readonly selection?: PoHubSessionSelection;\n /** Pi model selector, `provider/id`, validated like `--model`. */\n readonly model?: string;\n /** Pi thinking level, validated like `--thinking`. */\n readonly thinking?: string;\n /** Text appended to the session's system prompt, like `--append-system-prompt`. */\n readonly appendSystemPrompt?: string;\n /** Variables layered over the host environment for the new session and the tools it runs. */\n readonly environment?: Readonly<Record<string, string>>;\n /** The only tools the new session's agent may see or call, like a Team agent's `tools:` list. */\n readonly tools?: readonly string[];\n}\n\nexport interface PoHubSessionPromptOptions {\n readonly signal?: AbortSignal;\n /** Refuses the prompt unless the target is a direct child of this session. */\n readonly parentSessionId?: string;\n}\n\n/** A prompt the session admitted. `settled` resolves once the agent settles and rejects on a harness fault. */\nexport interface PoHubSessionPromptReceipt {\n readonly settled: Promise<void>;\n}\n\n/** Host-bound inter-session events. The source identity is attached by the hub, never by payload data. */\nexport interface PoSessionCommunicationEndpoint {\n readonly sessionId: string;\n /** Current human-readable session name, read live so renames are reflected. */\n readonly sessionName?: string;\n publish(targetSessionId: string, type: string, payload: unknown): boolean;\n subscribe(type: string, listener: (sourceSessionId: string, payload: unknown) => void): () => void;\n onPeerReady(listener: (peerSessionId: string) => void): () => void;\n /** Describes a live peer authorized to communicate, including same-checkout peers. */\n describePeer?(peerSessionId: string): PoSessionPeerDescription | undefined;\n close(): void;\n}\n\n/** How a session sees a peer it may message, so an agent can address it by the name a person uses. */\nexport interface PoSessionPeerDescription {\n readonly sessionId: string;\n readonly name: string;\n readonly profile?: string;\n /** Groups both sessions belong to; empty when related through parentage or checkout. */\n readonly sharedGroups: readonly string[];\n}\nexport interface PoPendingSessionSetup {\n readonly id: string;\n readonly name: string;\n readonly createdAt: string;\n readonly cwd?: string;\n readonly setupKind?: 'managed-worktree' | 'existing-directory';\n readonly status?: 'provisioning' | 'failed' | 'interrupted';\n readonly errorCode?: 'SESSION_WORKTREE_PROVISION_FAILED' | 'SESSION_UNAVAILABLE';\n}\n\n/**\n * One short line a session's extension publishes about work it runs for that\n * session, such as a background job. The host shows it on the session's rail\n * card but never interprets it.\n */\nexport interface PoSessionActivity {\n readonly label: string;\n /** The work needs the reader: the rail marks the card the way it marks a pending question. */\n readonly attention?: boolean;\n /** ISO 8601 start of the work; the rail appends the elapsed time. */\n readonly since?: string;\n}\n/** A host-owned setup can be fulfilled by any execution-directory provider. */\nexport interface PoHubSessionReservations {\n read(id: string, parentSessionId: string): { sessionId: string; cwd?: string };\n prepare(id: string, parentSessionId: string, cwd: string): Promise<{ sessionId: string; cwd: string }>;\n complete(id: string, parentSessionId: string): Promise<PoHubSessionScope>;\n}\n\n/** Authoritative execution state. Missing background coordination is unknown, not empty. */\nexport interface PoHubSessionExecutionState {\n readonly isIdle: boolean;\n readonly hasPendingMessages: boolean;\n readonly backgroundWork?: PoBackgroundWorkSnapshot;\n}\n\n/** Direct lifecycle owned by the canonical headless hub, never by a package transport. */\nexport interface PoHubSessionService {\n create(request: PoHubSessionCreateRequest): Promise<PoHubSessionScope>;\n close(sessionId: string): Promise<void>;\n isLive(sessionId: string): boolean;\n /** Reads a live child's ownership without starting a turn. */\n readExecutionState?(\n sessionId: string,\n options?: Pick<PoHubSessionPromptOptions, 'parentSessionId'>,\n ): Promise<PoHubSessionExecutionState>;\n /** Starts a turn in a live session, as if its user had submitted `text`. */\n prompt?(sessionId: string, text: string, options?: PoHubSessionPromptOptions): Promise<PoHubSessionPromptReceipt>;\n /** Aborts the live session's current turn. The session stays open. */\n abort?(sessionId: string, options?: Pick<PoHubSessionPromptOptions, 'parentSessionId'>): Promise<void>;\n /**\n * Adds guidance to a live session's running turn. A session with no turn in\n * progress takes it as its next message instead.\n */\n steer?(\n sessionId: string,\n message: string,\n options?: Pick<PoHubSessionPromptOptions, 'parentSessionId'>,\n ): Promise<void>;\n /**\n * Stops a live session's runtime and keeps it dormant: its history stays\n * readable where it is shown, and it can be woken later. A session that has\n * done its work no longer holds a model, tools and extensions in the host.\n */\n release?(sessionId: string, options?: Pick<PoHubSessionPromptOptions, 'parentSessionId'>): Promise<void>;\n readonly reservations?: PoHubSessionReservations;\n /** Provisions a host-reserved Git worktree child. This is not exposed to remote MCP clients. */\n provisionReservedWorktree?(request: PoHubReservedWorktreeRequest): Promise<PoHubSessionScope>;\n /** Core host hook. A Git provider registers its implementation while its channel is mounted. */\n registerReservedWorktreeProvisioner?(provisioner: PoHubReservedWorktreeProvisioner): () => void;\n /**\n * True when both live sessions have a direct parent-child relationship, or execute in the same\n * checkout. Remote conversations only qualify through the parent-child relationship.\n */\n canCommunicate?(sourceSessionId: string, targetSessionId: string): boolean;\n /** Core host hook. Session API construction removes this method before exposing the service to extensions. */\n bindCommunication?(sessionId: string): PoSessionCommunicationEndpoint;\n}\n\nexport interface PoHubSessionApiRequest {\n basePath: string;\n path: string;\n method: string;\n body?: string | Uint8Array<ArrayBuffer> | null;\n signal?: AbortSignal;\n /** Forwarded by the authenticated host, including content type and trace context. */\n headers?: RequestInit['headers'];\n}\n\nexport type PoComputerUseHostOperation = 'status' | 'targets' | 'activate' | 'observe' | 'act' | 'stop';\n\nexport interface PoComputerUseHostRequest {\n readonly operation: PoComputerUseHostOperation;\n readonly payload?: unknown;\n readonly signal?: AbortSignal;\n}\n\nexport interface PoComputerUseHostBinding {\n readonly available: boolean;\n /** Global opt-in, separate from the presence of a native host. */\n readonly enabled?: boolean;\n request(scope: PoHubSessionScope, request: PoComputerUseHostRequest): Promise<unknown>;\n /** Checks a proof injected by the owning Desktop process, never a renderer marker. */\n authorize?(headers: Headers): boolean;\n /** Pins a session to Desktop before asking for a native grant. Ownership is not persisted. */\n claimSession?(sessionId: string, headers?: Headers): void;\n ownsSession?(sessionId: string): boolean;\n /** Server-authenticated paired identity, checked against live native approval for this session. */\n authorizeSession?(sessionId: string, headers: Headers): boolean;\n authorizeRecording?(sessionId: string, headers: Headers): boolean;\n authorizeActivation?(headers: Headers): boolean;\n /** Own pending activation only, never general session control. */\n authorizePending?(sessionId: string, headers: Headers): boolean;\n revokeDevice?(deviceId: string): void;\n readRecording?(scope: PoHubSessionScope, artifactId: string, range: string): Promise<Response>;\n forgetSession?(sessionId: string): void;\n /** Without `sessionId` the listener hears every session's ownership change. */\n subscribe?(listener: () => void, sessionId?: string): () => void;\n close?(): void;\n}\n\n/** Narrow, host-bound access. An extension cannot select another session's identity. */\nexport interface PoComputerUseSessionAccess {\n readonly available: boolean;\n readonly enabled?: boolean;\n authorize(headers: Headers): boolean;\n authorizeRecording?(headers: Headers): boolean;\n authorizeActivation?(headers: Headers): boolean;\n authorizePending?(headers: Headers): boolean;\n claim(headers?: Headers): void;\n fetchRecording?(artifactId: string, range: string): Promise<Response>;\n subscribe(listener: () => void): () => void;\n}\n\nexport interface PoHubChannelConnection {\n connectionId: string;\n /** Host-verified native renderer proof, never copied from a channel payload. */\n desktopAuthorized?: boolean;\n /** Live session authorization evaluated by the host, never a client frame. */\n computerUseAuthorized?: boolean;\n}\n\nexport interface PoHubChannelHost {\n sessions(): readonly PoHubSessionScope[];\n /** Canonical hub lifecycle for sessions created by channel commands. */\n sessionService?: PoHubSessionService;\n /** Same-process events emitted by session packages. */\n readonly directEvents: PoDirectEventBus;\n publish(sessionId: string, payload: unknown): void;\n publishToConnection?(connectionId: string, sessionId: string, payload: unknown): boolean;\n requestSessionApi(scope: PoHubSessionScope, request: PoHubSessionApiRequest): Promise<Response>;\n computerUse?: PoComputerUseHostBinding;\n onNotice(message: string): void;\n}\n\nexport interface PoHubChannelSource {\n payloadFor(scope: PoHubSessionScope): unknown;\n /** Read-only compact projection of already-owned state. Must not start work or add watchers. */\n homeFor?(scope: PoHubSessionScope): HomeProjection;\n sessionAdded?(scope: PoHubSessionScope): void;\n sessionRemoved?(sessionId: string): void;\n close(): void;\n}\n\nexport type PoHubChannelLifecycle = 'session' | 'hub';\n\nexport interface PoHubChannel {\n frameType: string;\n lifecycle?: PoHubChannelLifecycle;\n start(host: PoHubChannelHost): PoHubChannelSource;\n receiveWithoutSubscription?: boolean;\n receive?(scope: PoHubSessionScope, payload: unknown, connection: PoHubChannelConnection): void;\n disconnected?(connection: PoHubChannelConnection): void;\n}\n"],"mappings":";;;;;;;AAkFA,MAAa,mCAAmC;;;;;;;AAQhD,MAAa,yCAAyC;;AAGtD,MAAa,yCAAyC"}
|
|
1
|
+
{"version":3,"file":"hubChannel.cjs","names":[],"sources":["../../../src/schemas/hubChannel.ts"],"sourcesContent":["import type { PoBackgroundWorkSnapshot } from './backgroundWork';\nimport type { HomeProjection } from './home';\nimport type { PoSessionStorageService } from './platform';\n\nexport interface PoHubChannelFrame {\n type: string;\n sessionId: string;\n payload: unknown;\n}\n\n/** Same-process lifecycle bus shared by a host's session APIs and hub channels. */\nexport interface PoDirectEventSubscriptionOptions {\n /** Replay the most recent value published for this frame and session, when one exists. */\n readonly replayLatest?: boolean;\n}\n\nexport interface PoDirectEventBus {\n publish(frameType: string, sessionId: string, payload: unknown): void;\n subscribe(\n frameType: string,\n sessionId: string,\n listener: (payload: unknown) => void,\n options?: PoDirectEventSubscriptionOptions,\n ): () => void;\n /** Drop retained state for a session after its lifecycle ends. */\n clearSession?(sessionId: string): void;\n close(): void;\n}\n\n/**\n * The extension-agnostic baseline every surface gets for one session, computed once by the\n * session host. Extensions build on it instead of re-deriving roots and relations from cwd.\n */\nexport interface PoSessionContext {\n readonly sessionId: string;\n /** Persisted workspace id, shared by every session and member checkout of the workspace. */\n readonly workspaceId: string;\n /** The admitted workspace root. It owns configuration, composition and settings. */\n readonly workspaceRoot: string;\n /**\n * The checkout the session executes in. Equals workspaceRoot unless the session runs in a\n * member checkout, such as a worktree, which may live outside the workspace folder.\n */\n readonly checkoutRoot: string;\n readonly cwd: string;\n readonly parentSessionId?: string;\n /** The spawner's label for the session. Opaque: hosts never interpret it. */\n readonly provenance?: string;\n}\n\nexport interface PoHubSessionScope {\n sessionId: string;\n workspaceId?: string;\n cwd: string;\n /** Environment admitted for this session, when supplied by the host. */\n environment?: Readonly<Record<string, string | undefined>>;\n /** The session's baseline context, when its host knows its workspace. */\n sessionContext?: PoSessionContext;\n}\n\nexport interface PoHubReservedWorktreeRequest {\n readonly reservationId: string;\n readonly parentSessionId: string;\n readonly signal?: AbortSignal;\n}\n\nexport type PoHubReservedWorktreeProvisioner = (request: PoHubReservedWorktreeRequest) => Promise<PoHubSessionScope>;\n\n/** Selection axes a caller pins for a new session instead of the workspace defaults. */\nexport interface PoHubSessionSelection {\n readonly majorMode?: string;\n readonly minorModes?: readonly string[];\n readonly profile?: string;\n /** An empty list starts the session with no domains. */\n readonly domains?: readonly string[];\n}\n\n/**\n * Provenance of a session a workflow step opened.\n *\n * The step's conversation belongs to the workflow that ran it and is read in\n * that workflow's view, so the session rail leaves such sessions out.\n */\nexport const WORKFLOW_STEP_SESSION_PROVENANCE = 'workflow';\n\n/**\n * Provenance of a session opened to launch workflows for its parent.\n *\n * It picks and starts work, then closes; the runs it started belong to its\n * parent. Like a detached helper, it takes no row in the session rail.\n */\nexport const WORKFLOW_DISPATCHER_SESSION_PROVENANCE = 'workflow-dispatcher';\n\n/** Provenance of a conversation an external MCP client opened and drives. */\nexport const REMOTE_CONVERSATION_SESSION_PROVENANCE = 'remote-conversation';\n\nexport interface PoHubSessionCreateRequest {\n readonly cwd: string;\n readonly name: string;\n readonly parentSessionId?: string;\n readonly sessionProvenance?: string;\n readonly signal?: AbortSignal;\n /** Host-issued reservation, not a caller-chosen target session id. */\n readonly reservationId?: string;\n /** Pinned axes stay put when the workspace defaults change between turns. */\n readonly selection?: PoHubSessionSelection;\n /** Pi model selector, `provider/id`, validated like `--model`. */\n readonly model?: string;\n /** Pi thinking level, validated like `--thinking`. */\n readonly thinking?: string;\n /** Text appended to the session's system prompt, like `--append-system-prompt`. */\n readonly appendSystemPrompt?: string;\n /** Variables layered over the host environment for the new session and the tools it runs. */\n readonly environment?: Readonly<Record<string, string>>;\n /** The only tools the new session's agent may see or call, like a Team agent's `tools:` list. */\n readonly tools?: readonly string[];\n}\n\nexport interface PoHubSessionPromptOptions {\n readonly signal?: AbortSignal;\n /** Refuses the prompt unless the target is a direct child of this session. */\n readonly parentSessionId?: string;\n}\n\n/** A prompt the session admitted. `settled` resolves once the agent settles and rejects on a harness fault. */\nexport interface PoHubSessionPromptReceipt {\n readonly settled: Promise<void>;\n}\n\n/** Host-bound inter-session events. The source identity is attached by the hub, never by payload data. */\nexport interface PoSessionCommunicationEndpoint {\n readonly sessionId: string;\n /** Current human-readable session name, read live so renames are reflected. */\n readonly sessionName?: string;\n publish(targetSessionId: string, type: string, payload: unknown): boolean;\n subscribe(type: string, listener: (sourceSessionId: string, payload: unknown) => void): () => void;\n onPeerReady(listener: (peerSessionId: string) => void): () => void;\n /** Describes a live peer authorized to communicate, including same-checkout peers. */\n describePeer?(peerSessionId: string): PoSessionPeerDescription | undefined;\n close(): void;\n}\n\n/** How a session sees a peer it may message, so an agent can address it by the name a person uses. */\nexport interface PoSessionPeerDescription {\n readonly sessionId: string;\n readonly name: string;\n readonly profile?: string;\n /** Groups both sessions belong to; empty when related through parentage or checkout. */\n readonly sharedGroups: readonly string[];\n}\nexport interface PoPendingSessionSetup {\n readonly id: string;\n readonly name: string;\n readonly createdAt: string;\n readonly cwd?: string;\n readonly setupKind?: 'managed-worktree' | 'existing-directory';\n readonly status?: 'provisioning' | 'failed' | 'interrupted';\n readonly errorCode?: 'SESSION_WORKTREE_PROVISION_FAILED' | 'SESSION_UNAVAILABLE';\n}\n\n/**\n * One short line a session's extension publishes about work it runs for that\n * session, such as a background job. The host shows it on the session's rail\n * card but never interprets it.\n */\nexport interface PoSessionActivity {\n readonly label: string;\n /** The work needs the reader: the rail marks the card the way it marks a pending question. */\n readonly attention?: boolean;\n /** ISO 8601 start of the work; the rail appends the elapsed time. */\n readonly since?: string;\n}\n/** A host-owned setup can be fulfilled by any execution-directory provider. */\nexport interface PoHubSessionReservations {\n read(id: string, parentSessionId: string): { sessionId: string; cwd?: string };\n prepare(id: string, parentSessionId: string, cwd: string): Promise<{ sessionId: string; cwd: string }>;\n complete(id: string, parentSessionId: string): Promise<PoHubSessionScope>;\n}\n\n/** Authoritative execution state. Missing background coordination is unknown, not empty. */\nexport interface PoHubSessionExecutionState {\n readonly isIdle: boolean;\n readonly hasPendingMessages: boolean;\n readonly backgroundWork?: PoBackgroundWorkSnapshot;\n}\n\n/** Direct lifecycle owned by the canonical headless hub, never by a package transport. */\nexport interface PoHubSessionService {\n create(request: PoHubSessionCreateRequest): Promise<PoHubSessionScope>;\n close(sessionId: string): Promise<void>;\n isLive(sessionId: string): boolean;\n /** Reads a live child's ownership without starting a turn. */\n readExecutionState?(\n sessionId: string,\n options?: Pick<PoHubSessionPromptOptions, 'parentSessionId'>,\n ): Promise<PoHubSessionExecutionState>;\n /** Starts a turn in a live session, as if its user had submitted `text`. */\n prompt?(sessionId: string, text: string, options?: PoHubSessionPromptOptions): Promise<PoHubSessionPromptReceipt>;\n /** Aborts the live session's current turn. The session stays open. */\n abort?(sessionId: string, options?: Pick<PoHubSessionPromptOptions, 'parentSessionId'>): Promise<void>;\n /**\n * Adds guidance to a live session's running turn. A session with no turn in\n * progress takes it as its next message instead.\n */\n steer?(\n sessionId: string,\n message: string,\n options?: Pick<PoHubSessionPromptOptions, 'parentSessionId'>,\n ): Promise<void>;\n /**\n * Stops a live session's runtime and keeps it dormant: its history stays\n * readable where it is shown, and it can be woken later. A session that has\n * done its work no longer holds a model, tools and extensions in the host.\n */\n release?(sessionId: string, options?: Pick<PoHubSessionPromptOptions, 'parentSessionId'>): Promise<void>;\n readonly reservations?: PoHubSessionReservations;\n /** Provisions a host-reserved Git worktree child. This is not exposed to remote MCP clients. */\n provisionReservedWorktree?(request: PoHubReservedWorktreeRequest): Promise<PoHubSessionScope>;\n /** Core host hook. A Git provider registers its implementation while its channel is mounted. */\n registerReservedWorktreeProvisioner?(provisioner: PoHubReservedWorktreeProvisioner): () => void;\n /**\n * True when both live sessions have a direct parent-child relationship, or execute in the same\n * checkout. Remote conversations only qualify through the parent-child relationship.\n */\n canCommunicate?(sourceSessionId: string, targetSessionId: string): boolean;\n /** Core host hook. Session API construction removes this method before exposing the service to extensions. */\n bindCommunication?(sessionId: string): PoSessionCommunicationEndpoint;\n}\n\nexport interface PoHubSessionApiRequest {\n basePath: string;\n path: string;\n method: string;\n body?: string | Uint8Array<ArrayBuffer> | null;\n signal?: AbortSignal;\n /** Forwarded by the authenticated host, including content type and trace context. */\n headers?: RequestInit['headers'];\n}\n\nexport type PoComputerUseHostOperation = 'status' | 'targets' | 'activate' | 'observe' | 'act' | 'stop';\n\nexport interface PoComputerUseHostRequest {\n readonly operation: PoComputerUseHostOperation;\n readonly payload?: unknown;\n readonly signal?: AbortSignal;\n}\n\nexport interface PoComputerUseHostBinding {\n readonly available: boolean;\n /** Global opt-in, separate from the presence of a native host. */\n readonly enabled?: boolean;\n request(scope: PoHubSessionScope, request: PoComputerUseHostRequest): Promise<unknown>;\n /** Checks a proof injected by the owning Desktop process, never a renderer marker. */\n authorize?(headers: Headers): boolean;\n /** Pins a session to Desktop before asking for a native grant. Ownership is not persisted. */\n claimSession?(sessionId: string, headers?: Headers): void;\n ownsSession?(sessionId: string): boolean;\n /** Server-authenticated paired identity, checked against live native approval for this session. */\n authorizeSession?(sessionId: string, headers: Headers): boolean;\n authorizeRecording?(sessionId: string, headers: Headers): boolean;\n authorizeActivation?(headers: Headers): boolean;\n /** Own pending activation only, never general session control. */\n authorizePending?(sessionId: string, headers: Headers): boolean;\n revokeDevice?(deviceId: string): void;\n readRecording?(scope: PoHubSessionScope, artifactId: string, range: string): Promise<Response>;\n forgetSession?(sessionId: string): void;\n /** Without `sessionId` the listener hears every session's ownership change. */\n subscribe?(listener: () => void, sessionId?: string): () => void;\n close?(): void;\n}\n\n/** Narrow, host-bound access. An extension cannot select another session's identity. */\nexport interface PoComputerUseSessionAccess {\n readonly available: boolean;\n readonly enabled?: boolean;\n authorize(headers: Headers): boolean;\n authorizeRecording?(headers: Headers): boolean;\n authorizeActivation?(headers: Headers): boolean;\n authorizePending?(headers: Headers): boolean;\n claim(headers?: Headers): void;\n fetchRecording?(artifactId: string, range: string): Promise<Response>;\n subscribe(listener: () => void): () => void;\n}\n\nexport interface PoHubChannelConnection {\n connectionId: string;\n /** Host-verified native renderer proof, never copied from a channel payload. */\n desktopAuthorized?: boolean;\n /** Live session authorization evaluated by the host, never a client frame. */\n computerUseAuthorized?: boolean;\n}\n\nexport interface PoHubChannelHost {\n sessions(): readonly PoHubSessionScope[];\n /** Host facts and storage for trusted in-process channels, never client-supplied roots. */\n readonly homeDirectory?: string;\n readonly sessionStorage?: PoSessionStorageService;\n /** Canonical hub lifecycle for sessions created by channel commands. */\n sessionService?: PoHubSessionService;\n /** Same-process events emitted by session packages. */\n readonly directEvents: PoDirectEventBus;\n publish(sessionId: string, payload: unknown): void;\n publishToConnection?(connectionId: string, sessionId: string, payload: unknown): boolean;\n requestSessionApi(scope: PoHubSessionScope, request: PoHubSessionApiRequest): Promise<Response>;\n computerUse?: PoComputerUseHostBinding;\n onNotice(message: string): void;\n}\n\nexport interface PoHubChannelSource {\n payloadFor(scope: PoHubSessionScope): unknown;\n /** Read-only compact projection of already-owned state. Must not start work or add watchers. */\n homeFor?(scope: PoHubSessionScope): HomeProjection;\n sessionAdded?(scope: PoHubSessionScope): void;\n sessionRemoved?(sessionId: string): void;\n close(): void;\n}\n\nexport type PoHubChannelLifecycle = 'session' | 'hub';\n\nexport interface PoHubChannel {\n frameType: string;\n lifecycle?: PoHubChannelLifecycle;\n start(host: PoHubChannelHost): PoHubChannelSource;\n receiveWithoutSubscription?: boolean;\n receive?(scope: PoHubSessionScope, payload: unknown, connection: PoHubChannelConnection): void;\n disconnected?(connection: PoHubChannelConnection): void;\n}\n"],"mappings":";;;;;;;AAmFA,MAAa,mCAAmC;;;;;;;AAQhD,MAAa,yCAAyC;;AAGtD,MAAa,yCAAyC"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { PoBackgroundWorkSnapshot } from "./backgroundWork.mjs";
|
|
2
|
+
import { PoSessionStorageService } from "./platform.mjs";
|
|
2
3
|
import { HomeProjection } from "./home.mjs";
|
|
3
4
|
//#region src/schemas/hubChannel.d.ts
|
|
4
5
|
export interface PoHubChannelFrame {
|
|
@@ -260,6 +261,9 @@ export interface PoHubChannelConnection {
|
|
|
260
261
|
}
|
|
261
262
|
export interface PoHubChannelHost {
|
|
262
263
|
sessions(): readonly PoHubSessionScope[];
|
|
264
|
+
/** Host facts and storage for trusted in-process channels, never client-supplied roots. */
|
|
265
|
+
readonly homeDirectory?: string;
|
|
266
|
+
readonly sessionStorage?: PoSessionStorageService;
|
|
263
267
|
/** Canonical hub lifecycle for sessions created by channel commands. */
|
|
264
268
|
sessionService?: PoHubSessionService;
|
|
265
269
|
/** Same-process events emitted by session packages. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hubChannel.d.mts","names":[],"sources":["../../../src/schemas/hubChannel.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"hubChannel.d.mts","names":[],"sources":["../../../src/schemas/hubChannel.ts"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hubChannel.mjs","names":[],"sources":["../../../src/schemas/hubChannel.ts"],"sourcesContent":["import type { PoBackgroundWorkSnapshot } from './backgroundWork';\nimport type { HomeProjection } from './home';\n\nexport interface PoHubChannelFrame {\n type: string;\n sessionId: string;\n payload: unknown;\n}\n\n/** Same-process lifecycle bus shared by a host's session APIs and hub channels. */\nexport interface PoDirectEventSubscriptionOptions {\n /** Replay the most recent value published for this frame and session, when one exists. */\n readonly replayLatest?: boolean;\n}\n\nexport interface PoDirectEventBus {\n publish(frameType: string, sessionId: string, payload: unknown): void;\n subscribe(\n frameType: string,\n sessionId: string,\n listener: (payload: unknown) => void,\n options?: PoDirectEventSubscriptionOptions,\n ): () => void;\n /** Drop retained state for a session after its lifecycle ends. */\n clearSession?(sessionId: string): void;\n close(): void;\n}\n\n/**\n * The extension-agnostic baseline every surface gets for one session, computed once by the\n * session host. Extensions build on it instead of re-deriving roots and relations from cwd.\n */\nexport interface PoSessionContext {\n readonly sessionId: string;\n /** Persisted workspace id, shared by every session and member checkout of the workspace. */\n readonly workspaceId: string;\n /** The admitted workspace root. It owns configuration, composition and settings. */\n readonly workspaceRoot: string;\n /**\n * The checkout the session executes in. Equals workspaceRoot unless the session runs in a\n * member checkout, such as a worktree, which may live outside the workspace folder.\n */\n readonly checkoutRoot: string;\n readonly cwd: string;\n readonly parentSessionId?: string;\n /** The spawner's label for the session. Opaque: hosts never interpret it. */\n readonly provenance?: string;\n}\n\nexport interface PoHubSessionScope {\n sessionId: string;\n workspaceId?: string;\n cwd: string;\n /** Environment admitted for this session, when supplied by the host. */\n environment?: Readonly<Record<string, string | undefined>>;\n /** The session's baseline context, when its host knows its workspace. */\n sessionContext?: PoSessionContext;\n}\n\nexport interface PoHubReservedWorktreeRequest {\n readonly reservationId: string;\n readonly parentSessionId: string;\n readonly signal?: AbortSignal;\n}\n\nexport type PoHubReservedWorktreeProvisioner = (request: PoHubReservedWorktreeRequest) => Promise<PoHubSessionScope>;\n\n/** Selection axes a caller pins for a new session instead of the workspace defaults. */\nexport interface PoHubSessionSelection {\n readonly majorMode?: string;\n readonly minorModes?: readonly string[];\n readonly profile?: string;\n /** An empty list starts the session with no domains. */\n readonly domains?: readonly string[];\n}\n\n/**\n * Provenance of a session a workflow step opened.\n *\n * The step's conversation belongs to the workflow that ran it and is read in\n * that workflow's view, so the session rail leaves such sessions out.\n */\nexport const WORKFLOW_STEP_SESSION_PROVENANCE = 'workflow';\n\n/**\n * Provenance of a session opened to launch workflows for its parent.\n *\n * It picks and starts work, then closes; the runs it started belong to its\n * parent. Like a detached helper, it takes no row in the session rail.\n */\nexport const WORKFLOW_DISPATCHER_SESSION_PROVENANCE = 'workflow-dispatcher';\n\n/** Provenance of a conversation an external MCP client opened and drives. */\nexport const REMOTE_CONVERSATION_SESSION_PROVENANCE = 'remote-conversation';\n\nexport interface PoHubSessionCreateRequest {\n readonly cwd: string;\n readonly name: string;\n readonly parentSessionId?: string;\n readonly sessionProvenance?: string;\n readonly signal?: AbortSignal;\n /** Host-issued reservation, not a caller-chosen target session id. */\n readonly reservationId?: string;\n /** Pinned axes stay put when the workspace defaults change between turns. */\n readonly selection?: PoHubSessionSelection;\n /** Pi model selector, `provider/id`, validated like `--model`. */\n readonly model?: string;\n /** Pi thinking level, validated like `--thinking`. */\n readonly thinking?: string;\n /** Text appended to the session's system prompt, like `--append-system-prompt`. */\n readonly appendSystemPrompt?: string;\n /** Variables layered over the host environment for the new session and the tools it runs. */\n readonly environment?: Readonly<Record<string, string>>;\n /** The only tools the new session's agent may see or call, like a Team agent's `tools:` list. */\n readonly tools?: readonly string[];\n}\n\nexport interface PoHubSessionPromptOptions {\n readonly signal?: AbortSignal;\n /** Refuses the prompt unless the target is a direct child of this session. */\n readonly parentSessionId?: string;\n}\n\n/** A prompt the session admitted. `settled` resolves once the agent settles and rejects on a harness fault. */\nexport interface PoHubSessionPromptReceipt {\n readonly settled: Promise<void>;\n}\n\n/** Host-bound inter-session events. The source identity is attached by the hub, never by payload data. */\nexport interface PoSessionCommunicationEndpoint {\n readonly sessionId: string;\n /** Current human-readable session name, read live so renames are reflected. */\n readonly sessionName?: string;\n publish(targetSessionId: string, type: string, payload: unknown): boolean;\n subscribe(type: string, listener: (sourceSessionId: string, payload: unknown) => void): () => void;\n onPeerReady(listener: (peerSessionId: string) => void): () => void;\n /** Describes a live peer authorized to communicate, including same-checkout peers. */\n describePeer?(peerSessionId: string): PoSessionPeerDescription | undefined;\n close(): void;\n}\n\n/** How a session sees a peer it may message, so an agent can address it by the name a person uses. */\nexport interface PoSessionPeerDescription {\n readonly sessionId: string;\n readonly name: string;\n readonly profile?: string;\n /** Groups both sessions belong to; empty when related through parentage or checkout. */\n readonly sharedGroups: readonly string[];\n}\nexport interface PoPendingSessionSetup {\n readonly id: string;\n readonly name: string;\n readonly createdAt: string;\n readonly cwd?: string;\n readonly setupKind?: 'managed-worktree' | 'existing-directory';\n readonly status?: 'provisioning' | 'failed' | 'interrupted';\n readonly errorCode?: 'SESSION_WORKTREE_PROVISION_FAILED' | 'SESSION_UNAVAILABLE';\n}\n\n/**\n * One short line a session's extension publishes about work it runs for that\n * session, such as a background job. The host shows it on the session's rail\n * card but never interprets it.\n */\nexport interface PoSessionActivity {\n readonly label: string;\n /** The work needs the reader: the rail marks the card the way it marks a pending question. */\n readonly attention?: boolean;\n /** ISO 8601 start of the work; the rail appends the elapsed time. */\n readonly since?: string;\n}\n/** A host-owned setup can be fulfilled by any execution-directory provider. */\nexport interface PoHubSessionReservations {\n read(id: string, parentSessionId: string): { sessionId: string; cwd?: string };\n prepare(id: string, parentSessionId: string, cwd: string): Promise<{ sessionId: string; cwd: string }>;\n complete(id: string, parentSessionId: string): Promise<PoHubSessionScope>;\n}\n\n/** Authoritative execution state. Missing background coordination is unknown, not empty. */\nexport interface PoHubSessionExecutionState {\n readonly isIdle: boolean;\n readonly hasPendingMessages: boolean;\n readonly backgroundWork?: PoBackgroundWorkSnapshot;\n}\n\n/** Direct lifecycle owned by the canonical headless hub, never by a package transport. */\nexport interface PoHubSessionService {\n create(request: PoHubSessionCreateRequest): Promise<PoHubSessionScope>;\n close(sessionId: string): Promise<void>;\n isLive(sessionId: string): boolean;\n /** Reads a live child's ownership without starting a turn. */\n readExecutionState?(\n sessionId: string,\n options?: Pick<PoHubSessionPromptOptions, 'parentSessionId'>,\n ): Promise<PoHubSessionExecutionState>;\n /** Starts a turn in a live session, as if its user had submitted `text`. */\n prompt?(sessionId: string, text: string, options?: PoHubSessionPromptOptions): Promise<PoHubSessionPromptReceipt>;\n /** Aborts the live session's current turn. The session stays open. */\n abort?(sessionId: string, options?: Pick<PoHubSessionPromptOptions, 'parentSessionId'>): Promise<void>;\n /**\n * Adds guidance to a live session's running turn. A session with no turn in\n * progress takes it as its next message instead.\n */\n steer?(\n sessionId: string,\n message: string,\n options?: Pick<PoHubSessionPromptOptions, 'parentSessionId'>,\n ): Promise<void>;\n /**\n * Stops a live session's runtime and keeps it dormant: its history stays\n * readable where it is shown, and it can be woken later. A session that has\n * done its work no longer holds a model, tools and extensions in the host.\n */\n release?(sessionId: string, options?: Pick<PoHubSessionPromptOptions, 'parentSessionId'>): Promise<void>;\n readonly reservations?: PoHubSessionReservations;\n /** Provisions a host-reserved Git worktree child. This is not exposed to remote MCP clients. */\n provisionReservedWorktree?(request: PoHubReservedWorktreeRequest): Promise<PoHubSessionScope>;\n /** Core host hook. A Git provider registers its implementation while its channel is mounted. */\n registerReservedWorktreeProvisioner?(provisioner: PoHubReservedWorktreeProvisioner): () => void;\n /**\n * True when both live sessions have a direct parent-child relationship, or execute in the same\n * checkout. Remote conversations only qualify through the parent-child relationship.\n */\n canCommunicate?(sourceSessionId: string, targetSessionId: string): boolean;\n /** Core host hook. Session API construction removes this method before exposing the service to extensions. */\n bindCommunication?(sessionId: string): PoSessionCommunicationEndpoint;\n}\n\nexport interface PoHubSessionApiRequest {\n basePath: string;\n path: string;\n method: string;\n body?: string | Uint8Array<ArrayBuffer> | null;\n signal?: AbortSignal;\n /** Forwarded by the authenticated host, including content type and trace context. */\n headers?: RequestInit['headers'];\n}\n\nexport type PoComputerUseHostOperation = 'status' | 'targets' | 'activate' | 'observe' | 'act' | 'stop';\n\nexport interface PoComputerUseHostRequest {\n readonly operation: PoComputerUseHostOperation;\n readonly payload?: unknown;\n readonly signal?: AbortSignal;\n}\n\nexport interface PoComputerUseHostBinding {\n readonly available: boolean;\n /** Global opt-in, separate from the presence of a native host. */\n readonly enabled?: boolean;\n request(scope: PoHubSessionScope, request: PoComputerUseHostRequest): Promise<unknown>;\n /** Checks a proof injected by the owning Desktop process, never a renderer marker. */\n authorize?(headers: Headers): boolean;\n /** Pins a session to Desktop before asking for a native grant. Ownership is not persisted. */\n claimSession?(sessionId: string, headers?: Headers): void;\n ownsSession?(sessionId: string): boolean;\n /** Server-authenticated paired identity, checked against live native approval for this session. */\n authorizeSession?(sessionId: string, headers: Headers): boolean;\n authorizeRecording?(sessionId: string, headers: Headers): boolean;\n authorizeActivation?(headers: Headers): boolean;\n /** Own pending activation only, never general session control. */\n authorizePending?(sessionId: string, headers: Headers): boolean;\n revokeDevice?(deviceId: string): void;\n readRecording?(scope: PoHubSessionScope, artifactId: string, range: string): Promise<Response>;\n forgetSession?(sessionId: string): void;\n /** Without `sessionId` the listener hears every session's ownership change. */\n subscribe?(listener: () => void, sessionId?: string): () => void;\n close?(): void;\n}\n\n/** Narrow, host-bound access. An extension cannot select another session's identity. */\nexport interface PoComputerUseSessionAccess {\n readonly available: boolean;\n readonly enabled?: boolean;\n authorize(headers: Headers): boolean;\n authorizeRecording?(headers: Headers): boolean;\n authorizeActivation?(headers: Headers): boolean;\n authorizePending?(headers: Headers): boolean;\n claim(headers?: Headers): void;\n fetchRecording?(artifactId: string, range: string): Promise<Response>;\n subscribe(listener: () => void): () => void;\n}\n\nexport interface PoHubChannelConnection {\n connectionId: string;\n /** Host-verified native renderer proof, never copied from a channel payload. */\n desktopAuthorized?: boolean;\n /** Live session authorization evaluated by the host, never a client frame. */\n computerUseAuthorized?: boolean;\n}\n\nexport interface PoHubChannelHost {\n sessions(): readonly PoHubSessionScope[];\n /** Canonical hub lifecycle for sessions created by channel commands. */\n sessionService?: PoHubSessionService;\n /** Same-process events emitted by session packages. */\n readonly directEvents: PoDirectEventBus;\n publish(sessionId: string, payload: unknown): void;\n publishToConnection?(connectionId: string, sessionId: string, payload: unknown): boolean;\n requestSessionApi(scope: PoHubSessionScope, request: PoHubSessionApiRequest): Promise<Response>;\n computerUse?: PoComputerUseHostBinding;\n onNotice(message: string): void;\n}\n\nexport interface PoHubChannelSource {\n payloadFor(scope: PoHubSessionScope): unknown;\n /** Read-only compact projection of already-owned state. Must not start work or add watchers. */\n homeFor?(scope: PoHubSessionScope): HomeProjection;\n sessionAdded?(scope: PoHubSessionScope): void;\n sessionRemoved?(sessionId: string): void;\n close(): void;\n}\n\nexport type PoHubChannelLifecycle = 'session' | 'hub';\n\nexport interface PoHubChannel {\n frameType: string;\n lifecycle?: PoHubChannelLifecycle;\n start(host: PoHubChannelHost): PoHubChannelSource;\n receiveWithoutSubscription?: boolean;\n receive?(scope: PoHubSessionScope, payload: unknown, connection: PoHubChannelConnection): void;\n disconnected?(connection: PoHubChannelConnection): void;\n}\n"],"mappings":";;;;;;;AAkFA,MAAa,mCAAmC;;;;;;;AAQhD,MAAa,yCAAyC;;AAGtD,MAAa,yCAAyC"}
|
|
1
|
+
{"version":3,"file":"hubChannel.mjs","names":[],"sources":["../../../src/schemas/hubChannel.ts"],"sourcesContent":["import type { PoBackgroundWorkSnapshot } from './backgroundWork';\nimport type { HomeProjection } from './home';\nimport type { PoSessionStorageService } from './platform';\n\nexport interface PoHubChannelFrame {\n type: string;\n sessionId: string;\n payload: unknown;\n}\n\n/** Same-process lifecycle bus shared by a host's session APIs and hub channels. */\nexport interface PoDirectEventSubscriptionOptions {\n /** Replay the most recent value published for this frame and session, when one exists. */\n readonly replayLatest?: boolean;\n}\n\nexport interface PoDirectEventBus {\n publish(frameType: string, sessionId: string, payload: unknown): void;\n subscribe(\n frameType: string,\n sessionId: string,\n listener: (payload: unknown) => void,\n options?: PoDirectEventSubscriptionOptions,\n ): () => void;\n /** Drop retained state for a session after its lifecycle ends. */\n clearSession?(sessionId: string): void;\n close(): void;\n}\n\n/**\n * The extension-agnostic baseline every surface gets for one session, computed once by the\n * session host. Extensions build on it instead of re-deriving roots and relations from cwd.\n */\nexport interface PoSessionContext {\n readonly sessionId: string;\n /** Persisted workspace id, shared by every session and member checkout of the workspace. */\n readonly workspaceId: string;\n /** The admitted workspace root. It owns configuration, composition and settings. */\n readonly workspaceRoot: string;\n /**\n * The checkout the session executes in. Equals workspaceRoot unless the session runs in a\n * member checkout, such as a worktree, which may live outside the workspace folder.\n */\n readonly checkoutRoot: string;\n readonly cwd: string;\n readonly parentSessionId?: string;\n /** The spawner's label for the session. Opaque: hosts never interpret it. */\n readonly provenance?: string;\n}\n\nexport interface PoHubSessionScope {\n sessionId: string;\n workspaceId?: string;\n cwd: string;\n /** Environment admitted for this session, when supplied by the host. */\n environment?: Readonly<Record<string, string | undefined>>;\n /** The session's baseline context, when its host knows its workspace. */\n sessionContext?: PoSessionContext;\n}\n\nexport interface PoHubReservedWorktreeRequest {\n readonly reservationId: string;\n readonly parentSessionId: string;\n readonly signal?: AbortSignal;\n}\n\nexport type PoHubReservedWorktreeProvisioner = (request: PoHubReservedWorktreeRequest) => Promise<PoHubSessionScope>;\n\n/** Selection axes a caller pins for a new session instead of the workspace defaults. */\nexport interface PoHubSessionSelection {\n readonly majorMode?: string;\n readonly minorModes?: readonly string[];\n readonly profile?: string;\n /** An empty list starts the session with no domains. */\n readonly domains?: readonly string[];\n}\n\n/**\n * Provenance of a session a workflow step opened.\n *\n * The step's conversation belongs to the workflow that ran it and is read in\n * that workflow's view, so the session rail leaves such sessions out.\n */\nexport const WORKFLOW_STEP_SESSION_PROVENANCE = 'workflow';\n\n/**\n * Provenance of a session opened to launch workflows for its parent.\n *\n * It picks and starts work, then closes; the runs it started belong to its\n * parent. Like a detached helper, it takes no row in the session rail.\n */\nexport const WORKFLOW_DISPATCHER_SESSION_PROVENANCE = 'workflow-dispatcher';\n\n/** Provenance of a conversation an external MCP client opened and drives. */\nexport const REMOTE_CONVERSATION_SESSION_PROVENANCE = 'remote-conversation';\n\nexport interface PoHubSessionCreateRequest {\n readonly cwd: string;\n readonly name: string;\n readonly parentSessionId?: string;\n readonly sessionProvenance?: string;\n readonly signal?: AbortSignal;\n /** Host-issued reservation, not a caller-chosen target session id. */\n readonly reservationId?: string;\n /** Pinned axes stay put when the workspace defaults change between turns. */\n readonly selection?: PoHubSessionSelection;\n /** Pi model selector, `provider/id`, validated like `--model`. */\n readonly model?: string;\n /** Pi thinking level, validated like `--thinking`. */\n readonly thinking?: string;\n /** Text appended to the session's system prompt, like `--append-system-prompt`. */\n readonly appendSystemPrompt?: string;\n /** Variables layered over the host environment for the new session and the tools it runs. */\n readonly environment?: Readonly<Record<string, string>>;\n /** The only tools the new session's agent may see or call, like a Team agent's `tools:` list. */\n readonly tools?: readonly string[];\n}\n\nexport interface PoHubSessionPromptOptions {\n readonly signal?: AbortSignal;\n /** Refuses the prompt unless the target is a direct child of this session. */\n readonly parentSessionId?: string;\n}\n\n/** A prompt the session admitted. `settled` resolves once the agent settles and rejects on a harness fault. */\nexport interface PoHubSessionPromptReceipt {\n readonly settled: Promise<void>;\n}\n\n/** Host-bound inter-session events. The source identity is attached by the hub, never by payload data. */\nexport interface PoSessionCommunicationEndpoint {\n readonly sessionId: string;\n /** Current human-readable session name, read live so renames are reflected. */\n readonly sessionName?: string;\n publish(targetSessionId: string, type: string, payload: unknown): boolean;\n subscribe(type: string, listener: (sourceSessionId: string, payload: unknown) => void): () => void;\n onPeerReady(listener: (peerSessionId: string) => void): () => void;\n /** Describes a live peer authorized to communicate, including same-checkout peers. */\n describePeer?(peerSessionId: string): PoSessionPeerDescription | undefined;\n close(): void;\n}\n\n/** How a session sees a peer it may message, so an agent can address it by the name a person uses. */\nexport interface PoSessionPeerDescription {\n readonly sessionId: string;\n readonly name: string;\n readonly profile?: string;\n /** Groups both sessions belong to; empty when related through parentage or checkout. */\n readonly sharedGroups: readonly string[];\n}\nexport interface PoPendingSessionSetup {\n readonly id: string;\n readonly name: string;\n readonly createdAt: string;\n readonly cwd?: string;\n readonly setupKind?: 'managed-worktree' | 'existing-directory';\n readonly status?: 'provisioning' | 'failed' | 'interrupted';\n readonly errorCode?: 'SESSION_WORKTREE_PROVISION_FAILED' | 'SESSION_UNAVAILABLE';\n}\n\n/**\n * One short line a session's extension publishes about work it runs for that\n * session, such as a background job. The host shows it on the session's rail\n * card but never interprets it.\n */\nexport interface PoSessionActivity {\n readonly label: string;\n /** The work needs the reader: the rail marks the card the way it marks a pending question. */\n readonly attention?: boolean;\n /** ISO 8601 start of the work; the rail appends the elapsed time. */\n readonly since?: string;\n}\n/** A host-owned setup can be fulfilled by any execution-directory provider. */\nexport interface PoHubSessionReservations {\n read(id: string, parentSessionId: string): { sessionId: string; cwd?: string };\n prepare(id: string, parentSessionId: string, cwd: string): Promise<{ sessionId: string; cwd: string }>;\n complete(id: string, parentSessionId: string): Promise<PoHubSessionScope>;\n}\n\n/** Authoritative execution state. Missing background coordination is unknown, not empty. */\nexport interface PoHubSessionExecutionState {\n readonly isIdle: boolean;\n readonly hasPendingMessages: boolean;\n readonly backgroundWork?: PoBackgroundWorkSnapshot;\n}\n\n/** Direct lifecycle owned by the canonical headless hub, never by a package transport. */\nexport interface PoHubSessionService {\n create(request: PoHubSessionCreateRequest): Promise<PoHubSessionScope>;\n close(sessionId: string): Promise<void>;\n isLive(sessionId: string): boolean;\n /** Reads a live child's ownership without starting a turn. */\n readExecutionState?(\n sessionId: string,\n options?: Pick<PoHubSessionPromptOptions, 'parentSessionId'>,\n ): Promise<PoHubSessionExecutionState>;\n /** Starts a turn in a live session, as if its user had submitted `text`. */\n prompt?(sessionId: string, text: string, options?: PoHubSessionPromptOptions): Promise<PoHubSessionPromptReceipt>;\n /** Aborts the live session's current turn. The session stays open. */\n abort?(sessionId: string, options?: Pick<PoHubSessionPromptOptions, 'parentSessionId'>): Promise<void>;\n /**\n * Adds guidance to a live session's running turn. A session with no turn in\n * progress takes it as its next message instead.\n */\n steer?(\n sessionId: string,\n message: string,\n options?: Pick<PoHubSessionPromptOptions, 'parentSessionId'>,\n ): Promise<void>;\n /**\n * Stops a live session's runtime and keeps it dormant: its history stays\n * readable where it is shown, and it can be woken later. A session that has\n * done its work no longer holds a model, tools and extensions in the host.\n */\n release?(sessionId: string, options?: Pick<PoHubSessionPromptOptions, 'parentSessionId'>): Promise<void>;\n readonly reservations?: PoHubSessionReservations;\n /** Provisions a host-reserved Git worktree child. This is not exposed to remote MCP clients. */\n provisionReservedWorktree?(request: PoHubReservedWorktreeRequest): Promise<PoHubSessionScope>;\n /** Core host hook. A Git provider registers its implementation while its channel is mounted. */\n registerReservedWorktreeProvisioner?(provisioner: PoHubReservedWorktreeProvisioner): () => void;\n /**\n * True when both live sessions have a direct parent-child relationship, or execute in the same\n * checkout. Remote conversations only qualify through the parent-child relationship.\n */\n canCommunicate?(sourceSessionId: string, targetSessionId: string): boolean;\n /** Core host hook. Session API construction removes this method before exposing the service to extensions. */\n bindCommunication?(sessionId: string): PoSessionCommunicationEndpoint;\n}\n\nexport interface PoHubSessionApiRequest {\n basePath: string;\n path: string;\n method: string;\n body?: string | Uint8Array<ArrayBuffer> | null;\n signal?: AbortSignal;\n /** Forwarded by the authenticated host, including content type and trace context. */\n headers?: RequestInit['headers'];\n}\n\nexport type PoComputerUseHostOperation = 'status' | 'targets' | 'activate' | 'observe' | 'act' | 'stop';\n\nexport interface PoComputerUseHostRequest {\n readonly operation: PoComputerUseHostOperation;\n readonly payload?: unknown;\n readonly signal?: AbortSignal;\n}\n\nexport interface PoComputerUseHostBinding {\n readonly available: boolean;\n /** Global opt-in, separate from the presence of a native host. */\n readonly enabled?: boolean;\n request(scope: PoHubSessionScope, request: PoComputerUseHostRequest): Promise<unknown>;\n /** Checks a proof injected by the owning Desktop process, never a renderer marker. */\n authorize?(headers: Headers): boolean;\n /** Pins a session to Desktop before asking for a native grant. Ownership is not persisted. */\n claimSession?(sessionId: string, headers?: Headers): void;\n ownsSession?(sessionId: string): boolean;\n /** Server-authenticated paired identity, checked against live native approval for this session. */\n authorizeSession?(sessionId: string, headers: Headers): boolean;\n authorizeRecording?(sessionId: string, headers: Headers): boolean;\n authorizeActivation?(headers: Headers): boolean;\n /** Own pending activation only, never general session control. */\n authorizePending?(sessionId: string, headers: Headers): boolean;\n revokeDevice?(deviceId: string): void;\n readRecording?(scope: PoHubSessionScope, artifactId: string, range: string): Promise<Response>;\n forgetSession?(sessionId: string): void;\n /** Without `sessionId` the listener hears every session's ownership change. */\n subscribe?(listener: () => void, sessionId?: string): () => void;\n close?(): void;\n}\n\n/** Narrow, host-bound access. An extension cannot select another session's identity. */\nexport interface PoComputerUseSessionAccess {\n readonly available: boolean;\n readonly enabled?: boolean;\n authorize(headers: Headers): boolean;\n authorizeRecording?(headers: Headers): boolean;\n authorizeActivation?(headers: Headers): boolean;\n authorizePending?(headers: Headers): boolean;\n claim(headers?: Headers): void;\n fetchRecording?(artifactId: string, range: string): Promise<Response>;\n subscribe(listener: () => void): () => void;\n}\n\nexport interface PoHubChannelConnection {\n connectionId: string;\n /** Host-verified native renderer proof, never copied from a channel payload. */\n desktopAuthorized?: boolean;\n /** Live session authorization evaluated by the host, never a client frame. */\n computerUseAuthorized?: boolean;\n}\n\nexport interface PoHubChannelHost {\n sessions(): readonly PoHubSessionScope[];\n /** Host facts and storage for trusted in-process channels, never client-supplied roots. */\n readonly homeDirectory?: string;\n readonly sessionStorage?: PoSessionStorageService;\n /** Canonical hub lifecycle for sessions created by channel commands. */\n sessionService?: PoHubSessionService;\n /** Same-process events emitted by session packages. */\n readonly directEvents: PoDirectEventBus;\n publish(sessionId: string, payload: unknown): void;\n publishToConnection?(connectionId: string, sessionId: string, payload: unknown): boolean;\n requestSessionApi(scope: PoHubSessionScope, request: PoHubSessionApiRequest): Promise<Response>;\n computerUse?: PoComputerUseHostBinding;\n onNotice(message: string): void;\n}\n\nexport interface PoHubChannelSource {\n payloadFor(scope: PoHubSessionScope): unknown;\n /** Read-only compact projection of already-owned state. Must not start work or add watchers. */\n homeFor?(scope: PoHubSessionScope): HomeProjection;\n sessionAdded?(scope: PoHubSessionScope): void;\n sessionRemoved?(sessionId: string): void;\n close(): void;\n}\n\nexport type PoHubChannelLifecycle = 'session' | 'hub';\n\nexport interface PoHubChannel {\n frameType: string;\n lifecycle?: PoHubChannelLifecycle;\n start(host: PoHubChannelHost): PoHubChannelSource;\n receiveWithoutSubscription?: boolean;\n receive?(scope: PoHubSessionScope, payload: unknown, connection: PoHubChannelConnection): void;\n disconnected?(connection: PoHubChannelConnection): void;\n}\n"],"mappings":";;;;;;;AAmFA,MAAa,mCAAmC;;;;;;;AAQhD,MAAa,yCAAyC;;AAGtD,MAAa,yCAAyC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"packageApi.cjs","names":[],"sources":["../../../src/schemas/packageApi.ts"],"sourcesContent":["/**\n * The HTTP surface a package offers its host.\n *\n * A server plugin registers one with its host. The host mounts it under the API\n * route prefix, and the package writes routes relative to that mount.\n *\n * The handler is a plain fetch callback so no host and no package is committed\n * to one HTTP framework; a Hono app satisfies it through `app.fetch`.\n */\n\nimport type {\n PoComputerUseSessionAccess,\n PoDirectEventBus,\n PoHubSessionService,\n PoSessionCommunicationEndpoint,\n PoSessionActivity,\n PoSessionContext,\n} from './hubChannel';\nimport type { PoMcpProjection } from './mcpProjection';\n/** The host-owned sync view a repository-scoped package API may inspect. */\nexport interface PoRepositorySyncView {\n fresh: boolean;\n reasons: string[];\n /** True while a background sync that may prepare what `reasons` names is running. */\n syncing?: boolean;\n mcpProjection?: PoMcpProjection;\n}\n\n/** Where an API runs: inside one session's server, or in the machine-wide hub. */\nexport type PoApiScope = 'global' | 'workspace' | 'session';\n\nexport const PO_API_SCOPES: readonly PoApiScope[] = ['global', 'workspace', 'session'];\n\n/** Identity of an independently mounted plugin host. */\nexport type PoApiMount =\n | { scope: 'global' }\n | { scope: 'workspace'; workspaceId: string }\n | { scope: 'session'; sessionId: string };\n\n/** Immutable browser contribution generation paired with a server mount. */\nexport interface PoWebComposition {\n id: string;\n scope: PoApiScope;\n revision: number;\n manifestUrl: string;\n rawAssetBaseUrl: string;\n verifiedAssetBaseUrl: string;\n /** `[slot, entry]` for each of this mount's plugin copies, the entry an absolute path below the asset prefixes. */\n pluginEntries: [string, string][];\n /** Every signed file this mount's slots can load, absolute below the asset prefixes. */\n assetPaths: string[];\n /** Per-plugin stylesheets of this mount's plugins only, so other mounts' classes never apply here. */\n stylePaths: string[];\n channels: string[];\n /** The slots resolved for this mount; the shared build may hold more. */\n plugins: string[];\n}\n\n/**\n * Immutable native contribution generation paired with a server mount. One signed CommonJS module at\n * `entryPath`, served through the same immutable plugin routes as web compositions.\n */\nexport interface PoNativeComposition {\n id: string;\n scope: PoApiScope;\n revision: number;\n manifestUrl: string;\n rawAssetBaseUrl: string;\n /** Always `/composition.js`. */\n entryPath: string;\n channels: string[];\n /** The `poNative.pluginId` values resolved for this mount; the shell installs only these. */\n plugins: string[];\n}\n\n/** Canonical public prefix. Scope selection never falls through to a parent. */\nexport function poApiMountPath(mount: PoApiMount & { workspaceId?: string }): string {\n if (mount.scope === 'global') return '/api/plugins';\n if (mount.scope === 'workspace') return `/api/workspaces/${encodeURIComponent(mount.workspaceId)}/plugins`;\n if (!mount.workspaceId) throw new Error('A session API path requires its workspace identity.');\n return `/api/workspaces/${encodeURIComponent(mount.workspaceId)}/sessions/${encodeURIComponent(mount.sessionId)}/plugins`;\n}\n\n/** Scope addressed by a public WebSocket upgrade. */\nexport type PoSocketMount =\n | { scope: 'global' }\n | { scope: 'workspace'; workspaceId: string }\n | { scope: 'session'; workspaceId: string; sessionId: string };\n\n/** Only canonical resource paths may select a protocol listener. */\nexport function parsePoSocketPath(pathname: string): PoSocketMount | undefined {\n if (pathname === '/api/ws') return { scope: 'global' };\n const match = /^\\/api\\/workspaces\\/([^/]+)(?:\\/sessions\\/([^/]+))?\\/ws$/u.exec(pathname);\n if (!match) return undefined;\n try {\n const workspaceId = decodeURIComponent(match[1]);\n return match[2] === undefined\n ? { scope: 'workspace', workspaceId }\n : { scope: 'session', workspaceId, sessionId: decodeURIComponent(match[2]) };\n } catch {\n return undefined;\n }\n}\n\n/** The segment an API is mounted under, below this prefix. */\nexport const PO_API_ROUTE_PREFIX = '/api/plugins';\n/** Selects the hub API bundle that owns the named cockpit session. */\nexport const PO_HUB_API_SESSION_QUERY_PARAM = 'hubSession';\n\n/** Trusted caller headers written only by the cockpit-to-session proxy. */\nexport const PO_API_CALLER_LOCALITY_HEADER = 'x-po-api-caller-locality';\nexport const PO_API_CALLER_DEVICE_ID_HEADER = 'x-po-api-caller-device-id';\nexport const PO_API_CALLER_STEP_UP_HEADER = 'x-po-api-caller-step-up';\nexport const PO_API_CALLER_HEADERS = [\n PO_API_CALLER_LOCALITY_HEADER,\n PO_API_CALLER_DEVICE_ID_HEADER,\n PO_API_CALLER_STEP_UP_HEADER,\n] as const;\n\nexport type PoApiCallerStepUp = 'not-required' | 'verified' | 'unavailable';\nexport type PoApiCaller =\n | { locality: 'local'; stepUp: 'not-required' }\n | { locality: 'remote'; deviceId: string; stepUp: PoApiCallerStepUp };\n\n/** Reads the proxy-authenticated caller identity, rejecting partial or contradictory stamps. */\nexport function poApiCallerFrom(headers: Headers): PoApiCaller | undefined {\n const locality = headers.get(PO_API_CALLER_LOCALITY_HEADER);\n const deviceId = headers.get(PO_API_CALLER_DEVICE_ID_HEADER);\n const stepUp = headers.get(PO_API_CALLER_STEP_UP_HEADER);\n if (locality === 'local') {\n return deviceId === null && stepUp === 'not-required' ? { locality, stepUp } : undefined;\n }\n if (\n locality === 'remote' &&\n deviceId !== null &&\n deviceId !== '' &&\n (stepUp === 'not-required' || stepUp === 'verified' || stepUp === 'unavailable')\n ) {\n return { locality, deviceId, stepUp };\n }\n return undefined;\n}\n/**\n * A browser-reachable OAuth redirect the host serves on its own listener.\n *\n * A package brokering third-party OAuth cannot use a loopback redirect when the\n * operator's browser is on another machine: `127.0.0.1` resolves to whichever\n * machine the browser runs on. The host owns a listener that is reachable from\n * wherever the cockpit is being used, so it lends that instead of the package\n * opening a port of its own.\n */\nexport interface PoOAuthRedirect {\n /** Absolute URL to register as the redirect target, already origin-correct. */\n readonly redirectUri: string;\n /**\n * Accept redirects carrying this state. Must complete before the\n * authorization URL is surfaced, or the redirect races its own reservation.\n */\n reserve(state: string, timeoutMs?: number): Promise<void>;\n /** Resolves once the redirect carrying this state arrives. */\n wait(state: string, timeoutMs?: number): Promise<{ code: string; state: string }>;\n /** Drops a reservation whose flow ended without a redirect. */\n cancel(state: string): void;\n}\n\n/** An exact, host-owned receipt address. Provider IDs are not event cursor positions. */\nexport interface PoRequestReceiptKey {\n namespace: string;\n activationId: string;\n requestId: string;\n}\n\nexport interface PoRequestReceipt extends PoRequestReceiptKey {\n fingerprint: string;\n destination: string;\n transactionId: string;\n outcome: 'reserved' | 'admitted' | 'rejected' | 'uncertain';\n}\n\nexport interface PoRequestReceiptReservation extends PoRequestReceiptKey {\n /** Lowercase SHA-256 of the authoritative request text, never the full transcript. */\n fingerprint: string;\n destination: string;\n transactionId: string;\n}\n\nexport type PoRequestReceiptReserveResult =\n | { kind: 'reserved'; token: string }\n | { kind: 'existing'; receipt: PoRequestReceipt }\n | { kind: 'conflict'; receipt: PoRequestReceipt };\n\n/** A global-only receipt capability. A reservation is not an execution receipt. */\nexport interface PoRequestReceipts {\n reserve(request: PoRequestReceiptReservation): Promise<PoRequestReceiptReserveResult>;\n lookup(key: PoRequestReceiptKey): Promise<PoRequestReceipt | undefined>;\n finish(\n request: PoRequestReceiptKey & { token: string; outcome: 'admitted' | 'rejected' | 'uncertain' },\n ): Promise<PoRequestReceipt>;\n}\n\n/** Permit returned for expensive local work. Calling it releases the slot. */\nexport interface PoHostExecutionPermit {\n (): void;\n attachProcess?(pid: number): Promise<void>;\n}\n\n/** Host-wide admission for expensive local work. Release only after the owned process exits. */\nexport interface PoHostExecutionBudget {\n acquire(signal?: AbortSignal): Promise<PoHostExecutionPermit>;\n getSnapshot(): Readonly<{ running: number; queued: number; limit: number }>;\n}\n\n/** Synchronous host-owned exclusion across media APIs mounted at different scopes. */\nexport interface PoHostMediaArbitration {\n register(busy: () => boolean): () => void;\n available(busy: () => boolean): boolean;\n}\n\n/** One host's paired agent registrations, shared across its global and session mounts. */\nexport interface PoPeerAgentRegistry {\n register(sessionId: string, agent: { fetch(request: Request): Promise<Response> }, hubToken: string): () => void;\n get(sessionId: string): { fetch(request: Request): Promise<Response>; hubToken: string } | undefined;\n}\n\n/** One agent that edits files: a hub session or an in-process child run. */\nexport interface PoEditPresenceAgent {\n /** `session:<id>` or `run:<runId>`. Unique across the host. */\n readonly key: string;\n /** Read when a note is rendered, so a name registered after the edit still shows. */\n readonly label: () => string;\n /** Hub session id other agents can reach with intercom. */\n readonly contact: string;\n readonly isLive: () => boolean;\n}\n\nexport interface PoEditPresenceEntry {\n readonly agent: PoEditPresenceAgent;\n /** `@file` tag of the bytes this agent's last successful edit or write left behind. */\n readonly tag: string;\n readonly at: number;\n}\n\n/**\n * Host-wide record of the last edit each live agent made to a file, keyed by realpath then agent key.\n * Owners delete their entries when they dispose, so no callback outlives its session or run.\n */\nexport type PoEditPresenceLedger = Map<string, Map<string, PoEditPresenceEntry>>;\n\n/** Why shareFile rejects while the host has no public tunnel origin. */\nexport const PO_SHARE_FILE_REMOTE_OFF_MESSAGE =\n 'Remote access is off, so Po cannot share files with remote MCP servers. Turn it on and retry.';\n\n/**\n * A file published at a short-lived public tunnel URL: 10 minutes, 3 downloads, and gone\n * when the tunnel revision changes. Call revoke as soon as the consumer is done with it.\n */\nexport interface PoSharedFile {\n /** Bearer link; never log or persist it. */\n url: string;\n fileName: string;\n mimeType: string;\n size: number;\n /** Expiry as epoch milliseconds. */\n expiresAt: number;\n maxDownloads: number;\n /** Idempotent. */\n revoke(): void;\n}\n\n/** What the host tells an API about itself when it starts. */\nexport interface PoApiContext {\n scope: PoApiScope;\n /** Stable, opaque workspace id, shared by every session and member checkout of the workspace. */\n workspaceId?: string;\n /**\n * The admitted workspace root for a workspace mount. For a session mount it is the checkout\n * the session runs in; read sessionContext for both roots. Absent from global mounts.\n */\n workspaceRoot?: string;\n /** The session's baseline context; present on session mounts whose host knows its workspace. */\n sessionContext?: PoSessionContext;\n /** Explicit host home, never selected by a remote request. */\n homeDirectory?: string;\n /** The session this host serves; absent for a hub-scoped API. */\n sessionId?: string;\n /** The session's working directory; absent for a hub-scoped API. */\n cwd?: string;\n /** Session environment admitted by the server, never supplied by remote clients. */\n environment?: Readonly<Record<string, string | undefined>>;\n /** Shared only with child processes in this session, never with remote API clients. */\n internalToken?: string;\n /** Shared only with the cockpit hub for privileged cross-session coordination. */\n hubToken?: string;\n /**\n * Resolves a hub-issued opaque repository id to an admitted canonical root.\n * Hub APIs must never accept a browser-supplied filesystem path instead.\n */\n resolveRepository?(repositoryId: string): string | undefined;\n /** Reads the admitted repository's sync projection without exposing its state path. */\n readRepositorySync?(\n repositoryId: string,\n ): Promise<PoRepositorySyncView | undefined> | PoRepositorySyncView | undefined;\n /** Admitted workspaces available to this mount. */\n repositories?(): readonly { id: string; name: string; path: string; active: boolean }[];\n /** Publish a successful config write to the owning mount's refresh lifecycle. */\n configurationChanged?(): void;\n /**\n * Borrows the hub's OAuth redirect surface. Undefined when the hub cannot\n * currently serve one, in which case the package keeps its own behaviour.\n */\n oauthRedirect?(): PoOAuthRedirect | undefined;\n /** Canonical in-process lifecycle for sessions created by this host. */\n sessionService?: PoHubSessionService;\n /** Host-bound, authenticated inter-session event endpoint for this session. */\n sessionCommunication?: PoSessionCommunicationEndpoint;\n /** Same-process events shared by session APIs and hub channels. */\n directEvents?: PoDirectEventBus;\n /**\n * Publishes this session's activity line to every page's rail; undefined clears it.\n * Session mounts only. The last publisher wins.\n */\n publishActivity?(activity: PoSessionActivity | undefined): void;\n /** Trusted in-process dispatch to an explicitly selected mounted API. No browser authentication is performed here. */\n requestApi?(mount: PoApiMount, basePath: string, request: Request): Promise<Response>;\n /** Present only on a session mounted by an authenticated Desktop host. */\n computerUse?: PoComputerUseSessionAccess;\n /** Deliver a typed method to the channel serving a session this mount reaches, retaining the caller's connection identity. */\n receiveChannel?(sessionId: string, frameType: string, payload: unknown, connectionId: string): boolean;\n /** Host-owned replay evidence, supplied only on the global mount. Never exposed to browsers or agents. */\n requestReceipts?: PoRequestReceipts;\n /** One host's exclusive media activity, shared across global and session scopes. */\n mediaArbitration?: PoHostMediaArbitration;\n /** One host-wide heavy-job budget, not a separate budget for every session. */\n executionBudget?: PoHostExecutionBudget;\n /** One host-wide edit presence ledger, shared by every session mount. */\n editPresence?: PoEditPresenceLedger;\n /** Paired agents belonging to this host only. */\n peerAgents?: PoPeerAgentRegistry;\n /** Machine-owned Remote Control service, mounted only by Po's own global server plugin. */\n remoteControl?: { fetch(request: Request): Promise<Response> };\n /**\n * Publishes a file from this session's cwd or attachments at a short-lived tunnel URL.\n * Session mounts only; rejects with PO_SHARE_FILE_REMOTE_OFF_MESSAGE while remote access is off.\n * The host asks no consent: the caller must obtain it before passing the URL on.\n */\n shareFile?(path: string, label: string): Promise<PoSharedFile>;\n onNotice(message: string): void;\n}\n\n/**\n * One running surface. The host strips the mount prefix before calling, so\n * routes are declared relative ('/runners/:id/log') and a package never\n * repeats where it was mounted.\n */\nexport interface PoApiHandler {\n fetch(request: Request): Response | Promise<Response>;\n close(): void;\n}\n\nexport interface PoApi {\n /** Segment under /api/plugins/; globally unique across loaded packages. */\n basePath: string;\n start(context: PoApiContext): PoApiHandler;\n}\n"],"mappings":";AA+BA,MAAa,gBAAuC;CAAC;CAAU;CAAa;AAAS;;AA6CrF,SAAgB,eAAe,OAAsD;CACnF,IAAI,MAAM,UAAU,UAAU,OAAO;CACrC,IAAI,MAAM,UAAU,aAAa,OAAO,mBAAmB,mBAAmB,MAAM,WAAW,EAAE;CACjG,IAAI,CAAC,MAAM,aAAa,MAAM,IAAI,MAAM,qDAAqD;CAC7F,OAAO,mBAAmB,mBAAmB,MAAM,WAAW,EAAE,YAAY,mBAAmB,MAAM,SAAS,EAAE;AAClH;;AASA,SAAgB,kBAAkB,UAA6C;CAC7E,IAAI,aAAa,WAAW,OAAO,EAAE,OAAO,SAAS;CACrD,MAAM,QAAQ,4DAA4D,KAAK,QAAQ;CACvF,IAAI,CAAC,OAAO,OAAO,KAAA;CACnB,IAAI;EACF,MAAM,cAAc,mBAAmB,MAAM,EAAE;EAC/C,OAAO,MAAM,OAAO,KAAA,IAChB;GAAE,OAAO;GAAa;EAAY,IAClC;GAAE,OAAO;GAAW;GAAa,WAAW,mBAAmB,MAAM,EAAE;EAAE;CAC/E,QAAQ;EACN;CACF;AACF;;AAGA,MAAa,sBAAsB;;AAEnC,MAAa,iCAAiC;;AAG9C,MAAa,gCAAgC;AAC7C,MAAa,iCAAiC;AAC9C,MAAa,+BAA+B;AAC5C,MAAa,wBAAwB;CACnC;CACA;CACA;AACF;;AAQA,SAAgB,gBAAgB,SAA2C;CACzE,MAAM,WAAW,QAAQ,IAAI,6BAA6B;CAC1D,MAAM,WAAW,QAAQ,IAAI,8BAA8B;CAC3D,MAAM,SAAS,QAAQ,IAAI,4BAA4B;CACvD,IAAI,aAAa,SACf,OAAO,aAAa,QAAQ,WAAW,iBAAiB;EAAE;EAAU;CAAO,IAAI,KAAA;CAEjF,IACE,aAAa,YACb,aAAa,QACb,aAAa,OACZ,WAAW,kBAAkB,WAAW,cAAc,WAAW,gBAElE,OAAO;EAAE;EAAU;EAAU;CAAO;AAGxC;;AA4GA,MAAa,mCACX"}
|
|
1
|
+
{"version":3,"file":"packageApi.cjs","names":[],"sources":["../../../src/schemas/packageApi.ts"],"sourcesContent":["/**\n * The HTTP surface a package offers its host.\n *\n * A server plugin registers one with its host. The host mounts it under the API\n * route prefix, and the package writes routes relative to that mount.\n *\n * The handler is a plain fetch callback so no host and no package is committed\n * to one HTTP framework; a Hono app satisfies it through `app.fetch`.\n */\n\nimport type {\n PoComputerUseSessionAccess,\n PoDirectEventBus,\n PoHubSessionService,\n PoSessionCommunicationEndpoint,\n PoSessionActivity,\n PoSessionContext,\n} from './hubChannel';\nimport type { PoMcpProjection } from './mcpProjection';\nimport type { PoSessionStorageService } from './platform';\n/** The host-owned sync view a repository-scoped package API may inspect. */\nexport interface PoRepositorySyncView {\n fresh: boolean;\n reasons: string[];\n /** True while a background sync that may prepare what `reasons` names is running. */\n syncing?: boolean;\n mcpProjection?: PoMcpProjection;\n}\n\n/** Where an API runs: inside one session's server, or in the machine-wide hub. */\nexport type PoApiScope = 'global' | 'workspace' | 'session';\n\nexport const PO_API_SCOPES: readonly PoApiScope[] = ['global', 'workspace', 'session'];\n\n/** Identity of an independently mounted plugin host. */\nexport type PoApiMount =\n | { scope: 'global' }\n | { scope: 'workspace'; workspaceId: string }\n | { scope: 'session'; sessionId: string };\n\n/** Immutable browser contribution generation paired with a server mount. */\nexport interface PoWebComposition {\n id: string;\n scope: PoApiScope;\n revision: number;\n manifestUrl: string;\n rawAssetBaseUrl: string;\n verifiedAssetBaseUrl: string;\n /** `[slot, entry]` for each of this mount's plugin copies, the entry an absolute path below the asset prefixes. */\n pluginEntries: [string, string][];\n /** Every signed file this mount's slots can load, absolute below the asset prefixes. */\n assetPaths: string[];\n /** Per-plugin stylesheets of this mount's plugins only, so other mounts' classes never apply here. */\n stylePaths: string[];\n channels: string[];\n /** The slots resolved for this mount; the shared build may hold more. */\n plugins: string[];\n}\n\n/**\n * Immutable native contribution generation paired with a server mount. One signed CommonJS module at\n * `entryPath`, served through the same immutable plugin routes as web compositions.\n */\nexport interface PoNativeComposition {\n id: string;\n scope: PoApiScope;\n revision: number;\n manifestUrl: string;\n rawAssetBaseUrl: string;\n /** Always `/composition.js`. */\n entryPath: string;\n channels: string[];\n /** The `poNative.pluginId` values resolved for this mount; the shell installs only these. */\n plugins: string[];\n}\n\n/** Canonical public prefix. Scope selection never falls through to a parent. */\nexport function poApiMountPath(mount: PoApiMount & { workspaceId?: string }): string {\n if (mount.scope === 'global') return '/api/plugins';\n if (mount.scope === 'workspace') return `/api/workspaces/${encodeURIComponent(mount.workspaceId)}/plugins`;\n if (!mount.workspaceId) throw new Error('A session API path requires its workspace identity.');\n return `/api/workspaces/${encodeURIComponent(mount.workspaceId)}/sessions/${encodeURIComponent(mount.sessionId)}/plugins`;\n}\n\n/** Scope addressed by a public WebSocket upgrade. */\nexport type PoSocketMount =\n | { scope: 'global' }\n | { scope: 'workspace'; workspaceId: string }\n | { scope: 'session'; workspaceId: string; sessionId: string };\n\n/** Only canonical resource paths may select a protocol listener. */\nexport function parsePoSocketPath(pathname: string): PoSocketMount | undefined {\n if (pathname === '/api/ws') return { scope: 'global' };\n const match = /^\\/api\\/workspaces\\/([^/]+)(?:\\/sessions\\/([^/]+))?\\/ws$/u.exec(pathname);\n if (!match) return undefined;\n try {\n const workspaceId = decodeURIComponent(match[1]);\n return match[2] === undefined\n ? { scope: 'workspace', workspaceId }\n : { scope: 'session', workspaceId, sessionId: decodeURIComponent(match[2]) };\n } catch {\n return undefined;\n }\n}\n\n/** The segment an API is mounted under, below this prefix. */\nexport const PO_API_ROUTE_PREFIX = '/api/plugins';\n/** Selects the hub API bundle that owns the named cockpit session. */\nexport const PO_HUB_API_SESSION_QUERY_PARAM = 'hubSession';\n\n/** Trusted caller headers written only by the cockpit-to-session proxy. */\nexport const PO_API_CALLER_LOCALITY_HEADER = 'x-po-api-caller-locality';\nexport const PO_API_CALLER_DEVICE_ID_HEADER = 'x-po-api-caller-device-id';\nexport const PO_API_CALLER_STEP_UP_HEADER = 'x-po-api-caller-step-up';\nexport const PO_API_CALLER_HEADERS = [\n PO_API_CALLER_LOCALITY_HEADER,\n PO_API_CALLER_DEVICE_ID_HEADER,\n PO_API_CALLER_STEP_UP_HEADER,\n] as const;\n\nexport type PoApiCallerStepUp = 'not-required' | 'verified' | 'unavailable';\nexport type PoApiCaller =\n | { locality: 'local'; stepUp: 'not-required' }\n | { locality: 'remote'; deviceId: string; stepUp: PoApiCallerStepUp };\n\n/** Reads the proxy-authenticated caller identity, rejecting partial or contradictory stamps. */\nexport function poApiCallerFrom(headers: Headers): PoApiCaller | undefined {\n const locality = headers.get(PO_API_CALLER_LOCALITY_HEADER);\n const deviceId = headers.get(PO_API_CALLER_DEVICE_ID_HEADER);\n const stepUp = headers.get(PO_API_CALLER_STEP_UP_HEADER);\n if (locality === 'local') {\n return deviceId === null && stepUp === 'not-required' ? { locality, stepUp } : undefined;\n }\n if (\n locality === 'remote' &&\n deviceId !== null &&\n deviceId !== '' &&\n (stepUp === 'not-required' || stepUp === 'verified' || stepUp === 'unavailable')\n ) {\n return { locality, deviceId, stepUp };\n }\n return undefined;\n}\n/**\n * A browser-reachable OAuth redirect the host serves on its own listener.\n *\n * A package brokering third-party OAuth cannot use a loopback redirect when the\n * operator's browser is on another machine: `127.0.0.1` resolves to whichever\n * machine the browser runs on. The host owns a listener that is reachable from\n * wherever the cockpit is being used, so it lends that instead of the package\n * opening a port of its own.\n */\nexport interface PoOAuthRedirect {\n /** Absolute URL to register as the redirect target, already origin-correct. */\n readonly redirectUri: string;\n /**\n * Accept redirects carrying this state. Must complete before the\n * authorization URL is surfaced, or the redirect races its own reservation.\n */\n reserve(state: string, timeoutMs?: number): Promise<void>;\n /** Resolves once the redirect carrying this state arrives. */\n wait(state: string, timeoutMs?: number): Promise<{ code: string; state: string }>;\n /** Drops a reservation whose flow ended without a redirect. */\n cancel(state: string): void;\n}\n\n/** An exact, host-owned receipt address. Provider IDs are not event cursor positions. */\nexport interface PoRequestReceiptKey {\n namespace: string;\n activationId: string;\n requestId: string;\n}\n\nexport interface PoRequestReceipt extends PoRequestReceiptKey {\n fingerprint: string;\n destination: string;\n transactionId: string;\n outcome: 'reserved' | 'admitted' | 'rejected' | 'uncertain';\n}\n\nexport interface PoRequestReceiptReservation extends PoRequestReceiptKey {\n /** Lowercase SHA-256 of the authoritative request text, never the full transcript. */\n fingerprint: string;\n destination: string;\n transactionId: string;\n}\n\nexport type PoRequestReceiptReserveResult =\n | { kind: 'reserved'; token: string }\n | { kind: 'existing'; receipt: PoRequestReceipt }\n | { kind: 'conflict'; receipt: PoRequestReceipt };\n\n/** A global-only receipt capability. A reservation is not an execution receipt. */\nexport interface PoRequestReceipts {\n reserve(request: PoRequestReceiptReservation): Promise<PoRequestReceiptReserveResult>;\n lookup(key: PoRequestReceiptKey): Promise<PoRequestReceipt | undefined>;\n finish(\n request: PoRequestReceiptKey & { token: string; outcome: 'admitted' | 'rejected' | 'uncertain' },\n ): Promise<PoRequestReceipt>;\n}\n\n/** Permit returned for expensive local work. Calling it releases the slot. */\nexport interface PoHostExecutionPermit {\n (): void;\n attachProcess?(pid: number): Promise<void>;\n}\n\n/** Host-wide admission for expensive local work. Release only after the owned process exits. */\nexport interface PoHostExecutionBudget {\n acquire(signal?: AbortSignal): Promise<PoHostExecutionPermit>;\n getSnapshot(): Readonly<{ running: number; queued: number; limit: number }>;\n}\n\n/** Synchronous host-owned exclusion across media APIs mounted at different scopes. */\nexport interface PoHostMediaArbitration {\n register(busy: () => boolean): () => void;\n available(busy: () => boolean): boolean;\n}\n\n/** One host's paired agent registrations, shared across its global and session mounts. */\nexport interface PoPeerAgentRegistry {\n register(sessionId: string, agent: { fetch(request: Request): Promise<Response> }, hubToken: string): () => void;\n get(sessionId: string): { fetch(request: Request): Promise<Response>; hubToken: string } | undefined;\n}\n\n/** One agent that edits files: a hub session or an in-process child run. */\nexport interface PoEditPresenceAgent {\n /** `session:<id>` or `run:<runId>`. Unique across the host. */\n readonly key: string;\n /** Read when a note is rendered, so a name registered after the edit still shows. */\n readonly label: () => string;\n /** Hub session id other agents can reach with intercom. */\n readonly contact: string;\n readonly isLive: () => boolean;\n}\n\nexport interface PoEditPresenceEntry {\n readonly agent: PoEditPresenceAgent;\n /** `@file` tag of the bytes this agent's last successful edit or write left behind. */\n readonly tag: string;\n readonly at: number;\n}\n\n/**\n * Host-wide record of the last edit each live agent made to a file, keyed by realpath then agent key.\n * Owners delete their entries when they dispose, so no callback outlives its session or run.\n */\nexport type PoEditPresenceLedger = Map<string, Map<string, PoEditPresenceEntry>>;\n\n/** Why shareFile rejects while the host has no public tunnel origin. */\nexport const PO_SHARE_FILE_REMOTE_OFF_MESSAGE =\n 'Remote access is off, so Po cannot share files with remote MCP servers. Turn it on and retry.';\n\n/**\n * A file published at a short-lived public tunnel URL: 10 minutes, 3 downloads, and gone\n * when the tunnel revision changes. Call revoke as soon as the consumer is done with it.\n */\nexport interface PoSharedFile {\n /** Bearer link; never log or persist it. */\n url: string;\n fileName: string;\n mimeType: string;\n size: number;\n /** Expiry as epoch milliseconds. */\n expiresAt: number;\n maxDownloads: number;\n /** Idempotent. */\n revoke(): void;\n}\n\n/** What the host tells an API about itself when it starts. */\nexport interface PoApiContext {\n scope: PoApiScope;\n /** Stable, opaque workspace id, shared by every session and member checkout of the workspace. */\n workspaceId?: string;\n /**\n * The admitted workspace root for a workspace mount. For a session mount it is the checkout\n * the session runs in; read sessionContext for both roots. Absent from global mounts.\n */\n workspaceRoot?: string;\n /** The session's baseline context; present on session mounts whose host knows its workspace. */\n sessionContext?: PoSessionContext;\n /** Explicit host home, never selected by a remote request. */\n homeDirectory?: string;\n /** The session this host serves; absent for a hub-scoped API. */\n sessionId?: string;\n /** The session's working directory; absent for a hub-scoped API. */\n cwd?: string;\n /** Session environment admitted by the server, never supplied by remote clients. */\n environment?: Readonly<Record<string, string | undefined>>;\n /** Shared only with child processes in this session, never with remote API clients. */\n internalToken?: string;\n /** Shared only with the cockpit hub for privileged cross-session coordination. */\n hubToken?: string;\n /**\n * Resolves a hub-issued opaque repository id to an admitted canonical root.\n * Hub APIs must never accept a browser-supplied filesystem path instead.\n */\n resolveRepository?(repositoryId: string): string | undefined;\n /** Reads the admitted repository's sync projection without exposing its state path. */\n readRepositorySync?(\n repositoryId: string,\n ): Promise<PoRepositorySyncView | undefined> | PoRepositorySyncView | undefined;\n /** Admitted workspaces available to this mount. */\n repositories?(): readonly { id: string; name: string; path: string; active: boolean }[];\n /** Publish a successful config write to the owning mount's refresh lifecycle. */\n configurationChanged?(): void;\n /**\n * Borrows the hub's OAuth redirect surface. Undefined when the hub cannot\n * currently serve one, in which case the package keeps its own behaviour.\n */\n oauthRedirect?(): PoOAuthRedirect | undefined;\n /** Canonical in-process lifecycle for sessions created by this host. */\n sessionService?: PoHubSessionService;\n /** Trusted in-process storage capability. APIs must retain their mount's session authorization. */\n sessionStorage?: PoSessionStorageService;\n /** Host-bound, authenticated inter-session event endpoint for this session. */\n sessionCommunication?: PoSessionCommunicationEndpoint;\n /** Same-process events shared by session APIs and hub channels. */\n directEvents?: PoDirectEventBus;\n /**\n * Publishes this session's activity line to every page's rail; undefined clears it.\n * Session mounts only. The last publisher wins.\n */\n publishActivity?(activity: PoSessionActivity | undefined): void;\n /** Trusted in-process dispatch to an explicitly selected mounted API. No browser authentication is performed here. */\n requestApi?(mount: PoApiMount, basePath: string, request: Request): Promise<Response>;\n /** Present only on a session mounted by an authenticated Desktop host. */\n computerUse?: PoComputerUseSessionAccess;\n /** Deliver a typed method to the channel serving a session this mount reaches, retaining the caller's connection identity. */\n receiveChannel?(sessionId: string, frameType: string, payload: unknown, connectionId: string): boolean;\n /** Host-owned replay evidence, supplied only on the global mount. Never exposed to browsers or agents. */\n requestReceipts?: PoRequestReceipts;\n /** One host's exclusive media activity, shared across global and session scopes. */\n mediaArbitration?: PoHostMediaArbitration;\n /** One host-wide heavy-job budget, not a separate budget for every session. */\n executionBudget?: PoHostExecutionBudget;\n /** One host-wide edit presence ledger, shared by every session mount. */\n editPresence?: PoEditPresenceLedger;\n /** Paired agents belonging to this host only. */\n peerAgents?: PoPeerAgentRegistry;\n /** Machine-owned Remote Control service, mounted only by Po's own global server plugin. */\n remoteControl?: { fetch(request: Request): Promise<Response> };\n /**\n * Publishes a file from this session's cwd or attachments at a short-lived tunnel URL.\n * Session mounts only; rejects with PO_SHARE_FILE_REMOTE_OFF_MESSAGE while remote access is off.\n * The host asks no consent: the caller must obtain it before passing the URL on.\n */\n shareFile?(path: string, label: string): Promise<PoSharedFile>;\n onNotice(message: string): void;\n}\n\n/**\n * One running surface. The host strips the mount prefix before calling, so\n * routes are declared relative ('/runners/:id/log') and a package never\n * repeats where it was mounted.\n */\nexport interface PoApiHandler {\n fetch(request: Request): Response | Promise<Response>;\n close(): void;\n}\n\nexport interface PoApi {\n /** Segment under /api/plugins/; globally unique across loaded packages. */\n basePath: string;\n start(context: PoApiContext): PoApiHandler;\n}\n"],"mappings":";AAgCA,MAAa,gBAAuC;CAAC;CAAU;CAAa;AAAS;;AA6CrF,SAAgB,eAAe,OAAsD;CACnF,IAAI,MAAM,UAAU,UAAU,OAAO;CACrC,IAAI,MAAM,UAAU,aAAa,OAAO,mBAAmB,mBAAmB,MAAM,WAAW,EAAE;CACjG,IAAI,CAAC,MAAM,aAAa,MAAM,IAAI,MAAM,qDAAqD;CAC7F,OAAO,mBAAmB,mBAAmB,MAAM,WAAW,EAAE,YAAY,mBAAmB,MAAM,SAAS,EAAE;AAClH;;AASA,SAAgB,kBAAkB,UAA6C;CAC7E,IAAI,aAAa,WAAW,OAAO,EAAE,OAAO,SAAS;CACrD,MAAM,QAAQ,4DAA4D,KAAK,QAAQ;CACvF,IAAI,CAAC,OAAO,OAAO,KAAA;CACnB,IAAI;EACF,MAAM,cAAc,mBAAmB,MAAM,EAAE;EAC/C,OAAO,MAAM,OAAO,KAAA,IAChB;GAAE,OAAO;GAAa;EAAY,IAClC;GAAE,OAAO;GAAW;GAAa,WAAW,mBAAmB,MAAM,EAAE;EAAE;CAC/E,QAAQ;EACN;CACF;AACF;;AAGA,MAAa,sBAAsB;;AAEnC,MAAa,iCAAiC;;AAG9C,MAAa,gCAAgC;AAC7C,MAAa,iCAAiC;AAC9C,MAAa,+BAA+B;AAC5C,MAAa,wBAAwB;CACnC;CACA;CACA;AACF;;AAQA,SAAgB,gBAAgB,SAA2C;CACzE,MAAM,WAAW,QAAQ,IAAI,6BAA6B;CAC1D,MAAM,WAAW,QAAQ,IAAI,8BAA8B;CAC3D,MAAM,SAAS,QAAQ,IAAI,4BAA4B;CACvD,IAAI,aAAa,SACf,OAAO,aAAa,QAAQ,WAAW,iBAAiB;EAAE;EAAU;CAAO,IAAI,KAAA;CAEjF,IACE,aAAa,YACb,aAAa,QACb,aAAa,OACZ,WAAW,kBAAkB,WAAW,cAAc,WAAW,gBAElE,OAAO;EAAE;EAAU;EAAU;CAAO;AAGxC;;AA4GA,MAAa,mCACX"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { PoSessionStorageService } from "./platform.mjs";
|
|
1
2
|
import { PoComputerUseSessionAccess, PoDirectEventBus, PoHubSessionService, PoSessionActivity, PoSessionCommunicationEndpoint, PoSessionContext } from "./hubChannel.mjs";
|
|
2
3
|
import { PoMcpProjection } from "./mcpProjection.mjs";
|
|
3
4
|
//#region src/schemas/packageApi.d.ts
|
|
@@ -270,6 +271,8 @@ export interface PoApiContext {
|
|
|
270
271
|
oauthRedirect?(): PoOAuthRedirect | undefined;
|
|
271
272
|
/** Canonical in-process lifecycle for sessions created by this host. */
|
|
272
273
|
sessionService?: PoHubSessionService;
|
|
274
|
+
/** Trusted in-process storage capability. APIs must retain their mount's session authorization. */
|
|
275
|
+
sessionStorage?: PoSessionStorageService;
|
|
273
276
|
/** Host-bound, authenticated inter-session event endpoint for this session. */
|
|
274
277
|
sessionCommunication?: PoSessionCommunicationEndpoint;
|
|
275
278
|
/** Same-process events shared by session APIs and hub channels. */
|