@agimon-ai/doompi-team 0.0.1-alpha.13 → 0.0.1-alpha.15

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 (72) hide show
  1. package/README.md +30 -16
  2. package/dist/adapters/process/sdkRunnerEntry.cjs +2 -0
  3. package/dist/adapters/process/sdkRunnerEntry.cjs.map +1 -0
  4. package/dist/adapters/process/sdkRunnerEntry.d.cts +5 -0
  5. package/dist/adapters/process/sdkRunnerEntry.d.cts.map +1 -0
  6. package/dist/adapters/process/sdkRunnerEntry.d.mts +5 -0
  7. package/dist/adapters/process/sdkRunnerEntry.d.mts.map +1 -0
  8. package/dist/adapters/process/sdkRunnerEntry.mjs +2 -0
  9. package/dist/adapters/process/sdkRunnerEntry.mjs.map +1 -0
  10. package/dist/extensions/orchestratorPrompt.cjs +2 -2
  11. package/dist/extensions/orchestratorPrompt.cjs.map +1 -1
  12. package/dist/extensions/orchestratorPrompt.mjs +2 -2
  13. package/dist/extensions/orchestratorPrompt.mjs.map +1 -1
  14. package/dist/extensions/spawnPlan.cjs +2 -2
  15. package/dist/extensions/spawnPlan.cjs.map +1 -1
  16. package/dist/extensions/spawnPlan.mjs +2 -2
  17. package/dist/extensions/spawnPlan.mjs.map +1 -1
  18. package/dist/extensions/subagentPromptRuntime.cjs.map +1 -1
  19. package/dist/extensions/subagentPromptRuntime.mjs.map +1 -1
  20. package/dist/extensions/toolDescription.cjs +1 -1
  21. package/dist/extensions/toolDescription.cjs.map +1 -1
  22. package/dist/extensions/toolDescription.mjs +1 -1
  23. package/dist/extensions/toolDescription.mjs.map +1 -1
  24. package/dist/runs/sdkRunnerEntry.cjs +1 -1
  25. package/dist/runs/sdkRunnerEntry.d.cts +2 -1
  26. package/dist/runs/sdkRunnerEntry.d.mts +2 -1
  27. package/dist/runs/sdkRunnerEntry.mjs +1 -1
  28. package/dist/schemas/team/packageConfig.cjs +2 -0
  29. package/dist/schemas/team/packageConfig.cjs.map +1 -0
  30. package/dist/schemas/team/packageConfig.mjs +2 -0
  31. package/dist/schemas/team/packageConfig.mjs.map +1 -0
  32. package/dist/services/agents/discovery.cjs +1 -1
  33. package/dist/services/agents/discovery.cjs.map +1 -1
  34. package/dist/services/agents/discovery.mjs +1 -1
  35. package/dist/services/agents/discovery.mjs.map +1 -1
  36. package/dist/services/agents/types.d.cts +2 -2
  37. package/dist/services/agents/types.d.mts +2 -2
  38. package/dist/services/runs/background/asyncExecution.cjs +1 -1
  39. package/dist/services/runs/background/asyncExecution.cjs.map +1 -1
  40. package/dist/services/runs/background/asyncExecution.mjs +1 -1
  41. package/dist/services/runs/background/asyncExecution.mjs.map +1 -1
  42. package/dist/services/runs/background/cliRunnerEntry.cjs.map +1 -1
  43. package/dist/services/runs/background/cliRunnerEntry.mjs.map +1 -1
  44. package/dist/services/runs/extensionErrorTelemetry.cjs +2 -0
  45. package/dist/services/runs/extensionErrorTelemetry.cjs.map +1 -0
  46. package/dist/services/runs/extensionErrorTelemetry.mjs +2 -0
  47. package/dist/services/runs/extensionErrorTelemetry.mjs.map +1 -0
  48. package/dist/services/runs/sdkRunnerEntry.cjs +1 -2
  49. package/dist/services/runs/sdkRunnerEntry.mjs +1 -2
  50. package/dist/services/runs/shared/piArgs.cjs +1 -1
  51. package/dist/services/runs/shared/piArgs.cjs.map +1 -1
  52. package/dist/services/runs/shared/piArgs.mjs +1 -1
  53. package/dist/services/runs/shared/piArgs.mjs.map +1 -1
  54. package/dist/tui/agentCatalog.cjs +1 -1
  55. package/dist/tui/agentCatalog.cjs.map +1 -1
  56. package/dist/tui/agentCatalog.mjs +1 -1
  57. package/dist/tui/agentCatalog.mjs.map +1 -1
  58. package/dist/tui/agentResourceProjection.cjs +1 -1
  59. package/dist/tui/agentResourceProjection.cjs.map +1 -1
  60. package/dist/tui/agentResourceProjection.mjs +1 -1
  61. package/dist/tui/agentResourceProjection.mjs.map +1 -1
  62. package/dist/tui/fleet.cjs +1 -1
  63. package/dist/tui/fleet.cjs.map +1 -1
  64. package/dist/tui/fleet.mjs +2 -2
  65. package/dist/tui/fleet.mjs.map +1 -1
  66. package/dist/tui/register.cjs +1 -1
  67. package/dist/tui/register.cjs.map +1 -1
  68. package/dist/tui/register.mjs +1 -1
  69. package/dist/tui/register.mjs.map +1 -1
  70. package/package.json +8 -8
  71. package/dist/services/runs/sdkRunnerEntry.cjs.map +0 -1
  72. package/dist/services/runs/sdkRunnerEntry.mjs.map +0 -1
package/README.md CHANGED
@@ -1,13 +1,18 @@
1
1
  # @agimon-ai/doompi-team
2
2
 
3
- Async-only subagent team runtime for Pi: named agents, peer messaging, shared task board.
3
+ **Subagents should leave a paper trail.**
4
4
 
5
- Named subagents that run asynchronously against a shared task board, sequentially or in
6
- parallel, with peer messaging and a model policy per layer.
5
+ This is Doompi's async-only team runtime: named agents, background runs, peer messaging,
6
+ and one task board shared with the parent. Agents can work in parallel and use the model
7
+ policy owned by the selected Team package entry without turning the main conversation
8
+ into a wall of child transcripts.
7
9
 
