@agimon-ai/doompi-core 0.0.1-alpha.84 → 0.0.1-alpha.85

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (27) hide show
  1. package/dist/childSession.cjs +1 -0
  2. package/dist/childSession.d.mts +2 -2
  3. package/dist/childSession.mjs +2 -2
  4. package/dist/src/systems/child/adapters/headlessChildSessionService.cjs +26 -6
  5. package/dist/src/systems/child/adapters/headlessChildSessionService.cjs.map +1 -1
  6. package/dist/src/systems/child/adapters/headlessChildSessionService.d.mts +3 -1
  7. package/dist/src/systems/child/adapters/headlessChildSessionService.d.mts.map +1 -1
  8. package/dist/src/systems/child/adapters/headlessChildSessionService.mjs +26 -6
  9. package/dist/src/systems/child/adapters/headlessChildSessionService.mjs.map +1 -1
  10. package/dist/src/systems/child/types/childSession.cjs +3 -0
  11. package/dist/src/systems/child/types/childSession.cjs.map +1 -1
  12. package/dist/src/systems/child/types/childSession.d.mts +9 -2
  13. package/dist/src/systems/child/types/childSession.d.mts.map +1 -1
  14. package/dist/src/systems/child/types/childSession.mjs +3 -1
  15. package/dist/src/systems/child/types/childSession.mjs.map +1 -1
  16. package/dist/src/systems/main/adapters/headlessSessionHost.cjs +5 -1
  17. package/dist/src/systems/main/adapters/headlessSessionHost.cjs.map +1 -1
  18. package/dist/src/systems/main/adapters/headlessSessionHost.d.mts.map +1 -1
  19. package/dist/src/systems/main/adapters/headlessSessionHost.mjs +6 -2
  20. package/dist/src/systems/main/adapters/headlessSessionHost.mjs.map +1 -1
  21. package/dist/terminalPiChildSessionService.cjs +2 -1
  22. package/dist/terminalPiChildSessionService.cjs.map +1 -1
  23. package/dist/terminalPiChildSessionService.d.mts +2 -1
  24. package/dist/terminalPiChildSessionService.d.mts.map +1 -1
  25. package/dist/terminalPiChildSessionService.mjs +2 -1
  26. package/dist/terminalPiChildSessionService.mjs.map +1 -1
  27. package/package.json +1 -1
@@ -1,6 +1,7 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_childSession = require("./src/systems/child/types/childSession.cjs");
3
3
  const require_index = require("./src/systems/child/services/childSession/index.cjs");
4
+ exports.DOOM_CHILD_SESSION_MCP_TOOL_SERVICE = require_childSession.DOOM_CHILD_SESSION_MCP_TOOL_SERVICE;
4
5
  exports.DOOM_CHILD_SESSION_SERVICE = require_childSession.DOOM_CHILD_SESSION_SERVICE;
5
6
  exports.createDoomChildSessionService = require_index.createDoomChildSessionService;
6
7
  exports.readDoomChildSessionService = require_childSession.readDoomChildSessionService;
@@ -1,3 +1,3 @@
1
- import { DOOM_CHILD_SESSION_SERVICE, DoomChildSessionCapabilityCeiling, DoomChildSessionEvent, DoomChildSessionFreshSource, DoomChildSessionHandle, DoomChildSessionIntercom, DoomChildSessionRequest, DoomChildSessionRuntime, DoomChildSessionRuntimeFactory, DoomChildSessionScope, DoomChildSessionService, DoomChildSessionServiceProvider, DoomChildSessionSource, DoomChildSessionState, DoomChildSessionTerminalPiForkSource, DoomChildSessionTool, DoomChildSessionToolResult, DoomChildSessionUsage, DoomChildSessionV4ForkSource, DoomChildSessionV4RestoreSource, readDoomChildSessionService, requireDoomChildSessionService } from "./src/systems/child/types/childSession.mjs";
1
+ import { DOOM_CHILD_SESSION_MCP_TOOL_SERVICE, DOOM_CHILD_SESSION_SERVICE, DoomChildSessionCapabilityCeiling, DoomChildSessionEvent, DoomChildSessionFreshSource, DoomChildSessionHandle, DoomChildSessionIntercom, DoomChildSessionRequest, DoomChildSessionRuntime, DoomChildSessionRuntimeFactory, DoomChildSessionScope, DoomChildSessionService, DoomChildSessionServiceProvider, DoomChildSessionSource, DoomChildSessionState, DoomChildSessionTerminalPiForkSource, DoomChildSessionTool, DoomChildSessionToolResult, DoomChildSessionUsage, DoomChildSessionV4ForkSource, DoomChildSessionV4RestoreSource, readDoomChildSessionService, requireDoomChildSessionService } from "./src/systems/child/types/childSession.mjs";
2
2
  import { DoomChildSessionServiceDependencies, createDoomChildSessionService } from "./src/systems/child/services/childSession/index.mjs";
3
- export { DOOM_CHILD_SESSION_SERVICE, DoomChildSessionCapabilityCeiling, DoomChildSessionEvent, DoomChildSessionFreshSource, DoomChildSessionHandle, DoomChildSessionIntercom, DoomChildSessionRequest, DoomChildSessionRuntime, DoomChildSessionRuntimeFactory, DoomChildSessionScope, DoomChildSessionService, DoomChildSessionServiceDependencies, DoomChildSessionServiceProvider, DoomChildSessionSource, DoomChildSessionState, DoomChildSessionTerminalPiForkSource, DoomChildSessionTool, DoomChildSessionToolResult, DoomChildSessionUsage, DoomChildSessionV4ForkSource, DoomChildSessionV4RestoreSource, createDoomChildSessionService, readDoomChildSessionService, requireDoomChildSessionService };
3
+ export { DOOM_CHILD_SESSION_MCP_TOOL_SERVICE, DOOM_CHILD_SESSION_SERVICE, DoomChildSessionCapabilityCeiling, DoomChildSessionEvent, DoomChildSessionFreshSource, DoomChildSessionHandle, DoomChildSessionIntercom, DoomChildSessionRequest, DoomChildSessionRuntime, DoomChildSessionRuntimeFactory, DoomChildSessionScope, DoomChildSessionService, DoomChildSessionServiceDependencies, DoomChildSessionServiceProvider, DoomChildSessionSource, DoomChildSessionState, DoomChildSessionTerminalPiForkSource, DoomChildSessionTool, DoomChildSessionToolResult, DoomChildSessionUsage, DoomChildSessionV4ForkSource, DoomChildSessionV4RestoreSource, createDoomChildSessionService, readDoomChildSessionService, requireDoomChildSessionService };
@@ -1,3 +1,3 @@
1
- import { DOOM_CHILD_SESSION_SERVICE, readDoomChildSessionService, requireDoomChildSessionService } from "./src/systems/child/types/childSession.mjs";
1
+ import { DOOM_CHILD_SESSION_MCP_TOOL_SERVICE, DOOM_CHILD_SESSION_SERVICE, readDoomChildSessionService, requireDoomChildSessionService } from "./src/systems/child/types/childSession.mjs";
2
2
  import { createDoomChildSessionService } from "./src/systems/child/services/childSession/index.mjs";