8
- Part of [Doompi](https://www.npmjs.com/package/@agimon-ai/doompi), a coding agent that loads
9
- only the skills and tools you name. This package is composed by Doompi and is not usually
10
- installed on its own.
10
+ Runs are detached from an environment snapshot and may outlive the parent that launched
11
+ them. Each child gets its own resolved harness state, so recovery does not depend on the
12
+ parent still being around to explain itself.
13
+
14
+ This is part of [Doompi](https://www.npmjs.com/package/@agimon-ai/doompi). Most users load
15
+ it through a major-mode layer.
11
16
 
12
17
  ## Install
13
18
 
@@ -17,29 +22,38 @@ npm install @agimon-ai/doompi-team
17
22
 
18
23
  ## How it loads
19
24
 
20
- Name it in a layer in `.doom/modes.yaml`, then add that layer to a major mode:
25
+ Put the package in a layer, then add that layer to a major mode. When Team needs
26
+ configuration, use the package-object form so the options stay with their owner:
21
27
 
22
28
  ```yaml
23
29
  layers:
24
30
  team:
25
- packages: ['@agimon-ai/doompi-team/extensions/doom']
31
+ packages:
32
+ - name: '@agimon-ai/doompi-team'
33
+ config:
34
+ models:
35
+ - model: openai-codex/gpt-5.6-luna
36
+ thinking: xhigh
37
+ excludeTools: [ask_user_question, intercom, subagent]
26
38
 
27
39
  majorMode:
28
40
  dev: [team]
29
41
  ```
30
42
 
31
- ## Leader
32
-
33
- `SPC a` opens the subagent fleet, once the extension is loaded.
43
+ Use the shorter string form when no Team configuration is needed. The package's Pi
44
+ manifest selects the Doom adapter. Later selected Team entries replace `models`; their
45
+ `excludeTools` values are unioned in layer order. A sibling `layer.config` block is
46
+ invalid because it cannot say which package owns the options.
34
47
 
35
- ## Notes
48
+ ## Leader
36
49
 
37
- Subagents run detached from an environment snapshot and can outlive the parent that spawned
38
- them, so each one gets a harness state file of its own.
50
+ - `SPC a l` lists the agents available to this session.
51
+ - `SPC a r` opens current-session runs and their controls.
39
52
 
40
- ## Entry points
53
+ ## Public API
41
54
 
42
- 8 subpaths are declared in the `exports` field of `package.json`.
55
+ The root export contains the team runtime. Supported subpaths expose agent discovery,
56
+ background-run services, and the Doom adapter; `package.json` carries the complete list.
43
57
 
44
58
  ## License
45
59
 
@@ -0,0 +1,2 @@
1
+ const e=require(`../../_virtual/_rolldown/runtime.cjs`),t=require(`../atomicJson.cjs`);require(`../../shared/atomicJson.cjs`);const n=require(`./env.cjs`),r=require(`../../shared/paths.cjs`),i=require(`./childTranscript.cjs`);require(`../../shared/childTranscript.cjs`);const a=require(`../../services/runs/background/parentWatchdog.cjs`),o=require(`../../services/runs/extensionErrorTelemetry.cjs`);let s=require(`node:fs`);s=e.__toESM(s,1);let c=require(`@earendil-works/pi-coding-agent`),l=require(`@agimon-ai/doompi-telemetry`),u=require(`@agimon-ai/doompi-extension-contracts/child-process`);const d=`doom_team.child_finished`,f=`doom_team.child_failed`;function p(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function m(e){return e instanceof Error?e.message:String(e)}function h(e){let t=r.currentRunConfigPath(e),n=JSON.parse(s.readFileSync(t,`utf8`));if(!p(n)||n.runId!==e||!p(n.sdk))throw Error(`Launch config for run '${e}' is invalid.`);return n}function g(e){let{cwd:t,sdk:n}=e;return n.sessionFile?c.SessionManager.open(n.sessionFile,n.sessionDir,t):n.sessionEnabled?c.SessionManager.create(t,n.sessionDir):c.SessionManager.inMemory(t)}function _(e,n){let r=e?.handshakePath;!r||s.existsSync(r)||t.writeAtomicJson(r,{state:`error`,error:m(n)})}let v,y;async function b(e,t,n){let r=y;y=void 0,r&&(n===void 0?await r.recordEvent(e,t):await r.recordError(e,n,t),await r.flush(),await r.shutdown())}async function x(){let e=Date.now();y=(0,l.createDoomTelemetry)({serviceName:`doom-team-sdk-child`,packageName:`@agimon-ai/doompi-team`,env:process.env,enableLogs:!0,enableTraces:!0});let t=process.env[n.SUBAGENT_RUN_ID_ENV]?.trim();if(!t)throw Error(`${n.SUBAGENT_RUN_ID_ENV} is required.`);if(!r.adoptSessionScopeFromEnv())throw Error(`${u.SUBAGENT_ROOT_SESSION_ENV} is required: a child cannot resolve its session scope without it.`);let s;try{s=h(t);let n=s;await y?.recordEvent(`doom_team.child_started`,{runtime:`sdk`,"agent.name":n.agent,...n.sdk.model?{"model.id":n.sdk.model}:{},outcome:`started`});let{sdk:r}=n,l=(0,c.getAgentDir)(),u=await(0,c.createAgentSessionServices)({cwd:s.cwd,agentDir:l,resourceLoaderOptions:{additionalExtensionPaths:r.extensions,additionalSkillPaths:r.skillPaths,noExtensions:r.noAmbientExtensions,noSkills:r.noSkills,noContextFiles:r.noContextFiles,...r.systemPromptMode===`replace`?{systemPrompt:r.systemPrompt}:{},...r.systemPrompt&&r.systemPromptMode!==`replace`?{appendSystemPrompt:[r.systemPrompt]}:{}}}),f=u.diagnostics.find(e=>e.type===`error`);if(f)throw Error(f.message);let p=r.model?(0,c.resolveCliModel)({cliModel:r.model,modelRuntime:u.modelRuntime}):void 0;if(p&&!p.model)throw Error(p.error??`Model '${r.model}' was not found.`);let{session:m}=await(0,c.createAgentSessionFromServices)({services:u,sessionManager:g(s),...p?.model?{model:p.model}:{},...p?.thinkingLevel?{thinkingLevel:p.thinkingLevel}:{},...r.tools?{tools:r.tools}:{},...r.noTools?{noTools:r.noTools}:{},...r.excludeTools?{excludeTools:r.excludeTools}:{}});v=a.startParentWatchdog({onParentLost:()=>{m.dispose(),b(d,{runtime:`sdk`,"agent.name":n.agent,duration_ms:Date.now()-e,outcome:`parent_lost`}).finally(()=>process.exit(0))}});let _=s.transcriptPath?i.createChildTranscriptWriter({transcriptPath:s.transcriptPath,source:`async`,runId:s.runId,agent:s.agent,childIndex:s.childIndex,cwd:s.cwd}):void 0;_?.writeInitialUserMessage(s.task);let x=m.subscribe(t=>{_?.writeChildEvent(t),t.type===`agent_end`&&setImmediate(()=>{m.agent.hasQueuedMessages()||(m.dispose(),b(d,{runtime:`sdk`,"agent.name":n.agent,duration_ms:Date.now()-e,outcome:`completed`}).finally(()=>process.exit(0)))})});try{await m.bindExtensions({mode:`print`,onError:e=>{o.recordNonBlockingExtensionError(y,e)}}),await m.prompt(s.task)}finally{v?.(),x(),m.dispose(),await b(d,{runtime:`sdk`,"agent.name":n.agent,duration_ms:Date.now()-e,outcome:`completed`})}}catch(e){throw _(s,e),await b(f,{outcome:`failed`},e),e}}x().then(()=>{process.exit(0)},async e=>{await b(f,{outcome:`failed`},e);let t=e instanceof Error?e:Error(`Doom Team SDK child failed`,{cause:e});setImmediate(()=>{throw t})}),exports.runSdkChild=x;
2
+ //# sourceMappingURL=sdkRunnerEntry.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sdkRunnerEntry.cjs","names":["currentRunConfigPath","fs","SessionManager","SUBAGENT_RUN_ID_ENV","adoptSessionScopeFromEnv","SUBAGENT_ROOT_SESSION_ENV","startParentWatchdog","createChildTranscriptWriter"],"sources":["../../../src/adapters/process/sdkRunnerEntry.ts"],"sourcesContent":["import * as fs from 'node:fs';\nimport { createDoomTelemetry, type DoomTelemetry } from '@agimon-ai/doompi-telemetry';\nimport {\n createAgentSessionFromServices,\n createAgentSessionServices,\n getAgentDir,\n resolveCliModel,\n SessionManager,\n} from '@earendil-works/pi-coding-agent';\n\nimport type { LaunchConfig } from '../../services/runs/background/asyncExecution.ts';\nimport { startParentWatchdog } from '../../services/runs/background/parentWatchdog.ts';\nimport { recordNonBlockingExtensionError } from '../../services/runs/extensionErrorTelemetry.ts';\nimport { writeAtomicJson } from '../../shared/atomicJson.ts';\nimport { createChildTranscriptWriter } from '../../shared/childTranscript.ts';\nimport { adoptSessionScopeFromEnv, currentRunConfigPath } from '../../shared/paths.ts';\nimport { SUBAGENT_ROOT_SESSION_ENV, SUBAGENT_RUN_ID_ENV } from './env.ts';\n\nconst SDK_RUNTIME = 'sdk';\nconst CHILD_STARTED_EVENT = 'doom_team.child_started';\nconst CHILD_FINISHED_EVENT = 'doom_team.child_finished';\nconst CHILD_FAILED_EVENT = 'doom_team.child_failed';\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\nfunction readLaunchConfig(runId: string): LaunchConfig {\n const configPath = currentRunConfigPath(runId);\n const parsed: unknown = JSON.parse(fs.readFileSync(configPath, 'utf8'));\n if (!isRecord(parsed) || parsed.runId !== runId || !isRecord(parsed.sdk)) {\n throw new Error(`Launch config for run '${runId}' is invalid.`);\n }\n return parsed as unknown as LaunchConfig;\n}\n\nfunction createSessionManager(config: LaunchConfig): SessionManager {\n const { cwd, sdk } = config;\n if (sdk.sessionFile) return SessionManager.open(sdk.sessionFile, sdk.sessionDir, cwd);\n if (sdk.sessionEnabled) return SessionManager.create(cwd, sdk.sessionDir);\n return SessionManager.inMemory(cwd);\n}\n\nfunction writeStartupError(config: LaunchConfig | undefined, error: unknown): void {\n const handshakePath = config?.handshakePath;\n if (!handshakePath || fs.existsSync(handshakePath)) return;\n writeAtomicJson(handshakePath, { state: 'error', error: errorMessage(error) });\n}\n\nlet stopWatchdog: (() => void) | undefined;\nlet childTelemetry: DoomTelemetry | undefined;\n\nasync function finishTelemetry(event: string, attributes: Record<string, unknown>, error?: unknown): Promise<void> {\n const telemetry = childTelemetry;\n childTelemetry = undefined;\n if (!telemetry) return;\n if (error === undefined) await telemetry.recordEvent(event, attributes);\n else await telemetry.recordError(event, error, attributes);\n await telemetry.flush();\n await telemetry.shutdown();\n}\n\nexport async function runSdkChild(): Promise<void> {\n const startedAt = Date.now();\n childTelemetry = createDoomTelemetry({\n serviceName: 'doom-team-sdk-child',\n packageName: '@agimon-ai/doompi-team',\n env: process.env,\n enableLogs: true,\n enableTraces: true,\n });\n const runId = process.env[SUBAGENT_RUN_ID_ENV]?.trim();\n if (!runId) throw new Error(`${SUBAGENT_RUN_ID_ENV} is required.`);\n // Before the launch config is read: its own path is scoped, so a child that\n // was spawned without a scope cannot find anything and should say why.\n if (!adoptSessionScopeFromEnv()) {\n throw new Error(`${SUBAGENT_ROOT_SESSION_ENV} is required: a child cannot resolve its session scope without it.`);\n }\n\n let config: LaunchConfig | undefined;\n try {\n config = readLaunchConfig(runId);\n const launchConfig = config;\n await childTelemetry?.recordEvent(CHILD_STARTED_EVENT, {\n runtime: SDK_RUNTIME,\n 'agent.name': launchConfig.agent,\n ...(launchConfig.sdk.model ? { 'model.id': launchConfig.sdk.model } : {}),\n outcome: 'started',\n });\n const { sdk } = launchConfig;\n const agentDir = getAgentDir();\n const services = await createAgentSessionServices({\n cwd: config.cwd,\n agentDir,\n resourceLoaderOptions: {\n additionalExtensionPaths: sdk.extensions,\n additionalSkillPaths: sdk.skillPaths,\n noExtensions: sdk.noAmbientExtensions,\n noSkills: sdk.noSkills,\n noContextFiles: sdk.noContextFiles,\n ...(sdk.systemPromptMode === 'replace' ? { systemPrompt: sdk.systemPrompt } : {}),\n ...(sdk.systemPrompt && sdk.systemPromptMode !== 'replace' ? { appendSystemPrompt: [sdk.systemPrompt] } : {}),\n },\n });\n const serviceError = services.diagnostics.find((diagnostic) => diagnostic.type === 'error');\n if (serviceError) throw new Error(serviceError.message);\n\n const resolved = sdk.model\n ? resolveCliModel({ cliModel: sdk.model, modelRuntime: services.modelRuntime })\n : undefined;\n if (resolved && !resolved.model) throw new Error(resolved.error ?? `Model '${sdk.model}' was not found.`);\n\n const { session } = await createAgentSessionFromServices({\n services,\n sessionManager: createSessionManager(config),\n ...(resolved?.model ? { model: resolved.model } : {}),\n ...(resolved?.thinkingLevel ? { thinkingLevel: resolved.thinkingLevel } : {}),\n ...(sdk.tools ? { tools: sdk.tools } : {}),\n ...(sdk.noTools ? { noTools: sdk.noTools } : {}),\n ...(sdk.excludeTools ? { excludeTools: sdk.excludeTools } : {}),\n });\n // The parent cannot signal us if it was SIGKILLed, and we are in our own\n // process group so its terminal cannot either. This is the only thing that\n // ends this run in that case.\n stopWatchdog = startParentWatchdog({\n onParentLost: () => {\n session.dispose();\n void finishTelemetry(CHILD_FINISHED_EVENT, {\n runtime: SDK_RUNTIME,\n 'agent.name': launchConfig.agent,\n duration_ms: Date.now() - startedAt,\n outcome: 'parent_lost',\n }).finally(() => process.exit(0));\n },\n });\n\n const transcript = config.transcriptPath\n ? createChildTranscriptWriter({\n transcriptPath: config.transcriptPath,\n source: 'async',\n runId: config.runId,\n agent: config.agent,\n childIndex: config.childIndex,\n cwd: config.cwd,\n })\n : undefined;\n transcript?.writeInitialUserMessage(config.task);\n const unsubscribe = session.subscribe((event) => {\n transcript?.writeChildEvent(event);\n if (event.type !== 'agent_end') return;\n // Pi emits session listeners only after awaiting every extension's\n // agent_end handler, including Doom Team's terminal persistence. Defer\n // one event-loop turn so every listener observes the event, then end\n // this dedicated one-session process unless an agent_end handler queued\n // a nudge or follow-up that Pi still needs to run.\n setImmediate(() => {\n if (session.agent.hasQueuedMessages()) return;\n session.dispose();\n void finishTelemetry(CHILD_FINISHED_EVENT, {\n runtime: SDK_RUNTIME,\n 'agent.name': launchConfig.agent,\n duration_ms: Date.now() - startedAt,\n outcome: 'completed',\n }).finally(() => process.exit(0));\n });\n });\n\n try {\n await session.bindExtensions({\n mode: 'print',\n onError: (failure) => {\n recordNonBlockingExtensionError(childTelemetry, failure);\n },\n });\n await session.prompt(config.task);\n } finally {\n stopWatchdog?.();\n unsubscribe();\n session.dispose();\n await finishTelemetry(CHILD_FINISHED_EVENT, {\n runtime: SDK_RUNTIME,\n 'agent.name': launchConfig.agent,\n duration_ms: Date.now() - startedAt,\n outcome: 'completed',\n });\n }\n } catch (error) {\n writeStartupError(config, error);\n await finishTelemetry(CHILD_FAILED_EVENT, { outcome: 'failed' }, error);\n throw error;\n }\n}\n\nvoid runSdkChild().then(\n () => {\n // This entry point owns a dedicated detached process for exactly one SDK\n // session. Extensions may retain polling intervals after session.dispose(),\n // so a successful run must terminate explicitly once synchronous result\n // persistence and session cleanup have completed.\n process.exit(0);\n },\n async (error: unknown) => {\n await finishTelemetry(CHILD_FAILED_EVENT, { outcome: 'failed' }, error);\n const failure = error instanceof Error ? error : new Error('Doom Team SDK child failed', { cause: error });\n setImmediate(() => {\n throw failure;\n });\n },\n);\n"],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ //#region src/adapters/process/sdkRunnerEntry.d.ts
2
+ declare function runSdkChild(): Promise<void>;
3
+ //#endregion
4
+ export { runSdkChild };
5
+ //# sourceMappingURL=sdkRunnerEntry.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sdkRunnerEntry.d.cts","names":[],"sources":["../../../src/adapters/process/sdkRunnerEntry.ts"],"mappings":";iBAkEsB,WAAA,CAAA,GAAe,OAAA"}
@@ -0,0 +1,5 @@
1
+ //#region src/adapters/process/sdkRunnerEntry.d.ts
2
+ declare function runSdkChild(): Promise<void>;
3
+ //#endregion
4
+ export { runSdkChild };
5
+ //# sourceMappingURL=sdkRunnerEntry.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sdkRunnerEntry.d.mts","names":[],"sources":["../../../src/adapters/process/sdkRunnerEntry.ts"],"mappings":";iBAkEsB,WAAA,CAAA,GAAe,OAAA"}
@@ -0,0 +1,2 @@
1
+ import{writeAtomicJson as e}from"../atomicJson.mjs";import{init_atomicJson as t}from"../../shared/atomicJson.mjs";import{SUBAGENT_ROOT_SESSION_ENV as n,SUBAGENT_RUN_ID_ENV as r,init_env as i}from"./env.mjs";import{adoptSessionScopeFromEnv as a,currentRunConfigPath as o,init_paths as s}from"../../shared/paths.mjs";import{createChildTranscriptWriter as c}from"./childTranscript.mjs";import{init_childTranscript as l}from"../../shared/childTranscript.mjs";import{startParentWatchdog as u}from"../../services/runs/background/parentWatchdog.mjs";import{recordNonBlockingExtensionError as d}from"../../services/runs/extensionErrorTelemetry.mjs";import*as f from"node:fs";import{SessionManager as p,createAgentSessionFromServices as m,createAgentSessionServices as h,getAgentDir as g,resolveCliModel as _}from"@earendil-works/pi-coding-agent";import{createDoomTelemetry as v}from"@agimon-ai/doompi-telemetry";t(),l(),s(),i();const y=`doom_team.child_finished`,b=`doom_team.child_failed`;function x(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function S(e){return e instanceof Error?e.message:String(e)}function C(e){let t=o(e),n=JSON.parse(f.readFileSync(t,`utf8`));if(!x(n)||n.runId!==e||!x(n.sdk))throw Error(`Launch config for run '${e}' is invalid.`);return n}function w(e){let{cwd:t,sdk:n}=e;return n.sessionFile?p.open(n.sessionFile,n.sessionDir,t):n.sessionEnabled?p.create(t,n.sessionDir):p.inMemory(t)}function T(t,n){let r=t?.handshakePath;!r||f.existsSync(r)||e(r,{state:`error`,error:S(n)})}let E,D;async function O(e,t,n){let r=D;D=void 0,r&&(n===void 0?await r.recordEvent(e,t):await r.recordError(e,n,t),await r.flush(),await r.shutdown())}async function k(){let e=Date.now();D=v({serviceName:`doom-team-sdk-child`,packageName:`@agimon-ai/doompi-team`,env:process.env,enableLogs:!0,enableTraces:!0});let t=process.env[r]?.trim();if(!t)throw Error(`${r} is required.`);if(!a())throw Error(`${n} is required: a child cannot resolve its session scope without it.`);let i;try{i=C(t);let n=i;await D?.recordEvent(`doom_team.child_started`,{runtime:`sdk`,"agent.name":n.agent,...n.sdk.model?{"model.id":n.sdk.model}:{},outcome:`started`});let{sdk:r}=n,a=g(),o=await h({cwd:i.cwd,agentDir:a,resourceLoaderOptions:{additionalExtensionPaths:r.extensions,additionalSkillPaths:r.skillPaths,noExtensions:r.noAmbientExtensions,noSkills:r.noSkills,noContextFiles:r.noContextFiles,...r.systemPromptMode===`replace`?{systemPrompt:r.systemPrompt}:{},...r.systemPrompt&&r.systemPromptMode!==`replace`?{appendSystemPrompt:[r.systemPrompt]}:{}}}),s=o.diagnostics.find(e=>e.type===`error`);if(s)throw Error(s.message);let l=r.model?_({cliModel:r.model,modelRuntime:o.modelRuntime}):void 0;if(l&&!l.model)throw Error(l.error??`Model '${r.model}' was not found.`);let{session:f}=await m({services:o,sessionManager:w(i),...l?.model?{model:l.model}:{},...l?.thinkingLevel?{thinkingLevel:l.thinkingLevel}:{},...r.tools?{tools:r.tools}:{},...r.noTools?{noTools:r.noTools}:{},...r.excludeTools?{excludeTools:r.excludeTools}:{}});E=u({onParentLost:()=>{f.dispose(),O(y,{runtime:`sdk`,"agent.name":n.agent,duration_ms:Date.now()-e,outcome:`parent_lost`}).finally(()=>process.exit(0))}});let p=i.transcriptPath?c({transcriptPath:i.transcriptPath,source:`async`,runId:i.runId,agent:i.agent,childIndex:i.childIndex,cwd:i.cwd}):void 0;p?.writeInitialUserMessage(i.task);let v=f.subscribe(t=>{p?.writeChildEvent(t),t.type===`agent_end`&&setImmediate(()=>{f.agent.hasQueuedMessages()||(f.dispose(),O(y,{runtime:`sdk`,"agent.name":n.agent,duration_ms:Date.now()-e,outcome:`completed`}).finally(()=>process.exit(0)))})});try{await f.bindExtensions({mode:`print`,onError:e=>{d(D,e)}}),await f.prompt(i.task)}finally{E?.(),v(),f.dispose(),await O(y,{runtime:`sdk`,"agent.name":n.agent,duration_ms:Date.now()-e,outcome:`completed`})}}catch(e){throw T(i,e),await O(b,{outcome:`failed`},e),e}}k().then(()=>{process.exit(0)},async e=>{await O(b,{outcome:`failed`},e);let t=e instanceof Error?e:Error(`Doom Team SDK child failed`,{cause:e});setImmediate(()=>{throw t})});export{k as runSdkChild};
2
+ //# sourceMappingURL=sdkRunnerEntry.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sdkRunnerEntry.mjs","names":[],"sources":["../../../src/adapters/process/sdkRunnerEntry.ts"],"sourcesContent":["import * as fs from 'node:fs';\nimport { createDoomTelemetry, type DoomTelemetry } from '@agimon-ai/doompi-telemetry';\nimport {\n createAgentSessionFromServices,\n createAgentSessionServices,\n getAgentDir,\n resolveCliModel,\n SessionManager,\n} from '@earendil-works/pi-coding-agent';\n\nimport type { LaunchConfig } from '../../services/runs/background/asyncExecution.ts';\nimport { startParentWatchdog } from '../../services/runs/background/parentWatchdog.ts';\nimport { recordNonBlockingExtensionError } from '../../services/runs/extensionErrorTelemetry.ts';\nimport { writeAtomicJson } from '../../shared/atomicJson.ts';\nimport { createChildTranscriptWriter } from '../../shared/childTranscript.ts';\nimport { adoptSessionScopeFromEnv, currentRunConfigPath } from '../../shared/paths.ts';\nimport { SUBAGENT_ROOT_SESSION_ENV, SUBAGENT_RUN_ID_ENV } from './env.ts';\n\nconst SDK_RUNTIME = 'sdk';\nconst CHILD_STARTED_EVENT = 'doom_team.child_started';\nconst CHILD_FINISHED_EVENT = 'doom_team.child_finished';\nconst CHILD_FAILED_EVENT = 'doom_team.child_failed';\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\nfunction readLaunchConfig(runId: string): LaunchConfig {\n const configPath = currentRunConfigPath(runId);\n const parsed: unknown = JSON.parse(fs.readFileSync(configPath, 'utf8'));\n if (!isRecord(parsed) || parsed.runId !== runId || !isRecord(parsed.sdk)) {\n throw new Error(`Launch config for run '${runId}' is invalid.`);\n }\n return parsed as unknown as LaunchConfig;\n}\n\nfunction createSessionManager(config: LaunchConfig): SessionManager {\n const { cwd, sdk } = config;\n if (sdk.sessionFile) return SessionManager.open(sdk.sessionFile, sdk.sessionDir, cwd);\n if (sdk.sessionEnabled) return SessionManager.create(cwd, sdk.sessionDir);\n return SessionManager.inMemory(cwd);\n}\n\nfunction writeStartupError(config: LaunchConfig | undefined, error: unknown): void {\n const handshakePath = config?.handshakePath;\n if (!handshakePath || fs.existsSync(handshakePath)) return;\n writeAtomicJson(handshakePath, { state: 'error', error: errorMessage(error) });\n}\n\nlet stopWatchdog: (() => void) | undefined;\nlet childTelemetry: DoomTelemetry | undefined;\n\nasync function finishTelemetry(event: string, attributes: Record<string, unknown>, error?: unknown): Promise<void> {\n const telemetry = childTelemetry;\n childTelemetry = undefined;\n if (!telemetry) return;\n if (error === undefined) await telemetry.recordEvent(event, attributes);\n else await telemetry.recordError(event, error, attributes);\n await telemetry.flush();\n await telemetry.shutdown();\n}\n\nexport async function runSdkChild(): Promise<void> {\n const startedAt = Date.now();\n childTelemetry = createDoomTelemetry({\n serviceName: 'doom-team-sdk-child',\n packageName: '@agimon-ai/doompi-team',\n env: process.env,\n enableLogs: true,\n enableTraces: true,\n });\n const runId = process.env[SUBAGENT_RUN_ID_ENV]?.trim();\n if (!runId) throw new Error(`${SUBAGENT_RUN_ID_ENV} is required.`);\n // Before the launch config is read: its own path is scoped, so a child that\n // was spawned without a scope cannot find anything and should say why.\n if (!adoptSessionScopeFromEnv()) {\n throw new Error(`${SUBAGENT_ROOT_SESSION_ENV} is required: a child cannot resolve its session scope without it.`);\n }\n\n let config: LaunchConfig | undefined;\n try {\n config = readLaunchConfig(runId);\n const launchConfig = config;\n await childTelemetry?.recordEvent(CHILD_STARTED_EVENT, {\n runtime: SDK_RUNTIME,\n 'agent.name': launchConfig.agent,\n ...(launchConfig.sdk.model ? { 'model.id': launchConfig.sdk.model } : {}),\n outcome: 'started',\n });\n const { sdk } = launchConfig;\n const agentDir = getAgentDir();\n const services = await createAgentSessionServices({\n cwd: config.cwd,\n agentDir,\n resourceLoaderOptions: {\n additionalExtensionPaths: sdk.extensions,\n additionalSkillPaths: sdk.skillPaths,\n noExtensions: sdk.noAmbientExtensions,\n noSkills: sdk.noSkills,\n noContextFiles: sdk.noContextFiles,\n ...(sdk.systemPromptMode === 'replace' ? { systemPrompt: sdk.systemPrompt } : {}),\n ...(sdk.systemPrompt && sdk.systemPromptMode !== 'replace' ? { appendSystemPrompt: [sdk.systemPrompt] } : {}),\n },\n });\n const serviceError = services.diagnostics.find((diagnostic) => diagnostic.type === 'error');\n if (serviceError) throw new Error(serviceError.message);\n\n const resolved = sdk.model\n ? resolveCliModel({ cliModel: sdk.model, modelRuntime: services.modelRuntime })\n : undefined;\n if (resolved && !resolved.model) throw new Error(resolved.error ?? `Model '${sdk.model}' was not found.`);\n\n const { session } = await createAgentSessionFromServices({\n services,\n sessionManager: createSessionManager(config),\n ...(resolved?.model ? { model: resolved.model } : {}),\n ...(resolved?.thinkingLevel ? { thinkingLevel: resolved.thinkingLevel } : {}),\n ...(sdk.tools ? { tools: sdk.tools } : {}),\n ...(sdk.noTools ? { noTools: sdk.noTools } : {}),\n ...(sdk.excludeTools ? { excludeTools: sdk.excludeTools } : {}),\n });\n // The parent cannot signal us if it was SIGKILLed, and we are in our own\n // process group so its terminal cannot either. This is the only thing that\n // ends this run in that case.\n stopWatchdog = startParentWatchdog({\n onParentLost: () => {\n session.dispose();\n void finishTelemetry(CHILD_FINISHED_EVENT, {\n runtime: SDK_RUNTIME,\n 'agent.name': launchConfig.agent,\n duration_ms: Date.now() - startedAt,\n outcome: 'parent_lost',\n }).finally(() => process.exit(0));\n },\n });\n\n const transcript = config.transcriptPath\n ? createChildTranscriptWriter({\n transcriptPath: config.transcriptPath,\n source: 'async',\n runId: config.runId,\n agent: config.agent,\n childIndex: config.childIndex,\n cwd: config.cwd,\n })\n : undefined;\n transcript?.writeInitialUserMessage(config.task);\n const unsubscribe = session.subscribe((event) => {\n transcript?.writeChildEvent(event);\n if (event.type !== 'agent_end') return;\n // Pi emits session listeners only after awaiting every extension's\n // agent_end handler, including Doom Team's terminal persistence. Defer\n // one event-loop turn so every listener observes the event, then end\n // this dedicated one-session process unless an agent_end handler queued\n // a nudge or follow-up that Pi still needs to run.\n setImmediate(() => {\n if (session.agent.hasQueuedMessages()) return;\n session.dispose();\n void finishTelemetry(CHILD_FINISHED_EVENT, {\n runtime: SDK_RUNTIME,\n 'agent.name': launchConfig.agent,\n duration_ms: Date.now() - startedAt,\n outcome: 'completed',\n }).finally(() => process.exit(0));\n });\n });\n\n try {\n await session.bindExtensions({\n mode: 'print',\n onError: (failure) => {\n recordNonBlockingExtensionError(childTelemetry, failure);\n },\n });\n await session.prompt(config.task);\n } finally {\n stopWatchdog?.();\n unsubscribe();\n session.dispose();\n await finishTelemetry(CHILD_FINISHED_EVENT, {\n runtime: SDK_RUNTIME,\n 'agent.name': launchConfig.agent,\n duration_ms: Date.now() - startedAt,\n outcome: 'completed',\n });\n }\n } catch (error) {\n writeStartupError(config, error);\n await finishTelemetry(CHILD_FAILED_EVENT, { outcome: 'failed' }, error);\n throw error;\n }\n}\n\nvoid runSdkChild().then(\n () => {\n // This entry point owns a dedicated detached process for exactly one SDK\n // session. Extensions may retain polling intervals after session.dispose(),\n // so a successful run must terminate explicitly once synchronous result\n // persistence and session cleanup have completed.\n process.exit(0);\n },\n async (error: unknown) => {\n await finishTelemetry(CHILD_FAILED_EVENT, { outcome: 'failed' }, error);\n const failure = error instanceof Error ? error : new Error('Doom Team SDK child failed', { cause: error });\n setImmediate(() => {\n throw failure;\n });\n },\n);\n"],"mappings":"24BAa6D,IACiB,IACS,IACb,CAE1E,MAEM,EAAuB,2BACvB,EAAqB,yBAE3B,SAAS,EAAS,EAAkD,CAClE,OAAO,OAAO,GAAU,YAAY,GAAkB,CAAC,MAAM,QAAQ,EAAM,CAG7E,SAAS,EAAa,EAAwB,CAC5C,OAAO,aAAiB,MAAQ,EAAM,QAAU,OAAO,EAAM,CAG/D,SAAS,EAAiB,EAA6B,CACrD,IAAM,EAAa,EAAqB,EAAM,CACxC,EAAkB,KAAK,MAAM,EAAG,aAAa,EAAY,OAAO,CAAC,CACvE,GAAI,CAAC,EAAS,EAAO,EAAI,EAAO,QAAU,GAAS,CAAC,EAAS,EAAO,IAAI,CACtE,MAAU,MAAM,0BAA0B,EAAM,eAAe,CAEjE,OAAO,EAGT,SAAS,EAAqB,EAAsC,CAClE,GAAM,CAAE,MAAK,OAAQ,EAGrB,OAFI,EAAI,YAAoB,EAAe,KAAK,EAAI,YAAa,EAAI,WAAY,EAAI,CACjF,EAAI,eAAuB,EAAe,OAAO,EAAK,EAAI,WAAW,CAClE,EAAe,SAAS,EAAI,CAGrC,SAAS,EAAkB,EAAkC,EAAsB,CACjF,IAAM,EAAgB,GAAQ,cAC1B,CAAC,GAAiB,EAAG,WAAW,EAAc,EAClD,EAAgB,EAAe,CAAE,MAAO,QAAS,MAAO,EAAa,EAAM,CAAE,CAAC,CAGhF,IAAI,EACA,EAEJ,eAAe,EAAgB,EAAe,EAAqC,EAAgC,CACjH,IAAM,EAAY,EAClB,EAAiB,IAAA,GACZ,IACD,IAAU,IAAA,GAAW,MAAM,EAAU,YAAY,EAAO,EAAW,CAClE,MAAM,EAAU,YAAY,EAAO,EAAO,EAAW,CAC1D,MAAM,EAAU,OAAO,CACvB,MAAM,EAAU,UAAU,EAG5B,eAAsB,GAA6B,CACjD,IAAM,EAAY,KAAK,KAAK,CAC5B,EAAiB,EAAoB,CACnC,YAAa,sBACb,YAAa,yBACb,IAAK,QAAQ,IACb,WAAY,GACZ,aAAc,GACf,CAAC,CACF,IAAM,EAAQ,QAAQ,IAAI,IAAsB,MAAM,CACtD,GAAI,CAAC,EAAO,MAAU,MAAM,GAAG,EAAoB,eAAe,CAGlE,GAAI,CAAC,GAA0B,CAC7B,MAAU,MAAM,GAAG,EAA0B,oEAAoE,CAGnH,IAAI,EACJ,GAAI,CACF,EAAS,EAAiB,EAAM,CAChC,IAAM,EAAe,EACrB,MAAM,GAAgB,YAAY,0BAAqB,CACrD,QAAS,MACT,aAAc,EAAa,MAC3B,GAAI,EAAa,IAAI,MAAQ,CAAE,WAAY,EAAa,IAAI,MAAO,CAAG,EAAE,CACxE,QAAS,UACV,CAAC,CACF,GAAM,CAAE,OAAQ,EACV,EAAW,GAAa,CACxB,EAAW,MAAM,EAA2B,CAChD,IAAK,EAAO,IACZ,WACA,sBAAuB,CACrB,yBAA0B,EAAI,WAC9B,qBAAsB,EAAI,WAC1B,aAAc,EAAI,oBAClB,SAAU,EAAI,SACd,eAAgB,EAAI,eACpB,GAAI,EAAI,mBAAqB,UAAY,CAAE,aAAc,EAAI,aAAc,CAAG,EAAE,CAChF,GAAI,EAAI,cAAgB,EAAI,mBAAqB,UAAY,CAAE,mBAAoB,CAAC,EAAI,aAAa,CAAE,CAAG,EAAE,CAC7G,CACF,CAAC,CACI,EAAe,EAAS,YAAY,KAAM,GAAe,EAAW,OAAS,QAAQ,CAC3F,GAAI,EAAc,MAAU,MAAM,EAAa,QAAQ,CAEvD,IAAM,EAAW,EAAI,MACjB,EAAgB,CAAE,SAAU,EAAI,MAAO,aAAc,EAAS,aAAc,CAAC,CAC7E,IAAA,GACJ,GAAI,GAAY,CAAC,EAAS,MAAO,MAAU,MAAM,EAAS,OAAS,UAAU,EAAI,MAAM,kBAAkB,CAEzG,GAAM,CAAE,WAAY,MAAM,EAA+B,CACvD,WACA,eAAgB,EAAqB,EAAO,CAC5C,GAAI,GAAU,MAAQ,CAAE,MAAO,EAAS,MAAO,CAAG,EAAE,CACpD,GAAI,GAAU,cAAgB,CAAE,cAAe,EAAS,cAAe,CAAG,EAAE,CAC5E,GAAI,EAAI,MAAQ,CAAE,MAAO,EAAI,MAAO,CAAG,EAAE,CACzC,GAAI,EAAI,QAAU,CAAE,QAAS,EAAI,QAAS,CAAG,EAAE,CAC/C,GAAI,EAAI,aAAe,CAAE,aAAc,EAAI,aAAc,CAAG,EAAE,CAC/D,CAAC,CAIF,EAAe,EAAoB,CACjC,iBAAoB,CAClB,EAAQ,SAAS,CACZ,EAAgB,EAAsB,CACzC,QAAS,MACT,aAAc,EAAa,MAC3B,YAAa,KAAK,KAAK,CAAG,EAC1B,QAAS,cACV,CAAC,CAAC,YAAc,QAAQ,KAAK,EAAE,CAAC,EAEpC,CAAC,CAEF,IAAM,EAAa,EAAO,eACtB,EAA4B,CAC1B,eAAgB,EAAO,eACvB,OAAQ,QACR,MAAO,EAAO,MACd,MAAO,EAAO,MACd,WAAY,EAAO,WACnB,IAAK,EAAO,IACb,CAAC,CACF,IAAA,GACJ,GAAY,wBAAwB,EAAO,KAAK,CAChD,IAAM,EAAc,EAAQ,UAAW,GAAU,CAC/C,GAAY,gBAAgB,EAAM,CAC9B,EAAM,OAAS,aAMnB,iBAAmB,CACb,EAAQ,MAAM,mBAAmB,GACrC,EAAQ,SAAS,CACZ,EAAgB,EAAsB,CACzC,QAAS,MACT,aAAc,EAAa,MAC3B,YAAa,KAAK,KAAK,CAAG,EAC1B,QAAS,YACV,CAAC,CAAC,YAAc,QAAQ,KAAK,EAAE,CAAC,GACjC,EACF,CAEF,GAAI,CACF,MAAM,EAAQ,eAAe,CAC3B,KAAM,QACN,QAAU,GAAY,CACpB,EAAgC,EAAgB,EAAQ,EAE3D,CAAC,CACF,MAAM,EAAQ,OAAO,EAAO,KAAK,QACzB,CACR,KAAgB,CAChB,GAAa,CACb,EAAQ,SAAS,CACjB,MAAM,EAAgB,EAAsB,CAC1C,QAAS,MACT,aAAc,EAAa,MAC3B,YAAa,KAAK,KAAK,CAAG,EAC1B,QAAS,YACV,CAAC,QAEG,EAAO,CAGd,MAFA,EAAkB,EAAQ,EAAM,CAChC,MAAM,EAAgB,EAAoB,CAAE,QAAS,SAAU,CAAE,EAAM,CACjE,GAIL,GAAa,CAAC,SACX,CAKJ,QAAQ,KAAK,EAAE,EAEjB,KAAO,IAAmB,CACxB,MAAM,EAAgB,EAAoB,CAAE,QAAS,SAAU,CAAE,EAAM,CACvE,IAAM,EAAU,aAAiB,MAAQ,EAAY,MAAM,6BAA8B,CAAE,MAAO,EAAO,CAAC,CAC1G,iBAAmB,CACjB,MAAM,GACN,EAEL"}
@@ -35,6 +35,6 @@ exploration. Widen only for a concrete missing dependency, not a repository
35
35
  inventory.
36
36
 
37
37
  **Children are not orchestrators.** Give every child a self-contained task.
38
- Tool availability, including coordination, is controlled by the selected layer;
39
- children must not assume they can contact main or delegate further.`;function t(e){return e.orchestratorPrompt!==!1}function n(t){return t?.includes(`## Delegating to subagents`)?t:t?`${t}\n\n${e}`:e}exports.appendOrchestratorPrompt=n,exports.shouldInjectOrchestratorPrompt=t;
38
+ Tool availability, including coordination, is controlled by Team package policy
39
+ and any active capability ceiling. Children must not assume they can contact main or delegate further.`;function t(e){return e.orchestratorPrompt!==!1}function n(t){return t?.includes(`## Delegating to subagents`)?t:t?`${t}\n\n${e}`:e}exports.appendOrchestratorPrompt=n,exports.shouldInjectOrchestratorPrompt=t;
40
40
  //# sourceMappingURL=orchestratorPrompt.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"orchestratorPrompt.cjs","names":[],"sources":["../../src/extensions/orchestratorPrompt.ts"],"sourcesContent":["/**\n * The system-prompt addendum that teaches a parent session how to orchestrate.\n *\n * WHY THIS EXISTS, AND WHY IT IS NOT MORE TOOL-DESCRIPTION TEXT:\n * Until this module, every piece of orchestration guidance this package had\n * lived inside the `subagent` tool's own description. That is the wrong\n * surface for it twice over. A tool description is read as \"how do I call this\n * thing\", so behavioural rules (\"choose what to do after launching\", \"synthesize\n * before delegating again\") compete for attention with call mechanics and lose.\n * And a description is only consulted when the model is already considering\n * that tool, whereas the rule that matters most - do not delegate work you\n * should just do - has to land BEFORE it reaches for the tool at all.\n *\n * So this is a MOVE, not an addition: the behavioural half of\n * `toolDescription.ts` came here, and the description kept the mechanics.\n * Token cost is close to neutral; placement is strictly better.\n *\n * WHY IT IS DEFAULT-ON:\n * `doom-pi` loads this extension in every session, so an opt-in flag would\n * mean nearly every session runs without it - which is today's behaviour and\n * today's problem. `ExtensionConfig.orchestratorPrompt: false` is the escape\n * hatch for a session that wants the tools without the guidance.\n *\n * KEEP THIS SHORT. It is prepended to every turn of every session. Anything\n * that is really call mechanics belongs in the tool description; anything that\n * is really package trivia belongs in a doc nobody pays per-turn for.\n */\n\n/**\n * Marker used to detect an addendum this package already appended, so a repeat\n * `before_agent_start` (or a host that replays the hook) cannot stack two\n * copies into one prompt.\n */\nexport const ORCHESTRATOR_PROMPT_MARKER = '## Delegating to subagents';\n\nexport const ORCHESTRATOR_PROMPT = `${ORCHESTRATOR_PROMPT_MARKER}\n\nYou can delegate work to subagent runs. Doing so well is a skill; doing it\nreflexively wastes time and tokens.\n\n**Do it yourself when you can.** A task you can finish with your own tools in a\nfew steps should not become a subagent. Delegation costs a process launch, a\ncold context, and a round trip. It pays off for work that is genuinely parallel,\ngenuinely long, or genuinely better done in a fresh context.\n\n**Launches return immediately.** \\`{action:\"run\", requests:[...]}\\` returns run\nhandles after startup, not completion. After launching, choose whether to keep\ndoing useful work that does not duplicate the delegated scope, or end your turn.\nDo not sleep or poll status in a loop. Completion messages wake you\nautomatically.\n\n**Results arrive as messages, not return values.** A finished run shows up as a\ncompletion message carrying its run id, its summary, and the handling it needs.\nAct on it: incorporate the finding, reject it with a reason, or say why it does\nnot apply. Never acknowledge one passively, and never invent or predict a\nresult that has not arrived. Use the run id it gives you to follow up -\n\\`{action:\"status\", id, transcriptLines:80}\\` for recent output, or\n\\`{action:\"steer\", id, message}\\` to redirect a live Pi child.\n\n**Workers cannot see this conversation.** Every task string must stand alone:\nthe goal, the paths, the constraints, the expected output. When you delegate\nfollow-up work after a research run, read the findings first and write the next\nprompt with the specific files and changes in it. Writing \"based on your\nfindings\" hands your own understanding to someone who does not have it.\n\n**Known context is a handoff, not a hint.** Put parent-verified paths and facts\nin a clearly labeled parent context pack. Tell the worker to read known paths\ndirectly before broad discovery; the pack satisfies generic initial-context\nexploration. Widen only for a concrete missing dependency, not a repository\ninventory.\n\n**Children are not orchestrators.** Give every child a self-contained task.\nTool availability, including coordination, is controlled by the selected layer;\nchildren must not assume they can contact main or delegate further.`;\n\nexport interface OrchestratorPromptConfig {\n /** `false` disables the addendum. Any other value, including absent, enables it. */\n orchestratorPrompt?: boolean;\n}\n\n/** Whether this session should receive the addendum. */\nexport function shouldInjectOrchestratorPrompt(config: OrchestratorPromptConfig): boolean {\n return config.orchestratorPrompt !== false;\n}\n\n/**\n * Append the addendum to a session's system prompt.\n *\n * Idempotent by marker rather than by a registration guard: the caller is a\n * per-turn hook, and the same base prompt reaching it twice must not produce a\n * prompt carrying the guidance twice.\n */\nexport function appendOrchestratorPrompt(systemPrompt: string | undefined): string {\n if (systemPrompt?.includes(ORCHESTRATOR_PROMPT_MARKER)) return systemPrompt;\n return systemPrompt ? `${systemPrompt}\\n\\n${ORCHESTRATOR_PROMPT}` : ORCHESTRATOR_PROMPT;\n}\n"],"mappings":"AAiCA,MAEa,EAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qEA8CnC,SAAgB,EAA+B,EAA2C,CACxF,OAAO,EAAO,qBAAuB,GAUvC,SAAgB,EAAyB,EAA0C,CAEjF,OADI,GAAc,SAAA,6BAAoC,CAAS,EACxD,EAAe,GAAG,EAAa,MAAM,IAAwB"}
1
+ {"version":3,"file":"orchestratorPrompt.cjs","names":[],"sources":["../../src/extensions/orchestratorPrompt.ts"],"sourcesContent":["/**\n * The system-prompt addendum that teaches a parent session how to orchestrate.\n *\n * WHY THIS EXISTS, AND WHY IT IS NOT MORE TOOL-DESCRIPTION TEXT:\n * Until this module, every piece of orchestration guidance this package had\n * lived inside the `subagent` tool's own description. That is the wrong\n * surface for it twice over. A tool description is read as \"how do I call this\n * thing\", so behavioural rules (\"choose what to do after launching\", \"synthesize\n * before delegating again\") compete for attention with call mechanics and lose.\n * And a description is only consulted when the model is already considering\n * that tool, whereas the rule that matters most - do not delegate work you\n * should just do - has to land BEFORE it reaches for the tool at all.\n *\n * So this is a MOVE, not an addition: the behavioural half of\n * `toolDescription.ts` came here, and the description kept the mechanics.\n * Token cost is close to neutral; placement is strictly better.\n *\n * WHY IT IS DEFAULT-ON:\n * `doom-pi` loads this extension in every session, so an opt-in flag would\n * mean nearly every session runs without it - which is today's behaviour and\n * today's problem. `ExtensionConfig.orchestratorPrompt: false` is the escape\n * hatch for a session that wants the tools without the guidance.\n *\n * KEEP THIS SHORT. It is prepended to every turn of every session. Anything\n * that is really call mechanics belongs in the tool description; anything that\n * is really package trivia belongs in a doc nobody pays per-turn for.\n */\n\n/**\n * Marker used to detect an addendum this package already appended, so a repeat\n * `before_agent_start` (or a host that replays the hook) cannot stack two\n * copies into one prompt.\n */\nexport const ORCHESTRATOR_PROMPT_MARKER = '## Delegating to subagents';\n\nexport const ORCHESTRATOR_PROMPT = `${ORCHESTRATOR_PROMPT_MARKER}\n\nYou can delegate work to subagent runs. Doing so well is a skill; doing it\nreflexively wastes time and tokens.\n\n**Do it yourself when you can.** A task you can finish with your own tools in a\nfew steps should not become a subagent. Delegation costs a process launch, a\ncold context, and a round trip. It pays off for work that is genuinely parallel,\ngenuinely long, or genuinely better done in a fresh context.\n\n**Launches return immediately.** \\`{action:\"run\", requests:[...]}\\` returns run\nhandles after startup, not completion. After launching, choose whether to keep\ndoing useful work that does not duplicate the delegated scope, or end your turn.\nDo not sleep or poll status in a loop. Completion messages wake you\nautomatically.\n\n**Results arrive as messages, not return values.** A finished run shows up as a\ncompletion message carrying its run id, its summary, and the handling it needs.\nAct on it: incorporate the finding, reject it with a reason, or say why it does\nnot apply. Never acknowledge one passively, and never invent or predict a\nresult that has not arrived. Use the run id it gives you to follow up -\n\\`{action:\"status\", id, transcriptLines:80}\\` for recent output, or\n\\`{action:\"steer\", id, message}\\` to redirect a live Pi child.\n\n**Workers cannot see this conversation.** Every task string must stand alone:\nthe goal, the paths, the constraints, the expected output. When you delegate\nfollow-up work after a research run, read the findings first and write the next\nprompt with the specific files and changes in it. Writing \"based on your\nfindings\" hands your own understanding to someone who does not have it.\n\n**Known context is a handoff, not a hint.** Put parent-verified paths and facts\nin a clearly labeled parent context pack. Tell the worker to read known paths\ndirectly before broad discovery; the pack satisfies generic initial-context\nexploration. Widen only for a concrete missing dependency, not a repository\ninventory.\n\n**Children are not orchestrators.** Give every child a self-contained task.\nTool availability, including coordination, is controlled by Team package policy\nand any active capability ceiling. Children must not assume they can contact main or delegate further.`;\n\nexport interface OrchestratorPromptConfig {\n /** `false` disables the addendum. Any other value, including absent, enables it. */\n orchestratorPrompt?: boolean;\n}\n\n/** Whether this session should receive the addendum. */\nexport function shouldInjectOrchestratorPrompt(config: OrchestratorPromptConfig): boolean {\n return config.orchestratorPrompt !== false;\n}\n\n/**\n * Append the addendum to a session's system prompt.\n *\n * Idempotent by marker rather than by a registration guard: the caller is a\n * per-turn hook, and the same base prompt reaching it twice must not produce a\n * prompt carrying the guidance twice.\n */\nexport function appendOrchestratorPrompt(systemPrompt: string | undefined): string {\n if (systemPrompt?.includes(ORCHESTRATOR_PROMPT_MARKER)) return systemPrompt;\n return systemPrompt ? `${systemPrompt}\\n\\n${ORCHESTRATOR_PROMPT}` : ORCHESTRATOR_PROMPT;\n}\n"],"mappings":"AAiCA,MAEa,EAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wGA8CnC,SAAgB,EAA+B,EAA2C,CACxF,OAAO,EAAO,qBAAuB,GAUvC,SAAgB,EAAyB,EAA0C,CAEjF,OADI,GAAc,SAAA,6BAAoC,CAAS,EACxD,EAAe,GAAG,EAAa,MAAM,IAAwB"}
@@ -35,6 +35,6 @@ exploration. Widen only for a concrete missing dependency, not a repository
35
35
  inventory.
36
36
 
37
37
  **Children are not orchestrators.** Give every child a self-contained task.
38
- Tool availability, including coordination, is controlled by the selected layer;
39
- children must not assume they can contact main or delegate further.`;function t(e){return e.orchestratorPrompt!==!1}function n(t){return t?.includes(`## Delegating to subagents`)?t:t?`${t}\n\n${e}`:e}export{n as appendOrchestratorPrompt,t as shouldInjectOrchestratorPrompt};
38
+ Tool availability, including coordination, is controlled by Team package policy
39
+ and any active capability ceiling. Children must not assume they can contact main or delegate further.`;function t(e){return e.orchestratorPrompt!==!1}function n(t){return t?.includes(`## Delegating to subagents`)?t:t?`${t}\n\n${e}`:e}export{n as appendOrchestratorPrompt,t as shouldInjectOrchestratorPrompt};
40
40
  //# sourceMappingURL=orchestratorPrompt.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"orchestratorPrompt.mjs","names":[],"sources":["../../src/extensions/orchestratorPrompt.ts"],"sourcesContent":["/**\n * The system-prompt addendum that teaches a parent session how to orchestrate.\n *\n * WHY THIS EXISTS, AND WHY IT IS NOT MORE TOOL-DESCRIPTION TEXT:\n * Until this module, every piece of orchestration guidance this package had\n * lived inside the `subagent` tool's own description. That is the wrong\n * surface for it twice over. A tool description is read as \"how do I call this\n * thing\", so behavioural rules (\"choose what to do after launching\", \"synthesize\n * before delegating again\") compete for attention with call mechanics and lose.\n * And a description is only consulted when the model is already considering\n * that tool, whereas the rule that matters most - do not delegate work you\n * should just do - has to land BEFORE it reaches for the tool at all.\n *\n * So this is a MOVE, not an addition: the behavioural half of\n * `toolDescription.ts` came here, and the description kept the mechanics.\n * Token cost is close to neutral; placement is strictly better.\n *\n * WHY IT IS DEFAULT-ON:\n * `doom-pi` loads this extension in every session, so an opt-in flag would\n * mean nearly every session runs without it - which is today's behaviour and\n * today's problem. `ExtensionConfig.orchestratorPrompt: false` is the escape\n * hatch for a session that wants the tools without the guidance.\n *\n * KEEP THIS SHORT. It is prepended to every turn of every session. Anything\n * that is really call mechanics belongs in the tool description; anything that\n * is really package trivia belongs in a doc nobody pays per-turn for.\n */\n\n/**\n * Marker used to detect an addendum this package already appended, so a repeat\n * `before_agent_start` (or a host that replays the hook) cannot stack two\n * copies into one prompt.\n */\nexport const ORCHESTRATOR_PROMPT_MARKER = '## Delegating to subagents';\n\nexport const ORCHESTRATOR_PROMPT = `${ORCHESTRATOR_PROMPT_MARKER}\n\nYou can delegate work to subagent runs. Doing so well is a skill; doing it\nreflexively wastes time and tokens.\n\n**Do it yourself when you can.** A task you can finish with your own tools in a\nfew steps should not become a subagent. Delegation costs a process launch, a\ncold context, and a round trip. It pays off for work that is genuinely parallel,\ngenuinely long, or genuinely better done in a fresh context.\n\n**Launches return immediately.** \\`{action:\"run\", requests:[...]}\\` returns run\nhandles after startup, not completion. After launching, choose whether to keep\ndoing useful work that does not duplicate the delegated scope, or end your turn.\nDo not sleep or poll status in a loop. Completion messages wake you\nautomatically.\n\n**Results arrive as messages, not return values.** A finished run shows up as a\ncompletion message carrying its run id, its summary, and the handling it needs.\nAct on it: incorporate the finding, reject it with a reason, or say why it does\nnot apply. Never acknowledge one passively, and never invent or predict a\nresult that has not arrived. Use the run id it gives you to follow up -\n\\`{action:\"status\", id, transcriptLines:80}\\` for recent output, or\n\\`{action:\"steer\", id, message}\\` to redirect a live Pi child.\n\n**Workers cannot see this conversation.** Every task string must stand alone:\nthe goal, the paths, the constraints, the expected output. When you delegate\nfollow-up work after a research run, read the findings first and write the next\nprompt with the specific files and changes in it. Writing \"based on your\nfindings\" hands your own understanding to someone who does not have it.\n\n**Known context is a handoff, not a hint.** Put parent-verified paths and facts\nin a clearly labeled parent context pack. Tell the worker to read known paths\ndirectly before broad discovery; the pack satisfies generic initial-context\nexploration. Widen only for a concrete missing dependency, not a repository\ninventory.\n\n**Children are not orchestrators.** Give every child a self-contained task.\nTool availability, including coordination, is controlled by the selected layer;\nchildren must not assume they can contact main or delegate further.`;\n\nexport interface OrchestratorPromptConfig {\n /** `false` disables the addendum. Any other value, including absent, enables it. */\n orchestratorPrompt?: boolean;\n}\n\n/** Whether this session should receive the addendum. */\nexport function shouldInjectOrchestratorPrompt(config: OrchestratorPromptConfig): boolean {\n return config.orchestratorPrompt !== false;\n}\n\n/**\n * Append the addendum to a session's system prompt.\n *\n * Idempotent by marker rather than by a registration guard: the caller is a\n * per-turn hook, and the same base prompt reaching it twice must not produce a\n * prompt carrying the guidance twice.\n */\nexport function appendOrchestratorPrompt(systemPrompt: string | undefined): string {\n if (systemPrompt?.includes(ORCHESTRATOR_PROMPT_MARKER)) return systemPrompt;\n return systemPrompt ? `${systemPrompt}\\n\\n${ORCHESTRATOR_PROMPT}` : ORCHESTRATOR_PROMPT;\n}\n"],"mappings":"AAiCA,MAEa,EAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qEA8CnC,SAAgB,EAA+B,EAA2C,CACxF,OAAO,EAAO,qBAAuB,GAUvC,SAAgB,EAAyB,EAA0C,CAEjF,OADI,GAAc,SAAA,6BAAoC,CAAS,EACxD,EAAe,GAAG,EAAa,MAAM,IAAwB"}
1
+ {"version":3,"file":"orchestratorPrompt.mjs","names":[],"sources":["../../src/extensions/orchestratorPrompt.ts"],"sourcesContent":["/**\n * The system-prompt addendum that teaches a parent session how to orchestrate.\n *\n * WHY THIS EXISTS, AND WHY IT IS NOT MORE TOOL-DESCRIPTION TEXT:\n * Until this module, every piece of orchestration guidance this package had\n * lived inside the `subagent` tool's own description. That is the wrong\n * surface for it twice over. A tool description is read as \"how do I call this\n * thing\", so behavioural rules (\"choose what to do after launching\", \"synthesize\n * before delegating again\") compete for attention with call mechanics and lose.\n * And a description is only consulted when the model is already considering\n * that tool, whereas the rule that matters most - do not delegate work you\n * should just do - has to land BEFORE it reaches for the tool at all.\n *\n * So this is a MOVE, not an addition: the behavioural half of\n * `toolDescription.ts` came here, and the description kept the mechanics.\n * Token cost is close to neutral; placement is strictly better.\n *\n * WHY IT IS DEFAULT-ON:\n * `doom-pi` loads this extension in every session, so an opt-in flag would\n * mean nearly every session runs without it - which is today's behaviour and\n * today's problem. `ExtensionConfig.orchestratorPrompt: false` is the escape\n * hatch for a session that wants the tools without the guidance.\n *\n * KEEP THIS SHORT. It is prepended to every turn of every session. Anything\n * that is really call mechanics belongs in the tool description; anything that\n * is really package trivia belongs in a doc nobody pays per-turn for.\n */\n\n/**\n * Marker used to detect an addendum this package already appended, so a repeat\n * `before_agent_start` (or a host that replays the hook) cannot stack two\n * copies into one prompt.\n */\nexport const ORCHESTRATOR_PROMPT_MARKER = '## Delegating to subagents';\n\nexport const ORCHESTRATOR_PROMPT = `${ORCHESTRATOR_PROMPT_MARKER}\n\nYou can delegate work to subagent runs. Doing so well is a skill; doing it\nreflexively wastes time and tokens.\n\n**Do it yourself when you can.** A task you can finish with your own tools in a\nfew steps should not become a subagent. Delegation costs a process launch, a\ncold context, and a round trip. It pays off for work that is genuinely parallel,\ngenuinely long, or genuinely better done in a fresh context.\n\n**Launches return immediately.** \\`{action:\"run\", requests:[...]}\\` returns run\nhandles after startup, not completion. After launching, choose whether to keep\ndoing useful work that does not duplicate the delegated scope, or end your turn.\nDo not sleep or poll status in a loop. Completion messages wake you\nautomatically.\n\n**Results arrive as messages, not return values.** A finished run shows up as a\ncompletion message carrying its run id, its summary, and the handling it needs.\nAct on it: incorporate the finding, reject it with a reason, or say why it does\nnot apply. Never acknowledge one passively, and never invent or predict a\nresult that has not arrived. Use the run id it gives you to follow up -\n\\`{action:\"status\", id, transcriptLines:80}\\` for recent output, or\n\\`{action:\"steer\", id, message}\\` to redirect a live Pi child.\n\n**Workers cannot see this conversation.** Every task string must stand alone:\nthe goal, the paths, the constraints, the expected output. When you delegate\nfollow-up work after a research run, read the findings first and write the next\nprompt with the specific files and changes in it. Writing \"based on your\nfindings\" hands your own understanding to someone who does not have it.\n\n**Known context is a handoff, not a hint.** Put parent-verified paths and facts\nin a clearly labeled parent context pack. Tell the worker to read known paths\ndirectly before broad discovery; the pack satisfies generic initial-context\nexploration. Widen only for a concrete missing dependency, not a repository\ninventory.\n\n**Children are not orchestrators.** Give every child a self-contained task.\nTool availability, including coordination, is controlled by Team package policy\nand any active capability ceiling. Children must not assume they can contact main or delegate further.`;\n\nexport interface OrchestratorPromptConfig {\n /** `false` disables the addendum. Any other value, including absent, enables it. */\n orchestratorPrompt?: boolean;\n}\n\n/** Whether this session should receive the addendum. */\nexport function shouldInjectOrchestratorPrompt(config: OrchestratorPromptConfig): boolean {\n return config.orchestratorPrompt !== false;\n}\n\n/**\n * Append the addendum to a session's system prompt.\n *\n * Idempotent by marker rather than by a registration guard: the caller is a\n * per-turn hook, and the same base prompt reaching it twice must not produce a\n * prompt carrying the guidance twice.\n */\nexport function appendOrchestratorPrompt(systemPrompt: string | undefined): string {\n if (systemPrompt?.includes(ORCHESTRATOR_PROMPT_MARKER)) return systemPrompt;\n return systemPrompt ? `${systemPrompt}\\n\\n${ORCHESTRATOR_PROMPT}` : ORCHESTRATOR_PROMPT;\n}\n"],"mappings":"AAiCA,MAEa,EAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wGA8CnC,SAAgB,EAA+B,EAA2C,CACxF,OAAO,EAAO,qBAAuB,GAUvC,SAAgB,EAAyB,EAA0C,CAEjF,OADI,GAAc,SAAA,6BAAoC,CAAS,EACxD,EAAe,GAAG,EAAa,MAAM,IAAwB"}
@@ -1,3 +1,3 @@
1
- const e=require(`../_virtual/_rolldown/runtime.cjs`),t=require(`../_virtual/_@oxc-project_runtime@0.127.0/helpers/decorate.cjs`),n=require(`../services/agents/discovery.cjs`);require(`../adapters/process/env.cjs`);const r=require(`../services/agents/skills.cjs`),i=require(`../container/types.cjs`),a=require(`../schemas/team/capabilityCeiling.cjs`),o=require(`../_virtual/_@oxc-project_runtime@0.127.0/helpers/decorateMetadata.cjs`),s=require(`../_virtual/_@oxc-project_runtime@0.127.0/helpers/decorateParam.cjs`),c=require(`../shared/errors.cjs`),l=require(`../services/runs/shared/depthGuard.cjs`),u=require(`../services/runs/shared/modelFallback.cjs`),d=require(`../services/runs/shared/runtimeRegistry.cjs`),f=require(`../services/runs/shared/runWithConcurrency.cjs`);let p=require(`node:fs`);p=e.__toESM(p,1);let m=require(`node:path`);m=e.__toESM(m,1);let h=require(`inversify`),g=require(`@earendil-works/pi-coding-agent`);var _;const v=`fresh`,y=`fork`,b=`runtime "pi"`;function x(e){if(!e?.trim())return!1;try{return p.accessSync(e,p.constants.R_OK),!0}catch{return!1}}function S(e,t){let n=e.getSessionFile();if(!x(n))return;let r=e.getLeafEntry(),i=t===`tool`&&r?.type===`message`&&r.message.role===`assistant`?r.parentId:r?.id??e.getLeafId();return i?{sessionFile:n,leafId:i}:void 0}function C(e){return!!e.leafId.trim()&&x(e.sessionFile)}function w(e,t){return e.sessionFile?v:e.context??t.defaultContext??v}const T=[`read`,`grep`,`find`,`ls`];function E(e,t){return t?e?`${e}\n\n${t}`:t:e}function D(e,t,n){if(d.isPiRuntime(e))return[];let r=[`Runtime '${e}' does not load Pi child extensions or hooks; launched best effort.`],i=[...t.tools!==void 0||t.mcpDirectTools?.length?[`tools`]:[],...t.skills?.length||t.skillPath?.length?[`skills`]:[],...t.extensions!==void 0||t.subagentOnlyExtensions?.length?[`extensions`]:[]];return i.length>0&&r.push(`Doom Team cannot project or enforce configured Pi ${i.join(`, `)} on runtime '${e}'.`),t.skills?.length&&r.push(`Configured skills were not injected: ${t.skills.join(`, `)}.`),n?.length&&r.push(`Runtime '${e}' cannot enforce layer subagent tool exclusions; launched best effort for: ${n.join(`, `)}.`),r}function O(e,t,n,r,i,a){let o=d.isPiRuntime(n)&&r&&i!==void 0?`${r.provider}/${r.id}`:void 0,s=[...t.modelSource?.scope===`layer`?[]:[t.model],...t.fallbackModels??[]],[c,...l]=(d.isPiRuntime(n)?[e.model,...s,...a??[],o]:[e.model,...s,...a??[]]).filter(e=>!!e?.trim());return{primaryModel:c,fallbackModels:l,model:u.selectAvailableModel(c,l,i)}}const k=`invalid_request`,A=`runtime_unavailable`,j=`unsupported_context`,M=`unsupported_operation`;let N=class{constructor(e,t,n=new a.SubagentCapabilityPolicyStore,i=new r.SkillDiscoveryService,o){this.agents=e,this.spawner=t,this.policies=n,this.skills=i,this.reportConcurrencyEvent=o}generateRunId(){return crypto.randomUUID()}createForkSessionFile(e,t){let n=g.SessionManager.open(e.sessionFile,void 0,t),r=n.createBranchedSession(e.leafId);if(!r)throw Error(`Could not create a branched Pi session from '${e.sessionFile}'.`);if(!p.existsSync(r)){let e=n.getHeader();if(!e)throw Error(`Forked Pi session '${r}' has no header.`);let t=[e,...n.getEntries()];p.writeFileSync(r,`${t.map(e=>JSON.stringify(e)).join(`
2
- `)}\n`,{flag:`wx`})}return r}removePreparedSessionFile(e){p.rmSync(e,{force:!0})}validateCwd(e){let t;try{t=p.statSync(e)}catch{throw new c.DoomTeamExpectedError(k,`Working directory '${e}' does not exist.`,!1,`Retry with an existing directory.`)}if(!t.isDirectory())throw new c.DoomTeamExpectedError(k,`Working directory '${e}' is not a directory.`,!1,`Retry with an existing directory.`)}resolveLayerExcludeTools(){return n.resolveActiveLayerSubagentConfig()?.config.excludeTools}resolveLayerModels(){return n.resolveActiveLayerModelSpecs()}executableAvailable(e){if(m.isAbsolute(e)||e.includes(m.sep))try{return p.accessSync(e,p.constants.X_OK),!0}catch{return!1}return(process.env.PATH??``).split(m.delimiter).filter(Boolean).some(t=>{try{return p.accessSync(m.join(t,e),p.constants.X_OK),!0}catch{return!1}})}resolveTaskList(e){let t=e.single!==void 0;if(t===(e.tasks!==void 0))throw new c.DoomTeamExpectedError(k,`A run requires exactly one of internal single or tasks representations.`,!1,`Submit a non-empty requests array.`);if(t)return[e.single];if(!e.tasks||e.tasks.length===0)throw new c.DoomTeamExpectedError(k,`A run requires at least one entry in its requests collection.`,!1,`Submit a non-empty requests array.`);return e.tasks}resolveAgentOrThrow(e,t,n){let r=this.agents.find(t,n,e);if(!r)throw new c.DoomTeamExpectedError(`agent_not_found`,`Unknown agent '${e}'.`,!1,`Call subagent({"action":"agents"}) and retry with an exact name.`);return r}resolveExecutableAgent(e,t,n){return e.inlineAgent?{name:e.agent.trim(),systemPromptMode:`append`,inheritProjectContext:!0,inheritSkills:!1,systemPrompt:e.inlineAgent.systemPrompt.trim(),tools:[...T],defaultContext:v,runtime:`pi`}:this.resolveAgentOrThrow(e.agent,t,n)}projectConfiguredSkills(e,t,n,i){if(!d.isPiRuntime(i)||!e.skills?.length)return{systemPrompt:e.systemPrompt,requireReadTool:!1,warnings:[]};let a=this.skills.resolveSkillsWithFallback(e.skills,t,n,e.skillPath,n),o=r.buildSkillInjection(a.resolved);return{systemPrompt:E(e.systemPrompt,o),requireReadTool:o.length>0,warnings:a.missing.length>0?[`Agent '${e.name}' could not resolve configured skills: ${a.missing.join(`, `)}; launched with resolved skills only.`]:[]}}async spawnOneChild(e){let{runId:t,operationId:n,agentConfig:r,capabilityCeiling:i,excludeTools:a,layerModels:o,taskInput:s,childIndex:c,fanout:l,fallbackCwd:u,parentSessionId:f,parentSessionFile:p,preparedSessionFile:m,handshakeTimeoutMs:h,artifacts:g,artifactDir:_,availableModels:v,parentModel:b,runtime:x,runtimes:S}=e,C=s.cwd??u,T=s.task??``,E=w(s,r),k=s.runtime??x??r.runtime??`pi`,A=O(s,r,k,b,v,o);if(A.primaryModel&&v!==void 0&&!A.model)return{agent:r.name,task:T,childIndex:c,error:`No authenticated model is available for '${r.name}'. Checked: ${[A.primaryModel,...A.fallbackModels].join(`, `)}.`};let j;try{j=this.projectConfiguredSkills(r,C,u,k)}catch(e){return{agent:r.name,task:T,childIndex:c,error:e instanceof Error?e.message:String(e)}}let M=[...j.warnings,...D(k,r,a)],N=M.length>0?M.join(` `):void 0,P={runId:t,...n?{operationId:n}:{},agent:r.name,...s.inlineAgent?{inlineAgent:s.inlineAgent}:{},task:T,cwd:C,childIndex:c,fanout:l,...p?{parentSessionFile:p}:{},piArgs:{baseArgs:[],sessionEnabled:d.isPiRuntime(k),...s.sessionFile?{sessionFile:s.sessionFile}:m?{sessionFile:m}:{},inheritProjectContext:r.inheritProjectContext,inheritSkills:r.inheritSkills,systemPromptMode:r.systemPromptMode,systemPrompt:j.systemPrompt,requireReadTool:j.requireReadTool,model:A.model,thinking:r.thinking,tools:r.tools,extensions:r.extensions,subagentOnlyExtensions:r.subagentOnlyExtensions,mcpDirectTools:r.mcpDirectTools,excludeTools:a,capabilityCeiling:i,cwd:C,...E===y&&f?{parentSessionId:f}:{}},...h===void 0?{}:{handshakeTimeoutMs:h},...g===void 0?{}:{artifacts:g},..._===void 0?{}:{artifactDir:_},runtime:k,runtimes:S};try{let e=await this.spawner.spawn(P);return{agent:r.name,task:T,childIndex:c,runId:e.runId,pid:e.pid,...N?{warning:N}:{}}}catch(e){return{agent:r.name,task:T,childIndex:c,error:e instanceof Error?e.message:String(e),...N?{warning:N}:{}}}}async spawn(e,t){let n=this.resolveTaskList(e),r=n.length>1,i=this.resolveLayerExcludeTools(),a=this.resolveLayerModels(),o=this.policies.resolve(),s=l.preflightSubagentDepth(e.currentDepth??l.resolveCurrentSubagentDepth(),t);if(s.error)throw new c.DoomTeamExpectedError(M,s.error,!1,`Give each child a self-contained task within the selected layer policy.`);let u=t.parallel?.maxTasks??8;if(n.length>u)throw new c.DoomTeamExpectedError(k,`Run requested ${n.length} tasks, but at most ${u} may run at once. Concurrency throttles how fast they start, not how many run.`,!1,`Split the requests into smaller explicit run calls.`);for(let e of n){if(!e.task?.trim())throw new c.DoomTeamExpectedError(k,`Run request for '${e.agent}' requires a nonblank task.`,!1,`Provide a self-contained nonblank task.`);if(e.inlineAgent&&!e.inlineAgent.systemPrompt.trim())throw new c.DoomTeamExpectedError(k,`Inline agent '${e.agent}' requires a nonblank system prompt.`,!1,`Provide a focused read-only exploration role.`)}let p=n.map(t=>this.resolveExecutableAgent(t,t.cwd??e.cwd,e.agentScope));for(let[t,r]of n.entries()){let n=w(r,p[t]),i=r.runtime??e.runtime??p[t].runtime??`pi`;if(n===y){if(!d.isPiRuntime(i))throw new c.DoomTeamExpectedError(j,`Fork context requires ${b} for '${r.agent}'.`,!1,`Use a Pi agent for fork context or explicitly request a fresh run.`);let t=e.parentSessionFile&&e.parentLeafId?{sessionFile:e.parentSessionFile,leafId:e.parentLeafId}:void 0;if(!t||!C(t))throw new c.DoomTeamExpectedError(j,`Fork context is unavailable for '${r.agent}': the parent Pi session has no readable source.`,!1,`Use an active persisted Pi session or explicitly request a fresh run.`)}}if(e.preallocatedRunIds&&e.preallocatedRunIds.length!==n.length)throw new c.DoomTeamExpectedError(`operation_conflict`,`The operation journal run-id count does not match the request count.`,!1,`Submit the run as a new tool call.`);let m=e.preallocatedRunIds??n.map(()=>this.generateRunId()),h=d.resolveRuntimeTable(t.runtimes);for(let[t,r]of n.entries()){let n=p[t],i=r.cwd??e.cwd;this.validateCwd(i);let s=r.runtime??e.runtime??n.runtime??`pi`,l=O(r,n,s,e.parentModel,e.availableModels,a);if(l.primaryModel&&e.availableModels!==void 0&&!l.model)throw new c.DoomTeamExpectedError(`model_unavailable`,`No authenticated model is available for '${n.name}'.`,!1,`Authenticate the requested model or choose an available model.`);if(r.inlineAgent&&!d.isPiRuntime(s))throw new c.DoomTeamExpectedError(M,`Inline agent '${r.agent}' requires ${b} to enforce its read-only tools.`,!1,`Remove the runtime override or use a discovered external-runtime agent without inlineAgent.`);if(o&&!d.isPiRuntime(s))throw new c.DoomTeamExpectedError(M,`Runtime '${s}' cannot enforce the active capability ceiling.`,!1,`Use ${b} while plan mode or another capability ceiling is active.`);if(!d.isPiRuntime(s)){let e;try{e=d.resolveRuntimeLaunch(s,h,{prompt:r.task??``,cwd:i}).command}catch(e){throw new c.DoomTeamExpectedError(A,e instanceof Error?e.message:String(e),!1,`Configure a valid external runtime or use ${b}.`)}if(!this.executableAvailable(e))throw new c.DoomTeamExpectedError(A,`Executable '${e}' for runtime '${s}' is unavailable.`,!1,`Install the executable, configure its absolute path, or use ${b}.`)}}let g=e.parentSessionFile&&e.parentLeafId?{sessionFile:e.parentSessionFile,leafId:e.parentLeafId}:void 0,_=[];try{for(let[t,r]of n.entries())_.push(w(r,p[t])===y?this.createForkSessionFile(g,r.cwd??e.cwd):void 0)}catch(e){for(let e of _)e&&this.removePreparedSessionFile(e);throw new c.DoomTeamExpectedError(j,e instanceof Error?e.message:String(e),!1,`Retry from an active persisted Pi session or explicitly request a fresh run.`)}let v=r?e.concurrency??t.parallel?.concurrency??4:1;return{outcomes:(await f.runWithConcurrency(n.map((n,s)=>()=>this.spawnOneChild({runId:m[s],operationId:e.operationId,agentConfig:p[s],excludeTools:i,layerModels:a,capabilityCeiling:o,taskInput:n,childIndex:s,fanout:r,fallbackCwd:e.cwd,parentSessionId:e.parentSessionId,parentSessionFile:e.parentSessionFile,preparedSessionFile:_[s],handshakeTimeoutMs:t.handshakeTimeoutMs,artifacts:e.artifacts,artifactDir:t.artifactDir,availableModels:e.availableModels,parentModel:e.parentModel,runtime:e.runtime,runtimes:h})),v,this.reportConcurrencyEvent)).map((e,t)=>e.status===`fulfilled`?e.value:{agent:p[t].name,task:n[t].task??``,childIndex:t,error:e.reason instanceof Error?e.reason.message:String(e.reason)})}}};N=t.__decorate([(0,h.injectable)(),s.__decorateParam(0,(0,h.inject)(i.DOOM_TEAM_TYPES.AgentDiscoveryService)),s.__decorateParam(1,(0,h.inject)(i.DOOM_TEAM_TYPES.AsyncSubagentSpawner)),s.__decorateParam(2,(0,h.inject)(i.DOOM_TEAM_TYPES.SubagentCapabilityPolicyStore)),s.__decorateParam(3,(0,h.inject)(i.DOOM_TEAM_TYPES.SkillDiscoveryService)),s.__decorateParam(4,(0,h.inject)(i.DOOM_TEAM_TYPES.ConcurrencyEventReporter)),s.__decorateParam(4,(0,h.optional)()),o.__decorateMetadata(`design:paramtypes`,[Object,Object,typeof(_=a.SubagentCapabilityPolicyStore!==void 0&&a.SubagentCapabilityPolicyStore)==`function`?_:Object,Object,Object])],N),Object.defineProperty(exports,`SpawnPlanner`,{enumerable:!0,get:function(){return N}}),exports.captureSessionForkSource=S;
1
+ const e=require(`../_virtual/_rolldown/runtime.cjs`),t=require(`../_virtual/_@oxc-project_runtime@0.127.0/helpers/decorate.cjs`),n=require(`../services/agents/discovery.cjs`);require(`../adapters/process/env.cjs`);const r=require(`../services/agents/skills.cjs`),i=require(`../container/types.cjs`),a=require(`../schemas/team/capabilityCeiling.cjs`),o=require(`../_virtual/_@oxc-project_runtime@0.127.0/helpers/decorateMetadata.cjs`),s=require(`../_virtual/_@oxc-project_runtime@0.127.0/helpers/decorateParam.cjs`),c=require(`../shared/errors.cjs`),l=require(`../services/runs/shared/depthGuard.cjs`),u=require(`../services/runs/shared/modelFallback.cjs`),d=require(`../services/runs/shared/runtimeRegistry.cjs`),f=require(`../services/runs/shared/runWithConcurrency.cjs`);let p=require(`node:fs`);p=e.__toESM(p,1);let m=require(`node:path`);m=e.__toESM(m,1);let h=require(`inversify`),g=require(`@earendil-works/pi-coding-agent`);var _;const v=`fresh`,y=`fork`,b=`runtime "pi"`;function x(e){if(!e?.trim())return!1;try{return p.accessSync(e,p.constants.R_OK),!0}catch{return!1}}function S(e,t){let n=e.getSessionFile();if(!x(n))return;let r=e.getLeafEntry(),i=t===`tool`&&r?.type===`message`&&r.message.role===`assistant`?r.parentId:r?.id??e.getLeafId();return i?{sessionFile:n,leafId:i}:void 0}function C(e){return!!e.leafId.trim()&&x(e.sessionFile)}function w(e,t){return e.sessionFile?v:e.context??t.defaultContext??v}const T=[`read`,`grep`,`find`,`ls`];function E(e,t){return t?e?`${e}\n\n${t}`:t:e}function D(e,t,n){if(d.isPiRuntime(e))return[];let r=[`Runtime '${e}' does not load Pi child extensions or hooks; launched best effort.`],i=[...t.tools!==void 0||t.mcpDirectTools?.length?[`tools`]:[],...t.skills?.length||t.skillPath?.length?[`skills`]:[],...t.extensions!==void 0||t.subagentOnlyExtensions?.length?[`extensions`]:[]];return i.length>0&&r.push(`Doom Team cannot project or enforce configured Pi ${i.join(`, `)} on runtime '${e}'.`),t.skills?.length&&r.push(`Configured skills were not injected: ${t.skills.join(`, `)}.`),n?.length&&r.push(`Runtime '${e}' cannot enforce Team package tool exclusions; launched best effort for: ${n.join(`, `)}.`),r}function O(e,t,n,r,i,a){let o=d.isPiRuntime(n)&&r&&i!==void 0?`${r.provider}/${r.id}`:void 0,s=[...t.modelSource?.scope===`package`?[]:[t.model],...t.fallbackModels??[]],[c,...l]=(d.isPiRuntime(n)?[e.model,...s,...a??[],o]:[e.model,...s,...a??[]]).filter(e=>!!e?.trim());return{primaryModel:c,fallbackModels:l,model:u.selectAvailableModel(c,l,i)}}const k=`invalid_request`,A=`runtime_unavailable`,j=`unsupported_context`,M=`unsupported_operation`;let N=class{constructor(e,t,n=new a.SubagentCapabilityPolicyStore,i=new r.SkillDiscoveryService,o){this.agents=e,this.spawner=t,this.policies=n,this.skills=i,this.reportConcurrencyEvent=o}generateRunId(){return crypto.randomUUID()}createForkSessionFile(e,t){let n=g.SessionManager.open(e.sessionFile,void 0,t),r=n.createBranchedSession(e.leafId);if(!r)throw Error(`Could not create a branched Pi session from '${e.sessionFile}'.`);if(!p.existsSync(r)){let e=n.getHeader();if(!e)throw Error(`Forked Pi session '${r}' has no header.`);let t=[e,...n.getEntries()];p.writeFileSync(r,`${t.map(e=>JSON.stringify(e)).join(`
2
+ `)}\n`,{flag:`wx`})}return r}removePreparedSessionFile(e){p.rmSync(e,{force:!0})}validateCwd(e){let t;try{t=p.statSync(e)}catch{throw new c.DoomTeamExpectedError(k,`Working directory '${e}' does not exist.`,!1,`Retry with an existing directory.`)}if(!t.isDirectory())throw new c.DoomTeamExpectedError(k,`Working directory '${e}' is not a directory.`,!1,`Retry with an existing directory.`)}resolveTeamPackageExcludeTools(){return n.resolveActiveTeamPackageConfig()?.config.excludeTools}resolveTeamPackageModels(){return n.resolveActiveTeamModelSpecs()}executableAvailable(e){if(m.isAbsolute(e)||e.includes(m.sep))try{return p.accessSync(e,p.constants.X_OK),!0}catch{return!1}return(process.env.PATH??``).split(m.delimiter).filter(Boolean).some(t=>{try{return p.accessSync(m.join(t,e),p.constants.X_OK),!0}catch{return!1}})}resolveTaskList(e){let t=e.single!==void 0;if(t===(e.tasks!==void 0))throw new c.DoomTeamExpectedError(k,`A run requires exactly one of internal single or tasks representations.`,!1,`Submit a non-empty requests array.`);if(t)return[e.single];if(!e.tasks||e.tasks.length===0)throw new c.DoomTeamExpectedError(k,`A run requires at least one entry in its requests collection.`,!1,`Submit a non-empty requests array.`);return e.tasks}resolveAgentOrThrow(e,t,n){let r=this.agents.find(t,n,e);if(!r)throw new c.DoomTeamExpectedError(`agent_not_found`,`Unknown agent '${e}'.`,!1,`Call subagent({"action":"agents"}) and retry with an exact name.`);return r}resolveExecutableAgent(e,t,n){return e.inlineAgent?{name:e.agent.trim(),systemPromptMode:`append`,inheritProjectContext:!0,inheritSkills:!1,systemPrompt:e.inlineAgent.systemPrompt.trim(),tools:[...T],defaultContext:v,runtime:`pi`}:this.resolveAgentOrThrow(e.agent,t,n)}projectConfiguredSkills(e,t,n,i){if(!d.isPiRuntime(i)||!e.skills?.length)return{systemPrompt:e.systemPrompt,requireReadTool:!1,warnings:[]};let a=this.skills.resolveSkillsWithFallback(e.skills,t,n,e.skillPath,n),o=r.buildSkillInjection(a.resolved);return{systemPrompt:E(e.systemPrompt,o),requireReadTool:o.length>0,warnings:a.missing.length>0?[`Agent '${e.name}' could not resolve configured skills: ${a.missing.join(`, `)}; launched with resolved skills only.`]:[]}}async spawnOneChild(e){let{runId:t,operationId:n,agentConfig:r,capabilityCeiling:i,excludeTools:a,teamPackageModels:o,taskInput:s,childIndex:c,fanout:l,fallbackCwd:u,parentSessionId:f,parentSessionFile:p,preparedSessionFile:m,handshakeTimeoutMs:h,artifacts:g,artifactDir:_,availableModels:v,parentModel:b,runtime:x,runtimes:S}=e,C=s.cwd??u,T=s.task??``,E=w(s,r),k=s.runtime??x??r.runtime??`pi`,A=O(s,r,k,b,v,o);if(A.primaryModel&&v!==void 0&&!A.model)return{agent:r.name,task:T,childIndex:c,error:`No authenticated model is available for '${r.name}'. Checked: ${[A.primaryModel,...A.fallbackModels].join(`, `)}.`};let j;try{j=this.projectConfiguredSkills(r,C,u,k)}catch(e){return{agent:r.name,task:T,childIndex:c,error:e instanceof Error?e.message:String(e)}}let M=[...j.warnings,...D(k,r,a)],N=M.length>0?M.join(` `):void 0,P={runId:t,...n?{operationId:n}:{},agent:r.name,...s.inlineAgent?{inlineAgent:s.inlineAgent}:{},task:T,cwd:C,childIndex:c,fanout:l,...p?{parentSessionFile:p}:{},piArgs:{baseArgs:[],sessionEnabled:d.isPiRuntime(k),...s.sessionFile?{sessionFile:s.sessionFile}:m?{sessionFile:m}:{},inheritProjectContext:r.inheritProjectContext,inheritSkills:r.inheritSkills,systemPromptMode:r.systemPromptMode,systemPrompt:j.systemPrompt,requireReadTool:j.requireReadTool,model:A.model,thinking:r.thinking,tools:r.tools,extensions:r.extensions,subagentOnlyExtensions:r.subagentOnlyExtensions,mcpDirectTools:r.mcpDirectTools,excludeTools:a,capabilityCeiling:i,cwd:C,...E===y&&f?{parentSessionId:f}:{}},...h===void 0?{}:{handshakeTimeoutMs:h},...g===void 0?{}:{artifacts:g},..._===void 0?{}:{artifactDir:_},runtime:k,runtimes:S};try{let e=await this.spawner.spawn(P);return{agent:r.name,task:T,childIndex:c,runId:e.runId,pid:e.pid,...N?{warning:N}:{}}}catch(e){return{agent:r.name,task:T,childIndex:c,error:e instanceof Error?e.message:String(e),...N?{warning:N}:{}}}}async spawn(e,t){let n=this.resolveTaskList(e),r=n.length>1,i=this.resolveTeamPackageExcludeTools(),a=this.resolveTeamPackageModels(),o=this.policies.resolve(),s=l.preflightSubagentDepth(e.currentDepth??l.resolveCurrentSubagentDepth(),t);if(s.error)throw new c.DoomTeamExpectedError(M,s.error,!1,`Give each child a self-contained task within the Team package policy.`);let u=t.parallel?.maxTasks??8;if(n.length>u)throw new c.DoomTeamExpectedError(k,`Run requested ${n.length} tasks, but at most ${u} may run at once. Concurrency throttles how fast they start, not how many run.`,!1,`Split the requests into smaller explicit run calls.`);for(let e of n){if(!e.task?.trim())throw new c.DoomTeamExpectedError(k,`Run request for '${e.agent}' requires a nonblank task.`,!1,`Provide a self-contained nonblank task.`);if(e.inlineAgent&&!e.inlineAgent.systemPrompt.trim())throw new c.DoomTeamExpectedError(k,`Inline agent '${e.agent}' requires a nonblank system prompt.`,!1,`Provide a focused read-only exploration role.`)}let p=n.map(t=>this.resolveExecutableAgent(t,t.cwd??e.cwd,e.agentScope));for(let[t,r]of n.entries()){let n=w(r,p[t]),i=r.runtime??e.runtime??p[t].runtime??`pi`;if(n===y){if(!d.isPiRuntime(i))throw new c.DoomTeamExpectedError(j,`Fork context requires ${b} for '${r.agent}'.`,!1,`Use a Pi agent for fork context or explicitly request a fresh run.`);let t=e.parentSessionFile&&e.parentLeafId?{sessionFile:e.parentSessionFile,leafId:e.parentLeafId}:void 0;if(!t||!C(t))throw new c.DoomTeamExpectedError(j,`Fork context is unavailable for '${r.agent}': the parent Pi session has no readable source.`,!1,`Use an active persisted Pi session or explicitly request a fresh run.`)}}if(e.preallocatedRunIds&&e.preallocatedRunIds.length!==n.length)throw new c.DoomTeamExpectedError(`operation_conflict`,`The operation journal run-id count does not match the request count.`,!1,`Submit the run as a new tool call.`);let m=e.preallocatedRunIds??n.map(()=>this.generateRunId()),h=d.resolveRuntimeTable(t.runtimes);for(let[t,r]of n.entries()){let n=p[t],i=r.cwd??e.cwd;this.validateCwd(i);let s=r.runtime??e.runtime??n.runtime??`pi`,l=O(r,n,s,e.parentModel,e.availableModels,a);if(l.primaryModel&&e.availableModels!==void 0&&!l.model)throw new c.DoomTeamExpectedError(`model_unavailable`,`No authenticated model is available for '${n.name}'.`,!1,`Authenticate the requested model or choose an available model.`);if(r.inlineAgent&&!d.isPiRuntime(s))throw new c.DoomTeamExpectedError(M,`Inline agent '${r.agent}' requires ${b} to enforce its read-only tools.`,!1,`Remove the runtime override or use a discovered external-runtime agent without inlineAgent.`);if(o&&!d.isPiRuntime(s))throw new c.DoomTeamExpectedError(M,`Runtime '${s}' cannot enforce the active capability ceiling.`,!1,`Use ${b} while plan mode or another capability ceiling is active.`);if(!d.isPiRuntime(s)){let e;try{e=d.resolveRuntimeLaunch(s,h,{prompt:r.task??``,cwd:i}).command}catch(e){throw new c.DoomTeamExpectedError(A,e instanceof Error?e.message:String(e),!1,`Configure a valid external runtime or use ${b}.`)}if(!this.executableAvailable(e))throw new c.DoomTeamExpectedError(A,`Executable '${e}' for runtime '${s}' is unavailable.`,!1,`Install the executable, configure its absolute path, or use ${b}.`)}}let g=e.parentSessionFile&&e.parentLeafId?{sessionFile:e.parentSessionFile,leafId:e.parentLeafId}:void 0,_=[];try{for(let[t,r]of n.entries())_.push(w(r,p[t])===y?this.createForkSessionFile(g,r.cwd??e.cwd):void 0)}catch(e){for(let e of _)e&&this.removePreparedSessionFile(e);throw new c.DoomTeamExpectedError(j,e instanceof Error?e.message:String(e),!1,`Retry from an active persisted Pi session or explicitly request a fresh run.`)}let v=r?e.concurrency??t.parallel?.concurrency??4:1;return{outcomes:(await f.runWithConcurrency(n.map((n,s)=>()=>this.spawnOneChild({runId:m[s],operationId:e.operationId,agentConfig:p[s],excludeTools:i,teamPackageModels:a,capabilityCeiling:o,taskInput:n,childIndex:s,fanout:r,fallbackCwd:e.cwd,parentSessionId:e.parentSessionId,parentSessionFile:e.parentSessionFile,preparedSessionFile:_[s],handshakeTimeoutMs:t.handshakeTimeoutMs,artifacts:e.artifacts,artifactDir:t.artifactDir,availableModels:e.availableModels,parentModel:e.parentModel,runtime:e.runtime,runtimes:h})),v,this.reportConcurrencyEvent)).map((e,t)=>e.status===`fulfilled`?e.value:{agent:p[t].name,task:n[t].task??``,childIndex:t,error:e.reason instanceof Error?e.reason.message:String(e.reason)})}}};N=t.__decorate([(0,h.injectable)(),s.__decorateParam(0,(0,h.inject)(i.DOOM_TEAM_TYPES.AgentDiscoveryService)),s.__decorateParam(1,(0,h.inject)(i.DOOM_TEAM_TYPES.AsyncSubagentSpawner)),s.__decorateParam(2,(0,h.inject)(i.DOOM_TEAM_TYPES.SubagentCapabilityPolicyStore)),s.__decorateParam(3,(0,h.inject)(i.DOOM_TEAM_TYPES.SkillDiscoveryService)),s.__decorateParam(4,(0,h.inject)(i.DOOM_TEAM_TYPES.ConcurrencyEventReporter)),s.__decorateParam(4,(0,h.optional)()),o.__decorateMetadata(`design:paramtypes`,[Object,Object,typeof(_=a.SubagentCapabilityPolicyStore!==void 0&&a.SubagentCapabilityPolicyStore)==`function`?_:Object,Object,Object])],N),Object.defineProperty(exports,`SpawnPlanner`,{enumerable:!0,get:function(){return N}}),exports.captureSessionForkSource=S;
3
3
  //# sourceMappingURL=spawnPlan.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"spawnPlan.cjs","names":["fs","isPiRuntime","selectAvailableModel","SubagentCapabilityPolicyStore","SkillDiscoveryService","SessionManager","DoomTeamExpectedError","resolveActiveLayerSubagentConfig","resolveActiveLayerModelSpecs","path","buildSkillInjection","preflightSubagentDepth","resolveCurrentSubagentDepth","resolveRuntimeTable","resolveRuntimeLaunch","runWithConcurrency","DOOM_TEAM_TYPES"],"sources":["../../src/extensions/spawnPlan.ts"],"sourcesContent":["/**\n * Turns `subagent` tool params into a resolved sequence of\n * `AsyncSubagentSpawner.spawn()` calls: SINGLE (one child), PARALLEL (N\n * children, bounded by `concurrency`).\n *\n * WHY THIS IS NEW LOGIC, NOT COMPOSITION:\n * `AsyncSubagentSpawner` is deliberately a per-child primitive -\n * `childIndex`/`fanout` arrive as inputs it does not derive (see that\n * module's header). Nothing else in this package decides \"how many\n * children, in what order, at what `childIndex`\" from a `subagent` tool\n * call. That decision is this file's job.\n *\n * PREFLIGHT, ALL-OR-NOTHING:\n * `resolveCurrentSubagentDepth`/`preflightSubagentDepth` run once, before\n * anything spawns. A depth refusal throws - a declared plan that cannot run\n * at all should produce one clear refusal, not a partial fan-out.\n * `AgentDiscoveryService.find` resolves and validates every child's agent\n * name up front too, for the same reason: a typo'd agent name is a\n * preflight failure named at the tool boundary, not a spawn error surfacing\n * deep inside one child while its siblings are already running.\n *\n * ONCE THE BATCH HAS STARTED, PER-CHILD FAILURE IS A RESULT, NOT AN\n * EXCEPTION:\n * `runWithConcurrency` never lets one child's rejection abort its siblings,\n * matching `failFast` being opt-in in the schema, not the default. Every\n * child gets an outcome - `{runId, pid}` on success, `{error}` on failure -\n * and the caller (`subagentTool.ts`) decides how to report a mixed batch.\n *\n * WHAT THIS DOES NOT WIRE YET, AND WHY - FLAGGED, NOT SILENTLY GUESSED:\n * - `maxSubagentSpawnsPerSession` (`spawn-budget.ts`) is NOT enforced here.\n * `preflightSpawnBudget` needs a durable, session-scoped `SpawnBudgetStore`\n * that accumulates spend ACROSS separate tool calls in the same session;\n * inventing a fresh store per call would never track real spend and would\n * be worse than not checking at all (false confidence). Wiring this needs\n * a real session-scoped store (`GlobalStateBridge`'s `protocolSlot`\n * pattern, used by `capabilityCeiling.ts`, is the likely shape) - a\n * follow-up, not guessed here.\n * - Fork context is resolved here and requires a captured persisted Pi source;\n * unavailable or non-Pi fork requests fail closed rather than becoming fresh\n * launches.\n * - Per-task overrides with no direct `BuildPiArgsInput` field confirmed yet\n * (`skill`, `toolBudget`, `turnBudget`, `outputSchema`/structured output,\n * `acceptance`, `output`/`outputMode`) are not mapped into `piArgs` for\n * v1. Each child still gets its resolved `AgentConfig`'s own defaults\n * (`systemPromptMode`, `inheritProjectContext`, `inheritSkills`,\n * `systemPrompt`) - not nothing, just not every param override yet.\n *\n */\n\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport type { InlineAgent } from '@agimon-ai/doompi-extension-contracts/subagent-tool';\nimport { SessionManager } from '@earendil-works/pi-coding-agent';\nimport { inject, injectable, optional } from 'inversify';\nimport { PI_RUNTIME_NAME } from '../adapters/process/env.ts';\nimport { DOOM_TEAM_TYPES } from '../container/types.ts';\nimport {\n type ResolvedSubagentCapabilityCeiling,\n SubagentCapabilityPolicyStore,\n} from '../schemas/team/capabilityCeiling.ts';\nimport { resolveActiveLayerModelSpecs, resolveActiveLayerSubagentConfig } from '../services/agents/discovery.ts';\nimport { buildSkillInjection, type ISkillDiscoveryService, SkillDiscoveryService } from '../services/agents/skills.ts';\nimport type { AgentConfig, AgentScope, IAgentDiscoveryService } from '../services/agents/types.ts';\nimport type {\n AsyncSubagentSpawnInput,\n AsyncSubagentSpawnResult,\n IAsyncSubagentSpawner,\n} from '../services/runs/background/asyncExecution.ts';\nimport { preflightSubagentDepth, resolveCurrentSubagentDepth } from '../services/runs/shared/depthGuard.ts';\nimport {\n type AvailableModelInfo,\n type ParentModel,\n selectAvailableModel,\n} from '../services/runs/shared/modelFallback.ts';\nimport {\n isPiRuntime,\n type RuntimeTable,\n resolveRuntimeLaunch,\n resolveRuntimeTable,\n} from '../services/runs/shared/runtimeRegistry.ts';\nimport { type ConcurrencyEventReporter, runWithConcurrency } from '../services/runs/shared/runWithConcurrency.ts';\nimport { DoomTeamExpectedError } from '../shared/errors.ts';\nimport type { ExtensionConfig } from './config.ts';\n\nconst CONTEXT_FRESH = 'fresh' as const;\nconst CONTEXT_FORK = 'fork' as const;\nconst PI_RUNTIME_REQUIREMENT = `runtime \"${PI_RUNTIME_NAME}\"`;\n\ntype SessionForkCaptureMode = 'tool' | 'settled';\n\nexport interface SessionForkSource {\n sessionFile: string;\n leafId: string;\n}\n\nexport type SessionForkSourceManager = Pick<SessionManager, 'getSessionFile' | 'getLeafId' | 'getLeafEntry'>;\n\nfunction readableSessionFile(sessionFile: string | undefined): sessionFile is string {\n if (!sessionFile?.trim()) return false;\n try {\n fs.accessSync(sessionFile, fs.constants.R_OK);\n return true;\n } catch {\n return false;\n }\n}\n\n/** Capture the parent branch while excluding an assistant turn whose tool is still executing. */\nexport function captureSessionForkSource(\n manager: SessionForkSourceManager,\n mode: SessionForkCaptureMode,\n): SessionForkSource | undefined {\n const sessionFile = manager.getSessionFile();\n if (!readableSessionFile(sessionFile)) return undefined;\n\n const leaf = manager.getLeafEntry();\n const leafId =\n mode === 'tool' && leaf?.type === 'message' && leaf.message.role === 'assistant'\n ? leaf.parentId\n : (leaf?.id ?? manager.getLeafId());\n return leafId ? { sessionFile, leafId } : undefined;\n}\n\nfunction isSessionForkSourceAvailable(source: SessionForkSource): boolean {\n return Boolean(source.leafId.trim()) && readableSessionFile(source.sessionFile);\n}\n\nexport interface SpawnPlanTaskInput {\n agent: string;\n inlineAgent?: InlineAgent;\n task?: string;\n cwd?: string;\n model?: string;\n runtime?: string;\n context?: typeof CONTEXT_FRESH | typeof CONTEXT_FORK;\n /**\n * An existing child transcript to continue instead of starting fresh.\n *\n * Set only by a restore. `sdkRunnerEntry.ts` opens it through\n * `SessionManager.open`, which is what makes a restored run pick up where it\n * was suspended rather than redo the task.\n */\n sessionFile?: string;\n}\n\ntype ExecutableAgentConfig = Pick<\n AgentConfig,\n | 'name'\n | 'defaultContext'\n | 'extensions'\n | 'fallbackModels'\n | 'inheritProjectContext'\n | 'inheritSkills'\n | 'mcpDirectTools'\n | 'model'\n | 'modelSource'\n | 'runtime'\n | 'skills'\n | 'skillPath'\n | 'subagentOnlyExtensions'\n | 'systemPrompt'\n | 'systemPromptMode'\n | 'thinking'\n | 'tools'\n>;\n\nfunction resolveEffectiveContext(\n taskInput: SpawnPlanTaskInput,\n agent: Pick<ExecutableAgentConfig, 'defaultContext'>,\n): typeof CONTEXT_FRESH | typeof CONTEXT_FORK {\n return taskInput.sessionFile ? CONTEXT_FRESH : (taskInput.context ?? agent.defaultContext ?? CONTEXT_FRESH);\n}\n\nexport interface SpawnPlanRequest {\n /** SINGLE mode: exactly one child. Mutually exclusive with `tasks`. */\n single?: SpawnPlanTaskInput;\n /** PARALLEL mode: N children, fanned out. Mutually exclusive with `single`. */\n tasks?: SpawnPlanTaskInput[];\n /** Max children in flight at once for PARALLEL mode. Ignored for SINGLE. Defaults to `config.parallel.concurrency` or 4. */\n concurrency?: number;\n /** Fallback cwd for any task that omits its own. */\n cwd: string;\n agentScope: AgentScope;\n /** Legacy session identity retained for delegation correlation. */\n parentSessionId?: string;\n /** Persisted parent transcript used for true Pi forks. */\n parentSessionFile?: string;\n /** Settled parent leaf used for true Pi forks. */\n parentLeafId?: string;\n artifacts?: boolean;\n /** Authenticated models reported by the live parent host. Undefined for callers without a host context. */\n availableModels?: AvailableModelInfo[];\n /** The live parent model, forwarded only for Pi child selection. */\n parentModel?: ParentModel;\n /** Overrides `resolveCurrentSubagentDepth()`'s own env read - a test seam, not a runtime path. */\n currentDepth?: number;\n /** Which runtime executes every child of this request. Defaults per agent, then to `pi`. */\n runtime?: string;\n /** Stable Pi tool-call identity used to correlate this batch. */\n operationId?: string;\n /** Run ids persisted by the operation journal before any process starts. */\n preallocatedRunIds?: string[];\n}\n\n/** Everything one child spawn needs. An object because this reached ten positional parameters. */\ninterface SpawnOneChildInput {\n runId: string;\n operationId?: string;\n agentConfig: ExecutableAgentConfig;\n excludeTools?: string[];\n layerModels?: string[];\n capabilityCeiling?: ResolvedSubagentCapabilityCeiling;\n taskInput: SpawnPlanTaskInput;\n childIndex: number;\n fanout: boolean;\n fallbackCwd: string;\n parentSessionId: string | undefined;\n parentSessionFile: string | undefined;\n preparedSessionFile: string | undefined;\n handshakeTimeoutMs: number | undefined;\n artifacts: boolean | undefined;\n artifactDir: ExtensionConfig['artifactDir'];\n availableModels: AvailableModelInfo[] | undefined;\n parentModel: ParentModel | undefined;\n runtime: string | undefined;\n runtimes: RuntimeTable;\n}\n\nexport interface SpawnPlanChildOutcome {\n agent: string;\n task: string;\n /** This spawn's position among its siblings. Always 0 for SINGLE mode. */\n childIndex: number;\n runId?: string;\n pid?: number;\n error?: string;\n warning?: string;\n}\n\nexport interface SpawnPlanResult {\n outcomes: SpawnPlanChildOutcome[];\n}\n\nconst DEFAULT_PARALLEL_CONCURRENCY = 4;\n/**\n * Hard ceiling on how many children one PARALLEL call may launch.\n *\n * `concurrency` does NOT bound this, and cannot: `spawnOneChild` resolves as\n * soon as its child confirms it started, and the child then runs detached. So\n * `runWithConcurrency` throttles how fast children are STARTED, not how many\n * are running - `{tasks: [8], concurrency: 4}` ends up with eight live model\n * processes, not four. Until a launch queue exists that drains as runs go\n * terminal, a width cap is the only thing standing between a fan-out and the\n * machine. 8 matches the sibling implementation's `PI_TEAM_MATE_MAX_PARALLEL`.\n */\nconst DEFAULT_PARALLEL_MAX_TASKS = 8;\nconst INLINE_AGENT_TOOLS = ['read', 'grep', 'find', 'ls'] as const;\n\nfunction appendPromptSection(prompt: string, section: string): string {\n if (!section) return prompt;\n return prompt ? `${prompt}\\n\\n${section}` : section;\n}\n\nfunction bestEffortRuntimeWarnings(\n runtime: string,\n agentConfig: ExecutableAgentConfig,\n excludeTools: string[] | undefined,\n): string[] {\n if (isPiRuntime(runtime)) return [];\n\n const warnings = [`Runtime '${runtime}' does not load Pi child extensions or hooks; launched best effort.`];\n const unsupportedResources = [\n ...(agentConfig.tools !== undefined || agentConfig.mcpDirectTools?.length ? ['tools'] : []),\n ...(agentConfig.skills?.length || agentConfig.skillPath?.length ? ['skills'] : []),\n ...(agentConfig.extensions !== undefined || agentConfig.subagentOnlyExtensions?.length ? ['extensions'] : []),\n ];\n if (unsupportedResources.length > 0) {\n warnings.push(\n `Doom Team cannot project or enforce configured Pi ${unsupportedResources.join(', ')} on runtime '${runtime}'.`,\n );\n }\n if (agentConfig.skills?.length) {\n warnings.push(`Configured skills were not injected: ${agentConfig.skills.join(', ')}.`);\n }\n if (excludeTools?.length) {\n warnings.push(\n `Runtime '${runtime}' cannot enforce layer subagent tool exclusions; launched best effort for: ${excludeTools.join(', ')}.`,\n );\n }\n return warnings;\n}\n\ninterface ChildSkillProjection {\n systemPrompt: string;\n requireReadTool: boolean;\n warnings: string[];\n}\n\ninterface ResolvedModelSelection {\n primaryModel: string | undefined;\n fallbackModels: string[];\n model: string | undefined;\n}\n\nfunction resolvedModelSelection(\n taskInput: SpawnPlanTaskInput,\n agentConfig: Pick<ExecutableAgentConfig, 'model' | 'modelSource' | 'fallbackModels'>,\n runtime: string,\n parentModel: ParentModel | undefined,\n availableModels: AvailableModelInfo[] | undefined,\n layerModels: string[] | undefined,\n): ResolvedModelSelection {\n const parentModelId =\n isPiRuntime(runtime) && parentModel && availableModels !== undefined\n ? `${parentModel.provider}/${parentModel.id}`\n : undefined;\n const agentModels = [\n ...(agentConfig.modelSource?.scope === 'layer' ? [] : [agentConfig.model]),\n ...(agentConfig.fallbackModels ?? []),\n ];\n const ordered = isPiRuntime(runtime)\n ? [taskInput.model, ...agentModels, ...(layerModels ?? []), parentModelId]\n : [taskInput.model, ...agentModels, ...(layerModels ?? [])];\n const candidates = ordered.filter((candidate): candidate is string => Boolean(candidate?.trim()));\n const [primaryModel, ...fallbackModels] = candidates;\n return {\n primaryModel,\n fallbackModels,\n model: selectAvailableModel(primaryModel, fallbackModels, availableModels),\n };\n}\n\nexport interface ISpawnPlanner {\n /**\n * Resolves the plan and spawns every child. Throws on any PREFLIGHT\n * failure (bad request shape, depth exceeded, unknown agent) before\n * anything spawns. Never throws for an individual child's spawn failure\n * once the batch has started - that is a `{error}` outcome instead.\n */\n spawn(request: SpawnPlanRequest, config: ExtensionConfig): Promise<SpawnPlanResult>;\n}\n\nconst ERROR_CODE_AGENT_NOT_FOUND = 'agent_not_found' as const;\nconst ERROR_CODE_INVALID_REQUEST = 'invalid_request' as const;\nconst ERROR_CODE_MODEL_UNAVAILABLE = 'model_unavailable' as const;\nconst ERROR_CODE_OPERATION_CONFLICT = 'operation_conflict' as const;\nconst ERROR_CODE_RUNTIME_UNAVAILABLE = 'runtime_unavailable' as const;\nconst ERROR_CODE_UNSUPPORTED_CONTEXT = 'unsupported_context' as const;\nconst ERROR_CODE_UNSUPPORTED_OPERATION = 'unsupported_operation' as const;\n\n@injectable()\nexport class SpawnPlanner implements ISpawnPlanner {\n constructor(\n @inject(DOOM_TEAM_TYPES.AgentDiscoveryService) private readonly agents: IAgentDiscoveryService,\n @inject(DOOM_TEAM_TYPES.AsyncSubagentSpawner) private readonly spawner: IAsyncSubagentSpawner,\n @inject(DOOM_TEAM_TYPES.SubagentCapabilityPolicyStore)\n private readonly policies: SubagentCapabilityPolicyStore = new SubagentCapabilityPolicyStore(),\n @inject(DOOM_TEAM_TYPES.SkillDiscoveryService)\n private readonly skills: ISkillDiscoveryService = new SkillDiscoveryService(),\n @inject(DOOM_TEAM_TYPES.ConcurrencyEventReporter)\n @optional()\n private readonly reportConcurrencyEvent?: ConcurrencyEventReporter,\n ) {}\n\n protected generateRunId(): string {\n return crypto.randomUUID();\n }\n\n protected createForkSessionFile(source: SessionForkSource, cwd: string): string {\n const sessionManager = SessionManager.open(source.sessionFile, undefined, cwd);\n const sessionFile = sessionManager.createBranchedSession(source.leafId);\n if (!sessionFile) throw new Error(`Could not create a branched Pi session from '${source.sessionFile}'.`);\n\n // Pi defers writing user-only branches until an assistant response. A tool-safe\n // fork usually ends at the user message immediately before the active tool call,\n // so materialize that valid child transcript before the runner opens it.\n if (!fs.existsSync(sessionFile)) {\n const header = sessionManager.getHeader();\n if (!header) throw new Error(`Forked Pi session '${sessionFile}' has no header.`);\n const records = [header, ...sessionManager.getEntries()];\n fs.writeFileSync(sessionFile, `${records.map((record) => JSON.stringify(record)).join('\\n')}\\n`, { flag: 'wx' });\n }\n return sessionFile;\n }\n\n protected removePreparedSessionFile(sessionFile: string): void {\n fs.rmSync(sessionFile, { force: true });\n }\n\n protected validateCwd(cwd: string): void {\n let stat: fs.Stats;\n try {\n stat = fs.statSync(cwd);\n } catch {\n throw new DoomTeamExpectedError(\n ERROR_CODE_INVALID_REQUEST,\n `Working directory '${cwd}' does not exist.`,\n false,\n 'Retry with an existing directory.',\n );\n }\n if (!stat.isDirectory()) {\n throw new DoomTeamExpectedError(\n ERROR_CODE_INVALID_REQUEST,\n `Working directory '${cwd}' is not a directory.`,\n false,\n 'Retry with an existing directory.',\n );\n }\n }\n\n protected resolveLayerExcludeTools(): string[] | undefined {\n return resolveActiveLayerSubagentConfig()?.config.excludeTools;\n }\n\n protected resolveLayerModels(): string[] | undefined {\n return resolveActiveLayerModelSpecs();\n }\n\n protected executableAvailable(command: string): boolean {\n if (path.isAbsolute(command) || command.includes(path.sep)) {\n try {\n fs.accessSync(command, fs.constants.X_OK);\n return true;\n } catch {\n return false;\n }\n }\n return (process.env.PATH ?? '')\n .split(path.delimiter)\n .filter(Boolean)\n .some((directory) => {\n try {\n fs.accessSync(path.join(directory, command), fs.constants.X_OK);\n return true;\n } catch {\n return false;\n }\n });\n }\n\n private resolveTaskList(request: SpawnPlanRequest): SpawnPlanTaskInput[] {\n const hasSingle = request.single !== undefined;\n const hasTasks = request.tasks !== undefined;\n if (hasSingle === hasTasks) {\n throw new DoomTeamExpectedError(\n ERROR_CODE_INVALID_REQUEST,\n 'A run requires exactly one of internal single or tasks representations.',\n false,\n 'Submit a non-empty requests array.',\n );\n }\n if (hasSingle) return [request.single!];\n if (!request.tasks || request.tasks.length === 0) {\n throw new DoomTeamExpectedError(\n ERROR_CODE_INVALID_REQUEST,\n 'A run requires at least one entry in its requests collection.',\n false,\n 'Submit a non-empty requests array.',\n );\n }\n return request.tasks;\n }\n\n private resolveAgentOrThrow(name: string, cwd: string, scope: AgentScope) {\n const resolved = this.agents.find(cwd, scope, name);\n if (!resolved) {\n throw new DoomTeamExpectedError(\n ERROR_CODE_AGENT_NOT_FOUND,\n `Unknown agent '${name}'.`,\n false,\n 'Call subagent({\"action\":\"agents\"}) and retry with an exact name.',\n );\n }\n return resolved;\n }\n\n private resolveExecutableAgent(taskInput: SpawnPlanTaskInput, cwd: string, scope: AgentScope): ExecutableAgentConfig {\n if (!taskInput.inlineAgent) return this.resolveAgentOrThrow(taskInput.agent, cwd, scope);\n return {\n name: taskInput.agent.trim(),\n systemPromptMode: 'append',\n inheritProjectContext: true,\n inheritSkills: false,\n systemPrompt: taskInput.inlineAgent.systemPrompt.trim(),\n tools: [...INLINE_AGENT_TOOLS],\n defaultContext: CONTEXT_FRESH,\n runtime: PI_RUNTIME_NAME,\n };\n }\n\n private projectConfiguredSkills(\n agentConfig: ExecutableAgentConfig,\n childCwd: string,\n requestCwd: string,\n runtime: string,\n ): ChildSkillProjection {\n if (!isPiRuntime(runtime) || !agentConfig.skills?.length) {\n return { systemPrompt: agentConfig.systemPrompt, requireReadTool: false, warnings: [] };\n }\n\n const resolution = this.skills.resolveSkillsWithFallback(\n agentConfig.skills,\n childCwd,\n requestCwd,\n agentConfig.skillPath,\n requestCwd,\n );\n const injection = buildSkillInjection(resolution.resolved);\n return {\n systemPrompt: appendPromptSection(agentConfig.systemPrompt, injection),\n requireReadTool: injection.length > 0,\n warnings:\n resolution.missing.length > 0\n ? [\n `Agent '${agentConfig.name}' could not resolve configured skills: ${resolution.missing.join(', ')}; launched with resolved skills only.`,\n ]\n : [],\n };\n }\n\n /**\n * Spawns exactly one child and returns its outcome. Shared by `spawn()`\n * (SINGLE/PARALLEL) and `spawnChain()`'s per-step/per-parallel-group-child\n * calls, so the `AsyncSubagentSpawnInput` mapping exists in exactly one\n * place. Never throws - a spawn failure becomes an `{error}` outcome, per\n * the \"preflight throws, per-child failure does not\" split documented in\n * the module header.\n */\n private async spawnOneChild(input: SpawnOneChildInput): Promise<SpawnPlanChildOutcome> {\n const {\n runId,\n operationId,\n agentConfig,\n capabilityCeiling,\n excludeTools,\n layerModels,\n taskInput,\n childIndex,\n fanout,\n fallbackCwd,\n parentSessionId,\n parentSessionFile,\n preparedSessionFile,\n handshakeTimeoutMs,\n artifacts,\n artifactDir,\n availableModels,\n parentModel,\n runtime,\n runtimes,\n } = input;\n const cwd = taskInput.cwd ?? fallbackCwd;\n const task = taskInput.task ?? '';\n const effectiveContext = resolveEffectiveContext(taskInput, agentConfig);\n const effectiveRuntime = taskInput.runtime ?? runtime ?? agentConfig.runtime ?? PI_RUNTIME_NAME;\n const modelSelection = resolvedModelSelection(\n taskInput,\n agentConfig,\n effectiveRuntime,\n parentModel,\n availableModels,\n layerModels,\n );\n if (modelSelection.primaryModel && availableModels !== undefined && !modelSelection.model) {\n return {\n agent: agentConfig.name,\n task,\n childIndex,\n error: `No authenticated model is available for '${agentConfig.name}'. Checked: ${[\n modelSelection.primaryModel,\n ...modelSelection.fallbackModels,\n ].join(', ')}.`,\n };\n }\n\n let skillProjection: ChildSkillProjection;\n try {\n skillProjection = this.projectConfiguredSkills(agentConfig, cwd, fallbackCwd, effectiveRuntime);\n } catch (error) {\n return {\n agent: agentConfig.name,\n task,\n childIndex,\n error: error instanceof Error ? error.message : String(error),\n };\n }\n const warnings = [\n ...skillProjection.warnings,\n ...bestEffortRuntimeWarnings(effectiveRuntime, agentConfig, excludeTools),\n ];\n const warning = warnings.length > 0 ? warnings.join(' ') : undefined;\n\n // Persist every Pi child's own transcript so a later explicit restore can\n // continue it. External runtimes retain their existing session behavior.\n const spawnInput: AsyncSubagentSpawnInput = {\n runId,\n ...(operationId ? { operationId } : {}),\n agent: agentConfig.name,\n ...(taskInput.inlineAgent ? { inlineAgent: taskInput.inlineAgent } : {}),\n task,\n cwd,\n childIndex,\n fanout,\n ...(parentSessionFile ? { parentSessionFile } : {}),\n piArgs: {\n baseArgs: [],\n sessionEnabled: isPiRuntime(effectiveRuntime),\n ...(taskInput.sessionFile\n ? { sessionFile: taskInput.sessionFile }\n : preparedSessionFile\n ? { sessionFile: preparedSessionFile }\n : {}),\n inheritProjectContext: agentConfig.inheritProjectContext,\n inheritSkills: agentConfig.inheritSkills,\n systemPromptMode: agentConfig.systemPromptMode,\n systemPrompt: skillProjection.systemPrompt,\n requireReadTool: skillProjection.requireReadTool,\n model: modelSelection.model,\n thinking: agentConfig.thinking,\n tools: agentConfig.tools,\n extensions: agentConfig.extensions,\n subagentOnlyExtensions: agentConfig.subagentOnlyExtensions,\n mcpDirectTools: agentConfig.mcpDirectTools,\n excludeTools,\n capabilityCeiling,\n cwd,\n ...(effectiveContext === CONTEXT_FORK && parentSessionId ? { parentSessionId } : {}),\n },\n ...(handshakeTimeoutMs !== undefined ? { handshakeTimeoutMs } : {}),\n ...(artifacts !== undefined ? { artifacts } : {}),\n ...(artifactDir !== undefined ? { artifactDir } : {}),\n // Per-call `runtime` wins over the agent's own default, matching how\n // `model` and `context` already resolve.\n runtime: effectiveRuntime,\n runtimes,\n };\n\n try {\n const result: AsyncSubagentSpawnResult = await this.spawner.spawn(spawnInput);\n return {\n agent: agentConfig.name,\n task,\n childIndex,\n runId: result.runId,\n pid: result.pid,\n ...(warning ? { warning } : {}),\n };\n } catch (error) {\n return {\n agent: agentConfig.name,\n task,\n childIndex,\n error: error instanceof Error ? error.message : String(error),\n ...(warning ? { warning } : {}),\n };\n }\n }\n\n async spawn(request: SpawnPlanRequest, config: ExtensionConfig): Promise<SpawnPlanResult> {\n const tasks = this.resolveTaskList(request);\n const fanout = tasks.length > 1;\n const layerExcludeTools = this.resolveLayerExcludeTools();\n const layerModels = this.resolveLayerModels();\n const capabilityCeiling = this.policies.resolve();\n\n // PREFLIGHT - all before any spawn call, so a declared plan that cannot\n // run at all produces one refusal, not a partial fan-out.\n const currentDepth = request.currentDepth ?? resolveCurrentSubagentDepth();\n const depthCheck = preflightSubagentDepth(currentDepth, config);\n if (depthCheck.error) {\n throw new DoomTeamExpectedError(\n ERROR_CODE_UNSUPPORTED_OPERATION,\n depthCheck.error,\n false,\n 'Give each child a self-contained task within the selected layer policy.',\n );\n }\n\n const maxTasks = config.parallel?.maxTasks ?? DEFAULT_PARALLEL_MAX_TASKS;\n if (tasks.length > maxTasks) {\n throw new DoomTeamExpectedError(\n ERROR_CODE_INVALID_REQUEST,\n `Run requested ${tasks.length} tasks, but at most ${maxTasks} may run at once. Concurrency throttles how fast they start, not how many run.`,\n false,\n 'Split the requests into smaller explicit run calls.',\n );\n }\n\n for (const taskInput of tasks) {\n if (!taskInput.task?.trim()) {\n throw new DoomTeamExpectedError(\n ERROR_CODE_INVALID_REQUEST,\n `Run request for '${taskInput.agent}' requires a nonblank task.`,\n false,\n 'Provide a self-contained nonblank task.',\n );\n }\n if (taskInput.inlineAgent && !taskInput.inlineAgent.systemPrompt.trim()) {\n throw new DoomTeamExpectedError(\n ERROR_CODE_INVALID_REQUEST,\n `Inline agent '${taskInput.agent}' requires a nonblank system prompt.`,\n false,\n 'Provide a focused read-only exploration role.',\n );\n }\n }\n\n const resolvedAgents = tasks.map((taskInput) =>\n this.resolveExecutableAgent(taskInput, taskInput.cwd ?? request.cwd, request.agentScope),\n );\n for (const [index, taskInput] of tasks.entries()) {\n const effectiveContext = resolveEffectiveContext(taskInput, resolvedAgents[index]!);\n const runtime = taskInput.runtime ?? request.runtime ?? resolvedAgents[index]!.runtime ?? PI_RUNTIME_NAME;\n if (effectiveContext === CONTEXT_FORK) {\n if (!isPiRuntime(runtime)) {\n throw new DoomTeamExpectedError(\n ERROR_CODE_UNSUPPORTED_CONTEXT,\n `Fork context requires ${PI_RUNTIME_REQUIREMENT} for '${taskInput.agent}'.`,\n false,\n 'Use a Pi agent for fork context or explicitly request a fresh run.',\n );\n }\n const source =\n request.parentSessionFile && request.parentLeafId\n ? { sessionFile: request.parentSessionFile, leafId: request.parentLeafId }\n : undefined;\n if (!source || !isSessionForkSourceAvailable(source)) {\n throw new DoomTeamExpectedError(\n ERROR_CODE_UNSUPPORTED_CONTEXT,\n `Fork context is unavailable for '${taskInput.agent}': the parent Pi session has no readable source.`,\n false,\n 'Use an active persisted Pi session or explicitly request a fresh run.',\n );\n }\n }\n }\n\n if (request.preallocatedRunIds && request.preallocatedRunIds.length !== tasks.length) {\n throw new DoomTeamExpectedError(\n ERROR_CODE_OPERATION_CONFLICT,\n 'The operation journal run-id count does not match the request count.',\n false,\n 'Submit the run as a new tool call.',\n );\n }\n const runIds = request.preallocatedRunIds ?? tasks.map(() => this.generateRunId());\n const runtimes = resolveRuntimeTable(config.runtimes);\n for (const [index, taskInput] of tasks.entries()) {\n const agent = resolvedAgents[index]!;\n const cwd = taskInput.cwd ?? request.cwd;\n this.validateCwd(cwd);\n const runtime = taskInput.runtime ?? request.runtime ?? agent.runtime ?? PI_RUNTIME_NAME;\n const modelSelection = resolvedModelSelection(\n taskInput,\n agent,\n runtime,\n request.parentModel,\n request.availableModels,\n layerModels,\n );\n if (modelSelection.primaryModel && request.availableModels !== undefined && !modelSelection.model) {\n throw new DoomTeamExpectedError(\n ERROR_CODE_MODEL_UNAVAILABLE,\n `No authenticated model is available for '${agent.name}'.`,\n false,\n 'Authenticate the requested model or choose an available model.',\n );\n }\n if (taskInput.inlineAgent && !isPiRuntime(runtime)) {\n throw new DoomTeamExpectedError(\n ERROR_CODE_UNSUPPORTED_OPERATION,\n `Inline agent '${taskInput.agent}' requires ${PI_RUNTIME_REQUIREMENT} to enforce its read-only tools.`,\n false,\n 'Remove the runtime override or use a discovered external-runtime agent without inlineAgent.',\n );\n }\n if (capabilityCeiling && !isPiRuntime(runtime)) {\n throw new DoomTeamExpectedError(\n ERROR_CODE_UNSUPPORTED_OPERATION,\n `Runtime '${runtime}' cannot enforce the active capability ceiling.`,\n false,\n `Use ${PI_RUNTIME_REQUIREMENT} while plan mode or another capability ceiling is active.`,\n );\n }\n if (!isPiRuntime(runtime)) {\n let command: string;\n try {\n command = resolveRuntimeLaunch(runtime, runtimes, { prompt: taskInput.task ?? '', cwd }).command;\n } catch (error) {\n throw new DoomTeamExpectedError(\n ERROR_CODE_RUNTIME_UNAVAILABLE,\n error instanceof Error ? error.message : String(error),\n false,\n `Configure a valid external runtime or use ${PI_RUNTIME_REQUIREMENT}.`,\n );\n }\n if (!this.executableAvailable(command)) {\n throw new DoomTeamExpectedError(\n ERROR_CODE_RUNTIME_UNAVAILABLE,\n `Executable '${command}' for runtime '${runtime}' is unavailable.`,\n false,\n `Install the executable, configure its absolute path, or use ${PI_RUNTIME_REQUIREMENT}.`,\n );\n }\n }\n }\n const forkSource =\n request.parentSessionFile && request.parentLeafId\n ? { sessionFile: request.parentSessionFile, leafId: request.parentLeafId }\n : undefined;\n const preparedSessionFiles: Array<string | undefined> = [];\n try {\n for (const [index, taskInput] of tasks.entries()) {\n preparedSessionFiles.push(\n resolveEffectiveContext(taskInput, resolvedAgents[index]!) === CONTEXT_FORK\n ? this.createForkSessionFile(forkSource!, taskInput.cwd ?? request.cwd)\n : undefined,\n );\n }\n } catch (error) {\n for (const sessionFile of preparedSessionFiles) {\n if (sessionFile) this.removePreparedSessionFile(sessionFile);\n }\n throw new DoomTeamExpectedError(\n ERROR_CODE_UNSUPPORTED_CONTEXT,\n error instanceof Error ? error.message : String(error),\n false,\n 'Retry from an active persisted Pi session or explicitly request a fresh run.',\n );\n }\n\n const concurrency = fanout\n ? (request.concurrency ?? config.parallel?.concurrency ?? DEFAULT_PARALLEL_CONCURRENCY)\n : 1;\n\n const factories = tasks.map(\n (taskInput, childIndex) => () =>\n this.spawnOneChild({\n runId: runIds[childIndex]!,\n operationId: request.operationId,\n agentConfig: resolvedAgents[childIndex]!,\n excludeTools: layerExcludeTools,\n layerModels,\n capabilityCeiling,\n taskInput,\n childIndex,\n fanout,\n fallbackCwd: request.cwd,\n parentSessionId: request.parentSessionId,\n parentSessionFile: request.parentSessionFile,\n preparedSessionFile: preparedSessionFiles[childIndex],\n handshakeTimeoutMs: config.handshakeTimeoutMs,\n artifacts: request.artifacts,\n artifactDir: config.artifactDir,\n availableModels: request.availableModels,\n parentModel: request.parentModel,\n runtime: request.runtime,\n runtimes,\n }),\n );\n\n const settled = await runWithConcurrency(factories, concurrency, this.reportConcurrencyEvent);\n // `spawnOneChild` never rejects (it catches its own spawn failure into\n // an `{error}` outcome), so `runWithConcurrency` never sees a rejection\n // here - this unwrap is defensive, not a real branch.\n const outcomes = settled.map((outcome, index) =>\n outcome.status === 'fulfilled'\n ? outcome.value\n : {\n agent: resolvedAgents[index]!.name,\n task: tasks[index]!.task ?? '',\n childIndex: index,\n error: outcome.reason instanceof Error ? outcome.reason.message : String(outcome.reason),\n },\n );\n\n return { outcomes };\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"spawnPlan.cjs","names":["fs","isPiRuntime","selectAvailableModel","SubagentCapabilityPolicyStore","SkillDiscoveryService","SessionManager","DoomTeamExpectedError","resolveActiveTeamPackageConfig","resolveActiveTeamModelSpecs","path","buildSkillInjection","preflightSubagentDepth","resolveCurrentSubagentDepth","resolveRuntimeTable","resolveRuntimeLaunch","runWithConcurrency","DOOM_TEAM_TYPES"],"sources":["../../src/extensions/spawnPlan.ts"],"sourcesContent":["/**\n * Turns `subagent` tool params into a resolved sequence of\n * `AsyncSubagentSpawner.spawn()` calls: SINGLE (one child), PARALLEL (N\n * children, bounded by `concurrency`).\n *\n * WHY THIS IS NEW LOGIC, NOT COMPOSITION:\n * `AsyncSubagentSpawner` is deliberately a per-child primitive -\n * `childIndex`/`fanout` arrive as inputs it does not derive (see that\n * module's header). Nothing else in this package decides \"how many\n * children, in what order, at what `childIndex`\" from a `subagent` tool\n * call. That decision is this file's job.\n *\n * PREFLIGHT, ALL-OR-NOTHING:\n * `resolveCurrentSubagentDepth`/`preflightSubagentDepth` run once, before\n * anything spawns. A depth refusal throws - a declared plan that cannot run\n * at all should produce one clear refusal, not a partial fan-out.\n * `AgentDiscoveryService.find` resolves and validates every child's agent\n * name up front too, for the same reason: a typo'd agent name is a\n * preflight failure named at the tool boundary, not a spawn error surfacing\n * deep inside one child while its siblings are already running.\n *\n * ONCE THE BATCH HAS STARTED, PER-CHILD FAILURE IS A RESULT, NOT AN\n * EXCEPTION:\n * `runWithConcurrency` never lets one child's rejection abort its siblings,\n * matching `failFast` being opt-in in the schema, not the default. Every\n * child gets an outcome - `{runId, pid}` on success, `{error}` on failure -\n * and the caller (`subagentTool.ts`) decides how to report a mixed batch.\n *\n * WHAT THIS DOES NOT WIRE YET, AND WHY - FLAGGED, NOT SILENTLY GUESSED:\n * - `maxSubagentSpawnsPerSession` (`spawn-budget.ts`) is NOT enforced here.\n * `preflightSpawnBudget` needs a durable, session-scoped `SpawnBudgetStore`\n * that accumulates spend ACROSS separate tool calls in the same session;\n * inventing a fresh store per call would never track real spend and would\n * be worse than not checking at all (false confidence). Wiring this needs\n * a real session-scoped store (`GlobalStateBridge`'s `protocolSlot`\n * pattern, used by `capabilityCeiling.ts`, is the likely shape) - a\n * follow-up, not guessed here.\n * - Fork context is resolved here and requires a captured persisted Pi source;\n * unavailable or non-Pi fork requests fail closed rather than becoming fresh\n * launches.\n * - Per-task overrides with no direct `BuildPiArgsInput` field confirmed yet\n * (`skill`, `toolBudget`, `turnBudget`, `outputSchema`/structured output,\n * `acceptance`, `output`/`outputMode`) are not mapped into `piArgs` for\n * v1. Each child still gets its resolved `AgentConfig`'s own defaults\n * (`systemPromptMode`, `inheritProjectContext`, `inheritSkills`,\n * `systemPrompt`) - not nothing, just not every param override yet.\n *\n */\n\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport type { InlineAgent } from '@agimon-ai/doompi-extension-contracts/subagent-tool';\nimport { SessionManager } from '@earendil-works/pi-coding-agent';\nimport { inject, injectable, optional } from 'inversify';\nimport { PI_RUNTIME_NAME } from '../adapters/process/env.ts';\nimport { DOOM_TEAM_TYPES } from '../container/types.ts';\nimport {\n type ResolvedSubagentCapabilityCeiling,\n SubagentCapabilityPolicyStore,\n} from '../schemas/team/capabilityCeiling.ts';\nimport { resolveActiveTeamModelSpecs, resolveActiveTeamPackageConfig } from '../services/agents/discovery.ts';\nimport { buildSkillInjection, type ISkillDiscoveryService, SkillDiscoveryService } from '../services/agents/skills.ts';\nimport type { AgentConfig, AgentScope, IAgentDiscoveryService } from '../services/agents/types.ts';\nimport type {\n AsyncSubagentSpawnInput,\n AsyncSubagentSpawnResult,\n IAsyncSubagentSpawner,\n} from '../services/runs/background/asyncExecution.ts';\nimport { preflightSubagentDepth, resolveCurrentSubagentDepth } from '../services/runs/shared/depthGuard.ts';\nimport {\n type AvailableModelInfo,\n type ParentModel,\n selectAvailableModel,\n} from '../services/runs/shared/modelFallback.ts';\nimport {\n isPiRuntime,\n type RuntimeTable,\n resolveRuntimeLaunch,\n resolveRuntimeTable,\n} from '../services/runs/shared/runtimeRegistry.ts';\nimport { type ConcurrencyEventReporter, runWithConcurrency } from '../services/runs/shared/runWithConcurrency.ts';\nimport { DoomTeamExpectedError } from '../shared/errors.ts';\nimport type { ExtensionConfig } from './config.ts';\n\nconst CONTEXT_FRESH = 'fresh' as const;\nconst CONTEXT_FORK = 'fork' as const;\nconst PI_RUNTIME_REQUIREMENT = `runtime \"${PI_RUNTIME_NAME}\"`;\n\ntype SessionForkCaptureMode = 'tool' | 'settled';\n\nexport interface SessionForkSource {\n sessionFile: string;\n leafId: string;\n}\n\nexport type SessionForkSourceManager = Pick<SessionManager, 'getSessionFile' | 'getLeafId' | 'getLeafEntry'>;\n\nfunction readableSessionFile(sessionFile: string | undefined): sessionFile is string {\n if (!sessionFile?.trim()) return false;\n try {\n fs.accessSync(sessionFile, fs.constants.R_OK);\n return true;\n } catch {\n return false;\n }\n}\n\n/** Capture the parent branch while excluding an assistant turn whose tool is still executing. */\nexport function captureSessionForkSource(\n manager: SessionForkSourceManager,\n mode: SessionForkCaptureMode,\n): SessionForkSource | undefined {\n const sessionFile = manager.getSessionFile();\n if (!readableSessionFile(sessionFile)) return undefined;\n\n const leaf = manager.getLeafEntry();\n const leafId =\n mode === 'tool' && leaf?.type === 'message' && leaf.message.role === 'assistant'\n ? leaf.parentId\n : (leaf?.id ?? manager.getLeafId());\n return leafId ? { sessionFile, leafId } : undefined;\n}\n\nfunction isSessionForkSourceAvailable(source: SessionForkSource): boolean {\n return Boolean(source.leafId.trim()) && readableSessionFile(source.sessionFile);\n}\n\nexport interface SpawnPlanTaskInput {\n agent: string;\n inlineAgent?: InlineAgent;\n task?: string;\n cwd?: string;\n model?: string;\n runtime?: string;\n context?: typeof CONTEXT_FRESH | typeof CONTEXT_FORK;\n /**\n * An existing child transcript to continue instead of starting fresh.\n *\n * Set only by a restore. `sdkRunnerEntry.ts` opens it through\n * `SessionManager.open`, which is what makes a restored run pick up where it\n * was suspended rather than redo the task.\n */\n sessionFile?: string;\n}\n\ntype ExecutableAgentConfig = Pick<\n AgentConfig,\n | 'name'\n | 'defaultContext'\n | 'extensions'\n | 'fallbackModels'\n | 'inheritProjectContext'\n | 'inheritSkills'\n | 'mcpDirectTools'\n | 'model'\n | 'modelSource'\n | 'runtime'\n | 'skills'\n | 'skillPath'\n | 'subagentOnlyExtensions'\n | 'systemPrompt'\n | 'systemPromptMode'\n | 'thinking'\n | 'tools'\n>;\n\nfunction resolveEffectiveContext(\n taskInput: SpawnPlanTaskInput,\n agent: Pick<ExecutableAgentConfig, 'defaultContext'>,\n): typeof CONTEXT_FRESH | typeof CONTEXT_FORK {\n return taskInput.sessionFile ? CONTEXT_FRESH : (taskInput.context ?? agent.defaultContext ?? CONTEXT_FRESH);\n}\n\nexport interface SpawnPlanRequest {\n /** SINGLE mode: exactly one child. Mutually exclusive with `tasks`. */\n single?: SpawnPlanTaskInput;\n /** PARALLEL mode: N children, fanned out. Mutually exclusive with `single`. */\n tasks?: SpawnPlanTaskInput[];\n /** Max children in flight at once for PARALLEL mode. Ignored for SINGLE. Defaults to `config.parallel.concurrency` or 4. */\n concurrency?: number;\n /** Fallback cwd for any task that omits its own. */\n cwd: string;\n agentScope: AgentScope;\n /** Legacy session identity retained for delegation correlation. */\n parentSessionId?: string;\n /** Persisted parent transcript used for true Pi forks. */\n parentSessionFile?: string;\n /** Settled parent leaf used for true Pi forks. */\n parentLeafId?: string;\n artifacts?: boolean;\n /** Authenticated models reported by the live parent host. Undefined for callers without a host context. */\n availableModels?: AvailableModelInfo[];\n /** The live parent model, forwarded only for Pi child selection. */\n parentModel?: ParentModel;\n /** Overrides `resolveCurrentSubagentDepth()`'s own env read - a test seam, not a runtime path. */\n currentDepth?: number;\n /** Which runtime executes every child of this request. Defaults per agent, then to `pi`. */\n runtime?: string;\n /** Stable Pi tool-call identity used to correlate this batch. */\n operationId?: string;\n /** Run ids persisted by the operation journal before any process starts. */\n preallocatedRunIds?: string[];\n}\n\n/** Everything one child spawn needs. An object because this reached ten positional parameters. */\ninterface SpawnOneChildInput {\n runId: string;\n operationId?: string;\n agentConfig: ExecutableAgentConfig;\n excludeTools?: string[];\n teamPackageModels?: string[];\n capabilityCeiling?: ResolvedSubagentCapabilityCeiling;\n taskInput: SpawnPlanTaskInput;\n childIndex: number;\n fanout: boolean;\n fallbackCwd: string;\n parentSessionId: string | undefined;\n parentSessionFile: string | undefined;\n preparedSessionFile: string | undefined;\n handshakeTimeoutMs: number | undefined;\n artifacts: boolean | undefined;\n artifactDir: ExtensionConfig['artifactDir'];\n availableModels: AvailableModelInfo[] | undefined;\n parentModel: ParentModel | undefined;\n runtime: string | undefined;\n runtimes: RuntimeTable;\n}\n\nexport interface SpawnPlanChildOutcome {\n agent: string;\n task: string;\n /** This spawn's position among its siblings. Always 0 for SINGLE mode. */\n childIndex: number;\n runId?: string;\n pid?: number;\n error?: string;\n warning?: string;\n}\n\nexport interface SpawnPlanResult {\n outcomes: SpawnPlanChildOutcome[];\n}\n\nconst DEFAULT_PARALLEL_CONCURRENCY = 4;\n/**\n * Hard ceiling on how many children one PARALLEL call may launch.\n *\n * `concurrency` does NOT bound this, and cannot: `spawnOneChild` resolves as\n * soon as its child confirms it started, and the child then runs detached. So\n * `runWithConcurrency` throttles how fast children are STARTED, not how many\n * are running - `{tasks: [8], concurrency: 4}` ends up with eight live model\n * processes, not four. Until a launch queue exists that drains as runs go\n * terminal, a width cap is the only thing standing between a fan-out and the\n * machine. 8 matches the sibling implementation's `PI_TEAM_MATE_MAX_PARALLEL`.\n */\nconst DEFAULT_PARALLEL_MAX_TASKS = 8;\nconst INLINE_AGENT_TOOLS = ['read', 'grep', 'find', 'ls'] as const;\n\nfunction appendPromptSection(prompt: string, section: string): string {\n if (!section) return prompt;\n return prompt ? `${prompt}\\n\\n${section}` : section;\n}\n\nfunction bestEffortRuntimeWarnings(\n runtime: string,\n agentConfig: ExecutableAgentConfig,\n excludeTools: string[] | undefined,\n): string[] {\n if (isPiRuntime(runtime)) return [];\n\n const warnings = [`Runtime '${runtime}' does not load Pi child extensions or hooks; launched best effort.`];\n const unsupportedResources = [\n ...(agentConfig.tools !== undefined || agentConfig.mcpDirectTools?.length ? ['tools'] : []),\n ...(agentConfig.skills?.length || agentConfig.skillPath?.length ? ['skills'] : []),\n ...(agentConfig.extensions !== undefined || agentConfig.subagentOnlyExtensions?.length ? ['extensions'] : []),\n ];\n if (unsupportedResources.length > 0) {\n warnings.push(\n `Doom Team cannot project or enforce configured Pi ${unsupportedResources.join(', ')} on runtime '${runtime}'.`,\n );\n }\n if (agentConfig.skills?.length) {\n warnings.push(`Configured skills were not injected: ${agentConfig.skills.join(', ')}.`);\n }\n if (excludeTools?.length) {\n warnings.push(\n `Runtime '${runtime}' cannot enforce Team package tool exclusions; launched best effort for: ${excludeTools.join(', ')}.`,\n );\n }\n return warnings;\n}\n\ninterface ChildSkillProjection {\n systemPrompt: string;\n requireReadTool: boolean;\n warnings: string[];\n}\n\ninterface ResolvedModelSelection {\n primaryModel: string | undefined;\n fallbackModels: string[];\n model: string | undefined;\n}\n\nfunction resolvedModelSelection(\n taskInput: SpawnPlanTaskInput,\n agentConfig: Pick<ExecutableAgentConfig, 'model' | 'modelSource' | 'fallbackModels'>,\n runtime: string,\n parentModel: ParentModel | undefined,\n availableModels: AvailableModelInfo[] | undefined,\n teamPackageModels: string[] | undefined,\n): ResolvedModelSelection {\n const parentModelId =\n isPiRuntime(runtime) && parentModel && availableModels !== undefined\n ? `${parentModel.provider}/${parentModel.id}`\n : undefined;\n const agentModels = [\n ...(agentConfig.modelSource?.scope === 'package' ? [] : [agentConfig.model]),\n ...(agentConfig.fallbackModels ?? []),\n ];\n const ordered = isPiRuntime(runtime)\n ? [taskInput.model, ...agentModels, ...(teamPackageModels ?? []), parentModelId]\n : [taskInput.model, ...agentModels, ...(teamPackageModels ?? [])];\n const candidates = ordered.filter((candidate): candidate is string => Boolean(candidate?.trim()));\n const [primaryModel, ...fallbackModels] = candidates;\n return {\n primaryModel,\n fallbackModels,\n model: selectAvailableModel(primaryModel, fallbackModels, availableModels),\n };\n}\n\nexport interface ISpawnPlanner {\n /**\n * Resolves the plan and spawns every child. Throws on any PREFLIGHT\n * failure (bad request shape, depth exceeded, unknown agent) before\n * anything spawns. Never throws for an individual child's spawn failure\n * once the batch has started - that is a `{error}` outcome instead.\n */\n spawn(request: SpawnPlanRequest, config: ExtensionConfig): Promise<SpawnPlanResult>;\n}\n\nconst ERROR_CODE_AGENT_NOT_FOUND = 'agent_not_found' as const;\nconst ERROR_CODE_INVALID_REQUEST = 'invalid_request' as const;\nconst ERROR_CODE_MODEL_UNAVAILABLE = 'model_unavailable' as const;\nconst ERROR_CODE_OPERATION_CONFLICT = 'operation_conflict' as const;\nconst ERROR_CODE_RUNTIME_UNAVAILABLE = 'runtime_unavailable' as const;\nconst ERROR_CODE_UNSUPPORTED_CONTEXT = 'unsupported_context' as const;\nconst ERROR_CODE_UNSUPPORTED_OPERATION = 'unsupported_operation' as const;\n\n@injectable()\nexport class SpawnPlanner implements ISpawnPlanner {\n constructor(\n @inject(DOOM_TEAM_TYPES.AgentDiscoveryService) private readonly agents: IAgentDiscoveryService,\n @inject(DOOM_TEAM_TYPES.AsyncSubagentSpawner) private readonly spawner: IAsyncSubagentSpawner,\n @inject(DOOM_TEAM_TYPES.SubagentCapabilityPolicyStore)\n private readonly policies: SubagentCapabilityPolicyStore = new SubagentCapabilityPolicyStore(),\n @inject(DOOM_TEAM_TYPES.SkillDiscoveryService)\n private readonly skills: ISkillDiscoveryService = new SkillDiscoveryService(),\n @inject(DOOM_TEAM_TYPES.ConcurrencyEventReporter)\n @optional()\n private readonly reportConcurrencyEvent?: ConcurrencyEventReporter,\n ) {}\n\n protected generateRunId(): string {\n return crypto.randomUUID();\n }\n\n protected createForkSessionFile(source: SessionForkSource, cwd: string): string {\n const sessionManager = SessionManager.open(source.sessionFile, undefined, cwd);\n const sessionFile = sessionManager.createBranchedSession(source.leafId);\n if (!sessionFile) throw new Error(`Could not create a branched Pi session from '${source.sessionFile}'.`);\n\n // Pi defers writing user-only branches until an assistant response. A tool-safe\n // fork usually ends at the user message immediately before the active tool call,\n // so materialize that valid child transcript before the runner opens it.\n if (!fs.existsSync(sessionFile)) {\n const header = sessionManager.getHeader();\n if (!header) throw new Error(`Forked Pi session '${sessionFile}' has no header.`);\n const records = [header, ...sessionManager.getEntries()];\n fs.writeFileSync(sessionFile, `${records.map((record) => JSON.stringify(record)).join('\\n')}\\n`, { flag: 'wx' });\n }\n return sessionFile;\n }\n\n protected removePreparedSessionFile(sessionFile: string): void {\n fs.rmSync(sessionFile, { force: true });\n }\n\n protected validateCwd(cwd: string): void {\n let stat: fs.Stats;\n try {\n stat = fs.statSync(cwd);\n } catch {\n throw new DoomTeamExpectedError(\n ERROR_CODE_INVALID_REQUEST,\n `Working directory '${cwd}' does not exist.`,\n false,\n 'Retry with an existing directory.',\n );\n }\n if (!stat.isDirectory()) {\n throw new DoomTeamExpectedError(\n ERROR_CODE_INVALID_REQUEST,\n `Working directory '${cwd}' is not a directory.`,\n false,\n 'Retry with an existing directory.',\n );\n }\n }\n\n protected resolveTeamPackageExcludeTools(): string[] | undefined {\n return resolveActiveTeamPackageConfig()?.config.excludeTools;\n }\n\n protected resolveTeamPackageModels(): string[] | undefined {\n return resolveActiveTeamModelSpecs();\n }\n\n protected executableAvailable(command: string): boolean {\n if (path.isAbsolute(command) || command.includes(path.sep)) {\n try {\n fs.accessSync(command, fs.constants.X_OK);\n return true;\n } catch {\n return false;\n }\n }\n return (process.env.PATH ?? '')\n .split(path.delimiter)\n .filter(Boolean)\n .some((directory) => {\n try {\n fs.accessSync(path.join(directory, command), fs.constants.X_OK);\n return true;\n } catch {\n return false;\n }\n });\n }\n\n private resolveTaskList(request: SpawnPlanRequest): SpawnPlanTaskInput[] {\n const hasSingle = request.single !== undefined;\n const hasTasks = request.tasks !== undefined;\n if (hasSingle === hasTasks) {\n throw new DoomTeamExpectedError(\n ERROR_CODE_INVALID_REQUEST,\n 'A run requires exactly one of internal single or tasks representations.',\n false,\n 'Submit a non-empty requests array.',\n );\n }\n if (hasSingle) return [request.single!];\n if (!request.tasks || request.tasks.length === 0) {\n throw new DoomTeamExpectedError(\n ERROR_CODE_INVALID_REQUEST,\n 'A run requires at least one entry in its requests collection.',\n false,\n 'Submit a non-empty requests array.',\n );\n }\n return request.tasks;\n }\n\n private resolveAgentOrThrow(name: string, cwd: string, scope: AgentScope) {\n const resolved = this.agents.find(cwd, scope, name);\n if (!resolved) {\n throw new DoomTeamExpectedError(\n ERROR_CODE_AGENT_NOT_FOUND,\n `Unknown agent '${name}'.`,\n false,\n 'Call subagent({\"action\":\"agents\"}) and retry with an exact name.',\n );\n }\n return resolved;\n }\n\n private resolveExecutableAgent(taskInput: SpawnPlanTaskInput, cwd: string, scope: AgentScope): ExecutableAgentConfig {\n if (!taskInput.inlineAgent) return this.resolveAgentOrThrow(taskInput.agent, cwd, scope);\n return {\n name: taskInput.agent.trim(),\n systemPromptMode: 'append',\n inheritProjectContext: true,\n inheritSkills: false,\n systemPrompt: taskInput.inlineAgent.systemPrompt.trim(),\n tools: [...INLINE_AGENT_TOOLS],\n defaultContext: CONTEXT_FRESH,\n runtime: PI_RUNTIME_NAME,\n };\n }\n\n private projectConfiguredSkills(\n agentConfig: ExecutableAgentConfig,\n childCwd: string,\n requestCwd: string,\n runtime: string,\n ): ChildSkillProjection {\n if (!isPiRuntime(runtime) || !agentConfig.skills?.length) {\n return { systemPrompt: agentConfig.systemPrompt, requireReadTool: false, warnings: [] };\n }\n\n const resolution = this.skills.resolveSkillsWithFallback(\n agentConfig.skills,\n childCwd,\n requestCwd,\n agentConfig.skillPath,\n requestCwd,\n );\n const injection = buildSkillInjection(resolution.resolved);\n return {\n systemPrompt: appendPromptSection(agentConfig.systemPrompt, injection),\n requireReadTool: injection.length > 0,\n warnings:\n resolution.missing.length > 0\n ? [\n `Agent '${agentConfig.name}' could not resolve configured skills: ${resolution.missing.join(', ')}; launched with resolved skills only.`,\n ]\n : [],\n };\n }\n\n /**\n * Spawns exactly one child and returns its outcome. Shared by `spawn()`\n * (SINGLE/PARALLEL) and `spawnChain()`'s per-step/per-parallel-group-child\n * calls, so the `AsyncSubagentSpawnInput` mapping exists in exactly one\n * place. Never throws - a spawn failure becomes an `{error}` outcome, per\n * the \"preflight throws, per-child failure does not\" split documented in\n * the module header.\n */\n private async spawnOneChild(input: SpawnOneChildInput): Promise<SpawnPlanChildOutcome> {\n const {\n runId,\n operationId,\n agentConfig,\n capabilityCeiling,\n excludeTools,\n teamPackageModels,\n taskInput,\n childIndex,\n fanout,\n fallbackCwd,\n parentSessionId,\n parentSessionFile,\n preparedSessionFile,\n handshakeTimeoutMs,\n artifacts,\n artifactDir,\n availableModels,\n parentModel,\n runtime,\n runtimes,\n } = input;\n const cwd = taskInput.cwd ?? fallbackCwd;\n const task = taskInput.task ?? '';\n const effectiveContext = resolveEffectiveContext(taskInput, agentConfig);\n const effectiveRuntime = taskInput.runtime ?? runtime ?? agentConfig.runtime ?? PI_RUNTIME_NAME;\n const modelSelection = resolvedModelSelection(\n taskInput,\n agentConfig,\n effectiveRuntime,\n parentModel,\n availableModels,\n teamPackageModels,\n );\n if (modelSelection.primaryModel && availableModels !== undefined && !modelSelection.model) {\n return {\n agent: agentConfig.name,\n task,\n childIndex,\n error: `No authenticated model is available for '${agentConfig.name}'. Checked: ${[\n modelSelection.primaryModel,\n ...modelSelection.fallbackModels,\n ].join(', ')}.`,\n };\n }\n\n let skillProjection: ChildSkillProjection;\n try {\n skillProjection = this.projectConfiguredSkills(agentConfig, cwd, fallbackCwd, effectiveRuntime);\n } catch (error) {\n return {\n agent: agentConfig.name,\n task,\n childIndex,\n error: error instanceof Error ? error.message : String(error),\n };\n }\n const warnings = [\n ...skillProjection.warnings,\n ...bestEffortRuntimeWarnings(effectiveRuntime, agentConfig, excludeTools),\n ];\n const warning = warnings.length > 0 ? warnings.join(' ') : undefined;\n\n // Persist every Pi child's own transcript so a later explicit restore can\n // continue it. External runtimes retain their existing session behavior.\n const spawnInput: AsyncSubagentSpawnInput = {\n runId,\n ...(operationId ? { operationId } : {}),\n agent: agentConfig.name,\n ...(taskInput.inlineAgent ? { inlineAgent: taskInput.inlineAgent } : {}),\n task,\n cwd,\n childIndex,\n fanout,\n ...(parentSessionFile ? { parentSessionFile } : {}),\n piArgs: {\n baseArgs: [],\n sessionEnabled: isPiRuntime(effectiveRuntime),\n ...(taskInput.sessionFile\n ? { sessionFile: taskInput.sessionFile }\n : preparedSessionFile\n ? { sessionFile: preparedSessionFile }\n : {}),\n inheritProjectContext: agentConfig.inheritProjectContext,\n inheritSkills: agentConfig.inheritSkills,\n systemPromptMode: agentConfig.systemPromptMode,\n systemPrompt: skillProjection.systemPrompt,\n requireReadTool: skillProjection.requireReadTool,\n model: modelSelection.model,\n thinking: agentConfig.thinking,\n tools: agentConfig.tools,\n extensions: agentConfig.extensions,\n subagentOnlyExtensions: agentConfig.subagentOnlyExtensions,\n mcpDirectTools: agentConfig.mcpDirectTools,\n excludeTools,\n capabilityCeiling,\n cwd,\n ...(effectiveContext === CONTEXT_FORK && parentSessionId ? { parentSessionId } : {}),\n },\n ...(handshakeTimeoutMs !== undefined ? { handshakeTimeoutMs } : {}),\n ...(artifacts !== undefined ? { artifacts } : {}),\n ...(artifactDir !== undefined ? { artifactDir } : {}),\n // Per-call `runtime` wins over the agent's own default, matching how\n // `model` and `context` already resolve.\n runtime: effectiveRuntime,\n runtimes,\n };\n\n try {\n const result: AsyncSubagentSpawnResult = await this.spawner.spawn(spawnInput);\n return {\n agent: agentConfig.name,\n task,\n childIndex,\n runId: result.runId,\n pid: result.pid,\n ...(warning ? { warning } : {}),\n };\n } catch (error) {\n return {\n agent: agentConfig.name,\n task,\n childIndex,\n error: error instanceof Error ? error.message : String(error),\n ...(warning ? { warning } : {}),\n };\n }\n }\n\n async spawn(request: SpawnPlanRequest, config: ExtensionConfig): Promise<SpawnPlanResult> {\n const tasks = this.resolveTaskList(request);\n const fanout = tasks.length > 1;\n const teamPackageExcludeTools = this.resolveTeamPackageExcludeTools();\n const teamPackageModels = this.resolveTeamPackageModels();\n const capabilityCeiling = this.policies.resolve();\n\n // PREFLIGHT - all before any spawn call, so a declared plan that cannot\n // run at all produces one refusal, not a partial fan-out.\n const currentDepth = request.currentDepth ?? resolveCurrentSubagentDepth();\n const depthCheck = preflightSubagentDepth(currentDepth, config);\n if (depthCheck.error) {\n throw new DoomTeamExpectedError(\n ERROR_CODE_UNSUPPORTED_OPERATION,\n depthCheck.error,\n false,\n 'Give each child a self-contained task within the Team package policy.',\n );\n }\n\n const maxTasks = config.parallel?.maxTasks ?? DEFAULT_PARALLEL_MAX_TASKS;\n if (tasks.length > maxTasks) {\n throw new DoomTeamExpectedError(\n ERROR_CODE_INVALID_REQUEST,\n `Run requested ${tasks.length} tasks, but at most ${maxTasks} may run at once. Concurrency throttles how fast they start, not how many run.`,\n false,\n 'Split the requests into smaller explicit run calls.',\n );\n }\n\n for (const taskInput of tasks) {\n if (!taskInput.task?.trim()) {\n throw new DoomTeamExpectedError(\n ERROR_CODE_INVALID_REQUEST,\n `Run request for '${taskInput.agent}' requires a nonblank task.`,\n false,\n 'Provide a self-contained nonblank task.',\n );\n }\n if (taskInput.inlineAgent && !taskInput.inlineAgent.systemPrompt.trim()) {\n throw new DoomTeamExpectedError(\n ERROR_CODE_INVALID_REQUEST,\n `Inline agent '${taskInput.agent}' requires a nonblank system prompt.`,\n false,\n 'Provide a focused read-only exploration role.',\n );\n }\n }\n\n const resolvedAgents = tasks.map((taskInput) =>\n this.resolveExecutableAgent(taskInput, taskInput.cwd ?? request.cwd, request.agentScope),\n );\n for (const [index, taskInput] of tasks.entries()) {\n const effectiveContext = resolveEffectiveContext(taskInput, resolvedAgents[index]!);\n const runtime = taskInput.runtime ?? request.runtime ?? resolvedAgents[index]!.runtime ?? PI_RUNTIME_NAME;\n if (effectiveContext === CONTEXT_FORK) {\n if (!isPiRuntime(runtime)) {\n throw new DoomTeamExpectedError(\n ERROR_CODE_UNSUPPORTED_CONTEXT,\n `Fork context requires ${PI_RUNTIME_REQUIREMENT} for '${taskInput.agent}'.`,\n false,\n 'Use a Pi agent for fork context or explicitly request a fresh run.',\n );\n }\n const source =\n request.parentSessionFile && request.parentLeafId\n ? { sessionFile: request.parentSessionFile, leafId: request.parentLeafId }\n : undefined;\n if (!source || !isSessionForkSourceAvailable(source)) {\n throw new DoomTeamExpectedError(\n ERROR_CODE_UNSUPPORTED_CONTEXT,\n `Fork context is unavailable for '${taskInput.agent}': the parent Pi session has no readable source.`,\n false,\n 'Use an active persisted Pi session or explicitly request a fresh run.',\n );\n }\n }\n }\n\n if (request.preallocatedRunIds && request.preallocatedRunIds.length !== tasks.length) {\n throw new DoomTeamExpectedError(\n ERROR_CODE_OPERATION_CONFLICT,\n 'The operation journal run-id count does not match the request count.',\n false,\n 'Submit the run as a new tool call.',\n );\n }\n const runIds = request.preallocatedRunIds ?? tasks.map(() => this.generateRunId());\n const runtimes = resolveRuntimeTable(config.runtimes);\n for (const [index, taskInput] of tasks.entries()) {\n const agent = resolvedAgents[index]!;\n const cwd = taskInput.cwd ?? request.cwd;\n this.validateCwd(cwd);\n const runtime = taskInput.runtime ?? request.runtime ?? agent.runtime ?? PI_RUNTIME_NAME;\n const modelSelection = resolvedModelSelection(\n taskInput,\n agent,\n runtime,\n request.parentModel,\n request.availableModels,\n teamPackageModels,\n );\n if (modelSelection.primaryModel && request.availableModels !== undefined && !modelSelection.model) {\n throw new DoomTeamExpectedError(\n ERROR_CODE_MODEL_UNAVAILABLE,\n `No authenticated model is available for '${agent.name}'.`,\n false,\n 'Authenticate the requested model or choose an available model.',\n );\n }\n if (taskInput.inlineAgent && !isPiRuntime(runtime)) {\n throw new DoomTeamExpectedError(\n ERROR_CODE_UNSUPPORTED_OPERATION,\n `Inline agent '${taskInput.agent}' requires ${PI_RUNTIME_REQUIREMENT} to enforce its read-only tools.`,\n false,\n 'Remove the runtime override or use a discovered external-runtime agent without inlineAgent.',\n );\n }\n if (capabilityCeiling && !isPiRuntime(runtime)) {\n throw new DoomTeamExpectedError(\n ERROR_CODE_UNSUPPORTED_OPERATION,\n `Runtime '${runtime}' cannot enforce the active capability ceiling.`,\n false,\n `Use ${PI_RUNTIME_REQUIREMENT} while plan mode or another capability ceiling is active.`,\n );\n }\n if (!isPiRuntime(runtime)) {\n let command: string;\n try {\n command = resolveRuntimeLaunch(runtime, runtimes, { prompt: taskInput.task ?? '', cwd }).command;\n } catch (error) {\n throw new DoomTeamExpectedError(\n ERROR_CODE_RUNTIME_UNAVAILABLE,\n error instanceof Error ? error.message : String(error),\n false,\n `Configure a valid external runtime or use ${PI_RUNTIME_REQUIREMENT}.`,\n );\n }\n if (!this.executableAvailable(command)) {\n throw new DoomTeamExpectedError(\n ERROR_CODE_RUNTIME_UNAVAILABLE,\n `Executable '${command}' for runtime '${runtime}' is unavailable.`,\n false,\n `Install the executable, configure its absolute path, or use ${PI_RUNTIME_REQUIREMENT}.`,\n );\n }\n }\n }\n const forkSource =\n request.parentSessionFile && request.parentLeafId\n ? { sessionFile: request.parentSessionFile, leafId: request.parentLeafId }\n : undefined;\n const preparedSessionFiles: Array<string | undefined> = [];\n try {\n for (const [index, taskInput] of tasks.entries()) {\n preparedSessionFiles.push(\n resolveEffectiveContext(taskInput, resolvedAgents[index]!) === CONTEXT_FORK\n ? this.createForkSessionFile(forkSource!, taskInput.cwd ?? request.cwd)\n : undefined,\n );\n }\n } catch (error) {\n for (const sessionFile of preparedSessionFiles) {\n if (sessionFile) this.removePreparedSessionFile(sessionFile);\n }\n throw new DoomTeamExpectedError(\n ERROR_CODE_UNSUPPORTED_CONTEXT,\n error instanceof Error ? error.message : String(error),\n false,\n 'Retry from an active persisted Pi session or explicitly request a fresh run.',\n );\n }\n\n const concurrency = fanout\n ? (request.concurrency ?? config.parallel?.concurrency ?? DEFAULT_PARALLEL_CONCURRENCY)\n : 1;\n\n const factories = tasks.map(\n (taskInput, childIndex) => () =>\n this.spawnOneChild({\n runId: runIds[childIndex]!,\n operationId: request.operationId,\n agentConfig: resolvedAgents[childIndex]!,\n excludeTools: teamPackageExcludeTools,\n teamPackageModels,\n capabilityCeiling,\n taskInput,\n childIndex,\n fanout,\n fallbackCwd: request.cwd,\n parentSessionId: request.parentSessionId,\n parentSessionFile: request.parentSessionFile,\n preparedSessionFile: preparedSessionFiles[childIndex],\n handshakeTimeoutMs: config.handshakeTimeoutMs,\n artifacts: request.artifacts,\n artifactDir: config.artifactDir,\n availableModels: request.availableModels,\n parentModel: request.parentModel,\n runtime: request.runtime,\n runtimes,\n }),\n );\n\n const settled = await runWithConcurrency(factories, concurrency, this.reportConcurrencyEvent);\n // `spawnOneChild` never rejects (it catches its own spawn failure into\n // an `{error}` outcome), so `runWithConcurrency` never sees a rejection\n // here - this unwrap is defensive, not a real branch.\n const outcomes = settled.map((outcome, index) =>\n outcome.status === 'fulfilled'\n ? outcome.value\n : {\n agent: resolvedAgents[index]!.name,\n task: tasks[index]!.task ?? '',\n childIndex: index,\n error: outcome.reason instanceof Error ? outcome.reason.message : String(outcome.reason),\n },\n );\n\n return { outcomes };\n }\n}\n"],"mappings":"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"}