3
- export { DOOM_CHILD_SESSION_SERVICE, createDoomChildSessionService, readDoomChildSessionService, requireDoomChildSessionService };
3
+ export { DOOM_CHILD_SESSION_MCP_TOOL_SERVICE, DOOM_CHILD_SESSION_SERVICE, createDoomChildSessionService, readDoomChildSessionService, requireDoomChildSessionService };
@@ -96,6 +96,7 @@ const NATIVE_TOOL_FACTORIES = {
96
96
  function adaptNativeTool(tool) {
97
97
  return {
98
98
  ...tool,
99
+ label: "label" in tool ? tool.label : tool.name,
99
100
  parameters: tool.parameters,
100
101
  async execute(toolCallId, parameters, onUpdate, _toolContext, _invocation, context) {
101
102
  const execute = tool.execute;
@@ -103,6 +104,10 @@ function adaptNativeTool(tool) {
103
104
  content: partial.content,
104
105
  details: partial.details
105
106
  }));
107
+ if (result.isError) {
108
+ const content = result.content;
109
+ throw new Error(content.filter((part) => part.type === "text").map((part) => part.text).join("\n") || "MCP tool failed.");
110
+ }
106
111
  return {
107
112
  content: result.content,
108
113
  details: result.details
@@ -111,7 +116,7 @@ function adaptNativeTool(tool) {
111
116
  };
112
117
  }
113
118
  /** Validate and project native fields before a source fork can publish a child journal. */
114
- function composeDirectHarnessRequestOptions(request) {
119
+ function composeDirectHarnessRequestOptions(request, resolveMcpTool) {
115
120
  const unsupported = [
116
121
  ...hasConfiguredValues(request.extensions) ? ["extensions"] : [],
117
122
  ...hasConfiguredValues(request.subagentOnlyExtensions) ? ["subagentOnlyExtensions"] : [],
@@ -119,16 +124,31 @@ function composeDirectHarnessRequestOptions(request) {
119
124
  ...hasConfiguredValues(request.capabilityCeiling?.allowedExternalProfiles) ? ["allowedExternalProfiles"] : []
120
125
  ];
121
126
  if (unsupported.length > 0) throw new Error(`Native child session configuration is unsupported by the direct harness: ${unsupported.join(", ")}`);
122
- const requested = request.tools ?? Object.keys(NATIVE_TOOL_FACTORIES);
127
+ const requested = [...new Set(request.tools ?? Object.keys(NATIVE_TOOL_FACTORIES))];
123
128
  const excluded = new Set(request.excludeTools ?? []);
124
129
  const allowed = request.capabilityCeiling?.allowedTools;
125
- const names = requested.filter((name) => !excluded.has(name) && (allowed === void 0 || allowed.includes(name)));
126
- const unknown = names.filter((name) => !(name in NATIVE_TOOL_FACTORIES));
130
+ const isMcp = (name) => name === "mcp" || name === "mcp_use";
131
+ const mcpDenied = request.capabilityCeiling?.allowMcpTools === false || [...excluded].some(isMcp);
132
+ const names = requested.filter((name) => !excluded.has(name) && (allowed === void 0 || allowed.includes(name)) && !(isMcp(name) && mcpDenied));
133
+ const unknown = names.filter((name) => !Object.hasOwn(NATIVE_TOOL_FACTORIES, name) && !isMcp(name));
127
134
  if (unknown.length > 0) throw new Error(`Native child session requested unknown direct harness tools: ${unknown.join(", ")}`);
128
135
  const missing = (request.capabilityCeiling?.requiredTools ?? []).filter((name) => !names.includes(name));
129
136
  if (missing.length > 0) throw new Error(`Native child session capability ceiling requires unavailable tools: ${missing.join(", ")}`);
137
+ const mcpTool = names.some(isMcp) ? resolveMcpTool?.() : void 0;
138
+ if (names.some(isMcp) && !mcpTool) throw new Error("Native child session MCP tools are unavailable. Enable MCP in the parent session.");
130
139
  return {
131
- tools: names.map((name) => adaptNativeTool(NATIVE_TOOL_FACTORIES[name](request.cwd))),
140
+ tools: names.map((name) => {
141
+ if (!isMcp(name)) return adaptNativeTool(NATIVE_TOOL_FACTORIES[name](request.cwd));
142
+ return adaptNativeTool({
143
+ ...mcpTool,
144
+ name,
145
+ execute(toolCallId, parameters, signal, onUpdate) {
146
+ signal?.throwIfAborted();
147
+ if (resolveMcpTool?.() !== mcpTool) throw new Error("The parent session MCP dispatcher is no longer available.");
148
+ return mcpTool.execute(toolCallId, parameters, signal, onUpdate);
149
+ }
150
+ });
151
+ }),
132
152
  activeToolNames: names,
133
153
  ...request.systemPrompt === void 0 ? {} : { systemPrompt: request.systemPrompt }
134
154
  };
@@ -173,7 +193,7 @@ function createHeadlessChildSessionService(options) {
173
193
  return require_index.createDoomChildSessionService(async (request, signal) => {
174
194
  signal?.throwIfAborted();
175
195
  if (request.source.kind === "terminal-pi-fork") throw new Error("Headless child sessions do not support terminal Pi sources.");
176
- const directRequestOptions = composeDirectHarnessRequestOptions(request);
196
+ const directRequestOptions = composeDirectHarnessRequestOptions(request, options.mcpTool);
177
197
  let sessionPath;
178
198
  let sessionId;
179
199
  if (request.source.kind === "v4-restore") {
@@ -1 +1 @@
1
- {"version":3,"file":"headlessChildSessionService.cjs","names":["readNativeChildTranscript","promptForAssistantText","createReadTool","createBashTool","createEditTool","createWriteTool","createGrepTool","createFindTool","createLsTool","prompt","path","SqliteSessionRepo","createNodeSqliteFactory","BACKGROUND_CONTEXT","randomUUID","createDirectHarnessRuntime","createHistoryOwnership","createDoomChildSessionService","registerNativeChild"],"sources":["../../../../../src/systems/child/adapters/headlessChildSessionService.ts"],"sourcesContent":["import { randomUUID } from 'node:crypto';\nimport fs from 'node:fs';\nimport path from 'node:path';\n\nimport { BACKGROUND_CONTEXT } from '@earendil-works/pi-agent-core/harness/context';\nimport type { Models, MutableModels, Provider } from '@earendil-works/pi-ai';\nimport {\n createBashTool,\n createEditTool,\n createFindTool,\n createGrepTool,\n createLsTool,\n createReadTool,\n createWriteTool,\n} from '@earendil-works/pi-coding-agent';\nimport { SqliteSessionRepo, createNodeSqliteFactory } from '@earendil-works/pi-session-backend-sqlite-node';\n\nimport {\n createDoomChildSessionService,\n type DoomChildSessionIntercom,\n type DoomChildSessionRequest,\n type DoomChildSessionRuntime,\n type DoomChildSessionService,\n type DoomChildSessionServiceProvider,\n} from '../../../exports/childSession';\nimport {\n createDirectHarnessRuntime,\n promptForAssistantText,\n type DirectHarnessRuntime,\n type DirectHarnessRuntimeOptions,\n} from '../../../server/directHarnessRuntime';\nimport { readNativeChildTranscript } from '../../../server/nativeChildTranscriptReader';\nimport type { HistoryOwnership } from '../../../services/historyImport';\nimport { createHistoryOwnership } from '../../../services/historyOwnership';\nimport type { DirectHarnessModel } from '../../../types/server/directHarnessRuntime';\nimport { registerNativeChild } from './nativeChildRuntimes';\n\nexport interface HeadlessChildSessionServiceOptions {\n readonly parentSessionId: string;\n readonly cwd: string;\n readonly sessionsRoot?: string;\n readonly models?: Models | MutableModels;\n /**\n * Providers to merge into the model registry for every child spawn. A thunk\n * is resolved per spawn so providers registered after this service was built,\n * such as Pi extension providers, are still visible to the child.\n */\n readonly providers?: readonly Provider[] | (() => readonly Provider[]);\n readonly defaultModel?: () => DirectHarnessModel | undefined;\n readonly historyOwnership?: HistoryOwnership;\n readonly now?: () => number;\n readonly runtimeFactory?: (options: DirectHarnessRuntimeOptions) => Promise<DirectHarnessRuntime>;\n}\n\nexport interface HeadlessChildSessionServiceProvider extends DoomChildSessionServiceProvider {\n close(): Promise<void>;\n}\n\nconst THINKING_SUFFIX_PATTERN = /:(off|minimal|low|medium|high|xhigh|max)$/;\n\nexport interface ParsedChildModel {\n readonly model: DirectHarnessModel;\n readonly thinking?: string;\n}\n\n/**\n * Child model specs may carry a Pi thinking suffix, for example\n * `anthropic-vertex/claude-sonnet-5:medium`. The suffix is a request option and\n * never part of the model id, so it has to be split off before model lookup.\n */\nexport function parseChildModelReference(value: string | undefined): ParsedChildModel | undefined {\n if (value === undefined) return undefined;\n const suffix = THINKING_SUFFIX_PATTERN.exec(value);\n const reference = suffix === null ? value : value.slice(0, value.length - suffix[0].length);\n const separator = reference.indexOf('/');\n if (separator <= 0 || separator === reference.length - 1)\n throw new Error(`Child model must use the provider/model form: ${value}`);\n return {\n model: { provider: reference.slice(0, separator), id: reference.slice(separator + 1) },\n ...(suffix === null ? {} : { thinking: suffix[1] as string }),\n };\n}\n\n/** Resolve the provider set for one spawn, tolerating both a fixed array and a thunk. */\nexport function resolveChildProviders(\n providers: readonly Provider[] | (() => readonly Provider[]) | undefined,\n): readonly Provider[] | undefined {\n const resolved = typeof providers === 'function' ? providers() : providers;\n return resolved === undefined || resolved.length === 0 ? undefined : resolved;\n}\n\nfunction sessionFile(runtime: DirectHarnessRuntime): string | undefined {\n const metadata = runtime.session.metadata as unknown as { path?: unknown };\n return typeof metadata.path === 'string' ? metadata.path : undefined;\n}\n\nfunction childRuntime(\n runtime: DirectHarnessRuntime,\n intercom?: DoomChildSessionIntercom,\n release?: () => void,\n): DoomChildSessionRuntime {\n const file = sessionFile(runtime);\n return {\n sessionId: runtime.sessionId,\n ...(file === undefined ? {} : { sessionFile: file }),\n ...(file === undefined\n ? {}\n : { readTranscriptPage: (request, signal) => readNativeChildTranscript(file, request, signal) }),\n prompt: (task) => promptForAssistantText(runtime, task),\n steer: (message) => runtime.steer(message),\n followUp: (message) => runtime.followUp(message),\n onUsage(listener) {\n return runtime.onEvent((event) => {\n if (event.type !== 'usage') return;\n listener({ rowId: event.row.id, cost: event.row.usage.cost.total });\n });\n },\n abort: () => runtime.abort(),\n dispose: async () => {\n try {\n await runtime.dispose();\n } finally {\n release?.();\n intercom?.dispose?.();\n }\n },\n };\n}\n\ntype DirectHarnessTool = Parameters<DirectHarnessRuntime['replaceTools']>[0][number];\n\nasync function installIntercom(\n runtime: DirectHarnessRuntime,\n intercom: DoomChildSessionIntercom | undefined,\n tools: DirectHarnessTool[],\n): Promise<void> {\n if (!intercom) return;\n const tool = intercom.bindRuntime(childRuntime(runtime));\n const adapted = {\n ...tool,\n parameters: tool.parameters as never,\n execute: (operationId: string, params: unknown, signal: AbortSignal, onUpdate: unknown) =>\n tool.execute(operationId, params, signal, onUpdate as never),\n } as unknown as DirectHarnessTool;\n await runtime.replaceTools([...tools, adapted]);\n}\n\nfunction hasConfiguredValues(value: readonly string[] | undefined): boolean {\n return value !== undefined && value.length > 0;\n}\n\nconst NATIVE_TOOL_FACTORIES = {\n read: createReadTool,\n bash: createBashTool,\n edit: createEditTool,\n write: createWriteTool,\n grep: createGrepTool,\n find: createFindTool,\n ls: createLsTool,\n} as const;\n\ntype NativeCodingTool = ReturnType<(typeof NATIVE_TOOL_FACTORIES)[keyof typeof NATIVE_TOOL_FACTORIES]>;\n\nfunction adaptNativeTool(tool: NativeCodingTool): DirectHarnessTool {\n const prompt = tool as NativeCodingTool & {\n promptSnippet?: string;\n promptGuidelines?: string[];\n };\n return {\n ...prompt,\n parameters: tool.parameters as never,\n async execute(toolCallId, parameters, onUpdate, _toolContext, _invocation, context) {\n const execute = tool.execute as (\n id: string,\n params: unknown,\n signal: AbortSignal,\n update: (result: { content: unknown; details?: unknown }) => void,\n ) => Promise<{ content: unknown; details?: unknown }>;\n const result = await execute(\n toolCallId,\n parameters,\n context.abortSignal ?? new AbortController().signal,\n (partial) => onUpdate({ content: partial.content as never, details: partial.details }),\n );\n return { content: result.content as never, details: result.details };\n },\n };\n}\n\n/** Validate and project native fields before a source fork can publish a child journal. */\nexport function composeDirectHarnessRequestOptions(\n request: DoomChildSessionRequest,\n): Pick<DirectHarnessRuntimeOptions, 'systemPrompt' | 'tools' | 'activeToolNames'> {\n const unsupported = [\n ...(hasConfiguredValues(request.extensions) ? ['extensions'] : []),\n ...(hasConfiguredValues(request.subagentOnlyExtensions) ? ['subagentOnlyExtensions'] : []),\n ...(hasConfiguredValues(request.mcpDirectTools) ? ['mcpDirectTools'] : []),\n ...(hasConfiguredValues(request.capabilityCeiling?.allowedExternalProfiles) ? ['allowedExternalProfiles'] : []),\n ];\n if (unsupported.length > 0) {\n throw new Error(\n `Native child session configuration is unsupported by the direct harness: ${unsupported.join(', ')}`,\n );\n }\n\n const requested = request.tools ?? Object.keys(NATIVE_TOOL_FACTORIES);\n const excluded = new Set(request.excludeTools ?? []);\n const allowed = request.capabilityCeiling?.allowedTools;\n const names = requested.filter((name) => !excluded.has(name) && (allowed === undefined || allowed.includes(name)));\n const unknown = names.filter((name) => !(name in NATIVE_TOOL_FACTORIES));\n if (unknown.length > 0)\n throw new Error(`Native child session requested unknown direct harness tools: ${unknown.join(', ')}`);\n const required = request.capabilityCeiling?.requiredTools ?? [];\n const missing = required.filter((name) => !names.includes(name));\n if (missing.length > 0)\n throw new Error(`Native child session capability ceiling requires unavailable tools: ${missing.join(', ')}`);\n const tools = names.map((name) =>\n adaptNativeTool(NATIVE_TOOL_FACTORIES[name as keyof typeof NATIVE_TOOL_FACTORIES](request.cwd) as NativeCodingTool),\n );\n return {\n tools,\n activeToolNames: names,\n ...(request.systemPrompt === undefined ? {} : { systemPrompt: request.systemPrompt }),\n };\n}\n\nasync function forkChildJournal(\n sourcePath: string,\n branch: string,\n entryId: string | undefined,\n ownership: HistoryOwnership,\n): Promise<string> {\n const directory = path.dirname(path.resolve(sourcePath));\n const sourceRepository = new SqliteSessionRepo({\n directory,\n databasePath: sourcePath,\n databaseFactory: createNodeSqliteFactory(),\n });\n const sources = await sourceRepository.list(undefined, BACKGROUND_CONTEXT);\n await sourceRepository.close(BACKGROUND_CONTEXT);\n if (sources.length !== 1)\n throw new Error('Child source must be an existing SQLite session; import JSONL offline first.');\n const id = randomUUID();\n const destination = path.join(directory, `${id}.sqlite`);\n const lease = await ownership.acquire(destination);\n const repository = new SqliteSessionRepo({ directory, databaseFactory: createNodeSqliteFactory() });\n try {\n await lease.assertQuiescent();\n const fork = await repository.fork(\n sources[0]!,\n {\n scope: 'branch',\n branch,\n id,\n ...(entryId === undefined ? {} : { entryId }),\n },\n BACKGROUND_CONTEXT,\n );\n await fork.close(BACKGROUND_CONTEXT);\n return destination;\n } finally {\n try {\n await repository.close(BACKGROUND_CONTEXT);\n } finally {\n await lease.release();\n }\n }\n}\n\nexport function createHeadlessChildSessionService(\n options: HeadlessChildSessionServiceOptions,\n): DoomChildSessionService {\n const runtimeFactory = options.runtimeFactory ?? createDirectHarnessRuntime;\n const ownership = options.historyOwnership ?? createHistoryOwnership({ sourceFormat: 'sqlite' });\n\n return createDoomChildSessionService(\n async (request: DoomChildSessionRequest, signal): Promise<DoomChildSessionRuntime> => {\n signal?.throwIfAborted();\n if (request.source.kind === 'terminal-pi-fork')\n throw new Error('Headless child sessions do not support terminal Pi sources.');\n const directRequestOptions = composeDirectHarnessRequestOptions(request);\n\n let sessionPath: string | undefined;\n let sessionId: string | undefined;\n if (request.source.kind === 'v4-restore') {\n sessionPath = path.resolve(request.source.sessionFile);\n if (path.extname(sessionPath) !== '.sqlite')\n throw new Error('Server child restore requires SQLite; import JSONL offline first.');\n } else if (request.source.kind === 'v4-fork') {\n sessionPath = await forkChildJournal(\n request.source.sessionFile,\n request.source.branch,\n request.source.entryId,\n ownership,\n );\n } else {\n sessionId = randomUUID();\n }\n\n const requestedModel = parseChildModelReference(request.model);\n const model = requestedModel?.model ?? options.defaultModel?.();\n const thinking = request.thinking ?? requestedModel?.thinking;\n const providers = resolveChildProviders(options.providers);\n const runtimeOptions: DirectHarnessRuntimeOptions = {\n storage: 'sqlite',\n ...(request.source.kind === 'v4-fork' ? { lane: request.source.branch } : {}),\n cwd: request.cwd || options.cwd,\n ...(sessionId === undefined ? {} : { sessionId }),\n parentSessionId: request.parentSessionId || options.parentSessionId,\n ...(sessionPath === undefined ? {} : { sessionPath }),\n ...(options.sessionsRoot === undefined ? {} : { sessionsRoot: options.sessionsRoot }),\n ...(options.models === undefined ? {} : { models: options.models }),\n ...(providers === undefined ? {} : { providers }),\n ...(model === undefined ? {} : { model }),\n ...(thinking === undefined ? {} : { thinkingLevel: thinking as never }),\n ...directRequestOptions,\n historyOwnership: ownership,\n };\n\n let runtime: DirectHarnessRuntime | undefined;\n try {\n runtime = await runtimeFactory(runtimeOptions);\n await installIntercom(runtime, request.intercom, (runtimeOptions.tools ?? []) as DirectHarnessTool[]);\n const file = sessionFile(runtime);\n return childRuntime(runtime, request.intercom, file ? registerNativeChild(file, runtime) : undefined);\n } catch (error) {\n let failure: unknown = error;\n try {\n await runtime?.dispose();\n } catch (cleanupError) {\n failure = new AggregateError([error, cleanupError], 'Headless child startup cleanup failed');\n } finally {\n request.intercom?.dispose?.();\n if (sessionPath !== undefined && request.source.kind === 'v4-fork')\n for (const suffix of ['', '-wal', '-shm']) fs.rmSync(sessionPath + suffix, { force: true });\n }\n throw failure;\n }\n },\n { now: options.now ?? Date.now },\n );\n}\n\nexport function createHeadlessChildSessionServiceProvider(\n options: HeadlessChildSessionServiceOptions,\n): HeadlessChildSessionServiceProvider {\n const service = createHeadlessChildSessionService(options);\n return {\n get: () => service,\n close: () => service.close(),\n };\n}\n\nexport type { DirectHarnessRuntime, DirectHarnessRuntimeOptions } from '../../../server/directHarnessRuntime';\nexport type { DirectHarnessModel } from '../../../types/server/directHarnessRuntime';\n"],"mappings":"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"}
1
+ {"version":3,"file":"headlessChildSessionService.cjs","names":["readNativeChildTranscript","promptForAssistantText","createReadTool","createBashTool","createEditTool","createWriteTool","createGrepTool","createFindTool","createLsTool","prompt","path","SqliteSessionRepo","createNodeSqliteFactory","BACKGROUND_CONTEXT","randomUUID","createDirectHarnessRuntime","createHistoryOwnership","createDoomChildSessionService","registerNativeChild"],"sources":["../../../../../src/systems/child/adapters/headlessChildSessionService.ts"],"sourcesContent":["import { randomUUID } from 'node:crypto';\nimport fs from 'node:fs';\nimport path from 'node:path';\n\nimport { BACKGROUND_CONTEXT } from '@earendil-works/pi-agent-core/harness/context';\nimport type { Models, MutableModels, Provider } from '@earendil-works/pi-ai';\nimport {\n createBashTool,\n createEditTool,\n createFindTool,\n createGrepTool,\n createLsTool,\n createReadTool,\n createWriteTool,\n} from '@earendil-works/pi-coding-agent';\nimport { SqliteSessionRepo, createNodeSqliteFactory } from '@earendil-works/pi-session-backend-sqlite-node';\n\nimport {\n createDoomChildSessionService,\n type DoomChildSessionIntercom,\n type DoomChildSessionRequest,\n type DoomChildSessionRuntime,\n type DoomChildSessionService,\n type DoomChildSessionServiceProvider,\n type DoomChildSessionTool,\n} from '../../../exports/childSession';\nimport {\n createDirectHarnessRuntime,\n promptForAssistantText,\n type DirectHarnessRuntime,\n type DirectHarnessRuntimeOptions,\n} from '../../../server/directHarnessRuntime';\nimport { readNativeChildTranscript } from '../../../server/nativeChildTranscriptReader';\nimport type { HistoryOwnership } from '../../../services/historyImport';\nimport { createHistoryOwnership } from '../../../services/historyOwnership';\nimport type { DirectHarnessModel } from '../../../types/server/directHarnessRuntime';\nimport { registerNativeChild } from './nativeChildRuntimes';\n\nexport interface HeadlessChildSessionServiceOptions {\n readonly parentSessionId: string;\n readonly cwd: string;\n readonly sessionsRoot?: string;\n readonly models?: Models | MutableModels;\n /**\n * Providers to merge into the model registry for every child spawn. A thunk\n * is resolved per spawn so providers registered after this service was built,\n * such as Pi extension providers, are still visible to the child.\n */\n readonly providers?: readonly Provider[] | (() => readonly Provider[]);\n readonly defaultModel?: () => DirectHarnessModel | undefined;\n /** Resolve the current session's MCP dispatcher at spawn and invocation time. */\n readonly mcpTool?: () => DoomChildSessionTool | undefined;\n readonly historyOwnership?: HistoryOwnership;\n readonly now?: () => number;\n readonly runtimeFactory?: (options: DirectHarnessRuntimeOptions) => Promise<DirectHarnessRuntime>;\n}\n\nexport interface HeadlessChildSessionServiceProvider extends DoomChildSessionServiceProvider {\n close(): Promise<void>;\n}\n\nconst THINKING_SUFFIX_PATTERN = /:(off|minimal|low|medium|high|xhigh|max)$/;\n\nexport interface ParsedChildModel {\n readonly model: DirectHarnessModel;\n readonly thinking?: string;\n}\n\n/**\n * Child model specs may carry a Pi thinking suffix, for example\n * `anthropic-vertex/claude-sonnet-5:medium`. The suffix is a request option and\n * never part of the model id, so it has to be split off before model lookup.\n */\nexport function parseChildModelReference(value: string | undefined): ParsedChildModel | undefined {\n if (value === undefined) return undefined;\n const suffix = THINKING_SUFFIX_PATTERN.exec(value);\n const reference = suffix === null ? value : value.slice(0, value.length - suffix[0].length);\n const separator = reference.indexOf('/');\n if (separator <= 0 || separator === reference.length - 1)\n throw new Error(`Child model must use the provider/model form: ${value}`);\n return {\n model: { provider: reference.slice(0, separator), id: reference.slice(separator + 1) },\n ...(suffix === null ? {} : { thinking: suffix[1] as string }),\n };\n}\n\n/** Resolve the provider set for one spawn, tolerating both a fixed array and a thunk. */\nexport function resolveChildProviders(\n providers: readonly Provider[] | (() => readonly Provider[]) | undefined,\n): readonly Provider[] | undefined {\n const resolved = typeof providers === 'function' ? providers() : providers;\n return resolved === undefined || resolved.length === 0 ? undefined : resolved;\n}\n\nfunction sessionFile(runtime: DirectHarnessRuntime): string | undefined {\n const metadata = runtime.session.metadata as unknown as { path?: unknown };\n return typeof metadata.path === 'string' ? metadata.path : undefined;\n}\n\nfunction childRuntime(\n runtime: DirectHarnessRuntime,\n intercom?: DoomChildSessionIntercom,\n release?: () => void,\n): DoomChildSessionRuntime {\n const file = sessionFile(runtime);\n return {\n sessionId: runtime.sessionId,\n ...(file === undefined ? {} : { sessionFile: file }),\n ...(file === undefined\n ? {}\n : { readTranscriptPage: (request, signal) => readNativeChildTranscript(file, request, signal) }),\n prompt: (task) => promptForAssistantText(runtime, task),\n steer: (message) => runtime.steer(message),\n followUp: (message) => runtime.followUp(message),\n onUsage(listener) {\n return runtime.onEvent((event) => {\n if (event.type !== 'usage') return;\n listener({ rowId: event.row.id, cost: event.row.usage.cost.total });\n });\n },\n abort: () => runtime.abort(),\n dispose: async () => {\n try {\n await runtime.dispose();\n } finally {\n release?.();\n intercom?.dispose?.();\n }\n },\n };\n}\n\ntype DirectHarnessTool = Parameters<DirectHarnessRuntime['replaceTools']>[0][number];\n\nasync function installIntercom(\n runtime: DirectHarnessRuntime,\n intercom: DoomChildSessionIntercom | undefined,\n tools: DirectHarnessTool[],\n): Promise<void> {\n if (!intercom) return;\n const tool = intercom.bindRuntime(childRuntime(runtime));\n const adapted = {\n ...tool,\n parameters: tool.parameters as never,\n execute: (operationId: string, params: unknown, signal: AbortSignal, onUpdate: unknown) =>\n tool.execute(operationId, params, signal, onUpdate as never),\n } as unknown as DirectHarnessTool;\n await runtime.replaceTools([...tools, adapted]);\n}\n\nfunction hasConfiguredValues(value: readonly string[] | undefined): boolean {\n return value !== undefined && value.length > 0;\n}\n\nconst NATIVE_TOOL_FACTORIES = {\n read: createReadTool,\n bash: createBashTool,\n edit: createEditTool,\n write: createWriteTool,\n grep: createGrepTool,\n find: createFindTool,\n ls: createLsTool,\n} as const;\n\ntype NativeCodingTool = ReturnType<(typeof NATIVE_TOOL_FACTORIES)[keyof typeof NATIVE_TOOL_FACTORIES]>;\n\nfunction adaptNativeTool(tool: NativeCodingTool | DoomChildSessionTool): DirectHarnessTool {\n const prompt = tool as (NativeCodingTool | DoomChildSessionTool) & {\n promptSnippet?: string;\n promptGuidelines?: string[];\n };\n return {\n ...prompt,\n label: 'label' in tool ? tool.label : tool.name,\n parameters: tool.parameters as never,\n async execute(toolCallId, parameters, onUpdate, _toolContext, _invocation, context) {\n const execute = tool.execute as (\n id: string,\n params: unknown,\n signal: AbortSignal,\n update: (result: { content: unknown; details?: unknown }) => void,\n ) => Promise<{ content: unknown; details?: unknown; isError?: boolean }>;\n const result = await execute(\n toolCallId,\n parameters,\n context.abortSignal ?? new AbortController().signal,\n (partial) => onUpdate({ content: partial.content as never, details: partial.details }),\n );\n if (result.isError) {\n const content = result.content as DoomChildSessionToolResultContent;\n throw new Error(\n content\n .filter((part) => part.type === 'text')\n .map((part) => part.text)\n .join('\\n') || 'MCP tool failed.',\n );\n }\n return { content: result.content as never, details: result.details };\n },\n };\n}\n\ntype DoomChildSessionToolResultContent = Awaited<ReturnType<DoomChildSessionTool['execute']>>['content'];\n\n/** Validate and project native fields before a source fork can publish a child journal. */\nexport function composeDirectHarnessRequestOptions(\n request: DoomChildSessionRequest,\n resolveMcpTool?: () => DoomChildSessionTool | undefined,\n): Pick<DirectHarnessRuntimeOptions, 'systemPrompt' | 'tools' | 'activeToolNames'> {\n const unsupported = [\n ...(hasConfiguredValues(request.extensions) ? ['extensions'] : []),\n ...(hasConfiguredValues(request.subagentOnlyExtensions) ? ['subagentOnlyExtensions'] : []),\n ...(hasConfiguredValues(request.mcpDirectTools) ? ['mcpDirectTools'] : []),\n ...(hasConfiguredValues(request.capabilityCeiling?.allowedExternalProfiles) ? ['allowedExternalProfiles'] : []),\n ];\n if (unsupported.length > 0) {\n throw new Error(\n `Native child session configuration is unsupported by the direct harness: ${unsupported.join(', ')}`,\n );\n }\n\n const requested = [...new Set(request.tools ?? Object.keys(NATIVE_TOOL_FACTORIES))];\n const excluded = new Set(request.excludeTools ?? []);\n const allowed = request.capabilityCeiling?.allowedTools;\n const isMcp = (name: string) => name === 'mcp' || name === 'mcp_use';\n const mcpDenied = request.capabilityCeiling?.allowMcpTools === false || [...excluded].some(isMcp);\n const names = requested.filter(\n (name) => !excluded.has(name) && (allowed === undefined || allowed.includes(name)) && !(isMcp(name) && mcpDenied),\n );\n const unknown = names.filter((name) => !Object.hasOwn(NATIVE_TOOL_FACTORIES, name) && !isMcp(name));\n if (unknown.length > 0)\n throw new Error(`Native child session requested unknown direct harness tools: ${unknown.join(', ')}`);\n const required = request.capabilityCeiling?.requiredTools ?? [];\n const missing = required.filter((name) => !names.includes(name));\n if (missing.length > 0)\n throw new Error(`Native child session capability ceiling requires unavailable tools: ${missing.join(', ')}`);\n const mcpTool = names.some(isMcp) ? resolveMcpTool?.() : undefined;\n if (names.some(isMcp) && !mcpTool)\n throw new Error('Native child session MCP tools are unavailable. Enable MCP in the parent session.');\n const tools = names.map((name) => {\n if (!isMcp(name))\n return adaptNativeTool(\n NATIVE_TOOL_FACTORIES[name as keyof typeof NATIVE_TOOL_FACTORIES](request.cwd) as NativeCodingTool,\n );\n return adaptNativeTool({\n ...mcpTool!,\n name,\n execute(toolCallId, parameters, signal, onUpdate) {\n signal?.throwIfAborted();\n if (resolveMcpTool?.() !== mcpTool)\n throw new Error('The parent session MCP dispatcher is no longer available.');\n return mcpTool!.execute(toolCallId, parameters, signal, onUpdate);\n },\n } satisfies DoomChildSessionTool);\n });\n return {\n tools,\n activeToolNames: names,\n ...(request.systemPrompt === undefined ? {} : { systemPrompt: request.systemPrompt }),\n };\n}\n\nasync function forkChildJournal(\n sourcePath: string,\n branch: string,\n entryId: string | undefined,\n ownership: HistoryOwnership,\n): Promise<string> {\n const directory = path.dirname(path.resolve(sourcePath));\n const sourceRepository = new SqliteSessionRepo({\n directory,\n databasePath: sourcePath,\n databaseFactory: createNodeSqliteFactory(),\n });\n const sources = await sourceRepository.list(undefined, BACKGROUND_CONTEXT);\n await sourceRepository.close(BACKGROUND_CONTEXT);\n if (sources.length !== 1)\n throw new Error('Child source must be an existing SQLite session; import JSONL offline first.');\n const id = randomUUID();\n const destination = path.join(directory, `${id}.sqlite`);\n const lease = await ownership.acquire(destination);\n const repository = new SqliteSessionRepo({ directory, databaseFactory: createNodeSqliteFactory() });\n try {\n await lease.assertQuiescent();\n const fork = await repository.fork(\n sources[0]!,\n {\n scope: 'branch',\n branch,\n id,\n ...(entryId === undefined ? {} : { entryId }),\n },\n BACKGROUND_CONTEXT,\n );\n await fork.close(BACKGROUND_CONTEXT);\n return destination;\n } finally {\n try {\n await repository.close(BACKGROUND_CONTEXT);\n } finally {\n await lease.release();\n }\n }\n}\n\nexport function createHeadlessChildSessionService(\n options: HeadlessChildSessionServiceOptions,\n): DoomChildSessionService {\n const runtimeFactory = options.runtimeFactory ?? createDirectHarnessRuntime;\n const ownership = options.historyOwnership ?? createHistoryOwnership({ sourceFormat: 'sqlite' });\n\n return createDoomChildSessionService(\n async (request: DoomChildSessionRequest, signal): Promise<DoomChildSessionRuntime> => {\n signal?.throwIfAborted();\n if (request.source.kind === 'terminal-pi-fork')\n throw new Error('Headless child sessions do not support terminal Pi sources.');\n const directRequestOptions = composeDirectHarnessRequestOptions(request, options.mcpTool);\n\n let sessionPath: string | undefined;\n let sessionId: string | undefined;\n if (request.source.kind === 'v4-restore') {\n sessionPath = path.resolve(request.source.sessionFile);\n if (path.extname(sessionPath) !== '.sqlite')\n throw new Error('Server child restore requires SQLite; import JSONL offline first.');\n } else if (request.source.kind === 'v4-fork') {\n sessionPath = await forkChildJournal(\n request.source.sessionFile,\n request.source.branch,\n request.source.entryId,\n ownership,\n );\n } else {\n sessionId = randomUUID();\n }\n\n const requestedModel = parseChildModelReference(request.model);\n const model = requestedModel?.model ?? options.defaultModel?.();\n const thinking = request.thinking ?? requestedModel?.thinking;\n const providers = resolveChildProviders(options.providers);\n const runtimeOptions: DirectHarnessRuntimeOptions = {\n storage: 'sqlite',\n ...(request.source.kind === 'v4-fork' ? { lane: request.source.branch } : {}),\n cwd: request.cwd || options.cwd,\n ...(sessionId === undefined ? {} : { sessionId }),\n parentSessionId: request.parentSessionId || options.parentSessionId,\n ...(sessionPath === undefined ? {} : { sessionPath }),\n ...(options.sessionsRoot === undefined ? {} : { sessionsRoot: options.sessionsRoot }),\n ...(options.models === undefined ? {} : { models: options.models }),\n ...(providers === undefined ? {} : { providers }),\n ...(model === undefined ? {} : { model }),\n ...(thinking === undefined ? {} : { thinkingLevel: thinking as never }),\n ...directRequestOptions,\n historyOwnership: ownership,\n };\n\n let runtime: DirectHarnessRuntime | undefined;\n try {\n runtime = await runtimeFactory(runtimeOptions);\n await installIntercom(runtime, request.intercom, (runtimeOptions.tools ?? []) as DirectHarnessTool[]);\n const file = sessionFile(runtime);\n return childRuntime(runtime, request.intercom, file ? registerNativeChild(file, runtime) : undefined);\n } catch (error) {\n let failure: unknown = error;\n try {\n await runtime?.dispose();\n } catch (cleanupError) {\n failure = new AggregateError([error, cleanupError], 'Headless child startup cleanup failed');\n } finally {\n request.intercom?.dispose?.();\n if (sessionPath !== undefined && request.source.kind === 'v4-fork')\n for (const suffix of ['', '-wal', '-shm']) fs.rmSync(sessionPath + suffix, { force: true });\n }\n throw failure;\n }\n },\n { now: options.now ?? Date.now },\n );\n}\n\nexport function createHeadlessChildSessionServiceProvider(\n options: HeadlessChildSessionServiceOptions,\n): HeadlessChildSessionServiceProvider {\n const service = createHeadlessChildSessionService(options);\n return {\n get: () => service,\n close: () => service.close(),\n };\n}\n\nexport type { DirectHarnessRuntime, DirectHarnessRuntimeOptions } from '../../../server/directHarnessRuntime';\nexport type { DirectHarnessModel } from '../../../types/server/directHarnessRuntime';\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { DoomChildSessionService, DoomChildSessionServiceProvider } from "../types/childSession.mjs";
1
+ import { DoomChildSessionService, DoomChildSessionServiceProvider, DoomChildSessionTool } from "../types/childSession.mjs";
2
2
  import "../../../../childSession.mjs";
3
3
  import { HistoryOwnership } from "../../../../historyImport.mjs";
4
4
  import { DirectHarnessModel, DirectHarnessRuntime, DirectHarnessRuntimeOptions } from "../../../types/server/directHarnessRuntime.mjs";
@@ -17,6 +17,8 @@ export interface HeadlessChildSessionServiceOptions {
17
17
  */
18
18
  readonly providers?: readonly Provider[] | (() => readonly Provider[]);
19
19
  readonly defaultModel?: () => DirectHarnessModel | undefined;
20
+ /** Resolve the current session's MCP dispatcher at spawn and invocation time. */
21
+ readonly mcpTool?: () => DoomChildSessionTool | undefined;
20
22
  readonly historyOwnership?: HistoryOwnership;
21
23
  readonly now?: () => number;
22
24
  readonly runtimeFactory?: (options: DirectHarnessRuntimeOptions) => Promise<DirectHarnessRuntime>;
@@ -1 +1 @@
1
- {"version":3,"file":"headlessChildSessionService.d.mts","names":[],"sources":["../../../../../src/systems/child/adapters/headlessChildSessionService.ts"],"mappings":";;;;;;;iBAqCiB;WACN;WACA;WACA;WACA,SAAS,SAAS;;;;;;WAMlB,qBAAqB,6BAA6B;WAClD,qBAAqB;WACrB,mBAAmB;WACnB;WACA,kBAAkB,SAAS,gCAAgC,QAAQ;;iBAG7D,4CAA4C;EAC3D,SAAS;;wBAsNK,kCACd,SAAS,qCACR;wBAwEa,0CACd,SAAS,qCACR"}
1
+ {"version":3,"file":"headlessChildSessionService.d.mts","names":[],"sources":["../../../../../src/systems/child/adapters/headlessChildSessionService.ts"],"mappings":";;;;;;;iBAsCiB;WACN;WACA;WACA;WACA,SAAS,SAAS;;;;;;WAMlB,qBAAqB,6BAA6B;WAClD,qBAAqB;;WAErB,gBAAgB;WAChB,mBAAmB;WACnB;WACA,kBAAkB,SAAS,gCAAgC,QAAQ;;iBAG7D,4CAA4C;EAC3D,SAAS;;wBAuPK,kCACd,SAAS,qCACR;wBAwEa,0CACd,SAAS,qCACR"}
@@ -93,6 +93,7 @@ const NATIVE_TOOL_FACTORIES = {
93
93
  function adaptNativeTool(tool) {
94
94
  return {
95
95
  ...tool,
96
+ label: "label" in tool ? tool.label : tool.name,
96
97
  parameters: tool.parameters,
97
98
  async execute(toolCallId, parameters, onUpdate, _toolContext, _invocation, context) {
98
99
  const execute = tool.execute;
@@ -100,6 +101,10 @@ function adaptNativeTool(tool) {
100
101
  content: partial.content,
101
102
  details: partial.details
102
103
  }));
104
+ if (result.isError) {
105
+ const content = result.content;
106
+ throw new Error(content.filter((part) => part.type === "text").map((part) => part.text).join("\n") || "MCP tool failed.");
107
+ }
103
108
  return {
104
109
  content: result.content,
105
110
  details: result.details
@@ -108,7 +113,7 @@ function adaptNativeTool(tool) {
108
113
  };
109
114
  }
110
115
  /** Validate and project native fields before a source fork can publish a child journal. */
111
- function composeDirectHarnessRequestOptions(request) {
116
+ function composeDirectHarnessRequestOptions(request, resolveMcpTool) {
112
117
  const unsupported = [
113
118
  ...hasConfiguredValues(request.extensions) ? ["extensions"] : [],
114
119
  ...hasConfiguredValues(request.subagentOnlyExtensions) ? ["subagentOnlyExtensions"] : [],
@@ -116,16 +121,31 @@ function composeDirectHarnessRequestOptions(request) {
116
121
  ...hasConfiguredValues(request.capabilityCeiling?.allowedExternalProfiles) ? ["allowedExternalProfiles"] : []
117
122
  ];
118
123
  if (unsupported.length > 0) throw new Error(`Native child session configuration is unsupported by the direct harness: ${unsupported.join(", ")}`);
119
- const requested = request.tools ?? Object.keys(NATIVE_TOOL_FACTORIES);
124
+ const requested = [...new Set(request.tools ?? Object.keys(NATIVE_TOOL_FACTORIES))];
120
125
  const excluded = new Set(request.excludeTools ?? []);
121
126
  const allowed = request.capabilityCeiling?.allowedTools;
122
- const names = requested.filter((name) => !excluded.has(name) && (allowed === void 0 || allowed.includes(name)));
123
- const unknown = names.filter((name) => !(name in NATIVE_TOOL_FACTORIES));
127
+ const isMcp = (name) => name === "mcp" || name === "mcp_use";
128
+ const mcpDenied = request.capabilityCeiling?.allowMcpTools === false || [...excluded].some(isMcp);
129
+ const names = requested.filter((name) => !excluded.has(name) && (allowed === void 0 || allowed.includes(name)) && !(isMcp(name) && mcpDenied));
130
+ const unknown = names.filter((name) => !Object.hasOwn(NATIVE_TOOL_FACTORIES, name) && !isMcp(name));
124
131
  if (unknown.length > 0) throw new Error(`Native child session requested unknown direct harness tools: ${unknown.join(", ")}`);
125
132
  const missing = (request.capabilityCeiling?.requiredTools ?? []).filter((name) => !names.includes(name));
126
133
  if (missing.length > 0) throw new Error(`Native child session capability ceiling requires unavailable tools: ${missing.join(", ")}`);
134
+ const mcpTool = names.some(isMcp) ? resolveMcpTool?.() : void 0;
135
+ if (names.some(isMcp) && !mcpTool) throw new Error("Native child session MCP tools are unavailable. Enable MCP in the parent session.");
127
136
  return {
128
- tools: names.map((name) => adaptNativeTool(NATIVE_TOOL_FACTORIES[name](request.cwd))),
137
+ tools: names.map((name) => {
138
+ if (!isMcp(name)) return adaptNativeTool(NATIVE_TOOL_FACTORIES[name](request.cwd));
139
+ return adaptNativeTool({
140
+ ...mcpTool,
141
+ name,
142
+ execute(toolCallId, parameters, signal, onUpdate) {
143
+ signal?.throwIfAborted();
144
+ if (resolveMcpTool?.() !== mcpTool) throw new Error("The parent session MCP dispatcher is no longer available.");
145
+ return mcpTool.execute(toolCallId, parameters, signal, onUpdate);
146
+ }
147
+ });
148
+ }),
129
149
  activeToolNames: names,
130
150
  ...request.systemPrompt === void 0 ? {} : { systemPrompt: request.systemPrompt }
131
151
  };
@@ -170,7 +190,7 @@ function createHeadlessChildSessionService(options) {
170
190
  return createDoomChildSessionService(async (request, signal) => {
171
191
  signal?.throwIfAborted();
172
192
  if (request.source.kind === "terminal-pi-fork") throw new Error("Headless child sessions do not support terminal Pi sources.");
173
- const directRequestOptions = composeDirectHarnessRequestOptions(request);
193
+ const directRequestOptions = composeDirectHarnessRequestOptions(request, options.mcpTool);
174
194
  let sessionPath;
175
195
  let sessionId;
176
196
  if (request.source.kind === "v4-restore") {
@@ -1 +1 @@
1
- {"version":3,"file":"headlessChildSessionService.mjs","names":["prompt"],"sources":["../../../../../src/systems/child/adapters/headlessChildSessionService.ts"],"sourcesContent":["import { randomUUID } from 'node:crypto';\nimport fs from 'node:fs';\nimport path from 'node:path';\n\nimport { BACKGROUND_CONTEXT } from '@earendil-works/pi-agent-core/harness/context';\nimport type { Models, MutableModels, Provider } from '@earendil-works/pi-ai';\nimport {\n createBashTool,\n createEditTool,\n createFindTool,\n createGrepTool,\n createLsTool,\n createReadTool,\n createWriteTool,\n} from '@earendil-works/pi-coding-agent';\nimport { SqliteSessionRepo, createNodeSqliteFactory } from '@earendil-works/pi-session-backend-sqlite-node';\n\nimport {\n createDoomChildSessionService,\n type DoomChildSessionIntercom,\n type DoomChildSessionRequest,\n type DoomChildSessionRuntime,\n type DoomChildSessionService,\n type DoomChildSessionServiceProvider,\n} from '../../../exports/childSession';\nimport {\n createDirectHarnessRuntime,\n promptForAssistantText,\n type DirectHarnessRuntime,\n type DirectHarnessRuntimeOptions,\n} from '../../../server/directHarnessRuntime';\nimport { readNativeChildTranscript } from '../../../server/nativeChildTranscriptReader';\nimport type { HistoryOwnership } from '../../../services/historyImport';\nimport { createHistoryOwnership } from '../../../services/historyOwnership';\nimport type { DirectHarnessModel } from '../../../types/server/directHarnessRuntime';\nimport { registerNativeChild } from './nativeChildRuntimes';\n\nexport interface HeadlessChildSessionServiceOptions {\n readonly parentSessionId: string;\n readonly cwd: string;\n readonly sessionsRoot?: string;\n readonly models?: Models | MutableModels;\n /**\n * Providers to merge into the model registry for every child spawn. A thunk\n * is resolved per spawn so providers registered after this service was built,\n * such as Pi extension providers, are still visible to the child.\n */\n readonly providers?: readonly Provider[] | (() => readonly Provider[]);\n readonly defaultModel?: () => DirectHarnessModel | undefined;\n readonly historyOwnership?: HistoryOwnership;\n readonly now?: () => number;\n readonly runtimeFactory?: (options: DirectHarnessRuntimeOptions) => Promise<DirectHarnessRuntime>;\n}\n\nexport interface HeadlessChildSessionServiceProvider extends DoomChildSessionServiceProvider {\n close(): Promise<void>;\n}\n\nconst THINKING_SUFFIX_PATTERN = /:(off|minimal|low|medium|high|xhigh|max)$/;\n\nexport interface ParsedChildModel {\n readonly model: DirectHarnessModel;\n readonly thinking?: string;\n}\n\n/**\n * Child model specs may carry a Pi thinking suffix, for example\n * `anthropic-vertex/claude-sonnet-5:medium`. The suffix is a request option and\n * never part of the model id, so it has to be split off before model lookup.\n */\nexport function parseChildModelReference(value: string | undefined): ParsedChildModel | undefined {\n if (value === undefined) return undefined;\n const suffix = THINKING_SUFFIX_PATTERN.exec(value);\n const reference = suffix === null ? value : value.slice(0, value.length - suffix[0].length);\n const separator = reference.indexOf('/');\n if (separator <= 0 || separator === reference.length - 1)\n throw new Error(`Child model must use the provider/model form: ${value}`);\n return {\n model: { provider: reference.slice(0, separator), id: reference.slice(separator + 1) },\n ...(suffix === null ? {} : { thinking: suffix[1] as string }),\n };\n}\n\n/** Resolve the provider set for one spawn, tolerating both a fixed array and a thunk. */\nexport function resolveChildProviders(\n providers: readonly Provider[] | (() => readonly Provider[]) | undefined,\n): readonly Provider[] | undefined {\n const resolved = typeof providers === 'function' ? providers() : providers;\n return resolved === undefined || resolved.length === 0 ? undefined : resolved;\n}\n\nfunction sessionFile(runtime: DirectHarnessRuntime): string | undefined {\n const metadata = runtime.session.metadata as unknown as { path?: unknown };\n return typeof metadata.path === 'string' ? metadata.path : undefined;\n}\n\nfunction childRuntime(\n runtime: DirectHarnessRuntime,\n intercom?: DoomChildSessionIntercom,\n release?: () => void,\n): DoomChildSessionRuntime {\n const file = sessionFile(runtime);\n return {\n sessionId: runtime.sessionId,\n ...(file === undefined ? {} : { sessionFile: file }),\n ...(file === undefined\n ? {}\n : { readTranscriptPage: (request, signal) => readNativeChildTranscript(file, request, signal) }),\n prompt: (task) => promptForAssistantText(runtime, task),\n steer: (message) => runtime.steer(message),\n followUp: (message) => runtime.followUp(message),\n onUsage(listener) {\n return runtime.onEvent((event) => {\n if (event.type !== 'usage') return;\n listener({ rowId: event.row.id, cost: event.row.usage.cost.total });\n });\n },\n abort: () => runtime.abort(),\n dispose: async () => {\n try {\n await runtime.dispose();\n } finally {\n release?.();\n intercom?.dispose?.();\n }\n },\n };\n}\n\ntype DirectHarnessTool = Parameters<DirectHarnessRuntime['replaceTools']>[0][number];\n\nasync function installIntercom(\n runtime: DirectHarnessRuntime,\n intercom: DoomChildSessionIntercom | undefined,\n tools: DirectHarnessTool[],\n): Promise<void> {\n if (!intercom) return;\n const tool = intercom.bindRuntime(childRuntime(runtime));\n const adapted = {\n ...tool,\n parameters: tool.parameters as never,\n execute: (operationId: string, params: unknown, signal: AbortSignal, onUpdate: unknown) =>\n tool.execute(operationId, params, signal, onUpdate as never),\n } as unknown as DirectHarnessTool;\n await runtime.replaceTools([...tools, adapted]);\n}\n\nfunction hasConfiguredValues(value: readonly string[] | undefined): boolean {\n return value !== undefined && value.length > 0;\n}\n\nconst NATIVE_TOOL_FACTORIES = {\n read: createReadTool,\n bash: createBashTool,\n edit: createEditTool,\n write: createWriteTool,\n grep: createGrepTool,\n find: createFindTool,\n ls: createLsTool,\n} as const;\n\ntype NativeCodingTool = ReturnType<(typeof NATIVE_TOOL_FACTORIES)[keyof typeof NATIVE_TOOL_FACTORIES]>;\n\nfunction adaptNativeTool(tool: NativeCodingTool): DirectHarnessTool {\n const prompt = tool as NativeCodingTool & {\n promptSnippet?: string;\n promptGuidelines?: string[];\n };\n return {\n ...prompt,\n parameters: tool.parameters as never,\n async execute(toolCallId, parameters, onUpdate, _toolContext, _invocation, context) {\n const execute = tool.execute as (\n id: string,\n params: unknown,\n signal: AbortSignal,\n update: (result: { content: unknown; details?: unknown }) => void,\n ) => Promise<{ content: unknown; details?: unknown }>;\n const result = await execute(\n toolCallId,\n parameters,\n context.abortSignal ?? new AbortController().signal,\n (partial) => onUpdate({ content: partial.content as never, details: partial.details }),\n );\n return { content: result.content as never, details: result.details };\n },\n };\n}\n\n/** Validate and project native fields before a source fork can publish a child journal. */\nexport function composeDirectHarnessRequestOptions(\n request: DoomChildSessionRequest,\n): Pick<DirectHarnessRuntimeOptions, 'systemPrompt' | 'tools' | 'activeToolNames'> {\n const unsupported = [\n ...(hasConfiguredValues(request.extensions) ? ['extensions'] : []),\n ...(hasConfiguredValues(request.subagentOnlyExtensions) ? ['subagentOnlyExtensions'] : []),\n ...(hasConfiguredValues(request.mcpDirectTools) ? ['mcpDirectTools'] : []),\n ...(hasConfiguredValues(request.capabilityCeiling?.allowedExternalProfiles) ? ['allowedExternalProfiles'] : []),\n ];\n if (unsupported.length > 0) {\n throw new Error(\n `Native child session configuration is unsupported by the direct harness: ${unsupported.join(', ')}`,\n );\n }\n\n const requested = request.tools ?? Object.keys(NATIVE_TOOL_FACTORIES);\n const excluded = new Set(request.excludeTools ?? []);\n const allowed = request.capabilityCeiling?.allowedTools;\n const names = requested.filter((name) => !excluded.has(name) && (allowed === undefined || allowed.includes(name)));\n const unknown = names.filter((name) => !(name in NATIVE_TOOL_FACTORIES));\n if (unknown.length > 0)\n throw new Error(`Native child session requested unknown direct harness tools: ${unknown.join(', ')}`);\n const required = request.capabilityCeiling?.requiredTools ?? [];\n const missing = required.filter((name) => !names.includes(name));\n if (missing.length > 0)\n throw new Error(`Native child session capability ceiling requires unavailable tools: ${missing.join(', ')}`);\n const tools = names.map((name) =>\n adaptNativeTool(NATIVE_TOOL_FACTORIES[name as keyof typeof NATIVE_TOOL_FACTORIES](request.cwd) as NativeCodingTool),\n );\n return {\n tools,\n activeToolNames: names,\n ...(request.systemPrompt === undefined ? {} : { systemPrompt: request.systemPrompt }),\n };\n}\n\nasync function forkChildJournal(\n sourcePath: string,\n branch: string,\n entryId: string | undefined,\n ownership: HistoryOwnership,\n): Promise<string> {\n const directory = path.dirname(path.resolve(sourcePath));\n const sourceRepository = new SqliteSessionRepo({\n directory,\n databasePath: sourcePath,\n databaseFactory: createNodeSqliteFactory(),\n });\n const sources = await sourceRepository.list(undefined, BACKGROUND_CONTEXT);\n await sourceRepository.close(BACKGROUND_CONTEXT);\n if (sources.length !== 1)\n throw new Error('Child source must be an existing SQLite session; import JSONL offline first.');\n const id = randomUUID();\n const destination = path.join(directory, `${id}.sqlite`);\n const lease = await ownership.acquire(destination);\n const repository = new SqliteSessionRepo({ directory, databaseFactory: createNodeSqliteFactory() });\n try {\n await lease.assertQuiescent();\n const fork = await repository.fork(\n sources[0]!,\n {\n scope: 'branch',\n branch,\n id,\n ...(entryId === undefined ? {} : { entryId }),\n },\n BACKGROUND_CONTEXT,\n );\n await fork.close(BACKGROUND_CONTEXT);\n return destination;\n } finally {\n try {\n await repository.close(BACKGROUND_CONTEXT);\n } finally {\n await lease.release();\n }\n }\n}\n\nexport function createHeadlessChildSessionService(\n options: HeadlessChildSessionServiceOptions,\n): DoomChildSessionService {\n const runtimeFactory = options.runtimeFactory ?? createDirectHarnessRuntime;\n const ownership = options.historyOwnership ?? createHistoryOwnership({ sourceFormat: 'sqlite' });\n\n return createDoomChildSessionService(\n async (request: DoomChildSessionRequest, signal): Promise<DoomChildSessionRuntime> => {\n signal?.throwIfAborted();\n if (request.source.kind === 'terminal-pi-fork')\n throw new Error('Headless child sessions do not support terminal Pi sources.');\n const directRequestOptions = composeDirectHarnessRequestOptions(request);\n\n let sessionPath: string | undefined;\n let sessionId: string | undefined;\n if (request.source.kind === 'v4-restore') {\n sessionPath = path.resolve(request.source.sessionFile);\n if (path.extname(sessionPath) !== '.sqlite')\n throw new Error('Server child restore requires SQLite; import JSONL offline first.');\n } else if (request.source.kind === 'v4-fork') {\n sessionPath = await forkChildJournal(\n request.source.sessionFile,\n request.source.branch,\n request.source.entryId,\n ownership,\n );\n } else {\n sessionId = randomUUID();\n }\n\n const requestedModel = parseChildModelReference(request.model);\n const model = requestedModel?.model ?? options.defaultModel?.();\n const thinking = request.thinking ?? requestedModel?.thinking;\n const providers = resolveChildProviders(options.providers);\n const runtimeOptions: DirectHarnessRuntimeOptions = {\n storage: 'sqlite',\n ...(request.source.kind === 'v4-fork' ? { lane: request.source.branch } : {}),\n cwd: request.cwd || options.cwd,\n ...(sessionId === undefined ? {} : { sessionId }),\n parentSessionId: request.parentSessionId || options.parentSessionId,\n ...(sessionPath === undefined ? {} : { sessionPath }),\n ...(options.sessionsRoot === undefined ? {} : { sessionsRoot: options.sessionsRoot }),\n ...(options.models === undefined ? {} : { models: options.models }),\n ...(providers === undefined ? {} : { providers }),\n ...(model === undefined ? {} : { model }),\n ...(thinking === undefined ? {} : { thinkingLevel: thinking as never }),\n ...directRequestOptions,\n historyOwnership: ownership,\n };\n\n let runtime: DirectHarnessRuntime | undefined;\n try {\n runtime = await runtimeFactory(runtimeOptions);\n await installIntercom(runtime, request.intercom, (runtimeOptions.tools ?? []) as DirectHarnessTool[]);\n const file = sessionFile(runtime);\n return childRuntime(runtime, request.intercom, file ? registerNativeChild(file, runtime) : undefined);\n } catch (error) {\n let failure: unknown = error;\n try {\n await runtime?.dispose();\n } catch (cleanupError) {\n failure = new AggregateError([error, cleanupError], 'Headless child startup cleanup failed');\n } finally {\n request.intercom?.dispose?.();\n if (sessionPath !== undefined && request.source.kind === 'v4-fork')\n for (const suffix of ['', '-wal', '-shm']) fs.rmSync(sessionPath + suffix, { force: true });\n }\n throw failure;\n }\n },\n { now: options.now ?? Date.now },\n );\n}\n\nexport function createHeadlessChildSessionServiceProvider(\n options: HeadlessChildSessionServiceOptions,\n): HeadlessChildSessionServiceProvider {\n const service = createHeadlessChildSessionService(options);\n return {\n get: () => service,\n close: () => service.close(),\n };\n}\n\nexport type { DirectHarnessRuntime, DirectHarnessRuntimeOptions } from '../../../server/directHarnessRuntime';\nexport type { DirectHarnessModel } from '../../../types/server/directHarnessRuntime';\n"],"mappings":"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"}
1
+ {"version":3,"file":"headlessChildSessionService.mjs","names":["prompt"],"sources":["../../../../../src/systems/child/adapters/headlessChildSessionService.ts"],"sourcesContent":["import { randomUUID } from 'node:crypto';\nimport fs from 'node:fs';\nimport path from 'node:path';\n\nimport { BACKGROUND_CONTEXT } from '@earendil-works/pi-agent-core/harness/context';\nimport type { Models, MutableModels, Provider } from '@earendil-works/pi-ai';\nimport {\n createBashTool,\n createEditTool,\n createFindTool,\n createGrepTool,\n createLsTool,\n createReadTool,\n createWriteTool,\n} from '@earendil-works/pi-coding-agent';\nimport { SqliteSessionRepo, createNodeSqliteFactory } from '@earendil-works/pi-session-backend-sqlite-node';\n\nimport {\n createDoomChildSessionService,\n type DoomChildSessionIntercom,\n type DoomChildSessionRequest,\n type DoomChildSessionRuntime,\n type DoomChildSessionService,\n type DoomChildSessionServiceProvider,\n type DoomChildSessionTool,\n} from '../../../exports/childSession';\nimport {\n createDirectHarnessRuntime,\n promptForAssistantText,\n type DirectHarnessRuntime,\n type DirectHarnessRuntimeOptions,\n} from '../../../server/directHarnessRuntime';\nimport { readNativeChildTranscript } from '../../../server/nativeChildTranscriptReader';\nimport type { HistoryOwnership } from '../../../services/historyImport';\nimport { createHistoryOwnership } from '../../../services/historyOwnership';\nimport type { DirectHarnessModel } from '../../../types/server/directHarnessRuntime';\nimport { registerNativeChild } from './nativeChildRuntimes';\n\nexport interface HeadlessChildSessionServiceOptions {\n readonly parentSessionId: string;\n readonly cwd: string;\n readonly sessionsRoot?: string;\n readonly models?: Models | MutableModels;\n /**\n * Providers to merge into the model registry for every child spawn. A thunk\n * is resolved per spawn so providers registered after this service was built,\n * such as Pi extension providers, are still visible to the child.\n */\n readonly providers?: readonly Provider[] | (() => readonly Provider[]);\n readonly defaultModel?: () => DirectHarnessModel | undefined;\n /** Resolve the current session's MCP dispatcher at spawn and invocation time. */\n readonly mcpTool?: () => DoomChildSessionTool | undefined;\n readonly historyOwnership?: HistoryOwnership;\n readonly now?: () => number;\n readonly runtimeFactory?: (options: DirectHarnessRuntimeOptions) => Promise<DirectHarnessRuntime>;\n}\n\nexport interface HeadlessChildSessionServiceProvider extends DoomChildSessionServiceProvider {\n close(): Promise<void>;\n}\n\nconst THINKING_SUFFIX_PATTERN = /:(off|minimal|low|medium|high|xhigh|max)$/;\n\nexport interface ParsedChildModel {\n readonly model: DirectHarnessModel;\n readonly thinking?: string;\n}\n\n/**\n * Child model specs may carry a Pi thinking suffix, for example\n * `anthropic-vertex/claude-sonnet-5:medium`. The suffix is a request option and\n * never part of the model id, so it has to be split off before model lookup.\n */\nexport function parseChildModelReference(value: string | undefined): ParsedChildModel | undefined {\n if (value === undefined) return undefined;\n const suffix = THINKING_SUFFIX_PATTERN.exec(value);\n const reference = suffix === null ? value : value.slice(0, value.length - suffix[0].length);\n const separator = reference.indexOf('/');\n if (separator <= 0 || separator === reference.length - 1)\n throw new Error(`Child model must use the provider/model form: ${value}`);\n return {\n model: { provider: reference.slice(0, separator), id: reference.slice(separator + 1) },\n ...(suffix === null ? {} : { thinking: suffix[1] as string }),\n };\n}\n\n/** Resolve the provider set for one spawn, tolerating both a fixed array and a thunk. */\nexport function resolveChildProviders(\n providers: readonly Provider[] | (() => readonly Provider[]) | undefined,\n): readonly Provider[] | undefined {\n const resolved = typeof providers === 'function' ? providers() : providers;\n return resolved === undefined || resolved.length === 0 ? undefined : resolved;\n}\n\nfunction sessionFile(runtime: DirectHarnessRuntime): string | undefined {\n const metadata = runtime.session.metadata as unknown as { path?: unknown };\n return typeof metadata.path === 'string' ? metadata.path : undefined;\n}\n\nfunction childRuntime(\n runtime: DirectHarnessRuntime,\n intercom?: DoomChildSessionIntercom,\n release?: () => void,\n): DoomChildSessionRuntime {\n const file = sessionFile(runtime);\n return {\n sessionId: runtime.sessionId,\n ...(file === undefined ? {} : { sessionFile: file }),\n ...(file === undefined\n ? {}\n : { readTranscriptPage: (request, signal) => readNativeChildTranscript(file, request, signal) }),\n prompt: (task) => promptForAssistantText(runtime, task),\n steer: (message) => runtime.steer(message),\n followUp: (message) => runtime.followUp(message),\n onUsage(listener) {\n return runtime.onEvent((event) => {\n if (event.type !== 'usage') return;\n listener({ rowId: event.row.id, cost: event.row.usage.cost.total });\n });\n },\n abort: () => runtime.abort(),\n dispose: async () => {\n try {\n await runtime.dispose();\n } finally {\n release?.();\n intercom?.dispose?.();\n }\n },\n };\n}\n\ntype DirectHarnessTool = Parameters<DirectHarnessRuntime['replaceTools']>[0][number];\n\nasync function installIntercom(\n runtime: DirectHarnessRuntime,\n intercom: DoomChildSessionIntercom | undefined,\n tools: DirectHarnessTool[],\n): Promise<void> {\n if (!intercom) return;\n const tool = intercom.bindRuntime(childRuntime(runtime));\n const adapted = {\n ...tool,\n parameters: tool.parameters as never,\n execute: (operationId: string, params: unknown, signal: AbortSignal, onUpdate: unknown) =>\n tool.execute(operationId, params, signal, onUpdate as never),\n } as unknown as DirectHarnessTool;\n await runtime.replaceTools([...tools, adapted]);\n}\n\nfunction hasConfiguredValues(value: readonly string[] | undefined): boolean {\n return value !== undefined && value.length > 0;\n}\n\nconst NATIVE_TOOL_FACTORIES = {\n read: createReadTool,\n bash: createBashTool,\n edit: createEditTool,\n write: createWriteTool,\n grep: createGrepTool,\n find: createFindTool,\n ls: createLsTool,\n} as const;\n\ntype NativeCodingTool = ReturnType<(typeof NATIVE_TOOL_FACTORIES)[keyof typeof NATIVE_TOOL_FACTORIES]>;\n\nfunction adaptNativeTool(tool: NativeCodingTool | DoomChildSessionTool): DirectHarnessTool {\n const prompt = tool as (NativeCodingTool | DoomChildSessionTool) & {\n promptSnippet?: string;\n promptGuidelines?: string[];\n };\n return {\n ...prompt,\n label: 'label' in tool ? tool.label : tool.name,\n parameters: tool.parameters as never,\n async execute(toolCallId, parameters, onUpdate, _toolContext, _invocation, context) {\n const execute = tool.execute as (\n id: string,\n params: unknown,\n signal: AbortSignal,\n update: (result: { content: unknown; details?: unknown }) => void,\n ) => Promise<{ content: unknown; details?: unknown; isError?: boolean }>;\n const result = await execute(\n toolCallId,\n parameters,\n context.abortSignal ?? new AbortController().signal,\n (partial) => onUpdate({ content: partial.content as never, details: partial.details }),\n );\n if (result.isError) {\n const content = result.content as DoomChildSessionToolResultContent;\n throw new Error(\n content\n .filter((part) => part.type === 'text')\n .map((part) => part.text)\n .join('\\n') || 'MCP tool failed.',\n );\n }\n return { content: result.content as never, details: result.details };\n },\n };\n}\n\ntype DoomChildSessionToolResultContent = Awaited<ReturnType<DoomChildSessionTool['execute']>>['content'];\n\n/** Validate and project native fields before a source fork can publish a child journal. */\nexport function composeDirectHarnessRequestOptions(\n request: DoomChildSessionRequest,\n resolveMcpTool?: () => DoomChildSessionTool | undefined,\n): Pick<DirectHarnessRuntimeOptions, 'systemPrompt' | 'tools' | 'activeToolNames'> {\n const unsupported = [\n ...(hasConfiguredValues(request.extensions) ? ['extensions'] : []),\n ...(hasConfiguredValues(request.subagentOnlyExtensions) ? ['subagentOnlyExtensions'] : []),\n ...(hasConfiguredValues(request.mcpDirectTools) ? ['mcpDirectTools'] : []),\n ...(hasConfiguredValues(request.capabilityCeiling?.allowedExternalProfiles) ? ['allowedExternalProfiles'] : []),\n ];\n if (unsupported.length > 0) {\n throw new Error(\n `Native child session configuration is unsupported by the direct harness: ${unsupported.join(', ')}`,\n );\n }\n\n const requested = [...new Set(request.tools ?? Object.keys(NATIVE_TOOL_FACTORIES))];\n const excluded = new Set(request.excludeTools ?? []);\n const allowed = request.capabilityCeiling?.allowedTools;\n const isMcp = (name: string) => name === 'mcp' || name === 'mcp_use';\n const mcpDenied = request.capabilityCeiling?.allowMcpTools === false || [...excluded].some(isMcp);\n const names = requested.filter(\n (name) => !excluded.has(name) && (allowed === undefined || allowed.includes(name)) && !(isMcp(name) && mcpDenied),\n );\n const unknown = names.filter((name) => !Object.hasOwn(NATIVE_TOOL_FACTORIES, name) && !isMcp(name));\n if (unknown.length > 0)\n throw new Error(`Native child session requested unknown direct harness tools: ${unknown.join(', ')}`);\n const required = request.capabilityCeiling?.requiredTools ?? [];\n const missing = required.filter((name) => !names.includes(name));\n if (missing.length > 0)\n throw new Error(`Native child session capability ceiling requires unavailable tools: ${missing.join(', ')}`);\n const mcpTool = names.some(isMcp) ? resolveMcpTool?.() : undefined;\n if (names.some(isMcp) && !mcpTool)\n throw new Error('Native child session MCP tools are unavailable. Enable MCP in the parent session.');\n const tools = names.map((name) => {\n if (!isMcp(name))\n return adaptNativeTool(\n NATIVE_TOOL_FACTORIES[name as keyof typeof NATIVE_TOOL_FACTORIES](request.cwd) as NativeCodingTool,\n );\n return adaptNativeTool({\n ...mcpTool!,\n name,\n execute(toolCallId, parameters, signal, onUpdate) {\n signal?.throwIfAborted();\n if (resolveMcpTool?.() !== mcpTool)\n throw new Error('The parent session MCP dispatcher is no longer available.');\n return mcpTool!.execute(toolCallId, parameters, signal, onUpdate);\n },\n } satisfies DoomChildSessionTool);\n });\n return {\n tools,\n activeToolNames: names,\n ...(request.systemPrompt === undefined ? {} : { systemPrompt: request.systemPrompt }),\n };\n}\n\nasync function forkChildJournal(\n sourcePath: string,\n branch: string,\n entryId: string | undefined,\n ownership: HistoryOwnership,\n): Promise<string> {\n const directory = path.dirname(path.resolve(sourcePath));\n const sourceRepository = new SqliteSessionRepo({\n directory,\n databasePath: sourcePath,\n databaseFactory: createNodeSqliteFactory(),\n });\n const sources = await sourceRepository.list(undefined, BACKGROUND_CONTEXT);\n await sourceRepository.close(BACKGROUND_CONTEXT);\n if (sources.length !== 1)\n throw new Error('Child source must be an existing SQLite session; import JSONL offline first.');\n const id = randomUUID();\n const destination = path.join(directory, `${id}.sqlite`);\n const lease = await ownership.acquire(destination);\n const repository = new SqliteSessionRepo({ directory, databaseFactory: createNodeSqliteFactory() });\n try {\n await lease.assertQuiescent();\n const fork = await repository.fork(\n sources[0]!,\n {\n scope: 'branch',\n branch,\n id,\n ...(entryId === undefined ? {} : { entryId }),\n },\n BACKGROUND_CONTEXT,\n );\n await fork.close(BACKGROUND_CONTEXT);\n return destination;\n } finally {\n try {\n await repository.close(BACKGROUND_CONTEXT);\n } finally {\n await lease.release();\n }\n }\n}\n\nexport function createHeadlessChildSessionService(\n options: HeadlessChildSessionServiceOptions,\n): DoomChildSessionService {\n const runtimeFactory = options.runtimeFactory ?? createDirectHarnessRuntime;\n const ownership = options.historyOwnership ?? createHistoryOwnership({ sourceFormat: 'sqlite' });\n\n return createDoomChildSessionService(\n async (request: DoomChildSessionRequest, signal): Promise<DoomChildSessionRuntime> => {\n signal?.throwIfAborted();\n if (request.source.kind === 'terminal-pi-fork')\n throw new Error('Headless child sessions do not support terminal Pi sources.');\n const directRequestOptions = composeDirectHarnessRequestOptions(request, options.mcpTool);\n\n let sessionPath: string | undefined;\n let sessionId: string | undefined;\n if (request.source.kind === 'v4-restore') {\n sessionPath = path.resolve(request.source.sessionFile);\n if (path.extname(sessionPath) !== '.sqlite')\n throw new Error('Server child restore requires SQLite; import JSONL offline first.');\n } else if (request.source.kind === 'v4-fork') {\n sessionPath = await forkChildJournal(\n request.source.sessionFile,\n request.source.branch,\n request.source.entryId,\n ownership,\n );\n } else {\n sessionId = randomUUID();\n }\n\n const requestedModel = parseChildModelReference(request.model);\n const model = requestedModel?.model ?? options.defaultModel?.();\n const thinking = request.thinking ?? requestedModel?.thinking;\n const providers = resolveChildProviders(options.providers);\n const runtimeOptions: DirectHarnessRuntimeOptions = {\n storage: 'sqlite',\n ...(request.source.kind === 'v4-fork' ? { lane: request.source.branch } : {}),\n cwd: request.cwd || options.cwd,\n ...(sessionId === undefined ? {} : { sessionId }),\n parentSessionId: request.parentSessionId || options.parentSessionId,\n ...(sessionPath === undefined ? {} : { sessionPath }),\n ...(options.sessionsRoot === undefined ? {} : { sessionsRoot: options.sessionsRoot }),\n ...(options.models === undefined ? {} : { models: options.models }),\n ...(providers === undefined ? {} : { providers }),\n ...(model === undefined ? {} : { model }),\n ...(thinking === undefined ? {} : { thinkingLevel: thinking as never }),\n ...directRequestOptions,\n historyOwnership: ownership,\n };\n\n let runtime: DirectHarnessRuntime | undefined;\n try {\n runtime = await runtimeFactory(runtimeOptions);\n await installIntercom(runtime, request.intercom, (runtimeOptions.tools ?? []) as DirectHarnessTool[]);\n const file = sessionFile(runtime);\n return childRuntime(runtime, request.intercom, file ? registerNativeChild(file, runtime) : undefined);\n } catch (error) {\n let failure: unknown = error;\n try {\n await runtime?.dispose();\n } catch (cleanupError) {\n failure = new AggregateError([error, cleanupError], 'Headless child startup cleanup failed');\n } finally {\n request.intercom?.dispose?.();\n if (sessionPath !== undefined && request.source.kind === 'v4-fork')\n for (const suffix of ['', '-wal', '-shm']) fs.rmSync(sessionPath + suffix, { force: true });\n }\n throw failure;\n }\n },\n { now: options.now ?? Date.now },\n );\n}\n\nexport function createHeadlessChildSessionServiceProvider(\n options: HeadlessChildSessionServiceOptions,\n): HeadlessChildSessionServiceProvider {\n const service = createHeadlessChildSessionService(options);\n return {\n get: () => service,\n close: () => service.close(),\n };\n}\n\nexport type { DirectHarnessRuntime, DirectHarnessRuntimeOptions } from '../../../server/directHarnessRuntime';\nexport type { DirectHarnessModel } from '../../../types/server/directHarnessRuntime';\n"],"mappings":"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"}
@@ -1,5 +1,7 @@
1
1
  //#region src/systems/child/types/childSession.ts
2
2
  const DOOM_CHILD_SESSION_SERVICE = "doom/child-session";
3
+ /** Optional session-owned MCP dispatcher. Children borrow it without owning its connections. */
4
+ const DOOM_CHILD_SESSION_MCP_TOOL_SERVICE = "doom/child-session-mcp-tool";
3
5
  function readDoomChildSessionService(context) {
4
6
  return context.get(DOOM_CHILD_SESSION_SERVICE);
5
7
  }
@@ -9,6 +11,7 @@ function requireDoomChildSessionService(context) {
9
11
  return service;
10
12
  }
11
13
  //#endregion
14
+ exports.DOOM_CHILD_SESSION_MCP_TOOL_SERVICE = DOOM_CHILD_SESSION_MCP_TOOL_SERVICE;
12
15
  exports.DOOM_CHILD_SESSION_SERVICE = DOOM_CHILD_SESSION_SERVICE;
13
16
  exports.readDoomChildSessionService = readDoomChildSessionService;
14
17
  exports.requireDoomChildSessionService = requireDoomChildSessionService;
@@ -1 +1 @@
1
- {"version":3,"file":"childSession.cjs","names":[],"sources":["../../../../../src/systems/child/types/childSession.ts"],"sourcesContent":["import type { Context } from '@deepseek-ai/cordis';\n\nimport type { TranscriptPage, TranscriptPageRequest } from '../../../schemas/sessionProtocol';\n\nexport const DOOM_CHILD_SESSION_SERVICE = 'doom/child-session';\n\nexport type DoomChildSessionState = 'starting' | 'running' | 'completed' | 'failed' | 'stopped';\n\nexport interface DoomChildSessionFreshSource {\n readonly kind: 'fresh';\n}\n\n/** Continue one previously-owned native child journal. Providers must validate the v4 header before opening it. */\nexport interface DoomChildSessionV4RestoreSource {\n readonly kind: 'v4-restore';\n readonly sessionFile: string;\n}\n\n/** Fork one branch of a headless v4 journal into a separate child journal. */\nexport interface DoomChildSessionV4ForkSource {\n readonly kind: 'v4-fork';\n readonly sessionFile: string;\n readonly branch: string;\n readonly entryId?: string;\n}\n\n/**\n * Immutable terminal Pi branch captured by the thin Pi adapter.\n *\n * The serialized v3 snapshot is data, not a writable parent path. The child host\n * converts it into a separate v4 journal and never opens the active Pi history.\n */\nexport interface DoomChildSessionTerminalPiForkSource {\n readonly kind: 'terminal-pi-fork';\n readonly sourceSessionId: string;\n readonly sourceLeafId: string;\n readonly snapshotJsonl: string;\n}\n\nexport type DoomChildSessionSource =\n | DoomChildSessionFreshSource\n | DoomChildSessionV4RestoreSource\n | DoomChildSessionV4ForkSource\n | DoomChildSessionTerminalPiForkSource;\n\nexport interface DoomChildSessionScope {\n readonly rootSessionId: string;\n readonly scopeKey: string;\n}\n\n/** Capability data is intentionally host-neutral; the owning runtime validates its fields. */\nexport interface DoomChildSessionCapabilityCeiling {\n readonly allowedTools?: readonly string[];\n readonly requiredTools?: readonly string[];\n readonly allowMcpTools?: boolean;\n readonly allowedExternalProfiles?: readonly string[];\n readonly denyExtensions?: boolean;\n}\n\nexport interface DoomChildSessionRequest {\n readonly runId: string;\n readonly parentSessionId: string;\n readonly scope: DoomChildSessionScope;\n readonly source: DoomChildSessionSource;\n readonly agent: string;\n readonly task: string;\n readonly cwd: string;\n readonly model?: string;\n readonly thinking?: string;\n readonly systemPrompt?: string;\n readonly systemPromptMode?: 'append' | 'replace';\n readonly extensions?: readonly string[];\n readonly subagentOnlyExtensions?: readonly string[];\n readonly tools?: readonly string[];\n readonly excludeTools?: readonly string[];\n readonly skills?: readonly string[];\n readonly mcpDirectTools?: readonly string[];\n readonly capabilityCeiling?: DoomChildSessionCapabilityCeiling;\n readonly intercom?: DoomChildSessionIntercom;\n readonly environment: Readonly<Record<string, string | undefined>>;\n}\n\nexport interface DoomChildSessionUsage {\n readonly rowId: string;\n readonly cost: number;\n}\n\nexport interface DoomChildSessionEvent {\n readonly runId: string;\n readonly state: DoomChildSessionState;\n readonly timestamp: number;\n readonly message?: string;\n readonly sessionFile?: string;\n readonly cost?: number;\n}\n\nexport interface DoomChildSessionToolResult {\n readonly content: readonly { readonly type: 'text'; readonly text: string }[];\n readonly details?: unknown;\n readonly isError?: boolean;\n}\n\nexport interface DoomChildSessionTool {\n readonly name: string;\n readonly description: string;\n readonly parameters: unknown;\n execute(\n operationId: string,\n params: unknown,\n signal?: AbortSignal,\n onUpdate?: (result: DoomChildSessionToolResult) => void,\n ): Promise<DoomChildSessionToolResult>;\n}\n\n/** Direct in-process Team intercom supplied by an owning extension. */\nexport interface DoomChildSessionIntercom {\n bindRuntime(runtime: DoomChildSessionRuntime): DoomChildSessionTool;\n dispose?(): void;\n}\n\n/** Host runtime owned by the direct headless or terminal adapter. */\nexport interface DoomChildSessionRuntime {\n readonly sessionId: string;\n readonly sessionFile?: string;\n prompt(task: string): Promise<string | void>;\n steer(message: string): Promise<void>;\n followUp?(message: string): Promise<void>;\n abort(): Promise<void>;\n onUsage?(listener: (usage: DoomChildSessionUsage) => void): () => void;\n /** Reads only this runtime's owned journal. The callback may remain valid after runtime disposal. */\n readTranscriptPage?(request: Omit<TranscriptPageRequest, 'threadId'>, signal?: AbortSignal): Promise<TranscriptPage>;\n dispose(): Promise<void>;\n}\n\nexport type DoomChildSessionRuntimeFactory = (\n request: DoomChildSessionRequest,\n signal?: AbortSignal,\n) => Promise<DoomChildSessionRuntime>;\n\nexport interface DoomChildSessionHandle {\n readonly runId: string;\n readonly sessionFile?: string;\n state(): DoomChildSessionState;\n subscribe(listener: (event: DoomChildSessionEvent) => void): () => void;\n steer(message: string, signal?: AbortSignal): Promise<void>;\n stop(reason?: string): Promise<void>;\n dispose(): Promise<void>;\n}\n\nexport interface DoomChildSessionService {\n start(request: DoomChildSessionRequest, signal?: AbortSignal): Promise<DoomChildSessionHandle>;\n get(runId: string): DoomChildSessionHandle | undefined;\n /** Resolves an owned run ID inside this session service. Callers never provide journal paths. */\n readTranscriptPage?(\n runId: string,\n request: Omit<TranscriptPageRequest, 'threadId'>,\n signal?: AbortSignal,\n ): Promise<TranscriptPage>;\n close(): Promise<void>;\n}\n\n/** Lazy provider lets Pi and headless composition bind the host-owned service later. */\nexport interface DoomChildSessionServiceProvider {\n get(): DoomChildSessionService | undefined;\n}\ndeclare module '@deepseek-ai/cordis' {\n interface Context {\n 'doom/child-session': DoomChildSessionService;\n }\n}\n\nexport function readDoomChildSessionService(context: Context): DoomChildSessionService | undefined {\n return context.get(DOOM_CHILD_SESSION_SERVICE) as DoomChildSessionService | undefined;\n}\n\nexport function requireDoomChildSessionService(context: Context): DoomChildSessionService {\n const service = readDoomChildSessionService(context);\n if (!service) throw new Error('The Doom child-session service is unavailable.');\n return service;\n}\n"],"mappings":";AAIA,MAAa,6BAA6B;AAuK1C,SAAgB,4BAA4B,SAAuD;CACjG,OAAO,QAAQ,IAAI,0BAA0B;AAC/C;AAEA,SAAgB,+BAA+B,SAA2C;CACxF,MAAM,UAAU,4BAA4B,OAAO;CACnD,IAAI,CAAC,SAAS,MAAM,IAAI,MAAM,gDAAgD;CAC9E,OAAO;AACT"}
1
+ {"version":3,"file":"childSession.cjs","names":[],"sources":["../../../../../src/systems/child/types/childSession.ts"],"sourcesContent":["import type { Context } from '@deepseek-ai/cordis';\n\nimport type { TranscriptPage, TranscriptPageRequest } from '../../../schemas/sessionProtocol';\n\nexport const DOOM_CHILD_SESSION_SERVICE = 'doom/child-session';\n/** Optional session-owned MCP dispatcher. Children borrow it without owning its connections. */\nexport const DOOM_CHILD_SESSION_MCP_TOOL_SERVICE = 'doom/child-session-mcp-tool';\n\nexport type DoomChildSessionState = 'starting' | 'running' | 'completed' | 'failed' | 'stopped';\n\nexport interface DoomChildSessionFreshSource {\n readonly kind: 'fresh';\n}\n\n/** Continue one previously-owned native child journal. Providers must validate the v4 header before opening it. */\nexport interface DoomChildSessionV4RestoreSource {\n readonly kind: 'v4-restore';\n readonly sessionFile: string;\n}\n\n/** Fork one branch of a headless v4 journal into a separate child journal. */\nexport interface DoomChildSessionV4ForkSource {\n readonly kind: 'v4-fork';\n readonly sessionFile: string;\n readonly branch: string;\n readonly entryId?: string;\n}\n\n/**\n * Immutable terminal Pi branch captured by the thin Pi adapter.\n *\n * The serialized v3 snapshot is data, not a writable parent path. The child host\n * converts it into a separate v4 journal and never opens the active Pi history.\n */\nexport interface DoomChildSessionTerminalPiForkSource {\n readonly kind: 'terminal-pi-fork';\n readonly sourceSessionId: string;\n readonly sourceLeafId: string;\n readonly snapshotJsonl: string;\n}\n\nexport type DoomChildSessionSource =\n | DoomChildSessionFreshSource\n | DoomChildSessionV4RestoreSource\n | DoomChildSessionV4ForkSource\n | DoomChildSessionTerminalPiForkSource;\n\nexport interface DoomChildSessionScope {\n readonly rootSessionId: string;\n readonly scopeKey: string;\n}\n\n/** Capability data is intentionally host-neutral; the owning runtime validates its fields. */\nexport interface DoomChildSessionCapabilityCeiling {\n readonly allowedTools?: readonly string[];\n readonly requiredTools?: readonly string[];\n readonly allowMcpTools?: boolean;\n readonly allowedExternalProfiles?: readonly string[];\n readonly denyExtensions?: boolean;\n}\n\nexport interface DoomChildSessionRequest {\n readonly runId: string;\n readonly parentSessionId: string;\n readonly scope: DoomChildSessionScope;\n readonly source: DoomChildSessionSource;\n readonly agent: string;\n readonly task: string;\n readonly cwd: string;\n readonly model?: string;\n readonly thinking?: string;\n readonly systemPrompt?: string;\n readonly systemPromptMode?: 'append' | 'replace';\n readonly extensions?: readonly string[];\n readonly subagentOnlyExtensions?: readonly string[];\n readonly tools?: readonly string[];\n readonly excludeTools?: readonly string[];\n readonly skills?: readonly string[];\n readonly mcpDirectTools?: readonly string[];\n readonly capabilityCeiling?: DoomChildSessionCapabilityCeiling;\n readonly intercom?: DoomChildSessionIntercom;\n readonly environment: Readonly<Record<string, string | undefined>>;\n}\n\nexport interface DoomChildSessionUsage {\n readonly rowId: string;\n readonly cost: number;\n}\n\nexport interface DoomChildSessionEvent {\n readonly runId: string;\n readonly state: DoomChildSessionState;\n readonly timestamp: number;\n readonly message?: string;\n readonly sessionFile?: string;\n readonly cost?: number;\n}\n\nexport interface DoomChildSessionToolResult {\n readonly content: readonly (\n | { readonly type: 'text'; readonly text: string }\n | { readonly type: 'image'; readonly data: string; readonly mimeType: string }\n )[];\n readonly details?: unknown;\n readonly isError?: boolean;\n}\n\nexport interface DoomChildSessionTool {\n readonly name: string;\n readonly description: string;\n readonly parameters: unknown;\n execute(\n operationId: string,\n params: unknown,\n signal?: AbortSignal,\n onUpdate?: (result: DoomChildSessionToolResult) => void,\n ): Promise<DoomChildSessionToolResult>;\n}\n\n/** Direct in-process Team intercom supplied by an owning extension. */\nexport interface DoomChildSessionIntercom {\n bindRuntime(runtime: DoomChildSessionRuntime): DoomChildSessionTool;\n dispose?(): void;\n}\n\n/** Host runtime owned by the direct headless or terminal adapter. */\nexport interface DoomChildSessionRuntime {\n readonly sessionId: string;\n readonly sessionFile?: string;\n prompt(task: string): Promise<string | void>;\n steer(message: string): Promise<void>;\n followUp?(message: string): Promise<void>;\n abort(): Promise<void>;\n onUsage?(listener: (usage: DoomChildSessionUsage) => void): () => void;\n /** Reads only this runtime's owned journal. The callback may remain valid after runtime disposal. */\n readTranscriptPage?(request: Omit<TranscriptPageRequest, 'threadId'>, signal?: AbortSignal): Promise<TranscriptPage>;\n dispose(): Promise<void>;\n}\n\nexport type DoomChildSessionRuntimeFactory = (\n request: DoomChildSessionRequest,\n signal?: AbortSignal,\n) => Promise<DoomChildSessionRuntime>;\n\nexport interface DoomChildSessionHandle {\n readonly runId: string;\n readonly sessionFile?: string;\n state(): DoomChildSessionState;\n subscribe(listener: (event: DoomChildSessionEvent) => void): () => void;\n steer(message: string, signal?: AbortSignal): Promise<void>;\n stop(reason?: string): Promise<void>;\n dispose(): Promise<void>;\n}\n\nexport interface DoomChildSessionService {\n start(request: DoomChildSessionRequest, signal?: AbortSignal): Promise<DoomChildSessionHandle>;\n get(runId: string): DoomChildSessionHandle | undefined;\n /** Resolves an owned run ID inside this session service. Callers never provide journal paths. */\n readTranscriptPage?(\n runId: string,\n request: Omit<TranscriptPageRequest, 'threadId'>,\n signal?: AbortSignal,\n ): Promise<TranscriptPage>;\n close(): Promise<void>;\n}\n\n/** Lazy provider lets Pi and headless composition bind the host-owned service later. */\nexport interface DoomChildSessionServiceProvider {\n get(): DoomChildSessionService | undefined;\n}\ndeclare module '@deepseek-ai/cordis' {\n interface Context {\n 'doom/child-session': DoomChildSessionService;\n 'doom/child-session-mcp-tool': DoomChildSessionTool;\n }\n}\n\nexport function readDoomChildSessionService(context: Context): DoomChildSessionService | undefined {\n return context.get(DOOM_CHILD_SESSION_SERVICE) as DoomChildSessionService | undefined;\n}\n\nexport function requireDoomChildSessionService(context: Context): DoomChildSessionService {\n const service = readDoomChildSessionService(context);\n if (!service) throw new Error('The Doom child-session service is unavailable.');\n return service;\n}\n"],"mappings":";AAIA,MAAa,6BAA6B;;AAE1C,MAAa,sCAAsC;AA2KnD,SAAgB,4BAA4B,SAAuD;CACjG,OAAO,QAAQ,IAAI,0BAA0B;AAC/C;AAEA,SAAgB,+BAA+B,SAA2C;CACxF,MAAM,UAAU,4BAA4B,OAAO;CACnD,IAAI,CAAC,SAAS,MAAM,IAAI,MAAM,gDAAgD;CAC9E,OAAO;AACT"}
@@ -2,6 +2,8 @@ import { TranscriptPage, TranscriptPageRequest } from "../../../schemas/sessionP
2
2
  import { Context } from "@deepseek-ai/cordis";
3
3
  //#region src/systems/child/types/childSession.d.ts
4
4
  export declare const DOOM_CHILD_SESSION_SERVICE = "doom/child-session";
5
+ /** Optional session-owned MCP dispatcher. Children borrow it without owning its connections. */
6
+ export declare const DOOM_CHILD_SESSION_MCP_TOOL_SERVICE = "doom/child-session-mcp-tool";
5
7
  export type DoomChildSessionState = 'starting' | 'running' | 'completed' | 'failed' | 'stopped';
6
8
  export interface DoomChildSessionFreshSource {
7
9
  readonly kind: 'fresh';
@@ -78,10 +80,14 @@ export interface DoomChildSessionEvent {
78
80
  readonly cost?: number;
79
81
  }
80
82
  export interface DoomChildSessionToolResult {
81
- readonly content: readonly {
83
+ readonly content: readonly ({
82
84
  readonly type: 'text';
83
85
  readonly text: string;
84
- }[];
86
+ } | {
87
+ readonly type: 'image';
88
+ readonly data: string;
89
+ readonly mimeType: string;
90
+ })[];
85
91
  readonly details?: unknown;
86
92
  readonly isError?: boolean;
87
93
  }
@@ -133,6 +139,7 @@ export interface DoomChildSessionServiceProvider {
133
139
  declare module '@deepseek-ai/cordis' {
134
140
  interface Context {
135
141
  'doom/child-session': DoomChildSessionService;
142
+ 'doom/child-session-mcp-tool': DoomChildSessionTool;
136
143
  }
137
144
  }
138
145
  export declare function readDoomChildSessionService(context: Context): DoomChildSessionService | undefined;
@@ -1 +1 @@
1
- {"version":3,"file":"childSession.d.mts","names":[],"sources":["../../../../../src/systems/child/types/childSession.ts"],"mappings":";;;qBAIa;YAED;iBAEK;WACN;;;iBAIM;WACN;WACA;;;iBAIM;WACN;WACA;WACA;WACA;;;;;;;;iBASM;WACN;WACA;WACA;WACA;;YAGC,yBACR,8BACA,kCACA,+BACA;iBAEa;WACN;WACA;;;iBAIM;WACN;WACA;WACA;WACA;WACA;;iBAGM;WACN;WACA;WACA,OAAO;WACP,QAAQ;WACR;WACA;WACA;WACA;WACA;WACA;WACA;WACA;WACA;WACA;WACA;WACA;WACA;WACA,oBAAoB;WACpB,WAAW;WACX,aAAa,SAAS;;iBAGhB;WACN;WACA;;iBAGM;WACN;WACA,OAAO;WACP;WACA;WACA;WACA;;iBAGM;WACN;aAA6B;aAAuB;;WACpD;WACA;;iBAGM;WACN;WACA;WACA;EACT,QACE,qBACA,iBACA,SAAS,aACT,YAAY,QAAQ,sCACnB,QAAQ;;;iBAII;EACf,YAAY,SAAS,0BAA0B;EAC/C;;;iBAIe;WACN;WACA;EACT,OAAO,eAAe;EACtB,MAAM,kBAAkB;EACxB,UAAU,kBAAkB;EAC5B,SAAS;EACT,SAAS,WAAW,OAAO;;EAE3B,oBAAoB,SAAS,KAAK,oCAAoC,SAAS,cAAc,QAAQ;EACrG,WAAW;;YAGD,kCACV,SAAS,yBACT,SAAS,gBACN,QAAQ;iBAEI;WACN;WACA;EACT,SAAS;EACT,UAAU,WAAW,OAAO;EAC5B,MAAM,iBAAiB,SAAS,cAAc;EAC9C,KAAK,kBAAkB;EACvB,WAAW;;iBAGI;EACf,MAAM,SAAS,yBAAyB,SAAS,cAAc,QAAQ;EACvE,IAAI,gBAAgB;;EAEpB,oBACE,eACA,SAAS,KAAK,oCACd,SAAS,cACR,QAAQ;EACX,SAAS;;;iBAIM;EACf,OAAO;;;YAGG;IACR,sBAAsB;;;wBAIV,4BAA4B,SAAS,UAAU;wBAI/C,+BAA+B,SAAS,UAAU"}
1
+ {"version":3,"file":"childSession.d.mts","names":[],"sources":["../../../../../src/systems/child/types/childSession.ts"],"mappings":";;;qBAIa;;qBAEA;YAED;iBAEK;WACN;;;iBAIM;WACN;WACA;;;iBAIM;WACN;WACA;WACA;WACA;;;;;;;;iBASM;WACN;WACA;WACA;WACA;;YAGC,yBACR,8BACA,kCACA,+BACA;iBAEa;WACN;WACA;;;iBAIM;WACN;WACA;WACA;WACA;WACA;;iBAGM;WACN;WACA;WACA,OAAO;WACP,QAAQ;WACR;WACA;WACA;WACA;WACA;WACA;WACA;WACA;WACA;WACA;WACA;WACA;WACA;WACA,oBAAoB;WACpB,WAAW;WACX,aAAa,SAAS;;iBAGhB;WACN;WACA;;iBAGM;WACN;WACA,OAAO;WACP;WACA;WACA;WACA;;iBAGM;WACN;aACM;aAAuB;;aACvB;aAAwB;aAAuB;;WAErD;WACA;;iBAGM;WACN;WACA;WACA;EACT,QACE,qBACA,iBACA,SAAS,aACT,YAAY,QAAQ,sCACnB,QAAQ;;;iBAII;EACf,YAAY,SAAS,0BAA0B;EAC/C;;;iBAIe;WACN;WACA;EACT,OAAO,eAAe;EACtB,MAAM,kBAAkB;EACxB,UAAU,kBAAkB;EAC5B,SAAS;EACT,SAAS,WAAW,OAAO;;EAE3B,oBAAoB,SAAS,KAAK,oCAAoC,SAAS,cAAc,QAAQ;EACrG,WAAW;;YAGD,kCACV,SAAS,yBACT,SAAS,gBACN,QAAQ;iBAEI;WACN;WACA;EACT,SAAS;EACT,UAAU,WAAW,OAAO;EAC5B,MAAM,iBAAiB,SAAS,cAAc;EAC9C,KAAK,kBAAkB;EACvB,WAAW;;iBAGI;EACf,MAAM,SAAS,yBAAyB,SAAS,cAAc,QAAQ;EACvE,IAAI,gBAAgB;;EAEpB,oBACE,eACA,SAAS,KAAK,oCACd,SAAS,cACR,QAAQ;EACX,SAAS;;;iBAIM;EACf,OAAO;;;YAGG;IACR,sBAAsB;IACtB,+BAA+B;;;wBAInB,4BAA4B,SAAS,UAAU;wBAI/C,+BAA+B,SAAS,UAAU"}
@@ -1,5 +1,7 @@
1
1
  //#region src/systems/child/types/childSession.ts
2
2
  const DOOM_CHILD_SESSION_SERVICE = "doom/child-session";
3
+ /** Optional session-owned MCP dispatcher. Children borrow it without owning its connections. */
4
+ const DOOM_CHILD_SESSION_MCP_TOOL_SERVICE = "doom/child-session-mcp-tool";
3
5
  function readDoomChildSessionService(context) {
4
6
  return context.get(DOOM_CHILD_SESSION_SERVICE);
5
7
  }
@@ -9,6 +11,6 @@ function requireDoomChildSessionService(context) {
9
11
  return service;
10
12
  }
11
13
  //#endregion
12
- export { DOOM_CHILD_SESSION_SERVICE, readDoomChildSessionService, requireDoomChildSessionService };
14
+ export { DOOM_CHILD_SESSION_MCP_TOOL_SERVICE, DOOM_CHILD_SESSION_SERVICE, readDoomChildSessionService, requireDoomChildSessionService };
13
15
 
14
16
  //# sourceMappingURL=childSession.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"childSession.mjs","names":[],"sources":["../../../../../src/systems/child/types/childSession.ts"],"sourcesContent":["import type { Context } from '@deepseek-ai/cordis';\n\nimport type { TranscriptPage, TranscriptPageRequest } from '../../../schemas/sessionProtocol';\n\nexport const DOOM_CHILD_SESSION_SERVICE = 'doom/child-session';\n\nexport type DoomChildSessionState = 'starting' | 'running' | 'completed' | 'failed' | 'stopped';\n\nexport interface DoomChildSessionFreshSource {\n readonly kind: 'fresh';\n}\n\n/** Continue one previously-owned native child journal. Providers must validate the v4 header before opening it. */\nexport interface DoomChildSessionV4RestoreSource {\n readonly kind: 'v4-restore';\n readonly sessionFile: string;\n}\n\n/** Fork one branch of a headless v4 journal into a separate child journal. */\nexport interface DoomChildSessionV4ForkSource {\n readonly kind: 'v4-fork';\n readonly sessionFile: string;\n readonly branch: string;\n readonly entryId?: string;\n}\n\n/**\n * Immutable terminal Pi branch captured by the thin Pi adapter.\n *\n * The serialized v3 snapshot is data, not a writable parent path. The child host\n * converts it into a separate v4 journal and never opens the active Pi history.\n */\nexport interface DoomChildSessionTerminalPiForkSource {\n readonly kind: 'terminal-pi-fork';\n readonly sourceSessionId: string;\n readonly sourceLeafId: string;\n readonly snapshotJsonl: string;\n}\n\nexport type DoomChildSessionSource =\n | DoomChildSessionFreshSource\n | DoomChildSessionV4RestoreSource\n | DoomChildSessionV4ForkSource\n | DoomChildSessionTerminalPiForkSource;\n\nexport interface DoomChildSessionScope {\n readonly rootSessionId: string;\n readonly scopeKey: string;\n}\n\n/** Capability data is intentionally host-neutral; the owning runtime validates its fields. */\nexport interface DoomChildSessionCapabilityCeiling {\n readonly allowedTools?: readonly string[];\n readonly requiredTools?: readonly string[];\n readonly allowMcpTools?: boolean;\n readonly allowedExternalProfiles?: readonly string[];\n readonly denyExtensions?: boolean;\n}\n\nexport interface DoomChildSessionRequest {\n readonly runId: string;\n readonly parentSessionId: string;\n readonly scope: DoomChildSessionScope;\n readonly source: DoomChildSessionSource;\n readonly agent: string;\n readonly task: string;\n readonly cwd: string;\n readonly model?: string;\n readonly thinking?: string;\n readonly systemPrompt?: string;\n readonly systemPromptMode?: 'append' | 'replace';\n readonly extensions?: readonly string[];\n readonly subagentOnlyExtensions?: readonly string[];\n readonly tools?: readonly string[];\n readonly excludeTools?: readonly string[];\n readonly skills?: readonly string[];\n readonly mcpDirectTools?: readonly string[];\n readonly capabilityCeiling?: DoomChildSessionCapabilityCeiling;\n readonly intercom?: DoomChildSessionIntercom;\n readonly environment: Readonly<Record<string, string | undefined>>;\n}\n\nexport interface DoomChildSessionUsage {\n readonly rowId: string;\n readonly cost: number;\n}\n\nexport interface DoomChildSessionEvent {\n readonly runId: string;\n readonly state: DoomChildSessionState;\n readonly timestamp: number;\n readonly message?: string;\n readonly sessionFile?: string;\n readonly cost?: number;\n}\n\nexport interface DoomChildSessionToolResult {\n readonly content: readonly { readonly type: 'text'; readonly text: string }[];\n readonly details?: unknown;\n readonly isError?: boolean;\n}\n\nexport interface DoomChildSessionTool {\n readonly name: string;\n readonly description: string;\n readonly parameters: unknown;\n execute(\n operationId: string,\n params: unknown,\n signal?: AbortSignal,\n onUpdate?: (result: DoomChildSessionToolResult) => void,\n ): Promise<DoomChildSessionToolResult>;\n}\n\n/** Direct in-process Team intercom supplied by an owning extension. */\nexport interface DoomChildSessionIntercom {\n bindRuntime(runtime: DoomChildSessionRuntime): DoomChildSessionTool;\n dispose?(): void;\n}\n\n/** Host runtime owned by the direct headless or terminal adapter. */\nexport interface DoomChildSessionRuntime {\n readonly sessionId: string;\n readonly sessionFile?: string;\n prompt(task: string): Promise<string | void>;\n steer(message: string): Promise<void>;\n followUp?(message: string): Promise<void>;\n abort(): Promise<void>;\n onUsage?(listener: (usage: DoomChildSessionUsage) => void): () => void;\n /** Reads only this runtime's owned journal. The callback may remain valid after runtime disposal. */\n readTranscriptPage?(request: Omit<TranscriptPageRequest, 'threadId'>, signal?: AbortSignal): Promise<TranscriptPage>;\n dispose(): Promise<void>;\n}\n\nexport type DoomChildSessionRuntimeFactory = (\n request: DoomChildSessionRequest,\n signal?: AbortSignal,\n) => Promise<DoomChildSessionRuntime>;\n\nexport interface DoomChildSessionHandle {\n readonly runId: string;\n readonly sessionFile?: string;\n state(): DoomChildSessionState;\n subscribe(listener: (event: DoomChildSessionEvent) => void): () => void;\n steer(message: string, signal?: AbortSignal): Promise<void>;\n stop(reason?: string): Promise<void>;\n dispose(): Promise<void>;\n}\n\nexport interface DoomChildSessionService {\n start(request: DoomChildSessionRequest, signal?: AbortSignal): Promise<DoomChildSessionHandle>;\n get(runId: string): DoomChildSessionHandle | undefined;\n /** Resolves an owned run ID inside this session service. Callers never provide journal paths. */\n readTranscriptPage?(\n runId: string,\n request: Omit<TranscriptPageRequest, 'threadId'>,\n signal?: AbortSignal,\n ): Promise<TranscriptPage>;\n close(): Promise<void>;\n}\n\n/** Lazy provider lets Pi and headless composition bind the host-owned service later. */\nexport interface DoomChildSessionServiceProvider {\n get(): DoomChildSessionService | undefined;\n}\ndeclare module '@deepseek-ai/cordis' {\n interface Context {\n 'doom/child-session': DoomChildSessionService;\n }\n}\n\nexport function readDoomChildSessionService(context: Context): DoomChildSessionService | undefined {\n return context.get(DOOM_CHILD_SESSION_SERVICE) as DoomChildSessionService | undefined;\n}\n\nexport function requireDoomChildSessionService(context: Context): DoomChildSessionService {\n const service = readDoomChildSessionService(context);\n if (!service) throw new Error('The Doom child-session service is unavailable.');\n return service;\n}\n"],"mappings":";AAIA,MAAa,6BAA6B;AAuK1C,SAAgB,4BAA4B,SAAuD;CACjG,OAAO,QAAQ,IAAI,0BAA0B;AAC/C;AAEA,SAAgB,+BAA+B,SAA2C;CACxF,MAAM,UAAU,4BAA4B,OAAO;CACnD,IAAI,CAAC,SAAS,MAAM,IAAI,MAAM,gDAAgD;CAC9E,OAAO;AACT"}
1
+ {"version":3,"file":"childSession.mjs","names":[],"sources":["../../../../../src/systems/child/types/childSession.ts"],"sourcesContent":["import type { Context } from '@deepseek-ai/cordis';\n\nimport type { TranscriptPage, TranscriptPageRequest } from '../../../schemas/sessionProtocol';\n\nexport const DOOM_CHILD_SESSION_SERVICE = 'doom/child-session';\n/** Optional session-owned MCP dispatcher. Children borrow it without owning its connections. */\nexport const DOOM_CHILD_SESSION_MCP_TOOL_SERVICE = 'doom/child-session-mcp-tool';\n\nexport type DoomChildSessionState = 'starting' | 'running' | 'completed' | 'failed' | 'stopped';\n\nexport interface DoomChildSessionFreshSource {\n readonly kind: 'fresh';\n}\n\n/** Continue one previously-owned native child journal. Providers must validate the v4 header before opening it. */\nexport interface DoomChildSessionV4RestoreSource {\n readonly kind: 'v4-restore';\n readonly sessionFile: string;\n}\n\n/** Fork one branch of a headless v4 journal into a separate child journal. */\nexport interface DoomChildSessionV4ForkSource {\n readonly kind: 'v4-fork';\n readonly sessionFile: string;\n readonly branch: string;\n readonly entryId?: string;\n}\n\n/**\n * Immutable terminal Pi branch captured by the thin Pi adapter.\n *\n * The serialized v3 snapshot is data, not a writable parent path. The child host\n * converts it into a separate v4 journal and never opens the active Pi history.\n */\nexport interface DoomChildSessionTerminalPiForkSource {\n readonly kind: 'terminal-pi-fork';\n readonly sourceSessionId: string;\n readonly sourceLeafId: string;\n readonly snapshotJsonl: string;\n}\n\nexport type DoomChildSessionSource =\n | DoomChildSessionFreshSource\n | DoomChildSessionV4RestoreSource\n | DoomChildSessionV4ForkSource\n | DoomChildSessionTerminalPiForkSource;\n\nexport interface DoomChildSessionScope {\n readonly rootSessionId: string;\n readonly scopeKey: string;\n}\n\n/** Capability data is intentionally host-neutral; the owning runtime validates its fields. */\nexport interface DoomChildSessionCapabilityCeiling {\n readonly allowedTools?: readonly string[];\n readonly requiredTools?: readonly string[];\n readonly allowMcpTools?: boolean;\n readonly allowedExternalProfiles?: readonly string[];\n readonly denyExtensions?: boolean;\n}\n\nexport interface DoomChildSessionRequest {\n readonly runId: string;\n readonly parentSessionId: string;\n readonly scope: DoomChildSessionScope;\n readonly source: DoomChildSessionSource;\n readonly agent: string;\n readonly task: string;\n readonly cwd: string;\n readonly model?: string;\n readonly thinking?: string;\n readonly systemPrompt?: string;\n readonly systemPromptMode?: 'append' | 'replace';\n readonly extensions?: readonly string[];\n readonly subagentOnlyExtensions?: readonly string[];\n readonly tools?: readonly string[];\n readonly excludeTools?: readonly string[];\n readonly skills?: readonly string[];\n readonly mcpDirectTools?: readonly string[];\n readonly capabilityCeiling?: DoomChildSessionCapabilityCeiling;\n readonly intercom?: DoomChildSessionIntercom;\n readonly environment: Readonly<Record<string, string | undefined>>;\n}\n\nexport interface DoomChildSessionUsage {\n readonly rowId: string;\n readonly cost: number;\n}\n\nexport interface DoomChildSessionEvent {\n readonly runId: string;\n readonly state: DoomChildSessionState;\n readonly timestamp: number;\n readonly message?: string;\n readonly sessionFile?: string;\n readonly cost?: number;\n}\n\nexport interface DoomChildSessionToolResult {\n readonly content: readonly (\n | { readonly type: 'text'; readonly text: string }\n | { readonly type: 'image'; readonly data: string; readonly mimeType: string }\n )[];\n readonly details?: unknown;\n readonly isError?: boolean;\n}\n\nexport interface DoomChildSessionTool {\n readonly name: string;\n readonly description: string;\n readonly parameters: unknown;\n execute(\n operationId: string,\n params: unknown,\n signal?: AbortSignal,\n onUpdate?: (result: DoomChildSessionToolResult) => void,\n ): Promise<DoomChildSessionToolResult>;\n}\n\n/** Direct in-process Team intercom supplied by an owning extension. */\nexport interface DoomChildSessionIntercom {\n bindRuntime(runtime: DoomChildSessionRuntime): DoomChildSessionTool;\n dispose?(): void;\n}\n\n/** Host runtime owned by the direct headless or terminal adapter. */\nexport interface DoomChildSessionRuntime {\n readonly sessionId: string;\n readonly sessionFile?: string;\n prompt(task: string): Promise<string | void>;\n steer(message: string): Promise<void>;\n followUp?(message: string): Promise<void>;\n abort(): Promise<void>;\n onUsage?(listener: (usage: DoomChildSessionUsage) => void): () => void;\n /** Reads only this runtime's owned journal. The callback may remain valid after runtime disposal. */\n readTranscriptPage?(request: Omit<TranscriptPageRequest, 'threadId'>, signal?: AbortSignal): Promise<TranscriptPage>;\n dispose(): Promise<void>;\n}\n\nexport type DoomChildSessionRuntimeFactory = (\n request: DoomChildSessionRequest,\n signal?: AbortSignal,\n) => Promise<DoomChildSessionRuntime>;\n\nexport interface DoomChildSessionHandle {\n readonly runId: string;\n readonly sessionFile?: string;\n state(): DoomChildSessionState;\n subscribe(listener: (event: DoomChildSessionEvent) => void): () => void;\n steer(message: string, signal?: AbortSignal): Promise<void>;\n stop(reason?: string): Promise<void>;\n dispose(): Promise<void>;\n}\n\nexport interface DoomChildSessionService {\n start(request: DoomChildSessionRequest, signal?: AbortSignal): Promise<DoomChildSessionHandle>;\n get(runId: string): DoomChildSessionHandle | undefined;\n /** Resolves an owned run ID inside this session service. Callers never provide journal paths. */\n readTranscriptPage?(\n runId: string,\n request: Omit<TranscriptPageRequest, 'threadId'>,\n signal?: AbortSignal,\n ): Promise<TranscriptPage>;\n close(): Promise<void>;\n}\n\n/** Lazy provider lets Pi and headless composition bind the host-owned service later. */\nexport interface DoomChildSessionServiceProvider {\n get(): DoomChildSessionService | undefined;\n}\ndeclare module '@deepseek-ai/cordis' {\n interface Context {\n 'doom/child-session': DoomChildSessionService;\n 'doom/child-session-mcp-tool': DoomChildSessionTool;\n }\n}\n\nexport function readDoomChildSessionService(context: Context): DoomChildSessionService | undefined {\n return context.get(DOOM_CHILD_SESSION_SERVICE) as DoomChildSessionService | undefined;\n}\n\nexport function requireDoomChildSessionService(context: Context): DoomChildSessionService {\n const service = readDoomChildSessionService(context);\n if (!service) throw new Error('The Doom child-session service is unavailable.');\n return service;\n}\n"],"mappings":";AAIA,MAAa,6BAA6B;;AAE1C,MAAa,sCAAsC;AA2KnD,SAAgB,4BAA4B,SAAuD;CACjG,OAAO,QAAQ,IAAI,0BAA0B;AAC/C;AAEA,SAAgB,+BAA+B,SAA2C;CACxF,MAAM,UAAU,4BAA4B,OAAO;CACnD,IAAI,CAAC,SAAS,MAAM,IAAI,MAAM,gDAAgD;CAC9E,OAAO;AACT"}
@@ -625,7 +625,11 @@ async function createHeadlessSessionHost(options) {
625
625
  cwd: options.cwd,
626
626
  sessionsRoot: parsed.sessionDir ?? node_path.default.join(agentDir, "server", "sessions"),
627
627
  models: modelRuntime,
628
- defaultModel: () => currentModel
628
+ defaultModel: () => currentModel,
629
+ mcpTool: () => {
630
+ if (disposed || !headlessReady || !headlessHost?.status.ready) return void 0;
631
+ return mcpServiceRoot?.get(require_childSession.DOOM_CHILD_SESSION_MCP_TOOL_SERVICE);
632
+ }
629
633
  });
630
634
  const completeAuxiliaryModel = async (reference, request) => {
631
635
  if (disposed || !headlessReady || promptPreparationFailed || !headlessHost?.status.ready) throw new Error("Headless capability preparation is not ready.");